From 9e3a746ebf3218f3d4c1ceaf9085691e5119f75d Mon Sep 17 00:00:00 2001 From: portnoytmy Date: Tue, 3 Jun 2025 01:57:27 +0200 Subject: [PATCH 1/3] removed comments --- analysis_model.h | 44 +++++-------------------------------- main.cpp | 19 ++-------------- ring_buffer.h | 55 ++++++---------------------------------------- sensor_network.cpp | 54 +++++---------------------------------------- sensor_network.h | 19 ++++------------ 5 files changed, 24 insertions(+), 167 deletions(-) diff --git a/analysis_model.h b/analysis_model.h index 4b4be10..d901b8a 100644 --- a/analysis_model.h +++ b/analysis_model.h @@ -2,50 +2,28 @@ #include #include -/** - * Implementiert das Reader-Writer Problem mit: - * - Mehrere gleichzeitige Leser - * - Exklusiver Zugriff für Schreiber - * - Verhindert Writer-Starvation - */ class AnalysisModel { - int value = 0; // Das geteilte Analysemodell (vereinfacht) - int reader_count = 0; // Zählt aktive Leser + int value = 0; + int reader_count = 0; - // Synchronisationsprimitive - std::mutex model_mutex; // Schützt Schreibzugriffe (exklusiv) - std::mutex count_mutex; // Schützt Leserzähler - std::condition_variable no_writer; // Garantiert Fairness + std::mutex model_mutex; + std::mutex count_mutex; + std::condition_variable no_writer; public: - /** - * Lesender Zugriff - * @return Aktueller Wert des Modells - * - * Funktionsweise: - * 1. Sperrt count_mutex und inkrementiert reader_count - * 2. Erster Leser sperrt model_mutex (blockiert Writer) - * 3. Entsperrt count_mutex während des Lesens - * 4. Liest Wert - * 5. Sperrt count_mutex zum Dekrementieren - * 6. Letzter Leser entsperrt model_mutex und benachrichtigt Writer - */ int read() { std::unique_lock count_lock(count_mutex); reader_count++; - // Erster Leser sperrt für Writer if(reader_count == 1) { model_mutex.lock(); } count_lock.unlock(); - // Kritischer Abschnitt (Lesen, kann parallel erfolgen) int result = value; count_lock.lock(); reader_count--; - // Letzter Leser gibt für Writer frei if(reader_count == 0) { model_mutex.unlock(); no_writer.notify_one(); @@ -54,22 +32,12 @@ public: return result; } - /** - * Schreibender Zugriff - * @param new_value Neuer Wert für das Modell - * - * Funktionsweise: - * 1. Sperrt model_mutex (exklusiver Zugriff) - * 2. Schreibt neuen Wert - * 3. Wartet bis alle Leser fertig sind (Starvation Prevention) - */ void write(int new_value) { std::unique_lock lock(model_mutex); value = new_value; - // Verhindert Writer-Starvation no_writer.wait(lock, [this]() { return reader_count == 0; }); } -}; \ No newline at end of file +}; diff --git a/main.cpp b/main.cpp index b608ad5..9b2ae67 100644 --- a/main.cpp +++ b/main.cpp @@ -4,16 +4,11 @@ #include #include -// Standardkonfiguration constexpr size_t DEFAULT_NUM_SENSORS = 3; constexpr size_t DEFAULT_NUM_ANALYSERS = 2; -constexpr int DEFAULT_RUN_TIME = 30; // Sekunden +constexpr int DEFAULT_RUN_TIME = 30; constexpr size_t DEFAULT_BUFFER_SIZE = 8; -/** - * Führt die Simulation mit gegebenen Parametern aus - * @tparam N Puffergröße - */ template void run_simulation(size_t num_sensors, size_t num_analysers, int run_time) { SensorNetwork network; @@ -30,21 +25,13 @@ void run_simulation(size_t num_sensors, size_t num_analysers, int run_time) { std::cout << "\n=== Simulation beendet ===\n"; } -/** - * Liest Benutzereingabe mit Standardwert - * @param prompt Eingabeaufforderung - * @param default_value Standardwert bei leerer Eingabe - * @return Eingegebener oder Standardwert - */ size_t get_input(const std::string& prompt, size_t default_value) { std::cout << prompt << " [" << default_value << "]: "; std::string input; std::getline(std::cin, input); - // Verwende Standardwert bei leerer Eingabe if(input.empty()) return default_value; - // Konvertiere Eingabe try { return std::stoul(input); } catch(...) { @@ -58,7 +45,6 @@ int main() { std::cout << "=== Sensornetzwerk-Simulation ===\n" << "(Leere Eingabe verwendet Standardwerte)\n"; - // Interaktive Konfiguration size_t num_sensors = get_input("Anzahl Sensoren", DEFAULT_NUM_SENSORS); size_t num_analysers = get_input("Anzahl Analysemodule", DEFAULT_NUM_ANALYSERS); int run_time = static_cast( @@ -66,7 +52,6 @@ int main() { ); size_t buffer_size = get_input("Puffergröße", DEFAULT_BUFFER_SIZE); - // Starte Simulation basierend auf Puffergröße switch(buffer_size) { case 8: run_simulation<8>(num_sensors, num_analysers, run_time); @@ -87,4 +72,4 @@ int main() { std::cout << "Simulation erfolgreich abgeschlossen.\n"; return 0; -} \ No newline at end of file +} diff --git a/ring_buffer.h b/ring_buffer.h index ee992c8..1bdfb0a 100644 --- a/ring_buffer.h +++ b/ring_buffer.h @@ -4,30 +4,19 @@ #include #include -/** - * Thread-sicherer Ringpuffer mit fester Größe - * @tparam N Größe des Puffers (muss > 1 sein) - * - * Implementiert das Producer-Consumer Pattern mit: - * - Mutex für exklusiven Zugriff - * - Condition Variable für blockierendes Pop - * - Überschreibt älteste Daten bei vollem Puffer - */ template class RingBuffer { static_assert(N > 1, "Buffer size must be greater than 1"); private: - std::vector data; // Speicher für Elemente - size_t read_ptr = 0; // Lesezeiger (nächstes zu lesendes Element) - size_t write_ptr = 0; // Schreibzeiger (nächstes freie Position) - bool full = false; // Flag, ob Puffer voll ist + std::vector data; + size_t read_ptr = 0; + size_t write_ptr = 0; + bool full = false; - // Synchronisationsprimitive - std::mutex mtx; // Schützt alle internen Zustände - std::condition_variable not_empty; // Signalisiert, dass Daten verfügbar sind + std::mutex mtx; + std::condition_variable not_empty; - // Hilfsfunktion: Zeiger mit Ringverhalten bewegen size_t advance(size_t ptr) const { return (ptr + 1) % N; } @@ -35,56 +24,28 @@ private: public: RingBuffer() : data(N, 0) {} - /** - * Schreibt Wert in den Puffer - * @param value Der zu schreibende Wert - * - * Funktionsweise: - * 1. Sperrt Mutex für exklusiven Zugriff - * 2. Schreibt Wert an aktueller write_ptr - * 3. Bei vollem Puffer: Bewegt read_ptr (überschreibt ältesten Wert) - * 4. Aktualisiert write_ptr und full-Flag - * 5. Benachrichtigt einen wartenden Consumer - */ void push(int value) { std::unique_lock lock(mtx); - // Schreibe Wert data[write_ptr] = value; - // Überschreibe ältesten Wert bei vollem Puffer if(full) { read_ptr = advance(read_ptr); } - // Zeiger aktualisieren write_ptr = advance(write_ptr); full = (write_ptr == read_ptr); - // Benachrichtige einen wartenden Consumer not_empty.notify_one(); } - /** - * Liest Wert aus dem Puffer (blockierend) - * @return Der gelesene Wert - * - * Funktionsweise: - * 1. Sperrt Mutex - * 2. Wartet mit Condition Variable bis Daten verfügbar - * 3. Liest Wert an read_ptr - * 4. Aktualisiert read_ptr und full-Flag - * 5. Gibt Wert zurück - */ int pop() { std::unique_lock lock(mtx); - // Warte bis Daten verfügbar (verhindert Busy Waiting) not_empty.wait(lock, [this]() { return !is_empty(); }); - // Lese und aktualisiere Zustand int value = data[read_ptr]; read_ptr = advance(read_ptr); full = false; @@ -92,13 +53,11 @@ public: return value; } - // Prüft ob Puffer leer ist bool is_empty() const { return !full && (read_ptr == write_ptr); } - // Prüft ob Puffer voll ist bool is_full() const { return full; } -}; \ No newline at end of file +}; diff --git a/sensor_network.cpp b/sensor_network.cpp index 038a7ca..62af088 100644 --- a/sensor_network.cpp +++ b/sensor_network.cpp @@ -3,43 +3,31 @@ #include #include -/** - * Startet alle Threads des Netzwerks - * @param num_sensors Anzahl der Sensor-Threads - * @param num_analysers Anzahl der Analyse-Threads - */ template void SensorNetwork::start(size_t num_sensors, size_t num_analysers) { running = true; - // Starte Sensor-Threads for(size_t i = 0; i < num_sensors; ++i) { sensors.emplace_back([this, i] { sensor_thread(i); }); } - // Starte Analyse-Threads for(size_t i = 0; i < num_analysers; ++i) { analysers.emplace_back([this, i] { analyser_thread(i); }); } - // Starte Controller-Thread controller = std::thread([this] { controller_thread(); }); } -/** - * Stoppt alle Threads und wartet auf Beendigung - */ template void SensorNetwork::stop() { running = false; - // Warte auf Thread-Ende for(auto& t : sensors) { if (t.joinable()) t.join(); } @@ -51,29 +39,18 @@ void SensorNetwork::stop() { } } -/** - * Thread-Funktion für Sensoren (Producer) - * @param id Eindeutige ID des Sensors - * - * Funktionsweise: - * 1. Generiert zufällige Messwerte - * 2. Wartet zufällige Zeit (Messintervall) - * 3. Schreibt Daten in Ringpuffer - */ template void SensorNetwork::sensor_thread(int id) { std::random_device rd; std::mt19937 gen(rd()); - std::uniform_int_distribution<> data_gen(0, 100); // Messwerte 0-100 - std::uniform_int_distribution<> sleep_gen(100, 500); // Intervall 100-500ms + std::uniform_int_distribution<> data_gen(0, 100); + std::uniform_int_distribution<> sleep_gen(100, 500); while(running) { - // Simuliere Messintervall std::this_thread::sleep_for( std::chrono::milliseconds(sleep_gen(gen)) ); - // Generiere und schreibe Messwert int value = data_gen(gen); buffer.push(value); @@ -81,22 +58,11 @@ void SensorNetwork::sensor_thread(int id) { } } -/** - * Thread-Funktion für Analyse-Module (Consumer) - * @param id Eindeutige ID des Moduls - * - * Funktionsweise: - * 1. Liest Daten aus Ringpuffer (blockierend) - * 2. Liest aktuelles Analysemodell - * 3. Verarbeitet Daten (hier nur Ausgabe) - */ template void SensorNetwork::analyser_thread(int id) { while(running) { - // Blockierendes Lesen aus Puffer int data = buffer.pop(); - // Lesender Zugriff auf Analysemodell int model_value = model.read(); std::cout << "Analyser " << id << " processed: " << data @@ -104,27 +70,18 @@ void SensorNetwork::analyser_thread(int id) { } } -/** - * Thread-Funktion für System-Controller (Writer) - * - * Funktionsweise: - * 1. Wartet zufällige Zeit zwischen Updates - * 2. Schreibt neuen Wert ins Analysemodell - */ template void SensorNetwork::controller_thread() { std::random_device rd; std::mt19937 gen(rd()); - std::uniform_int_distribution<> update_gen(0, 100); // Modellwerte - std::uniform_int_distribution<> sleep_gen(500, 2000); // Update-Intervall + std::uniform_int_distribution<> update_gen(0, 100); + std::uniform_int_distribution<> sleep_gen(500, 2000); while(running) { - // Warte bis zum nächsten Update std::this_thread::sleep_for( std::chrono::milliseconds(sleep_gen(gen)) ); - // Aktualisiere Analysemodell int new_value = update_gen(gen); model.write(new_value); @@ -132,7 +89,6 @@ void SensorNetwork::controller_thread() { } } -// Explizite Instanziierung für gängige Puffergrößen template class SensorNetwork<8>; template class SensorNetwork<16>; -template class SensorNetwork<32>; \ No newline at end of file +template class SensorNetwork<32>; diff --git a/sensor_network.h b/sensor_network.h index 1480dc3..8f54024 100644 --- a/sensor_network.h +++ b/sensor_network.h @@ -5,22 +5,12 @@ #include "ring_buffer.h" #include "analysis_model.h" -/** - * Hauptklasse des Sensornetzwerks - * @tparam N Größe des Ringpuffers - * - * Verwaltet alle Komponenten: - * - Ringpuffer für Sensordaten - * - Analysemodell - * - Threads für Sensoren, Analyse und Controller - */ template class SensorNetwork { - RingBuffer buffer; // Gemeinsamer Datenpuffer - AnalysisModel model; // Geteiltes Analysemodell - std::atomic running{false}; // Steuerflag für Threads + RingBuffer buffer; + AnalysisModel model; + std::atomic running{false}; - // Thread-Container std::vector sensors; std::vector analysers; std::thread controller; @@ -34,8 +24,7 @@ public: void stop(); private: - // Thread-Funktionen void sensor_thread(int id); void analyser_thread(int id); void controller_thread(); -}; \ No newline at end of file +}; From e71c96d8254e4d8f00b990d75ea67f04e4cf10e2 Mon Sep 17 00:00:00 2001 From: portnoytmy Date: Tue, 3 Jun 2025 07:38:26 +0200 Subject: [PATCH 2/3] added executable to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 80ccb77..95c692b 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ Makefile *.exe *.out *.app +sensor_network # IDE-spezifische Dateien .vscode/ From 1612d8988dc7c8a4339f0ea28a132bc240fabda2 Mon Sep 17 00:00:00 2001 From: portnoytmy Date: Tue, 3 Jun 2025 07:41:46 +0200 Subject: [PATCH 3/3] added executable to .gitignore --- .gitignore | 2 +- sensor_network | Bin 85008 -> 0 bytes 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100755 sensor_network diff --git a/.gitignore b/.gitignore index 95c692b..f300b53 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,7 @@ Makefile *.exe *.out *.app -sensor_network +./sensor_network # IDE-spezifische Dateien .vscode/ diff --git a/sensor_network b/sensor_network deleted file mode 100755 index a918fbc171ebbd4db0f619bcea1b551b07d61c64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 85008 zcmeFa4SZC^^*4SK5{L>UDp;zhi-HXbm`wr%L=7*C8weOlf)v3eBnzx=UQ9M2SkTxI z%No+=XQ4%lmRetEwMy$-Y7v7XiI!@lR#T-K741f-rj}}I(fxnV%$a*Y#sc zImEvvbS;$k3hL!VeRa%lgR{~lUO~Ma*`{}=r1$QNgbr>*9Wl|xddA}`p>{k?NWect z!W3e_rJ%AWiK9;*+tUuSL8B{M{A(EYa?M=M4o5S;f>Z}x1nD#SH+0t*It11u8V!J6ysIQc&r670M|Sv&en{cZ0Ej>xqYC!`yvqTGe}kQ`x>3m%Je z+`l8<*kB}3+u{etB{<@ZgoKp%lX8t4mJ#no_>9MA0zOWB$fYyz$;4+OK9lg7jL#H& zrs6XVpG)z%9G`4_uKB^9&6&4fx_s(wORd=hV&Lu=@w=F3P!o{Fu_gGbg_O z!2SQsyx}hI+}R)f#COB(|1)(`?gxvO-SvmexjjRs%~KX4{-4LNLqZJvQ!(_U*x4&x1U|UuTnJ zzz&4Jko7r-`F|q(FTy{r$sVXz6ex1#kz7lv zb0P?`5waQ=B&1cB`EIE8dMW~yIrH;9s%B6!OS~(Js{H{p)$a{>bMl=Ymn&~}O%17) zADDusm-@<}X3g=b>2yM!;-ZS8Vqaj5s}w>Cav;`QTkNd}_{z(qRA*Lkd0B~%5T2T% zN*`G{b2ZxQT0re*?fvD&*Q4;n(&~V>mh>y}=hcwN`T6DkDwi*|teH+1>+j5{EGjE0 zFGYK6e8t`=&~BwSP*dbr3}3e&oaxlS@-p;Sb#WjE-RyGJ6nOHp(7WkrE6OWZ7gd&c ze6V9tpd7tev{I`1wd+YkJtbaLQ!edz96m#>l|CtY;y5JCN*8uQr$B${+zMXC`Z?UqsX%yW2+3#5hz}TqWZw8 zT7xlHDhCdAYknZJ7^CPoEtl?@PWpLP`7oYmrenk`n46!0Ax^`_<`6WjR`|+%${ixd zs@eQ>r?0%qgOTd>Ah)h8s$7GX`2sM3XJu`zr@~uVRbE!)htGRz(oj(WhF!FAKlkeo zeCH&n2%nWkC#RCS9*-y*oW3d#jAIP|ZgJ*y<-RiR?DVXN&aSL1TH`76s`y6zj?QzU z>97U5-hdS4js)n7kvN|nJn*GF!wmzSq3?O6{3ng%8JO7 zA!BhlMxD2)G^e=0Np~NJ_1X{8u%+} zJWe4rC8dk6uVuY~R zad>T3X;CdA-;L4*j>9t%MG@|ORTbq`QU-;<^6J2Gjv`@dG0bJsK!J)vu(zzl48X^u zCG}vWScC%S6csM~DaLk17xyO_Px5_{xF2Nf<@-NAay?cW1C2lN zeYT({8eM!J7<)TbGzrGXd|xT(1B`#;o~}61u4fwE5A*qk7_i>SqE&{m>3@EN70$`V zFus3G+$S05@_qH0KCF!5jSF#4m)cK8rQ%9CpTF?BPvKk7W4aAr$M+*_c*hNr-(kbg zVSK6$zmM@*HvAU8&$i)fnBQ%~Z)1F(4S$&N8*F$-gVb}I4PVE2;}uC)c2M`K-Ly=n zH8c4aT}od&zM16{9u8(++hgEcUzRNBOxiLquXYWu>Lg-^h97Nm8%C#wPu1{U8h)&X zPvZ8Ho@#ARAOv5FSbsRR*xOZjwSFf&?enTj?Qam?sgMLavH9tV+^Y4~J~f0c$mRl`?kczqwRR>PmJ@z-g1IyX?)1`R)4Apx5;{23a4 zi-!M(hTo>)M`-x%8vdIaeusuXOT)Kl_>mgERm1bqouIaB_;WS>4h=s_!*^{E4q8Eb#xL1^$tI&gbs>!%6PO#1|eh40l6oAU@pTuHTdN zoM>)%;)_6s$Lzzu$>(O{8{MxWT6b3%*O+JNo7J(A?mTgS zBi&Po@6HzYm2^*`y*o|ZUq|;8(z_kvemUJ!DDO@Y_lxPCLU^|!?ibK~GTrxl3B;H= zbe}@^UE+QQ-BSqf?hyA=>7GJ&cdNKhr+W(7-8;nng>+A$x_g_rKacJyM0Yof`!ngD zLUVVWxIc~VDI|ASi2IZ2o?%i%3> z?Gkrm!WhcJ+(B2!+3Id;XohLr!M4!9;OOqQhFaW`i{on@zLNJd(^K?)m!N_D)}e;c z*5C&V8Q9&lnZAOvfF+X;5@-jcVl6w#C_2) zp=a{?XTj6mLX7pF#|0AI!RHR$Ow3!4QcVpTM7_fYE+I*YSCi>w_0zr}`g86^$w4Xdu3mQ=WFw7PYGH%bJ)qzNCBYC( zVIsBO(D;bh2t>0fFIGuW851=Dz^Hob52p}QuxEqo2-TYWMBx!>z$!GpIa22p$se~S zpK2tZnw_#D`L%2Zgh(A&id4HT)DB~zXdjwvGI6zK!yRBcYD#@;5_RaKWMO%qM)yCr z?ibPh@BS@>iZpSFNQ8eBd3j~C(*vI)Jxnz-+-B*6iTEs!CgXspdTj> zB)t}qaqa~%-cHO+ey$OF4*k|D)Dpvs$E;A#uqgAQnhPVMftY>^N1cZVnm{NC(T>YsM> zkLZunWjpC!^v6Y?!+2nz!777FVA7$BX~=O6)WywF2FLz?!5GkB4g`drryDUiRPQ;^ zyb#GnjKWyJC+O;J7Bx{R2jY;~XEc`By)nRxJHQTvG8Sx=ZMRjgvo&-IL_la4Y}17j z?Hnmu1++)gYL(WtwasL;eNV^2d+@F zsIrL)i5U67XW?*tZ@BvOP$|AO8uh&i)q`5lOU9u@G3wX1R_{9$M~&~b%$ykdL2o$B zL(?`Cs1ZE!$X8N@F@x2pun?NeLnD^LxS}yiiJyzc>_#2X{aJVLC5nmT5$VB)XgrT> z6cXsRPypydXNtH=xV8{&wNW4A>y1!Ki*xmd9a>MymVbNefmVWW+63Q6@DG9ukVSA469<` zQzW1sbHivYaOxepIy6@|x?0FKK{#O(IbvJr8AL?c6+0vaZYurnKBA0$&K-P1^m`Nf z(Q>-IV#vV<^@$b@n2H8O^j{iO>D1MLRiK9G?3q-9uhn?*&P$@$XsoQF2USGa==Fb^ zHqwT!n()xNDbH37By$}~z`wm#Px5s26$aV?RmcV}19n0{2Oz?s#I%KePvP$pS4;Bk z6r;d|EQ0)J{hNXF!L0?d#L#$XiiBWSKDl>WsO$*YhI&9tPGGZv#AeRzeMcOP92!N^ zb=paRMiF!{c!W2722{j=Y89bE*m$fdT#t>tBH{(%lVV7;g$$9t(D;R?k$g~)NkHo! zSszNwNHSxl42r0r8s;fPIA7Oc1kz9%DAHC~4LwIbMiR+?=g~b>7UQo%AHm#>TK{Ch zYf!YhRreg}!0pma$r({uTj)!Q7?>~`UGOV%ZG>bQP!AGi%5%wEL5Q^Yrhn)bj}hYC zE$COe&V|qpZc7(n7q<~@!I(6;;3MQQa-6^{qH9E|Ckz_l!>2<5E4N9bF(Pa!4M>$h zfG{Lg#)jh=Otg99KSU(squqrFeOOm$+EQ1xsyYcQg z86<;wDOOx{m{Q48f)vEbFGNQ|r0B>SQG?QhW9P9)OUQ>@Of2>5x{Sa@&`H`<+L(L> zA6L&)r~^GK>iY)Vv6&|}bM}fT$dRqu9TNt6!?#t~xHeXINtxD6iG-?>ikjCqW+%y7 zW%YrxMM1){3>v}0kndTUx{8RMa)>MieCruX{X=QLS%%k$8D34~O3&$6PhU8_aC!myI}a8_pH**z+%0;4cZ#`dyIUsj=pSg?7CMN8 zz}@DeRkv}-jTUWpH?@d7p1z`=bDJh!i+DHv8RE!ARLiC4)-(^DFPx_p%f--b*fl}f z9dM2~6xt!aU*g(U`EVcEVntxe9`gxundwhU*`7uQI9t@w4%gQCFlxs z#o8tb?L;_&k+6%XB=lhrx<3&9vsnmgY9J;}Ua(;YA(}Qz(9mL$pO;c4rY-a*ajV3T z5-g?)gkZyCglKG_rZ#S-8yPy*Q#UjXubE3Aan(;qFA-Bp50QXp8ymM7P=8A|_4vO}{>Vw^4r%yzCtY}~Xk$1tl%&muH^mfp76qc!+ zgNm9G=if>73CrY*I-YHG9h4S$Pu_zmk9Z|=f@12G_q$A{EQ{$R#dK6M-C;6)o?}Wn z*iEe<huyA)7Ee2rq5SO%v}2{QOOFt}#BOfqHv zZh9)Q^mWs0p-o$;1u&E$s-*2owdzQLpY}pBwzyQE?}w$=w+03aEG&LlF8IKq;$1G8 zUzCxdw=ML!oXNnWHp)UKh73nNmnnx@FMU4>U*Lq6mlqf_mM-A92c@7zV(9V@M0yjk zHz@aogrxQ4$dTFgbQHC+WhqrFfgX^O-+#YPQK%?dW~Q)O>4*&eR;vMOwCe+b=1Q@x z&=z`63@T9=Q;KpDIt#&O0W_yc!`x`N9gWpC5cEw3OnRGI<*GTj?r5;O7aefE>nN|I z*?JK>i_#r)psCg04vI_UNtjQ2+gv>$8kpR6g~J#)ZK1p2c0t#X`gKPJpf=71&vQ2o zd0`d|(=_~D0TPQ{7?GdwhXQNEZ=3X%H( zL-Xh+V&7GIF^#84yT5P1Mh61s_QtlUDy>qZ0ZMTbyO5PeA&%Ywz)gVlTb z8V!pN>@HYFyH4)3wl@~;5er1n-HR|V0Lie(u3iq!C+&FIyH@gRiBe=smJq#fOLo5_ zTQUWW2t7tOR!j7V&j%0ZiMGnooQLypI744QW!_IA%^K}#Xn7|_dxze1b5m37)rb^c zE+f!FO7LlUN-K=hXpt;W3_9dpGYApsd~cUFGDKw*YhO)%!u2ZTpytBf4X%&tydTH) zjjC>JE6d>#9~mTDv&q224+xMr1Yp;nIY`#N9WAO3mjxb_1rFfH&AZ;<0$0caagjCr zO%}LO7I=^fyvYU5Kmi;HeoQUBHKmzaVp&_X&~8e!%)oUh(OvKAiQDV?7z0J@W%STK zRg>#u&TMAj$p%br*fn_#!eREvN$yvu*s3WaGLSCh_zzLvTb-LCLOIj!hjhi)61HNQ z@_*q4=#O@|8u}Lf3xV_#S9g#$QrjsJqgefRXaQ;wd!*ILNX_1YaftP%x5!K7X3xzc z_rXp^oaQm};3Fhe#QWPJLv8Ykn#MpS8VHay3k{9%ciC3jSu?lN#7q>Dn>3-lIK%)6 zw{4-DVQKmfTwD}OBtMazq-SXus!>M^@rk|&ocs(r-U$8RFQR#v0L9Y|-#{JWJF3i+ z#~;0L3`1d_qyQuN~$gbX&-3Q$;w=(Pc|W%aIRcjH}>;jL$qs1N?~ zb~v09+%tU_bvT-~0sLFg2z*>rb{pDMy9_sXKpB8a|O_9eItK%Tiiq$bC$&I@nNWcfpq~q`?(jNV@ zE-l530+HkYALwXX#0yp*3Cb7&*2Z~9q@gQdxju2qTr)+Shx`JpsvRo!Kw0Q|tWOqn z;ISw)tc&vm_=X5p1F=;=3wHg=|2>6Hc~I6# z_kR^G+V{zVd9SM{3r@$kV}G(>Vy9_+HCM*Y74-!BG6eC)rF+n$7!@?HE^u(`dtsE| z2qIt>NX2|~u4Kv+IA)qc?WA(S84}%?=MZetg2GyoEYXVGm_34G^(Hz3Yu}KUD#~#3 z_lwuW7!!7Trx)MhZPqF(F_Z(#$f>t){zwkm7J3@0V`h=79W#FDDNpp(hEvvt^B<8f z^Er^nm+vJPp*SF>j|C&R{eOh-HHsyMpb6U`RtWbwTNJ@;BW=?{Pv&SVh=Higo>WKX z-3LD-r|CqM)P8d#A&2aPR_+E2O`{tus3~=~9MrTgM9BCf0Sor;`=15ap7sNtR(l8Cke2g=%yc9_i)}0}n9?>!x$H_xSpjjcMPWVge zVLD(J+TBF<#;N+IR*XVqR20gylic;a$ztWsi*(HktSBhE*m|_84+V$M%C>!J)`=o$ z8XtU%pF)sRO&4@(heJ^V5dOr}1I^9Tb4msJ(LsCg%j#W>WIV8&42fui7}Y^o#q!8y zFjz~plt3;FccA(X6y6TlNu3A{=!A*Jh0rtPz6cMQ;HDi&JWkP@Tyr@ld%A1UPrpB= zg+!3z6lxP4c?b25h?OR48&HQ%l02>+REJS-t;Yun?;_^5(C9CyYq40t5j7n>QWo-Z zXeN9Ehk%s-z$YmTo1)LB0z8YnE^3bS$4mB`{%B>-a_{!(cH$2{-YUT676F=e0O+HG zQmCfkAEi^x4OBv=me5sXWx<9nDp&tB0mUMEq#;BESw=Wyu%So8K)}@^fKduA1dEX- zPz{~L*d&2Ec@<}Jt>}>!(R_6JSghvgfii59HS}tt8#fD`WOvLW+XWj8VPpw{4N2mz zNf>~+8y^=eoV+cfQjHB{4Ae+{fe)LA5@`A~NyAZYO`pew3Qg1gDSJtZi^Bus)#z~g zu)Uv7p~{1gj}U-Y8k@xmBPjEFmEJdGNu?!Vmd#?Z(8z#`H;I);BLf!wc%H0bkpOb7 z5p0l)3|{^;h{Z$WU6Pa65O@4BVhtfn1m%*UQ7%Lp8%mizHV8lK7rWgXb>F%iNKu#N#nxJ=Wq=Vk9nN1;b>*fkLd;RKYA^D(dc&~)3{ zrwT(YH+aa+RbMG0LnjOrk;VV=CF*_bx4w+&`7XM-We<%&^voL_uwzSy7eJ&V zJ##d`{n;CGyQ2%-UEtzeUWG*43gK;t)idj+;g7E&bJKKZ&KoM!Fk_hpJ=K1RKD70AcFV~aM(c*IGlkh&;i&D=rBN$;e8VkiSuOa6UG@2B8z|sqd54fTJ>!CIx z5~Yn?O<%=G`Q{!GjtK-Sj1Y`h-F0Y*C`->MiHSaetRrjK9XiMDCK zw3%eZF&X#tYj4;igy02w!i!>K&wb0fo^qT+*4!zix7F3*+*&*tsQOu*HfgJ}BckVe z;X`usy%&)hEyf--Quv?hM@iepqt2$`4+xN$G662?hY3i%`WH=0)BcV;Ib4TWQeEc` zZmvZ?=tF_>^ETIZvR?~GZG@9hOl5OYS`9&yIChnR;_l65GMwb%oSSQyF-p3?TL1ok7hh8 zrZY-0=hZCGW_n|f(w}F3~dkU1?EWTah>ZoiyLc9#+;8!6=VMFQ)-S<2~~6=xstN%G@G1bPv2hA)xOG ztvY2B8BrYyo9iumR{Sc6wv`yAZT8+4>nCa|h4yx`6a8sNkpeY2)`hlP;0no7i8UD=F`SDYC&Irm?STors>Dht z@%x`W!Z%t-#2=p%-$nWINO8-gd8qlV7^d)2(Mf9vjpoMzLH;G{&LHd*S6Ag}3KOPh z4C$d_dXz%Q{~Iue5^#r7k@LkDLJR$=A%|(aV}C;YbS$Q)LZ?u~2##o$lbu?1 zqzLn{8JbYU95xY@@Asw1?74@xWm4Sr&nAfjb^IdNvVMe+;=V$-V){Y7vOjef&`2k3 zGavo1Qs39ZGncAuOVPH*!h`PQN3caezTxUcst(&<;yPHBg@-CX>lB+fpH&|W79OF; zf}~Bx#4dNF@(mJ0*`3l%p9dR7s_ed0WY6>fov`uy^1(NBog_E8DKvp}8zt7_Yh!|` zB4nR}EK}w1ySoOBsarViE)9_k1^0ezAws9A?@A}-+``XNgvRF9np%prQ}~J&y5N{1 ztdi@tg`N-&676?9TZt0&cRc%^p|GXRE@|*5tbZHLAE?V!tf-(+RIuCq)XSgczjxnH z_Bh zr5T_tbcp(k7Ipjt-=mbFiw=v&IEma@duNwfl^m?Gnps9de686tl1a8bvwn4V^pb8 z`^L6NAme~K4PFFwx1-i=2$owAB%5{jqwP%E%!BT;T5%$r3Lgx8x)Xh%od}Z}(0Lx| z4GEYf<)$kn(xwwW@^ttDwB9@&ZsF76U*K2(nf_USA~3H-)+QpfhpG|3&}a)0mpmON z4d`_E7EsmcFl6DcF@Qxo9aenb249rZ;RT`%*n0pZUxhcSt*XS(L?YJjSrmCXoTA72 zWz>_X^-au{HtR?6JLK;n<{J(P2^N@6Y=7B@8TgOh(B;%u}ceF=}ig5bq8pxStv|WWR&{cYpRS zh2>X52xPP$(g0~a|8(ilIv5{gfzB=xI^1IfPjI*B zbAED@2xCNP|MpplI~EaTu%56iIsH) z2jg!Ax!U8fuhsr8>P)`1nu0NoQr^RzsT2f9D%FAKTrg9UlnABZN(c;1&1aJoOQ{}H zsh+P?3i=79I!LLGGT4%p65{G=DKB92P%EK zh^3-(OAn3Lej}fv$AP~k*h1xz z+Gq8I*t`R*=CjJ{3Ep8-G%Us=bcff6;7zd z2tK?AZ^hdXe)J?~=U$$bWiw@Rg=j0LuD{bLtao+dSXoZ?ov68^`gs&pb9J_WV8^wjV0~oBX`l-6#(;#b&r`o25w|L~MYF4S?XH zeRFyw65r9%wUF10!nf?9CW`Gn)gKPCKV;g_B`t>;NP05OAj;mV=VYvaZE13)a79Op zhC7Jg4_{?HEn#!ZRw+o<%d1^=I21kn-hmR)UA#%BWJekDF!Ztcz_pQDg@k8Dv@ZqC z1lm05Lv7}K!Oe)Seu+?0+4(E9q-+U~T}1A6I3WSGW0yrdLqlEyW0N)_ickes*NE;= zD~4l>Qddd&v7!{6KSRFiu_(6br|%tK;a3Pcn(|R(_p!V3r>5cW(_cCh(T1P6RVrPHBPny9dgAKe)1sm+)0&N}>s4N2~??C6`PYudH zW$-(y!aNudEubtXRSY~itD5zEW(w@o>!CwJmPQ1)QJ2wg{ir6wa| zbI=@UMjD|7Mge9`E35ohM9r4Rz}cojuBlT5B|9dCULIxf>_J+1>RY$GPLa%xxSUmarYQgg&Q<`D1#x!?In3 zp7fZPsZ9jsRh=U39bqf#*Cd$f*mQ)#^b12oOrazGbmD8#G~%cAU_Nj+<#>r=c_m)a=&8iJNbzb#!6GDiJb2GxDPAQ;Z(N+_$tepIR9rT7 zst2$B3yAkh$_it!`OAw+QiUA7maz`;)=tMYt9^l04!rKQ!f~l%d3m}25{D*NqVV*> z#nn}n7yHVJ{naJji}8xDi=7iEI43wSUXGWtUaV<10q?Sm(xjr|8>m?Zzi!pY_m)+` zHio03vb?0a*jpk@IUR2uTZ4BeN_?>w?@=UzW36LeIbP6;uQSWb@CH!7A3W6+c>k-n z#8FBlN1zDy1=D(VB8!Nx#;rLZ5k4Efb8B+>xd`HlsyThm20IYt!FyJ5_cC zy+9RjfOV{>EH8DGRr~!8UzLNL3a@ANl^D{U(ChPHN%6)}PfIJWKPyX`X_LaSr(sPR}qch-PQmL%a#a@cXn zyAwN;_@1{l9Ige-xeI&y2=K4o4T$>>0XqQ){WKiz1w0LK1fEP84MU4|)Q=2{;0eOb)ysdIFvbNWVwh0k{@$=mX*Ky?_OPdjRhNJP7z} zzy$mj^t|oia4O(7KsVsKfb_47hQofqI>3#9&jLOKnDS6K+yR&h_z-^Vb@#8(4#2|?hr>qz59|nsN8&j9sb7b~ z(*W1wu_(I1R7^a6VuUU;r=$ ze{1ekod2W&jt9&G^Z-@>ZliM{!0T|D)B<=b-~qw|9tAuMI1+j~aMn5vFzdJYkqO`e z!1aLfI0Y<$z7qiHFIdh4YzKS_Fa)?2kB%haO(6sEa7`-Ug@A5AdJ@ME_zB=9z|5!7 z&wxt+I{~)?_5ywmIAXYAOvN^Q7T}y#)Caf;cRJOu-v? zZUjsNyaO-~@TTX`ZoslVs2A}2fR6#*_&nMT*a3JH@B%#E@4&CF-GJGEivgDb)&kZ6 zh5)w#p4S!*w*saCb^+D_CX6tQI{`-nJ^?rja6e!P;9G#}0nceiKLcg~?g3m57y_() z0rvVP#xH(ik_q@KU;*GqfC0ekUJ8e|0yYEg1bhPU0N@!fLvO&HfFsXDf8pVSX@J33 zpf})afOUXh0&W8wf#2b^0zL$I5O6PG!dZqf4nIB|4LBQc7GND<31BPWdccE#_X4KB zihc&n1`Gi%156r;I085haO0m~Z@||8D*%rGHUqAE4gCf96krFz*D($N6FS4;VP_*w z0A>Py2XGPK!+^Dbqw%LPwg4^%YyrFzuoLhxz+S+Y07sl-82tfFZyEU9j6Ij90)^z%77ozz+ad z0giqL@dWU4z#V{#0XqN#fIWae1WY*(@&MBSzyBWW4!9k#0`O75X26#KcL4SRb^zXT z5bXy15^%)%c&qCBup3|%;3B}+0BZqLKY-l;uLNuX^Z|AP)&uqez6&@4hf~A;it>QV z0T%)O3a}RN-Vp2txF2vQpwSJx0gePb3YZQ!5|8ra0!{;50k{P4H-L43oq*c_>CZ&A z0{$Ja3vlp1JD6@ z6fhfbtOKr-0i5 zM|^~S2b>QW0$c@{G}bV_3rP9cRzNpk%Eu@Vcp=~hz*&IX0q+592W$ll0lo#8bRqf^ zFct8O9+U@616&12fAxF=U@qWxz{P;=fOH|OiYxBM1x8$LO59n42PHMfNj!$4(ecA@ z7$!pHgD``@2l2_or{#ZOvv_5DA-R-gxgjugS7&$j40f&OH3IE<;uqUT!l z13(`HJ(m2VpuYn;rY@`eJgYpNxcw1yOuZI;jzy=Fvu8mU_EGICvgk`dZwDPA!79Jl zqOWB-LZ(GuXwkQVz6a$Cbb9=if?*_ZJ3;RSJy!VxpdaaneiZbce&{37zlTA;F{1uz zvwlLy-I$jvJZI2PHfI~gS;~LNPv{f89e)o8^(36{u-fRZA28siI8)Ag)bl0kiPewy zf=+s3YO-V$N;^><8}a!N^tS;M-iEbRU%2WA#Q#b1k-ZK>&OPv_@%V1?tg`5X2Owtz zJyw5>1N{-u59;OP-!|Kk3wqU$W9yj-JCuQb6UryJYWXKg{e z(aRTGGPiI)RN_&?~s1N|bMzQQVh z0Q9|}M~fd0l%cGs+T7nHcJ_!fe*oF#@!JPFU9wS`w&TV-^#b@awlTG1D{Km z6`w5_NLP9z<_6H`N6=-55PbvaPk;umy;8~~h#MhcS z90r}%kkfVgTC4ovfre2D`a+!^F9SB|I1cpfpgVQC-zuLA`ct6C@+m*)?V#uA<>P0W z`fUXL@1VyTpAUilWsLeAkhu@^b(N2w$0L$q0Za3p`jNSamG0=$k-4_1-Z3?$Dyo zu;`D0(EIb~@qzm3RnU)up01ZKwaOm>eJJE#rqkD0^kJBw$ANxG4|xgJ?hKf9|LLBcT5Y z^jP*8b`o-U(4&nLiU~*ILrM4H!7qGIxC;v{JtjOO^>lzX8g~9A_-KAk_@2h6&GGb8 z|9ij_ZEmBs(BBc*3i@1pH|vR)Nf6OnL2n10ax#-%E_EPXw?l^mpwr))PZ*@>fN?Qk zs5J*Cos98we>e;dOHP3$rw4NOg1!UfgjcXQ)!Tf(#g_*;0mPtc)MxVK{$RlO6YvN9 z2M#Eq8cA>3KYA8pd7jRPH^h=8(wly>+k$S6?nYmcoJ(zTc3N_hFiHFf?Ta;+q=J4A=$LJ-dN`MJ0F{D%=)}HR1HLDO zFtU|>;_HMi)Mh_qtb>eFe7EQ_0U`QE&|d`ooe25?v;0G#Z+sve_C?TTaH8`2Kz|K% zYPTt0%Nrhpj&FeeEszu3nvOF33A@w&-&^3>Mm(t+55>_R2~|Yyo`rq4h1+AtK?nM! z7Iab9M_2(UdvIN(?^?)M3!b_7Zqha1-U|A5&=*9|Wr9xScY^)~=-E2`J5t9~;O>PE zpM#!)IXt0E(_#Mi2Q(#YOspR`;0y8q;_U$MTffA6e92F)(s*;425d~IPaKe9`AX&x z@IM%P9xDL-bI|AMdTF^+0Cd^|j1^xufj$BBv3hxJ4tfmqtbXXPf<6QEXue8zI|BN2 z&=2bJIgfP!Hw;PRz+Z*KAM14L|M#{22hV=+5Wm@X*GM|~p96hE^uzd`@J(#Oss1N9 z?^<%|Am>L9N1sa^C`)hl-pBNW_pn-3aAa8=}W9S4uWnx5I%@T&g1!LsY@N4YqLm+~X{Zt}(d((JQd&}$!yJ>PYqu1e6?qIkmhw7RHYDlMI}vB232 zzF1><8R+}^q1S=FAM{vjoNb_=_INmaUqm~$neAu=eGBL%5p)^!9l&*gegJfzZc~~= zmss&E0nHorWbAk~8ua;~Qy-YN)Yf{lKwk)YtiCS+JrDFvdU>+rZI&H3fTuNv4C>GA zpg#rr3SCBgk!go^(CJTGMay5Pd#l`{k3GrgrjCeZ0 z(+nBy_-^Vzw%%pg`UrS3e;W?Z(Rt!srY(md%w7w6taz9S`V!EC5#`sLOr%y;`ToSD5Xb2Ksu?FVpGTI%)~%_kccGr=y)z1=YV6^rt|N zHg1T%74*mYq3;C!VbCwq<*%@8cmVX@_EY{S=#Tb8ABi-G7)WvBpN`!|2k1vo{@W4d<-&;CkPZ5Hl#dm^mx1mFJxwovy=9|1(AR=K zU#G`g`$F45|0U?La*I~bp96iSUj8Oaei!H;fF3QTkp2diL`07klPKPY;3KbsJ^}Mb z!jF+1sBxt7Vuv-4)YF&j3Bz`i17tY3K(B=rn&M6rW_ZfyVC5mcML;oLj)R4t!QS zWdNsk>;(NS(4+Y-(GP&W5A>B0<>dmD=tn_69nS(3N6@bo3J`rH8n_Vjt0L$!01|x~ z=o>(%HLj_jw!U2gI{k?%RAbQ#t@f=2J=hO@E9mv0$BHdGL4Ou>r!HUHk39hTtDwh< zEk{9*e=hp^+X0y)(a7mlDv=0zHsb0rY6`fb?Gv`t6{{iu?D1es@3R z_kg~=pYjJme+=|k@iYO1{^+Bb9?M5(fxZLsqtP8`UkT_Bf$r1oC-ZhOI}*4=YT#Nby0PdM)6>52En8863yfV;sL!CkISyw<3a_k>HDlz6GJK;93%B=HAv z#{9&ajNftz;utys)N3wyJI>fZ6#z5D30Ro8+StZy$>~5$e|0Y=vV$&)+|@RH5( zO#_VIGKz}Q=j6E=b#caKt%_5+;uC*7z}PWhx{yC?3d(vDUyL(0#U=hW&iEIz3Qckn zAB{5(XoX2+O8$d!2nq>_e;R1~54~y=xTM0wCB_Z%yQ-StuuFlfPQ(ii?~O~uSx1mt zrFfE-C;E(=xLg8kNozJpH?Ejph<`D^@JHO7_~(QLPFUcC1x{GtgauAm;DiNESm1;O z{+C-I<$S4NE7lnLRrd#Z=MaYkct)S$K8A{S3-i@5ejCHXHa^AwRnXB8oukf%ryQKF zS=dUZOWo(&?w8u`>1{-G;qeH0IV2duw^=pv3$}X2)w@qZu}6WgN%GbZYi;_@?Wc7r zU5ftCFXdwo9RnmDO9*jwa{bsb6W4ZHK;UAuF-dHO8T7M2abe3>TsTgMxLB+adRe05 znM%*y(uE^BaSdXK;|y_Sv*HTh!UU!F1}=}?WpSzc|ILqa04Z3%RzxZC+SqT5X@XrqJFMHLK91=5|;X;Nh7}hYnmEn&V-p}v}hI<*l#_$7% zpE4Xc$`IEX3@>0fiQ#O93mL9pSi|sEhCgC>Kf@;&?q&EI!w(pK%5Wf$^D`JqZSe0a z=C_D1SInF_)sc$T?pTNX%K(n_wDgH-nduWF*!tYW0h3_-J!~hCpGU(JUo({&|2=NUtc3b7fB4GMw9ISJ#toD%U3#y`k-75~H@ zEO68yk~40mWSlF3F$N7L{Jr@Sq2kA-jNiUe;>Fn#zIHOcC0F7}Z@TEWBP3@dS4ihR zbj@M>s*B})js!+E@bn0W{kom`CoPwhQ<>of#t*(kB2?LbGd?g?;xAzSQ!$`PAHUfA z!+tj7{ftjwe(@{-Xg4$dJ&$Bmagv@rB01aGU<+B!OEKiU1N*--NV^&efCh?l29 z&TW(BJw2aF*An1KzQZl=Rez-*@T#^;iu`vH@Wh`}B=2uvBK@9#@b}D<2o;C#XZ+zZ ziRZ9p{F(8$v;S~0<0#`(OC&#?1Jjj>z)$k0UMTMs{|d&Rce%vxkifWw@kbX)gz~F< z7+>p?c%^4M<420pne$3w;cZGq>)8lY!2qv`*>82E=-{-(uJ zNIT2=gz9>${-Oc>%EGH<@Mm&N%wQCyt$&HNvCgX46 zfN=xkR{a?x|T5Boh$FTdgJGe&*He3Bgw{#j92Tla~XgBFe!gM zSE%}{9QbHPWQ7TNsd3+BJJN($!gG_FQsN%}0jRN|H0Di}YMCnzQxKV!Uoes5!Z(tIiB zLe`&tqC@f%*#A{~moeVn-g_9o7C+Qb`yY%pz5zVd`zb3piV2r9{<|E1xSNdD(c@)#9!^Ff@X_?IVg3cSxc3C` z6bIBk7>19yk{nXLJ)U32czZs1HSp2uy^Z-RrWxXTK?39FjNiv`OpUu27=O?&8CARf z&iIsN5|3$ATw~CoWdA+a$onAUS28}09Yo2whw=7x-1Ch89>)zeZw^CZM)K`>(JjD7 zYwr(%r*WNR8`lrAoVAOjf*7{qnveW|OCKuR-ER{I_LG#5;_? zo$;@8Vt5MUDGw%o`@X?p#=pbzf6Dx4!H}-kP;ce_;{A1sicr{)=V!Ya4WpTy~ z30I#^U-e;}?46J z_`iqo_Pi?<9Zhn!bG^!LWsFZ|M>xpx={I&++hA(*FXdF?+li6E932X@5{iGo@E)5aUR>h^fHNeu*1SF#nsJn z0%h`E#j$h8OMUF)C5Q3x>~Bi{p8y}NU*3*^|2xZhc%G~`TLR;9C_w#n+fs?hVSIq` z|6oT@^$xpOw(FrulJPC(Cp$*d=Stv7zCDlfFy5Yj{+RJ!UM>YIe|VVj_VviW8UML$ zo|*%{qvqQf8s+GMS;W=K_)l`>{ZPiA3_l<_ejcYj#%D18ol7JFX@I(KK6Nk zEbz2$vhTA^WPba4t&s8d_^_Sv>q@0QpR!u-F+O>vL@2v0m?-sGwL;=~*ci2pf7ljJ ze#ZFPnUa42%YUBnbr|<_@h~$!Wc;6}Nc3WCp*RsQ^c712El;4W@P1i;VjBdv7we|1pEXf~YJj9CYr;P8JD({v5KgoFe zdcPO=Q;oBX>{ldz3dhNzXg{_0$h8uWuqm!3jNe!&?@Jip4E(A5T?c!Z|7Se!dziQc z`jLG5xyBC0Kf-oUGB3q=CVqQn}-`{>#@SkPW{*e`A(8l~pmrKMq8UHckD|w09rnqin z{7yz7?1<~9G34xHetVvITDFuwlAX1B~TjALc zx!J~O%pcS)yZ@Ilegw~(Y8*Yn__W1Rt{T7pV7y(QOW@zp?70|tsyCkHsDA%3m)+?kB9NMvj3}b@iWFhSuFYC2IBgV@pAy_ zQvPs$j;!}K9`9jEHWo6z=UWn?_%{NtY{IMpJiz?+{i4Z;Dt@h8Kt>7u`-LsuH& z0_lJMHS+!(35;6cqv`)9^V{dUQRpXq+<;G@a$EB<_0;aaZu4~)O+I*C}v zc>1v~$+z!Ir(pm_lRq1H;lbg=cfUZv*e(?>hK5^Y60hzvN0; zZzT^1WzV}9KbOZ#It%LrKAQd?GrwJ*F-R<_UEk*Zg;~V4nDJS*xc5uO+n*Eo3**l$ zk>!W7oYbqN{HKZ}LiNi7jJNLtJi~Y&kGq2`=kx_q&UGG%P;uj0#uu}LAl!*-6XWgY z&f9@Mjd^tNC+2@^oWv?Q1JEC2pC>rZoXUkJGyYxfUxg1Sye%$$pYfMgNCC<|e__0R zA3Lr<)@#p)Co=xg@<=&1Fy0=29$>sZ&pga{!xjg|VjiXT+V>4sGyaQ9WWDKZhb_RX zwlhkA$C=-rx4Z^?wE6dMz&msS{QW4)so*>cVMkoa3#Fb@{PJG;!%d7opXZ}w=Kmh> z4*sr#pE3WmDv3RhiS$Pd$qxA}pWV)A#5f`RC*vifiYJdU-hK}9cgBAJd((BF1jhPB za(%RHzeK3@(Vf7P{EMea{B-8u$$0y@SUTo!;&&{QjH{Xd6UN`f^8%+k#%YTse;yBX zWw(6B8_b`^aw-^aKd&@Oi+p7hiYqFND)CAjPnmoXhCq2dc%aVXa(iYkm_E4h9K(_IVZ=BKF=Q#^%bzA|56mKSeRDPMC%bx~zWPM)vEHJM*V?CkH5V5dU`oXX?4I`>zY(uMhL~lHBXXn6@mV&QF=zHw-UxH!)sAi z<7F^-fs(gurLWAJQ<__vk?zVZos^!5e>0{`rhlFICw=0i$(dOhlbjQA<0MRG`jpHm zlP0H6Aq?@QPs*4yB|U3WW*V^&HZv_feR4+HR;#EbJo_Qh6Lr5Bg;Dt67q$9&OOMx8iuWXWD=W*&$=*fu-kj_!a&uZSc`jb! zQoO3NysSK{q#7@t0ZWb_{UW~RUk;C)TL6+Ulegg<3gtuCr?EyyQ-gbbANiFd`wm&epZe@#r9XAa&IQvioZcbWxI z*NW;g58k8YU2$bWn&-*_r)O5hl?B*<7K4M`2>x@Ws14&K%LDd6kH}4SlWQo*|Bqi<6Zujcw8Qq=9Oq=bSBhVZ<&ke$ zQvQ>kX@5(RdRr2LLa`qW`QI^sTrS^&0y1&|-W8;b%Y)q|9dywmPsW7I3E0Y&JtD@!7A0t#!cM&!NZ#{E*;2AELl<0&5lzCUHp;BInK{?B*EQ!(S z_7;`Mph}LB*H_WpACR<@n|-n2Ru6lUE@8QH5U9TXLc~`J6m> z-hxtBjmveVt=v}*P&jVpjo!*~slPKrzFo~%CElerado9H;C1<^;d7m73w&iOXH>7i zo56B&OS4?A$wehKMR-RT1q(5y^s$WDN6PbQ=z9~q z`+KO;#e1lV{Zar$MLD*zt}FMI6)pFRAnnC#=!z^W(NyNC2vn-qUa2z5m7`b$U94ii zFi|D*MRuoKrfxGe?XwxTiEizX4~a)8!+dBfZR!EnW~7CC1aMx)9^PUWm^R zOhF1ziv9_BYxKAwwVMXcAGu%VYNQXCH8E_WW>9+bCuF3t&eDg|eI@9O z8l$YJth~za^;X!E0FtT?MjFm@@@x|ioNO|3i&cn=&_m6!Ht$Jyl`2<3D5F3oJb)(c zm44rHq)473yy~$s;8}r5IB#yTkBpq=iK2erNR?SpUA0QaF^tcz42sBFCEvX zur8QO3guks!Mg>0Wu9uhbW&O>hE=VZ-kHW`$9Rtt*I+?=@DoFQW_k|h9@I?1ojXOo zLNjN%t0>>KJffq_*@TCDn(P0EArDoNtim(OS7UxFk%J)0@UagDyI)&$8r0T!_}ZCp zI=qVBl_}>=_ylH7q+wZVG0imlF}qkbT44v6(s|_GPM(%qhY# zzwA;b8Du264JbeCx4vC| zZnQ#PI?q#uRSZJp%D^fWc2qnvqom5@BC|AJARMQo=woFP)Tpes(!b-gp3_MSGP&}S z%Ll9g+h&7&)s&WtB#9rd}QVVTftp%R16U8YrpiKmtdwEmRrdo8n@MeL& zexl7N-h;Kan8cm|cZe-;L{G^nU^qQ+{O``Z#?hybsZm#YO#`~-p1U;n}U_zs%mWe6nN(F`c*AoC(_mmrWZC=25rWc zm%{&Re8pa?cVZ4^G+tW-TA`=!3~R;#wLwI?Bwst$eC;gPHGh)S&{~AVY>d@+Q8FC+ zP{DkR**T`yeBG8!_T(dduULcB1A#?lA7ABqlhwHext@p8X{!zLP(ZDlMeK=o$Pq<^ zJSq4;+&@q}4?9=V5!JTQG3A72G>MiHeswz7cZICEapZsyJ~Zp<3D_y0fTcK=;n=pT zDyJ1gV2!7S_6zjcqG}BeS4!n<;fol`B2l6t8ri{751y1Zw3}uwdW&n8%gAX9;LZ#_ z6_eqZw=1Dkf1BFQw2Gq2qEZiSX*pT0Ib1b|iunq9x$h(gL^>_P#4?TcE$BeuIJ%VP zb(!Xi3^>z+Bsd}ihUuo5lXCe=UvYnPvTX`L?ighw8WN-KJ*ds;zSCzvbCkBY%22U2 z`T`E-U4V!!Jja>o@!<53&X~NOB9AjC&+G-n8I?c5qFC3%B*<>D%WHVBWEH#8Fv!ZX zYI%Sbd03Y2y#bpx#VEmj5o-r6!z<6?JhaP%?VTcQG0}OebY7fyWn@YT|2vLA5ZpLY zS|bAnrR^YW_+m>lr&MfK!I$tqxBXalybv{z5?Fg(6bp}OtBeZjn`DdsPe)POhE-8C zMs%TkU0>_^N{tE`EDl&P6_4_}FNYf4?^i!(i%=WbnCAFQ* zD;($7TH&Y!Ky5sMb@3%`Y=4kDQ*YXv9ajV(F*566Kye z%wmNYHJzCQ%J1!a9C=)O75awYaqldq!_Rd=eRmddUS3?W#vC2aOhaV^IElq!inq4d zTS2D|5%I>Ep$=5B*IE_8uBUdy8tqX5bJJaH+eAJ?;6gZ>;uQyK9^ZmHBHz~qs3#My(?**VeF zSeU*l$FH9$iy#^;3pWQEuOYQZjcm~h#|~I2tnwCLkHwu&?7Fy06?=X_JQt$vspHhj z)z@7x_|TNH5)ZZ)=__{hJn&tyVyu#Trbq#<_X;OM@Nwc~xU{^+Yn?FoaGI8bg(DqU z)48#r;!w)BQn;lcnf_O!yblHPui%N;HaqnRE?S_FQT{k*4SkPDJBP4^=cpTsDzDYj zIXSmdE*>ku^@*YrW9H4InpmxiELUXCm>tY>4r{*`)qRb$g+@3(bA*jX`RGO(2EFdf zUw3YR@o^|oR8drnrH;zFzN!o1tL*I7`czJ~lu!NFdKHsu)LnA8rhUT;D0`M~siJmW z_>{@i)aeYYf{ROir--v(4^GsgO&w{r&DUL3@na~q4aH0xdmaDNfRx$N z@=0!mm|0BBXEo6pUVQ1BZ~uijqfRX%lS2w4v{s)`hK_4-DQ82w`sBkt^|%zZ+7`54Z3iFk`LSLeRS1 zX3?)XinWPxB2DZ00e=W=J$+A6%2t=^du1~9 z`p<$H8M_!clG^|HD*K4Z&N|(dD*S)VUCoOeMHFxGD=La0XaoH({8aUER@{%sR71_oN3!1rfoEp1kHF1o0rK7!Th3Itcm?2)TNZTr~dPS9Mi& zbx(Ki3K^2Eo}PZ))zww6-uu1ZtJWF#kPLb1_ISRBX2nOHXlbPnRB|62A!D}^M6@;P zUKo2UkB&OA3Ki#_e@_3&+mFpvohTz!?v0aTCrgDca$5-Icsh8?T{{FJib1SuOyZb_ zN#Fq-tYhgwf`v@eHuUz8$s=3y)OX{nQgD+3liDdKQ<>b#A;04qjm7wq?i-KE<6^9@ zu47>6A*Cj*P6vko;rPb5O_HI-Q(J)|_!4o#$O8`jGgMr_K=fD-TCEAJ(xeE@D~R=uP|ZIVHX7EI%aI82h^4rTjeM% z8`MMtM|G^&!7%7k3W6C6=@@NjXi3bXcka2*##7ulRgcMH0&I3hnq0b? zX9ZZar-TW*Ou(|U%fnelp9hAlgER7na%>q2P&x;&>)jb}*$bH4e7;BWZ16yhONT)) znf6~&hJFipl&u2zf$U+}O_b_PzA`KwcB%TiyNIl;mGDr3HW9n)f}?ji|FN;LL1sma zW}y`i&CGB$8xK?NuQ1H06D|!V<1v`m6jNM#Hb6Vo6+R1;&83qVp&mxslkjsko)&Ae zinMRwOiR^NO{8FY6mf9qUf`27;8ASsZNKVuT;OjK-=j0No9djEv5efYy`pifimSfc z#oU`bvWhwBgOxBjM59eAZclmr`Bksvf z))aB?zmbTzCovu8Yt})>3E!=bnq*!g6ifk}vOuP^48y1s_zcG`utShPED0tGKI^R@@RULrG0K~EaX3`MN`vdr zpU&3cOu|g*0=iMV(NfQ&%<~j4nrw1^>gqTS)Il(M*Nsf=m=(z#b7*lfnvd%SP(a_P z6F{+k+r&JF;&eLA)J}19AcZy`c46aGP>x6)(Y&r$FPUIXR60u&=u%MWEi7d+x+wy0 z_t?1KaazButYAvNReLW5?H#gQ$Q5y(u;%fj)j}TF6*3PT#G%QH>hAv(A*2&h@24oHARhK_*V5N|SLXvWmT68#-bUjudVpA{<>ydvJ}J zj?~bssoh2iCXIMR;zH!)7WI5E9UdAYPz4>WgsTb29i;ePT(73-X~hR?#ysjYw-;CG z@upgg&J|`qH9Z5__hx@0>l5>^@#yNCEm(X=Q?q43nhJXrm>4sNQ0djN3lYp8u;@>) zGx7^@$}G%TFhf%L!`BC~jGUA}^&(@Om$FGP_zNfnLAZ(e2W09+u-q||hf`1v^%Mfx z&Xj;inlo81sPCbz7T<0J01-l=+N^UHtKt3I+KE+5-vO0+0N)quqL5SZe zMd{6ucg{@tN5p9QZ zXIq?wrkw-~QRsfd1h3e&@iMK?QsSQ-3=i|{3)EC;TAm3*ovl<+ky3P=Wb_g9d&?yP zSKQeqlhJH7NWclE)O@L<6c3kF-Z4+*v7Mi2-EdHYQ}5?vS6o6=YHs?hog;Ss6f2n^ zd1#6d)(Cml=VoIZ`Ut84|9xs#wgrMwmCDb1hG#2m`kd`dVE33>ryH5E=n#4m_+ zdNO=09-&%#ZIo3BJHRzTD<(CXbQKeYF-b-53w(iTFQ-nEM^XZ%!wB<9WzLqZO{kOy zREtwdI7(YG7PTKHc{8<(;IzNGokMWas5C7TMmkN4e2k2Wcs5dc8pe4vL?oMC0yd; z5-|QaNClbNL($V|#u%HgOGE?ZrZLYGMZXc%s27(gYuz-O!73zC@5X*eKmtbNg}k|l z*B6qE!t58ni|fp#^SnW{9O%y>+K9m>$WZSk3L-P`Vl)mRtL01r$CV(joYcPHEAt4L zt1Y<_#G%`OtxEHB$t>+^1bRe@$D%~HmVxVhW^1L^WoVmbr*8*Kiix#WY_l07#PHi< zgIFM+EZMT`;p@YbT%K)jZ?Q9pM4JIt0V#I!m}ZBNy`R+I#=^%e3V*%H(q8$Z2TqGr zDoj{`Ju;jmn@YK3Tgax`?jRMrvpbz&fq=dJtmAfVzBU|fJwDvZI*eQI zW_;jIf3}l#w)W5Cq*Crp!K3S7C20KRr0~vk zLid<;ws(3jBEx^Xx3dLV`-YPakT}ozidYejTnwow7J+-5R*2&>_WG0vD`&KAIxAHH z7vSpl$HM{6Ho=AQr^B_8D+4#rI>ZISQkuH5_rVH!f5xr&udjW`x;M)CtUM`S-QOc_ zOEx+veEE-5-b!6o-$~u%wq%3WMZW?6?fPG;yp<0`$J4R?2e04A{=Rl?V)DPLyp_M{ z!8dCe*B{IF^E(Gk{-RdU%EenmkP5oC$sd*78ND8ZE@|?A+%7*@dHfDNP>ZQD8w`s-=4H?cvtZ0GyxKKaGU_w)z5 zzRBDDzpwJAL@Yb03(;G7#go4u$HejouC@P$4L{1FH z{Z-4Kt>Ja|f|gc%jtyV_*LUO>D_^h%SAn?wzK-Mlev5(%tp~F7A`Xe2cWmmtEGP-@&|7`zX zIE>ycVe;8eBA0zzPyQbqMz?74_8!(FDt}Q=XN6tYzTXaE8=JK6l3xFk%G>*RYbYe?OtuKl+Fq xPw(rYerokM{dXJoS>5GG`P;oB<-2(AhX1ka+CF;cN=p9sQ*z`=BoKYg{sUcPuHgUx