From 9340ea20c6ff75b4b576c2bb5bf0819a66eecf88 Mon Sep 17 00:00:00 2001 From: Nico Date: Thu, 8 Jan 2015 17:44:04 +0100 Subject: [PATCH] Added Raw HID, made Custom reports more easy Also added a new picture and a keyboard + mouse report definition --- Readme.md | 2 + avr/boards.txt | 68 ++++++++++++++- avr/cores/hid/USB-Core/HID.cpp | 25 +++++- avr/cores/hid/USB-Core/HID.h | 60 +++++++++---- avr/cores/hid/USB-Core/Keyboard.h | 14 +++- avr/cores/hid/USB-Core/Mouse.h | 13 +++ avr/cores/hid/USB-Core/RawHID.cpp | 30 +++++++ avr/cores/hid/USB-Core/RawHID.h | 79 ++++++++++++++++++ avr/variants/leonardo_custom/pins_arduino.h | 52 +++++++++++- avr/variants/leonardo_gamepad/pins_arduino.h | 24 ++---- avr/variants/leonardo_hid/pins_arduino.h | 27 ++---- avr/variants/micro_custom/pins_arduino.h | 52 +++++++++++- avr/variants/micro_gamepad/pins_arduino.h | 24 ++---- avr/variants/micro_hid/pins_arduino.h | 27 ++---- .../HoodLoader1_API_Legacy.ino | 2 + hid-core.png | Bin 0 -> 34248 bytes 16 files changed, 405 insertions(+), 94 deletions(-) create mode 100644 avr/cores/hid/USB-Core/RawHID.cpp create mode 100644 avr/cores/hid/USB-Core/RawHID.h create mode 100644 hid-core.png diff --git a/Readme.md b/Readme.md index bf69280..5cf7295 100644 --- a/Readme.md +++ b/Readme.md @@ -46,6 +46,7 @@ Make sure you use Arduino IDE 1.5.8 or newer. You don't have to modify the origi At the moment you have to move the cores/hid folder into your Arduino installation *arduino-1.6.0/hardware/arduino/avr/cores/hid* because of a bug in the IDE. +![HID Folder Picture](hid-core.png) **Your sketchbook folder should look like this:** ![Installation Picture](installation.png) @@ -208,6 +209,7 @@ Version History * Added Keycode functions in Keyboard API * Inlined a lot of the HID API functions to save flash * Added Gamepad +* Added RawHID API (but RawHID itself isnt working still) * Added USB Wakeup support * Separated USB-Core in its own folder * Added HID Tables diff --git a/avr/boards.txt b/avr/boards.txt index d03c595..43f101d 100644 --- a/avr/boards.txt +++ b/avr/boards.txt @@ -100,4 +100,70 @@ microExtended.menu.usbcore.NO_USB=No USB functions microExtended.menu.usbcore.NO_USB.build.variant=micro_no_usb microExtended.menu.usbcore.NO_USB.build.core=arduino:hid -############################################################## \ No newline at end of file +############################################################## + +uno.name=Arduino Uno HID-Project + +uno.vid.0=0x2341 +uno.pid.0=0x0043 +uno.vid.1=0x2341 +uno.pid.1=0x0001 + +uno.upload.tool=arduino:avrdude +uno.upload.protocol=arduino +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 +uno.upload.speed=115200 + +uno.bootloader.tool=arduino:avrdude +uno.bootloader.low_fuses=0xFF +uno.bootloader.high_fuses=0xDE +uno.bootloader.extended_fuses=0x05 +uno.bootloader.unlock_bits=0x3F +uno.bootloader.lock_bits=0x0F +uno.bootloader.file=arduino:optiboot/optiboot_atmega328.hex + +uno.build.mcu=atmega328p +uno.build.f_cpu=16000000L +uno.build.board=AVR_UNO +uno.build.core=arduino:hid +uno.build.variant=arduino:standard + +############################################################## + + +mega.name=Arduino Mega 2560 HID-Project + +mega.vid.0=0x2341 +mega.pid.0=0x0010 +mega.vid.1=0x2341 +mega.pid.1=0x0042 + +mega.upload.tool=arduino:avrdude +mega.upload.maximum_data_size=8192 + +mega.bootloader.tool=arduino:avrdude +mega.bootloader.low_fuses=0xFF +mega.bootloader.unlock_bits=0x3F +mega.bootloader.lock_bits=0x0F + +mega.build.f_cpu=16000000L +mega.build.core=arduino:hid +mega.build.variant=arduino:mega +# default board may be overridden by the cpu menu +mega.build.board=AVR_MEGA2560 + +## Arduino Mega w/ ATmega2560 +## ------------------------- + +mega.upload.protocol=wiring +mega.upload.maximum_size=253952 +mega.upload.speed=115200 + +mega.bootloader.high_fuses=0xD8 +mega.bootloader.extended_fuses=0xFD +mega.bootloader.file=arduino:stk500v2/stk500boot_v2_mega2560.hex + +mega.build.mcu=atmega2560 +mega.build.board=AVR_MEGA2560 + diff --git a/avr/cores/hid/USB-Core/HID.cpp b/avr/cores/hid/USB-Core/HID.cpp index 587c016..dac5d61 100644 --- a/avr/cores/hid/USB-Core/HID.cpp +++ b/avr/cores/hid/USB-Core/HID.cpp @@ -54,7 +54,30 @@ const u8 _hidReportDescriptor[] = { #ifdef EXTERN_HID_REPORT EXTERN_HID_REPORT #else - DEFAULT_HID_REPORT + // use the hid descriptors of the selected hid devices +#ifdef HID_KEYBOARD_LEDS_ENABLE //TODO move keyboard below mouse? + HID_REPORT_KEYBOARD_LEDS(HID_REPORTID_KEYBOARD), +#elif defined(HID_KEYBOARD_KEYS_ENABLE) + HID_REPORT_KEYBOARD_KEYS(HID_REPORTID_KEYBOARD), +#endif +#if defined(HID_MOUSE_ENABLE) + HID_REPORT_MOUSE(HID_REPORTID_MOUSE), +#endif +#if defined(HID_MOUSE_ABSOLUTE_ENABLE) + HID_REPORT_MOUSE_ABSOLUTE(HID_REPORTID_MOUSE_ABSOLUTE), +#endif +#ifdef HID_RAWHID_ENABLE + HID_REPORT_RAWHID(HID_REPORTID_RAWHID), // not working at the moment +#endif +#ifdef HID_CONSUMER_ENABLE + HID_REPORT_CONSUMERCONTROL(HID_REPORTID_CONSUMERCONTROL), +#endif +#ifdef HID_SYSTEM_ENABLE + HID_REPORT_SYSTEMCONTROL(HID_REPORTID_SYSTEMCONTROL), +#endif +#ifdef HID_GAMEPAD_ENABLE + HID_REPORT_GAMEPAD(HID_REPORTID_GAMEPAD), +#endif #endif }; diff --git a/avr/cores/hid/USB-Core/HID.h b/avr/cores/hid/USB-Core/HID.h index 79a3fbe..020f2ec 100644 --- a/avr/cores/hid/USB-Core/HID.h +++ b/avr/cores/hid/USB-Core/HID.h @@ -48,6 +48,36 @@ THE SOFTWARE. // for the extern HID descriptors + settings #include "pins_arduino.h" +#ifndef EXTERN_HID_REPORT +// by default enable mouse + keyboard api +#define HID_MOUSE_ENABLE +#define HID_KEYBOARD_KEYS_ENABLE +#endif + +#ifdef HID_KEYBOARD_LEDS_ENABLE +// enable the Keyboard Led functions if the led report is selected +#define HID_KEYBOARD_LEDS_ENABLED +#endif + +#if defined(HID_MOUSE_ENABLE) || defined(HID_MOUSE_ABSOLUTE_ENABLE) +#define HID_MOUSE_API_ENABLE +#endif +#if defined(HID_KEYBOARD_LEDS_ENABLE) || defined(HID_KEYBOARD_KEYS_ENABLE) +#define HID_KEYBOARD_API_ENABLE +#endif +#ifdef HID_RAWHID_ENABLE +#define HID_RAWHID_API_ENABLE +#endif +#ifdef HID_CONSUMER_ENABLE +#define HID_CONSUMER_API_ENABLE +#endif +#ifdef HID_SYSTEM_ENABLE +#define HID_SYSTEM_API_ENABLE +#endif +#ifdef HID_GAMEPAD_ENABLE +#define HID_GAMEPAD_API_ENABLE +#endif + // extern accessible led out report #if defined(HID_KEYBOARD_LEDS_ENABLED) extern uint8_t hid_keyboard_leds; @@ -302,10 +332,18 @@ extern uint8_t hid_keyboard_leds; // note by NicoHood: RawHID might never work with multireports, because of OS problems // therefore we have to make it a single report with no idea. No other HID device will be supported then. +#ifndef RAWHID_USAGE_PAGE #define RAWHID_USAGE_PAGE 0xFFC0 // recommended: 0xFF00 to 0xFFFF +#endif +#ifndef RAWHID_USAGE #define RAWHID_USAGE 0x0C00 // recommended: 0x0100 to 0xFFFF +#endif +#ifndef RAWHID_TX_SIZE #define RAWHID_TX_SIZE (USB_EP_SIZE-1) +#endif +#ifndef RAWHID_RX_SIZE #define RAWHID_RX_SIZE (USB_EP_SIZE-1) +#endif #define LSB(_x) ((_x) & 0xFF) #define MSB(_x) ((_x) >> 8) @@ -331,18 +369,6 @@ extern uint8_t hid_keyboard_leds; 0xC0 /* end collection */ #endif -// default HID report descriptor -#ifdef HID_KEYBOARD_LEDS_ENABLED -#define DEFAULT_HID_REPORT \ -HID_REPORT_KEYBOARD_LEDS(HID_REPORTID_KEYBOARD), \ -HID_REPORT_MOUSE(HID_REPORTID_MOUSE) - -#else -#define DEFAULT_HID_REPORT \ -HID_REPORT_KEYBOARD_KEYS(HID_REPORTID_KEYBOARD), \ -HID_REPORT_MOUSE(HID_REPORTID_MOUSE) -#endif - #if defined(USBCON) #include "USBDesc.h" @@ -375,14 +401,10 @@ void HID_SendReport(uint8_t id, const void* data, int len); // include all HID APIs #define HID_MOUSE_API_ENABLE #define HID_KEYBOARD_API_ENABLE +#define HID_RAWHID_API_ENABLE #define HID_CONSUMER_API_ENABLE #define HID_SYSTEM_API_ENABLE #define HID_GAMEPAD_API_ENABLE - -#elif !defined(EXTERN_HID_REPORT) -// by default enable mouse + keyboard api -#define HID_MOUSE_API_ENABLE -#define HID_KEYBOARD_API_ENABLE #endif #ifdef USBCON @@ -395,6 +417,10 @@ void HID_SendReport(uint8_t id, const void* data, int len); #include "Keyboard.h" #endif +#ifdef HID_RAWHID_API_ENABLE +#include "RawHID.h" +#endif + #ifdef HID_CONSUMER_API_ENABLE #include "Consumer.h" #endif diff --git a/avr/cores/hid/USB-Core/Keyboard.h b/avr/cores/hid/USB-Core/Keyboard.h index 5f405a5..1bf159d 100644 --- a/avr/cores/hid/USB-Core/Keyboard.h +++ b/avr/cores/hid/USB-Core/Keyboard.h @@ -143,13 +143,25 @@ THE SOFTWARE. #define RAW_KEYBOARD_SCROLL_LOCK 0x47 #define RAW_KEYBOARD_PAUSE 0x48 +typedef union{ + // Low level key report: up to 6 keys and shift, ctrl etc at once + uint8_t whole8[8]; + uint16_t whole16[8 / 2]; + uint32_t whole32[8 / 4]; + struct{ + uint8_t modifiers; + uint8_t reserved; + uint8_t keys[6]; + }; +} HID_KeyboardReport_Data_t; + // Low level key report: up to 6 keys and shift, ctrl etc at once typedef struct { uint8_t modifiers; uint8_t reserved; uint8_t keys[6]; -} KeyReport; +} KeyReport; //TODO typedef union above class Keyboard_ : public Print { diff --git a/avr/cores/hid/USB-Core/Mouse.h b/avr/cores/hid/USB-Core/Mouse.h index 05e48c9..ce57999 100644 --- a/avr/cores/hid/USB-Core/Mouse.h +++ b/avr/cores/hid/USB-Core/Mouse.h @@ -59,6 +59,19 @@ THE SOFTWARE. // but the last 3 wont do anything from what I tested #define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE | MOUSE_PREV | MOUSE_NEXT) +typedef union{ + // mouse report: 8 buttons, position, wheel + uint8_t whole8[4]; + uint16_t whole16[4 / 2]; + uint32_t whole32[4 / 4]; + struct{ + uint8_t buttons; + int8_t xAxis; + int8_t yAxis; + int8_t wheel; + }; +} HID_MouseReport_Data_t; + class Mouse_ { private: diff --git a/avr/cores/hid/USB-Core/RawHID.cpp b/avr/cores/hid/USB-Core/RawHID.cpp new file mode 100644 index 0000000..b5a1687 --- /dev/null +++ b/avr/cores/hid/USB-Core/RawHID.cpp @@ -0,0 +1,30 @@ +/* +Copyright (c) 2014 NicoHood +See the readme for credit to other people. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "RawHID.h" + +//================================================================================ +// RawHID +//================================================================================ + +RawHID_ RawHID; \ No newline at end of file diff --git a/avr/cores/hid/USB-Core/RawHID.h b/avr/cores/hid/USB-Core/RawHID.h new file mode 100644 index 0000000..bd31630 --- /dev/null +++ b/avr/cores/hid/USB-Core/RawHID.h @@ -0,0 +1,79 @@ +/* +Copyright (c) 2014 NicoHood +See the readme for credit to other people. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef __RAWHIDAPI__ +#define __RAWHIDAPI__ + +// to access the HID_SendReport via USBAPI.h and report number +#include "Arduino.h" + +//================================================================================ +// RawHID +//================================================================================ + +typedef union{ +// a RAWHID_TX_SIZE byte buffer for rx or tx +uint8_t whole8[RAWHID_TX_SIZE]; +uint16_t whole16[RAWHID_TX_SIZE / 2]; +uint32_t whole32[RAWHID_TX_SIZE / 4]; +uint8_t buff[RAWHID_TX_SIZE]; +} HID_RawKeyboardReport_Data_t; + +class RawHID_ : public Print{ +public: + inline RawHID_(void){ + // empty + } + + inline void begin(void){ + // empty + } + + inline void end(void){ + // empty + } + + using Print::write; // to get the String version of write + inline size_t write(uint8_t b){ + write(&b, 1); + } + + inline size_t write(const uint8_t *buffer, size_t size){ + size_t bytesleft = size; + // first work through the buffer thats already there + while (bytesleft >= RAWHID_RX_SIZE){ + HID_SendReport(HID_REPORTID_RAWHID, &buffer[size - bytesleft], RAWHID_RX_SIZE); + bytesleft -= RAWHID_RX_SIZE; + } + // write down the other bytes and fill with zeros + if (bytesleft){ + uint8_t rest[RAWHID_RX_SIZE]; + memcpy(rest, &buffer[size - bytesleft], bytesleft); + memset(&rest[bytesleft], 0, RAWHID_RX_SIZE - bytesleft); + HID_SendReport(HID_REPORTID_RAWHID, &rest, RAWHID_RX_SIZE); + } + } +}; +extern RawHID_ RawHID; + +#endif \ No newline at end of file diff --git a/avr/variants/leonardo_custom/pins_arduino.h b/avr/variants/leonardo_custom/pins_arduino.h index 5fed3ae..c198ad0 100644 --- a/avr/variants/leonardo_custom/pins_arduino.h +++ b/avr/variants/leonardo_custom/pins_arduino.h @@ -28,20 +28,60 @@ THE SOFTWARE. // HID Settings //================================================================================ +/* +You have two options to enable/disbale hid functions: + +The nearly full automatic way which enables the specific hid report for you, +enables the specific hid api and also enables the keyboard led function if needed. + +The fully customizable variant where you can create your very own HID report. +You still can use the predefined hid reports or add you very own ones. +You have to enable the specific hid apis on your own then, also the keyboard led function. +*/ + +#define HID_AUTOMATIC +#define HID_CUSTOM_SETTINGS + +//================================================================================ +// Automatic +//================================================================================ + +#ifdef HID_AUTOMATIC +// pre selected hid reports with autoinclude of the api +#define HID_MOUSE_ENABLE // normal mouse with buttons + wheel +//#define HID_MOUSE_ABSOLUTE_ENABLE // only works with system and without gamepad +#define HID_KEYBOARD_LEDS_ENABLE // leds OR keys +//#define HID_KEYBOARD_KEYS_ENABLE +//#define HID_RAWHID_ENABLE // currently not working +//#define HID_CONSUMER_ENABLE +//#define HID_SYSTEM_ENABLE +//#define HID_GAMEPAD_ENABLE // only works without mouse absolute + +//================================================================================ +// Custom Settings +//================================================================================ + +#elif defined(HID_CUSTOM_SETTINGS) + +// default setting here shows a mouse + keyboard with no led function +// like in IDE 1.0.6/1.5.8 or lower + // use this to enable the Keyboard Led functions -#define HID_KEYBOARD_LEDS_ENABLED +//#define HID_KEYBOARD_LEDS_ENABLED // add your custom report here: #define EXTERN_HID_REPORT \ -HID_REPORT_KEYBOARD_LEDS(HID_REPORTID_KEYBOARD), \ +HID_REPORT_KEYBOARD_KEYS(HID_REPORTID_KEYBOARD), \ HID_REPORT_MOUSE(HID_REPORTID_MOUSE) // activate your custom HID-APIs here: #define HID_MOUSE_API_ENABLE #define HID_KEYBOARD_API_ENABLE +//#define HID_RAWHID_API_ENABLE //#define HID_CONSUMER_API_ENABLE //#define HID_SYSTEM_API_ENABLE //#define HID_GAMEPAD_API_ENABLE +//#define HID_ENABLE_ALL_APIS // enables all of the ones above /* You can use the pre defined reports as well. @@ -58,7 +98,11 @@ Currently available pre defined reports : //HID_REPORT_KEYBOARD_KEYS(HID_REPORTID_KEYBOARD), //HID_REPORT_MOUSE(HID_REPORTID_MOUSE), //HID_REPORT_MOUSE_ABSOLUTE(HID_REPORTID_MOUSE_ABSOLUTE), -////HID_REPORT_RAWHID(HID_REPORTID_RAWHID), // not working at the moment +//HID_REPORT_RAWHID(HID_REPORTID_RAWHID), //HID_REPORT_CONSUMERCONTROL(HID_REPORTID_CONSUMERCONTROL), //HID_REPORT_SYSTEMCONTROL(HID_REPORTID_SYSTEMCONTROL), -//HID_REPORT_GAMEPAD(HID_REPORTID_GAMEPAD), \ No newline at end of file +//HID_REPORT_GAMEPAD(HID_REPORTID_GAMEPAD), + +#else +#error Please select automatic or custom hid report in the pins_arduino.h! +#endif \ No newline at end of file diff --git a/avr/variants/leonardo_gamepad/pins_arduino.h b/avr/variants/leonardo_gamepad/pins_arduino.h index 738c80e..85a19e2 100644 --- a/avr/variants/leonardo_gamepad/pins_arduino.h +++ b/avr/variants/leonardo_gamepad/pins_arduino.h @@ -28,18 +28,12 @@ THE SOFTWARE. // HID Settings //================================================================================ -// use this to enable the Keyboard Led functions -#define HID_KEYBOARD_LEDS_ENABLED - -#define GAMEPAD_HID_REPORT \ -HID_REPORT_KEYBOARD_LEDS(HID_REPORTID_KEYBOARD), \ -HID_REPORT_MOUSE(HID_REPORTID_MOUSE), \ -HID_REPORT_GAMEPAD(HID_REPORTID_GAMEPAD) - -// add your custom report here: -#define EXTERN_HID_REPORT GAMEPAD_HID_REPORT - -// activate your custom HID-APIs here: -#define HID_MOUSE_API_ENABLE -#define HID_KEYBOARD_API_ENABLE -#define HID_GAMEPAD_API_ENABLE \ No newline at end of file +// pre selected hid reports with autoinclude of the api +#define HID_MOUSE_ENABLE // normal mouse with buttons + wheel +//#define HID_MOUSE_ABSOLUTE_ENABLE // only works with system and without gamepad +#define HID_KEYBOARD_LEDS_ENABLE // leds OR keys +//#define HID_KEYBOARD_KEYS_ENABLE +//#define HID_RAWHID_ENABLE // currently not working +//#define HID_CONSUMER_ENABLE +//#define HID_SYSTEM_ENABLE +#define HID_GAMEPAD_ENABLE // only works without mouse absolute diff --git a/avr/variants/leonardo_hid/pins_arduino.h b/avr/variants/leonardo_hid/pins_arduino.h index 4d8fbc4..22545bf 100644 --- a/avr/variants/leonardo_hid/pins_arduino.h +++ b/avr/variants/leonardo_hid/pins_arduino.h @@ -28,21 +28,12 @@ THE SOFTWARE. // HID Settings //================================================================================ -// use this to enable the Keyboard Led functions -#define HID_KEYBOARD_LEDS_ENABLED - -#define EXTENDED_HID_REPORT \ -HID_REPORT_KEYBOARD_LEDS(HID_REPORTID_KEYBOARD), \ -HID_REPORT_MOUSE(HID_REPORTID_MOUSE), \ -HID_REPORT_MOUSE_ABSOLUTE(HID_REPORTID_MOUSE_ABSOLUTE), \ -HID_REPORT_CONSUMERCONTROL(HID_REPORTID_CONSUMERCONTROL), \ -HID_REPORT_SYSTEMCONTROL(HID_REPORTID_SYSTEMCONTROL) - -// add your custom report here: -#define EXTERN_HID_REPORT EXTENDED_HID_REPORT - -// activate your custom HID-APIs here: -#define HID_MOUSE_API_ENABLE -#define HID_KEYBOARD_API_ENABLE -#define HID_CONSUMER_API_ENABLE -#define HID_SYSTEM_API_ENABLE +// pre selected hid reports with autoinclude of the api +#define HID_MOUSE_ENABLE // normal mouse with buttons + wheel +#define HID_MOUSE_ABSOLUTE_ENABLE // only works with system and without gamepad +#define HID_KEYBOARD_LEDS_ENABLE // leds OR keys +//#define HID_KEYBOARD_KEYS_ENABLE +//#define HID_RAWHID_ENABLE // currently not working +#define HID_CONSUMER_ENABLE +#define HID_SYSTEM_ENABLE +//#define HID_GAMEPAD_ENABLE // only works without mouse absolute diff --git a/avr/variants/micro_custom/pins_arduino.h b/avr/variants/micro_custom/pins_arduino.h index 4e7ff4c..1b6241f 100644 --- a/avr/variants/micro_custom/pins_arduino.h +++ b/avr/variants/micro_custom/pins_arduino.h @@ -28,20 +28,60 @@ THE SOFTWARE. // HID Settings //================================================================================ +/* +You have two options to enable/disbale hid functions: + +The nearly full automatic way which enables the specific hid report for you, +enables the specific hid api and also enables the keyboard led function if needed. + +The fully customizable variant where you can create your very own HID report. +You still can use the predefined hid reports or add you very own ones. +You have to enable the specific hid apis on your own then, also the keyboard led function. +*/ + +#define HID_AUTOMATIC +#define HID_CUSTOM_SETTINGS + +//================================================================================ +// Automatic +//================================================================================ + +#ifdef HID_AUTOMATIC +// pre selected hid reports with autoinclude of the api +#define HID_MOUSE_ENABLE // normal mouse with buttons + wheel +//#define HID_MOUSE_ABSOLUTE_ENABLE // only works with system and without gamepad +#define HID_KEYBOARD_LEDS_ENABLE // leds OR keys +//#define HID_KEYBOARD_KEYS_ENABLE +//#define HID_RAWHID_ENABLE // currently not working +//#define HID_CONSUMER_ENABLE +//#define HID_SYSTEM_ENABLE +//#define HID_GAMEPAD_ENABLE // only works without mouse absolute + +//================================================================================ +// Custom Settings +//================================================================================ + +#elif defined(HID_CUSTOM_SETTINGS) + +// default setting here shows a mouse + keyboard with no led function +// like in IDE 1.0.6/1.5.8 or lower + // use this to enable the Keyboard Led functions -#define HID_KEYBOARD_LEDS_ENABLED +//#define HID_KEYBOARD_LEDS_ENABLED // add your custom report here: #define EXTERN_HID_REPORT \ -HID_REPORT_KEYBOARD_LEDS(HID_REPORTID_KEYBOARD), \ +HID_REPORT_KEYBOARD_KEYS(HID_REPORTID_KEYBOARD), \ HID_REPORT_MOUSE(HID_REPORTID_MOUSE) // activate your custom HID-APIs here: #define HID_MOUSE_API_ENABLE #define HID_KEYBOARD_API_ENABLE +//#define HID_RAWHID_API_ENABLE //#define HID_CONSUMER_API_ENABLE //#define HID_SYSTEM_API_ENABLE //#define HID_GAMEPAD_API_ENABLE +//#define HID_ENABLE_ALL_APIS // enables all of the ones above /* You can use the pre defined reports as well. @@ -58,7 +98,11 @@ Currently available pre defined reports : //HID_REPORT_KEYBOARD_KEYS(HID_REPORTID_KEYBOARD), //HID_REPORT_MOUSE(HID_REPORTID_MOUSE), //HID_REPORT_MOUSE_ABSOLUTE(HID_REPORTID_MOUSE_ABSOLUTE), -////HID_REPORT_RAWHID(HID_REPORTID_RAWHID), // not working at the moment +//HID_REPORT_RAWHID(HID_REPORTID_RAWHID), //HID_REPORT_CONSUMERCONTROL(HID_REPORTID_CONSUMERCONTROL), //HID_REPORT_SYSTEMCONTROL(HID_REPORTID_SYSTEMCONTROL), -//HID_REPORT_GAMEPAD(HID_REPORTID_GAMEPAD), \ No newline at end of file +//HID_REPORT_GAMEPAD(HID_REPORTID_GAMEPAD), + +#else +#error Please select automatic or custom hid report in the pins_arduino.h! +#endif \ No newline at end of file diff --git a/avr/variants/micro_gamepad/pins_arduino.h b/avr/variants/micro_gamepad/pins_arduino.h index 54a65b7..18a3497 100644 --- a/avr/variants/micro_gamepad/pins_arduino.h +++ b/avr/variants/micro_gamepad/pins_arduino.h @@ -28,18 +28,12 @@ THE SOFTWARE. // HID Settings //================================================================================ -// use this to enable the Keyboard Led functions -#define HID_KEYBOARD_LEDS_ENABLED - -#define GAMEPAD_HID_REPORT \ -HID_REPORT_KEYBOARD_LEDS(HID_REPORTID_KEYBOARD), \ -HID_REPORT_MOUSE(HID_REPORTID_MOUSE), \ -HID_REPORT_GAMEPAD(HID_REPORTID_GAMEPAD) - -// add your custom report here: -#define EXTERN_HID_REPORT GAMEPAD_HID_REPORT - -// activate your custom HID-APIs here: -#define HID_MOUSE_API_ENABLE -#define HID_KEYBOARD_API_ENABLE -#define HID_GAMEPAD_API_ENABLE \ No newline at end of file +// pre selected hid reports with autoinclude of the api +#define HID_MOUSE_ENABLE // normal mouse with buttons + wheel +//#define HID_MOUSE_ABSOLUTE_ENABLE // only works with system and without gamepad +#define HID_KEYBOARD_LEDS_ENABLE // leds OR keys +//#define HID_KEYBOARD_KEYS_ENABLE +//#define HID_RAWHID_ENABLE // currently not working +//#define HID_CONSUMER_ENABLE +//#define HID_SYSTEM_ENABLE +#define HID_GAMEPAD_ENABLE // only works without mouse absolute diff --git a/avr/variants/micro_hid/pins_arduino.h b/avr/variants/micro_hid/pins_arduino.h index b687abd..18ec7e1 100644 --- a/avr/variants/micro_hid/pins_arduino.h +++ b/avr/variants/micro_hid/pins_arduino.h @@ -28,21 +28,12 @@ THE SOFTWARE. // HID Settings //================================================================================ -// use this to enable the Keyboard Led functions -#define HID_KEYBOARD_LEDS_ENABLED - -#define EXTENDED_HID_REPORT \ -HID_REPORT_KEYBOARD_LEDS(HID_REPORTID_KEYBOARD), \ -HID_REPORT_MOUSE(HID_REPORTID_MOUSE), \ -HID_REPORT_MOUSE_ABSOLUTE(HID_REPORTID_MOUSE_ABSOLUTE), \ -HID_REPORT_CONSUMERCONTROL(HID_REPORTID_CONSUMERCONTROL), \ -HID_REPORT_SYSTEMCONTROL(HID_REPORTID_SYSTEMCONTROL) - -// add your custom report here: -#define EXTERN_HID_REPORT EXTENDED_HID_REPORT - -// activate your custom HID-APIs here: -#define HID_MOUSE_API_ENABLE -#define HID_KEYBOARD_API_ENABLE -#define HID_CONSUMER_API_ENABLE -#define HID_SYSTEM_API_ENABLE \ No newline at end of file +// pre selected hid reports with autoinclude of the api +#define HID_MOUSE_ENABLE // normal mouse with buttons + wheel +#define HID_MOUSE_ABSOLUTE_ENABLE // only works with system and without gamepad +#define HID_KEYBOARD_LEDS_ENABLE // leds OR keys +//#define HID_KEYBOARD_KEYS_ENABLE +//#define HID_RAWHID_ENABLE // currently not working +#define HID_CONSUMER_ENABLE +#define HID_SYSTEM_ENABLE +//#define HID_GAMEPAD_ENABLE // only works without mouse absolute diff --git a/examples/Projects/HoodLoader1_API_Legacy/HoodLoader1_API_Legacy.ino b/examples/Projects/HoodLoader1_API_Legacy/HoodLoader1_API_Legacy.ino index 546a413..b8f4fe9 100644 --- a/examples/Projects/HoodLoader1_API_Legacy/HoodLoader1_API_Legacy.ino +++ b/examples/Projects/HoodLoader1_API_Legacy/HoodLoader1_API_Legacy.ino @@ -27,6 +27,8 @@ See official documentation for more infos */ +#include "USB-Core/Keyboard.h" + // Serial to write Protocol data to. Default: Serial #define HID_SERIAL Serial #define SERIAL_HID_BAUD 115200 diff --git a/hid-core.png b/hid-core.png new file mode 100644 index 0000000000000000000000000000000000000000..4d3d0ce7c2641f710307c621b3e60bbcc31c874a GIT binary patch literal 34248 zcmbTdby$>r`aVn#Ih3SBg8@i)H%Ll%ry|`sz>p#+AdRHbjfC_N0)m7f4MTT#^A7m9 z_1o|69`7F<;~@7Zt~k%D?uZx4vN)LJmN)z!R*l2Ahd>sF=az{^}oTYrS{5I?js+0Q` zg;PMznNze{GVFY7zqUX%M<$A#`_&;V36g3gDu4Iyk$g*w%as_}pIKzqs8Jxr``>Xi zlCdaia`t1A^C$iO8&6Jyq(ZASA}(jPyJu8;_pIvJG=K0h*({mdea}gl|KVs_nBt^0 z*bTk=F7vECb-qo5d$BmP({WF1|I$NX7Q_`P1+v?eWVQZfsl(3A z%8!~YV{(T3C!;1o)uPdFVv1A#T0q)u@1d-$_la_JdRlrT+0GOUR#{bHHr&yDz8)bl z^sSwLJLJ|vt8-%Ze6=>`3*qe%6CKQ6xRa>?OWT8_bmP16L~?ER;wDwC-?6B^3zZ%J zVNR~7kQ#UaaGX)fE`N92s7Z;}Po~gGdkV=|Tpc*m*6>f^*Zo3z3hjfM=VkrqQxvyt zYTWVeNf-(=S6}psGdETW9&pvV>Uc7wKj6UHymu>%)*U+mP1o_B;xPSsv9ka7pXO-3yh z43IQmh$oeFy4SF?W9`md!NtNaZI;IA{cWrAUAeWvkEv9(@g=?@ zP<(Mw`X-k~jy^e-zmkcc^?n0p24Qc{p3PsR?P~iSR&D%jBAl-x^tf^KSaaPbQFt4R zlG>XQNnS0b_W&UK5^il|Ftr5}n+Pn@J7Y8BJ5wH`q?y}~Aw11(uRedLnQjczx?vpm zsM~}DYE7pbmC$sB0=nnxwZnpl*^RP9?In>Z zy?XpD!NEpBjax0B^Uz$F9dDtAiw9f7KI)zi)3 zw4tq)b9(U@Veb*dR(32md!QpfOCmOhzsb40R>jQ0CS!S9uV9k@f-epZAe#;@>B2^x07Iw~?_>c8|X7Z=VFljAYWb;0X!ig#q znK*j2CoDdd+>%UrY4K`lEUx`l!0EDSgLS9n>K9Y|s&U}$lWF_&39-ZU&??d9i&Q`q zW0T)wbUImwdx-@@;=Q58j_Be;+Q898$6;(AJpLrTdhV4e>bG27p`G|_v6`F)YqNDO zem|?}cJ7db9V9f^sD$oWzABc#-Na;_kdUr7q*JFgURy=W^Z=9lK?(PrWXtQ8Efu3x zoR1IOJRqpfE*iU_%@mfllg+w_z*1IhEjlg_fWmqukBF0p zFKBA;SL`U*`>6ktNdR`G`ss3RB@WEZe#Yt{DN5Dw)%KI^R6OkZS7)59LW^(Z>70K=#MO z)DHoIMYRbT-kD2lKkE;Bq0J>EiM0=&Ap^#Uqp*>hFAMGD^NCk#4!&?=%m(I%a}8dY!ku$3eE`CU+r0dp{k2vAMX8x=kKyg-_ZULpwDE?Bv|q3tP0?erjK@F z$D)I2XK6nib)_j2|7r(lwSjsV{Vt?I-y!{MP1yqr{cI(%W!--hjJ;(rdNqmr&^Yoe zH|f~;s?%oR#Ib8-K0!N-oHqe{G;=lJuXA*cJJsw}yuBdWS~fTL{oU8kl8OlW@r;2IYF zh&%)LlAt8I!76~$GCRB9eliB$Th0Y@6&|@Sc4vf5-M*|l zUxtQ~*pG>**W3;q07VVX)?u~8!jpPOIW-RcSMsX*owB!``IV`Ij*5tqbO80#&6Nd{ zp)fAFP!alD_NGU0h|B!LsqCO>t@B0#N56f}xw-82({-Rdqvxj;4FV$)ztf$y@$t3s zJ+Z@0QS#Z_j=@VNeIsLcmnmEym}lMUVunPt>gU=NNf^beiyo617i4agQ)7LXb%^L! z$2Dk>3YGmcBOsDJtKs!D)y8*R-?4nm*DOe(GQeD(u^&TFTBSx>jSe`f{F9*8M>gH0 zi);_HN0&+pd-RckEPPjv#}mud=S6cTwJU9l+lOwnqDJhgz-ywX>d?%ki=@uX=L?>n`F%8~n^?T92!19)E%VeDZIOx z8Ed(k|6FowaJ%C0HccwUvAloqbCpsV%clQzR&?S`>8Xb(M9vkUeSL9Ta=leXt~@>F zd=eOqg-djEC7R~FI&iahc&oO*3I7@L=*7LV#&cX|y`9bfP0b@}Q)Ysmr4P?E9d?_p z`}3&$Vo!U8$H4VB8~r5xO}8%iyoEW{zP5*pL5~Pet*B}kw1Y}PC^P?HTR*xh}!U9u~n4bD?KSd z#(?*``{)cFeHB}I661=# z&sS%f3C_mY&wu}CprVQjtib~pmk++8P`Kjr!*T+=>6;-Y-}V4x&=+xu{-wlm7| zSE7P2)EpB_C-j%J#%u$?X!^+!fjXN@u-}5mEFsb&+jRh;REJmYE=GH@9c!Bi^1ui- zA&U4XbO}HltqGsp7x?AOY+hs9ha6KAJF0D(5DkT84t$-> zxBNEK0kS6rDj0uepY%Ts_VRw|+vYzN>w^&_XT3Aq1fRa&N?^E)+Padq2-IVb#Dn(LD+uR(dts^t%pBkyjdsxMzJ8T6kGe`B)r8e|-JD&EUqv<1inEDd`1!YegRxN!p zjs9(9V06!G!Q4kT+4YAMtks?JBl zJvaZ7F~6%}+DQ>7<-uoWYWiz-0D8kKt%X(AXkG1xrrmLB*8RyD>Zl_JH|eLf1sS2I z9=czyF#;ZYO~7^H(sy>|X=%wYeMvbd1^}9igri{t#36G7{T^iEHnhg?LxDWbRug*z ztHBjLMUuky0AxYR{M4^OWg*si%B`?de6m@k#Y|tN*)6e1lIo4 zSgf2%jc#U-4?`v<*Fp-V2FiZ(R~k*to7ytbYkJhHwOfsQ(V>v5+0Xp&<~;3%JlQnqN)ko?;wXtU0jKq7tI8x1i%_yMR!!*F;n4 z@AN|k!w5~7%usr>K36GvA+1fAo_bdCS(hiR9its()^sF&##F7N_&nel$q(p4DWSlM z7t*13p<>PfltcF8^VXMZJ%g}jLl<6gybfRXA5di8Bi^2%N3*$-V{A>bvefly2-ok) z-sZ?k!FJH|(1Q_H5gah8!=2hTilzEb0uE7D<~4|3KeJn31DjuUG>K05rcuE?)p?Nn z%G7B$c@ueqTel_v(U}eIY2x%z1Q&g1HfO7JcV6ro0#dwlkAlGesh>ng%!#JV| zGRJV-oo#CH*o~IY#Ki|G_<(Nh(9J4hI#_YK3f3ZHlIYZS=hoNP8yg!-^lNt}s#aSA zkuOho!;E3zTfgu$5kGGm8}!2k3uoubva+(8nwpA=ih=@+Mqo=D4I3Lsjwfoo~LrekS;kiAU*eT1NVl2X;bf!|F|hE*P}KGyp;}Nk$6n)7;GQ zg#|MqAksAUX;&hPVVgMs4FGVMu0t&CT%?xBdg11F+}({%na6O^g5$C`{?dk%Q+-g6 zwXDIY($aNqe8h8hXD| zCU17%)>CWV1d$j!?@==b0$0e>U)CRKXx?lZYS#w(b%m)!&xlMKHLF?>NPSzZvs+$X zHf7~lGNG;h)CZ;V-Gi=XfTIBfb(=(U6(}0l{eru2yk2xd*_mn3Ha5m}?li}kCdAs) z`8hi~J2DasI7Axv!0M827Xf%|0@Djwjr^9|dMRM`XqVB!z?rY-PWltxiVU%s2Fl>8 zF0g^7W=I!^@2d9p1V#>RRWxI9oUW;HfThR9K>+x2Zy=_<-hqcJsSb~p*U1$tT~_-` zOId_Y2>CF>9JS3+at0*(@FgWBjeYk!jexG%Ern0Hf%dkxkX}m@6NGpCnGEPifxKNU zXPvBOJN70M4|(n90?}Sa!<^?5$R$B_7@>3HiVUIJIBC9G#pjKn={$b?^+^FIs*$cCpaRRb&n1J@PJU zF*1s|d~LffQ@$&9xbxy#AD-FUb5nfVaz(mPsz|irODE;$!-=T0^E>>(>v)NEbyC|h zQ)Bn=iit|t`$1Qb+%(jY5L;i}xur-NXjIpFdv4-DQrof+N(y`j;ty&kE^ylGq5>B; zXknZk4v4P4%N8D~GFy|B_|P?U3fH{%aiRAdHVGB@YHMhA*4~!%M2U@;Qc5N*9WnYV z^kV}vGR{>wg~gs62B zRd))vZF75I|JvFb?CJ+BP2@*2E)JYE1O)_Id6~3|&vHaBa^!Az@jDC@Xov|m-z>LU z->$%}9tzV6<&A1$EDWa8U`9WFq$T9Jm#Jd|hZ)8vu0{RxQM|L%fXC6-@62Rr?ezC< zU%u#X*llJaaNind#~sKvE%Jg(=+XH$ij$oB&~%d~4tqti|{f+%=)59{`(iadFzE2CA|4Ha2+QaHL+6PGf6kQ&BjH zV7?W|aqaCWI+lKn2Nz$aS1R6~$w1(XDIe{A=4Zmy*%gi@REGe<=IyvD zVou_BW_$gS_Qwn~fR6#;oi!?_qsB4g5jgcfB*ftCi?+w?Q}6uyy+tvpiTpXwDQJk2 zu2gQ1ROYqkD!M3hh{X?=mmMx=;7yih@;x}&|>RLf$h!15ph1>9Ya^%4&Lu1 zx!T`!yby`J*(fU86B}l8ZLJna!oRJuL4X%eBDqkoryIS7mvz4&^&|RJg)s5i17M96 z&oSz%ylu}50P@i+C4w!WttoFOFNGnFGs#~>QjMrf;0DhXZ&AE*^g5JBDAfTb!5U(( zG5K6iqjZ3+i|F~%`{O^LG7$*s(eBM6g{P>2IfcmYA?m2FQCrS` zILw(5UN)MTHa=1qV+*|!yVCCQR7!|pb13Uk3kMSkg}=FR7*@Z2L*Qt;Y-{;A;Q{z$ zF3P31wfP6CLRLwiU42XoW)%bv+~f{J+hU+>3Q`_XnQJXmNMQC_ijnOw&TMeVF8ds? zoGls|x=fv2#zb&LfO?rBQQTnKMaZf3z^_SiAbS;QzYKY&#&n{$VNp-EtCj$1P&v$r|HNs?+)e+Hg*#%l!(Dz%c+q?mOTavM=E1D z4%dNi{l{lT7aQ9Hl|OXVioF71PeQPUJR_Ws5@iND2OiBd`H%#`69`Ws*1mq|N6m-v z0jcu5A1GQ{&bnhKtNNO=g+15w>}KWrl(DlU>*B9=JX)}3iNM>m`OQ;>sZRy=aNjiP zpl9r_eqXVz{4n*_O%sXQ{)05tN}ys4Ax0PBu(pPua6a+pF$;#oC%0lTHE>q2-=3<) z)%fHuh92xX*NT|L=xB{V;8E_F?%B^wDTtgYe9T84)K)ndHheh-zScHOrZvt$IVyNZ zo-8((PpL7`w9c)27)r1wOXc?~~pXH^pL5 z7tl@|A(%uRfGc|S0$t~pxDe~9%ii1^weLqM?}Osukr9;Son1`~i4cS0xM>u{+j4jywL@|_K4Ne;oV-hmY9QOAFYx9?+;$|XY(_mgohBCB4D{j9p|L%X!s z0W`~#j9T*`#Ccp^3ifkgLvT z*e|#T12~r4h@!70CMHH|^H09ZH75Xu*}i(Er>_s~8lF@r=q$>aPpEHho?UjKP{Z<@ zAe5qpM?~gw6_7x9B@7-SU2j>7BF_{K?1hOqUL36tP56IjUDNUny{)z#OIfl$lcW;( zcBzr~?8s6DFYrAi;w{ZF99<$DX6jLc9*7yYfIo7xZFh8_gc~6EfppLZ6NSZ5;F&i^ zsH+p3De^53ig+LQ*)cJZB11So0&8Xd{~m<@UqO4s2X@lOFE}DqSZTsL6&0xbdinqx zyJQ|r*6=9!d#mjr*%KN7EA`DqPhy4aC!q7*)q5IXv*C4QpzY-a<7~Z`mx9B(s0X;J z;BbLyJA}1nrOe^{f@9G^dq*4_OVv zc5=Lp|2Q9Qd}=)9xA{F9nt+>H)+EaAZR(x<;!A_1am~`uZ80aH5$$6jf%9I_T+7Yb z`D6e1s>Por#s)yYBp3V~DMo6*0B-W)Tu;UD;5U2lEUdh2y{H&Q<-a>U5l6yea0Z88 zXBQV2XXoatgWkeIMrLYa4o@5bWQL`=qt)hL58cxnJxhhJ!gA*qq8)WlIhEHCVdr>A8sRIz8bwNs`mvBR{IL z`a!;>`}c*UJRCpRJ^KMNI6v_`I~(5{8k&-A%Yyw%H;T!)Y*;9Z_8sOqH0`m_JspqQ zn}M61-^F^K&KxqRxUbhQEuIee6XALq9i>bhr%nyka|<93FQ?#>EX|$Myn#5WN0yg- zPJ}pUHgfYEb#`y7>;?mY$Ns+8BexGup$#qR=P;v;bHA>>!ZtF;y)4PF^42hz3(jS8 zq71O3{3Hk6z{x~MA%adkL)=L;E)wCF$$gto7bRi zq4YTzEn@9^L$`&^yXv+EwfVFaDG&>B5{xs^plbs89v+Ow1h#wFU%Tg@j@1g@R$rXG z>+o}wzU^~p{`j;}_|WLtle5{!8NNZNBG>~j39JmIhAT;y#hVO{y&eMyX_S6>GLa33 z$NHTaq~(cAwW;+5Nn;s7K#daT+;4<8y+dL9dbfWOMi%I69cGjq|!Syv= zAPo2Bhl4-e!SxyeYSP9hgU{PKic6lt5k{pK1{qq~scJ>vdlrP#^UxqamnN9q_sEw> zwey^w1jM3HTuDpMdY_3_Q{E+gQ4mOH$!d&(rwN;b@uL%oDjfk!;}KQRTL6Ad^^vpV zz-L~x2GOlu&s(kD=2RS?Qr~?)C#vZz#FtclM={-}IbP9-3Cm&MJ3(BTqTNHinxbs^ z#}h*2ufOXY?h(XSBtdQ8n;WONqsSAuIS%xFzTW6bJzd5W_hkw5K=wrs{sGw&-H&Dk z(-1V~xxbzw(2U_>4U!Y4$Z8lrG_5P##X1k~zO6=hd13mYSEQ7cY!w8IXM+=l__pAvtt$E-LzHFI(b>rpGzOyq~+j6~?)p|L1eR&$` zD_VcW)!Y9SviLC!D*alEg=df46-^#a)h}eTaQAm5#1p}?n5X!oB*rItcAfYRi8SF{ zIkway0EMG6)OfPx%CM{?V-9DGTt#kvw69fBMAgek5KmxWTp#amtoqpt{n*KR%Duf^ z0{f+TsMS^dgD67;&y(s33ZM%26%D=mF#n}FPjU26S9R=ZQTYtn_^BF0%+D)bUt!KK z-S;r}JQQ-?9B|t;Mtde|ySXV;UUvO1y*eDGKo|aC*u@9rBXU$kjsWOwe`1U^#Nw04 zO13*nwo{YLO+&iZMAMLSyzPRXZqcj?9;nmjk23<=v-(!#*~^X{+ih##eyu*JK4@1! z+J)SeEMj)U)?X~trq*q8EgCiF8absAE%l@OIXJVcI+7o;A^IS&G}u7zu=ja1WFLHe zp#)q4@1zUJS;lOrg_8t+x;kL$}Pn<#klF5Yrl-$fV3zSJ%B+Rb?d| zsIplEAwB-f8u~vaLiAa#%ojtfH=2!n7B?R|ED7tn?>PXke6MA9?XPCKL@$?G)3>f0 zL~h1B{IBQBzW4T41n6|naj#*2p#K4FX4Q7r?@PC}6R8~A7a;;&i#3W2pCU>Oc zt~_h>_A@3q84L1_PpIprGdgkd>#?5rU&IDLFwEFFgm^-P%~;^NBicup((~p|($PS#s)tjA zNlgdp zn+6srpL!a-01wjA zJNaZ^--9osy_=dHohe#(s<6fDp#KpO^-r?<8$Oc*xZn(M8G08o z-X510O|>>JwmiHz4P+}4d~w%Ep#3O*ck9WZ|IqC38tE=qQFOd0M!C)* zVIE)QlA>go#83zKp`V}*5> zByx-suRvX0cP)z$iLB7<>Lk0x0_{XL zIgPJz#~~bFCAoXOdt~0nn?z}EAD>ATrtSSPKX~t9u++Y_rsh2e^lH2qWqPW-;owLz zF z(eR(GL@CL)e*C51t0Mfu+4bej`LYRYG_qI!O+p}K6LZw01|xq^Y^F*+A{Mera%Xn* z;(%fO5_}Z)yx%5E!(W$oLBudO`hD!XGV{}$E$GA5gh0PktON=D}wLvR*5-mZ0i-t?+>y|AlOlFxjMSW#gPjWhGZHIR!XFFfB(0gYf>8 z&`T5VBJLpSl?T5qogPrDDN=@FV0?wmSGTt3R}V?WqtHg2JbUZ1eu9P@OBfhww#mjdmdwILnTAe2F(ZOyF%G@hPBii^QnAv<(>p#jBXtV-+i0RQ6H% ztN#9JBlc_wBb2=|0;fsO&@YmK>1F*`FCMo+R*KCiVLgw4e+)LTr{VgVVwGIJ_5=9* zI`VPGt3m-Dk=T(IQ8P;XJ5M8UbwqNgCWb;UPA?yxY?})|j^+4PYgqxN$`AMnI~q+3aEcj_H7CTKe-hBE1x;G`vtDRn zq$h9|(QLkJrDfDT)_p8E#cHaBc`F)Tx3(qrPZ;_<2&g<)GD^#r*m8nvTBJ5&NXMzk5Kf+A_blAC=CcoWisSttR$5PMO z^(`kpzHLy)zg?cIisMM~OLnfJw8hXx(=*d*opvjt=gj%KGn;4w;&`QN%1Cb|1MLd} zP`I~NOhQCT0zsH^>=Mn~3`Rh8UUzo%miYpcm#yR&L3fDD?aUU#@ecx7|B3om@&Wr; z9?vJCHz^5PR$=1aCtar5nHbzbE7a)LLJaJ*LVL$tmXBMF0#StQHZ=k)l#p;0`$w0_L?;t%k6GG@! z#LbqaMze`Uw6Znq*4u?+$w+l+s%|52Y^44Sl5Ss(;Uy7FhCyq@l_QNu9$6$PCoGJwCRBV5+np>EHEYw)n4gWG<~K+MfD|3Ll3w2X1cm@#OsyWF zmXr{Vb0X%8bUpfdmg@6HDb{=+?Nr&a1CTOa6#{m!J4)8MaF0?az7t*G#0zBMN0G$^ z8m(zs?c_lL>}6&08CqRT!-J3uDu%!9@_q-h9)-qv&+UJKk`$h*KeHSjXQ0^cgHTiS zal?;NH}~5+{D_qts%7vx4DMA}jk-KH(K2LWa7J}aR{l6pm5NQEjZz0q^!bN(93`5x zK&eLujOzh^2@LT!ngIWx$>Tj4h!g%V=<@)uMN=&m&Ica%?SeTc&$CX22Y z@paT6OKdw1q8s$#D zBmN>k`F|YCIjIVzO)F(Zu~QcV5t^x*D>2}OX9-|_GUyf#5jjc%3k5+e`&vq61{q&M z{xyR5Erxu3`SreCwv2`1-~f}sd{_ux6mx5)xUkh*+pq%*8hVx1|NC)T2d*`Y$aVQ6 zuCNM`?{A`P3vAeU>@~=i8J{T7daEKNzZywbC+ZF7P5p>nZt9ka$gkQ@)A{ctvKoap z(VO%-Y@d#O2i|JNI!Kf!)Aas2nz$)vEsG@o8eqH3myaW^O*Iro>O8K1Kn<@yp$8>B z{=>v~Ms9k)@N=iVe6&z_r#2Sx4_5!(GUC zXYqp@FrLeh&HbtW7KvL>f|y&8a5lLerlI@?pZ#qX#n^qyh8I7_VEv#L?|YhF>dSc8 zHXSXJ_0k-~gxH!U=aLc^{?vB@3B6)UZMXlyMjz_o@c`OCN9=u_ zRW?Io4^b+p5iE7reU;5Rl>v28MKK;IE(@Atx{Q z^1N3sEMV|Pcw|z~qXO8g)B)bXzA0*YK($QTKVN}<9bP~8YZAv(cdKLI|DKZmbiTEr z>(_Bl@T)6Noh=EnyIlz0i-jPkqxvvlbBendeBvh)-@K?)%4{V+Dp^J>uu2M{-=JUm z;B4rnEUwUrd~Z2-MZEifH+I?Np`|fmE~8Mq#DIG_`ANYC{B~$y2qHHMJ3wyttl_78 zpw`Gi9}1JGiErK^aNx({g+@uaR87ta)qQ0!1DR;9KyG)&7c$Ax?qmCRMBjfw3_ zP{;Abuq4K+z$VV1dkH=>2l@W@W_!fZeQJ~}2w-BfXzS?Cki49=jsm;WO9~9Tm#@(Y zJu}N9f{Pf{H>coj5jtL$392oF3=-jIH19sqypEPq>Q-o_PP}BmDoXL^km3T%WL)9= zTUDgEMTC1cOm_J%`4VbVh?e(#^xYQ&4}1*=-n3GSe|nQ7O1!k^A{j|=Z*G>EkguWE zDJ;U8@$l~PFFO<1{(PKy?Yo*phX=`0DgTO}3F5$=Q3@eVs` zhl@3p$4TUn%$dQPT*?@>KY3-iE86eFF3t%W`UD4b$tq8$0>@TFwY>cO^v{b-VDqK8 zXj7-vA4I|m*fVDw)9)>ZqYXZ+Wx;%(Z}oxzxE@;sNR$sRd|zePUTiKCeI2Mtut&KB za_s_twfr(_p4S>S?Tbd^_x%0z-7wc*$=cn+HO;w5`-$bW$0-Vq-#;`Y>Q{M%UF8H5-x9F{44faMneGq zH8DaOm6CO~W(1fI96q~ZF=T9T4)?H(#eR7n{I6N5-U=VzNVzUXU9G9d@_HBx1^A1| zu2Z>#>_ke9gH`}!6Dy0Eu^>7a$KS!)HC< zxo^j7C{AzGTX>=A-#3xIb0M)x^2Tn?wH#NOcL9IGABp&Lr4*0NH(Fy$WyL-EnsK#g zAOpv<`HiYx+e2;Ww!@E*u7?UnTMl_XL%)~UnS)MA7Jju&5*~B(&dw6$t1!V;rhWH~ zdZQ0z9(bu3oQcaf$IjEu4kH$j55hi|*BR7j_-@T4MR_387}#1(y3vTh-3?g@GBbh) z^sV=&W@GcJZE0CFkX%nVU~K{KFR3eOc72nLy{J{7Cu+o=Nx}j!5lRB^$iICO+xv{b zf|(|$9t(-+m_O<1uMufMUzmR0^z|zr!pYBPL=1=mW;{d~I?@aiQk1b&irp*f3Z%AA z8_^ZISg??^a(C930^qt#UNJE<4TLMiWy8eMjI`|&bqCgFM;YlGba(*>{Go^5ve+)yA|(~UPR_)=7j@1BeZugir=}s z4GL9j7Qx`8`+h1#h?`7SVKlM2E5@SLqq{5=aJ-b7xRf7afg#=zmCK)q+Qj8fxI^y_6LLsc#m-YBD0B*(b7@z)X2ob)qn%fd*tsdYZ*A&+1nSsgN*aNJbk{i`aY235kydJ zv4Y5>oAI0-TZ&+fK6n(Kf;SO)qe-v2MdE~xb|$w}jgUaEitH?}`!v!*$ZIZi84WH< z22Zkjb`l_uo(2H2jU7zJjRjX6YG^5I##pf=wN?;MGFZ{LlaB9ugzy8WX9(Zkaso8o z=V=$Dv@QkzHje+D-r$xZR}VpsSTj*~{~i~LKa}{IbTLJBq7J=~F~MDbX1dZ->y9{zYq-_O2$*67W07Jo=vsck75oq4xA+ zP}Np?(VERqpldqEjv=GCWz?3qcm_zJJnPuS^gPIiO9HNS98&ac8`1=RWn?ZQ&Oqs} zvj{EDO`46^oPhFBYU-6=#D|4JV@Mjw(Uc>%PXc=|0`H*5?Z496b1m;Xdw%W;_icZ( z8=d#<1337gJM2^ZPqjcUM7TlSbAxD|>DL(D|HNb|@@w;10QgPsQyQ>iyE9!5$T!dS z9p2tqcZARI{Nz;^<3O1M6PRdAaQYZ(a@m~lbCr!d{yjwaUy*b^+EAj^TrxvN=|~IQ z)JS_eG5Ryg1Qxh5lXX!$*~>fqO5p9pQwV75?o$7Vu`j%QjMR z?ay-H+4B9YXht!9;p)eP2C^1{o2K|(4fOgqcEYFcd1&UK>Bw0%r=@ASdfu<3&FA$@ zVf}B4UpyIk@rAfbiHm#1;`wS2W@niIBcZ^giVtINW%HAv?DXMd=i&gCO>vW$I_-aj z`7m-GCd5;otx}=u!Ox5DMpuP_C)-c-hfjWBIy(BnLB(!vCdip9%v*0M45W|^^%L#} zo@sE{l);PYP+Ek4QjaRI*~>hRz|s16^gtc=1ISR%!=Hb=_ITkSA=`3pu0Du6$*%Rv zdL}rCB_7g*vNrJsXKPbjlNA!k^roEU<}KR4thQ6&FO5+LZ;4bAD!dW(+57g@(gd~= z^m$Ngg=ePQIAr2cri@AwC_Dgu`vlPtQNbSH?+wV1t$&|z!uARIa1#aCQ= z9eaxp5WylIMnv9t`zM0_;QbheYU^Y_X`j8p>dD6VBs;ntF;v~l4=+EvEVEq}>oBM; ze{U7p+*3)g?AF(RHe5?PCQR$XNpa`L*^o{jwT;#)TLX;j7DAnW@kI#eL3Xd!Y4esRR)~0`jlB z*gBZJ(saDkcbVV+7E5wDwR#AQ1A&m?QJ`am#B&0Q*S@bznQ;Kuw%^0(dqPV=W=1Ad zKACt&h=kn96%OSWwR7fC zua3KjajODCUfi=R#j2?KFQ{rHi%?K}Wf`TwSW z@RC-~696F=*6*wJfcSNiNkiFs;LQ^Y%9O<~r5_4~_Q;fa36n4a(x`u?jnco4HZTrt zogYrQBIGRQw7`$gxhRhNxXo(ydG8jI6e)98biON=-6fWtm<-Q7%G-LN_^{)*9w+lf z8y`ez-puuG>5zkyXHT2+Zf#Oh(B`{V^iX14g$&O%Rzki~_(=?Znry3BwE(qLFQl1i%{oibcb@Rre2{R_M5z0}9x zG__Kufu}YFp70Pp?5<<=muWduyymh7R6U#@2WsgSTj!Z-M7>1$A%oW=>)i#5*TVdg zonZY)=N!=ma|FTlY8=b?NRvNsHB_euuRKoky^7}N6)eT*yNr&b3%ZzPKEKm6-`~_; z(h!#7fy2GsJX3C-Y44NoZVNm9QM+*xe2K{xFNga_Rj!WIsuawYYdxA69Nj65-ww99 zXiSe2Sj9%*_d2(!K_c`rS|SJvH?{NQc^r8CNjU;+C>{W@tY8d77{Jg`z|vLk<)HF@ahrqk zsOv6!_^;Vtr*HFfV*H1H=|ByXCK6yGj7lg)j(^w{1oF4HQKf~W1)4yTt!M7~Pj$`n zG7rNUv=a&{5q|ee8=rHTnCG7`{(>2Jv^`iGgb}1O2+xD!{&NZ_7Nl~u7C8UKLK73q)5%G3Iaoc@}AYUg15%JcLMQG6OE;!qUQf*?f*`! z*-r<{B%Q1a&vk+4BaDk2-CUR+zlzJ2r898C_#zjTNq>9!KT5>+@Y^GXIe4>vIgj!Q zfBl!8E9Y{D&Cca#(!H%vH&k1;DXHNs7L8pQ-tLsbw#dl*y0{R3t!R0O^3eowgeUj? zK*jG|`)>MxANb!XRvaF2zY(VU5m)G)--l8p9MbykuDo_mtKhSb*uNX~h+Qz*PyZmmwtaNO1%$sx z)ki#Ck_Ok)zwe>d7Aex*UkF~bx(Y|@iKY;gYlk<|fWOb;^J=z)NzX8@rSg%3rqV3A zqa$=atZ0Cx?1wRGZ3{OEr3159MT=jBUoUsb?;(n8NR-Mm*WvP$awIC#?l7`uYs#u` zw>H7>Zr({U`Xm5UE*W|*GKe=OIz+w4iSMcSx6&ymNilC`^np0`sGgDi;Q7-Lav__~ z2fD?F;eg*aK>oKghV+3g3TDy2H!p?6M`R(RVQW_v6<-sgonr; zO71nV(rjD`Ly7lKf!hRuifcc9bRu#?gsne4r>1H3E1adbd3LoYQ4=K0ulxh8qBkf2 z{M?`X#H$1OP8=T~5h18|lW2dZRx-Y|sU!Hb(|k6+@}_*jcjSzrFG7LI2;CU8KVB-e zt#lt-qJu zlDG6{1&fu7OnN~sMvaI#J=TC2zHb4OyouBn3NeAYbQ0kpu0;atl$dfsZo(R3Qo#D8 z5JhXR8UJ`E^;Ia5C(k&HP7Jf? zauoU(^8waSBaC*%K@iDHWtqYH=GTNz%F+C6y~GO1tY{(xF!(niW9@h^A?ASDpz~Pqmkmu=px~AN3W2fd3XM|3zV1tBYi@ z1^RdoV|QMm+9B$rE=0Kgn27=J{m^KSLpf{#?3 za(FJmR!nR$tI{kq;b)rP_7m4ICeh6XBE}2y+e}U?yv~wRzNL#bGf(PamD2?f2bWsk zwl49t!Uu(<7v_BEgnb^%swk_>VxMmBI!sLHRJ=4>x;m1|vRRx@OW*jIq|irlKQnpH zpHK0w`8hAxVh=-Q(|3{ZpL zmnPqwZu%9Re+DvU^8fVqky3d60PX~xym$TD{by2#5WH=o7sf)?*4wSLnr94xFV{)c+$Ll&jz&pLab^Aw222#|urbNU))XIQ10 zAlRtC=Y!$ZP65cBIdnpK9bT&;?G(@I`ELZq<|u6TvjQ$_j0|SgzF>n4w9C<|aD)UI zVXp`n00YGTkGM}YTC!25_0IJsA{aU|ggqChIm#VeplUWuE~)lQWo@sKEfsTn#3H=k zB=CN}tJ0`iekjUh-oNBizlUo$DE&?T|8ZzUsZM{wWv!U`QiRmxWNC5sufY-K35UO4 zN%q?U994ca{O7mjqZn9EYOSw^VMj>!F7j7*FtQ7Jk%JXT5z)ge4+_x558E{^w|*AW zZ)&gnPELQ^n%0xbu{D}+8)Gv66t&_f)c3Gw6|NMjPJzvjRwHBd*=x zV@v}j(`UWIC89VP0&N94zfbmm6i=sb)FQqj-k(GqaHww_>RgVKoARj$a-0a9>w4Nx z?!31UXv-itRb>m$Ax~N*>m8`oL3#{`_<_tANrVEly3({tZEpD);j(k@;jG6)rTlpm zJ@liMd(G}}iVo@=>q4*e$L9d}d^$0Fp3W8dek&&c*5!s$zV%efmzVI% zVc*T--Mh=-oCzYar<4oZ5#H|Sy`fndoY3WxBA#cT_VX8CJ12ckUBT{F<@97iW3lM7 z_|fU&Jdz=20YHm5>f)m6BC%*Yv>a!!>R?1<>v}9?{1HsR9%B41oE^nYCORd;t@UFX zLg4qOzD42dM{)S=Cmi^2q#?V@Z0|##l?B}|YnwPhI&-`M)fk+m{X-wJ5t1ZkKYv_uAS}2W@DeXe*IGI>lex$ zUt6E_A;U0UK$_?s4xEVJL&*Nue3tUwIG#I|V_W&zQOxUqZD|bu6d8G+^8dAV-SJfRZ`eNe%-+H=GmaUuqYz3~iNYxol2SGY zSs5AGqRc3}l66YiA-k;Xz3JG$=bWS7x5@8)-~KtDK6TFdp6B^K-}}C<`?~J?c!hv5 znU&INv#r1!*A?uRRRKF16-<;fqpCbSsXXElI0J0wx4HJ^`HW3Yx0r~7JJL3>Xn#t3 z^;9F*eGn=w?3Fh3Vy8;u^3~Sc^0Jk+dzAjE>2j%IVcm7Sh{ObDojD?44`;eZ`UboD zXgB*I8eZvfo(@y@P!OEphO(28ld1^tV_gWSmJB!sZLUl0z2@mb<6?Y)^@OW6{*;Q^ zxyE>P+}yXp0Y)4Rt!ixP^)rF~=!XdYM*%6aAi9J)abp3|?E494eH^?1T&-Z%8G=hR zT=e+pTT%~*=pb4TlCtYP%BQC!^5zi>b@`vvJ~c=NYH|eZ9k6Fe024;47b-h@r~cdS zQ8juTcYgJb#HVsfRl|qDb6R(=F0($7t*pr1I-56d-vyKoHjPgvzxnHZNJR}QJ#M5s zh+UK1Z=W{v{EuJQ4N`odNebd-mjs&$jiKWuhKs9g4opeSqboznE%!as?T%C zn#VY(ha!A{8a7bO`f<<%kyv34MFpB~i4E`(hxaXYGC~c#7INW|p}X<_ByACKQH&I3Ea(n)J0()}aGq04YnE+~YWy-z=EE@OFua zWT>*4eznU2CB?Q3H}{Ek2qn?oY@6*i;%*RIQSE%IemI~X{Jv1;#oN?X=GKM6>B zZXDt$!@SuNw&995pyKs}H^=f$>1xL3Gip-QM5tvQ{v|H0o_&@OBZyAqZ{~@LIAWw+ z)D%4tm^`Ln)tGg?=YSHhjkh~&H^fBbNjtdF2l6O0iJuK_zD@}?OZ3aKJjS|3%RY6U z;rl4XoTFY1Z&6+di6psW7nFXX2rMs8_d}RY`WmK3k^|Hn+SfM?*lA?b*QF}hsFH-< z91%IJPv9wi?DP867N82+a#jfjDxnVTnmO2WBRKear#_!k)yzl^rYm_6fIgN0LKwLl zM4g&bnVD>;ECgsS);R>P`VPOKze9KFbO?$=+Qk((>oF;#s+>(>>r3jT6eND zil3a``v_yT9it38l=EXk`h1znHd{*w)>U<_CUec_)(mv_&5fh0 z=%ei`mTiZJxBF%f8Hz4voqcB+#!ERTYGm3Fbc~Vox+8drod& zzX-z9W{;Xaz#H!<`PD!AIsT4OJtJcxu5H!spDhZ1sKjxjrNiQ?ppIj7Q>xabriY^& zHApJ?_6c1-*TM52jVq45iK{DqFk z8FA5TDSqu@OO~z9>Qvbtx6H2#DKdIKy?m#TjS#ijLh23>Zimnhw-IRw;Ed|VJ59kY zvZG*7t{W#$A5#6oRg2~gB)O9HhJ^HcGusD+*i&XSHr6#g2!&ogUtC z%G}9aTOxTLM`~U|AT7o5JsN%QNK0gVkLvuGnBu+0t|?W)sB`hxT+Yq07B@^Q!C_qu9HaX&)SBPepJj$5+`s%#1shi3&=aalDi=F8 zDfS}zkr3RBcj}nSk?$cgv9y%LzR??p7)(9B9*V2$kPkZsi*$NJz}xS?XvEuYT5BSGZ|1x&%Lt!zE{<{&HJiK#}xGkcqZg?l%aIYtPIeY($i zv>Va>+K{0$iH7YKCwC#wb+)G&v@^Wwk8i}xPO8S==xl5npiVgxHM=Q>eXCY@V3mGo z<1Q^7t0zV+jLFYkkrHRD1_Vw!T1zGg0-PeC3n#`RzkQ4J zpK8AmF~6z(V*lNiexejc9Uw*LjNcz#z`ovT-XApB&OdBs*k5Yhri3gGao;s6<$dDG zBo2FiX;A5%CKHR~z;sj6nM$rN+^_)(i81Dj*>|!DFW6PWnZh;yNqP9YpW7=J1aR2* zQt+~vlLTrEP229R+{YiaaQiz{Z!tf8>DDP9dUERgyEr*aYTc*#j4T_J5GFDNm3o#T zU5j7J9IgwqgrowiVww z>iOWULtc;~f`oqoCr5k;=etXk1=|i;*n~-kr95WegYW%b=j6V^cN0xle_SkwBKj2o z|G6TD?5iGhz_NuvDUZlF_|!sF*M}#pDvpJ#2w)QENevq18N3#z601>-i=ZfaD)b45 zFh_B~m?g~G&qzJ>l+r2QuBh=tMS8N|aVT{+^ID;kX55q)$tD7rDxqaZscCiD`6e!p zW{ORyBsbadF@H@S+$OG{r4h?W&}gDFr?zY7zU|JD^?xaokqB_G`+$AEI9SjnrinoX z=&+gi>tGINKY3ZAIu}J-&RJeZ{pd0~$Di=~1$DLfFs>kZt(F7~&OAFRjly?^s`2zd zqs2J+Aa&BX+$xnM+Lu0TLk9FUrm5g7hyCTimoicbVSPZeQFChs7p(PyD^~@pLNJWU zOOv*-0sS!Qeu=!4{7~rRurjhT(quodvlE?ok2;?F_bLxB=3?WPobZ^$n~8N(yqV!k8IwQ~~}lQjBmHWQXC*i2B+ zLQAm0bwY7Flrn}1gwBTc=|Hx^ZB&TPg#fyK$mh@t{D5_HMN)amBA&e?H1ba}=kt33 zcATY5E2^rA7l3)^_uhBB^d?BVgZ5d4!{^ZuJ4u+En$q35-mMq8Hgf5di$HS%2;eR~ zg$pDO_PD6adVp->WHt6rIST!Oz`Ya-68;TK+uPtB%mG^Vz#U*Qi@Ut*X~PO?+_us( zWX<#qAr?44WdXnM_4F0sb89B=*rn%pm0b~~feG-m71>n=I9>Nt;C^ZFBi6UKQ6hep^`c_oM5BaR^y+3CYq)bq*>vBEgISE)i2c~! zg+8TiXq63P( z?$Z83?DbvcxSCmD=80s=g^n6Ms!zuY7uuM31Y^(CzZ`VZo~Bv#0<7#xlz zu#jgmuKMuq!_w}s?WdQgmSN&GR(~Y`S#@6%0O674Bh~hL7aQL{0f>6tLwI-rj&Itc zv@I{hd};-YT?;nn!ib@=I&}l!>4nZ=u-`g2)fcOj7;Bys%DnI(t72lJXNY)Zr02Ub z@Hb;n)f=j4KXzKj81+sYADZF0p^N?jI;T3nU?fdKSP!Fl`oIrS=->}Or3Wf3-deSB zAie|hQsn4cAU*_tP@0N!y!wjiZG0lD zjMwI4e8<3>V1r5IBK}P^ya6sz54e3+7f$#dKAaRCSyp6m=E{)5_dNY&G*AD=>dm|Z zmbhPa%y|-^TH>hu|47eJco1BFK=aYo*T-0bt*_Rp3d@8KtI6<^&&%U0KwDRrrx8vG zInU((621f{xGkwu8%mE6i)vKQ_!_Dt6r3cijjjp{Mi9=jh1>oUi5hyrwFh7j(2H$M zgi+Ip>QbIY6jifMc&n>cCpWrQ*Nk2*pet=~y$~cG&vaS1xUL7&vJ|=nrEH;@`=vc0?cCo;juzcg!|1$u;TkAs*50U3cT z>ZnQJaVlNI#|#Zkcp=IBw8qv=%SzP6=@!F6KvJi6MgOUI2Me2kJ`yEtV0P}dKG zQKkL1!Tz~`9`4@U8EHo!Np1_E62I|@sUF$F;jc$*P}X@ zTu448aPm@$2dwhqK!s02)~QgBX>Yd-7*j%)eHRdDXZbc-TDfpyhgyzM)cW-Io@dg5 zbl*50heL_gn=z&3-T9hK$b!E+Vz}Lg{FMMc;=xG9#bmYbF<*d;VYh*uQh9c07Wd@T zpv5VxM%=q2gN?`k+#l#gWCeksyK;v`IH!q0b&`_0Wq&1 z2zrvg5?r0rOnKiZ(p*D|XwWltT(P;1=e%U|eZKKsQ9djPS(LZ&;rn~ECwR0o$NW$Jc6HB?eQM!W^IU+J6%7A&ekNDwWrbLxA1jaV59L>MEY1=Bn@(&J_w5 zy4*eIL?%AZVExez=m)CMx27}OSuq{IX*%(IAP6fgZ<&2D@XviD7F3!7oSqd z$C`33JXSHmUnyFF%Mr(mOYKDA0iEFq|6`m#gNjQB1Q%JJVjkf_jq&#i7BboGi@|{XEI!#v^Jr^!YRGTiOafExTlw$rPncc{s z%0*HZ8Io&ID53H6=*=#Tl3-G%c!uV9rcG-O*Yv_6aLh^d4^40tti4*iN+T`D1_N2xl+#WxDIWBQVJ(~<=l_c9*!GhA(lJPrY$;MU2K>DJP`k3-wqm0M zP!Yh4R1kdC2sFg}K)IKH9872Ty2*JcQGQ&AH7caTu^~w#D8;E3u7g!PBMJuap~haE zz;62F;|X#h_4(NU$^mLMnMHli_o}a(41WR8$6dMAxKRSL@8p+)xsOzIV#>X5N6e5u zCM&cAg=+uEO*I?cm2sgTbJ6)@2ZUA@StJqt`ZNAKwI>H|L*-!4q(IPK(2xK~%mmS3 zK6PI-9+623Wp<{S#pKdyIC29hmKUK(#()n-#kvG9vK*Cr7B_=J1+wHCX81qC?mq1p z%dNJFm>{L0N$;{?|LF?-D)t_!@bAF^7Xw5+kzf@$FvdU>b@1A!I-Z^1N9_IL#UgZ> zw~-I<@Nd#^<(r*~n!48gTqs4G=YGa` z69fd-e2n`aaO?_%e*x?W$D8(|8Aan*Z@`;A0b)x3CeC6`&U{n7l^wQJ-fFwCp1<+% z!umQ~SisJt*oyt08uR6dHv)Yt778J8@N**e?7N!ea1j#oTNk1p?F6SD1C&jS|4uSsMXwc)hi!}E$Bf`$q-yD_36{P;IkaD7c$>z}vFq(oaSx-uI$cn(3 zLrp_p#4iwVfoOblfpAO{gRmV|BAleJQRn-MyktOX@ce+5i2S*SuBZw&YvwIsj~&Vc zba45!BNI;?u$oEo@3WhMpRgropKPN2#_l#95L)lmyU~3;DzIrLPE*wS+a8&jtZVsl z9y~8)Wa>ef7{$dZAk&ymN+-QJ63&A50d*9U8Wnn{hEf`fAKZ@A?|Cb0d3QeoAo?h znY7W@J0HYRzt-GxBk9lsZ1+D1(DDhyZS=9`u63K-*+|i-Va;uJ0Xp~VmZZg}WQ_RCJQzjF+nt zg@`#O?HM(Z_KY@k;NGvejuhb08hf$>>$gBB&fO~qYLDo`P~Lw#1yz%{F9539h~#A4 z#m4)_t1tS^O9y%#m78BbVJs`mK8F9V3|`ayF z^)enr93E>0gGCAF;%00rO;lNrmiho<_m5myu`TiOLD<%KF7MSN6qGzS^~z7Q7$ZLW z+Tgl4B*c+idVq_$dw)x82JJHY=9A+5N#~Be8w@1g{~4~v*&sOFqO4|{l2d=42h&SdZ>*Ov)Df24ioBVEl&3}NtxgfY%b zgr+4JN;4(xuOPlhAvLnBGJ`^A+*(@;-_lRi6{3~Qdp+i3gD$tGK9j`1Q$6m6cR5lLQSce7C!$IC>@CX zt|RR#6X7?30GDK`sk8OU@y$3CV%I7TeL#0 zq(N|9hrL;ty5wW0EfcFW1%B&0Q12*K;S2>5g__WEHZ{{Is@t~yQN)-sM!4&GXRRwx z1aIKs$3%2)%z*IaopR0VKfr0bj#+{))Mk7XWT^b-FQxlhL~tg>7{i{@y-#0BUV7dw zx=@=X3yZ%dK@l1dQyvDO;^;$Rf?n+O7hyxq4F4QUJc7@RO@km4$HI9@a%@YUw zg#^#yqA>Adf#np?s{Bcy4cVY=n%4#irLY2N$U!UP79qd@3qWD0Y8GawP`#DUb~l;P zI1-51;QPS9Hv9iN%!kEOxKw~|rB#=J?UHcG(7{V;8|drf143bY^BenjQ^9b7q|Orj zEC4&G51iuXw;qg74-kD?Nww1NzIF34LR25eR5v>``_4+&vq0HpsivPlbbtJcb#9902u3fzjMAzGOi3n}e^X7=@MWF|*audCG0sZ(=cZCTLCjJlI2V>zG_8AADH!?Ky)~mf@>Ca z6v>Hb%KQV0?%LTb0-xHnKS)p0euXW3Esj)Qq_a@NVnAaVuF519=00dSjda}wsN!F! zR{8iwvIM~fs!89kS8{y!ly8Vw_PB0SL3YFOd&cF@nugV~WSZa&oyf@^R6*o_Tb$OP zx+H5kS~@3IeOZg>KlHqS&9GL~dfP3w)-%8i$B6tnQmtu^C3J~n_A}!-*D#oQ+b^ch z=KJ(N6}4R`xQTZ%RmQN4m*2C7;YBP(H5Lx=#*V=q%JqBT^>;L^NQuCKa)C|n7t5ML z3k9Ry4~m(+?(>k2nKBT|uEFBz6$KO)IJiGx^jdPvKwQm($Q<&heyNBDmL#hSd;;Br zV&tF(byAvj43=|)(BtGp$Sbpg@g?qIpC9VpA)`bIQ(5M^UYSHG=A54Ne%F2{EP6*7>wFJNwv=i9%2 z+h7OAZ$jr#yInvDd8Jq?^523EeAwC`=dtYlHWvi?mhD$Myf4m(y7fTUPY&b_|GHBi z{mH>QgoRwCMJJG1ddFNveG|ZV0mC5|JfL0RZu?YDWF66)jfRM=wW0h`p)HaS1O6)) z`c<9e$JbI=<srRDeN;T9fy2x1*Lo6S`dtUz4gqqCs0-;BFBYF zkL8caWo>K8w~BX0D>`?#PE8kt8tuaL0+BkPzIrSr>|Ll18dGxu}W>J^6VmyU<>># z4E8xT_OlD5%kT1gr)H+f7+#jxti-sZyjBH=3W>!kmyZ531bwG}CrZybS_jhRl%CS@b&F zjUAQGnYeNy4d%87ixsiE|d(z|ih6N<__7rXt(TPtLp@2^l*a*5Q zGKQ}5h#Q?Y zQ3D_Gu87vcm$(hZj&$Ms>APK^{4CSN{q0&>xXB|zSvD$nLU-3$cP-xBul%%A9XC+6 zNS174>NHY#Q%&2$A+0DigzNFvCLA*U{EoKY=P{`X-s_y8PXp>9Q)VGAcGEAnB4-eX z%nhPH&UJ0qeJR6ZZ6;*5#A?9Q&izZcllx1Xc^U1k4bvp~#r0_OyQjwoUpr)Jn}m6h zrD8^z$8@~N5dMWGRJlP z0|ZpjcfDw?#rNrUP5qg1v)K~`w=@U~h+S2Sz`8H2qP3IUBBbPk#s)Z{brhyfv#7_% zP!Aw$f#EhDoulw)0j}~=+*uwpiAmq~E!D2Oy_*IYAr6&sOF2X&KvRs|(Wp%aJU>&L zaMq++1LV_TKZJUZ|6A|5K_g)9G;;K8BWg?n&;=9^{rA6K!>)LffKO6h|2n^VZ}zkb z=*-^W*|DO7Pq7C2oTDdLYiKF|^#QNscGh;u)TyF0n$2EiU;uwksGd@Js$}N