From 0d5c1d1077651590499e0654d20fde9fb28f8d28 Mon Sep 17 00:00:00 2001 From: Rodrigo Alfonso Date: Sat, 24 Aug 2024 08:12:09 -0300 Subject: [PATCH 1/4] Starting JOYBUS --- examples/LinkCube_demo/Makefile | 284 ++++++++++++++++++++++++++++ examples/LinkCube_demo/src/main.cpp | 114 +++++++++++ lib/LinkCube.hpp | 186 ++++++++++++++++++ lib/_link_common.hpp | 6 + 4 files changed, 590 insertions(+) create mode 100644 examples/LinkCube_demo/Makefile create mode 100644 examples/LinkCube_demo/src/main.cpp create mode 100644 lib/LinkCube.hpp diff --git a/examples/LinkCube_demo/Makefile b/examples/LinkCube_demo/Makefile new file mode 100644 index 0000000..dbc85d2 --- /dev/null +++ b/examples/LinkCube_demo/Makefile @@ -0,0 +1,284 @@ +# +# Template tonc makefile +# +# Yoinked mostly from DKP's template +# + +# === SETUP =========================================================== + +# --- No implicit rules --- +.SUFFIXES: + +# --- Paths --- +export TONCLIB := ${DEVKITPRO}/libtonc + +# === TONC RULES ====================================================== +# +# Yes, this is almost, but not quite, completely like to +# DKP's base_rules and gba_rules +# + +export PATH := $(DEVKITARM)/bin:$(PATH) + + +# --- Executable names --- + +PREFIX ?= arm-none-eabi- + +export CC := $(PREFIX)gcc +export CXX := $(PREFIX)g++ +export AS := $(PREFIX)as +export AR := $(PREFIX)ar +export NM := $(PREFIX)nm +export OBJCOPY := $(PREFIX)objcopy + +# LD defined in Makefile + + +# === LINK / TRANSLATE ================================================ + +%.gba : %.elf + @$(OBJCOPY) -O binary $< $@ + @echo built ... $(notdir $@) + @gbafix $@ -t$(TITLE) + +#---------------------------------------------------------------------- + +%.mb.elf : + @echo Linking multiboot + $(LD) -specs=gba_mb.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + $(NM) -Sn $@ > $(basename $(notdir $@)).map + +#---------------------------------------------------------------------- + +%.elf : + @echo Linking cartridge + $(LD) -specs=gba.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + $(NM) -Sn $@ > $(basename $(notdir $@)).map + +#---------------------------------------------------------------------- + +%.a : + @echo $(notdir $@) + @rm -f $@ + $(AR) -crs $@ $^ + + +# === OBJECTIFY ======================================================= + +%.iwram.o : %.iwram.cpp + @echo $(notdir $<) + $(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) $(IARCH) -c $< -o $@ + +#---------------------------------------------------------------------- +%.iwram.o : %.iwram.c + @echo $(notdir $<) + $(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) $(IARCH) -c $< -o $@ + +#---------------------------------------------------------------------- + +%.o : %.cpp + @echo $(notdir $<) + $(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) $(RARCH) -c $< -o $@ + +#---------------------------------------------------------------------- + +%.o : %.c + @echo $(notdir $<) + $(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) $(RARCH) -c $< -o $@ + +#---------------------------------------------------------------------- + +%.o : %.s + @echo $(notdir $<) + $(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ + +#---------------------------------------------------------------------- + +%.o : %.S + @echo $(notdir $<) + $(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ + + +#---------------------------------------------------------------------- +# canned command sequence for binary data +#---------------------------------------------------------------------- + +define bin2o + bin2s $< | $(AS) -o $(@) + echo "extern const u8" `(echo $( `(echo $(> `(echo $(> `(echo $( $(BUILD)/$(TARGET).map + +all : $(BUILD) + +clean: + @echo clean ... + @rm -rf $(BUILD) $(TARGET).elf $(TARGET).gba $(TARGET).sav + + +else # If we're here, we should be in the BUILD dir + +DEPENDS := $(OFILES:.o=.d) + +# --- Main targets ---- + +$(OUTPUT).gba : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +-include $(DEPENDS) + + +endif # End BUILD switch + +# --- More targets ---------------------------------------------------- + +.PHONY: clean rebuild start + +rebuild: clean $(BUILD) + +start: + start "$(TARGET).gba" + +restart: rebuild start + +# EOF diff --git a/examples/LinkCube_demo/src/main.cpp b/examples/LinkCube_demo/src/main.cpp new file mode 100644 index 0000000..1c5f747 --- /dev/null +++ b/examples/LinkCube_demo/src/main.cpp @@ -0,0 +1,114 @@ +#define LINK_ENABLE_DEBUG_LOGS 1 + +// (0) Include the header +#include "../../../lib/LinkCube.hpp" + +#include +#include +#include "../../_lib/interrupt.h" + +void log(std::string text); +void wait(u32 verticalLines); +bool didPress(unsigned short key, bool& pressed); +template +[[nodiscard]] std::string toHex(I w, size_t hex_len = sizeof(I) << 1); +inline void VBLANK() {} + +// (1) Create a LinkCube instance +LinkCube* linkCube = new LinkCube(); + +void init() { + REG_DISPCNT = DCNT_MODE0 | DCNT_BG0; + tte_init_se_default(0, BG_CBB(0) | BG_SBB(31)); + + // (2) Add the interrupt service routines + interrupt_init(); + interrupt_set_handler(INTR_VBLANK, VBLANK); + interrupt_enable(INTR_VBLANK); + interrupt_set_handler(INTR_SERIAL, LINK_CUBE_ISR_SERIAL); + interrupt_enable(INTR_SERIAL); +} + +int main() { + init(); + + // (3) Initialize the library + linkCube->activate(); + + int counter = -1; + u32 index = 0; + std::string received = ""; + + while (true) { + // Title + std::string output = // TODO: IMPLEMENT pending + "LinkCube_demo (v7.0.0)\n\nPress A to send\nPress B to clear\n\nLast " + "sent: " + + std::to_string(counter) + "\n(pending = " + std::to_string(0) + + ")\n\nReceived:\n" + received; + + // if (index == 0) { + // Link::_REG_JOY_TRANS_L = 0; + // index++; + // } else if (index == 1) { + // Link::_REG_JOY_TRANS_L = 0b100; + // index++; + // } else if (index == 2) { + // Link::_REG_JOY_TRANS_L = Link::_REG_JOYSTAT & 0xff; + // index = 0; + // } + + output += std::to_string(linkCube->n) + ", \n"; + output += std::to_string(Link::_REG_JOY_RECV_H) + ", \n"; + output += std::to_string(Link::_REG_JOY_RECV_L) + ", \n"; + output += "joycnt: " + std::to_string(Link::_REG_JOYCNT) + ", \n"; + output += "joystat: " + std::to_string(Link::_REG_JOYSTAT) + ", \n"; + + // TODO: IMPLEMENT transfers + + // Print + VBlankIntrWait(); + log(output); + } + + return 0; +} + +void log(std::string text) { + tte_erase_screen(); + tte_write("#{P:0,0}"); + tte_write(text.c_str()); +} + +void wait(u32 verticalLines) { + u32 count = 0; + u32 vCount = REG_VCOUNT; + + while (count < verticalLines) { + if (REG_VCOUNT != vCount) { + count++; + vCount = REG_VCOUNT; + } + }; +} + +bool didPress(u16 key, bool& pressed) { + u16 keys = ~REG_KEYS & KEY_ANY; + bool isPressedNow = false; + if ((keys & key) && !pressed) { + pressed = true; + isPressedNow = true; + } + if (pressed && !(keys & key)) + pressed = false; + return isPressedNow; +} + +template +[[nodiscard]] std::string toHex(I w, size_t hex_len) { + static const char* digits = "0123456789ABCDEF"; + std::string rc(hex_len, '0'); + for (size_t i = 0, j = (hex_len - 1) * 4; i < hex_len; ++i, j -= 4) + rc[i] = digits[(w >> j) & 0x0f]; + return rc; +} diff --git a/lib/LinkCube.hpp b/lib/LinkCube.hpp new file mode 100644 index 0000000..894280e --- /dev/null +++ b/lib/LinkCube.hpp @@ -0,0 +1,186 @@ +#ifndef LINK_CUBE_H +#define LINK_CUBE_H + +// -------------------------------------------------------------------------- +// A JOYBUS handler for the Link Port. +// -------------------------------------------------------------------------- +// Usage: +// - 1) Include this header in your main.cpp file and add: +// LinkCube* linkCube = new LinkCube(); +// - 2) Add the required interrupt service routines: (*) +// irq_init(NULL); +// irq_add(II_SERIAL, LINK_CUBE_ISR_SERIAL); +// - 3) Initialize the library with: +// linkCube->activate(); +// // TODO: WRITE +// -------------------------------------------------------------------------- +// (*) libtonc's interrupt handler sometimes ignores interrupts due to a bug. +// That causes packet loss. You REALLY want to use libugba's instead. +// (see examples) +// -------------------------------------------------------------------------- + +#include "_link_common.hpp" + +/** + * @brief // TODO: WRITE + */ +#define LINK_CUBE_QUEUE_SIZE 10 + +static volatile char LINK_CUBE_VERSION[] = "LinkCube/v7.0.0"; + +#define LINK_CUBE_BARRIER asm volatile("" ::: "memory") // TODO: USE? + +#if LINK_ENABLE_DEBUG_LOGS != 0 +#define _LCLOG_(...) Link::log(__VA_ARGS__) +#else +#define _LCLOG_(...) +#endif + +/** + * @brief A JOYBUS handler for the Link Port. + */ +class LinkCube { + private: + using u32 = unsigned int; + using u16 = unsigned short; + using u8 = unsigned char; + using U32Queue = Link::Queue; + + static constexpr int DEVICE_GBA = 0x0004; + static constexpr int COMMAND_RESET = 0xff; + // static constexpr int COMMAND_INFO = 0x00; // TODO: DOESN'T MATTER + // static constexpr int COMMAND_DATA_WRITE = 0x15; + // static constexpr int COMMAND_DATA_READ = 0x14; + static constexpr int BIT_CMD_RESET = 0; + static constexpr int BIT_CMD_RECEIVE = 1; + static constexpr int BIT_CMD_SEND = 2; + static constexpr int COMMAND_DATA_READ = 0x14; + static constexpr int BIT_IRQ = 6; + static constexpr int BIT_JOYBUS_HIGH = 14; + static constexpr int BIT_GENERAL_PURPOSE_LOW = 14; + static constexpr int BIT_GENERAL_PURPOSE_HIGH = 15; + + public: + /** + * @brief Returns whether the library is active or not. + */ + [[nodiscard]] bool isActive() { return isEnabled; } + + /** + * @brief Activates the library. + */ + void activate() { + LINK_CUBE_BARRIER; + isEnabled = false; + LINK_CUBE_BARRIER; + + resetState(); + stop(); + + LINK_CUBE_BARRIER; + isEnabled = true; + LINK_CUBE_BARRIER; + + start(); + + Link::log("ACTIVATED!"); + } + + public: + int n = 0; // TODO: REMOVE + + /** + * @brief Deactivates the library. + */ + void deactivate() { + isEnabled = false; + resetState(); + stop(); + } + + /** + * @brief This method is called by the SERIAL interrupt handler. + * \warning This is internal API! + */ + void _onSerial() { + n++; + + if (!isEnabled) + return; + + if (isBitHigh(BIT_CMD_RESET)) { + Link::log("RESET HIGH?", Link::_REG_JOY_RECV_H); + Link::log("RESET LOW?", Link::_REG_JOY_RECV_L); + return; + } + if (isBitHigh(BIT_CMD_RECEIVE)) { + // TODO: RECEIVE + return; + } + if (isBitHigh(BIT_CMD_SEND)) { + // TODO: RECEIVE + return; + } + } + + private: + U32Queue incomingQueue; // TODO: SYNCHRONIZE? + U32Queue outgoingQueue; + volatile bool isEnabled = false; + + void resetState() { + incomingQueue.clear(); + outgoingQueue.clear(); + } + + void stop() { + setInterruptsOff(); + setGeneralPurposeMode(); + } + + void start() { + setJoybusMode(); + setInterruptsOn(); + _LCLOG_("Activated irq"); // TODO: REMOVE + } + + void setJoybusMode() { + Link::_REG_RCNT = Link::_REG_RCNT | (1 << BIT_JOYBUS_HIGH) | + (1 << BIT_GENERAL_PURPOSE_HIGH); + } + + void setGeneralPurposeMode() { + Link::_REG_RCNT = (Link::_REG_RCNT & ~(1 << BIT_GENERAL_PURPOSE_LOW)) | + (1 << BIT_GENERAL_PURPOSE_HIGH); + } + + void setInterruptsOn() { setBitHigh(BIT_IRQ); } + void setInterruptsOff() { setBitLow(BIT_IRQ); } + + // TODO: REMOVE? + static u32 buildU32(u8 msB, u8 byte2, u8 byte3, u8 lsB) { + return ((msB & 0xFF) << 24) | ((byte2 & 0xFF) << 16) | + ((byte3 & 0xFF) << 8) | (lsB & 0xFF); + } + static u16 buildU16(u8 msB, u8 lsB) { return (msB << 8) | lsB; } + static u16 msB32(u32 value) { return value >> 16; } + static u16 lsB32(u32 value) { return value & 0xffff; } + static u8 msB16(u16 value) { return value >> 8; } + static u8 lsB16(u16 value) { return value & 0xff; } + bool isBitHigh(u8 bit) { return (Link::_REG_JOYCNT >> bit) & 1; } + void setBitHigh(u8 bit) { Link::_REG_JOYCNT |= 1 << bit; } + void setBitLow(u8 bit) { Link::_REG_JOYCNT &= ~(1 << bit); } +}; + +extern LinkCube* linkCube; + +/** + * @brief SERIAL interrupt handler. + */ +inline void LINK_CUBE_ISR_SERIAL() { + linkCube->_onSerial(); +} + +#undef _LCLOG_ + +#endif // LINK_CUBE_H diff --git a/lib/_link_common.hpp b/lib/_link_common.hpp index 1dffb72..4bd89e1 100644 --- a/lib/_link_common.hpp +++ b/lib/_link_common.hpp @@ -76,6 +76,12 @@ inline vu32& _REG_SIODATA32 = *reinterpret_cast(_REG_BASE + 0x0120); inline vu16& _REG_SIODATA8 = *reinterpret_cast(_REG_BASE + 0x012A); inline vu16& _REG_SIOMLT_SEND = *reinterpret_cast(_REG_BASE + 0x012A); inline vu16* const _REG_SIOMULTI = reinterpret_cast(_REG_BASE + 0x0120); +inline vu16& _REG_JOYCNT = *reinterpret_cast(_REG_BASE + 0x0140); +inline vu16& _REG_JOY_RECV_L = *reinterpret_cast(_REG_BASE + 0x0150); +inline vu16& _REG_JOY_RECV_H = *reinterpret_cast(_REG_BASE + 0x0152); +inline vu16& _REG_JOY_TRANS_L = *reinterpret_cast(_REG_BASE + 0x0154); +inline vu16& _REG_JOY_TRANS_H = *reinterpret_cast(_REG_BASE + 0x0156); +inline vu16& _REG_JOYSTAT = *reinterpret_cast(_REG_BASE + 0x0158); inline vu16& _REG_VCOUNT = *reinterpret_cast(_REG_BASE + 0x0006); inline vu16& _REG_KEYS = *reinterpret_cast(_REG_BASE + 0x0130); inline vu16& _REG_TM1CNT_L = *reinterpret_cast(_REG_BASE + 0x0104); From 53089ce3fdadf1c373b3593139e01dc115a19641 Mon Sep 17 00:00:00 2001 From: Rodrigo Alfonso Date: Sat, 24 Aug 2024 09:40:23 -0300 Subject: [PATCH 2/4] Sends are working! --- examples/LinkCube_demo/src/main.cpp | 15 +-------------- lib/LinkCube.hpp | 29 +++++++++++++---------------- 2 files changed, 14 insertions(+), 30 deletions(-) diff --git a/examples/LinkCube_demo/src/main.cpp b/examples/LinkCube_demo/src/main.cpp index 1c5f747..7bae28c 100644 --- a/examples/LinkCube_demo/src/main.cpp +++ b/examples/LinkCube_demo/src/main.cpp @@ -1,4 +1,4 @@ -#define LINK_ENABLE_DEBUG_LOGS 1 +#define LINK_ENABLE_DEBUG_LOGS 1 // TODO: 0 // (0) Include the header #include "../../../lib/LinkCube.hpp" @@ -36,7 +36,6 @@ int main() { linkCube->activate(); int counter = -1; - u32 index = 0; std::string received = ""; while (true) { @@ -47,18 +46,6 @@ int main() { std::to_string(counter) + "\n(pending = " + std::to_string(0) + ")\n\nReceived:\n" + received; - // if (index == 0) { - // Link::_REG_JOY_TRANS_L = 0; - // index++; - // } else if (index == 1) { - // Link::_REG_JOY_TRANS_L = 0b100; - // index++; - // } else if (index == 2) { - // Link::_REG_JOY_TRANS_L = Link::_REG_JOYSTAT & 0xff; - // index = 0; - // } - - output += std::to_string(linkCube->n) + ", \n"; output += std::to_string(Link::_REG_JOY_RECV_H) + ", \n"; output += std::to_string(Link::_REG_JOY_RECV_L) + ", \n"; output += "joycnt: " + std::to_string(Link::_REG_JOYCNT) + ", \n"; diff --git a/lib/LinkCube.hpp b/lib/LinkCube.hpp index 894280e..debff0f 100644 --- a/lib/LinkCube.hpp +++ b/lib/LinkCube.hpp @@ -54,7 +54,6 @@ class LinkCube { static constexpr int BIT_CMD_RESET = 0; static constexpr int BIT_CMD_RECEIVE = 1; static constexpr int BIT_CMD_SEND = 2; - static constexpr int COMMAND_DATA_READ = 0x14; static constexpr int BIT_IRQ = 6; static constexpr int BIT_JOYBUS_HIGH = 14; static constexpr int BIT_GENERAL_PURPOSE_LOW = 14; @@ -84,11 +83,10 @@ class LinkCube { start(); Link::log("ACTIVATED!"); + Link::_REG_JOY_TRANS_H = 0xffee; + Link::_REG_JOY_TRANS_L = 0xaadd; } - public: - int n = 0; // TODO: REMOVE - /** * @brief Deactivates the library. */ @@ -103,23 +101,23 @@ class LinkCube { * \warning This is internal API! */ void _onSerial() { - n++; - if (!isEnabled) return; if (isBitHigh(BIT_CMD_RESET)) { - Link::log("RESET HIGH?", Link::_REG_JOY_RECV_H); - Link::log("RESET LOW?", Link::_REG_JOY_RECV_L); - return; + resetState(); + _LCLOG_("LinkCube: reset!"); + setBitHigh(BIT_CMD_RESET); } if (isBitHigh(BIT_CMD_RECEIVE)) { - // TODO: RECEIVE - return; + _LCLOG_("LinkCube: cmd receive!"); + setBitHigh(BIT_CMD_RECEIVE); + // return; } if (isBitHigh(BIT_CMD_SEND)) { - // TODO: RECEIVE - return; + _LCLOG_("LinkCube: cmd send!"); + setBitHigh(BIT_CMD_SEND); + // return; } } @@ -129,8 +127,8 @@ class LinkCube { volatile bool isEnabled = false; void resetState() { - incomingQueue.clear(); - outgoingQueue.clear(); + incomingQueue.syncClear(); + outgoingQueue.syncClear(); } void stop() { @@ -141,7 +139,6 @@ class LinkCube { void start() { setJoybusMode(); setInterruptsOn(); - _LCLOG_("Activated irq"); // TODO: REMOVE } void setJoybusMode() { From 0063b465e471ed518f0fa7450413b6f145f7a157 Mon Sep 17 00:00:00 2001 From: Rodrigo Alfonso Date: Sun, 25 Aug 2024 00:25:43 -0300 Subject: [PATCH 3/4] Improving LinkCable docs --- lib/LinkCable.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/LinkCable.hpp b/lib/LinkCable.hpp index 80fcfeb..1fb73d8 100644 --- a/lib/LinkCable.hpp +++ b/lib/LinkCable.hpp @@ -535,11 +535,10 @@ inline void LINK_CABLE_ISR_TIMER() { * - On each VBLANK, SERIAL, or TIMER IRQ: * -> **If the user is not syncing**: * -> All `newMessages` are moved to `readyToSyncMessages`. + * - If (playerId == 0 && TIMER_IRQ) || (playerId > 0 && SERIAL_IRQ): * -> **If the user is not sending**: * -> Pops one message from `outgoingMessages` and transfers it. * - `sync()` moves all `readyToSyncMessages` to `syncedIncomingMessages`. */ #endif // LINK_CABLE_H - -// TODO: REPEAT IN LinkWireless / LinkUniversal From 0e16794ccb77d0f7151f4c12b4a80d2f6e554a62 Mon Sep 17 00:00:00 2001 From: Rodrigo Alfonso Date: Sun, 25 Aug 2024 04:13:22 -0300 Subject: [PATCH 4/4] Finishing LinkCube --- README.md | 39 ++++++- docs/img/link-cube.gif | Bin 0 -> 123831 bytes examples/LinkCube_demo/src/main.cpp | 65 +++++++---- lib/LinkCable.hpp | 12 +- lib/LinkCube.hpp | 167 +++++++++++++++++++++------- lib/LinkUART.hpp | 14 +-- lib/LinkWireless.hpp | 4 +- lib/_link_common.hpp | 17 ++- 8 files changed, 230 insertions(+), 88 deletions(-) create mode 100644 docs/img/link-cube.gif diff --git a/README.md b/README.md index 8070db2..6d0964d 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ A set of Game Boy Advance (GBA) C++ libraries to interact with the Serial Port. - [🔌](#-LinkGPIO) [LinkGPIO.hpp](lib/LinkGPIO.hpp): Use the Link Port however you want to control **any device** (like LEDs, rumble motors, and that kind of stuff)! - [🔗](#-LinkSPI) [LinkSPI.hpp](lib/LinkSPI.hpp): Connect with a PC (like a **Raspberry Pi**) or another GBA (with a GBC Link Cable) using this mode. Transfer up to 2Mbit/s! - [⏱️](#%EF%B8%8F-LinkUART) [LinkUART.hpp](lib/LinkUART.hpp): Easily connect to **any PC** using a USB to UART cable! +- [🟪](#-LinkCube) [LinkCube.hpp](lib/LinkCube.hpp): Exchange data with a *Wii* or a *GameCube* using the classic **Joybus** protocol! - [📱](#-LinkMobile) [LinkMobile.hpp](lib/LinkMobile.hpp): Connect to **the internet** using the *Mobile Adapter GB*, brought back to life thanks to the [REON](https://github.com/REONTeam) project! - [🖱️](#%EF%B8%8F-LinkPS2Mouse) [LinkPS2Mouse.hpp](lib/LinkPS2Mouse.hpp): Connect a **PS/2 mouse** to the GBA for extended controls! - [⌨️](#%EF%B8%8F-LinkPS2Keyboard) [LinkPS2Keyboard.hpp](lib/LinkPS2Keyboard.hpp): Connect a **PS/2 keyboard** to the GBA for extended controls! @@ -81,8 +82,8 @@ You can update these values at any time without creating a new instance: You can also change these compile-time constants: - `LINK_CABLE_QUEUE_SIZE`: to set a custom buffer size (how many incoming and outgoing messages the queues can store at max **per player**). The default value is `15`, which seems fine for most games. - - This affects how much memory is allocated. With the default value, it's `390` bytes. There's a double-buffered pending queue (to avoid data races), `1` incoming queue and `1` outgoing queue. - - You can calculate the memory usage with: + - This affects how much memory is allocated. With the default value, it's around `390` bytes. There's a double-buffered pending queue (to avoid data races), `1` incoming queue and `1` outgoing queue. + - You can approximate the memory usage with: - `(LINK_CABLE_QUEUE_SIZE * sizeof(u16) * LINK_CABLE_MAX_PLAYERS) * 3 + LINK_CABLE_QUEUE_SIZE * sizeof(u16)` <=> `LINK_CABLE_QUEUE_SIZE * 26` ## Methods @@ -186,8 +187,8 @@ You can update these values at any time without creating a new instance: You can also change these compile-time constants: - `LINK_WIRELESS_QUEUE_SIZE`: to set a custom buffer size (how many incoming and outgoing messages the queues can store at max). The default value is `30`, which seems fine for most games. - - This affects how much memory is allocated. With the default value, it's `960` bytes. There's a double-buffered incoming queue and a double-buffered outgoing queue (to avoid data races). - - You can calculate the memory usage with: + - This affects how much memory is allocated. With the default value, it's around `960` bytes. There's a double-buffered incoming queue and a double-buffered outgoing queue (to avoid data races). + - You can approximate the memory usage with: - `LINK_WIRELESS_QUEUE_SIZE * sizeof(Message) * 4` <=> `LINK_WIRELESS_QUEUE_SIZE * 32` - `LINK_WIRELESS_MAX_SERVER_TRANSFER_LENGTH` and `LINK_WIRELESS_MAX_CLIENT_TRANSFER_LENGTH`: to set the biggest allowed transfer per timer tick. Transfers contain retransmission headers and multiple user messages. These values must be in the range `[6;20]` for servers and `[2;4]` for clients. The default values are `20` and `4`, but you might want to set them a bit lower to reduce CPU usage. - `LINK_WIRELESS_PUT_ISR_IN_IWRAM`: to put critical functions in IWRAM, which can significantly improve performance due to its faster access. This is disabled by default to conserve IWRAM space, which is limited, but it's enabled in demos to showcase its performance benefits. @@ -421,6 +422,36 @@ The GBA operates using `1` stop bit, but everything else can be configured. By d - Green wire (`TX`) -> GBA `SI`. - White wire (`RX`) -> GBA `SO`. +# 🟪 LinkCube + +*(aka JOYBUS Mode)* + +This is the GBA's implementation of JOYBUS, in which users connect the console to a *GameCube* (or *Wii* with GC ports) using an official adapter. The library can be tested using *Dolphin/mGBA* and [gba-joybus-tester](https://github.com/afska/gba-joybus-tester). + +![screenshot](https://github.com/user-attachments/assets/93c11c9a-bdbf-4726-a070-895465739789) + +You can change these compile-time constants: +- `LINK_CUBE_QUEUE_SIZE`: to set a custom buffer size (how many incoming and outgoing values the queues can store at max). The default value is `10`, which seems fine for most games. + - This affects how much memory is allocated. With the default value, it's around `120` bytes. There's a double-buffered pending queue (to avoid data races), and 1 outgoing queue. + - You can approximate the memory usage with: + - `LINK_CUBE_QUEUE_SIZE * sizeof(u32) * 3` <=> `LINK_CUBE_QUEUE_SIZE * 12` + +## Methods + +Name | Return type | Description +--- | --- | --- +`isActive()` | **bool** | Returns whether the library is active or not. +`activate()` | - | Activates the library. +`deactivate()` | - | Deactivates the library. +`wait()` | **bool** | Waits for data. Returns `true` on success, or `false` on JOYBUS reset. +`wait(cancel)` | **bool** | Like `wait()` but accepts a `cancel()` function. The library will continuously invoke it, and abort the wait if it returns `true`. +`canRead()` | **bool** | Returns `true` if there are pending received values to read. +`read()` | **u32** | Dequeues and returns the next received value. If there's no received data, a `0` will be returned. +`peek()` | **u32** | Returns the next received value without dequeuing it. If there's no received data, a `0` will be returned. +`send(data)` | - | Sends 32-bit `data`. If the other end asks for data at the same time you call this method, a `0x00000000` will be sent. +`pendingCount()` | **u32** | Returns the number of pending outgoing transfers. +`didReset([clear])` | **bool** | Returns whether a JOYBUS reset was requested or not. After this call, the reset flag is cleared if `clear` is `true` (default behavior). + # 📱 LinkMobile *(aka Mobile Adapter GB)* diff --git a/docs/img/link-cube.gif b/docs/img/link-cube.gif new file mode 100644 index 0000000000000000000000000000000000000000..891579120107d887bfde226ff5d9c2f71b67516d GIT binary patch literal 123831 zcmeFYcU%)+_wSoRRgjK=^sdsIG?CsxL95nr(b|iP>_F6I4t~g=$Eh2UlYH5PfbirOHR&ANy$o0{gIhb z^y5cyQBi5hzf@dY`m?w^uedU+1d&lvo>5kiS(TC6kdW5(J%1>%Y9g){^|fvZQnwS@ zycN;C6NB7M7}mHO>l&+S8~oMU-PGFA*4EM0)z#bEJNS>fk;rx=vJHvs zL=Fxj2a$JWXlQ6;WMq7Ne0q9%c6JtpLM<&VE&ogZ{o}vBEHAIDtgNoCuCK3e{##rB zq3wTbXM5)#?e1>x?{6I)ZJwU4onI_nT+Lrx&z#?kpWck1Z-x$T`nGRcH?JDkFPk?m zJ2tO+cK#0To{#SzF77OEtd1U_I!@}b$r-(cG!J>IDk1EKRH}II^0Dc9-t5Z=Q=nzxHF*9=%at>_}@DDN2mX# zv$Hb{26O%|UHn^r|Ngzayu4ffm#+S;>;Iw4o11ei_85yj#A5fc*j+4k4~sp(VlT1S zYb+Lf^KV_>++1L>cUAAo|5LZOEVuWymGoXK$mu8v@d@pk~#3Z*x zn8)aQP8P1_{+DHX=>-XSI2q^d%?YmMj-cneF#OWV^vKb-(~Ho_Qph_mfgV*|$dW`y z1j{k~3IV0B7C0G}Q(_zI8`+)|7f`ugfJ2rX%B{n%Nq$NXO*m49%NlHOt+{AS_Atkm zv3O^G*2VjI*A(@|qvSWb--2xuf2l3ISduGRCK?SCZe}u|6c)0ymrh=?J!d`5vDpKv zpfX<1W0>4?mY`X_vFbZkPzKCL9FAA^>gnIHKh$iX`WUbEcwD=I?H>-Q7@9&XbV4F6 zA@p%#k54SBmf1C?WYXwE1j7@!976KK`tzSsNWmB5tfG3B5d~WiR@+1GwSh#^{R6@)Ef%j-|u7Rk2hcoykT=<{X@q( zYKmc`b8Q2A54`Ua74}~GUj6M$^3Z677sJrWrHQbwUPEem#?=OzsSB*DT;=o>&k>Q$ z^r6tTG>2JCw22|yp69{-06j;=yGK%+&C?ZP&f`wK`p5Gg6kWN-=VoP(VC1$hb!IkiTc z5)OT9-|Hz3r1p)uCrVESe2K2_R{dU{-A$GD0x@m-nm}qUZ6wD1x^BwlRyIn6Os3bF z!{wy1N)qQd#-@IT*+Qkqv6tiy1UkWsT(@3qWP5%A4y6BN`=aHjD|4@NHjDq1C`%#U25~$}Nk6VBXFmL*z3)muH_VQY@30#qZLKzFG<%#_ zkNm;s)jw!s87g%J0%z6Jvz~xC6fVfZ= zUwt%)?i3Cz&6f-(f0-$AnzCD+#ao&(;%0c7Lo-yU{A}QNjL&H=5 zhKY)PTO-@SmST3@Um* z?cX>~pOry|ip|akrdlq~%Av$17Wf*|9dsB(glLJ_?7(!*AM&z~XLzRjKG6e4tCiz@ zCDzXdXNG++RdC``TNRDjKdG4NLakDJ1F6|TqgA@-Xl$v*qWaeY^~9oSgroHj7Gm2A zOkEpsnQOSl{0iN9eVKGIS-p{aKtZv$Hr9WacOO<8(;oO9T;^>K`kO&YwvxM z&s3B1=Zd7EJ!`3}nbDZq+_;RrAF5Zg)5Ep3bwm3quN!C8wrlHqwGKX}T}>}p5B!=M zI`C|4oLkhcd$pi-=reb7YIM9$|dFLc@jW+6G38m}C>Y-%_Z>a?5;=O1oa;4nONCa0{V=D5Db#+AhHHD6aw!sVK_u{%b%OFbuh*3>z$j=YX;IzU=5sEB$zZe7 zGGEm0{Z{!uFA=axmnG06+snZ?D9%&W3`_kNs`GCv&tT)GtmY$)3ojWxX-e8~9?`%E z@LoWOqn6g6%65=-0lY$y83)o2`%p(M=L5zv%kRwPh&16ani2~fP5fqp%orRx;^aO&4r5SLas&=k4D2cJ9 z5^_k`L~B^^lkOC+ZN}C0?bl&P{5|=li8%>g%&Gvu^k`Xp=}{@FM7MO_~Oz@Rg6+Rh#aE0Z$ORPeep*J9uqvW%cBO`P_na`$+X^!aqjX8;X;TS>UGGg!piSIY2PYWD>i2 z0>5`YDh z0l==Laacoq0YuC*SKQ~ZxUz8ISaRGWT1ti)7dj~TlK?n50?3aB1#^LgMq>yN(K>_) zy0k!kQt%r!P;+tu9W%&?5KM{&%tLTjnekDozyvX%z>*u?(ia*52q^$;PZ~$p2JQra zTc*Ij3BU#j@D+Ew!e0udNEelq_~b&Ms7|aP0{k{MmWmnl9EvNA02@NVtfNteuDG%S zDP*)jVF5fL3$W1=*qS+7pbc!|`oIqX7Ig(CC<6tViJ!;Dv=~OY|HOL>0P`<_tpq@V z7Ia%kaD6wQ&HK8MW6TT`AO(j?+EGMie3=EOU*@yACS|4KZHEJLjf#8*5{1!; z=>*`J&v7Yz(X6Cyg{ehc6-E1;KsHxg*eFQ<+B4r<- zj4K{&+m_27kA10>)B+56Qnr?grPvs7W{$LQmj%~teKnEI7SO?a1_yfmv=D;=37CO0 z0{Da*;O%5w52%IYQt9tV3oAGxUM$Xu|0B=7iOx&&u4T$UikU z&_^`>RGnri3!KlcWb;>~GrK}+xXn8bAOAFJucwiv z%Hq-=wGg-wsxv=PuW7k-aN92?J@q9!l4{+xY`wUW7lDIM(IiMT$P&@|V9)i&nDkJi zb@5Tl>LW6sBPl%g`S^Xp76BY7cr%R<&co~Wxi2(Kn$71|Bx4%Q#~SSuPg`#h4{`v6 zITr21LilV5@XSZt<;yl%dRH<{Qi>>=R76J-a|dZ$J2_9wExP$!qw{#~0Xq*VC$b~r z9pUQJZjfBtv_lswvRh=Y3y$dU`-aB~z`126ks1Bu&bx*~u;4HyqSskL+=g?#GCAf#rIW04)qr?Ls{5 zX0N+%0ex`4Zh?}H47a}Zw5~1VUN6UPcnOyzvh#MSGu~wIz`EZ&eXz)pOjENf%db6$ zr!PdaTh#z@*a(3s9d8pDbh(hRw7S)Ly`1$LX>}9qo~uE$+K})21g~Q zak98^?HdP;p>dL*;6xNdt*-v1(c)j z#ZOKq<4t{^ocwq*>1=BMiPypV`IJZV)VIkgH?67IjVU|R>D$`LkY>A(jOn5Pr( ze7u=x|0&OX+Zf&{Z{C@(=9z`w$@u3p!Nk*v{!_^}Gr9h=nY`0qIcF0mr{Z~MgED4{ zP_y}_vw=>t@aJ=W8ME-AnHJOjOw*ZSt=TSy`9g--LZ`VN|C#RQdFTDv0pb~7Z0UTb zzuls!K9a^Z~o5e}fxrU6zQ{JT;)Z#g6>B4m3V1IszVfNGhY%aq>5%Ka* z(`8!hEMwWsU*3iK=O}#b6{3SBZpPn_TUK}$>>N-l0*tHQF)Ko5tAg6AVwtOtV^$>> zRxv}XGK_2K#B1_qYqnZz%9(2~qu10I*5sq7XQCZmwaj(lt!M|V&)}^CWE?=+>z&r? zhKw7d`Rl{c%a#5cd;5!a0n4_G(@w)1Sx(FEWj0sv)~mFZOkygYnqItpCY%5WFoPcj7W??~(4~1v8{q?~XPQZ5F zf@3)2awOk2{qSbC*^=AvP9%1RUS{dF*-mZQcwOf1j>Bd!<4n!)cERLsgUp@|!hVXszs<45z>&$1od2Rk2!H=MECV=?=#2YU%c&}Vpd%K5;Lc=tQ+?tsj?%fde1A)4{UDihPOTi+VlFm`XydFfH$GCuz?55EI@ z*3v-0@xzgW9>#Uf#bfbXbXv^Lw9`?c_TdgMxBoa;g(( zr&_*0!#ATiGDq|PrN?w;LV}iBJj(Sv8{bD6FP>SG9KuR>o|W5iVwX9vJ2p(`shH!B z=I5l2=a4KnkF0aQMHk=2bLdN#K&Fe3R_9>zi-@m_k*ya&BNs7?&f&Kg-xgsOS#}QP z(=S^$znhwylkFR)Fm*Bj=J_YQ7$0@wK$Ff%SU8!d+wF*jhQ(|M-b zJega-(Y^LISUC=>fFasKKIA^b6ZUBVR)xQ;AgiBoj*aW=F5+O{rOT z>YL&>na`<&&eW^7M-i5=0rokMU87njR7>b1gM;}}(`KQj=~p}pRocBz-rRp(ZrBh? z%%q%dc=W!9bDs~_V{a+8?7+<)qbVtt-1(^K(xH0sF%Zt(U(qkt#+n_ho^a@iieKp)Q zCnW84ygqb}2^e>}INC(DhLcF%m?F&OwE27~Z_nF~Zf@}fDo%GE6*X5+Up;O|+&v@Z z@E23RmbVbCk;vuZY3#}oKU*U$`il+X>5A$}i|V+RR1{RAdUL5Gk7JG#rT7Dr>!$R` zrOOSz`*E#8g{ge@NQEVwT{oZki=vPkhl1osHLfi7N;U3+yg$m1i@St0@XN<5HTY4h z#~OmYC48DfBZ?>D!ef?IL#Rm)VQmTHV63~g)FDx+w)FX0mC*Am9FfruEM>Kh!W8SN zj?%+~C$E&5LgP7A*nU*&QuB6;j46w*SC6G~o{8wG%Td*gE2)W!zL9(Nre@;#+fSnU z67LdfCPnOOL=6PpCTga5yw5}pxnWeb)9jI=VsBaE-qg;}r+gAKqRLLFohANRBW8?O zF;P2rQGX_8a?(asXR_ZX`V6%_`lilwWBSvxh0V1eNh*-tZi71ClXb6J|0~?&nm{mT zeKqX9vSCZeL%i?r!uzEz-bFtA0(t+1xcK6IbmLt82hrzv-t|!moHNzmUbZ+{#vAmg zStXh;5L&0acK5bU<8PL*8L^-IWy9%@#hV?0hvz5T=8~-b-OBu~FKLsXR{Phk&??bq zC#ksB$Eu`C#@nGx4Rh%b+ezK{p>lBY!m*lH-`6Q}&U5Zv{i+$nxq)n$*`@h>qtT`H z7Eju>9iOYowUb0e+O7McP5NP@v9t8YenEKC#{vGfYtVhM%_jGe7x>RTeyeabdyKtQ zdH!j_z^3`r6ffjDp9q`X>^bMs``ioVwVC1Ny_OxG>E3gs{K&B+PMKDAONT957ztg7 z63Q=V@!2i!mGRxL+idYYY{h@!cht+(dVQGtmEqUIlufJuc_2vu#HCGeA=NsbFyw(m zs!DF)?Jd3q09RZVL_G?{SF`|Osp{{B7o#u|KZ{G5b(wqmh@e(*COSf;)j=nhwvzyd zX-gnnqEGIDtL(dbZ|dc#Yez%*L*5Zti7U`ej)pz!diUUysshEZT+p{l3)0YfsSCoF z0rYuzBFV5;SpbOC5Bi?+hq%%c{okJry53XQ)GP6M{{CW)^MR&&ONk5X%B7(AfliR- z#b2sJh?=D`eYl{C)%foiudWY_XZ0#FnBQLmaV(i}B~<09|HOu0uhNIN6A9Bjj{Zuy zLKiI_LmUKt)LRuMT3Df`?fK_>7LFCSl7zZ$;-B~eMXM)oeyQu%eoUCOwbZo6S2JpP z`R#iN`%QI)h8gBhQY((NKqyv1^F8%ga<8JbP{J=wYq6@7ijaOD2Z^DDcLKqVdF&j` z6c~i8g|T1`s>F9MP{i9Cw2&lg*uH4P&J!TVNDwbjP`I zQ3>tUdG!_ddtDQI_Wp}9L=a7~ELhO6oq(qJ9ho#Wp-6J)e$gOm&WRcyuu#VB>KdYS z&DQuyClm5V+G&MGfnX|N@aFfpIyDDW1H#Dd*k+< zLVDeBol65z|)H&*9kPUR%n!7Tij^)%jDMM$WP;DayuK-8kktc4ZXHuJ`W<`#XJ2D^s}V*^&EyQR0LFgv3ve{ zW~`cW58|7&{!LMwm{V5Nhx|)qfkt{XO=5+-81SBrHr)zQNW?NYt6uWeU~_9`arrT zW_y8GzN^e!;=TAS1QAlw^WoNzEdB#W+WRTLNDDlB+)ACY!~MqIZ2s-5X=%hYm+<1A zI=;Nrd3RrRX>{q`kGV!7xiPC0Kd0;4~Zh zzRfw)H}l1UTfPhGsHU-U$_3w(vxc8|Z$lQ>EE7W>514o&j(x@@K_OAlsQ}`F>(`TL7e%uF@W$pqNb1rFr#JQb5y>dBQwz)ZqNorbiQ1Ol~y!ISJ z$cIkI_|wuDb|;*bM=GR2CJvLUa5n^_Reayq6;Jmr_VRahmin`Wi&5&;%Y3dVgM1Li zUYtMs1$jB_ha>*NYoz|4*;1m{FskX`tKDKYg*M!^r&tXMJQG>mkT$}o$M{VIx4CUN z-`j}R+KejOBHG#>P_~opwUMw#kg~T^>b0*5%Q3ude;CqE=-7_^(oR?1UYaIH+0@Rk zCRaSr&WO{&j4WZI>|hm<|IFIKrq{utnagh3!4)EpaqHmD>v&>?v(24lpgPVuBjlg*7*Xb zOO~=rj=f8MUjBthm!e*ml4X}Nk)onUmuh^MT3(mBB|A@bm*#kv)>@ZjNS8KFw+^M! ztLv^;BHgbQyOnsl^(?#fJ(Q$Ox((vH-{y4-Ms*u?b(^Gj8;^IJop!%k>o%wCc~{b9 z!QS&hu}4v)$I`OLdcM{K!>OzHT)Oa5+vM*XsRnVkIXcQVy4YRjYBSydi z;rPUTJ$&?P&q~zfoBEwJ)fOWAQ`Y45m z+UGSGEn5DErb5ZJLTQOYfk{@;bw^xNzn%pwmq?9wZQw^#t`#Lv^dkIWta_p!EKmnb zRzFY`m8(lL0A^M*p;5=N0JgG6aH^^|MX|NxXj+eI;4BSxq{CpgK)525+EufU2N_M@ zPeKy`cE#ypM@FT?aF;a290$*S4kE_;uxUJ@If{d=ihvHyfmTP&t~HHO%Aw(Fjp=w~ z*ZffB-SomZz~v&`IZA`<0^em6+Q{BN&914pgfzQ=R_=w;3Jf%{!-hpPx8jFs(SsXn znyow<%|s)+I4`YTwYdw`Du~p!@{qdBBe)hrVnoAda@ymHBUMqu{2nh=EJg z%-tKg;lX{-rb*2`3g%E=qSRiAS6{8hYs^z?^3YbX7{;Men`s(Z*V6<~blkHVJ|$8+ z>q6q%g2+%h-A&ro&|wNuq-grcLZr@>BC=~uel{fNrb&~5HL3Bmgq*~{EmxyEx^$)e8XC*e`qpksdV>71$RIXNwGEA6g6UQsTv+K5Rv}u^L6;wCiST`WVa)7 znm(dZGZe-Q)Eyf2X3*`y5={<9=@Ad<_7U~_+zhw!3{*>Z#>_K#?suSYKz3GPK1xvE zANszfdS6WSy_KNB6FT(kuPKo7LOiNAPESHaltLJ~;-2?G^)%E&l&vFr-RZ*}3{{A2 zdtWQg#Ph18{Fw1^e4DgCCbZUL-=v%+{We0YEBj12_hv@bZzey~$i{EB@Whq#JI8#-x^e!zQG-^eAfn^tBXAe)+ioX?o&=NU*WtbU9lxTD2TDz( zn@sv{+G43X**Q?yH6G*PeG{qcd8C#J|2PyQXj-X+8voHbu`a(9Vp^SHIvc7m_q=Oz zzhlZOYnpftwQl@~v8w+3IsMG0lY<95X)3g)^1~4Gy&r{$?Uk z3##c0frSeaO$!=P^MdmW3)^OaZ(gYk4M8UiMnZ;%h|D2pe|poA8xsaMrAREU*5J6| zw4x^UsAdn5Ie*^5iB{*Sso4R?xOmY7iS5X4myU@A49GF^aDUjG_oZTVu4%?FN!ciA zz{t_s%lk3rI3B@nd@^#XgE&d)d9-xjzzPKb`L+F1|l*wm*-Vn_TFaDs$>f+z*LiTg2{n zwK$=a4^RPnD+hZ^o_oKn52jmo*76UU)}46S52~;sq^?0*o(H3hoqL(t-6F4B7Y+`v zyW4p4{INh9R~HV%9Dg$KY2iU*g3BfK{4V1`1LxtCw98?b{jxRQQ49;*5kz?zLSY-+ zf;~LN%FiFnT`>mh!~)q1U78cn*JjQLF;|=yFg*T)!+hJ{3oIH43+kY$g9T?=sHV8# z5w+LRydt{Q1coC6cs!lG`e2^uVJHm(MEDT*JPgK01IBo|uok$|ps`1+Suh4ym-|UB zT;ag`{KuFu;6>TT^On2!gNGdWCO3?()nZ4~hS|5;Zj`e_R1rtV$_`{)4&+nWAf-df zOB{+&@Me6Fq``?U4NTe``uy-jFdQtC1fno-*N6a;PO&hUAO4MTq16exdVs5P8^m@2 zqGLYhp9W&W4jFIVXl0N8S|94%y3rxfYW!!KiykUdu3It=68!E5WhdZXcf;EdDpC)5 zmlHtXLFWRCsR4`h*CWo0!xKKwgUL@6E+9h{*Ml_#Q_(}QGpk!LVm1I!06 zP~h$RcP<#e5f4Iq|u@ zwYe9UY^Z-Y*sArU{d&dQ24yz2NB-i-qV?$Axfe9c8*+FO7l^@sXu^1YMC5frgNA(^ z!Gx4wIKS|Dx^zLv?*+g87+YX3XOMm3>?QS*Wpf;sR_^eu+)I2a`+?UHNx>hf)}vG} z%t@k;o-0V<#b3p`OZsrn)&$pk;m3ceai5Uj($#ysv2nS7e)>h_GN#qz$-^K${$s6j zjQ;tjYP>6)XPAoK6KADtT>&6}gm;b2-zGd4K}9bt&CVhCg?p93QPr)+_wo~%j(bq| zkwm2W(D-}29mWn{qyzR z<{wdsNw$d+pY!A9dMdlAh9La=O@pJnD_x%-3On!B^UT*1`RkN9{uSClrap5&*!$}~ z&y%C_ozLk~WM{m{pvsxyTzGG~(q>Tm@0-dZ{Cvg5UXC{CI63N!aD! z+Pib%Pr>VQXa6mit=T&F!-E^C3-o;XcYYVF-{IcMRF%si_W3n>YjdpJrM2+#;`03D z@Q~@+A9zok8OF1I&J;xWq~0P3SMq{6WQ?JYIh4u>lI>1rU(XUAp%uXr!Sb2=eK_Mu9LuG|(gj zaJPh+0YpNKL_%g)wmM*DclpvCFj0WX*SmfGkN!^&{IA>tcd7BX1pk>D&jS7Lsqrg{ zKsu1^f279i<^jIkrN&e0{3|uyI8#rpYC|DW@Gdpp?oa+mytwy020HhRkzDd%a?=6I zyjOWT31S(ur;o>Tb${AZ*`F1Slo)qXpV7Us4T`weMJ;Xtefl=f!jumXD<%sgBJU`3 z8m!u#OOT=!fh-;I0PZ_YnL$(y1wTaNGEYWdk17O*KOo&Zy?SUh|Ba9vjiQm*4?@PV z;iv+Dayt{HxD?jWvIu)TDo(_wxtR@{Z`D$nlO{gprnNoicn?dMPiXUp6Il(w>CH)8zf!t7IC*snYXUdj$8G+?L`ZJYo0b&62Y_C^|Y#SCYT}q#%}1HalEw_U&g7ryC2EUJC6(81D@=pX2jSRsmEp( z?G(`C;QSANXaNKOC4mY5@`vk3S4S72l$4aTw6p-o)ZNv4=g@9%!($}@v2%BBa<0}I z0D%C`&jWAgVry@2kw~QEouSs+y7tb6TCX2fNdhG2?rK}t-c<)k#zN{p-rm;2My^Z% z64n68e|cKTJM;QTbkjztNy*iEiRJJ`=+VW;+@rfX0BZo?=)!#aWU?s%uzqwd5;1kO zp>cPxJ0JWL0-&Lx0RSxHA)=7GQf$6++KWDqr=p_TJ#AS(nu0w89AI*Oj)fkbf7v~4 zI~o%`JWt*_Swx?IJ3C7|KAxlxZv|LXi2x*E5taae1O^lL6T*1+GveDmqS1Rz#Tw`5 zp~uI_hYuf$04%$XuF&VPCeNZzPirxl=#L)(duL75)YSWD<-_aer>E7<^uo8dv4CgM zMulHwQ?q4Ka=$iv#X}fhy#jo!_A)X8bRAVeieH_c)+=RX+}`$rK!Bx-P)Pt__q0PR zI}v>z14+=ZDh)b0X^gdw4Y88Gy-k&jy=&{s$;q#!HqlVor-?=!>qmc2PFgUSNC$_z zZjabK?aG+#y8HWNWB~PRG5;&Om;dd~?am(({)az=jD{&ZGDL)I%eg`S=co`lpzZ$? z6>9$V@jp}?4Smz z_!nEDV5YOD^@!z85kfXIq#Hv4w3 zkdQl-iO!xg$N2pOhqI{D)azt9nTMM`)=wfIXH&q#=y2mJEp0TGUR~OR@VnVRPGPFO z*Y*R802W#1R9G8X=jx?wS>0{u-JD!h`=!>dG=JvFQnAMFx1znT-8GE`8Uw!+3z{PCsXwvn(xtU( znA1MXtmA_XzII;$)-lK3W`;?v>sv7*YD%PS$Zq zl&83rS)Ly8dV$<8Nv}Mc)6Bp0Y>r=ph%S~f7&u9kJ&K!?$k?38TAcfvI*~pi08>#d zT+7#r94`}at4*8GGwnNjj~9sgKK1?)wdagvT(qZ!P5Hiym%lVD!v{W`_vK*A&|d{}=o zCuxCVJHH@?VyCFCrDhlLf$?fjw?bQLuXb_4=b)ir*!S?q?E}B94w6IfqaKGCzvD#y zk*2lb7l)A3KToy&&%(^VHZRS(9D1EE>=FlDcz%7^GQW{^=y|!5I}~vBzLn&~)bYse z#~X~xmq2Xv!N`k9?3MW^5O>=kDFW)Du!Me4DBCB1fI))c2aMe9ojQmhzs{vSzCyV+ zS41!roV_c<-O&__2nkWhKGd^qpr}Oi^7*|pe$U-mGl~d{>RdkZsQ>loSbzsBbG>X3 z#NAa!S`iVizHsbD2PIwuvjLHxWDI`e-lQFCP%0naBFDzfW26 zI4&j~jL)gouWt0`n>Uo5?f&0y3Nb7IIMEMo6}17~)Z_Tvu3&(E|A2nOaRP`L^hD_` zK%1I~3pe>6R7m4t+Z`(8(az^!H<*HAPioT47g8VuGXhRh%GQ8H9(Mo{e$g zo-;}xq+Yt*O5M=(L07T=Egq(u4Ez~r5p|2B5-X-uB%7N*aap3oAfNnJQ;Ezy{ zMG5p`7ANS1^@j0wIuDj=HGV#&Sou<%++RGLcX;u_j#GBkW=xepTPNS|xu!t%W&d=)A+>^s|tS<)8L7{lE!r4Bi zTY^JxCyK+4acr2kH3+YOor%;H)ZB`MpW)-#_p%8zt*{(cPp>ouO7x0&yEimGJQ-*U z(3;td&WEw2Q4e%*sGY?;>vYEkyL?!Z#(Q#OOjhT-gR`88wxIOu zPIl)`76|Q|d*#X9Gn7aCqSE6kz&aDERz_m1+K9@ds!+{1Ef9 zR?AX)ZvXP7B*Frm)DJ^51l$rM3N~yN)$)R%gd-?-TrwFw_}n z4&Vmz1OFM8--VTTIQCrt+S=M$T6%}A4%`KkwJ0wn)b-+%U63D#uM?W=#E(L)GkSNvzscG_{mE3PZ(OKGWK!e zankl|9pq%^lbU{6f3Z>N%Dl!uVQ2)!Q!`|J#cFRXn?|PQT^Kr;EbOp={8hC%0$2FL zsMS!tJy!U-*lehwW_JqlVK7sxv37s1-hFprsIl&Fu`T#MlXg@6(Q4oKr{=>=zfLws zb2YNGn;Xt{r>h(mhnpME50^TzUzlFDH2po<8Y?y*X=%PXN3RZMy=-l{xw<&nT^wm` zz4HZl+)Gd#YTG3k0cYV-5Rur{QZT79_i_lOzU^`-jdkI27`^A#ayWAs_eunNqU}l~ zcYfi@XP(-vl`jH4+^bO{leVkT;v0plG18c=)vvO6kJn-qsqNO{R5^dHebW@%Ui+@2 z{CGWHPv34m!O;5WdZLNv_Igr@Ai!FYC_*A%!79~zL*B0F7pJ^a!(VGTw*iR)*-x_) zHkm$U{We)2CcO*f>_9pjaF0}P?i}#1U);Ho@;;-v-&P2@bK><=?S7nO3gS_1v~H_MKLQ8_Eg5d`DYBS&#aSv6Vae{Gk| z9W)+=^#)N0P4`2o?w;H8EjQ%%5N(T*%)zqvuVWR-U+^%;60u%eLO}$M`3QMR<0wJ7 zhc-OMgpXVS07_t9i4Y~g6#=Zr3yu1Q)cL(f(a*`XCWOS*iftRQQ$@Rj&+IN}%-UWO1|r81O=|^q2&I6bPEI zzV88hKp4VYi3Q4Y$$}OYY+^l7AmG6>z+Lj>QMc8#W6%g;vH)Z?j-;g?^vMrhg-1oh zchPOR)#j~aFUtmWAorJ? zGWr|({;w!WkjNsiN$${Kv}OJFzVUSwrWI=nCHNxT38bi}T_!7sr~zati{MQ#@p2H- zn7Pk7{6&YI4)a6HOr&zMrLTYbj{gPSJwCLFFz=zRLRoz4pEDb?^K4_}-82ANO~!Kla*KYwf+;4_(jKHP6@eF7`E8 zyyl~cxIF9j$We1>te1aSoGUrqk3FrYvmg=qt+9Tq=fTxamrJ3s9^`*Si0%GVQFXgy zYxu3leP4ey*0K*< zK1fY4NRuw{gbXop*F^op-KA`8kAB%BRwAX@&GBXk_l-g)fE1`ns&^L=91t zPn!>#QpM1%C=}!fyED-f8Lq*w+#5$2AgDUhj%gC)aNAcSTft z+XiQTAL%OD6V__Ti8-#7^I+b^dZ|4RV&o02Iu9tCo?a%#qAOJhJN6+`c$WVh({G(J zV(jsc#l$)OIXw^VY(J*M_xIbTDmAxsd)YlzKS8SX%-HkWsMVtZ2Rqi@wjQ2Ul7{jX zXqLZGBl{nn^hfxr1rcRiN8Xp zmwY(#xLUk#_9b;MbbGkc_n~iZF0`BO8Sy>Nec3m^R!PJR)38u~EzSR$n|>^4>vQ$d z$?2BJowV#jn-4!_z6&eZjNmS=6TRQ!_UM-Xk53zLPpa!@%s&0$ZM3cPv2h0Xsu*{C zbe<-BB~H{0V>j@k?!s+>E3W0I)ITm<{hw!l{N^Z4qooewpl zPEAiESvp6(Quxd|HS=rD*ZT>**Fqv#EoIxrPMmNXOTCf$eEmMZbq`f4!gV+7kIG^s)YyzQLeF@%WCxP^qe&5_HTiCBdyjBpK$` zp~^6m@Lg*j2*wroIf~Iqrv)ZW0*#312ZU(ts%Xo>Kt` z<2<`PI%ci&wu<+4kN0t3S9>siQ&oIWQT)iqI37J={RI8+EHo$1@OUHhM59r7bHXln zquu1hNGoj&=I<$JFJgtP#~A;Xf`D-$x4@Ap*vGrMxj_aaNi4u!@*fCO-)TQnLKaaJZWiZ2rY2*OHNMi(xpowAtCPW?r^FJi^XPS zWWaGNZEfv0Z{A2qNcj2rLE@rND3DK36g_k1jERW}pU;<-l_d}e3l=Ppl9GamLZi_( zZ{BQbYO1EDW^ZpVBO?C>k-ZQ8VQ z<;wHt&-?iJz!|A~_wKD(vj#e>u*kn~;liOqhhk%6)6>%-3&F9drlux1$~ArZ^u2rc zUb%7wK7yD%d$zN)GhCj6lT(F-g|A<~Ha9n?QmIx}R&b^(Ffg#ZynM@+Eq#4`o}QkI z7cYML^y&8P+g)8+2^ZBrIFD?A*C?a3!q0y*(-_ z%E7_G(a{k?;G8*g;1C)du}V%(hGeL!stSjzw6wI~mety|YgesWm71D5ckbNM($bii z7%rE4_3Bl~sPN&#^5x5ef`WuX;m(~qTU%Qp)WMChb?esI+1c&dwF`0`gr4;6Fx~`v)MK_HkU77-nMNUgtq~lnom;w6wGwJ9cbvaB$(mg)3I9fJ9nU zRAgvq2w{82jvZUKZasML;IwJeva_@6>+9p=<2yP!Dl01?n!@cg7Z;bLq$D`eb@AfG z%*@Qj#zwe_=HcPN;c(WkU!Rqg6%Y`xWXX~fCr$(h2g6CWef#zq7#NIyTTy3$Q@pBAh?>>KlfUkE*%W)_`QJ6OVK*tq>H1=h+fvCR30?lE z8exgYkq67Y9kShLmD6Au@0MX9%tS@6rOGbQ)Gv2pFBQZ%hgA(5=EW>N<}BrCEyKuL zCBVu$GD6IF(&}iYor`ne{f!T9uIpHo>!QrUn_*c|XHrMypH@h%(!DyGa7+PN6!PPY zITj(+Xfn==r#XsIiQOYBytmriw^!NCm@Bx86IC&z zSJkr*aiZ(hhr}^DdZ!<;R6WpU_4(uYCgh+y8>9KvH+b>V9lqE$roLEAqw^+0iSqXC z?PP;CPKZcxO@NNQLBj-N>C(2*kB&=kTj(A~#-L9WSB>%!S+XN`gQdHV3*!S{7K2PT>8MrS;!)>jN5&`PH@J{P zNgHB9?QF(@SQK**ix&i{?Ff3bF^i(zuxa(= zMo2*{f7wF)BU|fU@(n6RSxssPE6p^W*~g?_aq^1F+^8as&uU*0ab_+YVL3GPXcKC+F%i(y3#=fz=E z7@bY5o1WW6b+mKhVx)^1jwq(Boc8kahh@BG%zmK`vRT}uCv1= zAiA-oJZr|yu8)h~H@T?Y_Fe2Z6Zty$>Vo8Z3vN6PG2~Kps?bj74qRM2YZ8|*S1s88 z_zR&6E`r&$zyyxY;KNuf$@g7f54spXzy#br={Rph{jQ^Ge+Nt1x_BVTRI=KvgKf6= z%`)G!$7i(P+IX{uLsY=)AahHzGEDDmdWzbkOI@NHvD8@E`O=F=gIy)&MzOwQPxH6m zB1%QsQ#ZJ}1fOQNFr_7oHgU`C9mwB91R8ZFoJ2aWR8g`;7S&v=xVO#B`p{ZW4H>N{ zwzk}^Y;xlwDTIK@s|zD6e6rg8rl_ptt$<`!kLX*~E~YukE74gd_~r2wN}-~BA;X+l zmtYgiLwJTqWzVAa+6{=-149f!eObCTM<~e`;?xa=$#Slv^hs+n%P^OTggQ3JRnbM- z#S9sLmreb{(Tz>UeHOFTocSskgKbZ4qLi?2kE#rjzY zSk=6ynKc{+y_Btfn`|kam$y%mkJ!JDSb$%N-{cE8f1}*gg7Q~A{|N2 zBxBnR<(&LjE7Xm2^eTr>&dABoZxB48yGMm-}5McRbZWl1ZGv}JuK3N?tD_PDP}8VY74zgVrZ$|Sk%5VZfy}8F)AWc%Y#$oL{56~7=he^@&xtKMoEGZb_SP$ zn49>}hiETZ`gt*ObRW53gs+q=jMe#$Y^i>(bQB*V?Ka9M8}Vxu+t3UZIwoHszt&xC z(*d>ww?OAi!+dIiM9pZN(l+#rvl0V~LGu}bi3TpgdMoyBF;Lqnr680;!W|4UblqMX1|o<7x>}SgcPK z9}I#ROrc2Wr3xR9&1c(ub@QPLN?8|0)In077%%Y>FP3A*#hH*16`agjB+*8w zV}@CA6>;c_W+2lCycpr5@+L&@m4#A;Dp6YaQ?o^f=eWO8q3(!XKDG|UsxU>zON?c- zS=6m&T-B5-tEM$6B(dgVBxODwEcaY?_t6YIX)%hK)Q4~E(jR6w{CKfi+A8_kxYWmd z#A>;I)yG(NTUC>#VxnZziv@!5DhBHgt+I;a>z%42R~3<>ek*O;Z%x6>!)rxzhq7nWP0@mM^nd*hR{2_TPN;j%^r zyV~(ZF_H3#7`xj+73rMOJiN$>xBab;Br~fCyVa3+I9@EH-$a0083}T2+RvW(UA89+ zlV^J5p;W_q?QveJZMR76O>^|LT$0_GWT8xjm4ngN4}9(bM!GwKZ;@+2v-J=wk@K+n z5yF(A+ZXoWyyi1CSP5F8&uM1@@N>3eVwTLkD>2uQtz5v4)o{!wQX?Fh5t!83g~5!j z89UANtk^!y(ek~hqgj*{e-_-|jS@B>hd9HEcrV0h*xq3_i>SHQlbT6zBnQoG2<<;YZu^I(Z0S5>{xr5^cZui7z_89*%2{TaJQ=}W^Q+k z-9!wF9$RHWy|r?QaX!9XEcZQAmW0w2NXUayvRy4jWI?hWv$StknB9)=VGw*!^M_!npOp!DagBz4wO3Y(ij>tPum* z8h}o^uo6UFgq1A9cts4#mFP@gE#;*i61SRK7PsDtXhcBFQM?Zs3BIo$y3y?w7iWyB z@1BpI9aRc2L^cJ;mX9j+oFZQ4AQ`jJBtyi3OWB*g`T9ZPlYVj@H~KaQDQ01|pz2rK zQ7Jx&z$Kb8aUEU~aucZ`3fM>;w@5^Qlp-Mtl6aY<4t6}YgS?%Cta994%t3CC+UJSM zPt4S{!)DV2#9O||LNSwOMjdY_Jr(QDW}-C&k2(UbAr8qI#WOg_%62&%O4z_$qk&={ zA%skkNoj=aw|2SB1?%zml91Ar0HIW+kg!fflF!4(G7+v=ZnZeU_>9htE5*u$iRp2#h| z%7^ET9>cPvdhL%6tZ`}JA%3HziWVsnSK?kJDw&5_bhS{WR7(3Lsw~C^@#j)Fn_CZU zer}ZgeND(wcZ=?Bo+S@`B!>%Rg12+e$H+YtN`6)J3JJDT@-% zCq8(YkQPl)J&dlo3ipUG9*gqu!Q^-@Id)8jo1EygDQ9D=(wum7bI+-YFQ+Inr?;=w zjPi;l)}G#zyei6zO7kk3sj_y~)h$+QiT4KqaVhb6X&$u+xUqy2#;Asy6~Z}tAoA>) zo^1RWIjT&8fjKqjA#$Z6CCvGhlrd6CLC%(1-bz2GaP=I$Rq4heG{U&piX$b-qBq!} zZl#v*N(-8eQ9}+{QY_g=Mp}(gVgiq%B&jMw3`((iqs6+HEJ-I4Bx=JvNjn@=42U6y3l=}5agYI92pf?SZ~VR!Rs zckkh2xTLbg3zyDZpa?Jx45_GmiJ7b-goo^JlD>ODN}59nK`@V464@y6Zaw@f!H-A& zDI)Zb&W#n3FEFIyh;cteO6&5F5-rr}aOhKnV8A?L&n3mQd?7BlM#-5^IqIcBUZ_T|^$!(veRlr5>(c)5N}N^nV;%I<=e?VB zqy2U3UZ_r!VG^i3!s+n38Q<%eYW3!G>n%L$XGhgr9j&(+S>)h_JQUxcDdFvEF?azo zTW0vDQMFCmqGAqp zt7kdO44S#&Yq6Fnelxo<+!1q(fp8g7r`Bc@^RXMFH03zN9u6h3R6n`8c~;{7TbK4L zU?kW((3vb^)_1r`&|-y>q(sN@9oS$Iep%hpM`0M7Qi?%o)0Vc@8v_{Pr#5nvf(&YS z_#jP?aS^xdR;A1CE4_pxVouF>w@Ds0rd{e54XJ-XBah^+-9MLlf7S@XDn*h}-7qnh%Gif6NqdEaG6t=U zhj}|X-Kjjh;a+%LZ}1)Fu}miEk>kUe)lrw6sOsS~`Pki9FR4qG?7}(dYP`w_$y6)9&8p zW4*1{d)uD$-ucnnuKuKR()LN$`X>)|Kj}X9r04pR-X~A`emoJY_dT=i8(7~rxVvxo zSl_GbeIrl$-onK$^{4M`pN_A8`f2ymiS;$)%%|Uf^kIa^56PIHP#gCQ#kq8IH}*YSKlTf>E!`&@MC`P|9pER6wsy8%bffdzX8oO1^j)eN}w4Y*DY za5P>lw|lYD^Tp~tFWhrqtgU(B(f7i0@b(A#d%*K^Qs&tO3A;HH|vpgy>ZHOQMG z`%QglgUo`^J_V`JA)EX~lRNjw72g}O(wfQF7>>3ZUe!M9invu4?5xAPwuJNYR?pIy# z!JaqWxo>)E-t_jp>6?5b)_D8O?(Kl*+rd3=hjZV)s)1`>&<1=vs`2i<-Mewmcc1pW zo5+3lwdURTJ~-w74tY96VUFTAj1u?my0~wYmOol{XOz-EdO>Q8tTk5RI!5#wJGXBP zpFeiy&KS0TtWfGbL-UpPQnlB5$48~i-skRlUw-Gk!7BCR1UKGl#UKR06`r@boleH zUk61U@dGg%ehg0a%$bP3K2q_sA~+cF_eZ?Fk-$J?#R`N-M7C@}=FdkwJP@$E?d=he zvAJA?Ooo59-;yQB+_}h(9SDPgfJ|;=ge+Y6%YXOuM5a$i)YK5LyJycvl$1b+uaJ>J zK!4x35t%jXm%{z?=k=dIf4Sv9e`ff>uGh~`SOJ^l$2Rca@!x;^`z!DlUjbN-lkjw_ zQiKnWT4-BvIbQYz2`MX!QNEx)MT#uT8x~=s<8XS8h%jBuN|GR1tQ^jR zNP|#EX2vE=zP&=i08F^^SelWypq4Ly{V=8!o}Ib}#eecT_l$roWlk*xgtD zj`D{hbXv8#?9mNZ+}-s@SCpktG`%!qSzZ@!C$86` zZ(iE{czpl<^vb;xxzA&y<+%4{`B&2)tlHLoETJ#tcST6cqjpJCCTD}5JAbK=?dyQW z=zcn!z|emnzvuDBQOphmE|09}u|0HLFquB&9@(ik@GN;`dRBXcnawOsf0Jc?sH4;9 z#`LB7lra7l45OP9_k6wlKp^Buey&NL8sTQ zh+1_%PzFC!SUAK!usZA1!8Q7!FSe3GzNi*X`b{Z9uU5zH(H2g#pONwT)s81#hYBt{ zoz=B@MQ%=I$9X%%;Ro0Q-2NjR@3a(B?=VVhNs7R>?;+u#+~{B{MUnC_^)-xWi8 zTh(s+?AXR58@8#R=$Kw%Qq>bT<7M|X<~6mM`QMBb!e8zQ|$Z(^mA zmC?E2_o|CFF&-)$Xm~dVe?{q~{Bse(`|XksJ6l+-A#zxg+kAQ5X54(Ix=|PDt@MVL zmEMCjidRSDngw@m>t~s&RJ6x4+n`TvsIUB7R$0eQi#wGZM&xS}VM8%f^nJw5wY zlTW9WOkc`<+?PC?aOHl9$sFabz=Wky zaUZXJ2$Yob>7B5h)hdE-sUAd?y?N-HA&`qvWi-(Cd;a>ri86z#_~EkCa$AbOb?p#y#?h| zVhp9sHm9)qrhD`2b^DZpj~wxqf2epxwTXpz7n@3Ebyv-*7z<#xV@+!!7<2C&CIzVZ zDvJ((4w)}xg9sLg-D zhvEP(_VFoq#E@8f;HIIe(JkxMdT`)-?KEF)T7I+d$i?G7gY>1E#ds4&DU!;FR*B%_ zl&V}wXLJAS+F3W^XPcVF5M+!;SL=f_J9X~&`yt{=~?`|-+bgUy4=J0H*QTL0Qp z`datRJ)xxsevAYxz1DX7{HKa*Ki+8i&*>d<{aktL`rC-RySm?<|6KFU_Epr+Yhu!c z5QNt|nk@DGmQ2QuI25i-&il~6@#{qEx;-z_4V(wR6;IsSHTglm<@=!Z(#R7tJ>M5e z{}^7ncjx_-zWe&yc0Y5v@qFJsjq%w|-{1ImM)sQaeO{k%{pK#|@6V{76BVYmkJP=t z58kxvs&}jTa9a9HyVJZ=U3VwPR!q*@HL`i{o2N^^z6pQ2Da%;>OUZ&OBTKjJzH`lP z==H<7U!SY(DLAnAbHjxjldp4s{`mIv&5zG}u@O5kR(#?_SZ6q&5)dv?#g|IlL73pn zc8AJX2^0f%O2RQQ_b`PjfkxGK^$CHt^L8z(X#J`P<%now!%(BD=ot~)^(Lat$suM| zF|)~g`@&;vvcjfU#n?HA%$kU?p~u<>#5lUgnn%Ps4@WPmiZ$+zbq$E-(BrhN;#Lj| zR!79CWW}uw5P&5lI}yhn=7S|fagX;4;0I*IW5E&{-n(@o{;N_#2z^hedqPimLWJ|~ zomB~U9wzJwh~m=|MV5)NiMuA_BNC4vPE3x7OzloQ_!*wFh_tmz(lJarG!dSam9)Du z>1bAX?nKgex1@pyLB4x3FFd)3%rC4;mM%&@-yKmxPw}@(xl|Ni5s|VbE9ELVp}IR| z`$S5a0!t{_mJVC)N|eY-jX9myZ6`J+>g8r z#aatp+=RrWP;$1A9+65@PL=v1+%d6V_DckHP5Qj>bb90-nJek{PN!=mZD%NFTyaX* zJrk}InKAQlhH*=b`lF1*fcgxkb-0Q3foBsLvtK5fXCK(&c3^H~h~1Y16IBNu4W&Kx z&m3~jw3kRDCmvX8xc`k?+H#}44<}OBS?=ewqz_hRrW9p*TnYF5ve(%<)u)C3!u`-K z`k@UiX`8YS3^;|czl1Kx-v5~#>wYG3#5pzG`XHnG(B|yJu3rx44Ihq{I2^ksYoT&h z;=%(7SF+^0v-TP75h`bIw9L+26B-jFug$10&NH+9&n_P8FI-rh$*#qJf zxLhE6f!G8R7|2XuBY`>wh8dVxpm2eV1#%DgSYT6uItF4Hm|I{Yfer-*7`SEN`ha=` zP7-KdAc27x1YQ@2L?DWRxC7n~7*t@4ff@x$7T7}IY=M*pni{BPAUQ$41x*TMDKN1> z)XaMwVL1FH$#CNSGT(gMp0Brq_XK(qo02?R0_#h^t5HWCP4AS8i$1rinbOdwQ& znFJyiC}^OIfyD*77>G(>R)Nk1J{HJWpv{3`2Z|NgX<#pb)CKkuI8Pvufn^2e6Zmsr zwt;mA3KTebptymZ1|k|LU*JN43_7~~%fB2{W z$@KdDg+>_`A6{r&{ree;t!>WbzDW9SeV5J?Er;pre!bAB@0?|2+Ji^)vjsDWGX3T( z3q0GVG|_k#V}PMSA~LNXExdfT@u)Q^q?7O0!k!&$k$Bc!BASMgptuGj_8AOw?MbrQ zv!uHx6eCtuqwE5%Nd?x}xpYy4{_0|!R#>87K@wa4G|lB=qhW!CtTsNtby_=a8rjHq zSzxKZi%`N&d*zurE;q{@YeSn`esbR+v|L`hMovIiS$z|m?^w@}-e?79_#*1#h!+D$ zGbR{(`xt>D-Zz5FOY*G2Do>6LW8imH@3nhRN8YRxW1RHfkBGh7WeND2*kg&!2s>18 zZ`DJVW}BMu$qu}AEm37-YR5{+EgYSC?W4s^+|E}Utz>s4%HWAc`uI*qNkXt#f?~w0 z$2k7@L1OVAurUG>DZ~J!%CzyLan|I*7-g)8)kt1156@|=Rme8aPI?{-TRWyWeY> zwtB<~rMe;7Hwh7;FSS!8JqpMq-%g}a+qP{C&nAV+)Sc2=`8*ZLb}2)03-t^A6G(KQ zc*z-Du8=-iRH$WdF>dr#??iXtXOVhVA-Yh{$;4MH{-omK_A_g2%Ls(#(0lRhctb80 zo#WE=?C@4+nfVgCe9QPMXAARLigN>qX`!12WaHWO6u*&cSgjN}?d1(9-jrCw3thVBb6L_2aJNzt^5WpAA1p~bm^mEX=J?iI?cV_Whu3CJ>wXnb{3EA@a5 zzL43#4iB!au2-a*61-)2=V7b>xqvO~)BZ)7@P2o}NUYzuj` z*ir4fX#Bp*XG6|?xBX0^lzYM(HrpWf&Bu;H{VlRRL6x>>0&e8xr(V5_maN`29VM2N zojaZ$``pKW`l#|LldyFnBSy}%vp@CR;i_jUEdz1OS+ll&DNA@#Vm)B+Vp<~6KOjV? zrxMU^?{HgBwn5D?b9n>h@Xg#WgE=>S+f^52vKkE6%7=>J$(i6=SE*}cQq`o2%<9Y~ z#9X#)**d#9Z(`R4Hkz6`VpG}qQNhjn2Xvt#l(U}MPRubvua8?V)BM8PJa?wE2Ab&A zF4@!2jx&=^Hx&`Ao9m?84Umr|`*)k3S^sfSs3fLY#LrS;%eWxXr^YWt{dk1IXhpD^ zYGZkO<|N82=f|u`EoLM)$4aWTBW&x2y-LmSBA(&34Dk{JvP=xc8;x5^cckX06(MSd zWk;!#`-u+2^|Zid$Ak$HHIMF~aCW7TsP78qrGR^L^yg8H;)I zwTSst8w*{D{cw6eqaE+yQiqqCz|ub#p?d9g#Q72RD~Sr^6{B9%!`{xS@F|_iT!f70 zBMKAF3u76A4Uen#vBy~#CFVL3W~DgjIRy%FRr$y~ZY^818c{NL#JZ`f8W}17Y5iOZ z4b?%!{r8Ct%j19l@$av||ASwFznIujba=`#nNIRjw}Y1U>V$=L_Rk1MxU5_cP4oVLD{_v=tf<%M5|Qm7g(|JNF-d;hx)RdZcF zLQs!juqoQj;%LH*LU9b19grV`SkUwBRirM7VCWo4}lH_u$ z3KERY4r`~$-$^V;GH$KP->-h2KCsWauj;^l0`X6`n*_)OBnHF$?OPIjKl-CC0to_w z0|W#>RtN=<9Uv({c7P}WoDbmw@&cp)$N~@+AU;4|07{2|03ZS>1EK^(0|*+B2%xY5 z@c|$c(gdUiz*@j>h!w!wkToEQOtC#g1_%g1o)BArjUfv_00H=i1Oc=^6(S%w0O~`C z0L};6hwK344A==64-5~?3D6Gp5{ME2@Q^7Wl>oX!pnzBbnPRHr0rU>s4#W-s4^agI z1)wq{3kVdz!w@I{(IHbnj+hE5kRX84fz=^QL12Lp0Z{@n3&aPA5`RPn$UzX4fYJfi zfzKf?K;{Bm|8-sJ^=n86P_%&50Qm@F0z?=H2oMt>BLJL3Mu4OMa1JSHDl9{NVq;?=tU-=|5CPc%5)I^tsfq>ENFYZ*?1Cr(MGmNlO!Y$`;6SK>GzX0!XkSd_ zi>YJ*NeB8H(D#6d0bP!%hync*$Yqc+AYwq!fRq8@0#XKaJRn~{y$2!+Z$K)!&K z0aX(S7mzX_Yd~EGQU-)Ih-{E4rh*294oF6jH6U?7K7xn=;Rx~?qztHh{7SyZpP+?h79e`LhI&5I z3ydbQRV!x0 z@heBo7HnOics6Txh$9k5nFVhn=nI2TM}qV!B!()?GUMdTeO1dQZ!;GWA`3itY|{a= z{`$!HVullTvb0=Ot0+z1^x8|yza?eO*p57(Xm%7GWh-0K7i-{g*{Cyvo##c6l(outz~vOa zkHOf`yUHV}mM@vNJ^b${C`_Y!rLtLb(`%8N@`jfXa)7u(lT2x7kctT9CK~Y#z1t_X z3_aKymKTbcw^eUl5?2t{r1F(d{)2tOFw=Ygv+> zw#`r}xyyd&h=0fV=cUwxI1D~3NGLrMZBKU8Zh!mjoi%MGM!IGLuYL4J0s|%9xF_X! zqRh$k$9R|9wjUq6{V)9Z)EoZp$7gZEhTXa)UfPpimSC3Ml*n=q;Yb@C6|)?oLy<(8 zV}{EX$)3o2_j75Wdo(_il{{U30OL7PryQLw882oi+c)#|XN)E?OZnI(6UT`gmgCe6 zang4qx>@%9akeY5GzITwOuS!S)t1pXBTTgJdlpGbSj&iRZlGKhr(R}rUEa>M5+WdJ zX>TgTW}>X=i4h{It`;_kk?FA75Ft0z5-d?|xwPi_$tGSnllDe6+Iv!PHv>nBSnp62 zFyCZTSqd+cto)!9s}fPiSjTEG=o%%ceBlw9iFK;aot+aBwPd%_V-%xSp~PwiwwUom zevP4!t@u8J5{XRD6k`J?(iw`01k?8%8pongVofQVmXn9I<7;7+N3r_;XHeylI^sg- z`fa_0ILlrynH2$v65fnBb!Hw7Cq@(lT3lk=`hy0C)7e?2S8#KEC67+CpII3wB;^T^ zxmI=TEGJ~vi~+P}g@$GJpA(4yd4ViN7{87G|1kSu%)@Ah*$<-~#{bmphao++G@P38 zFri`g|3L#V?_o&?qZ-C1jDMK%FyLVj!i3^NjjF${j#8v+vmWB`T0;GbIX!FYhV3-cZ(Jl-*$2BuH|UPyl8>41PcsnEf#F zf#Ie`K9p-=+o3rzi~kq_(w^B(X8X8+XGpBnkF`Gt88 z!yZs=Z-DIlUegm z2{cWy&f(t%3*Yh;!rR>16}; z?8DL<<7jR94uM!%l^%Cxcb@Olx}9(j~iE0VyVCRWXE zXV`L!3zsW6=M&Scb%{#V<9UvmzJ|tfzM>Q1hloDhfWczcLLExpeASg9_Aw7xD8Y@d zRgcQh#~W3BXd!7qb0}Rt@yElgIAn(s76D<4mdl!PrKAY76UQ!XB*y@ zH0?rb&rNDsa7c#O#@bhCy-0?vO~_Z~=ipYU@Xg(-RWJ(i_ZcE$fZ70CAIp;)Oh_Pe zOD^*VSnax&9~I`m^UIgE)O*@qlunflE@Ohz5eEWpy@RodMx(Z za!O{c)P!R1yGvw);?X*q<;Z9~>SQw3Anz75)<}1wEp*88jcS*g9?D-xC#~;flfJE5 z(2NQum=yFZJ~;U%E}M;)WaX7NXL#lOn%nJ>KNT6ZNarlL>cTN++7o#*F(%oCP7MnJTVx13@>!Lfgvtq z+M|laGOhb~Zg7cCw|lpljA|Puu@_jc@lcX4ZF)-K7}PnB0Nsi>aS0UNf9=$Vt8D6>G7y0V#p zq0&do;s_{@Jrh~ntL=dL;Z1~;8HL_X+Tp{8qVcZ1rFv5LRKQ4?;A!zyAgUXoN4~pFem8VgxJ%CInCf zXoM{iz!(4|uojRWKnSdm04V|LV50 zkaCJJ0Skd7VFLwZ2=F$Alt6~CU;<_Xumt`DHiI1pP$lr^)FKIZ5;jM`P5^blNU$~n zgoBTJrx+4o65wr$B!Nh$NOEeA0~?$vm;{mpMg@eMVpJeWfFEGCskIb98ZhbF;6`9bfHB}k*v@33e&P z7ztZ8;9mG}8h8?*7e1K=j0CC#j0EnTS{1?02v$W9AAlHvA*Y}bK9Ghz5pXZi;}kan zq60Sq00a60H^PQ!3LOD=fg7iA7ZCk_YB%(sew+9cF_PtsJ^p@WaZJolrqA5;`=`#y zY75H?7w*H&$ep^f$n=3vomY4-I*8x&>i30_esyFz%QgSk4!iY|5vKr`su8y6@>$qn zUzCldu+Bb!D~rkMb22u&o$&poP|q%TbaBPwU&p@B->Kxi`L)9~T~xq3+4ONSAXGhG zT1TVEip6e>(>Yu%kypgMkTKIA-hMOVH|E*yRV=wOzCm!v?1-nN%-FMz6SfJ86FHaP zBpFK#I_|n=S@-CYYKo$UTKT)@a*;YtGv;1;-cx&`-qTfGOOS~@=r(UsC1U8^y_1vM zHthQ`5;0h49j>o_#CH6{^;?@0mj3Mj_O%ad7tXJ4NBZ(mtlQWhdo*o5Mn86^2RSoXH@tP#udbc7mX;+g->j;3=yjtn`**oF>v4s z5Cz|F=9?*(IJI)7e6Mz8MG=RrV{Q@KBBOverz!@zc#L-}Tr87>b(wQJWm47BJ)`z1 zr6*lNp(rX3NXt$Ylliz$8 zh~C~|%tsBOggu85M#^71QF>|?a*5@AZ~2A|^5Qt^C|5$AnW*e76KfLS5G0$V+Ci+c z7}0C@rMC63Gz|IVMI6(e0kMPvnSEq>p|m8oR@##zBV)6eJh{5cp74qx;)t}#lEVUa z4kCds!cs1-$Y;3^*C}-p(A6kLW}g=--J6dm7&fUJJ`?DFXCW&`YiW4%gc&QnB$BHH z3=K0>KA->>VS-1SO36qbA{)$!R~qfc$c~KBR$p37rEqYnYK0QHh9U!IK|E7loI&8$ zvCKONE*b&`Hvp$k6;e&m2I`4wU5RIhov#MfB1Bd#+olYMYsczbiq$izWTKQz_Tg!a zL~Lx{Vq63x1Sepbc}2FZ{s)D6ww=48!TBUjX_tQ7(e4KJol${wK%Q2Tdo&}FMbW*a zEpbLX7}+g~r7&vcJthqkvCT{gIhqcU)=_7k%8BL_BPtI#wL~6c>8nB(wYkWC=2=5@ zrLa~ySJ70#Gd=z2X( zIhheX?Pwjt!`)Feo+**rxYAp#TOe5|>MHH?BiivC^fJtdNQ{5gL55aQqv?BYqNN3%q$_4)dHiTQ=V*c+1LwW#1dcn(kO&gZXJ>K~ti<^; zI|Hno@v@}}Gnir$L4;^8c&%!~?@(PdvsrD%6@G#|=D=q0o8b6BzPVvPqt!yRS}B^a zzLRz3oW!4wRd0ZEgT;u}Zx}TNQ2*(W`S(x$`z!Fj`zt`chu{#pb7@{JG|~QqQFNBL z0pvZvsAWF$Q`8-PVbp+VKV!+SW7T@CnbQHIjK=g_a;&xwUW#0C`tEVP$WQo1mxkx( zJER$}&uQ0(W7SG~@EkM1sFl-KH@1cawwA1~HzrK0FyWN@-P`JTPFT`YDMw(1QY*JQ zU_#V8FW*wq>Z{(3+y0&EUfN$3D?M$WGyUDOn>5uq@h*?@23ihI+t76MOWDAkV?VKC zTF-XR&XWpC3y$@KZf-B$pt*1QW9FNl-D7`_ON`$drxU*~*dY`^qJh`~`2`>xk`a84 z4j~271n@unKMe^5*1QlmU~vliEPNOYJpA^~x$Nq`b9dhMRcAxgf<|g}-%t3tJ8$7f zZ-2d?^s}!I{w@4+cJNm!VjR}3h)nYSooWv-3tHNV2Q%U9`YBoULlV_P=e3|1=GHteQ^P%u)YRphd2Nl0YsJRzPH)c)pz=S8Ocyvy;J>*($C$2_V3%NnA2BX{aEN%-Pd=g z?+$Fgq3;ScS4f5MXUI(u-_D(@zH{d-6mubuKvMhP{oCMw{r@_MOGYkqt9I;fjnisq zoYqOHT3ErSVX^foTIAI{dNe5^4!11xZ;ewUiNRqQoN zzco&G|6}7ca?IhM8mHM)jnfYD@_*4d4f&Ui(|Lc@IF@aB#)E9N`K zs10|>Szg{;akFB=`{ueO>%R=-QJ||tH+lI zKeY>wP5ca>uZu{g-$xsMPG8rmTz-Y^?)7B$V+kM4lB*BTeI}oeOr5UT^=Q;j?|tNu zp6b(&J=zx@N)#t4DtAwx6nc#hmM!dFJVTKDiR90{Vt(Q6oW>n*W^V6&yyLXm4M{Pd z?2?C7Y8DY~Mg?eU9^SyYma=v4Grgt7b;YctUtW{Z(sb3ylyML#VPWIXEjYm`$ zp4zobaG>07s5ZZFLFjt3g`^t}!d;JC%_eQC^I!E@TsTZCG_gD*>hvW$Mvn-0aA?xs z#0wmcy6E}g3#m`(&iub_oNhTv4c+>wKI*<%%ISKalF=PPe0&-5*Nsyxqnk=Sul60j zRH*T=a^ae>j{TnUg_s3XZzKIDjnmHZ4C{K|lF&yjZ$B<~34i?@;~?R@yhofh+lv2} zjngGTlkbm+X$Ch&hzK5=m(r;A!tC&xm>myTnE#@2`tgx#u*!HInILB^k%Zh=kdFm^}lz1*+kr&*F`ISGrp3RFH8 z{oXiLyj(Ej*HQYMLvd2bF#<2ZTxU@Se#C;z-NJXjx#&T8&d1_^YMi=NL?1jGaeJEQ zo7pbeeg{vzD;&nw^?)Hzi%I-@<8P2>lnB)ifFMiz9^B<1VpXVhk_UNlyeW`iLR)d8pt_k+zr>KU-IL~i< zBW5jSqoKVFL-geB&VM{gzvRNshqwAZU42;Hv+8`*(7Bm4v%}9(Mvc)#&iZLVpQ%ex z2e}MkESWwbBDdau%p(wnGYMQn(u6bm{kMa}#k%#7Pz=Ipcg z|D3(&>_6{v%|e`I;FT}A@_hGu-P2c}vOgHStaAD|n@1HwWDR5{c| zXf6rTGoc3yy_(mn&wC9$6aBo0~S+ zkQvuslhiQuT+wgw>T)+ypZN=w^u-}(i%Yb$dqam6e_FiemX(N1fV$wp;&norYS#P^ zbR(rI_|h&>nYK9VFf|WHSk&eu`b`;XFO5(voO9P~nKs?ydp!PfZGpzMBdUj*Z&BIn zisFBswn|^RUF2z2y#3nDu9hWYX+T|>)1ztYTT6Ev18U28uaWnCUb@$Yu!3a%+W^W&|N+g7l?cQw9K%V;%uP@IvKQGv-j0Xm{ zld#N8$ly-u`$GE+UF3=8PV1m?+q3Q^hMPRnlWM;GJVqq%g5C56rw#iu zH)Wq@@}IHih#$G-@G*>&*;J>k;qd|K|DNLMLvvqOs#-aB~H(FoZ3R=7dCr+8Cb*45~ z`i#WWKE!HloY{TF`_3iW#{*s)Upf8casL+W6GOwsH(slcKl+(A-}GtYT=+WIr`*3R z6svD~pS;fHx#};A>7JWD6mC5-z5SP^==x2c8faUcU!VHr^BKj{*nndv5l7;a7nNFj z`QEsOTZA+41+d(6`j-*71D z{84`40me?@TK%Wk7NRS?L&}|_t5af}l%tPo25u9;T8svNk&2*jWW#-*jsX>hW z0j$)3$&^zsttr_~6r7FIMLzEyPVcZ}3c<&VQ!7^V#Tg!-*v}5J0!^`XIk6&(v02zS zajl)AT5*yxu~MmVOgrOb@5l9b#3>5W;=54sDmL*x&heU&N3@#amHXm1*_{1JFd%_hOvC&Abx!L%ts_kM!KbiActqPAAzj>!03K8fp76Kw_K?d~TkEGF8g#yMyu zN!lbGmWgvtOjVDd?=SPz?If={w{B*nKWnel#dz>)K0!IS~blo00V zFrSpfl$0o+@R<84)(a^Vncz6BRCepsBtddYYUbly>!AT7{2)m0)_8Mtbd{U%gLyOLBU%k6-Kk^h@*U?TfyhS{bFgGkSe|`%^P= z8#0C#eXcKNr1NLqO!c{KlbPt1IZ8|QeUO^)$R=TIF*AlgYa-Hn(k9E(D{D&7Z&oJp z^+5d0VwM5_#rMpoKG|s-@@FwkV)Ko| zFHtY?WpgdL@YrUTdu9uy`3sLFts0CKTFTBfO0yWph|8WXT%<^)Q73qg$}OFgnaNo< zc=4%(x2mk0@{Fs-*m13rTildLS`ul#_w_~cvpte|pmpfWGH zk~VW3#o~)-SBW}RW$muQwW#7-sNky&(h59Dp5{0+9@|@^FL>ZA;8GZi8zvo~1 z2LH<)z@`5<`jmi)XJ-Io|_fOJ1 z9Qp$2?HvDfz5bWq)XE>O?7)BM4&d%UqzWNYe!Epcc}hZ|(X2;}t8)xP(HM)?{^~V) zkr-WHk^7vE-RC5>t0&;B@&=Pxq;f(`E)`r$6gx5I@4cBPG;$-Z``f(ofBYx!0E`Dw2#)yeBH}_5l#~$tV8%738OH9^?qFtS z74rp4Dw+K2g@Z=q521<3`emQhd|6FzToSan|0nOx%J;Ui1HZEaIJe*HZ_nwWM`Ehs z?H~~%F#}d4Bm{+_$fvxQFoR0;W}Z=%f{rxAZ7iYq)JwCJO&kRnp#=M@S-S4xb@xxn z4CGrFa-FfM{gy2LjWgH&m{)N@5fLR+;jgb=%Ndg2`65?7y|M%U$vg17@&0P@9^`wx zUsT~+yng_E5Js4Rn*6KhWtZdq@MbS;-KiN?pG%NSBL#~-G)X8L&V_h?xpnRI)qKlb z)4embvi-&2gGfA5C)ZaFZ}#?1*BvES!<#)u`}$X74Q_??ABDh>o_(t2@uREBhxe79 zVPH|T;Uyy%(4#`Dh8mT-OCmW=#Ms@gets2KzU_LWkMfHf$t}mvNeEW71wJ&|#(a5?_c`r~Eq(-7Oqi%{X` zJwo0pSTwGWlWZIh#;+Gx6~e>5R?Lj|u<>xHfXmd=aAKJBM1(|=^F*X{LD58%eErl! zv{JA1vlz9z&d<(iz9@QjUgy))vkN4w%p}Et@5p4Vv1IXNoVoh+WW1%3%=3gDyN*0h zv_4$?Jju>;`g!udBHq8fif%}EnJsU8Q8HW6`e|mivK?#o!lqLt#HyO*P{>g|AqCg$ zn(N0Kt!f!M3>3Cr58!#d`*u*Fb;FY|zw+AgxIM?~y0iRVHKEH(k2m-K_$>QlDiCse za6%f+QT;_Q5Kgy1C=bGb5W9nfAjIzAa)S&VWb1w`t$>6doH6>bx?;S8`fGbd{o(47 zIeL2qBnrP5Sd7g5LhrDk!XN+g%Q$=m;~jG&)xXS*z(*t1RB8u&Zmxs6{1GGpA@m2? zKnNScry&nmP3?fJA|w_e^jA%-hR`8|4Iv%~NkhmULN*X`h|6Kas<+r9!q5qJr?ZLl_W(giwJ2@kVIAfK($r1_;?k$P7ZC#oTzuNXH1|5Ie@_ z#^**L&j?XOddUTZBCAK>a~%*BgxDkGAEEXF0*26h0inqMKq=g0=(iqJ03^M7N)TPHP>__Kz2Nr$X0B;+4N>y+J`*pAA2aK%{VPb(#Ad%97%nNOn7hc zfB$ptCR_#g@ydK+`)VwjWEjt}0>kC*P{@tt<5`J!JIShwLv-Lg^{E zaQL>9f4_$Uod3I-%&fh`c9uCldZ`;Rcz3NlB>k+(j#6gdQ-K;+?_c-*bcxCaJrriP zH}pK2L${Q>toE_aI_`1NxsImG;5%nMu&V=S;~`~ehmM0Jdl`QJ_jItt}3^czFEFK%d3QhRZLV5^c) zX#QMwPpZPU%gd?2L()!7-%^3QKR;JqP6eKKqNUy%dZFIpbKEuHQpQVjC)J*&>)zKd zWyPO*x$*Pj4YH@%MTRX?dcsS@;7zqT{Ci&-s6r}m)1};=qk*P-mTo3u;~78s#d2B` zZ&H({^18kpDNL}{%X;CVw`~=q0#Dtx-}KSYah2GvHQjeBuAi1a@aT}OT=zXf&H9Sd zTaK!~A5+jJ>+{Q&hl;0kppUtA*$18@xcnr2r%SQE-plJ%Jw_K~xg;TZ5=N{)o5k9V zP;l?qvFEidkJ#UTC}`Mn0_~Zuplhsw#93k$L?&_1X)`SY5+`=v`#i4EGH)9+9uh2} z%ls6Jw1*Ps3ft3lN3%3KH7eGHmWDoM4_~-KV|a5XFx+HR=w;(zVvGpo?Vd?4DWBb2 zHf0}h@_Vky5#M)f;(hpL{|Q5q9(&LxkL;}pFX}87%M-JHF4*k+(s^2IC{WQOhx_Z) zD~Lz3U7m^7{yN(exM8%<;*)eT^iUKgj^4Wdss6^H*T*lkJiLXTZ+h_c4Rf*f<9S7| zwx7SgJu?FPY42m}bzW#xI$t|Q`#JE_ zaw^biITd(H9a4ce4lkzy4|+l>@W!F#RN&4xs!WRQpIN5Hi6TWP7Ni|TxZT6pc7?=k zK}?<~UAxfL*Y-jC4bRKnPZm7f16kkD9KIIRk{IPuE-x(R`@Pc0|9o;})BLrwv2VlA zewl07xwy*V>zg(E7l)jpm!>Pj1m^ZJts^n=6a5i{L5*^DT{}aU(-~C1-}q+#wuUpG z_yd`g8I+Z>=xj6YgO&Tx{6d1wN^WFgMNclM6xC0-<{%!tENvqo;z%&Y{81 z5m}>r5fQ;T(h(t3eCJXkE~K1|bq>Z%`9pKFxO3#&mr5{#qkI>l zhnWyn0`_eoU!inVKvAfiWv~)~vE11|&p3RCQjlT9nGS)l&Z3YE>!{YzbL>x}jd1>L z$)V2fXWJS=?(&CojK(k+W0joG%on2V=g55CC@$xK7ZGO~1sU}Y%yfs-uvDPI{W?1HhkrDAz(tO+);0!N$#n_@LiFQ)>xGR28AZ(U9W-VcOS zVC9bGRN&#MI3;G9ld@L4W>=h=PrUPic+IBxE!pupi}ARp@ubCgJ*@<7n*<}Dc;nOr z)use<=6H+61O>swZK-iPY!W4X60K$8Y?~5S-%s4v6l*V-B%qb#XcBwaCy6sP$>l!f z==~)8Vv?I6<)l{fSLX0by`S(}a5)wDf$!q`;$x5s?Do94VB_=o zNa9zYI7kIjAr*)}0;#|lNCl4huq-9A4aPz$Fa%P8cxOlj20$us$()0tD%6}^twvbS zoO66Lfq8SzF(+@IfP%a<6vSBX`&^?ZLbdjXxhzFAu%Dz`2tSG!qt<4i8A zV4l53?jkzRC`wgQHpiqnZ*x?xMOv=q(rJSY`9Im_tDEMz6z1yF6l3$DyGxYX9p`@ z52nAxSH4?H|Jk(iqin`}ROO;=#^=GxuTdGl;HywA84PAsjI$X`(N)aCnJibU*vv9H zqCF>ts-0yKKEG;#^lG7&YLN%kqM!dV6(}G~4;%2nJ6QQZBn{z4H~es)6lNeWiU9L4 zy~Knrk^y1Nk1iRI$AC)){4sEJ68teBkNIwnp&MerSqRQQaK?Zh2Bz1boB?MH7-c~8 z0#X^6u|T#7Y%y@q5KdvjaZI``2Fx*V#E>q1`RJ zAe8}^3am=B?D>}a3z9K z29$(!sSLP$z|jI~84%uplo(8Ybkz-b6Tx;vw-SO{25dKUZz4!#z$gRfI6*K2NanTE@F_%fJo-MMF#vg z;2@-1WWXN-o?%ePfR6_hGT^_VTVy~U0~$rTO9qB)Ad&%j3=G!j>Os0pkuH*f*%v5e z=!GW#dqbDspEUn^yJx`?q2KNSk<9X>dHDpiJsCmk)PI{ar)z=?J@VE;1X1?EuQIJI z8i7f($`>t4@y$Y*G-v)QlKJg+&p#0>de%o-W0qy!RP+35imL15p{7eOZ&3B4MYlB9 zPT$(Se*+`c_w;N*`R?4TE!xjr1J}8$Ub|-N`F5;5_`=Y&&kZh*`u8sJU2pXHQq&&i@DskLHF%IPpQ|Nuk~-<%-y?saUJKzub&rwo_%uT z$`yzrVWr2(7{32OkxWyLxgMY3HcKPPCM$CT*=Y$wbM?i^1a?E2wTaf^j?WWqJY|NH z?0h5FrW}Y`lt?|4mO7c_k~Sb=d8EFnz}$E+^-%ojvFSruzMcb47kAK@rxJqLOB}Pq zzKLXx8n$=9>>l_~hirCFv>$9GAlNGocCY_WQpuWX5GNwaJzO(_ar zdOitFoG#0^@Rh63INmH**@SL+R@qswxS_#xi^iINv?02rV2{mG{35!ebX}6EBChb!(G?6ZQr^$zkHf~dj(;VpKHhP zAD!#?o9aQQvUj~AUa#Ku5yRzGPL=Vvg$iQWP8y@+Pmu^B{#Ej)P%=5lKOV>H_os$R?tYO_PAE}gdN2* zB46eAwyhu4rLJH57Q@=je>+^p-;ro^tAEeVa~SD|%KFTVkt7*^1fyy|7Gt&C!?9sF zP+6XhmlL=84NfC0r;^jGUD!2m-j4~+c zGJA%fNDP542lZHNm9)6Zo-)(8LJ&rUer;AG1i#vNf{6=tg}{}^CN+oR--fjF?8`@u z5rfy&+iwhNB(pRdcQHD25P03jW1RBZ5q~0X6(*KDBBGswN8{VcR=4<=w)I> zl`7z&mJe9AD?_Dg%c(<^J%=PjY5ROAuR- z6;m)#9Jjt5!8A`11`9mv%Fi6L?zG2n*=4g~v%A+ktO_%)I$q<_g0Mv)q2qXddD*Ez zk#1t7J$oK1h14OB9eXf^^{l$bb`|XzixJg))`S`9QlM3Z8?+gB^%orMt%_qF7D?F`p1Vyc#B5mehi2QBFV@()c9{C2N*{OI3PJ-IC$X%U;>N- zD1|tPayCLKotPW zcNriU3jqXy-rz15H~{JDKcF|jN}xADHy}3PLNHW={SWSM0U81x0k;7R0crps0#?$i zBY+Ws;Q$SRgy_8yKyQF?VE+Sdqmv>aBRBwof#@|AKyQF}X82J`~} zN3W5fcSr!Yfd&w`jSg)9k-%zTkcOL!z`MX|K*PXlaX94K#p2Y@h@L zP@_wv!3PKcM8`E?O~5t4P2fwq0}zM}e1PAr(V)Br(c)j*|LCj+lm^m2P@T}de?Xky zi4C+N-_?J>mjG};mT*(^yE2+?{{vk6u_b~ojs|X{+y4OCfZpiP2E+z%4A2JRXfOf( z?{V8-|IL4w6rl_IlRX-SHX423;@aT90H_^{R<^6gfd7UQZ+l8<+D|M3Cg^pd6-{p-a zbAxBJH*-8}`xH&If0*R{IGF+3-_8uky{hWwbA46aFIoDkW=Q?d zNp7EkDatZN*K&0r5Ah8SQym!IIK@Y4C;8;bRjl*P@}ZjL~UM<@sDnr3W6 z)(2ozIWc|Euhc&KhHQY58bX^hnE1OJu}eBCpIXb%Ruzcg9mzom`=}fRtD3BI1c(2^ z*&%KrkkF&Det`>ZAX3B?p{DUgSP9|EBa#@|SU&`UYK~Zo7_d01-85BwtwuvES%@F= zSe?h)IV0>3Q22SRm3qV!)eM+9*}rr|@f;YAsUJIfE1Q+!L|^7+VP)%^9aF~LWHn~W zL-$Tht{1rvyB}vht;#Y^WMY%!F+fShW+;I~@VU~@d=eBQw*8_d<k$nWS z5lN5Bh=jz>b@49TBby*W=n?JyM{)Hqbky)-gOeTOBA}3&g zJ*PwxqEIx1Hyw+Lo$2B>a0}Zn5W;ZExdZW4W{PqnVfPZq_#6@xy|O*dVFh+`mA zx1imKUJL^yt!$s`N1N!a>X&%YqC5z98*QSUONY$7MWmZW6y9oxPQ>8s-=bQ@8CXTC z!nW%^J|`GR8L7o2x+Cf1P6gFN=EEVDp8x~#JDNWj{4XG7!CoC+@=Y# z#Ee@Aj@&^E?hnJ&TE;|@+tEsGyo@E;#$o~?C<#jj_9$XY#22-q`k)SG7fQ6I0ERFU zp~oULY+i^?%&kWU3mPDdRswnWP?A1D?5^pyZ{4kegJK z#0gpUpoc~eSkX*&FQ{UfNt)0R*abiYQzl>~pdpxX0Y(8O z!3z;k61{B$@Cv{OmZT^C50BQiTfb8gcV*msgl+n57JJfuiK>>5ojmz}u z98AyX6CRKp!x#-<2Uv_wIsiC8HvnS5H88THGY*}_V4ena11e}BLBK%zR1LTcs0Ugy zV8#d&DqtTNtifywzz2p@^w|`UCh!`Jr|7UoryjcJ7^sKdm_aZ409XTf1onXm8@-Je zzzx6$kPX0%-jD^uE5IN6oDB#FMp$4$21fplLcnnVn1Gh_;T24=0EGbGz=90yMz7AG z(-6$u{u)^RU7z{;pyc*fpkx&shWY`NxNalJZ=iHL??%>dpp>?0zvLPE$cwGh!$yztkE%R?-t5S*k(SQTt< zBXcMN@>~~g&*fNz+1%S~nlVU_ai?#}MskJZHp=<>idwsJ26mVAB!;hlJjAvb3W`FvAFj!G=Ia zv3HBK525e)pSrF+&)R+ig}Ii`BxtXsFDxhUVKc*(FYQ>GDBCJ-My%se2Q1f`{h1%{ zS|iT_@7bRfi^K(561CXGAI9j3ZXmmnCwbgZACi5QD4kN;8J3oe!4FY-I9?^SkbVy; z8O{Axd>iVntv(WlQB-=)Lfwzfh&S=D{?y(;d(!}_%xRpYpFiXMjbX1Gi@g7Yg% zH^4d7;XD=2@YmX4S!#3@BlY;%#zR#J_LS}YL`IsCv%aBqQMu%Yc8ov~3UkptQlOv8 zh!xab#|owofjkVJLS|1Qgeyd5Gf9xq@~kx|VL~=iQH3&8S3!!z5Kt(Gaq9R1^PF*8P2wJ{FT#TZRQnx{5 zSwlFEk2~_hY7nXtgRZsPAUdVfOpl15JlzOu6UfM}stAQcGG=0|dFbx(wRjx( zo9E&XVWmf;9d71mGK70EJ$ipC0cMC|41X7Dr?=*3vRLxo{<*<37hNwQ)pg2)U;H-(YoXh%n&d?)(> zV?EJH=~%U@TbXCa$gA~~8JItG5G%=8=1FpNBrcn=fgGs*mFI_ZyLPAsqzEziZ2$w$ z>Tnl;m(BW2RC5V4a+P zu0inObIo_4#BNKfma|VJiwHma#r#JBY^enM?X<%ax~%f7eg$%H#ffcL10D!(6 z3Nfyp(2e9)aLJ2Me%5<|S=$$5a+2B~yH+>LAa&cai%08n%;GzVEpY<;ovn+OIi!m^ z8on5z9nY`l5F*7-`*)jc8VG-%-L_zOQG=a&}h*zAb>!&+?UZ4dz;wAq(lX zZO!o~C)Z!CFS}EJ^69>|Jq_c#FQ0jhwZM71jkTU(5#}orI7a%DVjv221@S_pSFYNB z@6XK2qyM{i05|l*RZA}q2ttd3VgL+UVQBGv%NUH`A4{quk|m%IVVG zp?j}HZJhRab+_tpPtKNKU+?+Yi1%EP=F{bmd(!8p_gy}7j>ae=FlFBvdP3AFL-U10 z@44NZ!bF-TpAKrzqZ^}bl=ofFJcP!s8as6)D{rfILD`tf?A_JdyWadN;`x@1`|*4r z3<_ad_ZNo)|MOY{Rw@Jj-51jz@$muZ|9Gtd)PJlsfbq^MQ%KwFX%Io%4bJ5v>7%|2eGzhyUVy;7V)2N^8JB)*9gVH(LYz{@K<5L`Eqa z@Awb520W5IdXL2d_s_KkxIt?GB~&>N#b&+I8t`jtK*~yM!2j9Sfc^i?)_{ipnAQN? zKiL}KKyM9jTWJmWzug+Zmm@CZB4L|T7nZ~0lOtPlM1CwM=~Ir9?HScHii&M+b674m zHHD)%7n^3-@gld5DGyo$7ESUDUGmU?8Yn#D zlJf*pL<>yI2{k>d;ahYfsVHj3F)|W$Zmhs21Vs@lK50ryuq{p+bh(gLoIY3_pH`f< zRJ=y0B*(NQz@?-xsw60?IA^A~%%!O1=aN#PQpJ*z1ea3k-C{~wY4hNbOkcv~rP79| zVrJ#CZrdX%k!1ryN74t%uFW{#*ibSeTmA%7ekaN~E3*9l*qKLzelbhsio6vQgWD!; zE8@Z`YP~9Ee2+nEz^kQ-ah}Te8;*bUh4X>FAJQt{^j79IKx=?Iy){64dlfca6_;M6 zajA+mJ(j~Ylhf6QUAvm#T%EAHTEOhI@MrJ;c5470-kHiXft#4=S2r>Ie&zn=AMx$_ z%GdP2zXQ1Sbge2;7lp>6NsVqq{U9`_shYRtQ&I$@st^zE9hHm-a0j*a$By@3kYpf= z9Er96;qJi#ih}SVyZ&_d;D7&XUU`I-9r)wz04{}o_kh@epjc&hM7TZe3_)WwJyHmy zu1NeETMUu&pzb+Q{V1N%>SxB0INd0Nl$(>raqF1s{RQ16x1=b;!P^14;_>^z+aHf> z)P3`;I+Pdv>|l|!x1-l_`t(|x3b7kWJw=`hJ@w8{;?6MNecc`HDI*%At#ZQl@?oE) zLoA~|UaWK_|B6lgkN4BF@)i9{cVO8jjzLJ4kkCUj@v#z+107J7V`{fxDF!cu0xCM* zoCm(!#DNz-qgoL>!u@L|ZY2%(Fa5__d9Xju4&ZbUMjS$_0$zkyIaUf>FJWx_dLFpg z?CvP6oP~eUh&cH?xAx)Mso30sAkLo(M5YPPO_LS2Zeu0<5Hd}Hkm)f*;7{1N5*GX8 z{3EY?CI7k|z*QiOh=6g`Z#7WMQ85f74x(bqz7~{mM#^%?ltber#-wI)bL<)jolFy! zLnpfI0+eA;sA#TZ$64MweEp&z!<>%ucJbj{o=|p$DX!w}5vIxP4~yQtxK+xSYr5W+ zw{&-iZSwiarMjcm#hm3yhQ55SchtF_tv_w1{^nK{%k0?35+3q!tJ{3dm)U#e_Lpqf zR-ZTXemBv3eqQhVQ7@H4m;S7ph8`_ClcG}*jr!9Ej ze87hl?R4DyjOU{RNja5I*57vBo|V=xQbERRmn8`Zmhj~KL`o{NZs{!H_l(EeOxLfz zf8VnHOo8m0q!sOS^TloMPd0glM9jbW{I;EG-IuxUUljHX3f8P>r&qMoE86K5?evOv zdPO_EqMcsRPXGTxJ8kPL9F??cFpvY`7h1~Rp-u=l&Uv?)5EPa(=fp+r&v~Z7ZH>*H zkXq-eoTE1A_?|1rBRThGL$1zP^rk33l2G2(z+C+(2lWy@j-Z{UNr85HW`CG((U-)cDA~O+V?~bG;zXI^#`&TIQ|lz(;{A!m zX=6Jx#)?-lmt@J5l+73CnOYV2mgE$azNAYUX2=uilM=Zce0g-)whh6crK+K{yJ8< zxKw$-s2nF&RqaqY7F8u=Qgyty$}y*k#kGogwrbY45>5GC?X+x5jeHAJ^&RGFHNhVS znmBYaBLC|tx|KM|AL;G+%GdHQ-2vSB<$)%SMC=I0am(5@Dv^*d!Wu;$lGV6=q=4!M z`ELWw<-XA$1k`Y9Ug_7W!*2rWU+;sz@$ilv?+rGHMjOw>7LVjITrh3Jt)DO|vdG;e zQF8jo&amyAyS8jtFK1A5F!7|q?8j&KYWF@EJjb$Y+OGV_ld;4mW#XR>y5i7jNDQ*} z*Ma4~bW>IyY-I=jI6HuwfzTHLy0qz+X#es(2e|vKCO{-3LENe?%LiQzf>2n855~)m zcxHXR9g)joi@$Y={ufb|zjnlLD(~NB-xGZF0owa&tb$#WyUf_$mU{|&uaLhECZ>2j zf6^p7Eh`%H;q{YF^1NQwRLb+o!C(%lz5cu39_nS+n*I1tL+MsyKF5QdY|UaWce6Mz zB$Wu(AML`eS1o(A>%;5oran)2*}sUncU`c$v8hz}>;i9gafdBAl0RIWnsreu%5dGohdmH=S=@8zlvY7?WFT zO%ml?|2s*wzrOrSz-#kbHg2fVgTtFEK3uKN^>jJ(`P;0X)7pFe$D zppOLqxt^XL_&q^k306&5n>TN!8$!W5X<=ajc1ZASf(IKMnxGQ}k*JN04T!!$01n1% zuvLN!5}H?FffEx1pkU#K<@nn=bm$PMJi+e`dI4xj0n;T&&cQ(m!c8z{f+7?2m(ZaC zf=iHWgUS;$o#6BY18G7+0<^7wKNM`6ps)lRCdf3wuMSFc(13!{6g-%)K=}^hPLPCG zRaMp0)PU9#w4q?S1m`BWO+keT(#)=|F3@*ErwjN@L4|qk+XBls$Wp-%52j0SiGu7B zY?z~?qfiM0zEN0UFNFpg@QOZp@&p{?AQOO&VW<`cAto$viNgZRD(FpNfx;b(pWr-& z1^vq4(}V>sPLQjD>k}4;Q^B4IN>*^Nf|C?PqM$tmX*?|OF#O)4(Z14XUud)i8toa4 z)=Hz1X|ydgnkJ1#q|rEOG(3%lq0!JZ8tU7B;R7_>hh)U5#h2Q5=%cv>?WXWi?cr$A zEkVZB4u*!?nbhF&!yhvzEu{|tP$Z!7k@y;9p z+^#0C9vv;+s|}S;u8GPTccjKx$eet6AOd@}pt zL$!D|`DS!+XfRnCzbMABXq2R+ za^;5ZsM&SGr9b3p*!kVJ&^u{GKBigMZ8#mL1jIjG9~Ikh$Ovb!pC;oNxOwK5%_TjA zpygr5bx(Hd#&^SKKQ^Hl40I7(vK`Nz!@|d}>~ww_D!|V7&`reTlZD)N^LG)N?IQ0( zl-{;Z1d$|)-dm{HQYV8&`iX0X_8wri)E8=#KRA3YO2oZWvgyP7M2)t|&PY7Eo!TRR zL*Rp%W~>CK-ht=1gTpFqMX?P0wUZ~!?W|sGiy-L>pwBB~??{JpI16!|S3anR<6P5S z^z(JKYRA~87s*&zXJcWm&7I5pOk$6D76>eGsfJ@4v!bmyDo*b;wcmy?Zn&#vLD(~Zju)44sSUAZyA z#Li11&Dbu6JUEc+-hEig;8@7d*QJ7&t6zBeWc8%F610b8oqQTixlH6$*i|B}m$oQB z=j!5#5nm(^s$GtG8dR*6(_Gjz@bIH-T5-9NtKDcybc|-przO`abWi(nmfmKgk(#&i z2al@_8!5A>SE+Rb)m=JJs?acA|LXnKc4jX;&ZhQ2_`0_`cZ*IA89Edzo~#||6|VJ= z-9|8+4GKXJ76~_Lz0Hq$cj2z$t;*l#iPsI=MvTi6t!96|LxH#V-8l_%UyIr?FJ zk8ot0yWL6aJoN|1yS8w0MM&K2eNStGb)&6IANwz4X*M$Cn+3zI@by*mZkDZw%&Vk~MIVtjWrdzikqvmUUV zz?_@w(IC9j-Rd07M|1Nw7IL&=+ukoG&^v|UAaq2ZRGSD+S};=hFdVX7;vnB)T$h;R zfpgm&0~ux0g}?S1_p&rS6?A@O$VcF0kwh_T`+O5dK}slWY@O*mJyTz?y7`yof*TG5Pr`^b4)vPP)2v96k4?D@yt zXp*LYfzIH~3l#~uB1eMdg`~++wVlKx&e9_6IU~yTxATJ{Q4*f+G4ncW`TCF^9?^-B zG!G9(S0zI`_IJ0ER1))fb-U$j-220a#@Wio?erM}Q?r(8i<@;bCNNx4UjD&=G}Gp` zV-dxjJmubBWeknqu~+Oe;C47P#Va&|8%o`Inn+++HBMa>xMOF9aJIfDX3iRgODqbv zM{nj3!{^(Qbe;#|&O9arOHrgYB|M+v$`ZfhW%)7J=L}8W?9v?1WuIr99+t!U$Y*w~ z$#C`^w?>3#xWh%|3)no2_3_T1dD2dHW1RYru@sO*m8H3xmrOeKeOWG-peWEtv!>3m=y z5X3)*3+3L1glOw92x7Iu)M`D-O`+=AHEIqb9ZEP=H{~$FMk>CN5=PVYFpgXsK_ZG(8Dy$3JZ@!n^t`|v zw7SMUMtvg#M`r8W<3?^lyhVD*5H2`JfOk(DR-n>yp+}>(j)}`{hkc12PpRE=wLWG8 z(%Yio^?Q}s5A4XUs5m{HD<=nM923P`+4`hx=c2q=8SocUTynk;_)T#bE_bbXB+vGo z@)u>r2{I$c22Os>583x3g}PK92jU6TiB%(Wo%-S^nT@StiWiM{@Q~k~w;n>o9gkht z$LDKY-gubHeNjILW8|beYsB?@CJcFey5f@BSV?J8DWkc4h{VG{;i1Ov{AVg`L4sws z-U^5o&5mOoyq|F!wP)`=AnXQX^UA%UxDzyv5eC}_LiZe1_*H$s&f2qtjP{BSTzV`P zNsKAIe8)!^1OD&fr=xg4<0v1 z>Ipw2v7mM^a2_M*pA}M|=oU@9LTk3jlCo{?Z&2@W@itVk3=A#IJm=E+*~4yTZrhG4 z>UC(21%10!?;l0onQXZJQCrEq{x$0Js?M;*>L(ps(zt6(S{gm~UwFShx+ia{OjDTO zxavbG3;EI3x9PWK-0R;tY}9w;M+CXVOvi3LCXh&ShPLDg6A1^b;<4F1p-$VPCif!T zl@U+g4q7RhJ8-!S&pwD=hjjk(ajwq7-!6()7u&aa-%Dlwfgu}oY({*ocqWIh`@}?K zY+lRbqU2S#^DDyd?U%-cPjySw3QtTkWZWS;pva%1f#Gk^Vni6ii5lNrs$37>+0iX*Ty zO{z5$*(r0nj31)62?*@4_TP!KN$j!8ks!F$21n!>J3DfoB^$|eGCT7aBz#~+XX7j> zERR!c$MbN{E!iU5{fCPD2=7e&4luSNn@`LIR$$C_6E56YVC|v?M3ap^N+DTutewM* z;wXkBMDR(q5pH~VcL|m+QUs?2BP(gbULtGsZI)9W zG5wn1)w_4Dxw}K;jz#Bf+Sa=g=6tc}W(kvzd0S>B2y#kjRVt;p4qedB)=$F9QO}b? zck;$EEKbIEdZ78pTi-uTAf+;_w~v&_Hk*_{ZiOTYS6g(3Sj_NPjMgT`OISRvHJ?a` z=IAi*{9v{uVSfDsK?2#@rIsw6n#?PPwj^L}-5h-dQ-ZWop!+t=CnX{^1-frz?x&nz zOrZ#-s*9aDzIz*Ked;S|f;km$deg#75|8chdfv?}p2)JpijzdbHxcn}@3$pS??@FS z#}y~92s*8imYT|^nf~e1S;@M%M_RjY-$RF5y1KthM=PVfsrb=$=0gZ3g2d7_uDX?E zUATs@OG&a-oFGYIQsm;lmzueuBeP*TbN&#Ov&cpM5aW`2no5V&?m3>#$c}?z_}1xk z`8g{Y!mfTd##M>_@*gqRnKN$|GqoVBMM{DUwyFI6=bve1;aqlA-;YzM+b{lczx0Sz zV!J%+pw)IuR-r+wRZHxvXBf=w(cCYsB-$})WC;%nIm#Z>XrHN1bXZrCAfK9fTO&7| z7abWS&1aRqercOHS(>AUDPkgQ6>pxt3(9aQ`yACP`>vHZ71Ky$zvPxrxr3Fe!ZgjX z*HbXG6EDstnH2C^73@p1vax4*p~8C5w18QlINVb4E`fhYiS;rOEBd_PibC6Wm95H?M3`I0S;MO^Y_jWpl~~^rSbdb_I$d(F zrIfxbDOEE)W4$x*GxZcx6s}1va znNnG!t5~8+;|D7Q8MBP1&)Sw0@v-n`QW=*9D@6>^N7dLakQvuoGF6aSv&QXW@!Ro! zv`iC0`>CZWoLqH~WU**+y6`(^Nqfcv!%TzrnJxru1rt*(l`U%=eycBIkFws*$@$Dm zm%udniN%fJtR9^oW_pR)Hr->i?qhR4-#gaKIfCvu{+R$yDc|JT==lPY#i~$~;RV*S z_NB_gmy#o^ZOyDA($c+Mt2NCyzkDF53W_QnvLG>Y_IEpr^d#AuGz836AdMA1+D!?2 znv(pQQqr5!TADH*G-Z8mq6#-s{`Ubf+PAR#?fk`D_cfl2A)&X+?Ro zn7?ZaV@Zo9XL=cn<(1D(wO2V6(=PExC%m<7Rq@@1;OeJso4fa0z-fyX?_o=fHsva_H+b!JmxTRtIb55PmU$-Rduzso8#;>9wt>J;+WtmrXucJFOu6DG#c8uNc;Qi7e7T7*!)5#{+#qqEc z5ov8{xk8A!BB;})Y~JCh(H7Xyt;Jex)Ow!xb0b>@nPA>Y@^3L7s#6r{h-=CH;@7EO z*12P--PEp!QK!RN=WN$@Jra{jyL+{F zX{J}~VYj<^pNDnt2KnB~)V{+y#dlizHht+keW^3Se;_4eAgy&EB?xiMB@M11!6X5It5Ib@txEK>zl zA)mzQ)}DTGoc9uGs3Q`8(;h$h4);WfC3@7V<$iiOVkA*^x#f$m8xcQ45DE$8Y-`8O zD|2sh!})Xb544&?*Wgu4<~?LgR254r^|}qo`p~eI)39vLu+@vmtkpHyJLP+x9zAPA z#1D+)KOOR~R$`AM#BCd@Nh0F=zOcWGF}{4us*`EA{2ktVUu?~)L|ZAe>_=a^NB4BF zlv|0pG4~VL$h$b5sqi|7-#Tp3vj_YCXuGelCi}Kc^mlq8KoVN$2~9xIfQS@J=tb0^ zB1OP}fHXB&v4`FZC!uBYk-c)r z6n+YSjw@?zPtzGCwzFkZNB1u)8?h_1avjC`vC+-}n6nO)LtOC!CA1%Naf)O|3%6;s z{l56nCe|dOPAHpCg~1419-GoI%Oh@3Zw)y+qJ7ho^#oTcq0|Wpru;s({@wLw+x+)G zPT7r363KK(jwspTi@9>OoLbA6C-Nvv23MwEL|nsN+Q6n1PhyFNg1()2Q>Ul%%LZR( zJyq+)W{Bk42jkIWXnzU$)+E`Vt6(C;`3;wxXLEjt2~Cr-`F!G&Ntte4ww48l)e|95 zu|@OBA|~s6N~$O)JPRf%*Vze5X1TYRSr(oy`Cloo=e@}MN znB`ifU)#B@b-^UDoUbu!X-Y0f#H=7}{-jL%AVDHr@5O(emx0R_P$WE}f>Fy}A^G7T zsb7~KEF|5LkR!>2Dz@CKx(RxTPbpKWoJ4ct6D~3-C6WPFCou+f6U`)C)Oq{SToMMPa@LAjv8IgyD{l|MO3wjEBBavUDxh?>gb(V z(fiv^-xG~V*V%G$QjC%q*CLdy6<|*keW)M!@Ko;OA~oDmkzA7?C-6A_tcY@&H}o;^ z{bCW`p8Dx?wrHi0cv&Ko#XEQBC+Q`hoTaDmaF&YQH2E~`h(sWpGx`b5$DQC)Bmx3q zK7AW+mi&N8-o`_RNJyXm2$fez*6A(Q_#X?{a<^ih0*( zxnw&YDQh9(fDYP4)mbMR_Eb;sX6QwRa$>eZVRChhn2_&`PGK7hKg&Ls{z<$_ z#2q7^O{1gl@Voh^KMDEsCP}wM6lBccs&oySqUBh~9kWlC)m)y)@EmtcS27LkDfE2q zoUOUcc0op7R` zA+pCc6qd|;ni$!cyV4dNa=TpzIkmbX0N&|V-|&7UGt*xuzBpu%$);AQmHryYPO4qp zyLqf7rD3*{e%BE^@|r~|E_oqwkY9l{bELWG zP5ouP!_LepVMk775B6uAnV3O~kLgQ@EFGX0c!(>mxOD7uQB;wy%h6Wbs>pLz&nR7x z;jCtaIkTvdv;(_T%}y_sh02U^)7WnD`TBw^%1yMj|JvyKnre#qnPb8H&BsGM-pmGH z|DC6&a6`AK=Su^#8nK}5PWE+NRg-8~S+ZF#<_^I+*DhH>N!YNnL+39GqMOE*_Tfct z9jL_`{HKggF4co7D&0O|^`?5AwkJWuL3GAqh2F6n3imyB-u>3!5y>!2a~Sq~MRO<< zI3d0#cr0V)+M?>sn=w^B_v#?TW!;x zu8o&>uM;eK=C(+uOHRBy(cZs4IoIaX4&%UtMHhli4dvRFY)bu}lmbVCc*dDp#qqbn$8;}9)9zB;Us2q(-Fq7C%5B7X_o?Qx*~j+o>5qS=I2#$M z^JGWteJ_<%hwx^F*s!*UQzw&cB2S;HZi}ov-)9qbw)s_C)cL>gw$b%h3@$}C+;X~m1bl7i{fTJ}CWNGU02dTnDq^pdy zG37$Zt~mO$SSJ=^yi4WRJmUouUB*vo*^VYG9RmqE%tANAg2*%Pdp}-Yh4{^yV$AJZx^op<{1%9O;k-^u3MNe$t{@rnNKdArINS4w?FC=_Vt2{dh}pTly-|VR+Gf2wzJFV&+#hc; zqgGh*qEl%s*2QSj+DBsek=no~{ia?U5&KAq`PAMZ1zX>1czxqgXU ze^}#DJ2F(g!SJN4X_V(XzZ25$jg5=bw}xhHtgtYkq>T322F5USKj#}7Un+{a8165g z!AEq*>F%tu4S2iZe%t-tZF`z71$^vFse5uZ6-PlCCmvL3r?2GDj^naGR?&|U}E@ZpmKdgvi`-HQO(WPYOl(jc<;$nurk zr1Tx085ezGS$uAir#DD#o*-a+qlq*)VeR>n^uCE&IQZ`WNW2ch5b5`zL zWH2uzJk)t-@!j??%jP1>C7#$(6Ols#-`u3g;Bc3Rb!@o3!+9MBJK>HGr2^QkhO<5#vZ1;F=Vs^(z?mK{{xItZ z6$Ln3!%`+(=i%}W;N%T$2RO>Z=s9!};CSun=?TM`P)mRj z0XU#Ty#Y@7(1n1TJ9Gx%P!1=4s4GC>0S@SJvWGQL=p?`nI1ENY9RjZ5&?tb-PPnSW z@F(;cpi2N-n{cCtM#163hvB{tg#nl&g+)(T423QPoZz7X0mTDY3_Wz{5bTn}_$ag> z;D!z-dzcP|x&_?vp~C?63AnSv;5hUFpbG(`=TJF-5&{frLd)Xz?b|Ru3OnXdMSxxb z^Z{V46M6;ELx8n(nB;^#PPpbns{uAdp_2e-eHhw=1_hk{VL=lv`>>Y@YoJg7fSN&4 zQWBIOpgaIw3+Qh^lL5*J&|!dEe}8{Jta!r0J4|>&`(kcg9eNQ^J%G{$6a!$k6S^7j zxjeK8U_Tui3oywEU5mLHPT1g_TNsUsih}CJ+y*LCEMPqpiV#pyfL4R4si{~jhH3=V z9$?WEN+5G1oiM5nr4bkt9UB{iJy9r%K-UAB5^LA4g_Tg41%*ve=taP8JM=D~^8hsx z=!VQKn?nZ!HcFvQQCeCGgQLfe9fKOio;`b@JCT~23Plm9WI%ZX$`b#SXa1*sELJDo z7hCD}Lh`St3+8HsSB}m#eM4Lg?ob+0PPtCaYaPk2Gj1G;d`@Z+klVyrBK;Y!v@| zF!!Cy)|~m+VY^J6K;^WMQxvLmaJLkLHbLyXX?jb%eQay`iaDhex~z_yh=6QPj!WGb z@-fHoS(>5T#iw@6J^G};y+0)m4gs<`k7YLR(?`h>cQo-5sKcWKJdHdm@b;Oui(?h* z4L;Rb$BYZiu)gS1p4L@W^DI)&3$a7 zT%(XyvJ5}@ymYtw$X)daLw2I(tV-QpFx$#b82hg5>=P#ixoe*n;$=>&R9Ns#_Fi$m zeeX~}FSn;*PQTeIlT$$n2q;;bY34*ci~`1nFoLK%=f4r-lVU$GZuR7SZvnfLkyx&cT4OOF>28< zuIiK|ld5R6@tO12%`4hJ54Zhv4=tBnmlnq$S~Vmh&W{C%721h)otVOGa9kwOfc4I+ zs@Onc;32-V1sb8_W|h`#Torb0J>f**vryW_iK-$sN5leiNCYjhmur>Hu$(|DDpEtb zeF4U6pgVPbdZA(3TA6KaUWt$9@hghc4|7rRlsr3C9MSQIH${Z%=eiRAU#q?LUup3?@>6lPfRIgFkXN=#T<1x+S~ z*kBOYlg#WBkqC&e)Z?$i+Y|LiNiVrH+;^vaV)}aj_nN2{U~gBoMjpn z;kJpsC^y$bmmEV{$;&s&=$@%!U%#>{#Gv7T+Dx_86}N#M#a~J%JWko%zdEp|4F<|X z0%aca1ks`@;@;V@0ghix#wCQgK%L>aWIaz{hP@S6mU+rvrCgTY1Fwp)67*e#X<6-d z7%r8ABhzu$1Y)^lqN6ExM}qsoF5IuyL@hKciN31Z+?Pk9zib&SE>FPCOHELw&=Z{) z0__7n-A<9rBu?p;3N#I?Yr)32CYH-IGJ1?XsL9IVr!WC;I*C|m{JFs(M!(x?4^?Zo z@OzDAraY9kg+NY+p@-|6#w_<6ti9qPCh19QoYh@OsP$r*fFjJfaDhFsCa=oh*MZzI zNn9^&#I{BIYTt7AMM9WpnGvk|^aiT^`c6#bwA04-BPZlydFRnTIh+2DObHI*NXX3D z_Z)jpvQ;LJin`f}U5mnT!gXnTsZyT`w^acfEKda6;R(A&(-QnebeF<7`T`#9PPsC2 z=3A6XvIu1--Ea}%*~@(7W0e>oGGZP_{WcSkjb&kabxqZdzFS>SESGI_?Xug!B`%l= zlF6<47?G3ys6xQwlr_+Zw`XM56<@XKA}t>n5A zc}vkm`-$X(q~HMbmLKQeP4?pG9*HbuTxLL;z%w6Ajx~C&i00TUE@!TCOK#|Xe*=-% zl4ck%rOXjQ5)Pe18Bi|h#k{KBgR%9Qml=fbip6MNBO{|^l?xVS2D7=h(o=%g+i89( z6xi*tLurbFy%`ZxoNLmgTAPZqj%QIFWk%J`ICD%Xoppw%erW4!vzC~-|o zm&(9ovhBoC3`v1eh&l-iX( z{ndj6Yeu4vuTPiR#QxY;g)#h|>7^5kwD9Y~gQ@0HZ@X{=uh~=asN{9q{m$hFvbG@j zTaz3cpEXoszpm_U_LVD)+eDSgcwClLy1-yoj8SSAO)tFPwJdguyaE2Q@R&^0S#CyI zY7v4q89|f71!QzMQ*kt;)Q$3dc92m10PD!$?0*?P^$uY~UH04>>hYq{HTXe-yJV$*kUTz4hOHAn;Y?{@qlZP> zLJ_8H(%ME5OGAiPa|kE_?gI~dk|Xm=499Q$Y9v8Zne;G7CV+L|z9KTlL1}(Y7(?q( zbyyxFK|wU~lEMU88hQyA<;JHhH$*t$W*fux0$Rd$ZIN{o#LL=YD@3G4T$J`8b_Efk zut^))7!nhe7%S5p8aul^)?Y;$?Ls9e1x1~k)c+>bC>7xB3~}?MD6%B&h%hxO3|%h5 zSRxF$peW9u(MdXrg5a?dxNo2&MEnWYO|d-ECN6FZkD#%KYDZltDt_yAHCM+vSI;-sU|+6bQLb@ouE~Sk1wV7y zs^P3y6x4~{MWd5oi)XP>rh!F2rJ!~PDwt1l+6tr4%ioS*k1 z#LHaZZxG>JYZCoQ%d|PEbS7yY59Kd#3k)J; zQe`4WNkN{N>rC=S9#^F(e_aB;qz2(iQI9wQHhGw{VhnjyFSERGw=m6!<1A3Mazru| zL=-rT?`9UDIQZKLvQ2`4f_)O7!V!^(?66xtMaH_yn@FzvM&**(qz)-IaEPcjii+Vb z2zy!V_nA?Dn)=QV*}>6JkrJ14$P!7SHMVrUF8;BVY&IT>rvL9l`%2%*fz*=Kk5p1>Tspb&ab3jf9W$L5WmLS=5iWi}fNa?cFP#Y!Ec9(m%b@f-g%JYIyuAxVQ&Ln$j3T zxf}eda6D6mL7n0mpISVH$>L&9jiOgRtdz;Ardwyf#+T3TCRYa9oO0e@v(ZmsF&{4@ zB@A-WH<-wlYt$AIsh*9GCPkY}>c;oy(?|VGi);M-&g_b$29XtFwvac`32%LA+N1ac zx5BGKrzyE<2|o!RaX|~zs;hrhrTEpP{-Vb;lkzTjDaWAp2#OSVa`jTL731lJB)m#~ z(B(5V(#V?Xx3wdF^!xOMYD~mMLReHDzagU5&nNS}Y6UCj4BPDV@yK(*SCda)IQPCy zu^Dy#@EIr6D7H$36iSK2psXL)6a%L)s|Do4Tgbl6)Q!iYB85jQ5ae?W5ubDPw~qvW zUCDhC_uLs7>7%X};_@AkFH(ADc>*?0c;xhKJ!eSiqa_t5*e;VJ=z4DZ(QYX=C}+W= zhULE-IO>h|wvCP(8=Vg{x|TG$UuyJt)VTV0BUim?t!>l#jZGU4H2IV?`CV%I@hfFk zkGeN5)xSh>#o9#uQ|Omg7u|D?uV*V`YcIOeRJY4CJF}D*~>j`l{o23b(<)CSW6pbbg;}iUi_vV zVWcLwroMhh^AV&K_orQY*ukhzKRcaX?{oI+0a_0O*?H+N%Fthb%Sg#AX~aq?*|Yvz z>`_LBRLN5)T(_0@Myh0%gK)Q7t?X25@6>qQsWsEtNk_h5yJUBIs(PWC-$_xN_0CF5 zB()LWJfusO@|KzO1jKdQQKSx(p0sz;$}sqy ziIiR0g*Myz+jlE#W$(|6qHoR(elxv1jlSTeeIfpRVF&xdO_mWTT__=?#FZNLzSG~1 zAR%7)eyy*jw%e(_bBmdU(@u-oO*fR*iy{$`W%P5)Ehg5h-gh=1>&u?$7iwJ1&1}~T zkKaY?Gj~m}OieIe*}K{h!|hk5?qr4Ra*9*t!2GPB?IXZyWB`rEe;XLI$&;~N7rHwN4P@~@9DSVX~eDzB=j zKzCM*sdujuCeyyKu;#?Q2xiMwxd6MWvME(@-1YA3N?t_l>o{HiAv8QARVI=Rm7s>D zs0Dod&CcrEcAED*&)vSR6ih37VsaF+pZ8b{u~AZg8<| zjjUC+><9MZ%Q7(t7A;$HAWMRHC{nH>lr?ExW(}^8JHP?jQbh-|fxuK1yGdTk1Aa z!Df@f5}(2p>%Ia~M)B36AWBKXs;(~I2TYSPGfo-W?3xzk#D3<97o@&Vswcmw_M_aX z81hKnlZWU2Je0^b`sYx#Xdr1F&N!~M`-5bkB{Nc zSVG&)!5dk(uZGG#=`nqBO|w66?D3stj~Crkf>jT{$B%E_eDd11pU5L!MUl=}?&DE9 z%kG>EitgkGAT!F3z8`uvUH0r(S?VJ9zQ8FNclXo3-FpMfszZ%Oudn(m_ROh+>7%^I zHAmG>|0*7>_;+W0`TyyxfUH2RfUH2R;Hl_ zV6ot=z^j0)z^lNnV5@+spsfI_psirBV5nfLV5nfL0H46Fz^mY|;HfGg-Mpea};Krgr{pe*nwKrc8kfGa>L*e9?na47&SAS(bZh$-kSI4cM% zkR-S=0P38cf|~-hg0KR4g0{}-DSR_ZfWe@rAhp1>pqoIjfUkhH z;HIFb;IDIH3Oo$>3dRXs3Q7w83S0_y3s4GT3Q!6P3+g#Xu)w{buyX_pN(vkc{tAu@ z{t8wKZVg%t@(R2S>TAwWK|_I20bD^+!H)q`fnC9L zK~jNT=NuOV7d#at6+9JG6(AN6cTQE|gR?nR?ds|RQnj$K09BpiSg=(PSrA+h);W{~ zX9Z*hVFhRX&&Uci`~Tyt2$f~?|LhX~yR%kyrPASv*tzdD|BDwD{uiHXt3`MAauy{> z6IB@{aiVi;H_IZ717j@5NCS$GDvMh6Bw=sU+b7oxsuwA{8)&r0rzVwU7FtYDnPQQ$ z!tNR&Yq+|A!#wf5jw`kHEV6WXYoAB(MU<70_h;lrl|!H1mu${ZOtDX-v+yMzi=+!P zPNpwUZlrPA>!nuN7NrxqB=-utM#J?Ho)!3%)FsP_99m3f?V6rdv$g#t4|ngod*M#) zrWN(L^u=mDAK1kB(vkzF^J2D(yXzEKlugPHcO|uYqS4&4vBZ-W-lJHln+^WR0lD_?Ukt+-n9G4QFOr>kB?B~eV z*3v?%t0L?@2iT10wgj~!3|f||(LTf#KO83TFhSoCI}y+Am=M>ECa=sRSh9ugR02aU z!;sxr?~yL;aNk^o2~KA^ZmZ_?lE!%E$$5LNPm9}Qn~Xnp5}$`8&v$yCuo{EMVNkNg z?J+|V%LLI zzq`_?d^D9%C8eNB{de^$V_%$IGK=z{tj|{5pI|mm8^LjA^cGq&SVW0QiCazN5X|&a2_^y= zwPCU8tYIlH>*-{d#=vCih0R^0$3j_WMhIi4YZ6H$wMnVu;vGzM=**54~t0Xa1LE`L%)kL)v%K@#%%9b#~I`jFSG0m`V|WZZCpg_@ffpaK1WHlJpNWM zt7zm#wPo|wo7?t(DH)}l`o~#I#oDWL@|#2~f?R#ZG73GdF;l;6dUk2L*`6uXdcHI2 zkf>8PT1w5cV4;sN2UO9*#4XW5@>$cTNUJ9k6<>TQUlHN7+m)8H4>;$5Dq%We_DL67Swx75&A}$i*etu4+o)BeU(NH*3BRC*T;d4zll&g{-5C5UoFk?iU)$E=_WX z3TJDMHL1qe*@);m0y{NwWWiD^9mQ%v;%vad!8A9kpasZNb5;@aK6XNc9%SCx6~MDr z)8nA(;)o}&BHmQ1)dOvhJA>5)6k2Q?B_z3D=^zSO;K3prKIqZU7o}omWG<%8Rz{X* z3R6qRG!ltD?2iJvSvU{l-rq?KR*tkPPZ=hsokKdL+7v5$)jVpFljiz&Yr=F|Mu>Wp zdF4@o32jUx;sTTORjwXO&oXre6Ig|-G`2Wk8}XhCnzkNlj<1UgRXFYV)LlTAaTOr= zt0l^PnpcpCX6E^_)I&1tcd0E*JdRC#>EZI}zjD^qQ|TLL#u>L-`j!k#WgnP%&XjNM zpLJRNIk#lyh2fgkYu*E&^B46lXcoC51HnR>XhUQFT{uRF|L$g2msOdO4J?)LwGpx!uXT zG>ca#Q97?>v$X|5sHmD`GTH2F`9eK*0+Cdt_fCok>Ebg5LpjtT#&VenA&=RB8KYe!Pd^}gB~?v$jinGvG<`mxKizX5-~A}>rj5wrez2ZJ)WQ7Vud)T zCL-KK*YKou^&yUf2R&mG914@%3lrB{CHpayUUVMfxh8q{Cx`eXtuv&qn@Hx0)$A{L zInxt&x~6QXN%ZMY-ZH(zFov-IHs%srYu3gm$+160Fp|2XKQ*2~+cat<3XV&gPR(dZ zJ!F-wIk^}C)3xeWLzN9>L$`9 zsToWsTaU6xA1-IWV0$$jG{Fl{M^>buTt+q%iAYOV;C&tf$ji zqm1lvtLzs(*{@==CknIQwq(DLwWZQXc+{2;HHxxLIJ})_x8+e6+QDDbiZdfeSJ`=O zNb>T<30LM|w<~$?e7O(rtC*bRliurd;l9w3cF@ktPtjUY+1hVYVa~GpobLNMTCEBn zuLL|*I-+Z&_yMb$stWBP7+`@mH^=dXss$}~{fttg}V4PyIXyUT?0Nin*YRL$dPwW>pndsz zIr+Q@L9`LwakGVMg~dyi0+W~}e_kKicV|iL1A1kHK>VfP-@of3DeC+zRHh-??Cv7JQJMzN&`u{v#&qsRi`Qv#)wask5sSuB?$ z8+E!wacFyoYH62sX^(Gd-)Y--!>jSa^;b?)e-E$u+i@Lcq?91`TrBmZ#zhU!l5DAF z>(GnK9;H#8lh$`DogmUSAnXmVTB)&B-Upjb5NN)~yx=W{(lfn&=kAsazu8Dd`FG(? zV#fRj^#hQ|zyl-^p?*8DO+#X=Y z`9ey9l(0w``ie^Pc)jZm2iYjZD|1iAlGais*fFzm>JWNDfE^QuPU5O z+rEYR_jGZlS`C#(aTk$$MY#KpR5vE(g#;VIlj*#Qch^PD+ljoAVh}0uk(7`zh$4t_ z_a;%hpO+-_0}r<1r@30k)<$+3mXeLBc@3C+4DC*(_Em=XT3g+XhjjzL>IT)$c9TM} zZK8mDFP=e|ocop?ySMCnB}%{Oll48EViS3{?L_mQbFcPA>kFgN;<85(TSEm~A6^up zxZAKX+boPrzgM4`zIgt&ngnet!EThak!aUNbtr`JTtw(G!)QfTp%7v|n>2>1r(Hk4 zvS69qe1st*A!N|wCna7sXV2MPP*pG8{i~iBIjf@ku3o>ko;G#CL`JkA;{x+tN&P+~ zm7{S;WU;zYG~b$<-YqgSs>5uN{D-q#A5h~_)bD_I@#&Q^h+(7k6N-G@F;T*XaO#OG}pZWUAV9G;~tUx zukF<7mj7_p+8BNQ=14Q;&B-DojTdYF?ooXs5zRcvc=X_M%luNK9&Fk?nG*Lx6zYGx z=v59c|9t+}%Rlhu544iznt1TK4wUhLhv1DD;GsDc0wkI%*8vZK_<#_B1OXBOAprvc z5`h5$-+&VV5&`-^M-G4nPzem^9~A-#0%-z20xAL$n(Oa@0fG2{0f8BT<^T)gp(2jB*{2Y?CC z3dm-zBM0sSVg+Ud9XXI1KqU|*=-Pn_0XBgLfv14QfCmBPfXK|1-#~MKtH6~2bO2?5 zr~rTfVnB1Co(Dt)gan8K4h0MZy*2P7P#7R2fEb`FkRY%aFe&gOkf6Ed7+A?a^*In6 zU?9L3kTTFNpd4^0&?q1$up1yPsM5{#=s>kVpa7MCgusJ9bLK1tcnDAoKnh3*KnF|; zXbJoUU_E{D$O%9PSOP(4zCB%2 zedg_%x{Gh$)`AcjzpHD!7y0gN%d0c*&b5Dk`|i9HKmWa?M>#6mK^$YBYZ~Lfi{o5A zCKY0Mno(PK?k~#ilR;ZZks{4dR)&g!p3_R5$`RBC<)&#~mwj;F-Vg2P&fX;(6K7tS zwrKp+LkLkggFN4z?4Shd53iMu5!FjZ;&%9h+}&KCRQ#Pts3x?Id(TCX#`aVr+bq3~;VMXASo@>q|ek)G)C0gqFC z4Twl2i09q$@(#oEIRs6!jfTs1-r+6U#?{(t4N>2qI4>X^*reD5mgKwi_1#Ec4fI~hHC zeSf9@dABUula4)vGtbF+zx~h7)N4MkE+kR#zS=$x8d{Q+-&=*=Yrd!scHnc%HDyu8 z({4}O?xdNg1`}ozshu*1zBSgY%1YMmEWSsVHYw~O5OqiFtj;hKSl=U~Lo=igZeP48 zY?R#&9Vqp4aq(fyuJj%>Ya2SbxhXN8g64Fq4^Gr}oF2;H(KN$W;~LsW#O z15sLbR64K4&(~){l6B0Rssx{BOYbg|EnKty z>UpA^Z;;IIqBBUNR1TY^glBeMO|<#TpP;X|FvQriNlg0w^zl5()IesNYUQ6 zUDNvHDyK=@9S_#J;FzRnshvAcvNr!-qvw7aS|Qf`&dCL5wmW`1?WvSBd?J~DI)(g} zTSoROIpkS=%QKYy<9H@NRr<`qXdNC_-0c$%guTI*?%-@G#r5qpP+n#|MQABL<^?9Wp(b z_UPf?Ha`1Sj;x(0GbuCnb4mNhfUPmLQSBtj)pIpNpSC`_{!C_mOS?Jx{4S;FaixlB zd*eX%md!K4%TO(SRs;3fs}@s#Y3i|T^Y3^>=H`{Y*XxgYd(FFRTuU$I^!6^c`I=Hn zbw`zs0?FFsctB%5B?N`o#@c%}Yg9C?7tuCzF|+c09Dp|OoGd#|nHa`qNxRgVIi31#sqfJ^gk&Y{tiw&d z-(2u}vDg}Y_Wrn3k5&~I8@?IXYAjnh+_c1!PU8#8gyHb=^zH`ANPO(zj6?#mlN`}#4`jCrFh zCD+tM2R}|?%ruWYBsza+O6E(i9?E5&q!2aD$0HOpWBnu+r-4@1dpwScU`pcVjeacm zc9Ny%@1mp+l^NI1%cK14t-Y+Jvhx1%RW_50d_?1U|h`x2{>5qXQ9l!s4Qhr-+ zN8J%FZ3yeP>`Yr-9UXg@-#cGBa%t3yJ{784;NoMaZ-kof{CT%0%(AI<)oU+k)UMz9 zwKi?(+jSMc?k);*(2TtNPRT)6UDM5FY4M*((eUmkw?aKSG5h!pEoZNnZpQMjV}J`nPAC!rnMaVH`E}h^FgqZ9@Ft_B#wt(bQZ8^IDvvP& zX4+Hn8jJ)IM%ki8dGX$z*7s>v;qf;8RF^G?+mD4S@9$cpvU}YXTEnD5kU%$qo5(`# z+2)08_THn@sqe~5Vvg;pbwpzBYwjY@x5lG*Ey>X%$=jxr`Gw0qD5RK)S15FIcD2w+ zc?*^DQcPHOw4Euqi4?gZJKc5Wv-2EM=hGZkC|HP3r5brUu60;Ej7l?%a|&&6irkzw zkG14TcUqZ`)?RFSalLZJ9jl|qHdGoWpm=VzjC7vZ{k&C1qff@g*o>A~lUI$@3B};n zLfZRXif*Vif3?uU#mc$DWYSm-fw}@G-D0H`{hP72j)Rg9!nbxD} zbY713@A`zh{Zu(LiyoZ)x{%LUf{m)zVGZhhFkIxcL(eUK&4)t$9LpfwWYPyiOw{L~ z!ajq@k!)g-5PEl%2SQ^Sn$ej-kna01Z6TYZctV*Oa1t-3u6vBg-jcurOu~#w+2vC7Of+L44%r@JIb>Kn^h;GC2fti1Co&A<085hf)UM0wi%|D;LK@Oh__Wwk2c<&fOJ|z6Pcn{hB|417D&;QB4k~x-P zMO761YYjuu$79Hzh?2t#%rN4FIGO({nXh+aOKX>LupWX5&ua^p$ZUL|YWVWbQCY%e zs=r%f%}|BwG2?)1Uv)eE8|8>Xw+7wx(`J_2Iy)W2C-4=IO(C8IZXEt`9j_iC4`LY%9S?3$X7PYMn53=L#-v=wXvjR?moc}9tytSiyhg`Nqw`lt@+b4X-2*>C$cx4QtOZ$n;^1| zk199ZctWSAmA=|K5&LZ5@}<3rp(eAbD)RQ6bgO;#7l-3YF9wjY+8(7~~ z;EOmda^;!-JEKydS~r)F&7hd<9+Lf3PUBf!&YRP84m3~HH8MW?s6Nh6AsF*fny z*f-iRMun&(xZ19E(j;ep|yT-?nmEO#d zx?D6%P55AI^L`TD4r*uY_}15}S8`F2CJktIhCpe1JJ!rR8CgxKAMKctd$CZ8ez%g{ z{AX5uQYv#&9Z_N;f}3V!mmBurxEWv@ADCOthelQzr3=OH(ly*JI>vs>uH- z#(4id^X*DP)uFqOPZ}-zHjtowxaj$jBZq%rR-K>ywKbBTir$0h2(*pzi7QINnRX#Z zm!ogb-cv*`icVWuap^Xq(l5o^OvX_&Mc8?+on*hsc!g*Uyu2b3&~Cs|dpvpw-m#g3>f4VF@`e-V#{2?`` zzsJC4Dvg_2uITbA$@DQ9!3z^8)eMb|R2|H&Z~^qEI_h?qZ*e$pjmc$;%fmZkP?whFaE zktyX_io98A`-q-P6f)!Fk@sa;;?3_$Ek_73ooYz;gE;0vu>#zZZd(j(;KU^ZjEuXF zL*nfEoN#Qu{t9*3kgBA(j9xyyDAu~ortBoGi2U%4wvW!4FiSLUl<*d7cnIYWqS)A? zbxV>Aav6!9Vq+4-m#w@l?=hDA7m|H@UwNRIgU!*I6?>N?3$J%Wm#I-igAfk6C_P@2 zK~}Povf`QJSeEWItRRGy`8J)}kUmSzI-`UL*QRINh6VfWhT;5?hGT1ciQNwrg_4-x$BO~kQN-}T0-f1{6GJ0yRwn<=yk(od8!t_g1 ze_BPvSqY{wk$m)?JFmEbD6eE$F5e?}I}-g~3@=FuJLbeId1f=Oq$5iBrD3vP$?NX< zqk-3uDy_)3vLdT9^u!5wwGUgFC+p^#D`;`hOL@x9Evm;6OoNLKVrZQBh~usQn%&3_ zB{$D9Y;X1pEO)fRo)ddd>11PV`Gsz(&*-cpg#@5Do^3A&9Ymc&R|_7we{1#A*<-tw z2gFb3bm-27IYjbLDD&;>vb_~{U~dt!&Jic5E@PQ4ncwttOBP}^RAX-0Fg)N+=?Qke zym;zi&!my2l{U||-41@^68Pk=>Mkd{58XeLRaa}J8zS%MFL;lvp19Yf(9S9Rf!UdH zxvh6Y1n)#Gr=9!Af4?{0<0D7!Y>*Jk)>7H)^3kY_ji|_IvTMn4^pl=f9#<9ytBx85 zi-cJ%cXsOaw1}y^F~r;vxuSQ$%%ess(cDS&2EX}i-NRx2SSN}(UqjGGf*F%AlFJ;t zigXB>=OIRoO(Zf0C3ZYy`cndjG+tyS?n#;ul+;3&t6fwc2$k+~*@;p3#K75)Zt*zA z!Ioy$aq!NwF|u;mQjLS++i*_}gj7>oBrfRQm$U!A{(we)gu@N=v};tFmY|+29i?ZrH(FgA}w^oFO|FTEJo91Z_a?iL>qox z^FVgrr%S7Tyrk_?uGY<%lrJ*Z9~zK2{R|OkdYjOD`;m8~WqEe{lYQ|)&%()MCd;+V z=&e=41eH6WY`F9<&XYYKQ{U}tyDrWN2pYpv*6v{HM*(BfZ3VdjtHCJCR=HqPK z$UbcA%Ujmx#*3F}eh-*Iq*Zn#J0fKSH~Qz#mw$f0EVN~DxM9CT>Zk>(6D8pl6pCU; zA!0#jDR07!eYFit{voE|Jaf-+MqN0mVSpiPEKb5B4BDn`_0~JYgblYI-Y*>EZM4a{ z-}l)vCaND*jN-XBE6{=WT`@+eVWZM$0v*@`2~2)<4qr4UO4^#_t|RV`=*}6(p=oiH zB!6?;IP0j$0z7iMDvm0J*r1UYZu>}$@jgTGe)I9c`kKV8h-aMUh$?bLB1}LByH$!T z)3D{8bv!0Wdiw?GGu1)fl<-Oy{6Hi|?V+4KC+MT$o)wY^Lp8u=`@=|Y^Q2&&m2+8& zSr&V@KiJ}TY43LHpi*2Ey)pUBQ1ZF?WNTr>y@2E;7JKJ~l}RRPOWfW73Hy?%5Gf8( zv_I_l-JpMp>i9oJ#ciDsI=R#E&^m!uTuyOE;Q>;>DR31K3OEIF;*P?@OgwZ(Ko#H# z%mkJK9)Y5`zyenRwxE!LpFmMiFo9VREwup?PFyyDpFm(-Jb}Re#1mvqARQD*@E-^a7zfG$ zgaM&|Q(QuUpP+Ao!+=l#GVZ87_z8#ue&R+_AQV^!6a}&YMR8A{0Hi=s+=CvVC{P+G zhdaLxz5&^AIR%64;5Hx{#7ZutxJu)eN^SrJ#{iqaPh3cG(D90u6}BSHH8deMKrI%0+8!}2S(Q^^ zyUUk)x$g_^elE1e98E|?T!Zd#MOFLqE<(!_RF=6{JXq>^Ipj%*eu$g6gJW`zSbFKB z%fa_b++P_|ax{zWkp*%@`I9SAA75Dw)eFUmJc=tTy3$ZJ)}D02dfDhiPMTwUzREer zrkWQ=T?BB#%)rEla2)?g{h58cr|w*U)_JzxVC$XZ8*iU;+P{sdt%}&b7Qa#tqH^M) zv|dU*)_QfMh*IjG*-8whjxpwv2m)YmH z&#$`YKlC0In;>3QnPEo3R3e~%aB9%Z^ z%(T?fm2$fwYZ_NH?xMzvv|=@H6}cVJ?hf9(j%ekA#Rze;D4J$Gbp}jW8h2@cemc5u43(bXyg5yU@tcnH~OWQmn`M_b$R3z zStu^v<0vCYS9Nm$qGK}FR$TlbWP6g|RUM1U(#7cQp*Ic%FHb63cI8bqjraAN z%N*-v)i zpL_l8I)Yz5%fU*9&bAU%%Vyj7DDbl$?+?>5satNk`=-LrFrq^qow%bt z2^dw&ur6`sFZfJSB$~u0IA*}&G_3gc(6N3cW?G?d_1{Ewl_BnGhGn9*JEA zm*o#kOAy~0r(<{^_4{nQnu`l^0=udGp@gFM-m~=w!aB!@@-EkxoagaFXy`@B$lG5y ziXIUz7SG;^4|I_#r-cdqaoKzE5@o3tym&L?Lr*a}{v>y_bRfCzMRvOw>ny%3%xHS* zJxcA>%*iUX*Hs;VPQxGJaW}wI2fHZ`aws{aTKp4~7fqE3rJ^YuOLJdTk3yI7`Y29Y za+c+bc-0k59Y>Td%?0(mYZFhVo=7eE^+y`7qO;J}(Y83;4j&{&UIx*<$?x65;M2>m zVkuA1);yrx#A`9AAF-S@AH=Ix?r@3yn6HS*kwPuUl4A(ifr~O{Vlcu{xuMoZ)FL+; zVhsjb$fXKiny|8&b|hF8wcN?jL4Hpk6PQ{z8Tdv00{;-jsCK!mFnXhG(-tvpad&sS<8vXvHYPIa6$8y5?e5sRXaE_csSOLj3#ci z_2(BeNfNSDh;b-OH}v&f(n9Qy-QKT(q_I19gn#T9Y@G2+Q$%D<7`7Jg<4w|f3RH}{ zx}2jwoXF+BsAgl=J%iFaP=7LbSW(QaWc|s!WXma*`2qq1lw(I-2=KiO-A5y>hj!n4BnN-&Y?#w+c$4Rp+boh=7_`?szx8}(P>M-trfmG;$sl$5O`7b;*`Sy36#;*2PORY>kVCsZ!Nn)X7YI=7Zcywxp7zmIL?h~cG~iF8MAoz9yB)fW?9hX z^_bO^T>Pzh$}*X6Lw5skyV0GC<~R*b{Kh6D&8ig%0-BE;3xm8^O=u62Pg5g!$LbXMzLLi0aO30R?Wg9i(yoeRzYN+E5K{dx#qifW&0|Py->1ADBE)pbj z^7hq_dO6hbE$WqO7@;tkMT?-XDnZwH>peg2dT^jswJT?%b=BbGtS7Z4t2)%~?5xnI zelJrTTGN^-Fndc%)oPlQK9<$s*m_YWO+f__&GE|ll-+RCal1(5Jq^<>deQvx<$RKKo{M7h=IkQ|4k9^GCQr(y&n-Y(HSsh(DR zp6ukyDliRSNC;hYAcYT2=1rWmXhL*y!?O~)U(z3P1<;H3Fk_*%k3|DCHbSX)J03I``uKt?W#wph7PEODdbBb9{( zSeL5SP2Gofiuw3AD)qN5H+debec-@r-}4KNHVJzxpO0wjXP52fZj(qeMevlMm_~DtZ5kPe9+UsTQ;!t>3(lI;;>PEjfPro zx%ip8X&0XjX(mO*6WmY&V^`N8c_eFI9pU7}rK>cYn7pKt1JOmwn~>Ya*Q(Pi4@?^W zoIrBpJ{?DC;_YF69 z@f4~B;t=%SLw`)e2kW3X1~_5E`l$f-%T#Qu;lizb>iF<|65-Mef+Qn&O$@_-me+!Y zPQT>PV#)AAQ0i=aj*;U{O9qoiytreBi&{vr8^hfsesD6R%ER<>5Tn7!_C*Bas)q-b zVyB*y5c0cqriqFh(#+6dW@Fh~_;0QzlS%GX2ivpOe!I7JC+yT`iddqRXi7l0U+$1@}GdU~D6~$qo#~9kv0m8;%@GeC&!gF@oU%DY|$rM3$l&5tT zpFQNaPr}$BH@;8eZ&w_-v!lNMad!02LIs|J9tBm3d#Vvs1+@w=1*!r=fu}%5;4Cl{ z@Crx;TmlnuM@+$4FdYgY0@nbnKvjSyP!BK)v<1R~!~~uKKmnfU?qSOAPY{R#*MjDqR~b^y3>_klrD04Tr?L?=)ih!0W~xQWXpZX*IQft5fvU>r~w7zYRm zx&itDZJ@t_#eg$lF>n(Aid(>da=}M15ek%pE(aO{(1E|W+rj`YkP*lZ zaKr@>*Id9l5D>5qs09K7cEM;U#4(6S+;#-z3h>1pwFN42_mII{P~L!D03VPS*ax%) z)B<*a<{(&csRicZ&a(cgEeK^0tRR$u96?x6tGJ`B04v}X42#0ZC^u3;q5A*8Qy44~ z$hJ*F2ulC8r(kweW}nXSfPPE1wA$adi|sDAVo~BovvT(TDpV=`s`IxYeHcD@$3`97_#`F7==bdC zUSUl)Gl`lPw{!HDTKQmFdBu~9g5{l>YhNC76)c*Ih?6?OQwUGQu9oFNp^=?;@_Vl| zyz3AkiXmjP8}FX~o*n)7p86t%OM!3IHZkct*H#A_?AJ=Nqx|F*RMmO>`kD6p%_DY6 zRPqD#cky7l*KuCUgoE=-z*BC^2uzg=MR?&jsi0u70A(_YA_zAV$C8xC<8m-LqohPx z#VnW|Rl&_B%DGRk$HPKm(etBnto&PA&)FYPM^}6Zo=6v6NtVDRsrQ@ny;e|vk%3WH zr(jE#kUN=fk;%$S8pc#;IZ;vDCXXr+jL%R)g2Mkzp)xP(Ux8Pz?V>cLG8B&PyaC&< zM4X2DHdJG-rF4KD!ynm79!L-((?s%z~s~p*zqBKb6Mc&{(mV_=IG^pEK??QTw=CWg}t~nBs{K z*hgwp#7#3;6ldHEo)t@JMjIMF4S(L@Ijmt>fykRxVI^PHd~>C(3cMTF@>#|4;nne1 z-WAu8N{HRL!*{EugB9$b zpknOlLJ|^-ij7%%DPnG8u&(5aOumw8ml@P99~4u*Zk~b1;@n?%EOlmioATtkjjjc20HzmO)cL|$5boqwU)J*Qjf!k@LSXby~6pp}@RH`q~(-no0K-JU~Z+x0GhRE!l9L z_@L@lE=hxd7HwD<9Wl?T4)N9WZVDO2VwiE;_t20lLa+FFE ztoG*rDAh@psA7>5k|`16qJ`pCN^9P1a)0cPR7u@fp;DIgTqC>FHi4uUayPZg{6hP@ zm9TLi>8MYJV@J5><<7g*ONbyAnFqov97*i}{~s~cn0 zMjmO2T#}{Lc<+`?V$4`8Uxf?)67vNb8@jqZnm=S#rCwaV)$aD>0Zr+;Pp1Ow)037F zC>Uu{pjL7b8y*Hk1)yMzlvmTFpCfU7l&PKB<(Sr#Cn!GOs&7w9*%Xv}O6IbN#Bw@n z#rO45qi#8wxp!mbeJDuxWhP%BYpy0IZ6n|M6nV_F)@8FA5voZ8 ze}6)xoyVt=ZMuQWhy`;;OIIwWXLc*I@kl#yYuejGA7&+HV8pJsi&+)>I}vmVdMr$700cN9n}9 z6Ri^RNpZY2{w%slyHTU;0^NyY*4sc;hn@%9ZnKa#-UI6+G1 ziiov7o3%Hc?6z0YU(9-#I;p;H%Wd(aA5W^Hr&jK5>fUK>fA&#m&>DxpJ3CbLlir<~ zx+mYDmXaZv&KzL)gA-MRnU$f#gLW5-qDE&~i^;%INfB^Jw#K;~VR8`-RM zfvpv4F5M8*&@y!}TP-4&=%*8R<#X@59)yZYnm3oWti~;Exq`*rNp*FDvj#M(1iJIx zA*G$tg%cFq>LQBZB9=@?@0Qb3&uv@1k&(2CK;|>fY41|F*PO8Sz@))Cb}#SI-5c$0 z;mU+5Qnk8W=Ug51JarbfT-#!Q@mHZb)_lLv`EyD8d)_PcroPr+&a=e4U-M}WJZ!DV zdeAf)*`&08Nc?zA_&7&obf{t2I8I7$dK_KfnUFE%ob6$vgij&y6n}LVS4pzMGM1Tn zkTyr5$cJWAHV~f+ouBXYwo+h|2*dUA`K8r&~F$plM?6x_QLHK+6DCT8lt858HOScWbOM%v4(w0F zQjze{6r2lEq4IlnH0MZj0@&y>O(hm=xV9+EmU$Cwn3uwN0P z5vI4{zT>~HIIhgFT)B5JUVi!K_>pCLPIs8mUKW|E*5UL*@~Q zT%PRvhyNMr0#KX(D^vm}q0@0^9=SV-fJy)+pb|I)K0Ve^HTu}lZL6o2y zP$!s?D@uSQpa38V_5@}EBteltOYYDjNR#VFt`}^`+cE(rmH zu!{%Saspi;{6VAx&;d5Vm_S89B8)mh0R+%-X9Ho>5zGkQ1SfJ+9heb@5CNVL zumFr8S%{cmPc9h2aR5fZEEkM`S%_#5=>T-VY8XER$pVwXj38NVrvoyBNkOB~6S)x( zC<;{Mnh~@JAO$djNx8KS)C?^BQ;vUUBixOGPRC^<5EbMLMCEQWf**mXfJY!CC>00^ zc@7i_T!nE^_t;~Wlo<1QayoAL#@x0$TVnCX_!+b2`nMyE z=~_nR#*|-gXPpovdoyN!p)zrGb=bRS>jHCzJ49qy=@hpq+xAw6<4{xtU1AbU;{pRv;;CxSQw<)#*rUlLpwet^`uQ>V zS!9B3DY0!L-BzXeZU9H^<;02gP7wl2Gze@I&nIf}ixZ+QZ2}lQ-;*!00u__3_)7b0 zsF?v-FIA53iqJzzUx=e6XG*mcZ%r5MEU?6h_xNwo)_k)~jeU?v=NB?#lbNK|{Nd9D zW^LhZ7qgF&DT2ji)R%=OS`wVI8)8C2(k`MX8d-()8UeIL&nj{v;;)7}Qrfsi>i#nK ziC3C&)T=r-Dq$h6@A!Bj|Je)|zi?zp%nMD9n;74B>v{$OFE}`xJttK*orx z@baiqEjQOUVeOVeoq?R@Pa1Wn#W$Tfz4Pk#l3H)A@|>!-IX@)i1}yb6;I$;_A^O=? z(qV&it3E2COzrWt#aAR`-!Y1rU2>NrH~J|F$xF^5%tj#=5w(e zBlMVI$d{22x#~@5+0GID9`V|-ym+ygsM;=l`g_F`m0R*SfeGhe526SYjQJ~$=7tbcq|P@{4D`1Xo*-%8fJ zB+Ar&o1wlZ>QuftpK=QBR=F;q75T(=5qQHUq|Gk+n(Q{gtWTxH<8Qk*n@gr@auQa! zA8SJE`qV^~m+k)&I1)+_>2#v?Kb%|k&uzD3|iNXFPeULc^W!yfkJeXR?7q+DN&ZnGiq|y zp0_XwSww{>mZb9=VU>_71BBfwAlH+h-)VCVyaLA3athiYj=(vOrP60E6Qw@E;kn63y-J zAUTSduhmD%XfUzv1WNS%Z_0-bWnn~T>FAXt|3xwHzxl zdelWHUN*RqQJ{P0vXqQ%J|1miWhhhY_;I;4?_flKfLF$UI9U}lNm^^58ZM(7udcS4 z?C3TX<|DCg-?+7#!D3V#DT-~h|EY?aJi$#y?0uT$f~yvlYGGtsm9lOAU2Y>URyUlM z=ot);f}&y^4QS@6hk_Jk#1R|qS9jZ)5f_%M*cKodgJ(^|6lfUsP|bJ|5oeuCCcVYZ zd%N$QTQJxt-iWU6i$q@h5Yt+#nKTl^xZn7_EGT;WEAMmBtRnlm6>BZ1n8itgkkqFV zH7ZBy9Nwc1t~ou@EcJTW{h+@2b2%fe)Mv_mLp%Ry1+I0wAHHhC)vSq%1Iv;&;q^RO zNY)vqK$$<^e$O_Z`YN(r8C}|8V`rpj<)O^7%`5njzHsd2l)*Ovcs{SRGyeP*tDmTA zh1pzP@1elnu~=s7Q#y3B&8YTR`CAGZMG&dV_d!f7Wo*N+D^)z|&kpVgHyqzMDc?|E zee-RYc$)=sU!Pt1IT);HN#8^t=v+L8AAIx)p)7>1^7*!^0J{V<0l7u4sxDX-#OqjID2(nCpxbr z;ZWj)eqZIGZ%vyPPnofmB7~72r8+UfbZZ1lyX_`;Ij6&MQt#M4#UZhzMeHiM&Dkbn zF&k%ZsG8ix>c~pPDV8D1!{m5cExE_S;NxSHDjrSthR)q5P=W@GV0qQ(yJ_|BA1BPl zYFV1zGV=*AEq)v$pccTlLXE0e0S~G~PBVWX1V#^z z(WV>4z`Jq`ZpG`EYsaz&jFu`tdA+kCMHRhErRv*b6+y~UYnaiPM?d>I#}qpG{*z@)3E9+U4Um`qB5Cj8=B-b9|}A zG`n?nF`~%E_m!)|s=?BopG)sD!_b!_$k8T^SGEz6*3aKx*mB1nL$b8IM~M2bZ`HXY z(?`11BnX#px9pL}4`OkwdY5=Prlh6PLvgxA{HeaV`YS))GLBt&JmvhQdF01T)L#pU z%s<8+Wfy15O$kzBdO8}HofWFuP1CoO2kIa8EnP9;#7;LmGPT5+*lztnw5G$vDDK)L z>PypCtOJv={H=(R4r&RTJSofn_GBZ1M&Am3L3AOAZ<+j%?3iJCL-yx<=elbjvhRGK zT=ny7|FLVI3jac7Sid-8i6|BK-pDI)qcR(bdNLg*?#J zY-A(iWH^iArSapb*nA2)g1NuBgBh|1qgxe;j4E8HB7HL=6_F!&R2Zs?B<+~(C^7?s zLisAymz?txoa z$O06BQUFEVZ7go(f{@0A3h0a5x*&9MiyANqS{D>Az!)g^&w)a~7@K|tJ7tqNg_{<~n7&t9+7t-Oz;*M7`srG58b1Bl7GHwYSsX;>)@Digt* z{aWezWgEvt!NHpLWsXI^1`xaJN}aVXs9cSj<_5C>@z$}_WZA6y++!<83Ucb`7wKJ3 zt}`)weI=Gw$7s>cSgGH^Y^eqNE}h>-u$ZmC{b`wWD;h;ovF#me#i;ZZxt2P=-pG*^ zAqK?iq(sz#ZL&Q&Bgns2x^}0`29O)y|NCIJ_q4pkA}or~^G>{*zIP{;ZXj~|i;ze0 z`E}2f_M^lK0xIrYKYa7s*Ov`Bhp`g2{Rd+Va_N}9PXEzZtV$~B}TlwN$i)c4_m@3__gdj!|PHn@R-01@2WY7C989`phlhD3ir!VCm3cNv- zms{^s7?Dt-VI$`WyU>e~9BM~NZIFQ&FAr-JlT|k-bC*VtnusT~EQI{SHY=>w-_-42 z^3AC<1aXP0z9qj2(Q&FDj-8E+J{sl=b>p-vqOk%&+tpk8aaeWb^4e_K+1VR|>q1d! zh#m!X>%RZocl{wRB7r%if8y*#rb}>J43f%kku?t$)DA#Lc4 zOJ<3QM&Q_PuVo1j=Ly*AQ`;QqHd5! zPVJ8sDQrCHkg7nyg|)9>+_ZXzEla(%Qb~sOoMrf!OeK0LF;e>zH4AdhjZLfw6H%vE zP?)?H(`;T(2G5#d9?JTaXBFIIJB7FGOfT9NnC6M?x<8#{vj%;ft#R^{(hnUw$ML|B zf(Q+za7spzj%S5YVvw;Lh_B{!^=QHME58dt?C|($Ipd@aRN~TMa3iKVL~h zEDiDn4Lh3#>M9%p1BjJ0w7LF3|FJdqFMRM(v)$00o^{QjV6Il3sYBykp?3U|gNrJY z-5)FbU98AaI>hBzid&&UK2K0^iCf+UEQz8>vLEGW)r=Rh%d>vV&`HEft;p1W zv)woai3+LNIe3S6wyJQAe^$+cZrk1UIy{*NJ(SV*xcf;gbii4OIt$%Jid4wmc(Vz` zoXV?7ZUZDtMbl_>)7#FS`!!>qjT<%Imm%&t$mcT=u8hDFWyqntl;@_|Ub49;B)AIo z+V9JiQGv>+4u_{7PJL;acB+hi_}2j9l*6-y;V;+bulCaT{n?3Cds-cNhi+;FiP844r{~qeR2f~MEU%Egxbei{a)yOuiGNSejeK};3@cv?+z?Ksh z3v*S*Ywo)rJmM**B&d1)*RhqoJrLiqhiBcx4@1)!%tfLfnJC}6S4}NR0C_ASAV(g( z{%R2C_pVgR%=POXreJL@-f7xgcA-DX`FAk0UbS$SeYCbf)#>F!9*V$b6I&!`MnU-kZ*i770h3ddk zwy#axuvWkXU2V4n*&a?6kYh8WFE)hIx9#S+nHd>f>>Ij0U<5a8tzDD(WXBGB1>M(6 z_ST&)cluItWyn02qUXg(Skst|*-hg}KIMs(QG>xyRvS5nO#G6ci(QLl3T>rcn7(Fw z#l|2%R{7Kud+s^j4TP%AXogvb{LiREXDqZnd^_GU@p<*i?y1rbnH>!;v<_?cY<}vO z`P_H{nVs)lTe16uXu*^TPjvsbzVLiW-wyMKjRTKXWjMpzGwzfG!PEiNy1gqAv#K^_ zn#Z2f!c~Z26-(ff7PCV3+ZFUF)Zo=`F9*t>yuKH?|Iwp0PiwFLc=NFC+vBloJAM=$ zd>8d|=Na))`~@*Zqur<99l?)VT-K_AXH{N%B7!Ew*;d2*#FERLZ**2)ut||IJ|t%s z9%!4s%(dh|l*o(jY#rYE23k2@|^&Lz`2nYq8_B$g&&6(*dJ=yZKv~T8V3;g;M{;qEZzN_J{r%&Nm z_}!B&KWBdZ9(;7N6#jW>%gIvs2>#sQGvTAB@Gm``IoZ3SK9aV>93FbTAn_I zx4uhDTmBFI6aJt7?f-v&1%TQ(xSqmBeqB#dTu!I?w_)-8Cd>Qjto9@P1VKh86CD$e zQ8Gi=>7$fnUYvnjXRaa>Ez6f9*C>qKU@HknelMcsc4ZO{@-R+{OjGl4qU&p;s*7EZ zV>c)Y(A^X)GYFM_ZZBz+-gp83IfIw)i+|6i{_Q*XOYw#{BAK+Od$#yN1FuPH51&}T zMg(nX{=LLC@J@-cZ;EfHlwx4Jnd_lm2Qft#9?xSQSNF5^?=|tuVP@&N+V%s81xf1ED6=c zrDDgT_R?OB9P?O1({J{DBJ}8?(~7e-3-goS0ZgX*+MngK>Vw|vCKY~NPx-a$7yd&+ z+SUBvpq#~;l{_vycr3$nlVnhor|T#Gttg&B)F>0@==;#~V7|Yy^ycx^+5O4Nmo~^d zh!;;Q3cI&)*?~GL(fx(SALbx zB(gTDSSrp=oI4TVHNoLgzPXQ`zbWKPK}HnIOY8#r=#)3h_xD{>#cBH4MFJVftzLw+>snXsJD~=l8J9)6=h->NWEzNf=A$wAgx*F$3k+Q=phgIy4I)6I3xvgaG zOl(t=)VcEwBGCv+!F>O+{4X<~OY4UAExfz*T88rW(y3EXRExPoDW{uWI`e0hYutMc z*HhX@3T)@Iir&@z2;mRhs}h~E$wRu&fSIq+9ktvcRPRi6`x5MqfnwXWBt~69#k|^` zrE8@OYb<9Xw>CY=PnEj0rG6y5Cm3G7VO{q%HZ0$A1n<{3G{awYXU=e$=3*^Fa{qe| zJ54?Vdp&zOvCR+D?e^48<=2MYdFdpecf_k9ZD)q+rfXAUL?^=M;a?ds;mxC`k-L5*rVc9;&o zKN{6@LHnGftF#{xyku1;&y59#dG0%cXZE_<&J$8-MEuHX7o zAO245KW03@D<{P(Wko#^3@=jIoC3fFw;x^rmZBP{q8QSkQtF*2WW z2~I`klHL6Y|Msrwzh+ZUeJW6MDz@LyJ&@J>>7q_rvEx?zd#8p!{gn|v6;cFBKv?(l zWj+_#I+d)??!JG?^m8#St;DU+ez3&rbBSkfiAO{CU`6!jQo2B?XNUcRnp2<4f}Q@6 z5g#@Wf3Ar77q#K8DeU^;9fsOu=BkpM$^s;B58X1I`wz3Jy=6hhw;%OI&t1+HC=a%A z7#@IwC`C@?AscQFKWLt-t4doe58di8GCVw2-`HEebMNhurwelp9D#~|Gn-oI@Z^=( zm*%0~ipYlBPiCV3?@+t9^3a#t&lVTHTu0!H#ec)gH;&I`M&^ItHT}P)w&M#8@2}mS zeKlDPJukHOf4xorBO{*v`s;cM_4oCZD_?sVM=zh5a-1?9`PvuNclq3xo~bq8{wr$d xxFfg3qiT;Rt=J~v+Km47 -[[nodiscard]] std::string toHex(I w, size_t hex_len = sizeof(I) << 1); inline void VBLANK() {} +bool a = false, b = false, l = false; + // (1) Create a LinkCube instance LinkCube* linkCube = new LinkCube(); @@ -35,23 +33,53 @@ int main() { // (3) Initialize the library linkCube->activate(); - int counter = -1; + u32 counter = 0; std::string received = ""; + bool reset = false; + u32 vblanks = 0; while (true) { // Title - std::string output = // TODO: IMPLEMENT pending - "LinkCube_demo (v7.0.0)\n\nPress A to send\nPress B to clear\n\nLast " - "sent: " + - std::to_string(counter) + "\n(pending = " + std::to_string(0) + + std::string output = + "LinkCube_demo (v7.0.0)" + std::string(reset ? " !RESET!" : "") + + "\n\nPress A to send\nPress B to clear\n (L = " + "+1024)\n\nLast sent: " + + std::to_string(counter) + + "\n(pending = " + std::to_string(linkCube->pendingCount()) + ")\n\nReceived:\n" + received; - output += std::to_string(Link::_REG_JOY_RECV_H) + ", \n"; - output += std::to_string(Link::_REG_JOY_RECV_L) + ", \n"; - output += "joycnt: " + std::to_string(Link::_REG_JOYCNT) + ", \n"; - output += "joystat: " + std::to_string(Link::_REG_JOYSTAT) + ", \n"; + // (4) Send 32-bit values + if (didPress(KEY_A, a)) { + counter++; + linkCube->send(counter); + } - // TODO: IMPLEMENT transfers + // +1024 + if (didPress(KEY_L, l)) { + counter += 1024; + linkCube->send(counter); + } + + // (5) Read 32-bit values + while (linkCube->canRead()) { + received += std::to_string(linkCube->read()) + ", "; + } + + // Clear + if (didPress(KEY_B, b)) + received = ""; + + // Reset warning + if (linkCube->didReset()) { + counter = 0; + reset = true; + vblanks = 0; + } + if (reset) { + vblanks++; + if (vblanks > 60) + reset = false; + } // Print VBlankIntrWait(); @@ -90,12 +118,3 @@ bool didPress(u16 key, bool& pressed) { pressed = false; return isPressedNow; } - -template -[[nodiscard]] std::string toHex(I w, size_t hex_len) { - static const char* digits = "0123456789ABCDEF"; - std::string rc(hex_len, '0'); - for (size_t i = 0, j = (hex_len - 1) * 4; i < hex_len; ++i, j -= 4) - rc[i] = digits[(w >> j) & 0x0f]; - return rc; -} diff --git a/lib/LinkCable.hpp b/lib/LinkCable.hpp index 1fb73d8..4e7a067 100644 --- a/lib/LinkCable.hpp +++ b/lib/LinkCable.hpp @@ -45,13 +45,13 @@ #include "_link_common.hpp" /** - * @brief Buffer size (how many incoming and outgoing messages - * the queues can store at max **per player**). The default value is `15`, which - * seems fine for most games. + * @brief Buffer size (how many incoming and outgoing messages the queues can + * store at max **per player**). The default value is `15`, which seems fine for + * most games. * \warning This affects how much memory is allocated. With the default value, - * it's `390` bytes. There's a double-buffered pending queue (to avoid data - * races), 1 incoming queue and 1 outgoing queue. - * \warning You can calculate the usage with `LINK_CABLE_QUEUE_SIZE * 26`. + * it's around `390` bytes. There's a double-buffered pending queue (to avoid + * data races), 1 incoming queue and 1 outgoing queue. \warning You can + * approximate the usage with `LINK_CABLE_QUEUE_SIZE * 26`. */ #define LINK_CABLE_QUEUE_SIZE 15 diff --git a/lib/LinkCube.hpp b/lib/LinkCube.hpp index debff0f..f07194d 100644 --- a/lib/LinkCube.hpp +++ b/lib/LinkCube.hpp @@ -12,7 +12,14 @@ // irq_add(II_SERIAL, LINK_CUBE_ISR_SERIAL); // - 3) Initialize the library with: // linkCube->activate(); -// // TODO: WRITE +// - 4) Send 32-bit values: +// linkCube->send(0x12345678); +// // (now linkCube->pendingCount() will be 1 until it's actually sent) +// - 5) Read 32-bit values: +// if (linkCube->canRead()) { +// u32 value = linkCube->read(); +// // ... +// } // -------------------------------------------------------------------------- // (*) libtonc's interrupt handler sometimes ignores interrupts due to a bug. // That causes packet loss. You REALLY want to use libugba's instead. @@ -22,19 +29,18 @@ #include "_link_common.hpp" /** - * @brief // TODO: WRITE + * @brief Buffer size (how many incoming and outgoing values the queues can + * store at max). The default value is `10`, which seems fine for most games. + * \warning This affects how much memory is allocated. With the default value, + * it's around `120` bytes. There's a double-buffered pending queue (to avoid + * data races), and 1 outgoing queue. + * \warning You can approximate the usage with `LINK_CUBE_QUEUE_SIZE * 12`. */ #define LINK_CUBE_QUEUE_SIZE 10 static volatile char LINK_CUBE_VERSION[] = "LinkCube/v7.0.0"; -#define LINK_CUBE_BARRIER asm volatile("" ::: "memory") // TODO: USE? - -#if LINK_ENABLE_DEBUG_LOGS != 0 -#define _LCLOG_(...) Link::log(__VA_ARGS__) -#else -#define _LCLOG_(...) -#endif +#define LINK_CUBE_BARRIER asm volatile("" ::: "memory") /** * @brief A JOYBUS handler for the Link Port. @@ -44,13 +50,8 @@ class LinkCube { using u32 = unsigned int; using u16 = unsigned short; using u8 = unsigned char; - using U32Queue = Link::Queue; + using U32Queue = Link::Queue; - static constexpr int DEVICE_GBA = 0x0004; - static constexpr int COMMAND_RESET = 0xff; - // static constexpr int COMMAND_INFO = 0x00; // TODO: DOESN'T MATTER - // static constexpr int COMMAND_DATA_WRITE = 0x15; - // static constexpr int COMMAND_DATA_READ = 0x14; static constexpr int BIT_CMD_RESET = 0; static constexpr int BIT_CMD_RECEIVE = 1; static constexpr int BIT_CMD_SEND = 2; @@ -81,10 +82,6 @@ class LinkCube { LINK_CUBE_BARRIER; start(); - - Link::log("ACTIVATED!"); - Link::_REG_JOY_TRANS_H = 0xffee; - Link::_REG_JOY_TRANS_L = 0xaadd; } /** @@ -96,6 +93,72 @@ class LinkCube { stop(); } + /** + * @brief Waits for data. Returns `true` on success, or `false` on + * JOYBUS reset. + */ + bool wait() { + return wait([]() { return false; }); + } + + /** + * @brief Waits for data. Returns `true` on success, or `false` on + * JOYBUS reset or cancellation. + * @param cancel A function that will be continuously invoked. If it returns + * `true`, the wait be aborted. + */ + template + bool wait(F cancel) { + resetFlag = false; + + while (!resetFlag && !canRead() && !cancel()) + Link::_IntrWait(1, Link::_IRQ_SERIAL); + + return canRead(); + } + + /** + * @brief Returns `true` if there are pending received values to read. + */ + [[nodiscard]] bool canRead() { return !incomingQueue.isEmpty(); } + + /** + * @brief Dequeues and returns the next received value. + * \warning If there's no received data, a `0` will be returned. + */ + u32 read() { return incomingQueue.syncPop(); } + + /** + * @brief Returns the next received value without dequeuing it. + * \warning If there's no received data, a `0` will be returned. + */ + [[nodiscard]] u32 peek() { return incomingQueue.peek(); } + + /** + * @brief Sends 32-bit `data`. + * @param data The value to be sent. + * \warning If the other end asks for data at the same time you call this + * method, a `0x00000000` will be sent. + */ + void send(u32 data) { outgoingQueue.syncPush(data); } + + /** + * @brief Returns the number of pending outgoing transfers. + */ + [[nodiscard]] u32 pendingCount() { return outgoingQueue.size(); } + + /** + * @brief Returns whether a JOYBUS reset was requested or not. After this + * call, the reset flag is cleared if `clear` is `true` (default behavior). + * @param clear Whether it should clear the reset flag or not. + */ + bool didReset(bool clear = true) { + bool reset = resetFlag; + if (clear) + resetFlag = false; + return reset; + } + /** * @brief This method is called by the SERIAL interrupt handler. * \warning This is internal API! @@ -106,29 +169,66 @@ class LinkCube { if (isBitHigh(BIT_CMD_RESET)) { resetState(); - _LCLOG_("LinkCube: reset!"); + resetFlag = true; setBitHigh(BIT_CMD_RESET); } + if (isBitHigh(BIT_CMD_RECEIVE)) { - _LCLOG_("LinkCube: cmd receive!"); + newIncomingQueue.push(getData()); setBitHigh(BIT_CMD_RECEIVE); - // return; } + if (isBitHigh(BIT_CMD_SEND)) { - _LCLOG_("LinkCube: cmd send!"); + setPendingData(); setBitHigh(BIT_CMD_SEND); - // return; } + + copyState(); } private: - U32Queue incomingQueue; // TODO: SYNCHRONIZE? + U32Queue newIncomingQueue; + U32Queue incomingQueue; U32Queue outgoingQueue; + volatile bool resetFlag = false; + volatile bool needsClear = false; volatile bool isEnabled = false; + void copyState() { + if (incomingQueue.isReading()) + return; + + if (needsClear) { + incomingQueue.clear(); + needsClear = false; + } + + while (!newIncomingQueue.isEmpty()) + incomingQueue.push(newIncomingQueue.pop()); + } + void resetState() { - incomingQueue.syncClear(); + needsClear = false; + newIncomingQueue.clear(); + if (incomingQueue.isReading()) + needsClear = true; + else + incomingQueue.clear(); outgoingQueue.syncClear(); + resetFlag = false; + } + + void setPendingData() { + setData(outgoingQueue.isWriting() ? 0 : outgoingQueue.pop()); + } + + void setData(u32 data) { + Link::_REG_JOY_TRANS_H = msB32(data); + Link::_REG_JOY_TRANS_L = lsB32(data); + } + + u32 getData() { + return buildU32(Link::_REG_JOY_RECV_H, Link::_REG_JOY_RECV_L); } void stop() { @@ -154,16 +254,9 @@ class LinkCube { void setInterruptsOn() { setBitHigh(BIT_IRQ); } void setInterruptsOff() { setBitLow(BIT_IRQ); } - // TODO: REMOVE? - static u32 buildU32(u8 msB, u8 byte2, u8 byte3, u8 lsB) { - return ((msB & 0xFF) << 24) | ((byte2 & 0xFF) << 16) | - ((byte3 & 0xFF) << 8) | (lsB & 0xFF); - } - static u16 buildU16(u8 msB, u8 lsB) { return (msB << 8) | lsB; } - static u16 msB32(u32 value) { return value >> 16; } - static u16 lsB32(u32 value) { return value & 0xffff; } - static u8 msB16(u16 value) { return value >> 8; } - static u8 lsB16(u16 value) { return value & 0xff; } + u32 buildU32(u16 msB, u16 lsB) { return (msB << 16) | lsB; } + u16 msB32(u32 value) { return value >> 16; } + u16 lsB32(u32 value) { return value & 0xffff; } bool isBitHigh(u8 bit) { return (Link::_REG_JOYCNT >> bit) & 1; } void setBitHigh(u8 bit) { Link::_REG_JOYCNT |= 1 << bit; } void setBitLow(u8 bit) { Link::_REG_JOYCNT &= ~(1 << bit); } @@ -178,6 +271,4 @@ inline void LINK_CUBE_ISR_SERIAL() { linkCube->_onSerial(); } -#undef _LCLOG_ - #endif // LINK_CUBE_H diff --git a/lib/LinkUART.hpp b/lib/LinkUART.hpp index 4d9e18c..e139119 100644 --- a/lib/LinkUART.hpp +++ b/lib/LinkUART.hpp @@ -256,19 +256,7 @@ class LinkUART { /** * @brief Reads a byte. Returns 0 if nothing is found. */ - u8 read() { - LINK_UART_BARRIER; - incomingQueue.startReading(); - LINK_UART_BARRIER; - - u8 data = incomingQueue.pop(); - - LINK_UART_BARRIER; - incomingQueue.stopReading(); - LINK_UART_BARRIER; - - return data; - } + u8 read() { return incomingQueue.syncPop(); } /** * @brief Sends a `data` byte. diff --git a/lib/LinkWireless.hpp b/lib/LinkWireless.hpp index 009d95e..cc2ea48 100644 --- a/lib/LinkWireless.hpp +++ b/lib/LinkWireless.hpp @@ -67,9 +67,9 @@ * @brief Buffer size (how many incoming and outgoing messages the queues can * store at max). The default value is `30`, which seems fine for most games. * \warning This affects how much memory is allocated. With the default value, - * it's `960` bytes. There's a double-buffered incoming queue and a + * it's around `960` bytes. There's a double-buffered incoming queue and a * double-buffered outgoing queue (to avoid data races). - * \warning You can calculate the usage with `LINK_WIRELESS_QUEUE_SIZE * 32`. + * \warning You can approximate the usage with `LINK_WIRELESS_QUEUE_SIZE * 32`. */ #define LINK_WIRELESS_QUEUE_SIZE 30 diff --git a/lib/_link_common.hpp b/lib/_link_common.hpp index 4bd89e1..464d215 100644 --- a/lib/_link_common.hpp +++ b/lib/_link_common.hpp @@ -219,6 +219,19 @@ class Queue { } } + T syncPop() { + _isReading = true; + asm volatile("" ::: "memory"); + + auto value = pop(); + + asm volatile("" ::: "memory"); + _isReading = false; + asm volatile("" ::: "memory"); + + return value; + } + void syncClear() { if (_isReading) return; // (it will be cleared later anyway) @@ -230,8 +243,8 @@ class Queue { } u32 size() { return count; } - bool isEmpty() { return size() == 0; } - bool isFull() { return size() == Size; } + bool isEmpty() { return count == 0; } + bool isFull() { return count == Size; } bool isReading() { return _isReading; } bool isWriting() { return _isWriting; } bool canMutate() { return !_isReading && !_isWriting; }