From 71de8270d877862b1c2ed76a6f9cea457ea8c9dd Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sat, 21 May 2022 20:40:44 +0200 Subject: [PATCH 001/110] Added warning to readme --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 3f4f381..e6fd47a 100644 --- a/readme.md +++ b/readme.md @@ -101,6 +101,8 @@ size KEY_SIZE, and they are combined using *ci+1 = ci &xop This is a one-way operation. Since the key used for this operation is the cleartext itself, you cannot undo it without already knowing the password(=cleartext) to begin with. *You could make a hashfunction out of this.* +## Noteworthy: +* This is no fixed algorithm. Newer versions may very well be unable to decrypt ciphertexts encrypted with earlier versions. ## LICENSE ``` From f3b6dc155c48d0557393bae0bda43324eb7fb0f8 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sat, 21 May 2022 20:41:09 +0200 Subject: [PATCH 002/110] Implemented digestion (feeding one block at a time) --- GCryptLib/include/GCrypt/Cipher.h | 39 +++++++++------- GCryptLib/include/GCrypt/GCryptWrapper.h | 7 +++ GCryptLib/include/GCrypt/SecureBitset.h | 5 ++- GCryptLib/include/GCrypt/Util.h | 4 +- GCryptLib/src/Cipher.cpp | 57 +++++++++++++++++------- GCryptLib/src/GCryptWrapper.cpp | 47 ++++++++++++++----- 6 files changed, 111 insertions(+), 48 deletions(-) diff --git a/GCryptLib/include/GCrypt/Cipher.h b/GCryptLib/include/GCrypt/Cipher.h index 0685818..e456d75 100644 --- a/GCryptLib/include/GCrypt/Cipher.h +++ b/GCryptLib/include/GCrypt/Cipher.h @@ -3,37 +3,42 @@ #include "GCrypt/Flexblock.h" namespace Leonetienne::GCrypt { - /** Class to apply a block cipher to messages of arbitrary length in a distributed manner + /** Class to apply a block/-stream cipher to messages of arbitrary length in a distributed manner */ class Cipher { public: - explicit Cipher(const Block& key); - explicit Cipher(const std::string& password); + //! Describes the direction the cipher runs in + enum class CIPHER_DIRECTION { + ENCIPHER, + DECIPHER + }; + //! Will initialize this cipher with a key + explicit Cipher(const Block& key, const CIPHER_DIRECTION direction); + + //! Will initialize this cipher with a key + explicit Cipher(const std::string& password, const CIPHER_DIRECTION direction); + + // Disable copying Cipher(const Cipher& other) = delete; Cipher(Cipher&& other) noexcept = delete; ~Cipher(); - //! Will set the key - void SetKey(const Block& key); - - //! Will set the key from a password - void SetPassword(const std::string& password); - - //! Will encipher a flexblock of data - Flexblock Encipher(const Flexblock& data, bool printProgress = false) const; - - //! Will decipher a flexblock of data - Flexblock Decipher(const Flexblock& data, bool printProgress = false) const; + //! Will digest a data block, and return it + Block Digest(const Block& input); private: Block key; + const CIPHER_DIRECTION direction; + + //! The feistel instance to be used + Feistel feistel; + + //! The last block, required for CBC. + Block lastBlock; //! Will zero the memory used by the key void ZeroKeyMemory(); - - // Initial value for cipher block chaining - Block initializationVector; }; } diff --git a/GCryptLib/include/GCrypt/GCryptWrapper.h b/GCryptLib/include/GCrypt/GCryptWrapper.h index 646e67c..46c5c62 100644 --- a/GCryptLib/include/GCrypt/GCryptWrapper.h +++ b/GCryptLib/include/GCrypt/GCryptWrapper.h @@ -1,5 +1,8 @@ #pragma once #include +#include "GCrypt/Flexblock.h" +#include "GCrypt/Block.h" +#include "GCrypt/Cipher.h" namespace Leonetienne::GCrypt { /** This class is a wrapper to make working with the GhettoCipher @@ -26,6 +29,10 @@ namespace Leonetienne::GCrypt { static bool DecryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password, bool printProgressReport = false); private: + + //! Will digest a flexblock with a key + static Flexblock DigestFlexblock(const Flexblock& data, const Block& key, const Cipher::CIPHER_DIRECTION direction); + // No instanciation! >:( GCryptWrapper(); }; diff --git a/GCryptLib/include/GCrypt/SecureBitset.h b/GCryptLib/include/GCrypt/SecureBitset.h index 927d6ab..b4b1a9d 100644 --- a/GCryptLib/include/GCrypt/SecureBitset.h +++ b/GCryptLib/include/GCrypt/SecureBitset.h @@ -2,6 +2,7 @@ #include #include #include +#include namespace Leonetienne::GCrypt { /** Wrapper for std::bitset that zeroes memory upon deletion. @@ -32,7 +33,7 @@ namespace Leonetienne::GCrypt { SecureBitset& operator^=(const SecureBitset& other); SecureBitset operator&(const SecureBitset& other); SecureBitset operator|(const SecureBitset& other); - SecureBitset operator^(const SecureBitset& other); + SecureBitset operator^(const SecureBitset& other) const; SecureBitset operator~() const; SecureBitset& operator<<=(const std::size_t offset); SecureBitset& operator>>=(const std::size_t offset); @@ -174,7 +175,7 @@ namespace Leonetienne::GCrypt { } template - inline SecureBitset SecureBitset::operator^(const SecureBitset& other) { + inline SecureBitset SecureBitset::operator^(const SecureBitset& other) const { SecureBitset bs; bs.bitset = bitset ^ other.bitset; return bs; diff --git a/GCryptLib/include/GCrypt/Util.h b/GCryptLib/include/GCrypt/Util.h index ced9f56..01019e0 100644 --- a/GCryptLib/include/GCrypt/Util.h +++ b/GCryptLib/include/GCrypt/Util.h @@ -241,7 +241,7 @@ namespace Leonetienne::GCrypt { // To provide confusion, xor the blocks together // To provide diffusion, hash fragment to fragment' first - b ^= Block(Cipher(fragment).Encipher(fragment.to_string())); + b ^= Block(Cipher(fragment, Cipher::CIPHER_DIRECTION::ENCIPHER).Digest(fragment).to_string()); } return b; @@ -258,7 +258,7 @@ namespace Leonetienne::GCrypt { // To provide confusion, xor the blocks together // To provide diffusion, hash fragment to fragment' first - b ^= Block(Cipher(fragment).Encipher(fragment.to_string())); + b ^= Block(Cipher(fragment, Cipher::CIPHER_DIRECTION::ENCIPHER).Digest(fragment).to_string()); } return b; diff --git a/GCryptLib/src/Cipher.cpp b/GCryptLib/src/Cipher.cpp index e3b611a..7fe3125 100644 --- a/GCryptLib/src/Cipher.cpp +++ b/GCryptLib/src/Cipher.cpp @@ -6,18 +6,22 @@ namespace Leonetienne::GCrypt { - Cipher::Cipher(const Block& key) + Cipher::Cipher(const Block& key, const CIPHER_DIRECTION direction) : key { key }, - initializationVector(InitializationVector(key)) { + direction { direction }, + lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key + feistel(key) { return; } - Cipher::Cipher(const std::string& password) + Cipher::Cipher(const std::string& password, const CIPHER_DIRECTION direction) : key { PasswordToKey(password) }, - initializationVector(InitializationVector(key)) { + direction { direction }, + lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key feistel(key) { + feistel(key) { return; } @@ -28,20 +32,42 @@ namespace Leonetienne::GCrypt { return; } - void Cipher::SetKey(const Block& key) { - ZeroKeyMemory(); + Block Cipher::Digest(const Block& input) { + + switch (direction) { + case CIPHER_DIRECTION::ENCIPHER: { + // Rename our input to cleartext + const Block& cleartext = input; + + // First, xor our cleartext with the last block, and then encipher it + Block ciphertext = feistel.Encipher(cleartext ^ lastBlock); + + // Now set our lastBlock to the ciphertext of this block + lastBlock = ciphertext; + + // Now return the ciphertext + return ciphertext; + } + + case CIPHER_DIRECTION::DECIPHER: { + // Rename our input into ciphertext + const Block& ciphertext = input; + + // First, decipher our ciphertext, and then xor it with our last block + Block cleartext = feistel.Decipher(ciphertext) ^ lastBlock; + + // Now set our lastBLock to the ciphertext of this block + lastBlock = ciphertext; + + // Now return the cleartext + return cleartext; + } + } + - this->key = key; - return; - } - - void Cipher::SetPassword(const std::string& password) { - ZeroKeyMemory(); - - key = PasswordToKey(password); - return; } + /* Flexblock Cipher::Encipher(const Flexblock& data, bool printProgress) const { // Split cleartext into blocks std::vector blocks; @@ -113,6 +139,7 @@ namespace Leonetienne::GCrypt { // Return it return ss.str(); } +*/ // These pragmas only work for MSVC and g++, as far as i know. Beware!!! #if defined _WIN32 || defined _WIN64 diff --git a/GCryptLib/src/GCryptWrapper.cpp b/GCryptLib/src/GCryptWrapper.cpp index 04d7f1f..280a664 100644 --- a/GCryptLib/src/GCryptWrapper.cpp +++ b/GCryptLib/src/GCryptWrapper.cpp @@ -5,15 +5,14 @@ namespace Leonetienne::GCrypt { std::string GCryptWrapper::EncryptString(const std::string& cleartext, const std::string& password) { - // Instanciate our cipher and supply a key + // Transform the password to a key const Block key = PasswordToKey(password); - Cipher cipher(key); // Recode the ascii-string to bits const Flexblock cleartext_bits = StringToBits(cleartext); // Encrypt our cleartext bits - const Flexblock ciphertext_bits = cipher.Encipher(cleartext_bits); + const Flexblock ciphertext_bits = DigestFlexblock(cleartext_bits, key, Cipher::CIPHER_DIRECTION::ENCIPHER); // Recode the ciphertext bits to a hex-string const std::string ciphertext = BitsToHexstring(ciphertext_bits); @@ -23,15 +22,14 @@ namespace Leonetienne::GCrypt { } std::string GCryptWrapper::DecryptString(const std::string& ciphertext, const std::string& password) { - // Instanciate our cipher and supply a key + // Transform the password to a key const Block key = PasswordToKey(password); - Cipher cipher(key); // Recode the hex-string to bits const Flexblock ciphertext_bits = HexstringToBits(ciphertext); // Decrypt the ciphertext bits - const std::string cleartext_bits = cipher.Decipher(ciphertext_bits); + const std::string cleartext_bits = DigestFlexblock(ciphertext_bits, key, Cipher::CIPHER_DIRECTION::DECIPHER); // Recode the cleartext bits to an ascii-string const std::string cleartext = BitsToString(cleartext_bits); @@ -45,12 +43,11 @@ namespace Leonetienne::GCrypt { // Read the file to bits const Flexblock cleartext_bits = ReadFileToBits(filename_in); - // Instanciate our cipher and supply a key + // Transform the password to a key const Block key = PasswordToKey(password); - Cipher cipher(key); // Encrypt our cleartext bits - const Flexblock ciphertext_bits = cipher.Encipher(cleartext_bits, printProgressReport); + const Flexblock ciphertext_bits = DigestFlexblock(cleartext_bits, key, Cipher::CIPHER_DIRECTION::ENCIPHER); // Write our ciphertext bits to file WriteBitsToFile(filename_out, ciphertext_bits); @@ -67,12 +64,11 @@ namespace Leonetienne::GCrypt { // Read the file to bits const Flexblock ciphertext_bits = ReadFileToBits(filename_in); - // Instanciate our cipher and supply a key + // Transform the password to a key const Block key = PasswordToKey(password); - Cipher cipher(key); // Decrypt the ciphertext bits - const Flexblock cleartext_bits = cipher.Decipher(ciphertext_bits, printProgressReport); + const Flexblock cleartext_bits = DigestFlexblock(ciphertext_bits, key, Cipher::CIPHER_DIRECTION::DECIPHER); // Write our cleartext bits to file WriteBitsToFile(filename_out, cleartext_bits); @@ -84,5 +80,32 @@ namespace Leonetienne::GCrypt { } } + Flexblock GCryptWrapper::DigestFlexblock(const Flexblock& data, const Block& key, const Cipher::CIPHER_DIRECTION direction) { + // Split input into blocks + std::vector blocks; + + for (std::size_t i = 0; i < data.size(); i += BLOCK_SIZE) { + blocks.push_back(Block( + PadStringToLength(data.substr(i, BLOCK_SIZE), BLOCK_SIZE, '0', false)) + ); + } + + // Create cipher instance + Cipher cipher(key, direction); + + // Digest all blocks + for (Block& block : blocks) { + block = cipher.Digest(block); + } + + // Concatenate ciphertext blocks back into a flexblock + std::stringstream ss; + for (Block& b : blocks) { + ss << b; + } + + // Return it + return ss.str(); + } } From 6dce12b6ee3fe654f0bc516864484c9854cbce04 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 00:23:10 +0200 Subject: [PATCH 003/110] Added class for hashing, that is now used for password to key transformation --- GCryptLib/include/GCrypt/Hasher.h | 34 ++++++++++++++++++ GCryptLib/include/GCrypt/Util.h | 46 ++++--------------------- GCryptLib/src/Hasher.cpp | 57 +++++++++++++++++++++++++++++++ GCryptLib/src/Util.cpp | 13 +++++++ 4 files changed, 111 insertions(+), 39 deletions(-) create mode 100644 GCryptLib/include/GCrypt/Hasher.h create mode 100644 GCryptLib/src/Hasher.cpp create mode 100644 GCryptLib/src/Util.cpp diff --git a/GCryptLib/include/GCrypt/Hasher.h b/GCryptLib/include/GCrypt/Hasher.h new file mode 100644 index 0000000..55e8483 --- /dev/null +++ b/GCryptLib/include/GCrypt/Hasher.h @@ -0,0 +1,34 @@ +#ifndef GCRYPT_HASHER_H +#define GCRYPT_HASHER_H + +#include "GCrypt/Flexblock.h" +#include "GCrypt/Block.h" +#include "GCrypt/Cipher.h" + +namespace Leonetienne::GCrypt { + /** This class implements a hash function, based on the GCrypt cipher + */ + class Hasher { + public: + Hasher(); + + //! Will add the hash value of `data` to the hashsum + void Digest(const Block& data); + + //! Will return the current hashsum + const Block& GetHashsum() const; + + //! Will calculate a hashsum for `data`. + static Block CalculateHashsum(const Flexblock& data); + + private: + //! The cipher to use + Cipher cipher; + + //! The current state of the hashsum + Block block; + }; +} + +#endif + diff --git a/GCryptLib/include/GCrypt/Util.h b/GCryptLib/include/GCrypt/Util.h index 01019e0..789f540 100644 --- a/GCryptLib/include/GCrypt/Util.h +++ b/GCryptLib/include/GCrypt/Util.h @@ -1,4 +1,6 @@ -#pragma once +#ifndef GCRYPT_UTIL_H +#define GCRYPT_UTIL_H + #include #include #include @@ -78,7 +80,7 @@ namespace Leonetienne::GCrypt { } // Pad rest with zeores - return Block(PadStringToLength(ss.str(), 128, '0', false)); + return Block(PadStringToLength(ss.str(), BLOCK_SIZE, '0', false)); } //! Will convert a string to a flexible data block @@ -226,43 +228,7 @@ namespace Leonetienne::GCrypt { } //! Creates a key of size BLOCK_SIZE from a password of arbitrary length. - //! Note that if your password is shorter (in bits) than BLOCK_SIZE, the rest of the key will be padded with 0 (see next line!). - //! To provide a better initial key, (and to get rid of padding zeroes), the raw result (b) will be xor'd with an initialization vector based on b. - //! : return b ^ iv(b) - inline Block PasswordToKey(const std::string& in) { - // Let's provide a nice initial value to be sure even a password of length 0 results in a proper key - Block b = InitializationVector(StringToBitblock("3J7IipfQTDJbO8jtasz9PgWui6faPaEMOuVuAqyhB1S2CRcLw5caawewgDUEG1WN")); - - // Segment the password in segments of key-size, and xor them together. - for (std::size_t i = 0; i < in.size(); i += BLOCK_SIZE / 8) { - const Block fragment = StringToBitblock( - PadStringToLength(in.substr(i, BLOCK_SIZE / 8), BLOCK_SIZE / 8, 0, false) - ); - - // To provide confusion, xor the blocks together - // To provide diffusion, hash fragment to fragment' first - b ^= Block(Cipher(fragment, Cipher::CIPHER_DIRECTION::ENCIPHER).Digest(fragment).to_string()); - } - - return b; - } - - //! Will reduce a flexblock (they are of arbitrary length) to a single block. - //! This single block should change completely, if a single bit in the input flexblock changes anywhere. - inline Block ReductionFunction_Flexblock2Block(const Flexblock& in) { - Block b; // No initialization vector needed here - - // Segment the input in segments of BLOCK_SIZE, and xor them together. - for (std::size_t i = 0; i < in.size(); i += BLOCK_SIZE) { - const Block fragment = Block(PadStringToLength(in.substr(i, BLOCK_SIZE), BLOCK_SIZE, 0, false)); - - // To provide confusion, xor the blocks together - // To provide diffusion, hash fragment to fragment' first - b ^= Block(Cipher(fragment, Cipher::CIPHER_DIRECTION::ENCIPHER).Digest(fragment).to_string()); - } - - return b; - } + Block PasswordToKey(const std::string& in); //! Will read a file into a flexblock inline Flexblock ReadFileToBits(const std::string& filepath) { @@ -307,3 +273,5 @@ namespace Leonetienne::GCrypt { } } +#endif + diff --git a/GCryptLib/src/Hasher.cpp b/GCryptLib/src/Hasher.cpp new file mode 100644 index 0000000..7767bdd --- /dev/null +++ b/GCryptLib/src/Hasher.cpp @@ -0,0 +1,57 @@ +#include "GCrypt/Hasher.h" +#include "GCrypt/Util.h" +#include "GCrypt/InitializationVector.h" + +namespace Leonetienne::GCrypt { + + Hasher::Hasher() : + // Initialize our cipher with a static, but randomly distributed key. + cipher( + StringToBitblock("CfRtNdMTP4Y5CWRd"), + Cipher::CIPHER_DIRECTION::ENCIPHER + ) { + block = InitializationVector(StringToBitblock("3J7IipfQTDJbO8jtasz9PgWui6faPaEMOuVuAqyhB1S2CRcLw5caawewgDUEG1WN")); + + return; + } + + void Hasher::Digest(const Block& data) { + // Encipher the current block, and xor it on the current hashsum + block ^= cipher.Digest(data); + return; + } + + const Block& Hasher::GetHashsum() const { + return block; + } + + Block Hasher::CalculateHashsum(const Flexblock& data) { + // Split input into blocks + std::vector blocks; + + for (std::size_t i = 0; i < data.size(); i += BLOCK_SIZE) { + blocks.push_back(Block( + PadStringToLength(data.substr(i, BLOCK_SIZE), BLOCK_SIZE, '0', false)) + ); + } + + // Add an additional block, containing the length of the input + std::stringstream ss; + ss << data.length(); + const Block lengthBlock = StringToBitblock(ss.str()); + blocks.push_back(lengthBlock); + + // Create hasher instance + Hasher hasher; + + // Digest all blocks + for (Block& block : blocks) { + hasher.Digest(block); + } + + // Return the total hashsum + return hasher.GetHashsum(); + } + +} + diff --git a/GCryptLib/src/Util.cpp b/GCryptLib/src/Util.cpp new file mode 100644 index 0000000..11f2179 --- /dev/null +++ b/GCryptLib/src/Util.cpp @@ -0,0 +1,13 @@ +#include "GCrypt/Util.h" +#include "GCrypt/Hasher.h" + +namespace Leonetienne::GCrypt { + Block PasswordToKey(const std::string& in) { + // We already have a hashing algorithm, so why not use it + // Yeah, this won't work, because it would create an include loop. This method needs to be outsourced to a cpp file.. + + const Block hashedPassword = Hasher::CalculateHashsum(StringToBits(in)); + return hashedPassword; + } +} + From 201917d38504cac9291132ce71979d0d6bf6aae6 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 12:31:33 +0200 Subject: [PATCH 004/110] Warnings are now treated as errors --- GCryptLib/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/GCryptLib/CMakeLists.txt b/GCryptLib/CMakeLists.txt index dba45a1..2e0a2bb 100644 --- a/GCryptLib/CMakeLists.txt +++ b/GCryptLib/CMakeLists.txt @@ -15,6 +15,8 @@ target_include_directories(${PROJECT_NAME} PRIVATE include ) +target_compile_options(${PROJECT_NAME} PRIVATE -Werror) + ######### # Tests # ######### From 29f0efbba52a44fe56f4f15282f0a6fb67034a17 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 12:31:48 +0200 Subject: [PATCH 005/110] Fix warning --- GCryptLib/src/Cipher.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GCryptLib/src/Cipher.cpp b/GCryptLib/src/Cipher.cpp index 7fe3125..4497e7e 100644 --- a/GCryptLib/src/Cipher.cpp +++ b/GCryptLib/src/Cipher.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "GCrypt/Cipher.h" #include "GCrypt/Util.h" #include "GCrypt/InitializationVector.h" @@ -64,7 +65,7 @@ namespace Leonetienne::GCrypt { } } - + throw std::runtime_error("Unreachable branch reached."); } /* From 1cc01a840df17ab52b7947a10b8ce79fade802f6 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 12:51:29 +0200 Subject: [PATCH 006/110] Cmake specify color output as always --- GCryptLib/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/GCryptLib/CMakeLists.txt b/GCryptLib/CMakeLists.txt index 2e0a2bb..0efcb68 100644 --- a/GCryptLib/CMakeLists.txt +++ b/GCryptLib/CMakeLists.txt @@ -15,7 +15,10 @@ target_include_directories(${PROJECT_NAME} PRIVATE include ) -target_compile_options(${PROJECT_NAME} PRIVATE -Werror) +target_compile_options(${PROJECT_NAME} PRIVATE + -Werror + -fdiagnostics-color=always +) ######### # Tests # From 4e2f99c28e9c1efe2f16259b3a945b506394b3e2 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 12:51:58 +0200 Subject: [PATCH 007/110] Renamed class Cipher to GCipher --- .../include/GCrypt/{Cipher.h => GCipher.h} | 16 +- GCryptLib/include/GCrypt/GCryptWrapper.h | 4 +- GCryptLib/include/GCrypt/Hasher.h | 11 +- GCryptLib/include/GCrypt/Util.h | 2 +- GCryptLib/src/Cipher.cpp | 163 ------------------ GCryptLib/src/GCipher.cpp | 89 ++++++++++ GCryptLib/src/GCryptWrapper.cpp | 15 +- GCryptLib/src/Hasher.cpp | 8 +- GCryptLib/test/EncryptEqualsDecrypt.cpp | 2 +- 9 files changed, 119 insertions(+), 191 deletions(-) rename GCryptLib/include/GCrypt/{Cipher.h => GCipher.h} (68%) delete mode 100644 GCryptLib/src/Cipher.cpp create mode 100644 GCryptLib/src/GCipher.cpp diff --git a/GCryptLib/include/GCrypt/Cipher.h b/GCryptLib/include/GCrypt/GCipher.h similarity index 68% rename from GCryptLib/include/GCrypt/Cipher.h rename to GCryptLib/include/GCrypt/GCipher.h index e456d75..c4d7120 100644 --- a/GCryptLib/include/GCrypt/Cipher.h +++ b/GCryptLib/include/GCrypt/GCipher.h @@ -5,32 +5,32 @@ namespace Leonetienne::GCrypt { /** Class to apply a block/-stream cipher to messages of arbitrary length in a distributed manner */ - class Cipher { + class GCipher { public: //! Describes the direction the cipher runs in - enum class CIPHER_DIRECTION { + enum class DIRECTION { ENCIPHER, DECIPHER }; //! Will initialize this cipher with a key - explicit Cipher(const Block& key, const CIPHER_DIRECTION direction); + explicit GCipher(const Block& key, const DIRECTION direction); //! Will initialize this cipher with a key - explicit Cipher(const std::string& password, const CIPHER_DIRECTION direction); + explicit GCipher(const std::string& password, const DIRECTION direction); // Disable copying - Cipher(const Cipher& other) = delete; - Cipher(Cipher&& other) noexcept = delete; + GCipher(const GCipher& other) = delete; + GCipher(GCipher&& other) noexcept = delete; - ~Cipher(); + ~GCipher(); //! Will digest a data block, and return it Block Digest(const Block& input); private: Block key; - const CIPHER_DIRECTION direction; + const DIRECTION direction; //! The feistel instance to be used Feistel feistel; diff --git a/GCryptLib/include/GCrypt/GCryptWrapper.h b/GCryptLib/include/GCrypt/GCryptWrapper.h index 46c5c62..664323e 100644 --- a/GCryptLib/include/GCrypt/GCryptWrapper.h +++ b/GCryptLib/include/GCrypt/GCryptWrapper.h @@ -2,7 +2,7 @@ #include #include "GCrypt/Flexblock.h" #include "GCrypt/Block.h" -#include "GCrypt/Cipher.h" +#include "GCrypt/GCipher.h" namespace Leonetienne::GCrypt { /** This class is a wrapper to make working with the GhettoCipher @@ -31,7 +31,7 @@ namespace Leonetienne::GCrypt { private: //! Will digest a flexblock with a key - static Flexblock DigestFlexblock(const Flexblock& data, const Block& key, const Cipher::CIPHER_DIRECTION direction); + static Flexblock DigestFlexblock(const Flexblock& data, const Block& key, const GCipher::DIRECTION direction); // No instanciation! >:( GCryptWrapper(); diff --git a/GCryptLib/include/GCrypt/Hasher.h b/GCryptLib/include/GCrypt/Hasher.h index 55e8483..a576137 100644 --- a/GCryptLib/include/GCrypt/Hasher.h +++ b/GCryptLib/include/GCrypt/Hasher.h @@ -3,7 +3,7 @@ #include "GCrypt/Flexblock.h" #include "GCrypt/Block.h" -#include "GCrypt/Cipher.h" +#include "GCrypt/GCipher.h" namespace Leonetienne::GCrypt { /** This class implements a hash function, based on the GCrypt cipher @@ -12,8 +12,11 @@ namespace Leonetienne::GCrypt { public: Hasher(); - //! Will add the hash value of `data` to the hashsum - void Digest(const Block& data); + //! Will add the hash value of the block `data` to the hashsum. + //! WARNING: If you compute hashes using this digestive method, + //! you REALLY REALLY should add a trailing block just containing the cleartext size! + //! You MOST LIKELY just want to use the wrapper function GHash::CalculateHashsum(Flexblock const&) instead! + void DigestBlock(const Block& data); //! Will return the current hashsum const Block& GetHashsum() const; @@ -23,7 +26,7 @@ namespace Leonetienne::GCrypt { private: //! The cipher to use - Cipher cipher; + GCipher cipher; //! The current state of the hashsum Block block; diff --git a/GCryptLib/include/GCrypt/Util.h b/GCryptLib/include/GCrypt/Util.h index 789f540..fc25dcc 100644 --- a/GCryptLib/include/GCrypt/Util.h +++ b/GCryptLib/include/GCrypt/Util.h @@ -9,7 +9,7 @@ #include "GCrypt/Block.h" #include "GCrypt/Flexblock.h" #include "GCrypt/Config.h" -#include "GCrypt/Cipher.h" +#include "GCrypt/GCipher.h" #include "GCrypt/InitializationVector.h" namespace Leonetienne::GCrypt { diff --git a/GCryptLib/src/Cipher.cpp b/GCryptLib/src/Cipher.cpp deleted file mode 100644 index 4497e7e..0000000 --- a/GCryptLib/src/Cipher.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#include -#include -#include -#include "GCrypt/Cipher.h" -#include "GCrypt/Util.h" -#include "GCrypt/InitializationVector.h" - -namespace Leonetienne::GCrypt { - - Cipher::Cipher(const Block& key, const CIPHER_DIRECTION direction) - : - key { key }, - direction { direction }, - lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key - feistel(key) { - - return; - } - - Cipher::Cipher(const std::string& password, const CIPHER_DIRECTION direction) - : - key { PasswordToKey(password) }, - direction { direction }, - lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key feistel(key) { - feistel(key) { - return; - } - - Cipher::~Cipher() { - // Clear key memory - ZeroKeyMemory(); - - return; - } - - Block Cipher::Digest(const Block& input) { - - switch (direction) { - case CIPHER_DIRECTION::ENCIPHER: { - // Rename our input to cleartext - const Block& cleartext = input; - - // First, xor our cleartext with the last block, and then encipher it - Block ciphertext = feistel.Encipher(cleartext ^ lastBlock); - - // Now set our lastBlock to the ciphertext of this block - lastBlock = ciphertext; - - // Now return the ciphertext - return ciphertext; - } - - case CIPHER_DIRECTION::DECIPHER: { - // Rename our input into ciphertext - const Block& ciphertext = input; - - // First, decipher our ciphertext, and then xor it with our last block - Block cleartext = feistel.Decipher(ciphertext) ^ lastBlock; - - // Now set our lastBLock to the ciphertext of this block - lastBlock = ciphertext; - - // Now return the cleartext - return cleartext; - } - } - - throw std::runtime_error("Unreachable branch reached."); - } - - /* - Flexblock Cipher::Encipher(const Flexblock& data, bool printProgress) const { - // Split cleartext into blocks - std::vector blocks; - - for (std::size_t i = 0; i < data.size(); i += BLOCK_SIZE) { - blocks.push_back(Block( - PadStringToLength(data.substr(i, BLOCK_SIZE), BLOCK_SIZE, '0', false)) - ); - } - - // Encrypt individual blocks using cipher block chaining - Feistel feistel(key); - - for (std::size_t i = 0; i < blocks.size(); i++) { - // Print reports if desired. If we have > 1000 blocks, print one report every 100 blocks. Otherwise for every 10th block. - if ((i % ((blocks.size() > 1000)? 100 : 10) == 0) && (printProgress)) { - std::cout << "Encrypting... (Block " << i << " / " << blocks.size() << " - " << ((float)i*100 / blocks.size()) << "%)" << std::endl; - } - - const Block& lastBlock = (i>0) ? blocks[i-1] : initializationVector; - blocks[i] = feistel.Encipher(blocks[i] ^ lastBlock); // Xor last cipher block with new clear text block before E() - } - - // Concatenate ciphertext blocks back into a flexblock - std::stringstream ss; - for (Block& b : blocks) { - ss << b; - } - - // Return it - return ss.str(); - } - - Flexblock Cipher::Decipher(const Flexblock& data, bool printProgress) const { - // Split ciphertext into blocks - std::vector blocks; - - for (std::size_t i = 0; i < data.size(); i += BLOCK_SIZE) { - blocks.push_back(Block( - PadStringToLength(data.substr(i, BLOCK_SIZE), BLOCK_SIZE, '0', false)) - ); - } - - // Decrypt individual blocks - Feistel feistel(key); - - // We can't do this in-loop for decryption, because we are decrypting the blocks in-place. - Block lastBlock = initializationVector; - - for (std::size_t i = 0; i < blocks.size(); i++) { - // Print reports if desired. If we have > 1000 blocks, print one report every 100 blocks. Otherwise for every 10th block. - if ((i % ((blocks.size() > 1000) ? 100 : 10) == 0) && (printProgress)) { - std::cout << "Decrypting... (Block " << i << " / " << blocks.size() << " - " << ((float)i*100/ blocks.size()) << "%)" << std::endl; - } - - Block tmpCopy = blocks[i]; - - blocks[i] = feistel.Decipher(blocks[i]) ^ lastBlock; // Decipher cipher block [i] and then xor it with the last cipher block [i-1] we've had - - lastBlock = std::move(tmpCopy); - } - - // Concatenate ciphertext blocks back into a flexblock - std::stringstream ss; - for (Block& b : blocks) { - ss << b; - } - - // Return it - return ss.str(); - } -*/ - - // These pragmas only work for MSVC and g++, as far as i know. Beware!!! -#if defined _WIN32 || defined _WIN64 -#pragma optimize("", off ) -#elif defined __GNUG__ -#pragma GCC push_options -#pragma GCC optimize ("O0") -#endif - void Cipher::ZeroKeyMemory() { - key.reset(); - return; - } -#if defined _WIN32 || defined _WIN64 -#pragma optimize("", on ) -#elif defined __GNUG__ -#pragma GCC pop_options -#endif - -} - diff --git a/GCryptLib/src/GCipher.cpp b/GCryptLib/src/GCipher.cpp new file mode 100644 index 0000000..8e30c93 --- /dev/null +++ b/GCryptLib/src/GCipher.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include "GCrypt/GCipher.h" +#include "GCrypt/Util.h" +#include "GCrypt/InitializationVector.h" + +namespace Leonetienne::GCrypt { + + GCipher::GCipher(const Block& key, const DIRECTION direction) + : + key { key }, + direction { direction }, + lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key + feistel(key) { + + return; + } + + GCipher::GCipher(const std::string& password, const DIRECTION direction) + : + key { PasswordToKey(password) }, + direction { direction }, + lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key feistel(key) { + feistel(key) { + return; + } + + GCipher::~GCipher() { + // Clear key memory + ZeroKeyMemory(); + + return; + } + + Block GCipher::Digest(const Block& input) { + + switch (direction) { + case DIRECTION::ENCIPHER: { + // Rename our input to cleartext + const Block& cleartext = input; + + // First, xor our cleartext with the last block, and then encipher it + Block ciphertext = feistel.Encipher(cleartext ^ lastBlock); + + // Now set our lastBlock to the ciphertext of this block + lastBlock = ciphertext; + + // Now return the ciphertext + return ciphertext; + } + + case DIRECTION::DECIPHER: { + // Rename our input into ciphertext + const Block& ciphertext = input; + + // First, decipher our ciphertext, and then xor it with our last block + Block cleartext = feistel.Decipher(ciphertext) ^ lastBlock; + + // Now set our lastBLock to the ciphertext of this block + lastBlock = ciphertext; + + // Now return the cleartext + return cleartext; + } + } + + throw std::runtime_error("Unreachable branch reached."); + } + + // These pragmas only work for MSVC and g++, as far as i know. Beware!!! +#if defined _WIN32 || defined _WIN64 +#pragma optimize("", off ) +#elif defined __GNUG__ +#pragma GCC push_options +#pragma GCC optimize ("O0") +#endif + void GCipher::ZeroKeyMemory() { + key.reset(); + return; + } +#if defined _WIN32 || defined _WIN64 +#pragma optimize("", on ) +#elif defined __GNUG__ +#pragma GCC pop_options +#endif + +} + diff --git a/GCryptLib/src/GCryptWrapper.cpp b/GCryptLib/src/GCryptWrapper.cpp index 280a664..1ae321b 100644 --- a/GCryptLib/src/GCryptWrapper.cpp +++ b/GCryptLib/src/GCryptWrapper.cpp @@ -1,5 +1,5 @@ #include "GCrypt/GCryptWrapper.h" -#include "GCrypt/Cipher.h" +#include "GCrypt/GCipher.h" #include "GCrypt/Util.h" namespace Leonetienne::GCrypt { @@ -12,7 +12,7 @@ namespace Leonetienne::GCrypt { const Flexblock cleartext_bits = StringToBits(cleartext); // Encrypt our cleartext bits - const Flexblock ciphertext_bits = DigestFlexblock(cleartext_bits, key, Cipher::CIPHER_DIRECTION::ENCIPHER); + const Flexblock ciphertext_bits = DigestFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); // Recode the ciphertext bits to a hex-string const std::string ciphertext = BitsToHexstring(ciphertext_bits); @@ -29,7 +29,7 @@ namespace Leonetienne::GCrypt { const Flexblock ciphertext_bits = HexstringToBits(ciphertext); // Decrypt the ciphertext bits - const std::string cleartext_bits = DigestFlexblock(ciphertext_bits, key, Cipher::CIPHER_DIRECTION::DECIPHER); + const std::string cleartext_bits = DigestFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); // Recode the cleartext bits to an ascii-string const std::string cleartext = BitsToString(cleartext_bits); @@ -47,7 +47,7 @@ namespace Leonetienne::GCrypt { const Block key = PasswordToKey(password); // Encrypt our cleartext bits - const Flexblock ciphertext_bits = DigestFlexblock(cleartext_bits, key, Cipher::CIPHER_DIRECTION::ENCIPHER); + const Flexblock ciphertext_bits = DigestFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); // Write our ciphertext bits to file WriteBitsToFile(filename_out, ciphertext_bits); @@ -68,7 +68,7 @@ namespace Leonetienne::GCrypt { const Block key = PasswordToKey(password); // Decrypt the ciphertext bits - const Flexblock cleartext_bits = DigestFlexblock(ciphertext_bits, key, Cipher::CIPHER_DIRECTION::DECIPHER); + const Flexblock cleartext_bits = DigestFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); // Write our cleartext bits to file WriteBitsToFile(filename_out, cleartext_bits); @@ -80,7 +80,7 @@ namespace Leonetienne::GCrypt { } } - Flexblock GCryptWrapper::DigestFlexblock(const Flexblock& data, const Block& key, const Cipher::CIPHER_DIRECTION direction) { + Flexblock GCryptWrapper::DigestFlexblock(const Flexblock& data, const Block& key, const GCipher::DIRECTION direction) { // Split input into blocks std::vector blocks; @@ -91,9 +91,8 @@ namespace Leonetienne::GCrypt { } // Create cipher instance - Cipher cipher(key, direction); + GCipher cipher(key, direction); - // Digest all blocks for (Block& block : blocks) { block = cipher.Digest(block); } diff --git a/GCryptLib/src/Hasher.cpp b/GCryptLib/src/Hasher.cpp index 7767bdd..9e117ea 100644 --- a/GCryptLib/src/Hasher.cpp +++ b/GCryptLib/src/Hasher.cpp @@ -8,14 +8,14 @@ namespace Leonetienne::GCrypt { // Initialize our cipher with a static, but randomly distributed key. cipher( StringToBitblock("CfRtNdMTP4Y5CWRd"), - Cipher::CIPHER_DIRECTION::ENCIPHER + GCipher::DIRECTION::ENCIPHER ) { block = InitializationVector(StringToBitblock("3J7IipfQTDJbO8jtasz9PgWui6faPaEMOuVuAqyhB1S2CRcLw5caawewgDUEG1WN")); return; } - - void Hasher::Digest(const Block& data) { + + void Hasher::DigestBlock(const Block& data) { // Encipher the current block, and xor it on the current hashsum block ^= cipher.Digest(data); return; @@ -46,7 +46,7 @@ namespace Leonetienne::GCrypt { // Digest all blocks for (Block& block : blocks) { - hasher.Digest(block); + hasher.DigestBlock(block); } // Return the total hashsum diff --git a/GCryptLib/test/EncryptEqualsDecrypt.cpp b/GCryptLib/test/EncryptEqualsDecrypt.cpp index 4f7d965..5d735bc 100644 --- a/GCryptLib/test/EncryptEqualsDecrypt.cpp +++ b/GCryptLib/test/EncryptEqualsDecrypt.cpp @@ -11,7 +11,7 @@ TEST_CASE(__FILE__"/SingleBlock_NoPadding", "[Encryption/Decryption consistency] // Instanciate our cipher and supply a key const Block key = PasswordToKey("1234"); - const Cipher cipher(key); + const Cipher cipher(key, Cipher::CIPHER_DIRECTION::Encryption); // Recode the ascii-string to bits const Flexblock cleartext_bits = From 734324ec100fe6db33c77f948595d714b58ff846 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 12:55:39 +0200 Subject: [PATCH 008/110] Renamed class Hasher to GHash --- GCryptLib/include/GCrypt/{Hasher.h => GHash.h} | 8 ++++---- GCryptLib/src/{Hasher.cpp => GHash.cpp} | 12 ++++++------ GCryptLib/src/Util.cpp | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) rename GCryptLib/include/GCrypt/{Hasher.h => GHash.h} (91%) rename GCryptLib/src/{Hasher.cpp => GHash.cpp} (84%) diff --git a/GCryptLib/include/GCrypt/Hasher.h b/GCryptLib/include/GCrypt/GHash.h similarity index 91% rename from GCryptLib/include/GCrypt/Hasher.h rename to GCryptLib/include/GCrypt/GHash.h index a576137..bf5301f 100644 --- a/GCryptLib/include/GCrypt/Hasher.h +++ b/GCryptLib/include/GCrypt/GHash.h @@ -1,5 +1,5 @@ -#ifndef GCRYPT_HASHER_H -#define GCRYPT_HASHER_H +#ifndef GCRYPT_GHASH_H +#define GCRYPT_GHASH_H #include "GCrypt/Flexblock.h" #include "GCrypt/Block.h" @@ -8,9 +8,9 @@ namespace Leonetienne::GCrypt { /** This class implements a hash function, based on the GCrypt cipher */ - class Hasher { + class GHash { public: - Hasher(); + GHash(); //! Will add the hash value of the block `data` to the hashsum. //! WARNING: If you compute hashes using this digestive method, diff --git a/GCryptLib/src/Hasher.cpp b/GCryptLib/src/GHash.cpp similarity index 84% rename from GCryptLib/src/Hasher.cpp rename to GCryptLib/src/GHash.cpp index 9e117ea..34864b1 100644 --- a/GCryptLib/src/Hasher.cpp +++ b/GCryptLib/src/GHash.cpp @@ -1,10 +1,10 @@ -#include "GCrypt/Hasher.h" +#include "GCrypt/GHash.h" #include "GCrypt/Util.h" #include "GCrypt/InitializationVector.h" namespace Leonetienne::GCrypt { - Hasher::Hasher() : + GHash::GHash() : // Initialize our cipher with a static, but randomly distributed key. cipher( StringToBitblock("CfRtNdMTP4Y5CWRd"), @@ -15,17 +15,17 @@ namespace Leonetienne::GCrypt { return; } - void Hasher::DigestBlock(const Block& data) { + void GHash::DigestBlock(const Block& data) { // Encipher the current block, and xor it on the current hashsum block ^= cipher.Digest(data); return; } - const Block& Hasher::GetHashsum() const { + const Block& GHash::GetHashsum() const { return block; } - Block Hasher::CalculateHashsum(const Flexblock& data) { + Block GHash::CalculateHashsum(const Flexblock& data) { // Split input into blocks std::vector blocks; @@ -42,7 +42,7 @@ namespace Leonetienne::GCrypt { blocks.push_back(lengthBlock); // Create hasher instance - Hasher hasher; + GHash hasher; // Digest all blocks for (Block& block : blocks) { diff --git a/GCryptLib/src/Util.cpp b/GCryptLib/src/Util.cpp index 11f2179..f514451 100644 --- a/GCryptLib/src/Util.cpp +++ b/GCryptLib/src/Util.cpp @@ -1,12 +1,12 @@ #include "GCrypt/Util.h" -#include "GCrypt/Hasher.h" +#include "GCrypt/GHash.h" namespace Leonetienne::GCrypt { Block PasswordToKey(const std::string& in) { // We already have a hashing algorithm, so why not use it // Yeah, this won't work, because it would create an include loop. This method needs to be outsourced to a cpp file.. - const Block hashedPassword = Hasher::CalculateHashsum(StringToBits(in)); + const Block hashedPassword = GHash::CalculateHashsum(StringToBits(in)); return hashedPassword; } } From cf784ca8accecf2ff1021ab3ed79b812e762e444 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 13:04:20 +0200 Subject: [PATCH 009/110] Renamed method DigestFlexblock to CipherFlexblock, and made it public --- GCryptLib/include/GCrypt/GCryptWrapper.h | 5 +++-- GCryptLib/src/GCryptWrapper.cpp | 14 +++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/GCryptLib/include/GCrypt/GCryptWrapper.h b/GCryptLib/include/GCrypt/GCryptWrapper.h index 664323e..bf56ada 100644 --- a/GCryptLib/include/GCrypt/GCryptWrapper.h +++ b/GCryptLib/include/GCrypt/GCryptWrapper.h @@ -28,10 +28,11 @@ namespace Leonetienne::GCrypt { //! @filename_out The file the decrypted version should be saved in. static bool DecryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password, bool printProgressReport = false); + //! Will enncrypt or decrypt an entire flexblock of binary data, given a key. + static Flexblock CipherFlexblock(const Flexblock& data, const Block& key, const GCipher::DIRECTION direction); + private: - //! Will digest a flexblock with a key - static Flexblock DigestFlexblock(const Flexblock& data, const Block& key, const GCipher::DIRECTION direction); // No instanciation! >:( GCryptWrapper(); diff --git a/GCryptLib/src/GCryptWrapper.cpp b/GCryptLib/src/GCryptWrapper.cpp index 1ae321b..9161f0a 100644 --- a/GCryptLib/src/GCryptWrapper.cpp +++ b/GCryptLib/src/GCryptWrapper.cpp @@ -12,7 +12,7 @@ namespace Leonetienne::GCrypt { const Flexblock cleartext_bits = StringToBits(cleartext); // Encrypt our cleartext bits - const Flexblock ciphertext_bits = DigestFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); + const Flexblock ciphertext_bits = CipherFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); // Recode the ciphertext bits to a hex-string const std::string ciphertext = BitsToHexstring(ciphertext_bits); @@ -29,7 +29,7 @@ namespace Leonetienne::GCrypt { const Flexblock ciphertext_bits = HexstringToBits(ciphertext); // Decrypt the ciphertext bits - const std::string cleartext_bits = DigestFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); + const std::string cleartext_bits = CipherFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); // Recode the cleartext bits to an ascii-string const std::string cleartext = BitsToString(cleartext_bits); @@ -47,7 +47,7 @@ namespace Leonetienne::GCrypt { const Block key = PasswordToKey(password); // Encrypt our cleartext bits - const Flexblock ciphertext_bits = DigestFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); + const Flexblock ciphertext_bits = CipherFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); // Write our ciphertext bits to file WriteBitsToFile(filename_out, ciphertext_bits); @@ -68,7 +68,7 @@ namespace Leonetienne::GCrypt { const Block key = PasswordToKey(password); // Decrypt the ciphertext bits - const Flexblock cleartext_bits = DigestFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); + const Flexblock cleartext_bits = CipherFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); // Write our cleartext bits to file WriteBitsToFile(filename_out, cleartext_bits); @@ -80,7 +80,11 @@ namespace Leonetienne::GCrypt { } } - Flexblock GCryptWrapper::DigestFlexblock(const Flexblock& data, const Block& key, const GCipher::DIRECTION direction) { + Flexblock GCryptWrapper::CipherFlexblock( + const Flexblock& data, + const Block& key, + const GCipher::DIRECTION direction) + { // Split input into blocks std::vector blocks; From bb76cbb2d7a9abf2b354542f3f1e89f8501592aa Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 13:07:40 +0200 Subject: [PATCH 010/110] Renamed class GCryptWrapper to GWrapper --- GCryptLib/exec/main.cpp | 10 +++++----- .../include/GCrypt/{GCryptWrapper.h => GWrapper.h} | 5 ++--- GCryptLib/src/{GCryptWrapper.cpp => GWrapper.cpp} | 12 ++++++------ 3 files changed, 13 insertions(+), 14 deletions(-) rename GCryptLib/include/GCrypt/{GCryptWrapper.h => GWrapper.h} (97%) rename GCryptLib/src/{GCryptWrapper.cpp => GWrapper.cpp} (82%) diff --git a/GCryptLib/exec/main.cpp b/GCryptLib/exec/main.cpp index d53da03..5f9d3dc 100644 --- a/GCryptLib/exec/main.cpp +++ b/GCryptLib/exec/main.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -14,11 +14,11 @@ void ExampleString() { std::cout << input << std::endl; // Encrypt - const std::string encrypted = GCryptWrapper::EncryptString(input, "password1"); + const std::string encrypted = GWrapper::EncryptString(input, "password1"); std::cout << encrypted << std::endl; // Decrypt - const std::string decrypted = GCryptWrapper::DecryptString(encrypted, "password1"); + const std::string decrypted = GWrapper::DecryptString(encrypted, "password1"); std::cout << decrypted << std::endl; return; @@ -28,10 +28,10 @@ void ExampleFiles() { std::cout << "Example on how to encrypt & decrypt any file:" << std::endl; // Encrypt - GCryptWrapper::EncryptFile("main.cpp", "main.cpp.crypt", "password1"); + GWrapper::EncryptFile("main.cpp", "main.cpp.crypt", "password1"); // Decrypt - GCryptWrapper::DecryptFile("main.cpp.crypt", "main.cpp.clear", "password1"); + GWrapper::DecryptFile("main.cpp.crypt", "main.cpp.clear", "password1"); return; } diff --git a/GCryptLib/include/GCrypt/GCryptWrapper.h b/GCryptLib/include/GCrypt/GWrapper.h similarity index 97% rename from GCryptLib/include/GCrypt/GCryptWrapper.h rename to GCryptLib/include/GCrypt/GWrapper.h index bf56ada..edd984b 100644 --- a/GCryptLib/include/GCrypt/GCryptWrapper.h +++ b/GCryptLib/include/GCrypt/GWrapper.h @@ -8,7 +8,7 @@ namespace Leonetienne::GCrypt { /** This class is a wrapper to make working with the GhettoCipher * super easy with a python-like syntax */ - class GCryptWrapper { + class GWrapper { public: //! Will encrypt a string and return it hexadecimally encoded. static std::string EncryptString(const std::string& cleartext, const std::string& password); @@ -33,9 +33,8 @@ namespace Leonetienne::GCrypt { private: - // No instanciation! >:( - GCryptWrapper(); + GWrapper(); }; } diff --git a/GCryptLib/src/GCryptWrapper.cpp b/GCryptLib/src/GWrapper.cpp similarity index 82% rename from GCryptLib/src/GCryptWrapper.cpp rename to GCryptLib/src/GWrapper.cpp index 9161f0a..386476a 100644 --- a/GCryptLib/src/GCryptWrapper.cpp +++ b/GCryptLib/src/GWrapper.cpp @@ -1,10 +1,10 @@ -#include "GCrypt/GCryptWrapper.h" +#include "GCrypt/GWrapper.h" #include "GCrypt/GCipher.h" #include "GCrypt/Util.h" namespace Leonetienne::GCrypt { - std::string GCryptWrapper::EncryptString(const std::string& cleartext, const std::string& password) { + std::string GWrapper::EncryptString(const std::string& cleartext, const std::string& password) { // Transform the password to a key const Block key = PasswordToKey(password); @@ -21,7 +21,7 @@ namespace Leonetienne::GCrypt { return ciphertext; } - std::string GCryptWrapper::DecryptString(const std::string& ciphertext, const std::string& password) { + std::string GWrapper::DecryptString(const std::string& ciphertext, const std::string& password) { // Transform the password to a key const Block key = PasswordToKey(password); @@ -38,7 +38,7 @@ namespace Leonetienne::GCrypt { return cleartext; } - bool GCryptWrapper::EncryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password, bool printProgressReport) { + bool GWrapper::EncryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password, bool printProgressReport) { try { // Read the file to bits const Flexblock cleartext_bits = ReadFileToBits(filename_in); @@ -59,7 +59,7 @@ namespace Leonetienne::GCrypt { } } - bool GCryptWrapper::DecryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password, bool printProgressReport) { + bool GWrapper::DecryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password, bool printProgressReport) { try { // Read the file to bits const Flexblock ciphertext_bits = ReadFileToBits(filename_in); @@ -80,7 +80,7 @@ namespace Leonetienne::GCrypt { } } - Flexblock GCryptWrapper::CipherFlexblock( + Flexblock GWrapper::CipherFlexblock( const Flexblock& data, const Block& key, const GCipher::DIRECTION direction) From 9fdc642bd64a557a6176d49476cb31f65ce05897 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 13:43:23 +0200 Subject: [PATCH 011/110] Implemented a key class --- GCryptLib/exec/main.cpp | 9 ++++--- GCryptLib/include/GCrypt/Feistel.h | 9 ++++--- GCryptLib/include/GCrypt/GCipher.h | 11 +-------- GCryptLib/include/GCrypt/GWrapper.h | 12 +++++---- GCryptLib/include/GCrypt/Key.h | 26 ++++++++++++++++++++ GCryptLib/include/GCrypt/Keyset.h | 5 ++-- GCryptLib/include/GCrypt/Util.h | 3 --- GCryptLib/src/Feistel.cpp | 12 ++++----- GCryptLib/src/GCipher.cpp | 37 +--------------------------- GCryptLib/src/GHash.cpp | 4 ++- GCryptLib/src/GWrapper.cpp | 38 ++++++++++++++++------------- GCryptLib/src/Key.cpp | 22 +++++++++++++++++ GCryptLib/src/Util.cpp | 7 ------ 13 files changed, 100 insertions(+), 95 deletions(-) create mode 100644 GCryptLib/include/GCrypt/Key.h create mode 100644 GCryptLib/src/Key.cpp diff --git a/GCryptLib/exec/main.cpp b/GCryptLib/exec/main.cpp index 5f9d3dc..62ecf6f 100644 --- a/GCryptLib/exec/main.cpp +++ b/GCryptLib/exec/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include using namespace Leonetienne::GCrypt; @@ -14,11 +15,11 @@ void ExampleString() { std::cout << input << std::endl; // Encrypt - const std::string encrypted = GWrapper::EncryptString(input, "password1"); + const std::string encrypted = GWrapper::EncryptString(input, Key::FromPassword("password1")); std::cout << encrypted << std::endl; // Decrypt - const std::string decrypted = GWrapper::DecryptString(encrypted, "password1"); + const std::string decrypted = GWrapper::DecryptString(encrypted, Key::FromPassword("password1")); std::cout << decrypted << std::endl; return; @@ -28,10 +29,10 @@ void ExampleFiles() { std::cout << "Example on how to encrypt & decrypt any file:" << std::endl; // Encrypt - GWrapper::EncryptFile("main.cpp", "main.cpp.crypt", "password1"); + GWrapper::EncryptFile("main.cpp", "main.cpp.crypt", Key::FromPassword("password1")); // Decrypt - GWrapper::DecryptFile("main.cpp.crypt", "main.cpp.clear", "password1"); + GWrapper::DecryptFile("main.cpp.crypt", "main.cpp.clear", Key::FromPassword("password1")); return; } diff --git a/GCryptLib/include/GCrypt/Feistel.h b/GCryptLib/include/GCrypt/Feistel.h index b6e39bc..9063d0a 100644 --- a/GCryptLib/include/GCrypt/Feistel.h +++ b/GCryptLib/include/GCrypt/Feistel.h @@ -1,6 +1,7 @@ #pragma once #include "GCrypt/Keyset.h" #include "GCrypt/Block.h" +#include "GCrypt/Key.h" #include "GCrypt/Halfblock.h" namespace Leonetienne::GCrypt { @@ -8,7 +9,7 @@ namespace Leonetienne::GCrypt { */ class Feistel { public: - explicit Feistel(const Block& key); + explicit Feistel(const Key& key); Feistel(const Feistel& other) = delete; Feistel(Feistel&& other) noexcept = delete; @@ -17,7 +18,7 @@ namespace Leonetienne::GCrypt { //! Will set the seed-key for this feistel network. //! Roundkeys will be derived from this. - void SetKey(const Block& key); + void SetKey(const Key& key); //! Will encipher a data block via the set seed-key Block Encipher(const Block& data); @@ -31,7 +32,7 @@ namespace Leonetienne::GCrypt { Block Run(const Block& data, bool reverseKeys); //! Arbitrary cipher function - static Halfblock F(Halfblock m, const Block& key); + static Halfblock F(Halfblock m, const Key& key); //! Split a data block into two half blocks (into L and R) static std::pair FeistelSplit(const Block& block); @@ -49,7 +50,7 @@ namespace Leonetienne::GCrypt { static std::string SBox(const std::string& in); //! Will generate a the round keys - void GenerateRoundKeys(const Block& seedKey); + void GenerateRoundKeys(const Key& seedKey); //! Will zero the memory used by the keyset void ZeroKeyMemory(); diff --git a/GCryptLib/include/GCrypt/GCipher.h b/GCryptLib/include/GCrypt/GCipher.h index c4d7120..2764341 100644 --- a/GCryptLib/include/GCrypt/GCipher.h +++ b/GCryptLib/include/GCrypt/GCipher.h @@ -14,22 +14,16 @@ namespace Leonetienne::GCrypt { }; //! Will initialize this cipher with a key - explicit GCipher(const Block& key, const DIRECTION direction); - - //! Will initialize this cipher with a key - explicit GCipher(const std::string& password, const DIRECTION direction); + explicit GCipher(const Key& key, const DIRECTION direction); // Disable copying GCipher(const GCipher& other) = delete; GCipher(GCipher&& other) noexcept = delete; - ~GCipher(); - //! Will digest a data block, and return it Block Digest(const Block& input); private: - Block key; const DIRECTION direction; //! The feistel instance to be used @@ -37,8 +31,5 @@ namespace Leonetienne::GCrypt { //! The last block, required for CBC. Block lastBlock; - - //! Will zero the memory used by the key - void ZeroKeyMemory(); }; } diff --git a/GCryptLib/include/GCrypt/GWrapper.h b/GCryptLib/include/GCrypt/GWrapper.h index edd984b..e10e550 100644 --- a/GCryptLib/include/GCrypt/GWrapper.h +++ b/GCryptLib/include/GCrypt/GWrapper.h @@ -3,6 +3,8 @@ #include "GCrypt/Flexblock.h" #include "GCrypt/Block.h" #include "GCrypt/GCipher.h" +#include "GCrypt/Key.h" + namespace Leonetienne::GCrypt { /** This class is a wrapper to make working with the GhettoCipher @@ -11,25 +13,25 @@ namespace Leonetienne::GCrypt { class GWrapper { public: //! Will encrypt a string and return it hexadecimally encoded. - static std::string EncryptString(const std::string& cleartext, const std::string& password); + static std::string EncryptString(const std::string& cleartext, const Key& key); //! Will decrypt a hexadecimally encoded string. - static std::string DecryptString(const std::string& ciphertext, const std::string& password); + static std::string DecryptString(const std::string& ciphertext, const Key& key); //! Will encrypt a file. //! Returns false if anything goes wrong (like, file-access). //! @filename_in The file to be read. //! @filename_out The file the encrypted version should be saved in. - static bool EncryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password, bool printProgressReport = false); + static bool EncryptFile(const std::string& filename_in, const std::string& filename_out, const Key& key, bool printProgressReport = false); //! Will decrypt a file. //! Returns false if anything goes wrong (like, file-access). //! @filename_in The file to be read. //! @filename_out The file the decrypted version should be saved in. - static bool DecryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password, bool printProgressReport = false); + static bool DecryptFile(const std::string& filename_in, const std::string& filename_out, const Key& key, bool printProgressReport = false); //! Will enncrypt or decrypt an entire flexblock of binary data, given a key. - static Flexblock CipherFlexblock(const Flexblock& data, const Block& key, const GCipher::DIRECTION direction); + static Flexblock CipherFlexblock(const Flexblock& data, const Key& key, const GCipher::DIRECTION direction); private: diff --git a/GCryptLib/include/GCrypt/Key.h b/GCryptLib/include/GCrypt/Key.h new file mode 100644 index 0000000..d63dd65 --- /dev/null +++ b/GCryptLib/include/GCrypt/Key.h @@ -0,0 +1,26 @@ +#ifndef GCRYPT_KEY_H +#define GCRYPT_KEY_H +#include "GCrypt/Block.h" +#include + +namespace Leonetienne::GCrypt { + + /* This class represents encryption keys. + You can copy them, create them from data blocks, + or even read from files (to be implemented). + */ + class Key : public Block { + public: + static Key FromPassword(const std::string& password); + Key(); + Key(const Key& k); + Key(const Block& b); + + private: + + }; + +} + +#endif + diff --git a/GCryptLib/include/GCrypt/Keyset.h b/GCryptLib/include/GCrypt/Keyset.h index 4857c37..ab331f6 100644 --- a/GCryptLib/include/GCrypt/Keyset.h +++ b/GCryptLib/include/GCrypt/Keyset.h @@ -1,8 +1,9 @@ #pragma once #include -#include "GCrypt/Block.h" +#include "GCrypt/Key.h" #include "GCrypt/Config.h" namespace Leonetienne::GCrypt { - typedef std::array Keyset; + typedef std::array Keyset; } + diff --git a/GCryptLib/include/GCrypt/Util.h b/GCryptLib/include/GCrypt/Util.h index fc25dcc..05de131 100644 --- a/GCryptLib/include/GCrypt/Util.h +++ b/GCryptLib/include/GCrypt/Util.h @@ -227,9 +227,6 @@ namespace Leonetienne::GCrypt { return ss.str(); } - //! Creates a key of size BLOCK_SIZE from a password of arbitrary length. - Block PasswordToKey(const std::string& in); - //! Will read a file into a flexblock inline Flexblock ReadFileToBits(const std::string& filepath) { // Read file diff --git a/GCryptLib/src/Feistel.cpp b/GCryptLib/src/Feistel.cpp index 167624e..dd14dc4 100644 --- a/GCryptLib/src/Feistel.cpp +++ b/GCryptLib/src/Feistel.cpp @@ -5,7 +5,7 @@ namespace Leonetienne::GCrypt { - Feistel::Feistel(const Block& key) { + Feistel::Feistel(const Key& key) { SetKey(key); return; } @@ -16,7 +16,7 @@ namespace Leonetienne::GCrypt { return; } - void Feistel::SetKey(const Block& key) { + void Feistel::SetKey(const Key& key) { GenerateRoundKeys(key); return; } @@ -59,7 +59,7 @@ namespace Leonetienne::GCrypt { return FeistelCombine(r, l); } - Halfblock Feistel::F(Halfblock m, const Block& key) { + Halfblock Feistel::F(Halfblock m, const Key& key) { // Made-up F function // Expand to full bitwidth @@ -174,7 +174,7 @@ namespace Leonetienne::GCrypt { return subMap[in]; } - void Feistel::GenerateRoundKeys(const Block& seedKey) { + void Feistel::GenerateRoundKeys(const Key& seedKey) { // Clear initial key memory ZeroKeyMemory(); roundKeys = Keyset(); @@ -234,7 +234,7 @@ namespace Leonetienne::GCrypt { Halfblock halfkey1 = F(halfkeys.first, roundKeys[i - 2]); Halfblock halfkey2 = halfkeys.second ^ halfkey1; // I know this is reversible, but it helps to diffuse future round keys. - roundKeys[i] = FeistelCombine(halfkey1, halfkey2); + roundKeys[i] = Key(FeistelCombine(halfkey1, halfkey2)); } return; @@ -248,7 +248,7 @@ namespace Leonetienne::GCrypt { #pragma GCC optimize ("O0") #endif void Feistel::ZeroKeyMemory() { - for (Block& key : roundKeys) { + for (Key& key : roundKeys) { key.reset(); } diff --git a/GCryptLib/src/GCipher.cpp b/GCryptLib/src/GCipher.cpp index 8e30c93..10cebab 100644 --- a/GCryptLib/src/GCipher.cpp +++ b/GCryptLib/src/GCipher.cpp @@ -7,9 +7,8 @@ namespace Leonetienne::GCrypt { - GCipher::GCipher(const Block& key, const DIRECTION direction) + GCipher::GCipher(const Key& key, const DIRECTION direction) : - key { key }, direction { direction }, lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key feistel(key) { @@ -17,22 +16,6 @@ namespace Leonetienne::GCrypt { return; } - GCipher::GCipher(const std::string& password, const DIRECTION direction) - : - key { PasswordToKey(password) }, - direction { direction }, - lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key feistel(key) { - feistel(key) { - return; - } - - GCipher::~GCipher() { - // Clear key memory - ZeroKeyMemory(); - - return; - } - Block GCipher::Digest(const Block& input) { switch (direction) { @@ -67,23 +50,5 @@ namespace Leonetienne::GCrypt { throw std::runtime_error("Unreachable branch reached."); } - - // These pragmas only work for MSVC and g++, as far as i know. Beware!!! -#if defined _WIN32 || defined _WIN64 -#pragma optimize("", off ) -#elif defined __GNUG__ -#pragma GCC push_options -#pragma GCC optimize ("O0") -#endif - void GCipher::ZeroKeyMemory() { - key.reset(); - return; - } -#if defined _WIN32 || defined _WIN64 -#pragma optimize("", on ) -#elif defined __GNUG__ -#pragma GCC pop_options -#endif - } diff --git a/GCryptLib/src/GHash.cpp b/GCryptLib/src/GHash.cpp index 34864b1..1fcb501 100644 --- a/GCryptLib/src/GHash.cpp +++ b/GCryptLib/src/GHash.cpp @@ -7,7 +7,9 @@ namespace Leonetienne::GCrypt { GHash::GHash() : // Initialize our cipher with a static, but randomly distributed key. cipher( - StringToBitblock("CfRtNdMTP4Y5CWRd"), + // Can't use Key::FromPassword here, because it depends on GHash. + // Instead use a hardcoded key. + Key(StringToBitblock("CfRtNdMTP4Y5CWRd")), GCipher::DIRECTION::ENCIPHER ) { block = InitializationVector(StringToBitblock("3J7IipfQTDJbO8jtasz9PgWui6faPaEMOuVuAqyhB1S2CRcLw5caawewgDUEG1WN")); diff --git a/GCryptLib/src/GWrapper.cpp b/GCryptLib/src/GWrapper.cpp index 386476a..eacc8bb 100644 --- a/GCryptLib/src/GWrapper.cpp +++ b/GCryptLib/src/GWrapper.cpp @@ -4,10 +4,10 @@ namespace Leonetienne::GCrypt { - std::string GWrapper::EncryptString(const std::string& cleartext, const std::string& password) { - // Transform the password to a key - const Block key = PasswordToKey(password); - + std::string GWrapper::EncryptString( + const std::string& cleartext, + const Key& key) + { // Recode the ascii-string to bits const Flexblock cleartext_bits = StringToBits(cleartext); @@ -21,10 +21,10 @@ namespace Leonetienne::GCrypt { return ciphertext; } - std::string GWrapper::DecryptString(const std::string& ciphertext, const std::string& password) { - // Transform the password to a key - const Block key = PasswordToKey(password); - + std::string GWrapper::DecryptString( + const std::string& ciphertext, + const Key& key) + { // Recode the hex-string to bits const Flexblock ciphertext_bits = HexstringToBits(ciphertext); @@ -38,14 +38,16 @@ namespace Leonetienne::GCrypt { return cleartext; } - bool GWrapper::EncryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password, bool printProgressReport) { + bool GWrapper::EncryptFile( + const std::string& filename_in, + const std::string& filename_out, + const Key& key, + bool printProgressReport) + { try { // Read the file to bits const Flexblock cleartext_bits = ReadFileToBits(filename_in); - // Transform the password to a key - const Block key = PasswordToKey(password); - // Encrypt our cleartext bits const Flexblock ciphertext_bits = CipherFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); @@ -59,14 +61,16 @@ namespace Leonetienne::GCrypt { } } - bool GWrapper::DecryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password, bool printProgressReport) { + bool GWrapper::DecryptFile( + const std::string& filename_in, + const std::string& filename_out, + const Key& key, + bool printProgressReport) + { try { // Read the file to bits const Flexblock ciphertext_bits = ReadFileToBits(filename_in); - // Transform the password to a key - const Block key = PasswordToKey(password); - // Decrypt the ciphertext bits const Flexblock cleartext_bits = CipherFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); @@ -82,7 +86,7 @@ namespace Leonetienne::GCrypt { Flexblock GWrapper::CipherFlexblock( const Flexblock& data, - const Block& key, + const Key& key, const GCipher::DIRECTION direction) { // Split input into blocks diff --git a/GCryptLib/src/Key.cpp b/GCryptLib/src/Key.cpp new file mode 100644 index 0000000..2bffc67 --- /dev/null +++ b/GCryptLib/src/Key.cpp @@ -0,0 +1,22 @@ +#include "GCrypt/Key.h" +#include "GCrypt/GHash.h" +#include "GCrypt/Util.h" + +namespace Leonetienne::GCrypt { + + Key Key::FromPassword(const std::string& password) { + return GHash::CalculateHashsum( + StringToBits(password) + ); + } + + Key::Key() : Block() { + } + + Key::Key(const Block& b) : Block(b) { + } + + Key::Key(const Key& k) : Block(k) { + } +} + diff --git a/GCryptLib/src/Util.cpp b/GCryptLib/src/Util.cpp index f514451..96e3293 100644 --- a/GCryptLib/src/Util.cpp +++ b/GCryptLib/src/Util.cpp @@ -2,12 +2,5 @@ #include "GCrypt/GHash.h" namespace Leonetienne::GCrypt { - Block PasswordToKey(const std::string& in) { - // We already have a hashing algorithm, so why not use it - // Yeah, this won't work, because it would create an include loop. This method needs to be outsourced to a cpp file.. - - const Block hashedPassword = GHash::CalculateHashsum(StringToBits(in)); - return hashedPassword; - } } From fedb30bb4322bc68b6644857aa809c7c77cce9ae Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 13:54:03 +0200 Subject: [PATCH 012/110] Added padding direction option for Util::StringToBitblock --- GCryptLib/include/GCrypt/Util.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/GCryptLib/include/GCrypt/Util.h b/GCryptLib/include/GCrypt/Util.h index 05de131..e900644 100644 --- a/GCryptLib/include/GCrypt/Util.h +++ b/GCryptLib/include/GCrypt/Util.h @@ -72,7 +72,9 @@ namespace Leonetienne::GCrypt { } //! Will convert a string to a fixed-size data block - inline Block StringToBitblock(const std::string& s) { + //! @s: The string to pad + //! padLeft: should padding be added to the left? If not, to the right. + inline Block StringToBitblock(const std::string& s, bool padLeft = true) { std::stringstream ss; for (std::size_t i = 0; i < s.size(); i++) { @@ -80,7 +82,7 @@ namespace Leonetienne::GCrypt { } // Pad rest with zeores - return Block(PadStringToLength(ss.str(), BLOCK_SIZE, '0', false)); + return Block(PadStringToLength(ss.str(), BLOCK_SIZE, '0', padLeft)); } //! Will convert a string to a flexible data block From b0e0c0cd99001371321af5f5f5e7f5b074a88069 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 14:13:10 +0200 Subject: [PATCH 013/110] Moved utility functions to cpp file --- GCryptLib/include/GCrypt/Util.h | 210 ++------------------------------ GCryptLib/src/Util.cpp | 209 +++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+), 197 deletions(-) diff --git a/GCryptLib/include/GCrypt/Util.h b/GCryptLib/include/GCrypt/Util.h index e900644..34f3e28 100644 --- a/GCryptLib/include/GCrypt/Util.h +++ b/GCryptLib/include/GCrypt/Util.h @@ -45,231 +45,47 @@ namespace Leonetienne::GCrypt { } //! Will pad a string to a set length with a certain character - inline std::string PadStringToLength(const std::string& str, const std::size_t len, const char pad, const bool padLeft = true) { - // Fast-reject: Already above padded length - if (str.length() >= len) { - return str; - } - - std::stringstream ss; - - // Pad left: - if (padLeft) { - for (std::size_t i = 0; i < len - str.size(); i++) { - ss << pad; - } - ss << str; - } - // Pad right: - else { - ss << str; - for (std::size_t i = 0; i < len - str.size(); i++) { - ss << pad; - } - } - - return ss.str(); - } + std::string PadStringToLength(const std::string& str, const std::size_t len, const char pad, const bool padLeft = true); //! Will convert a string to a fixed-size data block //! @s: The string to pad //! padLeft: should padding be added to the left? If not, to the right. - inline Block StringToBitblock(const std::string& s, bool padLeft = true) { - std::stringstream ss; - - for (std::size_t i = 0; i < s.size(); i++) { - ss << std::bitset<8>(s[i]); - } - - // Pad rest with zeores - return Block(PadStringToLength(ss.str(), BLOCK_SIZE, '0', padLeft)); - } + Block StringToBitblock(const std::string& s, bool padLeft = true); //! Will convert a string to a flexible data block - inline Flexblock StringToBits(const std::string& s) { - std::stringstream ss; - - for (std::size_t i = 0; i < s.size(); i++) { - ss << std::bitset<8>(s[i]); - } - - return Flexblock(ss.str()); - } + Flexblock StringToBits(const std::string& s); //! Will convert a fixed-size data block to a bytestring - inline std::string BitblockToBytes(const Block& bits) { - std::stringstream ss; - - const std::string bitstring = bits.to_string(); - - for (std::size_t i = 0; i < BLOCK_SIZE; i += 8) { - ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong(); - } - - return ss.str(); - } + std::string BitblockToBytes(const Block& bits); //! Will convert a fixed-size data block to a string //! The difference to BitblockToBytes() is, that it strips excess nullbytes - inline std::string BitblockToString(const Block& bits) { - // Decode to bytes - std::string text = BitblockToBytes(bits); - - // Dümp excess nullbytes - text.resize(strlen(text.data())); - - return text; - } + std::string BitblockToString(const Block& bits); //! Will convert a flexible data block to a bytestring - inline std::string BitsToBytes(const Flexblock& bits) { - std::stringstream ss; - - const std::string bitstring = bits; - - for (std::size_t i = 0; i < bits.size(); i += 8) { - ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong(); - } - - return ss.str(); - } + std::string BitsToBytes(const Flexblock& bits); //! Will convert a flexible data block to a string //! The difference to BitsToBytes() is, that it strips excess nullbytes - inline std::string BitsToString(const Flexblock& bits) { - // Decode to bytes - std::string text = BitsToBytes(bits); - - // Dümp excess nullbytes - text.resize(strlen(text.data())); - - return text; - } + std::string BitsToString(const Flexblock& bits); //! Turns a fixed-size data block into a hex-string - inline std::string BitblockToHexstring(const Block& b) { - std::stringstream ss; - const std::string charset = "0123456789abcdef"; - const std::string bstr = b.to_string(); - - for (std::size_t i = 0; i < bstr.size(); i += 4) { - ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()]; - } - - return ss.str(); - } + std::string BitblockToHexstring(const Block& b); //! Turns a flexible data block into a hex-string - inline std::string BitsToHexstring(const Flexblock& b) { - std::stringstream ss; - const std::string charset = "0123456789abcdef"; - const std::string bstr = b; - - for (std::size_t i = 0; i < bstr.size(); i += 4) { - ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()]; - } - - return ss.str(); - } - + std::string BitsToHexstring(const Flexblock& b); //! Turns a hex string into a fixed-size data block - inline Block HexstringToBitblock(const std::string& hexstring) { - std::stringstream ss; - - for (std::size_t i = 0; i < hexstring.size(); i++) { - const char c = hexstring[i]; - - // Get value - std::size_t value; - if ((c >= '0') && (c <= '9')) { - // Is it a number? - value = ((std::size_t)c - '0') + 0; - } - else if ((c >= 'a') && (c <= 'f')) { - // Else, it is a lowercase letter - value = ((std::size_t)c - 'a') + 10; - } - else { - throw std::logic_error("non-hex string detected in HexstringToBits()"); - } - - // Append to our bits - ss << std::bitset<4>(value); - } - - return Block(ss.str()); - } + Block HexstringToBitblock(const std::string& hexstring); //! Turns a hex string into a flexible data block - inline Flexblock HexstringToBits(const std::string& hexstring) { - std::stringstream ss; - - for (std::size_t i = 0; i < hexstring.size(); i++) { - const char c = hexstring[i]; - - // Get value - std::size_t value; - if ((c >= '0') && (c <= '9')) { - // Is it a number? - value = ((std::size_t)c - '0') + 0; - } - else if ((c >= 'a') && (c <= 'f')) { - // Else, it is a lowercase letter - value = ((std::size_t)c - 'a') + 10; - } - else { - throw std::logic_error("non-hex string detected in HexstringToBits()"); - } - - // Append to our bits - ss << std::bitset<4>(value); - } - - return ss.str(); - } + Flexblock HexstringToBits(const std::string& hexstring); //! Will read a file into a flexblock - inline Flexblock ReadFileToBits(const std::string& filepath) { - // Read file - std::ifstream ifs(filepath, std::ios::binary); - - if (!ifs.good()) { - throw std::runtime_error("Unable to open ifilestream!"); - } - - std::stringstream ss; - std::copy( - std::istreambuf_iterator(ifs), - std::istreambuf_iterator(), - std::ostreambuf_iterator(ss) - ); - - ifs.close(); - - const std::string bytes = ss.str(); - - // Convert bytes to bits - return StringToBits(bytes); - } + Flexblock ReadFileToBits(const std::string& filepath); //! Will save bits to a binary file - inline void WriteBitsToFile(const std::string& filepath, const Flexblock& bits) { - // Convert bits to bytes - const std::string bytes = BitsToBytes(bits); - - // Write bits to file - std::ofstream ofs(filepath, std::ios::binary); - - if (!ofs.good()) { - throw std::runtime_error("Unable to open ofilestream!"); - } - - ofs.write(bytes.data(), bytes.length()); - ofs.close(); - - return; - } + void WriteBitsToFile(const std::string& filepath, const Flexblock& bits); } #endif diff --git a/GCryptLib/src/Util.cpp b/GCryptLib/src/Util.cpp index 96e3293..21a98e0 100644 --- a/GCryptLib/src/Util.cpp +++ b/GCryptLib/src/Util.cpp @@ -2,5 +2,214 @@ #include "GCrypt/GHash.h" namespace Leonetienne::GCrypt { + + std::string PadStringToLength(const std::string& str, const std::size_t len, const char pad, const bool padLeft) { + // Fast-reject: Already above padded length + if (str.length() >= len) { + return str; + } + + std::stringstream ss; + + // Pad left: + if (padLeft) { + for (std::size_t i = 0; i < len - str.size(); i++) { + ss << pad; + } + ss << str; + } + // Pad right: + else { + ss << str; + for (std::size_t i = 0; i < len - str.size(); i++) { + ss << pad; + } + } + + return ss.str(); + } + + Block StringToBitblock(const std::string& s, bool padLeft) { + std::stringstream ss; + + for (std::size_t i = 0; i < s.size(); i++) { + ss << std::bitset<8>(s[i]); + } + + // Pad rest with zeores + return Block(PadStringToLength(ss.str(), BLOCK_SIZE, '0', padLeft)); + } + + Flexblock StringToBits(const std::string& s) { + std::stringstream ss; + + for (std::size_t i = 0; i < s.size(); i++) { + ss << std::bitset<8>(s[i]); + } + + return Flexblock(ss.str()); + } + + std::string BitblockToBytes(const Block& bits) { + std::stringstream ss; + + const std::string bitstring = bits.to_string(); + + for (std::size_t i = 0; i < BLOCK_SIZE; i += 8) { + ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong(); + } + + return ss.str(); + } + + std::string BitblockToString(const Block& bits) { + // Decode to bytes + std::string text = BitblockToBytes(bits); + + // Dümp excess nullbytes + text.resize(strlen(text.data())); + + return text; + } + + std::string BitsToBytes(const Flexblock& bits) { + std::stringstream ss; + + const std::string bitstring = bits; + + for (std::size_t i = 0; i < bits.size(); i += 8) { + ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong(); + } + + return ss.str(); + } + + std::string BitsToString(const Flexblock& bits) { + // Decode to bytes + std::string text = BitsToBytes(bits); + + // Dümp excess nullbytes + text.resize(strlen(text.data())); + + return text; + } + + std::string BitblockToHexstring(const Block& b) { + std::stringstream ss; + const std::string charset = "0123456789abcdef"; + const std::string bstr = b.to_string(); + + for (std::size_t i = 0; i < bstr.size(); i += 4) { + ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()]; + } + + return ss.str(); + } + + std::string BitsToHexstring(const Flexblock& b) { + std::stringstream ss; + const std::string charset = "0123456789abcdef"; + const std::string bstr = b; + + for (std::size_t i = 0; i < bstr.size(); i += 4) { + ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()]; + } + + return ss.str(); + } + + Block HexstringToBitblock(const std::string& hexstring) { + std::stringstream ss; + + for (std::size_t i = 0; i < hexstring.size(); i++) { + const char c = hexstring[i]; + + // Get value + std::size_t value; + if ((c >= '0') && (c <= '9')) { + // Is it a number? + value = ((std::size_t)c - '0') + 0; + } + else if ((c >= 'a') && (c <= 'f')) { + // Else, it is a lowercase letter + value = ((std::size_t)c - 'a') + 10; + } + else { + throw std::logic_error("non-hex string detected in HexstringToBits()"); + } + + // Append to our bits + ss << std::bitset<4>(value); + } + + return Block(ss.str()); + } + + Flexblock HexstringToBits(const std::string& hexstring) { + std::stringstream ss; + + for (std::size_t i = 0; i < hexstring.size(); i++) { + const char c = hexstring[i]; + + // Get value + std::size_t value; + if ((c >= '0') && (c <= '9')) { + // Is it a number? + value = ((std::size_t)c - '0') + 0; + } + else if ((c >= 'a') && (c <= 'f')) { + // Else, it is a lowercase letter + value = ((std::size_t)c - 'a') + 10; + } + else { + throw std::logic_error("non-hex string detected in HexstringToBits()"); + } + + // Append to our bits + ss << std::bitset<4>(value); + } + + return ss.str(); + } + + Flexblock ReadFileToBits(const std::string& filepath) { + // Read file + std::ifstream ifs(filepath, std::ios::binary); + + if (!ifs.good()) { + throw std::runtime_error("Unable to open ifilestream!"); + } + + std::stringstream ss; + std::copy( + std::istreambuf_iterator(ifs), + std::istreambuf_iterator(), + std::ostreambuf_iterator(ss) + ); + + ifs.close(); + + const std::string bytes = ss.str(); + + // Convert bytes to bits + return StringToBits(bytes); + } + + void WriteBitsToFile(const std::string& filepath, const Flexblock& bits) { + // Convert bits to bytes + const std::string bytes = BitsToBytes(bits); + + // Write bits to file + std::ofstream ofs(filepath, std::ios::binary); + + if (!ofs.good()) { + throw std::runtime_error("Unable to open ofilestream!"); + } + + ofs.write(bytes.data(), bytes.length()); + ofs.close(); + + return; + } } From 967eba2f03f0b9d2f5456540205657d9225deaa6 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 14:21:21 +0200 Subject: [PATCH 014/110] Cmake make colored output --- GCryptLib/CMakeLists.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/GCryptLib/CMakeLists.txt b/GCryptLib/CMakeLists.txt index 0efcb68..26fdf1a 100644 --- a/GCryptLib/CMakeLists.txt +++ b/GCryptLib/CMakeLists.txt @@ -34,6 +34,12 @@ target_include_directories(test PRIVATE include ) +target_compile_options(test PRIVATE + -Werror + -fdiagnostics-color=always +) + + ## Move test images to build dir ADD_CUSTOM_COMMAND( TARGET ${PROJECT_NAME} POST_BUILD @@ -55,3 +61,8 @@ target_include_directories(exec PRIVATE include ) +target_compile_options(exec PRIVATE + -Werror + -fdiagnostics-color=always +) + From fe6ec11672f9fb221a9cecf4ad09a10adc49b750 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 14:26:23 +0200 Subject: [PATCH 015/110] Adjusted tests --- GCryptLib/test/EncryptEqualsDecrypt.cpp | 54 ++++++++--------- GCryptLib/test/GCWrapper.cpp | 58 +++++++++---------- .../test/Password2Key_CollisionResistance.cpp | 52 ++++++++--------- 3 files changed, 80 insertions(+), 84 deletions(-) diff --git a/GCryptLib/test/EncryptEqualsDecrypt.cpp b/GCryptLib/test/EncryptEqualsDecrypt.cpp index 5d735bc..e66e371 100644 --- a/GCryptLib/test/EncryptEqualsDecrypt.cpp +++ b/GCryptLib/test/EncryptEqualsDecrypt.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include "Catch2.h" @@ -10,8 +10,7 @@ using namespace Leonetienne::GCrypt; TEST_CASE(__FILE__"/SingleBlock_NoPadding", "[Encryption/Decryption consistency]") { // Instanciate our cipher and supply a key - const Block key = PasswordToKey("1234"); - const Cipher cipher(key, Cipher::CIPHER_DIRECTION::Encryption); + const Key key = Key::FromPassword("1234"); // Recode the ascii-string to bits const Flexblock cleartext_bits = @@ -25,24 +24,23 @@ TEST_CASE(__FILE__"/SingleBlock_NoPadding", "[Encryption/Decryption consistency] "0000011110010110111010110110111110011110011010001100100111110101"; // Encrypt our cleartext bits - const Flexblock ciphertext_bits = cipher.Encipher(cleartext_bits); + const Flexblock ciphertext_bits = GWrapper::CipherFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); // Decipher it again - const Flexblock decryptedBits = cipher.Decipher(ciphertext_bits); + const Flexblock decryptedBits = GWrapper::CipherFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); // Assert that the decrypted text equals the plaintext REQUIRE( - cleartext_bits == - decryptedBits - ); + cleartext_bits == + decryptedBits + ); } // Tests that encrypting a message of less than BLOCK_SIZE yields the exact message plus zero-padding back TEST_CASE(__FILE__"/SingleBlock_Padding", "[Encryption/Decryption consistency]") { // Instanciate our cipher and supply a key - const Block key = PasswordToKey("1234"); - const Cipher cipher(key); + const Key key = Key::FromPassword("1234"); // Recode the ascii-string to bits const Flexblock cleartext_bits = @@ -65,24 +63,23 @@ TEST_CASE(__FILE__"/SingleBlock_Padding", "[Encryption/Decryption consistency]") "0000000000000000000000000000000000000000000000000000000000000000"; // Encrypt our cleartext bits - const Flexblock ciphertext_bits = cipher.Encipher(cleartext_bits); + const Flexblock ciphertext_bits = GWrapper::CipherFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); // Decipher it again - const Flexblock decryptedBits = cipher.Decipher(ciphertext_bits); + const Flexblock decryptedBits = GWrapper::CipherFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); // Assert that the decrypted text equals the plaintext REQUIRE( - cleartext_bits_EXPECTED_RESULT == - decryptedBits - ); + cleartext_bits_EXPECTED_RESULT == + decryptedBits + ); } // Tests that a decrypted ciphertext equals its plaintrext version, using a cleartext that requires A LOT of blocks TEST_CASE(__FILE__"MultiBlock_NoPadding/", "[Encryption/Decryption consistency]") { // Instanciate our cipher and supply a key - const Block key = PasswordToKey("1234"); - const Cipher cipher(key); + const Key key = Key::FromPassword("1234"); // Recode the ascii-string to bits const Flexblock cleartext_bits = @@ -120,24 +117,23 @@ TEST_CASE(__FILE__"MultiBlock_NoPadding/", "[Encryption/Decryption consistency]" "0101110011001101010110010100011001110110000110010001100110011111"; // Encrypt our cleartext bits - const Flexblock ciphertext_bits = cipher.Encipher(cleartext_bits); + const Flexblock ciphertext_bits = GWrapper::CipherFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); // Decipher it again - const Flexblock decryptedBits = cipher.Decipher(ciphertext_bits); + const Flexblock decryptedBits = GWrapper::CipherFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); // Assert that the decrypted text equals the plaintext REQUIRE( - cleartext_bits == - decryptedBits - ); + cleartext_bits == + decryptedBits + ); } // Tests that a decrypted ciphertext equals its plaintrext version, using a cleartext that requires A LOT of blocks TEST_CASE(__FILE__"MultiBlock_Padding/", "[Encryption/Decryption consistency]") { // Instanciate our cipher and supply a key - const Block key = PasswordToKey("1234"); - const Cipher cipher(key); + const Key key = Key::FromPassword("1234"); // Recode the ascii-string to bits const Flexblock cleartext_bits = @@ -208,15 +204,15 @@ TEST_CASE(__FILE__"MultiBlock_Padding/", "[Encryption/Decryption consistency]") "0000000000000000000000000000000000000000000000000000000000000000"; // Encrypt our cleartext bits - const Flexblock ciphertext_bits = cipher.Encipher(cleartext_bits); + const Flexblock ciphertext_bits = GWrapper::CipherFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); // Decipher it again - const Flexblock decryptedBits = cipher.Decipher(ciphertext_bits); + const Flexblock decryptedBits = GWrapper::CipherFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); // Assert that the decrypted text equals the plaintext REQUIRE( - cleartext_bits_EXPECTED_RESULT == - decryptedBits - ); + cleartext_bits_EXPECTED_RESULT == + decryptedBits + ); } diff --git a/GCryptLib/test/GCWrapper.cpp b/GCryptLib/test/GCWrapper.cpp index 2a5be98..e0d228c 100644 --- a/GCryptLib/test/GCWrapper.cpp +++ b/GCryptLib/test/GCWrapper.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include "Catch2.h" @@ -9,50 +9,50 @@ using namespace Leonetienne::GCrypt; // This test will start from scratch after encryption, to ensure EVERYTHING has to be re-calculated. TEST_CASE(__FILE__"/Encrypting and decrypting strings works", "[Wrapper]") { - // Setup - const std::string plaintext = "Hello, World!"; - const std::string password = "Der Affe will Zucker"; + // Setup + const std::string plaintext = "Hello, World!"; + const Key key = Key::FromPassword("Der Affe will Zucker"); - std::string ciphertext; - std::string decrypted; + std::string ciphertext; + std::string decrypted; - // Encryption - ciphertext = GCryptWrapper::EncryptString(plaintext, password); + // Encryption + ciphertext = GWrapper::EncryptString(plaintext, key); - // Decryption - decrypted = GCryptWrapper::DecryptString(ciphertext, password); + // Decryption + decrypted = GWrapper::DecryptString(ciphertext, key); - // Assertion - REQUIRE(plaintext == decrypted); + // Assertion + REQUIRE(plaintext == decrypted); } // Tests that encrypting and decrypting files using the wrapper works. // This test will start from scratch after encryption, to ensure EVERYTHING has to be re-calculated. TEST_CASE(__FILE__"/Encrypting and decrypting files works", "[Wrapper]") { - // Setup - const std::string testfile_dir = "testAssets/"; + // Setup + const std::string testfile_dir = "testAssets/"; - const std::string filename_plain = testfile_dir + "testfile.png"; - const std::string filename_encrypted = testfile_dir + "testfile.png.crypt"; - const std::string filename_decrypted = testfile_dir + "testfile.png.clear.png"; - const std::string password = "Der Affe will Zucker"; + const std::string filename_plain = testfile_dir + "testfile.png"; + const std::string filename_encrypted = testfile_dir + "testfile.png.crypt"; + const std::string filename_decrypted = testfile_dir + "testfile.png.clear.png"; + const Key key = Key::FromPassword("Der Affe will Zucker"); - // Encryption - GCryptWrapper::EncryptFile(filename_plain, filename_encrypted, password); + // Encryption + GWrapper::EncryptFile(filename_plain, filename_encrypted, key); - // Decryption - GCryptWrapper::DecryptFile(filename_encrypted, filename_decrypted, password); + // Decryption + GWrapper::DecryptFile(filename_encrypted, filename_decrypted, key); - // Read in both the base, and the decrypted file - const Flexblock plainfile = ReadFileToBits(filename_plain); - const Flexblock decryptfile = ReadFileToBits(filename_decrypted); + // Read in both the base, and the decrypted file + const Flexblock plainfile = ReadFileToBits(filename_plain); + const Flexblock decryptfile = ReadFileToBits(filename_decrypted); - // Assertion (If this fails, maybe check if the image is even readable by an image viewer) - REQUIRE( - PadStringToLength(plainfile, decryptfile.length(), '0', false) == - decryptfile + // Assertion (If this fails, maybe check if the image is even readable by an image viewer) + REQUIRE( + PadStringToLength(plainfile, decryptfile.length(), '0', false) == + decryptfile ); } diff --git a/GCryptLib/test/Password2Key_CollisionResistance.cpp b/GCryptLib/test/Password2Key_CollisionResistance.cpp index 8cad00a..19587c4 100644 --- a/GCryptLib/test/Password2Key_CollisionResistance.cpp +++ b/GCryptLib/test/Password2Key_CollisionResistance.cpp @@ -55,39 +55,39 @@ inline std::string Base10_2_X(const unsigned long long int i, const std::string // Already validated range: Password 0 - 1.000.000 TEST_CASE(__FILE__"/Password to key transformation collision resistance", "[Key extrapolation]") { - // To test resistence set this to a high number around a million. - // This will take a LONG while to execute though (about 2.5hrs on my machine), hence why it's set so low. - constexpr std::size_t NUM_RUN_TESTS = 1000; + // To test resistence set this to a high number around a million. + // This will take a LONG while to execute though (about 2.5hrs on my machine), hence why it's set so low. + constexpr std::size_t NUM_RUN_TESTS = 10; - std::unordered_map, std::string> keys; // + std::unordered_map, std::string> keys; // - // Try NUM_RUN_TESTS passwords - const std::string charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + // Try NUM_RUN_TESTS passwords + const std::string charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - for (std::size_t i = 0; i < NUM_RUN_TESTS; i++) { - // Get password - const std::string password = Base10_2_X(i, charset, 0); + for (std::size_t i = 0; i < NUM_RUN_TESTS; i++) { + // Get password + const std::string password = Base10_2_X(i, charset, 0); - // Generate key - const std::bitset newKey = PasswordToKey(password).Get(); + // Generate key + const std::bitset newKey = Key::FromPassword(password).Get(); - // Check if this block is already in our map - if (keys.find(newKey) != keys.cend()) { - std::cout << "Collision found between password \"" - << password - << "\" and \"" - << keys[newKey] - << "\". The key is \"" - << newKey - << "\"."; + // Check if this block is already in our map + if (keys.find(newKey) != keys.cend()) { + std::cout << "Collision found between password \"" + << password + << "\" and \"" + << keys[newKey] + << "\". The key is \"" + << newKey + << "\"."; - FAIL(); - } + FAIL(); + } - // All good? Insert it into our map - keys[newKey] = password; - } + // All good? Insert it into our map + keys[newKey] = password; + } - return; + return; } From bedfc91e047f5bc6129e6a0af3cf783254325b8c Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 14:30:24 +0200 Subject: [PATCH 016/110] GHash now uses a full-size key for the cipher --- GCryptLib/src/GHash.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GCryptLib/src/GHash.cpp b/GCryptLib/src/GHash.cpp index 1fcb501..666580d 100644 --- a/GCryptLib/src/GHash.cpp +++ b/GCryptLib/src/GHash.cpp @@ -9,7 +9,7 @@ namespace Leonetienne::GCrypt { cipher( // Can't use Key::FromPassword here, because it depends on GHash. // Instead use a hardcoded key. - Key(StringToBitblock("CfRtNdMTP4Y5CWRd")), + Key(StringToBitblock("nsoCZfvdqpRkeVTt9wzvPR3TT26peOW9E2kTHh3pdPCq2M7BpskvUljJHSrobUTI")), GCipher::DIRECTION::ENCIPHER ) { block = InitializationVector(StringToBitblock("3J7IipfQTDJbO8jtasz9PgWui6faPaEMOuVuAqyhB1S2CRcLw5caawewgDUEG1WN")); From 04c67436c429f7bf1c09db44a72f15b1455665d6 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 16:54:40 +0200 Subject: [PATCH 017/110] Implemented GPrng pnrg --- GCryptLib/include/GCrypt/Feistel.h | 2 + GCryptLib/include/GCrypt/GCipher.h | 4 +- GCryptLib/include/GCrypt/GHash.h | 2 + GCryptLib/include/GCrypt/GPrng.h | 63 +++++++++++++++++++++++++ GCryptLib/src/Feistel.cpp | 6 +++ GCryptLib/src/GCipher.cpp | 9 ++++ GCryptLib/src/GHash.cpp | 5 ++ GCryptLib/src/GPrng.cpp | 75 ++++++++++++++++++++++++++++++ 8 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 GCryptLib/include/GCrypt/GPrng.h create mode 100644 GCryptLib/src/GPrng.cpp diff --git a/GCryptLib/include/GCrypt/Feistel.h b/GCryptLib/include/GCrypt/Feistel.h index 9063d0a..586d131 100644 --- a/GCryptLib/include/GCrypt/Feistel.h +++ b/GCryptLib/include/GCrypt/Feistel.h @@ -26,6 +26,8 @@ namespace Leonetienne::GCrypt { //! Will decipher a data block via the set seed-key Block Decipher(const Block& data); + void operator=(const Feistel& other); + private: //! Will run the feistel rounds, with either regular key //! order or reversed key order diff --git a/GCryptLib/include/GCrypt/GCipher.h b/GCryptLib/include/GCrypt/GCipher.h index 2764341..5228ecf 100644 --- a/GCryptLib/include/GCrypt/GCipher.h +++ b/GCryptLib/include/GCrypt/GCipher.h @@ -23,8 +23,10 @@ namespace Leonetienne::GCrypt { //! Will digest a data block, and return it Block Digest(const Block& input); + void operator=(const GCipher& other); + private: - const DIRECTION direction; + DIRECTION direction; //! The feistel instance to be used Feistel feistel; diff --git a/GCryptLib/include/GCrypt/GHash.h b/GCryptLib/include/GCrypt/GHash.h index bf5301f..f962529 100644 --- a/GCryptLib/include/GCrypt/GHash.h +++ b/GCryptLib/include/GCrypt/GHash.h @@ -24,6 +24,8 @@ namespace Leonetienne::GCrypt { //! Will calculate a hashsum for `data`. static Block CalculateHashsum(const Flexblock& data); + void operator=(const GHash& other); + private: //! The cipher to use GCipher cipher; diff --git a/GCryptLib/include/GCrypt/GPrng.h b/GCryptLib/include/GCrypt/GPrng.h new file mode 100644 index 0000000..99e9a6a --- /dev/null +++ b/GCryptLib/include/GCrypt/GPrng.h @@ -0,0 +1,63 @@ +#ifndef GCRYPT_GPRNG_H +#define GCRYPT_GPRNG_H + +#include "GCrypt/GHash.h" +#include "GCrypt/Util.h" +#include +#include +#include + +namespace Leonetienne::GCrypt { + /** This class implements a pseudo random number generator, based on the GCrypt hash function + */ + class GPrng { + public: + //! Will instanciate the prng with a seed. Seed could also be a GCrypt::Key. + GPrng(const Block& seed); + + //! Will instanciate the GPrng with no seed. You should really seed it later. + GPrng(); + + //! Will reset and seed the prng. Seed could also be a GCrypt::Key. + void Seed(const Block& seed); + + //! Will return a random bit. + bool GetBit(); + + //! Will return a randomized instance of any primitive. + template + T GetRandom() { + static_assert(std::is_fundamental::value, "Leonetienne::GCrypt::GPrng::GetRandom() may only be used with primitive types!"); + + // Pull the required amount of bits + std::stringstream ss; + for (std::size_t i = 0; i < sizeof(T)*8; i++) { + ss << GetBit() ? '1' : '0'; + } + + // Transform to bytes + const std::string bytes = BitsToBytes(ss.str()); + + // Cram bytes into type + T t; + memcpy(&t, bytes.data(), sizeof(T)); + + // Return our randomized primitive + return t; + } + + //! Will return a random block + Block GetBlock(); + + private: + //! Will generate the next block of random bits + void AdvanceBlock(); + + GHash hasher; + Block seed; + std::size_t nextBit = 0; + }; +} + +#endif + diff --git a/GCryptLib/src/Feistel.cpp b/GCryptLib/src/Feistel.cpp index dd14dc4..6301eb5 100644 --- a/GCryptLib/src/Feistel.cpp +++ b/GCryptLib/src/Feistel.cpp @@ -240,6 +240,12 @@ namespace Leonetienne::GCrypt { return; } + void Feistel::operator=(const Feistel& other) { + roundKeys = other.roundKeys; + + return; + } + // These pragmas only work for MSVC and g++, as far as i know. Beware!!! #if defined _WIN32 || defined _WIN64 #pragma optimize("", off ) diff --git a/GCryptLib/src/GCipher.cpp b/GCryptLib/src/GCipher.cpp index 10cebab..103011d 100644 --- a/GCryptLib/src/GCipher.cpp +++ b/GCryptLib/src/GCipher.cpp @@ -50,5 +50,14 @@ namespace Leonetienne::GCrypt { throw std::runtime_error("Unreachable branch reached."); } + + void GCipher::operator=(const GCipher& other) { + direction = other.direction; + feistel = other.feistel; + lastBlock = other.lastBlock; + + return; + } + } diff --git a/GCryptLib/src/GHash.cpp b/GCryptLib/src/GHash.cpp index 666580d..dec8f6c 100644 --- a/GCryptLib/src/GHash.cpp +++ b/GCryptLib/src/GHash.cpp @@ -55,5 +55,10 @@ namespace Leonetienne::GCrypt { return hasher.GetHashsum(); } + void GHash::operator=(const GHash& other) { + cipher = other.cipher; + + return; + } } diff --git a/GCryptLib/src/GPrng.cpp b/GCryptLib/src/GPrng.cpp new file mode 100644 index 0000000..371761d --- /dev/null +++ b/GCryptLib/src/GPrng.cpp @@ -0,0 +1,75 @@ +#include "GCrypt/GPrng.h" +#include + +namespace Leonetienne::GCrypt { + + GPrng::GPrng(const Block& seed) { + this->seed = seed; + hasher.DigestBlock(seed); + } + + GPrng::GPrng() { + } + + void GPrng::Seed(const Block& seed) { + hasher = GHash(); + this->seed = seed; + hasher.DigestBlock(seed); + + return; + } + + bool GPrng::GetBit() { + // If we have no more bits to go, create new ones + if (nextBit >= BLOCK_SIZE) { + AdvanceBlock(); + } + + // Return the next bit. + return hasher.GetHashsum()[nextBit++]; + } + + void GPrng::AdvanceBlock() { + // To prevent an attacker from being able + // to predict block n, by knowing block n-1, and block n-2, + // we will advance the hash function by block n-1 XOR seed. + // This way it is impossible for an attacker to know the + // state of the hash function, unless the seed is known. + + // Advance the block (Add the current hashsum XOR seed to the hasher) + hasher.DigestBlock(Block(hasher.GetHashsum() ^ seed)); + + // Reset the pointer + nextBit = 0; + + return; + } + + Block GPrng::GetBlock() { + // Getting a block is a bit troublesome. + // Just fetching 512 bits would be too much of a performance hog. + + // Slurp up the rest of the current block + std::stringstream ss; + const std::size_t bitsLeft = BLOCK_SIZE - nextBit; + ss << hasher.GetHashsum().to_string().substr(nextBit, bitsLeft); + + // Now we have to advance to the next block + AdvanceBlock(); + + // Now, grab the remaining bits + const std::size_t remainingBits = BLOCK_SIZE - bitsLeft; + ss << hasher.GetHashsum().to_string().substr(0, remainingBits); + + // Assert that we have the correct number of bits + assert(ss.str().length() == BLOCK_SIZE); + + // Set out bitpointer + nextBit = remainingBits; + + // Return our block + return Block(ss.str()); + } + +} + From a3c04b957f74c1bbf310a0abef44e19b4b11aae7 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 17:24:56 +0200 Subject: [PATCH 018/110] Implemented a Key::Random() method --- GCryptLib/include/GCrypt/Key.h | 5 +++++ GCryptLib/src/Key.cpp | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/GCryptLib/include/GCrypt/Key.h b/GCryptLib/include/GCrypt/Key.h index d63dd65..c7d505b 100644 --- a/GCryptLib/include/GCrypt/Key.h +++ b/GCryptLib/include/GCrypt/Key.h @@ -11,7 +11,12 @@ namespace Leonetienne::GCrypt { */ class Key : public Block { public: + //! Will generate a key from a password static Key FromPassword(const std::string& password); + + //! Will generate a random key from actual randomness (std::random_device) + static Key Random(); + Key(); Key(const Key& k); Key(const Block& b); diff --git a/GCryptLib/src/Key.cpp b/GCryptLib/src/Key.cpp index 2bffc67..f77623b 100644 --- a/GCryptLib/src/Key.cpp +++ b/GCryptLib/src/Key.cpp @@ -1,6 +1,8 @@ #include "GCrypt/Key.h" #include "GCrypt/GHash.h" #include "GCrypt/Util.h" +#include +#include namespace Leonetienne::GCrypt { @@ -10,6 +12,24 @@ namespace Leonetienne::GCrypt { ); } + Key Key::Random() { + // Create our truly-random rng + std::random_device rng; + constexpr std::size_t bitsPerCall = sizeof(std::random_device::result_type) * 8; + + // Fetch BLOCK_SIZE bits + std::stringstream ss; + for (std::size_t i = 0; i < BLOCK_SIZE / bitsPerCall; i++) { + ss << std::bitset(rng()); + } + + // Verify that we actually have the correct size + assert(ss.str().length() == BLOCK_SIZE); + + // Return them as a key + return Key(Block(ss.str())); + } + Key::Key() : Block() { } From cb6c50b684e55c461cac2dac85e69fadb96a5066 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 17:29:38 +0200 Subject: [PATCH 019/110] Now using actual include guards --- GCryptLib/include/GCrypt/Block.h | 6 +++++- GCryptLib/include/GCrypt/Config.h | 7 ++++++- GCryptLib/include/GCrypt/Feistel.h | 7 ++++++- GCryptLib/include/GCrypt/Flexblock.h | 7 ++++++- GCryptLib/include/GCrypt/GCipher.h | 7 ++++++- GCryptLib/include/GCrypt/Keyset.h | 6 +++++- GCryptLib/include/GCrypt/SecureBitset.h | 7 ++++++- GCryptLib/include/GCrypt/Version.h | 6 +++++- 8 files changed, 45 insertions(+), 8 deletions(-) diff --git a/GCryptLib/include/GCrypt/Block.h b/GCryptLib/include/GCrypt/Block.h index ae029d0..2ebbb39 100644 --- a/GCryptLib/include/GCrypt/Block.h +++ b/GCryptLib/include/GCrypt/Block.h @@ -1,4 +1,6 @@ -#pragma once +#ifndef GCRYPT_CONFIG_H +#define GCRYPT_CONFIG_H + #include "GCrypt/SecureBitset.h" #include "GCrypt/Config.h" @@ -6,3 +8,5 @@ namespace Leonetienne::GCrypt { typedef SecureBitset Block; } +#endif + diff --git a/GCryptLib/include/GCrypt/Config.h b/GCryptLib/include/GCrypt/Config.h index 0560a19..c5ec236 100644 --- a/GCryptLib/include/GCrypt/Config.h +++ b/GCryptLib/include/GCrypt/Config.h @@ -1,4 +1,6 @@ -#pragma once +#ifndef GCRYPT_CONFIG_H +#define GCRYPT_CONFIG_H + #include namespace Leonetienne::GCrypt { @@ -8,3 +10,6 @@ namespace Leonetienne::GCrypt { // MUST BE > 2 constexpr std::size_t N_ROUNDS = 64; } + +#endif + diff --git a/GCryptLib/include/GCrypt/Feistel.h b/GCryptLib/include/GCrypt/Feistel.h index 586d131..50bd4dd 100644 --- a/GCryptLib/include/GCrypt/Feistel.h +++ b/GCryptLib/include/GCrypt/Feistel.h @@ -1,4 +1,6 @@ -#pragma once +#ifndef GCRYPT_FEISTEL_H +#define GCRYPT_FEISTEL_H + #include "GCrypt/Keyset.h" #include "GCrypt/Block.h" #include "GCrypt/Key.h" @@ -60,3 +62,6 @@ namespace Leonetienne::GCrypt { Keyset roundKeys; }; } + +#endif + diff --git a/GCryptLib/include/GCrypt/Flexblock.h b/GCryptLib/include/GCrypt/Flexblock.h index 2873f74..80f9174 100644 --- a/GCryptLib/include/GCrypt/Flexblock.h +++ b/GCryptLib/include/GCrypt/Flexblock.h @@ -1,7 +1,12 @@ -#pragma once +#ifndef GCRYPT_FLEXBLOCK_H +#define GCRYPT_FLEXBLOCK_H + #include namespace Leonetienne::GCrypt { //! A "bitset" of variable length typedef std::string Flexblock; } + +#endif + diff --git a/GCryptLib/include/GCrypt/GCipher.h b/GCryptLib/include/GCrypt/GCipher.h index 5228ecf..f17a277 100644 --- a/GCryptLib/include/GCrypt/GCipher.h +++ b/GCryptLib/include/GCrypt/GCipher.h @@ -1,4 +1,6 @@ -#pragma once +#ifndef GCRYPT_GCIPHER_H +#define GCRYPT_GCIPHER_H + #include "GCrypt/Feistel.h" #include "GCrypt/Flexblock.h" @@ -35,3 +37,6 @@ namespace Leonetienne::GCrypt { Block lastBlock; }; } + +#endif + diff --git a/GCryptLib/include/GCrypt/Keyset.h b/GCryptLib/include/GCrypt/Keyset.h index ab331f6..9871d23 100644 --- a/GCryptLib/include/GCrypt/Keyset.h +++ b/GCryptLib/include/GCrypt/Keyset.h @@ -1,4 +1,6 @@ -#pragma once +#ifndef GCRYPT_KEYSET_H +#define GCRYPT_KEYSET_H + #include #include "GCrypt/Key.h" #include "GCrypt/Config.h" @@ -7,3 +9,5 @@ namespace Leonetienne::GCrypt { typedef std::array Keyset; } +#endif + diff --git a/GCryptLib/include/GCrypt/SecureBitset.h b/GCryptLib/include/GCrypt/SecureBitset.h index b4b1a9d..e288b13 100644 --- a/GCryptLib/include/GCrypt/SecureBitset.h +++ b/GCryptLib/include/GCrypt/SecureBitset.h @@ -1,4 +1,6 @@ -#pragma once +#ifndef GCRYPT_SECUREBITSET_H +#define GCRYPT_SECUREBITSET_H + #include #include #include @@ -285,3 +287,6 @@ namespace Leonetienne::GCrypt { return ifs >> bs.Get(); } } + +#endif + diff --git a/GCryptLib/include/GCrypt/Version.h b/GCryptLib/include/GCrypt/Version.h index a536c89..801185e 100644 --- a/GCryptLib/include/GCrypt/Version.h +++ b/GCryptLib/include/GCrypt/Version.h @@ -1,3 +1,7 @@ -#pragma once +#ifndef GCRYPT_VERSION_H +#define GCRYPT_VERSION_H + #define GHETTOCRYPT_VERSION 0.22 +#endif + From 91819c97233826c88462278e3cf93a880b70d681 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 17:30:15 +0200 Subject: [PATCH 020/110] Bump gcryptlib version --- GCryptLib/include/GCrypt/Version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GCryptLib/include/GCrypt/Version.h b/GCryptLib/include/GCrypt/Version.h index 801185e..ff66ec4 100644 --- a/GCryptLib/include/GCrypt/Version.h +++ b/GCryptLib/include/GCrypt/Version.h @@ -1,7 +1,7 @@ #ifndef GCRYPT_VERSION_H #define GCRYPT_VERSION_H -#define GHETTOCRYPT_VERSION 0.22 +#define GCRYPT_VERSION 0.23 #endif From cd119f21bb4ce6f64f144ccb707f20cd3e61539c Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 17:32:54 +0200 Subject: [PATCH 021/110] Indentation --- GCryptLib/include/GCrypt/Util.h | 100 +++++----- GCryptLib/src/Feistel.cpp | 328 ++++++++++++++++---------------- GCryptLib/src/GCipher.cpp | 6 +- 3 files changed, 217 insertions(+), 217 deletions(-) diff --git a/GCryptLib/include/GCrypt/Util.h b/GCryptLib/include/GCrypt/Util.h index 34f3e28..bd60300 100644 --- a/GCryptLib/include/GCrypt/Util.h +++ b/GCryptLib/include/GCrypt/Util.h @@ -13,79 +13,79 @@ #include "GCrypt/InitializationVector.h" namespace Leonetienne::GCrypt { - //! Mod-operator that works with negative values - inline int Mod(const int numerator, const int denominator) { - return (denominator + (numerator % denominator)) % denominator; - } + //! Mod-operator that works with negative values + inline int Mod(const int numerator, const int denominator) { + return (denominator + (numerator % denominator)) % denominator; + } - //! Will perform a wrapping left-bitshift on a bitset - template + //! Will perform a wrapping left-bitshift on a bitset + template inline SecureBitset Shiftl(const SecureBitset& bits, const std::size_t amount) { - std::stringstream ss; - const std::string bitss = bits.to_string(); + std::stringstream ss; + const std::string bitss = bits.to_string(); - for (std::size_t i = 0; i < bitss.size(); i++) { - ss << bitss[Mod((int)(i + amount), (int)bitss.size())]; - } + for (std::size_t i = 0; i < bitss.size(); i++) { + ss << bitss[Mod((int)(i + amount), (int)bitss.size())]; + } - return SecureBitset(ss.str()); + return SecureBitset(ss.str()); } - //! Will perform a wrapping right-bitshift on a bitset - template + //! Will perform a wrapping right-bitshift on a bitset + template inline SecureBitset Shiftr(const SecureBitset& bits, const std::size_t amount) { - std::stringstream ss; - const std::string bitss = bits.to_string(); + std::stringstream ss; + const std::string bitss = bits.to_string(); - for (std::size_t i = 0; i < bitss.size(); i++) { - ss << bitss[Mod((i - amount), bitss.size())]; - } + for (std::size_t i = 0; i < bitss.size(); i++) { + ss << bitss[Mod((i - amount), bitss.size())]; + } - return SecureBitset(ss.str()); + return SecureBitset(ss.str()); } - //! Will pad a string to a set length with a certain character - std::string PadStringToLength(const std::string& str, const std::size_t len, const char pad, const bool padLeft = true); + //! Will pad a string to a set length with a certain character + std::string PadStringToLength(const std::string& str, const std::size_t len, const char pad, const bool padLeft = true); - //! Will convert a string to a fixed-size data block - //! @s: The string to pad - //! padLeft: should padding be added to the left? If not, to the right. - Block StringToBitblock(const std::string& s, bool padLeft = true); + //! Will convert a string to a fixed-size data block + //! @s: The string to pad + //! padLeft: should padding be added to the left? If not, to the right. + Block StringToBitblock(const std::string& s, bool padLeft = true); - //! Will convert a string to a flexible data block - Flexblock StringToBits(const std::string& s); + //! Will convert a string to a flexible data block + Flexblock StringToBits(const std::string& s); - //! Will convert a fixed-size data block to a bytestring - std::string BitblockToBytes(const Block& bits); + //! Will convert a fixed-size data block to a bytestring + std::string BitblockToBytes(const Block& bits); - //! Will convert a fixed-size data block to a string - //! The difference to BitblockToBytes() is, that it strips excess nullbytes - std::string BitblockToString(const Block& bits); + //! Will convert a fixed-size data block to a string + //! The difference to BitblockToBytes() is, that it strips excess nullbytes + std::string BitblockToString(const Block& bits); - //! Will convert a flexible data block to a bytestring - std::string BitsToBytes(const Flexblock& bits); + //! Will convert a flexible data block to a bytestring + std::string BitsToBytes(const Flexblock& bits); - //! Will convert a flexible data block to a string - //! The difference to BitsToBytes() is, that it strips excess nullbytes - std::string BitsToString(const Flexblock& bits); + //! Will convert a flexible data block to a string + //! The difference to BitsToBytes() is, that it strips excess nullbytes + std::string BitsToString(const Flexblock& bits); - //! Turns a fixed-size data block into a hex-string - std::string BitblockToHexstring(const Block& b); + //! Turns a fixed-size data block into a hex-string + std::string BitblockToHexstring(const Block& b); - //! Turns a flexible data block into a hex-string - std::string BitsToHexstring(const Flexblock& b); + //! Turns a flexible data block into a hex-string + std::string BitsToHexstring(const Flexblock& b); - //! Turns a hex string into a fixed-size data block - Block HexstringToBitblock(const std::string& hexstring); + //! Turns a hex string into a fixed-size data block + Block HexstringToBitblock(const std::string& hexstring); - //! Turns a hex string into a flexible data block - Flexblock HexstringToBits(const std::string& hexstring); + //! Turns a hex string into a flexible data block + Flexblock HexstringToBits(const std::string& hexstring); - //! Will read a file into a flexblock - Flexblock ReadFileToBits(const std::string& filepath); + //! Will read a file into a flexblock + Flexblock ReadFileToBits(const std::string& filepath); - //! Will save bits to a binary file - void WriteBitsToFile(const std::string& filepath, const Flexblock& bits); + //! Will save bits to a binary file + void WriteBitsToFile(const std::string& filepath, const Flexblock& bits); } #endif diff --git a/GCryptLib/src/Feistel.cpp b/GCryptLib/src/Feistel.cpp index 6301eb5..ce69306 100644 --- a/GCryptLib/src/Feistel.cpp +++ b/GCryptLib/src/Feistel.cpp @@ -6,238 +6,238 @@ namespace Leonetienne::GCrypt { Feistel::Feistel(const Key& key) { - SetKey(key); - return; + SetKey(key); + return; } Feistel::~Feistel() { - ZeroKeyMemory(); + ZeroKeyMemory(); - return; + return; } void Feistel::SetKey(const Key& key) { - GenerateRoundKeys(key); - return; + GenerateRoundKeys(key); + return; } Block Feistel::Encipher(const Block& data) { - return Run(data, false); + return Run(data, false); } Block Feistel::Decipher(const Block& data) { - return Run(data, true); + return Run(data, true); } Block Feistel::Run(const Block& data, bool reverseKeys) { - const auto splitData = FeistelSplit(data); - Halfblock l = splitData.first; - Halfblock r = splitData.second; + const auto splitData = FeistelSplit(data); + Halfblock l = splitData.first; + Halfblock r = splitData.second; - Halfblock tmp; + Halfblock tmp; - for (std::size_t i = 0; i < N_ROUNDS; i++) { - // Calculate key index - std::size_t keyIndex; - if (reverseKeys) { - keyIndex = N_ROUNDS - i - 1; - } - else { - keyIndex = i; - } - - // Do a feistel round - tmp = r; - r = l ^ F(r, roundKeys[keyIndex]); - l = tmp; + for (std::size_t i = 0; i < N_ROUNDS; i++) { + // Calculate key index + std::size_t keyIndex; + if (reverseKeys) { + keyIndex = N_ROUNDS - i - 1; + } + else { + keyIndex = i; } - // Block has finished de*ciphering. - // Let's generate a new set of round keys. - GenerateRoundKeys((Block)roundKeys.back()); + // Do a feistel round + tmp = r; + r = l ^ F(r, roundKeys[keyIndex]); + l = tmp; + } - return FeistelCombine(r, l); + // Block has finished de*ciphering. + // Let's generate a new set of round keys. + GenerateRoundKeys((Block)roundKeys.back()); + + return FeistelCombine(r, l); } Halfblock Feistel::F(Halfblock m, const Key& key) { - // Made-up F function + // Made-up F function - // Expand to full bitwidth - Block m_expanded = ExpansionFunction(m); + // Expand to full bitwidth + Block m_expanded = ExpansionFunction(m); - // Shift to left by 1 - m_expanded = Shiftl(m_expanded, 1); + // Shift to left by 1 + m_expanded = Shiftl(m_expanded, 1); - // Xor with key - m_expanded ^= key; + // Xor with key + m_expanded ^= key; - // Non-linearly apply subsitution boxes - std::stringstream ss; - const std::string m_str = m_expanded.to_string(); + // Non-linearly apply subsitution boxes + std::stringstream ss; + const std::string m_str = m_expanded.to_string(); - for (std::size_t i = 0; i < BLOCK_SIZE; i += 4) { - ss << SBox(m_str.substr(i, 4)); - } + for (std::size_t i = 0; i < BLOCK_SIZE; i += 4) { + ss << SBox(m_str.substr(i, 4)); + } - m_expanded = Block(ss.str()); + m_expanded = Block(ss.str()); - // Return the compressed version - return CompressionFunction(m_expanded); + // Return the compressed version + return CompressionFunction(m_expanded); } std::pair Feistel::FeistelSplit(const Block& block) { - const std::string bits = block.to_string(); + const std::string bits = block.to_string(); - Halfblock l(bits.substr(0, bits.size() / 2)); - Halfblock r(bits.substr(bits.size() / 2)); + Halfblock l(bits.substr(0, bits.size() / 2)); + Halfblock r(bits.substr(bits.size() / 2)); - return std::make_pair(l, r); + return std::make_pair(l, r); } Block Feistel::FeistelCombine(const Halfblock& l, const Halfblock& r) { - return Block(l.to_string() + r.to_string()); + return Block(l.to_string() + r.to_string()); } Block Feistel::ExpansionFunction(const Halfblock& block) { - std::stringstream ss; - const std::string bits = block.to_string(); + std::stringstream ss; + const std::string bits = block.to_string(); - std::unordered_map expansionMap; - expansionMap["00"] = "1101"; - expansionMap["01"] = "1000"; - expansionMap["10"] = "0010"; - expansionMap["11"] = "0111"; + std::unordered_map expansionMap; + expansionMap["00"] = "1101"; + expansionMap["01"] = "1000"; + expansionMap["10"] = "0010"; + expansionMap["11"] = "0111"; - // We have to double the bits! - for (std::size_t i = 0; i < HALFBLOCK_SIZE; i += 2) { - const std::string sub = bits.substr(i, 2); - ss << expansionMap[sub]; - } + // We have to double the bits! + for (std::size_t i = 0; i < HALFBLOCK_SIZE; i += 2) { + const std::string sub = bits.substr(i, 2); + ss << expansionMap[sub]; + } - return Block(ss.str()); + return Block(ss.str()); } Halfblock Feistel::CompressionFunction(const Block& block) { - std::stringstream ss; - const std::string bits = block.to_string(); + std::stringstream ss; + const std::string bits = block.to_string(); - std::unordered_map compressionMap; - compressionMap["0000"] = "10"; - compressionMap["0001"] = "01"; - compressionMap["0010"] = "10"; - compressionMap["0011"] = "10"; - compressionMap["0100"] = "11"; - compressionMap["0101"] = "01"; - compressionMap["0110"] = "00"; - compressionMap["0111"] = "11"; - compressionMap["1000"] = "01"; - compressionMap["1001"] = "00"; - compressionMap["1010"] = "11"; - compressionMap["1011"] = "00"; - compressionMap["1100"] = "11"; - compressionMap["1101"] = "10"; - compressionMap["1110"] = "00"; - compressionMap["1111"] = "01"; + std::unordered_map compressionMap; + compressionMap["0000"] = "10"; + compressionMap["0001"] = "01"; + compressionMap["0010"] = "10"; + compressionMap["0011"] = "10"; + compressionMap["0100"] = "11"; + compressionMap["0101"] = "01"; + compressionMap["0110"] = "00"; + compressionMap["0111"] = "11"; + compressionMap["1000"] = "01"; + compressionMap["1001"] = "00"; + compressionMap["1010"] = "11"; + compressionMap["1011"] = "00"; + compressionMap["1100"] = "11"; + compressionMap["1101"] = "10"; + compressionMap["1110"] = "00"; + compressionMap["1111"] = "01"; - // We have to half the bits! - for (std::size_t i = 0; i < BLOCK_SIZE; i += 4) { - const std::string sub = bits.substr(i, 4); - ss << compressionMap[sub]; - } + // We have to half the bits! + for (std::size_t i = 0; i < BLOCK_SIZE; i += 4) { + const std::string sub = bits.substr(i, 4); + ss << compressionMap[sub]; + } - return Halfblock(ss.str()); + return Halfblock(ss.str()); } std::string Feistel::SBox(const std::string& in) { - static std::unordered_map subMap; - static bool mapInitialized = false; - if (!mapInitialized) { - subMap["0000"] = "1100"; - subMap["0001"] = "1000"; - subMap["0010"] = "0001"; - subMap["0011"] = "0111"; - subMap["0100"] = "1011"; - subMap["0101"] = "0011"; - subMap["0110"] = "1101"; - subMap["0111"] = "1111"; - subMap["1000"] = "0000"; - subMap["1001"] = "1010"; - subMap["1010"] = "0100"; - subMap["1011"] = "1001"; - subMap["1100"] = "0010"; - subMap["1101"] = "1110"; - subMap["1110"] = "0101"; - subMap["1111"] = "0110"; - mapInitialized = true; - } + static std::unordered_map subMap; + static bool mapInitialized = false; + if (!mapInitialized) { + subMap["0000"] = "1100"; + subMap["0001"] = "1000"; + subMap["0010"] = "0001"; + subMap["0011"] = "0111"; + subMap["0100"] = "1011"; + subMap["0101"] = "0011"; + subMap["0110"] = "1101"; + subMap["0111"] = "1111"; + subMap["1000"] = "0000"; + subMap["1001"] = "1010"; + subMap["1010"] = "0100"; + subMap["1011"] = "1001"; + subMap["1100"] = "0010"; + subMap["1101"] = "1110"; + subMap["1110"] = "0101"; + subMap["1111"] = "0110"; + mapInitialized = true; + } - return subMap[in]; + return subMap[in]; } void Feistel::GenerateRoundKeys(const Key& seedKey) { - // Clear initial key memory - ZeroKeyMemory(); - roundKeys = Keyset(); + // Clear initial key memory + ZeroKeyMemory(); + roundKeys = Keyset(); - // Derive the initial two round keys + // Derive the initial two round keys - // Compress- substitute, and expand the seed key to form the initial and the second-initial round key - // This action is non-linear and irreversible, and thus strenghtens security. - Halfblock compressedSeed1 = CompressionFunction(seedKey); - Halfblock compressedSeed2 = CompressionFunction(Shiftl(seedKey, 1)); // Shifting one key by 1 will result in a completely different compression + // Compress- substitute, and expand the seed key to form the initial and the second-initial round key + // This action is non-linear and irreversible, and thus strenghtens security. + Halfblock compressedSeed1 = CompressionFunction(seedKey); + Halfblock compressedSeed2 = CompressionFunction(Shiftl(seedKey, 1)); // Shifting one key by 1 will result in a completely different compression - // To add further confusion, let's shift seed1 by 1 aswell (after compression, but before substitution) - // but only if the total number of bits set are a multiple of 3 - // if it is a multiple of 4, we'll shift it by 1 into the opposite direction - const std::size_t setBits1 = compressedSeed1.count(); + // To add further confusion, let's shift seed1 by 1 aswell (after compression, but before substitution) + // but only if the total number of bits set are a multiple of 3 + // if it is a multiple of 4, we'll shift it by 1 into the opposite direction + const std::size_t setBits1 = compressedSeed1.count(); - if (setBits1 % 4 == 0) { - compressedSeed1 = Shiftr(compressedSeed1, 1); - } - else if (setBits1 % 3 == 0) { - compressedSeed1 = Shiftl(compressedSeed1, 1); - } + if (setBits1 % 4 == 0) { + compressedSeed1 = Shiftr(compressedSeed1, 1); + } + else if (setBits1 % 3 == 0) { + compressedSeed1 = Shiftl(compressedSeed1, 1); + } - // Now apply substitution - std::stringstream ssKey1; - std::stringstream ssKey2; - const std::string bitsKey1 = compressedSeed1.to_string(); - const std::string bitsKey2 = compressedSeed2.to_string(); + // Now apply substitution + std::stringstream ssKey1; + std::stringstream ssKey2; + const std::string bitsKey1 = compressedSeed1.to_string(); + const std::string bitsKey2 = compressedSeed2.to_string(); - for (std::size_t i = 0; i < HALFBLOCK_SIZE; i += 4) { - ssKey1 << SBox(bitsKey1.substr(i, 4)); - ssKey2 << SBox(bitsKey2.substr(i, 4)); - } + for (std::size_t i = 0; i < HALFBLOCK_SIZE; i += 4) { + ssKey1 << SBox(bitsKey1.substr(i, 4)); + ssKey2 << SBox(bitsKey2.substr(i, 4)); + } - compressedSeed1 = Halfblock(ssKey1.str()); - compressedSeed2 = Halfblock(ssKey2.str()); + compressedSeed1 = Halfblock(ssKey1.str()); + compressedSeed2 = Halfblock(ssKey2.str()); - // Now extrapolate them to BLOCK_SIZE (key size) again - // Xor with the original seed key to get rid of the repititions caused by the expansion - roundKeys[0] = ExpansionFunction(compressedSeed1) ^ seedKey; - roundKeys[1] = ExpansionFunction(compressedSeed2) ^ seedKey; + // Now extrapolate them to BLOCK_SIZE (key size) again + // Xor with the original seed key to get rid of the repititions caused by the expansion + roundKeys[0] = ExpansionFunction(compressedSeed1) ^ seedKey; + roundKeys[1] = ExpansionFunction(compressedSeed2) ^ seedKey; - // Now derive all other round keys + // Now derive all other round keys - for (std::size_t i = 2; i < roundKeys.size(); i++) { - // Initialize new round key with last round key - Block newKey = roundKeys[i - 1]; + for (std::size_t i = 2; i < roundKeys.size(); i++) { + // Initialize new round key with last round key + Block newKey = roundKeys[i - 1]; - // Shift to left by how many bits are set, modulo 8 - newKey = Shiftl(newKey, newKey.count() % 8); // This action is irreversible + // Shift to left by how many bits are set, modulo 8 + newKey = Shiftl(newKey, newKey.count() % 8); // This action is irreversible - // Split into two halfblocks, - // apply F() to one halfblock with rk[i-2], - // xor the other one with it - // and put them back together - auto halfkeys = FeistelSplit(newKey); - Halfblock halfkey1 = F(halfkeys.first, roundKeys[i - 2]); - Halfblock halfkey2 = halfkeys.second ^ halfkey1; // I know this is reversible, but it helps to diffuse future round keys. + // Split into two halfblocks, + // apply F() to one halfblock with rk[i-2], + // xor the other one with it + // and put them back together + auto halfkeys = FeistelSplit(newKey); + Halfblock halfkey1 = F(halfkeys.first, roundKeys[i - 2]); + Halfblock halfkey2 = halfkeys.second ^ halfkey1; // I know this is reversible, but it helps to diffuse future round keys. - roundKeys[i] = Key(FeistelCombine(halfkey1, halfkey2)); - } + roundKeys[i] = Key(FeistelCombine(halfkey1, halfkey2)); + } - return; + return; } void Feistel::operator=(const Feistel& other) { @@ -254,11 +254,11 @@ namespace Leonetienne::GCrypt { #pragma GCC optimize ("O0") #endif void Feistel::ZeroKeyMemory() { - for (Key& key : roundKeys) { - key.reset(); - } + for (Key& key : roundKeys) { + key.reset(); + } - return; + return; } #if defined _WIN32 || defined _WIN64 #pragma optimize("", on ) diff --git a/GCryptLib/src/GCipher.cpp b/GCryptLib/src/GCipher.cpp index 103011d..785d851 100644 --- a/GCryptLib/src/GCipher.cpp +++ b/GCryptLib/src/GCipher.cpp @@ -7,11 +7,11 @@ namespace Leonetienne::GCrypt { - GCipher::GCipher(const Key& key, const DIRECTION direction) - : + GCipher::GCipher(const Key& key, const DIRECTION direction) : direction { direction }, lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key - feistel(key) { + feistel(key) + { return; } From 88cb36fd7b8e5775ac140f74a7066f94b7a951ef Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 17:54:04 +0200 Subject: [PATCH 022/110] Fix include guard --- GCryptLib/include/GCrypt/Block.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GCryptLib/include/GCrypt/Block.h b/GCryptLib/include/GCrypt/Block.h index 2ebbb39..db9552f 100644 --- a/GCryptLib/include/GCrypt/Block.h +++ b/GCryptLib/include/GCrypt/Block.h @@ -1,5 +1,5 @@ -#ifndef GCRYPT_CONFIG_H -#define GCRYPT_CONFIG_H +#ifndef GCRYPT_BLOCK_H +#define GCRYPT_BLOCK_H #include "GCrypt/SecureBitset.h" #include "GCrypt/Config.h" From 19660fc696badc12d8b6c8e65d3de59dddd48c53 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 17:54:26 +0200 Subject: [PATCH 023/110] Add method to load and save keyfiles --- GCryptLib/include/GCrypt/Key.h | 6 ++++ GCryptLib/src/Key.cpp | 51 ++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/GCryptLib/include/GCrypt/Key.h b/GCryptLib/include/GCrypt/Key.h index c7d505b..d0133da 100644 --- a/GCryptLib/include/GCrypt/Key.h +++ b/GCryptLib/include/GCrypt/Key.h @@ -17,6 +17,12 @@ namespace Leonetienne::GCrypt { //! Will generate a random key from actual randomness (std::random_device) static Key Random(); + //! Loads a keyfile + static Key LoadFromFile(const std::string& path); + + //! Will save a keyfile + void WriteToFile(const std::string& path); + Key(); Key(const Key& k); Key(const Block& b); diff --git a/GCryptLib/src/Key.cpp b/GCryptLib/src/Key.cpp index f77623b..c353d9d 100644 --- a/GCryptLib/src/Key.cpp +++ b/GCryptLib/src/Key.cpp @@ -3,6 +3,8 @@ #include "GCrypt/Util.h" #include #include +#include +#include namespace Leonetienne::GCrypt { @@ -30,6 +32,55 @@ namespace Leonetienne::GCrypt { return Key(Block(ss.str())); } + Key Key::LoadFromFile(const std::string& path) { + // Read this many chars + const std::size_t maxChars = BLOCK_SIZE / 8; + + // Open ifilestream for keyfile + std::ifstream ifs(path, std::ios::in | std::ios::binary); + + // Is the file open now? Or were there any issues... + if (!ifs.good()) { + throw std::runtime_error(std::string("Unable to open ifilestream for keyfile \"") + path + "\"! Aborting..."); + } + + // Read these chars to buffer + char* ckeyfileContent = new char[maxChars]; + memset(ckeyfileContent, 0, maxChars * sizeof(char)); + ifs.read(ckeyfileContent, maxChars); + ifs.close(); + + // Convert the buffer to a bit block of key size + std::stringstream ss; + for (std::size_t i = 0; i < maxChars; i++) + ss << std::bitset<8>(ckeyfileContent[i]); + + Block key(ss.str()); + + // And delete the buffer + delete[] ckeyfileContent; + ckeyfileContent = nullptr; + + // Return it + return key; + } + + void Key::WriteToFile(const std::string& path) { + // Transform key to bytes + const std::string keybytes = BitsToBytes(to_string()); + + // Create an ofilestream + std::ofstream ofs(path, std::ios::out | std::ios::binary); + + // Write the key + ofs.write(keybytes.data(), BLOCK_SIZE/8); + + // Close the file handle + ofs.close(); + + return; + } + Key::Key() : Block() { } From 5677d94e6aa22c657f8440d6dc4beb38f28509e8 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 20:13:41 +0200 Subject: [PATCH 024/110] Improved security --- GCryptLib/include/GCrypt/Config.h | 2 +- GCryptLib/include/GCrypt/GCipher.h | 3 +++ GCryptLib/src/Feistel.cpp | 15 +++++++-------- GCryptLib/src/GCipher.cpp | 6 ++++++ GCryptLib/src/GHash.cpp | 7 +++++-- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/GCryptLib/include/GCrypt/Config.h b/GCryptLib/include/GCrypt/Config.h index c5ec236..dd56656 100644 --- a/GCryptLib/include/GCrypt/Config.h +++ b/GCryptLib/include/GCrypt/Config.h @@ -8,7 +8,7 @@ namespace Leonetienne::GCrypt { constexpr std::size_t BLOCK_SIZE = 512; // MUST BE > 2 - constexpr std::size_t N_ROUNDS = 64; + constexpr std::size_t N_ROUNDS = 400; } #endif diff --git a/GCryptLib/include/GCrypt/GCipher.h b/GCryptLib/include/GCrypt/GCipher.h index f17a277..6050233 100644 --- a/GCryptLib/include/GCrypt/GCipher.h +++ b/GCryptLib/include/GCrypt/GCipher.h @@ -25,6 +25,9 @@ namespace Leonetienne::GCrypt { //! Will digest a data block, and return it Block Digest(const Block& input); + //! Will update the base key used + void SetKey(const Key& key); + void operator=(const GCipher& other); private: diff --git a/GCryptLib/src/Feistel.cpp b/GCryptLib/src/Feistel.cpp index ce69306..9ac75da 100644 --- a/GCryptLib/src/Feistel.cpp +++ b/GCryptLib/src/Feistel.cpp @@ -54,12 +54,13 @@ namespace Leonetienne::GCrypt { // Block has finished de*ciphering. // Let's generate a new set of round keys. - GenerateRoundKeys((Block)roundKeys.back()); + GenerateRoundKeys((Key)roundKeys.back()); return FeistelCombine(r, l); } Halfblock Feistel::F(Halfblock m, const Key& key) { + // Made-up F function // Expand to full bitwidth @@ -74,15 +75,13 @@ namespace Leonetienne::GCrypt { // Non-linearly apply subsitution boxes std::stringstream ss; const std::string m_str = m_expanded.to_string(); - for (std::size_t i = 0; i < BLOCK_SIZE; i += 4) { ss << SBox(m_str.substr(i, 4)); } - m_expanded = Block(ss.str()); - // Return the compressed version - return CompressionFunction(m_expanded); + // Return the compressed version, shifted by 3 + return Shiftl(CompressionFunction(m_expanded), 3); } std::pair Feistel::FeistelSplit(const Block& block) { @@ -124,13 +123,13 @@ namespace Leonetienne::GCrypt { std::unordered_map compressionMap; compressionMap["0000"] = "10"; compressionMap["0001"] = "01"; - compressionMap["0010"] = "10"; + compressionMap["0010"] = "11"; compressionMap["0011"] = "10"; compressionMap["0100"] = "11"; compressionMap["0101"] = "01"; compressionMap["0110"] = "00"; - compressionMap["0111"] = "11"; - compressionMap["1000"] = "01"; + compressionMap["0111"] = "01"; + compressionMap["1000"] = "11"; compressionMap["1001"] = "00"; compressionMap["1010"] = "11"; compressionMap["1011"] = "00"; diff --git a/GCryptLib/src/GCipher.cpp b/GCryptLib/src/GCipher.cpp index 785d851..3a2883f 100644 --- a/GCryptLib/src/GCipher.cpp +++ b/GCryptLib/src/GCipher.cpp @@ -51,6 +51,12 @@ namespace Leonetienne::GCrypt { throw std::runtime_error("Unreachable branch reached."); } + void GCipher::SetKey(const Key& key) { + feistel.SetKey(key); + + return; + } + void GCipher::operator=(const GCipher& other) { direction = other.direction; feistel = other.feistel; diff --git a/GCryptLib/src/GHash.cpp b/GCryptLib/src/GHash.cpp index dec8f6c..5ea48fa 100644 --- a/GCryptLib/src/GHash.cpp +++ b/GCryptLib/src/GHash.cpp @@ -7,8 +7,8 @@ namespace Leonetienne::GCrypt { GHash::GHash() : // Initialize our cipher with a static, but randomly distributed key. cipher( - // Can't use Key::FromPassword here, because it depends on GHash. - // Instead use a hardcoded key. + // The key really does not matter, as it gets changed + // each time before digesting anything. Key(StringToBitblock("nsoCZfvdqpRkeVTt9wzvPR3TT26peOW9E2kTHh3pdPCq2M7BpskvUljJHSrobUTI")), GCipher::DIRECTION::ENCIPHER ) { @@ -18,6 +18,9 @@ namespace Leonetienne::GCrypt { } void GHash::DigestBlock(const Block& data) { + // Set the cipher key to the current data to be hashed + cipher.SetKey(Key(data)); + // Encipher the current block, and xor it on the current hashsum block ^= cipher.Digest(data); return; From 1e479986fc8063c520cefc0ebd3a97ce70a965e6 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 20:16:26 +0200 Subject: [PATCH 025/110] Readme and visualizations --- .../visualizations/input-big-flip.bmp.png | Bin 0 -> 938 bytes GCryptLib/visualizations/input-big.bmp.png | Bin 0 -> 938 bytes GCryptLib/visualizations/input-big.gif | Bin 0 -> 6334 bytes GCryptLib/visualizations/input-flip.bmp.png | Bin 0 -> 355 bytes GCryptLib/visualizations/input.bmp.png | Bin 0 -> 358 bytes GCryptLib/visualizations/input.gif | Bin 0 -> 1107 bytes .../visualizations/output-big-flip.bmp.png | Bin 0 -> 1087 bytes GCryptLib/visualizations/output-big.bmp.png | Bin 0 -> 1089 bytes GCryptLib/visualizations/output-big.gif | Bin 0 -> 7873 bytes GCryptLib/visualizations/output-flip.bmp.png | Bin 0 -> 442 bytes GCryptLib/visualizations/output.bmp.png | Bin 0 -> 443 bytes GCryptLib/visualizations/output.gif | Bin 0 -> 3729 bytes readme.md | 108 ++++++++++++++---- 13 files changed, 87 insertions(+), 21 deletions(-) create mode 100644 GCryptLib/visualizations/input-big-flip.bmp.png create mode 100644 GCryptLib/visualizations/input-big.bmp.png create mode 100644 GCryptLib/visualizations/input-big.gif create mode 100644 GCryptLib/visualizations/input-flip.bmp.png create mode 100644 GCryptLib/visualizations/input.bmp.png create mode 100644 GCryptLib/visualizations/input.gif create mode 100644 GCryptLib/visualizations/output-big-flip.bmp.png create mode 100644 GCryptLib/visualizations/output-big.bmp.png create mode 100644 GCryptLib/visualizations/output-big.gif create mode 100644 GCryptLib/visualizations/output-flip.bmp.png create mode 100644 GCryptLib/visualizations/output.bmp.png create mode 100644 GCryptLib/visualizations/output.gif diff --git a/GCryptLib/visualizations/input-big-flip.bmp.png b/GCryptLib/visualizations/input-big-flip.bmp.png new file mode 100644 index 0000000000000000000000000000000000000000..18127a336ddfea9052ec4fb6592c8163785391f4 GIT binary patch literal 938 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K59)QUsR;_=59F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&V7%KUyadSO zEbxddW?lFzi8y?AW^~?b10I*1 z%1YvE_rYfg`DeG*a7IQL=V3w~`jhKYi&r2^*$+N6~n{l1I8;`qN^ zY7C#;LSMgk+MaXFFUFF=jyLkVk zD!vqSPzdopG|j)H;8SScf7h!l4-|iWI5(-Nto@+X-dXH_E-Kl1uCZEUxAO0VDkg`X zHSTwJo(rhE`%v4Rm%%IKtU}7t46hZp+yYj)Gq@ko(22<})V*=VmQh16B5l{Qn~tj! ze7kQmJP`b~;brF10})sE8Cb^I?Bl685Oik8y^^IfYqm({_%fW@YWJzJC*!ne+d4x= zfy9e%%f2tRn(m=``8mgex&E;kPd^4-2L32Z4)D=H(zJ;zra5Ahp5Tn z>Z^%cLu}O<&!M>Z5XLioy)B73?z@ zIyQ({GO>$JOB0qj`2iSKnHRm>R5+I3iwM1(dm#6K@Rx<>92V3CX#QR5yoc|H!(%~* z{6`aFCrb(%D@QRM|5WQBuqE%Pcka)bvs%0FF*303`}BO7!Dg2y#<8h940FzSE`4|8 z+YLVRnHJv}J7adTe^_H6xmfVrrK^kwn7=4~n!WyA>p#_x3=jUVkz@QK$@pN}mx${7 zKhM@O2ko6xwu^gD})w24B??V%Y5D8_5S6XZ@ zHcdX(&gnSmd=}FO*7tGOr9IiU0rr literal 0 HcmV?d00001 diff --git a/GCryptLib/visualizations/input-big.bmp.png b/GCryptLib/visualizations/input-big.bmp.png new file mode 100644 index 0000000000000000000000000000000000000000..88608c75aea626511cdb498008f3a9dafff31f99 GIT binary patch literal 938 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K59)QUsR;_=59F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&V7%KUyadSO zEbxddW?lFzi8y?AW^~>g10LtC z%x~+b-)hW~yLI`cYvJ?LSv@mN3L_k*y1u&jf?u1BVWQw`sld5`HfbeCzwhF&IR0;! z8p9{I(AUqMw&xsk%vN6Q&M ziZ2Bn6hgcYP4h1)_!OG=-}NfX1I1q-&P^&RYd>hUcNY7fi%NE$YpmATt^7Noipim8 zjr-l5=K|{PKGb&SW$+3)tB|rZ!)wJYw}4gd4DLrXbYk)gb#Gj;Wz-OiNZYmSrsL`a z-|pKC4+MX0c$vBMK*ZI329|L)`*5C z`fB3V5L_f){AJ-ehXr*3ntzu%@8SF5@L13x z|Ivil$&!M`%27b*FCD|TF$uOkOX5uxS_-G zb1trjJner7uVdcFV0-y`c##XYA298zmbgZgq$HN4S|t~y0x1R~10y3{15;fiqYy(2 uD)ZR(k~1pp_sJVkSXsNz7{09xWPTwo21j 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 BViEuV literal 0 HcmV?d00001 diff --git a/GCryptLib/visualizations/input.bmp.png b/GCryptLib/visualizations/input.bmp.png new file mode 100644 index 0000000000000000000000000000000000000000..a6df3cafd71b5de5a391f3d94ae2ec35ef7b26ab GIT binary patch literal 358 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58o=b4b6v}U9F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMHK4i{28LfC^)DD0N(~qoUL`OvSj}Ky5HFasE6@fg!Ib3f?!v%$w@Y{lkjGiz z5n0T@z%2~Ij105pNB{-dOFVsD*`KkB2}$cZ37Gx`3PpOlIEF+VetUHzFM|RPv*Wk; zTL)PD#l8JstyZ#*Y>X5tc-FjILqLjQ;YJ3p9@ZxdEw}`9`dA+=@u`q-Vek5?1`l!ovlk|8slhCZ?zQ zCZ=a5XY-~f=H@2a8t9prnwXk0=z#QtOk!aA-_yVH^jrSLbGF>--h6M*Z~nGN9@Cz6 zE_-!q+dJ;#pM0)=>wW&~-1mR{JY4N64IevvwEB-MGv3h8qu-PQ|FThDs=`?sWy)t)Gs zikewDJA7{K`N1O_Ysnk4w$gXbUS8?vf4SxMS^L#x*V)Zp_wUrbzB6q5_3ZWI^5yfV zo&R<2{NDHS#x+ciKeaPnDjf3Q5;qchHbMAE$8@!zDJdV57WX`s5-faU@j}_dUdery zO{dY)Q&V-KchztjFY}4xO%Gd{`I+ zcSTTfz*?)Vn%4rZZo9SPRVmwz4d%TQbyvSx*Yor zeSW2ZbMrBipQbMlZ%W*~&Nf;q@Aj7R=WS1B7ruGG0l&+xb-8=Y3)xOK>c?NG`BD7h)Xebtbqc%k-dvkoKK-2S?^4#|sp1R_ F)&R$D7@YtB literal 0 HcmV?d00001 diff --git a/GCryptLib/visualizations/output-big-flip.bmp.png b/GCryptLib/visualizations/output-big-flip.bmp.png new file mode 100644 index 0000000000000000000000000000000000000000..eca1a58639805da35e85d200e8a126b56391d515 GIT binary patch literal 1087 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K59)QUsR;_=59F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&V7%KUyadSO zEbxddW?%5bv%8Slk;D0A z!@u22n0w|~ly5lVr&q0h-k?V1K%k_gXz0bOD}zhVFI`>IX~B?k{;efr_q=H43zyIA zl&@u+@m=BBoj-2N-i0RSKj%$&H>K{`1fzo5W!@(`*&C*;&kFFp^UP|VwExLWOUFG7 zCW2Dim%N#ny2+4Dm3y~8LzUF2>pM@yH%{eR6!eQ_!2%86-cCfb`cjYRV7vI8S7;dGV@L;q~Fw*e-TEnzK_Li zzg=&#*(=#cu9mT5X%yJ^)DSJGpyh%=nJ9C^w@tufvG;4FsI z^O+@%>82z~E`5A$^4#Wo%(rY>7wtG3XKX9*g;hb2?_xw_j#ZwP`KQ}awrmDn#Sg-! zt~_(LZ}Lye15R$YJLgrI{419#Wc=~XgvWmNzGorgmpL0g>8?M$$13>!d&!?17vzp` znf{!%{K|!Q#{3MP2`_RNzLyQ!F4!Y|K<;LCu>OyghyI@9bTE1~Rd839S}Nb>6*7!T z-%bC89qcy#*XrQMuxUkM&vun9)t7{hZq#S^I{n*^X{qNF*_5;IW;;}eK9jw8jeDA) z+qv_Mt75p0e2y>twk{?6m2E@e;yd3fPtL37DJ^B(uxYaC-}xLjAN)MMjG4iC`tJDY z6M621?%&^2&G&;*Ug3|*vA;_iff-7*#5JNMC9x#cD!C{XNHG{07#ZmrnCcoCg&0~` u8JSy|m}(msSQ!{R5mB3jq9HdwB{QuOw}z>n^Ynlk7(8A5T-G@yGywpv)w_rQ literal 0 HcmV?d00001 diff --git a/GCryptLib/visualizations/output-big.bmp.png b/GCryptLib/visualizations/output-big.bmp.png new file mode 100644 index 0000000000000000000000000000000000000000..fdca11b6c7d102976c2e9e9ef216336d1cebdce6 GIT binary patch literal 1089 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 literal 0 HcmV?d00001 diff --git a/GCryptLib/visualizations/output-flip.bmp.png b/GCryptLib/visualizations/output-flip.bmp.png new file mode 100644 index 0000000000000000000000000000000000000000..bf90029ceb53b5264f25bc0930140f3e57e839e8 GIT binary patch literal 442 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 literal 0 HcmV?d00001 diff --git a/readme.md b/readme.md index e6fd47a..ca84f5f 100644 --- a/readme.md +++ b/readme.md @@ -49,11 +49,11 @@ const std::string input = "I am a super secret message!"; std::cout << input << std::endl; // Encrypt -const std::string encrypted = GCryptWrapper::EncryptString(input, "password1"); +const std::string encrypted = GWrapper::EncryptString(input, Key::FromPassword("password1")); std::cout << encrypted << std::endl; // Decrypt -const std::string decrypted = GCryptWrapper::DecryptString(encrypted, "password1"); +const std::string decrypted = GWrapper::DecryptString(encrypted, Key::FromPassword("password1")); std::cout << decrypted << std::endl; ``` @@ -62,18 +62,38 @@ std::cout << decrypted << std::endl; using namespace Leonetienne::GCrypt; // Encrypt -GCryptWrapper::EncryptFile("main.cpp", "main.cpp.crypt", "password1"); +GCryptWrapper::EncryptFile("main.cpp", "main.cpp.crypt", Key::FromPassword("password1")); // Decrypt -GCryptWrapper::DecryptFile("main.cpp.crypt", "main.cpp.clear", "password1"); +GCryptWrapper::DecryptFile("main.cpp.crypt", "main.cpp.clear", Key::FromPassword("password1")); ``` -If you want to do more complex stuff, use the cipher-class [`GCrypt::Cipher`](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/master/GCryptLib/include/GCrypt/Cipher.h) aswell as the conversion methods in [Util.h](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/master/GCryptLib/include/GCrypt/Util.h). This way you can cipher on bitlevel. Examples on how to do this are in [GCryptWrapper.cpp](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/master/GCryptLib/src/GCryptWrapper.cpp). -This way you could, for example, decrypt an ecrypted file directly into memory. Or use a full-length key instead of a password. +### Prefer keyfiles instead? +```cpp +using namespace Leonetienne::GCrypt; + +// Create a random key +const Key newKey = Key::Random(); // Will create a key from actual randomness (like, hardware events) + +// Use the key +GCryptWrapper::EncryptFile("main.cpp", "main.cpp.crypt", newKey); + +// Save the key to a keyfile +newKey.WriteToFile("/var/stuff/mykeyfile"); + +// ... + +// Load the key +const Key loadedKey = Key::LoadFromFile("/var/stuff/mykeyfile"); +``` + +If you want to do more complex stuff, use the cipher-class [`GCrypt::GCipher`](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/master/GCryptLib/include/GCrypt/GCipher.h) aswell as the conversion methods in [Util.h](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/master/GCryptLib/include/GCrypt/Util.h). +This way you can cipher on bitlevel. Examples on how to do this are in [GWrapper.cpp](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/master/GCryptLib/src/GWrapper.cpp). +This way you could, for example, decrypt an ecrypted file directly into memory. Without saying, this is more advanced and not as-easy as the methods supplied in the wrapper. --- -\* A key is always of size `BLOCK_SIZE`. The default block size is 512 (bit), but you can easily change it in [Config.h](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/master/GCryptLib/include/GCrypt/Config.h) or wherever it'll be put in the INCLUDE/*.cpp. `BLOCK_SIZE` is also the minimal output length! +\* A key is always of size `BLOCK_SIZE`. The default block size is 512 (bit), but you can easily change it in [Config.h](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/master/GCryptLib/include/GCrypt/Config.h) or wherever it'll be put in the INCLUDE/\*.cpp. `BLOCK_SIZE` is also the minimal output length! ## The deets 🍝 @@ -83,23 +103,69 @@ Without saying, this is more advanced and not as-easy as the methods supplied in * [RRKM] Never heard of a mode like this, so i've named it **R**olling**R**ound**K**ey**M**ode. This basically means that the round key extrapolation is carried out continously over EVERY round on EVERY block. So in addition to *Mi* being dependent on *E(Mi-1,Ki-1,0)* due to CBC, so is now *Ki* dependent on *Ki-1,r* with *r* being the maximum number of extrapolated keys within a call of *E()*. This is handled within the feistel network class, as an instance lifecycle sees all blocks. Just in case you want to take a peek. ### Password to key -How does *GC* transform a password to a key? -First up, we have to establish what requirements this transformation must fulfill: -* A full key. Not just *len(passwd)\*8* bits and the rest zero-padded. -* Even if *len(passwd)\*8 > KEY_SIZE*, every bit of the password should affect the key -* Diffusion -* Ideally good collision resistance +How does GCrypt transform a password to a key?.. +Well, it uses the included hash function [GHash](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/feature/relaunch/GCryptLib/include/GCrypt/GHash.h). -Let's be honest, I'm not a cryptographer, I have no idea how collision resistant this is. -This means, it has to be considered *insecure*! -I have tried a few passwords brute-forcibly, experimentally (about 1mil) and have not been able to produce a collision. -Obviously there have to be collisions, since *|P|, len\(p\) ∈ ℵ ≫ |C|, len(c)*. +### Hashing with GHash +GHash is a streaming hash function based on the GCipher. +For all intents and purposes, it does the following: +You have a *Block b*, which is initialized with a static random distribution. +Once you give the GHash instance a data block to digest, it will use the GCipher to encrypt it, with itself as a key, and xor that onto *b*. +(*bi = bi-1 ⊕ E(key=b, data=k)*) -How does it work? Basically, what happens is your password gets recoded to binary. It is then split into blocks of -size KEY_SIZE, and they are combined using *ci+1 = ci ⨁ E(c=blocki, k=blocki)*. *c0* is a static initialization vector. The final *c* is they key corresponding to a password. +The lastest *b* represents the current result of the hash function. -This is a one-way operation. Since the key used for this operation is the cleartext itself, you cannot undo it without already -knowing the password(=cleartext) to begin with. *You could make a hashfunction out of this.* +GHash also supports a do-it-all wrapper method that takes a Flexblock (A block of arbitrary length), and returns a hashsum for it. +This wrapper function adds an additional block including the length of the input. This wrapper function is used to transform Passwords to Keys. + +### GPrng...? +Whilst we're at it, why not implement a pseudo-random number generator based on GHash aswell. So here it is, [GPrng](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/feature/relaunch/GCryptLib/include/GCrypt/GPrng.h). +GPrng is really nothing special. I just wanted to implement it, mainly to visualize the GCiphers entropy. + +GPrng basically does the following: It creates a GHash instance, which initially digested the prngs seed. This produces a hash result, which is one block in size. +This block gets eaten up, as pseudo-randomness is used. Once there are no bits left, the GHash instance will digest the result of this block ⊕ seed. +The xor operation ensures that an observer will never know the internal state of the GHash instance. This is important, as to ensure an observer won't be able to predict +future output. + +### Speaking of... Visualizations! +
+ +`"Hello :3"` in binary: +!["Hello :3" in binary](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/input.bmp.png) + + + +It's ciphertext: +![Ciphertext 1](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/output.bmp.png) + +
+ +Now, let's flip a single bit in the input: + +One bit flipped: +![One bit flipped](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/input-flip.bmp.png) + +It's ciphertext: +![Ciphertext for flipped bit](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/output-flip.bmp.png) + +Let's gif them together, to better see the difference... + +Input: +![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/input.gif) + +Ciphertext: +![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/output.gif) + + +What about input longer a single block? + +Input: +![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/input-big.gif) + +Ciphertext: +![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/output-big.gif) + +Notice how the ciphertext doesn't change until the block containing the bitflip is reached. This is a limitation of cipher block chaining. ## Noteworthy: * This is no fixed algorithm. Newer versions may very well be unable to decrypt ciphertexts encrypted with earlier versions. From 17dece8dafad1693b02fc0eedea10ee45aad672d Mon Sep 17 00:00:00 2001 From: Leon Etienne Date: Sun, 22 May 2022 20:55:04 +0200 Subject: [PATCH 026/110] Put images in readme next to each other --- readme.md | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/readme.md b/readme.md index ca84f5f..ed47e68 100644 --- a/readme.md +++ b/readme.md @@ -128,41 +128,31 @@ The xor operation ensures that an observer will never know the internal state of future output. ### Speaking of... Visualizations! -
- -`"Hello :3"` in binary: +`"Hello :3"` in binary, and it's ciphertext: + !["Hello :3" in binary](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/input.bmp.png) - - - -It's ciphertext: +    ![Ciphertext 1](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/output.bmp.png) - -
-Now, let's flip a single bit in the input: -One bit flipped: +Now, let's flip a single bit in the input: + +One bit flipped, and again the corresponding ciphertext: ![One bit flipped](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/input-flip.bmp.png) - -It's ciphertext: +    ![Ciphertext for flipped bit](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/output-flip.bmp.png) -Let's gif them together, to better see the difference... - -Input: +Let's gif them together, to better see the difference: ![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/input.gif) - -Ciphertext: +    ![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/output.gif) What about input longer a single block? -Input: +Input, and ciphertext: ![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/input-big.gif) - -Ciphertext: +    ![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/output-big.gif) Notice how the ciphertext doesn't change until the block containing the bitflip is reached. This is a limitation of cipher block chaining. From 8c7506297f029b84f0fa2e65f6e7e10eb29a6a73 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 21:10:36 +0200 Subject: [PATCH 027/110] Added another visualization to readme --- .../visualizations/input-big-flip.bmp.png | Bin 938 -> 938 bytes GCryptLib/visualizations/input-big.bmp.png | Bin 938 -> 938 bytes .../visualizations/input-extreme-flip.bmp.png | Bin 0 -> 306 bytes .../visualizations/input-extreme-key.bmp.png | Bin 0 -> 308 bytes .../visualizations/input-extreme.bmp.png | Bin 0 -> 327 bytes GCryptLib/visualizations/input-extreme.gif | Bin 0 -> 813 bytes GCryptLib/visualizations/input-flip.bmp.png | Bin 355 -> 355 bytes GCryptLib/visualizations/input.bmp.png | Bin 358 -> 358 bytes .../visualizations/output-big-flip.bmp.png | Bin 1087 -> 1087 bytes GCryptLib/visualizations/output-big.bmp.png | Bin 1089 -> 1089 bytes .../output-extreme-flip.bmp.png | Bin 0 -> 1091 bytes .../visualizations/output-extreme.bmp.png | Bin 0 -> 1078 bytes GCryptLib/visualizations/output-extreme.gif | Bin 0 -> 7873 bytes GCryptLib/visualizations/output-flip.bmp.png | Bin 442 -> 442 bytes GCryptLib/visualizations/output.bmp.png | Bin 443 -> 443 bytes readme.md | 18 ++++++++++++++++-- 16 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 GCryptLib/visualizations/input-extreme-flip.bmp.png create mode 100644 GCryptLib/visualizations/input-extreme-key.bmp.png create mode 100644 GCryptLib/visualizations/input-extreme.bmp.png create mode 100644 GCryptLib/visualizations/input-extreme.gif create mode 100644 GCryptLib/visualizations/output-extreme-flip.bmp.png create mode 100644 GCryptLib/visualizations/output-extreme.bmp.png create mode 100644 GCryptLib/visualizations/output-extreme.gif diff --git a/GCryptLib/visualizations/input-big-flip.bmp.png b/GCryptLib/visualizations/input-big-flip.bmp.png index 18127a336ddfea9052ec4fb6592c8163785391f4..23ec9b8b750b70e05b88ad542926a02dedb6283c 100644 GIT binary patch delta 18 acmZ3*zKVT954$j%#4FzKUpGz`X9fU2rv~@{ delta 18 ZcmZ3*zKVT954(`Gu9JZ2-;I;SnE^MP1;PLT diff --git a/GCryptLib/visualizations/input-big.bmp.png b/GCryptLib/visualizations/input-big.bmp.png index 88608c75aea626511cdb498008f3a9dafff31f99..dfc6e9e046eed0a0bd5b15a6d94926431000c0ba 100644 GIT binary patch delta 18 acmZ3*zKVT954$j%#4FzKUpGz`X9fU2rv~@{ delta 18 ZcmZ3*zKVT954(`Gu9JZ2-;I;SnE^MP1;PLT diff --git a/GCryptLib/visualizations/input-extreme-flip.bmp.png b/GCryptLib/visualizations/input-extreme-flip.bmp.png new file mode 100644 index 0000000000000000000000000000000000000000..15178e23a10632848d17cdcb1625275d3af0ac56 GIT binary patch literal 306 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K59)QUsR;_=59F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&V7%KUyadSO zEbxddW?lFzi8%cBlp!wz0|)a4 z%LDtPZQdv?+&i1WA(@W_sDgoEUu4`&23r>87mq<2N?apKQW8s2t&)pUffR$0fsv7} zfvK*MQHY_Xm4TU+k+HUcft7)Q_GH0O6b-rgDVb@NxHUwbTlo@XpQo#z%Q~loCICB# BOyvLo literal 0 HcmV?d00001 diff --git a/GCryptLib/visualizations/input-extreme-key.bmp.png b/GCryptLib/visualizations/input-extreme-key.bmp.png new file mode 100644 index 0000000000000000000000000000000000000000..e08f89d23aec6943c3372da3a956d880acc86fa9 GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58o=b4b6v}U9F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMHK4i{28LfC^)DD0N(~qoUL`OvSj}Ky5HFasE6@fg!Ib3f?!v%$w@Y{lkjGiz z5n0T@z%2~Ij105pNB{-dOFVsD*`KkB3A0JO;{E;=D5UP`;usQf`0c5MKzHykDg3XG z@{fpU^{MJm;An!OL;5^Nbw4~hIOolLpcd5<*NBpo#FA92>k|Q5paM literal 0 HcmV?d00001 diff --git a/GCryptLib/visualizations/input-extreme.bmp.png b/GCryptLib/visualizations/input-extreme.bmp.png new file mode 100644 index 0000000000000000000000000000000000000000..85d9ce52625a9ee83401a9ff7e1d64794233f9bd GIT binary patch literal 327 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K59)QUsR;_=59F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&V7%KUyadSO zEbxddW?*3mbrU3JJ1{KHsKTO4-T^f)gprjLMA3to|Qh_N;T+ zt5e(FaUcKWbNyTI^Izw_|KsQ3YCp2*V~3B{^fSvobM|^Izq0CU*V(M?ch-I9=IcKG zWYfmR3n?F3Vy0*TtxwXA>*X})g_w8R^IXyeSxV*Z)dF%F_yZ7!NpS-@ke|&y@|NQm) z&)O{g6w!{_(_y&ySZ{!gb=4mZqa`OMs(8<` z=`>n;YN}53t{P6`WoKrZWZ&A;X}tX0T$}1&e>hE6Tv+JREoIwfvhvbWpV?NmT&An8 ltPEKlwYST3^|iGzyQ}_km3cCf5d|#+9tDC9Qo|_2EYIS diff --git a/GCryptLib/visualizations/input.bmp.png b/GCryptLib/visualizations/input.bmp.png index a6df3cafd71b5de5a391f3d94ae2ec35ef7b26ab..5f84f7f09ecd131e68b56cb83ea3e077a147a4ba 100644 GIT binary patch delta 17 ZcmaFH^o(gj54$j%#4FzKUnfq!3;;j%2mb&7 delta 17 ZcmaFH^o(gj54(`Gu9JZ2--(ki0{}T72FU;b diff --git a/GCryptLib/visualizations/output-big-flip.bmp.png b/GCryptLib/visualizations/output-big-flip.bmp.png index eca1a58639805da35e85d200e8a126b56391d515..ae865e8146465aa7c623889735a9dca797c15d9c 100644 GIT binary patch delta 18 acmdnbv7ci?54$j%#4FzKUpG!(!wdjJy9c=d delta 18 acmdnbv7ci?54(`Gu9JZ2-;I;kFarQPum*zw diff --git a/GCryptLib/visualizations/output-big.bmp.png b/GCryptLib/visualizations/output-big.bmp.png index fdca11b6c7d102976c2e9e9ef216336d1cebdce6..2b157909ecc6b7a0bc52637a7b39b6dc1ccce3c6 100644 GIT binary patch delta 18 acmX@eagbv|54$j%#4FzKUpG!(#|!{O0|&nV delta 18 acmX@eagbv|54(`Gu9JZ2-;I;kF#`ZQ_y&mp diff --git a/GCryptLib/visualizations/output-extreme-flip.bmp.png b/GCryptLib/visualizations/output-extreme-flip.bmp.png new file mode 100644 index 0000000000000000000000000000000000000000..f175415a12a788383ce82fd247ef5331938855dd GIT binary patch literal 1091 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K59)QUsR;_=59F}xPUq=Rpjs4tz5?O(Kg=CK) zUj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&V7%KUyadSO zEbxddW?h4(Kzmwe@NR_Offe-^e|8E5GI^!`_Veh&B5 zOFOUDn=u$4DLZ6&@nub|)4byLnz<+LGoMS{Z+V_?(;Vx1-$!K(&s!DzJCs}>r}w?J zF=J5cs1Q>zteqvmZ&R+r(32@2{Q1#iW08FVPl^w8p67YkbLypH>4P)(ZZiDfO*B<~ zvV97#>fAef*?%4l zbCkR@9Pc`YHq2SQnQ=o{M~|de_Q!(@H@rQf%kbmaqKh)2!jB*JOW%qKt>pb+c`?+N zKl{YnrD*||1Me}nv>ljrvaqnlL|k?9dB!chD?@l(a!qWz#J1M+Iv9Txy{5N1TxgnK z^0R&HQ;JPG)B`HAZS#M5uVu)1xr=w|j2DF(+>5p`7{q5JpX}q_X*l2Msu@Gt=?nW~ zGYxuhg-UlH@^{#H8SH1pM#<0vs=Kcjg(a-14_-($+aKz(G=^c*M zXZ?&qr5U)`SG@=p>Ctx;eP+X6(&o71)wX5%cE-sc558wKH@{o>;DX9)so-fD^O-Mb zS-~^+8`(m;1hr z)^nS?XY64Y;D6;?T>f`S)AQT6_po0v&oyyhb|>)7+Go;1^2|r%EUoljZ8sMEdY4a! z;n}k8o6oBXPFQ_^%=94d*(LvohYOd@eYIAU;ab~G{_d;gozXvME=*&-usz`7Tk9@A zo%QQ}*7Ke4m!4Uh{C)9K!O%a~iy7uP7`+eL9^_bholUwSpzUtR|HUCdB zT3PPTrK9_lw6`R>e~|gWT-EixA*~-TH+c}l9E`GYL#4+3Zxi}42+C)4NP^7 yj6w`8tqjbpj7+o*46F7r%ZE**c?ba#%j*(V5=d$NA?6SKNVgCO4P0R3<40E@5hAQEz6X~B7g?;Wxaj({6 zaP^Rq-oJ&^6W-KuBx}wl6 z>SU9;w5E*l#VV)mms^{IU#rwK{i);^X?S$(edo2Z+`uO>44!-E^n{)}mDo3Zr-N>{ zbi*4DnI#Mt&;INYF0Erfu)b~C>GBEd`{Zk1GI2Z#b9Fx2@>n_MW9;eb_l!RmSxjEm zbL!B6xS2iM=P}2gll^(JY}Lh!smJoNZWcFW1nyEWJ(HTxlRAfCzew4YBIm}_Cj*c0 zF>s05vffP1oT!&ATFMw;Rho2AK1+*t*+kj&hN-R>Zml(szJB=m54nQ>k3tUVvQ#SD zNAkxrv~F5(zIf`Dm0Ol>nep6VVNt;Jtn5>gD$`QG^EOytiaMU&{!h8{OEpu=Ws%O< zlvC&2^z_sne(u?E_npq)m5J)#sukvJF7nE=op|BN4UHx5881!a6j^*h{C>%oue+W% zXoV_iJuvz`-9xVD9&@(j!b=(4&*XVr8)O*5{%xt8FTKyHYWwl0-yMwdBIDP#&Jlj) z@B58m!R+cE8s7V-+J2h$f_s7LiWh17UMO;`bo94o__OKioELA)7|iX(8=}r%qHW>?=u34ta9odB)pY z^}lgSVDy<%+{KA@^}Gd4P{>Yu`_!mHH{ZCy9+ zu|~aPvMgTxl2PE>v`b&2*(x%p?Y#8c@_<@P%E$V9r%s)YcT1OHc+)b$vhmidh^Y@v z>=^zrtYUfZpuPREBrqSTmbgZgq$HN4S|t~y0x1R~10y3{15;fiqYy(&D+4ntBV%m? m11kdq?a6|nC>nC}Q!>*kachV=xAG-W1B0ilpUXO@geCw!pUP|i literal 0 HcmV?d00001 diff --git a/GCryptLib/visualizations/output-extreme.gif b/GCryptLib/visualizations/output-extreme.gif new file mode 100644 index 0000000000000000000000000000000000000000..f2e1266887c77032a3d1cde12a0be3b685463ad7 GIT binary patch literal 7873 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 E0Gg1s8UO$Q literal 0 HcmV?d00001 diff --git a/GCryptLib/visualizations/output-flip.bmp.png b/GCryptLib/visualizations/output-flip.bmp.png index bf90029ceb53b5264f25bc0930140f3e57e839e8..8372825f20da211932f31225b7bbd24da13896ac 100644 GIT binary patch delta 18 acmdnRyo-5454$j%#4FzKUpG!xX9NI2Wd|Mr delta 18 ZcmdnRyo-5454(`Gu9JZ2-;I;i838$31?T_( diff --git a/GCryptLib/visualizations/output.bmp.png b/GCryptLib/visualizations/output.bmp.png index 1e62f1a22373b75200b101422169bfda943806cd..9d473428f505b241f0366c8c659cacb8e97327f7 100644 GIT binary patch delta 18 acmdnZyqkGK54$j%#4FzKUpG$HU<3d`i3cG7 delta 18 ZcmdnZyqkGK54(`Gu9JZ2-;I+s7y&tc1?vC+ diff --git a/readme.md b/readme.md index ed47e68..0e36a94 100644 --- a/readme.md +++ b/readme.md @@ -128,6 +128,7 @@ The xor operation ensures that an observer will never know the internal state of future output. ### Speaking of... Visualizations! +#### Single-block diffusion `"Hello :3"` in binary, and it's ciphertext: !["Hello :3" in binary](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/input.bmp.png) @@ -135,7 +136,7 @@ future output. ![Ciphertext 1](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/output.bmp.png) -Now, let's flip a single bit in the input: +Now, let's flip than a single bit in the input: One bit flipped, and again the corresponding ciphertext: ![One bit flipped](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/input-flip.bmp.png) @@ -148,7 +149,7 @@ Let's gif them together, to better see the difference: ![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/output.gif) -What about input longer a single block? +#### What about input longer a single block? Input, and ciphertext: ![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/input-big.gif) @@ -157,6 +158,19 @@ Input, and ciphertext: Notice how the ciphertext doesn't change until the block containing the bitflip is reached. This is a limitation of cipher block chaining. +### What about extreme inputs? +How non-transparent is the cipher with extreme inputs? Even with a super problematic key?: + +Input, key, and ciphertext: +![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/input-extreme.gif) +    +![Key](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/input-extreme-key.bmp.png) +    +![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/output-extreme.gif) + +Notice how even cleartexts that are almost completely uniform, with a key that is just zeores, will produce ambiguous ciphertexts. +I darkened the input gif, as to not cause disorientation by flickering. + ## Noteworthy: * This is no fixed algorithm. Newer versions may very well be unable to decrypt ciphertexts encrypted with earlier versions. From 3978bb6b1859d2ec78eb23a8d4c4998be55ef571 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 21:25:53 +0200 Subject: [PATCH 028/110] Fix invalid html in readme --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 0e36a94..4f7c8e4 100644 --- a/readme.md +++ b/readme.md @@ -111,7 +111,7 @@ GHash is a streaming hash function based on the GCipher. For all intents and purposes, it does the following: You have a *Block b*, which is initialized with a static random distribution. Once you give the GHash instance a data block to digest, it will use the GCipher to encrypt it, with itself as a key, and xor that onto *b*. -(*bi = bi-1 ⊕ E(key=b, data=k)*) +(*bi = bi-1 ⊕ E(key=b, data=k)*) The lastest *b* represents the current result of the hash function. From 12b0f6b031cba7def2936acf7af9d775bb86a850 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 21:27:34 +0200 Subject: [PATCH 029/110] Fix typo in readme --- readme.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index 4f7c8e4..9320955 100644 --- a/readme.md +++ b/readme.md @@ -62,10 +62,10 @@ std::cout << decrypted << std::endl; using namespace Leonetienne::GCrypt; // Encrypt -GCryptWrapper::EncryptFile("main.cpp", "main.cpp.crypt", Key::FromPassword("password1")); +GWrapper::EncryptFile("main.cpp", "main.cpp.crypt", Key::FromPassword("password1")); // Decrypt -GCryptWrapper::DecryptFile("main.cpp.crypt", "main.cpp.clear", Key::FromPassword("password1")); +GWrapper::DecryptFile("main.cpp.crypt", "main.cpp.clear", Key::FromPassword("password1")); ``` ### Prefer keyfiles instead? @@ -76,7 +76,7 @@ using namespace Leonetienne::GCrypt; const Key newKey = Key::Random(); // Will create a key from actual randomness (like, hardware events) // Use the key -GCryptWrapper::EncryptFile("main.cpp", "main.cpp.crypt", newKey); +GWrapper::EncryptFile("main.cpp", "main.cpp.crypt", newKey); // Save the key to a keyfile newKey.WriteToFile("/var/stuff/mykeyfile"); @@ -111,7 +111,7 @@ GHash is a streaming hash function based on the GCipher. For all intents and purposes, it does the following: You have a *Block b*, which is initialized with a static random distribution. Once you give the GHash instance a data block to digest, it will use the GCipher to encrypt it, with itself as a key, and xor that onto *b*. -(*bi = bi-1 ⊕ E(key=b, data=k)*) +(*bi = bi-1 ⊕ E(key=b, data=b)*) The lastest *b* represents the current result of the hash function. @@ -122,8 +122,8 @@ This wrapper function adds an additional block including the length of the input Whilst we're at it, why not implement a pseudo-random number generator based on GHash aswell. So here it is, [GPrng](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/feature/relaunch/GCryptLib/include/GCrypt/GPrng.h). GPrng is really nothing special. I just wanted to implement it, mainly to visualize the GCiphers entropy. -GPrng basically does the following: It creates a GHash instance, which initially digested the prngs seed. This produces a hash result, which is one block in size. -This block gets eaten up, as pseudo-randomness is used. Once there are no bits left, the GHash instance will digest the result of this block ⊕ seed. +GPrng basically does the following: It creates a GHash instance, which initially digests the prngs seed. This produces a hash result, which is one block in size. +This block gets eaten up, as pseudo-randomness is used. Once there are no bits left, the GHash instance will digest the result of this block ⊕ the initial seed. The xor operation ensures that an observer will never know the internal state of the GHash instance. This is important, as to ensure an observer won't be able to predict future output. From b873c13bf2a95570bdbf19bed21e6cab24de3e59 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 21:27:34 +0200 Subject: [PATCH 030/110] Fix typo in readme --- readme.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/readme.md b/readme.md index 4f7c8e4..f7ed17f 100644 --- a/readme.md +++ b/readme.md @@ -62,10 +62,10 @@ std::cout << decrypted << std::endl; using namespace Leonetienne::GCrypt; // Encrypt -GCryptWrapper::EncryptFile("main.cpp", "main.cpp.crypt", Key::FromPassword("password1")); +GWrapper::EncryptFile("main.cpp", "main.cpp.crypt", Key::FromPassword("password1")); // Decrypt -GCryptWrapper::DecryptFile("main.cpp.crypt", "main.cpp.clear", Key::FromPassword("password1")); +GWrapper::DecryptFile("main.cpp.crypt", "main.cpp.clear", Key::FromPassword("password1")); ``` ### Prefer keyfiles instead? @@ -76,7 +76,7 @@ using namespace Leonetienne::GCrypt; const Key newKey = Key::Random(); // Will create a key from actual randomness (like, hardware events) // Use the key -GCryptWrapper::EncryptFile("main.cpp", "main.cpp.crypt", newKey); +GWrapper::EncryptFile("main.cpp", "main.cpp.crypt", newKey); // Save the key to a keyfile newKey.WriteToFile("/var/stuff/mykeyfile"); @@ -93,7 +93,7 @@ This way you could, for example, decrypt an ecrypted file directly into memory. Without saying, this is more advanced and not as-easy as the methods supplied in the wrapper. --- -\* A key is always of size `BLOCK_SIZE`. The default block size is 512 (bit), but you can easily change it in [Config.h](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/master/GCryptLib/include/GCrypt/Config.h) or wherever it'll be put in the INCLUDE/\*.cpp. `BLOCK_SIZE` is also the minimal output length! +\* A key is always of size `BLOCK_SIZE`. The default block size is 512 (bit), but you can easily change it in [Config.h](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/master/GCryptLib/include/GCrypt/Config.h). ## The deets 🍝 @@ -111,7 +111,7 @@ GHash is a streaming hash function based on the GCipher. For all intents and purposes, it does the following: You have a *Block b*, which is initialized with a static random distribution. Once you give the GHash instance a data block to digest, it will use the GCipher to encrypt it, with itself as a key, and xor that onto *b*. -(*bi = bi-1 ⊕ E(key=b, data=k)*) +(*bi = bi-1 ⊕ E(key=b, data=b)*) The lastest *b* represents the current result of the hash function. @@ -122,8 +122,8 @@ This wrapper function adds an additional block including the length of the input Whilst we're at it, why not implement a pseudo-random number generator based on GHash aswell. So here it is, [GPrng](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/feature/relaunch/GCryptLib/include/GCrypt/GPrng.h). GPrng is really nothing special. I just wanted to implement it, mainly to visualize the GCiphers entropy. -GPrng basically does the following: It creates a GHash instance, which initially digested the prngs seed. This produces a hash result, which is one block in size. -This block gets eaten up, as pseudo-randomness is used. Once there are no bits left, the GHash instance will digest the result of this block ⊕ seed. +GPrng basically does the following: It creates a GHash instance, which initially digests the prngs seed. This produces a hash result, which is one block in size. +This block gets eaten up, as pseudo-randomness is used. Once there are no bits left, the GHash instance will digest the result of this block ⊕ the initial seed. The xor operation ensures that an observer will never know the internal state of the GHash instance. This is important, as to ensure an observer won't be able to predict future output. From 7cf55414b5801f342817a239afe88a596335bb23 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 23:22:54 +0200 Subject: [PATCH 031/110] Wording readme --- readme.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index f7ed17f..eda2ff9 100644 --- a/readme.md +++ b/readme.md @@ -136,7 +136,7 @@ future output. ![Ciphertext 1](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/output.bmp.png) -Now, let's flip than a single bit in the input: +Now, let's flip a single bit in the input: One bit flipped, and again the corresponding ciphertext: ![One bit flipped](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/input-flip.bmp.png) @@ -148,15 +148,16 @@ Let's gif them together, to better see the difference:     ![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/output.gif) +As shown, flipping even a single bit, affects the entire ciphertext. -#### What about input longer a single block? +#### What about input longer than a single block? Input, and ciphertext: ![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/input-big.gif)     ![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/output-big.gif) -Notice how the ciphertext doesn't change until the block containing the bitflip is reached. This is a limitation of cipher block chaining. +Notice how the ciphertext doesn't change until the block containing the bitflip is reached? This is a limitation of cipher block chaining. ### What about extreme inputs? How non-transparent is the cipher with extreme inputs? Even with a super problematic key?: From 3819fbe69346c83f9d39cbed5f50624384c921ab Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sun, 22 May 2022 23:27:23 +0200 Subject: [PATCH 032/110] Typo readme --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index eda2ff9..bc18f9a 100644 --- a/readme.md +++ b/readme.md @@ -122,7 +122,7 @@ This wrapper function adds an additional block including the length of the input Whilst we're at it, why not implement a pseudo-random number generator based on GHash aswell. So here it is, [GPrng](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/feature/relaunch/GCryptLib/include/GCrypt/GPrng.h). GPrng is really nothing special. I just wanted to implement it, mainly to visualize the GCiphers entropy. -GPrng basically does the following: It creates a GHash instance, which initially digests the prngs seed. This produces a hash result, which is one block in size. +GPrng basically does the following: It creates a GHash instance, which initially digests the prng's seed. This produces a hash result, which is one block in size. This block gets eaten up, as pseudo-randomness is used. Once there are no bits left, the GHash instance will digest the result of this block ⊕ the initial seed. The xor operation ensures that an observer will never know the internal state of the GHash instance. This is important, as to ensure an observer won't be able to predict future output. From ed45b693424916d7923085d888dd5fa35201fdd7 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Mon, 23 May 2022 22:42:14 +0200 Subject: [PATCH 033/110] Experimentally implement matrix-mult --- GCryptLib/include/GCrypt/BlockMatrix.h | 49 +++++++++++ GCryptLib/include/GCrypt/Config.h | 2 +- GCryptLib/include/GCrypt/Version.h | 2 +- GCryptLib/src/BlockMatrix.cpp | 114 +++++++++++++++++++++++++ GCryptLib/src/Feistel.cpp | 5 +- 5 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 GCryptLib/include/GCrypt/BlockMatrix.h create mode 100644 GCryptLib/src/BlockMatrix.cpp diff --git a/GCryptLib/include/GCrypt/BlockMatrix.h b/GCryptLib/include/GCrypt/BlockMatrix.h new file mode 100644 index 0000000..6f28a84 --- /dev/null +++ b/GCryptLib/include/GCrypt/BlockMatrix.h @@ -0,0 +1,49 @@ +#ifndef GCRYPT_BLOCKMATRIX_H +#define GCRYPT_BLOCKMATRIX_H + +#include "GCrypt/Block.h" +#include +#include + +namespace Leonetienne::GCrypt { + + /* This class represents a block as a matrix, + * providing typical matrix operations + */ + class BlockMatrix { + public: + BlockMatrix(); + BlockMatrix(const Block& block); + BlockMatrix(const BlockMatrix& other); + + //! Will calculate the product of two matrices. + //! Since the matrices values are pretty much sudo-random, + //! they will most likely integer-overflow. + //! So see this as a one-way function. + BlockMatrix MMult(const BlockMatrix& other) const; + BlockMatrix operator*(const BlockMatrix& other) const; + + //! Will do a regular matrix-mult, but instead of + //! adding, and multiplying, all ints get xored. + BlockMatrix MXor(const BlockMatrix& other) const; + + bool operator==(const BlockMatrix& other) const; + bool operator!=(const BlockMatrix& other) const; + + void FromBlock(const Block& block); + Block ToBlock() const; + + private: + //! Returns items of data, indexed by 4x4 coordinates + std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column); + //! Returns items of data, indexed by 4x4 coordinates + const std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column) const; + + std::array data; + }; + +} + + +#endif + diff --git a/GCryptLib/include/GCrypt/Config.h b/GCryptLib/include/GCrypt/Config.h index dd56656..0bcac82 100644 --- a/GCryptLib/include/GCrypt/Config.h +++ b/GCryptLib/include/GCrypt/Config.h @@ -8,7 +8,7 @@ namespace Leonetienne::GCrypt { constexpr std::size_t BLOCK_SIZE = 512; // MUST BE > 2 - constexpr std::size_t N_ROUNDS = 400; + constexpr std::size_t N_ROUNDS = 10; } #endif diff --git a/GCryptLib/include/GCrypt/Version.h b/GCryptLib/include/GCrypt/Version.h index ff66ec4..256c32b 100644 --- a/GCryptLib/include/GCrypt/Version.h +++ b/GCryptLib/include/GCrypt/Version.h @@ -1,7 +1,7 @@ #ifndef GCRYPT_VERSION_H #define GCRYPT_VERSION_H -#define GCRYPT_VERSION 0.23 +#define GCRYPT_VERSION 0.231 #endif diff --git a/GCryptLib/src/BlockMatrix.cpp b/GCryptLib/src/BlockMatrix.cpp new file mode 100644 index 0000000..e1915c9 --- /dev/null +++ b/GCryptLib/src/BlockMatrix.cpp @@ -0,0 +1,114 @@ +#include "GCrypt/BlockMatrix.h" +#include + +namespace Leonetienne::GCrypt { + + BlockMatrix::BlockMatrix() { + } + + BlockMatrix::BlockMatrix(const Block& block) { + FromBlock(block); + } + + BlockMatrix::BlockMatrix(const BlockMatrix& other) { + data = other.data; + } + + void BlockMatrix::FromBlock(const Block& block) { + + const std::string blockstr = block.to_string(); + constexpr std::size_t cellSize = sizeof(std::uint32_t)*8; + + for (std::size_t i = 0; i < 16; i++) { + data[i] = std::bitset(blockstr.substr(i*cellSize, cellSize)).to_ulong(); + } + + return; + } + + Block BlockMatrix::ToBlock() const { + + std::stringstream ss; + constexpr std::size_t cellSize = sizeof(std::uint32_t)*8; + + for (std::size_t i = 0; i < 16; i++) { + ss << std::bitset(data[i]).to_string(); + } + return Block(ss.str()); + } + + BlockMatrix BlockMatrix::MMult(const BlockMatrix& o) const { + + BlockMatrix m; + + m.Get(0, 0) = (this->Get(0, 0) * o.Get(0, 0)) + (this->Get(0, 1) * o.Get(1, 0)) + (this->Get(0, 2) * o.Get(2, 0)) + (this->Get(0, 3) * o.Get(3, 0)); + m.Get(0, 1) = (this->Get(0, 0) * o.Get(0, 1)) + (this->Get(0, 1) * o.Get(1, 1)) + (this->Get(0, 2) * o.Get(2, 1)) + (this->Get(0, 3) * o.Get(3, 1)); + m.Get(0, 2) = (this->Get(0, 0) * o.Get(0, 2)) + (this->Get(0, 1) * o.Get(1, 2)) + (this->Get(0, 2) * o.Get(2, 2)) + (this->Get(0, 3) * o.Get(3, 2)); + m.Get(0, 3) = (this->Get(0, 0) * o.Get(0, 3)) + (this->Get(0, 1) * o.Get(1, 3)) + (this->Get(0, 2) * o.Get(2, 3)) + (this->Get(0, 3) * o.Get(3, 3)); + + m.Get(1, 0) = (this->Get(1, 0) * o.Get(0, 0)) + (this->Get(1, 1) * o.Get(1, 0)) + (this->Get(1, 2) * o.Get(2, 0)) + (this->Get(1, 3) * o.Get(3, 0)); + m.Get(1, 1) = (this->Get(1, 0) * o.Get(0, 1)) + (this->Get(1, 1) * o.Get(1, 1)) + (this->Get(1, 2) * o.Get(2, 1)) + (this->Get(1, 3) * o.Get(3, 1)); + m.Get(1, 2) = (this->Get(1, 0) * o.Get(0, 2)) + (this->Get(1, 1) * o.Get(1, 2)) + (this->Get(1, 2) * o.Get(2, 2)) + (this->Get(1, 3) * o.Get(3, 2)); + m.Get(1, 3) = (this->Get(1, 0) * o.Get(0, 3)) + (this->Get(1, 1) * o.Get(1, 3)) + (this->Get(1, 2) * o.Get(2, 3)) + (this->Get(1, 3) * o.Get(3, 3)); + + m.Get(2, 0) = (this->Get(2, 0) * o.Get(0, 0)) + (this->Get(2, 1) * o.Get(1, 0)) + (this->Get(2, 2) * o.Get(2, 0)) + (this->Get(2, 3) * o.Get(3, 0)); + m.Get(2, 1) = (this->Get(2, 0) * o.Get(0, 1)) + (this->Get(2, 1) * o.Get(1, 1)) + (this->Get(2, 2) * o.Get(2, 1)) + (this->Get(2, 3) * o.Get(3, 1)); + m.Get(2, 2) = (this->Get(2, 0) * o.Get(0, 2)) + (this->Get(2, 1) * o.Get(1, 2)) + (this->Get(2, 2) * o.Get(2, 2)) + (this->Get(2, 3) * o.Get(3, 2)); + m.Get(2, 3) = (this->Get(2, 0) * o.Get(0, 3)) + (this->Get(2, 1) * o.Get(1, 3)) + (this->Get(2, 2) * o.Get(2, 3)) + (this->Get(2, 3) * o.Get(3, 3)); + + m.Get(3, 0) = (this->Get(3, 0) * o.Get(0, 0)) + (this->Get(3, 1) * o.Get(1, 0)) + (this->Get(3, 2) * o.Get(2, 0)) + (this->Get(3, 3) * o.Get(3, 0)); + m.Get(3, 1) = (this->Get(3, 0) * o.Get(0, 1)) + (this->Get(3, 1) * o.Get(1, 1)) + (this->Get(3, 2) * o.Get(2, 1)) + (this->Get(3, 3) * o.Get(3, 1)); + m.Get(3, 2) = (this->Get(3, 0) * o.Get(0, 2)) + (this->Get(3, 1) * o.Get(1, 2)) + (this->Get(3, 2) * o.Get(2, 2)) + (this->Get(3, 3) * o.Get(3, 2)); + m.Get(3, 3) = (this->Get(3, 0) * o.Get(0, 3)) + (this->Get(3, 1) * o.Get(1, 3)) + (this->Get(3, 2) * o.Get(2, 3)) + (this->Get(3, 3) * o.Get(3, 3)); + + return m; + } + + BlockMatrix BlockMatrix::operator*(const BlockMatrix& other) const { + return this->MMult(other); + } + + BlockMatrix BlockMatrix::MXor(const BlockMatrix& o) const { + + BlockMatrix m; + + m.Get(0, 0) = this->Get(0, 0) ^ o.Get(0, 0) ^ this->Get(0, 1) ^ o.Get(1, 0) ^ this->Get(0, 2) ^ o.Get(2, 0) ^ this->Get(0, 3) ^ o.Get(3, 0); + m.Get(0, 1) = this->Get(0, 0) ^ o.Get(0, 1) ^ this->Get(0, 1) ^ o.Get(1, 1) ^ this->Get(0, 2) ^ o.Get(2, 1) ^ this->Get(0, 3) ^ o.Get(3, 1); + m.Get(0, 2) = this->Get(0, 0) ^ o.Get(0, 2) ^ this->Get(0, 1) ^ o.Get(1, 2) ^ this->Get(0, 2) ^ o.Get(2, 2) ^ this->Get(0, 3) ^ o.Get(3, 2); + m.Get(0, 3) = this->Get(0, 0) ^ o.Get(0, 3) ^ this->Get(0, 1) ^ o.Get(1, 3) ^ this->Get(0, 2) ^ o.Get(2, 3) ^ this->Get(0, 3) ^ o.Get(3, 3); + + m.Get(1, 0) = this->Get(1, 0) ^ o.Get(0, 0) ^ this->Get(1, 1) ^ o.Get(1, 0) ^ this->Get(1, 2) ^ o.Get(2, 0) ^ this->Get(1, 3) ^ o.Get(3, 0); + m.Get(1, 1) = this->Get(1, 0) ^ o.Get(0, 1) ^ this->Get(1, 1) ^ o.Get(1, 1) ^ this->Get(1, 2) ^ o.Get(2, 1) ^ this->Get(1, 3) ^ o.Get(3, 1); + m.Get(1, 2) = this->Get(1, 0) ^ o.Get(0, 2) ^ this->Get(1, 1) ^ o.Get(1, 2) ^ this->Get(1, 2) ^ o.Get(2, 2) ^ this->Get(1, 3) ^ o.Get(3, 2); + m.Get(1, 3) = this->Get(1, 0) ^ o.Get(0, 3) ^ this->Get(1, 1) ^ o.Get(1, 3) ^ this->Get(1, 2) ^ o.Get(2, 3) ^ this->Get(1, 3) ^ o.Get(3, 3); + + m.Get(2, 0) = this->Get(2, 0) ^ o.Get(0, 0) ^ this->Get(2, 1) ^ o.Get(1, 0) ^ this->Get(2, 2) ^ o.Get(2, 0) ^ this->Get(2, 3) ^ o.Get(3, 0); + m.Get(2, 1) = this->Get(2, 0) ^ o.Get(0, 1) ^ this->Get(2, 1) ^ o.Get(1, 1) ^ this->Get(2, 2) ^ o.Get(2, 1) ^ this->Get(2, 3) ^ o.Get(3, 1); + m.Get(2, 2) = this->Get(2, 0) ^ o.Get(0, 2) ^ this->Get(2, 1) ^ o.Get(1, 2) ^ this->Get(2, 2) ^ o.Get(2, 2) ^ this->Get(2, 3) ^ o.Get(3, 2); + m.Get(2, 3) = this->Get(2, 0) ^ o.Get(0, 3) ^ this->Get(2, 1) ^ o.Get(1, 3) ^ this->Get(2, 2) ^ o.Get(2, 3) ^ this->Get(2, 3) ^ o.Get(3, 3); + + m.Get(3, 0) = this->Get(3, 0) ^ o.Get(0, 0) ^ this->Get(3, 1) ^ o.Get(1, 0) ^ this->Get(3, 2) ^ o.Get(2, 0) ^ this->Get(3, 3) ^ o.Get(3, 0); + m.Get(3, 1) = this->Get(3, 0) ^ o.Get(0, 1) ^ this->Get(3, 1) ^ o.Get(1, 1) ^ this->Get(3, 2) ^ o.Get(2, 1) ^ this->Get(3, 3) ^ o.Get(3, 1); + m.Get(3, 2) = this->Get(3, 0) ^ o.Get(0, 2) ^ this->Get(3, 1) ^ o.Get(1, 2) ^ this->Get(3, 2) ^ o.Get(2, 2) ^ this->Get(3, 3) ^ o.Get(3, 2); + m.Get(3, 3) = this->Get(3, 0) ^ o.Get(0, 3) ^ this->Get(3, 1) ^ o.Get(1, 3) ^ this->Get(3, 2) ^ o.Get(2, 3) ^ this->Get(3, 3) ^ o.Get(3, 3); + + return m; + } + + const std::uint32_t& BlockMatrix::Get(const std::uint8_t row, const std::uint8_t column) const { + return data[column*4 + row]; + } + + std::uint32_t& BlockMatrix::Get(const std::uint8_t row, const std::uint8_t column){ + return data[column*4 + row]; + } + + bool BlockMatrix::operator==(const BlockMatrix& other) const { + return data == other.data; + } + + bool BlockMatrix::operator!=(const BlockMatrix& other) const { + return data != other.data; + } +} + diff --git a/GCryptLib/src/Feistel.cpp b/GCryptLib/src/Feistel.cpp index 9ac75da..31d916d 100644 --- a/GCryptLib/src/Feistel.cpp +++ b/GCryptLib/src/Feistel.cpp @@ -1,6 +1,7 @@ #include #include "GCrypt/Feistel.h" #include "GCrypt/Util.h" +#include "GCrypt/BlockMatrix.h" #include "GCrypt/Config.h" namespace Leonetienne::GCrypt { @@ -69,8 +70,8 @@ namespace Leonetienne::GCrypt { // Shift to left by 1 m_expanded = Shiftl(m_expanded, 1); - // Xor with key - m_expanded ^= key; + // Matrix-mult with key + m_expanded = (BlockMatrix(m_expanded) * BlockMatrix(key)).ToBlock(); // Non-linearly apply subsitution boxes std::stringstream ss; From 939df4731bc7c8a608c58afb8a509013e8bbee1a Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Tue, 24 May 2022 01:02:06 +0200 Subject: [PATCH 034/110] [Progress:] Completely re-done Block class to not use bitsets, and provide custom operators. --- GCryptLib/include/GCrypt/Block.h | 120 ++++++++- GCryptLib/include/GCrypt/BlockMatrix.h | 49 ---- GCryptLib/include/GCrypt/Version.h | 2 +- GCryptLib/src/Block.cpp | 220 +++++++++++++++ GCryptLib/src/BlockMatrix.cpp | 114 -------- GCryptLib/src/Feistel.cpp | 27 +- GCryptLib/src/GPrng.cpp | 4 +- GCryptLib/src/Key.cpp | 2 +- GCryptLib/src/Util.cpp | 8 +- GCryptLib/test/Block.cpp | 251 ++++++++++++++++++ .../test/Password2Key_CollisionResistance.cpp | 13 +- 11 files changed, 619 insertions(+), 191 deletions(-) delete mode 100644 GCryptLib/include/GCrypt/BlockMatrix.h create mode 100644 GCryptLib/src/Block.cpp delete mode 100644 GCryptLib/src/BlockMatrix.cpp create mode 100644 GCryptLib/test/Block.cpp diff --git a/GCryptLib/include/GCrypt/Block.h b/GCryptLib/include/GCrypt/Block.h index db9552f..2184e75 100644 --- a/GCryptLib/include/GCrypt/Block.h +++ b/GCryptLib/include/GCrypt/Block.h @@ -1,12 +1,126 @@ #ifndef GCRYPT_BLOCK_H #define GCRYPT_BLOCK_H -#include "GCrypt/SecureBitset.h" -#include "GCrypt/Config.h" +#include +#include +#include +#include namespace Leonetienne::GCrypt { - typedef SecureBitset Block; + + /* This class represents a block of data, + * and provides functions to manipulate it + */ + class Block { + public: + //! Will constuct an uninitialized data block + Block(); + + //! Will construct this block from a string like "101010".. Length MUST be 512. + Block(const std::string& other); + + //! Copy-ctor + Block(const Block& other); + + ~Block(); + + //! Will construct this block from a string like "011101..". Length MUST be 512. + void FromString(const std::string& str); + + //! Will create a bitset-compatible string ("0101110..") representation + //! of this block. Length will always be 512. + std::string ToString() const; + + //! Will matrix-multiply two blocks together. + //! Since the matrices values are pretty much sudo-random, + //! they will most likely integer-overflow. + //! So see this as a one-way function. + Block MMul(const Block& other) const; + Block operator*(const Block& other) const; + + //! Will matrix-multiply two blocks together, + //! and directly write into this same block. + //! Since the matrices values are pretty much sudo-random, + //! they will most likely integer-overflow. + //! So see this as a one-way function. + void MMulInplace(const Block& other); + Block& operator*=(const Block& other); + + //! Will xor two blocks together + Block Xor(const Block& other) const; + //! Will xor two blocks together + Block operator^(const Block& other) const; + + //! Will xor two blocks together, inplace + void XorInplace(const Block& other); + //! Will xor two blocks together, inplace + Block& operator^=(const Block& other); + + // # TO BE IMPLEMENTED + //! Will shift rows upwards by n + void ShiftRowsUp(const std::size_t n); + + // # TO BE IMPLEMENTED + //! Will shift matrix rows downwards by n + void ShiftRowsDown(const std::size_t n); + + // # TO BE IMPLEMENTED + //! Will shift matrix columns to the left by n + void ShiftColumnsLeft(const std::size_t n); + + // # TO BE IMPLEMENTED + //! Will shift matrix columns to the right by n + void ShiftColumnsRight(const std::size_t n); + + // # TO BE IMPLEMENTED + //! Will shift array cells to the left by n + void ShiftCellsLeft(const std::size_t n); + + // # TO BE IMPLEMENTED + //! Will shift array cells to the right by n + void ShiftCellsRight(const std::size_t n); + + //! Will copy a block + Block& operator=(const Block& other); + + //! Will compare whether or not two blocks are equal + bool operator==(const Block& other) const; + //! Will compare whether or not two blocks are unequal + bool operator!=(const Block& other) const; + + //! Will zero all data + void Reset(); + + + //! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3) + std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column); + //! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3) + const std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column) const; + + //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) + std::uint32_t& Get(const std::uint8_t index); + + //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) + const std::uint32_t& Get(const std::uint8_t index) const; + + //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) + std::uint32_t& operator[](const std::uint8_t index); + + //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) + const std::uint32_t& operator[](const std::uint8_t index) const; + + static constexpr std::size_t CHUNK_SIZE = sizeof(std::uint32_t); + static constexpr std::size_t CHUNK_SIZE_BITS = CHUNK_SIZE * 8; + + friend std::ostream& operator<<(std::ostream& os, const Block& b); + + private: + + std::array data; + }; + } + #endif diff --git a/GCryptLib/include/GCrypt/BlockMatrix.h b/GCryptLib/include/GCrypt/BlockMatrix.h deleted file mode 100644 index 6f28a84..0000000 --- a/GCryptLib/include/GCrypt/BlockMatrix.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef GCRYPT_BLOCKMATRIX_H -#define GCRYPT_BLOCKMATRIX_H - -#include "GCrypt/Block.h" -#include -#include - -namespace Leonetienne::GCrypt { - - /* This class represents a block as a matrix, - * providing typical matrix operations - */ - class BlockMatrix { - public: - BlockMatrix(); - BlockMatrix(const Block& block); - BlockMatrix(const BlockMatrix& other); - - //! Will calculate the product of two matrices. - //! Since the matrices values are pretty much sudo-random, - //! they will most likely integer-overflow. - //! So see this as a one-way function. - BlockMatrix MMult(const BlockMatrix& other) const; - BlockMatrix operator*(const BlockMatrix& other) const; - - //! Will do a regular matrix-mult, but instead of - //! adding, and multiplying, all ints get xored. - BlockMatrix MXor(const BlockMatrix& other) const; - - bool operator==(const BlockMatrix& other) const; - bool operator!=(const BlockMatrix& other) const; - - void FromBlock(const Block& block); - Block ToBlock() const; - - private: - //! Returns items of data, indexed by 4x4 coordinates - std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column); - //! Returns items of data, indexed by 4x4 coordinates - const std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column) const; - - std::array data; - }; - -} - - -#endif - diff --git a/GCryptLib/include/GCrypt/Version.h b/GCryptLib/include/GCrypt/Version.h index 256c32b..e6e5330 100644 --- a/GCryptLib/include/GCrypt/Version.h +++ b/GCryptLib/include/GCrypt/Version.h @@ -1,7 +1,7 @@ #ifndef GCRYPT_VERSION_H #define GCRYPT_VERSION_H -#define GCRYPT_VERSION 0.231 +#define GCRYPT_VERSION 0.232 #endif diff --git a/GCryptLib/src/Block.cpp b/GCryptLib/src/Block.cpp new file mode 100644 index 0000000..e30d738 --- /dev/null +++ b/GCryptLib/src/Block.cpp @@ -0,0 +1,220 @@ +#include "GCrypt/Block.h" +#include "GCrypt/Config.h" +#include +#include +#include +#include + +namespace Leonetienne::GCrypt { + + Block::Block() { + } + + Block::Block(const std::string& str) { + FromString(str); + } + + Block::Block(const Block& other) { + data = other.data; + } + + void Block::FromString(const std::string& str) { + + assert(str.length() == BLOCK_SIZE); + + for (std::size_t i = 0; i < data.size(); i++) { + data[i] = std::bitset( + str.substr(i*CHUNK_SIZE_BITS, CHUNK_SIZE_BITS) + ).to_ulong(); + } + + return; + } + + std::string Block::ToString() const { + + std::stringstream ss; + for (std::size_t i = 0; i < data.size(); i++) { + ss << std::bitset(data[i]).to_string(); + } + return ss.str(); + } + + Block Block::MMul(const Block& o) const { + + Block m; + + m.Get(0, 0) = (this->Get(0, 0) * o.Get(0, 0)) + (this->Get(0, 1) * o.Get(1, 0)) + (this->Get(0, 2) * o.Get(2, 0)) + (this->Get(0, 3) * o.Get(3, 0)); + m.Get(0, 1) = (this->Get(0, 0) * o.Get(0, 1)) + (this->Get(0, 1) * o.Get(1, 1)) + (this->Get(0, 2) * o.Get(2, 1)) + (this->Get(0, 3) * o.Get(3, 1)); + m.Get(0, 2) = (this->Get(0, 0) * o.Get(0, 2)) + (this->Get(0, 1) * o.Get(1, 2)) + (this->Get(0, 2) * o.Get(2, 2)) + (this->Get(0, 3) * o.Get(3, 2)); + m.Get(0, 3) = (this->Get(0, 0) * o.Get(0, 3)) + (this->Get(0, 1) * o.Get(1, 3)) + (this->Get(0, 2) * o.Get(2, 3)) + (this->Get(0, 3) * o.Get(3, 3)); + + m.Get(1, 0) = (this->Get(1, 0) * o.Get(0, 0)) + (this->Get(1, 1) * o.Get(1, 0)) + (this->Get(1, 2) * o.Get(2, 0)) + (this->Get(1, 3) * o.Get(3, 0)); + m.Get(1, 1) = (this->Get(1, 0) * o.Get(0, 1)) + (this->Get(1, 1) * o.Get(1, 1)) + (this->Get(1, 2) * o.Get(2, 1)) + (this->Get(1, 3) * o.Get(3, 1)); + m.Get(1, 2) = (this->Get(1, 0) * o.Get(0, 2)) + (this->Get(1, 1) * o.Get(1, 2)) + (this->Get(1, 2) * o.Get(2, 2)) + (this->Get(1, 3) * o.Get(3, 2)); + m.Get(1, 3) = (this->Get(1, 0) * o.Get(0, 3)) + (this->Get(1, 1) * o.Get(1, 3)) + (this->Get(1, 2) * o.Get(2, 3)) + (this->Get(1, 3) * o.Get(3, 3)); + + m.Get(2, 0) = (this->Get(2, 0) * o.Get(0, 0)) + (this->Get(2, 1) * o.Get(1, 0)) + (this->Get(2, 2) * o.Get(2, 0)) + (this->Get(2, 3) * o.Get(3, 0)); + m.Get(2, 1) = (this->Get(2, 0) * o.Get(0, 1)) + (this->Get(2, 1) * o.Get(1, 1)) + (this->Get(2, 2) * o.Get(2, 1)) + (this->Get(2, 3) * o.Get(3, 1)); + m.Get(2, 2) = (this->Get(2, 0) * o.Get(0, 2)) + (this->Get(2, 1) * o.Get(1, 2)) + (this->Get(2, 2) * o.Get(2, 2)) + (this->Get(2, 3) * o.Get(3, 2)); + m.Get(2, 3) = (this->Get(2, 0) * o.Get(0, 3)) + (this->Get(2, 1) * o.Get(1, 3)) + (this->Get(2, 2) * o.Get(2, 3)) + (this->Get(2, 3) * o.Get(3, 3)); + + m.Get(3, 0) = (this->Get(3, 0) * o.Get(0, 0)) + (this->Get(3, 1) * o.Get(1, 0)) + (this->Get(3, 2) * o.Get(2, 0)) + (this->Get(3, 3) * o.Get(3, 0)); + m.Get(3, 1) = (this->Get(3, 0) * o.Get(0, 1)) + (this->Get(3, 1) * o.Get(1, 1)) + (this->Get(3, 2) * o.Get(2, 1)) + (this->Get(3, 3) * o.Get(3, 1)); + m.Get(3, 2) = (this->Get(3, 0) * o.Get(0, 2)) + (this->Get(3, 1) * o.Get(1, 2)) + (this->Get(3, 2) * o.Get(2, 2)) + (this->Get(3, 3) * o.Get(3, 2)); + m.Get(3, 3) = (this->Get(3, 0) * o.Get(0, 3)) + (this->Get(3, 1) * o.Get(1, 3)) + (this->Get(3, 2) * o.Get(2, 3)) + (this->Get(3, 3) * o.Get(3, 3)); + + return m; + } + + Block Block::operator*(const Block& other) const { + return this->MMul(other); + } + + void Block::MMulInplace(const Block& o) { + + Block m = *this; + + this->Get(0, 0) = (m.Get(0, 0) * o.Get(0, 0)) + (m.Get(0, 1) * o.Get(1, 0)) + (m.Get(0, 2) * o.Get(2, 0)) + (m.Get(0, 3) * o.Get(3, 0)); + this->Get(0, 1) = (m.Get(0, 0) * o.Get(0, 1)) + (m.Get(0, 1) * o.Get(1, 1)) + (m.Get(0, 2) * o.Get(2, 1)) + (m.Get(0, 3) * o.Get(3, 1)); + this->Get(0, 2) = (m.Get(0, 0) * o.Get(0, 2)) + (m.Get(0, 1) * o.Get(1, 2)) + (m.Get(0, 2) * o.Get(2, 2)) + (m.Get(0, 3) * o.Get(3, 2)); + this->Get(0, 3) = (m.Get(0, 0) * o.Get(0, 3)) + (m.Get(0, 1) * o.Get(1, 3)) + (m.Get(0, 2) * o.Get(2, 3)) + (m.Get(0, 3) * o.Get(3, 3)); + + this->Get(1, 0) = (m.Get(1, 0) * o.Get(0, 0)) + (m.Get(1, 1) * o.Get(1, 0)) + (m.Get(1, 2) * o.Get(2, 0)) + (m.Get(1, 3) * o.Get(3, 0)); + this->Get(1, 1) = (m.Get(1, 0) * o.Get(0, 1)) + (m.Get(1, 1) * o.Get(1, 1)) + (m.Get(1, 2) * o.Get(2, 1)) + (m.Get(1, 3) * o.Get(3, 1)); + this->Get(1, 2) = (m.Get(1, 0) * o.Get(0, 2)) + (m.Get(1, 1) * o.Get(1, 2)) + (m.Get(1, 2) * o.Get(2, 2)) + (m.Get(1, 3) * o.Get(3, 2)); + this->Get(1, 3) = (m.Get(1, 0) * o.Get(0, 3)) + (m.Get(1, 1) * o.Get(1, 3)) + (m.Get(1, 2) * o.Get(2, 3)) + (m.Get(1, 3) * o.Get(3, 3)); + + this->Get(2, 0) = (m.Get(2, 0) * o.Get(0, 0)) + (m.Get(2, 1) * o.Get(1, 0)) + (m.Get(2, 2) * o.Get(2, 0)) + (m.Get(2, 3) * o.Get(3, 0)); + this->Get(2, 1) = (m.Get(2, 0) * o.Get(0, 1)) + (m.Get(2, 1) * o.Get(1, 1)) + (m.Get(2, 2) * o.Get(2, 1)) + (m.Get(2, 3) * o.Get(3, 1)); + this->Get(2, 2) = (m.Get(2, 0) * o.Get(0, 2)) + (m.Get(2, 1) * o.Get(1, 2)) + (m.Get(2, 2) * o.Get(2, 2)) + (m.Get(2, 3) * o.Get(3, 2)); + this->Get(2, 3) = (m.Get(2, 0) * o.Get(0, 3)) + (m.Get(2, 1) * o.Get(1, 3)) + (m.Get(2, 2) * o.Get(2, 3)) + (m.Get(2, 3) * o.Get(3, 3)); + + this->Get(3, 0) = (m.Get(3, 0) * o.Get(0, 0)) + (m.Get(3, 1) * o.Get(1, 0)) + (m.Get(3, 2) * o.Get(2, 0)) + (m.Get(3, 3) * o.Get(3, 0)); + this->Get(3, 1) = (m.Get(3, 0) * o.Get(0, 1)) + (m.Get(3, 1) * o.Get(1, 1)) + (m.Get(3, 2) * o.Get(2, 1)) + (m.Get(3, 3) * o.Get(3, 1)); + this->Get(3, 2) = (m.Get(3, 0) * o.Get(0, 2)) + (m.Get(3, 1) * o.Get(1, 2)) + (m.Get(3, 2) * o.Get(2, 2)) + (m.Get(3, 3) * o.Get(3, 2)); + this->Get(3, 3) = (m.Get(3, 0) * o.Get(0, 3)) + (m.Get(3, 1) * o.Get(1, 3)) + (m.Get(3, 2) * o.Get(2, 3)) + (m.Get(3, 3) * o.Get(3, 3)); + + return; + } + + Block& Block::operator*=(const Block& other) { + MMulInplace(other); + return *this; + } + + Block Block::Xor(const Block& other) const { + + Block m; + for (std::size_t i = 0; i < data.size(); i++) { + m.Get(i) = this->Get(i) ^ other.Get(i); + } + return m; + } + + Block Block::operator^(const Block& other) const { + return Xor(other); + } + + void Block::XorInplace(const Block& other) { + for (std::size_t i = 0; i < data.size(); i++) { + this->Get(i) ^= other.Get(i); + } + return; + } + + Block& Block::operator^=(const Block& other) { + XorInplace(other); + return *this; + } + + void ShiftRowsUp(const std::size_t n) { + // TO BE IMPLEMENTED + } + + void ShiftRowsDown(const std::size_t n) { + // TO BE IMPLEMENTED + } + + void ShiftColumnsLeft(const std::size_t n) { + // TO BE IMPLEMENTED + } + + void ShiftColumnsRight(const std::size_t n) { + // TO BE IMPLEMENTED + } + + void ShiftCellsLeft(const std::size_t n) { + // TO BE IMPLEMENTED + } + + void ShiftCellsRight(const std::size_t n) { + // TO BE IMPLEMENTED + } + + Block& Block::operator=(const Block& other) { + data = other.data; + return *this; + } + + std::uint32_t& Block::Get(const std::uint8_t row, const std::uint8_t column){ + return data[column*4 + row]; + } + + const std::uint32_t& Block::Get(const std::uint8_t row, const std::uint8_t column) const { + return data[column*4 + row]; + } + + std::uint32_t& Block::Get(const std::uint8_t index) { + return data[index]; + } + + const std::uint32_t& Block::Get(const std::uint8_t index) const { + return data[index]; + } + + std::uint32_t& Block::operator[](const std::uint8_t index) { + return data[index]; + } + + const std::uint32_t& Block::operator[](const std::uint8_t index) const { + return data[index]; + } + + bool Block::operator==(const Block& other) const { + return data == other.data; + } + + bool Block::operator!=(const Block& other) const { + return data != other.data; + } + + std::ostream& operator<<(std::ostream& os, const Block& b) { + for (std::size_t i = 0; i < b.data.size(); i++) { + os << std::bitset(b.data[i]).to_string(); + } + return os; + } + +#if defined _WIN32 || defined _WIN64 +#pragma optimize("", off ) +#elif defined __GNUG__ +#pragma GCC push_options +#pragma GCC optimize ("O0") +#endif + Block::~Block() { + Reset(); + } + + void Block::Reset() { + memset(data.data(), 0, CHUNK_SIZE*data.size()); + return; + } + +#if defined _WIN32 || defined _WIN64 +#pragma optimize("", on ) +#elif defined __GNUG__ +#pragma GCC pop_options +#endif +} + diff --git a/GCryptLib/src/BlockMatrix.cpp b/GCryptLib/src/BlockMatrix.cpp deleted file mode 100644 index e1915c9..0000000 --- a/GCryptLib/src/BlockMatrix.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "GCrypt/BlockMatrix.h" -#include - -namespace Leonetienne::GCrypt { - - BlockMatrix::BlockMatrix() { - } - - BlockMatrix::BlockMatrix(const Block& block) { - FromBlock(block); - } - - BlockMatrix::BlockMatrix(const BlockMatrix& other) { - data = other.data; - } - - void BlockMatrix::FromBlock(const Block& block) { - - const std::string blockstr = block.to_string(); - constexpr std::size_t cellSize = sizeof(std::uint32_t)*8; - - for (std::size_t i = 0; i < 16; i++) { - data[i] = std::bitset(blockstr.substr(i*cellSize, cellSize)).to_ulong(); - } - - return; - } - - Block BlockMatrix::ToBlock() const { - - std::stringstream ss; - constexpr std::size_t cellSize = sizeof(std::uint32_t)*8; - - for (std::size_t i = 0; i < 16; i++) { - ss << std::bitset(data[i]).to_string(); - } - return Block(ss.str()); - } - - BlockMatrix BlockMatrix::MMult(const BlockMatrix& o) const { - - BlockMatrix m; - - m.Get(0, 0) = (this->Get(0, 0) * o.Get(0, 0)) + (this->Get(0, 1) * o.Get(1, 0)) + (this->Get(0, 2) * o.Get(2, 0)) + (this->Get(0, 3) * o.Get(3, 0)); - m.Get(0, 1) = (this->Get(0, 0) * o.Get(0, 1)) + (this->Get(0, 1) * o.Get(1, 1)) + (this->Get(0, 2) * o.Get(2, 1)) + (this->Get(0, 3) * o.Get(3, 1)); - m.Get(0, 2) = (this->Get(0, 0) * o.Get(0, 2)) + (this->Get(0, 1) * o.Get(1, 2)) + (this->Get(0, 2) * o.Get(2, 2)) + (this->Get(0, 3) * o.Get(3, 2)); - m.Get(0, 3) = (this->Get(0, 0) * o.Get(0, 3)) + (this->Get(0, 1) * o.Get(1, 3)) + (this->Get(0, 2) * o.Get(2, 3)) + (this->Get(0, 3) * o.Get(3, 3)); - - m.Get(1, 0) = (this->Get(1, 0) * o.Get(0, 0)) + (this->Get(1, 1) * o.Get(1, 0)) + (this->Get(1, 2) * o.Get(2, 0)) + (this->Get(1, 3) * o.Get(3, 0)); - m.Get(1, 1) = (this->Get(1, 0) * o.Get(0, 1)) + (this->Get(1, 1) * o.Get(1, 1)) + (this->Get(1, 2) * o.Get(2, 1)) + (this->Get(1, 3) * o.Get(3, 1)); - m.Get(1, 2) = (this->Get(1, 0) * o.Get(0, 2)) + (this->Get(1, 1) * o.Get(1, 2)) + (this->Get(1, 2) * o.Get(2, 2)) + (this->Get(1, 3) * o.Get(3, 2)); - m.Get(1, 3) = (this->Get(1, 0) * o.Get(0, 3)) + (this->Get(1, 1) * o.Get(1, 3)) + (this->Get(1, 2) * o.Get(2, 3)) + (this->Get(1, 3) * o.Get(3, 3)); - - m.Get(2, 0) = (this->Get(2, 0) * o.Get(0, 0)) + (this->Get(2, 1) * o.Get(1, 0)) + (this->Get(2, 2) * o.Get(2, 0)) + (this->Get(2, 3) * o.Get(3, 0)); - m.Get(2, 1) = (this->Get(2, 0) * o.Get(0, 1)) + (this->Get(2, 1) * o.Get(1, 1)) + (this->Get(2, 2) * o.Get(2, 1)) + (this->Get(2, 3) * o.Get(3, 1)); - m.Get(2, 2) = (this->Get(2, 0) * o.Get(0, 2)) + (this->Get(2, 1) * o.Get(1, 2)) + (this->Get(2, 2) * o.Get(2, 2)) + (this->Get(2, 3) * o.Get(3, 2)); - m.Get(2, 3) = (this->Get(2, 0) * o.Get(0, 3)) + (this->Get(2, 1) * o.Get(1, 3)) + (this->Get(2, 2) * o.Get(2, 3)) + (this->Get(2, 3) * o.Get(3, 3)); - - m.Get(3, 0) = (this->Get(3, 0) * o.Get(0, 0)) + (this->Get(3, 1) * o.Get(1, 0)) + (this->Get(3, 2) * o.Get(2, 0)) + (this->Get(3, 3) * o.Get(3, 0)); - m.Get(3, 1) = (this->Get(3, 0) * o.Get(0, 1)) + (this->Get(3, 1) * o.Get(1, 1)) + (this->Get(3, 2) * o.Get(2, 1)) + (this->Get(3, 3) * o.Get(3, 1)); - m.Get(3, 2) = (this->Get(3, 0) * o.Get(0, 2)) + (this->Get(3, 1) * o.Get(1, 2)) + (this->Get(3, 2) * o.Get(2, 2)) + (this->Get(3, 3) * o.Get(3, 2)); - m.Get(3, 3) = (this->Get(3, 0) * o.Get(0, 3)) + (this->Get(3, 1) * o.Get(1, 3)) + (this->Get(3, 2) * o.Get(2, 3)) + (this->Get(3, 3) * o.Get(3, 3)); - - return m; - } - - BlockMatrix BlockMatrix::operator*(const BlockMatrix& other) const { - return this->MMult(other); - } - - BlockMatrix BlockMatrix::MXor(const BlockMatrix& o) const { - - BlockMatrix m; - - m.Get(0, 0) = this->Get(0, 0) ^ o.Get(0, 0) ^ this->Get(0, 1) ^ o.Get(1, 0) ^ this->Get(0, 2) ^ o.Get(2, 0) ^ this->Get(0, 3) ^ o.Get(3, 0); - m.Get(0, 1) = this->Get(0, 0) ^ o.Get(0, 1) ^ this->Get(0, 1) ^ o.Get(1, 1) ^ this->Get(0, 2) ^ o.Get(2, 1) ^ this->Get(0, 3) ^ o.Get(3, 1); - m.Get(0, 2) = this->Get(0, 0) ^ o.Get(0, 2) ^ this->Get(0, 1) ^ o.Get(1, 2) ^ this->Get(0, 2) ^ o.Get(2, 2) ^ this->Get(0, 3) ^ o.Get(3, 2); - m.Get(0, 3) = this->Get(0, 0) ^ o.Get(0, 3) ^ this->Get(0, 1) ^ o.Get(1, 3) ^ this->Get(0, 2) ^ o.Get(2, 3) ^ this->Get(0, 3) ^ o.Get(3, 3); - - m.Get(1, 0) = this->Get(1, 0) ^ o.Get(0, 0) ^ this->Get(1, 1) ^ o.Get(1, 0) ^ this->Get(1, 2) ^ o.Get(2, 0) ^ this->Get(1, 3) ^ o.Get(3, 0); - m.Get(1, 1) = this->Get(1, 0) ^ o.Get(0, 1) ^ this->Get(1, 1) ^ o.Get(1, 1) ^ this->Get(1, 2) ^ o.Get(2, 1) ^ this->Get(1, 3) ^ o.Get(3, 1); - m.Get(1, 2) = this->Get(1, 0) ^ o.Get(0, 2) ^ this->Get(1, 1) ^ o.Get(1, 2) ^ this->Get(1, 2) ^ o.Get(2, 2) ^ this->Get(1, 3) ^ o.Get(3, 2); - m.Get(1, 3) = this->Get(1, 0) ^ o.Get(0, 3) ^ this->Get(1, 1) ^ o.Get(1, 3) ^ this->Get(1, 2) ^ o.Get(2, 3) ^ this->Get(1, 3) ^ o.Get(3, 3); - - m.Get(2, 0) = this->Get(2, 0) ^ o.Get(0, 0) ^ this->Get(2, 1) ^ o.Get(1, 0) ^ this->Get(2, 2) ^ o.Get(2, 0) ^ this->Get(2, 3) ^ o.Get(3, 0); - m.Get(2, 1) = this->Get(2, 0) ^ o.Get(0, 1) ^ this->Get(2, 1) ^ o.Get(1, 1) ^ this->Get(2, 2) ^ o.Get(2, 1) ^ this->Get(2, 3) ^ o.Get(3, 1); - m.Get(2, 2) = this->Get(2, 0) ^ o.Get(0, 2) ^ this->Get(2, 1) ^ o.Get(1, 2) ^ this->Get(2, 2) ^ o.Get(2, 2) ^ this->Get(2, 3) ^ o.Get(3, 2); - m.Get(2, 3) = this->Get(2, 0) ^ o.Get(0, 3) ^ this->Get(2, 1) ^ o.Get(1, 3) ^ this->Get(2, 2) ^ o.Get(2, 3) ^ this->Get(2, 3) ^ o.Get(3, 3); - - m.Get(3, 0) = this->Get(3, 0) ^ o.Get(0, 0) ^ this->Get(3, 1) ^ o.Get(1, 0) ^ this->Get(3, 2) ^ o.Get(2, 0) ^ this->Get(3, 3) ^ o.Get(3, 0); - m.Get(3, 1) = this->Get(3, 0) ^ o.Get(0, 1) ^ this->Get(3, 1) ^ o.Get(1, 1) ^ this->Get(3, 2) ^ o.Get(2, 1) ^ this->Get(3, 3) ^ o.Get(3, 1); - m.Get(3, 2) = this->Get(3, 0) ^ o.Get(0, 2) ^ this->Get(3, 1) ^ o.Get(1, 2) ^ this->Get(3, 2) ^ o.Get(2, 2) ^ this->Get(3, 3) ^ o.Get(3, 2); - m.Get(3, 3) = this->Get(3, 0) ^ o.Get(0, 3) ^ this->Get(3, 1) ^ o.Get(1, 3) ^ this->Get(3, 2) ^ o.Get(2, 3) ^ this->Get(3, 3) ^ o.Get(3, 3); - - return m; - } - - const std::uint32_t& BlockMatrix::Get(const std::uint8_t row, const std::uint8_t column) const { - return data[column*4 + row]; - } - - std::uint32_t& BlockMatrix::Get(const std::uint8_t row, const std::uint8_t column){ - return data[column*4 + row]; - } - - bool BlockMatrix::operator==(const BlockMatrix& other) const { - return data == other.data; - } - - bool BlockMatrix::operator!=(const BlockMatrix& other) const { - return data != other.data; - } -} - diff --git a/GCryptLib/src/Feistel.cpp b/GCryptLib/src/Feistel.cpp index 31d916d..565d54a 100644 --- a/GCryptLib/src/Feistel.cpp +++ b/GCryptLib/src/Feistel.cpp @@ -68,25 +68,27 @@ namespace Leonetienne::GCrypt { Block m_expanded = ExpansionFunction(m); // Shift to left by 1 - m_expanded = Shiftl(m_expanded, 1); + //m_expanded = Shiftl(m_expanded, 1); + m_expanded = (m_expanded); // Matrix-mult with key - m_expanded = (BlockMatrix(m_expanded) * BlockMatrix(key)).ToBlock(); + m_expanded *= key; // Non-linearly apply subsitution boxes std::stringstream ss; - const std::string m_str = m_expanded.to_string(); + const std::string m_str = m_expanded.ToString(); for (std::size_t i = 0; i < BLOCK_SIZE; i += 4) { ss << SBox(m_str.substr(i, 4)); } m_expanded = Block(ss.str()); // Return the compressed version, shifted by 3 - return Shiftl(CompressionFunction(m_expanded), 3); + //return Shiftl(CompressionFunction(m_expanded), 3); + return (CompressionFunction(m_expanded)); } std::pair Feistel::FeistelSplit(const Block& block) { - const std::string bits = block.to_string(); + const std::string bits = block.ToString(); Halfblock l(bits.substr(0, bits.size() / 2)); Halfblock r(bits.substr(bits.size() / 2)); @@ -119,7 +121,7 @@ namespace Leonetienne::GCrypt { Halfblock Feistel::CompressionFunction(const Block& block) { std::stringstream ss; - const std::string bits = block.to_string(); + const std::string bits = block.ToString(); std::unordered_map compressionMap; compressionMap["0000"] = "10"; @@ -184,7 +186,8 @@ namespace Leonetienne::GCrypt { // Compress- substitute, and expand the seed key to form the initial and the second-initial round key // This action is non-linear and irreversible, and thus strenghtens security. Halfblock compressedSeed1 = CompressionFunction(seedKey); - Halfblock compressedSeed2 = CompressionFunction(Shiftl(seedKey, 1)); // Shifting one key by 1 will result in a completely different compression + //Halfblock compressedSeed2 = CompressionFunction(Shiftl(seedKey, 1)); // Shifting one key by 1 will result in a completely different compression + Halfblock compressedSeed2 = CompressionFunction((seedKey)); // Shifting one key by 1 will result in a completely different compression // To add further confusion, let's shift seed1 by 1 aswell (after compression, but before substitution) // but only if the total number of bits set are a multiple of 3 @@ -192,10 +195,11 @@ namespace Leonetienne::GCrypt { const std::size_t setBits1 = compressedSeed1.count(); if (setBits1 % 4 == 0) { - compressedSeed1 = Shiftr(compressedSeed1, 1); + //compressedSeed1 = Shiftr(compressedSeed1, 1); + compressedSeed1 = (compressedSeed1); } else if (setBits1 % 3 == 0) { - compressedSeed1 = Shiftl(compressedSeed1, 1); + compressedSeed1 = (compressedSeed1); } // Now apply substitution @@ -224,7 +228,8 @@ namespace Leonetienne::GCrypt { Block newKey = roundKeys[i - 1]; // Shift to left by how many bits are set, modulo 8 - newKey = Shiftl(newKey, newKey.count() % 8); // This action is irreversible + //newKey = Shiftl(newKey, newKey.count() % 8); // This action is irreversible + newKey = (newKey); // This action is irreversible // Split into two halfblocks, // apply F() to one halfblock with rk[i-2], @@ -255,7 +260,7 @@ namespace Leonetienne::GCrypt { #endif void Feistel::ZeroKeyMemory() { for (Key& key : roundKeys) { - key.reset(); + key.Reset(); } return; diff --git a/GCryptLib/src/GPrng.cpp b/GCryptLib/src/GPrng.cpp index 371761d..a89b9cd 100644 --- a/GCryptLib/src/GPrng.cpp +++ b/GCryptLib/src/GPrng.cpp @@ -52,14 +52,14 @@ namespace Leonetienne::GCrypt { // Slurp up the rest of the current block std::stringstream ss; const std::size_t bitsLeft = BLOCK_SIZE - nextBit; - ss << hasher.GetHashsum().to_string().substr(nextBit, bitsLeft); + ss << hasher.GetHashsum().ToString().substr(nextBit, bitsLeft); // Now we have to advance to the next block AdvanceBlock(); // Now, grab the remaining bits const std::size_t remainingBits = BLOCK_SIZE - bitsLeft; - ss << hasher.GetHashsum().to_string().substr(0, remainingBits); + ss << hasher.GetHashsum().ToString().substr(0, remainingBits); // Assert that we have the correct number of bits assert(ss.str().length() == BLOCK_SIZE); diff --git a/GCryptLib/src/Key.cpp b/GCryptLib/src/Key.cpp index c353d9d..0356b0b 100644 --- a/GCryptLib/src/Key.cpp +++ b/GCryptLib/src/Key.cpp @@ -67,7 +67,7 @@ namespace Leonetienne::GCrypt { void Key::WriteToFile(const std::string& path) { // Transform key to bytes - const std::string keybytes = BitsToBytes(to_string()); + const std::string keybytes = BitsToBytes(ToString()); // Create an ofilestream std::ofstream ofs(path, std::ios::out | std::ios::binary); diff --git a/GCryptLib/src/Util.cpp b/GCryptLib/src/Util.cpp index 21a98e0..9c315e5 100644 --- a/GCryptLib/src/Util.cpp +++ b/GCryptLib/src/Util.cpp @@ -53,7 +53,7 @@ namespace Leonetienne::GCrypt { std::string BitblockToBytes(const Block& bits) { std::stringstream ss; - const std::string bitstring = bits.to_string(); + const std::string bitstring = bits.ToString(); for (std::size_t i = 0; i < BLOCK_SIZE; i += 8) { ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong(); @@ -97,7 +97,7 @@ namespace Leonetienne::GCrypt { std::string BitblockToHexstring(const Block& b) { std::stringstream ss; const std::string charset = "0123456789abcdef"; - const std::string bstr = b.to_string(); + const std::string bstr = b.ToString(); for (std::size_t i = 0; i < bstr.size(); i += 4) { ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()]; @@ -139,7 +139,7 @@ namespace Leonetienne::GCrypt { } // Append to our bits - ss << std::bitset<4>(value); + ss << std::bitset<4>(value).to_string(); } return Block(ss.str()); @@ -166,7 +166,7 @@ namespace Leonetienne::GCrypt { } // Append to our bits - ss << std::bitset<4>(value); + ss << std::bitset<4>(value).to_string(); } return ss.str(); diff --git a/GCryptLib/test/Block.cpp b/GCryptLib/test/Block.cpp new file mode 100644 index 0000000..faa715e --- /dev/null +++ b/GCryptLib/test/Block.cpp @@ -0,0 +1,251 @@ +#include +#include "Catch2.h" +#include +#include +#include + +using namespace Leonetienne::GCrypt; + +// Tests that writing and retrieving data from a block works +TEST_CASE(__FILE__"/Write-read", "[Block]") { + + // Setup + Block block; + + // Exercise + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i * 1024; + } + + // Verify + for (std::size_t i = 0; i < 16; i++) { + REQUIRE(block.Get(i) == i * 1024); + } +} + +// Tests that the copy constructor works +TEST_CASE(__FILE__"/CCtor", "[Block]") { + + // Setup + Block block; + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i * 1024; + } + + // Exercise + Block block2(block); + + // Verify + for (std::size_t i = 0; i < 16; i++) { + REQUIRE(block2.Get(i) == i * 1024); + } +} + +// Tests that operator= works +TEST_CASE(__FILE__"/operator=", "[Block]") { + + // Setup + Block block; + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i * 1024; + } + + // Exercise + Block block2; + block2 = block; + + // Verify + for (std::size_t i = 0; i < 16; i++) { + REQUIRE(block2.Get(i) == i * 1024); + } +} + +// Tests that converting to, and from, strings works +TEST_CASE(__FILE__"/StringConversion", "[Block]") { + + // Setup + srand(time(0)); + std::stringstream ss; + + for (std::size_t i = 0; i < 512; i++) { + ss << (rand()%2 == 0 ? '1' : '0'); + } + + // Exercise + Block block(ss.str()); + + // Verify + REQUIRE(block.ToString() == ss.str()); +} + +// Tests that operator* is the same as *= +TEST_CASE(__FILE__"/operator*&=", "[Block]") { + + // Setup + Block block1; + for (std::size_t i = 0; i < 16; i++) { + block1.Get(i) = i * 1024; + } + + Block block2; + for (std::size_t i = 0; i < 16; i++) { + block2.Get(i) = i * 1024 * 2; + } + + // Exercise + Block block3 = block1 * block2; + block1 *= block2; + + // Verify + REQUIRE(block1 == block3); +} + +// Tests that operator^ (xor) works +TEST_CASE(__FILE__"/xor", "[Block]") { + + // Setup + Block block; + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i * 1024; + } + + Block xorRH; + for (std::size_t i = 0; i < 16; i++) { + xorRH.Get(i) = i * 5099; + } + + // Exercise + Block result = block ^ xorRH; + + Block manualResult; + for (std::size_t i = 0; i < 16; i++) { + manualResult.Get(i) = (i * 1024) ^ (i * 5099); + } + + // Verify + REQUIRE(result == manualResult); +} + +// Tests that operator^ is the same as ^= +TEST_CASE(__FILE__"/operator^&=", "[Block]") { + + // Setup + Block block1; + for (std::size_t i = 0; i < 16; i++) { + block1.Get(i) = i * 1024; + } + + Block block2; + for (std::size_t i = 0; i < 16; i++) { + block2.Get(i) = i * 5099 * 2; + } + + // Exercise + Block block3 = block1 ^ block2; + block1 ^= block2; + + // Verify + REQUIRE(block1 == block3); +} + +// Tests that operator== works correctly +TEST_CASE(__FILE__"/operator==", "[Block]") { + + // Setup + Block block; + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i * 1024; + } + + SECTION("Expected true") { + Block sameBlock; + for (std::size_t i = 0; i < 16; i++) { + sameBlock.Get(i) = i * 1024; + } + + REQUIRE(block == sameBlock); + } + + SECTION("Expected false") { + Block otherBlock; + for (std::size_t i = 0; i < 16; i++) { + otherBlock.Get(i) = i * 1024 + 1; + } + + REQUIRE_FALSE(block == otherBlock); + } +} + +// Tests that operator!= works correctly +TEST_CASE(__FILE__"/operator!=", "[Block]") { + + // Setup + Block block; + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i * 1024; + } + + SECTION("Expected false") { + Block sameBlock; + for (std::size_t i = 0; i < 16; i++) { + sameBlock.Get(i) = i * 1024; + } + + REQUIRE_FALSE(block != sameBlock); + } + + SECTION("Expected true") { + Block otherBlock; + for (std::size_t i = 0; i < 16; i++) { + otherBlock.Get(i) = i * 1024 + 1; + } + + REQUIRE(block != otherBlock); + } +} + +// Tests that getting the data via the matrix accessor works +TEST_CASE(__FILE__"/matrix-accessor", "[Block]") { + + // Setup + Block block; + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i; + } + + // Exercise + REQUIRE(block.Get(0,0) == 0); + REQUIRE(block.Get(1,0) == 1); + REQUIRE(block.Get(2,0) == 2); + REQUIRE(block.Get(3,0) == 3); + REQUIRE(block.Get(0,1) == 4); + REQUIRE(block.Get(1,1) == 5); + REQUIRE(block.Get(2,1) == 6); + REQUIRE(block.Get(3,1) == 7); + REQUIRE(block.Get(0,2) == 8); + REQUIRE(block.Get(1,2) == 9); + REQUIRE(block.Get(2,2) == 10); + REQUIRE(block.Get(3,2) == 11); + REQUIRE(block.Get(0,3) == 12); + REQUIRE(block.Get(1,3) == 13); + REQUIRE(block.Get(2,3) == 14); + REQUIRE(block.Get(3,3) == 15); +} + +// Tests that the reset method works +TEST_CASE(__FILE__"/reset", "[Block]") { + + // Setup + Block block; + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i + 33; + } + + // Exercise + block.Reset(); + + // Verify + for (std::size_t i = 0; i < 16; i++) { + REQUIRE(block[i] == 0); + } +} diff --git a/GCryptLib/test/Password2Key_CollisionResistance.cpp b/GCryptLib/test/Password2Key_CollisionResistance.cpp index 19587c4..a2fe221 100644 --- a/GCryptLib/test/Password2Key_CollisionResistance.cpp +++ b/GCryptLib/test/Password2Key_CollisionResistance.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -59,7 +60,7 @@ TEST_CASE(__FILE__"/Password to key transformation collision resistance", "[Key // This will take a LONG while to execute though (about 2.5hrs on my machine), hence why it's set so low. constexpr std::size_t NUM_RUN_TESTS = 10; - std::unordered_map, std::string> keys; // + std::unordered_map keys; // // Try NUM_RUN_TESTS passwords const std::string charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; @@ -69,23 +70,23 @@ TEST_CASE(__FILE__"/Password to key transformation collision resistance", "[Key const std::string password = Base10_2_X(i, charset, 0); // Generate key - const std::bitset newKey = Key::FromPassword(password).Get(); + const std::string newKeyBits = Key::FromPassword(password).ToString(); // Check if this block is already in our map - if (keys.find(newKey) != keys.cend()) { + if (keys.find(newKeyBits) != keys.cend()) { std::cout << "Collision found between password \"" << password << "\" and \"" - << keys[newKey] + << keys[newKeyBits] << "\". The key is \"" - << newKey + << newKeyBits << "\"."; FAIL(); } // All good? Insert it into our map - keys[newKey] = password; + keys[newKeyBits] = password; } return; From fa47a48dae7e0ba1eb6a043e00fa34bf7c9159db Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Tue, 24 May 2022 01:05:45 +0200 Subject: [PATCH 035/110] Add comment --- GCryptLib/src/Block.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/GCryptLib/src/Block.cpp b/GCryptLib/src/Block.cpp index e30d738..6315c40 100644 --- a/GCryptLib/src/Block.cpp +++ b/GCryptLib/src/Block.cpp @@ -44,6 +44,8 @@ namespace Leonetienne::GCrypt { Block m; + // Maybe pre-calculate the 1d-index...? + m.Get(0, 0) = (this->Get(0, 0) * o.Get(0, 0)) + (this->Get(0, 1) * o.Get(1, 0)) + (this->Get(0, 2) * o.Get(2, 0)) + (this->Get(0, 3) * o.Get(3, 0)); m.Get(0, 1) = (this->Get(0, 0) * o.Get(0, 1)) + (this->Get(0, 1) * o.Get(1, 1)) + (this->Get(0, 2) * o.Get(2, 1)) + (this->Get(0, 3) * o.Get(3, 1)); m.Get(0, 2) = (this->Get(0, 0) * o.Get(0, 2)) + (this->Get(0, 1) * o.Get(1, 2)) + (this->Get(0, 2) * o.Get(2, 2)) + (this->Get(0, 3) * o.Get(3, 2)); @@ -75,6 +77,8 @@ namespace Leonetienne::GCrypt { Block m = *this; + // Maybe pre-calculate the 1d-index...? + this->Get(0, 0) = (m.Get(0, 0) * o.Get(0, 0)) + (m.Get(0, 1) * o.Get(1, 0)) + (m.Get(0, 2) * o.Get(2, 0)) + (m.Get(0, 3) * o.Get(3, 0)); this->Get(0, 1) = (m.Get(0, 0) * o.Get(0, 1)) + (m.Get(0, 1) * o.Get(1, 1)) + (m.Get(0, 2) * o.Get(2, 1)) + (m.Get(0, 3) * o.Get(3, 1)); this->Get(0, 2) = (m.Get(0, 0) * o.Get(0, 2)) + (m.Get(0, 1) * o.Get(1, 2)) + (m.Get(0, 2) * o.Get(2, 2)) + (m.Get(0, 3) * o.Get(3, 2)); From 83854e42cbdba17f7174f4544c655ecbed0281fa Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Tue, 24 May 2022 01:07:00 +0200 Subject: [PATCH 036/110] Fix blanklines in block.cpp --- GCryptLib/src/Block.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GCryptLib/src/Block.cpp b/GCryptLib/src/Block.cpp index 6315c40..0152541 100644 --- a/GCryptLib/src/Block.cpp +++ b/GCryptLib/src/Block.cpp @@ -214,11 +214,11 @@ namespace Leonetienne::GCrypt { memset(data.data(), 0, CHUNK_SIZE*data.size()); return; } - #if defined _WIN32 || defined _WIN64 #pragma optimize("", on ) #elif defined __GNUG__ #pragma GCC pop_options #endif + } From db0add6e6e9e68ccfa7d22c9391a31d3c6b05bc5 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Tue, 24 May 2022 21:41:49 +0200 Subject: [PATCH 037/110] Implemented remaining operands for block class --- GCryptLib/include/GCrypt/Block.h | 93 +++++--- GCryptLib/src/Block.cpp | 316 +++++++++++++++++++++++-- GCryptLib/src/Feistel.cpp | 1 - GCryptLib/test/Block.cpp | 384 +++++++++++++++++++++++++++++++ 4 files changed, 748 insertions(+), 46 deletions(-) diff --git a/GCryptLib/include/GCrypt/Block.h b/GCryptLib/include/GCrypt/Block.h index 2184e75..3fefbd5 100644 --- a/GCryptLib/include/GCrypt/Block.h +++ b/GCryptLib/include/GCrypt/Block.h @@ -35,8 +35,8 @@ namespace Leonetienne::GCrypt { //! Since the matrices values are pretty much sudo-random, //! they will most likely integer-overflow. //! So see this as a one-way function. - Block MMul(const Block& other) const; - Block operator*(const Block& other) const; + [[nodiscard]] Block MMul(const Block& other) const; + [[nodiscard]] Block operator*(const Block& other) const; //! Will matrix-multiply two blocks together, //! and directly write into this same block. @@ -47,67 +47,98 @@ namespace Leonetienne::GCrypt { Block& operator*=(const Block& other); //! Will xor two blocks together - Block Xor(const Block& other) const; + [[nodiscard]] Block Xor(const Block& other) const; //! Will xor two blocks together - Block operator^(const Block& other) const; + [[nodiscard]] Block operator^(const Block& other) const; //! Will xor two blocks together, inplace void XorInplace(const Block& other); //! Will xor two blocks together, inplace Block& operator^=(const Block& other); - // # TO BE IMPLEMENTED - //! Will shift rows upwards by n - void ShiftRowsUp(const std::size_t n); + //! Will add all the integer making up this block, one by one + [[nodiscard]] Block Add(const Block& other) const; + //! Will add all the integer making up this block, one by one + [[nodiscard]] Block operator+(const Block& other) const; - // # TO BE IMPLEMENTED - //! Will shift matrix rows downwards by n - void ShiftRowsDown(const std::size_t n); + //! Will add all the integer making up this block, one by one, inplace + void AddInplace(const Block& other); + //! Will add all the integer making up this block, one by one, inplace + Block& operator+=(const Block& other); - // # TO BE IMPLEMENTED - //! Will shift matrix columns to the left by n - void ShiftColumnsLeft(const std::size_t n); + //! Will subtract all the integer making up this block, one by one + [[nodiscard]] Block Sub(const Block& other) const; + //! Will subtract all the integer making up this block, one by one + [[nodiscard]] Block operator-(const Block& other) const; - // # TO BE IMPLEMENTED - //! Will shift matrix columns to the right by n - void ShiftColumnsRight(const std::size_t n); + //! Will subtract all the integer making up this block, one by one, inplace + void SubInplace(const Block& other); + //! Will subtract all the integer making up this block, one by one, inplace + Block& operator-=(const Block& other); - // # TO BE IMPLEMENTED - //! Will shift array cells to the left by n - void ShiftCellsLeft(const std::size_t n); + //! Will shift rows upwards by 1 + [[nodiscard]] Block ShiftRowsUp() const; - // # TO BE IMPLEMENTED - //! Will shift array cells to the right by n - void ShiftCellsRight(const std::size_t n); + //! Will shift rows upwards by 1 + void ShiftRowsUpInplace(); + + //! Will shift matrix rows downwards by 1 + [[nodiscard]] Block ShiftRowsDown() const; + + //! Will shift matrix rows downwards by 1 + void ShiftRowsDownInplace(); + + //! Will shift matrix columns to the left by 1 + [[nodiscard]] Block ShiftColumnsLeft() const; + + //! Will shift matrix columns to the left by 1 + void ShiftColumnsLeftInplace(); + + //! Will shift matrix columns to the right by 1 + [[nodiscard]] Block ShiftColumnsRight() const; + + //! Will shift matrix columns to the right by 1 + void ShiftColumnsRightInplace(); + + //! Will shift array cells to the left by 1 + [[nodiscard]] Block ShiftCellsLeft() const; + + //! Will shift array cells to the left by 1 + void ShiftCellsLeftInplace(); + + //! Will shift array cells to the right by 1 + [[nodiscard]] Block ShiftCellsRight() const; + + //! Will shift array cells to the right by 1 + void ShiftCellsRightInplace(); //! Will copy a block Block& operator=(const Block& other); //! Will compare whether or not two blocks are equal - bool operator==(const Block& other) const; + [[nodiscard]] bool operator==(const Block& other) const; //! Will compare whether or not two blocks are unequal - bool operator!=(const Block& other) const; + [[nodiscard]] bool operator!=(const Block& other) const; //! Will zero all data void Reset(); - //! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3) - std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column); + [[nodiscard]] std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column); //! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3) - const std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column) const; + [[nodiscard]] const std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column) const; //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) - std::uint32_t& Get(const std::uint8_t index); + [[nodiscard]] std::uint32_t& Get(const std::uint8_t index); //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) - const std::uint32_t& Get(const std::uint8_t index) const; + [[nodiscard]] const std::uint32_t& Get(const std::uint8_t index) const; //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) - std::uint32_t& operator[](const std::uint8_t index); + [[nodiscard]] std::uint32_t& operator[](const std::uint8_t index); //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) - const std::uint32_t& operator[](const std::uint8_t index) const; + [[nodiscard]] const std::uint32_t& operator[](const std::uint8_t index) const; static constexpr std::size_t CHUNK_SIZE = sizeof(std::uint32_t); static constexpr std::size_t CHUNK_SIZE_BITS = CHUNK_SIZE * 8; diff --git a/GCryptLib/src/Block.cpp b/GCryptLib/src/Block.cpp index 0152541..bd16dd1 100644 --- a/GCryptLib/src/Block.cpp +++ b/GCryptLib/src/Block.cpp @@ -5,6 +5,10 @@ #include #include +// Just to be sure, the compiler will optimize this +// little formula out, let's do it in the preprocessor +#define MAT_INDEX(row, column) (column*4 + row) + namespace Leonetienne::GCrypt { Block::Block() { @@ -132,28 +136,310 @@ namespace Leonetienne::GCrypt { return *this; } - void ShiftRowsUp(const std::size_t n) { - // TO BE IMPLEMENTED + Block Block::Add(const Block& other) const { + + Block m; + for (std::size_t i = 0; i < data.size(); i++) { + m.Get(i) = this->Get(i) + other.Get(i); + } + return m; } - void ShiftRowsDown(const std::size_t n) { - // TO BE IMPLEMENTED + Block Block::operator+(const Block& other) const { + return Add(other); } - void ShiftColumnsLeft(const std::size_t n) { - // TO BE IMPLEMENTED + void Block::AddInplace(const Block& other) { + for (std::size_t i = 0; i < data.size(); i++) { + this->Get(i) += other.Get(i); + } + return; } - void ShiftColumnsRight(const std::size_t n) { - // TO BE IMPLEMENTED + Block& Block::operator+=(const Block& other) { + AddInplace(other); + return *this; } - void ShiftCellsLeft(const std::size_t n) { - // TO BE IMPLEMENTED + Block Block::Sub(const Block& other) const { + + Block m; + for (std::size_t i = 0; i < data.size(); i++) { + m.Get(i) = this->Get(i) - other.Get(i); + } + return m; } - void ShiftCellsRight(const std::size_t n) { - // TO BE IMPLEMENTED + Block Block::operator-(const Block& other) const { + return Sub(other); + } + + void Block::SubInplace(const Block& other) { + for (std::size_t i = 0; i < data.size(); i++) { + this->Get(i) -= other.Get(i); + } + return; + } + + Block& Block::operator-=(const Block& other) { + SubInplace(other); + return *this; + } + + void Block::ShiftRowsUpInplace() { + Block tmp = *this; + + Get(MAT_INDEX(0, 0)) = tmp.Get(MAT_INDEX(1, 0)); + Get(MAT_INDEX(0, 1)) = tmp.Get(MAT_INDEX(1, 1)); + Get(MAT_INDEX(0, 2)) = tmp.Get(MAT_INDEX(1, 2)); + Get(MAT_INDEX(0, 3)) = tmp.Get(MAT_INDEX(1, 3)); + + Get(MAT_INDEX(1, 0)) = tmp.Get(MAT_INDEX(2, 0)); + Get(MAT_INDEX(1, 1)) = tmp.Get(MAT_INDEX(2, 1)); + Get(MAT_INDEX(1, 2)) = tmp.Get(MAT_INDEX(2, 2)); + Get(MAT_INDEX(1, 3)) = tmp.Get(MAT_INDEX(2, 3)); + + Get(MAT_INDEX(2, 0)) = tmp.Get(MAT_INDEX(3, 0)); + Get(MAT_INDEX(2, 1)) = tmp.Get(MAT_INDEX(3, 1)); + Get(MAT_INDEX(2, 2)) = tmp.Get(MAT_INDEX(3, 2)); + Get(MAT_INDEX(2, 3)) = tmp.Get(MAT_INDEX(3, 3)); + + Get(MAT_INDEX(3, 0)) = tmp.Get(MAT_INDEX(0, 0)); + Get(MAT_INDEX(3, 1)) = tmp.Get(MAT_INDEX(0, 1)); + Get(MAT_INDEX(3, 2)) = tmp.Get(MAT_INDEX(0, 2)); + Get(MAT_INDEX(3, 3)) = tmp.Get(MAT_INDEX(0, 3)); + + return; + } + + Block Block::ShiftRowsUp() const { + Block b; + + b.Get(MAT_INDEX(0, 0)) = Get(MAT_INDEX(1, 0)); + b.Get(MAT_INDEX(0, 1)) = Get(MAT_INDEX(1, 1)); + b.Get(MAT_INDEX(0, 2)) = Get(MAT_INDEX(1, 2)); + b.Get(MAT_INDEX(0, 3)) = Get(MAT_INDEX(1, 3)); + + b.Get(MAT_INDEX(1, 0)) = Get(MAT_INDEX(2, 0)); + b.Get(MAT_INDEX(1, 1)) = Get(MAT_INDEX(2, 1)); + b.Get(MAT_INDEX(1, 2)) = Get(MAT_INDEX(2, 2)); + b.Get(MAT_INDEX(1, 3)) = Get(MAT_INDEX(2, 3)); + + b.Get(MAT_INDEX(2, 0)) = Get(MAT_INDEX(3, 0)); + b.Get(MAT_INDEX(2, 1)) = Get(MAT_INDEX(3, 1)); + b.Get(MAT_INDEX(2, 2)) = Get(MAT_INDEX(3, 2)); + b.Get(MAT_INDEX(2, 3)) = Get(MAT_INDEX(3, 3)); + + b.Get(MAT_INDEX(3, 0)) = Get(MAT_INDEX(0, 0)); + b.Get(MAT_INDEX(3, 1)) = Get(MAT_INDEX(0, 1)); + b.Get(MAT_INDEX(3, 2)) = Get(MAT_INDEX(0, 2)); + b.Get(MAT_INDEX(3, 3)) = Get(MAT_INDEX(0, 3)); + + return b; + } + + void Block::ShiftRowsDownInplace() { + Block tmp = *this; + + Get(MAT_INDEX(0, 0)) = tmp.Get(MAT_INDEX(3, 0)); + Get(MAT_INDEX(0, 1)) = tmp.Get(MAT_INDEX(3, 1)); + Get(MAT_INDEX(0, 2)) = tmp.Get(MAT_INDEX(3, 2)); + Get(MAT_INDEX(0, 3)) = tmp.Get(MAT_INDEX(3, 3)); + + Get(MAT_INDEX(1, 0)) = tmp.Get(MAT_INDEX(0, 0)); + Get(MAT_INDEX(1, 1)) = tmp.Get(MAT_INDEX(0, 1)); + Get(MAT_INDEX(1, 2)) = tmp.Get(MAT_INDEX(0, 2)); + Get(MAT_INDEX(1, 3)) = tmp.Get(MAT_INDEX(0, 3)); + + Get(MAT_INDEX(2, 0)) = tmp.Get(MAT_INDEX(1, 0)); + Get(MAT_INDEX(2, 1)) = tmp.Get(MAT_INDEX(1, 1)); + Get(MAT_INDEX(2, 2)) = tmp.Get(MAT_INDEX(1, 2)); + Get(MAT_INDEX(2, 3)) = tmp.Get(MAT_INDEX(1, 3)); + + Get(MAT_INDEX(3, 0)) = tmp.Get(MAT_INDEX(2, 0)); + Get(MAT_INDEX(3, 1)) = tmp.Get(MAT_INDEX(2, 1)); + Get(MAT_INDEX(3, 2)) = tmp.Get(MAT_INDEX(2, 2)); + Get(MAT_INDEX(3, 3)) = tmp.Get(MAT_INDEX(2, 3)); + + return; + } + + Block Block::ShiftRowsDown() const { + Block b; + + b.Get(MAT_INDEX(0, 0)) = Get(MAT_INDEX(3, 0)); + b.Get(MAT_INDEX(0, 1)) = Get(MAT_INDEX(3, 1)); + b.Get(MAT_INDEX(0, 2)) = Get(MAT_INDEX(3, 2)); + b.Get(MAT_INDEX(0, 3)) = Get(MAT_INDEX(3, 3)); + + b.Get(MAT_INDEX(1, 0)) = Get(MAT_INDEX(0, 0)); + b.Get(MAT_INDEX(1, 1)) = Get(MAT_INDEX(0, 1)); + b.Get(MAT_INDEX(1, 2)) = Get(MAT_INDEX(0, 2)); + b.Get(MAT_INDEX(1, 3)) = Get(MAT_INDEX(0, 3)); + + b.Get(MAT_INDEX(2, 0)) = Get(MAT_INDEX(1, 0)); + b.Get(MAT_INDEX(2, 1)) = Get(MAT_INDEX(1, 1)); + b.Get(MAT_INDEX(2, 2)) = Get(MAT_INDEX(1, 2)); + b.Get(MAT_INDEX(2, 3)) = Get(MAT_INDEX(1, 3)); + + b.Get(MAT_INDEX(3, 0)) = Get(MAT_INDEX(2, 0)); + b.Get(MAT_INDEX(3, 1)) = Get(MAT_INDEX(2, 1)); + b.Get(MAT_INDEX(3, 2)) = Get(MAT_INDEX(2, 2)); + b.Get(MAT_INDEX(3, 3)) = Get(MAT_INDEX(2, 3)); + + return b; + } + + void Block::ShiftColumnsLeftInplace() { + Block tmp = *this; + + Get(MAT_INDEX(0, 0)) = tmp.Get(MAT_INDEX(0, 1)); + Get(MAT_INDEX(1, 0)) = tmp.Get(MAT_INDEX(1, 1)); + Get(MAT_INDEX(2, 0)) = tmp.Get(MAT_INDEX(2, 1)); + Get(MAT_INDEX(3, 0)) = tmp.Get(MAT_INDEX(3, 1)); + + Get(MAT_INDEX(0, 1)) = tmp.Get(MAT_INDEX(0, 2)); + Get(MAT_INDEX(1, 1)) = tmp.Get(MAT_INDEX(1, 2)); + Get(MAT_INDEX(2, 1)) = tmp.Get(MAT_INDEX(2, 2)); + Get(MAT_INDEX(3, 1)) = tmp.Get(MAT_INDEX(3, 2)); + + Get(MAT_INDEX(0, 2)) = tmp.Get(MAT_INDEX(0, 3)); + Get(MAT_INDEX(1, 2)) = tmp.Get(MAT_INDEX(1, 3)); + Get(MAT_INDEX(2, 2)) = tmp.Get(MAT_INDEX(2, 3)); + Get(MAT_INDEX(3, 2)) = tmp.Get(MAT_INDEX(3, 3)); + + Get(MAT_INDEX(0, 3)) = tmp.Get(MAT_INDEX(0, 0)); + Get(MAT_INDEX(1, 3)) = tmp.Get(MAT_INDEX(1, 0)); + Get(MAT_INDEX(2, 3)) = tmp.Get(MAT_INDEX(2, 0)); + Get(MAT_INDEX(3, 3)) = tmp.Get(MAT_INDEX(3, 0)); + + return; + } + + Block Block::ShiftColumnsLeft() const { + Block b; + + b.Get(MAT_INDEX(0, 0)) = Get(MAT_INDEX(0, 1)); + b.Get(MAT_INDEX(1, 0)) = Get(MAT_INDEX(1, 1)); + b.Get(MAT_INDEX(2, 0)) = Get(MAT_INDEX(2, 1)); + b.Get(MAT_INDEX(3, 0)) = Get(MAT_INDEX(3, 1)); + + b.Get(MAT_INDEX(0, 1)) = Get(MAT_INDEX(0, 2)); + b.Get(MAT_INDEX(1, 1)) = Get(MAT_INDEX(1, 2)); + b.Get(MAT_INDEX(2, 1)) = Get(MAT_INDEX(2, 2)); + b.Get(MAT_INDEX(3, 1)) = Get(MAT_INDEX(3, 2)); + + b.Get(MAT_INDEX(0, 2)) = Get(MAT_INDEX(0, 3)); + b.Get(MAT_INDEX(1, 2)) = Get(MAT_INDEX(1, 3)); + b.Get(MAT_INDEX(2, 2)) = Get(MAT_INDEX(2, 3)); + b.Get(MAT_INDEX(3, 2)) = Get(MAT_INDEX(3, 3)); + + b.Get(MAT_INDEX(0, 3)) = Get(MAT_INDEX(0, 0)); + b.Get(MAT_INDEX(1, 3)) = Get(MAT_INDEX(1, 0)); + b.Get(MAT_INDEX(2, 3)) = Get(MAT_INDEX(2, 0)); + b.Get(MAT_INDEX(3, 3)) = Get(MAT_INDEX(3, 0)); + + return b; + } + + void Block::ShiftColumnsRightInplace() { + Block tmp = *this; + + Get(MAT_INDEX(0, 1)) = tmp.Get(MAT_INDEX(0, 0)); + Get(MAT_INDEX(1, 1)) = tmp.Get(MAT_INDEX(1, 0)); + Get(MAT_INDEX(2, 1)) = tmp.Get(MAT_INDEX(2, 0)); + Get(MAT_INDEX(3, 1)) = tmp.Get(MAT_INDEX(3, 0)); + + Get(MAT_INDEX(0, 2)) = tmp.Get(MAT_INDEX(0, 1)); + Get(MAT_INDEX(1, 2)) = tmp.Get(MAT_INDEX(1, 1)); + Get(MAT_INDEX(2, 2)) = tmp.Get(MAT_INDEX(2, 1)); + Get(MAT_INDEX(3, 2)) = tmp.Get(MAT_INDEX(3, 1)); + + Get(MAT_INDEX(0, 3)) = tmp.Get(MAT_INDEX(0, 2)); + Get(MAT_INDEX(1, 3)) = tmp.Get(MAT_INDEX(1, 2)); + Get(MAT_INDEX(2, 3)) = tmp.Get(MAT_INDEX(2, 2)); + Get(MAT_INDEX(3, 3)) = tmp.Get(MAT_INDEX(3, 2)); + + Get(MAT_INDEX(0, 0)) = tmp.Get(MAT_INDEX(0, 3)); + Get(MAT_INDEX(1, 0)) = tmp.Get(MAT_INDEX(1, 3)); + Get(MAT_INDEX(2, 0)) = tmp.Get(MAT_INDEX(2, 3)); + Get(MAT_INDEX(3, 0)) = tmp.Get(MAT_INDEX(3, 3)); + + return; + } + + Block Block::ShiftColumnsRight() const { + Block b; + + b.Get(MAT_INDEX(0, 1)) = Get(MAT_INDEX(0, 0)); + b.Get(MAT_INDEX(1, 1)) = Get(MAT_INDEX(1, 0)); + b.Get(MAT_INDEX(2, 1)) = Get(MAT_INDEX(2, 0)); + b.Get(MAT_INDEX(3, 1)) = Get(MAT_INDEX(3, 0)); + + b.Get(MAT_INDEX(0, 2)) = Get(MAT_INDEX(0, 1)); + b.Get(MAT_INDEX(1, 2)) = Get(MAT_INDEX(1, 1)); + b.Get(MAT_INDEX(2, 2)) = Get(MAT_INDEX(2, 1)); + b.Get(MAT_INDEX(3, 2)) = Get(MAT_INDEX(3, 1)); + + b.Get(MAT_INDEX(0, 3)) = Get(MAT_INDEX(0, 2)); + b.Get(MAT_INDEX(1, 3)) = Get(MAT_INDEX(1, 2)); + b.Get(MAT_INDEX(2, 3)) = Get(MAT_INDEX(2, 2)); + b.Get(MAT_INDEX(3, 3)) = Get(MAT_INDEX(3, 2)); + + b.Get(MAT_INDEX(0, 0)) = Get(MAT_INDEX(0, 3)); + b.Get(MAT_INDEX(1, 0)) = Get(MAT_INDEX(1, 3)); + b.Get(MAT_INDEX(2, 0)) = Get(MAT_INDEX(2, 3)); + b.Get(MAT_INDEX(3, 0)) = Get(MAT_INDEX(3, 3)); + + return b; + } + + void Block::ShiftCellsLeftInplace() { + Block tmp = *this; + + Get(15) = tmp.Get(0); + + for (std::size_t i = 0; i < 15; i++) { + Get(i) = tmp.Get(i+1); + } + + return; + } + + Block Block::ShiftCellsLeft() const { + Block b; + + b.Get(15) = Get(0); + + for (std::size_t i = 0; i < 15; i++) { + b.Get(i) = Get(i+1); + } + + return b; + } + + void Block::ShiftCellsRightInplace() { + Block tmp = *this; + + Get(0) = tmp.Get(15); + + for (std::size_t i = 1; i < 16; i++) { + Get(i) = tmp.Get(i-1); + } + + return; + } + + Block Block::ShiftCellsRight() const { + Block b; + + b.Get(0) = Get(15); + + for (std::size_t i = 1; i < 16; i++) { + b.Get(i) = Get(i-1); + } + + return b; } Block& Block::operator=(const Block& other) { @@ -162,11 +448,11 @@ namespace Leonetienne::GCrypt { } std::uint32_t& Block::Get(const std::uint8_t row, const std::uint8_t column){ - return data[column*4 + row]; + return data[MAT_INDEX(row, column)]; } const std::uint32_t& Block::Get(const std::uint8_t row, const std::uint8_t column) const { - return data[column*4 + row]; + return data[MAT_INDEX(row, column)]; } std::uint32_t& Block::Get(const std::uint8_t index) { @@ -222,3 +508,5 @@ namespace Leonetienne::GCrypt { } +#undef MAT_INDEX + diff --git a/GCryptLib/src/Feistel.cpp b/GCryptLib/src/Feistel.cpp index 565d54a..9f2d20d 100644 --- a/GCryptLib/src/Feistel.cpp +++ b/GCryptLib/src/Feistel.cpp @@ -1,7 +1,6 @@ #include #include "GCrypt/Feistel.h" #include "GCrypt/Util.h" -#include "GCrypt/BlockMatrix.h" #include "GCrypt/Config.h" namespace Leonetienne::GCrypt { diff --git a/GCryptLib/test/Block.cpp b/GCryptLib/test/Block.cpp index faa715e..09730f7 100644 --- a/GCryptLib/test/Block.cpp +++ b/GCryptLib/test/Block.cpp @@ -1,4 +1,5 @@ #include +#include #include "Catch2.h" #include #include @@ -148,6 +149,116 @@ TEST_CASE(__FILE__"/operator^&=", "[Block]") { REQUIRE(block1 == block3); } +// Tests that operator+ (add) works +TEST_CASE(__FILE__"/add", "[Block]") { + + // Setup + Block block; + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i * 1024; + } + + Block addRH; + for (std::size_t i = 0; i < 16; i++) { + addRH.Get(i) = i * 5099; + } + + // Exercise + Block result = block + addRH; + + Block manualResult; + for (std::size_t i = 0; i < 16; i++) { + manualResult.Get(i) = (i * 1024) + (i * 5099); + } + + // Verify + REQUIRE(result == manualResult); +} + +// Tests that operator+ is the same as += +TEST_CASE(__FILE__"/operator+&=", "[Block]") { + + // Setup + Block block1; + for (std::size_t i = 0; i < 16; i++) { + block1.Get(i) = i * 1024; + } + + Block block2; + for (std::size_t i = 0; i < 16; i++) { + block2.Get(i) = i * 5099 * 2; + } + + // Exercise + Block block3 = block1 + block2; + block1 += block2; + + // Verify + REQUIRE(block1 == block3); +} + +// Tests that operator- (subtract) works +TEST_CASE(__FILE__"/subtract", "[Block]") { + + // Setup + Block block; + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i * 1024; + } + + Block subRH; + for (std::size_t i = 0; i < 16; i++) { + subRH.Get(i) = i * 5099; + } + + // Exercise + Block result = block - subRH; + + Block manualResult; + for (std::size_t i = 0; i < 16; i++) { + manualResult.Get(i) = (i * 1024) - (i * 5099); + } + + // Verify + REQUIRE(result == manualResult); +} + +// Tests that operator- is the same as -= +TEST_CASE(__FILE__"/operator-&=", "[Block]") { + + // Setup + Block block1; + for (std::size_t i = 0; i < 16; i++) { + block1.Get(i) = i * 1024; + } + + Block block2; + for (std::size_t i = 0; i < 16; i++) { + block2.Get(i) = i * 5099 * 2; + } + + // Exercise + Block block3 = block1 - block2; + block1 -= block2; + + // Verify + REQUIRE(block1 == block3); +} + +// Tests that subtraction undoes addition, and vica versa +TEST_CASE(__FILE__"/subtraction-undoes-addition", "[Block]") { + // Setup + const Block a = Key::FromPassword("Halleluja"); + const Block b = Key::FromPassword("Ananas"); + + // Exercise + const Block a_plus_b = a + b; + const Block a_plus_b_minus_b = a_plus_b - b; + + // Verify + REQUIRE(a == a_plus_b_minus_b); +} + // Tests that operator== works correctly TEST_CASE(__FILE__"/operator==", "[Block]") { @@ -249,3 +360,276 @@ TEST_CASE(__FILE__"/reset", "[Block]") { REQUIRE(block[i] == 0); } } + +// Tests that shift rows up works +TEST_CASE(__FILE__"/shift-rows-up", "[Block]") { + + // Setup + Block a; + a.Get(0,0) = 10; a.Get(0,1) = 11; a.Get(0,2) = 12; a.Get(0,3) = 13; + a.Get(1,0) = 20; a.Get(1,1) = 21; a.Get(1,2) = 22; a.Get(1,3) = 23; + a.Get(2,0) = 30; a.Get(2,1) = 31; a.Get(2,2) = 32; a.Get(2,3) = 33; + a.Get(3,0) = 40; a.Get(3,1) = 41; a.Get(3,2) = 42; a.Get(3,3) = 43; + + Block e; /* expected */ + e.Get(0,0) = 20; e.Get(0,1) = 21; e.Get(0,2) = 22; e.Get(0,3) = 23; + e.Get(1,0) = 30; e.Get(1,1) = 31; e.Get(1,2) = 32; e.Get(1,3) = 33; + e.Get(2,0) = 40; e.Get(2,1) = 41; e.Get(2,2) = 42; e.Get(2,3) = 43; + e.Get(3,0) = 10; e.Get(3,1) = 11; e.Get(3,2) = 12; e.Get(3,3) = 13; + + // Exercise + a.ShiftRowsUpInplace(); + + // Verify + REQUIRE(a == e); +} + +// Tests that ShiftRowsUpInplace() does the exact same thing as ShiftRowsUp() +TEST_CASE(__FILE__"/shift-rows-up-same-as-inplace", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + const Block initial_a = a; + + // Exercise and verify + a.ShiftRowsUpInplace(); + REQUIRE(a == initial_a.ShiftRowsUp()); +} + +// Tests that shift rows down works +TEST_CASE(__FILE__"/shift-rows-down", "[Block]") { + + // Setup + Block a; + a.Get(0,0) = 10; a.Get(0,1) = 11; a.Get(0,2) = 12; a.Get(0,3) = 13; + a.Get(1,0) = 20; a.Get(1,1) = 21; a.Get(1,2) = 22; a.Get(1,3) = 23; + a.Get(2,0) = 30; a.Get(2,1) = 31; a.Get(2,2) = 32; a.Get(2,3) = 33; + a.Get(3,0) = 40; a.Get(3,1) = 41; a.Get(3,2) = 42; a.Get(3,3) = 43; + + Block e; /* expected */ + e.Get(0,0) = 40; e.Get(0,1) = 41; e.Get(0,2) = 42; e.Get(0,3) = 43; + e.Get(1,0) = 10; e.Get(1,1) = 11; e.Get(1,2) = 12; e.Get(1,3) = 13; + e.Get(2,0) = 20; e.Get(2,1) = 21; e.Get(2,2) = 22; e.Get(2,3) = 23; + e.Get(3,0) = 30; e.Get(3,1) = 31; e.Get(3,2) = 32; e.Get(3,3) = 33; + + // Exercise + a.ShiftRowsDownInplace(); + + // Verify + REQUIRE(a == e); +} + +// Tests that ShiftRowsDownInplace() does the exact same thing as ShiftRowsDown() +TEST_CASE(__FILE__"/shift-rows-down-same-as-inplace", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + const Block initial_a = a; + + // Exercise and verify + a.ShiftRowsDownInplace(); + REQUIRE(a == initial_a.ShiftRowsDown()); +} + +// Tests that shift columns left works +TEST_CASE(__FILE__"/shift-columns-left", "[Block]") { + + // Setup + Block a; + a.Get(0,0) = 10; a.Get(0,1) = 11; a.Get(0,2) = 12; a.Get(0,3) = 13; + a.Get(1,0) = 20; a.Get(1,1) = 21; a.Get(1,2) = 22; a.Get(1,3) = 23; + a.Get(2,0) = 30; a.Get(2,1) = 31; a.Get(2,2) = 32; a.Get(2,3) = 33; + a.Get(3,0) = 40; a.Get(3,1) = 41; a.Get(3,2) = 42; a.Get(3,3) = 43; + + Block e; /* expected */ + e.Get(0,0) = 11; e.Get(0,1) = 12; e.Get(0,2) = 13; e.Get(0,3) = 10; + e.Get(1,0) = 21; e.Get(1,1) = 22; e.Get(1,2) = 23; e.Get(1,3) = 20; + e.Get(2,0) = 31; e.Get(2,1) = 32; e.Get(2,2) = 33; e.Get(2,3) = 30; + e.Get(3,0) = 41; e.Get(3,1) = 42; e.Get(3,2) = 43; e.Get(3,3) = 40; + + // Exercise + a.ShiftColumnsLeftInplace(); + + // Verify + REQUIRE(a == e); +} + +// Tests that ShiftColumnsLeftInplace()() does the exact same thing as ShiftColumnsLeft() +TEST_CASE(__FILE__"/shift-columns-left-same-as-inplace", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + const Block initial_a = a; + + // Exercise and verify + a.ShiftColumnsLeftInplace(); + REQUIRE(a == initial_a.ShiftColumnsLeft()); +} + +// Tests that shift columns right works +TEST_CASE(__FILE__"/shift-columns-right", "[Block]") { + + // Setup + Block a; + a.Get(0,0) = 10; a.Get(0,1) = 11; a.Get(0,2) = 12; a.Get(0,3) = 13; + a.Get(1,0) = 20; a.Get(1,1) = 21; a.Get(1,2) = 22; a.Get(1,3) = 23; + a.Get(2,0) = 30; a.Get(2,1) = 31; a.Get(2,2) = 32; a.Get(2,3) = 33; + a.Get(3,0) = 40; a.Get(3,1) = 41; a.Get(3,2) = 42; a.Get(3,3) = 43; + + Block e; /* expected */ + e.Get(0,0) = 13; e.Get(0,1) = 10; e.Get(0,2) = 11; e.Get(0,3) = 12; + e.Get(1,0) = 23; e.Get(1,1) = 20; e.Get(1,2) = 21; e.Get(1,3) = 22; + e.Get(2,0) = 33; e.Get(2,1) = 30; e.Get(2,2) = 31; e.Get(2,3) = 32; + e.Get(3,0) = 43; e.Get(3,1) = 40; e.Get(3,2) = 41; e.Get(3,3) = 42; + + // Exercise + a.ShiftColumnsRightInplace(); + + // Verify + REQUIRE(a == e); +} + +// Tests that ShiftColumnsRightInplace()() does the exact same thing as ShiftColumnsRight() +TEST_CASE(__FILE__"/shift-columns-right-same-as-inplace", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + const Block initial_a = a; + + // Exercise and verify + a.ShiftColumnsRightInplace(); + REQUIRE(a == initial_a.ShiftColumnsRight()); +} + +// Tests that shift cells left works +TEST_CASE(__FILE__"/shift-cells-left", "[Block]") { + + // Setup + Block a; + for (std::size_t i = 0; i < 16; i++) { + a.Get(i) = i; + } + + Block expected; + for (std::size_t i = 0; i < 15; i++) { + expected.Get(i) = i+1; + } + expected.Get(15) = 0; + + // Exercise + a.ShiftCellsLeftInplace(); + + // Verify + REQUIRE(a == expected); +} + +// Tests that ShiftCellsLeftInplace()() does the exact same thing as ShiftCellsLeft() +TEST_CASE(__FILE__"/shift-cells-left-same-as-inplace", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + const Block initial_a = a; + + // Exercise and verify + a.ShiftCellsLeftInplace(); + REQUIRE(a == initial_a.ShiftCellsLeft()); +} + +// Tests that shift cells right works +TEST_CASE(__FILE__"/shift-cells-right", "[Block]") { + + // Setup + Block a; + for (std::size_t i = 0; i < 16; i++) { + a.Get(i) = i; + } + + Block expected; + for (std::size_t i = 1; i < 16; i++) { + expected.Get(i) = i-1; + } + expected.Get(0) = 15; + + // Exercise + a.ShiftCellsRightInplace(); + + // Verify + REQUIRE(a == expected); +} + +// Tests that ShiftCellsRightInplace()() does the exact same thing as ShiftCellsRight() +TEST_CASE(__FILE__"/shift-cells-right-same-as-inplace", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + const Block initial_a = a; + + // Exercise and verify + a.ShiftCellsRightInplace(); + REQUIRE(a == initial_a.ShiftCellsRight()); +} + +// Tests that shifting down undoes shifting up, and vica versa +TEST_CASE(__FILE__"/shift-down-undoes-shift-up", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + const Block initial_a = a; + + // Exercise + a.ShiftRowsUpInplace(); + a.ShiftRowsDownInplace(); + + // Verify + REQUIRE(a == initial_a); +} + +// Tests that shifting left undoes shifting right, and vica versa +TEST_CASE(__FILE__"/shift-left-undoes-shift-right", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + const Block initial_a = a; + + // Exercise + a.ShiftColumnsRightInplace(); + a.ShiftColumnsLeftInplace(); + + // Verify + REQUIRE(a == initial_a); +} + +// Tests that shifting cells left undoes shifting cells right, and vica versa +TEST_CASE(__FILE__"/cellshift-left-undoes-cellshift-right", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + const Block initial_a = a; + + // Exercise + a.ShiftCellsRightInplace(); + a.ShiftCellsLeftInplace(); + + // Verify + REQUIRE(a == initial_a); +} + +// Tests that multiple, combined shifts and additions can be undone +TEST_CASE(__FILE__"/multiple-combined-shifts-and-additions-can-be-undone", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + Block key = Key::FromPassword("Papaya"); + + const Block initial_a = a; + + // Exercise (mix-up) + for (std::size_t i = 0; i < 64; i++) { + a.ShiftRowsUpInplace(); + a.ShiftColumnsLeftInplace(); + a += key; + a.ShiftCellsRightInplace(); + } + + // Exercise (un-mix) + for (std::size_t i = 0; i < 64; i++) { + a.ShiftCellsLeftInplace(); + a -= key; + a.ShiftColumnsRightInplace(); + a.ShiftRowsDownInplace(); + } + + // Verify + REQUIRE(a == initial_a); +} + From e552e1a6f870219b329d5de6c0662cd09aa93b44 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Tue, 24 May 2022 23:18:39 +0200 Subject: [PATCH 038/110] Add GetBit() method to Block --- GCryptLib/include/GCrypt/Block.h | 3 +++ GCryptLib/src/Block.cpp | 11 +++++++++++ GCryptLib/test/Block.cpp | 15 +++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/GCryptLib/include/GCrypt/Block.h b/GCryptLib/include/GCrypt/Block.h index 3fefbd5..d6c2b8c 100644 --- a/GCryptLib/include/GCrypt/Block.h +++ b/GCryptLib/include/GCrypt/Block.h @@ -123,6 +123,9 @@ namespace Leonetienne::GCrypt { //! Will zero all data void Reset(); + //! Will return the state of any given bit + [[nodiscard]] bool GetBit(const std::size_t index) const; + //! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3) [[nodiscard]] std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column); //! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3) diff --git a/GCryptLib/src/Block.cpp b/GCryptLib/src/Block.cpp index bd16dd1..b2b5660 100644 --- a/GCryptLib/src/Block.cpp +++ b/GCryptLib/src/Block.cpp @@ -1,4 +1,5 @@ #include "GCrypt/Block.h" +#include #include "GCrypt/Config.h" #include #include @@ -447,6 +448,16 @@ namespace Leonetienne::GCrypt { return *this; } + bool Block::GetBit(const std::size_t index) const { + // Fetch index of integer the bit is located in + const std::size_t intIndex = index / CHUNK_SIZE_BITS; + + // Fetch bit index relative to that int + const std::size_t relBitIndex = index - (intIndex * CHUNK_SIZE_BITS); + + return data[intIndex] & (1 << (CHUNK_SIZE_BITS - relBitIndex - 1)); + } + std::uint32_t& Block::Get(const std::uint8_t row, const std::uint8_t column){ return data[MAT_INDEX(row, column)]; } diff --git a/GCryptLib/test/Block.cpp b/GCryptLib/test/Block.cpp index 09730f7..0a9976b 100644 --- a/GCryptLib/test/Block.cpp +++ b/GCryptLib/test/Block.cpp @@ -633,3 +633,18 @@ TEST_CASE(__FILE__"/multiple-combined-shifts-and-additions-can-be-undone", "[Blo REQUIRE(a == initial_a); } +// Tests that the get-bit method works +TEST_CASE(__FILE__"/get-bit", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + + // Exercise + std::stringstream ss; + for (std::size_t i = 0; i < 512; i++) { + ss << a.GetBit(i); + } + + // Verify + REQUIRE(ss.str() == a.ToString()); +} + From 9a9cd05bed4a8dd9ab1c7ce6ea45b39084a05134 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Tue, 24 May 2022 23:51:17 +0200 Subject: [PATCH 039/110] Add SetBit, and FlipBit methods to block --- GCryptLib/include/GCrypt/Block.h | 6 ++++ GCryptLib/src/Block.cpp | 42 ++++++++++++++++++++++- GCryptLib/test/Block.cpp | 57 ++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) diff --git a/GCryptLib/include/GCrypt/Block.h b/GCryptLib/include/GCrypt/Block.h index d6c2b8c..f2d5bc3 100644 --- a/GCryptLib/include/GCrypt/Block.h +++ b/GCryptLib/include/GCrypt/Block.h @@ -126,6 +126,12 @@ namespace Leonetienne::GCrypt { //! Will return the state of any given bit [[nodiscard]] bool GetBit(const std::size_t index) const; + //! Will set the state of any given bit + void SetBit(const std::size_t index, const bool state); + + //! Will flip the state of any given bit + void FlipBit(const std::size_t index); + //! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3) [[nodiscard]] std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column); //! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3) diff --git a/GCryptLib/src/Block.cpp b/GCryptLib/src/Block.cpp index b2b5660..ac5a648 100644 --- a/GCryptLib/src/Block.cpp +++ b/GCryptLib/src/Block.cpp @@ -455,7 +455,47 @@ namespace Leonetienne::GCrypt { // Fetch bit index relative to that int const std::size_t relBitIndex = index - (intIndex * CHUNK_SIZE_BITS); - return data[intIndex] & (1 << (CHUNK_SIZE_BITS - relBitIndex - 1)); + // Pre-calculate the bitmask to use + const std::size_t bitmask = 1 << (CHUNK_SIZE_BITS - relBitIndex - 1); + + return data[intIndex] & bitmask; + } + + void Block::SetBit(const std::size_t index, const bool state) { + // Fetch index of integer the bit is located in + const std::size_t intIndex = index / CHUNK_SIZE_BITS; + + // Fetch bit index relative to that int + const std::size_t relBitIndex = index - (intIndex * CHUNK_SIZE_BITS); + + // Pre-calculate the bitmask to use + const std::size_t bitmask = 1 << (CHUNK_SIZE_BITS - relBitIndex - 1); + + // Set the bit + if (state) { + data[intIndex] |= bitmask; + } + // Clear the bit + else { + data[intIndex] &= ~bitmask; + } + + return; + } + + void Block::FlipBit(const std::size_t index) { + // Fetch index of integer the bit is located in + const std::size_t intIndex = index / CHUNK_SIZE_BITS; + + // Fetch bit index relative to that int + const std::size_t relBitIndex = index - (intIndex * CHUNK_SIZE_BITS); + + // Pre-calculate the bitmask to use + const std::size_t bitmask = 1 << (CHUNK_SIZE_BITS - relBitIndex - 1); + + data[intIndex] ^= bitmask; + + return; } std::uint32_t& Block::Get(const std::uint8_t row, const std::uint8_t column){ diff --git a/GCryptLib/test/Block.cpp b/GCryptLib/test/Block.cpp index 0a9976b..1de73c9 100644 --- a/GCryptLib/test/Block.cpp +++ b/GCryptLib/test/Block.cpp @@ -648,3 +648,60 @@ TEST_CASE(__FILE__"/get-bit", "[Block]") { REQUIRE(ss.str() == a.ToString()); } +// Tests that the set-bit to-false method works +TEST_CASE(__FILE__"/set-bit-to-false", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + + // Exercise + a.SetBit(5, 0); + a.SetBit(15, 0); + a.SetBit(105, 0); + a.SetBit(205, 0); + + // Verify + REQUIRE(a.GetBit(5) == false); + REQUIRE(a.GetBit(15) == false); + REQUIRE(a.GetBit(105) == false); + REQUIRE(a.GetBit(205) == false); +} + +// Tests that the set-bit to-true method works +TEST_CASE(__FILE__"/set-bit-to-true", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + + // Exercise + a.SetBit(5, 1); + a.SetBit(15, 1); + a.SetBit(105, 1); + a.SetBit(205, 1); + + // Verify + REQUIRE(a.GetBit(5) == true); + REQUIRE(a.GetBit(15) == true); + REQUIRE(a.GetBit(105) == true); + REQUIRE(a.GetBit(205) == true); +} + +// Tests that the flip-bit method works +TEST_CASE(__FILE__"/flip-bit", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + + std::string compare = a.ToString(); + compare[5] = compare[5] == '1' ? '0' : '1'; + compare[15] = compare[15] == '1' ? '0' : '1'; + compare[105] = compare[105] == '1' ? '0' : '1'; + compare[205] = compare[205] == '1' ? '0' : '1'; + + // Exercise + a.FlipBit(5); + a.FlipBit(15); + a.FlipBit(105); + a.FlipBit(205); + + // Verify + REQUIRE(a.ToString() == compare); +} + From b5369a3c3235cfdb91b2152dac00f228aeb1492a Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Wed, 25 May 2022 12:54:26 +0200 Subject: [PATCH 040/110] Added bitshift methods to block class --- GCryptLib/include/GCrypt/Block.h | 12 +++ GCryptLib/src/Block.cpp | 132 ++++++++++++++++++++++++++++++- GCryptLib/test/Block.cpp | 123 ++++++++++++++++++++++++++++ 3 files changed, 263 insertions(+), 4 deletions(-) diff --git a/GCryptLib/include/GCrypt/Block.h b/GCryptLib/include/GCrypt/Block.h index f2d5bc3..b28748a 100644 --- a/GCryptLib/include/GCrypt/Block.h +++ b/GCryptLib/include/GCrypt/Block.h @@ -132,6 +132,18 @@ namespace Leonetienne::GCrypt { //! Will flip the state of any given bit void FlipBit(const std::size_t index); + //! Will shift all bits to the left by 1 + [[nodiscard]] Block ShiftBitsLeft() const; + + //! Will shift all bits to the left by 1, inplace + void ShiftBitsLeftInplace(); + + //! Will shift all bits to the right by 1 + [[nodiscard]] Block ShiftBitsRight() const; + + //! Will shift all bits to the right by 1, inplace + void ShiftBitsRightInplace(); + //! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3) [[nodiscard]] std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column); //! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3) diff --git a/GCryptLib/src/Block.cpp b/GCryptLib/src/Block.cpp index ac5a648..7631962 100644 --- a/GCryptLib/src/Block.cpp +++ b/GCryptLib/src/Block.cpp @@ -1,6 +1,6 @@ #include "GCrypt/Block.h" -#include #include "GCrypt/Config.h" +#include "GCrypt/Util.h" #include #include #include @@ -134,9 +134,7 @@ namespace Leonetienne::GCrypt { Block& Block::operator^=(const Block& other) { XorInplace(other); - return *this; - } - + return *this; } Block Block::Add(const Block& other) const { Block m; @@ -498,6 +496,132 @@ namespace Leonetienne::GCrypt { return; } + Block Block::ShiftBitsLeft() const { + Block b; + + // First, copy this block over + b = *this; + + // Then, shift all integers individually + for (std::size_t i = 0; i < data.size(); i++) { + b.data[i] <<= 1; + } + + // Current state: the LSB is zero everywhere. We have to carry + // it over manually from the previous state. + + // Carry over the MSB of data[i] to LSB of data[i-1] + constexpr std::size_t bitmaskMsb = 1 << (CHUNK_SIZE_BITS - 1); + constexpr std::size_t bitmaskLsb = 1; + for (int i = 0; i < data.size(); i++) { + const bool msb = data[i] & bitmaskMsb; + + // Set the lsb + if (msb) { + b.data[Mod(i-1, data.size())] |= bitmaskLsb; + } + // Clear the lsb + else { + b.data[Mod(i-1, data.size())] &= ~bitmaskLsb; + } + } + + return b; + } + + void Block::ShiftBitsLeftInplace() { + Block tmp = *this; + + // Then, shift all integers individually + for (std::size_t i = 0; i < data.size(); i++) { + data[i] <<= 1; + } + + // Current state: the LSB is zero everywhere. We have to carry + // it over manually from the previous state. + + // Carry over the MSB of data[i] to LSB of data[i-1] + constexpr std::size_t bitmaskMsb = 1 << (CHUNK_SIZE_BITS - 1); + constexpr std::size_t bitmaskLsb = 1; + for (int i = 0; i < data.size(); i++) { + const bool msb = tmp.data[i] & bitmaskMsb; + + // Set the lsb + if (msb) { + data[Mod(i-1, data.size())] |= bitmaskLsb; + } + // Clear the lsb + else { + data[Mod(i-1, data.size())] &= ~bitmaskLsb; + } + } + + return; + } + + Block Block::ShiftBitsRight() const { + Block b; + + // First, copy this block over + b = *this; + + // Then, shift all integers individually + for (std::size_t i = 0; i < data.size(); i++) { + b.data[i] >>= 1; + } + + // Current state: the LSB is zero everywhere. We have to carry + // it over manually from the previous state. + + // Carry over the LSB of data[i] to MSB of data[i+1] + constexpr std::size_t bitmaskMsb = 1 << (CHUNK_SIZE_BITS - 1); + constexpr std::size_t bitmaskLsb = 1; + for (int i = 0; i < data.size(); i++) { + const bool lsb = data[i] & bitmaskLsb; + + // Set the msb + if (lsb) { + b.data[Mod(i+1, data.size())] |= bitmaskMsb; + } + // Clear the msb + else { + b.data[Mod(i+1, data.size())] &= ~bitmaskMsb; + } + } + + return b; + } + + void Block::ShiftBitsRightInplace() { + Block tmp = *this; + + // Then, shift all integers individually + for (std::size_t i = 0; i < data.size(); i++) { + data[i] >>= 1; + } + + // Current state: the LSB is zero everywhere. We have to carry + // it over manually from the previous state. + + // Carry over the LSB of data[i] to MSB of data[i+1] + constexpr std::size_t bitmaskMsb = 1 << (CHUNK_SIZE_BITS - 1); + constexpr std::size_t bitmaskLsb = 1; + for (int i = 0; i < data.size(); i++) { + const bool lsb = tmp.data[i] & bitmaskLsb; + + // Set the msb + if (lsb) { + data[Mod(i+1, data.size())] |= bitmaskMsb; + } + // Clear the msb + else { + data[Mod(i+1, data.size())] &= ~bitmaskMsb; + } + } + + return; + } + std::uint32_t& Block::Get(const std::uint8_t row, const std::uint8_t column){ return data[MAT_INDEX(row, column)]; } diff --git a/GCryptLib/test/Block.cpp b/GCryptLib/test/Block.cpp index 1de73c9..7ac92dc 100644 --- a/GCryptLib/test/Block.cpp +++ b/GCryptLib/test/Block.cpp @@ -4,6 +4,7 @@ #include #include #include +#include using namespace Leonetienne::GCrypt; @@ -705,3 +706,125 @@ TEST_CASE(__FILE__"/flip-bit", "[Block]") { REQUIRE(a.ToString() == compare); } +// Tests that bitshifts (to the left) work +TEST_CASE(__FILE__"/bitshift-left", "[Block]") { + + // Setup + srand(time(0)); + std::stringstream ss; + + for (std::size_t i = 0; i < 512; i++) { + ss << (rand()%2 == 0 ? '1' : '0'); + } + const std::string originalBits = ss.str(); + ss.str(""); + + // Shift string manually + std::string shiftedBits = originalBits; + shiftedBits.erase(0, 1); + ss << shiftedBits << originalBits[0]; + shiftedBits = ss.str(); + + // Create block of original bits + Block block(originalBits); + + // Exercise + block = block.ShiftBitsLeft(); + + // Verify + REQUIRE(block.ToString().length() == shiftedBits.length()); + REQUIRE(block.ToString() == shiftedBits); +} + +// Tests that inplace-bitshifts to the left do the exact same as copy bitshifts +TEST_CASE(__FILE__"/bitshift-left-inplace", "[Block]") { + + // Setup + srand(time(0)); + std::stringstream ss; + + for (std::size_t i = 0; i < 512; i++) { + ss << (rand()%2 == 0 ? '1' : '0'); + } + Block a(ss.str()); + + // Exercise + Block b = a.ShiftBitsLeft(); + a.ShiftBitsLeftInplace(); + + // Verify + REQUIRE(a == b); +} + +// Tests that bitshifts (to the right) work +TEST_CASE(__FILE__"/bitshift-right", "[Block]") { + + // Setup + srand(time(0)); + std::stringstream ss; + + for (std::size_t i = 0; i < 512; i++) { + ss << (rand()%2 == 0 ? '1' : '0'); + } + const std::string originalBits = ss.str(); + ss.str(""); + + // Shift string manually + std::string shiftedBits = originalBits; + shiftedBits.erase(shiftedBits.length() - 1); + ss << originalBits[originalBits.length()-1] << shiftedBits; + shiftedBits = ss.str(); + + // Create block of original bits + Block block(originalBits); + + // Exercise + block = block.ShiftBitsRight(); + + // Verify + REQUIRE(block.ToString().length() == shiftedBits.length()); + REQUIRE(block.ToString() == shiftedBits); +} + +// Tests that inplace-bitshifts to the right do the exact same as copy bitshifts +TEST_CASE(__FILE__"/bitshift-right-inplace", "[Block]") { + + // Setup + srand(time(0)); + std::stringstream ss; + + for (std::size_t i = 0; i < 512; i++) { + ss << (rand()%2 == 0 ? '1' : '0'); + } + Block a(ss.str()); + + // Exercise + Block b = a.ShiftBitsRight(); + a.ShiftBitsRightInplace(); + + // Verify + REQUIRE(a == b); +} + +// Tests that bitshifting undoes itself +TEST_CASE(__FILE__"/bitshifting-undoes-itself", "[Block]") { + + // Setup + Block a = Key::FromPassword("Halleluja"); + + const Block initial_a = a; + + // Exercise (mix-up) + for (std::size_t i = 0; i < 100; i++) { + a.ShiftBitsLeftInplace(); + } + + // Exercise (un-mix) + for (std::size_t i = 0; i < 100; i++) { + a.ShiftBitsRightInplace(); + } + + // Verify + REQUIRE(a == initial_a); +} + From edbf36eb6d23ca4015eec0c6c158498677b297b5 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Wed, 25 May 2022 13:05:25 +0200 Subject: [PATCH 041/110] Cipher now using new block class --- GCryptLib/include/GCrypt/Config.h | 2 +- GCryptLib/include/GCrypt/Util.h | 11 ++++ GCryptLib/include/GCrypt/Version.h | 2 +- GCryptLib/src/Feistel.cpp | 87 ++++++++++-------------------- 4 files changed, 41 insertions(+), 61 deletions(-) diff --git a/GCryptLib/include/GCrypt/Config.h b/GCryptLib/include/GCrypt/Config.h index 0bcac82..5340563 100644 --- a/GCryptLib/include/GCrypt/Config.h +++ b/GCryptLib/include/GCrypt/Config.h @@ -8,7 +8,7 @@ namespace Leonetienne::GCrypt { constexpr std::size_t BLOCK_SIZE = 512; // MUST BE > 2 - constexpr std::size_t N_ROUNDS = 10; + constexpr std::size_t N_ROUNDS = 6; } #endif diff --git a/GCryptLib/include/GCrypt/Util.h b/GCryptLib/include/GCrypt/Util.h index bd60300..5398e7f 100644 --- a/GCryptLib/include/GCrypt/Util.h +++ b/GCryptLib/include/GCrypt/Util.h @@ -18,6 +18,17 @@ namespace Leonetienne::GCrypt { return (denominator + (numerator % denominator)) % denominator; } + inline Block Shiftl(const Block& bits, const std::size_t amount) { + std::stringstream ss; + const std::string bitss = bits.ToString(); + + for (std::size_t i = 0; i < bitss.size(); i++) { + ss << bitss[Mod((int)(i + amount), (int)bitss.size())]; + } + + return Block(ss.str()); + } + //! Will perform a wrapping left-bitshift on a bitset template inline SecureBitset Shiftl(const SecureBitset& bits, const std::size_t amount) { diff --git a/GCryptLib/include/GCrypt/Version.h b/GCryptLib/include/GCrypt/Version.h index e6e5330..655c9f3 100644 --- a/GCryptLib/include/GCrypt/Version.h +++ b/GCryptLib/include/GCrypt/Version.h @@ -1,7 +1,7 @@ #ifndef GCRYPT_VERSION_H #define GCRYPT_VERSION_H -#define GCRYPT_VERSION 0.232 +#define GCRYPT_VERSION 0.233 #endif diff --git a/GCryptLib/src/Feistel.cpp b/GCryptLib/src/Feistel.cpp index 9f2d20d..cca9860 100644 --- a/GCryptLib/src/Feistel.cpp +++ b/GCryptLib/src/Feistel.cpp @@ -62,17 +62,19 @@ namespace Leonetienne::GCrypt { Halfblock Feistel::F(Halfblock m, const Key& key) { // Made-up F function - // Expand to full bitwidth Block m_expanded = ExpansionFunction(m); - // Shift to left by 1 - //m_expanded = Shiftl(m_expanded, 1); - m_expanded = (m_expanded); + // Mix up the block a bit + m_expanded.ShiftCellsRightInplace(); + m_expanded.ShiftRowsUpInplace(); - // Matrix-mult with key + // Matrix-mult with key (this is irreversible) m_expanded *= key; + // Now do a bitshift + m_expanded.ShiftBitsLeftInplace(); + // Non-linearly apply subsitution boxes std::stringstream ss; const std::string m_str = m_expanded.ToString(); @@ -180,65 +182,32 @@ namespace Leonetienne::GCrypt { ZeroKeyMemory(); roundKeys = Keyset(); - // Derive the initial two round keys + // Derive all round keys with simple matrix operations + roundKeys[0] = seedKey; - // Compress- substitute, and expand the seed key to form the initial and the second-initial round key - // This action is non-linear and irreversible, and thus strenghtens security. - Halfblock compressedSeed1 = CompressionFunction(seedKey); - //Halfblock compressedSeed2 = CompressionFunction(Shiftl(seedKey, 1)); // Shifting one key by 1 will result in a completely different compression - Halfblock compressedSeed2 = CompressionFunction((seedKey)); // Shifting one key by 1 will result in a completely different compression - - // To add further confusion, let's shift seed1 by 1 aswell (after compression, but before substitution) - // but only if the total number of bits set are a multiple of 3 - // if it is a multiple of 4, we'll shift it by 1 into the opposite direction - const std::size_t setBits1 = compressedSeed1.count(); - - if (setBits1 % 4 == 0) { - //compressedSeed1 = Shiftr(compressedSeed1, 1); - compressedSeed1 = (compressedSeed1); - } - else if (setBits1 % 3 == 0) { - compressedSeed1 = (compressedSeed1); - } - - // Now apply substitution - std::stringstream ssKey1; - std::stringstream ssKey2; - const std::string bitsKey1 = compressedSeed1.to_string(); - const std::string bitsKey2 = compressedSeed2.to_string(); - - for (std::size_t i = 0; i < HALFBLOCK_SIZE; i += 4) { - ssKey1 << SBox(bitsKey1.substr(i, 4)); - ssKey2 << SBox(bitsKey2.substr(i, 4)); - } - - compressedSeed1 = Halfblock(ssKey1.str()); - compressedSeed2 = Halfblock(ssKey2.str()); - - // Now extrapolate them to BLOCK_SIZE (key size) again - // Xor with the original seed key to get rid of the repititions caused by the expansion - roundKeys[0] = ExpansionFunction(compressedSeed1) ^ seedKey; - roundKeys[1] = ExpansionFunction(compressedSeed2) ^ seedKey; - - // Now derive all other round keys - - for (std::size_t i = 2; i < roundKeys.size(); i++) { + for (std::size_t i = 1; i < roundKeys.size(); i++) { // Initialize new round key with last round key - Block newKey = roundKeys[i - 1]; + const Key& lastKey = roundKeys[i - 1]; + roundKeys[i] = lastKey; - // Shift to left by how many bits are set, modulo 8 - //newKey = Shiftl(newKey, newKey.count() % 8); // This action is irreversible - newKey = (newKey); // This action is irreversible + // Stir it good + roundKeys[i].ShiftRowsUpInplace(); - // Split into two halfblocks, - // apply F() to one halfblock with rk[i-2], - // xor the other one with it - // and put them back together - auto halfkeys = FeistelSplit(newKey); - Halfblock halfkey1 = F(halfkeys.first, roundKeys[i - 2]); - Halfblock halfkey2 = halfkeys.second ^ halfkey1; // I know this is reversible, but it helps to diffuse future round keys. + // Bitshift and matrix-mult 3 times + // (each time jumbles it up pretty good) + // This is irreversible + roundKeys[i].ShiftBitsRightInplace(); + roundKeys[i] *= lastKey; + roundKeys[i].ShiftBitsRightInplace(); + roundKeys[i] *= lastKey; + roundKeys[i].ShiftBitsRightInplace(); + roundKeys[i] *= lastKey; - roundKeys[i] = Key(FeistelCombine(halfkey1, halfkey2)); + // Lastly, do apply some cell shifting, and other mutations + roundKeys[i].ShiftCellsRightInplace(); + roundKeys[i] += lastKey; + roundKeys[i].ShiftColumnsRightInplace(); + roundKeys[i] ^= lastKey; } return; From 3630243d8db023b4e1de14bfe86c454fda440ad9 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Wed, 25 May 2022 14:57:40 +0200 Subject: [PATCH 042/110] Fix macos compile issue --- GCryptLib/include/GCrypt/GPrng.h | 2 +- GCryptLib/src/Block.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GCryptLib/include/GCrypt/GPrng.h b/GCryptLib/include/GCrypt/GPrng.h index 99e9a6a..b037a53 100644 --- a/GCryptLib/include/GCrypt/GPrng.h +++ b/GCryptLib/include/GCrypt/GPrng.h @@ -32,7 +32,7 @@ namespace Leonetienne::GCrypt { // Pull the required amount of bits std::stringstream ss; for (std::size_t i = 0; i < sizeof(T)*8; i++) { - ss << GetBit() ? '1' : '0'; + ss << (GetBit() ? '1' : '0'); } // Transform to bytes diff --git a/GCryptLib/src/Block.cpp b/GCryptLib/src/Block.cpp index ac5a648..a9b2a23 100644 --- a/GCryptLib/src/Block.cpp +++ b/GCryptLib/src/Block.cpp @@ -532,7 +532,7 @@ namespace Leonetienne::GCrypt { std::ostream& operator<<(std::ostream& os, const Block& b) { for (std::size_t i = 0; i < b.data.size(); i++) { - os << std::bitset(b.data[i]).to_string(); + os << std::bitset(b.data[i]).to_string(); } return os; } From f7d80936682d69f9077e23817a876863c239da03 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Wed, 25 May 2022 16:38:16 +0200 Subject: [PATCH 043/110] Templatified block class --- GCryptLib/include/GCrypt/Block.h | 99 ++++++++------- GCryptLib/src/Block.cpp | 207 +++++++++++++++++++------------ 2 files changed, 183 insertions(+), 123 deletions(-) diff --git a/GCryptLib/include/GCrypt/Block.h b/GCryptLib/include/GCrypt/Block.h index b28748a..e87d337 100644 --- a/GCryptLib/include/GCrypt/Block.h +++ b/GCryptLib/include/GCrypt/Block.h @@ -5,24 +5,26 @@ #include #include #include +#include namespace Leonetienne::GCrypt { /* This class represents a block of data, * and provides functions to manipulate it */ - class Block { + template + class Basic_Block { public: //! Will constuct an uninitialized data block - Block(); + Basic_Block(); //! Will construct this block from a string like "101010".. Length MUST be 512. - Block(const std::string& other); + Basic_Block(const std::string& other); //! Copy-ctor - Block(const Block& other); + Basic_Block(const Basic_Block& other); - ~Block(); + ~Basic_Block(); //! Will construct this block from a string like "011101..". Length MUST be 512. void FromString(const std::string& str); @@ -35,90 +37,90 @@ namespace Leonetienne::GCrypt { //! Since the matrices values are pretty much sudo-random, //! they will most likely integer-overflow. //! So see this as a one-way function. - [[nodiscard]] Block MMul(const Block& other) const; - [[nodiscard]] Block operator*(const Block& other) const; + [[nodiscard]] Basic_Block MMul(const Basic_Block& other) const; + [[nodiscard]] Basic_Block operator*(const Basic_Block& other) const; //! Will matrix-multiply two blocks together, //! and directly write into this same block. //! Since the matrices values are pretty much sudo-random, //! they will most likely integer-overflow. //! So see this as a one-way function. - void MMulInplace(const Block& other); - Block& operator*=(const Block& other); + void MMulInplace(const Basic_Block& other); + Basic_Block& operator*=(const Basic_Block& other); //! Will xor two blocks together - [[nodiscard]] Block Xor(const Block& other) const; + [[nodiscard]] Basic_Block Xor(const Basic_Block& other) const; //! Will xor two blocks together - [[nodiscard]] Block operator^(const Block& other) const; + [[nodiscard]] Basic_Block operator^(const Basic_Block& other) const; //! Will xor two blocks together, inplace - void XorInplace(const Block& other); + void XorInplace(const Basic_Block& other); //! Will xor two blocks together, inplace - Block& operator^=(const Block& other); + Basic_Block& operator^=(const Basic_Block& other); //! Will add all the integer making up this block, one by one - [[nodiscard]] Block Add(const Block& other) const; + [[nodiscard]] Basic_Block Add(const Basic_Block& other) const; //! Will add all the integer making up this block, one by one - [[nodiscard]] Block operator+(const Block& other) const; + [[nodiscard]] Basic_Block operator+(const Basic_Block& other) const; //! Will add all the integer making up this block, one by one, inplace - void AddInplace(const Block& other); + void AddInplace(const Basic_Block& other); //! Will add all the integer making up this block, one by one, inplace - Block& operator+=(const Block& other); + Basic_Block& operator+=(const Basic_Block& other); //! Will subtract all the integer making up this block, one by one - [[nodiscard]] Block Sub(const Block& other) const; + [[nodiscard]] Basic_Block Sub(const Basic_Block& other) const; //! Will subtract all the integer making up this block, one by one - [[nodiscard]] Block operator-(const Block& other) const; + [[nodiscard]] Basic_Block operator-(const Basic_Block& other) const; //! Will subtract all the integer making up this block, one by one, inplace - void SubInplace(const Block& other); + void SubInplace(const Basic_Block& other); //! Will subtract all the integer making up this block, one by one, inplace - Block& operator-=(const Block& other); + Basic_Block& operator-=(const Basic_Block& other); //! Will shift rows upwards by 1 - [[nodiscard]] Block ShiftRowsUp() const; + [[nodiscard]] Basic_Block ShiftRowsUp() const; //! Will shift rows upwards by 1 void ShiftRowsUpInplace(); //! Will shift matrix rows downwards by 1 - [[nodiscard]] Block ShiftRowsDown() const; + [[nodiscard]] Basic_Block ShiftRowsDown() const; //! Will shift matrix rows downwards by 1 void ShiftRowsDownInplace(); //! Will shift matrix columns to the left by 1 - [[nodiscard]] Block ShiftColumnsLeft() const; + [[nodiscard]] Basic_Block ShiftColumnsLeft() const; //! Will shift matrix columns to the left by 1 void ShiftColumnsLeftInplace(); //! Will shift matrix columns to the right by 1 - [[nodiscard]] Block ShiftColumnsRight() const; + [[nodiscard]] Basic_Block ShiftColumnsRight() const; //! Will shift matrix columns to the right by 1 void ShiftColumnsRightInplace(); //! Will shift array cells to the left by 1 - [[nodiscard]] Block ShiftCellsLeft() const; + [[nodiscard]] Basic_Block ShiftCellsLeft() const; //! Will shift array cells to the left by 1 void ShiftCellsLeftInplace(); //! Will shift array cells to the right by 1 - [[nodiscard]] Block ShiftCellsRight() const; + [[nodiscard]] Basic_Block ShiftCellsRight() const; //! Will shift array cells to the right by 1 void ShiftCellsRightInplace(); //! Will copy a block - Block& operator=(const Block& other); + Basic_Block& operator=(const Basic_Block& other); //! Will compare whether or not two blocks are equal - [[nodiscard]] bool operator==(const Block& other) const; + [[nodiscard]] bool operator==(const Basic_Block& other) const; //! Will compare whether or not two blocks are unequal - [[nodiscard]] bool operator!=(const Block& other) const; + [[nodiscard]] bool operator!=(const Basic_Block& other) const; //! Will zero all data void Reset(); @@ -133,46 +135,59 @@ namespace Leonetienne::GCrypt { void FlipBit(const std::size_t index); //! Will shift all bits to the left by 1 - [[nodiscard]] Block ShiftBitsLeft() const; + [[nodiscard]] Basic_Block ShiftBitsLeft() const; //! Will shift all bits to the left by 1, inplace void ShiftBitsLeftInplace(); //! Will shift all bits to the right by 1 - [[nodiscard]] Block ShiftBitsRight() const; + [[nodiscard]] Basic_Block ShiftBitsRight() const; //! Will shift all bits to the right by 1, inplace void ShiftBitsRightInplace(); //! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3) - [[nodiscard]] std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column); + [[nodiscard]] T& Get(const std::uint8_t row, const std::uint8_t column); //! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3) - [[nodiscard]] const std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column) const; + [[nodiscard]] const T& Get(const std::uint8_t row, const std::uint8_t column) const; //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) - [[nodiscard]] std::uint32_t& Get(const std::uint8_t index); + [[nodiscard]] T& Get(const std::uint8_t index); //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) - [[nodiscard]] const std::uint32_t& Get(const std::uint8_t index) const; + [[nodiscard]] const T& Get(const std::uint8_t index) const; //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) - [[nodiscard]] std::uint32_t& operator[](const std::uint8_t index); + [[nodiscard]] T& operator[](const std::uint8_t index); //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) - [[nodiscard]] const std::uint32_t& operator[](const std::uint8_t index) const; + [[nodiscard]] const T& operator[](const std::uint8_t index) const; - static constexpr std::size_t CHUNK_SIZE = sizeof(std::uint32_t); + static constexpr std::size_t CHUNK_SIZE = sizeof(T); static constexpr std::size_t CHUNK_SIZE_BITS = CHUNK_SIZE * 8; - friend std::ostream& operator<<(std::ostream& os, const Block& b); + friend std::ostream& operator<<(std::ostream& os, const Basic_Block& b) { + for (std::size_t i = 0; i < b.data.size(); i++) { + os << std::bitset::CHUNK_SIZE_BITS>(b.data[i]).to_string(); + } + return os; + } private: - std::array data; + std::array data; }; -} + // Instantiate templates + template class Basic_Block; + //template class Basic_Block; + //! This a full-sizes 512-bit block + typedef Basic_Block Block; + + //! This is a half-block used within the feistel class + //typedef Basic_Block Halfblock; +} #endif diff --git a/GCryptLib/src/Block.cpp b/GCryptLib/src/Block.cpp index 39cf60b..6398949 100644 --- a/GCryptLib/src/Block.cpp +++ b/GCryptLib/src/Block.cpp @@ -2,7 +2,6 @@ #include "GCrypt/Config.h" #include "GCrypt/Util.h" #include -#include #include #include @@ -12,18 +11,22 @@ namespace Leonetienne::GCrypt { - Block::Block() { + template + Basic_Block::Basic_Block() { } - Block::Block(const std::string& str) { + template + Basic_Block::Basic_Block(const std::string& str) { FromString(str); } - Block::Block(const Block& other) { + template + Basic_Block::Basic_Block(const Basic_Block& other) { data = other.data; } - void Block::FromString(const std::string& str) { + template + void Basic_Block::FromString(const std::string& str) { assert(str.length() == BLOCK_SIZE); @@ -36,7 +39,8 @@ namespace Leonetienne::GCrypt { return; } - std::string Block::ToString() const { + template + std::string Basic_Block::ToString() const { std::stringstream ss; for (std::size_t i = 0; i < data.size(); i++) { @@ -45,9 +49,10 @@ namespace Leonetienne::GCrypt { return ss.str(); } - Block Block::MMul(const Block& o) const { + template + Basic_Block Basic_Block::MMul(const Basic_Block& o) const { - Block m; + Basic_Block m; // Maybe pre-calculate the 1d-index...? @@ -74,13 +79,15 @@ namespace Leonetienne::GCrypt { return m; } - Block Block::operator*(const Block& other) const { + template + Basic_Block Basic_Block::operator*(const Basic_Block& other) const { return this->MMul(other); } - void Block::MMulInplace(const Block& o) { + template + void Basic_Block::MMulInplace(const Basic_Block& o) { - Block m = *this; + Basic_Block m = *this; // Maybe pre-calculate the 1d-index...? @@ -107,86 +114,102 @@ namespace Leonetienne::GCrypt { return; } - Block& Block::operator*=(const Block& other) { + template + Basic_Block& Basic_Block::operator*=(const Basic_Block& other) { MMulInplace(other); return *this; } - Block Block::Xor(const Block& other) const { + template + Basic_Block Basic_Block::Xor(const Basic_Block& other) const { - Block m; + Basic_Block m; for (std::size_t i = 0; i < data.size(); i++) { m.Get(i) = this->Get(i) ^ other.Get(i); } return m; } - Block Block::operator^(const Block& other) const { + template + Basic_Block Basic_Block::operator^(const Basic_Block& other) const { return Xor(other); } - void Block::XorInplace(const Block& other) { + template + void Basic_Block::XorInplace(const Basic_Block& other) { for (std::size_t i = 0; i < data.size(); i++) { this->Get(i) ^= other.Get(i); } return; } - Block& Block::operator^=(const Block& other) { + template + Basic_Block& Basic_Block::operator^=(const Basic_Block& other) { XorInplace(other); - return *this; } - Block Block::Add(const Block& other) const { + return *this; + } - Block m; + template + Basic_Block Basic_Block::Add(const Basic_Block& other) const { + + Basic_Block m; for (std::size_t i = 0; i < data.size(); i++) { m.Get(i) = this->Get(i) + other.Get(i); } return m; } - Block Block::operator+(const Block& other) const { + template + Basic_Block Basic_Block::operator+(const Basic_Block& other) const { return Add(other); } - void Block::AddInplace(const Block& other) { + template + void Basic_Block::AddInplace(const Basic_Block& other) { for (std::size_t i = 0; i < data.size(); i++) { this->Get(i) += other.Get(i); } return; } - Block& Block::operator+=(const Block& other) { + template + Basic_Block& Basic_Block::operator+=(const Basic_Block& other) { AddInplace(other); return *this; } - Block Block::Sub(const Block& other) const { + template + Basic_Block Basic_Block::Sub(const Basic_Block& other) const { - Block m; + Basic_Block m; for (std::size_t i = 0; i < data.size(); i++) { m.Get(i) = this->Get(i) - other.Get(i); } return m; } - Block Block::operator-(const Block& other) const { + template + Basic_Block Basic_Block::operator-(const Basic_Block& other) const { return Sub(other); } - void Block::SubInplace(const Block& other) { + template + void Basic_Block::SubInplace(const Basic_Block& other) { for (std::size_t i = 0; i < data.size(); i++) { this->Get(i) -= other.Get(i); } return; } - Block& Block::operator-=(const Block& other) { + template + Basic_Block& Basic_Block::operator-=(const Basic_Block& other) { SubInplace(other); return *this; } - void Block::ShiftRowsUpInplace() { - Block tmp = *this; + template + void Basic_Block::ShiftRowsUpInplace() { + Basic_Block tmp = *this; Get(MAT_INDEX(0, 0)) = tmp.Get(MAT_INDEX(1, 0)); Get(MAT_INDEX(0, 1)) = tmp.Get(MAT_INDEX(1, 1)); @@ -211,8 +234,9 @@ namespace Leonetienne::GCrypt { return; } - Block Block::ShiftRowsUp() const { - Block b; + template + Basic_Block Basic_Block::ShiftRowsUp() const { + Basic_Block b; b.Get(MAT_INDEX(0, 0)) = Get(MAT_INDEX(1, 0)); b.Get(MAT_INDEX(0, 1)) = Get(MAT_INDEX(1, 1)); @@ -237,8 +261,9 @@ namespace Leonetienne::GCrypt { return b; } - void Block::ShiftRowsDownInplace() { - Block tmp = *this; + template + void Basic_Block::ShiftRowsDownInplace() { + Basic_Block tmp = *this; Get(MAT_INDEX(0, 0)) = tmp.Get(MAT_INDEX(3, 0)); Get(MAT_INDEX(0, 1)) = tmp.Get(MAT_INDEX(3, 1)); @@ -263,8 +288,9 @@ namespace Leonetienne::GCrypt { return; } - Block Block::ShiftRowsDown() const { - Block b; + template + Basic_Block Basic_Block::ShiftRowsDown() const { + Basic_Block b; b.Get(MAT_INDEX(0, 0)) = Get(MAT_INDEX(3, 0)); b.Get(MAT_INDEX(0, 1)) = Get(MAT_INDEX(3, 1)); @@ -289,8 +315,9 @@ namespace Leonetienne::GCrypt { return b; } - void Block::ShiftColumnsLeftInplace() { - Block tmp = *this; + template + void Basic_Block::ShiftColumnsLeftInplace() { + Basic_Block tmp = *this; Get(MAT_INDEX(0, 0)) = tmp.Get(MAT_INDEX(0, 1)); Get(MAT_INDEX(1, 0)) = tmp.Get(MAT_INDEX(1, 1)); @@ -315,8 +342,9 @@ namespace Leonetienne::GCrypt { return; } - Block Block::ShiftColumnsLeft() const { - Block b; + template + Basic_Block Basic_Block::ShiftColumnsLeft() const { + Basic_Block b; b.Get(MAT_INDEX(0, 0)) = Get(MAT_INDEX(0, 1)); b.Get(MAT_INDEX(1, 0)) = Get(MAT_INDEX(1, 1)); @@ -341,8 +369,9 @@ namespace Leonetienne::GCrypt { return b; } - void Block::ShiftColumnsRightInplace() { - Block tmp = *this; + template + void Basic_Block::ShiftColumnsRightInplace() { + Basic_Block tmp = *this; Get(MAT_INDEX(0, 1)) = tmp.Get(MAT_INDEX(0, 0)); Get(MAT_INDEX(1, 1)) = tmp.Get(MAT_INDEX(1, 0)); @@ -367,8 +396,9 @@ namespace Leonetienne::GCrypt { return; } - Block Block::ShiftColumnsRight() const { - Block b; + template + Basic_Block Basic_Block::ShiftColumnsRight() const { + Basic_Block b; b.Get(MAT_INDEX(0, 1)) = Get(MAT_INDEX(0, 0)); b.Get(MAT_INDEX(1, 1)) = Get(MAT_INDEX(1, 0)); @@ -393,8 +423,9 @@ namespace Leonetienne::GCrypt { return b; } - void Block::ShiftCellsLeftInplace() { - Block tmp = *this; + template + void Basic_Block::ShiftCellsLeftInplace() { + Basic_Block tmp = *this; Get(15) = tmp.Get(0); @@ -405,8 +436,9 @@ namespace Leonetienne::GCrypt { return; } - Block Block::ShiftCellsLeft() const { - Block b; + template + Basic_Block Basic_Block::ShiftCellsLeft() const { + Basic_Block b; b.Get(15) = Get(0); @@ -417,8 +449,9 @@ namespace Leonetienne::GCrypt { return b; } - void Block::ShiftCellsRightInplace() { - Block tmp = *this; + template + void Basic_Block::ShiftCellsRightInplace() { + Basic_Block tmp = *this; Get(0) = tmp.Get(15); @@ -429,8 +462,9 @@ namespace Leonetienne::GCrypt { return; } - Block Block::ShiftCellsRight() const { - Block b; + template + Basic_Block Basic_Block::ShiftCellsRight() const { + Basic_Block b; b.Get(0) = Get(15); @@ -441,12 +475,14 @@ namespace Leonetienne::GCrypt { return b; } - Block& Block::operator=(const Block& other) { + template + Basic_Block& Basic_Block::operator=(const Basic_Block& other) { data = other.data; return *this; } - bool Block::GetBit(const std::size_t index) const { + template + bool Basic_Block::GetBit(const std::size_t index) const { // Fetch index of integer the bit is located in const std::size_t intIndex = index / CHUNK_SIZE_BITS; @@ -459,7 +495,8 @@ namespace Leonetienne::GCrypt { return data[intIndex] & bitmask; } - void Block::SetBit(const std::size_t index, const bool state) { + template + void Basic_Block::SetBit(const std::size_t index, const bool state) { // Fetch index of integer the bit is located in const std::size_t intIndex = index / CHUNK_SIZE_BITS; @@ -481,7 +518,8 @@ namespace Leonetienne::GCrypt { return; } - void Block::FlipBit(const std::size_t index) { + template + void Basic_Block::FlipBit(const std::size_t index) { // Fetch index of integer the bit is located in const std::size_t intIndex = index / CHUNK_SIZE_BITS; @@ -496,8 +534,9 @@ namespace Leonetienne::GCrypt { return; } - Block Block::ShiftBitsLeft() const { - Block b; + template + Basic_Block Basic_Block::ShiftBitsLeft() const { + Basic_Block b; // First, copy this block over b = *this; @@ -529,8 +568,9 @@ namespace Leonetienne::GCrypt { return b; } - void Block::ShiftBitsLeftInplace() { - Block tmp = *this; + template + void Basic_Block::ShiftBitsLeftInplace() { + Basic_Block tmp = *this; // Then, shift all integers individually for (std::size_t i = 0; i < data.size(); i++) { @@ -559,8 +599,9 @@ namespace Leonetienne::GCrypt { return; } - Block Block::ShiftBitsRight() const { - Block b; + template + Basic_Block Basic_Block::ShiftBitsRight() const { + Basic_Block b; // First, copy this block over b = *this; @@ -592,8 +633,9 @@ namespace Leonetienne::GCrypt { return b; } - void Block::ShiftBitsRightInplace() { - Block tmp = *this; + template + void Basic_Block::ShiftBitsRightInplace() { + Basic_Block tmp = *this; // Then, shift all integers individually for (std::size_t i = 0; i < data.size(); i++) { @@ -622,56 +664,59 @@ namespace Leonetienne::GCrypt { return; } - std::uint32_t& Block::Get(const std::uint8_t row, const std::uint8_t column){ + template + T& Basic_Block::Get(const std::uint8_t row, const std::uint8_t column){ return data[MAT_INDEX(row, column)]; } - const std::uint32_t& Block::Get(const std::uint8_t row, const std::uint8_t column) const { + template + const T& Basic_Block::Get(const std::uint8_t row, const std::uint8_t column) const { return data[MAT_INDEX(row, column)]; } - std::uint32_t& Block::Get(const std::uint8_t index) { + template + T& Basic_Block::Get(const std::uint8_t index) { return data[index]; } - const std::uint32_t& Block::Get(const std::uint8_t index) const { + template + const T& Basic_Block::Get(const std::uint8_t index) const { return data[index]; } - std::uint32_t& Block::operator[](const std::uint8_t index) { + template + T& Basic_Block::operator[](const std::uint8_t index) { return data[index]; } - const std::uint32_t& Block::operator[](const std::uint8_t index) const { + template + const T& Basic_Block::operator[](const std::uint8_t index) const { return data[index]; } - bool Block::operator==(const Block& other) const { + template + bool Basic_Block::operator==(const Basic_Block& other) const { return data == other.data; } - bool Block::operator!=(const Block& other) const { + template + bool Basic_Block::operator!=(const Basic_Block& other) const { return data != other.data; } - std::ostream& operator<<(std::ostream& os, const Block& b) { - for (std::size_t i = 0; i < b.data.size(); i++) { - os << std::bitset(b.data[i]).to_string(); - } - return os; - } - #if defined _WIN32 || defined _WIN64 #pragma optimize("", off ) #elif defined __GNUG__ #pragma GCC push_options #pragma GCC optimize ("O0") #endif - Block::~Block() { + template + Basic_Block::~Basic_Block() { Reset(); } - void Block::Reset() { + template + void Basic_Block::Reset() { memset(data.data(), 0, CHUNK_SIZE*data.size()); return; } From 1f913b3a542a8db0a852f40b7a24ddbde4b9b81d Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Wed, 25 May 2022 16:51:38 +0200 Subject: [PATCH 044/110] Typo in comment --- GCryptLib/include/GCrypt/Block.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GCryptLib/include/GCrypt/Block.h b/GCryptLib/include/GCrypt/Block.h index e87d337..36d856f 100644 --- a/GCryptLib/include/GCrypt/Block.h +++ b/GCryptLib/include/GCrypt/Block.h @@ -182,7 +182,7 @@ namespace Leonetienne::GCrypt { template class Basic_Block; //template class Basic_Block; - //! This a full-sizes 512-bit block + //! This a full-sized 512-bit block typedef Basic_Block Block; //! This is a half-block used within the feistel class From 8ddd9d6bfb2c7f2d866abe67e9b460be780cb30f Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Thu, 26 May 2022 00:55:24 +0200 Subject: [PATCH 045/110] Replaced halfblock with instanciation of Basic_Block --- GCryptLib/include/GCrypt/Block.h | 5 +- GCryptLib/include/GCrypt/Config.h | 3 - GCryptLib/include/GCrypt/Feistel.h | 1 - GCryptLib/include/GCrypt/Halfblock.h | 9 - GCryptLib/include/GCrypt/SecureBitset.h | 292 ------------------------ GCryptLib/include/GCrypt/Util.h | 38 --- GCryptLib/src/Block.cpp | 2 +- GCryptLib/src/Feistel.cpp | 10 +- GCryptLib/src/GHash.cpp | 5 +- GCryptLib/src/GPrng.cpp | 8 +- GCryptLib/src/GWrapper.cpp | 5 +- GCryptLib/src/Key.cpp | 8 +- GCryptLib/src/Util.cpp | 4 +- 13 files changed, 25 insertions(+), 365 deletions(-) delete mode 100644 GCryptLib/include/GCrypt/Halfblock.h delete mode 100644 GCryptLib/include/GCrypt/SecureBitset.h diff --git a/GCryptLib/include/GCrypt/Block.h b/GCryptLib/include/GCrypt/Block.h index 36d856f..64038a7 100644 --- a/GCryptLib/include/GCrypt/Block.h +++ b/GCryptLib/include/GCrypt/Block.h @@ -165,6 +165,7 @@ namespace Leonetienne::GCrypt { static constexpr std::size_t CHUNK_SIZE = sizeof(T); static constexpr std::size_t CHUNK_SIZE_BITS = CHUNK_SIZE * 8; + static constexpr std::size_t BLOCK_SIZE_BITS = CHUNK_SIZE_BITS * 16; friend std::ostream& operator<<(std::ostream& os, const Basic_Block& b) { for (std::size_t i = 0; i < b.data.size(); i++) { @@ -180,13 +181,13 @@ namespace Leonetienne::GCrypt { // Instantiate templates template class Basic_Block; - //template class Basic_Block; + template class Basic_Block; //! This a full-sized 512-bit block typedef Basic_Block Block; //! This is a half-block used within the feistel class - //typedef Basic_Block Halfblock; + typedef Basic_Block Halfblock; } #endif diff --git a/GCryptLib/include/GCrypt/Config.h b/GCryptLib/include/GCrypt/Config.h index 5340563..39d44c3 100644 --- a/GCryptLib/include/GCrypt/Config.h +++ b/GCryptLib/include/GCrypt/Config.h @@ -4,9 +4,6 @@ #include namespace Leonetienne::GCrypt { - // MUST BE A POWER OF 2 > 4 - constexpr std::size_t BLOCK_SIZE = 512; - // MUST BE > 2 constexpr std::size_t N_ROUNDS = 6; } diff --git a/GCryptLib/include/GCrypt/Feistel.h b/GCryptLib/include/GCrypt/Feistel.h index 50bd4dd..cb7d35f 100644 --- a/GCryptLib/include/GCrypt/Feistel.h +++ b/GCryptLib/include/GCrypt/Feistel.h @@ -4,7 +4,6 @@ #include "GCrypt/Keyset.h" #include "GCrypt/Block.h" #include "GCrypt/Key.h" -#include "GCrypt/Halfblock.h" namespace Leonetienne::GCrypt { /** Class to perform a feistel block chipher diff --git a/GCryptLib/include/GCrypt/Halfblock.h b/GCryptLib/include/GCrypt/Halfblock.h deleted file mode 100644 index 4be13a0..0000000 --- a/GCryptLib/include/GCrypt/Halfblock.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include -#include "GCrypt/SecureBitset.h" -#include "GCrypt/Config.h" - -namespace Leonetienne::GCrypt { - constexpr std::size_t HALFBLOCK_SIZE = (BLOCK_SIZE / 2); - typedef SecureBitset Halfblock; -} diff --git a/GCryptLib/include/GCrypt/SecureBitset.h b/GCryptLib/include/GCrypt/SecureBitset.h deleted file mode 100644 index e288b13..0000000 --- a/GCryptLib/include/GCrypt/SecureBitset.h +++ /dev/null @@ -1,292 +0,0 @@ -#ifndef GCRYPT_SECUREBITSET_H -#define GCRYPT_SECUREBITSET_H - -#include -#include -#include -#include - -namespace Leonetienne::GCrypt { - /** Wrapper for std::bitset that zeroes memory upon deletion. - * This does not include ALL methods, but the ones needed. - * - * Just creating a specialization of std::bitset does not work. - */ - template - class SecureBitset { - public: - explicit SecureBitset(); - explicit SecureBitset(const std::string& str); - explicit SecureBitset(const long long int i); - - ~SecureBitset(); - - bool operator==(const SecureBitset& other) const; - bool operator!=(const SecureBitset& other) const; - bool operator[](const std::size_t) const; - bool test(const std::size_t index) const; - bool all() const; - bool any() const; - bool none() const; - std::size_t count() const; - std::size_t size() const; - SecureBitset& operator&=(const SecureBitset& other); - SecureBitset& operator|=(const SecureBitset& other); - SecureBitset& operator^=(const SecureBitset& other); - SecureBitset operator&(const SecureBitset& other); - SecureBitset operator|(const SecureBitset& other); - SecureBitset operator^(const SecureBitset& other) const; - SecureBitset operator~() const; - SecureBitset& operator<<=(const std::size_t offset); - SecureBitset& operator>>=(const std::size_t offset); - SecureBitset operator<<(const std::size_t offset) const; - SecureBitset operator>>(const std::size_t offset) const; - SecureBitset& set(); - SecureBitset& set(const std::size_t index, bool value = true); - SecureBitset& reset(); - SecureBitset& reset(const std::size_t index); - SecureBitset& flip(); - SecureBitset& flip(const std::size_t index); - std::string to_string() const; - unsigned long to_ulong() const; - unsigned long long to_ullong() const; - - std::bitset& Get(); - const std::bitset& Get() const; - - private: - std::bitset bitset; -}; - - template - inline SecureBitset::SecureBitset() - : - bitset() { - return; - } - - template - inline SecureBitset::SecureBitset(const std::string& str) - : - bitset(str) { - return; - } - - template - inline SecureBitset::SecureBitset(const long long int i) - : - bitset(i) { - return; - } - - - // Don't optimize the destructor out!!! - // These pragmas only work for MSVC and g++, as far as i know. Beware!!! -#if defined _WIN32 || defined _WIN64 -#pragma optimize("", off ) -#elif defined __GNUG__ -#pragma GCC push_options -#pragma GCC optimize ("O0") -#endif - template - inline SecureBitset::~SecureBitset() { - bitset.reset(); - return; - } -#if defined _WIN32 || defined _WIN64 -#pragma optimize("", on ) -#elif defined __GNUG__ -#pragma GCC pop_options -#endif - - template - inline bool SecureBitset::operator==(const SecureBitset& other) const { - return bitset == other.bitset; - } - - template - inline bool SecureBitset::operator!=(const SecureBitset& other) const { - return bitset != other.bitset; - } - - template - inline bool SecureBitset::operator[](const std::size_t index) const { - return bitset[index]; - } - - template - inline bool SecureBitset::test(const std::size_t index) const { - return bitset.test(index); - } - - template - inline bool SecureBitset::all() const { - return bitset.all(); - } - - template - inline bool SecureBitset::any() const { - return bitset.any(); - } - - template - inline bool SecureBitset::none() const { - return bitset.none(); - } - - template - inline std::size_t SecureBitset::count() const { - return bitset.count(); - } - - template - inline std::size_t SecureBitset::size() const { - return bitset.count(); - } - - template - inline SecureBitset& SecureBitset::operator&=(const SecureBitset& other) { - bitset &= other.bitset; - return *this; - } - - template - inline SecureBitset& SecureBitset::operator|=(const SecureBitset& other) { - bitset |= other.bitset; - return *this; - } - - template - inline SecureBitset& SecureBitset::operator^=(const SecureBitset& other) { - bitset ^= other.bitset; - return *this; - } - - template - inline SecureBitset SecureBitset::operator&(const SecureBitset& other) { - SecureBitset bs; - bs.bitset = bitset & other.bitset; - return bs; - } - - template - inline SecureBitset SecureBitset::operator|(const SecureBitset& other) { - SecureBitset bs; - bs.bitset = bitset | other.bitset; - return bs; - } - - template - inline SecureBitset SecureBitset::operator^(const SecureBitset& other) const { - SecureBitset bs; - bs.bitset = bitset ^ other.bitset; - return bs; - } - - template - inline SecureBitset SecureBitset::operator~() const { - SecureBitset bs; - bs.bitset = ~bitset; - return bs; - } - - template - inline SecureBitset& SecureBitset::operator<<=(const std::size_t offset) { - bitset <<= offset; - return *this; - } - - template - inline SecureBitset& SecureBitset::operator>>=(const std::size_t offset) { - bitset >>= offset; - return *this; - } - - template - inline SecureBitset SecureBitset::operator<<(const std::size_t offset) const { - SecureBitset bs; - bs.bitset = bitset << offset; - return bs; - } - - template - inline SecureBitset SecureBitset::operator>>(const std::size_t offset) const { - SecureBitset bs; - bs.bitset = bitset >> offset; - return bs; - } - - template - inline SecureBitset& SecureBitset::set() { - bitset.set(); - return *this; - } - - template - inline SecureBitset& SecureBitset::set(const std::size_t index, bool value) { - bitset.set(index, value); - return *this; - } - - template - inline SecureBitset& SecureBitset::reset() { - bitset.reset(); - return *this; - } - - template - inline SecureBitset& SecureBitset::reset(const std::size_t index) { - bitset.reset(index); - return *this; - } - - template - inline SecureBitset& SecureBitset::flip() { - bitset.flip(); - return *this; - } - - template - inline SecureBitset& SecureBitset::flip(const std::size_t index) { - bitset.flip(index); - return *this; - } - - template - inline std::string SecureBitset::to_string() const { - return bitset.to_string(); - } - - template - inline unsigned long SecureBitset::to_ulong() const { - return bitset.to_ulong(); - } - - template - inline unsigned long long SecureBitset::to_ullong() const { - return bitset.to_ullong(); - } - - template - inline std::bitset& SecureBitset::Get() { - return bitset; - } - - template - inline const std::bitset& SecureBitset::Get() const { - return bitset; - } - - template - inline std::ostream& operator<<(std::ostream& ofs, const SecureBitset& bs) { - return ofs << bs.Get(); - } - - template - inline std::istream& operator>>(std::istream& ifs, const SecureBitset& bs) { - return ifs >> bs.Get(); - } -} - -#endif - diff --git a/GCryptLib/include/GCrypt/Util.h b/GCryptLib/include/GCrypt/Util.h index 5398e7f..adb1bf2 100644 --- a/GCryptLib/include/GCrypt/Util.h +++ b/GCryptLib/include/GCrypt/Util.h @@ -5,7 +5,6 @@ #include #include #include -#include "GCrypt/SecureBitset.h" #include "GCrypt/Block.h" #include "GCrypt/Flexblock.h" #include "GCrypt/Config.h" @@ -18,43 +17,6 @@ namespace Leonetienne::GCrypt { return (denominator + (numerator % denominator)) % denominator; } - inline Block Shiftl(const Block& bits, const std::size_t amount) { - std::stringstream ss; - const std::string bitss = bits.ToString(); - - for (std::size_t i = 0; i < bitss.size(); i++) { - ss << bitss[Mod((int)(i + amount), (int)bitss.size())]; - } - - return Block(ss.str()); - } - - //! Will perform a wrapping left-bitshift on a bitset - template - inline SecureBitset Shiftl(const SecureBitset& bits, const std::size_t amount) { - std::stringstream ss; - const std::string bitss = bits.to_string(); - - for (std::size_t i = 0; i < bitss.size(); i++) { - ss << bitss[Mod((int)(i + amount), (int)bitss.size())]; - } - - return SecureBitset(ss.str()); - } - - //! Will perform a wrapping right-bitshift on a bitset - template - inline SecureBitset Shiftr(const SecureBitset& bits, const std::size_t amount) { - std::stringstream ss; - const std::string bitss = bits.to_string(); - - for (std::size_t i = 0; i < bitss.size(); i++) { - ss << bitss[Mod((i - amount), bitss.size())]; - } - - return SecureBitset(ss.str()); - } - //! Will pad a string to a set length with a certain character std::string PadStringToLength(const std::string& str, const std::size_t len, const char pad, const bool padLeft = true); diff --git a/GCryptLib/src/Block.cpp b/GCryptLib/src/Block.cpp index 6398949..809d6bf 100644 --- a/GCryptLib/src/Block.cpp +++ b/GCryptLib/src/Block.cpp @@ -28,7 +28,7 @@ namespace Leonetienne::GCrypt { template void Basic_Block::FromString(const std::string& str) { - assert(str.length() == BLOCK_SIZE); + assert(str.length() == BLOCK_SIZE_BITS); for (std::size_t i = 0; i < data.size(); i++) { data[i] = std::bitset( diff --git a/GCryptLib/src/Feistel.cpp b/GCryptLib/src/Feistel.cpp index cca9860..57a5844 100644 --- a/GCryptLib/src/Feistel.cpp +++ b/GCryptLib/src/Feistel.cpp @@ -78,7 +78,7 @@ namespace Leonetienne::GCrypt { // Non-linearly apply subsitution boxes std::stringstream ss; const std::string m_str = m_expanded.ToString(); - for (std::size_t i = 0; i < BLOCK_SIZE; i += 4) { + for (std::size_t i = 0; i < Block::BLOCK_SIZE_BITS; i += 4) { ss << SBox(m_str.substr(i, 4)); } m_expanded = Block(ss.str()); @@ -98,12 +98,12 @@ namespace Leonetienne::GCrypt { } Block Feistel::FeistelCombine(const Halfblock& l, const Halfblock& r) { - return Block(l.to_string() + r.to_string()); + return Block(l.ToString() + r.ToString()); } Block Feistel::ExpansionFunction(const Halfblock& block) { std::stringstream ss; - const std::string bits = block.to_string(); + const std::string bits = block.ToString(); std::unordered_map expansionMap; expansionMap["00"] = "1101"; @@ -112,7 +112,7 @@ namespace Leonetienne::GCrypt { expansionMap["11"] = "0111"; // We have to double the bits! - for (std::size_t i = 0; i < HALFBLOCK_SIZE; i += 2) { + for (std::size_t i = 0; i < Halfblock::BLOCK_SIZE_BITS; i += 2) { const std::string sub = bits.substr(i, 2); ss << expansionMap[sub]; } @@ -143,7 +143,7 @@ namespace Leonetienne::GCrypt { compressionMap["1111"] = "01"; // We have to half the bits! - for (std::size_t i = 0; i < BLOCK_SIZE; i += 4) { + for (std::size_t i = 0; i < Block::BLOCK_SIZE_BITS; i += 4) { const std::string sub = bits.substr(i, 4); ss << compressionMap[sub]; } diff --git a/GCryptLib/src/GHash.cpp b/GCryptLib/src/GHash.cpp index 5ea48fa..9d1bc44 100644 --- a/GCryptLib/src/GHash.cpp +++ b/GCryptLib/src/GHash.cpp @@ -1,6 +1,7 @@ #include "GCrypt/GHash.h" #include "GCrypt/Util.h" #include "GCrypt/InitializationVector.h" +#include namespace Leonetienne::GCrypt { @@ -34,9 +35,9 @@ namespace Leonetienne::GCrypt { // Split input into blocks std::vector blocks; - for (std::size_t i = 0; i < data.size(); i += BLOCK_SIZE) { + for (std::size_t i = 0; i < data.size(); i += Block::BLOCK_SIZE_BITS) { blocks.push_back(Block( - PadStringToLength(data.substr(i, BLOCK_SIZE), BLOCK_SIZE, '0', false)) + PadStringToLength(data.substr(i, Block::BLOCK_SIZE_BITS), Block::BLOCK_SIZE_BITS, '0', false)) ); } diff --git a/GCryptLib/src/GPrng.cpp b/GCryptLib/src/GPrng.cpp index a89b9cd..f54728f 100644 --- a/GCryptLib/src/GPrng.cpp +++ b/GCryptLib/src/GPrng.cpp @@ -21,7 +21,7 @@ namespace Leonetienne::GCrypt { bool GPrng::GetBit() { // If we have no more bits to go, create new ones - if (nextBit >= BLOCK_SIZE) { + if (nextBit >= Block::BLOCK_SIZE_BITS) { AdvanceBlock(); } @@ -51,18 +51,18 @@ namespace Leonetienne::GCrypt { // Slurp up the rest of the current block std::stringstream ss; - const std::size_t bitsLeft = BLOCK_SIZE - nextBit; + const std::size_t bitsLeft = Block::BLOCK_SIZE_BITS - nextBit; ss << hasher.GetHashsum().ToString().substr(nextBit, bitsLeft); // Now we have to advance to the next block AdvanceBlock(); // Now, grab the remaining bits - const std::size_t remainingBits = BLOCK_SIZE - bitsLeft; + const std::size_t remainingBits = Block::BLOCK_SIZE_BITS - bitsLeft; ss << hasher.GetHashsum().ToString().substr(0, remainingBits); // Assert that we have the correct number of bits - assert(ss.str().length() == BLOCK_SIZE); + assert(ss.str().length() == Block::BLOCK_SIZE_BITS); // Set out bitpointer nextBit = remainingBits; diff --git a/GCryptLib/src/GWrapper.cpp b/GCryptLib/src/GWrapper.cpp index eacc8bb..76720a3 100644 --- a/GCryptLib/src/GWrapper.cpp +++ b/GCryptLib/src/GWrapper.cpp @@ -1,6 +1,7 @@ #include "GCrypt/GWrapper.h" #include "GCrypt/GCipher.h" #include "GCrypt/Util.h" +#include namespace Leonetienne::GCrypt { @@ -92,9 +93,9 @@ namespace Leonetienne::GCrypt { // Split input into blocks std::vector blocks; - for (std::size_t i = 0; i < data.size(); i += BLOCK_SIZE) { + for (std::size_t i = 0; i < data.size(); i += Block::BLOCK_SIZE_BITS) { blocks.push_back(Block( - PadStringToLength(data.substr(i, BLOCK_SIZE), BLOCK_SIZE, '0', false)) + PadStringToLength(data.substr(i, Block::BLOCK_SIZE_BITS), Block::BLOCK_SIZE_BITS, '0', false)) ); } diff --git a/GCryptLib/src/Key.cpp b/GCryptLib/src/Key.cpp index 0356b0b..97ecb4d 100644 --- a/GCryptLib/src/Key.cpp +++ b/GCryptLib/src/Key.cpp @@ -21,12 +21,12 @@ namespace Leonetienne::GCrypt { // Fetch BLOCK_SIZE bits std::stringstream ss; - for (std::size_t i = 0; i < BLOCK_SIZE / bitsPerCall; i++) { + for (std::size_t i = 0; i < Key::BLOCK_SIZE_BITS / bitsPerCall; i++) { ss << std::bitset(rng()); } // Verify that we actually have the correct size - assert(ss.str().length() == BLOCK_SIZE); + assert(ss.str().length() == Key::BLOCK_SIZE_BITS); // Return them as a key return Key(Block(ss.str())); @@ -34,7 +34,7 @@ namespace Leonetienne::GCrypt { Key Key::LoadFromFile(const std::string& path) { // Read this many chars - const std::size_t maxChars = BLOCK_SIZE / 8; + const std::size_t maxChars = Key::BLOCK_SIZE_BITS / 8; // Open ifilestream for keyfile std::ifstream ifs(path, std::ios::in | std::ios::binary); @@ -73,7 +73,7 @@ namespace Leonetienne::GCrypt { std::ofstream ofs(path, std::ios::out | std::ios::binary); // Write the key - ofs.write(keybytes.data(), BLOCK_SIZE/8); + ofs.write(keybytes.data(), Key::BLOCK_SIZE_BITS / 8); // Close the file handle ofs.close(); diff --git a/GCryptLib/src/Util.cpp b/GCryptLib/src/Util.cpp index 9c315e5..3caaa06 100644 --- a/GCryptLib/src/Util.cpp +++ b/GCryptLib/src/Util.cpp @@ -37,7 +37,7 @@ namespace Leonetienne::GCrypt { } // Pad rest with zeores - return Block(PadStringToLength(ss.str(), BLOCK_SIZE, '0', padLeft)); + return Block(PadStringToLength(ss.str(), Block::BLOCK_SIZE_BITS, '0', padLeft)); } Flexblock StringToBits(const std::string& s) { @@ -55,7 +55,7 @@ namespace Leonetienne::GCrypt { const std::string bitstring = bits.ToString(); - for (std::size_t i = 0; i < BLOCK_SIZE; i += 8) { + for (std::size_t i = 0; i < Block::BLOCK_SIZE_BITS; i += 8) { ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong(); } From bc3dae96a3afad8fc5620dedd6171e0d84b644ee Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Thu, 26 May 2022 02:30:16 +0200 Subject: [PATCH 046/110] Implement new sbox, reduction, and expansion function --- GCryptLib/include/GCrypt/Block.h | 7 ++ GCryptLib/include/GCrypt/Feistel.h | 8 +- GCryptLib/include/GCrypt/SBoxLookup.h | 46 ++++++++++ GCryptLib/src/Block.cpp | 10 +++ GCryptLib/src/Feistel.cpp | 124 ++++++++++++++------------ 5 files changed, 132 insertions(+), 63 deletions(-) create mode 100644 GCryptLib/include/GCrypt/SBoxLookup.h diff --git a/GCryptLib/include/GCrypt/Block.h b/GCryptLib/include/GCrypt/Block.h index 64038a7..032ebfc 100644 --- a/GCryptLib/include/GCrypt/Block.h +++ b/GCryptLib/include/GCrypt/Block.h @@ -163,8 +163,15 @@ namespace Leonetienne::GCrypt { //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) [[nodiscard]] const T& operator[](const std::uint8_t index) const; + //! Will return a reference to the data array + T* Data() noexcept; + + //! Will return a reference to the data array + const T* Data() const noexcept; + static constexpr std::size_t CHUNK_SIZE = sizeof(T); static constexpr std::size_t CHUNK_SIZE_BITS = CHUNK_SIZE * 8; + static constexpr std::size_t BLOCK_SIZE = CHUNK_SIZE * 16; static constexpr std::size_t BLOCK_SIZE_BITS = CHUNK_SIZE_BITS * 16; friend std::ostream& operator<<(std::ostream& os, const Basic_Block& b) { diff --git a/GCryptLib/include/GCrypt/Feistel.h b/GCryptLib/include/GCrypt/Feistel.h index cb7d35f..60f3d10 100644 --- a/GCryptLib/include/GCrypt/Feistel.h +++ b/GCryptLib/include/GCrypt/Feistel.h @@ -46,11 +46,11 @@ namespace Leonetienne::GCrypt { //! Will expand a halfblock to a fullblock static Block ExpansionFunction(const Halfblock& block); - //! Will compress a fullblock to a halfblock - static Halfblock CompressionFunction(const Block& block); + //! Will reduce a fullblock to a halfblock + static Halfblock ReductionFunction(const Block& block); - //! Substitutes four bits by static random others - static std::string SBox(const std::string& in); + //! Substitutes eight bits by static random others, inplace + static void SBox(Block& block); //! Will generate a the round keys void GenerateRoundKeys(const Key& seedKey); diff --git a/GCryptLib/include/GCrypt/SBoxLookup.h b/GCryptLib/include/GCrypt/SBoxLookup.h new file mode 100644 index 0000000..ded1088 --- /dev/null +++ b/GCryptLib/include/GCrypt/SBoxLookup.h @@ -0,0 +1,46 @@ +#ifndef GCRYPT_SBOX_LOOKUP +#define GCRYPT_SBOX_LOOKUP + +#include + +namespace Leonetienne::GCrypt { + + static const std::array sboxLookup { + 0x23,0xF7,0xA2,0x31,0x5B,0x0C,0x13,0xEE, + 0xF8,0x1B,0x0B,0xA9,0x37,0x9F,0x55,0xF3, + 0x7D,0x71,0x9E,0x89,0x38,0x53,0x3D,0xE9, + 0x47,0xA4,0x30,0xBF,0x82,0xE3,0x69,0x5C, + 0x3C,0x88,0xDE,0x7F,0x29,0xEB,0x5F,0x02, + 0x63,0x42,0xDC,0x36,0x20,0x6B,0x9C,0x4A, + 0xA8,0x11,0x6D,0x67,0x3A,0xF4,0x33,0x61, + 0x1C,0x4C,0x22,0x07,0x6F,0x80,0xA5,0x96, + 0x77,0x62,0xDD,0x6A,0x60,0x05,0x08,0x72, + 0xE5,0x1D,0x39,0xA7,0x58,0x3F,0x57,0xAD, + 0xFF,0x09,0xC5,0xB2,0xE7,0x94,0xEA,0x34, + 0x9A,0x5D,0x52,0xE2,0xAE,0x99,0xBB,0x44, + 0xFD,0x73,0xEC,0x87,0xED,0xBA,0x7C,0xF5, + 0xDA,0x01,0xC7,0xC1,0xB6,0x81,0x12,0xD5, + 0x7A,0x16,0x18,0x97,0x74,0x32,0xBD,0x56, + 0xFE,0x79,0x3E,0x95,0x93,0xAB,0x6C,0xC6, + 0x2A,0x27,0x19,0x26,0x2E,0x41,0x0F,0x85, + 0x66,0x59,0xEF,0x98,0x10,0xE8,0xE6,0x49, + 0xAC,0x0D,0x2D,0xD3,0xF0,0x92,0x8F,0xD9, + 0xAF,0xC8,0xB5,0xBC,0x6E,0xD6,0x78,0x8E, + 0x17,0xCB,0x75,0x50,0x51,0x84,0xB7,0x4D, + 0x70,0x9D,0x8A,0x2B,0x0E,0x35,0xB9,0x40, + 0x00,0x21,0xC3,0xB3,0x43,0xCD,0x65,0xC0, + 0x4E,0xCF,0xCA,0x28,0x45,0x46,0x54,0x8B, + 0x0A,0x5A,0x1F,0x24,0xFA,0xA6,0xB4,0xD7, + 0x3B,0xFC,0x5E,0xA3,0xB8,0x04,0xCE,0xF2, + 0xFB,0xD4,0x8C,0xE4,0x90,0xB1,0x06,0x8D, + 0x86,0xA1,0xE0,0x68,0xD1,0x2C,0x03,0x64, + 0x9B,0x4F,0x14,0x1E,0x7B,0x76,0x48,0xCC, + 0xC4,0x15,0xAA,0xC9,0xE1,0x91,0xF6,0xD0, + 0x25,0xA0,0x7E,0xB0,0x1A,0xBE,0xC2,0x4B, + 0xF1,0xD2,0xDF,0x2F,0xF9,0xDB,0xD8,0x83 + }; + +} + +#endif + diff --git a/GCryptLib/src/Block.cpp b/GCryptLib/src/Block.cpp index 809d6bf..3a83d2c 100644 --- a/GCryptLib/src/Block.cpp +++ b/GCryptLib/src/Block.cpp @@ -694,6 +694,16 @@ namespace Leonetienne::GCrypt { return data[index]; } + template + T* Basic_Block::Data() noexcept { + return data.data(); + } + + template + const T* Basic_Block::Data() const noexcept { + return data.data(); + } + template bool Basic_Block::operator==(const Basic_Block& other) const { return data == other.data; diff --git a/GCryptLib/src/Feistel.cpp b/GCryptLib/src/Feistel.cpp index 57a5844..7fb731e 100644 --- a/GCryptLib/src/Feistel.cpp +++ b/GCryptLib/src/Feistel.cpp @@ -2,6 +2,7 @@ #include "GCrypt/Feistel.h" #include "GCrypt/Util.h" #include "GCrypt/Config.h" +#include "GCrypt/SBoxLookup.h" namespace Leonetienne::GCrypt { @@ -54,14 +55,14 @@ namespace Leonetienne::GCrypt { // Block has finished de*ciphering. // Let's generate a new set of round keys. - GenerateRoundKeys((Key)roundKeys.back()); + GenerateRoundKeys(roundKeys.back()); return FeistelCombine(r, l); } Halfblock Feistel::F(Halfblock m, const Key& key) { - // Made-up F function + // Made-up F function: // Expand to full bitwidth Block m_expanded = ExpansionFunction(m); @@ -75,82 +76,86 @@ namespace Leonetienne::GCrypt { // Now do a bitshift m_expanded.ShiftBitsLeftInplace(); - // Non-linearly apply subsitution boxes - std::stringstream ss; - const std::string m_str = m_expanded.ToString(); - for (std::size_t i = 0; i < Block::BLOCK_SIZE_BITS; i += 4) { - ss << SBox(m_str.substr(i, 4)); - } - m_expanded = Block(ss.str()); + // Apply the sbox + SBox(m_expanded); - // Return the compressed version, shifted by 3 - //return Shiftl(CompressionFunction(m_expanded), 3); - return (CompressionFunction(m_expanded)); + // Reduce back to a halfblock + Halfblock hb = ReductionFunction(m_expanded); + + // To jumble it up a last time, + // matrix-multiply it with the input halfblock + hb *= m; + + return hb; } std::pair Feistel::FeistelSplit(const Block& block) { - const std::string bits = block.ToString(); + Halfblock l; + Halfblock r; - Halfblock l(bits.substr(0, bits.size() / 2)); - Halfblock r(bits.substr(bits.size() / 2)); + memcpy(l.Data(), block.Data(), Halfblock::BLOCK_SIZE); + memcpy(r.Data(), block.Data() + 8, Halfblock::BLOCK_SIZE); + // +8, because 8 is HALF the number of elements in the array. We only want to copy HALF a full-sized block. return std::make_pair(l, r); } Block Feistel::FeistelCombine(const Halfblock& l, const Halfblock& r) { - return Block(l.ToString() + r.ToString()); + Block b; + + memcpy(b.Data(), l.Data(), Halfblock::BLOCK_SIZE); + memcpy(b.Data() + 8, r.Data(), Halfblock::BLOCK_SIZE); + // +8, because 8 is HALF the number of elements in the array. We only want to copy HALF a full-sized block. + + return b; } - Block Feistel::ExpansionFunction(const Halfblock& block) { - std::stringstream ss; - const std::string bits = block.ToString(); + Block Feistel::ExpansionFunction(const Halfblock& hb) { + Block b; - std::unordered_map expansionMap; - expansionMap["00"] = "1101"; - expansionMap["01"] = "1000"; - expansionMap["10"] = "0010"; - expansionMap["11"] = "0111"; - - // We have to double the bits! - for (std::size_t i = 0; i < Halfblock::BLOCK_SIZE_BITS; i += 2) { - const std::string sub = bits.substr(i, 2); - ss << expansionMap[sub]; + // Copy the bits over + for (std::size_t i = 0; i < 16; i++) { + b[i] = hb[i]; } - return Block(ss.str()); - } - - Halfblock Feistel::CompressionFunction(const Block& block) { - std::stringstream ss; - const std::string bits = block.ToString(); - - std::unordered_map compressionMap; - compressionMap["0000"] = "10"; - compressionMap["0001"] = "01"; - compressionMap["0010"] = "11"; - compressionMap["0011"] = "10"; - compressionMap["0100"] = "11"; - compressionMap["0101"] = "01"; - compressionMap["0110"] = "00"; - compressionMap["0111"] = "01"; - compressionMap["1000"] = "11"; - compressionMap["1001"] = "00"; - compressionMap["1010"] = "11"; - compressionMap["1011"] = "00"; - compressionMap["1100"] = "11"; - compressionMap["1101"] = "10"; - compressionMap["1110"] = "00"; - compressionMap["1111"] = "01"; - - // We have to half the bits! - for (std::size_t i = 0; i < Block::BLOCK_SIZE_BITS; i += 4) { - const std::string sub = bits.substr(i, 4); - ss << compressionMap[sub]; + // Multiply the block a few tims with a bitshifted version + // This is irriversible, too + for (std::size_t i = 0; i < 3; i++) { + b *= b.ShiftBitsRight(); } - return Halfblock(ss.str()); + return b; } + Halfblock Feistel::ReductionFunction(const Block& block) { + + // Just apply a modulo operation, remapping a 32bit integer + // onto 16bit space (default configuration). + // Without saying, modulo is irreversible. + Halfblock hb; + for (std::size_t i = 0; i < 16; i++) { + hb[i] = block[i] % (1 << (Halfblock::CHUNK_SIZE_BITS - 1)); + } + + return hb; + } + + void Feistel::SBox(Block& block) { + + std::uint8_t* curByte = (std::uint8_t*)(void*)block.Data(); + + // Iterate over all bytes in the block + for (std::size_t i = 0; i < Block::BLOCK_SIZE; i++) { + curByte++; + + // Subsitute byte + *curByte = sboxLookup[*curByte]; + } + + return; + } + + /* std::string Feistel::SBox(const std::string& in) { static std::unordered_map subMap; static bool mapInitialized = false; @@ -176,6 +181,7 @@ namespace Leonetienne::GCrypt { return subMap[in]; } + */ void Feistel::GenerateRoundKeys(const Key& seedKey) { // Clear initial key memory From 101a1e0fd64eaf003981c1e6c0d67793d36d59ee Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Thu, 26 May 2022 02:44:22 +0200 Subject: [PATCH 047/110] Add additional jumbling-up in feistel rounds --- GCryptLib/include/GCrypt/Feistel.h | 2 +- GCryptLib/src/Feistel.cpp | 48 ++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/GCryptLib/include/GCrypt/Feistel.h b/GCryptLib/include/GCrypt/Feistel.h index 60f3d10..5d30334 100644 --- a/GCryptLib/include/GCrypt/Feistel.h +++ b/GCryptLib/include/GCrypt/Feistel.h @@ -32,7 +32,7 @@ namespace Leonetienne::GCrypt { private: //! Will run the feistel rounds, with either regular key //! order or reversed key order - Block Run(const Block& data, bool reverseKeys); + Block Run(const Block& data, bool modeEncrypt); //! Arbitrary cipher function static Halfblock F(Halfblock m, const Key& key); diff --git a/GCryptLib/src/Feistel.cpp b/GCryptLib/src/Feistel.cpp index 7fb731e..1c54a7f 100644 --- a/GCryptLib/src/Feistel.cpp +++ b/GCryptLib/src/Feistel.cpp @@ -30,7 +30,7 @@ namespace Leonetienne::GCrypt { return Run(data, true); } - Block Feistel::Run(const Block& data, bool reverseKeys) { + Block Feistel::Run(const Block& data, bool modeEncrypt) { const auto splitData = FeistelSplit(data); Halfblock l = splitData.first; Halfblock r = splitData.second; @@ -38,19 +38,43 @@ namespace Leonetienne::GCrypt { Halfblock tmp; for (std::size_t i = 0; i < N_ROUNDS; i++) { - // Calculate key index - std::size_t keyIndex; - if (reverseKeys) { - keyIndex = N_ROUNDS - i - 1; - } - else { - keyIndex = i; + + // Encryption + if (modeEncrypt) { + const std::size_t keyIndex = i; + + // Do a feistel round + tmp = r; + r = l ^ F(r, roundKeys[keyIndex]); + l = tmp; + + // Jumble it up a bit more + l.ShiftRowsUpInplace(); + l.ShiftCellsRightInplace(); + l.ShiftBitsLeftInplace(); + l.ShiftColumnsLeftInplace(); + // Seal all these operations with a key + l += ReductionFunction(roundKeys[keyIndex]); + } + + // Decryption + else { + // Decryption needs keys in reverse order + const std::size_t keyIndex = N_ROUNDS - i - 1; + + // Unjumble the jumble + r -= ReductionFunction(roundKeys[keyIndex]); + r.ShiftColumnsRightInplace(); + r.ShiftBitsRightInplace(); + r.ShiftCellsLeftInplace(); + r.ShiftRowsDownInplace(); + + // Do a feistel round + tmp = r; + r = l ^ F(r, roundKeys[keyIndex]); + l = tmp; } - // Do a feistel round - tmp = r; - r = l ^ F(r, roundKeys[keyIndex]); - l = tmp; } // Block has finished de*ciphering. From 81a95706735c2a740f1582baac013f0cc92f46a8 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Thu, 26 May 2022 04:22:42 +0200 Subject: [PATCH 048/110] Implement direct file i/o to- and from blocks. --- GCryptLib/include/GCrypt/Flexblock.h | 6 +- GCryptLib/include/GCrypt/Util.h | 25 ++++- GCryptLib/include/GCrypt/Version.h | 2 +- GCryptLib/src/GWrapper.cpp | 42 ++++++--- GCryptLib/src/Key.cpp | 40 +++----- GCryptLib/src/Util.cpp | 136 ++++++++++++++++++++++++++- GCryptLib/test/GCWrapper.cpp | 10 +- 7 files changed, 205 insertions(+), 56 deletions(-) diff --git a/GCryptLib/include/GCrypt/Flexblock.h b/GCryptLib/include/GCrypt/Flexblock.h index 80f9174..5e551b2 100644 --- a/GCryptLib/include/GCrypt/Flexblock.h +++ b/GCryptLib/include/GCrypt/Flexblock.h @@ -4,7 +4,11 @@ #include namespace Leonetienne::GCrypt { - //! A "bitset" of variable length + //! A type used for conveying "bitstrings". e.g. "10101001001" + //! These should generally not be used, as they are really really slow. + //! The only valid usecase I can think of is when using GHash for example, because for hashing + //! an absolute input length is required. + //! If you need to, you can use the StringToBits() and BitsToString() functions defined in Util.h. typedef std::string Flexblock; } diff --git a/GCryptLib/include/GCrypt/Util.h b/GCryptLib/include/GCrypt/Util.h index adb1bf2..8a108f8 100644 --- a/GCryptLib/include/GCrypt/Util.h +++ b/GCryptLib/include/GCrypt/Util.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "GCrypt/Block.h" #include "GCrypt/Flexblock.h" #include "GCrypt/Config.h" @@ -28,12 +29,22 @@ namespace Leonetienne::GCrypt { //! Will convert a string to a flexible data block Flexblock StringToBits(const std::string& s); - //! Will convert a fixed-size data block to a bytestring - std::string BitblockToBytes(const Block& bits); + //! Will convert a string to a vector of blocks + std::vector StringToBitblocks(const std::string& s); - //! Will convert a fixed-size data block to a string + //! Will convert a fixed-size data block to a bytestring + std::string BitblockToBytes(const Block& block); + + //! Will convert an array of data blocks to a bytestring + std::string BitblocksToBytes(const std::vector& bits); + + //! Will convert a fixed-size data blocks to a textstring //! The difference to BitblockToBytes() is, that it strips excess nullbytes - std::string BitblockToString(const Block& bits); + std::string BitblockToString(const Block& block); + + //! Will convert an array of blocks to a character-string + //! The difference to BitblocksToBytes() is, that it strips excess nullbytes + std::string BitblocksToString(const std::vector& blocks); //! Will convert a flexible data block to a bytestring std::string BitsToBytes(const Flexblock& bits); @@ -59,6 +70,12 @@ namespace Leonetienne::GCrypt { //! Will save bits to a binary file void WriteBitsToFile(const std::string& filepath, const Flexblock& bits); + + //! Will read a file directly to data blocks + std::vector ReadFileToBlocks(const std::string& filepath); + + //! Will write data blocks directly to a file + void WriteBlocksToFile(const std::string& filepath, const std::vector& blocks); } #endif diff --git a/GCryptLib/include/GCrypt/Version.h b/GCryptLib/include/GCrypt/Version.h index 655c9f3..171c1f9 100644 --- a/GCryptLib/include/GCrypt/Version.h +++ b/GCryptLib/include/GCrypt/Version.h @@ -1,7 +1,7 @@ #ifndef GCRYPT_VERSION_H #define GCRYPT_VERSION_H -#define GCRYPT_VERSION 0.233 +#define GCRYPT_VERSION 0.234 #endif diff --git a/GCryptLib/src/GWrapper.cpp b/GCryptLib/src/GWrapper.cpp index 76720a3..5cf15ac 100644 --- a/GCryptLib/src/GWrapper.cpp +++ b/GCryptLib/src/GWrapper.cpp @@ -46,14 +46,23 @@ namespace Leonetienne::GCrypt { bool printProgressReport) { try { - // Read the file to bits - const Flexblock cleartext_bits = ReadFileToBits(filename_in); + // Read the file to blocks + const std::vector cleartext_blocks = ReadFileToBlocks(filename_in); - // Encrypt our cleartext bits - const Flexblock ciphertext_bits = CipherFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); + // Encrypt our cleartext blocks + std::vector ciphertext_blocks; + ciphertext_blocks.reserve(cleartext_blocks.size()); - // Write our ciphertext bits to file - WriteBitsToFile(filename_out, ciphertext_bits); + // Create cipher instance + GCipher cipher(key, GCipher::DIRECTION::ENCIPHER); + + // Encrypt all blocks + for (const Block& clearBlock : cleartext_blocks) { + ciphertext_blocks.emplace_back(cipher.Digest(clearBlock)); + } + + // Write our ciphertext blocks to file + WriteBlocksToFile(filename_out, ciphertext_blocks); return true; } @@ -69,14 +78,23 @@ namespace Leonetienne::GCrypt { bool printProgressReport) { try { - // Read the file to bits - const Flexblock ciphertext_bits = ReadFileToBits(filename_in); + // Read the file to blocks + const std::vector ciphertext_blocks = ReadFileToBlocks(filename_in); - // Decrypt the ciphertext bits - const Flexblock cleartext_bits = CipherFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); + // Decrypt our cleartext blocks + std::vector cleartext_blocks; + cleartext_blocks.reserve(ciphertext_blocks.size()); - // Write our cleartext bits to file - WriteBitsToFile(filename_out, cleartext_bits); + // Create cipher instance + GCipher cipher(key, GCipher::DIRECTION::DECIPHER); + + // Decrypt all blocks + for (const Block& cipherBlock : ciphertext_blocks) { + cleartext_blocks.emplace_back(cipher.Digest(cipherBlock)); + } + + // Write our cleartext blocks to file + WriteBlocksToFile(filename_out, cleartext_blocks); return true; } diff --git a/GCryptLib/src/Key.cpp b/GCryptLib/src/Key.cpp index 97ecb4d..a6d80da 100644 --- a/GCryptLib/src/Key.cpp +++ b/GCryptLib/src/Key.cpp @@ -19,17 +19,14 @@ namespace Leonetienne::GCrypt { std::random_device rng; constexpr std::size_t bitsPerCall = sizeof(std::random_device::result_type) * 8; - // Fetch BLOCK_SIZE bits - std::stringstream ss; - for (std::size_t i = 0; i < Key::BLOCK_SIZE_BITS / bitsPerCall; i++) { - ss << std::bitset(rng()); + // Create a new key, and assign 16 random values + Key key; + for (std::size_t i = 0; i < 16; i++) { + key[i] = rng(); } - // Verify that we actually have the correct size - assert(ss.str().length() == Key::BLOCK_SIZE_BITS); - - // Return them as a key - return Key(Block(ss.str())); + // Return it + return key; } Key Key::LoadFromFile(const std::string& path) { @@ -44,36 +41,23 @@ namespace Leonetienne::GCrypt { throw std::runtime_error(std::string("Unable to open ifilestream for keyfile \"") + path + "\"! Aborting..."); } - // Read these chars to buffer - char* ckeyfileContent = new char[maxChars]; - memset(ckeyfileContent, 0, maxChars * sizeof(char)); - ifs.read(ckeyfileContent, maxChars); - ifs.close(); + // Create a new key, and zero it + Key key; + key.Reset(); - // Convert the buffer to a bit block of key size - std::stringstream ss; - for (std::size_t i = 0; i < maxChars; i++) - ss << std::bitset<8>(ckeyfileContent[i]); - - Block key(ss.str()); - - // And delete the buffer - delete[] ckeyfileContent; - ckeyfileContent = nullptr; + // Read into it + ifs.read((char*)(void*)key.Data(), Key::BLOCK_SIZE); // Return it return key; } void Key::WriteToFile(const std::string& path) { - // Transform key to bytes - const std::string keybytes = BitsToBytes(ToString()); - // Create an ofilestream std::ofstream ofs(path, std::ios::out | std::ios::binary); // Write the key - ofs.write(keybytes.data(), Key::BLOCK_SIZE_BITS / 8); + ofs.write((char*)(void*)Data(), Key::BLOCK_SIZE); // Close the file handle ofs.close(); diff --git a/GCryptLib/src/Util.cpp b/GCryptLib/src/Util.cpp index 3caaa06..2dcd0ee 100644 --- a/GCryptLib/src/Util.cpp +++ b/GCryptLib/src/Util.cpp @@ -1,5 +1,6 @@ #include "GCrypt/Util.h" #include "GCrypt/GHash.h" +#include namespace Leonetienne::GCrypt { @@ -50,13 +51,22 @@ namespace Leonetienne::GCrypt { return Flexblock(ss.str()); } - std::string BitblockToBytes(const Block& bits) { + std::string BitblockToBytes(const Block& block) { std::stringstream ss; - const std::string bitstring = bits.ToString(); + std::uint8_t* curByte = (std::uint8_t*)(void*)block.Data(); + for (std::size_t j = 0; j < Block::BLOCK_SIZE; j++) { + ss << *curByte++; + } - for (std::size_t i = 0; i < Block::BLOCK_SIZE_BITS; i += 8) { - ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong(); + return ss.str(); + } + + std::string BitblocksToBytes(const std::vector& blocks) { + std::stringstream ss; + + for (const Block& block : blocks) { + ss << BitblockToBytes(block); } return ss.str(); @@ -72,6 +82,16 @@ namespace Leonetienne::GCrypt { return text; } + std::string BitblocksToString(const std::vector& blocks) { + // Decode to bytes + std::string text = BitblocksToBytes(blocks); + + // Dümp excess nullbytes + text.resize(strlen(text.data())); + + return text; + } + std::string BitsToBytes(const Flexblock& bits) { std::stringstream ss; @@ -211,5 +231,113 @@ namespace Leonetienne::GCrypt { return; } + + std::vector ReadFileToBlocks(const std::string& filepath) { + // Read file + + // "ate" specifies that the read-pointer is already at the end of the file + // this allows to estimate the file size + std::ifstream ifs(filepath, std::ios::binary | std::ios::ate); + + if (!ifs.good()) { + throw std::runtime_error("Unable to open ifilestream!"); + } + + // Create our vector of blocks, and resorve a good guess + // of memory + std::vector blocks; + blocks.reserve((ifs.tellg() / Block::BLOCK_SIZE) + 1); + + // Move read head to the file beginning + ifs.seekg(std::ios_base::beg); + + // Whilst not reached eof, read into blocks + while (!ifs.eof()) { + // Create a new block, and zero it + Block block; + block.Reset(); + + // Read data into the block + ifs.read((char*)(void*)block.Data(), Block::BLOCK_SIZE); + const std::size_t n_bytes_read = ifs.gcount(); + + if (n_bytes_read > 0) { + // Append the block to our vector + blocks.emplace_back(block); + } + } + + // Close the filehandle + ifs.close(); + + return blocks; + } + + void WriteBlocksToFile( + const std::string& filepath, + const std::vector& blocks + ){ + + // Create outfile file handle + std::ofstream ofs(filepath, std::ios::binary); + + if (!ofs.good()) { + throw std::runtime_error("Unable to open ofilestream!"); + } + + // Write all the blocks + for (const Block& block : blocks) { + ofs.write((char*)(void*)block.Data(), Block::BLOCK_SIZE); + } + + // Close the filehandle + ofs.close(); + + return; + } + + std::vector StringToBitblocks(const std::string& s) { + + // Create our block vector, and reserve exactly + // how many blocks are required to store this string + const std::size_t num_blocks = (s.length() / Block::BLOCK_SIZE) + 1; + std::vector blocks; + blocks.reserve(num_blocks); + + for (std::size_t i = 0; i < num_blocks; i++) { + // Create new block, and zero it + Block block; + block.Reset(); + + std::size_t bytes_copied = 0; + + // Iterate over all bytes in the block + std::uint8_t* curByte = (std::uint8_t*)(void*)block.Data(); + for (std::size_t j = 0; j < Block::BLOCK_SIZE; j++) { + curByte++; + + // Carry our character over + + const std::size_t strIdx = i*Block::BLOCK_SIZE + j; + // The string still has chars to give + if (strIdx < s.length()) { + *curByte = s[j]; + bytes_copied++; + } + // We've reached the end of the string + else { + // Save our block, if it contains any bytes + if (bytes_copied) { + blocks.emplace_back(block); + } + + // Return our blocks + return blocks; + } + } + } + + return blocks; + } } diff --git a/GCryptLib/test/GCWrapper.cpp b/GCryptLib/test/GCWrapper.cpp index e0d228c..ef59209 100644 --- a/GCryptLib/test/GCWrapper.cpp +++ b/GCryptLib/test/GCWrapper.cpp @@ -46,13 +46,11 @@ TEST_CASE(__FILE__"/Encrypting and decrypting files works", "[Wrapper]") { GWrapper::DecryptFile(filename_encrypted, filename_decrypted, key); // Read in both the base, and the decrypted file - const Flexblock plainfile = ReadFileToBits(filename_plain); - const Flexblock decryptfile = ReadFileToBits(filename_decrypted); + const std::vector plainfile = ReadFileToBlocks(filename_plain); + const std::vector decryptfile = ReadFileToBlocks(filename_decrypted); // Assertion (If this fails, maybe check if the image is even readable by an image viewer) - REQUIRE( - PadStringToLength(plainfile, decryptfile.length(), '0', false) == - decryptfile - ); + REQUIRE(plainfile.size() == decryptfile.size()); + REQUIRE(plainfile == decryptfile); } From 8cf8ad2628be947f409c37771cbe2189d2fada2b Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Thu, 26 May 2022 04:23:32 +0200 Subject: [PATCH 049/110] Add artifact directory --- .../artifacts/optimization-performance-log.md | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 GCryptLib/artifacts/optimization-performance-log.md diff --git a/GCryptLib/artifacts/optimization-performance-log.md b/GCryptLib/artifacts/optimization-performance-log.md new file mode 100644 index 0000000..c019e69 --- /dev/null +++ b/GCryptLib/artifacts/optimization-performance-log.md @@ -0,0 +1,21 @@ +Old way (400 rounds, no matrix mult): 38.01s + 400 was the minimum for good diffusion + +New way (10 rounds, with matrix mult): 1.16s + 10 rounds now give sufficient diffusion + still using bitsets and strings + +With new block class (instead of bitsets) (10 rounds): 0.35s + still partially using bitsets and strings + +With new block class (6 rounds, still good diffusion): 0.21s + +With new templated block class (full block and half block): 0.14s + finally no more bitsets + +With new sbox, reduction, and expansion function: 0.03s + +With additional jumbling in feistel rounds: 0.03s + +With direct file reading/writing from data blocks: 0.02s + From c3ff7a1326689e3a8d274536589af0fe66bcac47 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Thu, 26 May 2022 04:25:02 +0200 Subject: [PATCH 050/110] Fix markup in artifacts --- GCryptLib/artifacts/optimization-performance-log.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/GCryptLib/artifacts/optimization-performance-log.md b/GCryptLib/artifacts/optimization-performance-log.md index c019e69..6d9edf0 100644 --- a/GCryptLib/artifacts/optimization-performance-log.md +++ b/GCryptLib/artifacts/optimization-performance-log.md @@ -1,17 +1,17 @@ Old way (400 rounds, no matrix mult): 38.01s - 400 was the minimum for good diffusion + - 400 was the minimum for good diffusion New way (10 rounds, with matrix mult): 1.16s - 10 rounds now give sufficient diffusion - still using bitsets and strings + - 10 rounds now give sufficient diffusion + - still using bitsets and strings With new block class (instead of bitsets) (10 rounds): 0.35s - still partially using bitsets and strings + - still partially using bitsets and strings With new block class (6 rounds, still good diffusion): 0.21s With new templated block class (full block and half block): 0.14s - finally no more bitsets + - finally no more bitsets With new sbox, reduction, and expansion function: 0.03s From 660ab5e9990b050fe86dc4f8f5a7fa92cbc3dc75 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Thu, 26 May 2022 04:40:23 +0200 Subject: [PATCH 051/110] Unstupided mathematical expression --- GCryptLib/src/Key.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GCryptLib/src/Key.cpp b/GCryptLib/src/Key.cpp index a6d80da..f129c03 100644 --- a/GCryptLib/src/Key.cpp +++ b/GCryptLib/src/Key.cpp @@ -31,7 +31,7 @@ namespace Leonetienne::GCrypt { Key Key::LoadFromFile(const std::string& path) { // Read this many chars - const std::size_t maxChars = Key::BLOCK_SIZE_BITS / 8; + const std::size_t maxChars = Key::BLOCK_SIZE; // Open ifilestream for keyfile std::ifstream ifs(path, std::ios::in | std::ios::binary); From e9377699f2fa8e4edcc8da8eb8a74c445eda1b4f Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Thu, 26 May 2022 12:23:27 +0200 Subject: [PATCH 052/110] Made GPrng::GetBlock() faster by a factor of 100 --- GCryptLib/src/GPrng.cpp | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/GCryptLib/src/GPrng.cpp b/GCryptLib/src/GPrng.cpp index f54728f..94b228b 100644 --- a/GCryptLib/src/GPrng.cpp +++ b/GCryptLib/src/GPrng.cpp @@ -46,29 +46,23 @@ namespace Leonetienne::GCrypt { } Block GPrng::GetBlock() { - // Getting a block is a bit troublesome. - // Just fetching 512 bits would be too much of a performance hog. + // Tactic on efficiently generating a new block: + // 1) Fetch complete current hashsum (it might have been partially given out already) + // 2) Bitshift it, and matrix-mult it with the seed (that is irreversible) + // That should be a one-way function, and create a new unique block. + // We don't even have to AdvanceBlock(), because we've only given out + // hashsum', not hashsum. - // Slurp up the rest of the current block - std::stringstream ss; - const std::size_t bitsLeft = Block::BLOCK_SIZE_BITS - nextBit; - ss << hasher.GetHashsum().ToString().substr(nextBit, bitsLeft); + // Fetch our current block + Block hashsum = hasher.GetHashsum(); - // Now we have to advance to the next block - AdvanceBlock(); + // Derive/'hash' it to hashsum' + hashsum *= seed; + hashsum.ShiftBitsLeftInplace(); + hashsum *= seed; - // Now, grab the remaining bits - const std::size_t remainingBits = Block::BLOCK_SIZE_BITS - bitsLeft; - ss << hasher.GetHashsum().ToString().substr(0, remainingBits); - - // Assert that we have the correct number of bits - assert(ss.str().length() == Block::BLOCK_SIZE_BITS); - - // Set out bitpointer - nextBit = remainingBits; - - // Return our block - return Block(ss.str()); + // Return our hashsum + return hashsum; } } From 800140bafaf4ec14f6353099f8265a0a1c41462c Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Thu, 26 May 2022 12:52:04 +0200 Subject: [PATCH 053/110] Added a method to GPrng to get a random uint32, which is about twice as fast as GetRandom --- GCryptLib/include/GCrypt/GPrng.h | 3 +++ GCryptLib/src/GPrng.cpp | 46 ++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/GCryptLib/include/GCrypt/GPrng.h b/GCryptLib/include/GCrypt/GPrng.h index b037a53..01845f5 100644 --- a/GCryptLib/include/GCrypt/GPrng.h +++ b/GCryptLib/include/GCrypt/GPrng.h @@ -46,6 +46,9 @@ namespace Leonetienne::GCrypt { return t; } + //! Will return a random unsigned 32-bit integer + std::uint32_t operator()(); + //! Will return a random block Block GetBlock(); diff --git a/GCryptLib/src/GPrng.cpp b/GCryptLib/src/GPrng.cpp index 94b228b..b1731bf 100644 --- a/GCryptLib/src/GPrng.cpp +++ b/GCryptLib/src/GPrng.cpp @@ -53,6 +53,10 @@ namespace Leonetienne::GCrypt { // We don't even have to AdvanceBlock(), because we've only given out // hashsum', not hashsum. + // Performance improvement over the previous method: + // (generating 100.000 blocks): + // 12 seconds -> 0.12 seconds + // Fetch our current block Block hashsum = hasher.GetHashsum(); @@ -65,5 +69,47 @@ namespace Leonetienne::GCrypt { return hashsum; } + std::uint32_t GPrng::operator()() { + // Tactic: + // A block intrinsically consists of 16 32-bit uints. + // We'll just skip all the bits until the next whole integer, + // fetch this complete int, and then advance our pointer + // by 32 bits. + + // Performance improvement over the previous method: + // (generating 1.000.000 integers): + // 5.26 seconds -> 3.84 seconds + + + // Advance our pointer to the next whole uint32 + + // Do we even have >= 32 bits left in our block? + if (nextBit > Block::BLOCK_SIZE_BITS - Block::CHUNK_SIZE_BITS) { + // No: Create a new block + AdvanceBlock(); + } + + // We don't have to do this, if our pointer is already at + // the beginning of a whole uint32 + if (nextBit % Block::CHUNK_SIZE_BITS != 0) { + nextBit = ((nextBit / Block::CHUNK_SIZE_BITS) + 1) * Block::CHUNK_SIZE_BITS; + } + + // Fetch our integer from the block + const std::uint32_t randint = + hasher.GetHashsum().Get(nextBit / Block::CHUNK_SIZE_BITS); + + // Advance our pointer + nextBit += Block::CHUNK_SIZE_BITS; + + // New state of the pointer: + // It ow may be more now than the size of a block, but that + // gets checked at the begin of a function. + // Not at the end, like here. + + // Return our integer + return randint; + } + } From 143ec19bf31ad21cf2853002c09b93994aeac24b Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Thu, 26 May 2022 15:04:39 +0200 Subject: [PATCH 054/110] Many methods now using vectors of blocks instead of flexblocks --- GCryptLib/include/GCrypt/Block.h | 25 ++++- GCryptLib/include/GCrypt/GHash.h | 11 +- GCryptLib/include/GCrypt/Util.h | 5 +- GCryptLib/src/Block.cpp | 100 +++++++++++++++++- GCryptLib/src/GHash.cpp | 49 ++++++--- GCryptLib/src/GPrng.cpp | 2 +- GCryptLib/src/GWrapper.cpp | 57 +++++++--- GCryptLib/src/Key.cpp | 4 +- GCryptLib/src/Util.cpp | 51 +++------ GCryptLib/test/Block.cpp | 73 +++++++++++-- .../test/Password2Key_CollisionResistance.cpp | 2 +- 11 files changed, 292 insertions(+), 87 deletions(-) diff --git a/GCryptLib/include/GCrypt/Block.h b/GCryptLib/include/GCrypt/Block.h index 032ebfc..a112fcc 100644 --- a/GCryptLib/include/GCrypt/Block.h +++ b/GCryptLib/include/GCrypt/Block.h @@ -26,12 +26,31 @@ namespace Leonetienne::GCrypt { ~Basic_Block(); - //! Will construct this block from a string like "011101..". Length MUST be 512. - void FromString(const std::string& str); + //! Will construct this block from a string like "011101..". + void FromBinaryString(const std::string& str); + + //! Will construct this block from a hexstring + void FromHexString(const std::string& str); + + //! Will construct this block from a bytestring (any characters) + void FromByteString(const std::string& str); + + //! Will construct this block from a textstring (any length) + void FromTextString(const std::string& str); //! Will create a bitset-compatible string ("0101110..") representation //! of this block. Length will always be 512. - std::string ToString() const; + std::string ToBinaryString() const; + + //! Will create a hexstring representation of this block. + std::string ToHexString() const; + + //! Will create a bytestring representation of this block. + std::string ToByteString() const; + + //! Will create a textstring representation of this block. + //! The difference to a bytestring is that it gets trimmed after a nullterminator. + std::string ToTextString() const; //! Will matrix-multiply two blocks together. //! Since the matrices values are pretty much sudo-random, diff --git a/GCryptLib/include/GCrypt/GHash.h b/GCryptLib/include/GCrypt/GHash.h index f962529..4cf6080 100644 --- a/GCryptLib/include/GCrypt/GHash.h +++ b/GCryptLib/include/GCrypt/GHash.h @@ -4,6 +4,7 @@ #include "GCrypt/Flexblock.h" #include "GCrypt/Block.h" #include "GCrypt/GCipher.h" +#include namespace Leonetienne::GCrypt { /** This class implements a hash function, based on the GCrypt cipher @@ -21,8 +22,14 @@ namespace Leonetienne::GCrypt { //! Will return the current hashsum const Block& GetHashsum() const; - //! Will calculate a hashsum for `data`. - static Block CalculateHashsum(const Flexblock& data); + //! Will calculate a hashsum for `blocks`. + //! Whilst n_bytes is optional, it is HIGHLY recommended to supply. + //! Without specifying the size of the input (doesn't always have to be 512*n bits) + //! b'293eff' would hash to the exact same values as b'293eff0000' + static Block CalculateHashsum(const std::vector& blocks, std::size_t n_bytes = std::string::npos); + + //! Will calculate a hashsum for a string + static Block HashString(const std::string& str); void operator=(const GHash& other); diff --git a/GCryptLib/include/GCrypt/Util.h b/GCryptLib/include/GCrypt/Util.h index 8a108f8..1d9dce7 100644 --- a/GCryptLib/include/GCrypt/Util.h +++ b/GCryptLib/include/GCrypt/Util.h @@ -30,7 +30,7 @@ namespace Leonetienne::GCrypt { Flexblock StringToBits(const std::string& s); //! Will convert a string to a vector of blocks - std::vector StringToBitblocks(const std::string& s); + std::vector StringToBitblocks(const std::string& str); //! Will convert a fixed-size data block to a bytestring std::string BitblockToBytes(const Block& block); @@ -71,6 +71,9 @@ namespace Leonetienne::GCrypt { //! Will save bits to a binary file void WriteBitsToFile(const std::string& filepath, const Flexblock& bits); + //! Will read a file directly to data blocks, and yield the amount of bytes read + std::vector ReadFileToBlocks(const std::string& filepath, std::size_t& bytes_read); + //! Will read a file directly to data blocks std::vector ReadFileToBlocks(const std::string& filepath); diff --git a/GCryptLib/src/Block.cpp b/GCryptLib/src/Block.cpp index 3a83d2c..3e3ef9d 100644 --- a/GCryptLib/src/Block.cpp +++ b/GCryptLib/src/Block.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include // Just to be sure, the compiler will optimize this // little formula out, let's do it in the preprocessor @@ -17,7 +19,7 @@ namespace Leonetienne::GCrypt { template Basic_Block::Basic_Block(const std::string& str) { - FromString(str); + FromBinaryString(str); } template @@ -26,9 +28,13 @@ namespace Leonetienne::GCrypt { } template - void Basic_Block::FromString(const std::string& str) { + void Basic_Block::FromBinaryString(const std::string& str) { - assert(str.length() == BLOCK_SIZE_BITS); + if (str.length() != BLOCK_SIZE_BITS) { + throw std::invalid_argument( + std::string("Unable to read binary block: \"") + str + "\": Length is not BLOCK_SIZE_BITS." + ); + } for (std::size_t i = 0; i < data.size(); i++) { data[i] = std::bitset( @@ -40,7 +46,58 @@ namespace Leonetienne::GCrypt { } template - std::string Basic_Block::ToString() const { + void Basic_Block::FromHexString(const std::string& str) { + + if (str.length() != BLOCK_SIZE*2) { + throw std::invalid_argument( + std::string("Unable to read hex block: \"") + str + "\": Length is not BLOCK_SIZE*2." + ); + } + + for (std::size_t i = 0; i < str.length(); i += CHUNK_SIZE*2) { + const std::string hexChunk = str.substr(i, CHUNK_SIZE*2); + try { + data[i / (CHUNK_SIZE*2)] = std::stoul(hexChunk, NULL, 16); + } + catch (std::invalid_argument&) { + throw std::invalid_argument( + std::string("Unable to read hex block: \"") + hexChunk + "\"." + ); + } + } + + return; + } + + template + void Basic_Block::FromByteString(const std::string& str) { + + if (str.length() != BLOCK_SIZE) { + throw std::invalid_argument( + std::string("Unable to read byte block: \"") + str + "\": Length is not BLOCK_SIZE." + ); + } + + // Iterate over all bytes in the block + std::uint8_t* curByte = (std::uint8_t*)(void*)Data(); + const char* strIt = 0; + for (std::size_t i = 0; i < BLOCK_SIZE; i++) { + *curByte++ = str[i]; + } + + return; + } + + template + void Basic_Block::FromTextString(const std::string& str) { + // Just pad the input string to lenght, and treat it as a byte string + FromByteString( + PadStringToLength(str, BLOCK_SIZE, '\0', false) + ); + } + + template + std::string Basic_Block::ToBinaryString() const { std::stringstream ss; for (std::size_t i = 0; i < data.size(); i++) { @@ -49,6 +106,41 @@ namespace Leonetienne::GCrypt { return ss.str(); } + template + std::string Basic_Block::ToHexString() const { + + std::stringstream ss; + for (std::size_t i = 0; i < data.size(); i++) { + ss + << std::setfill('0') + << std::setw(CHUNK_SIZE*2) + << std::hex + << data[i] + ; + } + + return ss.str(); + } + + template + std::string Basic_Block::ToByteString() const { + + std::stringstream ss; + ss.write((const char*)(void*)Data(), BLOCK_SIZE); + return ss.str(); + } + + template + std::string Basic_Block::ToTextString() const { + + std::string bytes = ToByteString(); + + // Trim extra nullterminators + bytes.resize(strlen(bytes.data())); + + return bytes; + } + template Basic_Block Basic_Block::MMul(const Basic_Block& o) const { diff --git a/GCryptLib/src/GHash.cpp b/GCryptLib/src/GHash.cpp index 9d1bc44..24a3614 100644 --- a/GCryptLib/src/GHash.cpp +++ b/GCryptLib/src/GHash.cpp @@ -31,34 +31,55 @@ namespace Leonetienne::GCrypt { return block; } - Block GHash::CalculateHashsum(const Flexblock& data) { - // Split input into blocks - std::vector blocks; + Block GHash::CalculateHashsum(const std::vector& data, std::size_t n_bytes) { - for (std::size_t i = 0; i < data.size(); i += Block::BLOCK_SIZE_BITS) { - blocks.push_back(Block( - PadStringToLength(data.substr(i, Block::BLOCK_SIZE_BITS), Block::BLOCK_SIZE_BITS, '0', false)) - ); + // If we have no supplied n_bytes, let's just assume sizeof(data). + if (n_bytes == std::string::npos) { + n_bytes = data.size() * Block::BLOCK_SIZE; } - // Add an additional block, containing the length of the input - std::stringstream ss; - ss << data.length(); - const Block lengthBlock = StringToBitblock(ss.str()); - blocks.push_back(lengthBlock); - // Create hasher instance GHash hasher; // Digest all blocks - for (Block& block : blocks) { + for (const Block& block : data) { hasher.DigestBlock(block); } + // Add an additional block, containing the length of the input + + // Here it is actually good to use a binary string ("10011"), + // because std::size_t is not fixed to 32-bits. It may aswell + // be 64 bits, depending on the platform. + // Then it would be BAD to just cram it into a 32-bit uint32. + // This way, in case of 64-bits, it would just occupy 2 uint32's. + + // Also, this operation gets done ONCE per n blocks. This won't + // hurt performance. + + // I know that we are first converting n_bytes to str(n_bytes), + // and then converting this to a binstring, making it unnecessarily large, + // but who cares. It has a whole 512 bit block to itself. + // The max size (2^64) would occupy 155 bits at max. (log10(2^64)*8 = 155) + + std::stringstream ss; + ss << n_bytes; + const Block lengthBlock = StringToBitblock(ss.str()); + + // Digest the length block + hasher.DigestBlock(lengthBlock); + // Return the total hashsum return hasher.GetHashsum(); } + Block GHash::HashString(const std::string& str) { + const std::vector blocks = StringToBitblocks(str); + const std::size_t n_bytes = str.length(); + + return CalculateHashsum(blocks, n_bytes); + } + void GHash::operator=(const GHash& other) { cipher = other.cipher; diff --git a/GCryptLib/src/GPrng.cpp b/GCryptLib/src/GPrng.cpp index b1731bf..524192c 100644 --- a/GCryptLib/src/GPrng.cpp +++ b/GCryptLib/src/GPrng.cpp @@ -78,7 +78,7 @@ namespace Leonetienne::GCrypt { // Performance improvement over the previous method: // (generating 1.000.000 integers): - // 5.26 seconds -> 3.84 seconds + // 5.26 seconds -> 3.75 seconds // Advance our pointer to the next whole uint32 diff --git a/GCryptLib/src/GWrapper.cpp b/GCryptLib/src/GWrapper.cpp index 5cf15ac..ced5957 100644 --- a/GCryptLib/src/GWrapper.cpp +++ b/GCryptLib/src/GWrapper.cpp @@ -10,33 +10,64 @@ namespace Leonetienne::GCrypt { const Key& key) { // Recode the ascii-string to bits - const Flexblock cleartext_bits = StringToBits(cleartext); + const std::vector cleartext_blocks = StringToBitblocks(cleartext); - // Encrypt our cleartext bits - const Flexblock ciphertext_bits = CipherFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); + // Create cipher instance + GCipher cipher(key, GCipher::DIRECTION::ENCIPHER); - // Recode the ciphertext bits to a hex-string - const std::string ciphertext = BitsToHexstring(ciphertext_bits); + // Encrypt all blocks + std::vector ciphertext_blocks; + + for (const Block& clearBlock : cleartext_blocks) { + ciphertext_blocks.emplace_back(cipher.Digest(clearBlock)); + } + + // Recode the ciphertext blocks to a hex-string + std::stringstream ss; + for (const Block& block : ciphertext_blocks) { + ss << block.ToHexString(); + } // Return it - return ciphertext; + return ss.str(); } std::string GWrapper::DecryptString( const std::string& ciphertext, const Key& key) { - // Recode the hex-string to bits - const Flexblock ciphertext_bits = HexstringToBits(ciphertext); + // Make sure our ciphertext is a multiple of block size + if (ciphertext.length() % Block::BLOCK_SIZE*2 != 0) { // Two chars per byte + throw std::runtime_error("Leonetienne::GCrypt::GWrapper::DecryptString() received ciphertext of length not a multiple of block size."); + } - // Decrypt the ciphertext bits - const std::string cleartext_bits = CipherFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); + // Recode the hex-string to blocks + std::vector ciphertext_blocks; + ciphertext_blocks.reserve(ciphertext.length() / (Block::BLOCK_SIZE*2)); + for (std::size_t i = 0; i < ciphertext.length(); i += Block::BLOCK_SIZE*2) { + Block block; + block.FromHexString(ciphertext.substr(i, Block::BLOCK_SIZE*2)); - // Recode the cleartext bits to an ascii-string - const std::string cleartext = BitsToString(cleartext_bits); + ciphertext_blocks.emplace_back(block); + } + + // Create cipher instance + GCipher cipher(key, GCipher::DIRECTION::DECIPHER); + + // Decrypt all blocks + std::vector cleartext_blocks; + for (const Block& cipherBlock : ciphertext_blocks) { + cleartext_blocks.emplace_back(cipher.Digest(cipherBlock)); + } + + // Recode the cleartext blocks to bytes + std::stringstream ss; + for (const Block& block : cleartext_blocks) { + ss << block.ToTextString(); + } // Return it - return cleartext; + return ss.str(); } bool GWrapper::EncryptFile( diff --git a/GCryptLib/src/Key.cpp b/GCryptLib/src/Key.cpp index f129c03..0dc23b1 100644 --- a/GCryptLib/src/Key.cpp +++ b/GCryptLib/src/Key.cpp @@ -9,9 +9,7 @@ namespace Leonetienne::GCrypt { Key Key::FromPassword(const std::string& password) { - return GHash::CalculateHashsum( - StringToBits(password) - ); + return GHash::HashString(password); } Key Key::Random() { diff --git a/GCryptLib/src/Util.cpp b/GCryptLib/src/Util.cpp index 2dcd0ee..83d412b 100644 --- a/GCryptLib/src/Util.cpp +++ b/GCryptLib/src/Util.cpp @@ -117,7 +117,7 @@ namespace Leonetienne::GCrypt { std::string BitblockToHexstring(const Block& b) { std::stringstream ss; const std::string charset = "0123456789abcdef"; - const std::string bstr = b.ToString(); + const std::string bstr = b.ToBinaryString(); for (std::size_t i = 0; i < bstr.size(); i += 4) { ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()]; @@ -232,8 +232,9 @@ namespace Leonetienne::GCrypt { return; } - std::vector ReadFileToBlocks(const std::string& filepath) { + std::vector ReadFileToBlocks(const std::string& filepath, std::size_t& bytes_read) { // Read file + bytes_read = 0; // "ate" specifies that the read-pointer is already at the end of the file // this allows to estimate the file size @@ -259,9 +260,10 @@ namespace Leonetienne::GCrypt { // Read data into the block ifs.read((char*)(void*)block.Data(), Block::BLOCK_SIZE); - const std::size_t n_bytes_read = ifs.gcount(); + const std::size_t n_bytes_read_block = ifs.gcount(); + bytes_read += n_bytes_read_block; - if (n_bytes_read > 0) { + if (n_bytes_read_block > 0) { // Append the block to our vector blocks.emplace_back(block); } @@ -273,6 +275,11 @@ namespace Leonetienne::GCrypt { return blocks; } + std::vector ReadFileToBlocks(const std::string& filepath) { + std::size_t bytes_read_dummy; // Create a dumme for the parameter + return ReadFileToBlocks(filepath, bytes_read_dummy); + } + void WriteBlocksToFile( const std::string& filepath, const std::vector& blocks @@ -296,45 +303,19 @@ namespace Leonetienne::GCrypt { return; } - std::vector StringToBitblocks(const std::string& s) { + std::vector StringToBitblocks(const std::string& str) { // Create our block vector, and reserve exactly // how many blocks are required to store this string - const std::size_t num_blocks = (s.length() / Block::BLOCK_SIZE) + 1; + const std::size_t num_blocks = (str.length() / Block::BLOCK_SIZE) + 1; std::vector blocks; blocks.reserve(num_blocks); - for (std::size_t i = 0; i < num_blocks; i++) { - // Create new block, and zero it + for (std::size_t i = 0; i < str.length(); i += Block::BLOCK_SIZE) { Block block; - block.Reset(); + block.FromTextString(str.substr(i, Block::BLOCK_SIZE)); - std::size_t bytes_copied = 0; - - // Iterate over all bytes in the block - std::uint8_t* curByte = (std::uint8_t*)(void*)block.Data(); - for (std::size_t j = 0; j < Block::BLOCK_SIZE; j++) { - curByte++; - - // Carry our character over - - const std::size_t strIdx = i*Block::BLOCK_SIZE + j; - // The string still has chars to give - if (strIdx < s.length()) { - *curByte = s[j]; - bytes_copied++; - } - // We've reached the end of the string - else { - // Save our block, if it contains any bytes - if (bytes_copied) { - blocks.emplace_back(block); - } - - // Return our blocks - return blocks; - } - } + blocks.emplace_back(block); } return blocks; diff --git a/GCryptLib/test/Block.cpp b/GCryptLib/test/Block.cpp index 7ac92dc..f643ccd 100644 --- a/GCryptLib/test/Block.cpp +++ b/GCryptLib/test/Block.cpp @@ -62,8 +62,8 @@ TEST_CASE(__FILE__"/operator=", "[Block]") { } } -// Tests that converting to, and from, strings works -TEST_CASE(__FILE__"/StringConversion", "[Block]") { +// Tests that converting to, and from, binary strings works +TEST_CASE(__FILE__"/BinaryStringConversion", "[Block]") { // Setup srand(time(0)); @@ -77,7 +77,60 @@ TEST_CASE(__FILE__"/StringConversion", "[Block]") { Block block(ss.str()); // Verify - REQUIRE(block.ToString() == ss.str()); + REQUIRE(block.ToBinaryString() == ss.str()); +} + +// Tests that converting to, and from, hexstrings works +TEST_CASE(__FILE__"/HexStringConversion", "[Block]") { + + // Setup + srand(time(0)); + std::stringstream ss; + + const std::string charset = "0123456789abcdef"; + for (std::size_t i = 0; i < 128; i++) { + ss << charset[rand() % charset.length()]; + } + + // Exercise + Block block; + block.FromHexString(ss.str()); + + // Verify + REQUIRE(block.ToHexString() == ss.str()); +} + +// Tests that converting to, and from, bytestrings works +TEST_CASE(__FILE__"/ByteStringConversion", "[Block]") { + + // Setup + srand(time(0)); + std::stringstream ss; + + for (std::size_t i = 0; i < 64; i++) { + ss << (char)(rand() % 256); + } + + // Exercise + Block block; + block.FromByteString(ss.str()); + + // Verify + REQUIRE(block.ToByteString() == ss.str()); +} + +// Tests that converting to, and from, textstrings works +TEST_CASE(__FILE__"/TextStringConversion", "[Block]") { + + // Setup + const std::string textstr = "Hello, World :3"; + + // Exercise + Block block; + block.FromTextString(textstr); + + // Verify + REQUIRE(block.ToTextString() == textstr); } // Tests that operator* is the same as *= @@ -646,7 +699,7 @@ TEST_CASE(__FILE__"/get-bit", "[Block]") { } // Verify - REQUIRE(ss.str() == a.ToString()); + REQUIRE(ss.str() == a.ToBinaryString()); } // Tests that the set-bit to-false method works @@ -690,7 +743,7 @@ TEST_CASE(__FILE__"/flip-bit", "[Block]") { // Setup Block a = Key::FromPassword("Halleluja"); - std::string compare = a.ToString(); + std::string compare = a.ToBinaryString(); compare[5] = compare[5] == '1' ? '0' : '1'; compare[15] = compare[15] == '1' ? '0' : '1'; compare[105] = compare[105] == '1' ? '0' : '1'; @@ -703,7 +756,7 @@ TEST_CASE(__FILE__"/flip-bit", "[Block]") { a.FlipBit(205); // Verify - REQUIRE(a.ToString() == compare); + REQUIRE(a.ToBinaryString() == compare); } // Tests that bitshifts (to the left) work @@ -732,8 +785,8 @@ TEST_CASE(__FILE__"/bitshift-left", "[Block]") { block = block.ShiftBitsLeft(); // Verify - REQUIRE(block.ToString().length() == shiftedBits.length()); - REQUIRE(block.ToString() == shiftedBits); + REQUIRE(block.ToBinaryString().length() == shiftedBits.length()); + REQUIRE(block.ToBinaryString() == shiftedBits); } // Tests that inplace-bitshifts to the left do the exact same as copy bitshifts @@ -782,8 +835,8 @@ TEST_CASE(__FILE__"/bitshift-right", "[Block]") { block = block.ShiftBitsRight(); // Verify - REQUIRE(block.ToString().length() == shiftedBits.length()); - REQUIRE(block.ToString() == shiftedBits); + REQUIRE(block.ToBinaryString().length() == shiftedBits.length()); + REQUIRE(block.ToBinaryString() == shiftedBits); } // Tests that inplace-bitshifts to the right do the exact same as copy bitshifts diff --git a/GCryptLib/test/Password2Key_CollisionResistance.cpp b/GCryptLib/test/Password2Key_CollisionResistance.cpp index a2fe221..7ab9526 100644 --- a/GCryptLib/test/Password2Key_CollisionResistance.cpp +++ b/GCryptLib/test/Password2Key_CollisionResistance.cpp @@ -70,7 +70,7 @@ TEST_CASE(__FILE__"/Password to key transformation collision resistance", "[Key const std::string password = Base10_2_X(i, charset, 0); // Generate key - const std::string newKeyBits = Key::FromPassword(password).ToString(); + const std::string newKeyBits = Key::FromPassword(password).ToBinaryString(); // Check if this block is already in our map if (keys.find(newKeyBits) != keys.cend()) { From e7c1e17e2c03f00dc9b95c9f66c4195f5c8316ac Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Thu, 26 May 2022 15:47:24 +0200 Subject: [PATCH 055/110] Got rid of flexblocks --- GCryptLib/include/GCrypt/Feistel.h | 6 + GCryptLib/include/GCrypt/Flexblock.h | 16 -- GCryptLib/include/GCrypt/GCipher.h | 11 +- GCryptLib/include/GCrypt/GHash.h | 1 - GCryptLib/include/GCrypt/GPrng.h | 7 +- GCryptLib/include/GCrypt/GWrapper.h | 13 +- GCryptLib/include/GCrypt/Util.h | 41 ----- GCryptLib/src/Feistel.cpp | 13 +- GCryptLib/src/GCipher.cpp | 22 +++ GCryptLib/src/GHash.cpp | 21 ++- GCryptLib/src/GWrapper.cpp | 28 +-- GCryptLib/src/Util.cpp | 184 +------------------- GCryptLib/test/EncryptEqualsDecrypt.cpp | 215 +++++------------------- GCryptLib/test/GCWrapper.cpp | 36 +++- 14 files changed, 160 insertions(+), 454 deletions(-) delete mode 100644 GCryptLib/include/GCrypt/Flexblock.h diff --git a/GCryptLib/include/GCrypt/Feistel.h b/GCryptLib/include/GCrypt/Feistel.h index 5d30334..5e3ce1a 100644 --- a/GCryptLib/include/GCrypt/Feistel.h +++ b/GCryptLib/include/GCrypt/Feistel.h @@ -10,6 +10,10 @@ namespace Leonetienne::GCrypt { */ class Feistel { public: + //! Empty initializer. If you use this, you must call SetKey()! + Feistel(); + + //! Will initialize the feistel cipher with a key explicit Feistel(const Key& key); Feistel(const Feistel& other) = delete; @@ -59,6 +63,8 @@ namespace Leonetienne::GCrypt { void ZeroKeyMemory(); Keyset roundKeys; + + bool isInitialized = false; }; } diff --git a/GCryptLib/include/GCrypt/Flexblock.h b/GCryptLib/include/GCrypt/Flexblock.h deleted file mode 100644 index 5e551b2..0000000 --- a/GCryptLib/include/GCrypt/Flexblock.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef GCRYPT_FLEXBLOCK_H -#define GCRYPT_FLEXBLOCK_H - -#include - -namespace Leonetienne::GCrypt { - //! A type used for conveying "bitstrings". e.g. "10101001001" - //! These should generally not be used, as they are really really slow. - //! The only valid usecase I can think of is when using GHash for example, because for hashing - //! an absolute input length is required. - //! If you need to, you can use the StringToBits() and BitsToString() functions defined in Util.h. - typedef std::string Flexblock; -} - -#endif - diff --git a/GCryptLib/include/GCrypt/GCipher.h b/GCryptLib/include/GCrypt/GCipher.h index 6050233..d496c37 100644 --- a/GCryptLib/include/GCrypt/GCipher.h +++ b/GCryptLib/include/GCrypt/GCipher.h @@ -2,7 +2,6 @@ #define GCRYPT_GCIPHER_H #include "GCrypt/Feistel.h" -#include "GCrypt/Flexblock.h" namespace Leonetienne::GCrypt { /** Class to apply a block/-stream cipher to messages of arbitrary length in a distributed manner @@ -15,6 +14,9 @@ namespace Leonetienne::GCrypt { DECIPHER }; + //! Empty initializer. If you use this, you must call Initialize()! + GCipher(); + //! Will initialize this cipher with a key explicit GCipher(const Key& key, const DIRECTION direction); @@ -30,6 +32,11 @@ namespace Leonetienne::GCrypt { void operator=(const GCipher& other); + + //! Will initialize the cipher with a key, and a mode. + //! If called on an existing object, it will reset its state. + void Initialize(const Key& key, const DIRECTION direction); + private: DIRECTION direction; @@ -38,6 +45,8 @@ namespace Leonetienne::GCrypt { //! The last block, required for CBC. Block lastBlock; + + bool isInitialized = false; }; } diff --git a/GCryptLib/include/GCrypt/GHash.h b/GCryptLib/include/GCrypt/GHash.h index 4cf6080..28e906a 100644 --- a/GCryptLib/include/GCrypt/GHash.h +++ b/GCryptLib/include/GCrypt/GHash.h @@ -1,7 +1,6 @@ #ifndef GCRYPT_GHASH_H #define GCRYPT_GHASH_H -#include "GCrypt/Flexblock.h" #include "GCrypt/Block.h" #include "GCrypt/GCipher.h" #include diff --git a/GCryptLib/include/GCrypt/GPrng.h b/GCryptLib/include/GCrypt/GPrng.h index 01845f5..89b7ab7 100644 --- a/GCryptLib/include/GCrypt/GPrng.h +++ b/GCryptLib/include/GCrypt/GPrng.h @@ -36,7 +36,12 @@ namespace Leonetienne::GCrypt { } // Transform to bytes - const std::string bytes = BitsToBytes(ss.str()); + const std::string bits = ss.str(); + ss.str(""); + for (std::size_t i = 0; i < bits.size(); i += 8) { + ss << (char)std::bitset<8>(bits.substr(i, 8)).to_ulong(); + } + const std::string bytes = ss.str(); // Cram bytes into type T t; diff --git a/GCryptLib/include/GCrypt/GWrapper.h b/GCryptLib/include/GCrypt/GWrapper.h index e10e550..9d9fab9 100644 --- a/GCryptLib/include/GCrypt/GWrapper.h +++ b/GCryptLib/include/GCrypt/GWrapper.h @@ -1,10 +1,11 @@ -#pragma once -#include -#include "GCrypt/Flexblock.h" +#ifndef GCRYPT_GWRAPPER_H +#define GCRYPT_GWRAPPER_H + #include "GCrypt/Block.h" #include "GCrypt/GCipher.h" #include "GCrypt/Key.h" - +#include +#include namespace Leonetienne::GCrypt { /** This class is a wrapper to make working with the GhettoCipher @@ -31,7 +32,7 @@ namespace Leonetienne::GCrypt { static bool DecryptFile(const std::string& filename_in, const std::string& filename_out, const Key& key, bool printProgressReport = false); //! Will enncrypt or decrypt an entire flexblock of binary data, given a key. - static Flexblock CipherFlexblock(const Flexblock& data, const Key& key, const GCipher::DIRECTION direction); + static std::vector CipherBlocks(const std::vector& data, const Key& key, const GCipher::DIRECTION direction); private: @@ -40,3 +41,5 @@ namespace Leonetienne::GCrypt { }; } +#endif + diff --git a/GCryptLib/include/GCrypt/Util.h b/GCryptLib/include/GCrypt/Util.h index 1d9dce7..d1a6869 100644 --- a/GCryptLib/include/GCrypt/Util.h +++ b/GCryptLib/include/GCrypt/Util.h @@ -7,7 +7,6 @@ #include #include #include "GCrypt/Block.h" -#include "GCrypt/Flexblock.h" #include "GCrypt/Config.h" #include "GCrypt/GCipher.h" #include "GCrypt/InitializationVector.h" @@ -21,56 +20,16 @@ namespace Leonetienne::GCrypt { //! Will pad a string to a set length with a certain character std::string PadStringToLength(const std::string& str, const std::size_t len, const char pad, const bool padLeft = true); - //! Will convert a string to a fixed-size data block - //! @s: The string to pad - //! padLeft: should padding be added to the left? If not, to the right. - Block StringToBitblock(const std::string& s, bool padLeft = true); - - //! Will convert a string to a flexible data block - Flexblock StringToBits(const std::string& s); - //! Will convert a string to a vector of blocks std::vector StringToBitblocks(const std::string& str); - //! Will convert a fixed-size data block to a bytestring - std::string BitblockToBytes(const Block& block); - //! Will convert an array of data blocks to a bytestring std::string BitblocksToBytes(const std::vector& bits); - //! Will convert a fixed-size data blocks to a textstring - //! The difference to BitblockToBytes() is, that it strips excess nullbytes - std::string BitblockToString(const Block& block); - //! Will convert an array of blocks to a character-string //! The difference to BitblocksToBytes() is, that it strips excess nullbytes std::string BitblocksToString(const std::vector& blocks); - //! Will convert a flexible data block to a bytestring - std::string BitsToBytes(const Flexblock& bits); - - //! Will convert a flexible data block to a string - //! The difference to BitsToBytes() is, that it strips excess nullbytes - std::string BitsToString(const Flexblock& bits); - - //! Turns a fixed-size data block into a hex-string - std::string BitblockToHexstring(const Block& b); - - //! Turns a flexible data block into a hex-string - std::string BitsToHexstring(const Flexblock& b); - - //! Turns a hex string into a fixed-size data block - Block HexstringToBitblock(const std::string& hexstring); - - //! Turns a hex string into a flexible data block - Flexblock HexstringToBits(const std::string& hexstring); - - //! Will read a file into a flexblock - Flexblock ReadFileToBits(const std::string& filepath); - - //! Will save bits to a binary file - void WriteBitsToFile(const std::string& filepath, const Flexblock& bits); - //! Will read a file directly to data blocks, and yield the amount of bytes read std::vector ReadFileToBlocks(const std::string& filepath, std::size_t& bytes_read); diff --git a/GCryptLib/src/Feistel.cpp b/GCryptLib/src/Feistel.cpp index 1c54a7f..51bfd4d 100644 --- a/GCryptLib/src/Feistel.cpp +++ b/GCryptLib/src/Feistel.cpp @@ -6,20 +6,20 @@ namespace Leonetienne::GCrypt { + Feistel::Feistel() { + } + Feistel::Feistel(const Key& key) { SetKey(key); - return; } Feistel::~Feistel() { ZeroKeyMemory(); - - return; } void Feistel::SetKey(const Key& key) { GenerateRoundKeys(key); - return; + isInitialized = true; } Block Feistel::Encipher(const Block& data) { @@ -31,6 +31,10 @@ namespace Leonetienne::GCrypt { } Block Feistel::Run(const Block& data, bool modeEncrypt) { + if (!isInitialized) { + throw std::runtime_error("Attempted to digest data on uninitialized GCipher!"); + } + const auto splitData = FeistelSplit(data); Halfblock l = splitData.first; Halfblock r = splitData.second; @@ -245,6 +249,7 @@ namespace Leonetienne::GCrypt { void Feistel::operator=(const Feistel& other) { roundKeys = other.roundKeys; + isInitialized = other.isInitialized; return; } diff --git a/GCryptLib/src/GCipher.cpp b/GCryptLib/src/GCipher.cpp index 3a2883f..3009142 100644 --- a/GCryptLib/src/GCipher.cpp +++ b/GCryptLib/src/GCipher.cpp @@ -7,17 +7,33 @@ namespace Leonetienne::GCrypt { + GCipher::GCipher() { + } + GCipher::GCipher(const Key& key, const DIRECTION direction) : direction { direction }, lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key feistel(key) { + isInitialized = true; + return; + } + + void GCipher::Initialize(const Key& key, const DIRECTION direction) { + feistel = Feistel(key); + lastBlock = InitializationVector(key); + this->direction = direction; + isInitialized = true; return; } Block GCipher::Digest(const Block& input) { + if (!isInitialized) { + throw std::runtime_error("Attempted to digest data on uninitialized GCipher!"); + } + switch (direction) { case DIRECTION::ENCIPHER: { // Rename our input to cleartext @@ -52,6 +68,11 @@ namespace Leonetienne::GCrypt { } void GCipher::SetKey(const Key& key) { + + if (!isInitialized) { + throw std::runtime_error("Attempted to set key on uninitialized GCipher!"); + } + feistel.SetKey(key); return; @@ -61,6 +82,7 @@ namespace Leonetienne::GCrypt { direction = other.direction; feistel = other.feistel; lastBlock = other.lastBlock; + isInitialized = other.isInitialized; return; } diff --git a/GCryptLib/src/GHash.cpp b/GCryptLib/src/GHash.cpp index 24a3614..85b9951 100644 --- a/GCryptLib/src/GHash.cpp +++ b/GCryptLib/src/GHash.cpp @@ -5,17 +5,23 @@ namespace Leonetienne::GCrypt { - GHash::GHash() : + GHash::GHash() { // Initialize our cipher with a static, but randomly distributed key. - cipher( + Block ivSeed; + ivSeed.FromByteString("3J7IipfQTDJbO8jtasz9PgWui6faPaEMOuVuAqyhB1S2CRcLw5caawewgDUEG1WN"); + block = InitializationVector(ivSeed); + + Key key; + key.FromByteString("nsoCZfvdqpRkeVTt9wzvPR3TT26peOW9E2kTHh3pdPCq2M7BpskvUljJHSrobUTI"); + + cipher = GCipher( // The key really does not matter, as it gets changed // each time before digesting anything. - Key(StringToBitblock("nsoCZfvdqpRkeVTt9wzvPR3TT26peOW9E2kTHh3pdPCq2M7BpskvUljJHSrobUTI")), + key, GCipher::DIRECTION::ENCIPHER - ) { - block = InitializationVector(StringToBitblock("3J7IipfQTDJbO8jtasz9PgWui6faPaEMOuVuAqyhB1S2CRcLw5caawewgDUEG1WN")); + ); - return; + return; } void GHash::DigestBlock(const Block& data) { @@ -64,7 +70,8 @@ namespace Leonetienne::GCrypt { std::stringstream ss; ss << n_bytes; - const Block lengthBlock = StringToBitblock(ss.str()); + Block lengthBlock; + lengthBlock.FromTextString(ss.str()); // Digest the length block hasher.DigestBlock(lengthBlock); diff --git a/GCryptLib/src/GWrapper.cpp b/GCryptLib/src/GWrapper.cpp index ced5957..69fd6ba 100644 --- a/GCryptLib/src/GWrapper.cpp +++ b/GCryptLib/src/GWrapper.cpp @@ -134,35 +134,25 @@ namespace Leonetienne::GCrypt { } } - Flexblock GWrapper::CipherFlexblock( - const Flexblock& data, + std::vector GWrapper::CipherBlocks( + const std::vector& data, const Key& key, const GCipher::DIRECTION direction) { - // Split input into blocks - std::vector blocks; - - for (std::size_t i = 0; i < data.size(); i += Block::BLOCK_SIZE_BITS) { - blocks.push_back(Block( - PadStringToLength(data.substr(i, Block::BLOCK_SIZE_BITS), Block::BLOCK_SIZE_BITS, '0', false)) - ); - } - // Create cipher instance GCipher cipher(key, direction); - for (Block& block : blocks) { - block = cipher.Digest(block); - } + std::vector digested; + digested.reserve(data.size()); - // Concatenate ciphertext blocks back into a flexblock - std::stringstream ss; - for (Block& b : blocks) { - ss << b; + // Digest all our blocks + for (const Block& block : data) { + Block digestedBlock = cipher.Digest(block); + digested.emplace_back(digestedBlock); } // Return it - return ss.str(); + return digested; } } diff --git a/GCryptLib/src/Util.cpp b/GCryptLib/src/Util.cpp index 83d412b..b86b8cb 100644 --- a/GCryptLib/src/Util.cpp +++ b/GCryptLib/src/Util.cpp @@ -30,58 +30,16 @@ namespace Leonetienne::GCrypt { return ss.str(); } - Block StringToBitblock(const std::string& s, bool padLeft) { - std::stringstream ss; - - for (std::size_t i = 0; i < s.size(); i++) { - ss << std::bitset<8>(s[i]); - } - - // Pad rest with zeores - return Block(PadStringToLength(ss.str(), Block::BLOCK_SIZE_BITS, '0', padLeft)); - } - - Flexblock StringToBits(const std::string& s) { - std::stringstream ss; - - for (std::size_t i = 0; i < s.size(); i++) { - ss << std::bitset<8>(s[i]); - } - - return Flexblock(ss.str()); - } - - std::string BitblockToBytes(const Block& block) { - std::stringstream ss; - - std::uint8_t* curByte = (std::uint8_t*)(void*)block.Data(); - for (std::size_t j = 0; j < Block::BLOCK_SIZE; j++) { - ss << *curByte++; - } - - return ss.str(); - } - std::string BitblocksToBytes(const std::vector& blocks) { std::stringstream ss; for (const Block& block : blocks) { - ss << BitblockToBytes(block); + ss << block.ToByteString(); } return ss.str(); } - std::string BitblockToString(const Block& bits) { - // Decode to bytes - std::string text = BitblockToBytes(bits); - - // Dümp excess nullbytes - text.resize(strlen(text.data())); - - return text; - } - std::string BitblocksToString(const std::vector& blocks) { // Decode to bytes std::string text = BitblocksToBytes(blocks); @@ -92,146 +50,6 @@ namespace Leonetienne::GCrypt { return text; } - std::string BitsToBytes(const Flexblock& bits) { - std::stringstream ss; - - const std::string bitstring = bits; - - for (std::size_t i = 0; i < bits.size(); i += 8) { - ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong(); - } - - return ss.str(); - } - - std::string BitsToString(const Flexblock& bits) { - // Decode to bytes - std::string text = BitsToBytes(bits); - - // Dümp excess nullbytes - text.resize(strlen(text.data())); - - return text; - } - - std::string BitblockToHexstring(const Block& b) { - std::stringstream ss; - const std::string charset = "0123456789abcdef"; - const std::string bstr = b.ToBinaryString(); - - for (std::size_t i = 0; i < bstr.size(); i += 4) { - ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()]; - } - - return ss.str(); - } - - std::string BitsToHexstring(const Flexblock& b) { - std::stringstream ss; - const std::string charset = "0123456789abcdef"; - const std::string bstr = b; - - for (std::size_t i = 0; i < bstr.size(); i += 4) { - ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()]; - } - - return ss.str(); - } - - Block HexstringToBitblock(const std::string& hexstring) { - std::stringstream ss; - - for (std::size_t i = 0; i < hexstring.size(); i++) { - const char c = hexstring[i]; - - // Get value - std::size_t value; - if ((c >= '0') && (c <= '9')) { - // Is it a number? - value = ((std::size_t)c - '0') + 0; - } - else if ((c >= 'a') && (c <= 'f')) { - // Else, it is a lowercase letter - value = ((std::size_t)c - 'a') + 10; - } - else { - throw std::logic_error("non-hex string detected in HexstringToBits()"); - } - - // Append to our bits - ss << std::bitset<4>(value).to_string(); - } - - return Block(ss.str()); - } - - Flexblock HexstringToBits(const std::string& hexstring) { - std::stringstream ss; - - for (std::size_t i = 0; i < hexstring.size(); i++) { - const char c = hexstring[i]; - - // Get value - std::size_t value; - if ((c >= '0') && (c <= '9')) { - // Is it a number? - value = ((std::size_t)c - '0') + 0; - } - else if ((c >= 'a') && (c <= 'f')) { - // Else, it is a lowercase letter - value = ((std::size_t)c - 'a') + 10; - } - else { - throw std::logic_error("non-hex string detected in HexstringToBits()"); - } - - // Append to our bits - ss << std::bitset<4>(value).to_string(); - } - - return ss.str(); - } - - Flexblock ReadFileToBits(const std::string& filepath) { - // Read file - std::ifstream ifs(filepath, std::ios::binary); - - if (!ifs.good()) { - throw std::runtime_error("Unable to open ifilestream!"); - } - - std::stringstream ss; - std::copy( - std::istreambuf_iterator(ifs), - std::istreambuf_iterator(), - std::ostreambuf_iterator(ss) - ); - - ifs.close(); - - const std::string bytes = ss.str(); - - // Convert bytes to bits - return StringToBits(bytes); - } - - void WriteBitsToFile(const std::string& filepath, const Flexblock& bits) { - // Convert bits to bytes - const std::string bytes = BitsToBytes(bits); - - // Write bits to file - std::ofstream ofs(filepath, std::ios::binary); - - if (!ofs.good()) { - throw std::runtime_error("Unable to open ofilestream!"); - } - - ofs.write(bytes.data(), bytes.length()); - ofs.close(); - - return; - } - std::vector ReadFileToBlocks(const std::string& filepath, std::size_t& bytes_read) { // Read file bytes_read = 0; diff --git a/GCryptLib/test/EncryptEqualsDecrypt.cpp b/GCryptLib/test/EncryptEqualsDecrypt.cpp index e66e371..f79ea87 100644 --- a/GCryptLib/test/EncryptEqualsDecrypt.cpp +++ b/GCryptLib/test/EncryptEqualsDecrypt.cpp @@ -7,13 +7,13 @@ using namespace Leonetienne::GCrypt; // THESE TESTS ASSUME BLOCK_SIZE == 512 // Tests that encrypting a message of exactly BLOCK_SIZE yields the exact message back -TEST_CASE(__FILE__"/SingleBlock_NoPadding", "[Encryption/Decryption consistency]") { +TEST_CASE(__FILE__"/SingleBlock", "[Encryption/Decryption consistency]") { // Instanciate our cipher and supply a key const Key key = Key::FromPassword("1234"); // Recode the ascii-string to bits - const Flexblock cleartext_bits = + const std::string cleartext_bits = "1011110011010110000010110001111000111010111101001010100100011101" "0101110101010010100000110100001000011000111010001001110101111111" "1110110101100101110001010101011110001010000010111110011011010111" @@ -23,196 +23,65 @@ TEST_CASE(__FILE__"/SingleBlock_NoPadding", "[Encryption/Decryption consistency] "1101100100000100010000001011100010010001101111100100101100010001" "0000011110010110111010110110111110011110011010001100100111110101"; + std::vector cleartext_blocks({Block(cleartext_bits)}); + // Encrypt our cleartext bits - const Flexblock ciphertext_bits = GWrapper::CipherFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); + const std::vector ciphertext_blocks = GWrapper::CipherBlocks(cleartext_blocks, key, GCipher::DIRECTION::ENCIPHER); // Decipher it again - const Flexblock decryptedBits = GWrapper::CipherFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); + const std::vector decrypted_blocks = GWrapper::CipherBlocks(ciphertext_blocks, key, GCipher::DIRECTION::DECIPHER); // Assert that the decrypted text equals the plaintext REQUIRE( - cleartext_bits == - decryptedBits - ); + cleartext_blocks == + decrypted_blocks + ); } -// Tests that encrypting a message of less than BLOCK_SIZE yields the exact message plus zero-padding back -TEST_CASE(__FILE__"/SingleBlock_Padding", "[Encryption/Decryption consistency]") { - - // Instanciate our cipher and supply a key - const Key key = Key::FromPassword("1234"); - - // Recode the ascii-string to bits - const Flexblock cleartext_bits = - "1011110011010110000010110001111000111010111101001010100100011101" - "0101110101010010100000110100001000011000111010001001110101111111" - "1110110101100101110001010101011110001010000010111110011011010111" - "1100110100111000000011100101010100110010001110010011000010111001" - "0000010000010000011001111010011110111001000000000110101000110001" - "0110111110110110100000010100000011010001000011100100111001001011" - "1101100100000100"; - - const Flexblock cleartext_bits_EXPECTED_RESULT = - "1011110011010110000010110001111000111010111101001010100100011101" - "0101110101010010100000110100001000011000111010001001110101111111" - "1110110101100101110001010101011110001010000010111110011011010111" - "1100110100111000000011100101010100110010001110010011000010111001" - "0000010000010000011001111010011110111001000000000110101000110001" - "0110111110110110100000010100000011010001000011100100111001001011" - "1101100100000100000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000000"; - - // Encrypt our cleartext bits - const Flexblock ciphertext_bits = GWrapper::CipherFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); - - // Decipher it again - const Flexblock decryptedBits = GWrapper::CipherFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); - - // Assert that the decrypted text equals the plaintext - REQUIRE( - cleartext_bits_EXPECTED_RESULT == - decryptedBits - ); -} - -// Tests that a decrypted ciphertext equals its plaintrext version, using a cleartext that requires A LOT of blocks +// Tests that a decrypted ciphertext equals its plaintext version, using a cleartext that requires A LOT of blocks TEST_CASE(__FILE__"MultiBlock_NoPadding/", "[Encryption/Decryption consistency]") { // Instanciate our cipher and supply a key const Key key = Key::FromPassword("1234"); - // Recode the ascii-string to bits - const Flexblock cleartext_bits = - "1011110011010110000010110001111000111010111101001010100100011101" - "0101110101010010100000110100001000011000111010001001110101111111" - "1110110101100101110001010101011110001010000010111110011011010111" - "1100110100111000000011100101010100110010001110010011000010111001" - "0000010000010000011001111010011110111001000000000110101000110001" - "0110111110110110100000010100000011010001000011100100111001001011" - "1101100100000100010000001011100010010001101111100100101100010001" - "0000011110010110111010110110111110011110011010001100100111110101" - "1000010010000000000100101011110001000101101101100000010011111011" - "1011111010110100100111100111110011100001111101111110000110001100" - "0001000111000111101110000111011011101010100010100101100111010100" - "0101111110110010110000111111011001101110101101100100100011000100" - "1000110010101001000100001001101000011111101011111100100000100101" - "1100001100111001011111001101000111011101011101000110010110110110" - "0111001010011010010000010110000110010101101100101110111100100011" - "0010111110011100010100000101100101110101101011110100100000110110" - "1001101110101001001111111000010100011100100000101000111101101111" - "0101111011110001101010111010001000111010101111001101100100100100" - "1110110111001100011010110000101000011001011100101100111101110000" - "1010101111011110000111011011011110000111010110110111111010101010" - "0111100101111001010111101000001010100000111010111100111011111001" - "0110111000000110100011011100101101010101101000010010011111100100" - "0010111000001011101110000110010011101001111010100111110111110101" - "1110111000000000101011000100101010000110110111101010011001111010" - "1101011110001110000011010111001100001100101000000101000101000010" - "0101000011011111010010110010000010101100001110011000110111110111" - "1110010101011110111001100010110101101011100111100011101010001011" - "0101110010100110101100111100010000111101111100000111000110110110" - "1001100111000000011010100000011101011000010010011010001011110000" - "1100100111111001001000011100110000011110001100000000010000001001" - "1110000000110010000010011010100011011011000000000111110000110111" - "0101110011001101010110010100011001110110000110010001100110011111"; + std::stringstream ss; + const std::string charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + // Read 10 blocks worth of characters + srand(time(0)); + for (std::size_t i = 0; i < 512*10; i++) { + ss << charset[rand() % charset.length()]; + } + const std::string cleartext_str = ss.str(); + + std::vector cleartext_blocks = StringToBitblocks(cleartext_str); // Encrypt our cleartext bits - const Flexblock ciphertext_bits = GWrapper::CipherFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); + std::vector ciphertext_blocks; + ciphertext_blocks.reserve(cleartext_blocks.size()); + { + GCipher cipher(key, GCipher::DIRECTION::ENCIPHER); + + for (const Block& clearBlock : cleartext_blocks) { + ciphertext_blocks.emplace_back(cipher.Digest(clearBlock)); + } + } // Decipher it again - const Flexblock decryptedBits = GWrapper::CipherFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); + std::vector deciphered_blocks; + deciphered_blocks.reserve(ciphertext_blocks.size()); + { + GCipher cipher(key, GCipher::DIRECTION::DECIPHER); + + for (const Block& ciphBlock : ciphertext_blocks) { + deciphered_blocks.emplace_back(cipher.Digest(ciphBlock)); + } + } // Assert that the decrypted text equals the plaintext REQUIRE( - cleartext_bits == - decryptedBits - ); -} - -// Tests that a decrypted ciphertext equals its plaintrext version, using a cleartext that requires A LOT of blocks -TEST_CASE(__FILE__"MultiBlock_Padding/", "[Encryption/Decryption consistency]") { - - // Instanciate our cipher and supply a key - const Key key = Key::FromPassword("1234"); - - // Recode the ascii-string to bits - const Flexblock cleartext_bits = - "1011110011010110000010110001111000111010111101001010100100011101" - "0101110101010010100000110100001000011000111010001001110101111111" - "1110110101100101110001010101011110001010000010111110011011010111" - "1100110100111000000011100101010100110010001110010011000010111001" - "0000010000010000011001111010011110111001000000000110101000110001" - "0110111110110110100000010100000011010001000011100100111001001011" - "1101100100000100010000001011100010010001101111100100101100010001" - "0000011110010110111010110110111110011110011010001100100111110101" - "1000010010000000000100101011110001000101101101100000010011111011" - "1011111010110100100111100111110011100001111101111110000110001100" - "0001000111000111101110000111011011101010100010100101100111010100" - "0101111110110010110000111111011001101110101101100100100011000100" - "1000110010101001000100001001101000011111101011111100100000100101" - "1100001100111001011111001101000111011101011101000110010110110110" - "0111001010011010010000010110000110010101101100101110111100100011" - "0010111110011100010100000101100101110101101011110100100000110110" - "1001101110101001001111111000010100011100100000101000111101101111" - "0101111011110001101010111010001000111010101111001101100100100100" - "1110110111001100011010110000101000011001011100101100111101110000" - "1010101111011110000111011011011110000111010110110111111010101010" - "0111100101111001010111101000001010100000111010111100111011111001" - "0110111000000110100011011100101101010101101000010010011111100100" - "0010111000001011101110000110010011101001111010100111110111110101" - "1110111000000000101011000100101010000110110111101010011001111010" - "1101011110001110000011010111001100001100101000000101000101000010" - "0101000011011111010010110010000010101100001110011000110111110111" - "1110010101011110111001100010110101101011100111100011101010001011" - "0101110010100110101100111100010000111101111100000111000110110110" - "1001100111000000011010100000011101011000010010011010001011110000" - "1100100111111001001000011100110000011110001100000000010000001001" - "11100000001100100000100110101000110110110000000001111100001"; - - const Flexblock cleartext_bits_EXPECTED_RESULT = - "1011110011010110000010110001111000111010111101001010100100011101" - "0101110101010010100000110100001000011000111010001001110101111111" - "1110110101100101110001010101011110001010000010111110011011010111" - "1100110100111000000011100101010100110010001110010011000010111001" - "0000010000010000011001111010011110111001000000000110101000110001" - "0110111110110110100000010100000011010001000011100100111001001011" - "1101100100000100010000001011100010010001101111100100101100010001" - "0000011110010110111010110110111110011110011010001100100111110101" - "1000010010000000000100101011110001000101101101100000010011111011" - "1011111010110100100111100111110011100001111101111110000110001100" - "0001000111000111101110000111011011101010100010100101100111010100" - "0101111110110010110000111111011001101110101101100100100011000100" - "1000110010101001000100001001101000011111101011111100100000100101" - "1100001100111001011111001101000111011101011101000110010110110110" - "0111001010011010010000010110000110010101101100101110111100100011" - "0010111110011100010100000101100101110101101011110100100000110110" - "1001101110101001001111111000010100011100100000101000111101101111" - "0101111011110001101010111010001000111010101111001101100100100100" - "1110110111001100011010110000101000011001011100101100111101110000" - "1010101111011110000111011011011110000111010110110111111010101010" - "0111100101111001010111101000001010100000111010111100111011111001" - "0110111000000110100011011100101101010101101000010010011111100100" - "0010111000001011101110000110010011101001111010100111110111110101" - "1110111000000000101011000100101010000110110111101010011001111010" - "1101011110001110000011010111001100001100101000000101000101000010" - "0101000011011111010010110010000010101100001110011000110111110111" - "1110010101011110111001100010110101101011100111100011101010001011" - "0101110010100110101100111100010000111101111100000111000110110110" - "1001100111000000011010100000011101011000010010011010001011110000" - "1100100111111001001000011100110000011110001100000000010000001001" - "1110000000110010000010011010100011011011000000000111110000100000" - "0000000000000000000000000000000000000000000000000000000000000000"; - - // Encrypt our cleartext bits - const Flexblock ciphertext_bits = GWrapper::CipherFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); - - // Decipher it again - const Flexblock decryptedBits = GWrapper::CipherFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); - - // Assert that the decrypted text equals the plaintext - REQUIRE( - cleartext_bits_EXPECTED_RESULT == - decryptedBits - ); + cleartext_blocks == + deciphered_blocks + ); } diff --git a/GCryptLib/test/GCWrapper.cpp b/GCryptLib/test/GCWrapper.cpp index ef59209..9fd086b 100644 --- a/GCryptLib/test/GCWrapper.cpp +++ b/GCryptLib/test/GCWrapper.cpp @@ -1,13 +1,12 @@ #include -#include #include #include "Catch2.h" using namespace Leonetienne::GCrypt; -// Tests that encrypting and decrypting strings using the wrapper works. +// Tests that encrypting and decrypting short strings using the wrapper works. // This test will start from scratch after encryption, to ensure EVERYTHING has to be re-calculated. -TEST_CASE(__FILE__"/Encrypting and decrypting strings works", "[Wrapper]") { +TEST_CASE(__FILE__"/Encrypting and decrypting strings works, Single block", "[Wrapper]") { // Setup const std::string plaintext = "Hello, World!"; @@ -26,6 +25,37 @@ TEST_CASE(__FILE__"/Encrypting and decrypting strings works", "[Wrapper]") { REQUIRE(plaintext == decrypted); } +// Tests that encrypting and decrypting very long strings using the wrapper works. +// This test will start from scratch after encryption, to ensure EVERYTHING has to be re-calculated. +TEST_CASE(__FILE__"/Encrypting and decrypting strings works, Many blocks block", "[Wrapper]") { + + // Setup + + // Read an not-multiple-of-blocksize amount of random chars, that's very large (about 200kb long string) + srand(time(0)); + + std::stringstream ss; + const std::string charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + for (std::size_t i = 0; i < 198273; i++) { + ss << charset[rand() % charset.length()]; + } + + const std::string plaintext = ss.str(); + const Key key = Key::FromPassword("Der Affe will Zucker"); + + std::string ciphertext; + std::string decrypted; + + // Encryption + ciphertext = GWrapper::EncryptString(plaintext, key); + + // Decryption + decrypted = GWrapper::DecryptString(ciphertext, key); + + // Assertion + REQUIRE(plaintext == decrypted); +} + // Tests that encrypting and decrypting files using the wrapper works. // This test will start from scratch after encryption, to ensure EVERYTHING has to be re-calculated. TEST_CASE(__FILE__"/Encrypting and decrypting files works", "[Wrapper]") { From c0418766d945a62d502b662c3aacd2e5874ef842 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Thu, 26 May 2022 18:24:44 +0200 Subject: [PATCH 056/110] Tidied up example/static test executables --- .gitmodules | 6 + GCryptLib/CMakeLists.txt | 46 ++++-- GCryptLib/exec/Benchmark.h | 23 +++ GCryptLib/exec/BmpPP | 1 + GCryptLib/exec/Eule | 1 + GCryptLib/exec/Visualize.h | 58 +++++++ GCryptLib/exec/benchmark-encryption.cpp | 21 +++ GCryptLib/exec/benchmark-prng.cpp | 42 +++++ GCryptLib/exec/encrypt-decrypt-files.cpp | 25 +++ GCryptLib/exec/encrypt-decrypt-strings.cpp | 30 ++++ GCryptLib/exec/execAssets/big-testfile.bmp | Bin 0 -> 11059338 bytes GCryptLib/exec/execAssets/testimage.bmp | Bin 0 -> 110646 bytes GCryptLib/exec/main.cpp | 46 ------ .../visualize-extreme-input-diffusion.cpp | 54 +++++++ .../exec/visualize-hashing-distribution.cpp | 34 ++++ .../exec/visualize-multiblock-diffusion.cpp | 45 ++++++ .../exec/visualize-prng-distribution.cpp | 146 ++++++++++++++++++ .../exec/visualize-singleblock-diffusion.cpp | 45 ++++++ GCryptLib/src/GHash.cpp | 13 +- GCryptLib/src/GPrng.cpp | 7 +- 20 files changed, 574 insertions(+), 69 deletions(-) create mode 100644 GCryptLib/exec/Benchmark.h create mode 160000 GCryptLib/exec/BmpPP create mode 160000 GCryptLib/exec/Eule create mode 100644 GCryptLib/exec/Visualize.h create mode 100644 GCryptLib/exec/benchmark-encryption.cpp create mode 100644 GCryptLib/exec/benchmark-prng.cpp create mode 100644 GCryptLib/exec/encrypt-decrypt-files.cpp create mode 100644 GCryptLib/exec/encrypt-decrypt-strings.cpp create mode 100644 GCryptLib/exec/execAssets/big-testfile.bmp create mode 100644 GCryptLib/exec/execAssets/testimage.bmp delete mode 100644 GCryptLib/exec/main.cpp create mode 100644 GCryptLib/exec/visualize-extreme-input-diffusion.cpp create mode 100644 GCryptLib/exec/visualize-hashing-distribution.cpp create mode 100644 GCryptLib/exec/visualize-multiblock-diffusion.cpp create mode 100644 GCryptLib/exec/visualize-prng-distribution.cpp create mode 100644 GCryptLib/exec/visualize-singleblock-diffusion.cpp diff --git a/.gitmodules b/.gitmodules index 64f5789..79eba58 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,9 @@ [submodule "GeneralUtility"] path = GeneralUtility url = https://gitea.leonetienne.de/leonetienne/GeneralUtility.git +[submodule "GCryptLib/exec/Eule"] + path = GCryptLib/exec/Eule + url = https://gitea.leonetienne.de/leonetienne/Eule.git +[submodule "GCryptLib/exec/BmpPP"] + path = GCryptLib/exec/BmpPP + url = https://gitea.leonetienne.de/leonetienne/BmpPP.git diff --git a/GCryptLib/CMakeLists.txt b/GCryptLib/CMakeLists.txt index 26fdf1a..9ca1629 100644 --- a/GCryptLib/CMakeLists.txt +++ b/GCryptLib/CMakeLists.txt @@ -40,7 +40,7 @@ target_compile_options(test PRIVATE ) -## Move test images to build dir +## Move test assest to build dir ADD_CUSTOM_COMMAND( TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory @@ -48,21 +48,39 @@ ADD_CUSTOM_COMMAND( ) -############## -# Executable # -############## -FILE(GLOB exec_src exec/*.cpp) -add_executable(exec - ${exec_src} -) -target_link_libraries(exec ${PROJECT_NAME}) - -target_include_directories(exec PRIVATE +############### +# Executables # +############### +FILE(GLOB bmpp_src exec/BmpPP/BmpPP/src/*.cpp) +FILE(GLOB eule_src exec/Eule/Eule/src/*.cpp) +add_compile_definitions(_EULE_NO_INTRINSICS_) +include_directories( include + exec/BmpPP/BmpPP/include + exec/Eule/Eule/include ) -target_compile_options(exec PRIVATE - -Werror - -fdiagnostics-color=always +## Move exec assets to build dir +ADD_CUSTOM_COMMAND( + TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/exec/execAssets/ $/execAssets/ ) +function(DECLARE_EXEC_EXAMPLE name) + add_executable(example-${name} exec/${name}.cpp ${bmpp_src} ${eule_src}) + target_link_libraries(example-${name} ${PROJECT_NAME}) + target_compile_options(example-${name} PRIVATE -Werror -fdiagnostics-color=always) +endfunction() + +# These are the names of the cpp files in /exec/, without the ".cpp". +DECLARE_EXEC_EXAMPLE(encrypt-decrypt-files) +DECLARE_EXEC_EXAMPLE(encrypt-decrypt-strings) +DECLARE_EXEC_EXAMPLE(benchmark-encryption) +DECLARE_EXEC_EXAMPLE(benchmark-prng) +DECLARE_EXEC_EXAMPLE(visualize-singleblock-diffusion) +DECLARE_EXEC_EXAMPLE(visualize-multiblock-diffusion) +DECLARE_EXEC_EXAMPLE(visualize-extreme-input-diffusion) +DECLARE_EXEC_EXAMPLE(visualize-prng-distribution) +DECLARE_EXEC_EXAMPLE(visualize-hashing-distribution) + diff --git a/GCryptLib/exec/Benchmark.h b/GCryptLib/exec/Benchmark.h new file mode 100644 index 0000000..6bb9679 --- /dev/null +++ b/GCryptLib/exec/Benchmark.h @@ -0,0 +1,23 @@ +#ifndef GCRYPTEXAMPLE_BENCHMARK_H +#define GCRYPTEXAMPLE_BENCHMARK_H + +#include +#include +#include + +void Benchmark(const std::string& brief, std::function toBenchmark) { + std::cout << "Benchmarking " << brief << "..." << std::endl; + + auto start = std::chrono::steady_clock::now(); + + toBenchmark(); + + auto end = std::chrono::steady_clock::now(); + double seconds = (double)std::chrono::duration_cast(end - start).count() / 1000.0; + std::cout << seconds << " seconds." << std::endl << std::endl; + + return; +} + +#endif + diff --git a/GCryptLib/exec/BmpPP b/GCryptLib/exec/BmpPP new file mode 160000 index 0000000..522f955 --- /dev/null +++ b/GCryptLib/exec/BmpPP @@ -0,0 +1 @@ +Subproject commit 522f9551ae31215cf63fcad88cacbfc8c818ccaf diff --git a/GCryptLib/exec/Eule b/GCryptLib/exec/Eule new file mode 160000 index 0000000..1bfd756 --- /dev/null +++ b/GCryptLib/exec/Eule @@ -0,0 +1 @@ +Subproject commit 1bfd756aa8bd1d484857735d63b4fdf8a15bbed5 diff --git a/GCryptLib/exec/Visualize.h b/GCryptLib/exec/Visualize.h new file mode 100644 index 0000000..4eb0aee --- /dev/null +++ b/GCryptLib/exec/Visualize.h @@ -0,0 +1,58 @@ +#ifndef GCRYPTEXAMPLE_VISUALIZE_H +#define GCRYPTEXAMPLE_VISUALIZE_H + +#include +#include +#include + +using namespace Leonetienne::GCrypt; +using namespace Leonetienne::Eule; +using namespace Leonetienne::BmpPP; + +void VisualizeBlock(const Block& block, const std::string& name) { + BMP bmp(Vector2i(32, 16), Colormode::RGB); + + std::size_t i = 0; + for (std::size_t x = 0; x < bmp.GetDimensions().x; x++) + for (std::size_t y = 0; y < bmp.GetDimensions().y; y++) { + const std::uint8_t pixel = block.GetBit(i) == false ? 255 : 0; + bmp.SetPixel(Vector2i(x, y), pixel); + + i++; + } + + bmp.Write(name); + + return; +} + +// size.x*size.y MUST equal blocks.size() * Block::BLOCK_SIZE_BITS. That should be, by defalt blocks.size * 512. +void VisualizeBlocks(const std::vector& blocks, const Vector2i& size, const std::string& name) { + + //! A bit of error checking... + if (size.x*size.y != blocks.size() * Block::BLOCK_SIZE_BITS) { + throw std::invalid_argument("Supplied unfitting widht/height for visualization. Does not fit bits!"); + } + + BMP bmp(size, Colormode::RGB); + + std::size_t i = 0; + for (std::size_t x = 0; x < bmp.GetDimensions().x; x++) + for (std::size_t y = 0; y < bmp.GetDimensions().y; y++) { + + const std::size_t blockIndex = i / Block::BLOCK_SIZE_BITS; + const std::size_t relBitIndex = i - blockIndex * Block::BLOCK_SIZE_BITS; + + const std::uint8_t pixel = blocks[blockIndex].GetBit(relBitIndex) == false ? 255 : 0; + bmp.SetPixel(Vector2i(x, y), pixel); + + i++; + } + + bmp.Write(name); + + return; +} + +#endif + diff --git a/GCryptLib/exec/benchmark-encryption.cpp b/GCryptLib/exec/benchmark-encryption.cpp new file mode 100644 index 0000000..1cf8441 --- /dev/null +++ b/GCryptLib/exec/benchmark-encryption.cpp @@ -0,0 +1,21 @@ +#include +#include "Benchmark.h" + +using namespace Leonetienne::GCrypt; + +int main() { + + Benchmark( + "file encryption", + []() { + GWrapper::EncryptFile( + "./execAssets/big-testfile.bmp", + "./execAssets/testimage.bmp.crypt", + Key::FromPassword("password1") + ); + } + ); + + return 0; +} + diff --git a/GCryptLib/exec/benchmark-prng.cpp b/GCryptLib/exec/benchmark-prng.cpp new file mode 100644 index 0000000..72977ba --- /dev/null +++ b/GCryptLib/exec/benchmark-prng.cpp @@ -0,0 +1,42 @@ +#include +#include +#include "Benchmark.h" + +using namespace Leonetienne::GCrypt; + +int main() { + + Benchmark( + "generating 1.000.000 32-bit uints using prng.GetRandom()", + []() { + GPrng prng(Key::Random()); + for (int i = 0; i < 1000000; i++) { + prng.GetRandom(); + } + } + ); + + Benchmark( + "generating 1.000.000 uint32_t using prng()", + []() { + GPrng prng(Key::Random()); + for (int i = 0; i < 1000000; i++) { + prng(); + } + } + ); + + Benchmark( + "generating 100.000 data blocks using prng.GetBlock()", + []() { + GPrng prng(Key::Random()); + for (int i = 0; i < 100000; i++) { + prng.GetBlock(); + } + } + ); + + + return 0; +} + diff --git a/GCryptLib/exec/encrypt-decrypt-files.cpp b/GCryptLib/exec/encrypt-decrypt-files.cpp new file mode 100644 index 0000000..1759fdf --- /dev/null +++ b/GCryptLib/exec/encrypt-decrypt-files.cpp @@ -0,0 +1,25 @@ +#include +#include + +using namespace Leonetienne::GCrypt; + +int main() { + std::cout << "Example on how to encrypt & decrypt any file:" << std::endl; + + // Encrypt + GWrapper::EncryptFile( + "./execAssets/testimage.bmp", + "./execAssets/testimage.bmp.crypt", + Key::FromPassword("password1") + ); + + // Decrypt + GWrapper::DecryptFile( + "./execAssets/testimage.bmp.crypt", + "./execAssets/testimage.bmp.clear.bmp", + Key::FromPassword("password1" + )); + + return 0; +} + diff --git a/GCryptLib/exec/encrypt-decrypt-strings.cpp b/GCryptLib/exec/encrypt-decrypt-strings.cpp new file mode 100644 index 0000000..846bef0 --- /dev/null +++ b/GCryptLib/exec/encrypt-decrypt-strings.cpp @@ -0,0 +1,30 @@ +#include +#include + +using namespace Leonetienne::GCrypt; + +int main() { + std::cout << "Example on how to encrypt & decrypt strings:" << std::endl; + + const std::string cleartext = "Hello, World :3"; + std::cout << "Cleartext: " << cleartext << std::endl; + + // Encrypt + const std::string ciphertext = GWrapper::EncryptString( + cleartext, + Key::FromPassword("password1") + ); + + std::cout << "Ciphertext: " << ciphertext << std::endl; + + // Decrypt + const std::string decrypted = GWrapper::DecryptString( + ciphertext, + Key::FromPassword("password1") + ); + + std::cout << "Decrypted: " << decrypted << std::endl; + + return 0; +} + diff --git a/GCryptLib/exec/execAssets/big-testfile.bmp b/GCryptLib/exec/execAssets/big-testfile.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ae0756ea14cc4af80e939d02a57394e5c34f50c4 GIT binary patch literal 11059338 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

IXTWD#$Iaj~ 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%0D9;#QKq3I4L5ra zjPEOg!y9^7b|2jz^ilt5d#m9F4k_ztQm!8a^)d4((fp-?40LeNA>{(;Q#q-F`Olm! z&B5&BYuyKsSr3}$Ge|plxc18P4VSvAID9^pPi~FW56Xq|g!In>VnqQj?e(Xo_ONEI zvEk1gJ|oE>;zHg+*dcQIlpr#9z6D3mLjOD);B3>z9%`Oi|0wX8t($y0J6W89kaJ^k zjkx@X{CO(x6~kwg&$g7_I#T!Yp#xXjcMon~`NF#7lN;s{W89F07-H~wY#pU0JeC#z zV%AI+98(dr*tFS(DvNi_=B)>OIX!>2kwXhFABp{1eUfL`$P;JLRyZsG;TZ~)TM!7E z1=l|d{Fy7C0isdE_nDkJNGwh8nI|P2T$4z#HUYu25Ms$+PAplbLg8PAe=96pDBvZ& zZUR9IvS)E&2J9@n^+3!SjcxI=)n~(A{pk(KB>3MrAHgX!=g%mEKf_ev%E2wK^&Ncq z5Rt31%s^u*f(CS&7Dh4tOj*omay>N6hZ;el$;hbhz({4@Pjk}X?|~GD!yA&%<3)>+q8HO@pnrZ8@@$tjPa)Eld~+=292hJ@aQ%fr76ynxdIxjT zk7g}8RkQ-y*E3Cf&UEd+bf}(kYV_4H$!I;sPcOGtohdIGEm(Oz_Zg^{!JoN)8~1vc zHsd8_Ib^x*nCy8%|IGO_@Fu}$JQ(DW$uk}g@Dj%X2jp}`*16{0cx)T*t~pmzcDgw4 zbm2+}vk49tre4CRbO8+$pDUv5z=PQfPZusZy<^>lhCSyxsxe-GQ3D)gK=SeGU1y6o zoGDy}DOdQ`*bPWqk+lIkfX~8y0zO}1>S%yydVpajA$+g+k$IG*-G|J{e0b*P6aJ_p zFyzNxz$7mm&xt5ZyTk(Z{D5E%8d-B!{=s$WEM_)17AJNANArT^)aD5a4>bTmPkUa^P$@nKXTzUy_Q6SpAo)N8hMBlR z8`(CI`w{|`Gmt{Sv!|MJcI@4Wuin{RyjHZsE7;m=RlxA}pgx1Ig@itC@>dGoV(-ux6_4d06e z@#nW*{oDnA6QoTeQm=165())Jne7p3fZWq5Uw}37;f1W+CO^a#lksWS`x$TDNRzp<1 zXY4`WxE+D<+2KwmM*=DSlF&__F)bdL!|vCsG4*KuUZ?9gwuDEQky}f$zy5h3E_V((<>x#?v z+CON$c$?xf6EG7Z=Gd8Vv@~g%bD|J<3uP=(k9Q$yPLsw{zCtMKWl4w(c`_o+nQ9hE z6U9rk0F;5vbPZN=( z4v$wwAZ1>pG&saDAW&lVllT}Vo?a3+H;G;+QE4S|plPMVNeaC*STyv~Ak)xGLo5vw z4?t`cZ!7Be5R^ntO@l;CJupvt0x+NzhfAZxrN`;N&WqR=!A zL{zZA$t;T3qh7@zitU2|xdE{>)~6S@h4h|MffO&p_Y* z{`t#c!6`WR;=+P^Dt3TBL)(BSWN1@w48Tu#-?{3o!`q+Zs#?2UgQq=HenaL&DjT6j1O?F3Y{rxCe5YtNl<_)quE?;9@;du8QA%1UOGCUvDoT-m?LU-;;T%G~XYt{W z_Ft;nbUJ_8;QCbBY+(kBL_nT7e-*sjUFmK(Q(ba;$NJMn%b;Ec6+B;%axQ-Xz~GsJ6!2KEW!Og#<}4X4$+_56 zjvv5qZyk0IgTmLkYOd6koZh->WYaU?sN{3PATu8S@Nhz+Uls(P`FtWq%W(`J1v?At z+I`4;O#Ip2a}G~hf#ob=HBj?J6s29X#&}T%&(ncJhbQM-jm1A7sJYp*|1u^B9ICSf zw{B)L6fO=lAxS0vWq{AuSiIaz1yUMg*o6j?CWVzt)7g!4oCUMsuycNiPjhiuxF&on ze5M9SIEV+Zz8abr$@nv}5MpaIC86seEOE|Nr_c!GH{PwL+-+lcL?^^luJ8yqsk3avLQ9+ac##eyP z#GhaP(u$yoKfnFjmvFj%{pH)e9VeX~TpdUVI0q0$AE1t09yotXWI~BKyu>A_Oc_$8 z46KC0R&6R)`Rt&8fZ4EJ=DAJkwpHe~Mee>;Ap}RwwA`UI>`;R_6L#LEHtvQ~G3j-o zb2eA1O;tMcUOi-k)z}vYVp+)jObCcHGtntH4_BL3mQgE~jQ6K0o zFJo#s7Y8zZpbiNH{kmO%odY`EgW3(DZC>H6#>i$ME=;}m3~e)T{%nJw0d@q( zS22i&gKI#ug6vz{T>Y9{ObxC+jTE5Jeyw`1TA5$1Jh(vk_bGk%s!fP}O8*KizEn`ImpTd= zoWOx(5$YhgZBSN0hp0^Fm<;Ebg>xcd#EP(yJ&Tmjli)Kz^i%#UX0~DmD=v%M%%&_} zS6rUWy5ctCb;V_In@1^&w<#_!l_pq(%@8MpGb7U+ShN%K*&qkB1H)%cY8hCGvRT7l<7|8D9qonzQH(P-y3bOj+D=b?h>A)CyJf zQf1U)c~pihGE*M27|zlPykidf#vrL*gHLp`Pjs7aWQ!r9)ibQ!4O#z49gU!|Ev>~M2tF7rh)!Dr zbXt%)`}8OgkSH^o4jO2iqB~wY0)LP(=D{iGpOAypw%V3+XE5UsE=s$i9FyJvWsSL zI7KsK6C4>ZeMgDPL1IuSgWU|#hM*|-AUBE5RpNT(+$;A!_!9gXxgNkm!Jj|-Et+r{&Lo_g_ByuJq6EzWF&m`iDm>{5c^ksJ~)6x{9zAhPT6wzM5Bi4_t06 z9^AR=B&KZ^QEuy}@feQ)x^f7}nK*yOlCxZJY3PeCW~Tx^BirE7yfgsSi#40BwpCr} zK6t6W7P2(-Vqm)g_zdOq>B@XC-cz|55KW=)11vC}zW_A&TwW>{KMNf$o0mfU!xi|% zSgZ@;&G|EzS6wJd!wg@75(SHo?^u1Idh5-uy|2J(14%6hAlt^ClNTa-G&I!|of>XV z$a-Y-62YkQ_~9lVymG>7gBd=f8MXtrXOL&)!MSm$=0CaClw(*!lz@vSS+)e!3y<#Kr{R>#6jZ*N6c!uiyk;__jvnSWa3Sn=RN%c&fJ0ZvYwwHnsdX@!2_dCmifSplzMAZC1tBXH(;-f7} z=EP&G5-1>bX2DYvqHGaJKN~yvT-@-ggpqa0gOE&H$ukHxwO5;Z8PeH}s6o;GaGID0RJ z(-vZ51gFzn1#KyBSO5|7OL>cjO0%Iwyb90ZzDAfZ6MyEIYZgnuuFC^0kQ_t0JTlO9 zdZ6jtkrrHC$2%*B_GBS{D?Sm-83Fi=UBYaO(VTfB*~yrl0SFAy?~A!h$I1$CweP>t z1+U}w^WF6TWur*LceojXYG&wRz0~syzI7>ZFmVCuO004kZXW%OV+=&&yI@TGdhh-# z&Ba5zSN}981^gMA&Ttt&lbwP~Jt*`8A?T^hc`A7px1lV4Oqq=PEQh814$dD5@adTH zgDs3?L;tyW1eQ~|OD~ld-sr4?(-h1KFs%$!A72WG`o^JVI0KJW7M$3$;zS-PoUu({ z=L^}Ch!DbNGKGeqI+x6Zg?->33gpY{R!2)X(_xgeq+=wB-KAFFKZ11-5_5%Qz zNE>~*ZWl~8a6>#@gb`unFJ5qN6CE^IW1Y>(fB^_J*w{~~wJ)}nou?Z#jMp0QGq~Pc zj|9iy{4eEaVh_(0kWQNq=3*ol_ftN4j$NXgDQ>AES-3!wQJCR*$?|oqPnDGMkOfu| zm(dI_acqeU7p3tyUzm#EWuD+zcuT0{Pc`2PlZA&Ln=O3%OP1%tvVFE=v`g5r{50$^ zegpV-5Q5&i@?v@JrJC*6dkz9YLk|zzWI%rY4uu{5{CMj5M-0IBnYmT>A(i7+1y!sl$zh8fF?;FJ3yZ7&b z34d_^V@`%2BXG9a)SdgkeV@fW;?H;PeE!i#==|RQ$A9?xKfLq1U!W`W+8^G1?LIWa zBocn(3z7|E`TCbr<3aiJ)GhFuC%v7wU;hIVDI&!@;@vmCdiV9OVJ(6W1%JkO1b@DD z{nt$mKX!BkOaZ-|1FoWul_lcN8&&jt!=2NEd-6Kc% zl*){|N!kqVLO=UWSxk78Il9~58n-9v&2Nb3QN=TiNOwd&C z;#249Tkpp4tg*?>*zAfhwYZwwT>RVg2mp}44p;CKQadA`7qV`(YQUVsI`rY4E)hr; z*69LD49#I!r!J!1HLBGBwO(|!DXi2xaEq6InN)^Me?biGVy-=ujSxC=t)rCB!grKm zGQM1*Ns`R3i3q9p4C!_a>(>SM$bvhiVO{FbPOsp0PhvQe#n0lG0OJCG<}=^^6 zbF+)N$rT71VQzFWH|qVHw8%>sglJF&*HVO5>msVX{CB#lp(=!u8ACN%i7Y^3SfmNx z=I3APX#|2ksP?K>84s$>`*nf)^>8eS*l!5iY}Ca{;cyH193(ZtDR+Ti`NyGXS1%jjd)#gS=?qeW%0V=@@&=>w-K)^E{ogPmSu5NBU)OZGz>SUM5a78 zLlJ|eZD4gd&r3M5L=93C0v%ft6aqn8!(u3nwQK@=BC_n@#vNF~+=B&~ON&EL_%jS1 z3zz8>Wej40YVJIBRI)leQ56=W2#S*WhdP=99gJQQy@y2OE>Yiy!+;tc<92T*AI`3hXu}ez@(qh zpd%IAp`HTGyLG7Mwa&d)YPJvUT8F+TdO&a?o}nx8^sR?D0yw1T!1CTDST5^x!C8^? zy6ECT3Wa>)IQTDYTRu`#1m@USrxCfmY4FAb>An6>H76_&9fPsY*W zeSR?bjO~0IaJFe6V9!|=1nkVWBfPX%5Od%M0?3cpc!D|Gn1sNuV|5}z;Lm{1$V-TT zA{w;$)SATMwMnPfB%XdQe(+hOEQ~+;T>OiORdFw^B6n!~5|EhkC6;XvIR|mvu&XE5 z#BgWn;k8&j5gP$^rmd|_0D>k(vB-Qw;Lj*<_{^!Ycxi*3g_lo=KjUQNC#F6AJd~9J z{`_KY#^COaH+!qEAUhcNGfNZpK>YbaPs6$Hrt|%+WBo1I0;m@*+T-oz$9JuLDL(`L z8@MQq<&fw6X)x#9g(JD3(DP7IJi{ABA}ZqL&<`VPbHlqkOm`_xP4&FXSv3%u5A*r8KX| z00__IKRSQrH~q_-mmgsbSYx>3YbF!K;y`?OaaAne6m4Ibi9yNs$o;D_Cw=0(rLK&%=c&kTerV zrBs8<1~;u4E-Sj!y!Tdr{p-lXTf6P#&S#GoE*jaCGPY>}62oD<;7smfBtX2Jvjhkl zpF0FI?XnGLTT5t+7>TF5$@v6UC+C`Wo+{ml8|zr!lJVTktGOB1^3o9))unx4)?qOB z7{zFBA#rkk5FX-Lh_AvPf#{)v7pxB$^im9;1v1RZvpxPiEqNA1&b%3B zM;%chqcI_I3gXW+iw*xi{9BQ>W4Q2{!7a}YR~DXWC_%!$YyEXNv+#R{^7-Q7)-y=c z$rb)g=M1QegO49Po_WYs;}G*(?yDbR&1h-C>@CqhBaf{J#0=};Y8@FDH#&RQ&GD&qG#+#&^M@+AZ-v5Kt}vBLjb$=piOOrY z)=;d$l7h^fH5NZ-NSz^>F4q7%`&DTW{`*vc)rx>RSzx_9pg|6Y4O4^Cw?XX-dx~Zk zpC-L`^F;Wxy85=cu&jcVTM${j7=_k?q5!Hc+i?hlg(U}}Qyc}JjgLZJ0 zc%-Z5)rW;Ox`njK!}{gn1F&pWu;hkrNF^o)&NgK+e7tzV-C2-+Xn2^$pw4Kf@PpK4iHy&>*EKzO0ieW6SOH(KB<3=RZKR7)MqTiwii z+)NcN{`=hg_PXLYM^$?TY;|#4D06a`Xy(X}ku5Z?9gwuDEQky}f$zy5h3E_V((<>x#?v z+S{uauPZLwYj3Y!yso%xue~k)wbEd|t}TC-$8+oq2N+SrEtOefnKVuus3+O;_co^5D$>ZQ)j6s|fUF3XyXp$x{UhN;PG>6N5LgZe7G6Sv{9uk;Kt2GjpLL!$* zq|UHimq;BY@;MZ^(9E#_YVI$MvlufP0wi-{B+68Y+e&9swk~LkTSS?A>1=atjm=Qg?Myp!JIM6gMu3k(Lf%f&_K|Air{`(P`@m& zPa4=O_oqazYHScTM}(j|U9n|c65->4DJK}Ai|8=TZSs$=4T-4?2`(_YFIFj|=fGXx zK`Vi+6S)1BqFuM&`yIs3P(gDo?uQ@zVG?|P(qqszL(+d{FQ@Y7_kTtH8{ZXw{`u>l z{^eUA|M2jo$e;zz633LVz~@VfFk^JQxfGh!vE5mNn^qpn%fReQJWRsrj%!CBx^wY# zMVljlzAEpp@!l3Xtvrzp_%l-fKoEtTeS^hoM(eho>#aC<Eeob}lA zKQ;b5l{t%Rrlrj`l>$J1pn{b)TQHaKQta(KZCMPNACW)LOrH6>-(Q~!mU8Rx!Iz(} ze&uk@rN*6uTUNZdF$LzgV1Q@?@(ctGM0^a6&{^}Q^5>~qXfcr%vt@e-THJ>7XL~Il zy?&P1S!ia%!-bdj3IczAM4tTUtMjh_V$7{JxR@EtnaJ~Vag>n|6nbUc$>$PItxg(R zlZ@qw=OB7tcy#?jXyAXcKKaLM=lyVPBH}OBCH;6^(vQ|9{A5icvKGQM`o*>J*evBG z#HI*4C!boIbaHhfwof0y-oi&CL7^Bvqbz35LK(X%0B4)RljF}EL5uk_S3VDKn2!Ps zkTDALQcn7*-Ro~aW69{y*x{B3(mxZM>Vd&U%Y}h9%Jdh+5nH}jHB60E>>>2-duU3xBmL!R^TiE zyf z;KnqhAvjx=4~$PK8wSXymx6M)QF0C3zpmErI97Ml4Ce* z;H&X~-vtl;l0T1;5f<1o3(5ePw`449=}7*{b7e)Zbnb=o@b#X`v(=jii&vg3N*O9z zc&acBPjsWXnHTbwfeO15YsU=f&3x7Q-J5j}w^X1edL`A_ku!sD?KPv&fhPb>W9>$2Y@XGjYAJL57P( z9v7PyUD}+ExV$A}eA6O?V1F^Sz#9lltRk67R)Noq4mso`nZ=^7!#%rWk%C zbn;s!Q=LOCG#y~VmxDb%u`&IrC(*;z*hA1fZ6d+v3H}UA_J&J6wO2b2oUh(F zRGc-uZOz!`6(jf&=49YoBOPb;%K1rVSB>0xcS-sG`k%k~=z}jmz4Hy?qq|?Yy5mfLdi>y%M6|z-AR9phfN1s`6`B`?M;3+ZCn`q|-uXF3KAS*a9;R z*pmWo1VY^h@QWm09s00#*N9e+kb2j!8Uy6bu?GU?mIwH6_I7zrrATumg)^8f^oO9$ zAV2t8!0POqAww2KjGhv$uf#Jz;uAV2Alxx%t~@kB9ht0(T&RvtR?js_4Cn~pr9fLSu*J^LlSPxT({b)1kY{-$0NO%%Oe*8g%bb#7%uC45%G?Ak zD0kZ+A~z{04V;)sip!H*POKx#?v+S{ua zuPZLwYj3Y!yso%xuf4r`@w(!&z4r9ufuva+?B~RxF|p#wK?WVxSSC%FHkLal@W8vU zjOMy!VP^;+Gj7bOHSua$EDvmXk<;LSN>m;arH4e}E`bfQOg9JmUy1V^!qb%Y5ECwNQQ}HzKCT2P z?I)4VmFnheJeRtf)_RiPPO(qi!9dt|L^ODYHMzo5I=D?4+)3(aOvH%j(MI;_5Me!9 zL`bhTqz}_HDCnBmqebdfiY^_cVeKVD4{q)O!VD+skS+!^Ep(|K+qT(hWHs7873iU3lpXU!4qT0e`cWgiGFcT{<;47 zJLk{PKmXv+cvRqgnZz;K&$}yk<kL!1Ll3zo%CdQvh3v{Fj zfmDNd7Zbyw(nn^@s|`CxOV%CF&pf^{6+i&9uql{~ndW5|kT8q~p?EO^33ZWog2@*1-m+D8`-nSPAc|Exm_WhYRYI3h@x@ED^Xew=0JiO0y;~U8sP>%ew zv9UEUtjyaPWbs;UPIR*3N2=veDwm(|_+?Mp1W%TgynY9D? zGrSjP=4(6G_H19pYZ5wecsLIf;m=8tJkU`=qkwJATzP4KYHua^8O3`FBPkwae6^0c zT-2~PYjUm@JlDEy#b$Lf_T5s(^B=myH8}qL|UwFMS_e#N*wyo>f<#KY|mDIQ^X^X|;I3pGx5BM|6 zXJs8W5@!3v+la_nH(1tyvx3h$e^w+}--d!ITOLVysB0VYO-Xz6QT*SOKZ_}Jaufp) z^8b~xm=^0yS%MeGsRWr6*0Cp%5r;c9hwdL9AkQdkw0tJ(88bL*zyuJ;ybj2hm9dBCbs9*Hy=Fs?FYa39Qgd{yTASL z{jWX{{wxR@E%fi4KfnLmU%&gc7)`(T<$Ldb34ccX{P%zN>03V%@v}DV)M!u9hjz)< zH;DNLl|%8~q3Zuo$I4cf5P;g6Ma%VT;gmb`xO?fuvz7*VJRv*7&3}PM}w`K z!O7F$I>F$9%PVv0=h;nNz%^Od}q~odY9Xij?nwK>qKCVmP$;=&U!&uOlSHg@(8X5rC$rpg?lP;n!p3dq3JJ%X+I~K%4`c1;#W>83v=51}o5Lv2 zBHP&u?Sf<6W<*H7FL^MzU8e z>!G;r8@+&l(%i}>8w`O4%TR;sa`TBv4uRXoAd|)oX?m`EK!GGJ4X*H0x@OBUdM<{OX3pr7(*2Izk$q4Vbt-g)@$zdpqO z`46Ih=4FW)SU-L9<3Dfen(n*6!C*GuYfR}gVTd%C$t#)caQsVMivKYE3-~i{)KB^I zlL6-;C#9w@Mn9vDsrWO38G0-9YQg^Jv!6k>)LnO=>v%r!x%pTj+!g-{EGcd_=JuBD zB;hz6Nh~7Si!P*ypGiKb%>X6Y5b?X_&nTZ&s-5QK=+g-iScM>azH}(hdOK(-~ zy#Hr~J&lLqDqTfeevlA#a{U4<6a))zntyiF0)(uHUC(_x{>;&aXUN~U!SK6}WbFvC zv%cB)kUuMlbw5n4>#q9&Y9oKvaI|=atWik@Lry(A2XAMLzF$}~?+2^q{pFekf4wR4 z#pET-dT8692D`gav6p+!?S|YtO}V#m2(Q}LTd^B?d`C_O?g1}luKbJm$P;T9Jil(? zpRZl`{OZu>SIz&yx<%x#d}(7iGU*rB&KJuLEoe+}FVRd_6l&IKvnhWb6g3Z8se|ZY zfOEf9rp$Se@+Q$d>-uNm&zr)|tY3I4F}h{vdQvu^tAq=QLUJ_z&p?cy64FUx)-6&`LT&Kr{srKW_?a+Y|;YZA*+g6Cd?rLiFk9 z)?cqWbX_tS7IGO}Ouu}H!xJ!B%XAnr9W>;2*E7|EQub1lQKAbPF}T*>Zo z$7EC#A!u9ra!i1`EB0t!(0La%Q7fWun&{PI7&YfyF4*3(V-pU#P)gpuc%mUG2SEdS z!I%t8OG*e0L_?lsq*YlfYd#OWLO_54;4FEOkoi-XNN29NylW$ONIdgFomWeDw(X5S zo4u5AinAP_=|Y%GlOG{1R?Ml=Ft3&)G;eu^CwR}1y*;S48}elq(ovC}UoF_&v1?;% z)(R3UVEByhL}%vW&P*|&0KgJPcsoi93*F$t)JcP~Uatyjt;Ud{%Eq{wi3D0guh9!# z>5;@YGG|j*O?kBZnWk2+#3Fq+(LYNLjx;nIq9|ZwM8xVTVh4?#nk16ek`gjT&%CW0 zH3x6h=k+$on-adzlFWkTvBE1y3woMzuh$+R)#l}r9UT?B@m}La=wcm-r{zx@hj#e` z7rze0pZg|}eHRFNIR32JZioR0gIrp$u}p2NFBBDYUEa-_+#BTwE*;E%C42o3GFI?^!^w4Fu(uc3slg;pN9^5OrwgS4%Nq> zzk2`OuRnPA;s5yW5C8VSo9j1EpBZv^D=lQSO%4P1eCZ&GaA2ua)-b&$7$s*Gs?%zu5b@2_ncMiKC8fE z#$k`?dpw!0K7Ng(!yj<%Z}V?QU(Aw)EdT7olST!uv}%)p*vuU9pe+EHIQo<@HXv~Caj5x^TWe=;FRxNJQ{*^Yq zmG(G_c$br4(T$iaj?iKXJ+ahoQn?)-ty9a!cprA2k~?Nv;e>#kaZ~nr_-u3c++=I9 zNCcAzp3U72*6s##7tvL^np;n^n}m&REZ@RhFkOtzY#6(E+rpp4@Oj=6E5T^6K@Af2 z&o=lt7k$JGbs1{E!sFXNCCvYpT0pa~5XfwzmNyyHFlEs)@DXdZV5m@}*K`Sd7NNc# zR`VaxY2Y&-O+?h-WzI{ULCws$@4T8eTQTrH(+{!x09^NN&n}Nb%>qE`tiUzP#nuZ6 zhNYI;E?8-^V5M#73Y+ZDX*slpKc| zlUCOBBtPU92b3Ofun91?3$gHc#?gJF!^E^Pep|;)-R;FBh*^a`Bv+kYB4$L>syzd0 zJn-L`QscyMo?or~lv>-VwYL5>HhwiW%;SJU``6hKNSc-51{;H&wGb<5;Io)@Xa%)| zNE0#+SnYzfKFnF7)?s?B-Sip<{Hp=coQTAQqP1>xn%d|Zc+73u30J=+N3R;&iIt91 zF%`)V@JpV^UCZ9X`QB@9{p!KzAn5mg`5FBAG3E1PbD*B`=i%OnhI+#pNj z@#p{aA3ys;@#p)meg4*)pB!)K3i1hcGMI-?a<6!15mHjgA(BEGyTxd4=xZSRfi&_) z{bclYU+^SrT_~4{*=`7Y*3?j{H}t#a&+1%sT5)?mld-&c*QP5) z&)uj!bPLlAGVF+Gr5{#`&K!Z`DEkf$OGk{k zt0Z;0lADSAo36SfZ%T<~3O3z64MB@4TWPl8&lgj~ii99T69E%I9c|Rh4dM1IhN6Q7 zS>5&cX81h7|CxE>Dn>$^)i#PSo0d(PvuSzc{COyresL|D83RQ5{D2bAM6XFQd#5IOYObqkuQ+!(5#OBHnS zGlk*x&%Za3^DrP<2g@TYz@G;mZ5Ro3KP>#6e;krCYgqyZt~Hu(X#80$n)?FNj91po z{o$&RzXU$74|_RdSkDo+6~XZkmjd_TW(-adw~iIaI9=8L_JXZv zcPG5KWzC-@#r=75++U?Gg-D;&;Pb{sEgKf1_J_(gZ(BpASE0U*CCC&JRSH!e zSxDkJrk0R;_^7xZ-L5aVRldJtchbx8v8NNFkUeXL&*5A{TS6EX$E};f&uPCz>%5io0X6)Pt(75OGzu8r_ucK(& z#RKVQHVA z_K89%;ln_6H88F7XAM3_iw8(bw0gexQBVf5$yzAq?Mx0Q2Lw>GEpsW>8Q02o-)Stm z(@=P;VlN-bQ%OF-){Mnm9sr-IQi5SqB1E$dTTWYiA#-`h!Q|^T`+JXxs+MQ&^`rT> zn{uyJY`?TW{(Sbb3u)l=n9B%~0mW#2VXf)0S2APzLF18s)ZsG+A=F1x@~mnG1FbtF_42Yd z+p%TqfB5@`AeIrsy!T;C^WRSP z4-uy&a=4H3J8pb0FCeTrRti=6ckb##HVPmzO)$x^V#L_&pc znS%;6%s6a-Tah~Z9&z%kaO1En$%LiN;19W_uQOGGxv-Q zdd@v4(|yufI|rcaR89S>n6u`tYHhG`FxaDTb~khOGI#Z{@(i$^7-AC`Y6Wnf9d0u> z%4R+hW3v!h<5F96&LNAf=Pa?F4Te%P`jHAhYaX%6A`;4^l#OwY^U*ZUvk#nT;bKXf zj5BzyaGr5+%8YVvAu#pMrp$TxvZ$b|9sB%4WX^j)wVevzDm$M_`^lA#laGkCwRgFT zPpO+<$r#+B@gealv&Hbluh?ZO9wQ};1&o31`6}nA5JT`c@&#dGrzKg~=k6}(f zv-!=)IXKbGeU9xE%mHGoW-hf1S#BE&RRgjCpFz+ly|EhLyAz}0&;6VbOcAsxdwg1c z+5)t|U6vwpXeqF&&t+OS z0HMGs2A-5ke(KyM^tF@;DwTaSJ2HG@49j`kH$c!Pu~4&{W-0d>#J#ByaPv;|y+N435qQd$RR8z@^P?Y|Je! zun{sdlTkKsG;Z*kYlqnkgY80d*Cn=|tL?p0+1?=`98|jRqaWhKC&MX@@!%Wf?76Xf6D!#wY~MK@@+U zR%Zu=o>k}0!Qs!7YHfV#Y{{9(K%2PbS6O=3Sx;)T_Gxeos2Vq;*e`JFBqpj@jj?~} z#dE*@)fWW*8}Mh$H~L#Z8;7Bv^5@?Ne}3=(KKw)RXEIZ~_S)xfzWG^GeP`h0dCmrl zSRap?XBQ%=Wlklp%A~-f*CW!7R1)EdvElC;_V)GczHJtp-}QBl_V|N-FB+DhGs0Ts z|BNE*LJ}#QVt~(=3$l9~4)q)}&buTNI^9)_86hgy%6E0_O9no(G5dFg!|&i>lMrGw>_r-0w9Vzmlk^g(bR#ItED?sFA1TJKo3pBrs#(eAZu)a zGL<5AHVISyOy69(=SR_d%M@&6&)9b`!}P|nGNfX68w+n&?(aO1hB-O#83L~{{BWqU z^aQmIxcb&|*&2UV{F1dUq2|>&7=j)YK2te5`20A3*5NaSZ{*LWV43na^5>Dk z=S8LrdHC}8ls|7+a1y2E&h@wJ4_-f>-*Y_g_VK)qoYb?4kz|pB7Gn5(GGQSZ=q{{Z z*s^|+RBptrw|^)KJwpCGjLvzORRcNj6V!|lJL{YM(edYg#QP*h&3#@Rz-QsWTE@n+ z>qD_|{=wRLFC<2t-L|H)aP!T&gLjS>UTY}6)>zupC{8|)MzXkFG!=+x0~S5_6df-n zjaqlr!OLZPE|AoqaLeVAZM{c!-Kjfpw`R|^f~@wP>;8J~bpmory&?@NCb z!;QK;8l23G82^${uB*P}=Fu`7t9pu`YuUY#VG)_slPWnN7%GKx>f&e4&b7%?kEIw) zVJa2F!F#pjfNXY|!Pbn(w#@JgDUzQN&UtB1%9WD+uQipw&RL3gckNDW&tBf1x%gsM zRBJ|9OZuXYEU{?D()n6i9I68`)7ZAMGbg3H<}gH&-$VEDqU+BWT|b_C^~m;1If<>? zR$kh&RQPjxRCjuGPeu%Z*jOlWX4JQdD_PMhI7nwkBtd~1^>I-CtZSYr=q!3r{qsQV ztZLM|lN!4p`Kui-8$F2<>c55^)f=5G8Q>PPFJl%(wTc#&ae>ru8Vc#S$PAKW&!jGq z*O;u;&DbVy+t{%qzH@tg=e7-ar?h81BUua6m%Wm*l!+d55+aN~;U z9*$u%rgyYldgq-_e);ZiKX~x)-FLnQ4uAN;7ax7_`G*fa13{yL9-cpwu6S)&`~6Sv-+A!-^F7v%dv2&k}QIyTPCWcq^=Bh$s7 zS==y=*!fo2`j*@KmN|Kgaj_c$X)GgrN*#&G+R~did z+?BwL0`wt<60=uMx^;$ZGf#f){i4rqTF1_Pmj~Ql zu+(zla*IVQCHQEJ`JiKd-U6t#Q7Rd%v6&rfHCx?4`f&7o!OOOx%j_1YOVUrF05x*x zXp8w#mJ6@}Vc3h{Z%_iCA8UrgaKa&Gb8F%T73&bP*l{ie?mR@a!>mZhStzAL9j485 z2$*T(7i8`2Z|UW2?#bxVSc9vF!O_KFZzIVK!O&*>6W0!gpd1YN)tgN)SdyZ2j=??J zcEU4Ge(~>>0jwSwRX(Z26udf@P#%FVbOIC{tfmL z^}?wAa{o`_()8H93yGm;X~n-q18>6{sH?WD1m zE?)S^U(TOw%f6o7zZL#W!alrBlm#^3o$hUO=8~2jt2zs_y6g5|J5k6?OhKLIeIX!vuoxA8zL>OVNG-I9i28TOpGOFv*=!(l9+Wfd zy5)h}s~UZS5f%m#U{zzPZPxY16in+)%UEhKvlX!H67zX$&OJ4MhsSRP?vD8xOK1e(M4Bf#J7M^lA!KdX&_C*opW zSsOyINHlN6+@v>a&l{eMI$}E)|7{(?d@X)caP=Ys@jLK0PY+=*ckTG`UNkq z6$B0XHs#NHW9`=rIDBZIPy_#;VNI-1+rnA6jcg95W{U+U?MRi~4dolcB9n;6Tu&*_9PMjNqu z20?emM-a$*FUCh-+!WCsABhCIHGa{B#IVyT5ih01ys&xs&4z=tb9X(Wbm7mJYaXSV zm1jg>h|jZ%J~5|Sg^Tr#s{O4yH@%b;hnH+y%JPfJOGtr-%33C{FdDAi)d8?PHyMg0 zDCij3IKn8>(?_AN9lkIqe5R7USgN-azB?uu@Mk6~bstQ+k(Z8h#VOoK7_ZkXpm`iO zr-olhi)c-kL1Azul(-`??tJ2su6?Owb-dD$558-`#NepdZgo&oHQyNXkBqJVDk)XI)IM_xaEOSL(-PLy;t z<#sgX^gLg1{Y2i4y1nfO5-x3D)sYb=Duwju-b^w8VqOs;__q%rcV{|~G#p{PQn@?5B&n87!J^Yz>70UdU7%^!{79*5%NsEoX-6% ze=;c+RXnLA@8Zr;o6AiP0;~`;{8=Gr#h=^jiw2FM`17C}Q#sW3n(Vm*b9f02cQeQZ ze8$ZDe0_dPeIau$TI-8j8_Q2u6&*XgXGzHPi7rluckTTjKmY$eeDL-AbT;3Ahy{n{ zw(%7R8u+ZmH}L20NdNrRM-RS!@XqJV`Tc;*ga7!&-~8w!90*1EOep>=`sYvobo9^n zzeLpilh;3ei@5it*o>g@M&SLUFYn&}@YUP@T2l71i0S~X?grnL?xAIqrj%ICtQ{kE z8ApU6dmnM|6^mv&-zr<5N*kXec0Lu37#E8*M~NE+P%|M`66Ma5Dx4AYYO-D@?@IAK zRsvw3Di_HiSdF2m8^J{Hpem1`a?fdn9#apxPu=A?ImLPGDto6z=4R-eQTH+B9Oi5Z zb+&ReIJg*`-GsonPc~qw>K|e^eSzI91cZ1yx6)=VS;>~z&%)m|#&#A4 z6rd!9Oo2rr{bggjkU0Cf3O+~ML!sGa0nQuL#5&E1v=4?qlWPov4%W`L4|2C0BQ4`< z;KHV7c>?EgUR63km4r)E4+@Pz>MW?4B#Fuhx|XuB9w9UUSpw321RU)Gil=d~<^Vwx zg6NMp;o~~B9K#c5p9)v;f-ZMPc}P=FEVYt-%bd|dPv1X&@+KF%8RoPPG=7YwYmm+K z`G~z8=0rKnh<2E<*nXBMLM=lSG1Ih{vw_cqW>cUe=x^Z9n)3N6e|{X34uM1a(a}Hc zkAw1OD*G7k2wH4V+N>1IYKY{qfs#H~4Lr>CFi}t|0*o^T1+^S_g~n^sQ1fyN;m<4u zL^JlJ*?q7J+GaVFHZwv}DB6*8P=b>JkTKbiAdjc@Ty+^n{;X}Ue4)7ufu>_E7sgnH z#aJ)Gj2drwK(vg1*)3E%ipf03gg*nft!EO-A%r8y-N|M)_1FYOL#LhQL^;h?-W`(b z(0)22Vl%C$OtJ9wG4q~in7{y>r(q0tCZ<2waWgQJM5}_M$!~~}?ihph1cSA|!7+%!L~4A;z-QD72r3pixA# zjc>ouvcxjP#&8=n+efVX9T{i~VkS$Ki}2@qj$@4h2>f|=nfLtMX$&cHLtnc#{=IiU zhCB-beTQLa(lKau5IS_#ETCnk($oBddYgQw1>w)U0=@HFEXdyb#l!#n590q!GGg4u zUcdWWEfL0-ObYw)&^};8jgOD29{zmi?&q(+`B`0Uhu?%bSV_fsdo(-~is3U%k~DVL zlB0Xb=bjX$?EXkMgD{5RjaoWWeevk6JH=>aY*Hhd5YvytmrdXNhu`v#Ypv<`qO6dw z4om5qAZNltndE&Pd*fkiH;?6BJ(|lfd+DD=J3+p=8GsQqTn-0c3O`W66o%X z2wL-k<{%^}1dOyEFKs=+tZ?=s|5QHH?XMipZrQR99MO^#NAHXuCoMpa67iDA;Zo(d zs@MV-Ou#7gQ0isifR3OCh0j!uoIeAf|FHadT* z0)o?_h&DZ`D)&2`j&1wZ>mT(E1}*5DsluS!JXxhqK1Wy>$ytVC(IcrJ2#rToqvPm7 z_Y(2*hWRh9nS+kKc|+)hRddd-4q*@hTjsx7H~$BzvF8sYV}^g@gqWk^?Zb^xoOy_& zWwO-#;h8I;T;g?CAGv?_1+yw-cuTYN;ig1ZJ7lQWYI80e%J{34WzVk-dvQY;841s< z3Bi9u(?5ssf2w{nDm9^Lf2PMygRu0df^|cB_x*f$tH;XaZj4J3?Rm7ItKsmC z`UAb?+b-v3p4_tb+?MriJCZvOX1DH2c{zK{U#GA9VN%=+3DL|oKsMZ!7;z;b99-G4 zDY|`QI0zapjrj%{2~Q=5|1c@y2kCL0rQ7cPMHzNUo%KcC$Bta8EkX<3(@+Fhrtuj# zkS9e$3BU@5#$aW8lO$H-si81ePhH`){4H%6E6#3&)Wx)HiV{EM)EE$V3!>uWFq!a@ z6si0TczT{o5}=0*2O)L`Tw7vvS5ge2@&X_v=6Ru>4v=bshogE-^jq=>=vTu>HWskV z6HueyFky}lKRlnkqB}p6XxXyrT%xjNj=G%AvpAwTJ(AG)v-o03XhzLwn=kK6fHO;K zzoP|^e}-cDZ<67X#^Rp({3}QHw;V`)C3E>HRMQ!8Jmc`!;$;j~0MBmT!~o09DRNBX zqnxx6#*iAGbi5CsPwvPBZ$_U>k7?chY{%jB?#e?<8Mu3*=yvViuAGDmTbFWql0%TZ z3CXcNsmprPmtqGENxqU5-nBW3!R71unXfe*>TSyDXgW+1%4K6=e#^?fh2kKSx~ zRU2{W?|8%Q()T8&E2Vjl>K8b$snFb1V)#j)&sg?S=JKBMUD%Fcu-wbrQC)FIU2%JT znUOy?2o3HUy#!ju>>7$tEc3z!b5=N-0)Lq5qbymaj}QrSHu7g-;ElzMp2z^oF)edP zEqOxA5J)%ImHkyk!RC$Y#@IW=L@d60^Yvf7_bGZOu=Bg`d_m&BKDmyXV{5t`<($)@ z93xe|wp5-Q(wRkNjn~KfzkTrT!+-vt5C86OKKaT0Pu{x!6;>OXPWVgFKNAqz`$k6& z)fXF8uj>1=G2i0;>q48~zW>?3yZ71KuYLK}Jz>%J-~9O28^5{z)~~wn{@0ajH(P?9 zk<(2v_-~#xt7JSX-|0tOzzBF^z)R8V!k;Hs*DoXHcnEVE%-u2fh4vjrU3S9Jk8Z zd7-r}e$HHiqgWZ^dSPW|a4<7-wXzv+RXGZ5}w!x-XlaW@rpLhCCCZZPo&V zRxpmRBRy=GR&Na9Mc`;{mD*7g1J6?%=rwEuhGJt_%2Y7BH}kMrOnjx=OUr@MkT? zAa(XW;x@U$m8G#z?m|*Rqi;#26B}b%g0S4T&?P9}YwFgq9&xso-qK1=23v2-i8F1c zEwY^xsfjAlRRXUhtmhDYuuj8w0KGn@x7Z5bT8Tk1soq=^)CQ(C-=;k1>7efY!VmteYl{D;x+d-3yDHL5kZ15i-Qq1#8sQ*=5FlvdbWTMqagn%qN> zKo2}-zw6OIDjyFu`lG9+AKP6&vR2@RBca`$R9Q_@P#QXD!Om?vThjfVFs2Wj)M1{+_4(@d)|;STO`j*~Wc zOiJ^ZvV-)dUQ=_&2NaGEEE_+qY8;%|yUr2pOvY7~lE<*dk$d=*dKVHJ@=;|rq)fo2 z#Xh>mRZaQ;M62Y60ksZz-3K>1POY&Is&^%OY;gIwnS~SGpS31S?5tU{{`r5s_Zvo{ z|K;It-gyWJg++hx;Pdw%;KZd3OuzT=!}r9Yi{RPa_p0!;@Ex=OE&M*_WABLV2^5+v z81Mb^;m`l`XMgkN$3Gz-1fFBUpTA^~`uD(}IT5cYKYsI*`r3PDr=vU&nNMafcx6fy<>Nu3qTe+{NA&->kD1ng#Gm)JBDG7kOY7TT3J$G^Y zn)d9aY7{_u6{@yUOCulF@*k-hae>yvSFAF&s+Jn5udiw{h@g5#s<$OmM}_E0zcMX? zt~5PL5m$>{WQ-)xA(?yj>We$#uaxY#Qgx6?)?6Wkxr=mBjYh&OvO0|+)2Ajt%Ji)1 zI!W(IdNiVZCZpm7Ehs>tsbm*PN_ecC`I~g9I!|BSJ z{2^KGc5mpc+S7Zy;L35iD*{F?Hp5MS?u(a zC6~d4$<2t*L~WEbwRJ|3Xt4c?k*O&roQ< zcwadw`GNQD)D*5Pv} zIruaLZOWe&g8oMSERb2vpfOp(pXD*i!!aomoiOKxKVR6qvb!j|yLj`(?dy1sgCE6v zIXwbv3&o$cN3d99so+`6V-&NFj{S+u-MD!)zpE+#Vq-o|Q@}v}o4Svd(rDe)`#bWp z`0qGFYJ)U+*!5u1oD#vodDzL59Zj{)pZmb3ssXDCWo4PU7;Q5e?2B6#x9(isUijRV z+QZBpc=Z^*=-aR4CgHO|Q;_obYT6Q(yq_R`?#Yh5u{o+cGrT){@s%B`dh*lJJTutW zd7_~6cv0_((p!xMcdHNH%FXWFvZ@^;Xmrk-qdK!AyR*cI<7##cVENMK7zi```ATL4 z*ctddkUyhy?nj>aI1oO6BY%cA>j+vEjQkn$teG(DNZGU?6nf~j#`n)*`LoWP^};~- z%p0-_S!L?cq1mtLAbMbdjkyMfOU|Y*elcTNdtNrv-@5Da7{M{&&*H@a3g&P53HY<< z1Q0E2{Fxt~Qa-DKE{*0lsRwsmx$$cHXHE+JzR*-mG}q^IBfWX7qPrG{>hg27<#jpx zLjnW6JSP?xRsX*~{}=Mz)6LXU-hcf*2>LNS&+m*szboBarKCb@E%2Eh?t2g4`PYa4 z^k2UIcW-@a%shzlnGozOw3a@Rkw4$V2V+PpjPDO;9_mW?I*LF4?A~Yp?zJy|cK0ih zK;QrD{u`g({>i5|e)8U>oBuv&R+Kq{Idg;M0*k4KCkK^#1Xej};T(u@M5Vw|QT8hS zP~$SW+S$9(6$9s~6&?iM8k4K+Mdu8-sBxKCBkA^7vYC%qPmBpf=X_*bP|3Jy`Qw5P zdiiZ0KVjn-r&ueCSqAJt4P!LHp2*_xldyF+I888&@v|5kU^8L5?PNTSBWz}w$`0X9 z3ZI%H9mSv3(zM>RY)Y$Cy{eJ<^?jj`lp<7|1)|H0_<7EO-Zo=h47T=`R@P$;?s3+W zvYck;dxuo`POBJ;QHFf?S|r~LUlpv{lJWyt~i^XK=z zdjFk=KmW&1gg+yAR{U8@!K{7!a;R5}@2Vc?{nn2@7XCbG4s)Iqe`dxXjFB!9FXwi_(JBCjfI<3h zs!yj1MiQtcXQ9u?milIFU_5W~;QU$g%WKiKFa9Ui?= z`g-(S=)*Q|e)iJA^s5!XXG#AgS~YZQnr+36V+Fmn2QC(5H}75#d}epmHC7~_kHo;9 zGBu*t!j8j)Kda6uP1lb&grz|2-5zdz9(-)u1Tyb&x zhTgo*uT~wpTy=<~Gm>HOsA#uT&=b+irUkIG&Yz(oNV}Ez*$AJHmv$a66DR?KZY(2^ zKqFA>ZImqVT}4|i>{#(4rTFw5p{mHK+Mq|_f4{Y8z@9g^7XE%lnb^LzBSbc;v4q8v;H*#Im9lvqo zk#C@b{{1d zvF+CLg}u)gq0~h$iX{=Ca)j7f-;CQ4cOLbTdn|VwZd_s$jir2J9!XsQZg;{u{_tqa~ zSdcF$Y0L0Ig4k;}Sej0|8*7FSjd|Cq_gy%U`azLu-dxPv5GK~J2I}*1hGVUQo<}%Jax3;Hz zH@kB#aegKXp(fGPXYPZ)RLDJFc(@3pNuGF_J znzcDBmz4%PA-ppooclKP8@4PYyf64TRLGl#W{EK9qjQ)_c~ENnnW1@zqWC{=UfEl+ zO_w@Y?pH~@9(+?(*2yy;jV+_U zzV;OqA2z;Q_Eqw6sCs>s+MwT3$Ig18-v;_e5VVv>$)6cP;8%JfH5SXMGdnhP9of@` zGNG}EVHyJRtl%?1_{sRQ0?VLget05vrckf>r)dQpK~pepsmY{u{><5p`sc=?_PTt0 z_`4fQFV$DPR95)hruA-ic2Qw5_g?!c$?oCL__OIzxeT8I$3|>{Q2#B0-xW$^YABk9*Wt>y|3=Q`P*0T zJviI^x~<(fTrMnJ44$iPXB_cj3buEHt#7@Zc!Ab9;WYsfCB$YatMR@r%D5MAYfY8Tb?^lFdb^06}ty@C&T1#BHZIev`WQahy1<}hbvufaTV z3$U}9v%z7kVaz1M_$dbOVDkWU&f=}%fE$L;6;0e5Ee4Yo#bCuL52y-oThJ{I6G(ZjEeDr)o$3I`X6=hX|nOD zw<4x!tw&1=pAiF9XVC|m_(D&CMIW&R&d|b=rcmS3GLyYl{ILQ4{^0!*kD#K7!3Vu3 zr+B!<+8ZW`KAZ~}XX!M<&ToRgaObMIo7ht$+N1~fVcHeuFbCpP$14neh8 zExAuS;yI&oyzf>wgNMP*)3xJbH~QxX|N8Kg_aEt>kwDAnuql6j|Es6^=f~fazAcpQ z$De8KKOlbwaWf$P*6SbF)wFp}n1zw~VqedORSWS|AUC??&`FFG1ySl^963nXOiDTMH64MA(fSW|cKzO6(iN{~a(h^~`#-%NBntWw*c z1Xc)9@nmBk;g5cn`${!e_1J_O?#%MEieBaTByzRjj0z# zof=6n?UyC28@EZ+?=8=*>NuDRsJT^l_!eo2aMjQzvjcX9!p^1$+9<};D3D$+l}FJz zYk3BnAQI9W0!JW|yHTIlUAD9BKne*NF<3aA5Ydt(7o+$y2%3lJrUe}@n^x*&eXT0|0r_)t zV(6(2A%L$JneV?h@lI3j^`rUB2fuZ!psVCLlCQnEPSm6=K=KW9n&Ss?-r(Yqvzp@K z5thFZ?V29v8#f-|1|!7I`eq|MtiIVd0_T1kj21NywY_e{(Xa5b#-9aHubu;ZKDBz@ zOY1_p?*aE-Z907Od7SVI+DWc=T)ZPdB|2ChVL=&j==>Q3jcW&YFbtw!Jyv|P_Rx*; zT~`jLaz=6;zOr!v4ND8~Ehq>W*YwYrJnQgzDE_P)MC-a}RTySDjQE*V!}DiU;`l#b z0QqhTV-^4s+M9GT zeZ>#g9@-&3%e2?(b$mz_$9 zKA99QzR(FWS>s|t7^w;IXT|~JRD9&AwB?r$W!}U#3e>Mn62s4@$|xkNT{v@hQY3LT zk+tE3%*HZ-&$`uyDyXH73Z-D8Z62!J?>Q^ejqyytL18J)Y9_uKy1jr+L(_~ z`K|gxuU787ynEB7%`2eR?w^*iLY(5LcO8CT~+|F#>_L2e(49oKZ=p z89r{`x2fmI_M4h>KK|!-j_kgEIIS&X2}&%Sf1*y4#5Z4;zhC%YmClEgia8`eh+T;jD zo8_izGDxHZ&uU9GR76?vXO{41Y}N=ai6O1d8f=kD&sUZ-9@-N+EntF&=aI6yfBEMR z9=!iKL9+Yze)-vNex;jl=$)zG0e@EdYWTAhwBw_HhCjdekPg>B{nsyl_SUc7eqH9A z3V&AS&ze=TGT#vW^B=kR8HEzxLiEq~zkol#{n}RopS5`7?!(va{Pxb>2le&M_$*r) z%xotZd^4R$9W|-J&a26qrFXppbFuxaUB&Jg3XO3D4iYLyRlQ`Y@~gE6GWb^60Uv~& zR=U6$W>r$;p(-Bka90?|>`&Zjdsg#&nX@}2qK&5*?#W)OFr|$FeNgM0A)Y&>f z$TPBM7Yny0Zr$+BCCag!Sx5+u01*iLJfEqYyN0KQG)qgb1~p9b!9Umff^q zyQx!cynSrECRn?3A9k~_aWpr#H#3OQ5KtQD4p)QCc!Ptl!F7g(XPEW)I9s3fPQEEl z0nfPv?H?1I=P{$$V@}1`S=D3l){t9P)fk=>x+Oj%Zru080KdwajD+I6R5b<>^|S-y zt^5pjPBsm7$4CVH;QxO8vBsZyG0>(a8D}SCsI2Gq&5`2mZ`!SZ#Id zM6a2Qgv3tqs9(JZ{@jLF26`Km%n7m0Ns^@dbk_1$wmyq9lj;j3qT#6Q2b4ymDXi-~fUL_(hPL9Qt62Fo2DT~{-t?ez`@@nltL|=5n zd6SoXE)9|m3TSYx`oQI!jOHz?NJWIjC5JM?WD^?`YKHGStG3dYrX6ba-=r@=xExAt zsmY|Z|DZGyD#f-T!P>c@J3m|aKvQ1t(Y(&aJW z2?b5^jh$c-A>zhk#gOgZy4;@PZI^Z@oJ?KvazfPklo)=NTs+wZ6?qo;tQk{t+2Z`1 zDh}0pQ<&Gd8anaLI3&6hJ`I#SKrZoiu{?}JW+DBYVY|S8{pDsH!c(#kPRV&@@I8q zwbUAw)aVVZV+WLOjS^p>&(8THxk^r7r z8~Vbk5dQFSynn4J=cZ^c^Di~!bAJ$M{6zX^HB-ZsKN}G=rn?Q|Fn{k@A*xP>HvS43 z@P@FH>qBXI_3bDa(+jSfXUdMPFis*a>AFq_}yi}0=V)k-U4Zf5daV7~v z49N*7NeMTJBS&*W^y$Rd=B?|mmh5K7o})5YfQnK9tJa31*2Y4f2#mJ^TDh=SA>l{% zT*=SwI+W72FTQol3XXX$X(2uv;;|3ePK<;(pGuD4t6@oTUdD5UHj68=I7kTKee@!s zO?%;zNHvRCS|yxS+4^`uKqigRHv((=OdO^x4@d3E%kGLlx1}zDKlhYu!BM$4KeKJi zvkcA4;|6k@5vG%8p~2c@B5gjA455;|uO&SefDi3wO#ep7Hr@ex8uPL2?mS+sg3%V9 zvv-b4-UkvxG-oX1MT?xp5M~aD*jSNRBY)N?w9aN(tJKIaVO56riiy_N<)m!rF5kiL z;m(QDJB@jFtM^^nwf^GfC2g6JI5S__9LoVYMGxj18ByJvqpxHyZii0qTyv{rE58~3 zv#$R+Qx9^l9Lv4^7e#lQ4qnYoZQr``a^{k&nQ_;$784p<78NuH?C1+QxEO8-rtZ}O zuW6=$4Gcxmhg#}yGQ$@Xe>TO%gO+*K)a(0UXZ@qTLBGO4{;X>HZT9HnX!OtWvZr2& z$q$mT_7Q?+Jca{8<6*en)%kw6{^Q?&^3yjT{Pf-@C~$ss=Zimi{*3MOTVx)* z`|yoE1pVfnukYP@uqCY&4V<-&!6DEvZJ!(Z+evkfUiFTX@c9HjYqRL^Al7jnl5F&Z)9w5wT8?ovv$V1?n0pv( zgALuka~lam0^s9gTKwh5SzeoJ87#} ztJx$qt9EwE7hI;J1-npQd9|A;5HOa9gF_~EPMvluktP2|_$8eB5jai)d2yFb*8+gVaw8-$4ruFq<}xyRJC}G z3r36|entQrA*D{u&XFeGp`(o;{GkX)-OP{+@cko_Q-tCgDXOm(`na3M4 zdQ_+&-6DdXmnnay9|wHKql4}t9YdKF%P#cJlq0le>8zn+>ZRvMZ-V|EoR&(RKlizL zJf^9Z4K#55eIw7R!=gH{8q^ifWCD*wmNXYsA8t=_^UFyn%$J_uvgUIBW<+R6)G&cW z+DETkI_B6ZBU-CF)R{-Ry;bLv$Pgq+bL3lVGAB-rd#M60Q+n#4=}UqGJuJ)BLBlRk3kPM`$+RwfH~94)wfq6m7R$n!VC zXMi)?vPx+`6;1YRgwHyErjMriWU8hxh0n<6bS*RmQx>h%&ZbM#ElulHd7#eOwC3B8 zXPrL}L!Q+tUHm+9{%j(i{KNBSQ$jmh{(L$iu$taOP3%!WR)1y=E>x-Y>10_k%T|SV`O{-+8Mk7o(M{CyKkC*U}5ZEtN|= z^Cm_UYO)5SUF-#U)`Qy@!eAu0%;~s$w17Dmr?#yJK{Lz&NjBxrkY~~(_T$frHiMLh z!p^4k1Ie>qGYo<@`4cw!Z^)u%g6<}JV0}Iynz&k@OG<+FqO9iqn@(4&cZ4=Q6GQiwFmx;`SYE|12;;xlAwXfVzL=I_|lCMWh4Gg zkG!gdWK~GllKEyZsvF0wq6-;uS9WiFwPZVjb3i?h{;S7Jx+M33JYl)HF<5Z5cpI4| zNk!L|wwMb;Gy%=#^-nK?kC6fD3JG(;ADi@)Spbb z+*ZZV$&vFlC4XL&vnVKVjH6R^RoyTC@2@}nm3Uu>1p2)%LC|zI2Owy@`$=JxovcR= z8~ToNG|n|JB-_p}9{#U?diWpz_M@M^@gd0v$?*Qh-9G*-7SL#hCHdf=hW=Sep!r6~ zyvZnp?Z*9kU%&C1SaAH!{fD=@{!iGfwIWKkHMlJ>n^ou)*x&{%om7jHv*ghew@(%5 z*~my$YwwNVxmLVAgBzS@HMoYv`=E>=67g2&gTXqw-NG_TF;EKo`IWmsO_vd zRzWkY{HIxZ`&oHSuyAuXcW^Ybu(i-K8bS%}4GbmPj5FBy8SFz1w$TQc<(8i7?7UK3 z{hsp(*gqjCe?nl9*R*oM(SbE%1M5BT!{-Syvt-iPg-&L6hLz8*;>F-Mq#=Iy;fLgC zc&9JVU>|%&mn&WzAB_HeV6^WK|HiiezVT=LH-38mqpBkp#(4%Q{@l1u_%oA3p?P#6 zn-dqG$y{}IZ*p7N&MWj&NPXUzhgRoQ^5Pb>9O+`yfm5{N&ql{%O;4gadh{4ok}7Z^sG9MhT<+nPvD#uXQ{)^z4?y;^vdTF~545K?2Q=OM+&cIG z-@PX#_L`=LQ9WXXNmX}v82+p@%%=QVC(o*&yF)7pv~fZ!29?P&!C6ubrY}94x#H6P z)b5h)x9ZV8;ki-J(U`}jUPh*MtQ4d`fOM3$Q2(f=x|=S+4)A9J{*1SCZ+$87nZPp; z{wy4cb~s)n@~WDBow=DP!%>%^5@*;#I(lN}8G*GX(yvGGIW>YG4g`gqQrq?r) zvMILJ%L>w}kNpm!Z}WXCaGj=?WXhSptMaL}vx(DUVKJgm{2B2xKHfiA6@rh%i*K^ z)i1+xwWOA!$6hbk`2zfTtz;)8OsVq7%Q|fyv@jHcR)59dWqdXic|Ma6N}NlO5vA6I z1rqV0Eg!$AM!;>z+-m`x6M{&D5O1R5me^zatKNDPCNZ zFKt|SVf_LUyfTi{ekiT8Vi$^Bru?hBI!m0K32;5R2>{5~5v5n|YCD{A=DF2pQsd6x zj}(s;MilzziwThz@R8>18OvLDZD8h9XX*BvO4T|X*EgD9ke`XgwWM9q8f@|Zc3YO&5E!ivK&-aez-m2W$ zzIy{wRZc3#%Nl*yAD$5Z%AjVm7moj28Sh$?M{OX=f*DH22>xUZ}twfSd zWlMz?`ud4dth}-5z$vA5^D~0DF=|ea?K`rZ0=TUoUy~V&4>ML6z-K75;=SYtWEIka zjxEo29ZUy7Gpy5nBER?8!7Jt2m-nu@oEto*mXC^oxP#W&7LZR}W z)EMHbmTyAYujxyC*i_k+0DmXtei(V+G1Ue`)%V+-k3;e2q3TBgpS9U@x{(O74d%+7 z-LgjVQ#a=0<<1C>5B&wuvg-@N_CM?bmu>5uMy{^o0a z{u@UAtmoYM<4!&Ze0~%pReb%k`>%g??+un;{OI-1e)h%}Z6|*=)+xvwI|)a_gq1Ec z%6z8OdT7(A#c+cHu++E4g@k%O^-d~CJ~gez0~gR4MPq{xxliBeId-+JOO&Nmuw=8s z8yVtkB?32VH-qCObB_S4$#d+dE^r7AbDR-j&-C!wh;ktwOJL4+5-V&)$Gc3dBtn+i z&7o$geaKS#xr^;W2vP7_O6V#+u-NciXsERVDP>=c&>PvywvRvC&V|)HYa71ODr|+t z!WHI=mRl^8uvxU!ei1pp_#%9xxsHKBcHZ8W9;EkT;; z+&28|y=FTEpizvnnz`6w4sd>@^`aH%v8~1S8DkJEprt*n=Y5+{E!Ni>^YsQCSfj6c zg2GT&INC!!J_#29E0aLP7AX4 z7uOEU@m^-`IQDxQTwE<2tnlmL_UC9Y8)LAVWN-+!au2f~yVPOQ23Oy#G1K;V2IY9n zDD#|I?GaSzJfFMYl8ILKW^?Aw{rS)TC$<|TAN=@(hrfRJ>klPOu!M-8fzMC*^B^xa z`Uv}z7rs~gnfDVU&_B`m^H`5*_&>)@9eZ?L80k)0G8SWZ04Tn=W$oph?5@g#m&A8Y z1WWXfdW*K5PF+r__x7|{g6;;+gaoz{$dy&HZ@O&K^yB;>g@eR*@{v*$Bc zok@S@T;{3^*=t(2ti}4cC3Cq*fKsEIlZ7Ha;?LUApwOy20BZjJ^Jh~wPTzsPstUTp z;9LweP%@uSTH2ESY}by&D~GrA)aG7pL=}eZ22;xm0I-nfUPxN?e$t(ve{S8`w52GJ zX#r&9Of*)KE!tM~vgws8IhKOb1DB8SXYFG8@n=5jdx^?OlNNJu{x6u6jqgYEo&;un zUaQUNAwg0@ekY+#5N7K1#rguEjnW?qh(_3^jGg-`)hc}{vbSRrlJ*OG=f*OEIh&*! zq=wy@Zj7ex3c|cYNf)=SVr-%-Elyc_B3EN91M;jHZh#|%P7qoqN9~uU{c=>ZjC`r+ zwCU1xU(mL#f=Nkt)722F_wGLHB7?!t9c$p zeGXRPBv3oKVSZcE0`$-QEI3T{&+61qz@PhJTM({JYZcBl{elBGHbuUFz_PkX(+kkQ z#dlax{CR{3TF$$6E^&H&=wGj%`}{K@Co`5I)0HffCkhciGd9=OQ~)bh{?AvN#JYLV zFlElBWu9Mz;?D{}!=D8~AD4Wu+`a^{lKSmLNmotIxdUl0Bt&91{>r-f=&=z73wB;N zPx0qLfip;X(E5IrgOX>xa!>?q%AYBNpmqK%2zukZmiW-N1aUqGLAQ|yFn$pSWFFJW z_(dY0 zRi+RP`O-KdT^0s~jRw$O{udhavGQOW6yxLtAdBv~d@1#L>C0~CW&XG!_ipXsn>9Jts}I~P-*dfS%hmlU?2g&U%gIsaQlgqM++gq&<#XR~ zB+oT@Zt9UrM%}(g^AP-52hMsyJr^)`W?vpUxPow48C6fw_;bj zD*#|6dv691SdXYKQUA)4?RLt&{235^IW-&v4M_%&wq>vE z%FF6$Jly@4*nQ+&YdUbVWb@S>tFV~nVlHOKwPZ$K&I-Sp9dSJ?>NdqHeZzjCh z=-7E+;Tt*dzzs%N^NpOj-*E<#XH_#4XCA74wEUTNs5qK;Aadq(PbcU6+~R-v*I$YGhUWQ<8d>>2)4Ti-;nQQ?tKT7iHp1t3zkdH+ z@*Y0?-~Z#`-@X0mTlYVF`_0dPeDCu&Z-0&$*yz9Ur^ugwg6%UP8u9ZRpWb`(V=X>? zgJk#jfAxc7z1F0If}DC9{8GmU9r2k^;T%xyG9B-TYNr5_4_3Qi0WFf<8aEWY{v@9& zofMoqdD?cbi5r}pBMde{1`98N58@hXX0S828Dr)$*LeW1zqp6^mSS-LEgm1xBA%rG9;v(DG^KE9# zwwfAfF?o`~!`rxw+CDx8HmX47YcA;i= ztPL<&Of(qWwOwosX67iz9lgxQ2iW*x)5^i|bmcl>&a3PeErS;s1R0@qm}^MtftKdfF*#~--VHyB}I;1LF1`A81+^f<$}($n_&ezp()FWQBvyQ17qQ8KGA z3Y!&zwhrZ{!Mu_s4CL8!YYmaG)eJfqYqOD=6a-^x%IKal+q2a4)kv&EF_(_Anipvm z5-CJ_UYPZ4Vv+5fFuRa2yE*f1X3nt)3byc{YB`zQtdnfUjx39Z;AiXDlOLzYED|y=p4sx?>H~y2|IhhxCtv{Ew{48!B8byTS^8OFX zmiS}l&-5KYrqch_Qr=4sB7GU`y>&-IZ{g0{^#y3jaC-)Q07Kxq_*wwdP?&e*Wnb8~ z{$$Gk&)$20S9P8F-m)nYVB?b5j^o&I;%-w!6%t5DqS!R`UJxL9N4-%D>IG*en-YcH+6 z&)(}C?Y-7-{n!8X5$6qDJMbq7o6#EK!KsY(znqidC%X)d4Tfx!p}u9H$2C|7-NKyB zNnM_tStW$f2-+)SeJkP@)ozJw*}kqrN#HE}ff2E~S{M$jMh3{5+bHJDE;rIrvfW_L zHW?7KXu1@C20!j!RR1U4Eh#GawY>{j?} z(LXb7!JyAfj|Y;sC(P!f?Eh-doXsU*XHAlCk3S<>929&8N1Hh_c>^OGac55 z?T@y52N87trz%}Cfn?Ma(2|1O4+puC!7D>ji1v_|Ckf9JC^Y<; z+r$O>K*+2&BYmnihGDveO9m6rL?xh!NY%MaKBmK?5JHPle_jfKVkIK&&h?F(A_xO| zAj}Kwtoe3%s0Wn$aOjM(aFJCLwUEGqqQ{P3h}%YKj1N>CKW9P5YSE335(wJmQH=Om zjFd4@3S)W8oTjxQr}k_;nulda22l}@Y^HvRs0myT1l2X+Gf3vwrGc7_jQOuR&kG%;v6}Ss5EvWbRTt@vAh|s~ zp7@wY^ENdmM^!AH(-7y&>xo!igG26@QwfRRoLC~n6G2%d(FJ>1>G1c)4%b?%*S7`ra?4Tn&IEjw^2i(T#LLvZ? z6aa@F^H;zxYUHC!y^nyPqrEDZ&#z96ZYfS^K>}TvcqTvbOyT3^d-el4S+AmP~F#MZ2()oT_3 z;TxlTX!-UqPu6XTRvcV!b^79?bvMQa^WJjT5eL5Ifi@Lxc^;bzHisL#jySW{A=qyR z%b%I=psPl6iF$!`bJ6n};scvDL>}L{^;m97JJUe9#A9W8LMfBQOk)t@XQQ%(Fz2LK z?@BtHz6t)^n4Lz_`e(Q_6{xIWwfH}i5jk{DdXqJgug%|nV0Y%$*a*bWQzuS3ed^sS zSFR&?wi`d1X|vAX{*X$9QVdb8>vs994=>#yeZWUw`TX)_71BuR^uV8g_uHQT{dd=Y z@$Tp1ym9(dz%0QB&z`s;2zrpw2G5OQCYAG!NGPmX-zIhUu#E9^XD z^aRh*qRs{93iMFK13zc)5pJ`GlcwWe3d>azKBe7NifCcKE|VauUN~L2OhJYR1Htv8 ze-L!bzxKl?g}MxPdwIAU8O~$yXRZX1wiXI%Gite7;4`+XBitl$FD!(2nIcy^%9Wd) z?)<##$Y-7(`NZQR9(iEc*pb7Ohm)k7luDQ*?HV_=Lzo4lfXW(ZfNsdmC!V@tR9skw*zwq>0{zb5~|;q z{u#x%Su}3NR(&*PKkd^`+xGdPLxn>vFw_EHcMDiF%=!V<*Z;ot0z@Fq^8v$WwvyN- zspptws~*MX5~~@J9H>%X_VSo@=)_#%=$E`kKRadmee{-tRr};FHfh{LBlFj~oB={r8P|VLxJ?9_=*-#-6oR#w@=_doTZ(_M?6c{F#yv_lcz*gw{7i|F39;aE-* zu8;ITCDb*G_3~t}*_N_;fB0NzDsILM@x;18Ay66Uh0c-$G)6=n;q_*i=i&H8ZAr_H zzq;{cb|SK+?ma0T*^-cO9LY{1?0Ywn-*>HJwJ#rv^ct}=PQN%#G=_N*q>ocE7NEmV zXI}T-Eh9n2rR{t8x@559g2A50(fPST^xoiNg4DN1dt*Gpu$Le^oF63^mX%d2{hO1P zckbHKm6O~mDzfyd0@*T-3vYBz)*jGBk?nHFXc%{k?kqa?nPF*GKl+oAuh zWuT8}IaD%OV_FG%d( zo7SxPv!1=u{JAg#$L0ZIXQP_IpFz-?KQphYpKR4C1BKRnTV}-al5qbZ+8qdbzu#2& zGu{;N=Zb)-nm=p!thc~td;Sb()?nEH&Ndk{b~fi7A!zusAZQbRM*Iwa20n}6pI>|6 zWK_^%#DNP(I4h6b$`xT2)A*nn)q!p}Jd^5zL?BI49zH^_%M{1PxC8!NL(QNWXqXR$ z%))=WJ}H)&K>`utxx{QKQO|1gGwXA+EO;tE105!v1Ud#saW8pwQ(M}KiZ%Xa1T4lB zI%Ed?nJdA=neE~5nNVl~3myt}FAa6aYJ)@}vS$*pBqW@KIWgM^?^XP{D$J)gKA>yI zCO!!JCKmql4#KAbsc<*;$hliucdu_wi>u!fTE1cdLH$r-SE!H^yx{P8K!__8R4pAs zy<8LJf%g1#Aw9Ny`8>qK27dY^}uW_6rb#l|I7=`n3Z ziI8L_zEADmaw07rpXaJLpNbfd`em~kmjcP%!PBXcZ%z` z?j5^n!?yqU)rAi}u+ced&ir-qXIaB52wEJcFMkFAzjEb^ix`-T!RiJ?2-?C! z6zCB4D@lMe>N_RCo8~#vVp7@<2)*T>G>z%A8rT{5Od`&pR8ab7FUa|50W9K-YQ;MS z!0{bE!*{rc?+7<;M{Y_TrR9YfVt6=@o9z7jOU}=r0RO)8_n&Zi3=@*?4SRrujp}!Y z-)~979{9nC?>s&Hd(RGgV%*)&OuGAp8N(*d96kjy?=^fXYwEp+8=)9wK|M*Yuh+z0 zb0H8kiM(-<=8O%0?(_C_VL$D2%cIPnIFui1fuR=ox?4ct^UcZT6ZMlyn6swM=Isc1 zqVkaO9HG+4X_8^vo7DW2l1a`@-~N?l@9 z)6O-lX9tQh(5shj>JGMuAKG%0;m-%c=T=Afz@Gtk4ATUMN=zS5#Lpyp?;u1RJPs^d zSiLQ#*qfje#7G$*NXNqB6t~da<<)@2^sW7!8KM||Ry2Kb+r3(cO^OR7Aia#@Q zk+Hy^34g8*^$;Kr%nT)*6ZjPQv3M6(5h*EJ#+5B8%R6^(mH177T(E5kTC&7CEKTxL zyYRS3Th*{GtRm(W%(1aPW^FG67KUl!9UbLCGLM(-N5_4X=wY3SKLfEzh@c?P>RXe6 zk}_EKs*Ug|i}tQuyQn247LgUwvLl3u%1tFCjePaiqywhIXUy=~hCdr1+Q=A08XXr1 zTAZ#6SqPujmX`!GtlNfYDyTeW9(r#Ptr12l+?{0jY?#!}nmpU`XNhikEB?&)!Yv!{ z86HB3PG; z!QQ!1rG_9klIG7EJ|7C5Mv^5MAn0IsQeBA0;lLROLp={Idj(IVw!E$FSfCW9V!lD+ zv=nR?0c2h#?ny$fa?_e})5P1kC=FNV_Fd~65@O2Y7vPCOTtXOlZI~O+aQ&>~(PunG zc^dOlvpft#J$QjK0c|8~G+3>p`Ey0c?87k&nvz$-pIJepW(q{C-ddd1UYtST0BuCv zmA$DoV>zJ=>(>O-Enh${r6OnPAGb z%UX~KIUC{s#6Q8rpX*{~>ZDn;z-Q&ifn$bpZ-x~U$JvX> zs?gmd>G8yRKCxF;2DO!BYW~bb4AU{kN>U_8SVp<#V$l0P;h?LkOBrC$l^!D{FoHBV)%r^W+cP+m3(o zQP1TI*L#)8%GXg1h3+VS)=PA?{+UQdR{o6h^W{sQYX1EG@4vWkq38Gi)$=d^r|0Ky ze+GGe`_yL|@Sauv&*#s4Vbwnm)bsgk)h*va{qxUGe)+Q#J@20AdHbY<9VGtX=`%Ml zf`04d|9$+iN#dIEkkgn2PA}|u_}QFqJ+{;3`+M$rCi{Vx_B=Wv<9jczd-RFGv16y) zHS7s7h#2nTbkFeN#G*p1`|OA(Cpy14ZPWzJka5_UJsNKfi&ujRcO}No+R|AWYlsk9 z<7KV2vx=WBVeddFR@4d66;e&|89tqA7RDOPX8)-y8p)ij^6FQ=p*{>%l7`?NKQ z-WV?tXVl1;LVKW^wn(Pc@^)6ZYujoco)4Pz8h*~25?h~CqIM?Xm?0VE5p8~S@c3odB6!wX zXe*$mGVB^pB#fZN3woq0$-vGQ7Hyr6lU*aPK1DsKv76=z)|<=FJ-q?}%h6hLf+b@6no8Mf0|996}ngo9)5aGva?wILgD}U}8^4~DiNbTVC2A?yCaa$F(~vzASfn9uyC@}uKc}{* zt~nSn4@+l-E`?_bf|k(pnDmNihOCwi_aeMe`KE~aof{d*w__KXr&jD1ZfEr_Cln2p zVC@VPuta;udZP8!jrHq;YGUVspc&mDp25%qS3nsHD31scT1!lDNqQjAr^w_E7CIVV zI4T!D%-T{!%L<2b3k?yz41sH+Uuj$$+L^u@J-I|1EV2*}iMUso!k8VUadTo^)ruum zQFCj;iB2fDubNi^7gj~is)&+w8~j;XL${bB&ze6AdFCs_zB|&JZ>j=39_|bNt=SS* zpSi3vXA4%7GB1#q(!m@-K~_s%CSw!f4C*Um)PsPTq^YvOmJQkr79bhBMh5s?UyzL1 zbyHyqo(bsIFtlvk8ig@9aw&B0b)ho_6mWU6?9{T-S+9521m58Ay-lG*3OeA=25q*_ zz(9;bgNF<}V*uoVXAIPAKEx;_V`k1~+6-1Q?;3dnEE^dOlZ{;?qstAXY{Q(*yGEUU zGB()O*foIj05gC%8}fF`T`;on=b*_|AyZ(0`va#z2)lN!KU$d9S)2i@;n!QUHB_{h z!u>4a1-TxBKO0wTpD`}m%#HiW+t6Ku#M+eK_O5Zl0cLLdgKQ2of7~C9KV!ZDe?GM6 zr9**};LpX2r$Di~^0pBo4Q|Y%(s+!JS78Ld5`WeYDEPAoo{KU;(CV=!TS3qm)EB0m z$lXTlyw`)=kwD`LB7}J{_T%!y)9_jIXF?P9!=LTp^DTemMgHB5HuiKOQ6v|oA|SUVhMp7gdMayZ*x@8 zr9m?=(;#qRbJi**cd&p!b=<71li*YWpv1jD3+-iXPO4Zl<)`o}KT^ozrp>Jx@t748 z{SYsX(jYPV;Ny72p@n8*kyICEaU9aqe-`C)=q!w*nXyH^41ea~FH?kJo|VBEYs{(H z6vbPK@2<8e3j{5$Dar$?PNMat;uC%hBjUoO?wl>hcdhSATh_ELs4`|Qu_`zlzSihS zu}voN9;u3$fe;!m4xMhvpLumccfqjmXOec1fIo|oa$4N6lH?Z zvowE3axCI!RIJe+z-L1RO-9Tyto#`StrC^R)~q_lw`q+(?$#%=x120V!)F`7-c-zg zK`Om6Zj&gz_$?pZv9@Vb$l>TYEZj*7;57b@IJHVf#kRJ$tmPjj#Ki7vL{CK52)~_jPRSOFe^V2Ky zBmsx%o(&v38#Oh5uE|a{m^1&^I`Q94GHMENrVr0&DgLYxw60mPCvE@kv?a6M?{{$t z4~zPbfB!uu&n&I|WANw80BvQ#Vd2j`TK|0M;wQ>~Mh@aul?^x5h<2|QOe)-m!Pdi%wapZ_c#RK9yPLD=9KcDq2*X+lh z-~P~xJ0E{0`Fl^qf9w8NoJYLmA_*nkB@lZ1((OC-1DsaJ>zjdM&}Gt zCb-qy(c?kQ0!FZO9zI$0x>y!FPXc97u3eoWw2}nsqSv)zXOq4TYTcWZ6R9%35JcP$ z1vRjB6s=kB_Q)#l``qATQG+E(}n9ya) zY;^`PEdj_YCa)FI^G8e;M~+?!)VC12pWD}Ma?1*RHl2w+_4m0$)rMMNs0Hp|3n(Bg z&lw~2$)7ca)(=~~bV6D8h$DwJiM<9FCR^()8yT4Me3dNx+4c#e96U6#7B#iFBS+diIc~x3<>DVw!0+wyZJXl|dZC7r*`Nw?{rWch>yh{`%tOE1xTqjh?Gk{`~Q! zYac4tEaks3#Gmhs?AZX<_Wb$sg`R)=m+OBb{qwccXFfgq_D7jnhaMXH)L5sxmb~=L zPnL(YXRK+>+Xg3OI9ZdMTA7_%otxQ|yIs1YdFib=DIIBR4@J&rSRum)LIufK(vu-1 zy?SDo15Oz~R!93(ulB3YSc{P+3MGc~I7ZgwWq_Tf!IP~{26cxT13H%`5_4XaPTZbq?N}m=-3w5mAUq4cH)tOG>igj z^OGy{WsCZk;T{eojfqRk;}#x{@U4%UBjh<;Jha);!kRyq-^`yiQoiL@kAQSFO`i3Z z5j_Jy8kwN#r9_NkIqk}TrmZn;Ih&jFwzU={wiTpci-BHUQhsJzUIs}hbiVj+fM}2l zlKSD#y|75FmuDCFT$i83_*6#FMakHT3ZPgU3?D#xEpm5}i>n|<*k!XgI>w^9N6|1z$Tbo#yV$*W3?wHvVLTZTsK7jibyQcp&-yFTnn<139OzVs=^ylv1eP_P2dGFhp~vuuk}2Pk_ss&SN& z=W%2(ZFr`DXf>gxA6z`>TJuv*79}?)$GjQo{kq?j1O8L-->C4P!X14T{ye~+x>3!H zpl{;O7J0LT1m(HGlYv7@nR5xAf$PP-5VwQj9%agZgJ+9SWspo@Hx&DZuU3yktsa zZW3lVNNSJn+1#44tY(e>!KgVbRY2U!QRYqCXs~rEkr)aPa;^}L%BPR$5BHBs{Fh`RTaj%mdFJhRmqjiA+*V1={r#NaaI1s9D9 zdN$6|E!!eli`1=bE(ozIMl=PYWJ(_5qq<6tWsHZfuLn^lLFn~ZqYw0 z%B}r3!~#0XqcM60pwOTHU(9ww>#kVi0;AMD4X7e{ArDUYu2hG1qpN;WM&yfI{#%v3CZ4qfg4dNOQYvj$IPX( zQ5Vi)E9uVBK_cmp4Sk|u1M~Lz*MS!r=dsB+I)hQorh-v!lX1kKzbbjwT4(}sMhkyt zs$Hfe!aP|5P#yJhU3^gembiwD^>w?kWKW|!3)yk691a*fu^Sx+sQ z&!A~DYaIBOrzcOpU7NsD6M|iyonDl*@dpn*@cqZWTXDGN!>cz4YENkUt1w}Og#|=g zYz*(T{@IW~TLKsff93+vKVQ7~nG9p!?*T#o`@i=5KkxnF?5WSrp2S_*;+}Di5QL|J z(pvUxv;BI_4+rb8aeMV8{@|%E-#IA=`rYF_=a2Wib@Iz|XFmC>k~Sx&`<#Y3-TghM zm)3q~eCi|a+n=49@a*>^9(%y|ey3-gobGqR8XCd#_eMVWobz|5jDE&_%=4aO#(R-m z#(O)D*W`K5=ojXZT*iqi4_GlmBKkoaK)b?|S;{S;uPm_z$sq1k%01hyg4G&XTecdm zYAD?&0;SNv&PK+*riMTE<&Ijdxe)uk#>4GygNGfep9ky93ooC009 zm~}{yM2+G_o-HR7_29($&J*U-CN2}aM&jf=nMhuJ1N0R2xM>5v45*E=cxK&0~Q4%BtDXD44~C zxe1*aD{I$<5VHvmTpR7v6yt+;2foK*eXPtX8K%LCiOfhcZeO>_Ew?xEXBCT(aj_hQ z&qkCN0Ur-W`<5+VT)QcQJ7Br>a=Ob zK(>a$*~p-&Bgy$4m}%H>W=Ff4A!}}I@Z|n825qLAkvC`lRQ$Pr?5zK4z-Kaj@@J}< z`RzdR24ovxrYXR^+8@p~`A~@Kf#C56gT|Ewx+3zdUa<)MUUx}GYe{;0Nor^A=DLkR zs4j`W25<)aaxtO~Rf)X$Ud(y(H5<5ifEjzbYcA>MBvf+*Y0YQ&I`X&tTt^k|RQb*P zc|!S;@uiE$?f0ATy8q-7zsX0ouO!A9Qcw6ZPz%qZUjAH^`qlZfAZRr^X3V3pt3E>F z8!`b0Ztd8y`sc%b{A={>!eNy6^HXE3YIbgV9*#WQS z(ZpW~9e9ALoTYP`6QYjiZaGn$%IqXMXGkNj30@ZDnW_fh*B5IUxdf%(A24jm{AqsCZP&KiK^g*JJaD6 zOFDLMlnWp{pR#ho%3BANB&+}#zCPs*mD*OEhE>JUy{X5GlaA$XY)_A?UALqxW_DS) zdu5o=W_YrhIh*qae>TvunLjfzYUaV?!T9VjNg#UbaRh%z&#|D4a2paJ) zXM-?n_-xOgVZtEjh6u#r?n*T+;g~_t^&3M@HIB%$r`;d%|KY01t#fzjbuUzc;uiy0i!{6il{09WjZ=Dpk z4U5OJ3biBSAc?c{7s#J2x26!Z2%(REdG6Hp^JhQWusY{%te@|8y7!r3o{8fpZh8E< z$VVTUdGE0Aiq!_T&|`)>KR)W=m&QDWUxfR}myqnv9X&;o%Onku(f7VQ+I7z8m*$Qc zhiaE{1ztq|#uDsaZ)D{rYQ@XQ_HH827Ox2ve-NT;PMVg$E*v3N_=bUEQ6*FkYi3SR~@gdYW-x59C;L9rLl~yt&Rm^5$dB`GFj3u46vdoHy4Q zNZx#`IX{qN&2>1IXPx;BI&akJ1qsH%fng4UA4%b`5dxh5_!Jycr>2v`WiSD&oR%jQ{5hzh=bFM z-+R8R77=yxDVe3R_PKXB_Gw9*w&$y zlBBq_GUCW2oOjpuwY97KAhCiaqlHY;@n)D~z-I%%>Vbd|@2@jC8ecdnmvDYW5yE=} z+sx?sRqMlAvo>hsYZ;oM6U$3wXoeshy4#tX)Sa=K6|BgQLGHMYz?l_NmbJ-}l&dzM zg>VQIZ>I4!fvxtj0!81jpfBqgMqZqVx6d`kpvU}qz9NBDF9oY~P|&8WH0{Gj+Vi|!rioE??h$ess+ zo$cYXBmPXencog1-zSTM!Z|8$^7E+mn~w9q!LUjDg2x{U9$y(WkSBnS!914if||T4;<2NIGx7HAK!f z8O@gM3N3CPJm09mlbOT^@rm62bz%xDUA_V}*iWY8lCD5pp!No00i8nWcL^(2Mv4f8BhWs}rMYrz~aWYU{e!Y8D4Bz~;I*cz$1VJC$ zwZ468czxVF5f$TQ9px^)GDV@`%wXrvs9DfvfzPobewM~+lC1*1;<9vOrdpf%(@#xm2wQ-B+pU|~K0*!=Qp?K+^hyzKqcSVF3(+c>UV7Sq# zT!`s6@&jn1{qvKWb2fM7ZmwJ#P`PwIJsc(x#G;Kr)hZ~Y4bC-oG4~)DyGBO$i0rr0 z@9Hx-2y1AAmyO-t54zcy+9+zVuRZ_cy^r5L_X(W&?5Qu$p1$$cX~mrF`7`m~Eg-r-{qvuN|1;8V^hJ_R zUq=Z2-pT9loxFDb^r!EfyE4xwY8cKMcR4-$!q|y%Pk(38y(6E#%gM#*{t+&Z-F^QL zhd(mT`3F;7o^u~L4iGwL%yh3|uCs>=VK#7w?}$mh!%^RfG!AKQucxT!|i zgvySXJ|E}g;cl`F+@#+Vsh(Q3Z2)94f?G#T;&b7>e4IwaeNt%iQ9AF4%-EOrmgvxj zhWJ^*=a;oL2ksmrrlaWQHnplyj?%DN1uKLh%dWGI4>(P)I)@SqY2g+|S?oKwW&LrS zM@tH&9n@NQefun3*N~ZJ)FNk1o7GLpNi-X`Z1n}pR+A_TBQju7zZqM2Wu-&5<-P4Q z0DZNAxf~s3R2X1p=sf*5)KL5U_iP_|wy1e1%k#m?hmEI-Hs@iBpATCeFWMPHn`7vQ zm`&3e$eMC0^wzgL$%S~E@wMcY*ANGax%BYq$}4G_e6%<($r_NkBPJU5(fYTloQS5e zpkvyo@jo2?_;U|G{Wq_@ap~%3zrT3xcNeZ{sk89sE1xL@eT@ZEL;U%UL-Na)Z(O-d zk4Pny=a;@}Lsa=_u26mR7ZBAB0 zcBa5*wb&N^+|58T-Vgo^6>N(2Vx%LApeXztyjTQ!IMRm*hAms8yLWF!Ju4m590|-V zz766JDHf58^i?JeB&%J8QCw*LT(xQmhLfBG2M@-ZGM!G>sGh9?aC!L1BPMN)3%&zu$? z?51!ZlE8K?V7_^K6Pq=$XkA$k%?$nw!$*<3hq{%mo44IyNhBm*pKTx`#ub-7VZXKs%_BYw8$x4Ogzs~Wpz^lHwVA)A@P zne%2Y*Wl+?wqZ@Tf?wWz$M-apGDmYas+sa5VSbio;>Rk z8^UbtayZG@H8K)_peSAQZMGUg^PxwIQ@ZlE9$Xjn*O4fSJ%187{f(e$XtRG3FhwOY zleyG`ep84}D9K-95t7V5TAe2#py}6cDDcHG!~AQ9BpZnzr~Z=xoGr9jId7n9*2hv! zJ82y9p9%4HstdX2G}lRPMI6>Q$^a8 zL+m)LsV2g$HhgLelHky32yXGsD2?%HO<#(nxxF~4r7#Hu&DTWWQC_KhYb}LY+8&C) zzO^Ok)kP_!=GW4iiW0l_CZF1yczn;=wuG>n6)(#hkVwIVld#4XH25>GVCK_x62}Z9 zS@|=*79eQi`U!vLt-W-9eNuGyUfLn?=#NsH)0b8*pWhnm1Am6`LXx%jh2el9Lg=WO z3PH2A$f0|+$_fs*M0s$mM$qMvLft{okbmZ4&=sROM|>{!BPCf4Mc{XY`Y9mj=FMT) zWiYvHowt=65x3_kkB-QhZNyBBac^AeA&wmI@Tl1xk>2pS0N6-yV=C8Na-gV@sX>V~Fm(Y0|4>LPt57Gc<|me5&rNSdQWT|m;n+0oWu%l711 zmvEjwlMOC5cIjR8nH*K1oUWJs_Uq=)qPqy6sabtp=qzRdYBxt$ut*(gK2QjtN zz4Yen?JYT?f3{C%o(xR3*){O8hR>QmBZoGs85Jne(FVy-XjpJyruSDF2@kv6{pdsA zZfozlbosNZS9(79-4_=9vkngUwfJv{{#o;9i9BfNpD%uK@%Nv7bQM+A4Q>AXPyg`6 z`LkEvJu4&@{qvcV*Up^!T*Ca_#Gh>>(EagerI-FQsBreowX+IAzjNj@;PZQ@!~y%A z^B14~;WQ_wVWXT!KKkUh9vVMJe4g)idU*H)<466#&EZ`5Q9MOW6=RMw>0f|{k>EQyx%RY}5lxe$I)J_|Xt!Jm;AlGlse zX(ffAhxoIt3xPq{hB&R!6n$of+NaNEF$%wF?PEMA2g#qstJ#8})gxC=e(9~juGuy7 zY8GEu9_FlVu`p+)npRF7+N?vOrjBrbh3#-6s7{w@JM4)@i2uJ(XbAyeG2+k{%p;3n ztc0)q;eAi0Zp*rO<Y9~{;Lnv&-tcE6QX&bC znJxWrYqBuauR-=a@bQI%afjHC5N)t-*}{&bxTAZvwCBmfZq$Enofit7&pJ>E+NEXfa;L(1GTVyM;REeBUFRltWp70gUb%cR zznt>WnYAGvuzFcr9qmyY?E!o)kD5_o<|26i?w zhWSRH{u`Phf5Z8+hR=rn*-Vwq{Mo+TTtfaf__KE2_?q~$J+(8J0QW3+huc8Vl&Umne7I3ZIJt>N4l0ik z#I2LRD?SpX0TXq?$>f%)JkV7q-I#h?=0CxvkP=G*DGw&?U;I)<&?G1{NBv~U#OhTG z&X!>QlOWu zHU=ZBUd!zH zy>Xi)DG#t2nLB+T=T&{_L}JPriSI27z& z7VKUT>`_I+{5e!?HvroD@j@Q)^L{KiqGy+`UR;$J)5Hlef+)!#s%=q+Rxf!o#uu=EAbggHqC?zy{K^A7%%eVJdTr3u zhOp^PVbfc~r!|M;2QsxhbZS|gclr7y$4e60iV|f4f?t9X#&;HFfuP$_KI_o8II9rr zwj_t*IBJD1bcP_7KnF7vBhD#Im57V=< zn0efn7Tn6ZAuc|Kz#JY8p>CYNw;!c|YFoHhN4QsKxM#bHI)Q$me8ob3`tiM7y(!e&;z9gdh=wamXQW%cnqAbDyX zJ)e@S>f)@5oFsO;vJ={pmLa7kvLqc9A{cUa%4URF0103%UxWhD7<5=bw4%xasEtN5 z`ZG9DJ7CV{a(!C!EVd$*YnX~o`n1s|BdvO zblaGDp@pk*5ee|^(^211zb6wuEGB6L5Zsg6yoVmO_~v2JOy66tJ=BtEq0qSMiLu^I zIJ*B`4Wb(hw<}VeR-cnfufDEe$KkwP@d1nO8#(OxXP&!!^)rAl;P>+Hu77g1$7K6_ zX9iF=4@kBD#x*H~KldifXI;9`LwKFv{%6nM{^AekPG9-i+lJ4^KnGTT9y(`0y7-6K zryJ)^eu2}-xw9X=b>@S2Pu(CK;m^-q?`Ziyqep-DE~mRk-Zkty_ul{beGfh1^6hah zPrBbb&QnL<({NP@Up0zR%-LQd+e<#d3)E3KR8_OGTm^8%m_ljf?9U)2`Y2DPH>TQZNNzMyZyjr8)Ad*nxBkh#az7>gpGW`Ie(UIj_BH!289L8U`EnyMzHeN*ED0!m^BaF?_bau4p?{{o#3D89IDq`W`u8vX=X;;L`xgB9 zI`&-fX9KbdN`s!5JcQbCkB_KbaF$2>-`iRgts2X?23Ojq?wHF*X; z8~sv7I=ButZ{Jk5HvIK4-#0_Nq0JRhUfRx4oc$ubt0H|XR)8GabJLp@zUG8< zeev`lA&fy)iwCl%m-r#;?r}3zHZi(+Gi>Gtbr{rBGKO54)=l*BMg(#hmN!uDRdXct4=bTYE-BW_dOUfuV!6%C!QPG zNn-U}kWp2XSy7k)d?sEJ18~+(c4w{a*b-5{>=o<~IjSB7FKS+6K%|MQ#>>``k;rn8 zK(njHr>v{(b)`@T@>h`+g?cuSl&)Btb%^FUO!PC&Q9cY_O2fR%;uh9yjDU?JMMmbt zw~661Bthe44VHVUa-l4&)=A(qGGj=2(L> zn=_7h^1#b)scjxe1w-m=@m$5MHN?#*Bx5eO<}C_mL(*&(JR61fVA-a`ygP90Y-X(k z$phAUQy(_V7Com%YHaP#X=b+e`9mR-LBt520d#eNQ)&YygXsWw`-7+LhYKZ#A1~Uf z!_~18pNSrnbm(aO;^RetLM|Z9R_8y9v^LoIv zzgdD1dMb__`vT<$Cj43XLYMnZWe!F2XXrGEU!da86WKcA&rGaTN>YY4Ruwe=FN6*x zp?t>ke1FhX5+~&M1Ahih!=Dd?%&OiP##@HzU7p)Stiz`Q5RG+1cRn!)wjSBDsS78E z%vBw!am2Q(UmsYxV!@$k-#3G2{xo13feW$bz@NDS5Um{YOGDj(&t-9Qur=<=*>DWR zT9ix(JY0yi-!j12KAEwzIp1EK!Q6o~V_{N9u7GIRcxUE{nstFy@e50%W)tgB+@Zq+ zlM+gg=!AlxBWAQjW6j}K89x2+(%EHeUO7>?^+<6tPCH;&bk{P`siGAy-Kmi{mnRM_ zC22aL!qv_^ERMiM8CiQv_LfE>FRWMyKxRe~1S(WH%H8rZQV|EF@1Y_U^4dj3EJ=e< z6+KYz*2WND*ta=p>Cu8j&fG!!WN#!^BLVvag!Wo(SP*nCN;R0OatJyiUeNsBI(Mx*Qk2BK%U8ggw`hl$T@+_ABLFdO+qt17X<0?wD>#@T2H@@_ zh8-r`5$ax{B#hi3z=tQNQod$nyQR@~ZM4&RhqvOptV(H%Jh^w9>1Z`-c%^5& z^^AN9%OUw|RbJNq>@1I$o*(NnYTcSmSFT>WaPgYf*j#;|)txs6l^hK=9i4>n6iFYY z`12PZUX(=1r3+sYdGP(;_59nv_Wa^!@aGTTeM_PZ_KB1ojkEf!+)v>*>^#@c9_u-O z=8JRZuAV)6h2iA+6JNf2`dUTl&xQ?u(8=kpF-|VuAN}aKQBO@7`J9*Y1niy7EJEis zK(H?#Y{}4h`fss6ulBLQO2)3Edo(HxFf(+X{u^qjeTLe{{2S=MHSGUtKGvMKui1Zz z`B-zl@1qpHp6N1v%Dpcg9Rmv8Xa{^UXrsh2-nxwNBR!BF{N zTcBV5{P`cBKVyUT&bg1X(%*bw^rQC=zdLr3_rX1>(m_>SQ@xZAkSNI_mPl{NPOi(^ zT)Hvl_1ML4M8AA6=H)}I3S8<-Hyc@tbdtlo%j5lO(&8Jl6GTjF<%zQL?1dY1Qb-I@#h+p4rpEPw4a?^-)DlD)HJc1$K%_+GKD_3}dTTDfWu7j*Mf~G{ zKWhqY-okPjkx5dZSOI5iSin$ZS^|*4$Vhq^e^tc1LR|8utc@MHVpWPHxVj*-sxYfs zMOVaA@ks8r*3=bstNbKXeb_9S|?>Wzh+T%jK0t&MRBKgg8*5M9N8G@PZgyoG}Vh;m>S^Gb?SgEbqNJStzs# zJ_DkuEaU+f4vbkC^03;va2JVyIGBDjGQuYGczzO;rgdvLb{}|tS}mO|kpvAyteLa@ z)`l?Oa@RPaO=jSn*}mpL!16%q+=?>`i|#A+!JiG7Y-Z6$VgH$d!)Iz59Cd)1Uib`T zyBW!<-TwHqfol870G~B~M*nPRL^<>RpvkYJa9*?U$euOF_v-j)X-7-4j%RPGUF*L; zNCc?Wp;JY1iriO_-Bi&(<2G=!{#n?d^|H+z*wO79m2EOceVcnRpVQ_LW7k~A=J0{< z+W2NT+7O^r0V2wwO=$|nN zBFvoP&#ik?zHa^ucE)0YhasjPvXrAFy|XyIt0eX0YZ<5ZrkyECIa9FpNLGB+TECx$ zd*KoNQ$JVCH!#EyvAW;nD!(ZeDg%OsNFUHC$n`*w>mlN12D%y(F)AY@+2%h;H@N(q zl=7LMJ(Dj8p>6mxg;;Zx1y09RqjGH!E03V%JhVZSa{YxV>~iH2kFO*RyI?N<^xl-y zWD2*Q%G-Qm&-$(%tBz!?;6}<%YYv9 zF5{JLkDZMYGjlfQdE;;_jmb%PJ7E2Eq97TIl{5K?CwFh`N?X>vIkaZg;<8v@tU2~E zHy1-s06q3}{&~@3V@X{Z<5d~|GJz@Ky`Xg*hT+ekS5(lzZOxy_TlljTLAUJ9Ai->L z3xN`My(Ud@oHHcHHm+IB1bTVoOk~e!j}2!DUb28n^-7Z2UeL6dVo}H|I7X?IF=~#P zi6t`pnR%}6`~=OPkK}Es-4a?I>jU%D_3gJd6k1n+KkNR9-ZiVB=_)Y&O;Cx_=()@< zwC!AnDGgt!`lpbEX{zNVqA^R2m}sDzQM)DxB>-I)(a_@EEsR}FnyU$J{i>yedj#r= z6-M|hAZJ6QcUg$%zK~f=2Q((ecF<2?Ra#NT@sc!VE^4=iW6)6*zYeU{v^Z+XWnX#TAGhjipP zKad~GJ9^g#!+gt@E~?oW*^;@QF9_Q@je?=Uy04BBfTVr%q!3jA*x8!2wxm8s7B*UY z^}PxcLuz855&bjjg4`_5$vhxSoLr+hgzRY(IMO(x(?LeEz}Jo)0hg zT=~6)3=ejcH1PU2^JfcuX7w&-fIs8>{M+C3{O`a2{JrxZitmIa&fp;AI*w4YBhKuo z{7-bA8)uJ8u*J9E{@~oX4;fv;pWiMX^v##7_Tct+>Zrb>a{Dvr5=ZqNl@FcAQOoG^q4pVS zAMTa)CBnRBTf%{xO)EVy}!GB_1eYDpKJb1%!ncWJn+uX zZPe8K`SSa+Ud&Ga{HNj1=g)qWnf8X6KdY!B(lxc^&y=VY(5RZ*_awLN*xa#eUXg;ftD@o}tqCG1g}XR#?} zz!D~I7-)$}bs+=?oQ>Oth>95%V&J?cfaRr#irWh^SPKk&Nj69#tAd$qPSH_RD43u6c%U!FB)C)El6*8P;6jP2P zN`yCpsD_QS3`#-1woUosG$ zJlHyB{%qv?0?sxR+Lk|?@iP3`ynD<1py2cE^JgoD-jAy;*1WrnROnJs36nO)wyg4tx#tQ;->;hw_<( z%9P7P`Mf`Pk`^=D(^rEh+hnZwrO2V_u8nFoH)TGvqhl#Is@WWV8@py2Y@avav(6Zw z>nLNs0Q7=4Kn)ozzm3ysLxTl&F%R!7985sg9C*>=tf}IPJ5j?}6d11Ach~1M;qJn0ULM0^7h@aulZLdkRL_-3NV+J4BnI2cO zdg0+{LRUz@KCx>iS-men!N`3j!bP+j$wHFB)MCD2;m=h|=ithVwj3Ug{<*tg8_}ETMJ=U%3jMkmHyexpDEV}nmCETUcf046Ap*ZE{mOCyD_YL$GVe+@`$5J zn{shEOXhpwD<<(1MWRnA=a%(hM3-QCn(h$u_&DM7mQ>MxEz66zLj8%td+AglW~Qd% zoW!K4T(+PwHNNFlR+R8HCDU9)5^PA0VTJ;GG-lqJ-EIx@L_RGD8qymLm!6FmM`h%k zx|IP((pH{A^IVwTkdw$Sur^<0^GBEgDM)Ngk1JoZgjohY4ykhsT5**$c195md{$dA z4>2QX8@znWT~4Thv+cHD+HBuNGmn+A!Qsj_gk8RNXlptpn6wOXwDub1p(nZ#akIuu!loG02{S{`c})`R%gukarw#V? zht6YerN7knG2i1*ey9b8T41OJ%q_rM#%ql0)Uo3p8~)uFo|w?w)P3cH>+fIuMELWi z8}Mh6TE3+GH-_}jciMjB(xvOfA2j&0;OI++|HhwyKc78w{q46t%t-y|{iD9~z=&aS zOMDMyr}e|1>vA&d_N2Dtq<1L0X3#NW8$^cZcC2Yz9f0(uG;02V<$hJ$mbJf{*qWV6 zAC{sBkjJA|bM_m}O-RE$G@8P8j7!MxFT7$L+ zhYcC*=M%ayg;8NgetK7a>e1XJxxr15#N9g(Cics9F+N-#;g$x?pRFb#T;xssIoeys zDIp$pp)=)D6)>*}orPf|Yi3#9+>#vE%}hZ_S{G0vClLa`xRpzV9s{3ATJUUOXCq^V z&o|{&V5!#H_LVmG=!Vm9!Z@044%;miglc2xcq z`E&n}+0kDI3zi2`-vG`w8G}Dp1WzX!yQWNk{P~u^*`~suJAW1r4aJ`YCI?QFq{th) zus8&hm1~xC@7aiB13^wdQufA)8h;8_@v1@aY#;*MZ*qqRIcOW*@raGmI$1@#J z>Noz7{{-a0ultQZ2*leQf0)IX@(7>O>x~G{1Hv&?N2uEESY48ma&O*m+H9@vvF0 zzokT+85)bk$zPt*09%z>U(0HP$7)IN-c+b8fjbH32OdP-%?bjD^pWh%Ej!k>?cR8- zBn3tz$a6*5Or}!_gjc^VVD38MOOZanp^vupENw^&2`3!1?OV`HC zAc<44vcPHtK3n;7Wvp-g=7^(t+eH6N@KZvdrZ1~swUEU=miqdrTWt;fGe_w}3GsP_ zKP#sTj47DnFQ*F;HMeUVmP(A* zS}f34F2-%6I&fxdm={3|@%X|ETA4X}AqW>c=t!TY)j`KI*PP5tY|l&LXTw!h5p))a5VGg1;baq{cS4{}*Jg;tLU~}R!bRc-C zvCM&0Y}NUxm_k?O(2dWm%E=(npV$0ZyKo46W?5o(fBI(>&V8mDj6QP3X-#6p2>tNNXIHLVzk2n{3-4cJ6#2o0!I^Jhvf&6mJM`aBaf_@+Y4R-F z4;W-!?78r}o`3nrYd?GY>iN?jz4z7^YI*6kJ`wI<`E#Eq5z^a-3A4atNA(?*-=Xtd z$NyQb3jTcVV{ZRvr+eNx^y)XUH<@-;5>!}~Vw*Tq}*Dt6!Ya9Ly z8nr|gzS9iW+FSTaM#_JtCxJhs4fsa!=W}O1NK1bGK9@%x965ZM-yHZeeOH7Npk|EY z#5+!W-qM6TQK9GvUOgxKF$hJo`Z0qKa*CO|Ne4&LiGE zLJR5oTKKap+*2$5l#ZJ4C9E7gnwQ$1v8HZ)Sb6LMmKKV}Ly=W&yCGX;F=6z~2bckM z+Se3hEfQk2V$`|-lk@9OwAt#<6^XKv452!PJd^NPt`9*hG^ae&_h9H894(p>mthCm z1@98e&5T-c+YtYa?xKtn1*u1OZ9)iCwcM{Fc0S_pim+MLm_;kC3m@T#KO5yYXFMCj zyh#mV-k@^J1uLgY9ZHX@MdzdMolhwXn^hXWs3tLn5LDt$SwI+|6fu0xO;Olc%$y~Y zFHs=1dJ3u|KF>NSw+$*73H_mxb4!dH33G!Sv5;}4SgD}D5`)M5lw)~`Cvp?&wnnoI zoQOrh=fmORUCGxW3aiMQQlI?UC?s>+{Miv(?!Vk1$u^XjUE@!K&DfvHT%tL%hR*}x z&o(@H;Jbq*&zgV2wFZ?8Q0V}x+UlQeaizb|wtkWZ$ogJTdrCw$#h(?Ln|8o|DoXp- z)aCrzL0f1(QF|fa&3QC}ro`%LAOdOgWgGWG#!(}f>)Yqe zN9mg~pVOSTKUSCY(-gP;Cv%${z}Y5azBY5-(TAGPc~joRmTwsk5yOhZi^hwgx0r8? z+aEabr~c!A>OYC#bSJj2I*D_Bu_!!&&%#udrng_(**^=t^9mP8=wh#R==bPG@ z1ACJ-G~rDr(Q^veH5a7gBLZgIu3c@;4}z~@5|KIO}n9LZdJl6VU6 zXZ59E1l^1`$li=2C1Noxs9YuOyup2m|FcTyp9O*LO#`;K7p96KN$%F>(?!*z-$?V zi(6smn<}V7G<;STTOJxgw?@qpz#Be`5F0Gfsth6A^PKwC{w*oX#frQ*6*Ch;5Q@QX zQ3i>5VM6|$%uhYFd&`l8*qY@FX*UowT@KYr5Ufq&=uG-K zM+Hm()$x8+VW4B5R(N%|drQO&bmP)80A$X? z;<-<#z#xvxqWTh+Mw2DvThE2FZ7#Z8)FISC@tKZ zlmyzIEf1tb^Jg0bExUJ!KihXQZ?8o6HubSOueTVX1E1+W@mpf%h3+xmK2B?GL<0$# zT^BqX2}H%xg;=sQWvy<_+lCztowwRT>2-shF~=ZPmb5HhNTx_jqKp4S1?pQ*cLGJXWIOmpnrxxrzHM(tn@R_(LEd9&h0e^1INon0du%7U;=$9))Wko0Ug9Zl%(rW&!7a^Lvbn;0$uTL)OXr;-)?1Ck$GW28266RGOI=ea)kv5^;mo#pSYD-^B zba)sA+F%BK+$^1c#`x&6j_0RzZ(rZKIl4aHpJ4)OA~9+Xn}tMK-;rGWVEi}48$`ip z&7UpTsqGxY7*2|JBDa7}hA@9M%NNwH4{FX@)tB`<*zcB=F1OQ!4*fj8FWw2{`h^t7cl@MAev{F-ZkEW~b%{#jHJ}cW4 znvXTNk2!C1h_P#P`*&pbCO+)%+UM?IKgj+h7BlBT^5^O$lX0uy3)=5Det#fo;+u=d zz2QHpVfCV;Su2kfCgIhTkJ@QB&~l&0ximC)Yqs?nU&KZ7hj8# z3>~JB2Q1IPqkA?tCB~M<&3^+oX1__aOhv#X;tBR9n6ntai2XR`8=zzJFGPT|(&yuI zuJcBTOuht85=^b4UYhxHRgeh#`9&QJnf^DyZl$Z2@F+ftc$=tvMcYYjN^&f#RIqC( z!b3Ylh3$jnD@ik8xmcvpZGW|+d2gn2R8GgvqW!f@G{eB#mLFvTc;!(q&L<*W?kLFW zEabFEnr|Y^dKXaNXKDditJGYy9Um2)m`%{_Ny9dk@NrqP6`giEUpLzFlf_A=^S7MX zxuzpAsycr0z9`>A%a=4JE$`030!8Kp;IKMZs;s z>A-djlZ!Lpw@0%#wI+pE$Ik`E;+pq|C!0C5P~|?kwDK#~o*0O+1wkv{Y0aOT!sv&nt_zdkVFbwV zu3EmZerptVEA5zCJInL77bS0f@jH(^I`)AR zohPnb`kVm{;%DLyest+ekw9Pma!|?9c*@a9to5z%`LaYZ5-6?2&%gZVYyabCAH4I{ zM}%2_=M>h*5{&QsnH%9Hn47%hScAhWb&u^Xh?CiNeoO}C|Gsi!B_sorR$AACC z!_$U4xr}uh_0-76r`_|C=V(_D0q}X=h$%z-d5Eije`dwaOZPte(1?e_{9}Ie>r0ofe10>37Tc~N{%q~r+)17GH;_M{J$*Gf;jix< z`OvqVN2~~#2Y&`E_o;stH@SjcHTgTC$8=)RSHN29_H3(5Sy37FN@du*eG&7@w?r$E zSZ4F9DeXBZfqVJ0>hW%`&)x}t=2WODnzEB?lH(7>Euss}cuIohg?rj`!rASUKWkRp ze?Q;mRDzU4J?XUH#GjRZ7}<{z8V^QF0y|q0Lq(N`6*C;Dj+$E=x2SGaP;2sv<9m{h zqQA;Z!+B3+-i5S}I9f37lK~nrfYyanE|t}PrhYFgJq+d4QK8Jn~wRj zQHP9~jG6O}_@pDIYA!eD9i7KfIsCaQM94W_8JfRo{#+M0r9NmXG_N$st#aie1bf)q z!aC5(0>q9LCL@8ycl}_1G^W9ybu>fH0DrCtm?j8XHH*0gbl!aL=DdAP`x0|~^Szt% z_DAUwNA2LK9NOvVPe!>tE4D8&Di11SoX4bW*=kB+w-NJK_I=^Ye=m{_H>XK-|0&yEmRJNX8hJ zcmz;r60DfpQ8(U8jKR)u<_?v}^Df}l+J3Yh7Oh?cqE^K}xeoYToZ0{r<{nFA<`M5K z!W@XjM_;K=_)H<^m)8xFY?ByUHzO}58kRQ>Zy)JbFnJ^{D=ECcx=T_{lq8=nOgxpd zv1|KE{+DrfYD`~sBoDt1W#Xa23yNe~1&D+{W6+I3iWWSxg*@vdF3{R|1h@@yhk+Mn zpj$pwoN{DGe8rjtr7@n>ab6Ws9yL+!wb3)t;)0+_%`x~(+{B+7quhu{2+qX}xo&+Z zm>0y#3ZtV0H_Y48kPwMrn>V0_&mx>QB}e>O$JgUU$%HIeSP(SU)561Nf}nMjK$%02 z6x(E8_hPKEY(YapOh@)+?w7BONpN1-)p=>Wv(&67Fn zv&CsAUfs~LEs}7D6(DOOB*x67o!eqPI$}t(NNrKdAlk~G2Zf*w{!E5e)pPVxh(Xz4 zB+!ofnKnI4W7koAN9D$W<_wzfdLoQOc!@Y%tss-`V(3iWjg+1wMsUh-yDZG>VEF8P z(evqk*YDiO^9u8~+TAHoVp*}s!b7ymcKo@Y;DdddZ&27&xV?H$3ely-+#`SI8#_`n zRxiKb=`Qz))Bf|9zy0v)4F)(DFI*r#y#Q(eElcf?a8oLnBd zYwQc7emH&f1Wy;&xud4P;yh!{-Bad{oN9v{HB_`IG!N27v~89I--t&CD=NnC!liY=IV`+WkEhQ zp>q#J%q#o<*?SM@IIi>Vn~o)sYL*q*acrg7i5V^v&gynRgQCFI#+O@r7*AY5I3Q@ zorURjiP29-u7aAPF7B}SadpiVI9KT`!L#F%XLX70n?IW`<8`k1GYFaredNw|6M5#Q zPmyQT&MMkCr0^v|O~r!G|FkWzZqwSvotDA;J%a_weMSjIQI(WZUPp?IW4l2uMc^~) ztcL9yt0Px%Y8Nks948Y{29kyZnwC)n&8fK%G@=?d zDdsHvxikaY$^O#xp~9r@tZleVpN?KpYxi$7rqp5gQ^D-1K>uvkIg@MJtlIUePA2QW zF|NWHGCXd(xp7>2Y;IJY%`Fqjz42%7YG=3NgRD-1KWo~2L;ei5(w*HBMYPn?%uda@ zH!SImshZo(x#u|QQ#{*Mi_&>=z?wfp@Bn&kA@hiq&_%VOi?|bSO|nx33@suE%Tb() zE)jKNj%IEg1=Oy=*;)suT_=VW25_DUg2n~9X5GUQ z8|R#k@bAiuIah@{guKVmQ<;bVF!0cme|m$Tw0m|Qw*@k(0@|iRcSCARXnd*?pfp^U zCI8ccH+kQrGk-_*j&;W@i=Nyt_e9u&XDE&tGN*duJmS>)dDZKI(ioC2{z>S9pM=go z5wZY3=h}@6oHa2w&gGZf9D>8S@c@ViF4p;{t@EJqX8w%$U+Mq(xuT2axeQ8aJ_Q%_ z+SnC+X)!Nie$JE7(hLNvg#33+{Xw9s!D*FAg<2}ju*im8Cr&q~LYRj*m6>fgCsay8 zAR%T>)R-iCX3UBH3e1hDJ@T?rW#&M^?&cKh z>79?(#jk1DwyI%EP(yS;y?rr%#iS@<%o5?NhW=Shi4~5X;L}S z@IL`c7wnUIm)jm`h+WpLE_QDVoV*SSoEaz&t?#<__G;7 z%ax%K>UvDCk|<2=jT_(6c6k91FCDu)Xy7nhg-Z-wgcPG(BG<{0ypFd7H3ABUy6~V= zn;);=AIlqggLtzW?s;v+d73j*jYSn?5!(&*HsU1xH$*#KnhVy()}yKX(35!?YZlJC zXWEx43oEX_^7fn8KYsO<_b70K{|2{{Z@qrY>kqng(P)Ig&hK5l`Yv}^ue~;M?TS<$ z{F}e}rbdW7g+t1<~|e2JxBN?^X56)M2^AS$8&_K}zu>~~<+tAa5dO@AVWd=k58}U(y#MIkw>|L9d+(07uJz&njA*%` zB(J`N5+vfkfhjbi*_N#My10!k))g%wK{d7&j-=?8l2q<`=)lD)=u#9-CjQ)ZB;Qex z3xcLXH{KmB+1q~-8C+wNyDD4+4O@%=E~oM0AV|!i8dZBMm*w8WyqC_|Q7kMB^ znm==gr2r}SbcV!eS*K+wL2Y+LCft&sKLI13umx3bTHBl$)pKAEC3Qq(0;k0U8*5F& zW3#h3>s)EpVE(?Ags9q0kDs(JN0-98lTyrG)W1%-ktl(Un@96)j$6*{hFgm|U~WmE z*&L5LX4p7KDAfk-I5!42ZF;PAUqpBA9wbIer>Af+OF|&|cmZlw9TZp=nY1eMg|`N^ z)Pc|Cxro#F9-EPQ7p4J!Ydz5rxN^5$L$N#*zXUz4%v{S*tnM`>I4EO1E~s3V(*Padx$q`KJwW zDHhP^mPP+;Sa7gHqbPh1_6ZfBMA()}lrnCHQqoA=e@ljuqKH6;3rP{~byqT4vWSK-eM>u1-l z7yf*5gGiujHq5MFFCmT`p>t1dS<#vqO(`_^l{i1}2+Rxr^wzGqsPDwv?wX*&OO=;} z(ou6T%HTq=Q!I!fkge&Po{C+0JaplcVGDk2S@e@|zmt*6s-pu>M=wWE%A?7X5y2;- zgPyYc|2S;%QyUjNy?%Z*&qp@MPqA@51|9R8LKij}?>$jijoa5C$`xN? zp`c4}gx35SFAh;eN68<%#;CxyonaJuQ1W2$oG(r7&X2F%@i<@>e69Gi`a1|rro|IJ ziy}H=3DlP>5W&l01nuO{P-ytGLeLzE+DZp5Dntbx?oY`}$M*Hg3%ai)jRy_^794WQ5pZCx*0rJ!VIYO4MjnTW*bA z)3I&+VDcvXsLz#ANED~9bQJacsQ5Ycm!}RC?(0a6Y}m3I50I{yfWFv(fhhmJh$VgE z>>>Oa^9{~d@#l$4pxv>vQI60DfA+lSQZ2WXGy51^@n;2}`Lg82J>zLUua(t>`_+Um z;ZXwL4hKn5Y`i#5gs-UG5!REvXQ(K%r;tk1Ssg`rjsohiNSOJvh@wHzljP5xCApLx z)y*yid?5;O??&aB{JKsd2M)O=wb|}vgZtggz#_>J#Q}Z)5Kjzoip?9Kl#p#-+TBE9%^ssdi|>CpQrfqWG{PeqW@=*Kcjz6N~nTAf9osv z>W$ZeSBs-F~R7b99x2))}P?>#&V}E2@QL^Zti=}WO`e*SO zHt}cl&&q#;t@u=QmrKY8NDpA~r)oo)CMLhi_TxivhX z)8gN5;le(k(drLI7G3dfOKaNZj)QyPt~eemBV~~U7iaKBDxx52DR!rB>)sQIHS}rw zO7?=s$_;{jsk-0f22)~^{8?+HF^=Z0P$5>qx!fm41Ta4Ll8)Hb?eSr~sd0k`_xBfa zJXun4rZ}6!GpMpbm`lWMLs4imi&j!+g`mMH;APH8t;);1hEoURnQo$6uuC}fe_~EsGz>|=<}t?-6d)L$MSI;9V}0$${4;hKMq+4 zpp$dQFW1GNWe}j>#Q3xMnDv~fMpn&d?K?NmgD(H48r6;*q~eNtSr;<<(~U`uOlNPO zuEz1UbrS6xX4P$&#cZ6~IGd$7rEHL(5gh&G#yKaptc2`gD}?1fB1|`EdDE*JM~^>( zfnfn<<^Yg7!*I92jDo<(0yHOn4##qa3imf9Mx5Nb_C(wxj{Vlw)Nu6M-8q|ka^i^Y z?5$l{o7=NCwWLNg>EO2aDJ(#m)s64gjXhvs6T6<+`&++WeV;OBclsOJh z&geLrE+E9IE*Q zBb&n@+fKf%ROs+$`Shdd9J7kfqe9V zQB!HLJf*iRslPI5_*m+NpM+CQRU*DY?+jnSBe|Z{ZF&)Bq#Y|fskr-xKyas|ZOi$M4rkxvWV^%}0 zxtaoLc1Hxjc=>d7Q6akJsHFrSCm0zMY-%^~;5#DNv1MI%$|k8dUB(0M)K02HmM3@R zZ>!t2fu|}MKKDoZ4@E8&(X#k9`-@$+Kvthe|@>xA8 z;9&vRSNxEm{dJN4JZ9p`xk;WuENc%7=&-FgWeKX?vY|U|$I#)l-ongoxgSo&vNsYSx{+(+lnzjyK6`!7EC%dGSt-#+cDcTc3`4cId^~m`}chNyAOQlXz>%*Uj3!w&s1$7M4dZYQ~1|${owkz&;MtA z2Kn=)^Vj$9t+?yUzy08S_wKf@yCHwBD@>QXN&4YMpi3656E7Da=(!QsUb!{2D`t(2 zQ-f`HiLt#TPAd}YQv5)m^g^K{{Hv{gC&HJW=Iz%V>pQve%-K0ykTO(~-B*;;RzR7U zT&(|ixwy*+RXR{;xj~`TQsHR5ggFDNIU~iN5q0Cv;oNG}C`9g#zvVz#T3>NudtQ7? zS}YzT7+edV=h(1|q(TtJAmNMQ&uxT3p1G@4@L6ud?Q-|@DTW(Qp6u!ksj|7lxKw!} zjT0fyr=qcEb?2{)ZDDKWyWwoVm zITf?&nXtte=PFy>T3ib(LbDry&l};=WAx8zx|k*N>6?#Px8DSRW>`HTZv2^c_0?!T zJZ>@xuImA=)qv<}^~icOsISh=2|dlLw=P%H!Z)rI(eUT`keM|hv!7Z&^T*+f(OdQx z?8Q<5*{b57PD*KbN0=$7XKwB}kz8qX&DdGxF4-_T;cP{o2jS1;Rk`AKQJVg2MK(Im z{=<8F@^^ZWh|5zpnx&zOO){2z&;~4}jn&>)~(Q}jznSE6f@LPqQA^a*>)d*U_YR#Wv zyfPc(>7TtedhlmOk4?;3$TOsr5Wa2HHuI2A zLD0GJ?TL}iTOV(XT7kk=>iUVhvcY&`f^fh9K4S;%FpRGO?_xcT#vAW1Luk#5B!k6C z80_~{ru9{&q8n$T8uo-X#IB~>K!pE5)Uy7VW#R}OCAQTtWDqxg7mk<}t?}zAM>tTL z)LoU{QYi?!u>z~=G)#4#txCUGkvx>W*|B|XbIfvVKssWAdSZj|qh>ZZyx!Pg4WCJF z2%qWTgFhoG)}b%SJX_Qz9}?wTx`~(F#A(eaob7aPGx&2|#L~LxKrWjp@r*Q`njp=g zJR?}i8;A{Y@Mqk%)BCV%F3iGbqs1t;qWH5Q=%VbKHYfGw}JCAM+WRb9Hu}OLL!zpMU@U`}Rg|s42>BEJWd)!&PgW;UI@lS%Tt& zh149$7TafoKX)nqyg%yc$kjDrK@M9mh535Zw%|F5G@2SEQX?A#ExV(I&XRK5yzwU# zI+u|V4EG&LqDWtL>?+FD!6d~WnCtEFsIsEaX8w%igBZ87k48i|gzBK~EEIp{j*nID zKJfJ5V!qK5*kBE6w68iHxw?MahK}S-efhh4jwH1grM47jpyl64*fHr3}y(9b|l#UJk+l`#3g|ao2&S9 z9WBy04u2kZ9yD-vp12{{*0W)r#);%^^P^Wa9QKh+mIIGFlpX~5?8cwnR&~#bB{R|G zPB2b~JX{kxvpPh6Ei%0u=GAYUV+7AB9P)@LY+v11x^0A_JS#qX#Neho6LqCJR|ThVnU0k!M+=B0ieg zWrU*8>bw+%9?PFcCB*P&g`nZj-saHT{Cl?Z4SI&c(afY9f7beEfzOrl>BfVA41woI zGYHrBVop3Lw8`Tdoi^ncdynR*6H$U{oFypKD4xlMNu6n%8n-_#7&#Jo@DgaVnLoE1 z{8|3WZ>GfF4jx0ppP}XAuw9xWRCd!!#h-auiE99IrGNHRL30H{@Yj>j{8@Jfz?wtr zpBWPbEe;j9idmNMt`5xH?U;n%#Ubt`m{9|wBZdF>#Ey!e6^Oneg7(IrHD^|dz9ciZ z>qZiNCH8AhoELt^8*}PPRTLUF|N8Kym~x-CFRP0TZrl18&mC%P%THRDKW)Jy?y>gN ztwRN=y%ZlTyKa>ibu(ethNCkyrnFEbK;x#SWkur0*koPhCg#@t@*IV$iQbsn^}UO(I-m{LF=*>tH18!mMC8B z*2t=pKO3qNZYvO$sH^(sFh4$;YU52(F;K4Lg*j zLZLyjG!7g}>`d9zxNSpC#Hw0rV6!cVPZ43ZOUcZzgkGIsqIThCNA=f(;P*(5tp_h_ zqd02M-qv{}0Y4B_*@BLXvmnfr0=hfC6j3KILWx3})K)NWdR!oI8;>ksP^?n#k0$t|;WNo&|*mQ1Ot8z}JEIDKs) zqH(lh#d`II$z<8G@BY4Nv)k5j!SX~JJ*lz_Dc_hs>z;}vPlP|Ko)cf1xu^!7=0X11^41UhcJC;wC}y0cpc-L9m+EXNW~#XqHNp9D4$ zfXAab{X|8UfIb+eVLvX_XNgOB8MR`i#AHwYHf4T7)zRiC;Ir6q zbVc9?;xykdCq5|j1o<=ASZazMVNXS^`mr_W>F7tAl45!bQqU@M)!kH-LvSgs_;YtrmU7{sWm522dFXNFPsz^a zg6z8Dyu#!?-+ti!-@fynfBf5j{w1XbjhAQP&+oiBf-L#!EAPH>9b4vGd<%Ky{Wo!$ zz6N=IAJggA4Ds`S{>RAw`spuUxQO%fuU>lY<4YIbhdfj1hU7D-Prjvxr1&%B`O?J^ zDD-m|t}j@y?)GVS-ZSmX-?{C9CHKr${CUL;q0qb;?Mcr(TYM80wbgSk&z7li%ro%$ zm>=^QnR9h^o=bC|iR7Lme3E(d9Bm@UVD95N!qo9h&5wBoeCJ=V-;eO;pxfvA&zQaF z-iIE#?@zvY$JZYZdi)>$&p&DYEVY9T3G@_yz7^L_pF#fo?9eMawjP=BrLTVH>klMt zvecF2dgIUPJ-+6G48W%7Y?Xm?VRBpkuExZulW~tfVO?Io)7pP95$icPvt0KIb~c32 zXrYZjlEJ=s6b~FqYTX-I7xU=J5DXcFKXaYmZ1rz4RUT9rnMTc@1wk9|nPsa*+EpLl zOAVqKT*e1Ahx?<~mB6pq@cp2@E8u)bh@)KOc@3D1fZtp#uC?+9dpD5K^xCrMa z4pA|e@jXY9JF|CDYOrzhLz7*4D`7D>_d4l{|bz>Yg2qn%L zio8B-NxdzoVe_Lc`)r-LI}jwpE-=k-6lP#`g2oAT3ajXy2oe!68=lW33N?EJ(W)K( ztel?#?C@tAQJ@W$XAc&pp#X1Bih;D(Ml3&VS<(P)jubQM7Q;82IYgU{fi@l{3g&aP zD%4a{Cz08fM+}Dl#svAZZ;X6%Tix*T4Ob_En%(+%lIKaaX!vX-6E)wMIC-Y08xd95 z)3Z@zsAHAA8nKR>z@J^RXOzzpzWMW{;4_^$a;1N!G@Ev8=CHw%7!;gRHQFqqj;4Ye z|5)HK7_ow?D0J0aif?V^nWE&*eRk||8p0MMAB8`Qzi!BU6w$SzQvY$>Y1I7LEzy(U zHcM_Z$ts^hc(#w*qA9e7!@d)5=-9K}V;teYKEe$Vdt3D}LVegw&uFmBGB?(RK1|ev zK72Av5H$Q5*>mH1;m@d`g+(Ll-S}{$NU3L^3|r6?|5*Q_ctpj*pIs)#pJJjUzAT*- z)amD7l)y9m8E_9U!u9C}o5c=7D)ezYM@3Q#rYdXrXckDBz?#M!5ONN_{TQO?Y;xEjNSq)+ z;4P=41DtN?mNk)fOEgK=3GkT^dt?v44rT@@syL*vq-H2{CBe)n{tOcDJtmM@>6{0T z%2^Co|W!1#?_ znOlL(IHmWM=JxO=R3TRgxp->f3(b#>Z;%QO_>i~l32WK3raf{w1($nmRQ(ghGO$FBy%{O8gq4ZazbRXIQ zg07ES-9+c8Kn|%p!cQplWDxXZ`LnuCbED9#db@0M@?pcJ`Ih8{TeyA_q2HeCvg#t-UlX+AwO8N5ZR6FKKe+np$Hd#OkG%Hk`)HE6sk{~UQ06hw zKfihH{p+v2hxrEP&lrHb{9hyg`p+XTU4G-mi|;^Rp}Syb;<<|~zli#0nSpa3!JjW( z{Ah6Szkcv%fnT0B9sc}Bw||W~Q1Itvx6fX2=iI>Qvx8>L@uX*-Exw70+UmKNXUo($ z<{9{W%#Znu%(*%{&!xG~L~_p&KFPd!jy92FF!%8sVd{9M=Epn(zVk2G?}tJIi{Q@z zcg^*?Z|1D~zW;}JeRJuorDyujPw{8-Rn4u-KZE@F%;3x0wj6>#|IzP!EqSxGzBJDV zf5zCM<#1N}k!+FIVypqBEX!yuNoqZ`yCH4U(_7ZpY`1o1?Cv?3-d2>~C@#bzdp2Yk zSxv>6h=&c^=ZwCC$cDGpMn6W$!un7uxd$U=Znp=5k;S%x#2$#og8&`VsQ9y!IfI>5 zaX>=?4W0H3HyrJoKLbUnkAqipb$GzZh~VnD#~TwOy7P8nBqGL%7+Du)K;1c!w&J{w zf}FNPX&pKHoAz(6-n#L0)FTZMD>!D6_}awju|fGg8q!}uuLdnQJf#igw#)qkXFp}` z=k3;pcFmuKW79t}s2;<{_|U%exPgOvaWCm9l2U{4aFI3v#tj1vY#s@@->(EdXNgrv zS(drTpz?W!P6O3P!*J>lm&j5%WrEQ}N=<3SBgw7lI~sS}PDMQepXViCNOBiWAmT)g zskL9LZ879ol;k*y@C3oKRB?Vm{X8$gQro(;(;}hxvzZ(FRz911-Y|zG->?rIZU~&s z9o)e31Xm|To83B(h0hor&&SjFhWh7msj0U{Pv+^#pH++I&%yvra%hEN%`N2gaf8ps zDvhHdINDG?tL0?*GxMPQpW)9cK+T*c(L9(Z{~NPZJl24>0=EUbmFIL;Eb6PL1fdS2#rZw*?cfgW2sa#|`S%#^_l(8AZrkI-x!W#RreCVU4PfM1&2 znPh9(yb`wr9>wyvk3hu=MHD+|Qz1fyoi%*c{8<3Ccm6C0T3kV7Gz_9a(4F=rB80}R zI%;`CWKd1qT1QGO*9rY48T}^3AkPKb z^LNzk4&e?%PBLk1?_1b^movH5Und&Qxr4`llN>G$rMHm$s{?6p_krt;vG zS3Z0b74)?c{5P(={O-HI96+Yn~$P_)qe?#%-*D?LLHuCd-ANjk#{Sfgp&d--& z&S&3+JYRn9Ls=R)`j+aAKWl@(Nby1V^Z5^e&lfJd-`(>sfAq(Terwuo_fDJsz1x2` z;45>{JO|w|OY!IBcTV{~^Ln_i@T7~LExt!kTRr#kZ26x!j<;i0XXm-}*56yZ=Lnx< z-aJS1_PO5LJx7>29`jsH&5wCDJo7Ku{LEW(r(eLAX9wIlXX#gF&AR7LzH{e;v%d52 z>1XO+zy98}Ywuq(`ET6nD~B)U_@6=kJUsB<+czJWKJDJ`e&g#Yan^>i+=hY-<^Qbc zvD5zPLkyEsy9-kX3R5VS*RnhOnb4pHYjCSAxWgXo2=#|TH`#*0xs8!4xuH{07qOz= z9?WGnzRC`3V2dT7)e_Kd@aGN#?J6|wTL?XdKbssOM3HOw=?Q$c23AL{uHR|t$lTU* zXn%J>N?So%b5TY^ai${YT(qMe={}g+k+rvWhwb#Hb*JpBP(GtVVG!smFPtimNAyl| zziHImQEnj=G*k#$tT~KO{26fVJT^nNglNb+!TMt`Y@leu5!3qse#-2{oSWvVq*Wa2i^T$182N+piM=W$igkY^(h%y0uP z_uzu2v$(13D@<+6if`N(c_Mc0$%vIq5nho@H6|Nf7QgQB#grO^KMREx4fzs>WeIw3 z&RzJkv6OkRF8y@*^SGQ@LE{_pXER&AVLn0H?AFbVCr@fs!)Lo z6Q!EB>Ky*5a}tF^Va2}rGcZ;YSJm_MhPf(CAbKo({$%{Q$$|uQfu_ME3J9A|Q?*c$ z5D92a*y7H;VU(-u!v(sW_u_deAOjrTk+HcZCb(w9d?{QQHedV=!l;}mKGF*DsU?sW zLtO$-0}1rfF7m9-U2Qcl-AS_H4Z_Ik2*=Db+}I$=e3l1l7C!8We?42=z^}&6Zo6x4 zEU*`lYb-SZCTXWoIq zOv1HlY&FJI$4Rw8s!6I)XT-ta|4cg;6R4w4hR$w`UDlbf;cQ|2`Ksiz$I@^)rWzX9 z8T@OAkPY>$!7YU+!>Es@^%BraqtKpOYPPIa4N0&FgF%`qq+J;cgPpYs+C33K3gKia z%+nS4KPZtfOF_*}qhlIJhZ10`ygOV=T0{lPAjhyZP93U9I(uYy+n&%<;Y+J6i+PHH z;d4{SoaT))TP?Gj!{n=Mw9Tut%q9drTjmhRq#MHL)>-F26Eded%D-*jhQY(z&Q_%i zJt2UdzYfT=F|`<|6#t4dM|05Li%cC7dIX?*3jP+Uy};eVjQsegs4yx&Odo4`5*5? zIXpqo#wG>2S>ipV${(;qxZYQuC1%vrA}rY7eR%ijo$G31m)F~t;84*W?T0soBVsX@ z6b;cUyAmRvEl3%z$l*U3&@RKWS8slNUEHHJ7BI4)-A>G@jGDalk^Y2w01Zw=&uoUz zW?i((&48L*cMu`;s8fg7gHRz+I&cXQ0U{2r+w@3FVpQ*u1PnJic%ELCD`g$ZavDoB z2`&%Bc)28H_((!`qTLa@nkW8vd_k~rYzF6ob`dS3d2Wi9XpULRDxZQNnP=k7(ZM|l zHt;ngaJ|u5DOVjl5g0nWuXRs2&&pfSW5-a|5Qx2`ZSxXGEa6Xxvj+tYvFV6i*`FG9 zu4w;Ic`8TZsLX1v%5SX5Z9!07k%zMS+>wN5v*SABDU}%58M~ZAf@b$b`=iR1Qj9Un z7z*&t0plD3IT!zs2(hYWa6a8|1{i*2iJuKR7b38-fQnaw2wzi{P-QksSQU`sM6BHHDO6kXJKw%VP0QBZf~K8 zM&v5d&{PP5HeTqP6oqCNemvEOGfI;8{=xnCJ#f!`7tg&Y;wA1JvD#3@gAC6NXUi@2 z-+1H7$JgQB*FU~;g&Wur%%A_`-$wrOrC+^x=~qIVFTLvwA>GeIKSZfwO?Ji z`VJ+Guf6)w8?TP=XZ7E}v`1Oo!=%2G1aBntfGr(B^WC5E} z%4D1nuxuDLh!FQkdTV}CW9Ghw>;%Vwbo#?@snZ8}rgC3zN!n0J3KhY6GPX2qUC%44 zI4x7=&tVN}wgk3^2X{uVZQmBww#(L@5Zjp?*On6JNZeGvC$c`?R=0V5L-b<};j5ZL zgB&5tdcv0v*q3*OF72`ec31-2tP%=DE9JAmPn*A#LjdG8f&tU?R0)ls?njCqk0_{<2+;mg$^I8-1i#>J6azZR<>M~IIi_06BL z2cF#gh+}_5Pwq|}Ci{vqanHul5kxFr8F)39jq04aqg1rn$(+kXpf26u(pWvaP;*yl z9yuBqz9V_oz+FkH$fD37wU?&#m8SO>C->&_E zA?tEm%FQWN7m;n_$YB_CK&J&zTm3vi@wgIbCrM_U@q!~!?KqRDaCYNE$HomI^SB+{ zkn#;zCk2^xXHA<8&b)|rbBoF~i1yq>iDWZZ#DPy%oRt~7+D)Td-kNo)!Av* zVW!qPpRCl`t-l(_OrG6xg`M4&Op#;D>b|^fIP2nsz`p{@T>(0JkL+vQy%C^?y@NU< z=Z-EQtSPh`e+EIT&sF^a$SOt=v5=*Cu>k_PR4TVQR%Xi z>zb@EG%?oj*@>WC{F!0LB52{y<`!pe8dJgN2J1{65K#&EwuCTe&v4Rdead4Kb>tij z{F$5&rA8r6(M|UGt#LtvSrO-pcRqhC`O@*UXOCy%Zw!YNqXxs&*Pxdf1Gpa_%j`Rr z-cyw-FxkYP$rV-BFjFT=B&^`G6G6LUXAMQo4iCC<{KSCLP6REW)qtPk$6Jw&iGkQ$ z7(^6`E-L6_a`4ZVCHH1;so(n835y>_<^1sA&#fV|+AXtNEQYs?~yVI8!<(mg}aD zW|huDm<^G+=FbWg%ekm9>7vKs&*O1mCV_9kJTvM`F@t*5;`ZHnt}6JkTJ*7+Pew|SVlc9}1V>UX@bUKaO+AGPJcHA&Tmas-%G~yDX_pk6BeO57UjBhEdC)*^qW5-;igxaT`Kt__OlCFaUD%=2aa@5yK^k z{Bl~#pwJl*drC$0=j=dJ-55ndjb)vi0@`Dj5F($B@nZzk+JJSSG{rI$#P?F{k^qwoa2UkxrWh-@Mq&I76%ykzZ7~7 z=&(t_k($UAQX@NaEAQ)ZnT;T%8GU;hw$E8jN7CC5W%eG)5&m3|E7yCf>>yrk#fA~| zBvsJO1?gNRHk2ONY2Em>JMZ?JxA^b>?qA<{W5km-d$xS~ileI|Z(bRB6X^Y#+^bT2 z@a0!V{^=h^UV7ee-f;5gUtKm>G#C~b`@+SKsK@6SlfA?896_~w#>V;Rg>xTq*4$2B zy7bQTm)~h@`m6gN_=DS~-S*XK_s*K}r_12aGiI&2b58Ibia-03{`$tDdaEK2diAE0 zsd0Qy-EVe&yz!-}_Nf_|nt`bq@HPXOZ!Et97mfuy_r(2a)_s5a%^6?cw`1QcuUvoa z`mZP(!C&)V8h_R?)VlK8Eq{ON)4wLU#Sh#+;Q@aJ`SU>UFXCdd@0xbc4}bp~**oCR zf?EYO7ou>^5fF{fhKWBb8)u_^6i2rf2%r{5eI&ziFtsT^nWf`!def0K;4`GOzcd}M zzu`lBJCmau;~uMxT3KTcs<8&1wgj9C^{=rkZ`<^E&)$fk+`WAV_V*u2!yvksDu)GW z9fwmo4XD|6{!JT~K%P|?{CTuSp1r9bSM_L$`kKkJSrP4I$S#R8r;n?~Dccgt)txI( z>n=$Hk8~eB07^Pjke$pb;+s5! zSi!A|+?v_4IY$Pp!rbU1cgm8-YLzvDR^-`}KQrJsz}YN*=1>hM4L!cl>~Lo^*=DPH zc}>>YM&MEG9tMs!1kwg}cJgZD^c8_u2f&di5UrQBVY6`jZrZxCC&fCPzh(H)j-kR` zLnZqL%aWfxmW9jlnPb_)ka>$A@$)gDw3u2LaMkG{tl2W6XcfR-9UyC=)-JF0jFXm;VSco{u#il`184{^oym5-Ko*lQNgFe7V$5) zapUZk(An^3N2u`UI&7cA0nT$n^Hu|K?S)9S{^AXQTst_y+&c!GJ`sYQqvM>G=aC7eZ1%yN+FY3tI4 zxJUbP;?7ni^_QnoLy${|!Sc*!OH+EYwl-{gjADh3=s;A;U50MCJ4zJVqSI!;Xp!|Y zlg)8!x>BOhU=NgWc=9~Gy)wVOJcpsUZaiC-dcHWZFM}%2kF-QDSC%8lrzuKkm}!Vl zwKF0``AlP5l<1#{apAKM{;WZ?TcW|WTQcTy&Q)@nMsJ*Xvh5J&G5p!(*@Drx6x84a zKznelJ@{nQ>c-vSSjP1irSXUX^E5=xj*=WM>UdXC?DAM*omZ5L9fvq_;00Zj-CZO_ z2`8n0Mo)sLM_tLGRdXM{=SyEsh)?*hU%ZZrM$=|pvtGA+!aFA4yUXqBb?m0!gMnXp z_2XasV&rfB>YW!Zy{(*|MRv&HH1U zcZVZ0J{2B}e)yCv=%j50mKUeCJXXKkihhGyIh{qRP*8E|C~;jy8^#?ig=w8flDiJ< z>&uPrquBRWDf!nLxdKNHCth|5kIm{_F409)Y+Xil8kQY&=1!2k8m$2}mH^B>n&LL# zY}}Tyqw}ELo#Dm_wnaLkP7_x{3jFnQRiC@Naj)%E?4ukuWyf9oSv1d3XeVAatg6k} zS#rbfW1Rbx2yxgzp~UWT%yOtpxd}xF#eGwQ&HuEWO7Sb|<3rlgwE%Q%=E_Cczcjn-3c>^7>AGO{}(&ZsbVM23)?Jr!)VJBzSz*!{} znH#u?KlJGv_h6LAKon^rXs>R?40*3D-R?`_{3R&8I(!X);Cxkp-wCkng=@*~K7(AZQ`($?Sk8-+xl-+$iyXSZ|6T(^dA2-67 zA4Jh+^6bp@EE%L4IkZwlYYGk5#qIeM@@FPZV`rV1XVP2l6luesk7l=3W#I?`g;x9- z#5z!(NtpSwnLMjpF=sP>RtTD{y=56gWoZ|RlLs?5gG{Ll*%&2$$be}6UU$TApbQ)y z2te;`FXBXcZh9Lum`?@n? z9orvoh~UXMzRkg}ZN&u=QHf?^SBO&6<;eBVz zc?u(v^%h>mLPk!_%97+WWvOS1llro^wCq^d6dlZDwnPMRY+|*+!+Mt@+DV?H#1`8P z6uYgu;pH2yy6vu4$GNUEQE1Pt-uSa;Pt{`Z=Ro$tiVgj{6+KM_~7!{51&8x5%Yll`NG9F%PV^Cy!&_H&ks!ds+m8pm_7@diZboy zn5ua%MIOv8H6>D(zJ$>jN0P#`r>pn*kEu1 z?`5LCAPqeXF4LX(0Tv>L*-{ttDB5YMa5vV^89*vm<`zHkD7FHhP5e15pgCk&U5I~O zSWsic>XvOGoe9xBSv$M(6Cls%gs}?2dqmuxQ4T|Hi!#raWe*)nY){=3}qy z`%q*ve9D=^)SirOj$PIhk*m0)sf}2U4vOh*3R}dis!-x*3`}q`X{4-@i$81B%(Y{tc)-7UDYtzlRq0DI#0OnSeFUCiSy+cUalZ|A)LR97&cxQWvnb^Zi0|O`pTwkyf5IcPT4Rh*sx{x zTsDQzQK2^}{Odd(g9)n^rzeJ~MeCC#@iM+@cb%QHKq2_o`6;H+RLhugO#Hbye2yuE zIjeBkXx9i@3_6qxhs&wMx$3m$2%A|O@(>@yrXkyfjt%vr-{-De#BJPs_? z)Kn#km#Tb>{@KtB(~jM=s;MVz5Sxf&S?v{RAZThP_LWJQ#d9nV#@BCNbuw%L|8|HNV{FxE@OEbmxCojHf z`^I`(5NcJhF#a1r{$A%Og21uF5hf(#r2}7>##koMY!kOs&D5ii$h=v)vEz zb9W5B9AacG-piYUsYO^9u?&mmXS25q7bT*jW{}R(l%DdG-qOU@jF{Rjk2KkrcZLV_ z+X99o0zuF~cxpJppAjlkh>!>F@<4ynn!dz{bBFdZ!$`+lN@ONGj^U@BfvlRRhl2%) zJ(*iucUkJ9R{>o)FOWV{+8-69967M#FdUM_9~&~S;JjwV=H!OJ*{y?lUvsV~@x+(j z__I=LdoI24XJp1c6U?Yl%@Ssx>!8I|Dbnb~B%HDgnBy+G7<+HqgNR<|&GKi4p zdLtT(@>&b?x(o7@Bge$`&&s=_t|%ul((-%v-t|Y{{Jp>a+23Bf`YzgIb-(lL=g&BA zU}K0@3iFL?S4RHf@8123%S!zG;pOum3x&po!w5tFj0N;9G&B6{4gR6<=kqcN@aN|) zzIE_G(~KEkyM5YiUz>LS+`E6M_0I->o*y{HpS>3!RE)(p6Q0P{&&N0uCr(p6r)FSk z2Bu~}%|PJvxtKqT|Hf^z`RlXrs}FtW?%$vLgL&<(-SB5h3B#Z9f2M@7Jk);u18*F4 zs{Q6>;Iqb`DNE7U{qIrMRQU7a?|=93-pvigBK^HN{w%f?E+Y;_p|L6M#uPehPxY?o zr=r(AXu$4av3wG?V)WmH(wLP>ZDZ1sr-nJ5K>(Xk9((1}G>q@hlOXU4QrKXn4 zti1~9kxvIXK}qS04d~|5DN?7vlv;3=!pA1YK2p^ z5Toh(u;8YMM?1EK_b0`j$xRqKlG0t64%Y=c*Og?7_ce0s67j4+4?I|yHkiG;cVBel z=5^IbwXGB$TF%w}82CKOpM%(hGKWKQhT%c2@VFV0yF5DNm|Ja&QA43D;uaD?6b^?c z!vmhO1vc#sNA^5$B#E2EK8}Y9gH(Pg%~k4U@VMsBO5v=QR413jW%6v;bO4#1vgd|U zjQeuLU$HE^xf~pwMnNL($}d)Coh#;T*==om?e(#1(S&n5Qx|UB5*l~Ma;GEr#eT*C ziy<@Q87Gql>k>Eqtl+b6{yfT-#~NjLwhJqE**m)>o;bSE;zxMmWkrlV+f|DB3ol!aBAZMB#8Zo_YPHNcNM4g^6-UU{*$>q70IU)Ehi%U zvFVV#42BFM)_7Sb8ZUb!ip|~(e>PKSGwIdvS!Ba5&g?rGgMVE}*^?DJyBYo%N}sG+ z%!7{^%2Nw%BF|%bx;|7IUH%&+Civ_G&YC})5VW{+X!5KR4WCJ*l%c_&S&};`G(4P2 zd=^omOPRv3xu-+toY*+~gk|1Ouu_j(-IE!6p*-pQaWR*GNs7?-iL5?cCS0Ml&;!S_ zguc2$^Jm>MntWpZtbi&@Xsyx@gHKTx!zu}WqS!36NlFkN&Fnj#4Lrw1L?$61+5q+H#Px(|{yYqVt`biYGkjM3S;1$P zH^HBo7BftCTh*KN9J(cHKAATvQHp?^IW&qtD*mkCv*OQCW#qNq__NkLE9VW>jptU3 zFho(jvUDD8bf!m~+!R=CU4S=*K-w*9P!0=mtxAVKQyLil%%4{*pj*X)V+EHDV#{pv z2SLl_id|lSQv8`EIGRxKSuH1opp`$chyO-zq<@di54&k7G)5e_gz@S15z9|)TGNzh z8$7({LPh$shUGXfe6{ocVMU&JL6_(7A7g)MDwY>iPHfp{Mcd2+adg@Oiea7+hVw?W zKQZ1Z!f{| zTdbZHI)*>jmE^*oTMYh;1e$B?N%7}~qMVw-oDKd9e*5+>uV1I&~wlI z3jUm)c5?dk2kw}5`|nJ9VBS3sK>(H;{?9Ba3uW+U>O*}Z6|~|EpKuU%pBl&a9R6nK zM}4~I(%Uh6_VnE{HO|!hn12JlXTx)=d0%tx+0%E6d0%txdoRze=6%h%XHVZP=6%h% z@4Y;?n)fy5o;`iHnD;g3-u4Q(V@}YFd8=nEq;tTXvlrg`(D&~7_V>Q|z2j9+QG$>< z!o1Lg`36-8g+E{al&kOE9JBpA?e!Vt&%Is$W)Dl8G3{>uAO2}^!Zxljr665FE(m(! z`e!qFR@@l=j0;Em;k538jQ)a5ES>xElZNv5pFf;(sW5H$K;l6D{_X?&yN)Dd{(x$? zu_OxuTw9z`UzC9W8&im`!mLh1L@k4tW&@?M=0K!L%8E8q#8ASvY!pEo z%4gN5#Y#!RaiZC}5I0Eb`%o3}gl);GsNnke4UVMfzC-(Z3sNA@ltBa|%RNF#4kZGW zh8g~>6xvGR40DD&t5E#e@aPcotl_g#K0}_H*tbkPD$x|-LV%{Imr_CdBO10memWx9 zCzsHGc*go8`?n7NtDc0}t%F{rr_RlZS@Z0c zYwSFlgw4ezxYjc73hhQgJy!vzo{a{7mU@5CUAV53KN~DsG}4BS7nF(?n%xH~($62og=1&a zwlzrl@qU3nqkneTP=L=;^#_5{@Mpx&&4&IN{@iX~fKvyK&|UV0ZMOORTwCIn^`)-A zSi0ll6N%@aN*nx9Iznh>WAJzm{8>+nl89@$xQ5IE!;PZ_K9g`#!kk5?J*NKPP3xZ- zP(x-PiRWahBk4Svj?oIDaWPJ*OzW*k?JrM5OiLKDbFqC^dS-kljL@sjL@S>?(X^C_ zEYGD3F*e0#nS`R<&50rPv3NnqpUBpj;Pxb2SJ6KBv!gN#{>-0mkSV48I?}gL#Oh=GBk)DcEP-9)1$RdXbLN@5 zm_kRPVfL5mfl)ymA%E5#u`Ap5gbp3r*>v_o^v_s8lP|dY&wlWgKl=Uq9?VS1edXmh zc$y6Ced{&h&#zsb;?JKxe*bLo=Zo(@fALp+-TxX9vj47WcLhHDP-)_h`oion{24v4 zsz2z{e}lLD#4_5zxyp+JXsj$aDCb8&p*s$xb{nY0UKp;(- zLJAkU2B9`eZ((*{VfH{lc5gvePk|VE(5L-KDpa;TZO6&j^-paKu0_loF8O^&x?d(14aO1Iaq6EVTvw&8lXX;5m?kQMuECgEELNS86#tS2)?V z;T$4H7Pcidwxy>c18cTE>ewH_T?2K@xn%&$3R;po5#ooe1UJa%?5|i_cEdW3VIp=jwwBjvc0`rY~H=~lEZE=fj zakIn{Lh)y+HAOZA%9T6~3LLBixDce-E|n!2E*yebHDB$2 zVhn4A0FSa|13rrqcx;U6FqS_&LQB>4iL19KO>E94WHK@KDWa*uhTwX_`Gd)edPT5 z&3>IJj}IM=xpXYy;*V0!98VoSmO=4Bf>YL01cHV?t3XanD9Ef%ii1>V4Sd%8nL|~Y z=gIPC0}cx!W^fmJ3+s(Jg#+pfaid@V53nkJnhlp9+g(M?y&Fk)3T7X{{AmJjLen2Fnfv z?VY(hYPLOI7Zrq%nCH3hTlJ!rToQa@{wxR@7ca2|UTU~c2!rLlst%i9w|xnLLj?gk zhRUL0hGf=8FRzPV*PaoF9W-iidB$Cm-Ce?|<@T26ae|yIt`|%)KI-i$5jC-^s%`!d zPCly}T+Eo9f_-s&gdbke*m0nRhDdkE2BN~nYy`MHSeC-qfq=QqC~kO`OOA|fZQC}s zM6Lps$|aCZKrtX1@=S1e%n2>HdDKP)ICgFrJQ$A(nlFxLg^r3Gz$t+;0R%l%p52?j z&#}i=8@mQkH^N}fODYc<13E?K27fkl;EC{IbN`9t<}uB=w|&Ru%ryGYKX=%~X~coZ z8U3@tpFz-k-8{D7>*xgL+XIY`QSr8Q;_aW0alG** zZ}Z@-zqj_OalFlpYM+{)srfPg27J$k=T`H+=G?QV?-ujE=6u|}AkRT}&tn;Un*=2Y z7v1&4hrjy$2k-sn_RYI~{_n5yDie>hHGihA@#jf<{8>1c&mMn%r?2~8Y#aB$pMz#T zT$Z@2zF@5W*~y=?C}QHn|5;zb3W9dIaLCJjDyPDoVGSWB5=EJ9#ThLH>FtFXL}vjZ zQfI^%T?IMHM4DCjGuT-NEks{&b}ytlHNIwh_=(8JpAHMIvkHP%K~+JO;2lwCTaH)r z)AkjA9<}P}xOKJrBRcYTVcy8=rOid@+{J)%c_&ds#l_jkyg5#Y^bk}WY0ciqrcIAE zhOcM}3+MX?qI`yVn)x%d8SJb+U7J6{!0D-(vraU8W*2xb&a@|O z{>Yvic5dv+-acHEjJ&7yNUE-2&Yc2&AcWD9$?by*?Z44knnS4RRcdE})kdIsRtYUi zDUI7R@~uJYuN_WkPl-LX<VAcsj(dDGTOpvtN<}kR1&l*{)#MN$gZx--N zySb;Uo0~%0on4z%)+nDxV+>sfn+rKtV`^ZoR?Q!3&J~D;MK@b!wpbn_+Kgzi%;f7h zZJA#a6VR6){ajV*b5G_+n0|&Egmn-+a_+;9p<7sD)r9JyZ z*6?7o8sCxnXvDzLEd487aHX(gat9 zejkUeC1SU7ff|wdyJ~k^t9Mz3N|JFTZYfP}smN$OnvI^8+IBsaBBs@xd18t4@2nU{ zSElz=r4E%R^rYEpBMfkAUq%JYw*0MBjf8UJ-_>7|!>bk;{$NSbxHtTSJrI7#UqeNP zQ9%QQ#f8Ig-tg2vo4q)cUxxr&D69Bjh{XgQl*NR|iJb^~nMTl1XsQId1)^v;EhO`V zeHnG1ThlfV6sBN{-BXA;cHVHs0eLQ8EbpU%(Az39(2(~RCA6n+s*76-TLvAYUdGuB z1kG7Ey`ZE0@EC8kFX)V32HXY+x9r%^pC3P5ktQA*rD+rs>?}#=s-r(|rz1X8h;g{6 zsX1&|v5;pf8%8W4R8c})CQjLw^d{Oa6eJ84CQ*2r<8hSd)qzhrJgy{5rD%n`x|O@V zY3D|YWiTLDRz|UD|L$&Gr!g$iX(z3VBNHJefys9!JM5C`@!;TN_(STkP;`w znfSTs>vqqCD|xObyDAPe9!~2l&nIsx%Bd|r7``IlYj;c!Sg`n?|M6ci-vIxP&!44) zz0()^mfd-Mc+GJC!1?(<{%z!Men#cNH~-?I_-s&gZ#2$}?D+-a!h4hD$=-Cu|5L_M z{27%I{?9L7{*~R94}V7g{Jj}}xZtiI2B3VNK6~Yi*(@nOxO~O}PyMqZ31+r%bNSRb zzUS?K*8GgimuU2Mj^6rvYo8j&+svr;sri|jAMHScTAJ$w3YG4E^6$K4C^ z>_2_h@;m3Qp0RlK?F%u2rUc;i2@*bH_idX6~x^XO36fEX1IRZrB^h^YIDvIYvX`VXdbWbSECimQoQTN|+kbLLaw z!KcH6C9$q}+8SKD>G7vy*Zu_G=DqfooL$I?Q6jaJq*WKB)L=1Pl37=n&J{R3901;1 zn0c-|uRkxLb#HWC>|=G1=kP$VbGyZ#Ko2Yq(sG02taT{#)$Hv|yV`0jRZme7bNi!l zF7JUFejxZ-s5d3C1UVfZ^y4u9nr-X5(zgs8+}mG}%v}{EnFHfK3z-U1XJ~WF|Igl= zK*w>NXWDXXYoQi9PU7)zC(d|_H;E)xf*=WkJ1L1G33Q{ou@T&N00hvDofJvzAh=1k zB~ioN1H;mb92F)s`zZ+WzA`_J9P#blk$a- zZDdHN4`uY{ZlacAZQ_!8du#&?+=f;adT9V(>N|$ zRwJ7?`9b5!uLkmG)#B&Fth-TGOu=VAysY7{Uwh!H?inN*BYrjzwD4!f3DQ3Vu`yBm z#4JMPYB_FyKQ4XC)iHP(h4aK=32RFTgFn~Dht|eLJijJ_SGHjw1H9H1$GU}N3|sc9qbJ3m&2nEKe;x-u zcP54qnln#6Q6O4TXjvxA20@!yt~vLCCF zWYtse!m9o_zeJp?ZQ?lHDqQ_xPr}2UMtH1`pn`6Q3&EbZZR@I`g0xGOnOB}F1hK-F z!OnzY&MFy~KTBf(f7S?EOGf^W?ww+I(s~C%5;Jo) z=TqU&Oj_Vf-m*oe>sUTIZ7NRUU_7#KNByQXPbV!$eoSpg>>%2YsGh2|=_x>cy?13(w>lv6vn{;vCwysblM7JddUzLc_-8p2D=Q>TJ!QQCZ^}jiYjV zZW`}5H6|~FHdB2MeyjMihR-B~nK_$t&7T#5HuGmdtJ3}Y5VThXZP+s7%sd)kUOpFV zXbdZw>@l_W*!m5R^B8*Y$&B;Wg}jo+%V@~9A@jJ9xhwP95sDuc50inC^xoVJo^5O0 zDWYBmb)s0t!&$g-;#@2^I#Z)NQs$E5r@^&QOVW~#UGe-+J5-U~Rpp}61i-%=L3Mdn zPr(+?&bU@88yc^ziG0@!T?p8|rahM?5Kuq|+JdVDy4%b9W~S1(c&yQ+}uBA&df zE26$i7y9jlT7rE ze#s87Lw6ceG6HH9x*la|#dt!UaB z*ZX98XIW17kwW}TD0IU6bfUos61G_$SAM+69*F0*; zWAQU*eo&7yvQ8*d?OrKU?=v_!Oe-^)LuAIQ)`=gh>XBRGCg6%2z5|F6R_yMgE{AM3_hja!a@T46lMiO~mSj`p9RQ1qNK=Wkp*p{=I={Zm)o?Hy^>u$~?(hL_R5RLl zCbw>mYfN0(U|ra3S%BJ^+d4upvQ>PfMc8ckIcxY#qFTJbSs`f4yf(``cr_J&)Cera z$Ra_;!Lx$5BavrQ;IF~Hv@Ur?dwNn&{`TQR*+UeIF?cw41Wn>Z?c>jt27E?DLeqWQC5yH-B?fn^1I{Tc&T$7RA}8*j~@!OP}d z6m9n7&*l#1{FcDkufr{XvkymWQFNO%g35H1rE9Q+H?9e*vqV!=3q2%U#Z!|9KmXNS7si{WZ8& ziI+}$sr49x3uBN`POJ3EX1uJ(^SDdhtut}1v%c0FQSmg$;^rOmt)YorS@nO?0 z-f3YTd^2M>awI&0=fw)hb{+siom!;U%lSeU&KMSc(eT8wP)dtX{0i?#{BJxka3h1qa%1 zsm5rXZPq{Y^Ha|Y)O4YIZZ)to+HjAQfnR6ta zI8h(V$8h6ZMa~Q5*&XSLPbV&I%CHYrX7SIQt*zBA;4=sg{w(6;YC!aqLg2ITXTw0A zpTXI(jMJ_Zyqy~?(Wg?DdU8{GtFq)j791xkr5vz)P=&Miz%F;XM2xxG z98uJ@Y)_u&w$JHH6yb4e{DNl3lFpqrd8%INLIMrSri>t-9(@&A7(};hTumuw%1kg0 zXTb~roZZP195X6tPNB&%muK|tTb`iU^y#u39?g5oT!^1}o(>ytt;m%c7B#%jl|A(2 zE+oEfDJ$F-kqz|VnQU0GA+gpVS0$PT`?c#;5bn64bmoCey`x{EKgcif>vqdky}L5# z5b|u|&&(2EfjVH}&q(484S8$QJZwy$&|IT(oyMzqwQ=+7Q&#pAZ0#=Di}_4TrPMkh z##J)#)icj5-Mpn($u+rLbGDV{VjR71`=)RIyFYs1GoR~h>HPWsdHn|E|6c#_wQCvx>moL#6>>Pvj57s_CPOzC#?bGu!JwN8(z{Il=xYfL`IS=ePaf^9h zb3X1~!k=f%#)1R!^RnNISoXOHSajHf-~Y}RzVXPnXExNjuf6&vfb`8@di|f@xbbnn zKlQ2e_xNq`XN{dvKI{DQg*V$;|E9Xi6ZiP~`|i4Xb@ZGQd3&1<=6gzu6$(a(+lE&L zfoX;rO8elm87XV3tOd*pBP;%_wkpB1lqU2Aoq4U#i<&8YXpGD*yldHD1PKTl2MOFf z*bx=9EX#NeQ)InTp$}i^eS2E-wl%x9c=C7jAJ}`kJa^Dw%i!hSvU~zVX?6kaHc;Xa zRdAULcV*l*&OEtyAZt_CwuE}?GORor<71lQ=W|~M_7tNGn#m& zv{k@0p>lSp^QG|wk3u_x_IS~jii$V?eLuopS^P-PMCy^39l_+}I{ z8;U=Vik}sKW@#{LWZMKc1%!gnh=Nc)w^vJTLGI27zBp9VXoR={+`A3boppFjs|IRkL9(q<9BW~3a7EJ#fNSpmy%p5p)K0bfe{rwcq=2e~R&Vh*^ zUcTk3a(kX&sQ|U+&-4V-!Joy?IWDYrZCLZB6+;KN4;~RcULW44)gpn$nPH%Kb7R_y zdV93u&rJyt*k!PSdv{8@8X$SUMen{W6r=dPqs zzZT!>`0&{v(xRFs{6KUt8my1RjDHmeRun$wq?Sf4n* zF+P;qix7VJGyWU(R#>z+lcRs;=ZAR}Uw zW6J!lJx`46OFdh%9ry=h1Mvzs38Kd@`0 zM$DxpPli9E5N@jyK{#Oc?7r=7X)Cd(s7qPeo}JiNvA4fQ zOn%_c{F$b}UspxWU{!Wk;rf#)3n?_*VHfy}e}$Pp8|4V+1u|#977d?C^d`-p)mFot zK~&HLC{l$|%u=VXGa-skA4n7@4X#yqAl{I&yw{aBbZE~Aw$;`7c$D#&8&hb`)Kit~ zu5zMbrX1nfikyL>ZIIrU^(*Tw3veXvNEA6Y1(e&8q9r&l9M==2WS%&orL5}7OvdSJ z@NmAT+SOd?gl6;nqVM3I_VmQYlt(G+OhIRP_DwkE3oqrE@%ysR1*-R@Ea^yE++bS> ztOh}2Vmwfqt!hcdauPIr8)#_n<@`ZJ|7o8(-=se zRZFmuH8=K4g7u$dyRwhQMVxO_eW8M&H8V#^j@&&dntImEWJi)%we;F!`|L|P9ZTJ5 zkMl+VbI5CSE#)riQ1hbP1pFBU4SyEkZ-_Uz)NHLNPF}V2s}DW&-LHS+m8*a8+V!`7 z^{bn&zWUw`d^UXiSs`cuveG|Ko+RH!PgK^R?;F=|{;&UW^FO`()+?9ZkvB%=9a8UW zo}(&gpZ=M9pDD#u^~u2o|E-O4&M0MQ@aL&t2sQJoqc@WW6Ag3_1QJ^=lm!?OY>(CG1&Qz@Mkl8R!+_uL9+?G z3}mh=$6QXN&a|*pjS4=iM)0f(4vd!pTT5~Y5)M*$Y(-udNvW&bh|Ysf${M1V7ME$G z5~2|G(!z!k7tR}W9xBTlE>7>wNNY=5Qy;g;ZC%oyun2Pu0@^G*))eEzXY|iw`7=Uj zZhTmZ=EMTyou^Q(g3kzkYVC`jcPxEAWmV%gOSfyw(7`OMKVaj8oKy)SZOR}P^OC8A zQm0hpiSvd}{|tZbHsG`3&k8=vO@#4Ms=SxVJXGdlHiB5XuRKQzpzq(=?OflwE$)B+Ux0QR1w#rTSJ#Lx4@&xMV{pGC>c`P!nJ?enOIs6)Z$WqC%GC(gU4%` zh(Bw>JaIDKuwE1CTLNdl4ik`PwaJe^H?0e8wnRYc6iKdK7gCoLLq)Cgyi{J5Gfw-`kawRG+*M{w%zj`ff(SK~SF1Ji}HOwk*Ke2yr}+RfB^1gwS62EI!6Y z_$c(K3K~i9*v@Jf&3hS8QgXqga#vD_ig88G-o~Vvohp1IOVp<$ zekKG#8wn$LyTR}iBQU0@r9feFbWi3J7msG2dphq766j+&B*f|CPWZE5fTLB6!slC3 zXq=@D_^g+cq0r#mp&A1$Ys2Sbxjn}ee9rZbU@&S`?+;hLP@+>}}bqVeHfj!1rK zVgh3eZL)ivVHAH>KUC(2Ie|Y5f<^`H2=zF^2*`7%Jsd#oP6%sG2o(gKG`BHrLBqz_ zhRusxw=E-@H!ZDSANyS5{2$w++tV#0`?p@Iah*Sw4~i5O^pSkgKl_<)7#*%f7&tGt! za1EAhuidg7;W{E!F;6!5vwGT#{uwAui*kh4V0qj`BWSiN*ACU9C^Sn}!IBD5>ZJjt zg-@yv!i57+j9eM=*?>#KhLxQ;NyDWXLsib+3Kw-E`o+AOLWBj#W#tM4_vXX-r>k9k z`*(OU6PwdkVX{F13#pwaweaB2^E#9H=xE05PZEK2OTr?UXHQNVkH34$#RwY3a?g>% zA^z9hzsJ2RsV-?HbvhV?z*eF?DMlPfn4H9UO4p6(m$DQMjzt)83_8;;lU`Sq1s7uUEOV}{MipL-*Q!dkY5sPNA>-V z`5CA=cf>F`XrYxZ+Pk}B0T$fYnBXN2&u3qL38=xlt+8C(wj{4SUAzMqZe|buEH2Qz zY-kh~QA!5$616j{@Mk4{Rv`N1{+va#A9?7rpSQ0|_-}vv_uMMpc;mxs*WRCiKL_#6 z2zB{J_tJ$AMdy6^{mVEWV`F&XJ?+8)nr72f zIdHK4!P=+FpFi$#l!fEfEAL*u^5#ode!XJpE~S5-`OtTxef)X(Jt5Ql*$?DuX5yFl zbz@a^2y9m^e!J_{!2X|%ar6mJC(|=9JpiJu0*h_g6a0D&cJVxKXYk>=d12L{lo6v zPp?nSTl1*nzPmmHfBtddUi>#O-w;C#_%q69y!*8N`OrQPu97HEeyOcCV9rD!f95h6 zr()nUw3%VGe0ofBD3{}bKX;Xj5L%ASFy-j15?b3*n%7+Fa>JsrJ2nIx-4#XjB!upk z7Il>rb{;D55EL9Vd=7hxb~kUgHzYmUY+KqKAA=rPl^5i;1^x_tZf40lszz-=F{!}r z*cVFV9IzDH41Ctz1VkHd&y0gOilXEv6PML)TGN)bp>JRMK#2=45st85B}?rm#ola^xkNZlW~ z(X+^LQe=?8o*MqFc(Ow7iaaZ|vnKFL_H15iCOk?0Jc@-ab2UKLgV3ULos8SfjGA?> z6ZZAfIgh*g@$qLrGmS~EPE4Ma^G5JKA1i!@65l?5o&Yq&II3Uknbgap9cXBA9SN#%2p1YD~ zN%&y3UwBzM4O)LmFM0n6MWV2iRpOqCUoX!|L_l7#~5K`13gGXyX&L zY}+rv+*owZ26pyC&{AyCDk^BcBM2=N+Px`uq+$om`TURa!OkpIB1AeMrpli+cJ@mq zqR>b3Mr!1@hqhU~i;w1Y6UTB1g`nA29HC*<^fV}R|FOK0qptqKH25=*nL2FY&2h6D z;~r^F2x&+VKMkdS_89tSY&Q&jxL|pvhKx(q zMgXPj6T%x3A}P&D#l!B5_zNYwuGF~Bf>LWJO_g;&2gf8+BF}lAkHhM(Ep| zy5hNng)KYQ^&i{`qK7|&sksj6t}f<9BxY>5GQBlpEy8sqz6t^>^9>L*3Gf+N@?`k4 zrjdYORke@=(x~~fM$n2mtEFPpD6Ww}_a!Y57Y;trA*(RzTKl}(^-J6t2?Gar4_D_Q z-bQKMgLz1WQi*fbCpOMZuROLpxVtAirET+SoWz=O8^d7?BM!%Wyrvc3<}3iY=#X0+ zOWL-q#bWw&r9A9|d@>anVh>g3aS7zfOle47$xC5PR=Ln(9BNOX0~cp$226++xSbT+ z>{v*B{`4dx^d9@-d~$!f)}jkCZ0Cn!~plplHZ=WoED1wP-nY4+dn(?5^P zjVEXfc0V=lF2bL$-Tc`<-2B_WeD{@0Z@+vV=jRXcf5vWta(f_XgYJ5bpg*AYM zLaw~|^3}JN#BNjk`QZn?W9H9TaKwHt{5JeI%y_|^e^UAC^m$Fp)y=3n(yre|P! z2J{TTpXc8<%gdiX8wG#H0($NPk0}0}U`hP1fBW|o6u$n8cjV7KzFt(yLj^q@cWwrL zTl^XL%ykI-SuGWdZm9b&k3E*L>e2Pf7q5QcGoOuH81<8)EO%KkLfmoqGw^xp{259N zD-IS0VU|kV1m49GhW=UYrC_z9)-Y!*puNyrG|yfZ?Jfa63x9?}w^Pm={|Y>iOPpL< zqmFhP0%^{rv$Tkiq+%ZjLlML7f}N+MV;a&PYs*OND%je4a4+?A5HQQ>bJ&n) z13q)`n2OLSWnX;u8s?h<8iCJ>Kg+FwA&}NGX>Kb9EAviQg`)GU zwah*l7kbhb-JgRVG9C2SS5r7B{J9XUG+2>&Ixn$fm5v(X7odOks()d;z*0>JNf7aNJ3_h>XA?b1Aw+L-sEWRn zFcrGRo21O{^+jK5$Y`X5(LoL39WW7yjlOzzhhvt8x>{YV$`ooP_GqG|#lD0(hC1NA z5|-IIs3ABS36H>^$3f6z`EwwGrbQp2PP*)~i5^=h(ZyV8FAl?z13fukN}CiVe1wxy z{Jb%FPJ6Cn0I-jWzDN`9M|Y%^m`39|_5IZ9ag?q#2b|uI1h7Rm} zE@^pf((={~PxS0b94y#2T%N_heY#BzL5p3yt4H3OKw@3oSzY9*E&@c4ROSxnZEfAK z`dMpC)0Wk}`?jGXHgK!)##UufM^!F+ovz91E=X=jUD)an{!D283>Fp|Jazuuk{I2T z7!7IE2wK&l6U&IPA!HTH4)}9oOphT{Znw{&VqjPDJgl3W9diXir!H&DaP;om*;|^^ zQ7)G#JR%>gkgAKk2iH{Y!tw$qjsD8)kwd!&oGCq9R(leWI`dg#LydG91WnCi(6Iq{ zp~?$e9LpQiR%8Fwe=rk&=?=p~qpzwEa}vs4bnmfuZhW-WzKDyZu7vsB)@TWv@Mr8J zJjn~;s4YkWz^zHKEvZX9uJs*H?!r=xOC41&gR3U>z8Id>qTGIRSI6F@)=iJLB`p#v z>*LRpq|j64&%rph-{kAnVEu!&8~SGqTV#5f7MbU<{2AT2w<4iIq`6vSsP;sDW75vI z(`D!Sc5$m?`6>Idp4_bie6w60m$4P}1*Z~nDE{14#WiYP`nr{W`o)L7 z`L(Z~89MjIjd!oV_Wm!fQvvWMBIIEH8^3)0!zo3uo6T_tL3a&*{-6Kfdw=!H+kbxf z-JhQQ;OaTy&sQ$K1#SgFOC@)o3$)_T-2RLkQ`IexI|z;c*2Yo#XA1q`|NP2JZ!cQ7 z3I2RP{?9YMHTV8mi|z|ua?fn^&n&0;vzaYxX5yEa`heh50@XX);-d7*`>Y|0qE?)TQ z>o?wg{n~qS8F1sKSa3|o9i4&S7Jo(wfbtpstjII@<#X@+=&6@y&RQ21zH(mV!Y|%^ zcfykS&lG3l|KR1%WlCY<(?3t0KP!x^;Im*=Um-#uGpHF*EV7C+@y&q8QhS|*O*n6` ziT0k-JZ^tj(#~B5mdFUC8_Mz;OLIlJai{=EGs0%5GC9W#wxwO6Y)Yl`f?=C+Zvx{L za7~929PJ9)4&)6|!EoQ+`i*hVS{5~;(y?-%B2pP2Yn|`5#HdgX8^C8F%$69BFYvDb zLHj7QkY_?v(;!^xw%cL^UmNhbiONJtOWd1RBSjuQl)=3!$|A1+IaAJvlLelO>f5M7 z&K;i$ugKY;?%XCQOicoZH}hxUvzI@YxtK$4E~sVSm%G`s%hr(c=<^8+Q5LCV11y7W z8)0#_Xl`m0H-`GM)l1PWF?fck&PJox8XAvi!hELeC79ZXsq$ydnS&)0v1OljdZIoP z@@GGKEUSL@&SO{2M9{&2@U7a%=g%4=t2%?a z+Tgzt{;XuuIB(Qj=76Aaer~sfV>Qrdky?bOERppoOM7!S43=k68VvqCd~Bb*7=GCG zLiwJ)^fir%^HD)JB}6LyGb+;#TbK%uBb;b=gbRiCxfv)=18Mj1=P^bcAB8^~@Y$a~ zr_An84ewtcs$vu}n}Ks`i0+`f34%_ZrTDWNlcf(q3xziGXUR=wASwqnd)tkz{^WTa z{!EQU!I)kO4S%-I5^*)mc|89O?^aWpLe))UXPx-*XK=j$XNQD{eiLSQB!;8$R{WWS z!)~yL)^A&Rx?=a$ALXAro^$T0+_Ts|A9tQb4(&DE$ft!6gAT7vbgn;wHu&?v@qBY2 zONKcEnFGnQY6-@lp`e85pN|v-(?2WzjQ$z^4D!VS8p2t-VMRUq#*K^H(_;H}u5913 zxOL;gmed8%$R>MKvn`SbD0SA5di(4~`^;7wp4bL|20*S?OrpmZ`0|@^pWc9{=+%2UqR5gUQFP; zp}aV5;lGhDie&@vs-;*c*W^wyMAbZSw79K2N30%B6r<3_c=>e6p7tH<_-pv=6H&Z{ z)VyVFU%{5)%A9_%aJ6`75R(Ma91kQJ_&Hb&RW9T*0}1p%rR&_2yFFXvBU(2--dnU~ zurdb{-c^~8ei(S$RZ~F0)6-Ao50>tz->|GXX#p0;;=dsXdM-Fx^v?+rAl&i8pu3`c zrUOeOV9xMo!pxsFLDkGtw}7Ul@}MJH0wazjiU!WdD45?&OLA;|QtY#iML$kiS-U&Y zvp*f2OMQ+0vV5@!qaYns|Ede9Tj#C>UAoRxciTF5(o)JVx)WpFU{Awz zTETEYD3?_fzmsCe8&{)(#tjVf4fN00dVn{%bT)DlH>Fw(2q^<4QSAGiOrqRRT%I8JY1NMgWeMV{4R$iy1787!~i zv-09#6IB<-sUT|qz46A)pZ)BuH(no~Kf|TR)h$oZ7;wMo zRX~lm%lqh`U;D+)|Mp+r`wuU@1%JMZ^Yi)NaD#K{+*{N7XXWexeY-+bkz zw_+D=`21%cgg<}p-fu+Bn7L?%kY_J{{(R`P{#oPSV7y3o(244)SN)Pt+c?3_ce;Ig z2Bv4=Q$7RQe`Cq##rzoy=*6E4jlTck&@X=P>kob{{NYGXd;j&<-sZaE`nC51t^}r8 z^c|Ri-xhy{Jpc5{hl)Q#o`3qnZ@5T1dicWEzp>!E-;136aOjt3+?%pu(R0N)o^pdf z8wM9#rYiFdA<1IOQ8Xq04b7j;@EPJtD7CZV&%&9@a=FbR@#D|55L^iZmYX2Ycyv@0 zv{n{^qtP=fR}JhnddiBs%8KPvK+t8m4Blca5ylASRb09hX>k#?4qFa7xvLu3pV7QI z?v!;2E`^k92fgBEi~tza%pDU~?C$tQ&2h2NX`;!pkf6Fcp%Aq2XWTZlUfO`qT=Og8 zH1L_y?YsoqoV=6*?j3uq=ML@}DanKnLy5VqE zs-(__<+WII_(Bl0x@9n|o|QX?$bJrG_3qoAJ&3ro#;(tlCi*9<7hse9Om4(E|T!V z=Z~2`1DVYT+RU7_4~DtX$i4hoVdP*e`c{zHD^4D-+rKUTY?e0%%e6-b{JG8&PT;)J z8XrcnHmTPZAJ$+AKWU9>+`4M;z&4Rb9(DnX;Lp6)eWBVpT)eq;=j!JZ7vR)^3$*B# zEl6!eWZUfs>m=-gpnYMqsCHwiw9r1oia=kE@K(E!a0wsxGsM#3Bdy^oi71~PhWSR) zOy#H1oie*e5$5%?1u3V61jaz>?7{UR!6TFo1E6ULHlx9!lV<8Ldqf+eXs?U1?_9iQ z*TyQESY+E?pJ$)d2K3S#3OgGuMwvVxg%-$Z>^o}vY>XzWz)y2PlGUfPiNtIb0#HSy zO`Sn0HK@hdhMkDVRA!Nx)LWVGhQzspISDTx$$06D>OO^M`*_h}HAy zqj~3_D!A};;kgrH&;gnrIgvMVJYR<@I|zC1JCWaeBES17AZISodm^|0xR^EzZKeug zKuGDpTZOsWAUIc}SF9U!4A;1Z4?BAg>}qwTx^of-_isK|w(Cs!uG1x3`}d`FyBwa( zc=xU+nzpQ<)ZH_-sFU`PTKnuKqeLUK$6R$K%aP}02H-7430d+s0Wkr~)mx21epGFM zhUJoDr=Z61TaM!+ZP09Rz22mAz%_O{VvbQ=jOzuWO{{g!ROg?s*z4Z87I==4NS$qN zL+X-_U2&AOyA1ZPDfS$eVuIKRtHb8M0{P#7lfvWLK-1nOp3m4m7+X&tE*z@jA|wwB z=#C@#eN{PU_V4K2`UEap4XMjIUF*?5Ga4Sz7+D~erc9puaBgP}<`vl;S;^1y=Px0; z*D<%p9@XK9Y)_oqY@5><9|dt07VU@%3`n)d5ycY4vKdfgysW~^rG;1;7SP(3L9u8= z#W-(xY*FZ+d)6=JWhk7Vc{qM5Y4NGlRdt)!HtumWW~DXdZgub9(=LVT@+gZ;a6tmJ zgh&gNrn&?r|M2*#$Ua?`IlO--4$rMSEvGg-R-3$}(JpQtI5~4J3Y_-YV!Y)D(^hq6 zr+}dOnq=z0#Z?7;r8#E~WeqqtAx-B>%wu2JEmaZa962wkqh}OE2F7+K$T$=|bf+xo z*=;@Zd; ziQ&tkMrLqHbS=NJNihCArTz*pYX(}4oj)sCk>TdB@ z*MCENlsm^?NgYEq0_6DvK1G(VeITUu`pJ-f*lq7vB@E2#Fb@2DX^D2FnBY3Tz3suem*NufP^_|6qCG zUV$ya_BFQ$?iJW#?jI}<+$*pp*uLiWz`X)n%>9GqfqMnE1lxBq?P|2ZG?6wMqobi{9wC*@_E_k!|;8Ix&M(l4}JgPFMj)nfBb`r zvJ=;Cym#&O5B~YuyS(w_yAt?FR}>%RYUGo*?~NOB9mU&f1lLi5qp#ik$Nzovum0lQ zmoB|y)NcL_Z;kQ5nkxtO^3;?rc&=P}pYUFHsjDwz>3tf0@!glNeDLChcdlN1`^5`y z)l`jq_3I&D{gZEe?_1ygqx(Lev^=Jvq!5KLAQ#RoVThJRoh$rVl*Y2@c0)wSV?zxk z0%=sxhE0d+FxqZ3s#UcKo=oD`fe}=Txu^NFbbCuhe)FO1fr{Lr{prnVtLx%pc{#B? z9#u?CbKKmM!$!vvybW8n#`WZGK3zr~z+7>A=5!2uZ5*~SGifa? zYOEj%nkovo$oER1jdFyzWcQYF>sQ!YQPg8tUMmL@=sNcZ+_=eYdxf*VJZI=o2KRuS zS;?NAagC`f>TC-eEyiKQi`BE%Gfy&6cv&wMB4!CLRwL+5BtoGv>#)sHgjo=`)mzYz z&fX3tyiEW4_$ay2HtHTy{jhbN+;_w68x483J1z=KYJ!CJhRGpl4UMOo2;z>9B+Nuw zwI~j3)-bC+<`#1v*xx*knJP~{H=}0u(yN+9lc+{DrtT0dG4D9}ylzdXIclE>AykXX z%`Hk79muh@URozgGJQ+KXTJ`?nDe;p_-`ow++^@)Pkac`79R#@J7o#4O^xl$v7M>P zICE59s|SJsug)CFKU=Z4FF&nm+oQEf{G*=JZjXRD1D|^hAPf`kN~G>v1mK9;c9NsB zHSuS(&vj6=N8-#5-^t*_gzA@t6hMl+ML;sKLek={2BN>N}kEbgqb`K zrG*lzMJEP-20qVH(UUS$!T`~_YM~E4i)fZG^JmQ@$4vtG^Q_Uri=znIk5R*-M?tij z6ElJ~f4Z0$8-!UIN@%dG6DCm2p-R+JZ)GUTQ1)(Hapl0qpB~$L@kh?#r-eWFJ)J*z zq5yP^(wHB^+2eVqkL99&Mii~c^Oy}l+IZ3CV+(xYd{^1}wR$v*7tYQKL?Zv!?99rkXpT~1!){uGJ1Vn6ZXBD=|P>MgJ z@Ekf^d=CCxmeIQHvAX1Wb+(8)YZwUHowlrZm+kD6dr&e%i6wlfnL&i58~j-v(kOp6 zx*^{kt}Gm`F5<6n2g2r~1%1`or}uC5Y&XMECS_EHZ z;4@2@q<3jlHwMu|GQ|g@JgfgudUw(GcGpHu+`VB{YjP}?Lm<$u#28$r`)%|40Hjtd zJ{GoaeWE*W12qJ>dZAV_0pjK>7(STQot@UUVKo;{92h%luC7i;$gOn&5B(8H<7w9t2><5SW-;`1dX!?PvpBwv-%G1?o3Z;OIwK;fRhD8Gq})NV{&9< zgWQ6A6@2dgnE5j_m=obc6^K^+nGYote^v;3EPoavO}i$~Dq#?Fs4to&%$f6I@>wd& zj{bxN-F(sZMJJP%G-W0CR%YV{1OM-sQGgrmzOwfAIzo&)kl5R{@sc3 z-~93)K6Kxgp7~Mpt3Q7W_-wo<3w-|YwO8N0Q+H}(_%ra?7n(nlsL%Z+?$fV+_&@&c z=AXav-sOwGx^nT?xJ+>C#Jvxm8!y6~RgB&QeR}ybcYl{IzV*sa-&_=%27kWiuDic~ z|FdH!u6O2Fq=RbeP%%8cAy0iQlh|NXF)r;?nNZ{hz z#0wYRtg7t$%GZAIhhP5kH~#o*U!HOIhDR4SmI;3r!v}*uw^41-7hK-^VO|Awe}|Sx zZp5&n)QJw68?KhL)s15QyqMyHKx3>b8tjXkQ&u&vf4n7aO~+PS_ny>l=hn`=?cKTC z2lID!XQsI~uH#+N`Z!U}peCYr53jN!_Z5O_TY&tj-V#%9UD%Mg+`T2P*SQfljQ*1B zt`a8}A~I1-CgjnzLZDa{%v z$>=ZME^dcgpTJLm@`Cl&c}?-6;>J<~#j@E?@IL)P&}y#aRy>%A6HkK3=Ol-^SQ+`b29u{JRfuzOy10&6`fYI)ieggU)#O<|U^bktZ#)>SdnAuiImt)oGd45zlgVhb2_pX^htd zcsPR8Sw9(R7dp*b1GD)aDQ?IE9p0UJeogqZYa&{bmbCAR@7%Y$qudF6?mtqbVX_uE z2O?!NXEq2YkW<9Z=63U5X1wf|dlB(i1Z_A!=Xcj&&Mbc}@pV62?K*pKN5h6C^^Q3$ zjtI_<{}%YG)RwZMH$90ez3|TgL$mEc8d@!y=T5vk&~jttVJyjwMzPx9Es35=xN8CY zx%+St{8{wR)!D@eStgOI#ia4e+WAQX$klQp&PL;390KSPg|3YsV2c#jNK1dO2qhrk`w51dy*Dn_W^?DN(r%XeL^%vkejzY!4vs`(ri8m{*3aRSsJd& zKV7NXKz?Lg6f<{JWe01i5&5O2kEr$^_994wSl?902G50`M zk4T&U%!f+%^te(mMQKi4?6$?C1O~1U7MH3)sB;2}DCwesfh=CTij_RN7^9?@}Veh9B7d58addf2S?%>aWdV~!V z@MnJiZ3nV2Id3Q}_{jlR{G#YD-F^4W?}wfp`Kic{Z+u9dAQB&lzC$7eYY#@NfS5gO^@>`|^c1U%2!Z{2ATO82Yy{@P=4TxKeBZ1E4?H~czHj~M{a@d{ zA@lG4|9}4ZYwx|v-}mbuO!H^owa^{9xZ?G(Ao}Nzn?Lhbnje3@a{gb+O1u8(E8l(a z3t#x^AN}E19=Lbg+LiF<)9{{5wRO$2(NHPvH&C-lE;^T}kzctKiSg z*4PH?!a7`_H$2*v?&xuC;Qpv5fBQi3?xBM)URQs4UVmxs2r8XJ*?sxjJ9gXY%jz`jjQ+Wa6^=E$cj4>wAlK4V7?1SI~Z60{;o0v9l^NDC8XFbD4`s6ytA^K;}9AbuLby5Y_-v9LK1DNoQ6 z$dErui+~k(P*{_2iWY(*G z{2BPH0%ArWct-fz5-%7H{|#0ftq~{VBcA1L@eJ$vs%$i+z12=JK&Z|>b1e7DG1uvX zn>{-puXRKr2gU6f&a8lNZ&Dc1lN?D1g-#ArA<)<)gx2ucNW>S~r-BZbx^IT_hR=UP z>b?cz&)vzP5{B~z@VVEp-5A)Q%{ONEt)FG4&=6)n<{Y?crqF%s8DTaK(o`*kKNHG@ zLrI`PxEkKVpS`}#KHCjNp3O_eiWN)-J_~=wk%Ku`F~*%ksh~~d*+9@rcB|^&DGEI$ z{>;&8?5q-f{F2~sVhd}G4+TYbW~@G6x#Pv3HsQp>EYwK3PGPc=Dcvs zdFhz*@=@o@$DCKI_M9$S&yV?eNAxr6#Q)ro-;1$xd;BaMp3y%O@Mj6D{4W zNuSoZnXPfNaG`063#p3>ZLmryTmIZMCNFK?9_KFF;XbriB*%xn{uO2x4O;XI&6$B< zYA<$Fx!z>n#g94rttteq8gb!}dV)vus65zpL>Mvv?Q~56ZomV%>pA!O1Rf;K;kAV} zYb1X=X8>1;z93V$~2pn=arRT7M&_%jT-`$!>2i^3NFXY|kX z>^h9A#@@mF_3jNzd10rHzhB$e4j$TL)E~rrL+p;xSHrGxfga)sSNY!F+*HBTwkRMo z{JA3`5*978Ra-O`(5eujS_+8vg`jDTqfPJ`939A?l@EjelD(3mJ%nLEfn#(3_O(~` zZF}WN-kFN5fvOz70>rV(jYODpxv*$uyP=kz%6urjfO?=h8slDUxA`pA z9M1JzhSh_b6Bj8g3~=TwsLv=%{H|@$jKjNTyysPywA8)b(wnyh^euMWmDCN%byo`0 z=G&JaRVCv5oZ+ghzQWBE;NVIRr9rr;<4`Ot90>jfh%Do4d@xP|Atrp zte!rU@Fc=NR$xr&0N=UYort z6C%;Jm_E%o{o1ee>&TFrG;q$cq`Ho##8ISdUTl|@VgK|NFt;Z!)&~Kx)zI67N zhYoc7!I!`Dz(WuHKY#cKU;D!SJL4Z4)jt~^7oRZxjEcCIdOC-kZF@IAleGF-%aW7v zi%wZ$PbMsG*}O*T1D2$psdA#{;g+huTwpJ?0=ZWAl**DfJ^Ra?NN(sX_cE6GJ@L^* zNBle-q_K%UCiDjPQ^-yaQ3=7uZwC}7gZa_tI!LZHa*snoj7n{ z=Sbz=(-oN`hjw>6lN-}koQj`EA8|M_?4W}o=wL{BO6`h2`ypj*$6;<)B-z}ea&!Af zq0NE&n)$QZN=qOyHg^l$s#?Y(;y_F1aazm~YTOvhJNs^jNT7QX!y(Uo$>Az`Qo>b?LC{cWgwRyGbA*{=)R9BiE)*gy zCG*VP%=%}gf>!*wCnbykJ_~1e*9Ulnvcqy zkAs~J7ZKG5jXGrYRQ#-l_4B)&aTlw1zVNj3(vR}aKb=Q8LijBd7x;`LbkEcIoloas z@{HB9nL@*&HG;;JL&0a^&qu|+<74N~$BH1OIC3bnXzJ@xkr3Z$f*Oc`Xnwtzav+Ds zMdad%g3HJ9UObw2r8*0NZu`zBa5d+#OD&ZI<3gI^W;Lywi6C47XXMS~9hUI+xKK}g z7@}xG{L(G(>WBtQm{jCUiFI#Y)ww&qJ1cRZU_&d4aMr8J^BMlE;j^@0OLD~3U6akfVkkXG^IWBKuyBiK$Ld-u zMo*!@=PrCLY;&+*=1&ZNvMCza?@EJFj~FxAemEB*YVha6fvQ6B*{Cc8L~{yoX%(PX zHVsr3i8dHgO^L&b%&yFY=A?zZ-P2&3*Sz_$f&JSN-(pgsPE8cKSY~0zakOxx$~o}l z*1FWi4R&0h=OBUZN{BSTGF6YGI&9uTgsL2&w)izHUtg$2!?_yTH6dFae3Zt-~ z(I|e=V?&%h>~ry&7ISH%5(HI}u}2=0?sF_M z94*8JnnNO}#@KDtJv2U!PaF+}pl`{FC)q($V!y<1cVIX{qZcL{NSR!R+TCw2Sv5SO z;m=Td!-XRn{W+(G-WzM~=FN}y6l}q?1W|;cd>+G}QICuNhL1ms627_+zq`iD{kfY{ ze(<%g{Qlkdo;duIU;OOXO8IPH=MQkhFevmLljs;XTn2wOoS&5i2VR8;qQr&c+K1O) z{mqTnZsJ?`fBxaazjztjjkjLB{LV`+yf=nFk1C(BfHwH^CF$VJRm-PfsrWNz4S)XW z)nBcCeD^eeRz&Eda6&UvnjXhI8^Q8V8)pkP55d}}=O@_AsP^gk`DDzG&*&+9;oai( zwD{hT#rMtTHJqs5|KYc0d_5*?$w2R=SFgQ$cX zr~Jv|&pn4+eNSf9?@E2jzUs&Jm9@!_)}}t*uz4+)<=7Y^u?*ysUZimmS5Yy0VC9 zDi!iGJ+Ht94aXyK+wI03L5dVg3qm$QfpprrYfAg;4Jrdr8$EoS;Ki- zdv`k;Qyx8OiG`et*N4?>_zZalIGf=!vYC&YKWl?%5)Fz4K3k&*Rr^no=Qg9TAcurb z`?-XL4O`aWgxOz~f$WM`WzmTZSG)QT>}uL+dDa$la@`yTl#=&xQB&f{Q|=t#xdD70 zR}^jL%x3azZVzP0Q*ANBWb?kN-Gq6)#MsB zF{U$T-MP}Omycv#eLC;T)A<)pK+O;87>V3P%p-o;#9%=}6wi zs_fx?TiW)-pG;bCV$JMR2@zPJV}=Y^ZnTE0z^0~oU1-ai5Q#VuJU4);6C#_F=CyBH z)|(kOQkZ)Bz}AtHoo6cdo}m&V7#spT*2x)EJ28KTGb_~0Qd4N%Xok<^+GN8o(IA>c zvuIr0d4e!hvv-8I7^-rpjyF`a)w6S5tsP>Cl@sdsaAkIl(zqdRj@V^b7vLAsm$!bT zJcH?CN~sbEhV7{q{!EcULh)zALn9wL4R`IYE@CSX591ChF!mqX-n?a1J+{)eXnZXi z*DoI^*nH+N6(j|=!{qy_sL5yur)%tBOCjB}K!Z+ihM8Xavce{!sDe;i~NJ!%pyf zQBSfwYx5vVZai}NQY?+4-Ov{$lozAr0L+MO7%IEe>4n=CNHXYzl2{;c3LbpuH_JRrHo z&Vk1^20=?H!&s?K!iAq#0_}YyfdvY`Ox`c+&Pp~sXQZYi?>UpDHifxOUZ7?!WI_U;UHrwgFZC59VwzVd~U>Kys&V&Bo==@4tTiriwRSyLs*B zH~+_ffA{69h@ZuIei)2ksTv5^P^{d*EJyE$05g^1!_UTY~L7nRYc=;Bqqin)?Kf zaC^r&J&t)+1M}(m37ivi%k=!1XCp8VHb24mbL4~H|Faq2nDvdYXMfxRe}3baH-XO} z=sSH~ac7^B|L%=80e_a7fal)3dP(XJD*xv@$e-17fBc^bDi5N6zI^sy4({)~|G__< z@xX&${{1ih=@%c|ZC(9|=g-|GxxI&6Eje4C-Fi(6Q~Zhmuo4CM~pmKc~bo)s;)Z5RkzEy2-3 zq=Wcx+*;T?IsLOAe;$=RkH?=mLX^)<>sNN|O~MAVzdVauPUeB&P0xPhaOF8|xf@Px ze(a=uAqE{EAAD|#o8t|m{-9PhE9Em-K(|bgnE7xZk!CAE*xY9_xn{_I`)bCklW}|M zM%_&%nj!nOkGrZn>jdDea}qOu)+6{ji2t)WRGmR{i#flg;MuRkxbWF5el~aDMf;BU z2m)h)W*}QaXg%()388qv;xiyM*RX)L&28DTVrc({3&(TLoN%Fi?ZbTIxbwnOuFFR= zMh>KP>{`{F64jO%0Vo#zbBZ8nA;3gxxC*6DR$67BZdrUeIsnl|cu+*E7^{m0L8}fL zT$^?`oHq>r4K=>kf5Z4_4WCKO{CRlOY+__{$he`l>Lm!;WaSaU8DYesLQ`lTg2vZ^ zT7=$;gkyLw=GCTv?wZ37IO|m(c?Ld9G{?_W(L`cMpuGs%;MIodv z0xr!jgcwqBTudrS@P|%{J~9 z2g6Y*Qw};0)fC__ap6ebh3cH4{ac%Nt$Q{l_E=o_Q|rQ?UKdLIc&#^nvL>W1A?lPR z616aO26;Q+B%F4`68EmvBl|a=t=N6>XpZptBO>DZF!H+h=hZu6da{!M;Dg5G0A?9V5Hu%F z*}fX&)7frU^7AQ+@asUE+M5v7oe%~8#F2yDVawx$V=lhsI+}g?SpKX*Gki?y5phbrIDYu?QBA5s@Mj4gxD)852g(XhSMM9-3MzYj?Z(IJl9#keQM|dm4hhZ?u`$&NsYTem@v;7l z#NGqDdHURQq@cZuhyG6H84bYT!OZsbBp&ED+ZVSd#C9jfs)~f7-%g4_)(enF6wN8{ zgc=ohb7HJ}+nNq%>Oe_4kF$CF0TLHGj;efjO%X&LBF%%65sb?7w|cf)-Kmdy5|;?s z7MbyUai}(Iv6&e$oi>S|bskJ_tmt&$atsy@u-Z_g30U@pGP~xCs$9I=@WY{1(UJj_vV7#XE;9a{J2Vg*&hRv!Q%8 z^Jg9b4Bry{JksYgxvp`&#Yd)>gwhHK(#@X&oE~amUr0y*=zo+?(9qy+MwJD zKBIiTasB4c{`bwl{;M~C`r@zgeCBougF)bP0Dm3}pFgeoXC?>!eD#GlEb-ZjKU05D z`EQu(4{B&&<_W6N+%lOwaIe6Y>2b_6@X44T^BI|Qb#{SEbDzoNfg^mBc?%qEGRI)< z6F9>3@l4N;c?KrVKW)FCK>kb#!q^#)M9%o`_aFGyH^21lefbqX``NEv$9HR*KaaT< zx-+c%Uzb0Rs-O*HG%61&{wyvWSI)h8=*g}xeBm22?tAc$9(?HAfApp7WD81NYUFuJ z@>HooII52E?3BGS>EEGEqGvA4YdetLR-E3we{bKREb7-_mqEdFp`eEB*+U)h@?uX} zQCmqt=b-{znn`GZA%mlF@aQPm`P}+7KejLbiG6AFmUX?ZO+yDVx#!{)RHhCAc}ICM zOG*v84;4za!4fX!CA>b*hVmKsOfb0GBuhgV%@KB&i`52Y;s*|7VE56Jlh(GwTA#cM z&2vNCf|j`X=z_Q}Yll3?;dc@3NmxL^!FH=uMI^Y<06X(8Ff{m1@n@}VHiK*6b9?+e z0=s6|G9SkcwF<3&=AB}#e@3nJoMi!6fY+i&YNSYzNT(``x+{v{_F}48nTLw0EhnX6 z^P>&61@-G9r=({FDNm;VD13%O`}ni=+)#;b50?1BAp`!I5-ISJ&?YO5ZfRUed|HLluu+(tmOA6~xYsu?evbFbjpr;c`8BMJC( zw}tTXXW(z}YV` z^Jfj8N#M^KK`R#yb~N*6r6dPL-yVPNw9RUZ{~$2=WLO6sSCUItU=s+ zwKC(CHgKeXKo1Nl1>C`$aTwqLlpMPAuoF0Jge3h(3sDFUNY%pJ^T+bf zRcH4-xz&@C)V4RFJu|_R8Q#WwQalCwCsAKb@v)bb!&#DuV{n39e|H+ zO%CIrF^0qWsLk8jyl;0f{_MBA z-zp!c_%rSNHR&ziONF(%&5xd3zv5)dGRh*HjGtE4|!?A%Hs&c}O4dyJOWkMlwCY%#D3KSN>pS^YyoX)=Or?x(Z zu?emw)FTFso{FE_ot}WF2WnnpLPQvhL2;h}-Z80`IXtlAxs9t%CBRW*x-4@$Es;P% z_%nnVw%lx=XI^UT?3ch}r_7%nQ9@Z0qKIBc43`R+E!S;a+56;nPg%OB+QrujwgoBo zRTlSG6pC|*Aa?^nSBd@^X|XJ8idZ6(20>GzP67lC&nzh%tlG!PdiL+GPq)`@SV28O z@aaI(0yN%$XuP0>AybzyaZzX5sy^4ozJq&!#*lfL+Zu5Z=Mn$#!Mz=OlBna1$wnIm z_zV*d1EJ6FrmUf=Y-pogpa5GCHwe0Q^JAUaDL8NApT^J0a1JSGDtEOVE)C!fZeO ztPr$FrUh<`H@M=@Tp2beENt7b8l}XUGMDDheh6CWpLtw@cN|y3?y3X(cWesz=AYhk z*IhZ8&j0y$KUd}(%J~`djei~ftmM|1KLej%zjpKbt2h7Q??3#Hul(}m7p3MPcQ>lQ z4KkaTE`R8?fEEd~aR;Q7&!1xbv*ynUR;T9A5i@?M^v}!h2~k);!w@qw`6xVXdK~i% znDf9{4Qw&@50(e+71$DNUvqolUV$y<{!`7>Xo1V=anuY1&dlx2|MWN$|DvYn=eIjQ z%kK%}Z_VO+eEu7(-Ww7-V^;M2Kb-l{cfWS;*LH8o`G@~`?H9lJHIKHDKu_zR@9Yfx zcKNem{`~F>=kb4j?}hWfELL`|f?<5AJ{9`(OQcMH`cw%L?5kx$TE?6@LaS zf0Fn!=Yp`Apj5iDzvwP?b(ZGBd%F$C3@M=w1O^o2hEZDFQ@XFGteEf|DgY@PjYWOs zg`VQfr#8ktw>_aXYeUceJ^dwFoh4Zmi|1uV@o)w~9~7|MRmLvG9VIf9+E?*sY@Y=_ z8-~xSE+Md*&ovGS4RGF2x$AsI?(n`{T^T9O8`p3b#=EGhR3g|}6&3_Ii`SoZfg->j zycP|&WMD5?I2d-;?PiQTnS4t8xjx=&z9I105~VfL7(zB}T-{r^6{kl`MOsQQoZQz_ zeW2|?9+S)sQ6CQ5uOp?v;*^f*6!C~`W zY|>cR+-)+s-jT%I-;XW(;a|O%2Ew%Hd`ii<*x8Ri>pps9#h(pRXyMO+w0YddJIkNV zI9l`PuJ~{Q{WHwD!4_6$4{NfAw%9^D?crSs;UMUC`<#~K`7N85^%o_*{7l~YALk7m z&p!W5!Nq6t&Yj45@kiM&9Ny8L`FK-GRC{VvcWMOuxj$w0Kq{(ZLp-c#uunFOg|bpX z>!mWXU{$f`Q6aQX5v@EoAlpWaYM%87D)CC7vHmbV%gc&^#=cPg8{^8J&5a5>4{e;K zLe(N<5VN3~oD&f{XoGkIqA`W;NPNWOcvyjGLkR8FLJNYn&Gd5V03o!2jxi7pnSei! zVbMPEvsOW?9hD1*dFjWx&EjV^nODuZakP(6ND*g`ChP1vYX}|`I8mHJ4GZJi{@92s z@%+Ipmn+j>sL8r?H2d;#=fx9Fa5T>*RLJTH=amz#{?eU;mFef6DnM!6bp)|=0Wq=u zSz~0Kj0>O5jk>2wK%<8Lvv;Z7C!o+~KMKPJ87E{3ptN#|<{&}PxE!B8oO1?yipsrb zD007DOhJS!!zSV<67f*cJ(>tAFLgcvLo%Vh~6 zga_g))lr)5Daq3O*)Q<}&U!U)d^X`H+>&8`${uq(e%>?o*gD4|%o&;z#O8uWQ66gq z(Vh_5W{YgKMe^XO-WnmrN$pWhw&=QqXnZs9wWfmJaAi(E4D)Caf@gdo_^iPrMIvUd z#_*&7F)e2eVnswcbSR@eJNen<#n0KIniHcK97|{Pz3tnc7(TFj*r;R3TqzwjJ|3Jn z5F5*s-tx@GOvm$%#r1LXj0eZ~8%N=c;ZB^}n((Xt+E=0uZh^D4tr)`eUkwb*gbS7|qmN0;%n0^qp`N(uJQa=Y@_htIlLz{PrJ4N& z8$8>dU_uZu8{+4A?a7oQi~*T;CCnF@ZtA1Mxtq?G?iEww!vz>P^8#AWk-|ad_CRJ& zRw{2xfuJ#b79Wp9uRPexV{taNNB1~5YjK$dbYtt`Nw?$R!3BoYeJ*nu`fd1gfxA*v z(6~(ZS2%H*#*3q8yT$ETj8z54#_YN6bC_h9t#X8xM0svw&|%a-)FNbn@Mr{RnJB|DorftAG9aJFj1RpTLdT9H^Co#ME>^+aHyiZC&5fh_{Np8J8ZWcKB z^f-ZYVs82E&QCCoH{Cux1Jg4wJp;jJVAwF4~IVR zy>C76P5bJUmtXpS(Lew4#{1L$8)GkorgkYc?!Kyy^BYuozRpWz?+cEWIvO|s@)fBG zh~b9Wf8*-;TU-SNUhP~#*zEt7nOv1|X+#M^s!{y((g(n2qY&Xc$B&%*>Q^70argZX z-F;8^cfMJ+du#o{+_uuZ_7WE&VPNbhkUxWb*3a5KI4YbTT)EGkUL5W zJ%~inl!;Lc>mG?%a@Oni)?io;J1kzolz9=bVD8gXT zMKV;GkyncB*)6ux`8Z2Mp}7kfsK`f*J+v=ls94WnA0)a)}gP6jMbsgI`6DiLAxI$|C&Yz#me-!aTtn{S|(ws^ygnuFy4VK$kua9~gK)(LX+IA(fm-bJ^Q(5{fOX1^pF|LR2V zqPyu$fr;*ON0U+W4aJ;;k!Q0D$K-P}WS$_`{JGN_L9``^<{AFn=m=|egtghjx*QRG zj)-o1xW^uW7!s4`-mE7sAKrfD$IjCyvY^nHp3T4T6X%Q1@{=uZ8BL_AP6sPtVCb#dk z)NNnw&a#~bL7&JUhCDwdJ{S}8X9bqcNZE{<19Njv&7b`cw3rMB=g%PMo?}v-kN`nr zoq@#!0f@#LS_QCf$Os^_VXWcmIP4^lQbS77>k?wWEL7P5&Q(P`uI;UmhFXhz{!<-aKmAxT>#c8&(n=r)9s&FwxR8TXH%?Svk=k_F{{+-tWLZ?7vLL{q(Wyf48@P~pI zlV@ur@VO7h>obKm^Jf9kh8h<5+)o%4_h6nFhMY`WjwMKc#a`+*a+SBJu>DsvleKHKW**;I)GpP4xxJ-20 zV=1E1wc&}LJ&6PRc7p4f-j?zl98QqX4^%jZ5A5mBPHo$~n%$cm3s6mCxPc@XB-@=B zgW6oeE^=;E!RUM4lweL<)sddqTfBn@*@K4*c))?WKrwR=w5q1T_cC0PIa0K}Kf~UZ zwzAc+uq|-`!fYdA1dkg5m-Zvi3PF#;XFzli{;d5m{E|Ta%$UlBgJbX{#rAD}v}fZ= z%1Jld7lFr7X!klKIBUprKZMy9(`}hYF4AZtfceTG8lK;4Tik1n?L*gXk43)?&2CRz zh+Q^DE3J0XFg$Nr{D0Xy5AZmy>ul3SA|*?1i5R2H%nS+$0*@sa31SO|jV+P=TM zgaED*xSF7#7GI8oC2ji(+xNq|OM9#Lh=PcMFJ-p=eR%_=+k11eIyRbH(^n%?5y3O$ zIW7!`=PnF45+cOmnOg~mr89U|mll%R@b{ZLULO#hKOa#zxi75{9g^ zVppE5TGWp3+08hV-uYG}zoGoO&FlwxR?%tk?G-a;f1=M4fVXptC7^rb;?WY*Gf(7! zpf4S@T{>>Nc&y;kv4W?L=0Ee;uJIBR9okd;2QmZ3)(63R2h$fR{;aWI@b455jb>Pf zw@SLKD72D8>r3UX%+f8g)*9`)=;`&(j$`mvRR#5GgOngNhTg81AXNNWEfIAq7OikJ zOFd9T_osXHrHKk!!tMoa$I+TW2Ob>`YYvSt{2W8}VKI)P+Y>6ry8;t33SCWcsg=Fd*JSYI{rXL2Xn?7Hg8nLV}e5$Kag ztMmFF**x^{=Cftno~%UXn%R`T^i(`HJ0Q5AwzvSQk@hAA;yx?MG;e|)G_iT>CD7(=d z)WX9oTzyP|{AFxPS=wXE0$FQED-IsOXQ^YTnRtMp#TTV47jvzF?3Au`55Z;u-~eP) z&7fm6%qkd-ARn}bLs>iG{6Oe~$)Q7*FqYU^pl3$E-C_#FivzZ-jSz&CTAVJlKoPC< z&uYmk;$ge~8U3(HyoEu#r!A3nYwsU>hg|lNdtQ}p<`F)qMT1)s>&CdpE~+>FT=v;8cfk}W8Bp^FJ5!&O$;AQ zjvg>akpQ2K{8=GrmVHS`qaz2BBBYNwsxvu?Njsew-juwgJ>#LCjR{?wl3F$=H}A@5 zE8gC!ePZ!Ml$ok9;fB(aOcjeEo+<2GpAbxgIGQamt(-i$P zDxK@^@Di@PhkN5qygshKzz0pd@Y9KZ{n5k^{``$+uKZlIG;UxDgOK?cl_ZTf1U|0*83=;qOaa`a(j&9i7(By&&|Nx49v}drx{TE8Rc_0 z2>K3xK=d+Ry_t^%^rC=!zVVd>Ukd$3cw2qnjpu*y@{6y}@#kBP-#;M!?BaE%73O#g z{>%l5(my|Q<*m~vp7mO|_|A_m_?>$`^-xIg;ryMA`;a}982B@V@Cp^G)pWuiKEr3H z!-lI%94wkN7&*wBhW5Y*L#!|yfh?J_g9IIrF8A->4Syawup5yx;tMDEM28O#}1J=Ms?KQgM}{n8wOFMTMr_{rhv;vQtl{tT+`H(z+(FGY(=9q_brsI@TL!m>Bmp=J02?g!w%iXA7C9 z>2E~MbTh6RbA^``BGyr}N?eyZNp{_&x9EM|r^Mk1?d{3F<0d|L8qKr5Nr|7;QoV8C zY4YnZ`L!o&VewV`xliNI{V4&cnmbecyR*UucHV!jdebwH=RbA45b-no`NGlsOHbrJ zd))R^&E}E(H62+Y-5Gu(YXda$>^-_pEI1}3!%>$o-ABRafpi~35k zfS{dyIg~P)rRc6TL_B!_nLZ;KUWAcC>-<@V&m=m3M#ybM&^mwC$+MmeWO#$1l?qw| z&LV^+$aVf~N6-!xG>BNyU=2RoF|reIc3PdDKO4O`fX_z$tRv{@`7@OVB`86t?cR~# z)gHg7J>IJ$!JEo-__Sbg0E=#k_i2ptZjSY7iS=oX^Tk~pqlU%=zlM09`Z#YeHL&{h z8lThgfgS4~IJbBGr9-)AYjcNd^G1;w*Sar3sNnPHkzx}1yeEHlh0nC;(7jXz@wE%wWuiNQ^=0nISd^$(3avJpQD5Of!V)D%)zakQ$4Kh{7|h&@Gtc~9qR zWx?6v^&MH1DhS0igEuTX6Mg#4QtzNKIl3!91D!4B!lB9;v7>#?1?h9NpxyCG+t~v< z$8G7o8y;-4@N!c?A0lUSP@gGKg-~cyFcM#oa#s?C9whj)PKY~%CA`fV+H6L-9RP(! zz6+04DroooS*t@Q<`tTAg<3+bA)hVQNDwskBUh?&&sODQp*()L6cb=63hekv*uOG) z2H_yjI)WzAN)S@GP-++APf}S(Sq%_0n0K@?XY9a^-u#sIbr0f_fuA#G5qxMH^g9u* z9)&cw5gquBGuIUKv$35cGxeoRQ*notxqttxGX&M&;X)6pnMXhHa&E zAQl|MW(`3nM?!0xk|LYZRzSRa3ewM(PP?ke_nFs z&yHK9_d)-x`16Z`pm`hj#TSJ?-?%aH-2Y7c!{5I1-KTy@#ddCI=J+$P`aSuxsz11C zWBHvQ|1|y^fArDc3%Yk9s@Rqg%&33HDC6e+H(dC$x;}B@&mB#Fy=;l;WApC#{3kw{v~r#jQ`L^QEAY!FY#vemR&^ml3QT$n!8Z>ULC~B%GCR!oM_-5=EQ;xy1 zQXCF(>VQ83pRwJ5&okNpmK|d3EaaJhuY&GD)2#<3Fglk02MgLYZxgzKsRs_^_Sn{T z?yxkki#eUVobrNoagnX@(I|qt5~7d>5qJQ?Z*fj;ND7hrTvJF>Qm_hDVNfT-Mg%S5 zXYDR^=7iZ(Pkns13Gi9?v*x@3eAfAMD@wDZkmfc1;>(c`er!!JdY;xz3F8lEkChim z?HkB^!U#H;$$wWfEf_W4lv+6YO`kyBPVir+l_!>X3Pw#K@o9ll-xJ z1wIp<$r6+i?6&w(@()7{s{XMY$O!C959mt|>RBIora0;8!#lov+;;V7-sKa8mrfQz zp|71R{Qil8C(E)1cdY2n4D8SJ9bfNH;ALTCzdEWVQRI0r!&e2X5NTD>Pv^`|6xsuV zR{VLALJy?)5Q;*BpocTW14IR%tHWf#GBK9v>o(L@wbXY}i9VEeI@nwrLkb`&J7~N( z#EwJLLMsrhEgceQ^CIQNF_k|H^>qTyvKsHDhvLu8af=A0f;RToh0r95KQo~Eh#4*g zK0C~)fzMqDUY)|97j-6zLp6ud!slwCpmbNfZ)coOTdX&Ya!B!BU}`WUEpTc64f5Y| z_qLex2R2_ioOkZg!Wr^s9YK47)kgS?T-ms4$ftNg>)6@o1#ReT!&^ffp*24ZP1tPL zHpBV|h#XK9Y&fcgJQ%GK6)O;Ol0O@HqdlL3myM{|ZLYM|AX(#9r&Xs-uBh2<3wt4& z?LSh2x)=~WSe1vz$iTiWr? zW6U?;&*+~AE%H)QlVvgbXAC72f0hH*;In;+DMw`y6c-<=^R-2n%XW>~tlevuaWK&4 zfutb2Lfb5G6`e3Fl*i3HdIpfTr9`!*EN-<%W14{o|5QRiy(zfa64qi4<*Bsz{Zg*Z z8aahOYo5<=W-;GT-o>gWU2-t)9AeM`druB);)Ajt7%R@YT$O+3kUWN9O7+JCPKoh5 za^zB}P`Ivk)=+Ci)QVj*X_OltJ+Nb_AftD4Tu0hc6xSHtw53M&Sfhw`OH`dXimH*6 z9v&&r8O8IY+J^idL_AQDf2OMNTt(hM;rjMX3FvsSDlY&ynAE)HuK|Y_djlmd?G&N zWMTv$x-(6DIY7!imS{k<5kU)!Hj9*EQ0v716(S=f}VLCtvC87<~T4U%Hqx z>$f(ynm@ld@v6i-5_bOlI{f+iixdCzpA&!c{kNXE0)Ku(veQpNkW?*gxJk5Xy z{_L~(F0asg?pyeYuYB!uUwx#Y?5F?z@@p@>i3`UZf4;R8o$EJD%wD-J{?EKnru?7r z-*~_IvwB1>;^#|TxxGaRLY9Nw|CAKJ`ObL@e(%%2l@+t*P|c5)?lT z&B_DAXB5s<6-4=rE*b>Q^*oJ)IC3~btf3KIm)me7q_+F;!Q6p8+uC!pTDB&gPFc}l zS;C8!4csZ%eV)Z_qdhK+I)emQ82iemL=8T3*M{s_Q$7Qq?U4`)pvIb`P3tTe8RKO= zG>x<;wmf~iTj1=}*d8CkM{|T|vvE&tOte=X|4NYAVEF7jjtBm%n6N99 zcH+-E1U52cW3G3YCYh$c4vlqAtG5^j)Eh}uPh*QQ*T?w)5>L$8*go6CmKcVyIu4D~9Tl~b0IaMe$(Vre5k?Plz9yGM$!E2QpzK8Aev4X3oiZ9iboI7E= zcs&2RCyT!Ot?d_gC-!X!>q++>Uh4;c9?4v&xh@+d&>9Mc-0I}n$e%?No$71ULOUU7 z9ZegOo8-^HWF0a)A!xl_Pjm!L%e4GiTsY(`3>4Y`pOHg5yKsPomDpG$LAXsUxf zI#cK=osBy>a7vT z7fwr|z&45xCI%5&om_E;MrMqoGJnXZM0xg+bytrRoT;^8iw!oHl8agiLg4e*AshVp zTa{2o}?ra@Y|x-qBF*`HMWA~$)#u7{MajHz^=WfB@Vq4@qQxqv(4g-|OC)Cpg6_;q zKX-^J%F}+O5YYnMGsbI*Mi1l-6>n@_`(U$mNuwzo!VHDR5gI8qyd5>TD3hrqXmM2Z z!)`h`vL)mGf!y?qW!ZdRBUSQKN1m--TkEP3RX>A^%STmSfARX(&9Ugfks=d9wo@WC ziM8FZT9-gOsh8cZiaoWvQ2beKfd1Pq*}NDzG#YZM4Nfta)~XqHSVIX8Nz6BrFp*x?vDHMqMJAu; z`-5dREY7Gif~_~_&R65apZTW54z99@O)UotjuvMxS@iW!%$xV%@|9Pweeb1L-sXly zbKB6dv!2`%{w&1@?TFjRpKrX0|Hk#}Z`^os;`!$${{5dP{^Hr!pSt)9a4P0sG1 zW+dW(&!T)5@w3z)RP-22XB8l50_k!`MG2108iL*pf@TD;v$}d$KF?CDkn(~$!3JV$ z9Gj}*7;&I>Mh-;9B7`VIwzVjEFrz@|3!CKzwk07PhYft5DK97(*};>Q+cSEeN!qNy zvId`_$F#GfgvNpGJXwd&B)5n^E1L@^_{^&CXIw$x&xvx|uJ|*z^YV^!LP%RoP;*Sk zso2oRsmY$3K7KG;6Ci05q7`0OT5)xA+GSf?m;S)XxUj}psuqTJ#0M+?XJ=wO4NSg? zP44)!5eTc?2}HYgaB4BaVYj)lzuOK*XsoERQwyu?=-TMEWwx02mh?ArW>5KSKgbC$ z>#I7K)>}wg69bx){0Yzy2pag@WA?-O8U1q?5HJJqKv#k()v4~vZ9RNp};^!n%v zdo0gBx&!`vTK2Oh27J+ZEATT|d;z1F2pjhfWpe4Lx-1Y+%$g<LtwCv@6S3akj`y$M{NUjJbz`+T@5!Ha;H;F%`l?f+wkr5+M9>JBjiFObW255C z;5!mKoyPS79;^90D_{s}wnt6ABsKZ=p&VdY0cu63yQ>Ps0$SU|fWy^=AXykJwdz=% zLLeP@*;6B&+0&+9v7M2DX8if)kM+>E_6{6|eC7@wl46UZORvniP?LAQV#k0jwK;3~ z$wX>R;<`h{I(bouKUh@mgGgh)Oa;J(ME};*$f2Bs^ZPcPug)E>6`?p}yQj94?`4=_ zD{=<*Z0Xu+f;02*w=F5KHQ66~pKg;Mjv45mTdd2v3)cZW6~mXwJXAn1$ufKRT2zpCXPoOLU3cCVz0dM6yB7&xMl5%zHHM-N#=#J?H8)E&s61% zRP4eY7O+;9oB9M(IQww(19Rm ztVrmFAx7ug2S-ZQkHhT`6?7ev6QAyT(S8#8vkZPA!&P}B)%hf_YXEO&O=(XxMG56~ zC#K@eq2e>;+5NV(whgNgnKQ|48H@2$?_9gAd;Ln(zbDPnr`N9PFWrc12fyClL&YMf z)-X88bgV3|CpWcoa|~r7p|#WvY{Q5nDO^?AYsWf6lP*J{F@*;0_F1HgU)$Q%y?N=w z2Xt@txb2Bh+!@aJ?9Y>Q_|CDL(Q&w=crvYjIbww*n=gNFi__irD` zOKH!1pgu7i#dvpeR4;W2wd#agjY1*bt(K4$`6|U_y2G@%Co5)1d+0CM^O_?ZzdD>! z2&B&KWd(9+S|QhC5*mC~OJo%kG})7BUiih&ee$Cp&E1*zPyh12*I#kKVK-HQ-go|d z0}JRECw}t36aVzXxBvX9pIz~3aj&^?jI-gI|9a;~eY)$? z^*B|FYtQLh=Ej+uALDOe`q^;ZYTVbDyY`&E#kj9ApMEdbt;T(gxogkqTa5b}^Xd0; z-D=#|n7j6zzQwq&F?YY0JN~@<4&UW>_$*)G#lujad;jdqpZrq%O7peL-+T4O8$5KL z(?8!@1ntD1W%UKBIZx`JaWi}J(i?=Z;#*;J^#Eduj z^DE`9rynL?Rya~&8!5}95>UssBnlKZ#Mx(~AwCFAb>mGS*~SkHC-thYEN zbkJMe@?@t*y)%i^Cbt0DQ={Uyp0?`kv&Fo(q`#3l-;x0tMDTKw__aEPTmB3e0zNmI z>=NiMvp)#BH`yQlj0H5F8@*|QpnKDNhtm8;)BVRXgL_f}$96sVWO>FjkMF#Eyx`o4 zg0m+JFP<*Gdc5HKrwae_@f}a@H4kr%9$Ftbygoo&IJ5$PuxNnukRe9b`U!&0^b>!K z3||GGS=!y3VckfGQ+x;=K9d;vvqI3Qvinjd%{S;E{u`-Yll~h9^9`f_hR&Z=qVs2+ zIeSbr{;asVqRU8WXXsfru4%%7&{C@CffUpuUL$lTRGv?1?vZ3>5 z5VV*-izHj3B@qODUvvD|VbN^~-{?RBO{1p4Zc13xkhriRQI_y$I^);Tu;%M{M4yWH zJsj(MbnUXfee2Im)jv-odscW^V5SGNXt(@XLFPUOg4W?Pi6{Py3>ERJa$O$QOe9zZ z4=P5j?YC_y&dIvj1+SsxHk+P5fwBZ8bDDn@41@1@v?10B^hno)|^a@JVvPk zp5ev^@m32I8vfjo=r8}hn1Y%T{o7Kb`?kl9?^zGH28Z@x7hF?dA7RhNw(X`9rYPzZ z$lqvoOb+Tw4(Lt_K)TG|@urkzJWlN|&ok5HM@N?L@w_2%%C=E#POm3_O+qq{epE8BUlD(CE>0&qI;Ury>!!BAz+(}xS5uG}_W zoYB7NAq<=wlEOgH0y&dHvGPC#4OO<2XA;e#L9B)?A zn()~kDzskMxBkk3jTax@aHcq`bGxZ=OJYySdgcVzj_xWO2)e&^4|WjZDP3i|P@RA7 zz}E57jdUK*OYPs9(7E=Z_RRYmEQ=egQH@p+R6~r#5jr_^&>Y^I5?z-RaVl+jS3&wv zg;=R{N^!%If$CCh%!kX1hbwpUb#TBvhYH4y6rOuz)99|m_KamBgtkN~HFb|AbV_JS zV`03=j2$p}`b0c2w2-exOXzRp&zgho4;V+xOh_=#j^6y!6Hk*I(!5&6f;u9UL5y8u$gx!CG`hz##eChfdNUv{PpZK5un)u;gzxnKwKfiY2jcM6xgrlYx36)pxp9oM;hO(?=SO|I>(cc&Rf}uS>09Q;nVTQuZ(#b_aNTO$ z*OQ5X*Vk9GLb-I;vu1_sTG}uV>3l?X^6Be4;J?A&+B`5CvF=}TTJy?ymq>@EQyK+)BBtisHTl!k^Fb0xX*fGMY2)KZQ+)h@V5K19dVMav1sn^JgO#Hs;gw zXQ!=-CoA@A9K@Kr<<&Yao?&8yy3_As?D>J^w}?M`X$NdyI?SB0be0fUqy=T;2>Ysm zPJ@P8OaW*b+mn2W4zq73Ve##;`iljJ7LZ=iKWF%kWCV<5p=}Ns-L>*+WyZ57@}8_K zJa@Vf6*NZB&zvg41^Nd^cYUWKePC-;dz#PKrr>ky{m*1B!U%d~y2V^#?oh2WHRHq6aSBXxZ1#3IVvzAZ^ z(NPT1PzF&jb-EYfhBjw7Y4CYwf;j$p=w|P!FREhf@_oC4}xa`=BKT z)hfNQT0($DQEc$s@RaLT%*JF&XAMLnPF5kt&K_d2k7mB1G}SIkjW#=6IPA*j1hJup zKR3oNY>bzsxPoXwQWxuWEZ*l>N<`o8jPr*h|Q zq17r&J0G5Erg0OEn)8O;kwfKbNfA9bHqomsIY@OFe1sBCv(&@sbB*ITZThvZg6ynomRXoxHK?9H>x5%O8fA!?>j&&>W z_a4Z%4wPgJmZbLQ#C2_cpgDbUojJ5FF_>t;epz(OJQ}8EK@d*7jqzbknGZ=}yUJWX zT|W|)$nj`US4qK{Ot5PAp3SGXCO)3Bygp?ag%Xa&MI1LTY1^DQQo8A4Mc%opLi`ix zrkPsU%~Fu2Lrn+DcJjkJS8MAoU4LrBs^iH~jY(l#Bn+B@hm%A4Eg@aWK^^AcE(j_n z51KzP@VU_()Q}w1kP_UI8rqo}++(HUp+C;mR3t<`-IlSWH#>gh;0E;kux`rs5&BaM z65;0_g401}ET>jmLZC<|1`m}&k9n*hr6+4BXlNU%$j9e-xGY<$6ISJqJ3^f%9dup2 z`a;#m@wrR_-yn7zXKQTiC4(H;$;0dJ{IrIRt4~?P7900we6!)tBdNgN(DszD=G4fB ztflSQ@x%Kzok4A0Ln+B(e8A8@qk_gHq@&8#R$b6l3*Ij{QL!e-A=p%P zw7~E&XbS01L#Qm$ag_78b3mtcF|&~;>tGofHo*v#hE$=0XgyJV`myykL64UW?y`0uXQmxXPz4LSmoG6&7Kxc zDNJ1E%Ji0)11d zTbD1se&y1eS1-O!xyHRkO?Tb# znY-qF>blOmdv#47{ca#una1*m<>tp=Io;oR*H;B=dQJS!RP0$l-LhCYDQ3I&IJfDh>!FmwZ#YW>Gg4er{V%U@n>C+O=2|Y(A$lTPC0N}4<~f2BVxDh zfaR80f48A_qyrqd4ijdQIDeusW-=OL10=L|`lxR7bm*Ub8e{Fz5aX>vwKT=~>Mbq_ zn>>aqYCav~C4p(}8Xx0UBP(uP?W0HiYTwD2x{Ct~Lxv}#agCQ#G{txu!??9!^&Nl_<>}*NgwIiFJK3Q<-R3R47@aN0NZOe-zs}JS-gMQYV5C8 zWtU%>JgX5DD>mjMHBz;ZLsIbB$e(ZF=iaL0pY1qKuvcFdR4b0qxIh$Q%Zw2ORT%nq zZyGAf=-(07oVm2Y65gsA|MFL_ImR0wW?re_&k+AzpNjXdGlw*!M4q;Uwx&`9Fi4(i zQMfQM2yhL5ZZZY(HyZos9^U#%3g-`f%ci)o@@(|duKZc2&>Rw=m9K-^e7qSnux}T~ zGhDcCI4`|-S4vNA+ED4{a}_AAOU9~;MMq85LOiH(RMzT6vScWjB=r!{LibhXwiU0f zTmKM$Mq!~t=8#cKXunld+3;uFo&l9Odx$%S1(9=T3z32YGg{do^v{EqASBQNY^`BU z$)SxI(LK5GqX#!5SBCoP#Rth@$O!2@@n^jq1g!u&%ic;M(rQ(8P^)^oS~V{9ahwvR z=U0uOX%z2Bnt850T9MmdvJM01#z^Nt;&b@GSxg2AAfjj-;N}T7*dZCv@7sAHKZ>ERv!XM z?n(`p8imQAX%RN-;%A*at7Hm)P6=g4)tM!p9x5FCIh=0?@p<3Y1g;yojO^B`Gvi^x zA+=YEY#TK=4+4hD^6_&XDO%rw_qZt%6!=Fdw_ zPygG$|L2!qdgG<%xgVUJAjc?{o=HB*pRYUM^L3F`Bh-2Eg^3q_GV#wpdgs}vUcGkd z=Qs*pz2K22d*a5P+TGqC(denar}p2haW1{V?c}A4KfiiePK0uej}*7weaCO#HSZ(B zpYQo<_+8$J(3WWYS%c4W{MpwNDe}~=Sc<2uGjIQJjbkK8#@y5S8vD#7|FDcREBH+3 z56gMY#7=XLj2zww!`9@+osfBnaEFTFCy zpJ#Wu_1>3fFUZ4v-X=p^Zs*TGg+EU`d-WGjU3~-cOr3}ijz3@h`SIfyzxHS0_k8T$ zheCr+?#<(kJXEQ@`wO}cl;9nKPPj#rKnq-@G~sQ*pIuP1D||M#C=ji+==@nj(Bj$w zl&-)yT3%*EG(v4bZWu9|;O4P;V{Co;ic{w3Qwd?G$bXnXpR4C79;Irb- zO^K8oLI^E(j;f-)@MmhMCHi+J1$4lKF{{Lm1G7ghlr=QqSKuwXB!!BQ#vIO80JYAa zH6^oFqfq-G_%olPJ{0>7z;ahy2>e-*XG${hKC--$j5lU{AWCLBAZBif3&xzeJ}!te zs!O0Od-(B$=#xoH>f)kW5~Gkh!&f;B?%BC>C*aR;=~MBMr_vv!qz?RFXAT4YOiaU{ov8B6S9SPI!UyTh*_e3Z&&EDZ zxgyC%usjWarn4SS{MksDU5T`DtCr6KKErt5lRwi(htDLF@EH(&tNAl58vg7utbsoR zpQnbBJ?l#yJF90jI(gRZI8fsg3PF3~&jV@xia!sh`-5BYWbR7y>)pEe%p;bk9@}*d z|BYh>@aGFh^RFE*_>0p;e|0kVyR{p}ZL2#n{qflt&+<95&QJ8u8Q#5_-UIOGOhL5( z+tD-$MQ-h$6$Z_-5kV{d+-t>-V@mW}y{8~(w9py{_Qap|8C)sl8`)zC~fln`3!w2l2gyt%I2))P1|l5d%I z6r|OKXKG8%9o~(G_FQ#7j>;Fxw~dvq9mq~>Uw1#kQ9v|o8AUYM7McfYZZ!vCTS0xm zX8t@S@V8i$()^#Jy87f+P z_Q0+SRfT72N~k|582oT?*O9{Zs{BDbYN`s68DBV5c>dsyzTD)NtYu6H=$N61L2Gz_ zicoqa<*1Ya@RiWT@njRxaDtJvdmnmO>#ogrI8RaRY*6 zh_N_klw*sRuMUr^spjoT$CIO}+t`^BjktXfzmeonj7Pfox_Ovljc&<&fKnqDDg;@> zpQWHSb+Idpxd0R67fk{Uh33K)tu>pFTeFF)Sv1lul_fhYYd&|+$3FAvd-m=t`|0zq zzV-?)Y`*p0H#oBd)J_8$`Lnjk?&(4Mi_cH|6!VS0dE@CPU%qMn?1>M1YM(7<{>>Wa z@|#yKy>a={FYw>sM6O+Y{otO?Pu%&ryXSor{_JzlS3~Fc^ZZ!@XD5`TSc+5QO{{*n z#&IP`(;vU5{+`-BO`xa#p4#8cXF2{K>>W{OvpNXTi=NIDc+! z`QGBFq`T(b9kJ-X!+Be{5EVm-1GgK0)|{WkHe{CY8SHH5&teUIP}4ta4$mDGrFchE zlu!`#K^xwNR2A5#iL7Y>KES$sSQIJ4@2T$zM=M#=?RH_c#V#uueD?;UH2 zh^X<+(2PES+j3`}AUfohm;l*JTtNh(pH2*~PhQ-Ry1XItA?SMBwxo`o$(_5bJ=v*! zTTFfH*R)%g!k-z9!)A9m+L)lugox8|VNaNrPY|Og zQS)rfjq+xd8^zBmH})~^tLJsAHO;d@RxO(}5UrDEl^FRmI7p|^I)4^+f4$T)Svy}rHb`WAI-md%tkFj_%n{s&z>&+tGYrE z^tFnNzU|QiYyGiG9$V*6MM5z~hWcjtl0a*Xp`bA%8=12)cf!v4YM;eRA!waKGn5DO z4e{R)=B%ld6@1n)wOV!J&w%JD2wGDVcg){#$>4fPd163}3DG(5T~y?>m#k~pmRO&)vIz?g4$Klc zZiyPQ*b6UGoUt{1Mc7y@c=D?$)s`SLe zc}dH{7JPKxSHALnSKq^Y<7KQQ zp1$(#)$_{a+09#`A8u~!*`#`Q=cT<)D~hJ8?+6&b_8_#*NdJ z+uR(lm>WmUfF}xcyUvfN^Sxc$XUm^&*Lj#buelkR$qexCMeimS(DUu~HSp)9cl+W8 z74)e^e|py+XRJ>D{ceEDl`@EVqO1?R8{leC={>b53TJvBhB>@wsNr&b{ZDT9cG zJSWLgnKrW&+l|B^%q5T?i^Yd2jIChj<8gsU6GHK&Y+CmathmRPHBh>FWZ#bQirlkR z`D5idyv_P#dG3|c4Feli!;nF~+{xnF(VrCBvDzPJkJGWC-;N6(dt}?0$~^ju;RXc< zAKuwpxUO}Z>6CT(x7P%niVLb2(+_{{@exi#fKfgprFILDX`I544SpJ`-P2xfcAUze zJ&|Xf8&AWZfzM7MG=9w#{tQf3Lm3IPj+8;cDtEh8?>3X?6393LppP&6IBl0X~zGcM3w$>PF+5p;hF-kypKYv#-u z{@v;REmr@Ib&;cmN!Mz(KYQGE z*cp3g1({J$>*U$4Mo#m?z*z;9+woabSTy=)ojDs5aIRBbLMdX%XJz_H7%CpBd@$38 z(6O_g3}tu`0O#TKMT9Pa){`k9da4%MPOa1Jg6c{CXHEZX=g%62MmpY`vPeVFm~Ti3 zf}TpD^;&^i=|J(~m=r>L_J!6F^fdh0$eBImp2)LmpPoMhpM^iiEovjt`19!mzm|2& zpFEUv;YeX`bsn@+@#iy#3RMV&u8~rGB)S9|Q;vQ|Adv+@zkm8?1z_FcS$my9MK2w0 z&rUsWn^lE;bp<%iCxUi4_d~^Ga_gH z1A#n)9C@fp^d?C3BxssvQ(!OVz-Ea)6Fq}E*FH#nJ-&2?<#YKImQDdKR-4$Wn5tS1 zRp$>@<@HzPiHkBt@v3bAXRVx~UGofT)^}vzp7LCfDIGe>bCFVC;Fngqv2(*J=xbYY zaH~161HTB&8InVQ&-_J(HlvHi8hXSMN(`BU1<$60qnK^BL^P&g8oaC}>;C4LWQKa3PZwB7Tc&)T#F7Mu+ zh+g_U#Sp9W2C8!UYV!D3sUND?dQ@xwa?5v)?OETuCAK?bIheP{EI?Z^ZG1TxQ{Xc* zYzRy+R4BGQ029{2i9ag}P2+&lpNpnCyeT=nb^WU0;`Ll6$yKGshe6OWP39RCW zLFvGpz60BP3Nt%5tm#Nu)}I_bY>F7xKy<$)s@)XTYFUaf;OyRQ=QXztG1)->TrMuq zT(wew1DegSJTmC0$ZxB#wN@53m)WE?O4Z(jJ2r%V<12T5WZudZ4_>+Yy_a5o_r~+@ zy!67X{hw#zxnb;MxZ9e9&%7~u1M`iaPW;P1zV+wNAbx)3>C3M_b@`nqFMw6umlX8G zX+5>iR=51&80XR(_&;+~srWPg8;7e$@44#>^XGlU&Y$o0in!Ao777-?e`Ah6>sVNa zBuc;BrF^+zM|3{KJ{``OBi=I2pTRQ^^J_~=o!4`Q_(+@v69Q-D(et|H}iuFu_&ajTc|H`#--h@%(>J{M}!{ zpT+Z;%7eTxB^L}Ii2w7oE595a{nt$!_TM${-aq}q7i}5lrhWNc2ata_@n5YkC4>`zNyd}9Kr}#D`R9qVWWn)P-E1^2g_=FFrFCnVdRda za2T~Xd*J8Hz6h8#7Y?!hfGXpsk-!VZyf_>zZxd57FezX%P(hnQ0KXVtP+94CLhus_ zp(j$7Hg1gVEy(OI-8j5I8>dP!&8RBj&V?oSeF(iSRpwpUw`FKsf;drQ0UhJl8ROrd z5ZtxeA6sdT94Ywd?hUB3M)qv%%TI6LZfe^YSC_g{3N6K;Gz;ewn*< z&YX2zpxc<9Kf6+BkNs!KpV5T74aJ$=EMxqd-GwV*R?6h}n?HNv(h4I_(&Ly#jat;L zS*SB%W8#FJ^;NZ(aoH5>3R-lG_}GXM zv|lG72wGIoy_ygjEi~l_yDZ+_6eUaz=&<;=S_6AGFTeP3+B4tIxpvHU`9$IQlZ9uF z<)1&Ai!byu$Mc?kbn`&&iq7>xooPOO=|Y(8hR^!6Cpv%DfwOC3M9?~OHYU3HhRB}v(2hr)sp8KLFK917w9cOqLMtt_ z&Y!i!E{C4P!XCUhJn?5woY`Z$!@YU(6Ag|W)AQ%1*o8!E>_Yf6$AkX4F44bv?K1fD znZpHm@b(`m0Vac>1v_g2g@!*%I2<`tAwnTt8iM}d`7=aX*={KQthlH&9x5hCZX4$8 zbRs&o6`K^Lg+5dw{<^h$`yYLH@JJ~*7lwKMQ2x~;1zox3h7I>OWGrr9ySzPfNo#5( zuE;#G<&P9O}^y(RqfdvgLMNx1DzGCNj5Iku_+#| z%veC;BvKcW?*cGhThw!?u)D^F&vXCb-SX|!+ABh;y%?WF)W~eA5he-a<@a{3Z0DKM zwQcKGaLm*h#QGRCifb{N?E!O$6d4q^=aAtPF_b_fjWoI~HIn|6S?tM8?zg247iR*o zFO+T?E8Wylx&{5Sa^8UY0-rH|X6Y6V(+GA3;gWDLU1fOW#32qRnz4ofJ}VIImOn$GjrwOLeik&XJrux#gVFGQX-r$vxjk`o&t`0><@?p_ znl&wSabKn8#eqw6bqS8p7>tWlzI0>%)`Xt472T$Yfu!)E+`bvv@=S8a;5vMk+fOBa{@?$e_y;lHcbS1e*5disGhP%s$h~$X+^yPI~4>WF$LGV0Y zwo3}lR~As32j^+Brm|!tn%t6x87JlR?1gv**tWR(qt) zE=p-#*lbKV662~d7f%vH=&LPj{N02*@~m*Q&YyKLvoem>S7(@b;>k*=>}jh@yWMhG z__KpNJM&>DHw+J}PP?<}7C!5Z4Y6K?8w%}Vd^>;EtTy!DuzEXway20c@~lGXpCwPw z>JmEmvs5rN`+}eqg;rYVZmUnb)w|8&rRkyrI?eu_DWN0TF;^=#U3)B#`h(-gY$M0= zLC_bD^NJ#^}@j|XC7WVT$IweeNA2Z5-CWR9NB4# zPv0avnH5Vk2x3<8mx*EvI`%Fi27_*-j%BCzMRCi^~)QqAsmnJ zXWTY`&&i?qgiw)Cis+?;vI##5$aBxG`11!gpR3$?u{QTyO&%j)i+!o400U}%x(2WE z$#YR>;kpzK>=1kRROYws-$`_p=PJE7oAh1m-87Q?p4eIMpj6__mF%urK&xtu1BZ9> z5x9|v2}yMUS1f~jH;Dm-HjdCB=*HBjwhgP$OP?*< zc3u#44iAPps-@T;|2p_Rh@D8K4Xc*3)kUNG1#8p4BYg=j*}{#@A%c{}K*KJ0)|JnC z!Y1kI2&IVD>lKRl*%BreC{}UdrZa53#TtnOy+7AFesCveO8r4DGR1tOLgUYsB@|4= zz`4CVkHe#QC0@`xDd^go)NEPWYmOK+;}a6mn;g}dytpZON#}-Gidvr8zY{_ASXB|4 zYAmmZF@;7oQI=21%a)w9p3+U@Rbm3e$@0(P)ZT*h`I| z{?2PJiE?JP{P~p|@6IZw@aG$Es>*}#XT;Ax{@E%eVv))_H(IKSd1;YXQ^yYE zv~Np3ow&3)AsV}5xid`+mnF6scrr`nJ`qhB`Lh^q7(#7Q_5QjNq{tw-z~{u!x}*r0 zb5q8u_Kk@h+bw+sYx|1U5ANPHyl2bE-Yvs>HV>6<8s5Eeuw-3tURuY_q?S!F^_lk{ zw=Tg{`J^eTAt9ngWZ2mpdsFXx>#|2`P0gmRaVQe}YlENO14?VSZ6=jS@ z9^O2%fBSIxF78UGFVBsMvLECoi0Cgb=`SnouaI(1ZN+PkW^`s_oZ~bG?P}F1at6QaA?>j~Q$mB%O>2A!BV<kUTRgrXO?Pk1)p^U?TJ6bqBR$e$#R5%=nnHD zBY%cMD+I0a=Y{ZRw+Px3e>QSvW3GNt#uht^cJODn2wMM?Df~Hcp(}rGiS<6U>YJzH z{p-@AE|qUXKRI*+U9nBo@>3#b<*EUPBovWWErW-JJgazL`Lm+UO41Cg1pTQN;h7qL z=6ND7v&d6LP~L5!e^!`Rhn&U)Gzx__f@m>?s3;n$-aT??&u~pC8eJZzG6J>yh7aYB z*V@h=v7Ld()?}Zr%^f+or7h1~m$9-wWeE>?`P0n1LWqa)xM)fC<#mZR9%fmBTk%rP zHsb<;Qg<5utVk>eqkyf#vwS&=Z)6_ zZ}T~El+^@&=9q!V&jzcIDx|jdx|!3=us+-B?DSPVaiZ>W*0bc#>R%HF!@eR^hRr&H zAFzB7Rw~sp3A}W0u{!@uaaQlfHJDmZf3QC-bRZ>Yz!ET=8Vrl>Neu%*H>5;%Y+8e2 z{7U7HbJe^0Ds!1?j#CqCgP=?02}PAWsTr#+8LiCevZXe!TL~h@D+39%0W1qW*0HlO zQOud1cKGaYfrdg0eAf8$XiCUHav*|gTOKr2?S>C` zYXt=P()j@oR1^$hRb8IjQ?#BRXO~qhpz*23c%;V?&6{P7)}_5TjqKiZcHj1M<+=34 z{cQYT?%2NUk-b~nwwiER>D-xoVgL3s`*)0$Z5&A{9Y7-vB7XW+9Fe_r}= zpT&20N8jZaH2*%IPk!^y?)}RCUHkv@@Bep>KRd37-WUFSotn-+p7_D{UU$QvFTVZM z1viy7JYC`3O#7ABpMLUZkJgTU^H0O)&-?g;LH^$^+|gONN2IMv|E$cP=lHV=e{LUdcn)N%6l2utE`xz(C}v!f|@mH^pvG?e%8z}fX`TD zv|+z&qTXM0efo-)jq%;N85ky?DYp%m7jVZhSe8#fh6&9O!!}l#N2&U;^6asLJNtHT zXxeT*p0(-;>xvVJ+=E1md|FdPqbTN(kXQqsd*cEL^vUgUQhX2|ekv)Vep7t+?u}y= z1;Z8jePy}w`X?%^avORZiSnYJ@*?2#pccc_b1dCdw=MBoNl{NA(oP7giwzX3kT?o6 z1-Gs7>!;G zXpNXB{m6iu@T6tq&!MC;mKz8{6Tt5esYiq?3l7LL135`IJHIyjqt!yGz8-z$GR> z#R)#M+G!3X>=fFh`Dqx+4#J;R;+wjr+p(pZ2pU6M+MB#-e@^Im}TC=e~ zdsS;%aBphR5D41hKb{^qqzRRs__NdyOmVh-_Qao6dyj>Rei9mv_69!dp@h)N+(YH? zUOki`SyjUpu~FAZyUL!`n2LKleJ*-zDQlQ; zpJOQR<~Z-RSP7+nJ`wBNn7)__Wss{eETC)idk+^3e!F<^TSa{&hYJaK9c~W}5h)Ol zMw`SDI@m@Iqc4?46%MX=Yf1qs+6+(AnISE}X9B7TtQ(^SUs+zyBRgPgvZ=<#Qm2Kt zYr;9I&}N{RLT|(f&c+TzFIydt5_mwMo)Lg#ahe)_WXoVtM(5V}mduq6)~NdA(9`C? z)5!t#$$m}N0AO!>=F*{j>)CSAKl7)Pk5H5Ev~-uaj5Kj;J?eU3t6SU$g!88L_44?)? zW5ZjugTHtWT*tq^AXx5edy zl8aR(2#yQO@G5D`SkjFOIwcCd@qkHFIK!W%jG*T7krLdO z66{K$F#ypbygwy;&=Lv3rl28SC_|!u4i>bZQx~yIy@YU z6|OnE5AEi7kU;ZwQ=>9$6+TOwPMBkL`Z9qU(j zZA%!;Pe&6@kf4`tTOV`U6otZ}E9-%d^$(5YrHt*}((~}ns*S1MzxVljKk^Z4g7t@g z_ixv)zjfor+b`XC_xg+PyBXta*WZ2l`L|wq@vYZhdh6vIZ@zNlotJM++<1QCx&NN{ z;a|P}ohM%t@$+SH@!MA~zI(;9|MSh<4S7J&AMT;FmufFxeB;`ccVXrot$*{`&;HRJ z^FH#~d7u2|U0)8p$0uTeZ}fbxr3<{J0+c(ov!Vw&CY@p8x|eIqOonpZ%e7^09ODf9 zdgsS@B*t7FmFv>jXC}Gp2*1ktx{fxJV|YLMxE{&$=jEyYY}-AZi>GluEd6iQan6l1 z{qJzL^Aokem*9^Mq4K3TZ`|o8{?B)Khu`59a@Qi?Pu=JDMV~FEEkAhrhl)S*gqpXg zu0Q|gYcEfbe*krmZ!z_qjb+*U`q8hvsJ+F;lYRAY|AmSF`j?5n`tIw`Tz*|$=kTf& z;%Cu6UwoT*e=mM6zj@`-s~v4WSQ2TzW8VC*Z+!LO&UH-(z>KAeKl5Iyh@XE0__MA_ z{vZ?4KWm}upHV@he`b}tlIDFm6oMZu&+pitj59`Sd~|nWq-dVSw^^zbp?p>~0a>aN zfySlscJ8x8H&LW7F;sbU;F8gr6k4Acd=lU0wGU9GeWY~L=>BZ%`-UrudV$_$_VO{f zf^=43*(X+h1hsx(#oVVrq(R3(>4AN_x{EdP zCJPr?og0@2kg& zSZ~7Kjy94!#*3hHLyWg_P6nUqI9lnSjVfsL&-JllKSCc@?&_&!vSQ$Bd-cGERo*IG zH_VB|C;5qDFf($j$aJo1)1_ktXO9<*JPv=h!Jp4Qk$>g!yr&<}KKn>o z=fQ)^*N$GChAbdO_o>tOBB|D73=P#-+4t6nc_BmKU0p-g9O^ih(mE>r(ce~>iCsT`DyVx zbmh-(TXfKE|MA;@pW1IS#;aM2)&yVvnIGke#+Fs*E4N?%Hjp{5yC%2)(L%J%uxOa! zz!AZ@O7^KCXyME{e;z(OS$U9l9X=}tI3s*FEiTq6BD@Z8$C4JspZja&)fF+AEyX=) zEq^kQ{(>Co@T-6BZ}*pR+tz?OEtDi1$rSSY(NtZTSVk(zn1r!iDF zIa&t~Cs9aTmi7}76shxP8X?K!725}jQ(D(81BpXHaTxA1hfp<789oDJn>MU$FHG() z-!fR6#}88b?b&}MjKKMJYLh_jdhlwZ*mMhGX4qM$(|~0{%r~TNrqpCq{u_Kp3PH1~ z+VRj<2zm@V=-lL{EKIyZ`_h63(}G4)cs>|}5eGgbn%_luYx?5e%?}Obnl6-WzkmmL zjg9LluI>;&!+RUcZ7o$r?O0*ZUY##LfQQ$2XD4*7yC1!AUveaV%R|;EVDdElSvf@` zZ=S-REs=^p52Jrh2_~S{l(}qArlw(ZN5;zjT~=OjlfunfIZGHghtW|}!i67lXbhY& z<>r^h^P`^f?9P(4&FPDAR_RO*(LxFucBMqNr$#rKrMP5M`tsJS`-zsc<;~V5P3EX> z>tc#3_VQWQ=+4ahTQ|fW-I%!Tf$-m7@Ubu6`zhPbqUV0{8W8x!7vFs8rFV$;_2!7d zjr{qg>u=z{f$sXn=fr&D2jBn2(^p=5>e4SY?J=_6chK~{zxPMC0g+bxnTgW)b9cuN zKliym`S`q#d}iLg-&pV`A)oL@hc?HbJy8_bc2^qX+TyyGYm4h%t}U*6xwg3O<=W!9 zmurjbUal>!d(FH>jpn+X`3S0~>j*b@oVRM6*&e^A{367@vqI2L{8{;LgniN{;Im#!z80MklXYR}NghUXRiK#jjThd6JVT-1 z?~9Pzczn0~`7gio%U>6Nrq5j-b_belrEh@>#(x(r?hw-P9g>3|$s zxpN4tjtl9Cqtsv+3gl)YDeN@G1TB%>TjK``GElz^mt|8UMrzPh3IWFV1M6w(9;$#0 z!-omVAR>vuBBQ%JpEoFZr5av6K;4;rIU{?v_uJOBZ!)V&#TfC)x zQ^KkE@cJ0d@;X*5uYu2S=DNhdhJ-*gs8UNYK9~~+`8HBj&_r=VALw*_j6cx3%N*IB z5P>&{0O9xmJA&5ub5l$pp@ZU?B+~$AkDI2}AJh>vs$<|Ys|tzh?Ko6}pb1bj^a*9S0NIRiAlQhLKpnzpKYQyS9ZuxUv>=e5RMO^KC*u{xL5oraP z_0iliXJey*KTq*|c3@t+8X1n~i9fSRgL`(BvV%G6?i^F#vqqAIKkGbDwdkBs@jWF^ zoop1`=ggng5sGiK7Mg*E13@Q=s+j-@O2qpSQ&=>RQ29S=B?vVHjq`?mD6lgKnx!Q8 zxSFXWCj5EG?B8$l?FLX=g4;GM8QEjK`t597pux`Lj|+c3_eA0O$MT*%QFQIduHiy+ z`})Pr$?_V0Uus})s-J|zd_zOTQ#GV!t0nN6L`Tp{2(2itYE<3yefbn; zb#%IqNT3~N(Zd?P>{{-zimONA7slnMp1$bOw@_c6B=E2>WeTB)*+g8R@^se9{-P`ZCZc!6pPjx+BhFQujK_lvdjvlamJ)XMI|-aM_-tp<4vH=(VyC#8 zAp^v?77yfIqkA*EH$T*3mEwccwv%Fc76iIt8`7G&bkJsjQKNk3hl+KK_6xB~!O0m@ z5qNEi+#qPDlls6`6?t~>XZgpa5VZQ%SSlQChth(e^UvUz{m90atq(P(gm$Hc45bGT zSpCsIBQ}Q2cUz?#VVgyS(A`3kDBt?#)l>S@%$H>eBAyDD(r=6GYXF3x|Y8l66N8DN1M!BjC?{n#h@+{nkhV zYR$JZB;FvwAaQnN6GMq0!5rC{zJl6B% z4r?)mpD;z0CoYLu_@&>PH}Aeb{_=^(>wfXGi5oAxdHwk}u3vux74-XkYxdgpiC12D zo2vJ(-jEOF#*-2`FZ^WUU;lC9FP{CyQvAUh8vD48aC66btHv=N+XtEdUpxL=b-r`sO#dtW z0Om(W&_@1D{lR4m{y%%~0UpP7rD?;q7(_{<8GAKpXLkHMOCpgoK!90^L};LqBXcH^ zBT0!QB0+*l%p`Ko86d$VQL@K7|9FDeyED6MkH=wTlawsUwz9bIsoPyBbfZCl5+zH+ z=Q+=PPT#(D>vmOv?0)O3?|9Ci?K=Nq55Gq|;+MoFgeEthX}|u9-}9A2k!M{6eYd}a ze4gjm{GUbqEc)jUc(Ux@|CMi6Z@+v=o+;z!nMmfgL3>B5bTYl!uvjsyx_SluH;lvF|ayJ7NAwYMyQOg#?;Vogiol&4Z%7 zD4Sv~gL}6(ZH+w}vjp{TE6&dm7#jOEMGH@Ejt<0X1EdUGCHRE`Yo#c8D|%zipaUvP zV1Ln$Iyy2CXABHC&O`9NSFt7C(zBmAT^p(zk_d?q5eD(R_? z^rQ<#nSDk1Js3L|?F2!$7E7f?2s{WH{>%d8@lR^slyX&MweHDmE7;JzC8j<};87aX+dam=4}_zZ{!M?-D_xpko)1oqCDY$zzLEI5!Z6KI&v z;&Gt`Oqi|ChI?8f)cy1d*Rw0cX}R9yVbn7tkQR+}IAO4!Fyt^^D<8HSV8^A6)Y?AB z>e=Gk|Ciw=cg?yyoiR^h?iYoj;m6ay0k+^LZDZ&$)ao`-P)fmn$~+uN!;MJZ$Q9_Gd#^n522gr&it5(O(Dlx)mh_2Op#jkfGLJ*h zDIThm*66dL+%|Ob+!gPpLfEoaSkTg1CE51y+1`1BWq(}!S%=d4bz;0oCdn;hArg+IfbmED0xK6Uu4$n(d}pV>7eQ%QW`gu)dob2=-s2KQxOF3D`( z6kU}XI$DxW;Wou!KQWegH+Ez>&W_S)@ zfcrDW9U24;z^}+2*_Sa=zHOjrL)VVfhVAD1t>*5X>nVW;#RZKrr_INl3V&99Ae=P~ zL5n!KYd?21BsfPbwPSy_hF;~?2J_3Dns6ErO%GSsAciozS9fj>#rGHpiT)XBF2dS& zO%24;S%&G2NSSDAyFtj!w>W*I;d9pE|%7p5C$*ln` z4SyM<#{-4i(54g;rqlQySE~9uyi{kdpAcyiR-|{u|d=& z?85#+iJUE*S(r0k)9j*^BngLSG1-vN__Kg$yf_j96|$zkCrLasy5bg4Oi;ctCN6GU zAKI0Z)L*=nGuv62DMl>KD2kDNK1(0XXIFq+VgSF)Y za`shp#w{S&1?D0Bu|a*&{{8Xt1@&y~q8%#&{QlyP{@BTBQ9#hek!!zwo!WnIy>{b0 zjX&RY=@I;yM{eJI^#jG9as0S>{njhLy!Ai+@!h|D>G#(z{{CgD@%R3V7e553f}n2? zU_S>M=8y6b;LjJ|y>jtAj@8xCclvvN{5M~9hCe^(H0N70zUnu}RrBGz$DeIouN_eu z#b=D~+V>dWb(Gt0W#8jyTVucdR`xx{@s4u)t?YXoZ9A2IHJg1qm2Hh<>}R;Mbvl~I zQNM8w#(cWtjoVHocQn7F{;ACQNse)}PDlNY);8Vo_vTSY%+Yah)c=VcXPrVT{|)%_ z;@O@7Go5`Oa`t}2H6uBFZTzMq6(@i8ef&H z<<{T5{MH2g`OED}q~N#>=_y?NL(Ys*re$2xeW?kB9#I0&FC&G5CmPE*IP!Rz^v}#3@ikxZ$3gX!Ti*w zbs^}h&uRR*CL-{3nE$bepz1Z@2)Rc}u>&no{F(BC?L~!hIy3~W{5P7)WIfHLS^V}P zu=wcP9*at+DLkMJHFc;Dn(FFs@6#r4#hNyHeam zE%x7tVcufL5$;nRCUINY^AyRmn#VZUQkQT%f7T5*lq0lysXH*k zoEt+i6_KdNzdBT`stG=q$hoyR7wU=Kv^Y+ONQ*tTnZb;ms;gmE~$IcCAS3-a3i2LdNDzQN3 z2v=jj-YJRV+Zun?$I!3m#)L(-#(7D^daF<@+C~wrD74X?!;O{@fVj*%a%A z=2->sStgA3MDq-G?x6%>ybqQdZSmeBY+f1MlWDqKzTw5AnIPy9FyoON5cJ5AtV>68 zK+xw)*0!XD)T|7w!9+U2t1SUFvZ$989|lLGh}Kc_go#d))rM@_rbTOHpc~7E8Z<6O&K%}*o^b?9U>!?|hICq<1W=-B~Y%Q)J<7Llc`)uR< z415;;Y*jwn>7U(n<+Cx-QS*d}etAs7oX5QtHqQn@bIt22X#1ooLJ%~2fj?K7^U3j6nN?s;}& zf6+Glc!dvJj624y$DTi{b+RfFwJ%VxBo^K)7mVeqP{3RpDJ&Fez4VB0vj(eWE1Bd# zHa5jWyVoiH+!F1J_*r~}V*P7l0&)5s%uTsens$Ca&q?L-9mDc5(Op}l*8;TVN|0-H z0`arF`!R))IU93F^N*c7y9LMrv|48?3l2bZD>vT{<&TtS_7$d5Y7lE>I6TT{ak|jT z1)@m?4nv`##9~yExUexcs3B!(XGZK$@n#Mq&jqxXWpT7|VCGmMIR-(~!+oW}%Df9@ z=_AkL{~z19`kDHqg;bvulr17>jWC0n6Q!h}kw0q)S{tDFb9^vxSd2Rou&0)O;4{%1 zzmPzj+!hmvXt{aK)16uI*m~no&DAB7wc~X@bQ5XvGWl;cScJ(^&GJu+){e01Xf z`IlE9z^IS#UBm_YH9VQ`>W?Gw-?;T##h-7o-*;cV!SlAae)%&o-+1}zZ?BCa)cFAT zjQO+hXS@nO3Y-1Uu&u_QfzN`VN8cG4{Mk3Y>7n@ZH)ed*=K+{~5XYw<6w~r4` z+2{+f=%2N^1B++6^9+vP%(-3<&UN|n<9pI}7o_icwy@+!|NQS@XQg~r{F!ec_xzvl z{A(Ee8H{h$Kf|B@?SI|+{_?qJyeYb3f`FNH)|i7%MlLv) zx}qgB1-UW?7wyQ55gwQ1HWudzb}lPy!xN)K6FC21^#foQ2g1vpngkC@1Cs~ee{*&Q(F-DtUHY` zzh>@H&|D($S@?4a@R`oMuDxk38^UWu_%nDGm<)WT zq#)G^Pni7AQc-bJRC~@!1m2ghbIf0JGH&Uq@Bk#x&EaB6-OMH?Z#XtmYS8Y42---J zr;;;?ahQV7w7Rhdi4LDh)JsL4$rX+UIOA5Wg4&4HAztS~yv~NPPM?z@o~J^+pz8!L z3EV}_gnFF_^*A05h4wld;ZqgijaV82e0GJi1q*8|i|6`9U8%)5HfvP{JL0h#e6#pe zIKtGLu-Q&EE&H8Ft85j2>L5<>VFjOU5wx-<7~krE+9t91Y}l!(_0Ow=L=x%LMq0Gi zhFv(~&mvZ=2{KTJdK!gErfkB3jooE8uLz&b+0_b0_A~dc?YQjt?cn z9^VRQ*5R|l&U$NOzHtZqS+VE|;WM53Wn*(aJ9??ZXO-wTT=WaxCV@Yzy;McGoQ-fp z?W`VBkPXA;5e?#SE)Or9iSRlTwUc zY5pvqSMwWDhuYDx(ocjWy05Z!gFrU1dRg@DE0nNWVQ>t2x9w0K2$~J)7n7@flF$#O z8~{XD8n(LGx(iE$l$g^@q4XOXWcj^sA_^Z~gTD-umw^5J8}4IMtb4*UizVe&wK;n zKDdsc?;OD1>Wu!p1sQ@U{SF>MMf@gAQGlUsob62UfSUp3VRZIOr#h;Zoh)$vV%koFd z@&=#V(w>!4yCLFa;?kpLKa|PXVgSHJW*i~QI~lXMB|Q=SOm``j2Xht2W)eOr!AhhM zq4rV=9cum?Sa38K<+SeFT($aXnb0H!4METZv>9j&I>u)Mh75KlV86(NPlx-|rY`Tu zOzwMb3l*>AQC55lcWtR!8-C0LfA((<^KGXpVz_ssN#OGt)AabW@MIf%4aYBS^v_24 zY@Y+7&xN?1Uha1K8P78zKIcq<*l5?pEUHadQkVQBmL|2yPu8VAS)clJJ;i-eo}$oC zb;8oBgvF<$0**&`KOgFTY=zs2P&ZW2peiKLqFAwLw8GAMtMg|gRkq0$kydhOQAAspswYN|4t+urqrzF|#w13nY~;r6u^wX) zH*T15lL_;-7z`4fyXj$+J=^5E;j>MmUobjwR&Fr*OPj=oKkF}b5UmoO zLc^a4_Ja6XS-vX?G#fUWoSVYuHH6G<2opyg{)srT+=YMi_>-?mUe=Kod!cCSrTsb3 zNQExN9Kc%O58y2P+0Oh~Nuy~$7N!T%RQwq-X~Ul(mVM7{tWAEJ=U+~S`FC!Q8L3Dc zIH)-x+bK&wmc@JmlgQ`Qs^&SOzQ#2u-b-ug)X*h#Q4h_5SvO%89t+xSJ&;YX3Byne z1E^uPRHzq5*5PBe#_VsH$=x1qJNK*|?dk+|BCk>aXc^{e%WWLhNaR>`!*Aw(3{ z>b3=SDk)?s8&>4A$IgRU@Mo$bD*h~2n#P|I?)L6j*|P5G22nnX__;OSzcFb+-Nvxa z!ZoVI9=cgRV-F?v$_rX5c1Y|m6xZtm+9a0i^X}@O)n}i23wg$q*~p(&MM9gSDidm2 zXoS!lu91?A(PuZ}_eD`ZpevGK;jtKHz=T22@&54V?xX+^G+x=*akM1`p=7R0S`6->2PJ|_UZ1KF>bff)ERSeQwKON%=PFd6rZ#ocQ{d$+{)WTxp)R^^H9@U%U0|>$gON{3{C31ESx)+dr=qf5w7?-SLz2wbyRF@{14u z^+)e~|D`wJ&(|)#d+pM#s~5!i8UB3vqNQm2JqqpU2xzq$-&On>-|TBwUv+a|@Fk}& z>il{B{ciX8^W;p%_^#qJllK_kb(DWz=b8NT+S4sZ;~n+e&tQKf9c^pucQns*`-A22 zfoa5a=l`_EFPPyrVchNY7|)S0ceG#Qn5pFV=9&B`-R zt2xL5;K0fO10>s9lG~ZHzB(o3Y{bI4$l%6^`AC`@q5>$ZhYGqiYJPK+NSzTpOGE|N z$1SQd&xcr6M+H`!r9vN3ALZ8^gI}}{cF@SA@t~+$8PfmkHcXo#z%6Av8%uX6t7phF zYGm}xT}601=b^(9?5wrogHa|AnTjVf#Rti?gnEVCHE4fsdvDIVmJQKo;-0|S<4jag zl^IpGZ)=2aXM{$2P5w~dQ|5(j+Y_j<-cy#{T9!?XbrnpD+F3DYq0pMX8h;N(x!d>V zw(i_gy&>dS6jEnzSUS>W_%p^7Vn7k*gEkoEtl+b_QbhSvb-gz$b$D+^e_1XMv^JGx zHYlU!tQm`DV(DIS;6E<__Mm$7k&=}7RiP}gPLgh9s_{*ke!j}z^ZiLNSI-nzg#Tj23 za~td?{LSPpod)P_)IT>wxzwATZ9+P&pjc0g@Yz0Reh!5Z5~@|{n@eKYQAdI|AqD=D zd^!_-q0sna2!hs3p$$eH9$JAyT3i0i82B^x9k@CJoJIT`?cSj34D(#eFV=o5Nj*`cN0j5y}${CXcgW zt|wQx^2kH|swajDR$VI3fD2*JsyhQH;0Z4K1o*R}aO_$`sTNa(4oxvj^|bbkxKm-i z=R$l=h4?hBeg@l+p~{Sp3w=+WD1MA1IkpP+(vBfqjW8QYuiB#;pmLo#>j_6p2(zUE zphXM}+SSzKR-+7!KLek;4(#lLIae0KLZOrZPo{-GEB*6?D^crF^Xu!eSvjuAQs<%F@qQ z=1bAK(k$F0sIJJPOps@)?9sLy(C(60U1DswuKrT3`4eu{`Bg}tTdTC2S^Gq@I4xuBtWjusZGq1g{WCiSWrMrp`0QeN zT^}6?mTyj4b}Dws&SwH#zdY+K7^y*(?2@`&NlrTe|}FLG~W8|wbwm; zmfiQo+3@FY&ibnFgKk0hyDhrkb?N0TS}QA=sjX)!tpg~{BzLk- z>%TU}ZKr#_9F2F>Z`_wLcQoEnzj0e*?r6NDe&e>r+|hVP{l;yLxufxp`iHp_!xD_#7&XqG2Xn#(n4j*Hg=k3BZ$>woj$UzhEw_@6)ex94_Ov^EX? z@@H?toE3Ja#R?1|^xgg*@_C)#$e+;_-1v`M|K~@yzI)}(moBUNgP$mWmS@?J6I^_I zXy7M_F&VR+=6w6V{zX#Hef2N1f`S28z>7wJw>GX7G`-tOp z{*3tsHTVc9H1u_#B)fS_+}W6=HKzG3Q47SqIns~nGazV8BYws8!g&6SdiMe)m)#ttSV+cMjTWm1XZC`hVkl3O9Y=rjqzl; z#+h~6TpJ0yc2zIOS^#pSW^4<;6^txp)Ch}@0q<%thL?5mbEJ!`MB7$2G$3e}q+?;p z&CDhUTD6U47x=TaXDqLem{%Jyw=Qy?guzKeh%2ok}vM?QG8~C#*ij%yEPTE8e zv`?2tq`}21M6|4VIAh~Xh>Y3rQgs5WrPJEBX>QWAL{E%&Pb~adT&7zz8)sUI3BtN% z{#ft&XsJcmpA~WKz?K(}W{n=n7x&l7ToQ~pE}Y1@csy&gVq;HwSaWJ%3p#DQIO1HJ zakohE5{!kx3QNxJ^7OSC6D59D zmmJrpjqKTSxpFl+2<-wE%XF)-pL-b-y3JTR>%v?K#=wxznVcme=2e?0ojJEYY;I%N z+?Mcpv<;z;Yu+03noM(>Opi5~=GL0#$tK#v3p~F7ZLX7WMf@ytYHl{wCTF>fBV0~} zx|}e1wr*H)xoF!9l~Mr~=U6~x_ko?7elowmvH;)UzVb|<*|Z>@5wck})F`F$kx;~v z79ggqJccTE^p%TU0Mt&riw|XWR&F0UuywF785bs;`RkUu<0Hh4(UBb~mn$<+((02; zDVgT_)tV=8PPn6a><^s{?6n^-#U6ED?9Yyx-!h58?ZJN9aU%_%jyb{3DiBL+2wE#C zsKITj0rpoS+06wbW9Y$63Y>oN8CJQvXF*OdfTid=G2Ge47}Dpsi;C)GVIZ zWjTDK!2g5;OG|K&hxg|Wm2B(GN~lkLvMDZD949nay|Pt;gI6AGhC55T(oJRAgOWH zlhgska2sQ1svLH+m!ts2pSdsDk*t}1Xl~3P=&pnXx)xfXwBo~>QM08wVf=g;vIGcP zD;?Mxzo0pOVWWzK1sFsVe6-dCOJLbS0GSE#+=%t-PYj^SA;u#LL}M!rh2{wKBrm9o z3wl0k;h7Dw=^;!0;!93no-u3ln$5p@9ju-m>gZfneu7=i1rj=uZdD<8Zt`nwme+kioHp6%+xYZg# zGhJ*#e@jnn2H3o07xQON5P`E?2z{_x3@tr@vz+z*2@}h%HQ1{L=$oqJo?u&ANk8a`pW~QM}GR_o2O5= z96wt3mv)K`L6QfmA5aC{(AHJeGlLNSC2gS@M_aD zRi$|?rFpGIIh}hcw6~+HXlHA2Ax6YfeohQ1{-8oUB0hR(1r`Of6Z&kRX3g(H%%AJ` z<`6hh^cCm!6t3sV<*JB4;3`izQg)C8%`-mF)#l(6k@GP$u3c|x1vuxSjNL|EKeiIp z^q$Q2om*-)$DD{=a?TuFh2w-d_*|&}ndrq08>4!5ZGr$d6;a)oq-bk*Ng9(klp}!_vd!*r;ZR3_I}yG3L+;xF zg(kYn3wwy-tcI+_!?D4~LOrqakmC^ULy5hrDBrW7U~I0#{c4wcBC&ox)Ter5c-NlI z9Ebk$ohZ7wz+mQpk^Zvm&b-w}O!Lo#2jC;k3}Os|e{zI3Q5)$~AL)bkSV@s}Xl#@# zTROqTVR%h@sjz}*pV}~q>M%bkXsCHg1DwxAhz^-J7v_N{#%YuL*(fjKr1q3OJH_f5 zhv%vgzjNk=b*sYLv)6R)PHQj8fa-MZ&w>(k@k72Wqi0`6|GrG1P5-`hg`EfYV+5K$ zSeY?&Fmv#bMYqN;(}CjceLL2+ZHwma!-)`23|Q*Jy&A*ZTO&L~b8Gf!k92L0nAaFJ zuPJ6;Q?zrV7WFaC_0g_GW2}2ajGF-7DB;6;)S2CCv>>UEa%9j?s1a47%6k^F%p+5LyJFygp$IOF_tsoh(a*CqHg z#(T9U`$Cf2VqLnEME|UeI9d`tEHeX~LFjRwU0RSJbyo1XIbN)%H5(9zt>VlOT?KND zXxEslVH34u+G!(sZi;eMVF#iGbQ?R>R(dN4I?he51WlN&uR$%(evzt2t}cx*>le1( zqhEm&COUT3RP>XPXLWTogbFt%$429f$(aB_EB*|2Zr1p-rg@gDUGCSI<~BrV{5gCs zY#9VC&N*S8wV@t5g4Tex=BBQ3Y;LTa4WD;1%(XgkQEz6##p1LJ810r(fUCcw_hr~!1039$Hk;QwE-16As+4N=Fxp=pLPEH$wSe}_sIFRImNtG@R`=0KXc-+=H`Ey z&aw=hJcFZ$4sy>TPX#!dP&p!PxwTQ2qjcAFBE%i8*w$N+(7a|@bBrH=5x<4{7!g1B z?@Srwf3AvL6_c<05Aa?1Go>>LrEh12a%?sJ++Lb3B?5WSKx6XU-@&mNcP|B^`9tG_ z4-{?b%uZ}t{S-wQTcZQ|5`zbl7xq#v5WzF97fJIW&tlPxGC5wzz+ zTI0`@IP`}?cO?6FCyUjygysRl2@)@8C5KL!&v-(Xln|i!^SIVpwUA9LAsbqZot0k) zQz7BDAZU3@$g}Y0INvUAu!<^szEmezxb;I zB?n%=`Su&HzWe&kciw!JvVeFp-$Fcd+aEX|aR9{!U%&AlyMFbxcW&PN;8(BQ`qv-b zdijOlYmb5goVDLaSKgMNNEbhpm?nR|cKQ7YigF&{{E#Geq)YGcXE1YhSQusclwI|L(WjCWwV@#rL(-O9P%SkXd^GuY2h6tlh5Ob zuGsHr@_FpXJL>to%wx-$?~Fg&;OMcJ6Ny?Koh#U6@dr>Xd-C(8&Y-#;?(t{)>-jU(qw{BOBFJ5vnI7=xrC;(ED1E>C z{D&U%_{z8bZ04W*>BE0odEof3UU_?H@a6K7HkdpS^SWt4q$<3 zzf1Dru3gVrQ5X61VNx+^{9CX=O-tWDxcpHReSv>mqyd*7g)<@EZy$3s{CHv(qk00c!9W z?oAOuPKql0M`Eo@Scp=(y=+%2cM3}Khf4DYcc=B{t!~<6u1Z*XGTg7h6xeK{+@U|7 z&%kHJpDD@)d1#CDYmW@94-dfqvnuteo`TgQ`^A5Qvup#OEeKk(;J}DO4gwX6_*_Nl zJ$p8F<|JS_*paxTLGZ6uWiQ4b>t+xudgg`|UKnc}iwLaGOn`?VpKdGJ(YP1=vsg*< z+nHjE*i+-bamM6d7v>LwW)c+CH4)x~BF{$nY|o+jFAX&BE6Ts%Bk;3y_&|=h zZt@uK&Nclx@+-I@c~Nz=pDe)S))?W@8s*Uz?E&>|GCvN*h2J*Ex~gc1#e-sQ0~9yf zwJAoFr~p8yZ=DIQE7)0)XM7}hSK&bja7&ac2%2F82^^Sd+oD_v5VX9d)mF1$z482+ z!72d7V@NR4t?LkN!6K(u1fV<1}7MNf!uHA%2VHLY^^ zb8nn?Z=8sbQ6|HOn-jfT6Gg*}j|Af6-UKvqzPNBy#d>ybedbE}hRX-DE*usM=z+tz zeMho;4`&S?&b)Fw=Y`5`7oJT4Q`g3LcBJ^>w!vW$*|z4zVWrR({WB71u(KZcY+(8U ze4Yw_=A%KCIq62gYoAZZff=Uv>xuoglk{j?jj5w`3atZb|(PL z=?Ss3-l_Pre&<3ZHDMTTOw6Lk^JhWO@MkVUXftjbm^s%z^Js0z<7|%M#<{S$z+`mz zqSZIKDB-lop2OWO^+Pq3t?f%D(XQvYT-ZpUPh-TvzhJ3P_U5g^1sVk=vP@xCl~CyX zw({)GeL20AViY{BfN|+z+0bAStoXB1KEt1ZnP9P=gBV2cXiO$#@)GyOcCBn(|4enH z&)F5OwIQBoLp+XzcvRrbzde%YHSmR=lI+>K(`hYUAFLx#620?tnW&Rx^U?G(sBR_j zE@V|R-^k(4X753Rv}X4-*D zRJa*KrJL(FEw4=oYKr!4jrK+9+88&#dF@jpyVqeNVY8Ue*h}rgf?soze?yXA zi$;Bw<+5_m0Ma5VW__VO95yWCXN^DiCHQy8`Vb&@HgAay#D4?oUK8WnygsxgXVs~k z4c`Cl&mVMh@^tnX>>GXK_4hD*);yoz=cnH%Q~Kx4>+<91H#gq8dGj5L5B~D!^84u8 zmES7q{;b29kNBb3+{nQ`%50yl zdGrJL2`7$@u>CTuf>=>I6FP}i$++>Fgxeui*7&o{=K9MCAv2x+Gv@h?4|)j2pC@X0 zYo3mv^+ey%6cZz}HRe;?{EmlB^ofMDJ32nb{z-PqM^Lvg99enj*Tc9II?bCM_qP3X zkAMw-20nB1OYvtOrU-cGv3U=F?UDN){BO3zy&e?hC&=e(3z;-wc}J zH1i2xuLF4-QNT)p@1jDDKa2hu=1F|M`LnKk))R42*7!5jy}hgu5pqM``sY)g!A==B zVDZp{vPSr|#LPcu3aE-(*04UZuVDRXdG?^@uSkWO9?j1g=n8*sEY9mFFQhCWKF{50 ziB&O6PMd;i;+FMguN*E)>nX|P7Yzrw0c~(;fu-gkAiAs&B28y~Np5plJ|G%_G@T4k z_X2>reWiI6F6`gArFC2Ux#Xu$MhBga^uuriS+dxJX#5#_YC_dLgg+CFCcj!!0M^s! zvC&KS7i~vJgt%Jg&*-030Kl8sdkMZD`EX;73AZQu%Cbkw(gyNV`Zh(h#suU1jGYLG z`?SeZJg&pNTf+U2K-Zb(pNa~`4|({IR>!ckfa4&Hy&RN{FgUFvJ5}e;jbS2z76fhO z&${NBM8W4tTBT}M_8JO73l%3qeQ1S9hvU4V#Lw>45mWU{Z%VGAd7wOt`ab9PWnbQ(bE#&|`&tlwRM)FEAIN`}{QIKl5u?U+*3$3YP6{2j7 za#sN@mrw=fVqNhQ?uv8ojB_QV!d-$(hZgPe&TVn?tSnk&(#*!3AViTsYsLk%n*WBv zh8oHXcUBT>jY+zQEL>yq11r5$46gK5(ZABSFV&|nmDX2*XsaAroT5RyS|ExR_X$U> z8UuC)J`;F)z?>n^ttgfgWu6`_I5jZpmUy4)SkJoDpsp;_#eG{Y9?n7e+k@A=$; z=W_=SWnDNT5@-nW* zZ*gjLmTOFOoI7DB?;88b_3=|l)V2yW+mL5uQQlQi-lrqo&qlZq_}fTj&u}r^ zP$B$zJmRJwM`&C-2;Rb}<9LYsaVouTHt|UQB?PPcGTX~D+ADCt$XB3DmvK&=0qW>- zY!i*h0o)Wf)}1$c_GihH8kM707;;@FqPT~3UE`ieKT=O>*?T2LM1-x}iwe{PBL$D9E-nDcu#0Z5ID z(QgD8JO5yFj+k;Fks^<}dR*hrD4(fI*jAAPt8W9>S7fQXFdS9!%Gf8S92_N}eOJj= zsxvfi3U5wY)Nb}4hz%S`3I+=|C3rW=ztRGS1^H?a7$yuHZb=Ai!6!LBn2Ln08^Z?+ z*HV#ibbl`TYMelt_lu1fdlA-+??-tK#R}p4L*?7J8Qq#0)wuS_hD50_2ylk|_G;p4 zO@wU0#n^EOd>$XhH7G^2YA58+7IzMOo;Am53#LX>Eg{7Rd*b|i6&h*nqm!C0#j59lN*fSrhly_un_i=?hOTdFo&O*H2&j4G(F)b>qg{NRNK=n-8!5 z`dxk!PVl>L3cq@$zSZm3-$!l@^p@X8H*fvhzkT@kfBX9vFa1uH!nwzvZLqWcavXCu zSc^!Z#!K&CyY!BV@4fWTo_`+B2bDI69PJitE;N!vfI}3lFV)Ax)7b_-tCtEv zPXwX`KHG#s(9F+{9EFkGsxii%spO7ko>u>a2SIfjIkTgD!gcEKT<6cq9DCe}yT_S7 z7e`hm<&|IjmU_f|4sH-8O| z{=hcw@n`#EV%H^1gbG@XahG$Ae=vSC3Z+`BZ706r_`EJX>+3h;%7 zJfqI-*|nu3Yh~S9)2X;cCrtjQ(IMk69UX}5Sr5pwg3r_nv}m@&eZl6`A3SPaa4L0q zbN0&4(rmqyp(4)+o(ax7=$p04HBge%TAay8L)3@pw`TRzlr=LaaHIK-%O1g|5XmHqxUy)VU^vT4RW}eQ`u- zOnIs!BXOuSy{%+hQ|Y#Lo=HEDHB!E(=f)51S#!Q(%gEvM3&%2tj;0SC-rl!=Q(y6#uEK=2 z^oYjwPxDYbP9WefR@D;Y(-tRg56w{?fM^AK1s!W*V-k2QEVn({r87oa0);K)S>Ur4 zsHW>;+z7BUQ61-A8|RLXM>7%aj&NGJTa5ANNZ_*@Y`Hz!O%IVtTi~q0Va53F5QzL zLDHV+*_Q0pmg3o=c}@2wdJQCbcgF~C??^-&?_HbVQ@eV>z|Q20mD@+2&*?gx(Q_ml z{)`0&2zuzSAm}S)8+*5f@PIQeADy^x#Ja0jhu8N|dY26!tEjkA-vNkr_inj#xZpg`&QxTdKaf3CnJrgQWfswS5Hy`9P`W&WVg%gd7_GR>1@T~1(?*27!2YVF$Y$eaix)W@Po0AtqX#0|a;LrT4 z-kIb_0vX0Aqb<>|CDE@b(XW-Fflz48&H~rvmgJ>WBKD3awj1lNkB4a_6wV3x8H62m_EtH^u;)QJu7~Wou;5 zvl|gwtbS%8l?T84z#nbely?2*TQ^^O_r}flUVZI@S6_W!@#ohk^j)<3jbr=6a5@7J zKf|B-nR)a2hc|w8>tFxnz3*Rpb7KCC^Tzc3H*{e8pCo}lQ>#(IXC%-szxca~107CI z!k-^;dYF1oI)BFU7eSh4{QKF~KiiP2=@L;#4^=0b|i$pt5?*$ z$?xhBQ2d!z`EMBY&kN_c`91X5*JuCvmuEcW?(EssIdt>J`$R)+Z&Q6A7SK9>=G(=@ zk7C{9&r|rKMSW+TKi|B5>*qhe^$-93)6_q|bmarZpNIQ@92vTKrqi59|Lb2BtV^gx z1dE?=@s94jJN|R>XDfFV%L_;^z8TcrgFiRz+;(b9%<<%9r=kNJu{bvQwwMEJqk_*R zKG~JCdax)9AlxOOIGZYg{1|~h19HK|ZToiCmFCNVEzKP$&l}p4-m*3ROze`{)a64v zHz1krF3v!HjP|&pI0xpeB+wveKs2QfLC{2d`3|vzF3!ho106M$5C`_8_3hkPwL0uf z(z26L^P%EGp83hC*(PIU%%j%IMY%D;hk!iOq6EgUy2c!IDm>tDc;LZ^;8Q6ps8`rs znl0L9oS(6q(8x2y8}f|w8fe^HQGh&KxG}$2OS5|SY^~d5LTgQtzUIh)7CbA$ym3^n zj|sqhqbkG${|($fszQB_g!we5$95NQYlg8`6bQuT_>^OtoYlX3bHj!RmVr$)1QgCJn*j`iz^@a!^sbVYk~#cJ*lah||T6wX*%w8cD*$3=6jb5pEyL!3k% z5$ghfW&lEHL8dY8UD48_qXt2vg2qi6*N!?Nfo=rUu}QPk5dIv+VA&Vr!QD{qvC!1f zB9I0?$GKTF&#`X0<{9iv^rpD=r4sHWss}lACqihk<8T3A_^5fkgCU&}^UPM4#GtuXBk$&6}PY+_Q4@SmxmKncauddk$sx zAIiatW8f%$tr=GiW?n5?*S+p35OialcT=n<^5#x!kn3t^1)_EMY{j`c*R@R`w>nie z4pu~0e{1qY23z^_#GKh$r_%OaYc)W--C10tt?+rwKb*7ah()VORBO8INPUbvqj2c`U~NcvA53l!ebH%zr-G?|GBQ33Sn+!k?SM zoJHqsa=~Py%H&4K4I?ac!rYs+Xb5qxBf@1uEPakgdYwuL>dJ{5F5YY59YTWEC5^G0ff!zAEC~&N@T0!7#T()0oz3uB+{$vkto&KM9Qz z8#=P%&#rlrE4C_*yU*TK(CdiygFn~A1U9UFy8pR#@Mq(}CkH-%R`@f=N*9f*L>)bj zWY57uj+p!v;IQ%BMyV0}+(xOnfPu+@ybh@tn1@jb z$CP7#zL;|CL&Pp59N(?;rD;PuSNCj>#6%i`O~nw%aBuR0zLW*nL3btjb*BV?prPMz zZ!IjI8#eq|7f1uB#a=`6eAbOPq%>iI7;A_Hhi21Z1s9b-bpVVgu`9=Xb9S zxm>uaGb6TV*Lsu>b$haxxIK2ilhfD!+t*K>seko1@4a&4EuBAupl@7%?-S5J1E00W zZ266O>y@A1`r$vm{qhTMUb~D0TFeQ@>7On22k&luoX91sp{~e)-Ka zXD>T_;Su=rmz^H;eBj&g=O^a4E}iLW<Dh;wlD3a;OZ3UXXMWKv;ODi=(^Ge*d&g| zJL7|P=tM41%z4pU%r(1vckN>8`&$RI8H(r~_=lLFg zo(_K&ynp@H&wh662j73|r7LeKe>3^E^U3-@qkn$k(mO9-ef!$w8|zY^eek|V{_>%R z(~_d9igNH<=qMKW++HO5XPDvV*nh()dsf_)78J~5E`EXH@1=Tp|Oy<%76z8&=#S(N1i zr6JWF87U{C7h%-gnVB@QcN-=T6wLuyi@^n`S*tln%Sx2|7!=%7wxh4CaG31f=2iYyZH$~wb>D3tN1$@@|v!;30__N8k*5pV1#1p0f zj4zJIEvsHe9A)c6u*>jl5tQvkG@3nC zs9je_ip}iFaF-L2ZpWj&PA3JPUA?3uH@bUQ@=)mp)U#I)XJ3X9iD^UD=)ttn1KTc? zZ#=(e^-x}X&(_e^)WuD4{`}ZP4owj~D6vSF5isNW8|$u-VT_%nY9S>HsaII5g$|$L zy^!bbX!rgoY2nWrxE3Q0T>=gIV_I0Hg3s{hPAyPDkCA69g;qcqB{TdP!;S6)EfQTt z_AKz(r8mV@gU@dLE8R&z(1gyP1wkus>PQ@Sh2vR3qLDvq@EPlA_N6|cg3nla46pVa zS>vVR{2HGLV`Q}tbea}At=u^ji0(-SEDKCF2A#&R);IL(O7+mAC&i;T$+JI65H#Xy zQBx;+w)$gv0br zw0AwkS>kq~(_Q_1sYJ)cMux2C0B5DHR|O?4p5B_@i|VJw`#kGl z*(OoSXWhNoV#lG$p-(J#IT7YwMXj-IrryG&;o|k972DhL66?2^&L%B7#XqF{v4^=f zhr58F!Ra*-&Q%(M7XBRW&h00~pPRIQ5SW?0oW%t?Occ~r$qQQ3Oe1?YTtEd~k%dJ- z>;Bx1>GS6a7^cRbmGd(k4BJ~UGXH|H7p#EKmv0@}v!*{QwsGaslVP4mo_0PR6;QwC zsqURAL;JTwFZ&MXQc6`M)1_I%lx+J5JbVnL-fj{j0-gF+pO2C13Pc`9j5( zD`i`U3Rkvn3O$#!fE$;%IW;EuH%EJNR%xM(d1msM)|yMUAXM z=Eq39XMIN~vDSLc{I=JOM^)>gw_`CnDN)T!knramH__Lk;$Q0l+U%+(zv*OSH{_meMf987^{Q0{t zyhCM*f~*sN^QVvf(U)ef414O-o=jA@!k>!@6@P}Ne(w3RPM%dF9~n1{@@$YY)VI4h z9|}$By`Hk{;nMBBS@Dgr!EMn&4d$S8F$=qLR}EnUSSkepo5~AewzwrX7iUWuN952& zI1?5EpBu^x;m@dxd-i6xrl$g*tK$|?|D`84d1%k(!IHGDz1xtZbnVUP!C<*G50Nu% zkEW@n?Jp6Z=fOQ0Xr9|Ml4{nhI29B8Jc?X?V@CR+bGA5aMEEpEQhO+X%6bGy7GA16 zpFza+Ccl~};Isen=-_j!Ls~PE`kvhkJRdB@5F;C4uIrz5{;b1il+RdOQ(ducbM(=e zMZ y_gUsF#NeKDv$+0bYbA4wKj>Fb6tf0iE!`MZRQI|?8>unP2>aim1gulx2Y{F zseWw;bQhwnTDlPlR}$2@}6)%sQ0ZktgxNN@v4d z;8CC__1L~ViEom+W1@ds36v(3 z@>v!Z?F@Wwjh&158UAb`&uhKU6Ki}fto0@IM7`8Ihu2PkppCTIm@7tY;m;`^FlWV| zN%~SehFALb#Jlw+cn+la;xCP#b61LAQ-W7rqF3$ez}|wW7Y=W~d@LK=jsC;=T?g|p zSm-@c$OGUPD|23~NbAjxsY(j2it%oUhANAPi9*mCe-;D{cGg4j=XSGKtJ&+e{8{I> zB#_(jY+01;3g_zmDlu$zC;ZtcRv!b=nkZU_&m@XJ>%>?G%lfM5Q7h5kx^1G*rom@y z!(Aq+HfRH%d1>U&3O)-c4)v%C_XN+LjSuS1j2nRaC$Un>bvymvvwO20p&{0A6?a%5f zPwOa1=8gXwF$w^iBkTr zJK4W4#lJta-{8^ODR`RS?Wm%h*KP#!Tv{*e$s}`?>&|~}=t}gsJ zF{mwZK|}n)>cl0TTVk%1r1OQ7L%}!Fw1mh%`l8eQ_sukg$Nl0z-uSiEc|+-r&?LY4 zn_I8mef~_L!|SiS{p$5wuU)_OfB)r!@4xiMOP7BOKK;1(^K?1$XMOzDiyvOO@D7y+ z;m_Z_{NW3uzZ)9*$wLo+`-@JqA9kAK{=hc_?|)qQ^Gx^8lm1y}n6M5A(&E`4wW#7} zjvG7TX7>Ge#*x%k_N{*8KVo7(Gd*A{oj)rl2OU1^J`b2eh@=_63yXf(sv_15E})?F zLqvtg&eAxosG6;sWN7fL?|5phPKiBde9K)6*NIv>ZGyq{xZU?n6>3{reIDV}HZkK- zK(6Sh?PJE{kY}5KFx&L#FGYzx&G6L5+q7QyJ?3%WW47&#M?LTRj(iroR@SevbYn{= z^j`6BBZW4KqK%4lavT24OZzL~9)EW9S8RW*9QD}Gpn4pQcho=Kd364a?wvU~m585d zgC1~oec+q_b=H5G^Tqp<3wui1dX>*J}J3@w0-i)Eulf1)Mg| zKNho~ZewK6t_@TG94O5gD$D6D$?h)6RsI`oWt!Ktwpv-U=9mF|MlCb6cY8;A5`H7c z!u-xf2VzOl9O;h__L%;eor0h-`k<0vm^b|S_zI84wJS!RTR&2gHdvBARFpQnXKQO( z{K@#mtmHIfH2BPT*#u;5@~P57x82ZW&jO!qm@_XMFwoGV$?V+{;Uy8N>4eRQpMlR( zfDisG0R%RCTHHuXzSxGet`8l0cFmQ_EG$xcDtKHsvv=RNj-9KHB`(Ha1s4&)_>tbo zo10ATXr~*ZylTWG)(wm-`f9T$p0Of;G+P25C8|geG>O>_<@0IN+^X<-lrY2V09c2F z5`?8wud@+8)p7G1S3l96W*#a?x>~;Jg^DdN9^C%o;dEH^r6cJV52q0q4sN?xx#eQ{ zhS5E%2J>ROHm_(%UWmgdl57GT4QvN3f-8kc1Ct|N+ap~&%&x#^1(Ox^75fV<;JT{9 zpoQ^9+w$i&jr}%9%_V@(0)Z`|%@8%WJ;oUXEzTPW!j>V--AT?i{22tT^JfIoQkO6u z*A8*^5EV3K5UqZ{I)YaGSya}V_*q-+7=KpI8wxmspf9ZRAx78xs>G&eWS#Hu8s7m_ z(5t-rR(h%EP4y(8$`ghdcW47-*h&wgUyH$1Phue1i%F4l+BguEF#)U0kFK%S`{810Ux z9Xj0<<)Kvc@MrxpwxP#zqN6;Fod%vP%y}xIHs|WqS z5`6eT2CxWMith4s-QBYo>Pt`KOse>>$e+YV;69L#R36#HoCC^ZX+Y4c~R^)wRG zDaABD@3an%44&dLKB-|?Tl62=fs->xnVSOK8t5s{#DbV(PFUFKzC0d!>MJi8swm)p z;q&FW#4xchTT0)SXAG33_ZLyjZbNfsV)e#|)2Yv#Onl;W;?i?TOV6Y%I+HLTW2pKV z@l|M!@oSEyEQNP_jAu`*SAU!j2%1s?)v>;{tC#ifUW+Q8ql6QMQUa4GSBhyL=evC# zCz@YDdmHksj-e{T2NDgyIT_j`5{t-#}6z@L72^ql?xC1R;d(Kz@)QLTCy@ zjPBhuvOgQ9-L@~c{lJd4{e>MBh45!?F38`MczI>_QU>m6Rx-eephn34TL~{sYMYfMT6LQ!9{QJxHC!ry4LG@2gCzEg%{?t(4LU!60ikq@Tg6 z>>!l~`{L(IBr%CU1DX;S)+Q{Wbn?i~jTcL)tt{f_+Twzc0M7@gOZV`9$;sU%YA9qaVEc-K%fB%)_CIKVN=V^WV_* z&yyve6@Bt_f3HpZb7>aYS1M#D%^NUWi9&(!HJnO4L56oLU z%VpX9UW;dYY5vc){u_!sIN}Ub@Bet`0dKNvz%rq;5qijZEBHQFeSo7Ce!S~(w3n&( ze_ZRCaF51Aqz33cD$#MVqkesWO7vki{W>333B=ew#*eXeX0`#6_AkYHVur;q8H{WM zn~ExnhS^A!XFlcwN}chj&wY>5D%wl}1h#Ng4HtV@iLuL!Z@A6)hE3~y-`D5e_jO}C z?@M2s`=zfr&-jK-xX%2h%gk>w(ir+|B#fsW7x#UW#Z17Zm8P1d-pz2+CZ|QS?Fv}F z?>jDE`nKDbzCB?pbbY3vb@@b&TgE8xu2wD-+JM#-|L0^8+z!x#8wZ?j-I_yBV3o$J zPF=wEfBW`VzJ8UGOnBKF2TYjT&v|biKluRv z4gAf<`EPuJ{Q2tWJ0NJ(1=p^=S#$2CK=05wUw9zUb#6(M$K=ET1Xkew!BrH z#hI-oJL-!HYl@_XAV*AUIBFW^Ui_bnaZVQa++38?i>mqA?Ts7E)#d=C!nJ1q>L`CG z^ogkX$D)FcMg<*@S$rn(N$Lr9Y)|OVS=E=jx+^nLFs2S{pp7O3L}OD7k;bLDK63tPQy`|(2&)G6ZtXA2>?_aY6Y;Dl zB?Xo8S4ewRP5o(#+nRRkevvox!m=A`pZNq-}(CD`#mFv{?cb^qBsc zDu)q%RS64g*F3`$#25E$87^GgywP+jdclb>-_xNOboi*UgTkMg!Q@jN?tM-Ruru01 zLTsEh6*r$$BFamJZg!!PHnR`>8CKkc7E~*!*BI?u7v+Kk8XfZ4D7WfZpR;BkP!f-z zwr!0Z;y%LuELaob=ksU+_pWK&7Ircr@RV8V7&b+Ewnch&M0mBEJln!OTEshgoLK=d zN_lz+ZqjUEHAd$OZc<^vs^M-7FoxhS3kSnB+KVHGr-y*?grMd%%X-pG=XWJvF5PhX zz}8ELwqJlhA5I%Rk}h#*`;|lKR}O5yShk5L>k+@zZ(4pPX~D@DzcZ2E=(JgLXS7e7 z$&~;>1EL|!90V2UnZeG46fUG{Aq+Xj6^5)jHMKLG*+o?qw6NbX@+=72>c}BPTIbKo zd_$Z!jQZ!5?gOd#KMR-E_0Mc#(LZaPTsLsA=g%x#p>oB&(LXEyXS_AW1kW0LhCi!N zESmh{20zt<1loo_L!n{II*!&87&QTZCM=z+Jo{F84rpP+p9Mi9fu=@bf(Ox_T2@?9V{T2r1&kY1PVd2KMESmS^_;Kla`Oyw2*(_mwSI zAdm)ugc1@G62O)$$&xI&0tN%Ndassyku9rN7u?ik8wj|_MYh#@vuw+9qs`ozd(S=R zo++7`GjpaBYC`BGI=^?Vy_Y`itt}*iGvvn4^FHfY-`eY2U*FRHt^fCb3sRUOB%k0B zG7pA(@pSXPgS_&fpL&enLwqpgp|qL6hj?oKTpK!rs9E*^Umf6UChY3gh2R|9Uy*yZ zs&Kr#*A;(;Zo#-Tf7bpRt-Cih=dU=md~tP{?=w%#cm{v_HBWTySao4PX%MqWUDv!n zrxDWt__KB-s3;H#?nvBkG&nh4kUQS-$J>9r`!i~P&Z>zoN4AAO?;{69*4cge=c@7% z=#o#6zc`(|WkVe-i77F%XHI^3(V6lB$n%A=y#Dfh-lYOr!!z3|vWO0D$cikI3^MV} z&C{NlczR_}b=;y~@V6|+_hjsx#@GOK&in(=6zzvz7o^!4>jQu8iu1*|=~P?*IR!e4 zQVf6A*Yv-fKU)O8TgwsiAednLr@Kop1 ztMSbyCm`L}P$!8wVE*L_L09B6|K3`(h6(Z0$&WT9ENG6OkItDyf!(nIL{DO%hR=38 z4xzyvvGWOBFIp28wX9gunHJTzeGUFy%vhl)=7P3Y;qJ~qP9zY?!J2~$-Stc%7nDnY z5n1=vRgD{h_;Y}{7Dmv0Npt%W1AF4VI3?XGyTtNyOqzp` z`Jrid&%5a%M25<_*L(hC8>O*Q1x*{QEnlvF?Zz=YgdKxC>i}5MKFY3MyZsquqoaKE zRqfA+o3NfDI+#UMalpuC(R3K4Vmc28%VNvyDzq)LX3OwoDq}3^rn#jqHGI|zTPxuN zcnV>*msY*5cF7QSs(`ZtM`cm-VTV#fW)Sp)lLbV(D*4DctkhbMV=Xm^b`VjssQE24 zc*L+0X=?}J#vGSZ={fPIGu`iVE@!HCQ_h(9;~5ivLJ53k9OqK#x&u5Pbx|J|dnl4` z`xVhR+B$JyLC|t181k$uhCl0vTHlKLJ~y}J=(j!H9QvCTN3V=HERCbD<^1XOar8ME znLkhU47l;3pHIK{TW;UD<;HLA*j4hMuf6-5w}1EUoAS!lKm78ww&wHy{x84be*^T- zm~V{y9@cgL=P_7tIPm9x{KwCR^Jisfro7ISx!Jh=&0PK8;;J3~EEdoMpS=3whwaUO z_4p&pr%$-)fxGYAp1SH}NkQ$N0wmDQy9-r!j>8Atl_ia&oFZi1l4zUIZ7co%<6{KA^2UN3JItWopU1JP5+TTgm+u>9m|)wfK09-^mzM%{c4Ix=rD;n!>%|&n?I!v5XEQo1u+4 z1C$71-KwG&DUF^JxY`gpO9z@~!>EPVDfp~VmAtUu80H1sW*m|gieYT<%;!SA4)Wgg zn#YwB&EBOb{9w-#T>2@~ zb3J1z^$jeg0)<1`M91l^>7$KgTKa2P| z*z4IK@56D6T62>IDzkgavk>7Oj-DP&MtpA+7>SXNw{2d5C3hQvHg@_lM4YE_OjnZUWM7C>$iSqe|dstCHaA zalUYKBX<~;-;Tg+$IFw)+kd?KAysNH5QZJoi`R^z7Yy zIw$FDMOJrJ76@9apfv;r{!3P36uC;5%S3>_Kui$mXxod&qU=SBpqRMf_N`?#myz? zgKG!8x;g2Q?$pqMt*bHU9uUYZJ|}3iwOX4BJ1OoTSiV=~GDFl~nGLUQSih_`VIk;P zjG9&ILjlF4dq8EKIKM4vQB&-E_;y>|LblR@^#{^uyFG{lf7TRQnRRIX9H{v-!xGIg z{tS3JejXZcjhue@aHS%Kflud+0~ccTl7c@SNj`olV?o7XTi-gFNDPt{6`YYXzui4dcK-qjt>DQrIsn>40wrVWrJDR|suZrWQ7AYxl}<=FEasfy_qF zJo#P`Do^>5G*0=^jLG*tIQd@Zl13droBYEECjHQqKXC@A=RkIG~<{G z?GjGl+9scNzfX49DI9pU=>TMAsIiwbCQ1LXmymPY4(r_>wKSMrpK}|FR+om0rRNCr zbyRs6#f4jL0Og=!OuV^^=1nshBxOd!%y&54+blXfbk+{~BWuf8>J9^%#j&hw?PFGS zs95`qrS7o0Sscr{);?xMhl;h&Sn3X|n?={_3c6SCM0oOdhr9!e@%NtU>373}_fNg& zX1AMe|K1O(4m|&>H{ORc!=Keu^=G|ZSN`RnP(+h{;xoAP$n)3N`SbYs^Z)vX&+y-{ z=%4@4{29v4zgU<1KOzO;#s1ggqH}MY^queBbaUp4*rR*$>-H7`R1JRyLVktn;;;Wu zaM#+>JhGXi`i4Arloa9r+)-N4u_xom>LAR4$>N8i_+-R9m}+xYGA}c>78fFcZY(Xr ze1ilu@Mjz?;LpgXwRW1-<=_6T8*A4^z?Q+nt&x7Hc15@wiGFELU1R_tx;}dTsVGqw z9}n{NS_y?{g16(Li#PR zZU1w5y$ABoK7;BkqcbO=Zuui(_uWSATzLzcmMJ3I2u0dScEcy7Ir863P;&`C77iB2oXLD##OC? zlW;V`w{`84-5F6AcC5Tqvgty3`njsiGy5{Tt1`|$n|uD*+zZd;0irMM&pKPWp}jD% zaZBj)F#$(n=D^ZVppFyE5wSr)FN$xi_*!5M9pfbt>q)?P?W*RP_0hHv{;Zs$4U48C zpQ5IYnt@W_{?d41@q0rqDoa04be zoj}W(a@y5?>K(I5pkqDYz-LzaY6RWCW)28i^Jihv%8SEDptb(_{JJ>?K?9;Si-tD4 zM9_*q58-G#nr6F#pqKj!g0}N#5OjN@H;WxAX<+-h$Ios}>@QE_a`Yc4II}Om3l;SK z{ANLuMTh_Bs^ojXd~Z;v)^Y ziP#;WJB2#Ji&_w`?%&2+AtHg^pWnNCLv3o<3$cOEF7x2oWGKPT%I8_8mO?yF1bJxq zEN<|_`Ex_?jFvEO>^`cOd12RI5$e~Pze0Q!DsxBXx?|(6Lf*8KLwT0r&!}y?%CoVU zM#z1&Ed5Mj%E=9(C(|N(cBcyYEX(9mpr}Api<`9eF&OvGxaO`SL)x(&*SL4X3_ITa z8MVI=KT{d`a7JBSuhLZ|_P-aZcmpD%qiFTvHNj{0Ztknf?%9{kEC79gz<54)R~CXp z4Nz5=L&!5u@;aKzvl>e?NEQjbJik95p)cPjXP#cunH^of3j5-Pr=kLDqXU@O;`ItF zIQUk<{F%RfO|ky9aRGHJAMGhh?kUUE*qJj-g;KNVFMq<#nZNcGP7aBWHKM1a4u~Fp z#^iC}lyc6I8Drsop>%y$er)aP$B!j0BFjc^;p%>+Mdx^VcCbB>b6!!v$(MR@7DgPc zTcUVt;FO}uI+35qi7{kO3TR3Spwu20+Sfva(20_}5Izhj?p(XJuT`~^24WM=SfCF2y@Z`#)m)S)!dr=a9hgb zZ7ZK>OnS6FZb3`ZqW0v4xNY#M-Ul0kc65q%6R0bDMUfoBM+| z-aYT;nLtI&pXX0=G~a+HXp&&SfXK?6tEygjM*4u(gp?rovQ}U77qOSh|_Q!b> z)_pL0t1Hf(UA60;4y&6*GmdE)z2Xdz9q6&cqH}+1i$iBnp%pS)>jpSmE5OFFgcizD zYF4Rzl82bHBG2Lrp};1nQ~N?_=4m6bhBm7T>=)|{K(Qvnx^(8o))q~ef9ihs7ly{s z^tXm}s1fU0P(2ET798y^*j$(T=uD~GomV$41_h6?Vpilt4aKA%0-xD`ea0SizsJ}<<^y_ba0B6R3gMSIIT1p1{*pI^BEfByLL!22&>{cYOD zs#|aQ;Z5#SRz)m3yfde+WNUNDHnD(K`e)&gB_f3W6A92ODHr({9sZ03G;A6EjGsp9 zw)KaWKVBU>zb<-ibM(BED3+raG^fXtu)YJMlH!6!G2f8jjG=aB75KB{E~HYL+r2Bj zF(dIr;*w)wfiP$Ivq8|BLetn78CV|`2#cm{h@MNn8wq9bSWAK-_5MCeCxpJds!u{a z8@`SR5PYpnHlX4Ji>%Hb9u5OYE+T$axoZA{P2Ty4YpEY?lr8s`*{DTnYh&iXg=HXCuf6O{q zlzfHC>RAc4F?<$rz_w@DyF0Yc?LmKYPSu;pFz-s&QvIG@#AD0G6S1v@)cG`VjRsD z#dSm|ABxIg?;}roR0sPYedqV%@l{VYq(`-FTXCj%WAEOL=gYV7PW`}vtbu29NP&0Z z+03&Qo6ePO=y^JYtc5kJ9z7a2=P0(-__V}G;zG`nvKp40cl9yIydl6sm4!1$&l1Q? zDnmGP%&dC53fdrOfzPVH_%lb5lu*n%2tm+so=|8}K`W_qd*V#(3vDa0ea7WOv2JmG z*2xF0@R_>e&$co`$Ulr)dRmO2!N0vJerHzr_pO|Bc2$4~q1Vg-GHWfgO%ZMJ-!S}H z!)H^D&Y!XPu!itzWy(R0LQ)oL{!A{y&IBL$b7!(|X9B>-r#>;TdEMiv=*c5_=|KLu z{rMn4#UJvq}YXqjSV0%D7O&V21n-4V&&~6GaY(9Wu$UQ#%!^19;!}aBO#`Hju%3!rtiE8IN>JI0NCawCEA6J&oph^on&AU6=mKH$yT5 zifGvjK{DnWcq6|MGxx;$p!OZBC50KnbqsQ=3R|IDRYedgaf=ldYex6(^>v%VpO2h# zFnAU|9uRC24uYT=jlqR%W9ShwOY>)*YY4fTTAEq6bVgmUM@^6i&O$GQ`N5yti&j8` z$IG9gZ90a4p#pBL<7v;Ai=k&RrWjcBgV^xc7?|cVCePcQ$rs z^CA{G^p~crV_orDQ_8RC5Uk|cS|96S+IOS1JQEl39vq2xrFIsss!a`lCU#+G;R@|B z&Kv=fU7HTMQtmh4BsuIFD)X8u^I9tNWPU-NF#xq7)AC&U3pm}E2WZ967>?avw&ncO z>$)=H>Q+8kLzc{#K(Y;DxKS7DkCGPQE500X>DuIn$ym`1!B(Wb-4(wD16GM1tfQ~tJoGuORxs5f2hVb|Ca!`3{Phm>q+Mtt3k2kLi z?JZh!zC0U06PdWtnqTV-GNT9fZai0()?1myV<`6zhgqJF;<~Xkr+r^h_r9&XcgE`vNaD}# z-qg)TvQh~uR(cbuu*aap3R6mmy_JRCAx9d6YNiY(!$21`E4nST2xX( z`wq+lO2fd}Hv&Q~@@Wxiiwm@EKNIISCC;mfpI5i`sow4DuomYZQU1+4RhoaaB!AvR zKmNu9x7)vS>z>_}5a8eZX7DYn7vGQ{fGWg=!e z+&_5b>iemiE8X0tOm~}b|J3gX-1s1DXVDaIgoX3QuYYz0D-0Jk72VS;I#j;IIA%bt zg|@lU-3L&dqj*$wB9XmMEGEIN1oJ;yO4k6v*_k6pD}HO!;e z?X+3t{+lZP%wr6#XLgV@Tjk9fQR)&82kn!rX)|^ZqN-J<5Rg^TFl%kIW}YrM^Uo#= zIHmmgq`U8*bhj>l>VDTK@so*n{@C4R+&AeiYdDX?R&=mYrw}!@7F0WO6r0F?7nJ#6>hlv#6!o4SmCw_pGC>vjf6F<=uv zPxDalS?Qk@fBvES_b0nenc?YE-`4rs+wb!q0{Ul4(hh$3-r$?R`Uv=p{&{5c4gT4< z&Y#D|pM~nb{^>h!|L)CS4gUS#ee##D{1@|QB+!=!KD~JU{a0W5VCRn0KfcFHryzWG zYkGa@w&v2J<~{lFX89i?FLCyS-@L>2+ZzV-^Zq z7St@!95ECuYN!jvrGpOY0(GPOwA-^7K4ZS2LyaKaG=EkI8s<#EqA9B*=8~+CY=h)5 zLZr=4HpnwDoPD!fJ?E2Q5ZK;~gxk14gWOfnlQiz9a#Eg4e)3t;1xASHGvv7?Lh}7V zzahiq0hC;a+Qb-RkZ?bEvQ|Nh99p#lc=6?s#t>gIO2weV?&?fpK^U)ePyu-c)QI^r zot61Bg3RI08y4BKO5cWpln|jWRvW;&XkT@%ME;G0_(XKz=@pCHGo$dSxLC0TS}VUy zE4TC%BsQ&k>Uiv2oV3wSV_1Pw zl10FmdN+T_Y5+D)91Hc-K~^#y)nT5*q2L+S!83_tDnvyIg+>7$>CZVqJo&q@Q2l08u@QwpY5q#8Qi z80$$up=}uk<2>8qX9|(FhfQToPD5EsyiG*v96pmc6*1!!B_YaZoBVZ%McWuPifB<^ zV}D@~w2eZqmL!8(3vK1k+5&n+{tQnx#u~aZBzRW(XR;hxgFf(Q$w;_d_%pI+$g}3p zZ3$j&$v)&FY>JzW!Anhyf8+Y6&hA)w`2Z6E1-vg0u(DIZJQUFv_UE11yP-KV>R8gk zBVj%~zW^d6-=rYalL8o(>$^)#IU>m^IWm8C;KpNLv;tx3V_9+7Dt6SY_0L1(S+`qg z^RTt-?aoa23tRL!)^1kpOuKba*R7o$>)i0zVkpN9#Lp;}t3$jG^6j+diMG7tbLC_n z%mdy6`XE}oq>uO+Z6x#$?gz6XFJbr2b&aWEheCW1PS*u_HU^8q4p*=y+=JYsvI7?W zOd}uF5y2kyq2A0T9bV>z*7{J&qkY92frp|)9*N7jYBc;=qhsl&P^Z4fG%3~m8D}Bb z7j^^$h8x#Y=@XX^->*NqphewqH`IapUGVYGHT`28~bW?7f>Ibw`=*p{-4 zrac?++&G>Zb~t6pFQOMzh4?pT#9mbIu=MTA5fG}7GB+Ey9OSvKDo^ugv1@=8tLT!y z+IbiY%dNOiG_(NfMogruvd`?#8>q^=NLJsiYumQOoLc$h(ZmIZdCdohdF(i%{hMRv z)nR?_pBaC&lXpkp7T#Y# z1%v;{QhHV12RhIVm9mUnRlswhmFnk9(wQTu+pz3- z;=)t$^B}iyU2SBcOAUT$>{<@{okMoQ?qr0}^N^a?C(LbJxwthgl!?gmrD-^U$Q)C7 zF8rCvER~T^O09M0qcauRl7wOhZYt3vB_tVfEf8DM4$i}_xi>puVE5)LC24&H%Ue@J z>Q*eSOxn3A>`m>356NUrpiUGxjEyI~d4Aa3{`O(B5SQm9&gJ|m@W-C-2 zc0etPgNF{Yx2A%|Scf?%=ZfiL)^ezD;0`UW7WG+j?r+-7u~-j~x@mW)nB&#V9}q1d zU3;FO<+dPbF7A*VntNmNgWMr<+f1GTf_C7~ieZY4gSoLCZg{h(zaq@y^~!(k85og2 zFPP@xbHmT?bo(CsdG3No&J0|B{nsBNa{ldG!k?Ar#^>+-2HWRPu;BRMw}WrJ{>cdc zZ(Qfk_)rT&evwD3RJwTY_(pCW;N@zUU>fse6(K63EV zY-S|fCN1=Os3K>B=%2BYz&oNua`62L@@FI>NP-)S@t`Q81S5Ct&aB-WTOG5gCR$Pl zHbn;_?mZbhuXg2=ecRTNzn(;XP+Z_MqT(iGIb{Xfw*=BFIsSI1*JmW+9nIUa5MxFl z;KtN7h}I>;s?>o2whnd*troF;o&%5sM^oxSbRB82h>autbzs(kLr8U40Qm}QQ={6p zukR?$l;0gnnB7)d*j`pd$;Fix+(OC=ae?MVQDNppX`v20LmGB$KD;UB`IMz6RxL$} zgGvVgg@G!5$eKUn2ZAvOp%FCjStE3Ce3aOmu#u_Rku3^M91T7eV?g3B^EUQQ$uDOa^{7M$WPuM9fnB+3Q%egzn=2pXs18yBU0{D`I&OF5w8l z6f}b^9}V#!$Y{pv{Mv8>QKe8p&J3m*;n+cYRtI|=37UE2sfVhUqLH2jgjXIQlIaXx z^oeDlZ@=1v`SmG}G^~4~DLt&UAg*oua?GOp$~Obp`>Qh1+TnCPP`2e_>E^Dy__mCQ zhILQkig_$P;ApI`aCHECgeUtcXfAvvhcCv_$~zk1TpQ(~<8*`vq3tphofeX;DYOwt z!QtB_&ldh{%oh061l_>Y3VLJiF&n*c*K)t^ z6#woNO3^~&$N_@Jl*1u4AzmEXaKq4MD|yxuXor%_gP`U<6=zrY5Pd5o1z`{HImM@a z`D{Y=A;G6BZgxk!H~hId(W@@rr!IbWee7(kPRJnHlo|wNCZlEF0VrQ?UsWF5Pe>+} zec9*sWt`u$p>=Z@Z$mSe#48M(aLu2Y2!KB;1U<{}XYK^&K$HJ_h9uF$6JreH=$^Wi zhf!JU;O@>hfFpml(`ji}%-OoGuIu?1Zhl?)!qU2y>1-1ihsylUxcD;XOqI{=SbH*lAzx6n zOK0J(gFif@$&)T{TXsqBCr&$5SY!rD`NoSSzIc6v`!(gn;Qzz>7hi%uTcyha4>dL2 zFU|v2rLNcuS7fzRWwYB5HX)7Wl5UJQS(to8iV3o_$!oPoaa9g-T-hHBhW+a6*BWVl zbvw_=6f$fN7Qe*V;3~A1Y(ANla56Q#dijz=u?wGz2t2X+DXicxRA!L(R$V5MG|OZM z^TKvV6pe)qd?w`t2E~FgxsK}Eq0h(F0kJe7nr`RH^Dk8hh3?8!}e%t1#?!D>U+uCzOgI~R&KZ;W1%F48yz10&a@+^=v6DQ|NN%kiy=<-}b zo?qeiIRuQCNhRz`x^`};PmepXF1Ti0aC`pp?x#2KMgwy+FnmGK>M6jQhPMWoW;#>4 zxqWL&V_I14s>QX6>*57{CSHOH6dKYiP#WxiF29P z?#)Z;-;;{m8elH_R#wnkwWGVN5J7_ce=3LpAceyP6{La-qIWf)ao~TQn-pRd^pwzVO>(WU3$j&-16xGDO!@G_Np=4i#54!=W3C*JvDu)y^C6XTofVcD)a-w(F|hx|Z%^ zE%m3?@@q1V*-1_092O0xbHK~ai#jKuF6T~~fekNC2+m=6vUA1RpV`Wpoe8rBk0X|d zV@-IHJ`V#5%)PqqrZna3Mw4bC}Db92QtM3X%AXx>dvpJf{y3X%*DHURGvJCpdriCl`x9=R;x_Hc;INnf^1r?L?#KLxp#7iU zedl+t|K|t4{k4rhzyI#_{DUz0FB#+?wCbOK`L`eaUoZXkznni`y*POJ;wP_M{h+(! zZ^Fk8I;P)t*4`eKOc)(*s>+A`{_;X#aa9UYOKhuE0;i5jE@Hj>W00dIceRw>11l; zvG|38m(dKXoP#1%juh(*0ntjs%+E%KB{WG^*m(}CH1LZuCJ;FjL4VMVbL~8^D4idl{WVb?V+Jd z&66oRmwR_F_ts@cvKK&`F}2V0nG_#_KGIn>B=|MNNn%0B4+>`{I56PF^x*tHQP%OD0LDa>N&>jc`|~dB+0e9hDbC(Zl(fXo zArYZU6X}H-;k~T32A~PykWa zv{REe;PZ9^Q4*u#_AHVtL?+B4V z+m+9lLKChe(5`+EeS!WN&64Gp)Z60!{Ml=-4gS^t`1qAe@4h@B{26;dsIT}xU;ap^ zAXGvfrP6UBeg*;?P&~%Uc)78wVZVOk2x-4^@%^ipKD>Hf{5M{_`bo{nKXae-?a6NL zcTM`X_YFVc_4Y+m{RHMr@vxFrE4p!Rw|?r(E}Z-8KF;l5dK_)L0e2$dAOU=)&S-2% z*QuDnowxgy?~n5)^v>uFIh4+wf1mxa4(KL3fjH=lgK05$stEw61EMCppvDseQw9Ug6&Kgk)a2DTY6F)RMUacRtn=^}(hGwBi zl&zr&^RRN#?E;@C-=WKU+`l(s+&fXVPrQRq@1Ah`-4k!qB{zW4K9i6~mdSSXa^Qrt@%_ zw~%KJ)>_Jf z_VRCEy7-~|Po-ZgQ?Hw;e`Ed-`e(hN%jZ7B0vb8Nl}o>hj@WeLlw0op&Moff zzp!l9sgxzHc`I9YrjcMB+*DVRO*8DYlK#LlS6dM;naZHPTiY0G_2B`OqI}k}XXKO$KEt1DBK?m?FKA1P z!x#i?0)HUGU~PE;zdP#7tHi#$}0V+cwStJAC$!I@tIsvs4Qw~74vZR2Z zYVr(cra}o3g*H=avGhp%*(QO8O)0W!v*Qpu=#W{^W}+s@i$KgQdgi5`CxgWES>(;i z9{}cDz3d^dvkg9rS+vLTpa%_qJ{0`mk>CfxUnni{6F9m|a-6;Jr02mP-y<;#PONyc zesd&m9Cz$k*S%{a?EO+%+DrSgUVS$Em1nZ9l&7A3dPPrOT=T}I^{W>1uJLi^EaaRE z{AUl9m$mRZLi1r1q}p#pG~PpUXdF2t412d$>cVH#$?nb20ZCS;Lgd!RLv8R`o8{7? zgJZPEjGCaCm}84)LKuk-XJdBJmgq;cC;0<}DLVv24+YZbo)vR?R|XJ33 zYA98+4^A2~Ab!sFFvEhKCDeA=ftGmRwm9F`*x40Zb}TXCx-^cy zuAay+eYmMOUD|&GZ*5*KI21m+cKuRvdY(U!*Ip)5hfEUyuMD~Ber6lgi*HVd4PW4W z4+r@jd(snEjarpCR6iZe+SI9BgltjoFdosoC(;-)yNNUb%X|)o1z^9> zSC-aZmDRdWc-M%?PE$DNQghC+m%`I5fK*o0l4*3dc513egPIC=MJa8Mv2W$t^)x#( zM)|S9?_=C0Eil%l#;Rh8P?=L-xbj4LRQ1}W$5$_@Tl09!`Xy)6gD(`to!hnQZ0RQc zlyo1+YCn+Ev@g59GMoH>pix!_bxPO}v|L=SVE6ta_KG);&Xr|dF3arANBKJtGI0%Vc!#{sK1LT9(5NuV*533Ckr!_OHa)P+3ksJ$ZdY+b{D%2mem+B}P!e zRGboDagNc|emd--USxBaW|+`=;9+|*;!&&Jlby7Gs#j6cXq!NqCrg`|_m+{buuxzx zmfBT0Ef_MFO2&uQ^!Ua#p)Kpf&Tm_D2{a9tuFPn8HouNn2KE)SVXs{w#F(t3XLoIG z$w=T|ySjvj>tg2va>ex`F`y&Czb%mv)QlSj%4b`4!gxWxJvc(g2DZk|Ye{~zZDUAp z!Sb^usoXZqS>W9*Csw_TAW0{c?ww1ID4o|U&QxY$GT)pNU$gef=Mx_}u{pYV`??+l z&%4F$JC{jhv;-&$>QkO*h+otcJHI1-QCIxJj<~tKtC#d`ifmjR#D8cflNKS9X2&|> z1KZ;QS}_vAO?vxkygry>Yv$EFWEBW-OcT`TfY6mvxnY({e6T+Z@%&A zTlg-%^*KNoI}Tf@MeA>w@znXvXhNhrD627SeCPE+<0yW6yHx!w4{P51aso4H`x?8k5LT{Q6_xF|wsYdDkA->1bD z?r=5cBa^*}N2f~YKJ1&I@@a4dM2B;Z}16o91YAZ$Xtd-AjKjY7A zDu6+2-N>6AP%~Oq6SLg!m$2xWbsgF~%(q#aX-JYg$q%SQD`xFP)TR(Noc6~P?~<^X zGi%`d!-+qTaR0s_;)!<%E+#Zyo^-olWL3X=(rr{I@0xhqUGBHaqEpa*kGpDDJ#~MD zscmbqE^BFU4Tu&N?XE(psSSTd5iKffrL`8^Z3#QO*6`NBXj9wiAeoft4F@)KnqQSK}tNLW#GeMn9_wU_1K{&j%)EwSgY9`OA5Vmg*t%d$6 zAbQfB`hx09tTPqDqVZHA#M4`uLi^wdJ@r9C?lHR^hq-%=ISh9=b?beuZ+`tu=@QPV zD|~yXFOXs1a(Xh$`T4SrU|n4gVjeNRg>*QNU~8E+>*0~Yd3@dCavb~DphJg0mT?wN z^&vPFm_G}Ao;I7Lx3j0u_}TQkzwP#o8zxTQyfN$F|Mi_W-uM{itPG#Oq|kRf|D60O zZ9-9cq55Qb{?Ea``Rk8feeu1QFMTBN`NH7P%>KnsapbU@a$LiIu}JOl>eWH`GntXq zMEN`GQ%k=2%{y(Z zwEr^`EO&0&5`5xz7+o`q#avnRgb>ze3!4I87+?9S*T>w0mvOdsH+ zQJmLYv9+PR2o*HiYydm1)Ier9Ihhv4g+n=SaK&-wXoX8FQ;v>3Sy!qGE*7nCNPeOw zd@jx&&}Puh3lV{YBsUE8I~G3YboAWQF@dL|CAS({TqMoa;oe|gkS6?DEThAGT0?!B z!bCL<*^T-z%q|3MYB;QMoS|)+>?w|9_a(-iLm6~HUu8v0$)ZCDp|$fdo1j<8p0#(b zLkVrxz!`?@9LS_?0hpz3$Fm5eb=W>tC>ufbv1MLImd-k~bk@NjuOp$ePejc z06W_v)YFJsr2>1`5^-gy%h?lLAL0pr)(F~A=phyjj_!CZERW?eUHcZo{ILy;Jr0v9xsfv7bc!7+k9q!MoU#@^Zx9n{dtJYxsI}~ zg+HUG74ol)ToAZ&mU!eZlx6i5u5Q~HRkt$e;?C5Il1)$Y57L30bffTRS9b+KSWO&= zlwB-hnB-Ef4l>V0ZoA_2vzTsW#MQ5Q3db0xBb&091C7}eSTXCeSF(pycG<83&Q|`+ zj%kofPtFX{U6RQ=T;}__LfzuzWcfzkq4?^CcPW*~yLTLuwKhor;^=lsLB|d2UxyKxd*jZ!{+a zHmcD48L@F!d|*#pAWG?;g!%0W3mcOk!Hc6aFScvfs=obMoywS9-m_rRL9ulH0Hse)~xuG>z+E1yzpea|c9ix1u~4>%j?b)4$<1?dRXTd-jbpQ4&5r&1dms(LY<^Gj#{h@p~@1 z;v}xxo%ypSKl7$};uZq`0Xw7DrKG-Sx)wZ-6+XkL$4h&h`#ZOc{8moE_jwSa8n;NVK}ox#fqJ=Yevhg_zB5$n7Q>|tf2N|sHV*t*EouZ! zsU_B$Dl3Zn1I3C(X#GRNi9!plwYh)T1lxA@>kN~HJS)BNa7?Wryp?HNIkT&}19mox zR{m@|y%T@H`7{UUP|=5PE$;#HD-^GRye>I>vnNIljdtD4HE=)Jyf`M`$Bjf@LJ%~e zZ#nG<%}r}=V1uAdW$1>V;$ap4KRkIBi*{}-2-+GWK5P1sbSSNB{a*Zex+fUcVQ{lJ z;{J@%XjXKnjIzpzA33aU7DwznN~2lPp|Ws_FZ}sY&7UWGFPb)c-ZXEY8y~#yhC9DC z;ihlj@U6nUr{8$(BN0Ep^%+y)*D>-}dY|*MJw=^+x3(4M zBbh)0_NT_5g&UWPHn??fZg+7`-=55tjO6OXCk{s~I1x4fRMcFRf-tZ(dQNksAA074 zv5&SEtU0qct6K~kb6XVhtt-w`{JDTd-jn5{uAN&*Vt8szSWUF3poKrj_zN_ShCf4( zXKNv}vf~I8_^kPJlpg@LF~+Yc+8^Kyc5VyzZ;K2dcOe)A;vob(#vcod!=c_{Prc%) zp6wfZO3A&B+L_lpx3-pTMZOMHZ>T6dE&N%f*|PIzpmbyT5P#Ob(9%+#2Tt$Xxw&g| zd~M9)V8Vo|R)+(z#T5E@s1K&lBBEBd9=Kkk z1LxBtk$%kgcC~N>t$tG)HQb2rNc)GDce{yb*7;>-p(k6uy0 zSu3cmCCE#=Lmyx2N$`-)uFYCi%)QKk{UA9OPmUp&7=el11+J)QnAaGwLddtUcqoso0mS2lffQf zXA@TVd^AMtuZJ;bD}uK3XWKXe@gy{VHV9ftk%dUZitUJ4K(PVHUsy57TKBXLVjag| zX9J%#a7MIDH0p@)ZjAA6h?d-!JcB3V<~D8!>f5pULRAhq!jKW7!DB*7TMC1K$Qs5w z_#N5tClVh%7Uj>wYcoX;7Xx#G=@kd@Gtanz&kp=q->zQ>kbln(*MdLuh>ejRj~zkF zgoP84rjh$i^Jf9Y;h5gc;>_2reG2pEb2{@NKv?OYh4Vn$@Q>Xmrm}6=?d}tWD)RNd zJ!!|6KlMCj8o_F|CD;SzterQQeBnVp8tio_#PeX7&%sDvGQk~*4mcJQSRFn0NbJJK zO_5|bBh49x00NY*^XE~Cy5`Sc8gYLizSb7Onm=*R<>?I( z+&qWk7LzXU5<+6uRS9Xi*IU#N;4oyg0CfhB*so zP71Qi&nHIwq z0o_87j{(KZ~IbXD@ zJvF=`<*~ZNMUBfJ?%o`ZsQyw}_POFM9otqkXM{6d(wOoHuiDkbEoe`RI=?qf&v&pn z{*y=lydolKs+$}C?Jt-!|Mh=+=l$QvE3UtOXHb;ScK)oT%kRF4ALEx+3R(HHAZTRI zI$^yCp%uhN@AT&DpZ~{y4F0$O_k&k?C-m}rSNUy1TAYF3iT;@%J2w6Eb^bi&pM;k_ zxqA6iB+%rSht+EtIbx^F1FzqAZy=ZbCby{%eCr^6OE}r7GWSWN2frQmA8f+94(se18YM09O(WK;zQswi{srly`izM<=o%7Wh|pPujSk_ zmT?q97x*mv*?wkJ#d8S6*~l~S*_JL)yXg)AXUH=yyUK1?o9+&kIPod~D5Y}cwbEu? zx26abKaI)v=~8<&4=a&3tK4&vgbp(eJ8gzJLq17zr}?K+$>Jj+l3lIl6>O_uCW``Z zQ8g=ItBC0L;hd09II}Kc!avaAe(U!qe)sl?-=)-S`TOqQrcP-i%%Em#xZjEifQsAf zB^3$VfD>+)3Z*^noOlP@l~RR)-uKwqIAHwViFbi;5ors^W#=`59$pU7T6J6+N85?? zD3;WsmuA?ZuxqMWcPuR00B48FsQh`DL|ij`EgBaZug<)j6MaRjVsZrMhDfW!)Qnvl zhA`=X(4Ab0Hf!j~_YTuSPyRWk9GXIF%W(%!^1x~K9EDRIwa``yt^GQzPs)hToo=Lb z^$eO0POIz5FBj8xP7-K`am=Et?Ye3=D>_tM^>@|ou)0}v)!$XSS<#{5ia-Bw%I!>s z{@^>`FE2R&d{#DJ*Y(d|`rj?rD}K%R^Ob>*_}A{`3xhB9gT6m|@#=dAkDPzVWBxSv z$qPLncs3`kX>UAF@ECtpp7_`{@EshMrcikD8GhSNop@f6Xdaq6gmysMeQu4H_HELT;Rb7zk}ia zjVqrzo4;y+tn1`M6d`v(TlrQb&05%usu{2h4dYi&S7||K3GSeUkai9hIt{PJ^I3Mj z1Y#yxa-c4!(-RNHJ$5K;{?Ul}ywY2{dTD)XSYujj86_aNB9yTWt+(ZX$n;z3^yb}A>AT;0C7@=dEs zCg3Pktdft1AYAn0Csp0brSP2A+~u7+HXv#ul|1UKKJ;DXIrtkOTk3s!Lu*!2!-lZa zE1ozWx8Q|PpM$}(z_40h%4k-+>;gCs>*EZybPH(9ATR5fhA>|%{yaLJwts39R4e)%~TL2C6bH?9V(~k=C(iL)+79PHc&& z*%W+q^^(K!3%IYyo(9UU4H8|nM2Kf?s8}=~3wa0+5S%~`279~^;z4;hWM*~nOyySn z&yT7uuY6!aei)rY={xGc$V@d0EM`6Apd;v zriQf0qX`R-MT)_DbIhE^2y%Kdl%JJ0Te-18&|3dYsc&6*K*kw*DC=6IE26IvfBwo5 zH20Eu9?cUfHyCeBfV=T>QP7y@;z*d!vBX8dC7fWP%{CAx9=U?52r5P+idg|x1H8Xq zoxGSY6TXY&whWqS}GixD!gpZT>8nZd6+P`+o|s{rv~|I*ee*^XLQ{tf%>{L7*&h(a-PCAE?ak-Ld-g zhGmCh0}e;}9F6oo8a4ZcNdNuh*xeMyR2|s^F$&hE!K@A#)cR*e;0$Q~jQNIkieNXI zc5OPA7W-`CV^tCJ4@56&%uG02nn}J(O@Ogt_;UQ2z16IhTUYaE!L2B+6{tK{nRBr! zhy1g>+t<`*#XYlfS#81U?y@Yqa9XxLivF1?67h?mtdtYQwh%ej6|Omzx3Y2D`p&)S zuu#dbs%C0L(>qRnuANVYmy$G4T@;PhZKds|Vtl**hR!_5vFosj&$R?ym9&fP2A0vv zV_73*x(O;T%f&1E;=Y2eU7L2%1P&N@{xi3GVQ-r4 zFG6Kb1Cx^bi}>%Fc?$Lo#kKgE0H{@Tm85r?}(m>Pqwa};EJI9Iyq?9NqfY2nOo9*$YimYskeo{Pmbl3S%Tx1oIN ze9s3aySaVy#&2v~oBHcFKYaVmkHF5?oQg`46U)7>3Ug4@;^JhwkWL-MMb< zIeJ~MYwhFQV*S)r-FYqN7FX+9+ckN1=Fda$d5Q@cRf0Xmo=y->Hx$02%UWO5x0~W%qA8l($Xz=JzIki=bV9bjQSR z5dxx}Li$Yn?rjrqyCaE&UqsJ&E+*ia$iNrk7GnE+xj3V*G#BEH_*rZ;O7hUL_m+y`GqxK7mQ}XFp3;Ku zl60KS+ zh0;tMn6+(em`8oI7y0k-d4NKLqYsD9IuhoKlCW`YPM1W0 zZFyN1SPx&#b9**-~Fl3a>0OuEiXB-UmI2h`ADAa>EqT*=i3_`nY*sMZ=L?Eq0c6dYtZ71jE zhyZ^TDvgVbe}U{4qvqw>Bbd9v<3f!&(k`Zs-;D7Mo&b6OB>6wutsY`K&_n zax%feBXBf2pk~EmZMg~OQI+qP3{zx+1BPh++*6u!VP64cqig4e+D#E4Xub!q*=dRJ z1wk{Ec$?czHVkUk6@#G1Sg{gjYkj=@+4jJaIn>$edBm16_&<;RDbtUbwZFA)eE{`M zWe_wK-Gbm5F+cnn{WEc5*~}xsUN2x|lo{Jsj5ts^5`e96XWfS_Lym@8!p9W+fv`zd zvb`IQB=EJ*_la0ZYtIe2QA075W@aY<;KTdxO*t{0yH@p-tnV&OWkQGKV%R=ox*}u= zL){AT)EzIc`#PZAKZ<=ABY)PM)8Q)62=wDZSARkiA1|9vTS^NIDfXeKqz%Fe?z%>2hXCt?(iay+GzZ8#3rtDyZ%=1>OvB10h>GiD=eER&5V|vIK7lE;hR@B3 zl7+A?!JlYIn%la3L3{E-jH5{&-Gou|nx%cYN&S0Lv3kar3Guw_UKRE}1!Ozztt=Em zUY>VG8HuwS@Nj8S2`J@)s_VsN?JUnce}F$9IUUhLZw&s^{~CPh#dltL@%>jWe|)+Bqn9oY z!k;brXJr9xOFQ@n%a1b#();_ri+U|aQ2hDgg%3G_FJ1baOpeHn;LoqT_?t%;Cc>X@ zaGU(&8*cZxVa9^#K95cHer$?(avD}}Eh-jJ<3b`h+~8C^LM^)lbG8wr={^CIJmySz zXznC&ffniEBxu(k(N56Q#2pjAsl&#f-M@RAL)eM5=F-;kE_k>_{|uMDONC9C zt#sM~qESAp5KXe(3|Swnl|NhSn%3$*!%7RC){xm+A`52_(_)oCQ#Taakv}Vw6S*k% zkVye$I?XDqD8sscU)0^q0;nru;4@c5%gaSrZVxa%VHcAtR};IF2?BC3wT(q<3T;Q_ zY>Rt??1Y4#p%9(Cn#d3k&FqHq4;NpK$v@{twXtZ0qq&E%i!rx1Qh!SfvxWvu8{Z67 zk*7vKea@xzS+myl_mU~KLA`o;#M%5uzUWK`hl=wSzufo0AImt4Ec}_%V)*ktlW(2w zHp%-T@7AX7ch&1xQ0VLY+5Bttl~ulG{248QSa1ydj!e_yzj5`0flL1q6ujz&$v5A5 z%QtqcS>Ct@^NnrI=$}jT$)@)wrGHkkVad~nX9egONigVGj2$4%yVA~V-_Vh}qH$C7 z$&{tlu@B?O@m$pW#@v-C8|l_soXsjEZ8RAY;m>egLC_^R2y75YpDWJn&PZ%nzT|l1 z9B36>6vB+QnZRE{`#+PE5cqsjWhA5n>S&M=3SnB1UXw)caP<7@#6|r2II-?2euf-f zx9sTJkW*40dh`^=(lIT1=b6{jqVb4);3@ms9*1k#kK1DG0rfN8-Xd>qw+0Q5~t$ z2u6CfhWilB5ndRpLNCF^M`GqwCoQa57X%9>m0n*-Mqfq#nX>%el7cg(g}o((7^L9& zO!}Vo{N-q~PbNRcDXIzftqt<2U*^*g>{A~y8`z8N7LI*5d{%X&w+7v=__LL0S=pC! zyR`+_Wx|;)YwWD4vaUP#8J#&>KQ(xE#ER*uKh@?KO0+3?59@=x>y~-dJ_Skks$POz z*$0XE$u&>ZriV8bCARKe(@~y=Y8UJPE<014-no5UD2_(H;@3xf}DsbBt z15W@Ezx_355U@~{hg_{^=f>0PLO_=|lQ)LX#?zxV+Ur!LXKgfNssV?C=rLkv=WbT` z{3Ys!KT{bKg1!d)nP<(4ovn5A7#jX;oIpr?pehU?sW>N2>z~`L^=EydN_U=jr zF`+XATWS6b#zAVxH4^>|D=sI8Y0kj@?B4Au2cwzw6aRVmGr{w9WSJ-L6x75nYF-z5 zreMX{Js2NtCi5wY>Uy5Z?%9`l=0NVb1M(=@vWbaVflL1l4Vs)wD~r2c|H3n%`Jv!A z7rJpPf7WbMGg6+)-tsK)-Ic1Wvrn%%wSMXI(Sgr|`#m2u@8sHLWDZ4C4C`Y?i5mt! z2}&inRRr5AFJhGrPu!I?RTgYmi3M~Xn&+Nfn*g3Q*-34CHuLQYofbgNi%6E7dJd@8 z)uP^ixsfVd0V))%Wx|RLa`)gTD)00={;btw0G6h=!u`Un0Aw z=(kARb#MY@W?_F}Lum%b)q8+zk=azZ{M6>~ru<~~8UJdido#Y`eARHvm1dsVlh%-% z(zr}Mi%@8-=Ffk$aQIpPXNNJB|1_I;j4 z^9G8a24N7WD0@|sJ{yMBnE{o^Swl{kGi=j@D4dnZ8A@!>v917?HDvy-`^^pkf7W5^ zpy0Dc(5Ae7!YztFi!NF?wmoih|F#K(QmqyCjh%!)v%|X71{8*`Y8tHJ?U3j5aQ@8U zTd^~B8=F;_*TH64D~Bb`pM~5S+Dt_cWm>*s{;aQ#g+JeE2hN5(e{aHfbZ7)^N`2ns zY8q*@rqFhqZq5?B&0V3T*BV5NNZulc#vxqaX*L$^e!me#3z44mfP*wzdvw^J0x_S_ zj|QbRJOuTzKG!Y zQ|829A~Uie=+8+oefjchD_3v*=1sSMd-Bvx5g{j^&clL3^XCQ&O*L5ckE{X{9#@nU z=mXUB7;MY$LT*Aw(nD~)-P*M$66hWI|*J8O` zBKl{LuSU>xU>uwx&TU`cxF+~$R3Pl)RHQ$$N%3|DLF2Xof{qNpnuGS5C|^PVb)*mC zXIgk$|4?|~!I*`o)&{raBzA3I-Mf1O)`DHTQ#*I2cJ0}6wj>8Oi^ADv++B{^r|^75 z;n_Xe?c27r@5OmT_%l!)_}o<@*#)o4<#QnJiWFf zFS#}~?9|#PF)k3{eW=e1L7p!>HS^$853()JFeTf9^NR#J#8boPA^r?@UgmvT;*0sS zAwETbt+TKQZm!BCS6y3077S3J7H{-x zTMs2xbcII0KJBnaS0S3%@r0{!MrpsM=Rq#3eHOqlSf0(EeT9%Z5cI&lT)y-=3s)Rn z_0+zoxs+W6DRO-)v(ZS~_%o2%jt8l5&j|Qc6q-6ux3r+BR}RU{aWJf;f!mb|<>r2a z2MQW3hwi$Zk6?t6L$g`yrxloQ2w9b2(s^G2UpPQif|GpqKp}s)hh|ljO^58B3hO5H zfv|6UM7!*ywnVNf;D|J7*GFv*P;&NJ_hbxpeg4ha)2r((no{qZJ_LxXLeO~Wo5;gt z!`4UTUepTk)(U~@YW_3}k-2)}gg^6XOVw7%YJsCW0e*+5GnKG+bKABx^|{G-L8FMK zg{#AZFW&F!gY?AxdVICyYg2yrAE}JJldEfCeO`rb2{S14jL6S{JB1H4)D2t zd7$v;1pn4}|K5avzQp-3>blrD*mpFnSlqEGthZpfIL~u0DR-u(@*MtK!=tIQax3q1 zA!E>+=CsHZm{Q2|CxdP+2a4)dPFv`D@BW zeXgpot2nD|*Om^FVwYhtRDj(_TjkdHM`zzK!ENFM_oto+{?&iHBjy`#e8R6k5VSLY ze(x*LKU-ALZ-0W;njptL+k$wLeDICe2LIyEfBW)_A6_1KUqR;2uJj8ywdtSL&mw8R z&YvAPv#UkLpYeazzb@g=R|h@;?7wvRH(NGWxVe2}s@s&ir{0GCdH!@C@^fkZvq3AP z;FmA`k%7Qtte6ey{+c|KLC&D zY$UZ*4A0a6(@;&#hYd`&R=$JU+5KkX+Y`Sr6ccX#w!|&Ocie9I?u2jZxYg|z9T;@n zuEXuyRGih(w@>;OG0Y~~Vi|q+r0=rldjBaMLLIDVxd|w;SJ{fA;r1Nzy%X-xr$zQ*qNwGyA{uKB8;j;nbN`Xtb(8M1f#^v; z;da$`uaQO@bu{-pp(kHp(L5A(B5f)TejP%m_4f&1DI)H|1B zdG@V+oJaU_-zV349HW26f`k2sKl@Gdn0dp`Zgac&2Dho9%fkQiFa9V054`@Xk469d z#wXYL^H+QZzJC0f|4EeB$M0V3M{n@Kr7N!&ZaaME9Y4Qu;^e3W^QyOIHJ22^pBp8W zo^aH!SBwiLkH51)$8yy6)sX~i4YQcIf{}}}yLY6vd0**91wbH?!DI|3BMAf|+s26`2_yj`gUMNl zj3Xcliap@dS-T?*>Ap`o%HSO&dyGc4Nh%$yW5HH_n!COqtcaxg-r+d znCIm@=hm${RkxC=e&>JwuLQmv;&-iyezxQt+qkU!`2|N`Scvf{FEU7u`PJ}qUX*x) zlX0WKnf#@vpPhSr*@Pq0pV*%{V1JqzKC`J}Qav^qJtqkVNjoTV=rMf>OgZ@0^5=b- zV)A@wTrZ*P=~${tkdE+B#(=}wkCx0Bb7tw}3+v|KZOG3Q0pX4nymOu1wv-$_r=OdB zV&&vwd^RQx-;*^2YYq}4zA~ye>RiAzn*j!wbcdsR5k+HqA4yMyq(R{j>+UtF^nh2E z9@kW{6w4}>oq)GmZmiU|>Q{GJ(1POcUI|;Tt`z41z&oKTP}Tw~K0KVPK0X0Upu2()u3CdHl$4gP&U|!y~?Bcd%XY=Qud~R0Rs+^)l zX@_P$zCUL$z9_Ga=!K^Tz8the>?g=qXxa?sMl@(z)Xt-Nv(j(m&lRrGM!brC71!lz zQFG9Z*@l0UPE6G4Y@W=poirdNFYli|YG6nZE&i3f4jG> zRSFGk9V=zkJR4ZfX*YlwA|4loa!ijuKkv}WDF^eWV2y%!Snmet!=;0OpIL~Fi97}2 z9esZDG9JB(=8Y_#`RHNN3r^^NB4^;4$%9T$8i)kCbW%SM^pVN^;LpdW4mdSs0Q~v% z#C|8I3_3P>AYL4$69<*%3_UvQ$@6*GK`#snp;1BaknRJX%Fb<7ERSACwyiAMvAXO>Ys&E7;B4Hol#Mz0>>M_@bn8lt^2)ZZ<~Q{!Qx z97l}JasA3~FuMA7o zEFxH{Zn_;aGG6aE{6qkF@dfknV%FwsD7MGmt6oc!71cav&RP#dA}*-4&( z&rXvK>b;D6Ga~08a}HH3bJmK1egd2YK6@Q*8{Rg+XOz!iOtIH60em*rzGC|j2A?Z{ zYNXgWYapi8082Iv$!Niqja&^h5+WLaF$EwSV-2fqhA<0!j;vRKoh^bk{JFlXE@2Tg zjliObAc8jSH=zvj=ems|>o#`d(IL^q6KD8ygXW&_Xz7k`cIxC*t+hRNfW32<3Ic>=_lU%k1u}x;T;BE-Dmpxg9=*t^ZQ?X z@WD6fpGgZy_UD?qw(rw)9!``$zw^e|Z@uvau50hS^XX4tzSyySN>oJPvEDsjUAwG& z%evA{t3>=<@FxbJ9ZcB5;rm-Tme1RkFl0b91YX#zIwv!J69Ai^hrz{#t%k~OT5#5X>sbR1W)Hw~qhxFfz*hM) zxdkE8CW7cm&~#>hd}7Hkc=+j27oS^jjS;L{av2hftWI)T@s5ee2Lp|K-e)(6$uqgm zx31)?)6Xv0KX>ep#}9vXdfJH>mkLEkp=~74yrk$$880UMK;HXM&WPlO5uo|Y7_^J8 zGGrV5%(47j-hgPcxNr^cIB=Cy`AbVyP2KnO$o-QZDVjL6G<#qXQs=Q^K@bd>d3sW5 zT4H%x;;}Ktkpm!{Ash?@4R$^Pv@Z`hON1s?e|FlB^0iYAEgZdT`op`%!<>`JBZjPc@0dhm@ha&HF`C$GJdi<5 zuvQo>6-rgof~N#`8~ro&3c}2o`pRLylFFD~-!c9${Miz0=hhkE@@K@WMA`U0wTbcxeKl&D zxfJzswJ|=a)P`dQ1j$tbm9mJRt^OHfcEU`g3rSSa3}h(IlEDl6vicpGI<$Dshzl>y z!=D^w9sF4kfjFSE{2&gsre#yP$Ab#2)>zq8GIt<#Qk5xs;te>n5$ zd{NWp(lOn!;Nbk{*75rIfhX5YV-N=tM_3cc4(D6ZSngN@&!Hj?23wXDubQ-b`lDC@ z!?9Tf;^*DzJzp7{e0YR6$RLU3g$Leqn`5_Ypgdr20wGv8B1PB1;kLM>FdPZ+NW zb)3*Y=(HT#l3?YY)^(Seb&u&zxXWz%m0SyqJ%Z+Wz&#s?dx_koN z2bc1fagU{Up00md=JqSTWINUz$65yjy*&?^H0_+&w77V~>?7-Dl|48AI8QzfT+jKy zLy_!ZgWm;Nzc`N!vve9Bo;dhu&fwz{2b>t6dTc`f@|@JtoKz4rfgGB=gePf@VfyX8eD4#Us*v!Yv=Z!kMZiexnN1vPvB4%jJ*=-wmLX(Z$E_k0V0M?5H zn$86_o~(t%J60og#%F`SCUl%J5brcun2o)L{J_Fh0-v|7M@r2D8@uJ)&UNf|{kv1T zW5bSBbDGzQAo*Z)OudsQE`I#c=fC>!>)Y@C?t|NR0K(?IFKE~NUHmsb_~1(-_!ep2 zeY7>S)~xaU_kRa}20p*fN^jr!`~UGf%r`12oP%RRzvLxFg0~g(!eTyt5!6NB%d1eZ z9c|4~-s^kT_oE&5)%DLLu6|)h*S>x2i+A4qWXHC0mn$~l^0)9NB-iN)2Y4hZd6>H! zIHg*=Y~{ych}a5=wF3Xt2%By{Isj?VBSM`bz{MfU;!4v8MfI{@QAzdpAX#3LtCQx= zL;tK&XTH+)%FF?NPI%Z2qhdFPigVn({ozhwq1Ny6Rn?jAKE*b5_ew1rasIB*4iwL4 zCC~l+;57km;!9uz&wc!zG@qc-IcRgxKtnw=913TPnx%pVuZb=gJDU)bjSz6gsu%36 zrLsXIdlvXC+3}38f?7sE7j1x=fy~V#;w^Kw2?6oJ5Gk^W5VQ>HmVw49W~NlCT;ElP z071t^O4N&}Qz=|^>p8+M8y^{`I9fq8rLIm5Jyi3oWixm6$qG?K3x9SuY8~0Im8)T^ zh=ewgjfvI~jrfSQ2vk|6yec`Sgr>HMfT;rH@gb3&!$%G3mPqS@lwjB(oDc0c3!JLR`i_b{1<7ozmr}Rltvw`V+6Wdb+pDWUWxoGsvPA?+|-avBB$ z1brrd`Jv?#Uz_&$>k|i)o{s_hWm&1f=d#TH#bZ;BAVAINLj}flG)n@I%g4PL{r2TN zd}76v%lXTYB{LY-zR;<72I75U%lcyl>)DdSFD~Wfg%=aFTRSs{ygdHV-7`j=+O(Xv z5{No4dZ?hwHs$hC!|NE^#%qhbyljzIElC8wWjX11)bG*Ahe${yBUsC~t&{D?gmB&T zgL6mknJ^d^>%(J3+l9r|7!uDr%ao>U0Z`wIV`d!_w{auqk0J=xkvV`H1Y3fa@xRN4*J@CU%eR0jnou zEu(snSnvozhQSfN@X7!q?;4f(YI^c(S^Y5^2f>x)W}aF<<;te{*S0RXxpnD{!X;NX zF1Y;M?6a$<9GNrfbRbZH12G~36Q^Iy()i(JRAPp zov+}}`z8-Nvwo(i)3>eQ&{+Nq=P4@8E8VsN%11|A>8i=QrakhLFdfTQ z`6JIhJNjf<0=e%-cH{{h5rMXv|7L$npko4l^b)Q&5rt({8^~4 z*#^bGN_Q=Pc2=O!!H>j!(s<=jPy9adc@G22jO|#vNOcb9&tjETJxJTy$y6(yLqZuI*S&QrAn{ zSJP`i*ZlQO3yv?&*q!q*X$wxRoc6}1#XLpuJVUc=aQV))Wjj}Kb(a@%OjmOKLZQVX zsc`wR&5IfHMV#848_Wi1^2UOHMN-a_632Zjyn4mCjdPE$m{>MB*W5 ziyjDP#`&2JGf!|9{Dpq9v^&e z`SXV#es%ly*SBsVdAjqrfAiVfH-8;M!76VKmI!wx#5;midZvE;D`dT)nZHR19Aea= zWwnKh^3SuK8(&o6&tEEkKDhsyH?l#LE7086uvb*qJ`r8v&yU9@SLM$TS^)+AN@;oQV@F>r2&ckTEkm;B=9;<=_$;2uxFs8JXMi&Z z8rm#sXJg$U_7_Hk+z?5#38j~|OmN3F@KlQW?t1mzVCUF6k->Nrbne! zM6(B6O(|Q0nj>4bAq6274-ObDA-e1$t@E+9t0`g0vsM7h0-TXRhh)!!e+`Rv@@HLR zurzMcs)i2D=RG(F|6|7imHfG{zU2kx&pc*&)?}!{N&fF0LhiHb>C7 zpo9=KAlh~=SP;!=pcI;xm2$(P?H*9NF24&8Z9~^Biw@yv`CWwbciG+(PH835B9QiV z=;eEm2woHrY12nTX#~<08tGJjS7p)a+94o1)XN5frf%;c&ikajVLGo?>Rk9(a99K# zb{`0v`Ooj;5Kofw=b-`fS0lQ2QdIZW?v{02QT1cuR<2t2-tA9i_|@$@AK&^K1pR~l z`M&P~<_#Lrj1{Q1oS7Lr1 z@-_JAoGxFP7SK@>tcxkkqXFg>#m;kciZz|} z4SqRez@8Z+v7SceSG+lwp_-y+#^i82`gYt7p}Teb&re6ZjfW~Z2i0xk=-58xSP*0gO*)hz*%HaFxEFdkrZ*Yc%BMeacJ31= zrVqoN0L?8q0gq*-9vlHzA9QT`h*L`@o?SQh%*N$t%S$$k*82SRwV=6^&n-BXH?3qr z=Ao%i>>ob}yKGhmIEAAgOzVDdY!Bj4M)#uh9*n6s2wG&!X2d;oIvD#idc&WQMuUaL zh{MRCEgY_8r7G0D%M@pucbUz8W%2U8R%{DeaV~DZIy9!&;n6*cM)#l;1U*Vp`>_uZ zg~FdLf`$Vtf(8XMrp`kx7s4OY6UPM50)Kk4_Ye58yUk1LJzpUqFsR)nJ42*hsb+ z{w#hVqa>%B4GRxzseg8IC z^229VO@3qBGP2PDuMAs|!SWY&tY>fmokW*OQMY-1>9UOdQ-*gUqW?^3a+5aMUm zKNpYbZu#@;Z1AkdF1|1az@@rY^vT>F0c$1O^YB?^kUO_WoPW-3TzGW(_@Wt)zdAZm z(ryB-Ck?ss!qXSGE?Xk1+eL>I` zIEPhg;?I9-ze~xmQd8xqT4KvUg}-<5M{v8C=w1-d3L|*t`0fClu7dsvgxt2uN~X0P zCB5X2qoS?Rh;~3QgJ93?QWAW$U+J9MLM=;OBz*0mHd&($yA~?n+_8!V`t*`#!OK0|9xKF-;lugEE%Gy3TC$BS}?9U4FQ z;KU(EraoFSYed;T?x$5E$5=k#1Cjy&MH06=v34==}3@k_6oRg|5XoS#GpVSW(^a&`m z3F=2DrW~EvzieXv(wqU}2tE0c6ALmfuA7O;6@$Fk7(EHYb}S!d`i?c6cvO%UfXA<( z5O{vk;bl3eU%<+PyqRk*6|T8ZulE-8~zOL{?*4{pnrb<{V#6c zx^wHjJOB2-@BHO2K7RX#k>UisH7bUGI`zhHUH#m~y>eq`JI?x_XFJvCpACP$`DyXt zw<2Bjy)J)qZ)5b&{R6$>&qKZ49}fAQDq69mMR{_Fa0VH#z+ND*@l&m38Perifo`yp z8t6_`{Z=8Wd==fjudi$G$d0{S9h2OhQ~cdD>>^5s>_=PC=@snAA!X!8RgrTCF}rFP zZE0yz7%%!3AC)Q9w4fzU-#CNLsRu}LdXSQt-Kd@$LFIF0&9itE_&Nk#oz=$KIB8U1 zy2>Kw3W=;CdzLwO@U{$#c0M%E!dI1r3O(q;kwowI7edhW>aB)l`dQ8fxmU-_X;bkvG1vFQKugp(7(!XoDIcpiX$1G7BRio|Xq}Ui8LVVlE4qj_ zNSh(@ETCJ-vsx(Y0fo>y)xyEs;dPSS1_-4;sA zkM*`u4;f3OEBrbTNINvr{rsI7N1#IqxU3XM>-_|2G!=W3)QY`HQlW<~)YT<77Oq)) zU5DKV?1lg5T^Z&{de|%aXZ$zVKmDS6_V7Q{($zG^U@%@zd9p^q%6TpB|R!nVe2Vy2CLnAa;rcWb9(qI)1~Aix>gZ1{73>KcG(`16Tz zeNJTcLmG{{^5L9EPA{K)dE-*tn0d(+xv~MmL4{0^KTAGAY(OB%xMwiB^XjutADH~; zD{1`>%^FFPcW?*Zv&b)bCzV`FB+S~mO6)aI_?YpV`VM#|KV&FvY*8imjY+ozk-qrC zBHoyI;o3b~;4?lUBKJ+}4S5!Mp-{3upv6~5_kvjNnmBOp)M4jVWnWpFb7H~BLlXxc z&Q8UmdH0A!liUAsRlRBD_c3~z?@O9Y;8vV0|(kl3~BIx}Yi3H@CV3TY(`S3l}E!4exMcZ`F zqh#1Q#nzqBSnDcs7EQ8oP7W(&L8A?>TB^LcY6*6RCqtfXfS{R;axY;d(6$shJ*vxr zFz)x^_K)hqX3M(9B<@Q~!YqYf$1fEGjUv4g ze@3L*9dSEh1G z$Wq6U@bg<1k#h|S#aEtv`q0!ze>x`l<&2cFMQJy-FT1c~`O$5; zr91OVcgXx<{F%En0l!lE$F~&-`g_iwEoZK&62_&!FZ|gF{bU@F3CJzj8C*%2?t|4% z_{<`Tc5C9#&|qdz{;UX^kBW#nF<4wlvNlr7Qn%B&wer_I6qY~RwbZKFKOld`Swc~& z_Gt3}!?Oq3C6MpZ>3nfZE|TUeTb3PPJ8l2mQLj%PdL(-w1H?2+VYU+n7L6Ztc*3CK zNe>rKeYAAu6Gvx{fKh{jOJ|QNnf(;rTn8o&EXf&MI$Fyvy6ypWnFwHxi-Qh0FQ-g3_RL>-ydK>$|mSj`@b)7ybNmg`fTU&U?T7&96SZ z^WiN)(4lu3n6op!g%}C*jn4_w&R5d%Z8NU+eN@)JQ~!-yx4w8E{`~HpfBvVh-hT7L z;H!}4VdwQHm}(HK4dcIIN(-N<)c#FJ=XAE?tp9noL*~I7zm;HrhMY_gHNA85)AMKk zwoX(F_%lYVJ)*m&MkNl9={qR0i}gEoLKQ#(oLNJSFM=i3sm5VgOT&uAPnD=T#eQq# zgh7wc;gI%mjpFw>l;QDaZM*erN}w-O1SV7fp}8c12+ z6HCOoV~9HLC?Ym85bO3uMS24f9>2>?P$7H~Zo=z|)bO|>Ot>Ol;o*slB-|15Ps&J_ zn~bZ}B3* z*emr=FauzjP}FSsv*oUGEX)kbpUp8M1tdNdsDjn1qLq^8Pzt{aH*e*!qJei%XzRs+ zvR&O&^x(pN6+tV1RzGLZu}Ye)O^TB|Yu$;RtJYQYE+E=uic}UIMx_BsW*r(v z9c@^&+;&3u7P&VncD5D$NO^bu?7XP|Gt`04XusjlLj&xw?#iE=xtc_|{Oww`f92KP zw?Fue<EKi~MRXp;Yc{P`V{ zQ(XC+HA19s{_KJD*r`sWXWFRYuRpW2D1T+iCdALi(D?hNYQDR|*)rkUR4j0I zR_?x_@@EW|#bdcL(8l8e)_QT%;__wV_vH*dz-tT4IioMY`EW+c!HkrB>3t=MUb@&; zASyndnNpH9U>Aw`raXRb?X1iBx#tR2Gk9N6x#X;IhFMqPTKF?BO)?g>VENUx(~%6l zHahv>)W^=gxBxdrUPi!Q3`f1VWjT(@r#CMse|G-yO_G`rHcp$o4B||ChL*SR{vz)_ z20qJXpWHC#_~Hq?(6Mbt()$#Xfs1Tw#_~eMlj+9KIiv5sj6Sc8?YDdC!w6;1KQr@< zjZdFjJ@L?tM}Lx@480^>ASnw^EFDj7y9=9^U}K2h2^FZAPH$Xt>iGqw%f}s=`_$_> zgMOOP=cnn3yE2k#@L+oK;k4u7XNr@#0WN z4k^W*I_7M6RL5b)~&#ork_V-qb6IwMG-GX+N*{){!W=${XVLP0ST1wLm5mn}vGjo?3{ z&!O=H0V8MDO}nyf#rd6*ix8?%wq*q<=IoCU{^gSL44cz)&(AqLZ{+UrDSI=M_Kxih zg0}owoTZJwwB^rET>P!;PMGX$#5uh-bw$m8YW$h)QT_~YR{mTxrYrmzPoCGX30g4n zg5l3H`hHuU>Yu?r)Uo4$njS06#e0E~AUO74#U^^~^jC6*{WND7s_APxaxd)2D~CS= zpLgaR+acx*STw+V#5W+Me}(}vg{G80GY{d^JUi=uYMi#F?E%wO8x}|ZiSTFVzIE0W z)jFxHvRwYsQBeUZe4$}(KV|0SxYW14#&}g4UKbI|JIy2}&gq#C`SxV&bTUTP8@dox6t0o_L`pJVigAYxR zO)4WD;iN&>ai}8tM9u(cGt3zlt-c&0ho02`6ft=abCSyN@RUc6EggFSAvaFf@NGlF zxyraH>7WS|+5~?%Sg-VI<*&GCDD=S}26mPE0#;_4>6dGoJ6`IuLgFU5bu@aGS1ePIxE5I(DhS>Fmn zXu76Xo3QCY{!9z9pup!KfBxu$&*9IY>07tH`T+BdU*7q7oCG7~dqlQ- z$kiIZ;>18_BH7=C5EdN@S*c^gltn9#CB>KqKSU{X(AKp&_+0HcdPUHd27l|ycc)Ai zK2r&H6Bto<=rBRXLdU}FI%Q~@lnuPr-PhIvMkR#-^|m9XyQ%KXzYt`ahT=+iqN3daA}Z4F zkMt1u0uf4urL>^9YNcW(L!aF)7vZTP=yD@`rnGfFl82R&2spw{)Hx}&SzU#ex^~?v zm;7Tyi8s;{o@QP)kvdxpfSEU4qA42ND4`xNH7beCDQCY z%ufhFw6bW<@R~H?+F8@v*C7~&NUL`=cN-mLV7t14w;IzW$B+$;fdN#|K}Vnvi?*WZ zaPMe)bExU|VrTfCRvz&s!JiR74~`1*=Wcs~@9`-s?4j#! zAI;FV3jX{r|MTnr`d7dEBl2hR5AuNb&b7~f{>JA&yZpPKUHSalwa>5J{PZV3z0$UI zQk2X6c;D`?Y*=(;b6#2g+H#5Sw*~awS#i~Gkp~k9jKcyjtD#mER)K7%+lnqIo`D7t z>vUzsyxLqQ@%q|X2c|u-Yiz$G#%hBcd`O@LK9B2%BL`6WaMl3mE=dU?u7@(owU>Hm z=I9I0&c_n@Btm7h)*=3Em0E@sixCGI2I0>*B3|FJnIJB7GT0S^fNEaFIg~lfA)}~ zw7z8+K9e^vJrSb27n$+6w&~x)j7iR6B{3!2_=sz*g0Kw5RKDw+z zlZYAX1|-mlhsPulMWc-(8XJd@yct%k_RH$FL5XS_aH@gqmT>Z9XFZG$+mCi0JEfKt z3zjR;vB~|%;$dIuM~j**e|Ao(Xyjh_Gdy|Mn4W}n+n`Nrc_H-PfaoBL9wQ#n2#+g~ zXQPzHy;*lM2pV(@Kqg)vlY}&#Zi1g=rU;0h`&7y538yyBIa9cZ&}4;|HqJh^asu>~ z*K^K8l>CzVEiDma7Fyu^kv;;lBI40eqyG7u;j?AM!iOCm&fm6P2|m*}%}Rv$bE%{z zti+!I(U>+fC-50W49gXx3^PyhxIQ50gX0IDSTYtR?HfB+0X#z@TXAN9GtmEnppL#6 zF49BOA3iuCg_EC97Y-U!{;UWZFAllcUj;HTn_xvBB1&?}X=H@97DX4i~!J)5->waIRR|}t+7$TqH{?C7`-{oY^ z&N}c=sG}ncMwXsdD)46lm8s4k;E^6!d=HF$gdS5C*BQ)$6?B(ByZq6IGZO+cO*aH3 zv*|=Cb|N#_iO!Ar#=35QwLd|&$8>f$8)1|Fg!nVA8U>Qf5iWZ1M{BO^Tzh55D#Me&Y%P2C0sD((uSEg3iHUBi2XPh6!#4hq4LK9!8Y8U zt1M^>Q?L?`GJXOH6Zb3`cVOu_k}a~}+dtaCgC7r6=YPEV!jJMUzO>@QpT z5k-qMnp8Mn!=L~CU+?_QU;hSOF8nscpF`|a391o7SHNdL^bh>`8|6t=`16}@d_^w8 zw{CoT^Txl{uh&lX&wc7Arucde@JL22h0mI7OL?Y}XNy*xfENN|*{@dAXSk-)j&QGi zCDGrpm%k%?tXpKeF0M9RBid32J_o&9y`3$8)|K}0cF|xvl|Kh5bcjDgp$B-oS_D1N z+mmqWpRLrn+Dc7asP@wp9Mv@c-LaCBJP-EtBnEoBOBkpwN6IVkSw-U<5xBj=XDfbI z=K;%~#b&`oQ0E-VJ*UPCmO0ysDxV>r3L%y01y#EsQ^>Qw5pcDMKLO^9$Qjy8|o*%Z)>zI3mgw8RLqKm2lUI@YI#?){FGT zx%~|y0}Z@^cz1MTe{>UHz(iD2e^fJXbaP*zg_nqG>5F>68`a7e)!JjDPWyn3*tStI zZ35A){e-WD+uJbm#d!3RhLYjq;U-qY=za3YBt-_X+F8# zey>QW0}(!U1^68Z4~mD$C-~~Ky9l(?O#_YCheD*InmrI`*2>qcjkksJXWi#o8u%Q{ zV+ee%e1JsaTSevD7XGX%U$AopaCSe~gD{F;GV}!_B$DrLgwT4D;04W!;M?$9i=dT1 z3xbYJPy}6>Ki35yTf(g5`R=9i=U^GiEa_y?7DQXK4%E>a>e@kxqd3_itw37rqix_l zj(rCn-4^K^XwQjl_8|&?%c5nEDY3T(>ELM1W0>geZ0~Y>O zZ;_Ki+bcTk!vA*nhph6Ts%JO9da*MIrk@Mkh;m|Pp$-T#Nu zKa+oujMDJuzqs}}796A?yngM=>o-3uEBk+X^>{SkitP44!ym7ihvUSt!VRTJp#RhG z=b&oZ!Jic!gM6K#8Og2on2#EEiaKKiDYT*1`W5e|49X^<9(Z3*7x%^vHQdKk7iL~D}QFaV%Kbfw;^7gSTz8d zt;Ow`#62a`A3Xs38rxUIISbNC*UrEc`q;XsX$?j6uFO<&ARb#i9pN!ADYC2)Y@gh+ z_RQ7|Ckxl}^LhJ5*LOC5$%&Pd4^JMxdt~p@^c3OGV^bSOmWekVMNp z^Qki{r(DZlN+zI-1*;HjA6=6DI*bHJ|Az0vm`PVb=v@6gypRWRbDq3UH!8{p3bUK~ZElcCUtFbC~5locz24sv5N zgLrq~Ry`(>usk`eQcJ3QUuLV8KZj9hK3Wj1UjN@EL_OO&RQL zOA$gl`Ll38(L77Y%w~1cxcMk87>5&%3*7-66dHduttU$LpNvg@DZAh6Glw5vHyJJT z)$Pk5b=SA&zO{YDTU(dE@vPW}@5&zd`q;j&j_LjK$Q}gC;>|0%>ycsk2c7;K)$?b| zoU2sez~4H;$#byrtQ3LImH2Z~QFhYd?4*MdB7}xNBY0+hwP>bf3a7E8;52DQxfsdS zh*8Pu9V?E$w30MfMO$;#*@o*H?1?4Lg@VOr@-mOleiQ^vFHFz{+5l(FZ8VfW|2`0O zRj^zWOs+bool?^xVbkvyUjD{*;LmzWqkKL*rt87zai`+{{YkxXnIde^w?}h$ZDQ=J}R^Gh=`b_AzN}geT1gD2w zs-~{rD&4h=mx@wlzGXIJAPj$ABWID}z;+@tFeiQvoG02;ZAvy9M`9Bd6urXQ#iS+# zR|fU=!IMzJnC!d>NvTEv~ zMdJ_5N#_s5dAuxUJbrLIrWt~2PfScH%j{i}omessUIe0q+Koy z?o95+65AN3u&R9Pin7AovV!G|gE(0zqGGwax2`@@u=aGJ3_xSN7&9E>hiuQiSh(c$ znn}kOjVYP(Fmh`Y+U3~;VBqj)te$b?U<;4u^gAh$LL8se_r%nGr4#!U^Sh=FDw{G` zmYO{DvLXAK6vjd z%%6YtL52Ubx@V~V`Th65C4YYZL*dL}{Q2V#dHwmVBpOA2-wk|Div+^gQ$>AB&o|9Q3(=D%_EYs;UnzVSbsH|-X1MU!w1{c|6m zVAzMFdW+^c&<&4MqQ9>T5z_co_&ESxz%LrTJ)NqB$rUWiLM>D2iR99e?atO!XQ-u} zNQEhw6?b#D?c{oZ0HE~*NBcT-_jc&vlO%dJgBX^rNuEy0o`*Cnh=vOh{X7yXfrdX< zAZWv%ErPC=IXfrT#9L}VU7=7-^VfuoET__n!sj4=HrQEz8ov?v+}9I?V|r-xScuq_ zJ@0L=f@jJgc{a=$x+ux!s)W_n8ul2p6b3(PuDzfygjaIpAv#5aiq2U@&KOf*)Eq5t z%s^MMTvnG1r&`(Qg+m2jV2uH`HF!BP+9hGYvb&B;z;c|6@F#czjU=L)xB<&C&Ac&9 z{jnfr2y;^pcv%T^OiN#E%RuY{{+QMh0OXjqzSwsD*!I4d4*uAVf!GIqF`fLe5BX!d z1Y)}dBc{7AE-5-LDNsK-%0`2v7@}d{xsIz)VOEYUDIHX$h{zIRN6Ua@gKqU&}G z)am4l?%;`P;|@F!8406?PJ^c5(rBucne*$!;vFA_dK1P{c$=5M0@U(NINOCvgokux~9wjzE8i``%g_9aIfuz z^v{MrNA>6%)3cMWL%gd2m%t+rKl=7x{PnF5e)A#Yu-+5?{Dc4VeP`xj{Q2Mh?aqJu zuV4HT`LhmlQ~qpRpuZIUeB-wlFaMw6!zagh{4MKxH!qr8wskG~=d#Uf{#g9Esxmn^ zrHV3HNpFp%!ypt=Y9hvsz-t^QX8U4%0_CK1D0)i$5;lbrKVew$+_V#`r=P{10xcGKaL5b9*vvu$nphPlOyGxv=j zaCmGoQ9OA_$)dDl>!zQ5Vd0?#S+9;8^y;XjePfc3&UozNGjn-o;f==ZKx{qMAJ1QR zqF~)A5cJk{@^%a*TR;8K>?aS7>yI8=%r}e`h9*orOrF7UeI?z`l!r?ek0S@rrTk@# zrM<*YeqlxVsyVMtd~E;J$BP$comfBn%%-IxFWj;E;!A58X9{^fvu4`Sd1;3x48oQH z$O%;gWC^M=83Q4%U{C6xKinILBN<7eYBt&Hlq%!Pp7qk8Wj*^3g$k2AA+ zo?x;KrZyHI-LPfeJErUIF-;_y6@iHW<@`|Qa~-93KDxfPQxZE_ zsammtMNPV6P3hK^rF8jWszB;AGP)KnmmwQF*MOuraNOJB$!8Tl8~&_RHjFRCnN58U#M8TA_4z^}z+l)4LL1_`{JE@_KVu+F0D+zS zIcVt+TDCSIS5DDd@aGByZM-Ayi9hob%pd)VU&n~5iU_Hxg+hmv_s>gvZQA3nOn!71DQl+;zp;L1`OGKic1O~TXGK{i znU{N?n$+)TPT!JAeZkH}6O#>gPKH9`WuYKilLEk*O=>?;M&NuW zWC?*?(|ur0o3n+vH+SZpUq7R4?nt~oaGx$gcRg{yvB?AB-lQW$=Zq0Fo*TeteiRaD zgwV&Qrj}1hm1Kp;q;m%12wgIM5bk7Ui?Yvdn0>Ke87gsZ3);T`375MKSWST1O&PcNq3<=e$&n#pb5H^tR5e>Y zGa_MCHN$2_#vI|T>+#q3M#cN18U+Y+%P~y?QB4VdFbrE3!ra_L_?kxsnz<=`ru4UP zBT**&Ej@t;yn$A36*kAT^G3CI6M+t%n2w(4PTrV@yir6KcXU^Gbazi|Pfwj*ULvM9 z;fd+vj!ALFrnu{-y6X+_#0~V;9~dAS4DiPd@JnT|KYnm@!qBM3L!+AvtJ8RBY@;DD zjfd1}GPG{9VGWuOt>1ib{iXxrnh$EwJhegNKJ@_9^}9vIJm~hcaz!-7@W>Sbl#Vfu zA8P0!;9a>i^j(asVf8?1(0!~cO0pb!8aDAZ!qo(W4veGQ`kPDmnh|)RbR>nE5bpZ6+zqCs;#J$8U#&+mgzfF#O*9A z9Hb-b0iuD@WVdwUXdtdR{H4Bu{IP4}yNZSC8&gZ~DBElHo~ z?j1dC>$>XrT)ros8u2%O`}ZGw^!Z2Rp)maU(+_^oKi_8=w({o>Z-4RrZE|qj`S*Xj z^Z)+M=WpL61tF<4jQ&}ZZt%?ThZ$dX^Q*T=K6w4N?-1tc?#3HmVajpy=7-st%j-wQ z$NM8zPR}@;zq07XmB$L!|9SIg5VR2|OQ~vS%b%_Ixmx~g5wwB8AqjL)gex_G7YsN`Mgmla>>Ux1OLMl%d(Hm8nJ)U zussupl`YLa|NQ(b1vo#i-~|L2!l5bIx)u=4HuLsW$t{relGkk0idW~3-I_W0<&6HN z(;qv%VD!xmGu|p(dX<5q>u2tr`uMA3QVxvmPlBG)^T%A-xQG`+eoh&w2@8ZjAKkL< z=%zKOpbax$d1~Xr!;8nhn%y5%SeBJiJT_UB!#H4!?TcIWuJk?!CO=%hXzclCXJ0MM zWjHObb!WG%y0Bw?*>lTwEzBuioOAiP1y}QzUngQH_)(%lZF_c)NzV_%xU=l$sby{<*+ z-8pbYX}u1O>~UaZuS27g52U5MKB_NWCq;9{99xld=DB%T7M$D0iLvPCFD-w2^V|!o zCzj5AYH!ZqUE}(`o-T$SoL#{!F~DDw4^mb@VB9V4Y6KnjtzA&vGwjFjSP6P@R7pYT zobITLOd1Ja@wnccGew#GPCWhO)%7#q{t<%b+>4KG9%P0fUNS|0W zi4Gk)p$=#EKiMx`Hk~@ml>S<%~`MJxTtpbUifWo7_W04$SR#g2x9sBc)oDe#e&rrw~!`p zt%_jJZeJ%fxL_q}c~~nQwWwhQ#_kYpDu1k5N{)z;sxpO^o#C@ol9zWtf9Z5v9rts@N|ES+YN1k(!xfMpl42#NVP zMqCT$uqiIg#nAqZt+`hVmR#Mu=<@S(&#akRzBsF7&S>!Ok(?n1=xrZAkhFcfa2Oju z@bbd+3-d;o=M2TFh`#t^69*i{SR+e#GIw>=IcsTvvy6yQ|Bb4pkY`8WadB)ye*zp0 z*~Xt4zvV-dh7`|w{Nn0KKij$#Fs@LS%b#Z_y7djNmy#nWk66Z*hnq79T8^?DHR(#Q zy$_&xx)mB)n@*Tpl2pUlm=xM|*H_UDe3>|0njk9<6xhJ*(^`^n>pIa<5v1Yr|BwIvzu*1$-+cP< z9r*LD|M)Ey(4TxH^?TyXHO(x@`hzduH{xf}Ki`)46t54=pUFS?!B@B6`|ADo?!5OO zcmDbpzd`(blfjsdJcFWn4#mCV;!5o}+Wh{vLn_9wkj#uV{;r!CZpg^iH!uD6&C6f> z)!TP&-ncz&>hmsFBaf?Yl*`x18`n9uL$5%m!M?6T+?^>w(Ea_LiGKdhef$q5`P%jJ zwgo^DRER_kj}WS^k!`v}wow{GNxdT6t)%WKkx&XHbGH0khgb5_<9ZS^@5Wl zp`>KX4LKK&5u8R;>}|E*z1^LA8D9m!V^?2$m@_)q&c4KghzW>jDTY6y2Rm0aZLYOlp zGdvJUcpr%LwQ~Dgdx$_=PgGlYHfrus8nUK>Q=Vgh%}i zhX>+`$NUM8MG*}jk8b>Ubdx7yh^9}*N<2}wQam2l^x=f2gBvzZtsmc~ZoM9{(GU7O zEh8ct373{#WQlZy*_p;q8u7H7Jh85TA0izQ)xcY)iNC=E(T&;!8nyK|?&xjS$y^uM zdW*BSuXT5Sn;yQlgfL`Kb7aR}5gmeq0(=jJ`jR^0Y?Bmtuy3FuLakHWa!Zh*+Zn z5gQG29apr8Kpj`0Li{WaEipulD>^Lr;Wn5*#>IltLYync8I|li&`TRPX^6B{O$(iN z)zbivqt+(aU^cs{D*=Qq;cDDGqKSsuTx+)r=`}H&QRfqN*j8(F2kmbY>_p?%WCm_9 zc0-9YCBsH+Uzm0qsbLOvb6ra>82Jj#-5^+UlNsozb1GPxdrrljM14Gh8Do8dtnU&6 ziUYl>4Z7QG+@*zTzq%*>toKZM@vz{)1$t;y@06IXoIKI403#o=a;E&R|8wiT+n+HA z>!WwS{z3m-(___loBk#6StJLy?|k^~o%jCz&OiT;umAF`PfXtDFX*AZX_G`ig9S?C z%kg`RV5Sf3K5l%*>Llag8+Rb#H?MxYD)04#`fYej&3=5qf&5h^n~_^QV;!)?CIg@Hx^B=8z&shU$+^F3aY{MC=G&pYrI5b<+WKsu4nc zcYgCS#$cY@Ft2poYy`uSP=?o^f|VE#GK}}g)>TE@*A#7A4T~mAAjxRXY~f9iaicg@ z%EB9(6dkgMr2y1$o6wvtOGuWcT>~a2voHI!sJ%4~|R5aO1~gQ})ds zb!_cSwApx5lfNGF%+6%1pxH-WT)O|6`AW#iu*NGA9;(;2Ehi~q`Qmi))bGpezaMW9 zatj)@vv6h;nm5pvI?-7MNvvVf@LT6ct&8Zfa)c4=uy6TjIk2bD7uOl= z#~LdReYJ(gVHGEr3;XK+e+=X2q0JLhj!@lHu*hJFm__4kaHPV$S@1q2S)HOuANhJ# z%ATBoMNdD5v&7{WW?n8_e0fLi8#{6@ZdrKdxmkeLq6MS(PkZ#0aVf8)CB8bk*Y31l zu;{&`yA!O!iHpMs^W8r>7nJk1a!SE({n5dejVZKRL)Ta)9m(oll$}_Xom`&Trz9N~ zoq7%r;pb*wGn&}4t;^xh$9As8b(RYpj=>OhRI=wcEh<}{y>IfcJ!7$t76mo@8Him3 z$Ik2>q|Jp{?Eh3iU)t?~rI59GukD+H(+>Q0;yQ<}Vs zJM#Dwf4N}U<;@E(K06z`p<_!jan?FC^-=td8I83+vp+XLvRz(Fv(F-Q=s1XPx4N&stah4C94A6DX5$mOesSz?qMnSe$l# zzgA*4KJy1Lj@%RT`*2lS^(wnC*dCFQr50oBRzLjUcg0&Lts4YUL*#o%B zA73@TXzmjSrwlrrgY9!)q|W7&grZ|-jUt-VggpBln;_&_BgCImaq1v7AsY;cW|R;~ z3DJsQ*s_%IVmMK=UOEK`wh;KtxyQp54}RQppx>8BD!pmR$#t{JmQFk{Kb;YC=Ql1s z@#4}mJD;C7=81+rw?87XQ^&6F{_+!EXJF2h*gh+HMkI5uQSCbs%vqfV5!(_7 z+h2Tg`wQT+AZX#wU*CH7&j0yecYg8nU-JT@CL1-O<7%hZ^m0_~%y*gi{b}b5_0Vuo zXyMN_#kDsC>A!RJOTU}-L-(A8%q3;)eh8lsGlpTS)6@A;1uL#vS zv&K~HK|E3dpZog+KFe@^F?p7Bidb!6f8E>nP=yx?n&-$)z~^oe;+V}YLi60o+q$E# zm5B#B`W^u3vnScZ?CN%&rosJh>elB0OJ~TNC|cbO8@WwJIb06hb?Ze&N4tCsoq#I? zo8`Z9X22<-E)$fX)VeNrd?dCQF)jQttpfGi#nx*d6W1;X>WlC1YcN2tGt9ZcV3;%H*;{XzufZ^X{YQKN=lYL& zi3Y=c5|4Wmp76y#=}mab*Wf81W&8+#!x8?3k%2}d0}V$@#G5ijk9!=QA$&?OBL)# zN-9QQWCY$MaqL}BT-&I|9b=kzif-A-FIwnsQEj>f1VqC>>6a1yj46$`bMJ@;lOySW z>CA8jNuMVn$vyc>+`>by=~R-uT@pPHQF3bWtqyrea<@y2XxGD>P943ixxnGiZ6cb9 z_}SICWkf^aw4O#-E@N|n@dc9OAmeq%83S+<5!R^}LBv*wpAkY=);~j-qw#Dp2wFij zCC(&-h0l;@XMnGXdah`i1w@CH;AqyUrD~@IP@|eQR9uzPmPO-S4U29V8IM4kvO*(` zUx&LPoi7Bx(d0C2qE`xcEt8J3rGjWm^yf0Nz=+SeDRCgQcTD@j*q;PPL2p4^#l|p4 zy2JE}hDdXbt4#+inyWr6^!}jbJ@IGgakcQ7i55OnsTMNdW#YZ^=YfHqgW%6(A@n9< z_tZD$p;lfoe~yZ-J9GY`|NGu2^j5>4KQ{VjvK3eRT=B!i@304iKY#N6*X&#P^X*^W z`Io={>aX7Un7hH_)1TvmW;ML0Gv_Ux9tvo9_?vTXA1sZZ|BOetY#e^v@&NTk1Ib4HUphJ-j` z(%w*UXLS^Xg?y-ILP8v!w!K1ipu-~?sx3B_sHNt7xT3%84 zIVGEyLv?spy|i;R<4I3HJF|Rw=HZ#c_hj|km)Qr14O^=K%W3FllPq=)tJv9U0>9sJ zdQE(|+GcB-**U$I{Mq_uRHnNEd#eR;RcHI-PJv51;B!xlsiDVvMs?dgy8EuQ9t52i z`?HbC4?esw9na6R8|Piwy7b0ND{kz}yK(LwSo{8^_!p2hmZ zl$JvC6}(!%($XoDw&=K~iiN;om3y5(Y;pZq?b&W8+C}V?T2>T6SLM(9ragRS{gf*^ zmYv@&X#s;+38`wx5m!kvOo^bb&I}@cHX%4vj#ni{U7L?eiGy6%@Ml#)JImVWlbvj~ zYF%lqZjX~8hrwrEk#mNsbsDKU(K+Spj@3l9vsF9Mxop*Xjhs1jT*7C#cL{Or=`K80 z+<;BGIvj&9Y$fU28q6qgCp)@*J%4}cGrG8K6{C|*JTv>)GqW)Ur~in*ePCzjT5wBn ze*BZJ?_ABbz*$O$JCWD&bYUDncp8z184-1pk9Z|o-^*K;U)sFnO2LvV`HL>SFz@_^ zS*KP_DPNL#WX`CAGakc9Z104DyE7%31xb((W%WOtom!NgilLBt>BC^b%RC5Co}2Lq zAE^^mY+#{W?Y*6eHSuTXbjzYe|2#qbHv~cF3@FY)eckU6NeL$nDqfI&eATo|FD|~i zH4lW#2o&iAlr)qGzvU58hB<6oYwpbQ+wJMc6y{{-2%t7e47KZ!Tle*COD{e<z?7qSQYwM@hWKx&LG;8_%tKC19)wv3ko?eu0YH0v z&q%#-{>6n?x39XeRYV8|ILj7tj5r*eqHt+0H2695kjnY;rp0HUpZ`Wd?$w=Z8M}9M z>odc9b!PmxJ0fD%tofgOECW2vsLZdmLa8|VJG|or2aQ&ve@6Ul^v{&EfBW4#@aKQ{ zyRUx!mhfjXq1VJwYvRK-P5<+4$0>fU*j+X42PEZ;Z@qTuv%h>BS<%M_cK@thn`BW` zdVRi_C`7B#L@NlQRKHd{t_490{OP8-{G6PJ zx_v2?d#OIG1;h_=&h6Nt=HFIFGU2;^-{sk{`!M_34{FcL;UrJ z`r{t#`>CMMz_eU*J4~;%Z#`d>GfNVNqAsXLaPx8EuTne zF}yyW9ti_tJ)K>V?Om=`E>{y{C|xJ$CM|~Akz&^2ce$fo9$0jOJGQB}K`Xg1TX*!g ze=yLYv%kYbKKhS3aFXB!!P$b;IVI{Lx>`aZsFU6ek=c8a21ZH@h)C+^O6(VznC$7D z=qv@m(Ee0ItDs)2(<0sZ%wrKwQ6gw{noxF>coODUbOLUbJ`d~=K5|@Pu8pF zsY{wg%)rUFXfZMX+45wqC{o69MEP@6M4;MmlIMzggdYUW$FP!?;oG((=Oeu*%;RL# zAZx48uJ00Qbb|<^j*g5&9ZitgP<^DExEnyENwWxx#_Algx7^M2-sP4{Nqf+&BMMg> zJ!P=y;O)pbb#VV7=+{eh8?$=DqLoPN6>ZG+g+&XF_6J$C5@`;T^hSl8g2HZ4`jLLC zu&9cTt0Be?U3As??>?oP)(~3PU?RlLb5K+-<r zntp1exx$}OK}!ziN)%l zEBLda-|*)%C;q-i*I}6C_h{Q}$C~*v=yHqXv-@6$<H39aq?$IO7ecn6kY+aeLnmAk|RrUUYqj7YniDB zd9xVX?*QrcGE%Run~gUG@36d9i0Y<5378d39odaAEH0bu)@)KgFBi{B+B+>5U2z zz!+2)XCU$v7Y=dENUuKbJAZbv;=9x>f4<8+)qeFI`EyNp?T<^FtF9g3Y{U62+>acE z`zSMd1D`?AuaD_Y!ogjm5;^m+g*m=3jhsyvH_f@SZPDc&i!N?kaAo_#OPiiPz9RF` zv`0i6pOJD1YjlThxh57-({$&u_q|?A3N6m1Mz_qU0Rry}F}|KK@X(x5XP%#P`K484 zvJ;C@GTE6i`;Y`wb_ff}b9Z6m+_EJZdnXMd#V4N9N3)ZUXC)sUmsmC~8AUWu`ap<3 zhm_Aj{tQ)Czi3-3f_6@KLTO8_0n{+2atO zA(gVuRuwNZg$|2qLuXb>rmJ=`-h1WGcH^Cmgw^jCf7W$bzE|7I?~^}sNpfOvZ9*DN zGC}EDE!(=9AxNb=*OhG(AbDw9-sugq_s$u;XZEP_wKH%I=dbYhmp}7kxgGJ$!0%;D z)1`tHJRw}%A}|wkEq*M2%}LyF?zwq*d6B;1_@Z&g7K|x<`Y9d>4&)5ompza)%5l77qFb&j}qX_APy>&3ZE%$K&orHw>vp=O?Atksffnd=$}Pe zJZT^jXo55Zd$I=}p8mw~CE5HOeitrbJhY&KmJW0?iVd?7MbN=xD*YgNdafG&EYFaf zCuer9qnF|MmgVTcukT!QeOun;=jNYXIqB%rPn1p`R6Id)5uTVdh(v^CBu1P(@W`ap z!zQ56@MnxTPMg5{8jbX^NrTuU3qRkVEH2Li(8ucV}TLM_SG0x zGw`i!%L-P_SUIHlZ){tM3Y{Z`D4Ivy*ETHa+AJP! z<-5QAS^o{1690`5e-?A;+jnjo^Ns)ZUw-q>&pv(Y+GlUw0IpUrRcE~>zFO0C=d#Xv zP4m|@-MOr@Ueo+FO?NKqtk*PuP17B+=Suskrul#Iv#+mS`t;4~UtPQU>&xf=W#kjn zBN)pch-}=keuIw428AWYdFwq?r+o_K+0_O0Y6MtC^>9Gwc_P z8dfNihfH(vjeYS6?l^*sX@u4($p~ia_FKuShBgvTg-FuVNF(SZjJGWb>=aEKOx-e~ zNef27yBal?0rK(U(JHXIIfJ!TMD4UG7UN=%m~{|h<>40nVFiT_*>vF7VLe(^6s;c7 zmi*MjpH*k5ybaxw?C$}8-FDG&55_d;R4@La zy7jx%soyn5Bd$wy-Ogm?^ONi^w!Mekd|JYvF=VDRAleh%HW)z`-P%(DnW?vNN4N3H zJf;*s=XPG}>P(w49lbE;Ku0%abZ3uvJA<9O_+q+w$tMVQhB?P3`syV4>m>PN`}phh z_16VE_cwmdgM4v=g*i7E7JxYu4IcG3c+8^aK>a5IN}Cf#LYp-L4M!nnj&3wsI5QES z9%z^z5WJib)o^UIMx${t4Kt$~Wky#jvjUAK`5WeV6DE2ZPH;Dx;B7R)Pc+Q-H_DD; zW}-<}o#xqfTa2&QBD?+rSq(Z&XxwgG!`7qXn+~trFf|JCwy%RLvZe9sh!yK>7q@bh z=jIqu_{Eiii?M0*K=W2nE!qTHbO^NS6lmQex_z&x4!r|nN-U=nwk@1d!RXQ7`~S1| z9`JEp=b86ldPDC3dlw5>KoA58cB-}lYFs`9M;jH;OIt*$Z5W0CrSD?VICX?X1EML$#e&|^ zaRKjW6N}cy(fW+U*HF*b;4FkY(4Fi;9r&pH>Ny?h;V?cR{q+|L&DfJFO`+k>Mj0m) zqhp58nj5p^{s5VK&AR9>T>0y)a2J1erH=IsO7-?iwnyU_A03zU{PvyizW*!nC4N`b zx#S>!{huG-ZK1_Gz@#(HpC#Mz-R2LNefIawfAL>FYK1?O8Sy*i&%X-zZz%r!_RWuP z-+X8Mm?DS8(K*srTQm1)?Rs$HA2fVs=g*3ocLPwg1%JjM;v9Gu0m;^tC!SvN>f+M6 z>d7z7E7-So&cRI!LD0q=Ogf_c3F74zomTm?fNo_H$i1Llj4ZBhS#{~DMQ7K{IJqSM zQ1xR!$jjWFH|kKu6K_Aa?DBKVz{RY|v#_!*Ks5T{#ySGo*T9gu*|Zs3MIpM9gHyW_ zF$~4zUrMWDVCEDooz>VH4?MDE%8kb7T?~v^v$|Ow>HmxV?)*H1=)uxCYbqynIW5(-=}YW$T!|^CxT`* z=&=qZgvJ~$OlSJQs~9^k&AamaLRbOF;xq=T;0r~rq+h%I{EnK}>sMTOcJ9%|S-9Wu zm4P`o6%3_7(0D;N6s8^wdT|*1*-$t`p83KWWeA~3^`egF4>8<4*vS5ZA+)kJRlwvH ziG*gn+$u~quVC)Cx^i0!%}4t;)o+DA=MLV51xMlVgY%xa_{<#KV0f!fZCiot6W9n@ z!v7>tLGiQTCgqo6w8lEE!eQmm2x;USdbED+p&e_eW9m4$vUS<(k;W<+dPRC+mBDu*xX0nnGP9rQ; zW_4+>4DS`rjF`C)OATt6%-Wy|(lvb69gU!Qh@fT#sOji_U|}1c|7|g6JT9nv@74RG z{WqY&M~X9Okr|VMakwz^K*<<cqy=d%AOqJh;==u+7Am?P!mj?b8Mp{Dfa=EXPb`E+C-u-!hP0#X?V(T+e!DHtrn z#tr{%ekHP3_;qibQ<@y^VFq_(bj<(vxBsNf0PhHFwCx5i9N&ol2G>5?c|&gv^9`d| z0)NK*`6vI<{O3RZ5dQqu^^Z~Nn%Qi7`fYL7_B__S&VSbJ@ES?;xpDK;H{bkl-P)Hz z{jom3%^qp#`*??#3?G)f%(krO9erbWSEnwnWZ)!HSWt76Jp%0_ zj0kGv46!*ZR-3Mn5LEO=v0RtVP(z_fxhxKf2T}&@kxB7jE4yabLbK5s#@SHb#w9uh zbSGG2!OpRksAy)yhr}dW6R3bAt2GhTZooA{Ie1`SjE{s^cBm{iu#XlWYW<;R(b}Lx zWwD7b0lutKgoWWS;Oq)z9}aJaYb-EB<1W4JQrVC^%4jZ?Ca_(k%A5>{bC{T`1ERtc<+#o zQq~R_I|H8ykLzOV(8->Rr8Dm{!vTy7MA^fkf^M6`Zna8Kpa#wuK2YQXGFc+jVvV%e zV=aXJVWts=lSXe}cpra6Uw?RiU&H`^Sc)&Szb|xv7msCc-w;|~Uz;k)`=dhpILZF= z_jY)CIe^Bb0fLb!13tIa5m>Dh&fXqQ9;hEHZ4fw{@&xS|J8QKwf@dNH!-jyJgUorj z8|)l9(iN8J3Rl=UTuGfHC%O?i!<;pCj+!LeW=hd!chpp&&Cyw&*c_jx%|UImFFwyN zs5#$rhcFlV;(`@lDHB4<)PxL+_9Ce_$qHqr6;<=9a-iy zD!SC2Sn5wI3F}lA(XBkXM`di!^0@9rvEA}wlOKzS9qr>~TDoB69>mdVI7zY$ncc!y zFT}}c0%qOGu9zO)4t+eG`nkIg@jR5~NlAAP9OfJ}#GaDk=-c1bJH_2A#nXMDyX!!2 zrxb5;KW}1RUs4Zmd}mK=yelfq9^tZu*+N2X7Oz0#5WClE!e9vDQUGd~Le}PmEH_qT2U--zt;g!1l|d7Ao@v=a zqzyr}dU$|Z!>D1`N;|E|c|b315vjHjfOrQ)t29G#jV91g>7vCoTCr%1uVK*|M;jA5 zv?yB4)vX=$lnpTs0z_N8N*=4uE@V&)rxd%Ki{x~q^B)ZmZDgk^MKn0tI9HfDB4WS$ zJaZ>L)l8)C&!V-G`Rm~2FMO=3!0lg3+_M-jOHQ%)Z~Sifvm{M_ zrjw=v{F!~=+28#1hj0G8qI9Lt5fS5Zte;c1_gQQJH~hZ%b3m(Xh?aw$FS|e5pzmJ( zEIEB}T~Y$K)HFV`bocVgm*(d0Sy6Rx!~BM)mT3MAYQ7J7HiKwQq4g58${KFW3|4eR z*SD>`UAN|~y47!PU2%SO^`YviFXxUqF}L8&=T}{Q9u3uorY&nvZAHCIAbUXk%rynY zPF~o)iS2`kuk2VWO6I2)G_9L;`I*I+o?VRbGVGeWL@&K{9bO+8Za}c1-$!?>J6tCh zDR?ttzHw^NG%m9C<_z0kka@83k&`P*@P+0Y^NJV=ioT1h?Blg78i`Y{UwL`k(xz4A z`^qL@6MZme*zx>~;t6z7cZq?bv&khXn$fb$pb3FMiA`)LafT0r!k z?18i_Kb$)d%jg4BQ}#_Auy^V}KJNX6>HCUD9;zIFa&h+6P1QFy&%af-m?_Noa$H0J zY~l}QfNWmgp1%39-&DUn{23U_?m-n;SB>@QLhK|#s^fQ+mf1g+gRXf=Xvl|LKs8O<}~ z`Ck64;j`w?qSjVHgyuLxGg8+5wixogYqF%RmG52tgI|nY7Vql}PJ_n(LZ(#!Py3|LgGQwzjO7o1g36CFXn0ee*VXi@sbvVE(Lm zeo+5Rro-xEWQM-5rlEe->7C;DOXS>(vrV&TuS=OrVX%7_9KV~|6oqwuLdwkYq+MzLIeT}(*UoZBfQ4j5eU zgDN10W&&D}KWhrjO&PjU{26m*JzI_6VEhsz^#eET%TLccx4igh)x!-1BTp8I=d*+% zmS-F-&j3Da{(Pz|L+hV$=QyhNA52Y5;kmNWI-u}q(Wu7hkMKd9Syz4jxka3Lh_4j{ z4Iw8ca_4$V{&o;~si-*LDX{tBZR<;(7#-=hLzvQrXa4I?{saDu+L_{74;3_*W(c8a zA1Hs;&|CB8zyG`6{`gP-<413Obo<74{P~Xd`^veowW=#gYL*zt6;9yJNJ}`p7bYn>SVt(X3!w-LEn*VRG=Hd(*!*(PXeOy!ZT4$k zVrXSGz%;=qz*G=wifMq;Vntpn8c3y4)LCO_4wXFERhkG@K{?+oIN() z9v^RuqmW_4PQ|{%Cf*SmL<64#rK9w$9klXLf)14&8Xg-kh_-h}6|5<=ZU-x*WsZ?V-Z^dSK4s1H91Y&=ik9#p4^`_6~4(`rF<8 zt>HtQVM8R{&zFMhven%;#M4KYO+o;BNr^>s5AkZI@X)}E1Nf}u&5x&i;M?XNNz<0fzMj^922=j_{#Q?XV&C8Y2{N9_0=j&T*?TMM;j-Ba= zo#l;F6+hjdINhIA?V~zY`=u&FJ6D8ttBUDak=U!WL-&G?9VR7(j|vYNV7GL)SUQDR z@Qx1JbjTN0D6tiq3OMaxi)Tgyz8w9Wz4}^v_Ox{AWb2r0Phv_!JhK>V-bkAx+-dVcQ{ngV8gvRU?_$v=(B{j6mEiR%Pb+usE#!W4yhDB=-ZE6h` z9U5T`(=3|#9du&A(aNJEfTKgiI9ltXF-|vobOcUQwmat~IW?(i8Vnez>ekN@I4@}s zO)Fpapi_{VqtOrJ9j%Kt{G!#VLj=->I$D9~!N%#R1%GaFvjs73%QvINYG3)L=Fg1c z!Jm1qQJ$26?rt1-#1Ql!nA&vl>IWalFOU!4ZKm{(5ZdqR8+`}F|M?Doez*DG{;Bz| z|KeA_Xa0=!2N8q;yXoIRq~E^%DM85_*1Z}R*(Ka+ub%qIuBTRr&*3-ZztI*?exS?2 z&TaAMfWtU50G<`qPWAuAj5NV)C)M1-G7Cd37^N=8f=YvVQd50+YFp5bX^K zgX$%~v4Ijyy*#~X_Q831*kbIToqcHjw1%3BDjq}!3$d!n3;o_8=IH6r*D4j zH`xC|1T7hVn3@(3hdhIesbhshMG;+;j+M>9(y`}PmEGJ{1MWCcyW(X1I==N#=q6lP z>k(eA!kzf_EemlIJu>rA96=eifgxiAEdu5O@<7GU*+9^`13*UG4F55TeZcoaO8lSY zUM+qW)T{#ymF!vF47fwzNB?Xl%w~YB$*}oebKkt?{rh@59NxO~by|)-~f+v>DdPwC#XsJ<4Y@6;q|K;caj;p^1_QNuhcF%zor6i`C3j|L)qBZSC(Dcyo?c8 zM6eWp#EnDf52eHJA7Q7PS2nJjxo76omy5@|S~!vbh`mK4_7$ZwR!HFs!MW&2$tVJp zWm*Tm^bqFaVL)brR;lAf=$un&8%xr4ohT-)b?8yCufM~eHHg+r=xhE=Ym^Yf4Fg(!rYr-}izhQWzb?o6E!tuth_g9~($r#WTu)x0+tJeSIonILGXZSOvT{ytebiP!z zb%}(Wi9&UAcZtU7eaxT#t@*G2@}nOUfAi+Yx2}D1AN@0TwOU`6)3&-17XHC(=f`Xt z(2z8VJX2a|14J7xtas5@C5H}j9-%z}p9;mI2if~jW)-wScwjqsSTR~9j8SJc05&}v{^pJ{>2gtL%r&x$Up4oXvSBjTIyr7PN zgf<7$9s}8qm}XNXd||TM!79OUp%$Op;vw*hcUx(l75ro1fDecdi;quuWp_UtcGt<#}X)T}j_j9VUYuZeUu|}9uI16na>I@s^H2j6T8%>ab2#;hn1^DEb|$LaC&x(D({>T%||W zpYDyV_5h-#o$eAAJ=2pg%S$EB_H~#Y)^SdFmpPFgXGC7F$2%8Xc=XR=#=`n^it^x7XrP2FU&hi`Q>qjLGG&IPLmi00Xlo z+*tGE2#bY><2#*Xv2?VAbg|gGOWC?v9Nna)@9br9_qH&^z^4=Xkm%dx17%o&P{@vU z%AOG7h!^F&HQEvqsX`TD#srWQJF zRjtC*4y!#-Ax?(@qJ!{R5VWx{*wIrnWGw7%Wwk-1nfIY^v;m?6(&#{xVMv%c#}F1R zI2v8FH8SAQVT}>9XsZ}>=vf=OPAz)`_pMK1Ug6C+!!cEu;DR8}X@Tzi6@} z_1UBKvz9Yp))7=k3zxnZK~HcF(S;`YE3@VHJW%sz+Hp<^AI$Xj@9*vsXAQ^WHzRZG zjkkaN-h02|M+op4|7U(tD6#H${P`Px2ap!XG_-fcXPf%TKR5rsfBCB)z4?pZr~Vo8 zeDl{qyAR>ds1e@0^}(xuaPtNUA3X8s(|C#zT) z%r^kba9wC^)8-lwE-gahi}f4zT?T*VQ4*-vhX00nIS^Rg)bD^Yf35=>ue&Tiiba6Y?bEp@(j{e^8CxMG!eueRpg^Gi;ws@yyMi60b<0$=aT z8iw68_8O4qhTLHdxv598hfqi>fn#5vKZ9_!{@F~AHP^j&$-P*ZCFa%4{Z>~tuiw@R zt)k{u7Y4S_n*Rpy?LN7L-zxH~X|uW2ySG0ph2m9cen^L#`*H?=p!eqvIG8)&P+kgJ z=!U#OM{^O}4&6I>0PZVzBO|MODKG6$iZc(w0allo`Gc7oo0qqzZ+`4I+rK}8K2?SP3?#L!~(Wr==atA8~Bf6PGs5yjoWSh$HMw^lUrUHr7kOiJ1#z5$;%l z8vOKfe0wJ1s(J`LVKG9%)ML{I9WP4NHqHix7Kybc%;x05X=(dWT&vn&FjUmeP;2Gg zAuF?H5K2owSY~>BpT3641|@E5&HFRw7Wc9>eH0m+{c0V9Kht3gW(1AT4+#3z+_Zz! zC!Ve;JinnDFAi`bzNwfGfS{p{B7IboQ1tZnyD7Ac4j4|bEgX0v3Q`uI}q@(Xn<&hJ=$fe9KrmRW8<-S^MFz_;G`sTL z;!CT_PtAC|v2-+SnW#ayx2DhvL}y4qA-ROilqnqn7;h?vKWCgP8Fs!j{bG5>nc{TG zB`hDcw={Ei)r5wn`RAUR10m=47(e0AW`m$92stMW^b+jDvAXr!H!SJZG1?*8Gb`rL z@4owqzQmJD5(S*O=+i>zZ(9G1p@+GC^Yizc2_O9Fzc&BZKl_g#|L|kN2XDUdo&LEU z`ey?^(=qYqR{OWEe+Or^6&l_% zG^~d|w7bvW#pCPb@pg3kl0Duew>!bPJ-9 zB9OLXO6(6+>S$QBsG~z7P;4UQ6$))lq+mODQ|JyY5HxB-T|gd;Sc9b;p>4g<8G?DW z`KsnQN?54OSK-FN0zsRZv$@|Ee-1L|fQhT#EU?I6&gKp~0CpxVPQz!-oJIC*@1rr) z9r%p5vr@azYVpst6zwtUkI(Uzm=Pw z0rV{t%4c)&5JbyH0hUoR>+(J16nBn?0yZ5QGP6EUN-G}DO5q$j&?z;@9*Vd+6+dUm z5Y)^WSBfSiUl}Bm}5)bab+G9%jNMYx-_OTJxM-Ck~+Y>+AMg?F77-g{we&pEN(t7AJCMJG*(jLP(T`Z=wLqN5e{h4d=Gt3P}` ze@2}+BsS|)9@ zz~^@IXR|?&!J_HlCQTW>({vPw779)ILwpn@->~V>Ifm$>1xE)hqqR+k)$`nh_<=+1G224!-_(&Iu-UwB)FgN$L=RG$kzB zu z%P$a|irX63{%-kKdk1(|MP^{|=l6v_|IJ^0`lGl0g9JcE;eS8=8~5<%H*bFO;~#x; z^4Ndv*E5sR(%x~=dp55>w3#rPF9DwgmVV3lvyf7ZtOI)`ztxQ^2qe((XP`0InV<1o z`%Ai?^4!qynZ7P=8vXlpM1(94k*5P$v;DKEi8ik~^S#9f7ni?WF{ysq*jEb2yjD2+ z($eCy3yZ#=JLdH#7cxnc>jicBAPI>)R+xEkJ6sPc_`e1u()7&2ee<$kE*Sl4e&(*? zv4`hopV~MJ>MQyjE_SxAKeHvkpV8`olyQ+gw{_|1)n%{bXTFk~zPn&_!~ATLg9xuj z^9ES@cd#f#CTDS zTh^WAx#|G;8)PF}S7Ug1am$LPC+8elRQOu?gjaGhfY0FT!#Qb(vWEiS&}{;r59bUy znv)7|q(IOOxd97kt$)71|Fanm>%Qi<=H+H4+}3h43fAk~OR!mP-jvZdZ?mnwdHco# zTV1H{H8^vNj)u3!!fzFGHt&p?JnOze4$U2nqgeufhC++}85fRh>F8I=r?4-Jbi$Nf zSwo1Yd^LN>E<&t|MglP&bZK(ZqP>@>u!35cejj{oX3+u9=X|j?rNA$Ti-sO4LKc|X zSeS|lMpM!7;{_uQ6lETpn|0x-IY^yPZm(fVb>j=9Nt~Ler;eoYHJ)n ztakaOjcx72w_&-CFQnBw!#i-FYK2ZeVEr>62ev2JUL9CcbaGWCUJ6$?FS@#A;g#p+ zTv%Urbk<{he-9R9?9EO^4}5uL3AqXS^WwLJp@Nn_(8@d7Ow0AX<|W^TK0iOsZ(q;Y zG*Nd=YpZruPy7=iQ?U#x7;?05$Q^mJn!y3)g)mDMrQg2OB+$bEg&tm|8sljz5o zlnjpWA=YgWsQ|MACGJ`2qU*6=Ud^dMSKvde;}e(j1~zCE4jv%rH?}Okx^c#tg;~eS z#*jtWR5F50X93a3q02J~C?sL}-Dt~CGg@8HiLGWYXGw}htR``4BZ`Mc$TcRdR>akzN+#VZ zbW-YQ5Shag0wzMBh!9Z&AEv;QW(b0&@P$?g8uW^}aln_OYe+zCsC9-ttyofY>|^cn zkgcnR&jai|s1!#}O8c*h$k5eC8!rd+gsuVF6neNT5Z0!bo7+3gC+N{?zE?k-*1S;L zeQ4aRTL=;bcGk1+1I*dhd$3UoJz@KdDiUw!zSd3{$pWc*+q(9$cIh6{xm!pFf(0c~ z(3z0zjD@FHw;}+R}O{x$@G&*Ws^o2{~$RSUv zo_D4@X_hB>jwgAptHV5Zhq>Mkv%)*ijP5ckru*#J9s>r;-miP441Qy z(lawXfpG_p1OTsCMTdC2&gc%|$phkgjOo}vr~8n~UV~mF0rw+~=VS@rE4HWf6QU*>GUA=OO=n*qKI}2SoHH+3Z9fn`D7DWq-RydlWA}J8G3Rk7oAR1}3cg}8|a_OdHnf%%|H9M=Ku9Sf5RNKH*fut9}LWydh^=n{G#~LjnCh{ zZv4jhEcj#N8}8h``D;pV9LH&%m%iwqZ~f}V^`BqA^3P+^^PLu7jNMVce(9mDq~JkB z0~q!Xv!mhj{a%9R##}IJ{`{q0ra`lLl$k$sQ*_i@R^k5)VZQM6(nE_&UMimOGJ4?R zQHP7ioSr#(ck%dZ&n!Y))mXdg$hOrDb!(V1$<+<~85<46%;IZNyY9pmnbgS@`k7}J z?VX#Y2{w*`SH3rg@G>sjC8-edPtxL6d_2gY5x?kj#13-r#+ip^phg}E^d>W?Y5mL# zq}y*_%>@yA2tYoub=|RA(a)USxdD`Mcum!-Rgb=0IFcayBc{0NMCqn-q98LyDG>1 zpdbwdjfk2cLeQ~Dsq;h#&GdH7pBttPrhh1Z@S%dVgC)ZcRg5~lc=E+HMNKu+8s5^=&XAb9V(ojbe*J|P*K0~l`xW@J!JLf_=Wt=g_2M_nHU(s1 zFRVbc{;MQ^n1Ti1(rdz>MLaBn6rz8o1w^w={!*}96J0u&URY22Z9vVf?gRU&cU9l} z<=`_a=m*N58I#?zNyh(p!`PqVJ5;Ddwz);mi!Vt$wR)xy8z@uG1=l4y+l}Q3IlpJ?nxwA1@tt zw2YZ40-^!DQpMsFjoWaFK=0j5SlL+Q^xq!biV#c0589Pjx$LO z@QX;^5agSVNd~a^QFjC@3|y6XcpYX+i!Q9MKD#XMSmlJq^07jpl>s$7i7WNVvQY+q z76e^BoH|pcs&a%9OOFIobENSb@_5C>#<^LqZ<@;=2);YA8;U>c-*t!t8frI`P8k=* zlxK@&{P@TI@&AA4!=FF+>$?DdRtOsYtPnKL&xoJjeW&?<|Ig+>`{9Rg-})tXf46RY z$DiAAan}Za=E4pB{G;2y#l{5wOe-E8*FO63o1bldx~WUYRAEh>EXi5Xoo2^$o)g=n zq_aQO$>e%h2Mapq_>747iT?P<1Rq5|;*EOPBR08XToIWr^rdh=0HCC~4Rk^XH8zAI z2866)o1o_16DrpO|6W{trMz7oK2@PzT>j2>e`lw+i#j)(&JZgpV}gt<&QRPrLc*g%$S#b=ygJ?zM`>RU zkWLq6Jps>A*2f)sIq^o8fl);}3ZJ}m3STSp2obK%3vRooEg!7nNRt8+R z)tc92`?^3zbYRZ30a>G?7rP-?DTtj1S$j!=o2=b+U>UM!$TR-2YVy9wo~drOPO$fm z_Jjm$3_48S8Aux8ZcsYGbo|Gs&->}M*y2KL9jvY{PG1jiXfHo%XP7hO86-$Vps0}_ za(W-Ks}jhp`~E&GvFes3_$?SKz?{h$476BtJmfUW+t(%4&l#wIp4sm2kBHh9IzY@c zG;J2(JVa@mhuZzBMBbck4;}6Z&9Da)&YC%oafFSN3LkF=I7dDz74?_{;EcjKW{NvD zODYcFoa=@;Lz`m?opD93xMFugi95d3olxdN$*gh!i2{@aK+Tzhc-fsWJx~fP!rm}Yu2fawNv`lDmAgBXyOT>j zfhzGP6?=>X!+^Oo!t8(&+m%q|q!O!LiPN1)Gh9;ac~xjaRTwRJyc39fhQCX-uWMy! z&&tT|#nD}|V^Jx`jEHdcbBU`4Uo?&ijty8e9o$zsigumvd*`g!?!|F^W+e8W7vF1P zRQE;UT^D)u8loAzmvD^EhD9oV6%}MT;Ujc;W&_1EN*k(M2=xMA)c? z()ifJq7Bz*4Wa|HIf9~SIh6%HqM5Z}AZSgS$2$g7nnM2$`12^opohJ~M!5$L_4V%V zO7ilCdwk{7XZ`C>|NT9rxj$?E<67soB>RS#_#NO*nIbBkG@S)vl@E>73$&ecD~Q;5nPi2dy1y~|5qoi%Ci ztVy7l%d5(-ZJPbY(+e+cUd~iv6xu*?u21E4p$sItu~x3gE^JwLYVGu06%$|08@_8Q ze$EOzE5ZyH0%7UWKERq3fuPO&Imnz_=g+`rGkk;m>CZ(@rz-eA=)EV!ZM*_Ed~NSyPDRH3%A42Qot;isX$-EFD>3farQ^ z6^7WyY6|vDAHN$lb^cH`-dHfK1%EzLFt{Oq(7|bg;Ll)c*wMkt(HCm+Z$CHZ=9YPv zpPqScLq+5AyoNcCA1EJ7f*1}t%u_g;m(I>mc%d-LBSS*@AZW3SHlyQK`>g`xR@XEZ zw)znB!d79j2FNhvb{6X&$Q!tiQZCSD7Y>x($8rWA%a$1#oI~L72dAZz(0XcF@r9=s zURSQmqIkqf^@R&O$+gUVcj_ez$I`HI=W-k)fd)@b9LQH02e1@ zEsB19=Q_A9FM;;k%%6=nL3fO|qD7|_<+CP!512on-BEMpg_Y+v%y=<>53-Y&Vo?v$0L1b07ZP;w~+RzO%vN;U@l^(NLOB9W51~>eD6Z*j$_`&Nx#vqOowK z%>OFNWN`4`~GB}1-TT)}b0em*s$x=Y{2&K>#n+{fMEXq7t zJnBUGg!5#1Y{fQ>UvxF%qE;^<)aUCqp4hzh;Fb+zhxT=Hac&8D_W2z@`9D9G4D<)B zFS>_6fAGO?bn@U&{-ybU{MBb-Jb2?HkSXHl@AS`KtTNKdXWg3g&%kHuhqpezef?J` zpC!!k_NPC(_0iQc|1kOC*_M!Sh;C?RSf?3D33Gkj=Eg>h@>@DsY!K;@QJo%-W2%0q zoG@nD?9Y6+{U*>M7>E0B27RtGjy$ z<>_XT>KfwiV)1qj@piFMp3YWJ=R2(|>1x9vR!RfvE-qgemqt&TK52opJ;rK}ve-f` zc6_9fYr@C0VpHR2m5#%)yz3nlYQm(~`Fq|nhrqu^n#K4yKgkpn0lb(iMG?Qca~9SjiEPoX2mkTfG= z)K5*DV!KlsJ42qO>^<2@$TNwGkY}JeFACQYZ9me%nh47Ra6z6`o?u7-J45F%G~hjq zv3U|*-cBx0PnV|;@@CAO{SgEFIBcMHmJbw9<^XoK!yx*W>Hwru+j`r34H#1T_z~`3KvGDMa23XAT`^12y{!tqC!xSgN??4ECjryuG7q#luH2be z;Yz4hU2BV0Ks3yf6$n_y zokO?Cm;v3oHT2cu_KfFqnMVZJ#1|I3;|ksJ`7U09u7o^Ke6Bk_+ZUVTi_h`K<$2#3 zgzm)&9kZk29`yi+`6!(olr1w~F&!yLi{3aU#NO2vmKqvAF}ibZOpl8AUNhr*&5i3g zGc0*#7zQBXQ$5`kQ|*kda>Q1;K+w^}PEda|I&^Ar)@eqL!_0h zP|((1&R~XRv`!ig*mMLv?S)0F0W2fFkn@#3k1>b_h1SzCGF>U!J4l1*u?V4qT4;km zw~#=$NAql6r!D>S1b5mP`ylksgb${AdvANc&N2mSl!+qZqNGw>M%t@-o2KW+YpzyJKd{J155MveUTwRQ}M2Y!Tn#WhX( z=iiw1&o^)V`u6Qlet7%C6$@U9_jUDIY(vI{dW=@&YgSwQ8EuSgnQMV< zYcFkEbD2z^XO=W9%sWt$fdv7SQsR4NJa+Awd6(;In0J3{`x>M&+Hl*$X3jy*PYqCMx2}pBHXh4=*HPc)=fW8y3MomuWng(V>|Y< zG69^IiJjolZR>!~T%3v?58sb%D=uxXY1%Y%-|We|3p4lSrbDqB^V9LxIFdW?aGpT0 z{dq(7PLrZT85EjpcB2B?=A1M*Sdc{{DwERiS@Y)>sQKQTW)$3J{~O}ZEw&GN*7e86 zpTF$u1v{e{6x@gTcJ^R2s7RgBIUmhVp&-u})xs~}Cx-sHP5!JH4$|e5`DvtIK~xALBn$5lS$Hdpups6;b#=!oG|wW$ty|4p z_}A+t&1){HJj+e#`#l^R8B-qhZ8jskTQ4#e->kEDGWMPWTB)S z8tC}mP77{q+`M;9V~MfO7j{~J=ysB4W3@xMIFJw2MjW&Tf(AY}<_u}fNks?^g4Wc1 zS5Ddw3P&GbT6lf)(px*%V1A+?u*i}*2l7F1CTCFKV(rSaTb6;6q?F%s`&)xQx4^AD z1!;yd?ohw#$_r~?o>%K@Uf;3u(oWGc^F-W>7FU<}PS>wwr~>SKW#?+vytrl2$tPzv zZk)w5fA}+^Xh5_aGs=jg{k!*jT+Yy5#V3 z?&1r=d5phb966$*m+_0id!`NDS2^y?rnwhuS7V7ls4;`KTDbm)!k^)#3aE-^o8#w= z`qfvqEIzqB|Fz-~#14X*Iolw9Huy85Xzi+TueU}E@(h1Itq^oO`7;z+6JrB7x9GHh z%*M^eq6}Tel6(0x<{Lr%GyGW)v@aJ@FUCaK@u2nWC~` z#*MmFSGKMuQJPT(artI^s$LK@@0fhoRMDXr=%-i*JvmO%(KPB6plGLFZ=ql zi?1+gqHZNKCNzI$-rT9$4KJ--)UQi|J;dU0`!8R4>%E_R{Nc|&d*BEf{;UzS7C(RR zYxwi~?=^q$v*v&NhvvWhub;kk>%+IMe=L(OZ~O+oVm$%#i!toiyXyG^-hLbW`AvE2 zJ`?hM{a2D5f8(Pcz4hxiZ@#}})4{GC2jTl`?e31xi|;f)Az_|yIZHPS>2ICKCHBtk z+#xp-ju$`G5j)92K%4(zr+2K~J=*5Uw0TE3eQ8eL5C`xXBUz-a?%qxqrn`sJ)6MB7 zXso-2&sJBEJOiJlI;-jw;trOpqeZH7pwwzscNbNiZ3LEiy4aOo+AYQ%R981#I<%uR zEZN~pusX@bi?UczY?>$It2y{e?id0o!k{%Q!~^HSdLq^ync$30bP9;>=m=;FMOdh; zR(mQfG(M}y2tm-s+;#}Cc3MtDmaLS?hMrJ5qygg3?CcFd4$xyHGw~E#g@{E@VFiKJdodKVXczZNf8)z(j z7N8kwaq;sNMJTQX;b3R0E6IVyL3mGpRG;w3exV4G<#X)kboX@_hRk#f_)G_|tP3RQ z@1Y7Xs7m0oD$SoYf|lU9eooDwL;JaPY3v+2&?Pn4g?Jtby(nOVz**t~q0J+0p_z6n zY?K4{W>B-zHshz^hb2f;<9`wkfZYKk-4_W97klflWj_6dt+3^ z=6DlweM$Mgjs;R!I(K?3GBGnEa*)s4-DOX3Si(su3_@Fmd-%E~T3io>M5eo#ACWjY ztV2;0G#k&2gc2VHCdi&~%%-A>95F?X=mJOdGzT9|Y&N^f415=foQ=q zS!O+5Q3%MIcPP7Zc`K;5)FtBcyw6f3>F>8T2(`77)Pr) z9XNGJg5llLXz`1d(?}3RbF$KBFetP*3k4Ch_N&JlT3k5V;Ll$NLEoQ06FxZ7Js{QJ ztD`L%{u~n>yWy#4fA-$T|M7k^{P`E}H2?C0W~NGg$DbdBJV5(D8~mA>X#ez&&42!1 zK6>k|U*Nh-S~0)D&_DkU`Lq7jcNc%Yar4t#H$Qp%#xGv2zuGaXKjW&SQ+mJl{7M`l zz9yml&;9VW__MM6T;00!Tj5A+FK?|mwzTkIId+jlnBIPsF&=Mw5*HhJ^YdX5O}*37#jnGdmmE%*u1mEZ)Dk=)l6lE1Q>L&xqQM%N%sbXl&3h zqkmRT(d#a5U;jF6dHw7Iv$A%TPH0?^cjLK**J^7p2t}xajG5`=AZtDs*|%Dt%7#m| z0?CD|Y+g#iJt$BH(7UOYr;uTY6WcauF+2;o&f?io@?aWpbZP#pg(G+84%#F zp<=HJe^z`<^Jfj8wGf&a{W7UP$e-^RYuv-14fsswUfO)`k`_$3^_vfXKO6A*k5K>o z75KBj=d4r>pO0n@KAts5D#)J&J}dIPH*di1X@Bti8Dwn~`saWIx?mV~89-xb4BQyf zOFkf`qX(3K;)FFrXZ#w$+@gtGWK->g(HF{E~%Er+=BYwuIl_!Nob1#8|yQdA?Q!?`8!l_rDnt6T43gGtj`qekSZwE!n1SFtgmWVoVR!OYZ3k^OxL|M1(&8_*^AB$27Q)eX@@M$o1NGnFZG63M*_CJK9i9Ee53+}H;yOAl zP5$n1IH_b+Z4*Sa0YjyGrVV?gDDy~7#hK@pU){M8vu+VTGh>K}LUniruQf{V^S4m{ ztobuPC+P5rFa_f}7GCSB_E(K(-WH=#cxVWM#y7rj81Py1XKk!uv_aXkNS)2aSX=wy za|`c|7V!B#Hx2$wMpCQbYSp^M+=B8dQafHg3<8*O`E}WT(EW{AwaM4IkiMtCj z8Y;(g7@S*Garw!4*J>G+kW|6bTUTgL9tIjH2JvMaKfs^m=NaQxf}oWEo^gL&%%|Y1 z#DoPj)n{tTj?SEPxMVDjA4s6J_*s)@?Zp9krq~neblE5@J5HC5B*BpV#IobWjK@$T z;Izib6#SVjqj?biT(_~NEW1Ormn-p3-FpA`zxw-My#L#e-fMo){P{z93S|Lp@aOkG zfB)U)58i41yT5JzZ-4g5+c!Uc>-w+clIKSAcl`N_!T3GOXGQGAH4*W%=FeP3!k?MG zdaChnrao3_cYBywAC?)`d1i8_g)trHg!&%0SbAFGMn!a=nw&f}3a0|0c~k5$PdFkT zcKXISy`ya2kv9JbXK1<$n-2dVr?O%VhcPF5%C}6h+A_j0oAYkfJWAou$Ce z0pP5$bFg)GGV^Ces)biu*$yFhXc&FzrhbW`MKS78=A@5aC%0p!OywLBv zTYLAub|W6K8-nM6=Goq%yFC%~)Ww<5*&W}}9nXu3bw`BST^^g=X$`@mgm(a&Y+ING z-8d!&LhpNsJ2!cPk`(!nTl`Y6$WUQ|SOMes?e1-X_!;n7=wBb30h#F_aW|K^CG-~G z75xz9E(Kahdv$$S}35JHu zv%Sf>X8Ev>2v!*3eH~{?5&Wl^vv^ie$eT51?tqJhftt(xN#*`zTKIN}l<2FAy$Fwu zLU)b&S}NZsa^+wJl*~C^@NZ;}C!980Dk4kO6ko&?U*r?MsK@+~kNP7X@kKrCkDTa> znBc|KI{INp^dmNDCpx7jh`X{;(GU9q^$5;6%6s`SH<62yx`-{wqi){Mu!o&g_#>`x z-q^>*s3c~RlaVG>&cvzV36Dp{O^o1d5SJD~P#|*<$PC5iLX`6$Xue-eJzy*&(ZU>u z$YJiN(VqB6Lzyv=oE@2v6N>FKk&a59?H13ITxEWuTu|a+<9KmA;lYk0>Jg_HbTh0# zK;&pZv_wV&|1J(MfTiZt38Zl&!05bUFEZaE`_=o5uv(eh;p5fH6gIv7WjT?mE7 zI9fC3yDU5IQ9cK;GgcnvVhl*wwL8R3nLRo%u2&_Ig<1}+ee9#GCU*{#B3e8;%q&{z zqESZ+h_=Vcd4TvrM8TBxAS66mjt zpxffl6FtMwKaX(@8tLgbG_+TeEz)7JB_t(p-SGna8QJqMe%k!ePn&=FZu8H7{@DjV z|MWZk^EZs38Tx-$#LvI@;B$$De!uzspEdu>zcl~FfBX3Dw}07!KPy4$G-gRia#FyY!Krw1sE`t8X0!23LNB8TF|$|qH*gpMiPb|OmxoqX(WGX z@~oLN(n_taglowJe|6bTdj~-Wm*~6h!=DYdY*1)p$rp6KB!B*bttmH&KW6@{T{X<@ zeTcLeJ0o~DSJ3KNwvfZT04XL2><2;TrhuS-m-^=x66iL(IKDvtY>*QzNX9f(N>OOd zpJm26>0Ja=utOGDuZAP=-nlV{zU0diaYwg7Tl>l@44dSJ`t?Ka;4 zPy?2aIoNC72Vh}|Hh8xyxTW- zu6%RH>K_sW`P`B-tE>0T%RO3Ca&7zaH+HW43jA5CrVaQkmKybI*v{1#)?C`M^!Tc> zgY&YEE|_{@Md9VO95SnIWPgD zvoCI};%f-?Wz2}f7`)6-K6OFO4wG?*pirMfT04O&1ig-5bO-=2YDQ_m5=jo-yyWbf z%Eo!wN6RO0);(FCDOMXOpUXz-XUFha)o5DyvrzF;@#4U$nicSoKDV;;($>XHh&WZh zitGT6H~HzfZ9~D>v?wo#%JSIMyubO|e?elzRbBuNKd@P%7&+eI&s6?3EbvkJax=atJJ>1u88XVM#aL*Bkce$Xcb+5hPeKfQkKgDsm+ zcj?qubbdW7oeSc7E{p@jb(In{1Wx5Pglo|F}Vi9tf1J3iMH^@I(vBFIZLsG}VI z5e{+RO>S zvMO=LP)J9E9dk>dq502a@9r}UlWpnqkVTM4Lfo_z43>%$66<1qLHJ{y$j3YpkGdls@rGlxKG7X9!4p2-6F$}*HpU}0 z+DnCx@`Po&p!5-=ZPJc%V8%{GW_lt=`lRS&dRPr0j8%J-D!q=_wo`bRjB@xg?TjV4 zGeSHgLwuubd;}2S=y6UeYP>6SoWnof6*0~eGsd4VDm*bGB5_DWY`?IGE^dE<-4Sk) zq(VKu1B+(3C)#35w!nnRAtjkKVO&_^V-bmyBjTs{6Q&YDs8R?;k}axi5oS*o1g$8v zXrTeoF=Rwea7T@IOK>C!k_tp~goJ8QG``;$faB0I$m&b6dIyBSq65cmPpp2h?oo>9 zE>>43D??GvBpU^bwkL$xVe-owD zKd>|)+8W}pTclvotyUZS85S+%`Ck4U^oYLW$e}^B$e}6a5sfd0SaXC#7=^Pv1&EHb zi9v^!MoVxZAle=Wixv;8ki2MqrF@jJ~QzVkWe&ma7| z4lI7~E@2Ps_s=&>kH7wYYX1D*=bAsukFlRM|J%Pc|K)%G75tfDYqS3O_sE}b-1zld z1Snts_|2>Dj2M{Zu(%Wa&KJM8kg8RjlpC^RA{X5&JDPpq5%gBcIM zQaWm1*|ByYi6DzAg(_FD~*~0Y;1rz2WK&Rud-+JWDxDKv4|J0%bi%X8I zs67AtGOlQ}?3t&)Xu4_3TJj1}GUNNFpRV!AxqBAn@1B=+X5$RWD6AEg4)7U0>b6fn` z44=*V=N3R1{@h|ot2ggp>IcA|?|Q~I+>h@=W&fb>GLvWBzt78I1!c7%t(Fe5M6a*? zpQQypo8H6UF@J6cg8otED~^f9=!Ua9Hwx6MUCB54=FXan&(Arvs_dty`2xq-CT{b4pl3yyO!p=q4RZ#Akch+Z&Q%w8)?BGyetGMB3_uQ4PiQC~ zb8hCN=PM^1&r3t6{bdm}NICG8&mD|XRQC3&R zYyM1Y7;&h>FGbr#bL^p)#sr4q^f*S$*NjnOC2hdvR@bBPZ30M|R|n z*gfO%H=bW`>jjbuznuPALstVnBU#k^8J`Wt0xo=S-kzD0zMq@%THbInY8y(&9hvp` z;klE*(Z?5MpIDr8d{I{8qO21OryiUA_>mbC50sADlb_CqyK8C+2y|a@=CM_k_-|Z( zVZCT~6@@l1uhHSzjWQN~&5ps4+ut#sQ9nehMh$Rx|Bi;w4_f~Wf4=m+Ij0t8GrNZ` z(c!7;tTk;gqhp8i2kp)7cQAVZXRy7K2ke^EU;f^ejNUyb_vnUs%y{B2zPLaKwXcTw zS)*P4jD8FC&ze7rb=VFe=S+0Ex??qooS35TEn=uElQ-dLzKoq2{F#|t6gPF@2(1gh z=z{?2;xt_cN&=lP3!?csVaCf}*w_47BWSb!8S@IGv@p4n8E*;G7|2R4+9I8ZU_@SI0a)a0LidiKS-6%6#qM+teBIcpm< zi00jsPh7=w;EaJZT8&4DNPyo_r?+q9cQq$=1}5<0xUzNGmG8|yyL8%#=@T0(MxCq} zf%&ucdBy`oMA0Rq8w*E?;d9AIN_5fqa#V~sR*}iMnl#LF&&)ahLe0q?E15>eA;(i3 zetPBj{$0I75^S3`Z~MD{eji(m|M=?1_~{2hP(a=s!mRaO`L`S!I>;m>c~!hhpe@aM)8f0vV6V|RsHA}#UbJ^kk;_F5R; zd8VglbyBC|SpO7jbiOmbz@IqHo0J0}!t1~;>QkuH7-v+bcq52Y>ku1?M6qe@CuYC+ zEnpZ6mZV%gtxh#N9;a62@GNuWWtu!(2#un-I)}ie1J%)@akOZp5lf43T1xqN$aH(k z)x!qu6pQITE+i|_*b_F$9Wl@wo+3mVGz!p$MLQ#GOv4W$ zWRpW(VI?Ru03PN<&=oG&(Ux!wqP06T8HET4fi_rMz<&EXIuCGmNfB`}>Os{}ELsz3 zfzMcB*t*>XjqR}FFJBI^an=yK5p zyzO*o`4n6VLDPzS8mDL?1rftTo>Qc7PLL6bAvlCP@ClC?CW=;ctq~(^kt0RqtaQ%8 zJe7yD0B3Ei5&gIu;EcP>k~G_?MbzJhB>_HPHf(Z z9gH0AjZXJP4fVyOhH)S<;{f|*M|6mo-e?M~!wQ*36KSz0SvYbcQ@yd7VK8uzG8*id z$GswW4wfd*fOqXBBFi6DjvOlFG;)GG3J@JR)-5a=x=zX@qZR1^n`jY5D-g{XhaA2A zWHd^~L2#ZY;go@@E_U2GINLZohBy#KQ%NBdQzWDkY|eNqEZV@)t_Yhm%;pU0qGiO& zcwL%B2RSq#n!49~Lz8EZ)p57-IiP~p`e$>ieWcC4(6DG#UR(vj2~oB9beUPSjx3C} zMo{2r-DtumTe>A;zeQnx0wMxS{&+@&YDZ-gnp1ERZjUq<>WJ) z7G8M1=Hgbe#@1e{Tg#;@bM239TXk&5DlRB+=Q#J=(vxdv9a&m=YVF)}TUN3Ijoa5@ z$c&O%G6W@X5HPi#YaekVtXp~J`6VYe%|5Yl`o-EM7hfc$eYr4X<>_&ub|a*kT?IZj zD$hU?uh=)h)TJlqpQ@=myr2N>G(m(Xo?R$g!!Mfssaq?tgSBcNG0q#cE6#12b7c0^ zz0)%HXQv;@&Db|-FbMj1$(UnhWA^1|;H0`cFMVHbI@)HYCsT&V*-W0>>bHQ;nm^x# zdG8Gtyzi3l`15_R@YlIZGv|BTR=3G&k}arwp0(OpM9w*bjM5aE4?18Coi(_zco4Mb8{K1$)a}&Ap z;pq>b-%yP+JZMg4K-6zwG>R{vSnH5QxI-*|U*Ep;TJ6Hd`IC-TjK;nLpA8g=QU!zY z-#Ae)q^UUVbbe~%G(4iy59X%r2WeJ6cJX@)&Tm{!j|1=ZY{`jt(!ORs%@ z&9!aIPOmOIyS(5gHX!q}u!BBwmjoI?^$?Vw_hHDuYR#YFz2<@{-{(>KE;D)78!<1@ zefV=b5j3l{;LnBx8W2riAEJtoi&H%@g~Fe+27sUu;r}3K;LCYKc9o4dIDG=v+y|>B z>?s=cTKx~-^Y(IZC;Pcnv&l>;A zKuoXAC0ER2-}vd!!=s zcv&XLn+_Q~T{60qV~Z+-Cc_iuFWK2iWnCrg*S zi2e&=d(QWOpnFuuCl^O2R)-N82I7lH$@zo>gV~tLzOeDmh_TL?(JuJ2OpPCE^$)R< z78eS$QZZq^J|UD=$+~)lID3SM|Ax*PBvnvl3krh%zwEsSm=srfuirVx$(bZ_m^{o3 zSs+k?fyn~{B8r@IkhEGQa!}Y+0+DkDk)z_Sy}plqZD0F3Joa^7A!%3IRSx{$@0{+U znSfx0wDRB5^F5{Nnx5{S>guBFJ-_pQ#GzxC(R8%l4l;_|vz67U;IpHZN%b+5d?WB# z_;Wiev0G<*$z8j<*eIt0p6+bBJI6|C;0f~#I^;4*_PBP09?98%*HPT8<&z(1xy1$sd$qQ>~OQ(fmh9d=+b-W{hZ9`NW zfM*+q5gK=))HZwDSVJ9L;VzJ8kG~7O1%*7rhsCDbS)96f47AOF_YU|>8$szL7+vDi zfa!^JH(Km=qg);A*NRbqPIgaMk%1F<=3VgQLY{3t0;`C83+-NvzC9>Qu&0&OZm^Fn z)XxfZ4feO9UjWY{f572P3A{ygJXA{PF5U*1GujGb#auVG|nkwJ(5)>w5+nt zD&FiP-kdSTmpRo>u|ff#g+BwIjZ)+}WrBy6d0^+{(Virj^GFZwVv6HGvD%{z%;cH1 zgqfG5IkSe$q5B@3s-xrUC;MOYiRtlH={CW)1Xp`1>e}b#EInV;w(cDWVAk z*Fu=B@jYz1;!3S?CH8Q!Ew0!W>TV4dSg1h0`C2jbLku|E>FegEWbh@2QrTcWl8P|P zlEAqt^;0pQ1iE6&(eJ*+)y3rMY;trmIXa?oHgPb0-R7Ak2lSZ*8-!39C*y3;j^UG9DKwQBoQ6x>f)1_Q0htQ z<4fxARfZ5Z5FQ7Jdfx@nN1(Lg&xv$f z?oyf#N7$^R(N@3NtgZ6=QBY_DL@Ox=ap*{?M6~vDxGYWz$xk#09dSp;l4sV%AgxMM zXuaeVWb`QXn_NcWu8&c3_zg!iZB>n8_>4+2heXh!8W$QZ3+Y;Dv@GP*q0}7GYn79a zYPZT6OnISIi&cWq27)F6O-Dk_pGhWvr~G+kH)1Z28f@aeEWgAG{BC{u1}vhr*w~eDBKF$k3RK_Lu+rv$x;; z9rp&&O6Q)BIU3x7RJ= z@pn8iW80GPTjq>>d1A%W!v{Sx;_i)8s`o6Lc$f}`>pn4zo-4y@Vo z=8F6#i_3XUn~kNuzX6|_ARk-C_8Y7i@R=2$Q!EzK>rHNq{OE>QTR&-o$8Qq7{{MAj zWAd!GH2L>x{tSYSRc#pXnHApI$S&2b3CnU1DENHyOJ*fg@M>Lxc2yZ$ZfQmTF8O5R zabOo9Voj3uQUJ2r$jXh&_$|n@v98q|JO#C{rr=e%eE3$#o6tJ3-(@sVHOXUU64$FJFzW1?(!(Uf+XnY#5TupjO?K0Z< z>iT8uPqj;B$=R6hfx6hq;3iS`i?3DS|NadN4{umRC&7!W=Nz70#jqXNnK1Llq1i8& zGc=PMQ!-KmB!_=)ueescFC=o2)%?67=amNsz52vt#2`o4%s%?;;)BmD-oq0;y+jj5 zErrmpO}%W@LQywTynboC;07xO&DJY7PAPvMKZPE{{S-rva@2(e)7C5cWpJG9;-=7V zB}Nc8g2IOU8^^!b2Vr+>7V%HsVW2CTsmG>~LZ_)NZwGUEVE()p99K-=*n_x!7!vz} z7s~Q~UR}C*;^0He#-3a;o5*zZWn3fM`sFpb6kEdWs3sqrjYb@obpx==mju-vPodFB z*F2nBoD<|*$6C23uZll}L**C~ogSS`;QzUbqOFxUoQwBX74E}e9}{~v^3M%Y&<2q< zRx}6J%h#sls`l5> zj*u$hHA8*3)OFtqh#uKz^Qe9Yrw_aQb(?_CZ8o>>(B+L^{pEkY z$K=+l@4oY$^XCt)eEHiepMUuN=O6s`^WVJxDa{ApfA8u$|8e#2{_3k=y@h$>V=dpH z`QYV?UtD6+WitU_;A)fA-2I!|-sFR@vAO#gf3tDl)&@r7X{#x z9)IJ~)z>e5eg5=&Z@vD`$l>$s0T_k}k?b9#)7nl%d3*8 zC!U7_N2t(AVWtfixw4jX9+qiE;Hbd z^eO59;*u>*@g1C@&bDx_E12sFLwup>ZOE$=$0stYCIW~hl!<>C6d`a!99)fUJX(QNAr=2AO9Cd35#l2>7 zu2AXXDu;}KsO+&c?^8_!NjOKX8g2QcwEv^)AIbmtN>?1M`i40}WzOLJuE2e6v=|hh z0#PL^ZL)uWoeK1~QFtnJ`TE*?eeB-eHXP}wEpVg1<3|! zc?rzZgR-^V-_jn)a(EKWj*!eHkmC?qtBXM{AI&aJzLwVbuI`i~Z*oshavv8Y86eN7 z7AF?wR-pK%I357eN%wk^?(rtx?UNehPZ;P+xXT|uz!%3Uh=lwA7r%uFNPeAgI4%+P zaCfKPnHcFAev(0`Y&%D$oFW)uk@J%JliQk{ZA{U2s1~MO=xDSC(XqY`O{ASkW=tJq zyzL~@+cr`@cvb3_Dv z9g$Wx524nIU9%EfUb9n2qZ^r`{Xugqjt)f9(Mr~#P0^|5c)Av5SQ4Pn;)sr_IieI= zPB@I6;f3zzXf4)yrQ^^#Xc2KZ5kYtB>CBFGLEmZ5rTW|R8x+}QBkJ5-&bhhmz~{SM z1w3F6SGUgLHg*&JkZmO;eSY=kU;Xx-FQCm=u6za;#Zmmb-=ZdlKmRD-xSe}IoX=8U z%8n%q{q9woL0`FY_3!`Y^FMv-cdwuONSqtzuF`+7xo8y3+i_Q73FQ5PV z;`z@&)6C?0iz#yF-szD)%+xB;emY~{W3vxEH9x9` zCQ=nC9$e?Hl`>krBkD>A;;oB47P)g&6CHa`X)pNr>^+Z6+p%QgmIdRs&KtXH@x*;U znNE9mxlkhTtSa&>s~5@kr{?TgGU53N!=A0b=amWNduG;?nm+mHl#457U0yl!FrCrr zdNL(^XN8bwbkMuY3&gNmmQ5T{M65%zncmJ6_?IejU#!TJDleb_JN%Z$&cJG*E_c3$ zF%_8v0bQdpq|S!rLI!w1eK#PIasODLbTjMxV&l6RkM`rr?b-vH3dTN~&OAqw&oSl= zeNV{qEmZ^l3~m1Q{P`Muu9dj*tyPS_G?uYM*RORal$13hj>?<^HTm$FE%iNiP9H*d zIZg$jAq~pNKNDSs3qgutN5D)zbSIaL-aX;|P4vmCF5aTp$Ywg6)`)`RKxH1azY6|b zNc%7Xw7bULe`@K(i;9lIpg_<=ViIiRut@+I{4BGalis{MXhB?;_%XxWd7XUb)i`Wl~ zByS~r+jYmVt~)EFwpVo3{P|_!&)t4jS8`~-&oUU$FvFv z?a5Vhd1oQp@`3unRCD~9y`lFEFBnyem`2pf{xuvbA~co}bIqTb>-6}vEmO*#uPxnH zRSXtpN(Bg7W;!&Fpc@crtDO{#F~fU&wO!G-@fFFD@O$jaJ)#F1YTz?c==~#5Qg`PC-~%~4viFhUeGb?4 zhC=Tf)qBsBA;*3?Nrn$rGF$DTT`M0OeOJG9Cs{00RrT<{{=0v@^1;_vNEy8^7a-s1 zB_5q_K6vl5SpH1j=0E=J>RP9bve=js4IO&H>jyWbmkubZ$UNzPDj5zlJ>v(Uu?U?Zr< zD!zp-qI3|GFv&yFv06NB%oI>dl|&GAX_H11OQm;?aA_TN#w`rWCVY!$19YZBw!)M; zON>*Pv%;RD7w%@4BzBHuJ|pnCP&~sTB~YLbhk&Qp<}R`ON?gGbcc|C}mj=(`=pZ5N zYwdtInF9))X}APuvM_O8GKz!}=?Io+3)9-KwI@T`6jFA;aym>{7wgP$*Li96ql}i8 zbgGp#vZ8P5Eo_wSD#I+0StSyA1Wl@2nbTTZB%{dVz@G&^tChBn^w!oC$uT<8GTdol z8`F+aY!DI@`>rKX#3q3bwuC%qQW3##dkCbNuiO_%Fu-v_=>& zpQ?U>@{8`ez;gsaa|eBA zqR|w#jnr}OYEzh3I>dPiIAJ1ET`Rp?i8zwI4TxX@K&P_{^(gJ_9)hpe`MCDMV>Fhwhwj~H*{KLX%d z5bc0M6LRK5O2MCj&y>NO0o2C2tVC_nIzBB+tKFywi&l*bb-zOGh}NNKh7zIBx@#dT zA&XGxc-69y;WM3x))X2L9qCjEg|?Fa7SV^S>E-&orMqZtB>&ohz0AAt9Dr$Xw&7 zG3&-gy>hFZw!yC(H=BK&|0evIKSYyTmJ)|n#hzrU=CMa6?VMh@dDLAJFRUouQB}OF zrj*&%sQeC2D?7P#)Uk)g??b=LWym9wcRx0B*JHEyJ~?my@&(4uxm_!~tzw*BvFO-x zsPck?Jj>&ASRP$TT3d=2tlxd^Nr^>d0NkY6^#q$ z9eaH8wrRt-P$i8?Dj8Suh_tzX8h1aa)FnokP){5r|a9$z{JQ7}EiXh+Di(0LG)E&T^8b6J9pRTXZoMB~u= zz>GQ>;ab1=5Xo4wpzFv&FM`Dp+y#jM7-_1-PtUEKyMI>gE7he;N#Fy!9i|O-R&tL< z{F%&iuE6JS;?J=kMh%u5U}xiI1MFFXq_THyp~Y|#jDqgb3^z) zbMx0NB+7nv)m)_CTWWf386snLoGszcn=1uA13WqVMTTjlHK(MVx1t~}M-?KkZF_mP zo=`wu`nh2R2WD4ZS~cs!)AKQV6M;VR^wLAT*Epb}{8>V+G)>d|xsf3xG6vDi_8%gD zz8>~MO{oS1SVw>LTcgS9u{BFIc|NdaiD(cuETeck=#_9`?E*%D56!IJR9U)XSRu5T zoxiCvkK&&#tp?gXtZ3_y0>+N%&3F9KiMYE@^X_Z2dZTA=@M6Bto3Z>^Kd-SX^i93H z`1orY&j|r#1RLew`qhhRkjLTu>hkHkW>>s4q9=1G_K-}j$j2AN2o$Mi11#U<%8mK6 zK4<>a`O`(D;Fe9vXvqM_BiopKN+;asRFzLT2#~tX=!;zyIfl zzxmD8U;kRVpMTf>4cgpj{*3(jH}8E$zngb|ef8h|-_<|=)yHpL`pDqV65oYCGwJfj z{Ig1WH@6?6Rz@btej(Rxl7Eiy=hrV@y>R+#X3qZdt=}(R_*`-_DL@l2w#Degj?>cb zn3~XLx<7M@D`T=V+2GIQpDX-$cjJe6klEsBrT-v(&;<1mJ2YAlMhTBfL5qkLPzl}v zU=orv3LM>J0i#rbtc8h1D$1NSTa(OfC-FrH`HWy^)zS{;jH?#l9Q6#Kw*@-s(nj0} ze~yZ9y(N-F1yY4eopGg}#8O{UaWJKOD5W5j)GZL#!RKw^qDh$v5UqQwsg$GDY;s#| z2rfcaZ=A)S?oI+klZb``!=e?A&LpLrWl1Ha3`}MT*ul9<87umxv61dz_&qY!k`>K@ zz|PbiW?90bHKuN1NvD9-bQr|*oZ(7Hat3`C7cWiV9`@>Zi>IY4u1g>>Ka^Y)Oe*mw zmU!ZdBvLB~E>Fx127ivwV*q|<=@qC;v*lQl$qqM4?{>B4mEu5Xzas+tmF+bY_(asI-EWgF?PEe0C)|WEck7OfhgczjJ%Onr=(g=@) zKWsB@phx)Uoi02xE-A%#nCSQ>$P-OBKnEd%>RaRWY z5$lB-1cAo0!$n1+OTm8`qv>XIcQw1aAiI#wjP)kJg9$i}2 z!CNLZ$SX$|?7F|3_YO@5(=<3oNwdWsE{2&fSIbF2O^AT}L-=K^gj0vwE%-)Y@PS^HcQJw zC^QwxLPsdHG$_30;;`P4Yi*xr>ri0rSZM16f`$pxi%^$PXhhAoJO4bul`H(&p3if& z31nKZx!7ET2A2Kv|M}047z%&?^LO9>?1T5ef{@0)U zz5#!}bm6n+zK7hl?M?A#5VX+mOTgz(-njVTFD`yCbJD7iKdENOUF4r3kPU!mlWjnpuZNqoB|7owwB6GxU#jc7vAV}L zs-kFHnGjdRgETPuS$W}ebv>UO)&JRX_iUXreE(0U?s9d5BQO?qZFuEcXD{A2o9kfa~>n%IW3U-$j>>X0b68^lkB2QN=t?ot|?*Ofv8FW(bf6VkuV~K&XZ1pm4zU+tz+*wx@_E;wF{1~n-38syQ^^% zd@_;_UAq8*@R`-~jw~L{OmL_*-U+xX2%7LSMG!hR|E!$P%D)lApPMAfv7ax!u0OWM zosE^)k8|w0!JqYD)=h%to4*@pBm+T{e>Nh}yDD;k`8*D%rdKKpo*$aGbL?GjET4K2 zcdJrr&_|4S2Rti0KMH#xy}F2)f}n*zuU~j*!y=ZfYuZl&8OsWt2X{{@d!@X1>ySJG zx6BsVG_(s=YG`MKKg-k)WlBext|+uvI0TPN!NzIm$#~q0!wSJxXMZ~B(z^M_SI<4N zcHWT7)3g`+boch>brud$;nmlFF5?>kF19KgRjoA2i^DBU^!zC(*g zpIAPNfBO)6FpnU@6>s8IeLweX%%8vEc@+_r(Wq665LwFr3cF?H%)RrfU#{<^hqq{K z%9)UJ%Z@r}J{Vg!Nul-KVo!##=hd6x&$lFnZVo2j@^-w?sEz6h$s|h-c~qa%Q-{1d zZRoa9{rN`s(ug~^jJt3Docgnm&%C^T2?8_}F6?cXuM4fd(o`ZRUSf!%E4WMgCWuA5N zS(b`F!xACSx`Ufu#uYo_OWg6@-3i^jfauiXaB^W>Tz0_M!Q*M;1Vmdx3PfWP04G^= zkQ3(Qg!U)}Yf##L*%DLjDH)E`49j)JZ1+raN)~h8r4seBg%uI2RF*9%LzSjLnoE;> zri473Q(4jY8m!IZq*@b`?4dZP$7^@k!On!V-O^i-#)3)N{^X)?N@+N`G!S3xiR&)u zZvJWscq{%)CcH`hEHP#%v=;w%vT8dtO9M5ly!5r4IS(ScJqrBg!PR~S@d@Z7Ro=rD z=;*C6MdG0vAs&Uu0a zl~X3E#PZ|_dCr^?prXuKe9pSG(m89gpTfm~l!Hge7>^g)mp;~)G1{9>cfygrlsbQM zt)HV>Uc*q2cpe6dju^c#J@RnNFe<@867DXo5<>;{AUzYYi03$^k!3e$AlnkiH8qf6 z;K85;r&I*?!h5x6Tkl)tTNdTA)un{n%DgQ>TwQ!d_>t`M&JJgnnCgsG!==mH#eHqP zldR*@fL8-iby8X{#mwAI{LEOL(KR<%lKb`1wX?00Lad>4zqoEB-W=NxRIQ7ly@eG7 zZSZFy&n-=qrG>y}bEcFv!(vUh+EX3&6end%c2KN1)100(7v)WLdQ)81ki`s$hCHj! z5wTVgRJbkJp~2ez_U>R8ufMa4K@B`4;Sx94U(PUn?UIEaXblathVQmw*p4`&Rr^AN zMJL`%K-!~}(UJCr1gBMw+9}rPJ{}nd>FMM#B^s?PDBx(iVRFXs=c1-zBt_ITdR#{0 z{c7xtX%{l{Lg8pp)3aMLtnPH1E5$)MlO2F)cY@6oXJ=5#?pJwlW|RP;W7Hg0v)OL3 zQFu8VW-DQ4rc?-XW@3f%Y&6H84Hm7r^fd&n^3Pht;Wc?EeD%6m2R_FVX(%-3C^=0@ z1yDmLDm%2M(8QsoMC=o{!9v*ulNn@#>olN%fS;&*hj$)|2|W0Nm{dlFzi{N&u1r&RuIZI6Y|`WRpiDI9~~CGnnDS3#(joF+lNVgW4?WeeA;%qV|k{KiRx zpRe!pLQU!O<%K^VmJh2T-VBT8a-J)9(tUV2jM_akZ!hqqh+YuatxUIvI4S;Y6%O{_$1wF07mP+KQQ{=hg8q^7bJ){M&@;nL!5*26p%>n4^Yf%ZR|Ryyx%B z**fx0nsuI7F@vE8`8SbC1hn-uxZ)3KMeileqFEZ>ACwy6n#&6`DrW##x|-<3Kk-C) z$v>kO*}t& za>J@CCj2a;gtf)Ep!w}`>xDW5-(UxL#MI3X}a;xNra*Ue`_+409FGyVwQrnB?Gx;{ti zdPAY%&(Lq+^X^flJL-$J4KLVM--GEG2j#V=p~@Xd=KbGZS3zIgUa__HWDn)g39$ASOn zZI|{yk@>1zuU(AzpD&*I^v#QOkpJ@S%bz~I?nKw@e&lBDElsUQB(p8)e zvppHJoEbA+$&($)<6S7Alk2798=Nq{!Wloz8b8EF3Q=UO1C)q^j40FIu`86?p}RU^ zC=^jzFEj<01Mi5dwhOUL#WsoED(0qur$a?FHMNsghOx96o~BE~Z6Dc1+y&7N zYdX^i1=SUaI>(ad?l#StK~Hc+T`*@^DYb`t*eKd5hI=?D0gokaDz3yESK>=34kTpz zQFGuHup|@ORGMfF(3B>c>ESk$&1G`?tp2b)oajhMu_dR)6nHru1P$boir335YkZ_^ z3EUyADGCh{$}}ftnvx|KZBOMvl1<@|$>%iFD^b}D5P~F|LLD3_`QGGWZ)$H}N*`|m z1Qj*6N_T^TDI&Xqh=sFZA&|C!I)Y1=Kxq`HnVUq)b+DZGi;ZZUCEF||E$viSJ1sU* z?g;idIcLNs!nc*&I9Te0IR|^W1APQL2k&%;`n!W1CkT`8b%#~jnSO%OzYnoi5fj|`a3uS9Xz^Vs?xN+ zV|M0R?70?Kp4E|O)$7h&vn$7hxFguv6zFL7cQECSYx(jD$JJF*dXiq(^3aVJ{oT1d-6 ztKWopL}VkJDEJ$dmxE6&f@oN@(_*Cn(Q3seZVfYrpGbMc^K-2X1RYsXeF=5`+2~Xl z1<@{J#pqqg7Bn3?9UYE>=y;?Yc%hY-0}8EO99jw;6>&)CQxJ3)YiszkM$nRic693Q z>|AOGK}*q;P`fyyCg=Qq4k}OAAMAhb=ga{?!=Fpt*%{6x__N*N8D2N`cfbCe{4>Cr z{Im9NXj8=Prmwd#OZ?yTp|0^~_AOt@-lN{V`fvYo^)LPm{)~U)OZ*$Jo&B0H!1wLn zknb~}(}}5yPqG` zZ{wH&nP?MPHLP z0M2Y|@>%4HX)W_fr3)dKwB)0>L`6vr+yIEdCCK<4TQ%qKW0MXp8@+pG)#fpGy zSJeOlf8)*D#h)8L(f7lj0mY;WiMPRu_f!<_sw&!E+vAlHz4y+lfJK~rdNBwZWWlFT z1OhlkQ7fz$lQ1Ot{Mxw}9-Vl6%8*@^#YorrfFN2I_*|3E!-7xu*L2@jQ9wj?;{*K; zE*gG%&@NYxEsINfIk~Ijnl%nUXf0z8bQlIn6f~FptqED(fMZxBvUzF zDbIVQqG)q{p9Awo9C>6CS@F~B7qZ6)GlO=K7;xUchM;5k^S(9n_N}MY9YA;yXLvaO zp(khVT{eDwZJ!NgMfij{2g09s4V7#&2-@J!O#RULXVsK2$KcQWy?Q)OG3xy12j@Ru z)$_p2noBEZUs8hzC)d*tQOwUqeH;G#gM!cUFOH5hM`3R)YK~nuu(0CK%p{Tq7Dv`R zM0+?sN9-9oa-Lr^|HMxw?wLMxYhAC+L-XO!i~^7Ni`o` zJQ{ER-jV(HR`=XnO-Dk}ZtNLZvVBD1u2IE1M|LL*y={2UJrjoTloq&aa`w|4hFdTHC+-1z{VCE1kdm^H1J>{r7KN z{8(9(qx|`X{RjW&apvZt;8Fgpm5FNlD*0zH{%dDGd+Wj%Z(aIe`jnNyc&5{v;tPH4 zC#ANTAJ=AXpw)a|i+Qe$+4js?ZuoQRgC4vG$q)FFMtIQ_VC7A$vj^0+Tzo!ak?@rahbNbEL9L`@`t3FS?VC7}C zoZ06!IqZByiB@_|_GDAw4rgMXH?2n?t*+}9H5ZIwX*34FRlb4@Jy zIt0z`6{IY0LA2C6qJrx>zMgG0G}@ALMy^7tTx+x$Wl+16_Zra6n~vf@a;oSKNIR1? zB}hC_T2;o~;|XK5D09aR6YLyc$sr^MQo?X&!boTGC>h;I9qooWr;T-?Vm7SKnUlR# z))b$%XXt){v=o%Cf-EOTDs7^V5{)wf>G8g#v7W>+ZXS~!g=zJk^x>YgI(KTVE4j*< zROw2oa3_^{5(c{y?(ryBgNL4*L43}=UA)B{9&+%ACEF=GN20JcD6zk@$=69Zt-piW z-`?tLtBPKGQj#L}t01u~@hU6XvZRYU2!)O;I|{FcFoUdRso=BV>rU2S7kjX?lL~cq z$8~mxyLjU}d*ix#LtR{ft}d3ut;1bBy4W7y%||74@x^uZC3f|5D6%A_AIc2`@>J#f z15#dHzC0J@&v(ZNsFi>s&lbwH@hJ=NUNh)GBD$kRs)I~SpyUr}D<&Lo8%11cJ{Z;J z&~}j0Z3-Q2EEI+cM+>_%(~fz=nI;95b!FI{={BOmXe&IK7F~fBfM|Ol-R@7Zx#6^a zlSOBt`2=xDQ_xzU$&qCDX1V?Ce9S%|@-6R3zTMm1;wdr9$Fq-B64CvvTFsF-(4{Ff zz&UxaCwYjQO2X(8Qz8x;;t_rQU^j{tLinPOzFQf{X?Lia7;*sfc}E-_aYq;1ad&$P zY?$pu)}14Ha#%F);5A=#D?6cacb46qVOC{zXIMRHR#&oxW`&M8lQV3y`OHG0brw1b zqHPwl1EaAj5VQ-sL=--=5(}U8`gI7}MD&O_Bn2IdptTEHM9?;&(C}wO93bc@b8ebH8z8#DO7yoPygG8znFD{O z?s68wpObCz@Mo9XKVkgzkKg?Y|1)0_m?Wk95B|uXzZ>?h_;YmP8@rmRaPMBZ`k()P z^?&~_NNc3i>D!iz_JON5fTY2nnCT)FQ zeRAq4l8wt}i1csOTnv6pz&yyb%~cDzU~KSEdLV#}`i;;({gz9eb~chxTtQ1ds+sWx zE>3A!wr|}+C^Q#S0>N<7u3o}bJeS)fe7JOiz>vl~vt|x|)Tu`w+&5|P#>(Os2j?NU zhCfTXFNQy}g-|qw`I%Ddxm@z=GRU*A=n)lyH(oaP)8-!MX12$=I1DhNX^C<3R##$Si?L2_5MqoXRl;>uh4lH_ zSB=cMXj4W0CWN1}D^ET(l@zpUb0!)AIUzva)-NVc3$H*Ud~yB!GY^kBH2MC$^?e{S z;_;}`+&B+)v!oU)^Jzr5v8DuND2?jQuAYUu_T<|6WH^c59auF_n4YMi7l5F7u5*t~ z-Zy2)rrJ`Xk3^u!W{U#4I#>HQcyQUMBG5O(pLurUliTFVjS(~-WCJ)iSozl2S=<_$ z<;qD(A!tJc9qmP!v!gH(9<>b`4Rng%&b27#0-2Ux~rf>i>X-ttXkbEzwW|= ztLGiYjIma-jz~_ZBP(X@dt~B^&2*x|TCxSwz9XCl2hai*kf!g=}HTq2)4D=^I~j z>>a-4Ki}W{>xxS^=Fj{S&-W8aLOiUbt^HrxCWu7`J?BQN5@6Dnc^+_)n*9 z9zO^h{0`bWR2G1s<-}55xVk9VQ z79JR0x~HymTTSWSad)3tSpO$9ADmLQrMl;?;eGav>c6?R^yf8&FO2HFe?cv>qf<}L zWHJIXO87JZoE3SN;623w$wqxbfIlDMo8cOjSkv?%FjBq8@I+Cj$upN=*-tQt?C`Q&n%yW0h9C;kS zeI4PbltbWTltq(CCW0%8S$fiG1*__a2iuI66VMdMVJW%;*s`RWqe}&ut;SNU2t_vZ z2m+Z^K}2;5mlc1BP4pUSqP?WDLE;LN8q0)I7x0;vM}Uam3nymaG`+cgnSawf%r}VYqE4wy9S~)Wx^3{aYiP^TYO<_Al@FL zWnrQZl%@|jDJCvT+8Q<5*=z~}eFl?x(vu4hKzOcs5mF|QpcYLiY zakvNBGFf^_)Z=v-=S-X6W`Kh>f|2D!w{8w-G!smp;+9hR=a_i2CuM>M+AJd@Jk)59 zC}Ku>66!s1!(H*U&V(8Vw3$jScO?#Wh%sicgHD3jgTsRy()3X68DB4_w};bP?DTYZ zfEnHSHfN5NATjO>#LLc(HriY|I+$D?OwM*DcRQ1-t;uzVNjK2MSs{f&`3?tf1WWM- z(;TzC4Mn+l8^mNHVREfsCOb`qyXd7o)YTE!#U;SGlPlcO9q#B2ckrPc54R7*>5`k? z_;%iKds)VmKd!AW;SOJXJAY!^Kz!RkQoCRR)jm$DLpZTxoK&Z9Qs=m&E}@ie;nbWE zm6jV$&yQ3}emI!p7haw3_viV1xn6IM$DiX0Zo$bud_9nMZQ@1wxTA4l3a?_Vk%IeCJ28Dsv_E0NF zxTW2nX7VPPoFO@+p|K*h(IDDkvIed8B$q40?QG@tw)bewh@0GguFaco^%e7hwFG)t z>1fGu$Pvgu7>Q_!Ix{pj*p*o3l5lsv6wi;LrWtd73}t-=J+G_H3U&JZt8nPu~0b!(THR z{-sE|kUzgGBjeD~?}ovC=fmzl;FsNqKfm|IyYGJe>;Js^SAX&8FD`u~eE`pY{n`(J zKjVMCe1V9<$G^Dv$)R0;o{`!yH5`8F(fNCqb2YtGOUprOA!PuY9K~O+Iy#8;zI2Pelm1YN3RPRB_R_d-;61R>icucFC!=OKB^1 zY89<&<{eu;AB)ASD;Lu?{nVO=UtO{6`0}L`m$XLaS*~qW7FuuN@f(-%>^Hfhg&y2l z|1HMjH~H&axyx0m;?G=0>Ay~2$?}r+p$Z|bO$RR8FcAn`x9GJE3(x&z90J1^hDuxz zyu7t6NBcJfn-D4+hEy|eW26hAtdr&2J2X!wJ}dF2;XV~9tK2zPsv_Gc&6XRm&>H~f z2KO{>Hm1#uw-|T+apim41I_W_#^gCR`P}%Y%{@+Y+j#{2qe$#I+Kv!b+!!@Cxv}xx zVz(H~x#0?m(dt6*&H-9Y)pQ3zqtSp%gMYV=8*q3*-RY;Mo>_}AShWjWvzV|VAG(7i zFqO~Y)cS?z*UY~7#H4)_@7+1F&sK$rcnbOtiXx*re|Kdr;c9^Pb2!*1-Fxcs2T4t9 zrY&-hsE9*8!tm$y3-L?rpH=ZvUC)ix!k@RP9JS`pu;|A888+LPA+tp}I)r{xvE-SL zYV6I%zZ?5g?%V)78#gsQ{`N~fDMLq~WBD_CPlOl%;R+cGI;09S|g|*;17%f4xd^*AJHoT+GDF`9(;K0rtyPbsw$RwB13Yv zm31NiOd0&y7>sMM!i(hm`C>)h^W_E4mKScHIC$TjI&!?Hme1nx;oI;l^|nU(50drO zv>Ec;9DL>u4Y0FuGnSqH5Z3jM1uyFtW8_N}*}Ddxxf`=}v;~E+6@WbJB9~aXkp8*H zAD#Znlzbin`(RPom+cs z^(<`OdttT+lUF}{eAO};6^g!?n^|e{-`PK4W8-fEkuAVv^(939u~yxLW0%}VBWRd2 z@HxVt$>l~nChuRlggfBpIq}5I%@gi>8Ff!(_g$5R%+3(nTw84LXI8!qe`b`;s93gq zlj{a&*7rAV8Y{PrKM(JIfcYsk1@Pzn^}Ps$GZJxNO4(bFO?vH-@yBMC6P`z^wyVD9 zt_ON;t}A}2wq*N*cOPFg;@lHc&aIlwN0I|iH@-Z$cBxckd_>T+9G@#im81BxeAm*4 z7VqGhbxTe>K7-j7yB@rkM%6opm(l}q-^h|(^+kJ!7rr{8f}oisOG%Ra+^2tf`Qw+KIol<>H)%tn zjGaejc3P0qYKgDqLbqOK&ULn&?@ycV5$HG3mom5VE2Z9v4k^g z;H;Msdj@0`?Lz~|te#Q&jz!BL&w2&Buax4?I{yr1lKeB+xwnmsrOfy5Az@2zFDvCM zwR=k>^vml<%8^*&k1zDc<@l3wLr`d6E0-lv>;d8s&@=88OS73sIa)ndhtKW_SiQ6? zjE6-t=Uq*EhxSm&SE&?B!nLx-5l2k2g_G=nYp>7ha9J(ZXgbs$F#EEcL|)^&`;$ro z2|az-HWK=|;^F@TY@xd>!2xD}f0Mtz#oyQF<8J|=^>Xo7N8;bGdMI>sw}Y3xg${PO zR|T78S!5;l$$k8kHhAcSvr2>Wo)SH!E1Zlq42U=oM1ycI9FHTxMbsIcGOBQFEnsIP z8wqu;#1XEB%?5Us6$PC2mb6Kpj7c7rI^it+2l@4}!kkk^ zc^MN)9PUo2bK~(4#9iqQmpj8l9dVIk(iy(jp}3+PmceMuHIi{v#~y#Xr$F$#8}f{^ zqO;ZB$!70pceJ) z3ZJm_w&TEx77)`0nX{VcYljD1iu+(!mNI)xI4&$c6Cwy(&}0vpB#s+zrfi8OdkdGX zrQ6ZQL)lxqC^{0l+B-sBeSvP?a1P~;%X7!)dlK_q2?gGy0&jetH!jyBmE#X~^9Q;H z{G9`VEq&wYy{owxrRa$(?2LW|{(7 zrcfrMG9I_zY1U2~C^Ua5>#U%#2#Z$Q)xzz)!{cw~Arb8(5zYLFJPXNWIX@7>7e};% z(+GfpwY86GS+nj<-m z{+I)u>X@-{D&wQXX+fXII0Nu`VFZow8ks>rPQHuyRS>7}mpa>+`0J#yEUru&6xx+) zgF<_fo!&$jap*`BM$j|GJO=e1+N~CcE$ZSB1g+&8!k^tHmnyd02L7xA(rBWMIJBnF zAZTrb)@LM!z;Mwc|3N+vf{t}TL!m*?`HuD==!gsYJK)a)JoyHHMp(`99SSEdTKE$N z#6S42FU9=){+I8)^ZD=I`}%|Ti9`R$pKm)VZ@`}koC|+`@7GuV&tHE2%gY}#h3XC9 z^I5_GpJ8CW!MBmy^CL#jg?N7{-1~a}#v8AFb?N*^ubuz>pIrXz#G$`y)gnLa_B^*_ z)~+Y!>l~3rlm@G8c$M@ce~v-u8sw5YYQUcnPI66maHV97MZEmff@8}Uo>;Zy=!zv= zy&hlr(2=K>9DQQRt4}RE@zf(M$sje{&$@R~Q}Ee%gPQ!6<~Hh=sxMc$GLnmZr zy}iNB26z7P=J&P-n&ZQ_x;>Uo-^}kez|O|6?5!&@Y7ZR=zo|4{jwR2H*RMm+RZMS} z8SW4sD2FcA2}Qqxy}7>6zM17Gekur>3EcoL&M?yOZXE<{{sCglPcJ&LVg9SDW}JC) z(!S|s#PEPZJR|evA*k|KROZ37!MuDPe^%Lj-`wg$%f`Y^nIwMp>7|0TSBi@R0tvJv zJ$rVAXr;G}zx#!X!p&8MqJXZ*;n6_Z(%dj6|BRkODx!lHDRg6)Y;1|8%1y2t_cT_T zyjznSV?X=1N~E>R!r;%0c4-QYidk&T<#}RYC>KFDrwGQ>UL4-<@S+FKv-j4>^m#Jm zyceVv53ggymRvFJi)C7TaboS#6RQ?*Pmun($ESjbFRY$_;TdM%&pNe%+4nP#Ju+tN z*Z~aH;rD<%Z!YV?PUh(-&75J;+tE-D?M4AYiQ~e+QFHUwJYQR~W7_>Eelq6#%30@D z&cz2}50Zidjt zK8XIU*k$x@X~dsbFFw3(8TaHLDaLu(^Cwo!JGY+U-FY~%Ioi=3Fa>GPvWdGEjoY_) z!l7l8jy*j2)rTjacxd9WrDONct$S(Qz_sOt&y?joUzYn)Ssn;lTquLHcMs+m$bY4- z=fU|SPOO`IaQ(vFs}_K}kFR-zf5C|jH~B}!zUJ%JoB5|!|Fg?K&AMX$6~47~wV(B` z=y_O@YF@b%8<@OQJ*iDOH}psrz;hpM8CNacyJ86@;RCB5I=JQ`PBN!f%zJs3g z@2D&xqQAGYXh(TbEPTGnb)5E8V^Xd0HS`z?O`BAT6@624>DYDsBepay132G!rAZv! z+^-mS7VUFw;UV~Qot#v`?^rLkjqJPSfjdtx8THzelg~dsVehmd8;AGUIiknmk-g*` zUf*MDZPBK>V!j2PSoQ!`oU_=I)C4z4bVMT1GEhRsgEKkDhRiHmyNsLi)76Xj=^=o1 zOBn??wQ|ncC#N2oTeW3WpUpMh_m1wpdt~<`qk9~$DLPZv>tJQi&2@K8?wi{_8DL@R zkeB!NFaPr0cR&B#l`nt)?pMG6;3`3*?>MOQCH@UcX4E3zxN`MB{`Kl#|HbETz5W4a zKXLuhZU*ukDKSp`m~+0tWgYza!iCQ-oR=%aH_v|c=D9E4IRCj^C(@^$2=wJo|Mb#_ z3+HTbfE?VWl)j-Z6Eiw2if_5h+iIyNYl$~&p*wTFH)F0hV@@D#nm=uFAnn0G`UHR4 zIDgt0u_ZvElj>YBoTO?`a+QP(6NWj-69Rn1%b|j%a6j#6)w$^S{w_($_LEW!Qviyp6WvB<_F~P{PyuNrkUEJAt zM*TzzKEt1{l|(BQ(`HGU8u+YBV{`CqsK6D@_k{91@p=BloPcN$I(U7p9gb9!HC_R< z=!|9|Vii5PUF~t#|>P|>>g~Bec+h!H= z42W}?%<(3yyr9dZf^b5yk34od0AO`?SXHv%~oon4#oh2$i z(uvX;<}Ac`yc_IH&N*$OH)XO1dvn@UkFJcV9tz+LXGXYzc0-)c+;f7PN+0h+%^~dw z8UCpEB8%q1MFj)gR?$`lK@x|!iM&F;6>t`ENEkcV-|1K65M2W!2;|tkr4~=IL}vl) zpi57#73@r*!gh5L-?F_uz}aeV>u|Jn*zd4ATHEZc%^ETbaHd0FE32oK9rK2_jcAj# zIhiG1=rAUYE_PNB1(SJ(( zXd^0Waw-rr7Q$m{n9BjkcnD<{7qK4B&=iz){ro(+ehIuHkICjInQZmNJA8>QUy_^d zfq@K9xQ&m{wWO~*1d}_3)4L_6b&bpD8kdz5&dLjBmtQW>3LyoSjF63Hep zPB^P$7zzBtQ6Y5TMN}EFdD4q9KAX->70}B?5?no$M zW|doJC_+lFTbv$56e{Wrqjs9GMmu7QAJNUwZFT9MhI$#vMMqQ6hNDBrp|u)1&f<^g zpe;e2f;JE|DQLQ&Y8P}TTg%S&R^9A(z@H185f?NO=u&6bCQ{JKq0!fsOEnpOW@B^t zXMP3#+~1zx-O+`!BBVYsC1cgfXW-Ajzj9T^soxjo{NZ;#GJe~+?thO5)ZfS0z0o}^ zI~)ZxU7`Q}|9 zLR-C5!q0e;bsb;5gd*qs>WW1tS1mcUnoHv)AZYkA6L`5WJVvSTGw_-Gb94OpcD?e* z$by=u+<4u%{?#jTL9~|1{#-XnMJ6@l-%yvy`g%$dXsW|IS5k;LF0Y$?Xny%~)dfEr zmILx)@;KZED73ReKo%I2n|L*8?ZixHuJN~)7j7)e+f-IS=e13h#Uukz1?zz&Pd!b8(YYrdowRN8{m)mIY*83odp5Qc1Fp&yzx4I~ z4SAhW1Z|+>CRdt7#|<_%_{9c4ZSH35dEj>OXB5x|e-;|7guq*BOZQAGXa8JUyAa+B zt~dP848w5(l;Jr#MXK;K6#66{gQa74PQ34D)xBP*zw_wQ(U&35YiA!{JL|%8^UtiB zx_4&T%QZ!e)A6Sfw-*1iii_*>qyT3$)MX-q(D3=?vg~JvvZZ1qF@Bi>y8`8wvTnQ#mlZv3w~U$Kl?PK|$h3tM8IC6+%QV(gnqSgRHjxRr1? zLryE_9a=tzf4lixWR!fx(*3KJ!JlE#-1+S4g_|anZLI3GWmxg{vckO;#XBp&$k*kc zZw5g#wxWxZl2IBybAHo2StIBM{8>}z#>>VC`Wv^za%O`q$8KzHeQ!4BVe%6tt_1h;7+BTxs{_5hRwI$s7Kz(;y%{%IQZW-MV zyEp?+m)0%jOv~5811lHstqIh8caO^J$Ka12+@n8ZM*R6! zxpZ^)Z*F^Y7gNpMzq#$->Em#*b{_tG;qy1neG$W-KfiGCGfatZUi|%u1AkjnIo;%T zn37Fd!{WQm$!xnM-0ER32)e~mU*;lj#sXjFJYVMAV8%>;`m`VjI(?EK(Qev!50YLe zH0EA<#%UNR=~Kdl5FYSjg~HKldb>ddB^i5Ozf>ioZC$2>dD;eFGQg@Dh5Lp*7awHucLC}hF3v*T>ZAl9ki#AzG zMYUrQG+VT8I+*96LOBGIUE!{7qzV`nLhamiTcZ;h>C;Gz6U3()kYQJMnCu>lJ7D#P z%t0wrIL;IXL@OLEnvNt#INs?G*j+B7t*|MV$rf+&w1jYa;|qcb-GlL^eu;c5*sga- zSX-Crs&*$`{{+2KYTuGYw?U!x4#89anb&NYC654V_F}pwCf(b{k6?G~K=!2kihhK< z#)sq_u3^vD6GgZBzJNAxcP z@sLY5%+Q@K{!-pwtRtQtc2}{@-Q7aDip=f;vn$`^$+Ng~&6p+J-AwK-CRZmjo&G54 z1K82xX$Lkm3m0wepu8+KbB2+Eom)Eyx(8dkgRPyxJFMXjmiSJ#_>PW*E}oR^V0vys zT5e)umr$rr6@ewyS$xz zf!t7BVSGYqVnXkP_`8x4?oLU%H!bD&GQ*ED~QgaqWf z*>_Pl=Fe|j{_OShpT2qiv$rpQnA>d-vyB#wt>FTMIzXp*I@Bn41YeK!wM^tXNL}N| zl?y93%=0w<={2z27&SNEq6l+i{;bI}7yA_JAZU%Fx%qA5L$~th81R`DuA?Q&!VBj5 zP8CyqxyU`eaz59>rVNkAP?;U~Ih8ZsV55%sF;T z1OCiSeT~nOKd=FRzQ(B4k-)(KkU76{%Fb!`JX4YT9E7Are>TJ#P2TMrHySTMuY4naZt4!*Z@`}sK2v~bp!Ck#0xE)_ zaY5G>lN)42X49y?hZfR3aONp6<2qr*0JL-KmasgsX8wK<^wSFuZb11v=kUX0i7s!h zDcP;MYcc4vr#$CCW!|33f?YMm+v|H@cx2qc#iO>)AHHS&s2xkkAAf2Nj{_Ug{24e2 zls@^?%ssQJ>8Q1-syikSLe6mPZ_l4KS=Gx1Bsq4YK0g@C2KQ|4rg19J7K@u-?qq08 ziJ*lr#}rSblh45C$Op4LfA81Kk4;;Z>H{l(ayj1-(& zF?Zjzp)Xc;fBNoj&kZfy@!-9$J~HOi%Bkm`L4h*k?CNPJmX6r^K<}4^=J3>l_bakD z4$bB!3J8JHoFtjARAo|SQ-rW=70Aa@5#QU!FY*n|pTB)* zdDY^5Pt8Y-MQIBC2mg!Do{^ms`5ME_CMg-zUIBJq!Z(v6PtN93Pbl}o+6AXp&%-|q zx0fWqiX{hEEIqjDAy_n|`s}L3TP9U(tn3Yc-Z8XjcSXsriV|ELH^ZE-yH8DbM!s}4 zNI~mpG)v8&bp*OGaBgnPH)7`|@6a57HtrnDqH!#vMWXhSXRa%j{Bv#b*18^>M)ce` zrvJ%D$6k774x>ni7Z2YtZs6|9(j(P9gjbK~eqaQ5mI*A7YR&-k6FmLI49*4|X$(uT zw`I72w`Se4{p*(OV~BsXGz}3O+o~leSJNMpH)5g8s#v?==(_o**7G%T#{NaaUwLrQ zE2H}G8V=U7a=2V8Ha!1t|Ngu8-}&nI?_+-c{I|dTnyHuH z>BSCLH|RdzfA`b(u6#}S`O1G>{rkVY`e$!{{Kkdf!JpOTj1hkR2L61j*FLw(hnsu+ zAJpRrf4=w`2%5{ox6gj{b|n7{fBxi+%b(KH@#W{vbnDg^f@JS#YBM^i?!m4hQJ>ComB|{ru6bKi4 z@f8D9;l@B?{tzG-MH9VHKX3R>pDGVKO6@vF_%6FHbQ$nuGSYg<{vpY!_mbFdVblZU zo_H$c{)221U%%VVTcfQSaYIC`ArW^KB^5x&TU?`J@Z?D0!w*m{!Or8{0+5x}8Fhw) znN<(L%xPXKYq~E|(*l`O0$G#&ROUo~#)H1h@&1f)zEssZkf99@B-o%nkVNKO=ApHm z3Zpt{HmAd=>aUQI2%YX`9D%U|Jv87ea=Hs0&OEy-&q_ISE!wal?Jso)Oro=$QTSqM zw$leN(9slVXY#i-`P-NRZLGmI4j^;5wKM(>H%ovj72nDo-_jG;!X3(VhFeGlGaSAY zn=8@ojCb0?Zfn46awAJn(P4Yg`9(oN1ZlQr2D?Boe{^M&)g!90MlKUf@!?~|Ae zD84@>xlAx}N@ZG7O?q-|dU9QAVtq>TnB?RMDJc(1B~MIEnUt0~IW=u+dg@e`8L2bU z(q?3)%}h_9nVB{#J#AJ-+Pt*1c`Va2=4GbOOG}^4#+0-fSy^*3TFlDKnwge0Jw0Pu za{A=t)QKr6ikRbse2DLf=8Zm`eY*X1a+*$T|&Y_p}C$G_ge@z+ayim z#P9!pp3(7GmK-^a+ueQB-oKNh*WLG(yoT-hGwF>~%Q2@WzF#Wg(B&BN43(6)Oix6$7Noeo`7_2$o|| zL*NB$XKFkZj+2MlUccZnB6p84HA$)Eqgz82DVLY{xdqrY*7x+(*V zj~JS*k!t3rjc=<1cE)7DRS-vz3mVfl8!BDgm|xv=Ui}e&e$L|8M||nxnG9^YZ^yd( zKkLo>%< z^ye6JQ)A`=Y#v9lqR@csaCR&W-xXOG1s4m4xM;SN@!y;FxBT{fj-_4F&7=H9Jacz@%Z^GhZmRgU=} z;Ln)laUdgRe@5KC^jP#d+@Br`wJZuh?t`NkYKYvSFsR(9TXub0$))CEbT(v9pzLfj zOTssmVg=X=#SyfSg2wat)9`1YU7QNrHWlJ*C?II}6YC$j&cQy;M6U2N*d6cb#(V`} z$T#bY0iR#Z8?iMdzHxFCeBJwIjyqj84Z;2!+bZ#55wZsK!*4O;0nT4IWkVK?j}=bY z$U?)JfRpvnITQA!#uI{`6x}j0>TpKV*(K@MHZ8{Mezu_$u~kf5a`~Sbe-_TvJj*Kl z*vl0TpE-a2V-Pg|9@Y7vF8+)k!94LdUf5D}vTE+}lIiEF=ic424DuH27MMv$S5jBO z=VZYZhQVT)vyM{~j~SUC8P z0uaWEJA!uK{vFoApWO+wu#USD*4(zp$*u2x_0dOPfAA5RnP249*~3phhIxbd^GEML z`uBf*^ml*#)sNoz^z}QRc3#)~z@MKZR)mYSo8ZrPzYzHIo3|+ref!?$_aA)v=7W#c zuR7r6W5Z=Vplkod0l`(?for@RYqXA4I+VRiXRFZLSL*ELdPkYgR;*I zlf)>o4sH9wJvE^onn51=!E&#`N}oY0pFtY0ek!$7E;D#aywRAjlQJO=P5*-s0h8zf zqFsJhI66R`;YyGzBr3fuAkf>tzn5>Q-YZh0jgceXsYn#7l1V5bG)dHhz>iRYJo}8+ zvZdN*j0!sk{u3g}FG*-g>!fS$vc!)t6#z9u-|Y)VH$mn%kw_g}xMWeDLS_|W&PW|Y zw34Ob1_R{Y@e&)Rsp#c~iWzQjB$naIm`A#1FlQ7@8Yu48z>-IuIg6%$TA%}Vw$Ifu z?5wrU)S9QONw1Nsf~prL1mv6zsVW4m>5Va7?)Q??f2>NdxFE<4iHbXLhLV?BCBn)Z zMTA)$DOW|v6roZ%7$7U=WF|QVngePFO0@%sg0fQT`^kI4GE^zSF}?l~K#PV*XvX|>%{Z8KHa%w-O9sohf8 zH>f-~sL1JD=5Q`@1TL^S=31?@td?m`V|Jh^(`uOP>orQF8KTn-(RmNkdyf=L;yq9v z@gh;ANE9Lx^%aR6B8pY>LYkWAm?cD3!KXo4k!l8RWhLsMBHc`Nv}A} zD$x??<+aIjn(u%Cm$4X9AyIk2Bn6}~#uO#mQySBi#&iW^(JEt>t4J%v_%kB+?q$qW zgGDnOts$+)WR>?sg&z6pmznQnlmbT;B%*0f0W#Qegu$7bLyC@#Ds*f_PMfi4G_1t4 zg~$bm1+_zgzZ#BcxxZNEE2f=;UBpN`?J*vQmPo*&-4QgcGxG*?9Pag8{23ySt_WJB zrXaLPiy$lvevx0p9ux8>`SZh%Km78;kG>!U$GeaI_1BO7zqh}5>+T=kzVr3# zH^2Pvz@L%9MgZWg+Yf*8`e#!nEmBL=xnqVLud6uOK>YbsZ3Xx~@weRIuseU|zm7cB`7I@<*DX0( zG3Q|6)I&?Nc266(de%vW7O#9DBK;_*`T0*~a42%_Tx%Ha$JA z+e3W&x*LDSbLjDDci!xe;m`bU?DAsq3ts+D=(clxxn=AuRy__Nz2qfY{`?HQ{4}!e0;_xC%sp-I zC4Z(wbT%n6kbFkq8O&KI+5#^}c09-@h%Pt=JQ#Z*zL+%vv#_siS&C2D?WUDC>Ip#u zDuOY#HvID(Dk$-M1yS#4Eu?3S4W+g!QOe&9TxSb=xpCR99$%?^7 zJTdO&=)#|S>EaL&v_PA|czfc{&qbku%AdC=+MO1T;`wKKCIqFU&=!!~_33mdYe|nr zi?J&u*>~y-(P$MDJAKT|BZX6ey6WA~+o;~qfU_D%}j zH92BeR{Y*+LyydVscrFu^NS~S%ozioPd=jb@ckK4yHcZ}>E4@@jGXhKg3%`yPQXn6 z_T_1(R%9JsF!|W>ENCKbZ>xZC<6J|@#cdTX+KhoqR(L*~IX}stD@g{@NJ|{O`LX)N zErFc{_{<+g5OMtR5BfBJ<{%oUAq@LMY>olnV~bMIQgHj^$emMSTIWr?x_ZI=W)hyC zsVVB%TGg?0&B^AfwuY+H&>%EdLobHc4toYKAClD=IOajtH zO^#`wJ>l}IIT)S6>y8(lbQX41u+YM#t zYuS=B;&590@idZev}Pt8&WP#4kiYdu{0c9DLUZiQT^z!%^NsisUl@8rmE95Xi&%G$ zNek;}@WU^k!JnT? zzJVL}aP{;={uviIfBmyRymkNgPlca}!BPX7p8e0yn?vsD_C0OyDdf}B?R(n(Lhnc5 z&oDp#_$HOWpYPoL_gk|?2!wN3UKP#zGpPEYU|wOVgy{FxARB?Y1F74A9? zfM|_v1%YVuQZ+0J@b{V)DWUU4FFB}v!J^6WJDYsJRKSvelbuAGLuptVC?JiVbSxu{ z7GP9Ny9&-ps56!OSBXmlKZ1gSK)R)-sn4A|m*#Yu5YQ_meI@TJD;JA)5os5T=80d| zvNIH|g?EDMj=7YBQE1qec@P>P8Y?al2k+d+_%rwtX@p}vsbVDhSg9WT6Y!IpU_;S? zjuN(-!7|-IxpshD*H@_vRv`{8^%sj_xJ9N9aYvpQ1z4k1#2%^OfK{p#z6Nhgu+h{n zz%bY^Aj}Ib;n45Q73_px0xc1TNx-`}SN9sJ^ck)89jo>pqard7R!@p%@*yL`jPNJe zGA(JHwy=Fjdy-P4EM6YoM+*MRvTuk zO%Q`a%!2WV1>|rhlLo9BEbUB7X4r5nrkpcHofl|2)6P2UY{Jg4I-93ypyVa&oS`zp zd*F&XtNdS9`7*Hv;_kj96ws}3Yd72@u%p0#;%WnjeI7~b0}3{Wi)sIdN)&^|R0Aa_ zWKb#OJV4gToRx^C`}EhrW9-vM>m8&e+8M0y3zQ?+4BD*nQ^>t!617aM0$WBD6)z9s z>JpJyCW5pV#sslWu{E0QO*Z>hl-1f~w=_Ad&5z60h1PAEN#|0r?v5M+3ExB4T1LhAV))xy@u76Ap4d;`zEJtBb8&F!&&8UR@#HA z96_rb!R!0Pa!H0-oFWswED|M& zM3kl$c>+xXN;A0!MW)3}L+ydLyQ`xjJ`O1KThw|=yd(-AqW#`xt-r;~*PzkpWm>J= z+gq(w$q=um4-6nJULUmx zeq)sW;}rg{C<7)a3=@?u7M;r8ducAh?4O}Q1pqiB1)Z&R6(le@I=+s7LWfNZrTL^P zy{9O>C#Wz+hJ%l8tPB$hG{dD_&7p~xV9W?lfCumK&ctB>Ic;)8_oL>OP>5*z$}zz~ z<&YuH4K)WSG{vF0l!G51n1%-no`_b!&cO<%XbzlR2%4EXK$YR^z>wB6lFwY|A&8){ z!tVh%TI;C-f`$&7dZc!`pb>#aJ3?4E0wtC{5-aD=gCs#nL3iQLNm3F)cZooM2mU-# z6-g0jX(SXMS{k(T7#tRL>B^n%__N?BevD6h_?q#<4SKr=-1#$H9FO@kdUO2t(Jy}T z5d0Z=D$iz&t}bBtq^M_ zCq$j7t7@-DCzNXNXGEZJS@c+%;hukHdEK6_DDmZ)SC<>$+D#}PS{9 zUBY;Y;{S93a}}S=KX-ZP=lW52{#{q-g3;Bm&z(Qxio1PtQTzHON2}%@D4O=_g7oH@ z6ShtryMOBF{W-~dG7|S@580nL^1!q)t@Ed}73JSTx3323V1*grY3ikO})Bl+5N4g3jiwvj=R)c0oVu*d2VY34u&9;H|kehT{{=1VtnY( z3=6?p+{uyb_}v-tH`mR%*-(fy-L;+7PSG)GR)> zVBEe`54$tKOm0{W<_raR(!+| zbPI)F!FfSAo`3Hv7q?d9KKWUR-}(3ZaNY7}JP@{H+yuhsi`4}OXN(4X#(4*=;yRFg z-copHTQzP#PTj`J_NL0#EoGSGg(epq7gO5^b{fU*!m~YFTYRa$1Unq4@X*xJdnQKV zM7HOZh{JiqPZnka0D=V4ZU@P4sO)l%=6Cqr=rR9YPNDgFmpkvxj{<+jmy=GB8u4e6 zlhl{N19qY?uQ4^Tabm>2tYo<5F;@bP;)`Wdudi8nYtxDwH6_<^OlV#SA@+sxX@~QN zwb0;i9NwikfS@5MFtPxRd$WRJFJ1zF=D!8tj1_@GbN-Cw)8S`#9Nl}=+*8i^Tkk=j z&3xrVb`lD|bt)(EEV9kHiKlXtj^`#G$s4jKJBcjNHB0ZIuP9_Y^=0SREIdAE!trS% zG4O}og|IZN(a27tDIxSn0MXc=M+?Rw3yqeSK-Tyz94`2GCwwsR8sUS(zgf}yki92q zVg+mEi7kj*kaK>^@{U#W_AW@Ro%&KnRFF|Z!K<0m=lt}izXW{#^n*vA{O32EKfnLs z7d_>lzc2nw7dY>IiROdv|Hq?W|LW0S{`fO!ir>12%bBjp=O6g9JJasrV(m+we+G7b z%%72nzW>?X*MEQF#Lvf#o{B4asZ-Q9KcHWgZ{Q}abDh??RtNq}#Z%DLTDUlz)mjH@ zN(d>mqg-n*)v`FW#!{%Yu25N*Yb?vu=A~rxWxeDyrbVt?G&wrvsTqzYSqF*-q^TPn zxf&=v3vUBgb|5BAP3xF{70LzV52?ExtP7o7+6ARqUK&uE8(BN^(%k03X(~C2!Cgt^ z!Sd2vH!ava9w(w%I$8)tyK>QRS)fPZ5IG8y_mQ0B1$YG)G>jbHojPblph1>USRo3E z`TkK7ByWL;d13awD$Enbi4!Qab}$?aO0NMbeP5+EPz78j3y>f-OW{6de+7CbszzYV zL#C2y{nfrUZ!fzBjMOhg=O3x1c89U#qb5l;VwR9^F#b#uk}(S3aVp=Jl~k`#V3>O| zsQ(%dmQNyYGg8ec>^;{$Oi`kFpPR;636nFV1dutyeSwz-FA!81luU*eqd-jq3bQoE zIhs!9tT8RrkQ;ol&L!F4K4$?wbNyt&Y1IK?2Mdq=YHn9n(b{d_#SpRk^ez51kv>{at~H{4^*N-r0+nj zUq8KHu+GP+^RlS51{Fn`ePo_$4-ciMNJ{vhVNl>dKtRA!h>_9S&nWV=NTh)>ML(@} zuud1{<1@m?YmA@wEB?Nd4Ss0>epv?JJfq(XgWnvZ|6&R-`xaRODkx)YTx;~JvYJ<0 zEvqc1RaVnln`yn(ywPUfg0fp`ZRQ#)Ld(Wl3NRZtV`(&Pp|aGNEcHff1C|D=29(*h zmCCx^WZPk~?c`;#?zCBVI&7~BWv3shoOW#7>9B9N+qR)>)~!^Q?KayED)x)+OWZ@C zV^@%KH6f(R{lntiB8iob59&$g4 z%B;{hRO&zlOc#p25_x|%`oN?d_*5brkB<+1kfGTbiV+Rc(SSu`i~~j&%0*AaJCNEA zBG`<0Gr+Q6IzeU^h0f7HLT=8}nes7QqBCN|Bu5jFt;VDP|17m{8vB*W3a<%r4x&lT zF{*QVMUs?jVJM}~hD+#u8-h2gCpW;T`ijx!QXMSS1}S+QTIT2JsrR7$!AGe`+5_V5 zDe(|fgThV(Eoh$!Ab0X-c(OTyek_je&cE>t{_KTzgp5B2uoSdl;b0e_5fSoyN z7M8gD$3O8O`EB^R@O8cSPpR8m;@f`r#e|CdO3>zAHizx2}j zC0AC>xx8{Zf=1_x^3E3Jb(GGyR5kDN`ejJJ;Chf^hsBW7_7^=be+IJP_yTv%lV*I0hj8c5z%RIZy1aSCvDxGIq{Lw6^1;l+gV{qsk59}S zkNn<+RkJQ_TyUj+1!RWT5Y)uW*I0@SA=rBd2s~cO?Numx-5Z(4vvKA9=888Oif^o% zePYflyVGKKO^U>|Ftsdv5<&m);~%#Ny64Y45!(A@Pr2yc-vhs8Ph9tOenR(^7cW5L z-mC~<87uC$hq2TB$HzCz13-xT4&{cRpW@FT&#YKatN3HNu_tn40iPk6{qY)Cpe{v@f%Aihy^(An0+}>Jxb<@JL zrCG-ch8@a`L~a@QbXR7=)itwjG!|XkQE{fe7@xIkjc7QC-dI)Wns>5sWn1IQv(4zB zR{;ybm8t^hj`1`|f0`AIKj&yp4CEWgKZ8F5nYLv_KAS&xi=cbj*lqY38{KjAGqAJp zPtVPtGs2H_7Jmm)v((hcwv?!2m~a8?mJ*4yp>E2fRIFb z8wu(n`HY>g^0UtO6bWHBHOrIa5e}B=pm*=!p@D4 z@PX9OgSiPE%hIk^&3;f<_+VT4?d|2)x0hXNE^ZM8S;Tb&Y#^+7Q$Jh`;|_)u`ovY>=nd``N@&9 zS=`W51$J={OPldenr70kYczXHxH6l5A)0*1f(dSmIuwet?mo46f#e^Pi`e)6Sd zsdws%DP@W@DQp`}G_VdTdtvL^a}Cwh`L`YlXkxQChhj&O0&8nkTYcH-hEj|&U>Xia zVPJmVHz8`@#7JbJ_s$r5tR(O3re)Z@I1kc8KRH;;|6VM+Z12sF{CB@!{)~xikYnSE z3ibd}&9~}GE>srm$sMtMQq=ymI3W7H=}~*K;-M)%F?VA7(#%t()6cA$duihm96ipJ z<6Mz2Qhu=I`^>Fp{@S_jD zK>tDHuHS|H`R~5|@ms%tXy@DqdUuWU+?x# zuF`%?AN(S~t&Cx<&8){eaGtxxsG7+en(jw6Y%hA@*H$v$fqwtN#(@+v2M`n8j>$nF|_BcvAgQ5Au zt<5+y2y+1K8I^yk8as+-%lWP&hX9hsaNB08NhyHfaW;uBO!+GFR5i*nO-+2b0Df;+ zzBPo4=Taf(Ot0fY9Tj_VO)#-6)|t7Ih1Ok#VF+ZQDG|*?(5!7G-5VcwK#rQk&JcQ} zQ6ED@uMxx6zbt`41up~yDWK~vw+5JVteoK@+4}$?{#%C3I1WTlYm5L~> zI?-D zU;kqNfR%m$l~80DEgOuMjRw=E00R}MvdLU$u{KyNjb>A$sk6-HCX1!nYHPMQnyt=l z4(E2P0~ZrIb`bux+jrVQgNZQjMmgqN9Hr9rv?{m>-8nzBzE<&G@(n$w~L(qc8Of+S5O%xliCm zr?u4RKgZ7}$HzBC?=@bf9wzn(_Y@8CAbp2TM3!m17JP;Pi%B!uES8}gpHeQDV}bxm z>_H>3Fpe`4 z#ER5C`f+lU?q#`tyv%E&R6iMw3l#`CP)&}4y@42YEsN{|jtln{dcF{s;ct!#Akj2Ag~N>pk%2FF$zi(SQEiqrd<8H*eo3{`>~&{uh5n{!HZgK3Smg zMe)Inuim=%`PwyyG&1ifhw*rA<%!yr;Lp?{rE%5w&z})gW+kxYE-M0Le#VOXJ@9ob zaX*|t|M3*MM}*7xb0>MGD?5H6j7tyv3cC5=YWHGIG0C6nOVQ;AA!kf=zfe;M_2T6% zrPt~zt~XX+ZCZnNKgdy^siU3DmqM(%H`l7dZMx;p{K<6tC-ii^-!=B!8H6TFA&SB0 zGmvdkF~2BsIGlB`hESj%)X8Y$(${9bv}eYsgR@^bx@5}f(mY`2E1MVHXezwiSV$q~ zCQ_BUWY-Ls6H$RmrM~ohE#m7Hm$z1fEu7lC0#{_0Ym4CGz~t6zYiA#s_wvrHgk2f2 zXv>9+Vi)3yZhBp|{P5$m_kde&ynFuqyga$5+xN7+CocUbx+UjJG7e84dMG>bP;TW`;WA;gFud4Y1f)EpTxV5*!>10c7u;w0IPKO<8Oj!jF*rG<6A1KT}pYh5Q@T`!6*L6b|sMb@teEF!?u@T-{cI(+%El8hF}+A<;bK^IE7j;rj`?TX3>P( z>lOl;V(5)%YF#nzH2*{N6DO-gl<*qU4z>1EUuJ(K`9f!c5>D%Y3DT%mCu z1H8fsm!I#jgtdSdY|I$Pyi!+mt9JR>;@n+1L$*!~N6$yNP2SkF@M=9xDZ;Oxs$Y4s zmNL)utp+XmYAR3=?P6zgCJ*LJ^slZQ8EJe9Fcy5dwh-+IPtKpbds6g)l-O4%gl~gI zYSzoADre$^&Pg~YgtUBuInzUQmP>!pnM|&7X)&n9v+JKQG=R@9Ie}~Gvy3`lOLvH0 z;eUSbmz|HozL~H_(yW&>1br(eC^iRGAl#G;?%}r9h|g5Qo?>GB^pIi@9OX@#(>#I9=zqoVnvwQbGtX_3UuXliH_zlrS76-!o zY~8GOY|sR**YN^^28#|{OXXava;#CJK%t%0YN0zJ?9k4YIwYcbD4MfqM5CQ0I!BS- zUZ}GdVyUOzh0Dp;LG26ODJ5}fNEg3FmTRVh|G>=JhYX_yHSwRf} zOEAw!6OMMVXccRdM@d>xXsQWlT1U;oIE!W!nt7zh%1P5P=CLoDH!cK*qHbcWv?FA^ zV2Vay(mz@0GenN^PL_d=azF|S4aY3H-Jx``3MiU2Q3`dG6bksitjw7v6GN3bAt zxLAw4Zm2{XB1Hj^dWR}$IY;$Kvr^(GCS5MT8;BETBcPCe#1c_lACcH3QU^-F zu6?7lK8YHyp&IYuYP21M?b-JwI7y`bAkR}I{wY!>(2xU~`KE)3Y5ialfVw$LW#XtA z8i71DFIY7Q__L6+WroT+Q*A523!&z~8Hr^IEiceo7wTAPsRw0efi_dzoiS$wp;5*K zYU6y3VV*i*E@Uh!*g0HEa9BIw?#NYv;Q3}Sn>6q^(#{h|J&hLvzHaRZ35+7tS20P7 zy$bBCkCyAA6xwhZ=slLS0_+^&sX;Nx2ADJcNrxR9=84jU%5{1FjV;4iC;qM`~cuImL@@ScIh*mew*Duvzm}axgcRH2_2Nqi` zi_r(r+k1wWeukfSL4eO3qt9$VuUWqS3%&go`uHsgFs?8di~Nnn0mkwGQ&oUvb%14^ z!Med<*%)BmVzAailwq_B1}jMw4ZYj^At%IbX0;zZ1NCvM46 zv(panOVpRu9^$~ZeGdEnAjg3~XA8>dIE1p<587;pto9b0<1m&M+aX?9=Ot`$ZFd~9 zIQOBff%~bP2ZXW(9>h8a*N(u0yqtJA>!Bd~Av`W|Z_sJSKC|_p!F)J4=u+t5H{+xJ zHa_Z?aS^|ak9-Fe8UCxm5&swx^UKKicLs+1O;prBL`VE0Z1CF-%ekn~Yhi=i`v$#c zF>NrzJ8dhsqC=u}QJ{TZplycDlxGY`^Yt08)s0Z9V-)Zv%lmpttRiuM$P=$0*HR#w zE{q&t;K0L$pz)IOS5+&L_=_-V!@Cp0w5)+|8P%TzEF{ATkpo22s1OD-$4YcBi7_UkpCBbc4HKcmT~9+`3`G0q(Oa6{)##OpPf)(bn5)G&4xhWh zk4SVZ;wpR0#lQgvT|r@?2kssw0r%D=i**TNfM~Bc<}Htq(3?C&j%TPFsK7)CFElVk z(?**F>UbKTVicNU&@A|k|01jp|F}#fm9xOJkbhRNAHOqy2FKQWs=%LNf%XyUfS`>c zA0TL}hd=K{h!ixBK=&61@)R^j&@tkHK+uAM<2&b{DJ-pw8mfpuMacWXu;S?<9y(&o z-~Z!p7#DqnuL^Jx1EsPCc|Z6!zGwLCzGG>JfAH`V%z*odCc&XS^!xw*=pX*-o1Z-R z9N#X$pWnRykopg@Y`}|Kx_t?xj)y4b-(bn-`(J}UBOCDG#usnj|E#v=q*h_*=kIfP zO9l8d@*$f2o`=FSF%6>B=M^+!+cB_DG`*SR27>|iTw#< zB!2yL&C1iYRj2BzPS;nX&NQszedj4{{+ySbz30!IKk!%3eMv7|Cme9S%8WUKJfna( z2tl*gni5}4ECme&T~F~pAZX%U4Q2SN&(#*6TEDn`_3VpV7G14bdb_FU-ZuE03z4_H z(o_T>hEDDfTw`w_X^Fx-Xhep9oiUvpMYDsOs<1p-IeXjO$tSAjT&pX3u)Xqb6X~EY zt)F*zN$R%D1W2Uag&QExtU`fXiQzoC>}0SUvHmHg%KzOT>%T33?t+EC^~augbx+&B z^$z(B1peF|Pwo*oHC^pgA=*>OTULYSZVI&s>pSo{+b$ha%ALuV1E z1>+?GJYz)L@)Ue1ZZ(xbM~n{<25tZ=_>mdMSaNGLm)&eCzEQK}TxtHn{1FJh((-!bR=c=clDbGdstCI^S z9ho-jKt@7KYTS{`q=Okr=o5Nu?n@9IAIwkMmrnBJj;xq7>5*sBBao5ijSH!FA*0Y7 z`4VK#jNnV?K|p}P*jqCru#V-C3>0F?q-7>-n-)b&{5t*X6Xm)$#+*-Z^2~1B1x@$- zBbhgzE*&PI0fL4h%q(d z&k#7&t~gUZ{nWAygiC?oc29{$>s6%3Thc;XGpLTFhqR`LwPZxV@6k4M)b+~gn9F~o zsT{|{s}P~EBs1<1M_M}JHVIRN2s`6t!l;4!kz81R#<>{h7vX46=l8}cUhW%(b--st z;!!w%;q(DiOSG1qp)fZJCo(WGDp2B@ic>Wl?Xq!Lc6)xt!IGa?`9Lj}{2a$gDerlQ zE$n>C&ZO)iD4bkZb)lvT1GR_*6FqLkn0O@uy+JF8t7cuTDFWK%4=0?j-5*_`wX~68Y7&msSHV1n9|>#MtT}QVzJSs9her4` z%GnC-5O96~YM}`GGa%1*GT-6sFRj88I9rR|Saqqk^4ga2n;TZN%};x6avVOtEh*95 zZ4SLT<`x}Hqv0)Tc9|Y~G=J!k++?UTFw#Ww4OnQfk{QeSFbFfqGg@j=Q79Th_$WF+ zVb}=M2Qp&8mJxW~Jvrvp%%KNnPdZ+df3k8`$J#~L;6kY>yuV>_D-If2$?a+J?J2RR zvnWwaBgrEQn1ywxA^_x(6a;UVLTMeE9SCGFGEw&GtEWqO~q%nuRPgQcCsFt_sYvnYpyh| zzFb?44+~!UOFP!$9o5mWx;THz0E@5GLlhg6@aCPr_~hNMkbFk}!H++F^dIkifxa`p z`}lk7KgfCYQz0DcKZvG>AN=Q|e|hK8Pk;0k%+I*4agz!@eDn47&lF0(3ihfFExY|2WA27n(Fh&EPtzm-H zFhycW^YqUY`)A91a}?g$DqXftPeENT|6C1r8pWHZ^TPgAV6U2IDNxisaE=NFZ=n!x zHZD?gyo`YZUO>(EB|0dbxov}9H5PIv_4gc&akkblOA}C_^`D{jou>Ams`1NL`{k&8 zv($c>Fy)e_!8WWBD?>!$I8WIKolm;A_cXI*iPKr>aI6XpULVw_4)No_p#4F?tw38p_cS&|s(vFjgB(Yv5`&m^T>Bn@!dlleN|iX@;!{ zq6~|D8+fwW{whU_Z3K|5EV_&(5H1QU!a8kny0!!Pa<=Tgv^x%gIXf76b~p}y_j0y? zGYf?~q;kJQXA2$+McWyL4s;%*r{vsE6}XSexgXryVLuuibaudi8)0ETii!H`xEQ3M z|2Zb+*O4**Cma?1>xhV7M}_}$ROqk52mK;+z>njje>AXvht;wNk#C#5!EUdyST|a& zYps?ltF_W%t~41}8UoO4vB*DQnV(^Sx8HQUMtbiFO6^dUCRU~xjQ)n6GKWZtq&hwu zFf-6_0{$#+{Iq;z``E-A!6-NPipZw!c#X=jATCM7XT*H42u*Ma?V7dbL6nu8}enw zsd9|1m~yqG=0Fckc66fgvK*SPfgAg=i%$OzdeF=Q{ z;MUh~-2ECRkRQGN<^4PFAJ}(SBe&YTd|q8sg64x@xyaE$&xxbVT18oT@?-pH?o z`PD9Ff4da}lATx01SeUSKo@g%Ge2Vs{cEQ{10JVj!BxGw0h+KalV=p8O{~4dGIqU$O~5_PElCYK4n*zQV6+v80P`w#0QM*0HYy z4`-MA#1*AbUH+-}KMMCCtnlB(tHWOxtl(*2N&Zj7W{264s z8~%)q{CzGQH1H!f!hPK`YYgUe;FyMZIS4;?5gp+%Jl9+eT8ozeF9i5AiuM~c!Zk%V zHY~focG3CLX)Og~UrmeNof38^BkV}}pw^7Rs3VzS`_m%!X2zUcFyYpQg}0c*1LRpK zej4p*+50nv>y|y7zq*{x_>UMLJl^Eu&vZtpLw`Er&tSP2DkTJ6L*YyU#q~6V%A>Z} z3G`MZUQNYM4cNlbD3<(O$-hzb#GesP27JC$LlhdZPmG3>AEv$xBje~yfk!7#MNJ7H zKW5h4Y*>1(BCc#wiTAn1C>z9@`t3*3^MQ*1E2WkL2PT z6gcqN8rsgsnlbT*dVp>&MEAOmWw|HjOxd45ZqL-0PnXVwp$md{yqy4+8FsEX)liP& ziFEp=;rdGE8WDJ65A&CRjTCVH+)=ygVr})+n#!B#Qn4s=S8C#+G-~Y2+49p%E@yV% z&Rxxz@&E)4X$GtshtlH?W&*fmI5*Ea*+Ji~+scAgAn2(h(EbA? zAHNQL^o1NMP-rxS#eE)yBRVhXXnu0*%#p_zzS3Ttadyqj3w2BJEf-BOFj&vN)UmfB z^3V8`@v)e?a(wPEiZN@_SYMS4g2`!9=l;!4fA#qX-~9f)M<2fT)d%3u?|%;d{PFue z`Zu2U8tv&8gp5dkg{vFzXGCk>p-Y=D(a@YttNem@Hb;E-4P0eVeMMVdeBS1Jx^8+= z?RdWJ={>x6>l<8@L5B#9_Jg}$-@E(h4(6!d|MX(}FH*)A;DX*GPy}EyV3mKL4Sx2G z+Mo@t>O{~Q0YM8Z4rHM_3u=zQ)#|`i8eWJ-!xYVnYdT=+aMem3!qP;f%QUu9wXH;B zEmm8KR2)RZAWgMY0}yRptU>{43RKfPS819=zbv*8A$l4mZ zShSm_12PIG=m0^Yf*9FnBDLh}EY_6|*65ezTp5ie46Z0lpC?VnD6+Z27tKx42r*K* z<7l3UW*iA930`O__=@Ai znj~{p06PQeTd+UpDuMdV^Ar~Jj-0QAD+9DyDD;;UijNThL0cC>!9fEAd~|^BWR}7> zQ)ZYhrduDnIqlWaa^I0M|6x-9AyU62nNNZY`A;NK z@#lj9x|ZQ&(m)oJNwWz-Yx<*yAmyC(5n_FW1nL;y!H_v?eEKPU`bc#_BDGy4MRz+d zPmw}KnNW&}g46lJry&;gSIR<_>VYzKAC>=LjbEbKJkw-YVX;*7=~ELF*xbMWo_>Ay z^$FhBr|+TQz9)i$&j$uwa|YdV1Yhej@RGCN36p(~#kRx8dy}u%YO`Ur&9cU9T4yqC zFqt+Hb2itQEySEHR?=vo5OPMs*=pMbiv=go5MuBWR2V#C%zy0EVvs$93hdY3(rrCK ziQS3ubFSNfpm_SD8m+c^m`Tj$2BWbdz)%}t*y3+oXR@p@m`jb;PPCUdCo)1=NB{H2@jRu7#xz480 z0YnF@&FMS&m7GP6%Mh~AR;LT-rabUi&+?21Sy9E z1r`la2fQ30&yZ<=GXq3}Iir*iL`#$ce+Hd~rUUTVi=~}=;?KS!y`P6y0Lwpf9JTMjAg{79Fb| z)K6v8Fl?TdlJ%S4zW*T*D8-&xD3>8zx{_FJ^1{M`yU=X{3E@(k3pla zFJFR7JT{5D7~e0Fp3>2*jmE;(IQaJ*z1@<>-UEhpU3P=3Cq2sgu@ z&+mlq0pitYOvac4Ww+P`FYXW*=D=L1wv-~5g3g3GICpDfMmsGfCo%W^`{4TNh>Z(BtXXb_uviu~PcEWTD%&^mMM9!M$EVs@v+ z9G)=>(ak$G%h7G^IXfs_b>T4~`2Ck;ZR5CsZNAUZVy z^M#S=0;4AKoKF5#0YU%3p9QLhl^4yEpZEUVB^b{}#Qa}-;>Q)p>Cdnre&t! z-=OA(Jrxp_y!)YW1NR6tvvx#t^TrA8-*~?KbC3L)b7}W?FSZ=ah}xZd@Xu^qaH24M|I}fSNF0RLcw+R?sbelx&bd@q zj9uiqXLg^xS;vDCKxX_I&m27suWVS@I)D6YlWE8j;og?X;d>^8A!WTMd)U4iFCAKv z)>@o@VdE0&2Z}+`S_-UE1R5djx=Q4zc~+V41d_C4Jh!eI4lWpjaXLG@c0pUov|~%s zTW7wqH)H7TwB#LA5}GC@9G;(gbK`Qfo5X$MJc}=2I5j`s?M;|PMZ1yjLoDgXPQuT3 zBOa08hCdU6;q_J6Z`ZdJpDN7Xmot>mF?<><+x+wre=Np%QCLe{c%^D(N3LpOF8Ud@xWrKjrPC#U&haG19tY2Uc&$foj1L!uFW7RwczYPSCC zKY#f7N00vN-EV+}Km72Uci;c~zdri%ckg~qJ*p=jiysf^Rrm;z6z z2bHh#XX0oi52^Tc_zV>_5rZ{4jhT>{se_!uQ>3(HE%`d3G>M~q#w&TbyQ9hDI!=xy zC(^DyhJezHNCQg4(c#KS4^=?UEC@QdO+uR};l60zwU7eRXkX~I) z_+2gA`D(t;k@FRz;n^NS4DKgT4Ody_*;*t{<^(12NHB{o2?5R)m)WmtH zVm*;|CUthCToECchs$K4a#@&E9wJeMc%oPvL6@!sC66_OsmgyTfhu+K#sp(8id3C{sjXA8wNS| z4-7moxc||Xq@XnO>OojyM3$OvCWPie^6)GUPS>rb4djcIRoAjZDxsLVd+X8 z^X&0c%WmN_Hhy3H`SJa9VrLGY?Y1K*zD`TWVg5|`3M?P&2CWX;F}vls&D0iXJ>#&S z3vyoX*Z2P5K|hO#_=ni&-^9iKOH}MT(Q*F_5REK!Z1k@aV&6%K`@8tqpY`j1*%^2O zC?5MK(6JX<=|Jm&AYg5@ICShlp;e;IwvANSwnpq>vu(54y5446XGZr%bG5}-Wi?dx z585;!c(c*3*jH2FtI70MkJBoXG>RytWU!Rl8p0rr`2+a0z#GhHG~N_o(ro$wyx$TZ zq^CX9HW@YhgB84wLf22GCpCwsZjeYHBGQG5s4bvN(}5u&8Pjyg)$s~#qDnhNtsAb^ zk5O|F&6*V|NvNKsGUq^|t~6tGY`WZxfu0#0M6>xCxhi%Ip={ ze9lDlUhFUeO|(8q4!1n@+=PfGhHN1)S9^u4^r0#^q7_!D*w=#*clM`sN;&ZNVij_1 zsR%`C4ixWE$lcC--QE1GbK}p5Kttl8@lb0$HF^&Xx)4Ia;p?FTf;M=1qbw3%6c98N z9DzInEwLg0%=t4Abd0#Ayfi zQ(Lr{t|L+A#rXD^zF~yxbt6sV*X5&`$_%`^eymb zjJCh^`tLeU{Y`++U~h%GdeIEdpMelBZ$vS7l#f-!pv#++D@ ziTvc9t#naO$uth1x2{A=6OxVVYv;Akn}F-q{S(8FrbQ#bygMc8(2SAiD`(t*tG1c? zLxH_qZzu%NK2w|pI*krW2Pa1!nG!*!R%Dw~LQ#iP0HP@feKZK>>haTvi_|B zyyv=sJ4L}d>>OvH_<)NeI}YO3eVOrl^M)K-JeehO%WgE40a*}O#>W!~dfUnlmS=|3 z=5~DvTH3W2WxqOe?6H;8NQT31MgvSZq_ZA&lz-mllDY#y;|PflDHYm-vWYNPno6%W zl_K{Gnu-tX)s2fzSIoFuTLfS6^_pd;t7jgV{|Y4Ski_EYoz5f*4ITxt2KX}yBnOy? zr=S6>sFz}AdqL)ZevF{;OTL>`7@U8p8||(VO$IcrH0D#FNA3ZL`!+NEuUX$P_sF$C709^O7BY|lz~EhTEtq==S@Q7w~W+hiO#=` zB#3r@tlq41?#-VPU@}fsus@w%k-j&TTHhX?9Nsc1?7*b3y^|wfn-a4vC8j?wngtr6+^l_5CT~~HzbMaNQCtfwLtu+78f=RDU9lj$i zZdXd|u8C3mQ{(riC2XGYxoI(rVI)sPD--{Ou zmJf7YY_B7!2wo<{kIz@kgn1Zaxch|2;}ZOyzpwIw$j$Vi620xt)SC*aT5)-QgI@#mA7$*0odPoze-WfI3m z^^|{p+Qs2Q&^_?yE<{>5>UN8oyWQxb)69Sb{(L+u9t{%#oB@qN%fX-9aEQxII+~Nb zDc(cA9OCQDq|=$nXEGAoGZTqv=O&`JEP4^1 z$xH6YO+J^CbOtJttfZr`d1NOeT7PWr#EX>$5WFB)f4QL)k{NvCI@MIs-hjS@Rd@rO zYhKe(G%t35QzjPqnXLPdw14pK7ytFaHy^+I_3u7-^uY&TzyJQ1pMU)I@8A2w3+2zq zT7UT7muNl+`SaiW{NWpSAM1^D-cVHg78&_erwwE^UO-lPrQs6z=UXkn!%{v5PkgK|gE zj795$*69PGk4Epp)q3|rmqSWNSLqy;S`^nuJInPDbOe^^V2vhmG-J^YxTC?Mmk9_| zZ9_B~2$b0#xS)esqg6yxVJe>WB#wrrgGHlV6X7A~$WK_M2Ce%#6s`sl|7Y0SZYh3TWY&=o|Qr=v$xtd}yL zXIO$u!`ji!64UV6jp<*Lh(7rwseBUE#vxv&WFJGKw_mIm934nI%K}9b3kyYqMFYB` zz}B!t@Dp3SL>?xQvcJeDR%{-vbWBzSXK9@IYWr-mZQB><>v854WX@pb~CIxerhRCQwCDK7eo>?<|?! z97sVc0;QftnaB&uTPSf61BIpp0dcJOi9DQW8tAPX8{m^+H!iZ9O8eW^g#>LL6u3Uf zTy73nZtz>^=eNM*Um4Nocv#T6U~6lz{jkNn*KFSJ=fBTlY6}j$8an8$h_Igx9{d-B z2K^)?{HFs4zlAJxWc2;euuFpmpX%4ACD69lV%%Z3?m&M)D*JY{2&687WOAm?eGUgH znvoL*Y8D`KFR}CE+rQxavpZpa%%X)Xw6MbIG$^$52+5^wtu{-m&3xQ$IvHp=8)&;Q zsPC=t!EePy|2!`4@8V+rF)HexqN3i3j)sB*DQM!)u`%z&MgJ-$`tKvdell?2ZHJ@X zYCi%X9~gKb*m)36>0s-TzV@Smwta#2J-o0du|J9DJGR*z%^>^^=T@t=$!y$eHf(no zcZKz9iy3@A*tE}}TW|6%vl^CI0t!rixp>{Zv}rocWVQMwxgyy^GDzfU5{dCX;nN0~ zDVl#+FoJ{4T9MdCBoFY=Sf%Jq2|b z;doC_YLZpD;Y$4|rO!AOtQzog-~eJwR~WMtrd+u(UuNbAdb-j~MT&JcYeQk2CNm)# zovlFY&rVG=O~-%^h!h{=Xto9V6?&t!C|LAR1!vKG8U>8#`bY&)Xc*4>Dm8%$nV+X8 zpC5t0i~p6LtUV#KLrX+rP-xDaxpMq3f@82WI8+i$B4}7Rq!2+r=FdC@jUcppjgUs7x=`p&DM!pGaqLJ%Y`ktz zAEiknl4|9ef`a+~{vV$Ze|{gr=O6OVFVZ*Cg+G)3*_D6(;N3?b{Kunzd*{*5e*77R zw*L(L8L?-Mpn3io%|TfHnK~if`Sk7Ae}Cn|FRg|sy;Qv{KOI3POdr0=_%r$+0sTR| z;Ns5&pQ-R2o4{tT`LoN_+?kPf!RIdK4X)tm1%Gx=LA&k>X}#voWc8CNXnyf7FlYA_ zT%-#ZZo*2p8~ML>e^LJo2q1vvUamajuDbiDp7=9f7k(Xz6%Iy_f9_bd5ZJi|Ijc$W zyCx^RmO6BI_NbQmY3=0&mugEo>Pmo@$iYSYs%L-?A6+m3jna1KB<)C#-I@{wFa=O{XVc<0x35H86Eo9^ z*Z@9nMLx3>dBV1ZlhEx5*SYBVb#w}OUl9x3nH~dUz^SSkml{@F+)9&D5yiaPTzsQ; z`IS|(+vbknn-a5s0<{Sv1dYaCY2mmEhEkO>&v2_kvih9-xl<_3wbGB5osN#)ik<&_ z_wzs7zwtC5?m~vU{MZv`?rD3s_Yc(E^={qxGry}YoVn*86A*8Exy%N5)Mzomen z@grt!gFm0jjsb|qkC?80Fe~BEv=K)ajK8vG&dvJecedfvLCI&p=QG=;& zF!%p56@h5L&$dR?N^(KemSXM*ScjQ{v9dPr1Ei1(0uh9Y#wZKL_E-JY$98-1w`xV7Z2P^6lE9^Cfw^Q)#Rd z@VRwT_)!W5$LyODwPR95^Tf#Jl$h3e6R%ViTvq=2{nyW9lR9|#) z%kpy@mt0)82(I9ZD{@cpXP!6oHIVc47>u-1E5Otk{0RqBqW4UR-Z?q)*sPcC*8pi! zdr+jl@szmZ1zi-eXAov4vxj>Gnh}0%!59J8p71>h_IPQ>T;(DYGfi}G&NAhb-MP<&Iu0TY84S2rxV zxIE`H#`?2|0k*egf?yMWMqfg>{qdB}X2-(_4Fr8YH~DP#5ZvZOR`QYTp~nlxon4lB zse1OMO^Ytp71EcVt>x|YMYwaOFRLn^mg+RWw-p9?0-M-=V$GKhi}|@bnoUD z@ISwG{}15LcX63^_shGt-d$DxnnLLdXlESl6;bZ&zuq6HS>Vr4Q|K=IS@o59$)X8IGg&lsFr2OCWh_whXf#hpBdkj;_L!Fy_!NEjFj?L}>1bCg!^bVd z7>I^DTIgm7*DKRUyKpp@Nb}Sp8X9_oMKfgw%o1EKfs8aY8bez{Mx=d4k>wRQnp-=% zE{DsJng(UUcI_y!t42ym^Z_^QD24B6rSB+Jz-YB$v<|PAd9;^tgqQzNtzn4DFN&nc znm!^lXY+Zeuy0q|#-I?%olKOzCzPo#(y`HqtKO%(f2mHEw;A?nO&Gw?D@&dz0C z_QiUXbFtpBkjlQm%Qjz+vd&?Sjsg|5+dyZKoX}p%0B~0LOk(+P$TY^N^rI9!`0Y1D zYDkv)B};sh#6AfU?|89S9MNWdtQ18)=O_?7DFV!hF{{EP@-T%YR3RNKM`TqxNFpEP zDIe?sxi7@da3FYviM`+)7$^q=R0b*3cBR^=Qu!$)UJ{W8iUpVk01&mL*YL1=cn*-s zVzj!K4ZhPI=F)!l+JVlU1A=x9?6)_x|Na4eUbUJxdV81Zyq4>Imih&hK$;OT@LWjn zMU!#2zp2^BRO4f6@(n;ozbjz_e-ab%x3Q6bH*mmT1owF`VBp&^(SL<3bVS4(4(Dk{ zU~8Yg$NC1H2n3b2x!MA<7J+-wl@H9B7vQRkJTr<5Y>N`|%+G?o0`>h z&Y=Ix-dTXhb)D;aG)!U~1~F?inh}`81~Hm3X12f-$BvztF=i0Uk}X*>$ZQz{ZJM-A zo1TWLrx0jQ+nY8?lg9V^_Zn@F$gy+mHoZ5`^FRAp+S;=Rq}kHE>s#+%iE?!w#J5Z} z5ODxLYfaTUbB*5AU@$c5wMWc`wy4kxi7_`)Z7-)gUhSXu>x_&y)6?E|I^TAtzL%Q% zf!+QNV$Y})`#a#z$+p*`BCcw+Ex5VCL}G1AXcasjW@EKQUt`hLS`DnKLrvAhrOgMe zmVH+1UX;9h)-9i4(AR4XFmIemS3-DhM=)2gY zSrckpYc;Mg8t~&T63SBr0xdU5f!`U<2M%WiL$!?A%7Canq+Vi~k5u6=Qw6KkdX=|D z=@}~X43~IDh*eP@s%U{S#sk)HnA>4-hb{(-7idvKe=&J@9+3JytiYupa0K%I^58sK zNU=;iN)FDVg;%HrN}>nKdVGal+r_`5GWaW?u$QD1X}1FDDnvs`x1iYEYJ)=BL&S6G#U}c ziL42tFq=3W{Mjj`2s8>2Xp}p7b|3e}p9hN^gE;E-|Z|7o}7&ropu;e(q$fBEk(Tmygp64TuOGXDns*VmOlU+?$|{%7P97=M2L z+Fvi8{UFTL-%F+*pY?F-wkPrN4g4AYjpIA$-)W9NV>S0;aB0rJL2JG7L7V@W+--n= zzgfAkGd@;xMQggbW!(%K--a1wlDkQ&-g6wj-Y{<@R_uI?ZOj_$2UzI zj(F99(GOHk8dg0mw{GsphVluguv&SOi$AxZOW+pj6^Lry1f)<3;EW$SO*(8N<_sS! zAn=)u^UtiGi&lfDpPq5z$;n4bM}j_~nGRa&RE_KpO0zE)veRV9G|DcC3nTQ4A<1m7eU`;jIo~vNY_%oyyM++ScK|{n*Q<7FSW?5mZbzTNt7jV3_5q?H7&WY;N?Ht2k7*bv*syx2Z~yHWicrw(hH zlaGkwk%|fJPtOBb1AnIcGyPel*BpEp({?9zEW^(NmrxML)&OYQ^MpkfP8l>~dIj{(xMoc-*mbm+`m#f#~+9>Ne=Lk8hE_n1j#D05)+9 z!q4E(jmYJ0MU%wEC!d+uwqiP3%fWYXZU_04a6nH4%}6P`3!XpYFlr{q<)1ll%K4(X z)GkGKH{xu|0fdjNm{B#S7;Wror;GsUt(o{(<(LN#lnjEzc>4$&P%T!?9LP$jf$cvl zxiZVqGCdbYW$&wpu&k(Ze&cTjrNEFC5ucKB1+2d~?~Dqot!87nIb^&99u11sem}P*xT8 z+n4X$onzmXZQGlhgx@6yqo9?B+M;H7JkE^ne!DXh4-}@gmyJBXb^+S*g8Uy_TL!ZS zj40sGhzGEFfu8)CgU`M2=fj(pHNhLaiTaA3Up=#BPA>A#=z7@~e`d6qDLC9k99;O> zm4D{ovx5<7;?MbH-oOHZLt`I;j{>a*(SjL;c^UjGf?o_YFUGY9O_|RsS2O{BoxTIgx z=zfjRJ{LPlRaBDJj8!d#sZevAEbiY{)DKzcmf`_*$W)IWa(MD%NLDwMk7`>z_0*>M zq&4GoXNT8SOv--153AQj9@&MXe*E({{`jY_KmFt@e5Pak`OhDJ_4z0N{QN%iXIMD? z_{le)esuGl*Khv#d93TCcIuG(0YQ_0lqm3gz zAtL;I4L#zoe15k5gBeqv6iO7r5P>N>Flnhd;wk^or#&stsIlz{pZOGY&q3%K^{ra% z8R}l02pS-oDLrGcXv6rx1pXaxg7B$4hxq_L*n zCGLPnI#`RzP;@I*!MbOo#$#(7?>haf<-X|@ld&J>Df*m;VVezK=-qL+4pCpCE- zg$8P}z#-(-mwECC#3CeFPVaB8`#C5iX6Es$*nOJtO4o7bo|RllsNTkU>>h#8Rz@{LR43 z(E5_h8F*bO@bD3cLPWAqsUlIPO!e}41WsV9Wma_L%Gk(lF%gGi!kS~kPDO^Ej0!&y z5!M3m8x*|V$N!mt;5EV8XZ(Yn3JKnt5P2@z((dQC(>G|nkM?Ol!)C3qAuj&;)RbSR zrMzKJ`ek_7b%Wt-XlMr|dsCp5xUSPT1!*fmlFjBOtEJIoth5*pqPRwZw|WJ3;mllk z7`PRQ-#f(4U2c9~DKzKSphxB6&jg=M)`L_QIH(UYijK#Fq%@wj)?B5t*67XkI%9)g z*J#ooiwr%N5Pj7acOx?xA^OB5j@CFPgw*}zm6&3R$+3$tM4 z3vzY*WJDU#Xk3MG06?^BI;?pdX#B#Dj0w;zeq{ZkbI zDXKu5r+=K%D@>*|h(&?i`-KDT?0G@Q!SQDgJZI=glmekr;G)o=&EU@pp+e4SH+Tfy z&A-7E96W*se-04_pbMc&g1f448QqWT3&;6tc10+=L z@EIW2Y>eW^jo-K>Bk@co$+T7S3Uy$1Ao5v{22rr2pYwqZ0hsanScKD z<8RP{@ZUy986TqQ1NCO&&j5hOx0a!Bz-{<*ckIkm8`yTjXOe924F`8D zW_jkbJC~w(3XMTu{Q2xI?j{_sX1)$=iD~y1fp+K5-4JxQkLUOPOCBtD9k}5gchuve z-*@#ecm(Z!E5@JkxerZ$P#ADOz6v1U*5wlpmzEq`I^p!1ndjEcKeGXnNm^nLpu}>{ z7+~%I6AdWHF)$5r2DEw0LMkMj*UbiS2536*#Q5e#MTci+*G(H*IpKjl#pyed-O5RZ zIs=7v_NeN7D)jBzpKCh=4de8o=a-DW{M6%Do}PYc`NYO~c{P(Ct{yuOzzVr3dKr@PM<33PZ_JH9oEr@U-9-GED;_>$a8LPjCz$GPuIP*R_O<_hpQo?$f8X}I z^I?qLQS&_+cRN4-Ww(>xA%6yib`L_|bNPU#y4PYbaREXu_t?L)zg20t4ZHt2$e?Go# z35rRi8RrBOQkTPYJxt-V#;D&0-E{@JaW(J}`Q(2mt z-_I`l?$`V~8TSF1`wR&KKA+gI+{K?aQ05kRnfx1^uLC_%k`NH-OeI zf$QUV`GoDm?fW?XT$hzln;Bn?%En5QB)ZeA5_8@&JYoNc#DiHjOtwOQaVRGdze`nFu~_nhBz!{_{docl#UD_R?dq`) zG?$KtF$1#b02wA{l4*|`P(LI4 zI41bGf4A_gY4T#*l1m%Qkb=gnMB|j<^&80Gt*I4ph_Vj3#cW3s5!$(X5Ua z_a`GqVZYkKjLPEv_%&#pm34ga=rgOPo?km3r>$8zKYy@Y0ePxSR=#}IyC44XQ#1km z_@7W=AdQR%ViKD2jOst7^O{E zZVY|OCv2^!^%;eAjk+gf#vTTxdv59Yr&YA=THx5Ym0L_2V=wMY+L~8+vNCZXnrG2S zMBh?#FjF+wwUB{mmWyVxXy)jEESj-s7ml8z1dFB)hBMX78cpKpPHS{GB8`kRZ|%^H zCxbNG-h$GM2!R^GH8BbpRzZ2`VigJ*U>24}WD#rU1K^bIETTqSVHrMEHU+1Hvk;t? z2XXBVk&Ohx4IB=TEAP4W86ok`k}@B)ZAJQ!bRYj zBv&UAQdY*uK$5v~4P;RgR@fj(>L4~uLKk8HMvH|X>Sb()&w=ojL{ zt_21j3exS;Shs7edn}R1lbt_FPkYUl^wXG_=gg+l8cnmwbRs6I!|8Z2I_8Yg(ufQ& zFs#M^8AZLtRAVt$^Tp$3CQk-)<_qwd_%jn(+`-mmV7|}r8KjrWSl9VPka;Eq4PiCl zGv%MbrRmYu8};=%LygW-skK(>EY(_LtxjL7*WJD6@2LUbx5^G2WfXMr~w5e9WypuwLF!XWTxLeL^DZ{dg* znJ5A+4n+hSmBLYI1fkQVB!cEBbbLQ)e1BOYiWfoi6uMKsVShlDGDPASq)4%=B6R{E z^dAiN3s}13sZam(&d%)o`Vq8Ft=&t6kvP?Mqxm z{RCN+qp{%mor`xF3J7 z#{3<18{F0Tc^1)g09e6JMbrZAv7ja78a{&apWL?S#MXspwpXA)m?@^t^()Y zSO`yb7E1o zg$Y#!@s;`URRsyye;_M@dDJSl5ZY(-{HRN^;KX>xyt`wS_6)gYU7mvMLZv3Bep1vOEziU4ag!w@? zGJH?I!=Jk$XwYWtp+{TdXfC#+T1ryDy&FfRSC34qo%GO&C1dcOMQc3J zV7#?i3YwrX*06A^KLDS(0mvRFc_!uwQeDx8{4*5LAk{$4ofMh`?_8bQz7!W3{2`zy z?=~`fG$RYW9V!6I`_b`RDsW*(3K|jL6N|?|OkG`)0YeDUX6{mOgo{8kbWHG>1RV~B zpuw+r`3441=uj0TqClQm-3fmN9J^QinNV|YY3jP{IADJ~c#uO7Ld>}BD$1yto^|%= zxrmn|orqTz3>KUX7?}|9_T`|U7y$j@x_S|gqtekk3(#hcGzHJ*rfh-4U`{>+Ccyak z84-N$n?K`X4vx*P_H^>Q3_k;|f~>M~2hkL)?cCpO0Qii8e**=E4CYDvdGq2E+n2UJ zJ-2pl@s6T_n=>7I3j5bh9#%U$A9S$=YG_tmwz(UB<`Fc@NF(IT^XJn5q#H>YO(E*7 z%j(f~Z4(w@Ej_t%2I8`NG9CLfX?_#p3vhdyZOpX8iBXkJodFRWMuZqB_)w0cc~(At z94#9beFy%GyT-3HwR_t{uN5BB1vEV@8~fWqmP;S6y{0`h|H!vdZNUj|TUPP~J zv+dQ{DF-u?!J-dj*@2^39m=v}x&d40HK^$TJkr@oh)*BNVh}r_J}{I~cs z;4@xKn7F`xp$a+j_+$IBuu6zDICof#LNoqcm+wRoe9m={{E931L#QLe=)qVKa29Ir zt;?xHF*p5<-v?NW@fh&(BD4T0$MMoJ2aC~y5Kj9HTm?#Hft6q7*{V5b_sMa=Uh9 zzXM|iH$OSOW$hwNTb#i!^9HC_2)|=~pV|?YkFB5h7~C3=c;MvqxHgVTLlK1@nbtfi zy=7!Z3x}YQg=Pr)XmLNNKkAG7*N*Ccc*28Nxdtov>DBXgmri*wF%0QKZ(qON`)Ypo z@!#OVKol7?m{I7@{&e#*M4Rc8A(P~~$ut0z<}AmQQDpiKq!STS#5Q;wmeQ-x+z?4cN=hTF zI1<@luEim@MRuBxPt$7pLh47x2olew*?`5TyKi%4KG_oA9I0Qfj7QA@1@eF*nP0xx zzeo~@9P()NGNT@g*kT+oMiDSx6*SQ^c#@Z9qBlxA$wxoY$1*k0Jk{Sg)!#JT&p5;1 zJUhTN+t)D12T^A<6U6HPb%}n47YrL{CWuTpQ7?ou(HyNv37qbiOQCKMa%#5tkeuZ$ zAsJ9XHQ*Gf>>~IFV9!9985w3}ltd9BQHDunp%O`$Occ(SR1!`l4VTIyWGF?rObMHA zq(U8~RKpk$Ef0*72E~elqUAy13O}RLGgztcQAl9|5Q3T^s)>$qz=M7Qp-wChS16Ob z)PwyzhX?tMG=xlpWW%UiVbreChpe~iw?|qJL`Br1HJ+dUKHq>UQ|QU~#Fye@Ur&gA zHzDqgq{Lq)r~J&}d>LdiH0-3obi|--PLBCWeE9Rh!8ID=KAm+}hBC@ zrr2JC%p@Y>g3;Wn)gRUx>hzXc6wb-~9(cL%-0_+)DvlI1933RnwpJO;j6XM+!;gbM zgKuYKe3+E-Gkw^p07IRhvDOfIJl^rV-T4~Q*Y<>8JCa_tCtU|%_wz&O{Yn48B_Sc@ zI{iYEX_i(q62DGTVVqPDDiUa<9zhCekX#-hQ}~NyYJrfYqw#x);sVkL5UT`YUk_QJ z$jc!2G|9azD3V3{giCy)q`okd$H-LiayX(fHG@v0n5hAUMz2!;VJg27D!*)1K!G~A z#4~ubmu8$-FevmSC9XLrtkGZ|dj_KUL^Q52xTIk90j>l7c_^iCuEHl<=9?+StdP%8 zvEQR&pNGVt(0+qtf&CQzX-a>GI>7D)OT1@Zi3TDM+-efD1}JQ8WaLSdkU3&|3P1YCkpVH@n?phwZZ_MFv#E$0{#pO2a7;Q zh+Gk9X5mPJh(i>~5Ok_6HrU(J z^IzP!^yN!8zD5heAKm!-u!p9J1+t8o(B>^q5{KMT4*q=N*~M6J4bFUK>k@pvCTO{% z4E!0UN)YM3_%jcpF>ud0_X?kJM;CT2aW9TDFFn7L5H#yN*o{21FTWdqW*mm$7mV+! z*sXeQ`#MR_BX57deI4J|{+{HS?cw<|yCM5AQNnp!S%Lh_l!j3^vT z-jz)i=oy6E&b5uDC(A}3o0AQ$b#TnUgQEsO?g~-H!2&1POJ%;DfHNmwbtMDw2|Axz zYc=I20{o)t^AjkVdAjXvN30$nN0@T?XY5&o!YVx0m38mi|_~!<)$E! zg%9$e&<)wKx3n941e(h~-z)yyZJj>Or9?2u(U@KL1SLEuj1}D_07d%R+aa z;Vx3m>?XK^vAVtK9pDkq0)0-akX(gr0Lwkb4mq`S!o>~q@oIB&DqNA4(Tf9>)Ar>^ zKGR?$wP3rr#TAA;xqNbK#h8}Gqgs}ZIksX_8+0h^7lKoPQ4=EO*fj-l0k7~Eb{kv} zi(C_h+>`+$ji5ikjjNSM%qPC1bBUOt>3zojUaL|sd z)V-N@c=-2b+ri&jpO^;7iQh5!e$g)vdEH~{mz>!A1j|1&h|QrUCgQ%_8(9skJw;gmE+)ENcZjHNC}J5xhIuJBW%2s94Ja~__W ziTo`S;` z#|YS&EBY4DIsp4Ygr##+w&(XdJg4ORnt9a4ZzIQ1eU{9xf{nzkS%I88B7pS~xiAl8c?7C5#mL7is@m38OIeU06r@tqvw zetci!ZrGXs5*-G?me0-@acbJIy5bBJ)XkU#JXVqh_}o@(rwDYBlX!Ab`hlW;`zDV# zvv%S64P|E_gh#(fZVm+#c6cLWu>j~XnqxMU5P}BB27<=Y6^5X3RfiFprWdio1yYWZ z^jlTj4^0o7OZwx6bz>i?dOWW*bD+~4h!3eL_SBOnE|UD2>+gfkgD8ygf$piBc7KHM?>{MY}v`IkQ-OT+1=fx98!c;oAz{^)ZwA4Hl3sQLM;-(2hX;%@mfiKBa~ zyXDoro&-DpQ_h1p5Qp*q0gcJkt6!t};0xFPUb*jTY)l5go~K&AnxG4>=uOX_N8UDiZAmjm0NWtqF1WjL(#@3RHTXK%D}ZObTuwq zqIL;7%4yIAM{}kQXgW~(`AUeRseq&Bs^FbKIvT~GG_!UvaR-pBp5xMh(ma}G1`jxp ziA%faGzAw4*zz6^&gsgpqvybp94*GkT!CW2X~1f5B(C7HpyH*|T?a@V2OxEf0&#-! z0^bFF!p%p^p>8I7^H^E%I9bpHIay>Ussbi>2Tt${n&cZi*;o6xuXd`JZn~#oy4plm z4He2f$5qBz3P5=D9K-?osa_J*JpQNK(*1( z79Dlj>G)+r!ke+NZzU$aWwXB?pZIE6#5JA1JtX9)-gMMrJw7PySJ7b|A(|?^<$%Gm z#~N9i;(X4T_Hshv6_ce6stuj4!Juuhm=9Azn9Dg6p5;u=dQ+9&eCYOk7_hoqb;Hiz z{^fn<&sO~rtG?N!Z!+l{k#IKXYgzo5$hooJWNHixYmJY+U`x0X6@FH)!RvNd$A!8< zp3RmT1fF;d^aWKZClctHrpG{lsD5- z-%7T>YPY|Vkn~(s)CFtUNponc(bA$fBU@ep5{pQ+Pysvi&D$bVyweoo`0Oz7S$OWs1BI?|daG^);L0&BWxl?Dn@(?2ve0#uP(9 z(6c(jemFxS!cL{w&N%GNagjSsn#IB1lQdpM0gA^0l@ItU`}?a?eZ3rBo{4frtV|Xz z^w0@CAhYP~?Z}QeqMUp8Rsebgz^h}hJ>fDK*n-Xs{ z6@?x8K^Ynp`e&;BbJU>FLB;Bz(W>AH6oJN@k*0yBaHb$`3XHL6Hvgp?ug3Hc-lqX0 z75>Faze1&7zRV|A;*%rx#^MMpkr+-C8n$`=!7{&r3jcm8bd~jYdimRZeB*t5BfS&` zDZQT*0uQ-B=#DS}Fxx$CDxeO#?*0WkN9uAX+6>c!^X#D4{3h8{p4= z0xwjMz%SUtAMjc05eWXQhk}DEM4&BV9TXf<5)(zB#b#ElLY^th(ZE1+n+t~hmZgE$tUQE{0;as z{&V=tr(aPn7voR9xmW+3{BWM0uK=k|=-)reKT}lTlbav?_U1cp-F)H3U%;QAyFw6{ zmt)-RKS+0YJlBD`Tf~}-90)4BaE)3m<9{>Q#?U(CM#o<#jDAWgP(|wk8#XL&-?0o> z_}oskvMNOjLI$7FE$%#^^s~hM&^!)1i9&ZPpy_SpEMD7l3(F;x4k&c6y6|kp#hr^$ zmv;A7yOvzqwS*nOwk`y{tKvM0%S$sCG~?Uu#2aIG0SIz{?q7BpcXF7%0Pp?Y&$FHH zc1Juq#sHtV`QmwUx6|T>h1f6xISAvyPY7Wtc{#Q&KePP_P^l9eN>2kUY+u@eHabtv zXqq?j;K+ekTMA)mbwO%Xz7t9f6y*%DsNgc*Z+uBa6t zdIA+l2p`n9d zDxPi28Gq)!{4lJMm(XB2@!On(aJ6aZE(yFd7 z3B{9VHxPZl_%kjSeIsbn$OEKPlheFJh^%p8L_fg`D<@yxvhe(N3Y>EtT1mS>?fE$Q zHeM^hXIOkMZ(Vw2^Acd&Gmr>vUU+)*{F9p(U?~dz9^o%3XcYEc}Ey7+>b%yr}|eYt9t06kY%DQ#{}CgYDO?iBaP zGUPme<_Dd$xo1YY7yb+#^npAl?A#|;Oap($V}QOJ_scVIjz5!|8vOa(%4szd9y*wx zT3e8c7&ao%_>ZD5nA~$ekCA(Ri|yeLxWfStoVyL^=EZ5P6CP}zKD=rC5d1HM6f{E7 zpv26-!T2*Safgf2tBW!Yj(MnM(YVX&OD{k_0vGhQWk299Pi>3M3F zk!D-{Y=w5V0#KTg(yZL_(mEEIejH|L6-ZIY;{>IHr%-m06%y2}G!tdP6J^AQ$Ac1+ z*@G2h)NC7!UVgomX0#ebCRmoTMkaZznw%J%GnVYl6Dg{Vd!)xOMIAKRJ7|h;@Z-KA z(|k13JvB4b!0C7jrrAo<962k?9JzV6%s4}4n5F>NBFV-$Pe=fu0)W>V*x5guS|}pw z%yP~MZL0f;lxZRba?UoHIzgdiuI6a5G(sc|^8j;}m<3?YQiF$#m0qOKi==vy2bi%* zAhZa@p<=|LL7wHILZwyc87}h4i5flrA=mUqisTbV5 zB1xD+VN)k9KmQ#*LAo`+*`OqT3Q|7vqvH$0T%E!cQTwY>jFQ z(p78pwZM!aK@AaM=WPiuCMW*Hmhh_0_D*8*2R8eAiAk>~B)k@v@N+1gHQM7O5H_|9 zO#ek(R0nA#%%q!$h&q~@_9HYIw1l-m4Pihk*hJZ27>SvP*kZ1vL@rA>o2!XGb2z#$ z3f&Dpkn%*HE?C%>07NxN*~l4c9|{vsB0m56l!tvqp{IfQd3`r3mPKm z6zA))@jtVMyf6cA4{eSQ5^e9q#J!3RlISTJ8F4Z$?h+axCMCS)Nd9SR%JT`)t%l$&!QM-a{)?n87)!83Y7^0Pn!@F8XW`iwnBqZ^#f8b2%LvW{cnxw{i(=f%;@VJUE>|v#wL|1^ou_%@QD1d0WU$NA;Na9x@p_LK25`QiZ9q_2a z?;)lC5VhZ6wf_LGfPP*+c9pNqDRSK9uT8v#4$B}k^*2SN(yqfXnQ)m~+@n_n0D^Bd-PM$kG8)Vz) z4xe{b^bVgvr0;+~gF*v5y7JY`|ICaZo!c&`xw8jimz|ybnF1*v7fg#lTQ~bm_Q*6Cd4^mkK*55?S=g8XxVsq$TbYr^QNV zfbJjo^Y@cTcjM1M#J!T?Z{6w6mhWWDPRNdQKlz=6pK**kE51)-mVX9(Mm3Cd9474s z`8NnYL&Q;NBO}MC^tvJ^mM2t>8gO(v7HgMutebOw(*nejftqniKLPT*^$9TKp8T1m zo%`a?IG!*5Qb`w_ZOb_ROx6yZ0hd-Naqu=gzkUuxJ#eC;C0Szu;Ikd%89ohAXlBv? zUdG(hp@I~+-w%$=sGBgPe)2k})G+a(Gt0+!Y+i6~TPZC1j6VZ6 zfn0>RIsTjY}?~HdO#j;Tnro8^^XUI=Z#Ac^ma}#DyK#;r8_eY>%!l2aiR( z8Lu-U&>+vyUbO?IZdeGRF3v_#;jPO~ZG8fWk73oGTSg#zZo6S;{>z?6vOOHkB>2qn zXX3_qQg{qNh!nf{Z=d|Kab{g>?&#%`ZAskalQz93;uT@@M9q)?QtT=B`g{q}ZeHB9u^bN!2Y`nYMO-lre^9n(+4p3VXd3*P5OgOu z#-Bx)SWx(NW#wvrke!4FLw_;30)@sOHEgj577niH0KOP@26^V;Gx#%7<$K_}&UV&M z&APOD&ZP|mkYRYnQ|RQ(-Sf|#`#I{~nTW>o!rTGC^{I7buz57jDm+j)@IY2dZLSl4 zBHj5jlWbs5-{hIG=uY`_r++QMQ^4e%Kh8tP`?=%&JSv=^)`8dNj(k&92w#tc3TFl{@YIJ$Ld!zQwD<5&7T z`c|x+4+DJd*azTt22X}c`bbeK3JGUOq4B@g;gRWxSYsv;#VvKAljAP9d+AqKIB-Ya z;H+pJK3YQyxnkLxkAL&mzkYz?%zOb!aj4z|LM8qo&=lix!dOjX*T4~FlJxt_y+tL{d&-v zXZN;K{(%P2KL3X$@f8N^%0T@ZZ^W3xpP@W+7rfjFqIv$@>vype2k_qlSmwvw2c5jS zuRG$P^eqr=S>E z)jbAe{9vV@t#l<7Z(hTg3R5psF&C^sNGn65-6e!JXmuZAT-LsU& znQGGvm2sNNFjZ-sqBI~>37rU1*)VJrs)F)VP=AnKgLM)F69aS3kf>9|h&m&;sY((m z;yvUsLM4pNVN$78EU}2BW}(C=6dODwdVxqQkmv*wt%r=2MySvTF&66uD2V}dTA(ls zJgq|SFtJ~l%s)&KU{(5=6y91X(#~R#W*{#lonbZ*`3O9~#jI-2bYH(=Awgq|`nh4D zPlj998}u7Y#vSND2k;mZ-IkPe&X#f+;)P)SF}>w{OyZ9s<6nqMd`@d=57ahW!cHUU z8Xx<-J^ANpPG}!qcR1fnPJY*(@?lEK`^m{~BZBL2yao9~TjPUV&NafW}u1uC7`Y*8v#2QW<&HVP&)`%qG${0mmMM$^F#_FQ0->J(Mr$9F61sICqgoLx!5fj@m7vg= z4&v4#K!z>#5JG^h7RnKX4qz18!zTa=Xb*oB6wn$`pk5q=;#1I8p*BKfh!h)vpkpN# zAm{{1Sdx^BKue<0kq{J`(?Q=#K{FRL%Rgf~NS2K7Gv%LUDH)2yWY0*GG(aVgSdF1| z4aYwH<5wSl^v@so^S%0K?6&7|37>Hc_aC5Z`5WWUpZwwG2k+l}@wvY|f9-Gh{{$iA z`_7+%mpKU=dDy5Cp{p4BrttICf8t-q>zDra;~QT;y{cI#Q0sj?x0O#vUJg0uGds%} ze+HSvKhK@~xeWZ-Wzt|i=UXyog3NA3ZfEyG=9yL3cM$EypBWAA$#~uO^m!ilbKb$YXC#|)Zm2t8;O@tC z>B$5+uqU1A$yI4<2WTCe&qnB=L1+AdpS`KD)YR!yO%f?+;ly`pS(6(^{ zfPDaMum$jO$s9nE-3r-eR9!(ls=hFR6@AGa!$cfFHy99G1_#bdBvW**4F!KDsv({iL&C0>t~(Y zwg_HpWTBCWZd);>^6?S7^ZM<{v_sg4!1h5dHOC${W9B{i^Y@d-{{Qx={s^w!~Rqk^=sW=7S7DlLfjcnKH(3bd-=; zw5}wre)NF)af92-OD;S!y<;1gFrmx#?N6ND{v;H;?)(|r4bWqDeZYVZKV$5o%G^bg z=g$~mt_p<<5z|4l!x+H^=*Ie&i(3{QUpl64`~%E~1Nk$Tc}^k=2jm;Yc35`~6xb`r z4s4n^;&^G%xfK&Hu9|Z3smZ68jBc5oRWo4--0}p{3zDn3i6?+)mWamnhh2qu^2`SA z{23IQC(H~f^IzU(@NMv!u6uYtf}*pl2ePB^^n$S;ott}p?X0t#7M$2p3jWN!Cd)uF z!BN4Vp{l_3_8gkott&sfo;WjJ>gLU*jawHrY+cj@5Y4r5JhO2r3RD^LVdAmWAd>w2 z3_jzJF9sKPEJsorTof}1C%H6luN?I@J9*&TZP3?Ec>c_+4vatJ8NtrfzIeic?6jH@ z$uLVa!hJC!j=JU*4{TjH=F&6sF04meTl_gAUJVfkZVm+P@<_XPAq0HpS^gcBB%TGHxC;!Bg(-G3fuR77% z^%dB%=g6LTug{mB-IgUsHj9DP6dGwy|F(delDoA+=2^yR-p{!AZdF5d)yrjHoJpP}IR zg7-fo%?qK#m8(DSXP0KAcV2x3P2oSs$FZxI{(0r{HyxM%aqSv{<^QvJU6aboA6DJq zOnKZgtzl(=ZVi`zUZV>AHvY^&v^!Pi(X=~)zTE*lg6`U&klmywe+Ghfr_d}BZC>FG z1Z{c33t4EkwJ!6tELDR-^95NnUrg444u-6WA;Zzw5{@oYF)od;G;wL>l!n9uX6c3M zTfu3lJUUa;q?qQN9vrFWbJUceW;yEF3e7CJc7{A;hHJ}sbuZiLYUGw7WJVdLL5>0F z4IaW8YFnmIBQ#$>vNNCem!jCztvKY_%~(11Yw5m+n@1nlAnmEWUsIBAi_ zgwh$7T9rehwoBAWVpTjToyn~cB~pY5k#mMpLuL?5^(Llh!FYcrID zD|xU`9^%1m1#-OrfJ<%k@G^@~zGjK9QSNI{r~)O3S&CI+tnlX+{6nZK6?k}yl~Cx~ z)ZYF4gEB3aX=Zb&LBHH;-I9<{9~p&~c6AnOYi!)5*w`y^@y~-9CMI`iO-BPY$Bdzu z679c;xBWae=_lrhD}lQ9h}h>Gj$b)aDCZm-`^$u+U!^zzC*MZ|8t^$a^@H^E4^ka( z;Q+K3OmRGKvtR3<@$=~L3n0&k@|q1tq9e{F#@w(NP9opS?W{HFYRQePtEK!i%2*eQ zZhg8YLePN8cZi+c54&3gjpOfMfi{~Dadi+0aII-SN@pUybBOT}RLllTgTV|xbA5=e z0h#c)xXT&ozwV#*PCw_bZSg-2vz{~RT0rR$nbzq@MM7C+bCV{hQKxAG98Pn*ik})% z&6pa{nT~}Rn$R~e#Mq!QHR;Ug0(mAn<|^g_;-X)UkNKq|@$Gcy`~6biNwvT3Nd8q) z?8`Ax*P|jX84SlT9e^-4V(Oe5qz*D_v%cA)Yjr05B+dCYez-KtV1JKQiv5G+%IZ=sj>2$lLFrMkaFmgFG{M_j)XM58$- zH=lw*3g0_5FfCGQ zMya%8)zpG;qLKxn*)$VF&`|4W9{0qOhv3Q7xDe|gg2pQ-5zSF({}MT*JrG0(AXc5J zAPNoF$0N#shm-+B!gs1h%i0GDWiE14GN7cw6{csAhf>_MM3CbaUes`I#D3%7JruL!^AHB3@PW zfd+qO2s%x|>7Y3ahdX};d}jQ45XYa>Iz~!Gm;quR) zaDDN9@Ne9sY(Q5W-HkuH5(vbfq2T`b=5Ky;^T#g|e+K*Qq`~*G=LP)-*c*T5)YAaq z=v(~_{^7ZH@$WBQ`+E0|OJadnh^OM|Sz}Kn?lS&-VJAUp;?LmB zy)+YahtC+7Geri!<#{q6d+yj%fx0LB8IOnO&-|d9m!tcaTS?8=v)mbPm+#&ITmH_B znxJ%V4+cBkACLR^Ho%$x7VmMz06YY%r-3g>=)Hw{N>brTalQNy;k&r4tYgc~nKjdLpUpvgL?;&YBbkOK zh6q~YSs(>njmO`^zw!SY>HU5_-#cN&?#J+;xZA+}m^&Hc=I)2_XLAS3cQw9G6dHJ$ z<>FlY83>xIw$W(>pE*x5c|^IMR)84wWBVUplz(a6Odx2$Odx0=LA>#y-@zLn&JDij zAcdkgFU2K-VQ2R(e*s}vHe4>44g%LJsF~auHQjt$Mf>)OOWVuOJ~i#=v=Lx6U__LE zh6TEW+LAVsbHfh!3{MDD)fbyc`TQ-#LHA@!y7^(GroA)VO-kG*)gh zcwJ>-I!po(ZeM^>V;lK5@Pa@AP03r>Zn^6@dalu|9|-d%P-W`X*tUJ~u^o$#Zm($G zR?hhI>CMYdZ+e1+6-cXc%4h=Dm_^-KdUVzFL#3l@mP|OcVG&{f4U~Tdgam@_m80Hf zC!?=Dx3{?ozQqAgrgR{lj0biZoe&p{bn)jA2@P2ZxTqoq3`sJYtevVDe`(!!T=&i>bXvNiyO#C@39*nngMEss%i4Zik%rEKKSO(gU$Im}s_B8Qjug{nG^X8?Nl%CZxG=ITIB(!QJ|2+vtTDdSF|Sr(d0 zI}>LHg$93yv;@V0XxqUoDt0QI6Z0A@8jbIQNbf|O#qp1vdukSf1B^YntgI@`SJC)_%r{&@WNi$SblZG0xVzJ zlkY_5V%)G-{(OfNx-SIX>;AiqLjy7c3&WLx>AdrciaIJr)r}pD2sDR2~lVivd}0vI#|`0^s6c!R6Z~^F+i#o3u5DvjvP7t*{A>f;!`*N{6GJI z4w^~-x_&TmC1LK#PKKcIaps-3zxm0Jkfr$>r`@=D_2Ny0YB>J}@#hz~PapW0^R4{3 zcOHBBK7KO#KHg&|e+I_C(sA=r$CuZye{ucNAJ;rlDOY%cJZN&|QOiPftNip&`#_oz z`jp}h`Li2y_6c2ctE}*N^eDFjyn5nmcT&x6%ZoT@z`pzh?-d}=8WLv{R zC13gl3d4K_ztzuEz&p)&wfmMF)N?o!wcC~jtqrqPhFPB7NlCU0nbb=xQXuGzoG4cKdy>S!LkF|2kGIX=ufLz)V}XH%{()mcG&2mwCH{fS z)IO_%bh{#AT4R#VN5)@@j=vrm_k4KN3yBG@!Y3RRbv)GC2$6y_<&}Q@-%PUqA~xaW z@R%1-aY;X;cyr48aq(}(#=RMr^man>yH4kaDfV~Jiq4t(Rz~_e2t_9({4_T9`G}}9 z@ktjm(q4%OKMTt-K(|46G~C*bI5fZ}WXM(v!o8Hd#TJ=c)?tvE^Z`e+hJBn7`pywF z%ps`z2$R19rZ!h=P5boLea6s3rm#v=Sd~7sQfEO`8?1FYb3JU#T2p<9zAjK#4`>XG z92NOea^f3cx#^BKZSgNhhH*h??U9g>T8rffxV^>Pf|oHl>4hN!UJnoL2oF1BhDqDd z2#8HI+ghhFR|V-0=`Fz8jXK>iqyBWbkL)!LK{u{jK-ZIx-Eer8v}wj z1Zp+}>Nep^i+QibwBKspW3eKKztLiT%4k?(HY^MYnBeQ3t5yt=N$es~q(GqOU@o97 z2cnT5Mhi`Edb7y2BDp~f;kkE=!ZQxt32AYG+9CAG5cv+IAhge8GOR=ZH%710;9`|_ z49yu~<_PmgY_WrO8df@Ba*CPTVTz{xD1hjoNlHeck%&fLR1&!tDVbC!Fk4QOO+%&r zk4gLYZj>;mTwG06Q z54>NQZbT%Ih=dBU1X5_V2U-)VeMR0u68~VazXl}=L@^gM8WCD0`cM%=(55Jf83>vS zLQ@JF77h|YcOq!kkq{z|P74S5H{AL25V<2w7N4jJ4HT&1--wNhId}fXA3pi=55NEF zlaIgoGdD~Amrpna^rtuf@`L~R-XrK+|NFVGfcxVgzxtF~RNwsF?{2>Q(r3?K|LkAH zpF0=9x%yC}6*bq58eKy00N~$v{@T|7)Ys7rvEv{0RWD0Letrr``MA8(yH}mrS#fIn zBIKV>?p$(i$5I%ZFCx9n@#pqk0L!$~E$ZBbJoCVr4VbPOTV~bZ;WMzai$CuvyM*eJ zf<_{`^LWn1;dZOVt_ZYy{+Y{N^VqrDpgVTv)6rX(xLPQ310Me}#>;=n5BfY0f5JN( zFp|U0#`Eg$z@ORUHUjoCgau6>b8bGd!7fd8vm-4m>t_=!tnnXO>NDUp0-Q*Xw6PtkJ%1 z2C~gBY@Yk#+UXZci<&17Ify2Pd35hcR6-VAmz6*#8I@i?W9Zp6Q!XR_yk+5;&7~dN zmmFU;>(I2E?b*ru@@$6+$t#N>B_z+C^c&KTcvp_mrGSQAgmXdXkuBsuwK{dy-%q^! zt&hqb0=tiSAbf`d_uGEAF}tI_m@|);`#J#o`D5IiVqf0A@m?uc2oe= zKuJMUU>g>l+f;US+u|$ee7a=v;ThRAqX$$KQ3@Ke4p8eV&ZNP0EleiZ?#7=xuQ|66 zG~>_TZQCb^E(D#UIV1k8LeSfmaiu1##W53<*`BQOGoKL(CKa^WtSWv2I??;_)ks2X2}??C8oF zgrGNImCEvy8y4S&KX)UpJZ|OpcN_2r^g3V+6W`)sS~-4F7uPRpoRPafD;4r*YO9wO zTbUDgAUk&d2#At0nrGykUo{=`fFvZ@1SbjkB6tMNTpa9^|_P1pN8>rbYGBhwm#) zgF*fF{Q2He=F$*;KGvpWqpNrD~pDF)blnRH& zf#Qs|(ot8i5`>%YL;fG}@3t)~FcAYHeP(kx-WtcBe7tc^PVLBk%s36p2a1i6f=2P! z83P8QYfJj?Ef_E(HQb;S2!(E>sD_~usr`9AY!_#0US8iS92|Ic6l z*B3u};WOy_2r^&l$)Eqh(k}=<-#-8ReWbzvdis3@%?H1Lf`jqri3WIl%oS-NxKG zT?gMfNgw=~A!r^xV*vh);^8wtVDOoJX-sY>_rc_=6#TN_-c4ITrIrwN`B5;Q+JXmLQm zN|onoZ@(R;up`hrCpce-OMcNBc_m1DT5swAe@;$*IXtu(-2fBgF541+?6m(^QsOV7 zVqda`-+)m8EE+M_RPaXI2MEEYI6q8wyql8zURvr0DULT1lJMPMWn{dWkobxQEeQ2T z;}bj5QeUx{+CyMD*4KwwPR2)Hj*C2JH8rE>AWX<$#jbd;sfxHUfHULI*kX*rPWNo{ zZO7kF{%i`ZHilLjER~RNXpB`_BRMw==0=^dNuzJn=#FUhM>U3)5Pfs7wmC?1!fbva zD(bal+gs_*_cEMsIg(zDinwaf9XA?VwKzDWF*@d)J^4AC?fJNv8-W2wjnv$bG#$YB zc&%_pMr#$7xt4P~13@<%^(U;Bv$0XvYzZ$V$Gu`tcopP1Bjt^Lsc#R=K&ttd@d+=- z#Jvz1do?utyxw%&VmW2Cw&PY|mJWOJ+fMuMQtiKU+JBR7|L@e~51h95)1AKqg0|a# zla%rS_%lS%^qbb~c6WxSIR{}Yq>oKDw%Pda9Z_NH!%Rz!n(4uT#Xdfd$Q2GyXrai&QD}6} z1hhrMzcUf-C6ES54$4*q=c~0PFu*G{ zV@Vp%5HtzrIsUAl;f27?J`T=ZNc(TOS`Xp*`^C=CjYzNH0ntak{^kp$*Q zgCP1CMsaHh-hBqiyay14_DxfI+hxi)ku*Xe3l}J(1YU6>?*thho^QOuCsu(zp&;jY z%L_rFF@wY{T;Sf%BDp}O7J2$hd_yDwT9i15@n>>D3pGH{77-!n2$3;TOuYzs{>*w2 zrii0>1P%C%%8*baLLNS|{PRFbGULw)N~@nhE)$3n;uEjkc;$B=eg6C3{R8~@FPspp zlRy9S2mX9d!T@e3`TEa)`Ue%)bI_eXBa^`R^B+FC`O{ba_QH*SRsNZ&*gC%M#-9;a zxO(x6tCv21?&?<{&#X?iyrouXyrsfv*$=kwT6uQY;`V13p4?f{zT3s0K`CLtIJ>*- z^zMo~kz2?t6iv~2{nKK)>zIA7K`ED^a zqdMQ2Kl6n7_5+|Hz-JWFcWv9tPZ4=ujGyV%ofX%gtvJ7SMoU>y&6EfB6*>0iCRU;e zV3CdT%*D345-fhFUSKR|$QfKYw#=bs)*p~v*XP@7=2;>UCT6k>jTNfdZeSJsyi(407TQ&LkwBcw{ z28K)+JU0$eYMc`w2s{}H$-Vi>&9g>aS~KnHw$jVn%W;wu8yB5iGrNB3V+V>H&yI+} z%4n#h4*_E2!~um7eExwyfB#_h-Lm4=QK`Ka^1!{;ouB{v$)Bku;z)uXwCj<(UMXyXP@g3BK@WO_<$LHk}s3Bi#GNzm$&;VCK zpR(%Wel4@IFFrLLnP=Sa*v3Ve3p)-xzHK?hvp1Gs+PoOy)vIggo>^Gf^7up5#i>Bn z=v0UT=|adECnWw{n8X+7oW}*{7JqiPaNI40?u$Ru+!>Z{WG51T&Z3@imATGcaM;ew zIlgKtBqw-fxR7}TGSA@rSZso)25d_VcJorIEktnv>gi7mx0;3$(FjX#e&WQ|Cjmb} z5dj$KyZB*Yt;&W4O;1kUKewo|Yz%}F^g3^-K!UyXnNl>!>q$`A9(TO#evJEm_p$pi z?qiT)l)D@Q01f>RPpz7DaNHvh93h|!GX_?~?9YkYn-v3qc`!2>@#Dt11+6Qm<09O; zrJ@^uCM-!2Xy#bH#h;ICsz3ojm?4~~liIWd(vu^_a#N5q~f z{LJ+|Wcg=E{*ixf#Dbb^8?C0vve%6qa%}F%6RQ_MzCqZ(YgXL-xpy5e1v15Z8BgI>b*8K_wTgl@8li5`?_GIzXsBD4O+34i#ML5QG{Pv++SoUWFIh3HF| zjl))F7Jxb82upjvI_T2Q5iFz-t{nzAqi+=syr~e0@jo*Fk&Y$rCg!;?h z(`XID&NwH}pa1m9SAY2JS3m#hUtf6cudqfS)^gOnt=g_u4N=s!E3FzWfEyq{9Ra5IUL+x^ZQSU+_aYET^d@?7jT5Ihv17-vW5?wr zZt+QSPEH&b{`;M8wX6li_KE%fKL5#ez1J|B9nH>;w1f8kp6`CmkB1??NPgJ=PW;&g zI0tBo41dS+!2lISc3nCY84oxgVkIE)p+KoG@$I0SoLOr=s5%d-W!!`QlzE{P+Gl6s zf0kMhXi<#_=lM%J!g>CbWv-vI9iekY;?4Dbf|py%!JIV^ZJ8&>iJj*!H8+5A5^2{J z=l9-e#rbscbL1T2>V4zt{iGDZt_yU{R6Fe-mYP6WcU^+DXZupIbsERkWFT?y>Snnn2`U%peP~%RK6+RIqUPhXc-K!7jWgzhwNYpvs+b_q9PJ(`! zdYH3Ms;8l&n<3fFE78r6;0AW4Zy+IOuP9F(u<&G`aGiIUr;n6}F3e3&$T>omSOq9U zxQD{dvS)d44rCB&GcnQo&Gc6Po;Ev8XO9@v}e9T91$m4KEcaO;12LbAr~0u$4b6w(M9URlak5zw*!WS`Jt&2M86% zm>Ovs2u4m!Je%C^LTaZcGt-~V&U!vK=NI{TFQMJQ(rnAc&-`L~)~`jTo%?!z{+k8) zuUWHxjwr(vLsP<|?c1Nt%(~Vo6H9@&C+Hu%DkJWHpd-EOg@ehJSFvdM%It4wim3qFIsbcm2G<&p>&q@<;<)X z5mUGCaG7&!m)O)Xd0&Tio0AikCRpZLOcSFbtAj)D4G1Xm53mLJrucg$8azyH=#A*` zs?x)dXxLy15`p;17)S~!wCO<15c5p*0BIz=ZI4#l6d zwRVJGvT)piKX>=Gk&#Yo<D@p4_21t8qz!)-3jM*i{8!4i`!~=3z@y!f zKY#r3=O29dcNE<3y?^6{pa1RIr~az_rS#qVpZSyK%HM&{ZTK^@Rx2pW0AQ)cNANxvu>A{Q9|U6bjw8;D=Jq z%(D|dU)(qso_txVUW)Lu#!4MS&Rce)GYpLxl4{C;I`UZl4 z_@KJG%qo)13R}bQE(a#ub86AZGs~uutLL}t9B7MN(6ZViq#tR>wQBaoRkN=wo6$0V zsY|n=)6HY5m!gJ?78fMFd*$XI!9E zQ*}NRTEcRKq6ZbQ)B?sf1)rO$a}E#8k-mh3@|Ym7eqiC&(S43A7;};4aVuxzc;_a- zAe8cN&?gT01Nmp=n0;;O ztS29v{FBEgT%1+Xcz=``&>jE{|yj*C;rS~ z$?%IfsMHFI+=n~2%)X^8cYQ@c`#EMEqrlD$-+0G089SWNrJcJG<`Vy3P?)@hnP?!Tp&NJ2q$JhKep5dS~HHfVqyL zcgLWf#}x;*4~#+n3?C5 zo(0;_gUC1f;iH!P^S*vL_@m(AsyHPclF|rsD~oneXpKeRG(xL=)bdOGSzcfUqZ|B! z(UW&~pH#3gBAT_hFD93rdwj-;$7V@r{7d}V@ncePXvLqk{IhbWh%CDCu{sbm6coEP zfqeP>Tr?30GYA^pH0K6eMxf1*ilWfGYFF~C*4f7)-}o|r<}D^Wl;<#5u(7Q0@RWg9 zADwyb(HUG!rvpSgt9lt-T3*xgz}Ou_du%AlA^*&Gftp?U^EX1!+!h+j^HeDo-Ke0n zV>^%L$`F{U3j3`H+F`v=?u*tP4p!JHNjO*MAE?Y@9tTY@4~@C^;+!EzCl-@i7XDnB zr-~hb&oJZzgY1~hKU{7~=Qdyj0d?Wk$ z82fmK-wk#)1b5M6d=1X^3e58IPxtmu@uHKUZ#x5q4eulmeVn__LIc58w?>4gXPCQZ zn1?>p!z`xxI3^-;T6EOh=%@!HBOZw|K5UL!6dSq7WPB{z zxE#T9cGg*2_ODNi~T62DA&;4agbW2>qne6N*$wFsmJ{27;NR}cKi;u#TusJ$@19}ShGq@52 zO=CW3JLu%k8iM{G#-G8?jsmAQB_^Is>2wjiZ_oX4LEZ~R`7ajay^MsJ>qdcdDY!0l zmj;fwEOPVSmTWoJW!rD^@?Hl))9o=W^|`FfA7^CzuwC-y_9<7ha-K`gdCU(e3@Wvu0BZ0vsF&zAj($%i|ooz1ddv*tdNm;ZBn{x8AZ>bdy6;(%0I z`b%jUzwDIucz@8TFj5zo z7h0wZtJH@N@`@PZ6E)07%R>8`NBKMR&z1=RlsI|t#!EL+M~hO4Oar2a^IhK2L+Na& zj~Hk$mg~YxDFYo3L;HyFBlK?HP}I;p{ldHZg?IG{EAR@LkGK8N39W|CW6+dVS(=Em8JX}-St+giZ!e^B#psGI=u4f4;(H=emFfcojH{~l|~@Ym^z z3o;I`oOc?oyJ7a(jnaq^+6*DoIsn#^e`Y&dTB}}LaV}Z;QYrone7;O6@~pvUhi#*k zKVRKgtIENp;m;dd8xfL!#>L@MjUtr`FbEXXS$rA>k+2)LvUU`D9)7{!w@DsxI28 zrHf%W2P-n0%QB9Zr5&xzI9zQ59PKS5Gn~;_N!l>;V0jjF+R2}hV6>Jn85jPXd8kb4 zV2KnU8vYC=-d2{q6_4x4?q});UR^%Q5;nj{hx@JCKLQrLAqPZ(%7CCle_B_dZRtxJ&Gt=dQ?=G#HdyyR;p3pd{ zcx#n?PX*3rIuE8EuF5=Ik-MiP=h*n-Cmx@28BaUoO>5>to`pKDKmkqab?nhu)rY4J zXc*P2dF)+BM|VFyvg?r{1wz`%NtV&1%wc#21xr;hFGCd2f}kt1@Wbz@%x0zoPpWoM zDN1e~QrfpD9Ib}TBp2P9y8P-DBm<>Poxr@2jeK4e>udxMZmaH$&icaQ$@E@C@k&UT zD?|R7fnztZg|V$S(oTJxN!2GY1Id7?!UHV>h)E#NJMk-o0rUlaq&asIEtex$3<(>So{o% z_o}5L%Py!hSZ5=To>{i=#N%_1EK$IAHscihn9e>rjqvlfvZC$1v-kGN2Ec-3 zcNA-IxHyGdG_Gb*8CMoGj_-SR!RV`?^2ZsEfIZg3qB+B3E9V|vHCH5uJgvEA*!KJHUDGFLV;_y^_D$Q{r_;gy>5avy^g0C05*tQXK~F#m>xDdf zamK#l%>522boSO_>xO=|&4YS0&l~~lFxLcE!j%q)PE*=a-7;vIO4p`%l4p zouO#wispirfH$vB)Eu%*ry%^K%D42-+fw<1LsJJ`TR!jHa)~kXLd2~t?H%Rku1K%* z$LhMGe#Gk6z_CsfQtS{9PS`uP-{t}NyZhxHEXh0AKZh>Byk+>Gnx+XmOR@--L!{x- zoU?ZFw}H}-XJ=%ZhK8h|cUKl7)H*Y35E%d5G8vJ<8$&VPbZJ!$?~%RZ`|y6*JU}AT zd*z;B8I$6VlctJX z=7}&Ih6RXXof6qdIc}~zO!au4sr?oC2g~!D%1~<9*_oS$(mQW2weK3-wRu|Uxw%6Q z4(r)i-T4r>SaW5_Qw)^aSDj09SWM26SRUG|W%e-ca*WD}SZ38+e#3?QBY{T?!yS+N zz`DBQk4@M=wQPHJ_lDAfBNbf^S9JkpBOT(*iC&+m%0E$&-&A7XUsbrFs@tTV*=b=u zB%87`Gn$W{diVXm{QIA7eDFS>IB0kNIk9I|d;kGHfArDk-xNW&e!Iw`|M=kzzFj-Q zXMg(m(?5Om$sgbU>z_aV;^Pm#_}~v;Ab)=K*PlN9#9yAg_P5s0FRHn@CT%9xLfxXU z_@A9mzUAdOU*Na%x@g36<*yXEAP#u-(%+xB_F2ox_r{N3?xy#4v$(|#4(PPd82hk) z?BnE_1Ct*KOXP?%~Pc`*p=}=Wn_TxA>nWbnZIKwY)W{{;OIIcFt zrGnz?f-SRy9917^#t}UyNR@JTIFNNKnogJ>Brk1#5GyQiR%?4ikrgY3)|{j9;3Q#2`)VS>lfLB^(tHJ0j3DG=OepxLy@@4(|<6($dad^i1l zFI^wd(cqu#>6_@`6Yu70ai_34V|GR6>|u0s5A%RIdxUs;hU%nP4|R7Baidsai!R*L zBUJM|w_<1iNH4H6%>;eJbpUElKX;j!FW6a2JG%vW=-cUitN}sYLPC3ohm{$_s*Pd8 z0CdLii7_!XX4AZ=h`CV_4_eGC+9hmAO4t$|xh^((Yp3J`Io8v;)|O5kkH%XL#Ktzl zffEy(I&?TjIu{z;q2tly4$VZPZT4rgtk1)o=_OZ~_dE2zdG=TH3tk2(CncXk8DX{@ z?38lWYP$|oHOG*ry^xpt)1tgzwNJht6?w!MeK0=hXmZM#NK;c`(JyV*U&X~fnVI#| zE}dV=%=l4q`%571X!BkQ6NM#V4_s7~5plaLmfcdZds#X%%nIScpTD=Id>}5TC+DxF zj+5IprKg?D&c0Yw_wssegD=Dm@d^IOQRY=Ib41+R22d^J7ohY9g#1^mVx(ir~E z_(X!xJ1DuZal16OFL+;8;&(`CwBKSmn2>n9WBZG!JS2&o`w{`>+`Qjp=e{a1+5QGp z*=Bp4C*|Do>~FHf{*8KtGqhUY$&q z-Y+;wPL-53;F|W7`K;T1nVRxUyTps}meVw&j58nM7m_@DlxdqWW`i+mtucCajA@;} z|Dvd5GNgM7h&F2Sb1ye{ zok(eTyWp@0_3%&d4o&xq%nLLY`2}~;1@-g{x>px)pGRnkS5QA)P=C+xa&L2$Kb2S= zoHR5nc6g9!Bp^C~28D6s1VP772#6c+Z{fZteM`j@Eo}5|bW4Oq2U-mXLqfCt!_tF7 zIt2R0db@?X%RrMR>n7cUA=AD`cB!Q9Rl5SJ|6lmox8vM@_TQ; z^U1sK{uh5veEi;xKfizDuOG4e)b%fo?|{U9o82z{2c4e$5%?jmy){@4eAbHC06jbS zTkgHzfBxnhH=cR&PoliIqIHYD^ItX2KX1O(75++;&V#qs)7SrO&$z$EmRO!c6#2rYx(l0XwbINO>*omp78ZSTsWIx=u1hC37Wllr=IX|}tDEbu zY?*y=bKNCbO7lTBUfQ z0#XG=W*^wHni}t%Ab-;kqD8e`kK?6SU=||t-&_b(`WG6wX-ijGIXf&Wb%_MYKXnH ztXgno)!decCc?3|RpfCfq$0euJtZA?m!!zcDbL*9KaGSNFbY95r7)>$k3v^dG~^lL zt;)IcSCZBLJ3A=D_N~kRJJ0^lKg(^w??2f1UGV2SJ>6}2@;BY+%AZ;Pr{S~X2u}Xo zW<@>Sk!m{>S|*ZL*&Bv-=M8w`ff39*IJ*WYT1!9|bcswDBmy19r{Uz!f}mH;r9i~M zXR^C=*26@^dsgu2>Ut(DaCagTdtzw~xxRBN>QQH0TRHbSN!|G)c8~0}g}`v7wW->6 zbYRBeigem_9jNMjYI=n<8C=0khgon)iW49hdH&I<4HNort}MWrv%TC3$vH64CaGyn z^?Xo+&w`+#M&vD9%ZZ>71Zn(POgoA{YqvE?S5mj(&mskKO!@zsD~@orhM+MEF|wxo zLhv{4Jlh9#IWV#K)*KhkbBZNNA&^e%+J=N_7T{_$Dx zXUH3@?!JpbUhD@$tlkKi1%c4-|M z;6saRn;)+|x|nQsJ-QF*^o7MUuRJ#8;=<8QlllXn*Y>5IqM+tB{8@RPd0ye(t&IYm zsM*P%+iXz?T9N15!e=P7#-AM>2^EV5L6e2v*@tv@_SU|+oBJ2+9bSBD&R7lR%MV(9 zYFdv)fzMjEL09bDX1$d{Yfg;i(x4EVbaUN^y~BEMA5gHbIQLM0`+@#B5Ou=OSgk0T zSk%g&HFAD?{wy50wMQW^nQviB!{BaoZ#*(*B--lBD`z3wVNS$}1;Y-`DBU`!^Ja!@ z`U9>-2oK`sNqG;dx9Y8LMkjD?v%+8yqd&?I&jcu*^k8Yu!2#Ch3Q-aPmhr~(C~w=Q zGTV_#>064ThljW`s5=SYLNh`5vlBtXpBr2GGdE1`GgzHz5y%cZstOrWX{jG_YRZ7d zLET6x(>IVAC^$D72HE#i*;o>RW^xMYWp+3|rS#mQ35-TD8;drh{Mz#lhAY< zPLK8?kmXj|xA@1;{p`ID{`38hKK=OLzmU%tAAI(oAAI_k52c7Jqx+-o#Gl#!cJ-+Q zlRo-HJw&ov+NMkA^iTdwruvVc{QHN0gFn;7=7T@nc<=W&Ui{^!PhC|LIop1kxYGxg zTR(LC<1PQYjst(b_BTp=CahojJE8HjC;l*Q!g4n+KlgaI#QQ^2ABc#1*bn|3|6pL! zgJBNftl2HZO`#QT3OKWX(*?eX^ZiKqlH+v-cLB&MSIkm6^l8cnBD>Cl@j42&?A)#q zW-`5yRf+XZk}RLZ`Nlz61*Dk9NXpkV%7=;>feqEiG~6daO|uAiWg<(b=3u`;#Gsw9i>rpg3XSA^!%X21;OzPg5l4W1wx@ogKNy$pX|4@ z5*GMVib88kO&-#UpyguLaSi=qYegKb;B(9*&GkAaAZB;~FDjbAb46fOiNCR*Z}`2; zruPc&ZV2kE^S2xPta{&cy-z2DH&N$AgHOB;gDXmBn6r138%3Cz7_&+{LzvNHI4T6x zED>lP(uE6`R;5>lXRvdWH)&_zaBoA9NH#R|1b2o&;dTx+7%YMQoq_^${Q`dw5L_G_ zRuvvTJR)qoF>Fdy_^c>neRSl!=%@!`q92Nme$*7b)DpX#Pju>ZqEm-s z9oipGN<2s|H`csIb^S|BIFQ`#kj6_JSm7bqGVm~|!xQw6%guQOs|LW(W_<~CY_c4q zpIs!;*|^Msl{nD28>kjRH zN|ZXs_A3I?(WWz|*k)`DgkuFkOAuFRb7EqH=pz(@hCkm74{JeU7r^`dV$m-ASz+_| zIPr%NMUJD3Vq9ZFLUXM7XhH&Je;x& zgPaMLm4x`64*slBeSy!kfQ;Km{u$uU(q!4muR*Mt&X4qhJkqY+>GZTG^6bCJEBtkC z-fQ@rvvS_dw9!>iursGB7Z|znq%-LTbuSQd57No%0Jk z;RK;`?62e%{5D^(`R_P+0J}pcVtb)e$1BisdMS!-#k5yq+wu6Zx5QZ1o8s4*;x@!s zHiSj2jxldePd}8Ialm9+5ga@}ENpgY*wm1)abaP@LPG`z3y3Za3hLt@AQU>l-$u_( zH}?oPw?OSJ1HJY1(0f90-9z2z_lI&hJm1&Y&6h@jL3il_?-3AmN74&obVZ0zpdb2a zW0fJI+z?ix5AUysLeroS3LSE{S8y-y;8qIF>6VPqZ46v`Pj+=Xq=V*(aT#KH_dh;XvLqMsQI=lDm(3b zE`^|3wq~J)MSq=gve`B(@Y^=MC7wM1JBRRRCsl5PpcP;J7k~ceIrE*4a3}VAr|sVsf4%FbKw@407E`QdqE&Mv9pTY$G5vlU26=9zLq z&<^UT*fJ>cEBQ0~AbB7mOzS#4734NAtf)V+VC4TdenhNtgxpMxA)eF>!2Ki^MjErln zm;;x?n0*>q$0O5@FC0&9nJ3yhu-m4Rob`P(HuX)z@&S3?PtRGN3*$%sOrC|HH4qs7 zOh{O%IbgOBV;%)TZ|s+~aexh&yl+%*`u8yk+49)*(~r;8g8FqbpT2JXhY?PG) zX$LQ}-dvX3T%N-m3I};Evq7o}OA~S?cP;$9LW-TyaX1|v{9UB|X(V!H0@B;ca`z4E zab{K}jR>1Z-i?$)ngfEGnP4(F5B|KrI``lp8p6s!_Ei=&4C^IbBbUwM4$1A5`zNXy zEYP$fl^+)G)@8H!3+>YCIp-gqe0*}nfk8bR;LlZsyW!8(Aav`ofp+rGM=E%VE-Onr z56DUic5@5zbg!8<N(y zs(+Sr(8Fe2E<#jsqM|h(Ajv&re{U+R*dWzcrjv)amJyudC^4yq7yE?ucU1TQpD>P7 z?kkz$fj&{dYMjYD^$1`1wplwR&Pt5R zs!WoZ0(Mc_x;x2d2|ovWAa~V+ox|KbNjrzSv4UsAH$vwhWeAM%4v6;h4fiqx>pcCC zY|vE==B!Bs+`>I|@!meE0si*zkRFlYeIg=CjgbSxqlQIBkBf+!92qe)Dsr|ddV$%r zD9-Yj$@FN9d9gWed8}o%*}OI`b_)`QjvbB=a&Fh|u-1)E%NUb=HSbg)*Am|#9_G0H z@d=GFF?)f@Va7wr9j|3se}Wu1GyNxd_80AT6wpst;*Zib&m7+%jqT#Z?n@6r5F!|v z?I|f&vNE4eZhtn)biin8h_M{b%=%%0{nvKe>(&g(zGhipOltphT*9UJ_|qK99M=Tv zCVDNx4f7t8$&u8R2=xCr{;W}G@hyvixj{qF4O&CMeHJsX?jYLdm>4Ou`7nL`(o(O} z=Mn9*J@*v}Lg&A!>6B$zkoS&+pB?#U!M2iu*5I@7XO%scyzyJCXJ-C7CG7=93T(MQ z%e6m`Z9B_$B|YnGN~fbqNzm^-4y3O|vKeKNXms2@!Tt(F$L+z+0jVY+jc}VC_$5h6 zJ>MziTE~>9Q__BFwZ1ARmJ9KI6Fd%Q766_r&JD~P`5A4%@Rbf1R26G6NQ( z3d#E&xo*CNCFjX$BNE|MGc#Y}nC;qMvm~81#~q5Y>@vk~wIpn_#O@HAcl^%SxNWiV zTg3#PuszzmJMuF^H6WbFcGc0e6bel! zS|R9gdw?-7C?Y2$BqJcGqrV|q$IV2>pa9VxqUFGn5u)=q>VizVuy{jM0ui)0>H35WN+%)?DpN~ATlMY9KjV2WG^9Er(1!G`hD@r+D>K(OH8mg}{_N{%DDG48 zZ}0s5H?RK3P5%7;jlX>4;Llp8ynpfMZ}SR#6@UH={`}7GZv60RdUkvt`SYk@_3-D^ z*vQR~%z{57%^-(-W&P|s@n;D|D;35q{MnT}JJ(y2%yWo6pWieG1PyaFx3jL4yvwGBZALc*atlI^lh2Oelm_fLz*bZ}6@LBQaHhZ?L znM1jL@153N`7;cMVvEz5p;pvB%-5!z{FzTQcO=iMPohisSx!$o`IBpA%fP{!nyag3 zwLCO(*XUlmM|9hDf8l}QMF&TAX&hd7U|8Y)q4|3T+jkALN|;&AZO6-@nKzJcG?iyH zmWTqHE%0Y88ZDV;4L*N~KSQ1Y(SU2>h;$p=Kj!WWkBoU@UHyf%a%BKn;4A)i6%Yn=Q8qnV<+zBG4zaT=*D7l|O5tXfnwIQUM^a_=}4GE*Fs#T0F#D+MO!NJ4~*->h|Cjf=VH>JshsA)5WR*b z?GgCgI>I#z_r=U2|Uy1Mqt;%VpS zk8B##dry^Q`6L)g)46X@E1K?!NKRC8w3Mg{8(gE-ZTPb=DE4nX+CN}i zt`G4-RL?a~o3e1wg%JMCk|uG2u*&IGXI)!tUD?;RzP#wb^lGxTs_meP7NdbxCRmou znu1u-Y4{<<`r*ZOOxd`!c*dFfp$$WSu&Fp3`nqj!4?G40bS0^~YW~Sbr|+0lv8JNS zqxWPkA5ge$WHEtZ($Rb)L<@Ya9a+p0np~n4L2Et@;G~m36OIKz-!}iuZfZNH-LzDM z6~Jvy;Orw)4^A#$Hz03IUn_}RTJJRskhm=P7Zgk$cx#^&F;tXV$sVukXWLZOb?4}Q zd#4OMv1rPv#k0W6Fi%p)2OqCF`1mXe9LG5`{>U!?&vh4^nohUd;?fdw#(oe9| z$}|K9gIM89_%mQxappEld248ovch{)-tsgtEVC1m-`vl>sehidaV*W-Fd&!T=dE(^ zoCBqHL>bWI0|TV)WN7K@7vFWbG>3v<1D{1qji;g{udy`0VSt_W9c6ht%ky`a zhQtq?Rj(^3#9jmiT9#!mDpRYk`p^u7MT z$kQ_`_7D5P&Wb$Y)pUSmYRSMH?pKY~BKKe;tyi~I6*i13Zh2@t(;4`?j@uo-@QxuT zMhZkYQ%{dhZhej%F#*X`>MNPFM&Vr9w_z?qSS}W9rH^?kuU{b*WfXDOwcVF7yuED!RD(B^;(0d57$VH!^k*Q}(FWG#%R54pz>e7BwuU{EhT zh*c;nee`~y5A1FT=%$B?ump@qbJ)FWPlU$F9MK=pkNsQ>m!ohUgJqQKP&}aGo(ff~INtH_^vD z*#`}XWvWO#;L;kJ_SLwwA6yz7Ek==gKb4eLz7FM!R;XF6t0mZ3$a7sF5o;5kYU0+@ z1L9CU!@V_v6gk=(k1Gz?h=D%gWx~=SMFgIMdKh@6hzZ6gJ4j%d>H_teC zPqT-6w7W;7ySvc?!-mY15B8wkDb1}R2wJUZTY%4=A<|gTyS047J^hS2fAr2qZ|_jO zK2Yc81zJ*RXPT&mySbbE{4)Xr@CsZ<{0x9xNdaJZe+XypDlY~&e(tx68B1jzj%ZU zyW!6gi$&N=wmGVSRBC+U*-q(C(0^U|$FJuLiUgv*Zp(QE1Wh>Bp7%4W^_i5E zOL(Wvv4_kM+PHljQ<)BbbLNO>4|9b>F}6CB;;cfcAMMnu(aF8ImnMbeurpSkg*WVj@`ph zNT-gc?YY-&Sr>T~rsxf^=GCUyB{AkjCes5^F>@j#YmE`p!;O=|jboVz0EG?-DG4|B zkBIDTH1-S+>k<@f*BjE@++y9`!ZlyImso7bLI;W-$G@G2(dHY`*+0CSe^7UC{~iYa z`}BeR4E_T=g9hkA%00se>ca=?B8KWBM(CqP8=}W}MUVBR0M6>REG&A0pG@%>OHx`8 zwDLlmhWRQZhZ^aV0lqRHV~HO(7Db_r_xgsRhQ7-ODTmy6xpQ`xTQ0ZOpdtfy=&%Bx z@B%+$fnS*2H_Ym1w1z;Ty<&CJZV@#!6xvfJMfgIYJ$$2dA+ZLdLePmGrgrY8PC849 z4iR($y$Dr1Lg2Ga--%v?`TCSXeVVfnaiD`%{JFiiDacLlr}HWsQ2pM&-T3t@e^&hY zkAD#V2K<@k#hN3cHKY5l6!f=r1-_C$(*^R~w{QIDhkwS*{5{M+&#PO*plO0JWaXTR zCpEps)lG9Rt*vdtpTWXxactE1v!c)}6%cj;=e8@G=U!^9t6Sz>**q7>OspCltx73A z9Q+wU$CqgH%`X+Nb{^b`pl>D2PTK7HkaOcr_zZ~t8vNP0Pn+Hdf)t4Ss%(-HsJEgX;(MR1FD0tj;@{CL_@B%5~swB3J1Ho zW)2Mp&pj}vVa$Eo2NscDBi_aYTa8ktfuO(4pQRt7ayaAA*wrs}2UEX^O;+V?E44B| zni;IUoNv2PQRr_g z|E!MVN}gGVgzO)bqe?^;l}seJ3xx(j(=BUox6?DLuP>Q?No#BhPi|aMi|`rehQoxj zQphvRP-eoV{y6?w0Zb#?eUXV%SiC`uIbW z8zxm^s94>vXk%rsqctPWJvNi%FlLEEq+wUhCr3>=__GF+Rob}?e+K!w@@Iv?6~J`x zXUxo+Vj9u(sRzb4O(oObWBq;HY;DqOuQ;1m4I?FNjE9+9E);sp04wR%jpV?G^gJ}Z z>g+?4g^e$*l_8AfbJf8K>ymgsjpmwejLW5W-mxXKDONa7v2ZM|JgVXXye*XG8@bN>X!tEXv1l@h{S5=VZYs9%MEoXmd6^i+ z|D;a-%s=71|?sZ^DubqQ?Y#Z2( zx6k&{{5>T?p*baP9SVH|pFz9iqE!&uiJ+m)&J;95RE*j27X{rh;Ln(u_m>wO7}EXx z>_Jx+jXpfNcq8b$(tfBapL3Scy($^$gB#=9r$^z|^1NL`dLEuW@WNx$F7kKXDw#sU zfYecKz5_p$i)$A0dya31hZrS4_rQdv@%?vJb*3Gm@aKVfM}`#P5}P1{UZKKlt?H4{p5wha0c_>hCg(^I!fAE&hEc{(PtHcglNTyZkBIXZW-9<++T1 zs7Jg?KGU5hEfV=p(_rN-uy0!cvmPpj|2q#@kOa$*^UGm&5MH7vX># zj+9+jgD~VmDOz9o=jr_DewC~D&(To`CB!L_W$?-J^vTpyz8O023>`~VKIxtqCn$8s zZ1Kx>_p!S9TitwZZUHuT|6Gp%yQiPsGZ0jZ(UeK$U3I}-J%hUGLVD;zd+EaO(S_Zo z3-7Hr_R&Z5HAM9DitO(l0hca8l&Uk9>6xw$okpOF-$UlG)75K)SIkInv4XThY2iE* z1sbChK~*j0YRu9|JT!xcl6Z)s1o63HIn2f!z- z%~j<}G8vzMA~+ooBv;Ai>6_{9-^oJ^&q?lHac%~)L?}HXgb=%hNx_-jnBLG@PX6o> z>_$PJbs_HFVV>UTox|PyB0K`4^+D0zK@ncQ!Fq$Ahljykb2|f-eB3-jJalFszm$-W zg7ENO5yoO;czJl(;P9|f;h~elLuW>W&5ev$5EV5)DrRAf>0z+5$-FeyveFX2Iz9nw z!Rpxfb>@Wi=J-uol+?kNmFz;f7tC?H=s*YSOGw(SSYLeN0ZBE-9*QwFM@Kg&C7(~v zcnVWQV!Lw@(M{1YO-b!fBzHJLIy$l4K_apMZBn%gY$lrbCB`*?4b6#rOqN6J92I>i zKJj>l^;$vE&vJ5J%**+0K@MqN6cexI*ng8>_(nm|>qVVk?b_wnox8l0oBLeHPUqt= zR9MJVHwbywWW^H4b%0!PSx9}a{2Q*Pq+xso^QFxnI5%#OLg<9Lxm=vQgplK~G4CRa z&Z97YqT^8Lh{(ps=p)h5r%a}c?UJ6&NPUs3EB?qhF9Bj-eRMce|`h62#pleGgUXk=i7I>&d`Gi(+g)JNPLeeb{8@b1~M2T ziHzA3Ye7riQdIEM{G8|7C!ID$Av58`w#1lLm}8fjElUacN0}ZW4$XTZB5Jk*(Zr#R z5yQhHhJ=P!gd0mEqDsTU`vnE}^z*iRd!~50#UioMV#M?)bocc2^fu}P+o4?c4K4C! z^ex~XgYUftue;p?i}iS+LrV0a6}nK3LK}zaBS(0ldX^DDgd5}hQ5Z>SMh>MjQZA#I z(f-`Jwbq1^pyqBSV}jhb%Y7N!GM4y;5AcoXOAk}uuzP(%?~yn(V|I+(L7^3hmQ;2Z zLuhAxSdlKgvp&4gJ1h?n9T=7q6rADbm+Zy;$1OnfL2G6Xe z(PKhu)$vW{uifeImT$WKwtp8reeEwRmo|F2`I>_Q9+-UpiH-BmuCIeXUtTA)8QAOe zZ)p4(pN39;LMgbJDgcptCdR%`X45u6~euBsYow^4rkpd?R@KY zSBA_abX6+q3~hF@XtmpIbJ4CxaAnSI&Xb(>#{ z);_th=Bf2FpIJNgxpmWjvTpiw%O^hl=*aUki;s-#3<3fy!>`n=c1#_Is+3AmOGj5_ z?W;=PTbTxhJ^*=c<=@qlXnpmi)w9m6n}hc7(5l(Z>lPedKOg=~ z=fRUJW?fx7`$_?`nSuU+oYi3&k}wfoZC3WP7oR}!rQjF(oUf*6*@Hd2d8TWqk2H2gwwupWzEfo zg9M>hG9_US*pPxh(_WBlDij*qFtI(xzb>q-d-9R-$0qdIT$R73JZBxqWx{=@=Tu*q zJ6PVrOjjpJIke}|Nu{UihO{gkedghDkmr+2r=DFQgH6oifIo|V0sk{yM_0|p2z`0+ zl*5zyZ`V4Aah?ojfuI$9h6TZ&i2_PrFy(Vr%T_v#AQ}sh5&_`?BK!<_7O2GlR+%_p zseh6`L(eGK8juY@2ZAQ~EMr*QtkC}S&jPF+0D|?)A%1yeTz{Gdij8@NpkUEEFPq=I zY~i6L^A9ZrN6*J=0fXWqb1AqWEzHw@XyX3KrQ54I6GMf|?Jq|EYu#L8Z=NyuJWB1A zbDJKk0oa~nMBu^6jgzalRNb|qq9^?M!eSI0VgNpf)>!j+d?WtchE+l)B^oWPOqx+* z=|B6(l*UPATdTSvWG49x4i)EfUulg8UnThrd?xd}qdXsNGAZJQ(S7JVczMZ8;IrUO z+74=NYAyxEs|L9@KQ-4f3WZF%O#x~Xu*)+Hd z#19<@2pTL*vpjkZQn&JF939kNIu%L_zYKm@u-vUEo%>_}nKu?^1Ih8FFcC%^9sQ-1 zA-GiwJY$o-Nr?qJxAJF&+!cb}qw(iEA!x;)UCFarcRjK*?aYbYi9e(Gz*E7ayZSP~ zVFP+^?UTjm1`+ffBknsqdn7Iq-kx$jm)&fq==#%C>+EoAakUvyI!;f<#WiTJjxL(G zXHqFvLGc4c6w6;p#`_x0CmfTr~*&EeQT3M{0(W*xx&{_l~OWTL+l&o43DbtXq6#aB8iQMu8ZfQ4NDnO_Kwn zCkSwk8torB(m!HEK-B&Im>-z9Ed_(Eb`Vh~vJl4wItb`!Z!KVak0GQNyg~=EAhhhr z&MBKHklAjKvgswbo9&4;LMp?d3z7?mUZMmWRJp3N#&<;}K-{2+7w47kY*i z=|a0mg>==2cGrjez!2I~A99zTrhcLK>S@$v>?1Z0QGbBeQG$>gtn!As18~4NGO>NQ z;9?;>AbQPTE#zl{T+f)v%1?r#mkovy?|^D!gHb8yL-obcw0OSCJ#fjn?6!{1&T(427(%4CQj)VB%w-{9uylx zG|2`_GS8tNhA>ZGqn?(60g+w=o_#_LhCrQ%H}FX3<}TRTU78feA`J)($O#MS77^Av z%2*Z^J~%?tJ4b|1HHOz1!{5FyN)f%9Z$9Ecq}2Qkpn`W(KVn-fH^0Usx|G7kJ%&f+N6C6$%p7m zXf!qwfzGx*VYNSni#R>)XUI1YN)VuhK-%-(plrFX5`?zdere7ASyuLQnVHu+rkt}R z9E^$)dBvCbvolNly@Jne&dP;93pUpXGg)p*Ky>V0u2^!?uB3$R@s_Qzv0E&$+vH`& zH^BU(W6+NfDZkXQ)3aHbzqH$b>*zvA-k8uh2wLFtziA~1njo?0p!0;}(|?e5gqrE% z)r`z%+C# z2yAO=>o@Z9-z?0>W&KJ{_D@nfJ&}}f)*RbR9-F{3<0Ixcl;Hb#7418;*zG^EWj)ua z{Z(_+k(j8)g!ltox@gmyxWo-+^Xiz`)h5#_aCD4mi4#PJN7O__&Opr(N+R0GG=Z_k zs8JEd`(vU8MTYeY4(R5i&(yimrjVhdAQ|oe=)%P=xQWRRmN8Hk7 za!R!?w=$-s0HWz5rnoFq69=6Vmo-nr+6iTpws9@ z=+WNl-XYI3l`7DsX$6Q*D=?%MdZiWkr04pjB)a0;z?J^qQc!n$3**Ku%{%=4}M z`O4b4k}+O8_tLt#Tm*i;=Qh@#+f;XY-OO|AW?WuB>#0q3Kio9?sWme$J~F0d?x54t ziyMa*ZLi4MK_8!rTt12l(XFsScejnF))XMv*u*E_4M zo62pw$J}-Lp%G;1xm-tA&py0%Zu7c%$Eej3q`ZV2WAT&|wFB`hLZA5jPPR~{&ojMU zGpxdv!OpH)3|Ib4$19moUrtCYoz_$!=-o6EEEgQTy)Zyij)&Is}(1OR$sPyKg9U4U*pgJLeSrCruv)m;jgp*o%V6v zek*fUkKVfdA8&DG%U@^xJLS(3fv&RRe?B;fEOZWq4qB*qrTu7Seq&i46XY95-Ax<2 zE2wzZ*3p^t@S538tLrHhgr+qibH)+lz?{X_PA!)vgS>-)iiG+u&8$2+q>IQ-2j+8s z*fXf0apVuEodXML#JZyhRuz@z+)J znwHhTIZrR2b#BR&!!s+kSCUs0dd!%YOlhyQF{*V)DZuZl}~>HH&07c?!N*Sr||G*9BbOX`Rg6G1<}blRzh#_S%0@wjMne`&|o z*gw0WFX7&-?PYnpM)g5le16q@R29f$@l>=dnSJ`fX?w?&ZyR2GV&24yuq;3>S8_?6 z@^28ghCRZ#z>Ln4Mug&pzPVkkyAn(FEns1^0EE&{Et_^~(fC8tE8%;P+nvQ$v>Py3 zpf2#4XfaV_v>3>i2^g>Go4u)`^TCOw7ay8*b!jd5{p8~_In=3Dh)3q)1`$~?QD^uz z4UQ2(gPNBLf9A^*E2PmO1(t7GEFuxSA9$fjN}pLhm(G}{m(4s-GjP|ayND~(84&i% zMF!Cy=$8fj-^FcTQ*#i3hCE}67FqOwES7uvra_^xLo1l<-E(N=4fz61GxNfxh2 zl{h^Jv-`A$o9Tja?Sf@ z;ey^)oQ39PLs{XjG5wD&7ze{dCfu|{V)p!SU4N8q*458iE!D3CKLUQE4lS-ZOuijQ z@k0~#jqAUytY}AZ4iR^rR{(fPHl+wNOJ}LKfLf|+rTDYTLbIfJgQ$0qD_E9|ym8bB zj^^v&P0C*s^g49Br_?*E^?TdA2VK7eBNMB}?6GA?k9||iPAnXayXNYOy35OIudJ9& zI)7}##BxI8TdO*6uPngJ!9)gR(cA+e&o}uqkh!(UFr(3+XDfFMIvZjH z!p?z|qq)3*{5BH%mW9L4EgID@sqe1AT~TdtC@jtNSCv~xX_Gv?kMgNktV zH`4L2JfEJe>jvZw%QB&%M5{P@_}I68`yL{c#~;bZy1#t%h14HE2NZw& z$1kWmeUPCU`fZEv)xP};j>a)Lg0|b|0-rzng!K>K|Kg+fZoKuTHih$vzdUvQlc%nJ zc58i8ZhY$z)RzBc$NB8~1=tygAv9x%ud&)ctkN&M%rC5zXq=C^gpI zVD|JfdkRyfabB#RGMIIGlcyo(OQnzYaF*jCzQy835eBBbf0jfsHFLCPv*rngWUnYuo}S1wVRUqpqbXddWKCY&CKg6@a=8WEC=^re)gL@iZbQElgf z8`*8RKbKwlCl2(Df(2o#?&pJ$1ndJ3m*h6*W7YX;*HA7XFUsPfkMg8NARPlm;2h#E zk>(&bPhgF(9@GdirVIkLiJ91zbr$)Mn*mN_9| zU%P|@iI)A6sx|LR!tfB=z|*B>oTKxg$#jh1bZ*{{JEmQ*#GlU0cp*RcjXapM?Kcoe zn$ST|v$J0>EO?vLZc^gYv2hpT6Iznmod$qg5*i5x!^6pDJMzyO1$BgOex=X&7vd z?Pqy;FDnZ)fnhYuH2af6@_ds&|C>ahbAJcG&$YjrmHiTxlk=)v-rV1GE_yjF?V8Ed z91$rx?zniO%aR*c{tZd0L%d!1vmj`RI`4osCnoGkjNhv&DSp3-wF@>U0!@fIp^>J9 z9os*jmh!41i+wn<9J9KJEPru49WSr%+Ddu=eT^ zK}a~47o|)>@^-TsvCL+ZX%p{)81q`*7cnu*qhl5uBOi_+5goHIGKL8Pb0VVZ!Xjpb z8K;Ctjg5>M9TPn&I%05CNWT!@F5Ye(-P}~0LQTrSf}x^#H~%b;umUgQ(BWNuB6|8p z-0jCrSmu=gqD#HPs(eES`h^eni?}}^YItDG$e`F!!Ni`4LnGyI+BwA0(W>8%8X==* z%weHKl%#=Z?mUcnMKa2!-S9*EIR+Mk@AXn3T1Mr1>B4$=hV^t0=_wOQg1dQ9fe50D zyu%9pq0r&BK;J~^dFn|PS|=3R$K4~)!#fnOk4H$1E+Wy(lN zkMttXj3Q4EG$2}B(D3Jc@3h>2PKjQT=&_A~VY8;qedD#i{_4d)Ir#H?Uwqt}fBqML zzSG}k|IGHUt_^vCh&+;YsEN8f3juSFF)6UK< zx2~L{W#R4Ww!I6_uEBR&e?eHbM;%sS zXIa-|&ZpPRrkntrl`k{rFEwGjux|F%b@LQ_zO;Vc+4Zwet*bk=q5k-~no}ERpISfb z{Ki^-+~-$JZJvMsjtPA>4(q;uOwR)&yX_g;W!JDSyNCZ^*T^2K_KoVbcVu@SY97(0 zc_^QfG8!vVn=3PvbHi!gfIsim`158y){VP|&uiD$)o>cB6XNl;b55+NJ-f2@(yE&C zk56ivQA)Q#a%hmE{bgBT=f(jU4FiPq@}T{wo1rF;w|Q`f@s@yQ2fRBjvGd2>nTu99>_)()QB>e*<6qaFNN zBhUZh&)+V2R!4JX!mjIgqQ0*CxUReI@4Ed?>(2dw#%f*d>D>O`Soy!npPL8acDA?4 zKf|AoROdDi$~`y`ifbhc4Ty$6H&xn>RN9XZ>ddrpCW#-NI^g`nV|dq}U0Xx*Q^tl+ zaInO}adcIkLeNaaAoC26q-6MJMg5t_W}KNn_SndKm_!ftJvOKiqDvl_IpeUGEtPo< zWA8mOyZY>-ljt-GY9{ZBY6HkD{Z&`g3ea9PpXes|3;ui3AOW7KSCxgcmJQ~Z z7*q?mhTI;WGi}ekcW#?B^w1-dk#FpJWD@)t&KWN8u?5es5WUpwcLo+NpIs6qKr!2&iY*0!SO@NM}qmN)0s? zD+hO`s~~I^B)henq{Ib=Yy5ewrr=QgSvnPV&t-jUuL3Ca=I&D79)-%+p*@RDsHA%r z;BH#eJx6xd;3tMxiE)K1P755PSETvtL7O;G&g5w*ud-=1EIk#T9gg?W6 zNjrVK=YpRiY3yr>C8jyw;ajYXq&<*#{P_maK@QM*G~!2ZX4zMx;4^ zKBwGdH|_=8#yXG{mWD+rnvgf01J<)CIhl%mk^XY|XQ`6imE zR+T~5NnFF9NkOl#Y`<@E{}Z!DGo@?o&}%jfXxBKP10VSv!mC|~ps{D5&Sq3@2g7jX zWm~G4X)?HJ_9VvLm{XwmGuQv!ZH0D0XYfy_E$a?IDJSRuPBW%QHMfGREUz^WAO^H|bB&(}mxt;;e_ z62B7qjrW$ptR2(r_cb(a^OuLP>v-tk#DI`Q|B&Q>uoVBW)PS(mz|b^9c$y(BBajNs zG=#M^gk%Rwg2IapVP%0l@$im85uJh|($UvRo3NNJp>1vs ziR~6DO%Ho&Guiuw$Cro44+xE|3`S1ERYiXthXK3w600-YE5hO`!{P@>nfr#Bdkf?j z750sE0SlB4gQbB{9z%pvAD+W`>O)iXTt*Om5b!z95YQ%2PjkSifWW8#eWWlSfO8=8 z)uVKJKr|KMy=jQn1;_Y>#QKNE>BC}!Lt)HOp+OPh0byY}KjgEa#G|=`-g`NL$<(YwS2%T#eN@!)|`iW|?WRJYu%YHe2SJtn&$fS`(JrVa{Y| z9a^`(BoX#fU|X>|Xl(>Dvi3V&%?0_V(^HQ^@RE}bXJwtp&OV-&z7Oj!F=I$_V(LbF z(mG(Z)xME{G%^HF;j1Hks{>7HgeN^wcfM6IKrhJ3ZC^Sb1e)yb)=a4aV#tmo>{jxZ&0Us}phSHaVzC9ibs@NOwM z*KG(k;=kO+wVPhD>bC$UKmjcgE#>8TAL_2%h3Mi%MTB zYWJGE_?7&^7qatynVbKj)Aa^=XNfu!c-Bg^8y*>J;9jbbb%-h2iI?LyWrhEz#PzGP zg7?}NzSqJ1PJ7Smgq+h-583RDnC!~QYbq)GS$;vY!?DL~-hmSaS2i(z()*GpXKX?n zo`6N$9qVk4)v#zNwB5FpZkxVDw8i$Q$vQLM{Gicvf4ueH7;AN$ZBm?hg3&nEVjN{R z4K}su9v#{~M4uC&vuj!CU~%Bk;4fCEx9ei_La;6y%OcF3BF)!@#orjJ#i4^^dWXjJ z4UOq9gNCNT;g+Eh)?w0i5ZY`Wg_pxus`qOMGc~jhu!5jfd3F7W`m2IX{iW9-0;M*+ zgF(>zUm%7ah24UpZwZw7Ah#G|Z^qK^A9aHtqht7#Fhz@IzjIK`HDNfbrU&kM?A^Ei@zM*QefYuOB>&vPpRss-`ui`ae}}dHbl=Ob0Q_0o_yw&x zzMg*;wHg~q6ny-VOkR8H?B9Qc{Q2mi3kl|eNPTFxcCOvT)mBbBzO1@gqs>~(xYo;` z$tSZ>g_*C!pA{=^oqT5f?8=&_S5A6n*`3GktJpTOQ~k)!XYU*I{E~6cEE)ggs_N!d zC^%|B&_t~9KQ}*4X<_M><9}EFd^v5te9IN#GaE1G&%kHJpH&1J%&XkdAY8Sgz^|ZS zjTHlmDRdcEM9^2rEo=7@6LKrDv*OR{2ry@LOa-D3FP%nR0-vwKpP})9U$Ao%$!8Gy zvgrqx)Nt~LSI*eSQ&=(mz%uO#F0DB@dtCiJw{DtLv29|%-8KD>-#h5!L&J|gI2?L> z{L#_JXWeml<_OZ!r)G{g^Wd##rdJ-htIN(oMLYZF?XD;g1YO~!(Ax(%>nfa^D_rEC z*Am6Nqs#FJZ+l|Nq|-|#)BW)1;+i9isv*zK^Clg8X!MQ={niiZw5l&aqW~01H^Z&H zbLkAYt&i|$;?3Y4e#w3le`X(e^;WHXTy#sn{Iz{@Hk9YnzK|ce5G{J59iBe?#N3HA zK-|A*@}Bt<_B}dwXKlsCTd$ER#?1dEFQm@O`z(!rhT$96w(@6e`scZ(){ zVePR+5>W>C(P2;!^uk)cc|?-4K%~vgA}3h5`~I;TZtqQ(Polrj>^=R9cVdPwNB{2G zGN_F4seLmBAD=s(NVCMJ7vH;=>@HKzwf=^JvWZg9pHAVFK=iR^(KOZ2@X&%uM<2Uu z-?YJ7M|J@nGlc=QdwoS=V})C^^Zg1CYY>Fy{Q0n>+#zjP&un)T9DNHR&wR$$R<+~f zymjP_b+_MCH~L0~$<|gBOEw#b1b^0=5`wS21iQ7zqor?}if&%M6av<#h}LE-RfD## z_?u?=P-A4`6X;V&S2bh~v<{@b-I=-7XXe))e{?c=;N!EWQ77h1Ju$oHz&)eu#`WJm zw)f6)z3IBR0`lD34S(aiPQLMa=kbjM;KdQKtX~NlfnyKju@{#Gw3d)C*AsaH<^(Jj zs48TmMt6aV`{rnE2U|gA(v=!!oDSe61x>Z)&k{@4!qUKDu`$euVNJ*CQ3@0ckRvjo66g5zoXy&8MmL9Q{5!IU7XJxkc0Ek zzVh);AAD9URAsXjA>TdsUbUi@1feO(e$$|K_BfgnZo0J#8j3Yt3y1_mWmUGB{Bvvm zEXik;d4@Anny{L5I;AMI`m0h#tL!xVnF2mj0AxYyJzYe*F+!^XdP^o*6)alnTastB z+tv7UYZlEq4^7WOGUEN>q95HWnydK^banlx*Nk33&x#RsA}!kRus z%V{h)sp1fmrxsN2UCf)jhPS$W+bj^G+qgj9c)W8C&Y5z2Zq43%M{J+iZ|$(_SJ6z6 zNfxwWrTJh#tn%LC>&sg$O$l4KBP9PU@}K^EpOkFA?Ye{a4&`4&b>sRlH2_Myt6w`@ z&D>p$!ELHQ#8JW+p9Gi(blf_$%dROyX++43lE!&j7ed@SbMK)TI8a6oL>&C};6iEY zy8oV`8>>2T$GQQXH&k6W<;MJCb5OWWmz9ybd40pDAOD@767XjN$pn@E!0(PvF8=A0 ze^IKlkN4NdckXK=lQcP$G#{kAcmIO$Gr4HE^e4Z)_}gD!eEFr%&!73zxzm3KlYSE- z{%QMnzXD&JI!^NW;`x*R9vv_v{E;}TESyV2j>h(aZVR^uc!W)%uWxz>q`(6`UL> z1>jB7o(s->pV(l#v0Kgb>wnh_D{iHW%;F0QLFuD5g*jJwqwf2TQqqSaVy zHQsACKIkyba#-frE%WTQg%niHmateeY&`BrUg1buP4_^%eLZ3afTxC?fzO*!3WMo@ zb;(Kl3-Zo&Z2xlS4zCxvp3lxamz_n(_UVj_qhMau>`!2F%4Sl{v?feW*`1krtO)G} zy5{0H%ZlGEE&i3;^$wh~sN{t_*XhKRoz{fS_TS$N;rV3LQrk;7RDD8t(EJEXG6KE zkv}^&B-%HjPa(T5Vrs2tBB^-ZLI_*H&W^-gpkOrM*in$Nv~Tx1uT*I%;{|WfJF=wg zrJ{B(<`q1hlzz%+IbyUN&B%PVq~vXK&WtYr&v8N1e6Yy%E00Uk&a^4~s$AlWE_S_F z;(o6~(L3!tZC2!EWyVBrQ>lG{Gan}U5=@4S<7-j7c8}E*0bkC1KH&4PK zT}(sxnhyvw2F9S{NDE5PM9^s(q#aA9A9{QWNn;evryj@B zjO|(YGjRCiO0UvcWEv}LuTUb;s5!lQ>X|j%u?CYf>*rTaerEaD6ZiGrbw|g>+e&r~ zE88=&(}^j)pP6_2GmlSvVpa9YRW-*}Og_4NGKW3CavIgVa_XroRSSz20d?yl|NNcm z*m5z4_?jnjQyRS3#U*(>BC%4twEu0Mcwo**?ITUX}gw8-LrTqz=z!gGB2KTV3G7jBsaKcaV^K> z;EFRdlf5;6Zb?21JQq~H49F}V60q~h$EQ>3%E)Oit|t6^c=-$tMX_>}LXN$7Doy&Z zupVDnO)s$KMKx!aR-aik;q>B3XP42ha5B}rw3eGsEvx<6qKRi`-gaPo_l6;50HPiJ z3qa5f<+=3(a(7e~G*&t5D+}PyTU!wH{&C%&m^Jd5h2zi7yZh8*V~#yK29$mL-VysI zlyAWnTUiEtUe(L%^nmyJdJB4aFCD(LAG7?Pg*%DuxmC4h!agsDpyP6R#~YeN{!&&dRU&vqI2dTU^knO-cF@72YzmW5bxPyC;<&zkgKI z%(2b0Cp0gp=1YL@G`=hND%-uNhT{82EE!Pf`L(-ej@w={bPFN9%3{DT!N0v#WfVLI z3&-xs{SM6<&6mmkg*7l|63*Ba&@3Q)-p7}rQh8|n88?OE&(imBk<8{ewqWw1N5<@~ zt=ciR+oq}#fH{#u2Bf6D-~cxzrX9@-jm(*TqXe57T@qYe)qeBv8yd#<#VB%Y=1A)J z!y^vQ7_{@Qu4JJ%_b-A!^XXQ)=I_Cuc?k5*+cf?xAi7o0HSn6ReCQ1RysCdG(=PT- zs6YUVlH%;_$>-+OoSZfB#LRK~rw-qGdrxVES6;HNqKw)4@+>sQ2;jvd#Ec9)_N)37 ztnA}l($j^^gt4>#!}ZwhfrnbAMDRtYO$kCH2%BN1x=F9l`#Cmq^p+{?W)C}7&E5EXij`Cda`b4g3@z2nkOOLGwU9{>ii8R5@X_r8RKYL?xO{LPO;+bL=JZ z)aKUUP(nt%XY!!!x81U~Ps!SDf;6=#vIclt<)7it3L`6?%svW1%d&+_dr>pu4luH> zeW4FN_bL$htVO#?ceh5+LZQEzKNJ1EVzu1m+fr!wGj$1n20@ee=CZHs>3O`oJr<5V z_uK)3Ch;pT{rnl4>_x7syzUx>{wDt1Fn2nhaQ5W2Adt^n>)`C_Ll2Kbo4j#Im(|^i zHuo&5qlX{~d?X~T`13bm=dW$oyzAQkYsA6s{ap0+Fm}T;;!?=-q8%Y~3dlV7rd6o; zI=)RQ1kL}=F=?zDblu+Rx8Y9TJ+HcP;S@v`@@AVoji*M{&u2vjFBnoeGN@k4i z4I{eH_YgHSu4WFkWk3<%iW>)b5J5LqmI<&9N2lLV*I>8`uB>yuCX5=zXEIDX3g z@w1EMpMOyP%Pl;knPxp86AZ;-C2Q6@N*6-;G}oem>VM z{8{-o;Lmh;T)+BU+uZg50b{4gwj(Xcceau6^U!c3tpj@nL!KjVG=yJgi0EX1tkMdQ zc(WLrU4ej5E#9mThR0?F3Ybm9q!9qHMa4|C7$XGs3{ht&+HCZL36o@&iVeUKA({w+ zd@){<3{S>OERG0ihvy#{Mn9G&2Q{m2KX4Y)>AJ4X>qK-J~ohe zupvH(3Ni)ToI#eGT=w}Gj+|EQQx$Z_oXli(*GpbElbj)@1L^H-$ znBs3U#gDcc$D2(x7Sjx~>3*x}VY_*@-7?={S>&)Sb=V$HbgXnFJf4`eGAVggV(Mxt zA!U^`7IbW|TGrdqF9U3)ecP6V#BHK_w$_`Cjdsia%(T-Q5Pq}F{d!@+i_U^ycs$Rw z%{qnYB0YT%eg^JE$2Zl7E-UjueqJ*H+Ct~^r6q6S%8+(}?sr|T*9x4^Jr+k}amgzn z=(c%h&Gvn5v!5y|daI=HeUIz?tjrfuQ=iVvc-rNDuC(lzZqNC&jJ+l+eepJlf1{N} z8U8FS{C*6~x%D}GGk^BQj3xQpQg}{Gj~Nj|z2EiEkMSsD&*MW2$2HAU-An3$jqC?ss78=%!u z??~R8p4pU{eb!m{3wQC$F6T?`LQE_#78SpYk0m?riG1hzT<3XI;kLwsM)Q8FqbVov zm&mAHg>O2YZ%W#^@IAC4#V)V5+U@?emp}7#-0$b+zMhf6Tk+>PZJ%aXBs0A!Bkg!W z?o%b6=gUe6$v>Hybu=+$mo2f*L^3~dqqU{9_qisf)~wpTYpZ}iEfgt5q50G#IF?fm z`!bb_Hrp1MghD@TwBH|Zn;vhSVlq!Qn#Nl#V=VE5jWIpiM0SV_%@5Hh`|HG&C0S^^ z&{6bM3v81W9Onu(whOmj8zDxHn?mq58$rWweVrHg4op5Gc94nx;0-piJ$TT!Kd?om-(Po%)^QtMTpwQIW^kX)Ts)PPl1N4G}(|%|YxI z%clz~*2wdbr8D5kD)#IH&X=rc{CR5Q(kXkEh@k@POcLe@aYPMw?_WHH5?ri7X-K%{ z0FjeXrTDXUl2a6FW*ruNY)LH$nigYnlXHH2+L0C0S;|w;bgbMFs7@rfX~{I~BC0{5 zXgZcnrAOiMB{e)d>i8nbEuURF<;;@F=NC*ke&4XhvE4QgYR9x$0MU*Cg*&U*5UwjWLpsh{}se;Qo> zFOp~V&^|u=@2@Dre92NB*0<5enOm={Sq zPKP!FpD*XnSU%vWfET{vxYyD7lMX+6*O3QD?7p*W!>#T4hG7bW1PjZhAt`Z6RIym- z#jsjgB8H8A2vj*tW1}wjk43#g|(}hpo4D*>iU}-5x1$ zbmN%bn}*)FvR^5=VpPTiiQ%7ozoCq%BmCS;j1USwuj=b$V2&Pn^mA+&-SgP}W18nr zBR9Td&Xl^jQ|jkWrI^mIa-MKD2qZK5aeb%~{!H>&+edb5#h(?0R_qt{B}Kq^!E`Vt zVbQ%0P1rQH|H|H_WPLYu1K5hNSFmlbe9nzrD@kLt39EWTK?~RPF5WrpmZQ}}PR*{N z4WgK+iDYY@XF;GX#k$6ywe+=?&;}`U&Mn&&nwGz|F0$Of=e@IqKVwwj%>&>{;UQCxWWf#6MmNW6_Isu>^wH9VSLrv0iDH4;TQ%xWFVtO77(4`JBik=8Bec(K2z=Cs=TBiIg>g4|jkGxnz9k=I zC_3MSjI*41Wc;aVw{IHUZBF_1{Y%oK19ZUw`k_N^|J8?|!k_6L`1_Ck_18a0rbzK; z?T3jLU?#)--~33q+E19v`LlSTKmC$k>d2qpf9K+}PyfC7#GlXn6n_4Jd&f)v!Lz3> zGBH;A51y2thx|y~vF*h!Hw;9|iK{bxs3l=!8|Z{%Pz2FjdI&~duMh8}4{a~uUdcJ< zgFpklGL5VNdfpk*`~p+_^hy4P!~mhqc44-9WEy6_0F%yNQ(@rH0Fct*E{JNQC(P_+ z%bJB)35szPi>4S~Lv^u|qG(ZOtQ%dDW1t(>&E; zkPfBNbjl-5i^H&7T{xW$3;ZHnv^CU4cy!^#x``Y^Y2W|Vk2-53Gjs?VT`JsbT*_#7jQT^FNu2o&BfU>^>T z;Tg|!Sez~_);}D?6KjyPb7YX0Jj+b}2%R6f@WjxNwvmy=v9Z^hOg&8I{wC89lWCO6 zc$djoZH~XkVtNq62D$*7eU8mBU-}6;mJ2{jSe=--hDu6Wi?<;qbzMrzdRB1u;&4b! z*$$WmBqk?q^Ch3HHdGjgk`s@mCNyWIJzbdpa+&At_7Y~k00fqnf(1_%6p)2J0zC%m zQfaC6DX9$^>H9L$kEEqErKX%NEqN2{>~e}LgT!)b+S$aU!>O5vQ`7g5K}|{lT>DzZ z5m(-Uw>dTSNI~1@%G~diq9gXa(XRL{m-FZ8ZI9TKc9#?rsD3#yb$`5NJIBe-f3CFf z?Xu$cz>jwO37hpWNolwHXJzf5b{3uhq03om{8pUn%3ki+e61SM`TM%(08*%16&+Ag=`LML`!!q};hzd(!xafUP$$K>Q zgF?I9n4jNAVc{u!j{-Z>h)|#|bQ=GLWQ;GAwSPM;?YzmjKhbeGC+oZ?|E2atZ+33? zMp5Cj85xJ^HOXLsC6NY{>)`oB$_4CedKOLwk#cHc9q#S~>*hrJ_N2td#Kb*`DF>3% zkAt1F@}6{he(5QBrL4nSp3>Jc+diAo_9+Gw^77ATWgX|GOigFc1CE5B6FyQBvpTy^@pjinH*YLOKtMwptn{a^~FRNl6vGgSi@A?ib(J-#ozIR2g6z6dX4&$T%>F zC822Jpis-;Fx5{M?Xxsay*1pfOdV=@Tc~w-Fmqu9O%Dsj3vC<}hSS4X5iS(EZ@2`Z zdxk=x+jI+MzDE2lA#pbgg>G|`UMoY?O)`9mk|_FyU?_CljS-fcVlCIl#&ige_Jm^O zV4{i)dk5g%Z_}sL7@}b8@)Zcy0j?u-9BRs;Nhm|x8an}tg**3iW?&{tLXAU{FcswF# z;?`$0{(SoJ@1B2FNcrDbdik>!9##?J))X2xA~p<`K;UIlfY0FB=B3rmizc34Fo8O? zVA9FO)ocV!gP;`|hV&j;CShjMeJaeXwqLS@IqzLoyL(yfe!|JirofGlE#~;JUpn;F zsJJ!9l%s)Yy!@H;wd_nO@~oD`umR4;m(@~DWW1NvLXuh8yLi&U6;qF{6!|m96eGvd z>0sxRT2n%pGj(#=3{}UM&j3?%GEi$S0<8njEuC_H(WKL}#vH1ts2|mZRN>lwZhmLs zTc&7swqu~HVPHXhRlZbZ!S3%8aGrFt)-!1IX}{!G8LNCpQdJo zGO_2nzPU91V}%m&g(kT0Qs~RF$FwP=1WkWkogpb`5oHKAfj>9&Eo|)TL@3Px*Oce4 z8CJG^a?eALjyksBZa~?YB~$2@b?n~J2gdZ;Uey6g08`?p=%!w|8++zlil8+H4hHv; z@c%TG{jSHqdia^Ye%Ay3kL~}T=Fi|?^$<8WeA*4)#>){jp!gCHefd6@?9lqAk28PM zN^8#iP3x`UGyAl@dG&Sp^DYz|m9o_Ma}n^lb=40n-d)c8dZOFi{lIMp=8VM-ePHqA-3umyh-IW~VJ%-}hZm0D_wb1NN&PkszhUFR zj%)fBudV1n7t!YV6Z!69-Urjk#kMhb>XF$~Pt2VG;8OfqmaO~y8(Joio#EB;1d>#D?RmZf;mx?N1zErqOQqW)L&yY7C ze-<|WRTZx7jey!iP!mb)I%fS>wqIA(VRd=Q%3khOy%1bWdR){5nx+{3EY{+l!g%4& zi0f4`JO`#;+rQneyUUM1eD|?=Q-~Hr+ZyIc;FAJdAshhYN&*&p^Vj(^MgriofxsdGCNfQz$!YuH&v*1&-?u$^Zww3+-_rEvlaMfd`g)6-0w5{;ymt|9 zf#bEeo_%B@+6~C_-nnvmur=T|^iPmrD=D#hXqYD}SLe@Oi-<<5HU2Ce4CzP+Wj#8( zy6KT|jd%B7QC@~0n~1VP(2{5VT8!E2ZEj7WFM+`P$yW+N3y#*z8)~~mpj-SKKKQJ1 z(U%;`ck_zynT@_3zU@kj=tDc;R}pmb&yxD??FPRu>F!xQ@VZ?S2OXU`PDC7Y$uPtJ zrK_V5d!!uS%%2$=z{suf=dbQ1qeVD#X5QU!cg5=Rj;p#6S1#Vvw}c4v<^Bz|D9f8c8%?K z^3e%&b7-7BiCF;Zy}fS^UW%fPpM z{5AfpC^WeEiu@VvJem$4e`a>WhN=$xCs&+#Y}~O2M%Rz(xqd(=RL=~<)m4=Vg4Xym zjw6wK5P_~}x1qA*mfO1{azCndd*thmu^~PhY7B@a>wHcbQKJ3pzInBb=A3_Q>YnOR zv#Ppx%(8?8=;GqyYNtN%@kf90@#jB%?3HhP9X|iS{2BQ(xcd(uUHs(#T)go5#iyS5 zJ9gr8r@#EZLEj(O#Lpkivw%5&dFIp?=TH3?$!Dd-W|HjTz3-10HeDAI6qXm9Jiz3* zH9EG+V23bt4aEEq(K#@zOi%1N)TPIPOw?JTzaY?5w8?(JSio$6UFUD}(_8%k&Z-o4 z78|oBYW6uaAkT(q__JQiGmD_uR}kq|+x-PNM+5{$>M281pdm6ymU3Tp1X*$rZHxD4 zB!1~@MX@3k?N3Zvl~>k5Ogc)6Ahd>{^+Imr1w=!q(QyE%SqiB(1%{Xci56q$APyZu z%-AlfYD~*iXi`8}vR*31KRh)+Dm@?~Ga$UJe?)cweHDEaI@0YI>Cr_N`9&4`N0tUe z7aJmr4N-J6^oU8rw~PQUy8|TNT&O2o9_}`fqeke#&EUd-5NAM0UVw;AH293Inlq79 zIbQ1)KeoEge(|tmQp~!*c&VUxU2wcE#Hfof>%)mQ$0+g~;%9*0gy{Uj!OlU!*?2bM zwfIQ<9 z5T!tiKS8LPhMfhn(E%`Fi`}-#YTk%RSeR`>9S}IH?GYr;h0bTlFngSYkl!lC;ox~6 z*o$eIRC7t`tM0<*oCQy$rXH|bx2DinF10?p?e5HsoyiFe4%-e>{0^ICe`(1}xw$`2 z&wScb{5nnX(o&n_;v3DD21jB8RtM-M{R#J=vV$U-+yXZBja(3Rc_M|39($SQZgHU1) zYqi%Q=%5g}fYVWn7vw)vR`!Oc=#89Qa__GK&&h9touybQdY_w+XH`7SLeJ~D1;0pZ zdnP&UP;$n;?EFLSqGpfhsjQ4<-V7YmW+#Tdh1jz_b-g`#jXh`kGe`GJNcoi0X{(0+cRwW8_NxG{iWgu1eq$NJ8FFYkl6BI6ON9mPz!BRX?Qv$+BhR6>;bBxO z1RY94Ra0d+{Z(<=8!_AW2~!jr=|_Awk=6T(PK6W*8hukNO8lF`aO20^7#4R^gt<$M zxm}ysf-wF+!v8O1C@fGH5TJ_=3blsDCk0!xf|CkD(%r#rOM-IB47sHt*{<*mnhz#M znu2utBuB=k4f|hz@vn+MfAqWm!vFlK#-I7u3(YC6(x2j+;p)}K&40R=`bXg9`R6}; z^tq2efBNyo4?p0aaDQfM)sKrm)AQowA7{9$xCVuE}C?7$t2+O zxg{8kN9?Jspia*o`_zgl=a$zVT|5zDBfAk=UhDCJslFRnQ^e|*#Zx9uI@8w5o7kmMwBVo4M$ zQ|kbi7I@Af`CLaw!peeem2832Vqh+y6(D$-N#*N%=h7UIbvlayf+)!%_M<0}#GBb+ zLm$~e@n=EM-<3ZLUln_^*fVH#)XV47$gh_aWxytNh1RRcZS@9ui!!Qo8EJwA5= zeF;y`t2z77nEm7WY^v-4GGaQsnvu;}`6AGgg4XymQElpf49tF~2l|OWe-p>{q2{ab zXYT7`$d~YE-(h__e5aMmDfBln=S#NxIJ4UByZJ3vN_SMLYUxf`fNnmaQM$dGqZzH%u-+_{ixOk%bL&m}W(+^Efc)MR`V4A1Q)y-g8Ecw9<0y>_wfr+s zS`{HcN@BMQrqbn5m6n>OL1FE=1(Od?AF_F5mz9<6R#cR&8PpNu$Bw&t9+)zaN%V*B zA9>`V(T5(wNI$0O(FrH#)gE0au2-6l@zC5Io%N3D0n51~0qMSO_%k_1#gU{%>G$Bz zOpdrxX*5hEw^S?m%(~*zg-DX2wU75GSlP=(auO&_wb-7WTYF03G4`p98JNTTyrwte zdMP5`5K+R$8wXvpW88p)4~(G~Auu0Q$n)JXyN3R8D&q=r1h^4@Rq_p$e-`;OP|M4o zXDHK!;=qawb6-|C6x*BX1$ybU=|F`#5jSkgroHlO>8L{okMdnYes4eQR-5gm77eJ>C7?eouk z;vm4QdzbE;Saovtq(k#+cFdW~n|#mwdl{)Gdqw$zWM;W?i|(r@iFA$ET5q=VB(ZXVg4wuUm#g3NP8DZ7!E=Bt&vY#UItePBEK39hf|v~xn` z(OKgG=6vHR5eFYnF1UJK)JGKxjSG7Jqt#7wrXPLmo>{{yb8Jz8{<^Hpwkua}CdcyU zKU|dG6rXC=-H9Z&kGe7IJ(te|9M(FSNi|q3JGyM7YAAb&i{@t%GzWO4L;=i0a zK|1&1xl>>KXyEPtADH&p=6{_&_0RLC#Qd!B=g)t3>R)G%embLid2nQ`E-dz_=UN-_>>Y|fiU}zTR2eiYIzYR+C3v%e_;zuvP0E-{(3;j)gek~mU z!J$g8p#sUuA_5akI4>>$qk18MCTb|oI!004OAplxlj*Yj>67? zqr)ZFGlEO%^bdFXf3>7tV?jW;ECaE5unf-E2jvAIn#MSd-URQ5S8PHan~=GdFb^;a zy`gYu2by&Tt%6OuP>U|Y>K|=4w6OQHS2gkm=F3$g}9q=iQ1N5@_h-R73q zxZd$`1B~&vnvAzw%;T(<8jE?l#eBa6o~?6i)&o&k5@R zuo7F_DDS2QenLnvtyk`2{~~ z*Zw7VbpmbRjN3rgf?g9g%DE+PN>1HoPlQ0$k%P_5IDrD9wCMHhwoj0JMn{~PaW*k| z59!uY_sjX&PaAEpMBKt#u?lBro-QkSfwN6cJ^j&;pXGV=F(!|WAKQTp{2ZTbTEmaY=!4dW$f}n{*gPk#QP|6W)A_a{{ zdZ?tPq0lr-)hKjmEbR_8DYP^w)D-uqp~Vh;i?pmo%@I#C*6v|sq!p2-H>;&b8%Ng| z+YN0@9U`M#!3<^6gFwEP^}0|)V4J`&TTonPSfVQ|69ips$o2$h=7*=*17odWv4J{$ zNSzIrF{`kx9_wSRR?se5GaE1J{k3Zw(`1F&D zzxmC@XMXk<{uTFQ|41UJA-Pqg4s@mKZ{8N z{=9H9+Ksc1PeG4->XA{6cXr=2wDaa$uQ^g%@#Ne)&o7?Xykz2uXI4*dT2_5*u?Ry>E}sT}M!0cok))snJ8RTh`8vSY9F51~ z$P7I+FP_x&$nA%wRyN*olei7bohW1}7_y*I^3N6SZ54&vD_tt{EabV;1>o8`z_qEr zYx96YYMboiuBQVU)T=*t%xmcHqQJt^O-$?S*TPP*J?DR|v@GvW+`s5l-JQpLq1H<|X(c$Df@yxp~%IdnZ?| z8+^@5Qj6st7&|ar?$}a4a{m0ai+0I1Y`OWJX!if)&OX5VBU!lwFZ<5wlI`FAW@`k^ zy><>Ny#zI1hZafZ`QY3d;PVm9{0w-}M9@>E9ihgb2|`0t`73)0mZ86) zW{PI$?f9d2(_d`akn5HYzOH_J|0DN}Jo@16r{+#PxnMGso9`|j>*#_hLbl;%THqFd zwtwLa&hXHqejY}fXmnWZnTYUUk=2o3o9n}Ja-DD7tF|W7k;SGMYy7rMz`Qvz(y_qdauXVC6Z(z7$iZ5rKYU9VE&slaDC3<5tX(NoZTuqTob_p0uNw7^?Gy!)PeM<1p! zB9wcsoP+mh8vNu;0MY7vT9)6LKdVryVDowR?wos1;j=z-JKjSNxgvOUSdj>D@>1XZBIyXCGVE63B31)pJnYMZxE*@MpPPSE@_S z=ju1*>2xooSmALM_vZBA>Y`BYCcPI46_bKS&@JS1*iHNHx#Qrhnq!D=G@phKL0^$S z^WISWpB2K=G{R#@Lc7TK5Lt(R9++3V`+++)j_$diLrldsTu z;)2#bo5G)YA+$vFRAw~nU39OE-OQS@XYPadji|Cj8uWg;;?lCFQ|JEl$It)vr!PPI z?ce_ah5kRE|K;PabsqHoHu=H$v;11bzaff`k1qcDy^GI3`w!&L%_siZe2V<@PyG3Z z(Y^qk-d`8suhR$U{OP>qFCDm~pe?>) z7JBPqyPw1YRe5*w?SS`~sp~DJj>hrSfqjQ$g;XJB(AY?*I7>A{h{!;KV*`}jBh;b~ zw+WGsOb(7n4T?$+iOvd*%?XRm507_7#<`_piz4ERrDBUiV~Rqe-9ZAPq0RaJ-oovi zrw`4=vmvSt3i51d4WCm3l~o(Kr1&!kS``$U7b3*s7jE^BwClmnQC343%@!jAxSl#a zOANF~*8mYp4L{EXs=IC-H&D=H?Jw* zc`7geR6*gn;^OB$o|jz(uK+EJ>GW zxd-x`4A!=_4$BFxLvQL+mzDTdSgrtL+S*OZMUdzdT64VUM#y*{ub`BRrV&+EL7n-b_Qj_*M z3(gdmJdq+okL?nsg=*S3a(za6qxe9Q>!86t{_G`jkGx z&pMrx{|iFG3{Cx~t`Lv9k`Qrg))%{VGtZ0cwA=Y~`x3e+zMh-=GO=yovlD_XI_tOH zo(od$x4rU>!Vd}yKPV`WbTm-C&;zV~COh{u3>@z?FkEXgNT^<9)F@@Jh43EJrT{Pz zK;{A@quNN^1bn7c$hAyX3=C4ous1$0P%-Mf7)V*Yl&58{Q99`b|@S17x=aVa{FXzu7WeBq%=r!I_ zH+@SG^qDpEADjxQM(iwZ=f@{My{hKfRW(notp3@G$t<<1{n?5d>fG|lXDPDQ8q+?u zs+MY6`9I2^eaUCIuBsOJOh-S272Y<25@23bjqv&W@)`tyyT|pS<<{nk5^^s)Zo78> zq~0eV8h&okc<3|~*TB&_pZZ_jiI|bl91+QB&hinFCJ+W z)0FR7``GoV$EPE;M)=Gr?VQ+W>+sH-1{Q57&nMMfU*XzO;i~JKPiruGnZcqVpWC3y z{b_lhk3eIc^v}v$M^3oEi@D_7q+q!qYv42Yg6M85&!o;8+u=ZVF&Cl*$N zy!K2Rv}M#yEBhC(>J6kSgu(jwvz%v(g5!UZ&3>E5`s#AQ+k1PX1^i|CN1w zfcHnTayeL5CwBSvt8d|6Y6l;G_TK!C2>LtmXN)(S29|DsdkmBaG$IbsL01*+p(EiS z=(JbI0f=s>68KC6dRtY|mZ~D|2)h=ooFfob!$RS^UqM{28ph_r9@fZtJ$XX9=-YPKod~VQh%&Iy&EV%iT=ZKeW%?3So&2 zlLzm6bOQ8m`@AXSHtC@zS!+`0b44#8U{ed?3JKRt8s6Ns<^Yj&t`@phC+R&;6$cey zu1XBjJR@=W&bhbYQPRB9nvgp(^l*>}^ynT-d%D510&KNXz!qk!cz!D!t%)_hPMFzQ zss-~3f7YnA${wqwKwxbLMU2^pOK}zce08w=E&qDS(;+!e@iaL-Xf5!0OLx~c{1rV5 zg>}=8kVNr_-i_189>u;gdny(V#h=x{gc=v%GV(T%cZDi6DZElzMp`~KE&Lf(%eFZ+ z4fACl!OrO;*3pKthewj|Jw=)2D<6XPZDFM~izeaEiIJ0E(-YlRJ3K87WBN2qsMvqc z2u8A)yl~*&TWJMIn@;pH?8$xQ6LDExkw24OUN`XCBlq8q{23ik{es%M1ygq|ybt*^ z`R7Bk?>U6m8W%bZ8Rtx?zxR&K6ROr$UAL}JyEP=S`$$i~t>q;gneiRw7f_&P3VIBA zuIpXu<Jr9oIn-gp4(|Brw8Ck+Ar_|bp;*Jl_1`q7tv{p2hDEK@H({TJ2B2>qRZ z#d!12>NuZ%!LLOhe}4bM7tcQV=d&mOf~NS?iJ$oM4+)=1lAme*{50~7=6}%J5&nGc zC`1JO!fCwK#@$k$VB*jqXxcbJp{4S**fV-w~O;k(Q7sQ@B)ISa@_;P)LX$o()~NA;=yQoD~^S z)~3x(ak2f3aRcMxhQ-E>iisZ^XPRWOO}E${w29k!9`0GY)$4W^y>lX&XK_2zOpv~5 zDT(V+6E{*RNt-3!34oQZf}0e720?@4fO5DLl9Pe7dmQ%N2?_gCQx9o%B&%(+)AdVN z;j0DtuNOMeHT){y`9Z$xy~5%T-6bCumV*1V$?f7!p|LxM88}_Y zHXvWPNp5nJ)&K}PN>=~qmkzEwHp3Tia+cx)Pa{585V>jY%XU@;td*13) z^kMtL-;~nAuZV7g7jj+C*^^J%lFsH7yjCf)AbfztQT~tc%y$bHSPa96lDSb!VJO z-fV>Gd3z9hhINDS#l!;ZPLRh{sb*ozKK`s(wXwnYik*4S$jhhF@@mh-O`I*~%tjTE z7OzXvI+5ErXyUnwO0cic+7vG2Lu#`yGYtyE+JyyW z^A)FITn3)R$Pt*JkIjp+bc{81i8OW(6Xe@70va51a}cE>%BcQhx)}&a$M*`3>k}l2 z=>8$*stD8IaO2Q$)2-psrf_7abyNst8yQTYhL#3}w}x7V2!*CQVO&*6Y(=P|&`3F8 z-SIubO+CWR-NOYwcMTx|%|>IdPyjVaY#s>WjlsjzC)(OO&eAn5rYxLUHu8NOEawhE zPtY5)0ux=qneK?TS>Z`-bfJ-cA%VKU?6&UaQ!oDV+0UMN@}n#AXAtyH{P{m{1+KuK z$($?x{K+T(fIt84cNd@k`Hzo3(@o>d7Y7f#TaewkO<+LzwYkEd*HoWcHTg7+2vm1@n`Tdf@oD<+N?2WD6~ecH3SWaUR8U3?X>f2rk`6q9jk^q6iedGM4g)-uX%FK z^e0wMIkTer^vW92)W_FUA6i{=cn$m+`h67y{cZgl-;{qwl6-lIxkB3xU7-ZeYDNB8 z^$-L^A6;C7ALH=M5e;|uLPjc0YAS`*&~aw#koG(8>U!{=szbAGKQM2CSW;VJ&k8~N zBG8v0XdV}p$MJ_p?3&Pf)39q-SCnoX+%Rj47 zbnE=Hk3U16&#bx!AIP4WBR7rjvuoO*qqFWH&n%g0jtOahTzV<`3PA^#3j}>?dCj@S zH76e)dwBZbo#T6L9@cSPrE6oQb6Zuxwu)Rj3^r8cHx9_(S>f6_ps=AYSu9N~+~38F ze)-K+S-g2*>9!&5>xXsPKD1Na;C5^w3$3)t@Mj?QhW z-bd&YbMu*@zv<5I`yU=ftR1(&k%f~_%%6DZ{@b?Qar3&$5;~m$W4RZwT`2Vb4g4AS z{C_on-aELgbzOp^cMUGPWXrd_+1mLG0ao|&ZM^zHu1=V*{#TCd11C&EiFVFH`rAvFaUtW2`jtN7K&#GyfI}P55c>`3t zeKxA+85CCo-U!a(MFH%y#I68>1~V!MEO}QA?b6LqR_4^Q52FB0vupOw7`+9E(&fPYckpu5p`l(h9Ury8XK8d;tKI{^XR^v(+IcB| z*6a}9g+G&jhClCFa6d8E9kZ&@6rY$sW&iZs7WEVj1*Zg(rMQxuGbLcTMaSWz(26jt z9a!=N73r0GwK8ug@~oCV{>(lKy0+f)Tk_=Zx|^JQcPB($PE5-``}i}5B2+9R6y2nO z0>G9x7#{4oy~;L^7YoN>6eW*gL6^4#{8{Ck6?tyG#NPscZUNLYcFdkeww#ds&IL2* zZpmoEzQxlIJ~pvo!oW?H*RAeeBs^JjfbhoVed{ZAZG9A)NVd276eD?7@R{K8J`5o< z$DW*Da}Z(0+)2k5R-c?dao?1I3<1NR`A5{Z=g&N4;m?DvJN&>Hz7zH?sNJEx3Hcu2 z9gczn_$(H5zK&+s?tbvD^>LvCoCI`rUU6AsR;rV*jEO`NBV0$>hd>H)QI#<+et$F>$x8L{|oomjW{M-4{7n@K12GcPfWKWI;0O#zGU$_o4QU}k>A}Gn6o{23 zdf{O?5#hN}k@?Y4uIQ+e*f#A=ao5^RH#@A|6Rmw5*1isNf19z~7C(TcHNKxIrdM2a zw>FVo+C*Ms2+T7CwIxPK=?!fI0<-+}nUu~yUFVmo)2n^L&H1cPm(3$=;Jw%tPMgc+{dWzwI&_qL6VsL~bEZPzk784Z^tgdo|e}FkG zBr_`99oOc%_?WKou{dLIjgJ{^j2mZ+uK`}gneL~@nZ-VvXeD}QoBeSl8xH$wP2;>4 z;LM5^bzYCvRuY?bL42uNwo@9z2~(wS-6oRHq(I@%pgDMNa!P$}4*B7xyxg$Hy@a3YSw-5#6-30@>T{1pv^&-y3GWYtx4-_$?N6O6Xj$GNNX5y9SQBEWa)|s!Q<{J z$-A;MkLBf_awIj{lItxATgbAyoKHeK2|ptiZeR3jvf~&>Hak`%rEEw}K}@j~;GC7c zJ2kTrE^W2b8gC0L*ea5f>Y&`((-(z>mnCZCP}ZdcO}AdE3-#|WTaN#I`E!dQM6fws z8WZY-+}i4r9QAqGhs%neLXCp|#N&Q7C;JyEDQA$7vi7eKhR@A;E;s8Jv^y*=dI{$VttXRH_i6r(2IAKFuIG!( z-trW`>2kkbh!Ug_Dfb)2?hD05Z@8S#!JloGdIk#;88S%Pn3l9j21gQP9SBVRnFxJ; z?%DRmuaxly%YG>%{g=o$ii&>C*as!z7upW8?)o+5cK%AM4~yNuDJ=MamWyRYA2@Sg zNN^kzGf7H=*|x^UJ1S)}UKidWc7!b;ZX70}b$uX(MZ)I==w<7K--MI|3pLgJU~{SZ|23-_pi>b3|;H;5J=?D7pkn z-K>ws(a|+9zI%|VXNa+Ph-pA1tp<$)q0nIJ_iAR!PpqQpJuFvhqry1V1MJ7@QIc6W^b^Hn8H69NOfvwQaZ z&vLz2U0+vMce<;qo9_F2>VB#4Gx+m*0-`x*nXu6)+1XBomW# z@H-I%JsHz_QyB(UPSdy^W=<~Vd@}<>V{$UgG?7?)^~!s%-u&aW;jccv{oh}H{=F{$ zjPDhsodnLP`Ukos|L3+3-UH-&;OMo~d2pov;2-b&{+qvk^Ue40KcfZVYcKuxm7zaj zru*N@pN7fzo~|$E%?hzJG+H1RH0Gxv|2%RwZKN=Ls4yKCXlOC$z%!k5)@ROl$7fP6 z7sKA1G<+uYdP(Nh)2Sl`NmmM!uN0;MK~pN}QJV*P7lJ=SB|Va#GMJZ$8Y)N{EK2Sz zOzJ31>?}&^EleRUj(bawNIyP*zPGU;1Qeu*%YqDmoxx*K80d*O(C-fl4&vWH=njS0 zF!IB#&#funy8LYP3^c~V3EfpevYJ3y6=J|4^5QT>Y5eT6Ez4S-Uq{+t;XaQ;>73k- zbJfvLFfSeW8b!AkB$?Y|slCV3hE613KD@bU*UEEIzQyRD9zu2Zi<(ihc^S0QgGY7^ zW#=`@bMz_JCqlqIgY;4&Xa3N+^NthbMrX*ByAxu^g zA+3m%l!X(?Gos6&!RP$FiOe}%+Ympmal?}K9Rb}bp`B?FU71ncdt-Z^PUzhi-@QBP zQc6hUw&gWz=9h*0j^+RZMdw4MAYkZSh&F#vK!Xm^5ojP{6k*y_1RC5J>1Eo3@u>Vc zKwJ?bJ0Iu+p)|>32Z@Pu1A%R-2N^n%m4ofzmwT|PFi24lt|{KQq~Y0hc#W_J+7IvS zKD>SC(6*-JAe{4#6X!{zLyAI=@n!QXt2YfgL#6L7V_;nONc3s5ZskJ;^!9LN(51^u-#^f8g8{KOQ+3bEa1vwIg_*})1!_&24~7#% zDIwU@l3t^~lD=C^u2qGqF}ViWdkIp4VcLu97qzE^^}MhR0I>HM=rNd53UG1Du}rXK z5J==;FH&v|Fs|0ah&{veLqr@1KkNJ(2uP!v4^uq~Dfz~@4G?dpx5pB9La;MIDjna`2d6rAN+cLm z8X4`|3RkI)`fG~Uu58(}p)V(`3o+w^X*F5t)!DnNa`vEVsGKkol|afp+38)RHR0%K z{sah9G#D(Jv_Z^c`XeG)lvB0LGT=-AH`{w6^cx zQ4qE8*fPag0-xojOCzKY@*}F&cwU}^cpC<=%g=X?rxl4K)+tNR`;su2FTww9@ztN3g|RBG2!{d zlFcF6E46u)^&0aaB)yNblU6~)g8xIM_|FkLkYwXm;4qfMwt<4NKDi}idsXas0gMWD~ut3Mi9M}Qb5D~Qn7Y1&QlwPnCQT^n#Axt>JQA8s`{iFl1J zi%+Gk3r_}C%m34gpGl7t_Iihmm-w*I?T<*Cu+;eBJ_s-qDN@byOp6uYjR|j${ z9Xx#u>cd6P}K z(@deBU>jR7Of79qEp3b~Esf1ArQsYM}+3 zi#WC8G$S`4-)V+EMkaC-Q?;q7pNZ*AQ?ps-7IQ7F7F$>?v9w-lWwQ)rJ$<>&^p&XT zwyRLKb^$0m`_(9Whd|Wy>8tG-VQh9BkGILiIm62<%hThCi}NvOVV;Xqp^$&lQJClG zbeu0d#1&*Yurn;IhV{wukm^5Gn4^H6fq*C?4K?*N15*;r`ag5D{CN{2?_TE+wVoMvTiM7(uT1}MEXh(>psnozoWMJ%LVBuq6 zcTPGtsXJcDO6AP9Rl&J=0@NA$r*YqjIj#CZA=BBglY*yLZgfZ;n z8TK0(4qF+_BnA_W%;0u@j>$U6;vQjfj&ZnoTwXqjSyCZqWG`v?N^fqJ& z=xwLfeysGpsaN$u9nJQ@`G(d^3e?CmrC&`eu__Ls6X=Zy1@}P*>fv7P8Y?p>xeyT zWxvx(zwlN3Mk=`_bnN5`FS>YjI=T0wQJ{zSbtP;VzV9Q|ES0?p*EC?VO7*5p@v@iq zFyFD+0geuK8H-mdlH5?J-&ASe_7dH6cD?H1`I1!n4iwO6j0os06~6%)2$OXYc%184 z&K8znKO;pWB8Ekeko3(?(-ppgI zWii97Z5B>3^fAC^IzDFc!HbDM3!>|X7n(cEhPTj~xya0V!8D5nlPwobGhH~veBl(E z#fE^=c25{F7n`sVT3%spx5~^ekn%hu;T&Vej5lMfF>}BYap(jq-WqFuf)zK;f*WIw zLJ*pe>If51Wi$~$f*OS=H6y^36qqwr%m8x~E6^PM5bZ+^5u7I748tuM;WpezTS26~ zQ-}j=p_#ciX{9B2NL}eIFHq&_WF61EjoC$7xy)f-6=y72>uyfy;bQChr z0M5e&X*bU9xq4hJXn-;tt9<&QPOb!_G?AEUMfnwS+Miv{GG2BVxZG* zBwsE_x?GTWm8utul5Z3yT`Nq&MXbD1n1q{OIh{OQlr&hdt1o}&Kw%=dG?;dOeliTn zsGd{FJ*QGp-T4`?HzNrQO01uArj^bBs>lrAt-Q?kyiD4IfmCzf@ywy)Bqld-JQHJp zXd3E5uK~>kbu0AjOKmxp1k)+n0(KqSH2_8P;VrFCMOJKGayHrz=W$a4RXIGywUo-3 zn2phEF9hdzD=(~HRFf3c@$8!ZLtBTA?HbNY9y*x}8Vtz>#+UPwhYxS>ePKh_GYNgq zuDuMwa^kY81i#V{$%PPPjOD~-0eNzSwq^T@o;}f*b9Y=tA3z{z;A?`xGkZ_$={df; z`&cGj826vp4Y3CB_)uQTmHf2pr&5LvZ*ATaes0sk6H%J88y2=b9ed?O;^kARpwnIG zEqEfe`FKhTWu?Y__ML!KBy$A1kF0Ir#?70btc&r(BcZ#M!MuS&Jo0Ra6fOLK+0R93 zD%Z@d-}2<8BDx1gb|czHQZf_z3DUhCM@1-qT!#2b;(7XMkv$KhyAebQz<;;Ngko`>)lZW*vXl5oX;$pC?baQh$T-P*1=>QWF9vldX2H7f%8L_ z1Zo{c{x%tZg{Y*n(YZCF?fLB`TUY0W%{UXHg}NEDPBece?|OVbQys_dN6@c-%mrq&;YSKa19_(fJK@1Km{^ApZ#$2iyqt$&oz=62YI5oFwt)+io#WYjS`L#5v*SVF*ZD3iD#4yGYRjE07FPi?!fJt7~VH~=rb&za>Suwpv=kK-Rl zBW6Z`WU)U%n+sPePp?oTFI~7yd3u$$EM{?Qa#YU?JGu`+5}t}bO%AqP0=Ju<-dwTK zAFTj!P+@B0aryJ9pc!Qw{X6z;>d#3AYVJ9jfk=E)R$}Fz4P|Kwl_{|eDX}$MgNh^P z7x-&opN4irA2MT1Bj|A}>5CM9Ch(b7z5_e!irflxI>fgmM2qR^GvR*CI|GNZwsarb zRkJ&;IAJNKW{{4q3GpL02_pVy@+~n~g;_kbJA@;;Ja+!Yq>$GAJHW|tJYUS-(~z^b z?%;07Lx=|FNE#Zv;^dC1+`Z52Sj)CFH8Pl@kiXj@&0<;A1U|W1HI;d z`~AS@OsfAU)JWeQQq&%!lFxrd`UpkfbMKF%{JHmMM4ueo1pzIhMQTEJD_KYoe%VDd% zelfN%Ia_h9t=)E8hjbR_fTLr+t81l)N3)x2yPIpbqwtc8ONX0#yR%!PBYX~y#Vl5i zt?fRc<1tUKGfehTzEh!-%Q;u~GB3|cQtsvMuBFZ{#m+8ggf6FrE_p6)*-kFcIy*h@ zl`6)EzqnWoR%3 zodKc0K~j1Wlp&MtCmZr6nYm8^g+@)6nNF9PBM>-UZET~SYArRe@HDV?H)6P3G2E@~ zgqG$GCQ~hqCmA6pXlr21on-D|Hr?08{z*IAUOt zKe6Zi>9$QA3Q~TbK$u5&_fJ}g5l0F3<9}PnD&#`%D@hl+VMS7V~Xy9ln z;tMv2a4bnI3oDRQMXZ#~1)#nFg3aTVyL+}k9qi%RuJygj<<+989OBkY<~b+lYNS+@%dXVP;Dc!X3sw+#7bzkHE;U*egb`pO7h3svGpyrflC`pP{kyZAk^!HSKq0Gnq{bQb?Z~e-^7#$4!=?Uto%Tw_?X1A34i`bsr(Qu zn&Qu}ZM-K}zU=JYptFB*^YHA$1*bUac@m{c#Lf`>SiH(`|o(s z$6hZTg2tN^2RVmV#O4;FIGlVQ=LCc~JkB9}xZ$l0H8kGiY}RfjBLyIu%SJoVu<6t1 zPc!nQPS!x47{Os;3NqqNb&y-K=h(2Gux4ORZ@!`Bf~nR|7+Nnh#@Kr9H2Vd{jK$`5 zOH3hfhARUM*&);zV3~9tj5BqJw_qe#a@JU*cxx@WYb<#2<|s5PB);evGk|Djq$##% z5VmZ>2sR;F=^#@uXHu&z*nyVpAPZ)QF(cfV=%XXe7?G9^(H87jOJ1B6KhDZ6#@=9@nFV|BY8VP!mpjqxLlNhPKD_4*M)|9R42inf=sYz6x0)d&*+**&@_n(BP2}P z_94Jb3>e2VQD`IBd15z!Ey2#mchlq<`C-I~v1L!u-mZeoj#FsBmkR9MagzKA(8%Ev zySn!$)F-Vvzjkg(q`D-GYPuI9s}7OYQdJWyLE&O$hz!3tE`)2!V`f&YomaK-iRx`j zE~W&u?hU*2OjOIB(5B4b#$^B6ZA&WFFDPF#w|4FPh7I%U6J}IKNy|e-Rbi6qaA`$| zs3KT`Zhg>MR42@ZS-R_)_`${C?H}q6{ea;1wMuC-qlBzNO46p-$Lp2$EB&2zlKR*D0(i@ESPb7M0DbC6- z4p!A}Ue@_sLf^5Sq*3FE6iA_g;)&NWY93Cx#bZF036LE8`Ft>;@eo|2sARQ>GE0kq z%||N$$`0UM8DQ7hKvJ}Og#OdN_L3sWR9t)<5WWWsk43m?5KZk*UF$}AFox(U%?Npr zfu#K+O`-7w?|QK5hK$(Y-ak5uxGDbpxX-aR+7|_GOe1I{pXu=PIR1Q>`i}A5`%&|R zYiORVyE%QaG1gDVne_+QOm|UtlV2E6k7pcGeyocV(qsud^20~a?RC820w zWOUjZhnIhK{tN_No0E+EGvpf}-krG_5K}ilz3FVilcz)d-~^}&RMZ42NJG*u9WKI^a7XUqEI3E?v#ezaLPa7OutRj?4ie?lNI{0WCi z@|j4Ivq?ue+P^^wmWdOC=Fep1m<=@d&*y4961x3vc4n9Z7*zTN{K!b zIuox&UHGi>)%d7X;;RKt9)SWH1 zgtqD6&wX7#4EO6Lb$joLKtC=w9v6GoUHt#a{q+59NWUOaj|SvS^2{`I2IDX>faQ4#8r}(zXErgB znV4uSOy^meFSfB*X=lBffl#h(1d|boVlktb%osK+p2J$lV{hiLwy+$wuoyexHD$8^ zQqtIPoHBQVt8h7_c-%cyJ;mda;`8>Q$e6Pa#brOGD*^v$Hv1_C^JxY%i{X&#;84Kh zR=K-&iG8ksFL`@j#}fU;#L^M5Y{=WEL+;(mvMJ)RN&)3;tctm;8c(+lnP|w}@sf{g zkHn)NVY-a+p`~fVNZ`PvA9DlZT9l1Rwyn?WwjFTDsPVq9dds? zS5gF@2`HB`uuUj6`+5pY~6U;>wZh&6~bYtV%9 z3ssBsEid;Q&Q5)>xG0o2w0bT@RqC6bp1oXNJ&#jE0^7V& zHl78)+}WiSif{00a>yx2w?XJTupG@lBLc1Z1O@mE1dYiNmGT`Q(J)8QfYiOSOPAF9 zWk1Dxv;97jNpJFr452F6k`-*p z4z*y15pgs-(wrG>fnvm1vf>HN7Ou5&U2Er^!14-Vv1eFL<53nPG##7_w-JO*lO|6w znl<~$*I)bm`tUb5N4_29&&WT2L1xSe3;hp&{+ILTZ@&78=Fi`LNg7Gt82R?!jX&dy z-{qk{=N_&%HF9utnEv$Uu)Z_mW&Xu9!nlK5fDug(e(dn-u zTwWR`KNF@XiJw)zZE54~h)XZ5ZO`7=acoP+iEX{7cJ}3iBq#PA-`1DAxj$zE2=k@% zpr&n4Rwv9Pme)`zdIi>nD_}6LiBQ$X&Zu8MuW9>=OKHKa&|*A|nS!{+z0pu}T-dte z%$kL#o~Fl>G9sYWa0zKgFSm^*TGHLpVjLZBY0dEIiq#M zqUuOZ$x3gyI7mA}(x6a^!pZUkX+9>;{Ke!g&?tTXG$Y0Me310aYUx?1RMsu(*b@Vs z-g_(&Pmox$b9U6Ggr13-4H^S-RT&IhwWQ47hdj1G^jnmapr~*-qR~LL*v|w(Q~VhZ z9)F?)ea8Tz1IhTGSEKCrUdTLdB_8wWE+vmdKmUB+0|Q~EUI-n6*1>0@?4bt!0IXPP_%CSxU?dT5i4EX#Y{;b>P7nrlYyJO7r z{8-Fce`A_3>(zV1WPla&_^>Gk7Z&B3ayWzADurxB=)R-75Fp!8!&zliF9@v zaZ2Z=cVs74Cx)Jlo`d-#oJ0@nJNPpaiFiLgh(7~xO^Bd>5jcq^SMSZq*|5zV8 z>yLq;^)HT%2?|Dt_Z%Y7DN*oaW8WenT$PnV%+HkM8Jro65mEw#P9ex8UKAi`s>hj* zKVwTEYxFwx&}homxiP2*Upi z{(NS+1hQh9KSNtV+6DTHQD;_(u`|)|v22B+bcw8Fi3}hbptxYU1bK37`LBV-1dspP zacC0rMpMF7s*)AT{AJ3L@cGS2F?}y2b;1o!x;Lg1%lF|-ST)G(!@*Q=Y5MS>U$Xo8 zGubRB1EKnstTa$)pzO}Q8!FZ=%Mb8{NVzb;_t+9y-f|@faQT|0nP+o7qgSmB$V{WJn|GKN-iEqX?|||`HicOQTlH1 zWXc+SS6MUe4RYVRNeRXa5lwNRZ&l2~hK>GpoBYe-mx6wuTs`CXO3kU2>N8-@glsD+ zRw=7jYao1nOay(GKVz0$$DhlCwJ01d!~z{Y1K$er0~BTJpX|)q4!d>l^INb(;QFWt z_NxfgREKKuVM5D`N`n+|N2AUMXA9eX>(vI*ea?a*Ew|*EI`~!Zo z{D(h3A{ZY9=`?&sOF??j`#nO=NRJP~wm}IuVA3WR`+pc5`hR2m`M)Xt{L_{0JE)P) zp9VYsU(O3HLYG+vhNfm*OIRRSDpSYV)=qP51b$Xbv6+>#p#|3nGUurl5Q?HdAV3D< z&4}&N*=9I2(7zB?XrZBnhl!2E!d7c(H^BJ}&baF6TKOXFr#l#pfL4qS!fz`SG~fcMBKCO2Eq{ z#XZ93G-raQlt&uEZ%4SKlr`*@AW#5aJ#c+7SWr(uQ9s~YJWD#;s4WH`ldKq%qq{)V^b z+diJ}dV0Kt)@D9Fx4gwKIlB*ei>`^pH)WDnl+sreG6Z)ArHW38s@2iElI?uPO2-Fz#N*X-*l-tDf|}xQ>5{s5 z2s9=LWXhXz#dWpnHKhXH=IgE=1J17fGWo0E&oCz=9j#H`#tY}=dDF}5RfL@3*^tZL z1Z37|(3kMz8NR>Ms6GRNR?0ph*?9R!YQ=4}>^-&ootf(Q=g#<0C4Jr7?W()WfXI79 zBpP)0=3~GC8{6R_rwv zoOKq$jh4IwGp7V=(K@a;){(#1Zi*YFGQwx!B=T>nq0zhrE8c$d>nj6a-WdMWd%Y-}v^+|M)lliOP`)^3O1G5ZgADe;)I1fIt84lRG!BkneJj_)X?tv)N$J--i4D zR8fA_e!3IG(ri=cqOLRh`XS#aN=FUr@n-~~fuMUzGCPYi;E3)mNCbR-tvL1C;q@J9 z{!N?aT}+r!7p<<3R$h$JHpXchV||*#mjGRhF<3ifY(RpH5=kY`&SHX=@ zy(A=@4ihpVq9@YeUPe(eXX0~4BDe8)N@E@=kY@s)PbQP7Gn~l<>Bx1DoJ<)xkpx9X z$FuQuNr6=xmy|^K!uDJms)7fVoRE${AUJc76q#p|e;(t{G<>cNlQ)LT8Y83);j+32 zDe}x!5t6bn@wrg%@<`eFNC{f+U5F4@M#_+RhE%ySOal0fH0aPn-`R)EGtV}R+YZ8I%8E$`pU|rrR6&oRc?LaT>Oml zQJQn1B&mx8HF<1-a9Q|ZH(rGFHAGexB1g8lIMVM-)GW~E;&o4yZdqEfb5(Vce_e7w zV@6QNQxQGS$9L~v- ztesyRuB}}&uVw85nwJ6~gVvr4B3Kw06G37W&2k@wYCfDl)As;$tbbSdL&%v!!~w%? zRowiRl+fOTTW~nRzJd&VbN06C6hg5I;k^uyLiY_ZNbPDgOeBvA50!3lh$Z|Xz_yr` zKs!acC`?Tvmo)MI$CvsKTYo$bHR~>d59`MF49G*$6=CUgjo#-Y^XGf+Q;&Y@KQ{fb z?hlO{RL5vhwBA`qeaX9?=FikpKONol&*#s&hw&%_9XI~F2mhY@na0%k#M6Oj3_!(6 zYeJk<9-^rX)m{koD~+60vvFB#dSu^$t$k>jdYstun{t!ub5rV%q&8sunEY9vEkDYb z=FiCbwjAD#%qKuJ5I1pCKeOS&hNXm)2P$D{Mko>HAG90O=g%1Hm@`efbQg64FsN~a z`QaDuBWA=Sgc=9d?!P!jm`A116JCU@0HR|AJ5LAso?o}DeosQ%;bbVd5k;nn;uw6+ zKqI+|Tv8b5^Jg7`M)Da|olP_vZGg#p)>kA(!d=ji8eP3Jv}EnlywF+b@dr+La+Lk>qL5MeRnWVs%6 zu8inGC$TL(rabP6(*Y_pBCHIC^g~e=szIlTVtnR=sPSnD7d`ny(eukU1++cAr3|BqJ&NzaTRnIOqCPf+M8NH-Q7Yd%Oi z435I*-kZ9(@ShqQue{g-*Rp zMhgrBG_}Tw|1$AA6484ipZBDa+cFZ}{6s9dEfT#ek-sNayyfb3Q=)tu?b2lO_vG?- zAfWIOUlS{brGCQ>uGMxf74EWDSFc(;FqO1=h8lL_BgiL9kr(B%(+1bRI7%!r1 z(qPd{ibccGL8-E_%fX~!ktTH7)7WA;i?hSkCCA6}tW;d1kX(}c45~y|)sic|iYpq$ zkh^O=lUc;#6tKAkTtOjF6}s{fW`&Msyb`!F2*sj`jt$?v_;6hS1;l7@%@v*{B`AT{ zg3CY01HI%|AX>}?85Y#D`SmUyJrd22lZ$@~ zJV?tBAY_1?0j1V_q)?Kys#g0cZUUr9l)OrG$9qNWbJ^9kQ^0Q&@ahEIDx{$4kTb!0 z6mbPTrdzy`iy+eUb9BTbB*-1%UY@X$!Ky@Lm&I-M6kSuOUiI>UUU*O_Y-X~`p>Y63 zN01xXkWO^#_~HHJPAMo2H@)0nb#c1p#2q~p(j_>%N8M*bP!TmI93@K^iVc5jsWzrMLMRyrNDp8xqP zgck06{^^~Uum2IPB_{md@;|i_-+YF8zH4rL!_`@BX=oU-NPX$_(>;Z0!>7|PpN8-m zIp@s2(520 zR9D2!sNJ*(-TFFrhxR=mht7RhPwco1A4nnLTzKb3-m%hg5i)fB1H=ZeE{l?%kCm6k zDN5s%D5R;2qZGyAva?~b(g?(INGC+dB0!t*km^GfwV_0?45E83L=KZi-R8v&J61F# z1vc%DXxbCm`b=C`_WJ%KTLzD98$7-h)qi{&c1Ry$ z)ZskHqBDj;q>m=|9NO7^a7$fASXJ_>^II0dPf`{=qdd|V!oy0^b_X#_O+~nGS@g{E zbqnf~{5zkE8#%i5dS24iyrhAn+iTN9i{j_us+NsU)<@1nMiE_&N&-YsTa<<%U_6>A zrt`+*pd~KqvrT&Z_wi?FG_c3YgV425ULH03;;z8s& zbVx7jL)5kYvf2O%JkKUa$B-v1OHYmNT%)qke6 zoO!~fF1md0;4X6>eE@oa=g}0p{u&VJKrtPDz8it2R_e0Q`Yc)(oE|sOzi0h1$TMBU z?L1Z((_RjmLL(8~66Mzx<%i`z&YyK5=lch`2k_{FzZ*O2Za5)-9v6Fl&_!KLnjVnW zfk4EMP>&LU#y0d_-9^wL_()OKhbZfCRj3AuV$hXyVSeXh=GE>9XxkUxdw3T*tF|9W zy_lQafaSl0Khu5*!k=^Zpb#U(S^r%*J8KeyOCx84`H(Z>L7^w&&oqt(EP4okrZLpR zv9s>l`}y49;4=$IGfbj~#feC*Ge5UyG8GoO1tHc-3d3LF!V!5(>h3fPYX~7D}|NYK{ z&A^rq=f;nCtxn54;r29q{&f*F&7WcCE?eq@r&f+o_j1Ll<;s$nC3R^Dup*-wXf=8c z9!jf10vV!jD%<=Z{tQZteGC3fBG6P`nsEN?jIONIzJnKM(0rKuHZV(%Bb0&cIn77EeH3sA58Dg zO0L-znIAD18GD48ADurV%uFVdV8wwH%b&U-ve2tYD7q9y`ZbWrCcx)%x|cB~j!6sA z2_n$CmHP1cLHwCU(0Jd0EyKbAW)2YtT+pXhtBThxZ+~v<(4nNkgF73O!iz#@oH`>cG|nft3kP_jmIY zbq`+q_S+v2c!q)l`DYYdq{})f9iM2|B}B8`1~`9cs9tsBBg`RB=Fq#V?V0@hrWUD`>7(^z^dIt5cK6< zAn3oLJK?py?{5tJIN0&WtAj9ae_2%6`Sf!I!I2w9s+q<%c9YG`4W>X-jF2-TbJGnB zSZJ|lYAUucSKHXkv$tQyWCXKW(Ok|NHfIZq7&9`EWM*^raya`~oM$-P=XpHXhO@c6 z!(1NlGP1ZQP+T6N$|wwog;;QkhajKhX)JXt1p^f5%2-k1RROHLgqn^nDMAREO0*C6 zE@{LH!p32j035k_G%M93TJ24R;w6NWJ=||N3WtHqG@7?H>Nh++M(l0tJX|_8$}6tU z9U}3FQvIq@`?^ed%hlrwN+f+nt$IhTc^`HNx%@+^^kWp@vs{XVC(h9S5G)$&!JIus zx5VUnyx- zN(LmNVdS*sUT;dh-d1?O<*RtdSM`Rs*8rPaW6vyR@u9;#%XOqA&)9ot%*VZe!hj~v zZ;Lqq%2SqTNzA=~;Tu!~KYr9l2qR`yb_`QQ*GsrV2AHuHS zkQ(3HYAr&rpJ>#-Q7b;zs=h=sI3MqKu@BYiPl2F;oq?k<2A3w}Q2H_Qu_RTi{b1&d zcm4d{fOSDBzv|`D?(WhEi3FwKAkqvfqO9K>kV>o4Pm}bdJBv<*Om;D{tV~WF-?7ul zbyzHa4H0V?Lfkz^1j0)&a!MsGnoW+g|^0uT+`Gt?aDFbG96=};-Tg(Y=9 z!Yj~v;3f9<>2PtWgHi);5Hv#+@N3}c<_l}kK9a>f&*YS%p(Kts9={GI96#-AzUo^l z{0={M94WK;1mcsd5+v8LiRyt-m^}^L@qbV%4(LuBuMEo zrv;~l!6Y*SW6oq7FJp$*oITf)Ip54?uCe({WAj-i7PE~Bf}S^J`V*7w7EiHTI+d}) zi0N;{3L?Gkm|!hPu;H(n&Rsj5 zyUvQU!HT=toVD3Rm}KFYWX;)T%HLw;mdJM6#&Qa0qt`8&|D0?v+1O}RQ1shx|KZx; zH!olPuTQA_^LJm}q4_fsx!-;L^MCmB-~T=Bq2Kq$;4@9334#Xjr2N`hoKEgP zoitLKdgEN`AMJY(EI?lH)mP94Xqts=QstZw?idet0ggJ0i zlqUv&g0?&z3qwVB&Zhp{?dTZTnZ3E|@Ye3!ZM{c#^d8xXB0i17@JMXIHa!P7cI{u= z{!C2kp77@M;MSDDiZ$~qaBtBwAaDj(f$S6~h<$mxdQa@^J+Zz2zeIL5wS)Ddf@oZffKtrvNx7*Uv(jNe*327 zbzw8Xh)Vs5*MhVo41#u8R1qkmoDcUQQwr+pBUy~~sqBQ~aodxdp!MNu(p!-HmDLi0 zfWrK$wytb^CIOD|cDSICt3SG{ZEsxpnnlF{YUIso{AK8nNJ*ZFe}j%dgFnMxO%OCC zsh|-w>7q!BFMbUKt^eTlpWTGySzp>b4jt>?&*+%)hv+k5{jvVdCm8FQJw_=s#jf@5 z;o;-aobwoYrok`8pQ%tZm460vCj2>aCQ4`Ln9%k-!Ak0$??=u0YaX38-@l~}Bmdol z2eIWxT(6IyADutb@#cq6Xj=ZPL(ue=Bmy0Q(?H~Sr{fb6E33k_7s9l~A==`IS@qjj z_w3)?pPLNtE6%=$1)7MUb05#Y@hF*R{cQ+*&LxRWuu8-%FCN(gDKR$aIF#I!8Cw>+ z@Z4$@QE&vQfRVwO$K{`O7r~8nnP+-HljPA12K{Eee}av3W)79^_pUI}Q;i287$Rc>~OurqBSLSp=&mFQhKVL^;c*SKrx`+0Q!j6C+E z7w#NLvvis0+)|%1eOG7ukVFs-@{B_W;+HX0ZGDx#XOnGEwT-={tzdxh(@V@4(-ECQ!J=y8VP9tVt6h5nn#>fvyLF*{--2r+a zu9o2xp0PI?Nj2kI9mK{P1VwK%w%J|&j4f&4th>X9@n?jY^$Kts>1$Xx$lqG6x)7{I z7sdS0IkmeYdk*dx%uT-Z%=)s;Dghfre z6E0;ZVZsQzi`r?KH3u>(5A4|$8elyMDX2*cmn?t(<1dka#%~t1Af(|lmNbk0)qcp_ z$Dh%&2ESIm{@tD1@7%dI^xftDKZ8FHbpI6%^?*-xqULdf$K}K0Zmzrdzx;lF9O}XE zsh{rl6CAZ<|3HW|RRl*P`8@Fb;J{x|q%R@z&wYQR>MtY(-Tyrr6khHBak%?0XjXXr z%3u3>zUt}ytf%kehSt|gtA>;J6waK#&W<_H(8$-sbRok&)KRdG#Y|wcH}d#9c!DIJ zAdMqPXA3epkS%kw*z7}eA;!$*9wn%mpGTu+KxR6mhb0S9J!JNTMO2-}l8{WQIKtCB zr?dLScP>VuKOjg8$!7w&+`9yP=1}mNUeebR+Jly46q9sxu5|Zm^b)tZd$pm5n!vG* z&1qq?TgBpQ8ttpdOgcKYF_|?SX0^9>w^DgUt$9hVd`08;u1NBli~Du4^bNW49S8>$ zDnyz;kjg(4%Lsoax&Z0>8rg@w@=vs~k2P`#2M~vT8(I%{m#c0rBPzw~v;5wYh^`9w ztt?hOUvLp8@{7Gkq~13aKCfw{$cw%tbRP1O+>mKrl`3CB&o!iZ9r?#yUH5sp?~uA} zbQ7+!obF{X8DT~4q-k^E#FluSkov&he87(JG|ss9@@!MeUQ$WkQ;0qUrpK<3f?g9w{211D-5Hyhhx%B#+x$pS;y+a-elF!o5)v_+W+3nh|IB;rrylFtw_Cm2)qCZ3eq_ca7@HJa;U z?{+V@1}9+^JQ6g5ChBHhxvMMoa~+>wg;shf*q$KGcAW?PCZn+l>{^AA?x$Qskst53A><7Gd zcpbr(fuIS-q|_qxUP2E?p;Ix^;M2jr5(GJ!L4L)Y8af0POiO>dm|U^ z}-Wy;qPxyNh~FgTGsL%2cnXUt{b0HX>A7;^YHqM(JrG3l%R zNG^R9M=z4kY;s5=Eq@*dl1ecomkc-yn@FUe;?IBg>!mx89ypjt@IpuWAFw2cJ)K%- z35w}r^2mG>rV_|(0=jK-&+vGKLP5ThV<83{?kTv5guLgS1j!s$q`8UOz<@zA(8v`- z<8NtT>1fE5T5x^M9sJC!W|*7LG6RApLFm~?L{GJvKh=8SRNKWyc1sK$mYcBr%~(OE z>@ag8(}*EaXMkvgpTVDb8?30Z;B6Q!3QC)E*N+x|y}4k$mD73~;RYMwdRsnfqcv}{ z6@QyKce@#ThY@#|u`tD)mu$}2WhO|TE=zQ0ifzb)L=#0b)9{!LufO^2<-xCS4FB=d z4}bXj%b&oU!Jq&1^^Y`v1}6R0zPCJ-$Nr!DE7-C3Mxej@<_F5cK{Drv6a3-pJ74|o z&aIdK>)(w(<9p84zW?s-{A_LfZo^5Y3Qs|4PGT1V&u3DHPNyJLJW!Z{!r)3#%Jrh; z>jgVsD%^Sb@Y<%Nr8NnD7vnUS;(gm=)t%AG&S-f@6p1=F$I36pD;nYz^>Ol=7%{3g znk?&LB(<@Ux)`Z`)yK+EWKFajg_~5zNKv(Ma#GRqnkZRKq?~TgR|BFOp@f&CAwrF+ zi&TTYo=3~Pm>CyhXO_jzE{~g2o-nU+?Sh6aOW|#9*tW7^`zqLsu_U!^W&P$Q^&1!0 zZdi!!euxBv*_MQ=U|=A>5kkOKi0K!FkTYmA2{x0=vjoX!P?wr;Wp#uC>19NhA;%~W zm!J?!Mv-xtY_tHP!kjjLu-63)hs!%xX>xZ9lNCD#|W)O)Jmj-*E5Ak_8z0?oco?k6`NFfJ~YxTD$e+90RaCr$D3kH%u zga9^7q341$=i?T1J-e>`;AXh2vD12vCbd1YrgGzQ_!|MNDgqUw0qj7epv6GtDBKAO zgA0V5kLjRSlkl+qAN|F#ewLU7jK_**zq*U$Zt-;PZw`3x_P7;=3PB4=O#qN7U`}mD zv@N5vD%9KxF6!#u^%LBc?twk%Pv|xnHy9~z{{{TH<>(&pXCyFbt#J+7oE=Grn4)Rln(~Cj zIA0#rs47^Ei1I`D^Mvpjut>+BG0=saA2Oh^m<~1T2Kvldf2`YJ+(3UD{V`M$CH@jL z&O7Zd&0i@+Z@Ah`{_Rh#>&;0f2>NhJ6DTy5g2qzEqQMEl6-l%eHQI%c&`5-z!Jlgm zB;l26JDORam0Wi)1w6m?$Zp8A5peCufeAkqx>{64#@dU|?}B3ibP@MP!mbbInb=^$ z0&SbHCft}_iS1#^Z92S{=FgCR(DMt$80OodbMc z2?Q+ys?C2=gnoquE7i~!cc;g8rN=^Z{j2k5P-uMw{cG`Om>=lUr_y|t=e}>HlM&%#{I{f0jhPN$9GQ#J;$gpbQ zf9I0ba;ix4g|q$=>iu{Rf7X#_-9R5f0~ZrwOwCp4!)GWsa1jw`60r`_&<2l^)tUl- zZTY$tounz}&ep6gb(t}RQS+h4DP08(2rSTWZs5BmS~tqk&!QTduV6Lqzc5%^u_d4* zYbWM<@TO}yvbR1fv*FOb(q}WG7Rz}{*^3La<-FfGYpGF40gM8!4zz^Whmxu0vojxuf{y(-o)nSl?pV6!F z`(fZ^s(_R!FUQZMw;;LpN8Po6&oqBV|3SLQRee8@w0ZB(Jsscobp3c`kTH-hLME1t$L>TX2XgJf>4* z2>FH33!})n;rt@%Tz*Q_0Ah&@s$((F`5fP+6p%+(U_K}cW)@>f27)svdW^s`2aUJD zpD6@AZpkBl+H>QVRJ;?Y2kV7SWx$UhGYrI`kf zmG45?Ay>WOt9^Oqi~*&h)X^#3#x}yhV6K6I)?kv-)Mlx(YsL)qg$0`axym7tM>Vu0 zcFZgmFVESfQRH<+>hrElMDo~RvB7q$_4^1BP_D3*$**J!$==4!L@ZpuIq$@- zbmmk6MC)K0&BSQkgl;7n=<{d(1xL_GY9)Q{KmF>k1?SM84)B@9uHy3>k-OHaU!6Vc zU5)w{35~-8EdN|B`ARANoJ63<__JI|_N_#ATP6ny`~*wzXPN91uxN=CN%D`$Sn`=t z@wrm=Tbbk|^eYrN4s-dPJoul5O%VJ-8G+}5d^_+d;=6=1qa7i?O61)ICxavZB2v2q z8{%aZR1&!{__=dAhjYQjwG9zjweLHGgsW~V)E@zp0!2z>H&v?ZYRzSZwA;nGnzSIi zmoq=);sc@LIG+E=cleOM^{7`pls}V`2*yMlc<^|#bpDx8dPij1$;k+$t0UwaoEk2p zK_z?1PyMD!_9~atZfjf56}Ac7FL}xaahiZq`5sIVw)Ugo1cYb!qs%NeE?GmI=|PBoh~1q})<=S_nY8b%J=MaK3^OqeT7IRWOp zKnrfDIU79(slJ4qwU!7okENi^`5P_o)+P)7SP3>+p@f^KkCn9m&W#!EPC}pHDeWV}*b)_&JeFk4D+;!{ZwxMUk8@DW|OVBpPYg^(qZLz9L z(X!4sWqXXgB}&>9B|+@DE>>0*EvbkU)q*6)O0cYpBP(@P8!bT*<~&B8Yr&bLWL0sp z3o)XyC{aa>1QZ%~QXMI+i6nHoK2nANFcQKSBb1F{3e?3=0&?rZNGcDcw1bk%C3r6x6C6hZ&uHq0g!3q5 z)`QQKUPD4;&Y|MU2*m|z8(?ZWCXJ9Y9xxs%AJXVn{e) zhztz`FNDcULlq@qinF0|RB5ETCSh*lhQ%G*S9k9W=}V3n*d2HI*$vmTwq8G!cr`cq z`th{kqp1T&Aj(J`IFa6;mqA>t$5LAIQrZeK&~mZ)cnYM=T_-c3#qK_lhHD|#fY^EX zWGW=jkdXA|Zbve_<2hu)0~?Z-)ox!@zHx3zJe1MOk_ZI}T2o1HJSjT1jchiFXNRI; zBB`nnpUPk=sttY)R2~Yc1<4iT>7YP*X}9ya5M==xfvsOuzbC3CdvhPUJ?191WyW3F z5!4jFusTo$yE1N77VJ|J?0qi8hY;O~5U!3(>#ltWe8yE1@@LW`GDw8Kf&tm>fzpZq z897fj`2S-4!C-{&+6~ z&M4Vk&EMO6dyfhu%(!ZN2$?hAhzeU(@9na^>fPRZpN0Eh6Hk)n>R8{pxPZEN|EgG1 z^-Oc^?0{|r4FNNkl(0J1AJIeq{HwVLd*EVzlHq86@&=W%nWo;s_vb-zj|%p=N6U>T z8BgY6GA3Dno-^NM1#ds0{|4TKEQF1H*0CT9VCUXpLCul6+-QpYC<@jMpO(YvG(F6m z6L)WYYCJwg2Y;^JkpS=oD-5_3qr%b-@+_K7_F3}m6csG~s{zF?dV)Wbfxu4W)Z19J zdp#u35MZBta%tg$hZ%n+^VJ!65dj?OS-_5iuY(csbyOIAx^c-kbB_{>^l0HH`@_pU z+Ivr42cH9dfYcD6&?kaWQ6n1~5Hxh8Wox4vx2$O1jU039NWi=;sq(1=i$ZlL=~TfL zi6vTtVMerrQM0h{YA9L-{ULRR+Xf%N*K7?~9JC+8R~}dXh7}>8W?U5f8Nd^P9R~D< zv2eq##JrWEFmNF61tcGQ$O~W)JQg?_7#1uVh8wxly>q5{Wlslu_BlF3yJxEEP?&$# zoGGVLWwLwsb?gQ~V@9(9vvpfL z*|92nc_?nP%n<+l5a0Y@N`OeOmoQx(g8PAi?1U#m4M(E_iq^%{Z(UuxBN5M3#rBQG zTQ(hkG$p{*8LkSBcH%=Paz6Q@n?L`4|G9AH(mw(||K%?~fBp5(UwlsbXMC-B`NB7y zEq{ghxwGXv=#$T!{-wQ@(C94%FKq5nxuun$bC1RO$^X=P&f>dKWEE`w9wqhx6-&LH zvI@4hecRdb&6&<`&Yu3;nfAY*Y5nGO z+^Iw)&IOYMy@Yz!-Mz-u<&>>$mAzfFx9967!^c`5WGf>J2;@qGuoLjgVEo8O`@UNL zKBw?}i?bFKZ7X&qBfpR}FG=?3!(Jv7@dh$N+s z@;o3l$d%z+0*0(`$d`+dc#gi`?;SiS>rs)5a}mVH7)0eRACZ4K`5_?Tpi)_*R-f_r zeQARKRS0E$O;Krwue3WgWy|}~<@Em($b;$rbg-wJ^ zRxENTLLNFlzbhJ_vyKi`_O_)CqEhS_D54yuzOq~?tc+#VZf>Um{7t^^Xf$t`OdkSN z!Yo3odEP-(3D02<*BXVqfDY4o-`-T^-^rG5W?PJ5S})eG90Izr{_H7}+?d;}u0mBn8UaM~P$HnEG-uR+cf5q9Q6`v$vNC>XW zVuwnZ}3>+Tgcz7{7qlGB?T?0&4bkEs~tEIA5tj$dFX>y#lx5HRfF2P$#I+(mt zQRwVcOg96&?SIevq4#^QcZ=m3(Uro(NXFfiL=xAI9z*&_cfcTe*yKA$-9K>Ll)(>#_i!Q}QlcerH1aOuJk z^2H+|gqAKDDO)-M0Y43j<--uN6(hMAC0{w3i&2WzqZDh0gFi$0EKeRROC2m(Pa)ng z#B;5qt!_BeKZ8FnUY`8oOJAIA`|9%9zrXj^5BMSR=g)us^XCMgfuR5PCAmZVUO!|0 zAD2V-;?E>F=TZ=obOGr+zUcb=?63!h@ICmuJ+~MSlM^Y{xO1!Xd>ACH*tC!zbvuJ#I zyb(aS0%p#Z#De6oQ4>d28x`?t(lf_vin$VX;ArN>ff9?b;9xTGWK_y$!mLBb>V+|0 zg|XhnGa;EKK#c%=?in!}sBIBo(UprgZE}ZQGaHg7TTv)RP2VeU+QPOL5~TEha^ zIhP5%IpoeCH9K$|H4B^sh`=eqBFw0xVPv7EfI|q(oWsGNDXSouEfV>W{wLIMC?+6p zO=#mzSWhQ4Z(muT9NWAuvIq&{!wm#=;V}~Jb0W+mGt>(>H!oaG`eZAJ?hT*$S-)E0 zmqi6CYeLYG-poA%q!gwZr6IcF5I`y;5Oi5$6r5W+4zGt+ykYmc_I+!sH^yen8Gj@g z+G#c1MM^__AYX^r8*U+3TY7}*SeO?OG!*j4P+1V-MMlt8jq%M?z-IgDhIR^GlYHZf zkRA)`7)-(N0RnC?til{%SiN^CB+tS+TPL0!;oh=Gi5?a!$433e`&kt?p>EEE`uOoc z(6uwor)FCybk!_h3nGs5WstdQW&omx!^XeJpRoy^B;TL{{*1Xo3f&vMfVAx(a7`XUnS411M%lwN&WHX;ziTo)C&DGMu-v=7M~jd@qn?TPXRsQ`5dr=T74-2C{jo69zCaxebqiNT z)IYuq>E{}Dq&Do@Sic*d6&Co63J;%&cX7e-=WYZI@(hs3#dQ>#7UayO*%~a%f(HM) z_%r-Bg#5V@ZXw&(W-ps@AW#SUU-0L&Dc%5m&;~=#O#FG8I(M2Xf0`<9x=(hH8en#B zpk~Jm5tX&)pOn9@Jdmmdgt=Wd!?WEtp>Y#NxWW2~|5+7jKxIF>mV8Kyy~0IXBRl zH-i?Z*9&CZ$juR=g&h!n0v!)GXDxWBX4Cw}9f>f4#_e6a{n4FkmrDl^LRvYskFKTd z;#YtDnb$w}_{WW9A?#iD=*Ca>?#Wv4c_!n}Uw`@i*I)mL&Hd@~Uq1h=>-~4So;&;Z z&K8(&Sm0`B$Isx;?BAB&Wq<#S^zM1%mj9OZU_TjfX8+A$632ylbHleSE#J4de&62m zO?&g7J6g!V*8M4}Frf8}Mg{0HMJKeWeo0Y6%pcIZEdug;OCs2SkpUL@xoI9Kp%+kvPx6u~s2J z>*Eb!P&Cz&DXRB66@;qpMaf$aRF(nwU?wWHDkq@ zc2FV8vnBEZz-Ne`ktI#1M_R)-)#?wtd_GobKi0q;zzpr^0*(b)*c8edcaL_1 z-^+U6*Eo}qcc3`+HGBqDD$I2~JUhg);&Bcqz^0s(SrW%|xkI+AtmxMGGsMrtpE=%T z1)FRr0Sp|fQ5V-5AD=dz?mV0~ygbghI$y>B)SY*89>-)05|673eP#TllGtjQ)BPi9upD_@_ zQu|Q}DLy?N0MYM^_q(RozJ%HF!R-oDXo+=kp4vHPRQtSDXaTkXviv;f%ll&<7ZKVOscb zz3l1r3Vp&r83u7{UBkc!jU2(nTHS#Znc(5LRkW(h8t;o9E=@{#B_VgtSRSt?AZWOh z-~^JxJWkQSg+H?k(HlOaMZllg^JpCpVwbE3e-=(+q>nilaf)aOK1*>tEEXMChT;P~?>`LdA+ z5;=oBuN)y=JrW^XGYX+tHCnl5v~ul8<+>4y#No=M;mVZZ%G9Cq^+Ti^2FW%K_FU^Q zMl*=<=evdvU$Od;7hn47Y}=nNpZUl8Z~q9{?N^_}g5xLf=fD2x2Md4xAAEQFP@I=+OnF#?v+Xha1JnR50a+hD9EWnl#r)G=y?XL-EI5Oh(r8e(H!Zww|} z9_dpRVTp=J9|Y4FlM6%`)j4ZrHDDluOfAS*gM`f%98Gwz8|zU{Kn^}L1PvCAO;B>c zC?9N^-#T^xQfD-Bb4ddXl1wle{24qp+6%$>b9t-^hl4;%QIuyvv}azFM-GcvuiRKj z#0~i|#=JOR_<@u!pHiC~-uT#@mMx3h_pEB$x3=Rz0#wRK0*C-T24rqJw6Wpfrc(zu zAWlBB9+GCn$^A*E4v@D7q8Zr(pGk&+GcB@jZR;K&>s9c4?%cJqZR?U#kIt@I7hb${ z8g#tJ!%fG+jK{-BDTGK1BUvw`;Ji;YD58ZWa!1PWJ45a~cxMNWqXvIQ2SU&S{!9+l z5o-L~#ni&k{{Sx|J0bYY(O})Nn1F&+A@y4ppFNa(dgsd8gows9p~&_Kq?t9t1G41o zC~~&|C@3Y9*YYnxvlpc&0)LLquUJ-G;CyQ z=H62~=N>q0K>S=Y3uZokHF4(Zc;8A2KScQ~Kb|x5XqQ#^_Wml}p!j-=>07enVEkE# zpu1OlL;j4N>;ai?JSjxb3@P6#g64rUDm_^AjVF2i^9@wcJeQ{IqHqD?0u|_rGb4SE zgqboIOs#u-G5nuv_9U0>PA=b*QocKxA!3xUO<*Cc^Np5SR_}@#k`Z{<&^v zBJ|HCi>Jd*2mA;88J4j43ZArxRtdBaHS>)ON8fze8#VXY(t|4B(xebUgQmi40SFo@ z=;OgYM}jCI?uC!R!Ks=P5fiiL1!gV|FHBhotAuh`C0J4O4JwR6lRt1be&pKSQj`^v~EX#xfur%~&`M027cF{2AWPfQKN@N8$WDU5&}y zsp|Zx>g=iNc@2qLsoT<8kX{M})^m)M(>y|~gZeH22B@y7aXltT{9&bzK)y_->%}=5N zO3VUyId?~L?#?7o=xzkf@#kVr0u823SesoV&RGQ>?3h)!B^h2H1v^u6wkPH6NG{m3 zDQ8D&J~Yx>Q>wQn)<3zjXhr1FP=92B#P9)=E;D+}*I5N97;0pc{G^Z=1OFm&gA9nA zKz(+gJ|~DvL^#6$RXhUA3j5zoooxvB66?$hp)K&)N}d^i&I>jm?PE@``AEe0!o=9x zU27_Lt*hO-x-=>NXv95f!TvdL;RrTi{0py_On6qqwG1zx85#_Pkpw#2T)Z;4Wy?x3 zg5C}R`R0__F~i{ec-tSQP6>MZoj-nsw1dCLe=EXu;y)Lf{0aQ|ONt-AfK}jUU2nYl z%f-&WLz;4~?WYcSK|tu+{u8ije|)&V_Wo#dfBpMw|G%~#oDd;@X1j;~?9O&}o$2U0 z)7k}9^SPF;3qZ}_%#DA$(EiP(bKjop{7YxspW7S%0y*@vZCz)YyV{$(S{l0Qs=Eqv zzT3Owla))Ko$^4LkJnLW#X*Jau(LefMVaL+hm}Ew4B$nM^kf8VrJ%K(X@k@OK-hwU zse?3weX0+)ScF1OODV+J*GDEA!Hp^4H_HVW4kOa6KO*C3?2#(@3N5_0;=LWUv ziplVnukk&SR_fou7y5u^D(@FOyB7DDSIJ!x2alX)Gr-rz z=Kir`m$)joJ1dX5dsX{Qd?8>WS#!Wr0IA$OJuWL`4akf}B1Xkgg_1JFVdt^W5=ptc z_i2@u`~-lV0ej7wPkeQsAhDXS`88M927AXG;6$YYlJYdED9u@xgEP}x{EQYlIlTjL zlIbl42paSr0o}MlQS9no0@wa0+pbbz=_%qK%{}GJ-uJVQYPQGh!6W-g*6JSgGJI@ zM+Jrq(v%9iQIT^E@^w$|lSb2djrM|za|bfwLD6b5zTu)g=k9tQP9Q4pPWTwRI+uCD zHQJ-m#ktAD{VWW+v06LZMn_Sjm*;t3(+euE4yj|AqkSHXxQX@kJ`exZEjPfYI4+() zqmG_5NR&e`R#fC9uYsOi>vI8v3juyF2l&5eG`y%)zXnroh@UzB{5~YmK+qVn0saN) z#e+aIxEuY=9|V{`_A}rr)0YM82EelLVTPfN%KJr$xZTmAL8)jp z=q_V(2Hhp(B2;TGVuZ!XrBSS?agbHXT$((5E@A}_^&g@;>@q6D4{KH5aqPLUf>knbYa*d#Q7QPIvZ`AAXIJ;5lnxZqkJe9I^ zCpa67E3Usc+k<|fK<9qDc>QNJz{UaXz;M9HUoS(3VoZ+9X5B2uo*79 zW2|b(IP>r^0fe9j`VF{y!tH}5-7#p=9}t5l-#+60J4Zcq*O=*dj}E#U6nb3vV7thn z4za_qj}SAL+bdxN_q#gle7R2+uz-{yb>pn8cJV&tLiKZ0lbxpZWHKYn<)FpMC*< zh87og5a7@MOF_u%0e-6rejn0LMEr_F{E4|hQ~p7A&V~FLrfTn9`}u4;GD`RSgblx5 zdN=-iT2428cfRAN({2B#tGVWH3?6g$u=&%+*B?wcdyL#REBxxnFS`x zq78(?AXJWkH-)M)!n-nDRS~JGj8e13L8qaPEDh6W#r(ijaA|6%tq3AP531`-IdE6w843zkKx zkueY$ydp|XEIk(PAFxa13@9L?=F-wZUQ3GNnfk1FW9DpA=3L+Gg#kHBCg!e~T)sY} zYE#t7C*qp7FKpYh3|aY*_z(2B^>A|Qq12XxDJ=(6ft?Yp2dJ#ymskrYjs27zujyc7 z^PwadIJZ2ruJyp$w*9L+_5n4o?AX1cW7m@Q?MqH?UC_8bvVLt)#gh99=Z-I!?Ozz@ zS2WAFDArUEZ6MbXd_)h2YC-f6jWbseoG4tK>wu(%y>kc79X`$gnLl&dTJ&V+79QF# z&_+O4%mOL-AORx4J3|Y(T3V!E(dyvFZA*|6v3~QM#`Uq4OCE$-G-z{1h$kp6BhNkf zGhniiAq(q5&V1uKTZ){YL%j>aIK%C5qNy-u0jGjm2_mI*(DFI=!dSa=&zg>dNhkNM zYC5pGY4?)Kq|nTnz93rAu9ri;9!xGA@EBqG=M!OM$AS9`jvxqQowEB`cq2A%GKpfSkfm&cIG?t{2AmqE6@jl7Vzhz;LkHukU&ES4WTB0+tKO9y;Dv5A|~e~#8(5`S~JSs z7zi_xjFJ#E=c-{TtzI0M)q4$Wsow3sNehplX|D)x@@5faP>f8A@XpPc|L_6u=V==7 zX9%7lkp+A{JXHn$3?xfX`eF5nscQI9>)_9Xj&GJf6GP71m5dTRnW1Jzs)hWST`Wkf@feovf+9M( zU|SNB9v1Axg2`AsZ&zyG&XoMEiKSbU8h53fdVE>l+^I(b^;sb%A%AAP8Y>Dx?;`STZFeD?+UKX?7{ z)2GPng^znHMLA(_H8){_Adk6is+DkAQMt(GzqEs#|cb3$7xpZh%&q8eJ?0(W1aMt91 zQEO;ddBX_e*ubH2Hn&f-x!Z4)eTcXEu?OxezsJAT$Gz3ju^D;#^rkn|hO1ihRrB~a zom|^&MJ33;2G`=z*qNCfbo4l&~oi1 z7ngcsi4K-g03;@(>)RKC?whmq&!545p&N(y1=7Qb>V$C6!meVR*u%H?^8qyj9TIzU}AtfyU=m zt>#r<-#0wnJ0We=s2Wt>4H8EPp-UmGh4S3ZrA=g4Z8xq$BCdfh8p-BdU8-f`Lcn&q zNx1XV_X%Nq@4u_W-O^uh%=0<~Eup~$&Q-g>Nm-%Qo;K*uY1HR%-jH9?)#bFa;yINU z%s1YG&5K5ZER*jLf+p|rYtXBc0|tkn!J-YucWB5)cMTR9xZ=RhCfz51)jA)lka36Z zeY5dHaBO$COA<+|v(ss{&vW3MKt5CSNd#RsS z!^=hcfmZz)h4v$uJR7k>{YQ*u>kL;l+7~b$gpmk8b&Twy0 z%M(qn0^!}r$TLQZkZIJh5MM61NYh>9Cr~m3P0tSJu@9SlJJBIqyZw%iyA|@S5^3rf z+quI>JT&kw=K-+c0P`JSGhozhLlgr?YlhkSj~o>+WLUsm0|Ra!G#(WC4@2(d;=bEQ zJ$U!XDR+;aI%r(bV7uU88m>;140hp?B;IZ_c;vWEkM6tl z+?Qut{(9-m_u$WD`vCroM0j8QKz79V(&|sY5GMW2f5ZGgyuzOR`A=kWay@^BqTokd z3;eG8@V%~c9e?M4!=Qo@bCmx{{@n7zxsG4pJl53k>8z;45w{PHn&?xzZ*|-5g=e3lsT&1JKwq|AV`e8`^}{5f8O5+E8@8?^?JA-EeN<&JD&YY-{abOJ@ zWxz=zQjI)-u);tIPYe<*TT94UnXVOOcRM<89uAE4@e*i=RFNqU0r@NGr8&=MNnWo&Afn9Kn6twrB`TORh%UZQ&xtnW#ro#Q1r*JhSi0a|WbP|j_E6!{ z2Z~out4s~6e{5#+)_LuFmYg}b3Xs3!$eQLOtD6q3ZalcE;lOGx)->#2durdB#=Yy1 z`3{a5rw^ob?oTz|%m^Vlp9?8*%h6^X&cs~*Z* zbWg@?zZ0=A7}OpQR~ND&;ru{QmWJ#2 z`gN8jkuW*2h7~@8KX*5h(=`RBC5D`s0{j{9IVV_^7py7?QCEZ+ih{{5HErhjtYr^3 zY+Ka6cV*@J$eM%@(=Ta-uW0!2vd zdEoqO{FxDEzU0X>Dm@z6!!GQ=*H3R*RJkrVcMc^3t(-rpZo#D5IsVW;*T$Rhokdj~ z@&;N`2bRMt!|KJ+jh6+|=)N0&4L)&#JXpS^3YatT=jj?Ifd+FvHbaGg5eKZT(;ij;m&N~?D2diWr0IR@ucIy zFWZ$=xMdxUEA2o=%Y>6pttwv|lNLGg$W(P^kRIoOKX!{~IoOyPY|IWdqhzy4$sA0> zD;Q!R!85Xg3WKB2Imiqcqyvs7G%cji{qW}-AZRdWo-?DJFr=hqp$M;drnK zp3gZe!Wy=%K^oA8?Fn_8mlZCL!1o9k62hKmaUYlAw*-d6kX<4#RF5Di4Y#p{57j-o zuwqL>+T#g2rQ@Ih1MJ3#_U}86go9sy^-F*Mto7@s(a-;4{q-kH#?OC*{`oIo|M+=O*8A*ygGS-9!ukys z>2sEFSz*1;&NpZjE-S2K5jKem51-Gp|9Gb3dl)-+HvW9(RM)wNE|iTGf2%0?u&Vss z!lGAm3tq0M`KY$;uf>Ib-@p6QRZFh;8M3wBnI2BZft{VeS|wRPml6lSSdy>;G|3eC zu%tk?KJaHd(FxEGhLjndrjld1q==TBP{^zyO;boL0%jl-9s*NmE(jEJ*1^}6XatLv zbFR^xO*G&zLp_XpGj%RsVpV;w2W#e_G`~4Z&p!AwN4Yup4APFHhR1?ZUW80@a%BOI zT_(+ScdzpHZt-yIfM^zO0A}OcfXRO5*VR6k0o=rnr<|1MShh8t=3OW%4VtT7ZkIh= zp9S+oPslrw1kK-c4U71ApL24mcXK=C>Cx=v+V1Vv=Ht->y5;UtHDP><*{@jc_S7)D z1-A_hy8Z4@ThTHXmnWSRJ6)Ym_^4`-vJm=GSC@+h6NJ`p7<^xcv4+}oMXap0ljc$; zL8OP1p1|dkit;3OdEn1taRC6DgMGPFT<_-Gp;J8%?CcMCuD=G?f&kN-uuYK5sv*XP z4YER+1NvkcUtliT0uXIwT;TJ*P zZ*^}47oF+bQM$O6d3e_PX>aXio#{0gp6iV7AcG|QaIh`1J=c)_ z8T{Fxd&AS~StqAfclS=vY&-&ZBHUdrDwG{iQ>!$m9UMxOigFk}W4M7E!O2lb@|4ni zdQCBS%ZZRNGDUVAw|W|Hz5jLmnOoe_BDf;mL>dpQ)!&|Vqf+2vWPRD@$sG&i4uwj` z0vAaZA!v?2E2WliA8=^k&-Rid_TmE~$!_xY7jJWP+$tAul-bW5H)7%+ZgaD-8DnE} zx6NI*-(h>_aF;#DKNYsWby5_xt>8S9Kl9gR?OrPKN` z&Kt)#ZyHVU$Vlf$Mre|xcgk&S?yvz2A2Q1J=`ANNp8N7_^WQI@`RT)JU0)&X-JgDe z1Q)3#zWU-jkY`N(k3aYKi|(ImXZ#s>8A1Bz9{l;s@A1hq0>hlbxaM~$$@1n?kk)VKqxgDidiGl2o}eC zmc{AH;tZv6I^xe<#z0`_ve|^A0j0^|IhF*^h}vk#o?*42FXIBj;Bt^>d{aNiuX?Q-@cxXgavI_0YQZg9)9763;%9fJI=@+_`P}*)2;to>%Aey0Wp!qZHa$w65$OZ|nFZM}&PlYsI989G zfWXTTY2&((j6B+hP;-PAOBx8@4ETf)kc?GvSd!_M=~S=)f<}~w>ngaY3fHoz3D+X3 zA|QC~=ATUe%u0*xiPh(X&@M-kaq>ZoVVDf(3Iw#!nc;?`(WcU*(DvO+o3JeB&j~0Hi2bb<|vb%pMS!A%$2kaqs4_7=57&%gt9_kHRo{v10 zk;eS^2^DK+G;NvJwtr3gfwiait?AsgylG=hPJF=OAnzPxx(w6sLlU^tP^U>jFa#}Z zxpAG{oIHQN4m(>d$KiPb%ke&guB>$y51e~c_zqmf!l?TI(L9kBR4nY8`wD=42mt0x zsEatN9<%)cvt7E)*) zKGR065@=zaZ=?#xpLq#1KiQ)q#K?Wtd6?YiT-M0p!re}fk ze1`cm-j<9%qf#7Y0D=ZiNsI9>STeOTCHB-4i<@_?t-YQ5&XG)*Lp}Xfq*KKX647<$M|zzh!#UdS+L;f$A6afSvs8d(St*+D)zGt@xPkZyv56)g;EerolpT`5IRuPxq2l2?{Akl|<^Ecb)ULXM)XXbEcFe&8c~MP3^W6xM5TIK|9+D~_>B6$ zvLWHBgzEu_PMdDw@K6`S9Q#11|1(jO_eM_M6M0|yqNtKh%WsW8!-xa2=bg!rpkJ>- zUym!oV`|L8wFX`Wg0A10TE8Qu@~PFOo0n8Rw(Qh45}cpfk<_p=xp7BQ_2#8HOT!LD zOgO}mXV6_9J_`>7^&ZEFZbYGH=yHO!eFSp+aqOMxqPxY<0KZoLY{kfwTTmE1I`ET1 z1kF)sWJ0_yEEXIgMw%PudnnMD9```)Ba1M=frCX3*3$L!Gv`b@65@9}*g#)lgwa@b z8jd2=jQxZW2S)KQcyuDdoWDAxa?6_isY~nz-;RIg6f&2#mWzM=n){~m7I|`i|Hbsj zpYc`f*MIy0|D^o&&p$E#{Kc1D@4oX3ve=((`^TB)AI~%qe}<+P@VTS?yVLz3=>GnB z!GAip6#p&jVf)Dr4Rxd=M1Vh^ZU6Rs$3M=seb?Ub*UG|=4(vR;W@%1z*bZOQGC$un zp<(+rZ0J~*aQ2}G^VD7k-JFlOIcMU_Yl-N%7=8tguoBG$Fq8o0fgHjHS(0rp$$*ss zxf#HWLP2S*ASC9wF5m_xfrtrRvh;$M41<)?4nY9qdL)8nX(^7MSa}HLu!9(nN~}!| z{WGapnKK4f4mm4Ug8W~?k|x0bxvkKGtRgJ2p91u4(LY-OIL%@bYmTyFJp@ak8HTc2 zR;Y9;c6KdsaVz!qtnqL=sg&2tWQ{Nf_V>Hy=l7<{=Q48D$>b*;9IKIe&Dr@ZMA4K- zPyPOQ(?=%tRX3+jsG8k9PU{TM13~+nk%;YGa<$c7Re3)LBVx1h1sKfgea>mTPP#kg zsoZlls^bpg!~p|CZW}ml;P4nP)vgHvWfT1y+?-0_?JS1W)4oh5Z}9XytJS?|fcu2` zZH@kAC$|<`alS~N3HVIsA179v2RS-t7XS}r(EdV4fM5GO2ghP3WgSe9b;uc~zZzhE zXS^@04_^27I0po6?~q656XId+BwI@E%rKC3J$7cCnJ3SfM7t)v9r3r5W=0fu)bnBG=UXdu<5ne9xB6x9N=mG947+A6FvlusI z9tI=G3|!JPIpcpHg1%M$%=fomUyeU#$&@*GDjj55$TEq9fEZb@w=IJav`P26zb|~b zUk1^Y$WD8EzYH^N@?`dZLt}WsQ+3(X^F@3bKyJ(!fH1ucaXV5^`uM!z?fnL>4zM$D zF;QsbE;PP}n*>G~8qJG%;-GT(HDB@aZo=mSj?#Rw92qBbZAG~b(lVKIy}|S%8EBZ_ zhSxfT*08eC8s8#A8>HRTQszzEJQ(1B?j7)XoNbv>aSDS$e#Tb=Os{*nUXV$foL!rg zPPJlDsi#{59v|GdWH+S9fCCQ(#prcGPRkg8u=w*}cn%ivblcxLRlfN}=oQy%{p`I* zo905upYaq^Sg|udi>-vc1Fdgeyl?ZAj@e2vERwjFp>-+T=j7oJZ+yj3NBJ`%@m>dq zeU7623dtTP$tI1%*^VDPBH*qe zQJ)TF^9Cl4BR-yjQx4jSwbHe3`jTnr&}{0Q0Hk;+A5T$b9ptr+LB zW~}qNu`Y>Yz@JI*ynYO@vtk2 z`un-{Z)-o@_H#?~4{fbKH8*~BU{|HXAX|gopr>Q})8_i+#On)Vj3qI?<+1)i#}%`^ z%i=wd5U>=v0*OLXfH{|fKf~}jmVzKB$2oyIfuP|>0r(6*3L;b}fuQ5f;Lnxw0_qk` zu3d6(-O~F|RxO-VGB==TwjUyYCWx*nE84^%Up-35iQ$l(6Jf}X(B_5%R%`Ra0TZC< zrNAWYg@wV-0ssWPBvu*1X=suB4k_nYMm*qd)VUyQVpuMOaW=(RTci#ff&vzi7NI#F zZ9E=phTkvc=8K<{HT$0IIg@ke-B+<csGxl&F)NVj3QcYkYD}^V18??pbqg zPr})~iRbnuojs6z=9!eU2UE`;T8}Jye4IXzjOctOrSl-XomaISSlRl_s<^JH>V?V6CP{6jksG({*ZFSMZgY4QHG z8>7$dUwP`u*(V>J33V}87XDwO>k_Jh5E_9B&y#t8ENtZG-h2hRWvH@IBJm%V!Yu)M zk04z=OrgV6FcQJ-ffR~)7%o{hrQwPBZF|?8JDhUvU}F2O<=E$(1@{~c*W#YRN(ymA zaB*Qi9!w!GK+rb^&OPS#$)7E!+RC4cV)};9xVX5i3_4c<^V73c7ER^9@wc zH>ZCVGG}3(N6oB}pX{#O9Dn8k^$qay&CI$Hd5$q*uF!vjuM5HQP1bw!XSBey2MJO$ zqmXdWhz~tD1g$HJv_`ZM&oaI-&zb3;&%Gf}J~AIZ7)%BUCFFIS+3E$|v#~G!T(x_B zH**$txSl^(@7P$mlQQmsKc9Shb$9QKG?;>^F=xd){B z)kz*K-(-b(6o58E1)US9%A@eg4f4T;js@$|XWdhgG_z^Py1Jc7(4f}r*#!7px1EqO zP79B7nXxnD!z7U2&d4*B=#R69U9Hf7?Q?tM5=eKgW9d(rfg)VWnpuc_O$0ry7D z_6;>pB~)%$lomJTU?7=AlX=Cz%l}yjRH4o0Cwp+$o0;U7MY6?%532#;VWbQr>l1*w zp{9&z|Ma+tN8=|SntR`gWx)l>@dZh!A zCiuS%LjV-z+cuPL+fclXk`H1f81aDxN6D7NvL{y8JhrMLd4Ar~$c(vxxeJ2JSH;w? zpWpcCvf9)I$T?WJEb{oQ`wz@89SPE5U~w65?c{I)P$6w z$__DQ&M=(_9bdR4tY-7_y6uVeNTvGJ%Ho7snX?~C3-!gGL-35vrG=P}&oF{N7lj(i zpn}G5NvQ77tO@CfajA2Hh77Q|bHHtr#y{}x+kXNXru6as@Mk0q>@#k)|KGpr`sy>% zKlA+gkALiX{p$DUJN|sW{rfY`KSRpf+44(g>rePb68xDYzFhwF9%X<3u=EF?do0dR z{`IRjwNFqi^TE@x$-0wm1e^`a18L(ej1>M$MWkgF6|<5xr3s@ z*}KI@`y#w1v_2o`)t|z|82l3~)M%nKZF>C`KV7Sb(@~K_;)t=c?-&#`;Pz0_*hkDh z<@cB_-sAhSpZT)VxyIHZn<$?M@H1cTRO05=Xx6+r0hYGvHzbl%_Bj7egpMKACRroC ztOq(%WQdi=0Htw$(2irrrL>czIm+{#-0ESN3=pSNzX@SBd^tQk&WNRD$QVc>>R;i{ zJagtN9DlQ-FalzN%L-~oKH(A?P(WHhsk8`=C2-X+83(XgBzKHMzF2%x zr+(RA|CUMns+UKnL{{!7A(^Y#sY<1}2*VSY10&#n;_B5RQk0ByL_WA`Z`VsYkJl#} z-}BeK4APEUiw+hrTv{Y|s&H{{^wB;GO7HFSidy}q!T1q;xe+9brLDi==5^jqM5<=F zq7VzhhXgweH*6Z15FZD4gq1W6e}KhtOb?#`bUOfZHBgSQLy)gcQ1cILG zi*nayiL%+%{W)^~CKqV9G+#qDK&DmJz~~$4CgJZ5V{i+9#&E+sBwW{Db@w0#Z;j6d zwW?Dgt#q)*RVzhSP?@aS(;Y)9FTj|ch9|U?>kzb=Y{S8~jTq*5pS(WE3FiYiw`G?66ZNd0Z@7Wji`- z$Ux(rw~GhdHu$yyHUo#-jFR4A?>)%DILyv>$XNe@BmD1%B6@`1;F11=L7_)Z95iC` z-J>5EH2R@|c7cO!XAHIrA8a2z)N$4@>6{VD1!J5Rk9J-$+G+JD=Y-L)-2i-s;2F$W z@rWgqkB(D5I##)Pv|{r}#bd+ODH0odPXBzH&G4~~M~_xrJo^>W>|W~p>4UerzWltK zKT~$&FFB3w|NJ-l`9;^?FSi@F-rdd%t#Ej2{U$HHQzKJ(4Y650S$RC(kRPuDW}&=bF=p`O>Uhukc|H)z!ipId&RQ;~+Rbjd>{i|#9&H@RRQ^u3b`=S(b^jhIjnHz9A9f9^~_5*|mJ5Jal20Wg99 zAwgtC8lYIt4%dSm0*L?*f?xyQX2lrbC6W=X&*TD=*)vTPasFBH0oijWX3w9Ly>K!j zYtg-#OYX~A@o>SKz_R3sstqxx9-Z9?{J3Rl$Bq?k+m^NMSkbDaxpefzTZZA;s?EN+9O`SH2!o98rdjHycuh0jUx zg8K^Q-h(5Bu|vU3Ql95UnTUr+YLL{A1%%BozAmJoe26@OEQ|m{hLZ-&s5OiTRYd3^ zT_)>h_?&Q8gk2YISuOdBa0%=fF{Y)WvJ;h`HZlYw@3Ak`oyg>z{sYvh57 zQwY3^!>JBq3OJ&WeM%(R0s}-tevBc2VWR7STNV{BdI*;r;|mx^ zV6+*0nCXgp;APg>=PbUbun+3p?L?k27@>ygbY?j5XE0}?^kH6fDq=LC&^a*E;1u|< zaLix)aNVPGfS{Z9t~#}MMf)?W>Yj|tT5u0#kc1*MSXG7yRYOqC_7)hq2Ux~rpN*^= zPDpnkgQ3+q`FfVyt!)-!WMQ4>&kQf~*ck~i5lHUY9noC6&uAZLdq=jhnW5!pm3Pql{3P_PT!839Z zQtV3QSv03xwt7Sh!LpzZ_}njlMmHoM4-rR2fX^SJ|?#Lx25+Z0cs}JR$>sCaTOL7!DGe-T@AF zEKoyvQG?Xr&w$Sb(+NSN4&P%C*Yd>J)}4v5w1pkBtmwAH#k7GaUwkJ1kO+W&{L%~L9n8A=KaAv0Y;LIGI zra3%ab2!X5XK`TFql-`NPOjO#zI1B}@M-;yjrC8gD_R-5`(Yh`El_0oH1B_#1e%A& zfX_ny%-VVE45W-clo_Ko1r z$R`Mmefc&b&jlNo6eP^fS`d^LJ$ZkiY2Q@+q3NdMAptot_*D~_7W>eFh{=a%K9sX4 zIA`9};}QM@%%`g9z^CieW*7lxPlN@)mm@uPa>mSib7ntSvN)(}d2q@6DOnK#K)-2{ebk zv%>t2BUNGuy_5=Os4y;;8)@1bq3iU?!6otGoUzGp<6QfOs`PMitdrUO)w z=~BfBsqz>FW=S)|(&J#!2wZFMYLP>UT-FTR0loS)KNC_DUcpwxiUQmKzs8@Lm8;ZoowuNoFt;4+X2RM!vMpWvr5(9kg(B zi9gHJ9c0JkE}2r-Ok43WTTv!FF%+^oz4kdj-&ei8&*Reog|b1T!Q@q~21XohVtL&d z`{Hq;3U|+QzNTwPIEb+in10ivVS2-eu^3XMze~DkP6bW50s)`(Z^EV72sO2$*} zsM*)>f|Il!&ddr~g}Zx$#^;P#|MCR$HDBF3$O>xK!s_`$58^}7Uo~o8a8|Y;=ioTo0ypQ@iGDA-JJ*6U$}6kxDD%@+yUrLar>s8{_xA^n$lp9~xc)1ZnwiW(!5;!seLCd6vW%2_OXrUdCjE% zJdk-1gcoMk`mdJ6pp#bsaLlquy$2o z<%((LD^SAq!V(qBrz1eH31TnCe=!uOmo1%Ay8PkN6;q3?QMzh+`I;cu&mx^1$Y<>% zu_vF1Z`d*qsQ_DcEun0HdzW|YTh+OL?YRT%&hB4(X75_$p+i{AG!7)5IhY8q3_#|l z{cBF{TS-6?i|kp}x_c?sfc0Q)5cJkR9#_3Fx-umk+X7)LU-mFib6(tdqUGUw1a#ei zHgG6qfltK?!nFkvlo=4Xm_gnAC~pcb@f_pB%tNCzN`;`SK$#H9E*n~9h?ZfRLGBrl zDPkqol#66n!nvA|&k5HEg)nAomP7M_!?aItqa

N>{0O<%} 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%0DHK}Le0wWUwRoE4Ei)BKqyeYhn> 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

Q6u9!| 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