From 8a01d89bb75b2a4dc565d74d29661a72f53a2b6b Mon Sep 17 00:00:00 2001 From: JohhnGoblin <35317840+JohnDGodwin@users.noreply.github.com> Date: Sun, 5 Jan 2025 01:08:05 -0600 Subject: [PATCH] Add files via upload --- .../ArduinoJoystickLibrary/CONTRIBUTING.md | 28 + .../ArduinoJoystickLibrary/LICENSE | 165 ++++ .../ArduinoJoystickLibrary/README.md | 234 ++++++ .../ArcadeStickExample/ArcadeStickExample.ino | 173 +++++ .../DrivingControllerTest.ino | 153 ++++ .../FlightControllerTest.ino | 181 +++++ .../FunduinoJoystickShield.ino | 85 +++ .../GamepadExample/GamepadExample.ino | 91 +++ .../examples/HatSwitchTest/HatSwitchTest.ino | 95 +++ .../JoystickButton/JoystickButton.ino | 50 ++ .../JoystickKeyboard/JoystickKeyboard.ino | 63 ++ .../examples/JoystickTest/JoystickTest.ino | 265 +++++++ .../MultipleJoystickTest.ino | 180 +++++ .../ArduinoJoystickLibrary/library.properties | 9 + .../src/DynamicHID/DynamicHID.cpp | 169 +++++ .../src/DynamicHID/DynamicHID.h | 144 ++++ .../src/JoystickMHX.cpp | 716 ++++++++++++++++++ .../ArduinoJoystickLibrary/src/JoystickMHX.h | 241 ++++++ .../photo_2023-03-30_04-58-32.jpg | Bin 0 -> 91648 bytes .../sbus-to-usb-joystick/readme.md | 13 + .../sbus-inverter-diagram-schematics.jpg | Bin 0 -> 70917 bytes .../sbus-to-usb-joystick.ino | 73 ++ .../sbus-to-usb-joystick/sbus.cpp | 291 +++++++ .../sbus-to-usb-joystick/sbus.h | 149 ++++ .../translated_readme.txt | 13 + 25 files changed, 3581 insertions(+) create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/CONTRIBUTING.md create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/LICENSE create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/README.md create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/ArcadeStickExample/ArcadeStickExample.ino create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/DrivingControllerTest/DrivingControllerTest.ino create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/FlightControllerTest/FlightControllerTest.ino create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/FunduinoJoystickShield/FunduinoJoystickShield.ino create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/GamepadExample/GamepadExample.ino create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/HatSwitchTest/HatSwitchTest.ino create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/JoystickButton/JoystickButton.ino create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/JoystickKeyboard/JoystickKeyboard.ino create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/JoystickTest/JoystickTest.ino create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/MultipleJoystickTest/MultipleJoystickTest.ino create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/library.properties create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/src/DynamicHID/DynamicHID.cpp create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/src/DynamicHID/DynamicHID.h create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/src/JoystickMHX.cpp create mode 100644 translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/src/JoystickMHX.h create mode 100644 translated_sandbox/sbus-to-usb-joystick/photo_2023-03-30_04-58-32.jpg create mode 100644 translated_sandbox/sbus-to-usb-joystick/readme.md create mode 100644 translated_sandbox/sbus-to-usb-joystick/sbus-inverter-diagram-schematics.jpg create mode 100644 translated_sandbox/sbus-to-usb-joystick/sbus-to-usb-joystick.ino create mode 100644 translated_sandbox/sbus-to-usb-joystick/sbus.cpp create mode 100644 translated_sandbox/sbus-to-usb-joystick/sbus.h create mode 100644 translated_sandbox/sbus-to-usb-joystick/translated_readme.txt diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/CONTRIBUTING.md b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/CONTRIBUTING.md new file mode 100644 index 0000000..6cb08fa --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/CONTRIBUTING.md @@ -0,0 +1,28 @@ +## How to contribute to the Arduino Joystick Library + +### Report a bug + +* **Check to see if the bug has already reported** by searching on GitHub under [Issues](https://github.com/MHeironimus/ArduinoJoystickLibrary/issues). + +* If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/MHeironimus/ArduinoJoystickLibrary/issues/new). Be sure to include a **title and clear description**, as much relevant information as possible (e.g. host OS, Arduino IDE version, etc.), any important hardware information (e.g. name of Arduino board being used, specific pin wirings if they are relavant, etc.), and a **sample sketch** file demonstrating the issue. + +### Fix a bug + +* Open a new GitHub pull request with the fix. + +* Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. + +### Whitespace, format code, or cosmetic updates + +* Changes that are cosmetic in nature and do not add anything substantial to the stability, functionality, or testability will generally not be accepted. + +### Adding a new feature + +* Feel free to [create a new issue](https://github.com/MHeironimus/ArduinoJoystickLibrary/issues/new) to document the feature you are planning to add. This will allow others to see and comment on what you would plan to add to the library. + +### Questions about the library + +* Be sure to check the [FAQ](https://github.com/MHeironimus/ArduinoJoystickLibrary/wiki/FAQ) in the [Wiki](https://github.com/MHeironimus/ArduinoJoystickLibrary/wiki) to see if your question has already been answered. +* Another good place to look for general Arduino questions is the [Arduino]() website. + +The Arduino Joystick Library is a volunteer effort done in volunteer's spare time. Please be patient as it may take some time for bugs to be fixed, features to be added, and questions to be answered. diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/LICENSE b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/LICENSE new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/README.md b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/README.md new file mode 100644 index 0000000..7801179 --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/README.md @@ -0,0 +1,234 @@ +# Arduino Joystick Library + +#### Version 2.1.1 + +This library can be used with Arduino IDE 1.6.6 or above (see [Wiki - Testing Details](https://github.com/MHeironimus/ArduinoJoystickLibrary/wiki/Testing-Details) for more information) to add one or more joysticks (or gamepads) to the list of HID devices an [Arduino Leonardo](https://www.arduino.cc/en/Main/ArduinoBoardLeonardo) or [Arduino Micro](https://www.arduino.cc/en/Main/ArduinoBoardMicro) (or any Arduino clone that is based on the ATmega32u4) can support. This library will also work with the [Arduino Due](https://www.arduino.cc/en/Main/ArduinoBoardDue), thanks to [@Palakis](https://github.com/Palakis). A complete list of supported boards can be found in the [Wiki - Supported Boards](https://github.com/MHeironimus/ArduinoJoystickLibrary/wiki/Supported-Boards). This will not work with Arduino IDE 1.6.5 (or below) or with non-32u4 based Arduino devices (e.g. Arduino UNO, Arduino MEGA, etc.). + +## Features + +The joystick or gamepad can have the following features: +- Buttons (default: 32) +- Up to 2 Hat Switches +- X, Y, and/or Z Axis (up to 16-bit precision) +- X, Y, and/or Z Axis Rotation (up to 16-bit precision) +- Rudder (up to 16-bit precision) +- Throttle (up to 16-bit precision) +- Accelerator (up to 16-bit precision) +- Brake (up to 16-bit precision) +- Steering (up to 16-bit precision) + +## Installation Instructions + +The following instructions can be used to install the latest version of the library in the Arduino IDE (thanks to [@per1234](https://github.com/per1234) for this update): + +1. Download https://github.com/MHeironimus/ArduinoJoystickLibrary/archive/master.zip +2. In the Arduino IDE, select `Sketch` > `Include Library` > `Add .ZIP Library...`. Browse to where the downloaded ZIP file is located and click `Open`. The Joystick library's examples will now appear under `File` > `Examples` > `Joystick`. + +## Examples + +### Simple example + +```C++ +#include + +// Create the Joystick +Joystick_ Joystick; + +// Constant that maps the physical pin to the joystick button. +const int pinToButtonMap = 9; + +void setup() { + // Initialize Button Pins + pinMode(pinToButtonMap, INPUT_PULLUP); + + // Initialize Joystick Library + Joystick.begin(); +} + +// Last state of the button +int lastButtonState = 0; + +void loop() { + + // Read pin values + int currentButtonState = !digitalRead(pinToButtonMap); + if (currentButtonState != lastButtonState) + { + Joystick.setButton(0, currentButtonState); + lastButtonState = currentButtonState; + } + + delay(50); +} +``` + +### Included Examples + +The following example Arduino sketch files are included in this library: + +#### Simple Samples + +- `JoystickButton` - Creates a Joystick and maps pin 9 to button 0 of the joystick, pin 10 to button 1, pin 11 to button 2, and pin 12 to button 3. +- `JoystickKeyboard` - Creates a Joystick and a Keyboard. Maps pin 9 to Joystick Button 0, pin 10 to Joystick Button 1, pin 11 to Keyboard key 1, and pin 12 to Keyboard key 2. +- `GamepadExample` - Creates a simple Gamepad with an Up, Down, Left, Right, and Fire button. +- `FunduinoJoystickShield` - Creates a simple Gamepad using a Funduino Joystick Shield (https://protosupplies.com/product/funduino-joystick-shield-v1-a/). +- `ArcadeStickExample` - Simple arcade stick example that demonstrates how to read twelve Arduino Pro Micro digital pins and map them to the library (thanks to [@nebhead](https://github.com/nebhead) for this example). NOTE: This sketch is for the Arduino Pro Micro only. + +#### Used for Testing + +- `JoystickTest` - Simple test of the Joystick library. It exercises many of the Joystick library’s functions when pin A0 is grounded. +- `MultipleJoystickTest` - Creates 4 Joysticks using the library (each with a slightly different configuration) and exercises the first 16 buttons (if present), the X axis, and the Y axis of each joystick when pin A0 is grounded. +- `FlightControllerTest` - Creates a Flight Controller and tests 32 buttons, the X and Y axis, the Throttle, and the Rudder when pin A0 is grounded. +- `HatSwitchTest` - Creates a joystick with two hat switches. Grounding pins 4 - 11 cause the hat switches to change position. +- `DrivingControllerTest` - Creates a Driving Controller and tests 4 buttons, the Steering, Brake, and Accelerator when pin A0 is grounded. + +## Joystick Library API + +The following API is available if the Joystick library in included in a sketch file. + +### Joystick\_(...) + +Constructor used to initialize and setup the Joystick. The following optional parameters are available: + +- `uint8_t hidReportId` - Default: `0x03` - Indicates the joystick's HID report ID. This value must be unique if you are creating multiple instances of Joystick. Do not use `0x01` or `0x02` as they are used by the built-in Arduino Keyboard and Mouse libraries. +- `uint8_t joystickType` - Default: `JOYSTICK_TYPE_JOYSTICK` or `0x04` - Indicates the HID input device type. Supported values: + - `JOYSTICK_TYPE_JOYSTICK` or `0x04` - Joystick + - `JOYSTICK_TYPE_GAMEPAD` or `0x05` - Gamepad + - `JOYSTICK_TYPE_MULTI_AXIS` or `0x08` - Multi-axis Controller +- `uint8_t buttonCount` - Default: `32` - Indicates how many buttons will be available on the joystick. +- `uint8_t hatSwitchCount` - Default: `2` - Indicates how many hat switches will be available on the joystick. Range: `0` - `2` +- `bool includeXAxis` - Default: `true` - Indicates if the X Axis is available on the joystick. +- `bool includeYAxis` - Default: `true` - Indicates if the Y Axis is available on the joystick. +- `bool includeZAxis` - Default: `true` - Indicates if the Z Axis (in some situations this is the right X Axis) is available on the joystick. +- `bool includeRxAxis` - Default: `true` - Indicates if the X Axis Rotation (in some situations this is the right Y Axis) is available on the joystick. +- `bool includeRyAxis` - Default: `true` - Indicates if the Y Axis Rotation is available on the joystick. +- `bool includeRzAxis` - Default: `true` - Indicates if the Z Axis Rotation is available on the joystick. +- `bool includeRudder` - Default: `true` - Indicates if the Rudder is available on the joystick. +- `bool includeThrottle` - Default: `true` - Indicates if the Throttle is available on the joystick. +- `bool includeAccelerator` - Default: `true` - Indicates if the Accelerator is available on the joystick. +- `bool includeBrake` - Default: `true` - Indicates if the Brake is available on the joystick. +- `bool includeSteering` - Default: `true` - Indicates if the Steering is available on the joystick. + +The following constants define the default values for the constructor parameters listed above: + +- `JOYSTICK_DEFAULT_REPORT_ID` is set to `0x03` +- `JOYSTICK_DEFAULT_BUTTON_COUNT` is set to `32` +- `JOYSTICK_DEFAULT_HATSWITCH_COUNT` is set to `2` + +### Joystick.begin(bool initAutoSendState) + +Starts emulating a game controller connected to a computer. By default, all methods update the game controller state immediately. If `initAutoSendState` is set to `false`, the `Joystick.sendState` method must be called to update the game controller state. + +### Joystick.end() + +Stops the game controller emulation to a connected computer (Note: just like the Arduino `Keyboard.h` and `Mouse.h` libraries, the `end()` function does not actually do anything). + +### Joystick.setXAxisRange(int32_t minimum, int32_t maximum) + +Sets the range of values that will be used for the X axis. Default: `0` to `1023` + +### Joystick.setXAxis(int32_t value) + +Sets the X axis value. See `setXAxisRange` for the range. + +### Joystick.setYAxisRange(int32_t minimum, int32_t maximum) + +Sets the range of values that will be used for the Y axis. Default: `0` to `1023` + +### Joystick.setYAxis(int32_t value) + +Sets the Y axis value. See `setYAxisRange` for the range. + +### Joystick.setZAxisRange(int32_t minimum, int32_t maximum) + +Sets the range of values that will be used for the Z axis. Default: `0` to `1023` + +### Joystick.setZAxis(int32_t value) + +Sets the Z axis value. See `setZAxisRange` for the range. + +### Joystick.setRxAxisRange(int32_t minimum, int32_t maximum) + +Sets the range of values that will be used for the X axis rotation. Default: `0` to `1023` + +### Joystick.setRxAxis(int32_t value) + +Sets the X axis rotation value. See `setRxAxisRange` for the range. + +### Joystick.setRyAxisRange(int32_t minimum, int32_t maximum) + +Sets the range of values that will be used for the Y axis rotation. Default: `0` to `1023` + +### Joystick.setRyAxis(int32_t value) + +Sets the Y axis rotation value. See `setRyAxisRange` for the range. + +### Joystick.setRzAxisRange(int32_t minimum, int32_t maximum) + +Sets the range of values that will be used for the Z axis rotation. Default: `0` to `1023` + +### Joystick.setRzAxis(int32_t value) + +Sets the Z axis rotation value. See `setRzAxisRange` for the range. + +### Joystick.setRudderRange(int32_t minimum, int32_t maximum) + +Sets the range of values that will be used for the Rudder. Default: `0` to `1023` + +### Joystick.setRudder(int32_t value) + +Sets the Rudder value. See `setRudderRange` for the range. + +### Joystick.setThrottleRange(int32_t minimum, int32_t maximum) + +Sets the range of values that will be used for the Throttle. Default: `0` to `1023` + +### Joystick.setThrottle(int32_t value) + +Sets the Throttle value. See `setThrottleRange` for the range. + +### Joystick.setAcceleratorRange(int32_t minimum, int32_t maximum) + +Sets the range of values that will be used for the Accelerator. Default: `0` to `1023` + +### Joystick.setAccelerator(int32_t value) + +Sets the Accelerator value. See `setAcceleratorRange` for the range. + +### Joystick.setBrakeRange(int32_t minimum, int32_t maximum) + +Sets the range of values that will be used for the Brake. Default: `0` to `1023` + +### Joystick.setBrake(int32_t value) + +Sets the Brake value. See `setBrakeRange` for the range. + +### Joystick.setSteeringRange(int32_t minimum, int32_t maximum) + +Sets the range of values that will be used for the Steering. Default: `0` to `1023` + +### Joystick.setSteering(int32_t value) + +Sets the Steering value. See `setSteeringRange` for the range. + +### Joystick.setButton(uint8_t button, uint8_t value) + +Sets the state (`0` or `1`) of the specified button (range: `0` - (`buttonCount - 1`)). The button is the 0-based button number (i.e. button #1 is `0`, button #2 is `1`, etc.). The value is `1` if the button is pressed and `0` if the button is released. + +### Joystick.pressButton(uint8_t button) + +Press the indicated button (range: `0` - (`buttonCount - 1`)). The button is the 0-based button number (i.e. button #1 is `0`, button #2 is `1`, etc.). + +### Joystick.releaseButton(uint8_t button) + +Release the indicated button (range: `0` - (`buttonCount - 1`)). The button is the 0-based button number (i.e. button #1 is `0`, button #2 is `1`, etc.). + +### Joystick.setHatSwitch(int8_t hatSwitch, int16_t value) + +Sets the value of the specified hat switch. The hatSwitch is 0-based (i.e. hat switch #1 is `0` and hat switch #2 is `1`). The value is from 0° to 360°, but in 45° increments. Any value less than 45° will be rounded down (i.e. 44° is rounded down to 0°, 89° is rounded down to 45°, etc.). Set the value to `JOYSTICK_HATSWITCH_RELEASE` or `-1` to release the hat switch. + +### Joystick.sendState() + +Sends the updated joystick state to the host computer. Only needs to be called if `AutoSendState` is `false` (see `Joystick.begin` for more details). + +See the [Wiki](https://github.com/MHeironimus/ArduinoJoystickLibrary/wiki) for more details on things like FAQ, supported boards, testing, etc. diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/ArcadeStickExample/ArcadeStickExample.ino b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/ArcadeStickExample/ArcadeStickExample.ino new file mode 100644 index 0000000..1f9df66 --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/ArcadeStickExample/ArcadeStickExample.ino @@ -0,0 +1,173 @@ +// Simple arcade stick example that demonstrates how to read twelve +// Arduino Pro Micro digital pins and map them to the +// Arduino Joystick library. +// + +// The digital pins 2 - 20 are grounded when they are pressed. +// Pin 10, A10, Red = UP +// Pin 15, D15, Yellow = RIGHT +// Pin 16, D16, Orange = DOWN +// Pin 14, D14, Green = LEFT + +// Pin 9, A9 = Button 1 +// Pin 8, A8 = Button 2 +// Pin 7, D7 = Button 3 +// Pin 3, D3 = Button 4 +// Pin 2, D2 = Button 5 +// Pin 4, A6 = Button 6 + +// Pin 20, A2 = Select Button 1 +// Pin 19, A1 = Start Button 2 + +// Pin 5, D5 = Other Button +// Pin 6, A7 = Other Button +// Pin 18, A0 = Other Button +// Pin 21, A3 = Other Button + +// NOTE: This sketch file is for use with Arduino Pro Micro only. +// +// Original gamepad example by Matthew Heironimus +// 2016-11-24 +// Adapted for arcade machine setup by Ben Parmeter +// 2019-05-20 +//-------------------------------------------------------------------- + +#include + +Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_GAMEPAD, + 8, 0, // Button Count, Hat Switch Count + true, true, false, // X and Y, but no Z Axis + false, false, false, // No Rx, Ry, or Rz + false, false, // No rudder or throttle + false, false, false); // No accelerator, brake, or steering + +void setup() { + // Initialize Button Pins + pinMode(2, INPUT_PULLUP); + pinMode(3, INPUT_PULLUP); + pinMode(4, INPUT_PULLUP); + pinMode(5, INPUT_PULLUP); + pinMode(6, INPUT_PULLUP); + pinMode(7, INPUT_PULLUP); + pinMode(8, INPUT_PULLUP); + pinMode(9, INPUT_PULLUP); + pinMode(10, INPUT_PULLUP); + pinMode(14, INPUT_PULLUP); + pinMode(15, INPUT_PULLUP); + pinMode(16, INPUT_PULLUP); + pinMode(18, INPUT_PULLUP); + pinMode(19, INPUT_PULLUP); + pinMode(20, INPUT_PULLUP); + pinMode(21, INPUT_PULLUP); + + // Initialize Joystick Library + Joystick.begin(); + Joystick.setXAxisRange(-1, 1); + Joystick.setYAxisRange(-1, 1); +} + +// Last state of the buttons +int lastButtonState[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +int buttonMap[16] = {10,15,16,14,9,8,7,3,2,4,20,19,5,6,18,21}; + +// ButtonMap = 0, Pin 10 = UP +// ButtonMap = 1, Pin 15 = RIGHT +// ButtonMap = 2, Pin 16 = DOWN +// ButtonMap = 3, Pin 14 = LEFT + +// ButtonMap = 4, Pin 9 = Button 1 +// ButtonMap = 5, Pin 8 = Button 2 +// ButtonMap = 6, Pin 7 = Button 3 +// ButtonMap = 7, Pin 3 = Button 4 +// ButtonMap = 8, Pin 2 = Button 5 +// ButtonMap = 9, Pin 4 = Button 6 + +// ButtonMap = 10, Pin 20 = Select Button 1 +// ButtonMap = 11, Pin 19 = Start Button 2 + +// ButtonMap = 12, Pin 5 = Other Button +// ButtonMap = 13, Pin 6 = Other Button +// ButtonMap = 14, Pin 18 = Other Button +// ButtonMap = 15, Pin 21 = Other Button + + +void loop() { + + // Read pin values + for (int index = 0; index < 16; index++) + { + int currentButtonState = !digitalRead(buttonMap[index]); + if (currentButtonState != lastButtonState[index]) + { + switch (index) { + case 0: // UP + if (currentButtonState == 1) { + Joystick.setYAxis(-1); + } else { + Joystick.setYAxis(0); + } + break; + case 1: // RIGHT + if (currentButtonState == 1) { + Joystick.setXAxis(1); + } else { + Joystick.setXAxis(0); + } + break; + case 2: // DOWN + if (currentButtonState == 1) { + Joystick.setYAxis(1); + } else { + Joystick.setYAxis(0); + } + break; + case 3: // LEFT + if (currentButtonState == 1) { + Joystick.setXAxis(-1); + } else { + Joystick.setXAxis(0); + } + break; + case 4: // Black Button 1 + Joystick.setButton(0, currentButtonState); + break; + case 5: // Black Button 2 + Joystick.setButton(1, currentButtonState); + break; + case 6: // Black Button 3 + Joystick.setButton(2, currentButtonState); + break; + case 7: // Black Button 4 + Joystick.setButton(3, currentButtonState); + break; + case 8: // Black Button 5 + Joystick.setButton(4, currentButtonState); + break; + case 9: // Black Button 6 + Joystick.setButton(5, currentButtonState); + break; + case 10: // Select Button + Joystick.setButton(6, currentButtonState); + break; + case 11: // Start Button + Joystick.setButton(7, currentButtonState); + break; + case 12: // Other Button 1 + Joystick.setButton(8, currentButtonState); + break; + case 13: // Other Button 2 + Joystick.setButton(9, currentButtonState); + break; + case 14: // Other Button 3 + Joystick.setButton(10, currentButtonState); + break; + case 15: // Other Button 4 + Joystick.setButton(11, currentButtonState); + break; + } + lastButtonState[index] = currentButtonState; + } + } + + delay(10); +} diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/DrivingControllerTest/DrivingControllerTest.ino b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/DrivingControllerTest/DrivingControllerTest.ino new file mode 100644 index 0000000..a659e71 --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/DrivingControllerTest/DrivingControllerTest.ino @@ -0,0 +1,153 @@ +// Program used to test the driving simulator functions on +// the USB Joystick object on the Arduino Leonardo or +// Arduino Micro. +// +// Matthew Heironimus +// 2016-05-29 Original version. +//------------------------------------------------------------ + +#include "Joystick.h" + +Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, + JOYSTICK_TYPE_MULTI_AXIS, 4, 0, + false, false, false, false, false, false, + false, false, true, true, true); + +// Set to true to test "Auto Send" mode or false to test "Manual Send" mode. +//const bool testAutoSendMode = true; +const bool testAutoSendMode = false; + +const unsigned long gcCycleDelta = 1000; +const unsigned long gcButtonDelta = 500; +const unsigned long gcAnalogDelta = 25; +unsigned long gNextTime = 0; +unsigned int gCurrentStep = 0; + +void testSingleButtonPush(unsigned int button) +{ + if (button > 0) + { + Joystick.releaseButton(button - 1); + } + if (button < 4) + { + Joystick.pressButton(button); + } +} + +void testMultiButtonPush(unsigned int currentStep) +{ + for (int button = 0; button < 4; button++) + { + if ((currentStep == 0) || (currentStep == 2)) + { + if ((button % 2) == 0) + { + Joystick.pressButton(button); + } else if (currentStep != 2) + { + Joystick.releaseButton(button); + } + } // if ((currentStep == 0) || (currentStep == 2)) + if ((currentStep == 1) || (currentStep == 2)) + { + if ((button % 2) != 0) + { + Joystick.pressButton(button); + } else if (currentStep != 2) + { + Joystick.releaseButton(button); + } + } // if ((currentStep == 1) || (currentStep == 2)) + if (currentStep == 3) + { + Joystick.releaseButton(button); + } // if (currentStep == 3) + } // for (int button = 0; button < 32; button++) +} + +void testAcceleratorBrake(int value) +{ + Joystick.setAccelerator(value); + Joystick.setBrake(260 - value); +} + +void testSteering(int value) +{ + if (value < 300) { + Joystick.setSteering(value); + } else { + Joystick.setSteering(600 - value); + } +} + +void setup() { + + Joystick.setAcceleratorRange(0, 260); + Joystick.setBrakeRange(0, 260); + Joystick.setSteeringRange(0, 300); + + if (testAutoSendMode) + { + Joystick.begin(); + } + else + { + Joystick.begin(false); + } + + pinMode(A0, INPUT_PULLUP); + pinMode(LED_BUILTIN, OUTPUT); +} + +void loop() { + + // System Disabled + if (digitalRead(A0) != 0) + { + // Turn indicator light off. + digitalWrite(LED_BUILTIN, 0); + return; + } + + // Turn indicator light on. + digitalWrite(LED_BUILTIN, 1); + + if (millis() >= gNextTime) + { + + if (gCurrentStep < 4) + { + gNextTime = millis() + gcButtonDelta; + testSingleButtonPush(gCurrentStep); + } + else if (gCurrentStep < 9) + { + gNextTime = millis() + gcButtonDelta; + testMultiButtonPush(gCurrentStep - 5); + } + else if (gCurrentStep < (9 + 260)) + { + gNextTime = millis() + gcAnalogDelta; + testAcceleratorBrake(gCurrentStep - 9); + } + else if (gCurrentStep < (9 + 260 + 600)) + { + gNextTime = millis() + gcAnalogDelta; + testSteering(gCurrentStep - (9 + 260)); + } + + if (testAutoSendMode == false) + { + Joystick.sendState(); + } + + gCurrentStep++; + if (gCurrentStep >= (9 + 260 + 600)) + { + gNextTime = millis() + gcCycleDelta; + gCurrentStep = 0; + } + } +} + diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/FlightControllerTest/FlightControllerTest.ino b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/FlightControllerTest/FlightControllerTest.ino new file mode 100644 index 0000000..2d7f633 --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/FlightControllerTest/FlightControllerTest.ino @@ -0,0 +1,181 @@ +// Program used to test the USB Joystick library when used as +// a Flight Controller on the Arduino Leonardo or Arduino +// Micro. +// +// Matthew Heironimus +// 2016-05-29 - Original Version +//------------------------------------------------------------ + +#include "Joystick.h" + +Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, + JOYSTICK_TYPE_MULTI_AXIS, 32, 0, + true, true, false, false, false, false, + true, true, false, false, false); + +// Set to true to test "Auto Send" mode or false to test "Manual Send" mode. +//const bool testAutoSendMode = true; +const bool testAutoSendMode = false; + +const unsigned long gcCycleDelta = 1000; +const unsigned long gcAnalogDelta = 25; +const unsigned long gcButtonDelta = 500; +unsigned long gNextTime = 0; +unsigned int gCurrentStep = 0; + +void testSingleButtonPush(unsigned int button) +{ + if (button > 0) + { + Joystick.releaseButton(button - 1); + } + if (button < 32) + { + Joystick.pressButton(button); + } +} + +void testMultiButtonPush(unsigned int currentStep) +{ + for (int button = 0; button < 32; button++) + { + if ((currentStep == 0) || (currentStep == 2)) + { + if ((button % 2) == 0) + { + Joystick.pressButton(button); + } else if (currentStep != 2) + { + Joystick.releaseButton(button); + } + } // if ((currentStep == 0) || (currentStep == 2)) + if ((currentStep == 1) || (currentStep == 2)) + { + if ((button % 2) != 0) + { + Joystick.pressButton(button); + } else if (currentStep != 2) + { + Joystick.releaseButton(button); + } + } // if ((currentStep == 1) || (currentStep == 2)) + if (currentStep == 3) + { + Joystick.releaseButton(button); + } // if (currentStep == 3) + } // for (int button = 0; button < 32; button++) +} + +void testXYAxis(unsigned int currentStep) +{ + int xAxis; + int yAxis; + + if (currentStep < 256) + { + xAxis = currentStep - 127; + yAxis = -127; + Joystick.setXAxis(xAxis); + Joystick.setYAxis(yAxis); + } + else if (currentStep < 512) + { + yAxis = currentStep - 256 - 127; + Joystick.setYAxis(yAxis); + } + else if (currentStep < 768) + { + xAxis = 128 - (currentStep - 512); + Joystick.setXAxis(xAxis); + } + else if (currentStep < 1024) + { + yAxis = 128 - (currentStep - 768); + Joystick.setYAxis(yAxis); + } + else if (currentStep < 1024 + 128) + { + xAxis = currentStep - 1024 - 127; + Joystick.setXAxis(xAxis); + Joystick.setYAxis(xAxis); + } +} + +void testThrottleRudder(unsigned int value) +{ + Joystick.setThrottle(value); + Joystick.setRudder(255 - value); +} + +void setup() { + + Joystick.setXAxisRange(-127, 127); + Joystick.setYAxisRange(-127, 127); + Joystick.setZAxisRange(-127, 127); + Joystick.setThrottleRange(0, 255); + Joystick.setRudderRange(0, 255); + + if (testAutoSendMode) + { + Joystick.begin(); + } + else + { + Joystick.begin(false); + } + + pinMode(A0, INPUT_PULLUP); + pinMode(LED_BUILTIN, OUTPUT); +} + +void loop() { + + // System Disabled + if (digitalRead(A0) != 0) + { + // Turn indicator light off. + digitalWrite(LED_BUILTIN, 0); + return; + } + + // Turn indicator light on. + digitalWrite(LED_BUILTIN, 1); + + if (millis() >= gNextTime) + { + + if (gCurrentStep < 33) + { + gNextTime = millis() + gcButtonDelta; + testSingleButtonPush(gCurrentStep); + } + else if (gCurrentStep < 37) + { + gNextTime = millis() + gcButtonDelta; + testMultiButtonPush(gCurrentStep - 33); + } + else if (gCurrentStep < (37 + 256)) + { + gNextTime = millis() + gcAnalogDelta; + testThrottleRudder(gCurrentStep - 37); + } + else if (gCurrentStep < (37 + 256 + 1024 + 128)) + { + gNextTime = millis() + gcAnalogDelta; + testXYAxis(gCurrentStep - (37 + 256)); + } + + if (testAutoSendMode == false) + { + Joystick.sendState(); + } + + gCurrentStep++; + if (gCurrentStep >= (37 + 256 + 1024 + 128)) + { + gNextTime = millis() + gcCycleDelta; + gCurrentStep = 0; + } + } +} + diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/FunduinoJoystickShield/FunduinoJoystickShield.ino b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/FunduinoJoystickShield/FunduinoJoystickShield.ino new file mode 100644 index 0000000..71c277a --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/FunduinoJoystickShield/FunduinoJoystickShield.ino @@ -0,0 +1,85 @@ +#include + +const uint8_t buttonCount = 7; +Joystick_ controller(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, buttonCount, + 0, true, true, false, + false, false, false, + false, false, false, + false, false); + +int const BTN_A_PIN = 2; +int const BTN_B_PIN = 3; +int const BTN_C_PIN = 4; +int const BTN_D_PIN = 5; +int const BTN_E_PIN = 6; +int const BTN_F_PIN = 7; +int const BTN_K_PIN = 8; +int const AXIS_X_PIN = A0; +int const AXIS_Y_PIN = A1; + +int const buttonPins[buttonCount] = { + BTN_A_PIN, + BTN_B_PIN, + BTN_C_PIN, + BTN_D_PIN, + BTN_E_PIN, + BTN_F_PIN, + BTN_K_PIN +}; +int lastButtonValue[buttonCount]; +int lastXAxisValue = -1; +int lastYAxisValue = -1; + +void setup() +{ + controller.setYAxisRange(0, 1023); + controller.setYAxisRange(1023, 0); + controller.begin(false); + + for (int i = 0; i < buttonCount; i++) + { + pinMode(buttonPins[i], INPUT_PULLUP); + lastButtonValue[i] = -1; + } + + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, LOW); +} + +void loop() +{ + bool sendUpdate = false; + for (int i = 0; i < buttonCount; i++) + { + const int buttonValue = digitalRead(buttonPins[i]); + + if (buttonValue != lastButtonValue[i]) + { + controller.setButton(i, !buttonValue); + lastButtonValue[i] = buttonValue; + sendUpdate = true; + } + } + + const int currentXAxisValue = analogRead(AXIS_X_PIN); + if (currentXAxisValue != lastXAxisValue) + { + controller.setXAxis(currentXAxisValue); + lastXAxisValue = currentXAxisValue; + sendUpdate = true; + } + + const int currentYAxisValue = analogRead(AXIS_Y_PIN); + if (currentYAxisValue != lastYAxisValue) + { + controller.setYAxis(currentYAxisValue); + lastYAxisValue = currentYAxisValue; + sendUpdate = true; + } + + if (sendUpdate) + { + controller.sendState(); + } + delay(50); +} diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/GamepadExample/GamepadExample.ino b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/GamepadExample/GamepadExample.ino new file mode 100644 index 0000000..ff728b3 --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/GamepadExample/GamepadExample.ino @@ -0,0 +1,91 @@ +// Simple gamepad example that demonstraits how to read five Arduino +// digital pins and map them to the Arduino Joystick library. +// +// The digital pins 2 - 6 are grounded when they are pressed. +// Pin 2 = UP +// Pin 3 = RIGHT +// Pin 4 = DOWN +// Pin 5 = LEFT +// Pin 6 = FIRE +// +// NOTE: This sketch file is for use with Arduino Leonardo and +// Arduino Micro only. +// +// by Matthew Heironimus +// 2016-11-24 +//-------------------------------------------------------------------- + +#include + +Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_GAMEPAD, + 1, 0, // Button Count, Hat Switch Count + true, true, false, // X and Y, but no Z Axis + false, false, false, // No Rx, Ry, or Rz + false, false, // No rudder or throttle + false, false, false); // No accelerator, brake, or steering + +void setup() { + // Initialize Button Pins + pinMode(2, INPUT_PULLUP); + pinMode(3, INPUT_PULLUP); + pinMode(4, INPUT_PULLUP); + pinMode(5, INPUT_PULLUP); + pinMode(6, INPUT_PULLUP); + + // Initialize Joystick Library + Joystick.begin(); + Joystick.setXAxisRange(-1, 1); + Joystick.setYAxisRange(-1, 1); +} + +// Last state of the buttons +int lastButtonState[5] = {0,0,0,0,0}; + +void loop() { + + // Read pin values + for (int index = 0; index < 5; index++) + { + int currentButtonState = !digitalRead(index + 2); + if (currentButtonState != lastButtonState[index]) + { + switch (index) { + case 0: // UP + if (currentButtonState == 1) { + Joystick.setYAxis(-1); + } else { + Joystick.setYAxis(0); + } + break; + case 1: // RIGHT + if (currentButtonState == 1) { + Joystick.setXAxis(1); + } else { + Joystick.setXAxis(0); + } + break; + case 2: // DOWN + if (currentButtonState == 1) { + Joystick.setYAxis(1); + } else { + Joystick.setYAxis(0); + } + break; + case 3: // LEFT + if (currentButtonState == 1) { + Joystick.setXAxis(-1); + } else { + Joystick.setXAxis(0); + } + break; + case 4: // FIRE + Joystick.setButton(0, currentButtonState); + break; + } + lastButtonState[index] = currentButtonState; + } + } + + delay(10); +} + diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/HatSwitchTest/HatSwitchTest.ino b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/HatSwitchTest/HatSwitchTest.ino new file mode 100644 index 0000000..22e040e --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/HatSwitchTest/HatSwitchTest.ino @@ -0,0 +1,95 @@ +// Simple example application that shows how to read four Arduino +// digital pins and map them to the USB Joystick library's hat switch. +// +// The digital pins 4, 5, 6, 7, 8, 9, 10, and 11 are grounded when +// they are pressed. +// +// Pin Mappings: +// 4 - Hat Switch #0 UP +// 5 - Hat Switch #0 RIGHT +// 6 - Hat Switch #0 DOWN +// 7 - Hat Switch #0 LEFT +// 8 - Hat Switch #1 UP +// 9 - Hat Switch #1 RIGHT +// 10 - Hat Switch #1 DOWN +// 11 - Hat Switch #1 LEFT +// +// NOTE: This sketch file is for use with Arduino Leonardo and +// Arduino Micro only. +// +// by Matthew Heironimus +// 2016-05-30 +//-------------------------------------------------------------------- + +#include + +Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, + JOYSTICK_TYPE_GAMEPAD, 0, + JOYSTICK_DEFAULT_HATSWITCH_COUNT, + false, false, false, false, false, false, + false, false, false, false, false); + +void setup() { + + // Initialize Button Pins + for (int index = 4; index < 12; index++) + { + pinMode(index, INPUT_PULLUP); + } + + // Initialize Joystick Library + Joystick.begin(); +} + +// Last state of the pins +int lastButtonState[2][4] = {{0,0,0,0}, {0,0,0,0}}; + +void loop() { + + bool valueChanged[2] = {false, false}; + int currentPin = 4; + + // Read pin values + for (int hatSwitch = 0; hatSwitch < 2; hatSwitch++) + { + for (int index = 0; index < 4; index++) + { + int currentButtonState = !digitalRead(currentPin++); + if (currentButtonState != lastButtonState[hatSwitch][index]) + { + valueChanged[hatSwitch] = true; + lastButtonState[hatSwitch][index] = currentButtonState; + } + } + } + + for (int hatSwitch = 0; hatSwitch < 2; hatSwitch++) + { + if (valueChanged[hatSwitch]) { + + if ((lastButtonState[hatSwitch][0] == 0) + && (lastButtonState[hatSwitch][1] == 0) + && (lastButtonState[hatSwitch][2] == 0) + && (lastButtonState[hatSwitch][3] == 0)) { + Joystick.setHatSwitch(hatSwitch, -1); + } + if (lastButtonState[hatSwitch][0] == 1) { + Joystick.setHatSwitch(hatSwitch, 0); + } + if (lastButtonState[hatSwitch][1] == 1) { + Joystick.setHatSwitch(hatSwitch, 90); + } + if (lastButtonState[hatSwitch][2] == 1) { + Joystick.setHatSwitch(hatSwitch, 180); + } + if (lastButtonState[hatSwitch][3] == 1) { + Joystick.setHatSwitch(hatSwitch, 270); + } + + } // if the value changed + + } // for each hat switch + + delay(50); +} + diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/JoystickButton/JoystickButton.ino b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/JoystickButton/JoystickButton.ino new file mode 100644 index 0000000..c6bc79e --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/JoystickButton/JoystickButton.ino @@ -0,0 +1,50 @@ +// Simple example application that shows how to read four Arduino +// digital pins and map them to the USB Joystick library. +// +// Ground digital pins 9, 10, 11, and 12 to press the joystick +// buttons 0, 1, 2, and 3. +// +// NOTE: This sketch file is for use with Arduino Leonardo and +// Arduino Micro only. +// +// by Matthew Heironimus +// 2015-11-20 +//-------------------------------------------------------------------- + +#include + +Joystick_ Joystick; + +void setup() { + // Initialize Button Pins + pinMode(9, INPUT_PULLUP); + pinMode(10, INPUT_PULLUP); + pinMode(11, INPUT_PULLUP); + pinMode(12, INPUT_PULLUP); + + // Initialize Joystick Library + Joystick.begin(); +} + +// Constant that maps the phyical pin to the joystick button. +const int pinToButtonMap = 9; + +// Last state of the button +int lastButtonState[4] = {0,0,0,0}; + +void loop() { + + // Read pin values + for (int index = 0; index < 4; index++) + { + int currentButtonState = !digitalRead(index + pinToButtonMap); + if (currentButtonState != lastButtonState[index]) + { + Joystick.setButton(index, currentButtonState); + lastButtonState[index] = currentButtonState; + } + } + + delay(50); +} + diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/JoystickKeyboard/JoystickKeyboard.ino b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/JoystickKeyboard/JoystickKeyboard.ino new file mode 100644 index 0000000..d1670c9 --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/JoystickKeyboard/JoystickKeyboard.ino @@ -0,0 +1,63 @@ +// Simple example application that shows how to read four Arduino +// digital pins and map them to buttons on a joystick or keys on a +// keyboard uisng the Arduino Joystick and Keyboard libraries. +// +// The digital pins 9, 10, 11, and 12 are grounded when they are pressed. +// +// NOTE: This sketch file is for use with Arduino Leonardo and +// Arduino Micro only. +// +// Pin 9 = Joystick Button 0 +// Pin 10 = Joystick Button 1 +// Pin 11 = 1 key on the Keyboard +// Pin 12 = 2 key on the Keyboard +// +// by Matthew Heironimus +// 2016-05-13 +//-------------------------------------------------------------------- + +#include +#include + +Joystick_ Joystick; + +void setup() { + // Initialize Button Pins + pinMode(9, INPUT_PULLUP); + pinMode(10, INPUT_PULLUP); + pinMode(11, INPUT_PULLUP); + pinMode(12, INPUT_PULLUP); + + // Initialize Joystick Library + Joystick.begin(); +} + +// Constant that maps the phyical pin to the joystick button. +const int pinToButtonMap = 9; + +// Last state of the button +int lastButtonState[4] = {0,0,0,0}; + +void loop() { + + // Read pin values + for (int index = 0; index < 4; index++) + { + int currentButtonState = !digitalRead(index + pinToButtonMap); + if (currentButtonState != lastButtonState[index]) + { + if (index < 2) { + Joystick.setButton(index, currentButtonState); + lastButtonState[index] = currentButtonState; + } else { + if (currentButtonState) { + Keyboard.write(47 + index); + delay(500); + } + } + } + } + + delay(100); +} + diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/JoystickTest/JoystickTest.ino b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/JoystickTest/JoystickTest.ino new file mode 100644 index 0000000..d58ac4a --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/JoystickTest/JoystickTest.ino @@ -0,0 +1,265 @@ +// Program used to test the USB Joystick object on the +// Arduino Leonardo or Arduino Micro. +// +// Matthew Heironimus +// 2015-03-28 - Original Version +// 2015-11-18 - Updated to use the new Joystick library +// written for Arduino IDE Version 1.6.6 and +// above. +// 2016-05-13 Updated to use new dynamic Joystick library +// that can be customized. +// 2022-03-29 Updated to work with version 2.1.0 of the +// Joystick library. +//------------------------------------------------------------ + +#include "Joystick.h" + +// Create Joystick +Joystick_ Joystick; + +// Set to true to test "Auto Send" mode or false to test "Manual Send" mode. +//const bool testAutoSendMode = true; +const bool testAutoSendMode = false; + +const unsigned long gcCycleDelta = 1000; +const unsigned long gcAnalogDelta = 25; +const unsigned long gcButtonDelta = 500; +unsigned long gNextTime = 0; +unsigned int gCurrentStep = 0; + +void testSingleButtonPush(unsigned int button) +{ + if (button > 0) + { + Joystick.releaseButton(button - 1); + } + if (button < 32) + { + Joystick.pressButton(button); + } +} + +void testMultiButtonPush(unsigned int currentStep) +{ + for (int button = 0; button < 32; button++) + { + if ((currentStep == 0) || (currentStep == 2)) + { + if ((button % 2) == 0) + { + Joystick.pressButton(button); + } else if (currentStep != 2) + { + Joystick.releaseButton(button); + } + } // if ((currentStep == 0) || (currentStep == 2)) + if ((currentStep == 1) || (currentStep == 2)) + { + if ((button % 2) != 0) + { + Joystick.pressButton(button); + } else if (currentStep != 2) + { + Joystick.releaseButton(button); + } + } // if ((currentStep == 1) || (currentStep == 2)) + if (currentStep == 3) + { + Joystick.releaseButton(button); + } // if (currentStep == 3) + } // for (int button = 0; button < 32; button++) +} + +void testXYAxis(unsigned int currentStep) +{ + int xAxis; + int yAxis; + + if (currentStep < 256) + { + xAxis = currentStep - 127; + yAxis = -127; + Joystick.setXAxis(xAxis); + Joystick.setYAxis(yAxis); + } + else if (currentStep < 512) + { + yAxis = currentStep - 256 - 127; + Joystick.setYAxis(yAxis); + } + else if (currentStep < 768) + { + xAxis = 128 - (currentStep - 512); + Joystick.setXAxis(xAxis); + } + else if (currentStep < 1024) + { + yAxis = 128 - (currentStep - 768); + Joystick.setYAxis(yAxis); + } + else if (currentStep < 1024 + 128) + { + xAxis = currentStep - 1024 - 127; + Joystick.setXAxis(xAxis); + Joystick.setYAxis(xAxis); + } +} + +void testZAxis(unsigned int currentStep) +{ + int z; + + if (currentStep < 128) + { + z = -currentStep; + } + else if (currentStep < 256 + 128) + { + z = currentStep - 128 - 127; + } + else if (currentStep < 256 + 128 + 127) + { + z = 127 - (currentStep - 383); + } + + Joystick.setZAxis(z); +} + +void testHatSwitch(unsigned int currentStep) +{ + if (currentStep < 8) + { + Joystick.setHatSwitch(0, currentStep * 45); + } + else if (currentStep == 8) + { + Joystick.setHatSwitch(0, -1); + } + else if (currentStep < 17) + { + Joystick.setHatSwitch(1, (currentStep - 9) * 45); + } + else if (currentStep == 17) + { + Joystick.setHatSwitch(1, -1); + } + else if (currentStep == 18) + { + Joystick.setHatSwitch(0, 0); + Joystick.setHatSwitch(1, 0); + } + else if (currentStep < 27) + { + Joystick.setHatSwitch(0, (currentStep - 18) * 45); + Joystick.setHatSwitch(1, (8 - (currentStep - 18)) * 45); + } + else if (currentStep == 27) + { + Joystick.setHatSwitch(0, -1); + Joystick.setHatSwitch(1, -1); + } +} + +void testThrottleRudder(unsigned int value) +{ + Joystick.setThrottle(value); + Joystick.setRudder(value); +} + +void testXYZAxisRotation(unsigned int degree) +{ + Joystick.setRxAxis(degree); + Joystick.setRyAxis(degree); + Joystick.setRzAxis(degree * 2); +} + +void setup() { + + // Set Range Values + Joystick.setXAxisRange(-127, 127); + Joystick.setYAxisRange(-127, 127); + Joystick.setZAxisRange(-127, 127); + Joystick.setRxAxisRange(0, 360); + Joystick.setRyAxisRange(360, 0); + Joystick.setRzAxisRange(0, 720); + Joystick.setThrottleRange(0, 255); + Joystick.setRudderRange(255, 0); + + if (testAutoSendMode) + { + Joystick.begin(); + } + else + { + Joystick.begin(false); + } + + pinMode(A0, INPUT_PULLUP); + pinMode(LED_BUILTIN, OUTPUT); +} + +void loop() { + + // System Disabled + if (digitalRead(A0) != 0) + { + // Turn indicator light off. + digitalWrite(LED_BUILTIN, 0); + return; + } + + // Turn indicator light on. + digitalWrite(LED_BUILTIN, 1); + + if (millis() >= gNextTime) + { + + if (gCurrentStep < 33) + { + gNextTime = millis() + gcButtonDelta; + testSingleButtonPush(gCurrentStep); + } + else if (gCurrentStep < 37) + { + gNextTime = millis() + gcButtonDelta; + testMultiButtonPush(gCurrentStep - 33); + } + else if (gCurrentStep < (37 + 256)) + { + gNextTime = millis() + gcAnalogDelta; + testThrottleRudder(gCurrentStep - 37); + } + else if (gCurrentStep < (37 + 256 + 1024 + 128)) + { + gNextTime = millis() + gcAnalogDelta; + testXYAxis(gCurrentStep - (37 + 256)); + } + else if (gCurrentStep < (37 + 256 + 1024 + 128 + 510)) + { + gNextTime = millis() + gcAnalogDelta; + testZAxis(gCurrentStep - (37 + 256 + 1024 + 128)); + } + else if (gCurrentStep < (37 + 256 + 1024 + 128 + 510 + 28)) + { + gNextTime = millis() + gcButtonDelta; + testHatSwitch(gCurrentStep - (37 + 256 + 1024 + 128 + 510)); + } + else if (gCurrentStep < (37 + 256 + 1024 + 128 + 510 + 28 + 360)) + { + gNextTime = millis() + gcAnalogDelta; + testXYZAxisRotation(gCurrentStep - (37 + 256 + 1024 + 128 + 510 + 28)); + } + + if (testAutoSendMode == false) + { + Joystick.sendState(); + } + + gCurrentStep++; + if (gCurrentStep == (37 + 256 + 1024 + 128 + 510 + 28 + 360)) + { + gNextTime = millis() + gcCycleDelta; + gCurrentStep = 0; + } + } +} diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/MultipleJoystickTest/MultipleJoystickTest.ino b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/MultipleJoystickTest/MultipleJoystickTest.ino new file mode 100644 index 0000000..60735c1 --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/examples/MultipleJoystickTest/MultipleJoystickTest.ino @@ -0,0 +1,180 @@ +// Program used to test using the Arduino Joystick Library +// to create multiple Joystick objects on a single Arduino +// Leonardo or Arduino Micro. +// +// Each joystick has a unique configuration. +// +// Matthew Heironimus +// 2016-05-13 - Original Version +// 2022-03-29 - Updated to work with Joystick Library v2.1.0 +//------------------------------------------------------------ +#include + +#define JOYSTICK_COUNT 4 + +Joystick_ Joystick[JOYSTICK_COUNT] = { + Joystick_(0x03, JOYSTICK_TYPE_JOYSTICK, 4, 2, true, true, false, false, false, false, false, false, false, false, false), + Joystick_(0x04, JOYSTICK_TYPE_JOYSTICK, 8, 1, true, true, true, true, false, false, false, false, false, false, false), + Joystick_(0x05, JOYSTICK_TYPE_JOYSTICK, 16, 0, false, true, false, true, false, false, true, true, false, false, false), + Joystick_(0x06, JOYSTICK_TYPE_JOYSTICK, 32, 1, true, true, false, true, true, false, false, false, false, false, false) +}; + +// Set to true to test "Auto Send" mode or false to test "Manual Send" mode. +//const bool testAutoSendMode = true; +const bool testAutoSendMode = false; + +const unsigned long gcCycleDelta = 1000; +const unsigned long gcAnalogDelta = 25; +const unsigned long gcButtonDelta = 500; +unsigned long gNextTime = 0; +unsigned int gCurrentStep = 0; +int gJoystickId = 0; + +void testSingleButtonPush(int joystickId, unsigned int button) +{ + if (button > 0) + { + Joystick[joystickId].releaseButton(button - 1); + } + if (button < 16) + { + Joystick[joystickId].pressButton(button); + } +} + +void testMultiButtonPush(int joystickId, unsigned int currentStep) +{ + for (int button = 0; button < 16; button++) + { + if ((currentStep == 0) || (currentStep == 2)) + { + if ((button % 2) == 0) + { + Joystick[joystickId].pressButton(button); + } else if (currentStep != 2) + { + Joystick[joystickId].releaseButton(button); + } + } // if ((currentStep == 0) || (currentStep == 2)) + if ((currentStep == 1) || (currentStep == 2)) + { + if ((button % 2) != 0) + { + Joystick[joystickId].pressButton(button); + } else if (currentStep != 2) + { + Joystick[joystickId].releaseButton(button); + } + } // if ((currentStep == 1) || (currentStep == 2)) + if (currentStep == 3) + { + Joystick[joystickId].releaseButton(button); + } // if (currentStep == 3) + } // for (int button = 0; button < 32; button++) +} + +void testXYAxis(int joystickId, unsigned int currentStep) +{ + int x; + int y; + + if (currentStep < 255) + { + x = currentStep - 127; + y = -127; + } + else if (currentStep < 510) + { + x = 127; + y = currentStep - 255 - 127; + } + else if (currentStep < 765) + { + x = 127 - (currentStep - 510); + y = 127; + } + else if (currentStep < 1020) + { + x = -127; + y = 127 - (currentStep - 765); + } + else if (currentStep <= 1020 + 127) + { + x = currentStep - 1020 - 127; + y = currentStep - 1020 - 127; + } + + Joystick[joystickId].setXAxis(x); + Joystick[joystickId].setYAxis(y); +} + +void setup() { + + for (int index = 0; index < JOYSTICK_COUNT; index++) + { + Joystick[index].setXAxisRange(-127, 127); + Joystick[index].setYAxisRange(-127, 127); + + if (testAutoSendMode) + { + Joystick[index].begin(); + } + else + { + Joystick[index].begin(false); + } + } + + pinMode(A0, INPUT_PULLUP); + pinMode(LED_BUILTIN, OUTPUT); +} + +void loop() { + + // System Disabled + if (digitalRead(A0) != 0) + { + digitalWrite(LED_BUILTIN, 0); + return; + } + + // Turn indicator light on. + digitalWrite(LED_BUILTIN, 1); + + if (millis() >= gNextTime) + { + + if (gCurrentStep < 17) + { + gNextTime = millis() + gcButtonDelta; + testSingleButtonPush(gJoystickId, gCurrentStep); + } + else if (gCurrentStep < (17 + 4)) + { + gNextTime = millis() + gcButtonDelta; + testMultiButtonPush(gJoystickId, gCurrentStep - 17); + } + else if (gCurrentStep < (17 + 4 + 1024 + 128)) + { + gNextTime = millis() + gcAnalogDelta; + testXYAxis(gJoystickId, gCurrentStep - (17 + 4)); + } + + if (testAutoSendMode == false) + { + Joystick[gJoystickId].sendState(); + } + + gCurrentStep++; + if (gCurrentStep == (17 + 4 + 1024 + 128)) + { + gNextTime = millis() + gcCycleDelta; + gCurrentStep = 0; + + if (++gJoystickId >= JOYSTICK_COUNT) + { + gJoystickId = 0; + } + } + } +} diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/library.properties b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/library.properties new file mode 100644 index 0000000..3e3fe88 --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/library.properties @@ -0,0 +1,9 @@ +name=Joystick +version=2.1.1 +author=Matthew Heironimus +maintainer=Matthew Heironimus +sentence=Allows an Arduino board with USB capabilities (e.g. Leonardo, Arduino Micro, Arudino Due, etc.) to appear as a Joystick or Gamepad. +paragraph=This library is built on the PluggableUSB library. It can be used with or without other HID-based libraries (Mouse, Keyboard, etc.). +category=Device Control +url=https://github.com/MHeironimus/ArduinoJoystickLibrary +architectures=avr,sam diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/src/DynamicHID/DynamicHID.cpp b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/src/DynamicHID/DynamicHID.cpp new file mode 100644 index 0000000..6c46a2c --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/src/DynamicHID/DynamicHID.cpp @@ -0,0 +1,169 @@ +/* + Modified by Matthew Heironimus to support HID Report Descriptors to be in + standard RAM in addition to program memory (PROGMEM). + + Copyright (c) 2015, Arduino LLC + Original code (pre-library): Copyright (c) 2011, Peter Barrett + + Permission to use, copy, modify, and/or distribute this software for + any purpose with or without fee is hereby granted, provided that the + above copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR + BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. + */ + +#include "DynamicHID.h" + +#if defined(USBCON) + +#ifdef _VARIANT_ARDUINO_DUE_X_ +#define USB_SendControl USBD_SendControl +#define USB_Send USBD_Send +#endif + +DynamicHID_& DynamicHID() +{ + static DynamicHID_ obj; + return obj; +} + +int DynamicHID_::getInterface(uint8_t* interfaceCount) +{ + *interfaceCount += 1; // uses 1 + DYNAMIC_HIDDescriptor hidInterface = { + D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, DYNAMIC_HID_SUBCLASS_NONE, DYNAMIC_HID_PROTOCOL_NONE), + D_HIDREPORT(descriptorSize), + D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01) + }; + return USB_SendControl(0, &hidInterface, sizeof(hidInterface)); +} + +int DynamicHID_::getDescriptor(USBSetup& setup) +{ + // Check if this is a HID Class Descriptor request + if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; } + if (setup.wValueH != DYNAMIC_HID_REPORT_DESCRIPTOR_TYPE) { return 0; } + + // In a HID Class Descriptor wIndex cointains the interface number + if (setup.wIndex != pluggedInterface) { return 0; } + + int total = 0; + DynamicHIDSubDescriptor* node; + for (node = rootNode; node; node = node->next) { + int res = USB_SendControl((node->inProgMem ? TRANSFER_PGM : 0), node->data, node->length); + if (res == -1) + return -1; + total += res; + } + + // Reset the protocol on reenumeration. Normally the host should not assume the state of the protocol + // due to the USB specs, but Windows and Linux just assumes its in report mode. + protocol = DYNAMIC_HID_REPORT_PROTOCOL; + + return total; +} + +uint8_t DynamicHID_::getShortName(char *name) +{ + name[0] = 'H'; + name[1] = 'I'; + name[2] = 'D'; + name[3] = 'A' + (descriptorSize & 0x0F); + name[4] = 'A' + ((descriptorSize >> 4) & 0x0F); + return 5; +} + +void DynamicHID_::AppendDescriptor(DynamicHIDSubDescriptor *node) +{ + if (!rootNode) { + rootNode = node; + } else { + DynamicHIDSubDescriptor *current = rootNode; + while (current->next) { + current = current->next; + } + current->next = node; + } + descriptorSize += node->length; +} + +int DynamicHID_::SendReport(uint8_t id, const void* data, int len) +{ + uint8_t p[len + 1]; + p[0] = id; + memcpy(&p[1], data, len); + return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, p, len + 1); +} + +bool DynamicHID_::setup(USBSetup& setup) +{ + if (pluggedInterface != setup.wIndex) { + return false; + } + + uint8_t request = setup.bRequest; + uint8_t requestType = setup.bmRequestType; + + if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE) + { + if (request == DYNAMIC_HID_GET_REPORT) { + // TODO: DYNAMIC_HID_GetReport(); + return true; + } + if (request == DYNAMIC_HID_GET_PROTOCOL) { + // TODO: Send8(protocol); + return true; + } + if (request == DYNAMIC_HID_GET_IDLE) { + // TODO: Send8(idle); + } + } + + if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE) + { + if (request == DYNAMIC_HID_SET_PROTOCOL) { + // The USB Host tells us if we are in boot or report mode. + // This only works with a real boot compatible device. + protocol = setup.wValueL; + return true; + } + if (request == DYNAMIC_HID_SET_IDLE) { + idle = setup.wValueL; + return true; + } + if (request == DYNAMIC_HID_SET_REPORT) + { + //uint8_t reportID = setup.wValueL; + //uint16_t length = setup.wLength; + //uint8_t data[length]; + // Make sure to not read more data than USB_EP_SIZE. + // You can read multiple times through a loop. + // The first byte (may!) contain the reportID on a multreport. + //USB_RecvControl(data, length); + } + } + + return false; +} + +DynamicHID_::DynamicHID_(void) : PluggableUSBModule(1, 1, epType), + rootNode(NULL), descriptorSize(0), + protocol(DYNAMIC_HID_REPORT_PROTOCOL), idle(1) +{ + epType[0] = EP_TYPE_INTERRUPT_IN; + PluggableUSB().plug(this); +} + +int DynamicHID_::begin(void) +{ + return 0; +} + +#endif /* if defined(USBCON) */ diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/src/DynamicHID/DynamicHID.h b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/src/DynamicHID/DynamicHID.h new file mode 100644 index 0000000..0a9a6ef --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/src/DynamicHID/DynamicHID.h @@ -0,0 +1,144 @@ +/* + Modified by Matthew Heironimus to support HID Report Descriptors to be in + standard RAM in addition to program memory (PROGMEM). + + Copyright (c) 2015, Arduino LLC + Original code (pre-library): Copyright (c) 2011, Peter Barrett + + Permission to use, copy, modify, and/or distribute this software for + any purpose with or without fee is hereby granted, provided that the + above copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR + BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. + */ + +#ifndef DYNAMIC_HID_h +#define DYNAMIC_HID_h + +#include +#include + +#ifdef _VARIANT_ARDUINO_DUE_X_ + // The following values are the same as AVR's USBAPI.h + // Reproduced here because SAM doesn't have these in + // its own USBAPI.H + #define USB_EP_SIZE 64 + #define TRANSFER_PGM 0x80 + + #include "USB/PluggableUSB.h" +#else + #include "PluggableUSB.h" +#endif + +#if defined(USBCON) + +#define _USING_DYNAMIC_HID + +// DYNAMIC_HID 'Driver' +// ------------ +#define DYNAMIC_HID_GET_REPORT 0x01 +#define DYNAMIC_HID_GET_IDLE 0x02 +#define DYNAMIC_HID_GET_PROTOCOL 0x03 +#define DYNAMIC_HID_SET_REPORT 0x09 +#define DYNAMIC_HID_SET_IDLE 0x0A +#define DYNAMIC_HID_SET_PROTOCOL 0x0B + +#define DYNAMIC_HID_DESCRIPTOR_TYPE 0x21 +#define DYNAMIC_HID_REPORT_DESCRIPTOR_TYPE 0x22 +#define DYNAMIC_HID_PHYSICAL_DESCRIPTOR_TYPE 0x23 + +// HID subclass HID1.11 Page 8 4.2 Subclass +#define DYNAMIC_HID_SUBCLASS_NONE 0 +#define DYNAMIC_HID_SUBCLASS_BOOT_INTERFACE 1 + +// HID Keyboard/Mouse bios compatible protocols HID1.11 Page 9 4.3 Protocols +#define DYNAMIC_HID_PROTOCOL_NONE 0 +#define DYNAMIC_HID_PROTOCOL_KEYBOARD 1 +#define DYNAMIC_HID_PROTOCOL_MOUSE 2 + +// Normal or bios protocol (Keyboard/Mouse) HID1.11 Page 54 7.2.5 Get_Protocol Request +// "protocol" variable is used for this purpose. +#define DYNAMIC_HID_BOOT_PROTOCOL 0 +#define DYNAMIC_HID_REPORT_PROTOCOL 1 + +// HID Request Type HID1.11 Page 51 7.2.1 Get_Report Request +#define DYNAMIC_HID_REPORT_TYPE_INPUT 1 +#define DYNAMIC_HID_REPORT_TYPE_OUTPUT 2 +#define DYNAMIC_HID_REPORT_TYPE_FEATURE 3 + +typedef struct +{ + uint8_t len; // 9 + uint8_t dtype; // 0x21 + uint8_t addr; + uint8_t versionL; // 0x101 + uint8_t versionH; // 0x101 + uint8_t country; + uint8_t desctype; // 0x22 report + uint8_t descLenL; + uint8_t descLenH; +} DYNAMIC_HIDDescDescriptor; + +typedef struct +{ + InterfaceDescriptor hid; + DYNAMIC_HIDDescDescriptor desc; + EndpointDescriptor in; +} DYNAMIC_HIDDescriptor; + +class DynamicHIDSubDescriptor { +public: + DynamicHIDSubDescriptor *next = NULL; + DynamicHIDSubDescriptor(const void *d, const uint16_t l, const bool ipm = true) : data(d), length(l), inProgMem(ipm) { } + + const void* data; + const uint16_t length; + const bool inProgMem; +}; + +class DynamicHID_ : public PluggableUSBModule +{ +public: + DynamicHID_(void); + int begin(void); + int SendReport(uint8_t id, const void* data, int len); + void AppendDescriptor(DynamicHIDSubDescriptor* node); + +protected: + // Implementation of the PluggableUSBModule + int getInterface(uint8_t* interfaceCount); + int getDescriptor(USBSetup& setup); + bool setup(USBSetup& setup); + uint8_t getShortName(char* name); + +private: + #ifdef _VARIANT_ARDUINO_DUE_X_ + uint32_t epType[1]; + #else + uint8_t epType[1]; + #endif + + DynamicHIDSubDescriptor* rootNode; + uint16_t descriptorSize; + + uint8_t protocol; + uint8_t idle; +}; + +// Replacement for global singleton. +// This function prevents static-initialization-order-fiasco +// https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use +DynamicHID_& DynamicHID(); + +#define D_HIDREPORT(length) { 9, 0x21, 0x01, 0x01, 0, 1, 0x22, lowByte(length), highByte(length) } + +#endif // USBCON + +#endif // DYNAMIC_HID_h diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/src/JoystickMHX.cpp b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/src/JoystickMHX.cpp new file mode 100644 index 0000000..8777cc3 --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/src/JoystickMHX.cpp @@ -0,0 +1,716 @@ +/* + JoystickMH.cpp + + Copyright (c) 2015-2017, Matthew Heironimus + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "JoystickMHX.h" + +#if defined(_USING_DYNAMIC_HID) + +#define JOYSTICK_REPORT_ID_INDEX 7 +#define JOYSTICK_AXIS_MINIMUM -32767 +#define JOYSTICK_AXIS_MAXIMUM 32767 +#define JOYSTICK_SIMULATOR_MINIMUM -32767 +#define JOYSTICK_SIMULATOR_MAXIMUM 32767 + +#define JOYSTICK_INCLUDE_X_AXIS B00000001 +#define JOYSTICK_INCLUDE_Y_AXIS B00000010 +#define JOYSTICK_INCLUDE_Z_AXIS B00000100 +#define JOYSTICK_INCLUDE_RX_AXIS B00001000 +#define JOYSTICK_INCLUDE_RY_AXIS B00010000 +#define JOYSTICK_INCLUDE_RZ_AXIS B00100000 +#define JOYSTICK_INCLUDE_S_AXIS B01000000 +#define JOYSTICK_INCLUDE_D_AXIS B10000000 + +#define JOYSTICK_INCLUDE_RUDDER B00000001 +#define JOYSTICK_INCLUDE_THROTTLE B00000010 +#define JOYSTICK_INCLUDE_ACCELERATOR B00000100 +#define JOYSTICK_INCLUDE_BRAKE B00001000 +#define JOYSTICK_INCLUDE_STEERING B00010000 + +Joystick_::Joystick_( + uint8_t hidReportId, + uint8_t joystickType, + uint8_t buttonCount, + uint8_t hatSwitchCount, + bool includeXAxis, + bool includeYAxis, + bool includeZAxis, + bool includeRxAxis, + bool includeRyAxis, + bool includeRzAxis, + bool includeSlider, + bool includeDial, + bool includeRudder, + bool includeThrottle, + bool includeAccelerator, + bool includeBrake, + bool includeSteering) +{ + // Set the USB HID Report ID + _hidReportId = hidReportId; + + // Save Joystick Settings + _buttonCount = buttonCount; + _hatSwitchCount = hatSwitchCount; + _includeAxisFlags = 0; + _includeAxisFlags |= (includeXAxis ? JOYSTICK_INCLUDE_X_AXIS : 0); + _includeAxisFlags |= (includeYAxis ? JOYSTICK_INCLUDE_Y_AXIS : 0); + _includeAxisFlags |= (includeZAxis ? JOYSTICK_INCLUDE_Z_AXIS : 0); + _includeAxisFlags |= (includeRxAxis ? JOYSTICK_INCLUDE_RX_AXIS : 0); + _includeAxisFlags |= (includeRyAxis ? JOYSTICK_INCLUDE_RY_AXIS : 0); + _includeAxisFlags |= (includeRzAxis ? JOYSTICK_INCLUDE_RZ_AXIS : 0); + _includeAxisFlags |= (includeSlider ? JOYSTICK_INCLUDE_S_AXIS : 0); + _includeAxisFlags |= (includeDial ? JOYSTICK_INCLUDE_D_AXIS : 0); + _includeSimulatorFlags = 0; + _includeSimulatorFlags |= (includeRudder ? JOYSTICK_INCLUDE_RUDDER : 0); + _includeSimulatorFlags |= (includeThrottle ? JOYSTICK_INCLUDE_THROTTLE : 0); + _includeSimulatorFlags |= (includeAccelerator ? JOYSTICK_INCLUDE_ACCELERATOR : 0); + _includeSimulatorFlags |= (includeBrake ? JOYSTICK_INCLUDE_BRAKE : 0); + _includeSimulatorFlags |= (includeSteering ? JOYSTICK_INCLUDE_STEERING : 0); + + // Build Joystick HID Report Description + + // Button Calculations + uint8_t buttonsInLastByte = _buttonCount % 8; + uint8_t buttonPaddingBits = 0; + if (buttonsInLastByte > 0) + { + buttonPaddingBits = 8 - buttonsInLastByte; + } + + // Axis Calculations + uint8_t axisCount = (includeXAxis == true) + + (includeYAxis == true) + + (includeZAxis == true) + + (includeRxAxis == true) + + (includeRyAxis == true) + + (includeRzAxis == true) + + (includeSlider == true) + + (includeDial == true); + + uint8_t simulationCount = (includeRudder == true) + + (includeThrottle == true) + + (includeAccelerator == true) + + (includeBrake == true) + + (includeSteering == true); + + uint8_t tempHidReportDescriptor[150]; + int hidReportDescriptorSize = 0; + + // USAGE_PAGE (Generic Desktop) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x05; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // USAGE (Joystick - 0x04; Gamepad - 0x05; Multi-axis Controller - 0x08) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = joystickType; + + // COLLECTION (Application) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xa1; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // REPORT_ID (Default: 3) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x85; + tempHidReportDescriptor[hidReportDescriptorSize++] = _hidReportId; + + if (_buttonCount > 0) { + + // USAGE_PAGE (Button) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x05; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + + // USAGE_MINIMUM (Button 1) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x19; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // USAGE_MAXIMUM (Button 32) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x29; + tempHidReportDescriptor[hidReportDescriptorSize++] = _buttonCount; + + // LOGICAL_MINIMUM (0) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x15; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // LOGICAL_MAXIMUM (1) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x25; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // REPORT_SIZE (1) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x75; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // REPORT_COUNT (# of buttons) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x95; + tempHidReportDescriptor[hidReportDescriptorSize++] = _buttonCount; + + // UNIT_EXPONENT (0) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x55; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // UNIT (None) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x65; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // INPUT (Data,Var,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x81; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; + + if (buttonPaddingBits > 0) { + + // REPORT_SIZE (1) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x75; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // REPORT_COUNT (# of padding bits) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x95; + tempHidReportDescriptor[hidReportDescriptorSize++] = buttonPaddingBits; + + // INPUT (Const,Var,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x81; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x03; + + } // Padding Bits Needed + + } // Buttons + + if ((axisCount > 0) || (_hatSwitchCount > 0)) { + + // USAGE_PAGE (Generic Desktop) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x05; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + } + + if (_hatSwitchCount > 0) { + + // USAGE (Hat Switch) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x39; + + // LOGICAL_MINIMUM (0) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x15; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // LOGICAL_MAXIMUM (7) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x25; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x07; + + // PHYSICAL_MINIMUM (0) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x35; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // PHYSICAL_MAXIMUM (315) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x46; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x3B; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // UNIT (Eng Rot:Angular Pos) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x65; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x14; + + // REPORT_SIZE (4) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x75; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x04; + + // REPORT_COUNT (1) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x95; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // INPUT (Data,Var,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x81; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; + + if (_hatSwitchCount > 1) { + + // USAGE (Hat Switch) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x39; + + // LOGICAL_MINIMUM (0) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x15; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // LOGICAL_MAXIMUM (7) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x25; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x07; + + // PHYSICAL_MINIMUM (0) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x35; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // PHYSICAL_MAXIMUM (315) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x46; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x3B; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // UNIT (Eng Rot:Angular Pos) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x65; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x14; + + // REPORT_SIZE (4) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x75; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x04; + + // REPORT_COUNT (1) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x95; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // INPUT (Data,Var,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x81; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; + + } else { + + // Use Padding Bits + + // REPORT_SIZE (1) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x75; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // REPORT_COUNT (4) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x95; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x04; + + // INPUT (Const,Var,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x81; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x03; + + } // One or Two Hat Switches? + + } // Hat Switches + + if (axisCount > 0) { + + // USAGE (Pointer) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // LOGICAL_MINIMUM (-32767) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x16; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x80; + + // LOGICAL_MAXIMUM (+32767) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x26; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xFF; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x7F; + + // REPORT_SIZE (16) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x75; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x10; + + // REPORT_COUNT (axisCount) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x95; + tempHidReportDescriptor[hidReportDescriptorSize++] = axisCount; + + // COLLECTION (Physical) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xA1; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + if (includeXAxis == true) { + // USAGE (X) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x30; + } + + if (includeYAxis == true) { + // USAGE (Y) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x31; + } + + if (includeZAxis == true) { + // USAGE (Z) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x32; + } + + if (includeRxAxis == true) { + // USAGE (Rx) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x33; + } + + if (includeRyAxis == true) { + // USAGE (Ry) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x34; + } + + if (includeRzAxis == true) { + // USAGE (Rz) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x35; + } + + if (includeSlider == true) { + // USAGE (Rz) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x36; + } + + if (includeDial == true) { + // USAGE (Rz) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x37; + } + + // INPUT (Data,Var,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x81; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; + + // END_COLLECTION (Physical) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xc0; + + } // X, Y, Z, Rx, Ry, and Rz Axis + + if (simulationCount > 0) { + + // USAGE_PAGE (Simulation Controls) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x05; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; + + // LOGICAL_MINIMUM (-32767) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x16; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x80; + + // LOGICAL_MAXIMUM (+32767) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x26; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xFF; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x7F; + + // REPORT_SIZE (16) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x75; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x10; + + // REPORT_COUNT (simulationCount) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x95; + tempHidReportDescriptor[hidReportDescriptorSize++] = simulationCount; + + // COLLECTION (Physical) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xA1; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + if (includeRudder == true) { + // USAGE (Rudder) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xBA; + } + + if (includeThrottle == true) { + // USAGE (Throttle) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xBB; + } + + if (includeAccelerator == true) { + // USAGE (Accelerator) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xC4; + } + + if (includeBrake == true) { + // USAGE (Brake) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xC5; + } + + if (includeSteering == true) { + // USAGE (Steering) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xC8; + } + + // INPUT (Data,Var,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x81; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; + + // END_COLLECTION (Physical) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xc0; + + } // Simulation Controls + + // END_COLLECTION + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xc0; + + // Create a copy of the HID Report Descriptor template that is just the right size + uint8_t *customHidReportDescriptor = new uint8_t[hidReportDescriptorSize]; + memcpy(customHidReportDescriptor, tempHidReportDescriptor, hidReportDescriptorSize); + + // Register HID Report Description + DynamicHIDSubDescriptor *node = new DynamicHIDSubDescriptor(customHidReportDescriptor, hidReportDescriptorSize, false); + DynamicHID().AppendDescriptor(node); + + // Setup Joystick State + if (buttonCount > 0) { + _buttonValuesArraySize = _buttonCount / 8; + if ((_buttonCount % 8) > 0) { + _buttonValuesArraySize++; + } + _buttonValues = new uint8_t[_buttonValuesArraySize]; + } + + // Calculate HID Report Size + _hidReportSize = _buttonValuesArraySize; + _hidReportSize += (_hatSwitchCount > 0); + _hidReportSize += (axisCount * 2); + _hidReportSize += (simulationCount * 2); + + // Initalize Joystick State + _xAxis = 0; + _yAxis = 0; + _zAxis = 0; + _xAxisRotation = 0; + _yAxisRotation = 0; + _zAxisRotation = 0; + _slider = 0; + _dial = 0; + _throttle = 0; + _rudder = 0; + _accelerator = 0; + _brake = 0; + _steering = 0; + for (int index = 0; index < JOYSTICK_HATSWITCH_COUNT_MAXIMUM; index++) + { + _hatSwitchValues[index] = JOYSTICK_HATSWITCH_RELEASE; + } + for (int index = 0; index < _buttonValuesArraySize; index++) + { + _buttonValues[index] = 0; + } +} + +void Joystick_::begin(bool initAutoSendState) +{ + _autoSendState = initAutoSendState; + sendState(); +} + +void Joystick_::end() +{ +} + +void Joystick_::setButton(uint8_t button, uint8_t value) +{ + if (value == 0) + { + releaseButton(button); + } + else + { + pressButton(button); + } +} +void Joystick_::pressButton(uint8_t button) +{ + if (button >= _buttonCount) return; + + int index = button / 8; + int bit = button % 8; + + bitSet(_buttonValues[index], bit); + if (_autoSendState) sendState(); +} +void Joystick_::releaseButton(uint8_t button) +{ + if (button >= _buttonCount) return; + + int index = button / 8; + int bit = button % 8; + + bitClear(_buttonValues[index], bit); + if (_autoSendState) sendState(); +} + +void Joystick_::setXAxis(int16_t value) +{ + _xAxis = value; + if (_autoSendState) sendState(); +} +void Joystick_::setYAxis(int16_t value) +{ + _yAxis = value; + if (_autoSendState) sendState(); +} +void Joystick_::setZAxis(int16_t value) +{ + _zAxis = value; + if (_autoSendState) sendState(); +} + +void Joystick_::setRxAxis(int16_t value) +{ + _xAxisRotation = value; + if (_autoSendState) sendState(); +} +void Joystick_::setRyAxis(int16_t value) +{ + _yAxisRotation = value; + if (_autoSendState) sendState(); +} +void Joystick_::setRzAxis(int16_t value) +{ + _zAxisRotation = value; + if (_autoSendState) sendState(); +} +void Joystick_::setSlider(int16_t value) +{ + _slider = value; + if (_autoSendState) sendState(); +} +void Joystick_::setDial(int16_t value) +{ + _dial = value; + if (_autoSendState) sendState(); +} + + +void Joystick_::setRudder(int16_t value) +{ + _rudder = value; + if (_autoSendState) sendState(); +} +void Joystick_::setThrottle(int16_t value) +{ + _throttle = value; + if (_autoSendState) sendState(); +} +void Joystick_::setAccelerator(int16_t value) +{ + _accelerator = value; + if (_autoSendState) sendState(); +} +void Joystick_::setBrake(int16_t value) +{ + _brake = value; + if (_autoSendState) sendState(); +} +void Joystick_::setSteering(int16_t value) +{ + _steering = value; + if (_autoSendState) sendState(); +} + +void Joystick_::setHatSwitch(int8_t hatSwitchIndex, int16_t value) +{ + if (hatSwitchIndex >= _hatSwitchCount) return; + + _hatSwitchValues[hatSwitchIndex] = value; + if (_autoSendState) sendState(); +} + +int Joystick_::buildAndSet16BitValue(bool includeValue, int16_t value, int16_t valueMinimum, int16_t valueMaximum, int16_t actualMinimum, int16_t actualMaximum, uint8_t dataLocation[]) +{ + int16_t convertedValue; + uint8_t highByte; + uint8_t lowByte; + int16_t realMinimum = min(valueMinimum, valueMaximum); + int16_t realMaximum = max(valueMinimum, valueMaximum); + + if (includeValue == false) return 0; + + if (value < realMinimum) { + value = realMinimum; + } + if (value > realMaximum) { + value = realMaximum; + } + + if (valueMinimum > valueMaximum) { + // Values go from a larger number to a smaller number (e.g. 1024 to 0) + value = realMaximum - value + realMinimum; + } + + convertedValue = map(value, realMinimum, realMaximum, actualMinimum, actualMaximum); + + highByte = (uint8_t)(convertedValue >> 8); + lowByte = (uint8_t)(convertedValue & 0x00FF); + + dataLocation[0] = lowByte; + dataLocation[1] = highByte; + + return 2; +} + +int Joystick_::buildAndSetAxisValue(bool includeAxis, int16_t axisValue, int16_t axisMinimum, int16_t axisMaximum, uint8_t dataLocation[]) +{ + return buildAndSet16BitValue(includeAxis, axisValue, axisMinimum, axisMaximum, JOYSTICK_AXIS_MINIMUM, JOYSTICK_AXIS_MAXIMUM, dataLocation); +} + +int Joystick_::buildAndSetSimulationValue(bool includeValue, int16_t value, int16_t valueMinimum, int16_t valueMaximum, uint8_t dataLocation[]) +{ + return buildAndSet16BitValue(includeValue, value, valueMinimum, valueMaximum, JOYSTICK_SIMULATOR_MINIMUM, JOYSTICK_SIMULATOR_MAXIMUM, dataLocation); +} + +void Joystick_::sendState() +{ + uint8_t data[_hidReportSize]; + int index = 0; + + // Load Button State + for (; index < _buttonValuesArraySize; index++) + { + data[index] = _buttonValues[index]; + } + + // Set Hat Switch Values + if (_hatSwitchCount > 0) { + + // Calculate hat-switch values + uint8_t convertedHatSwitch[JOYSTICK_HATSWITCH_COUNT_MAXIMUM]; + for (int hatSwitchIndex = 0; hatSwitchIndex < JOYSTICK_HATSWITCH_COUNT_MAXIMUM; hatSwitchIndex++) + { + if (_hatSwitchValues[hatSwitchIndex] < 0) + { + convertedHatSwitch[hatSwitchIndex] = 8; + } + else + { + convertedHatSwitch[hatSwitchIndex] = (_hatSwitchValues[hatSwitchIndex] % 360) / 45; + } + } + + // Pack hat-switch states into a single byte + data[index++] = (convertedHatSwitch[1] << 4) | (B00001111 & convertedHatSwitch[0]); + + } // Hat Switches + + // Set Axis Values + index += buildAndSetAxisValue(_includeAxisFlags & JOYSTICK_INCLUDE_X_AXIS, _xAxis, _xAxisMinimum, _xAxisMaximum, &(data[index])); + index += buildAndSetAxisValue(_includeAxisFlags & JOYSTICK_INCLUDE_Y_AXIS, _yAxis, _yAxisMinimum, _yAxisMaximum, &(data[index])); + index += buildAndSetAxisValue(_includeAxisFlags & JOYSTICK_INCLUDE_Z_AXIS, _zAxis, _zAxisMinimum, _zAxisMaximum, &(data[index])); + index += buildAndSetAxisValue(_includeAxisFlags & JOYSTICK_INCLUDE_RX_AXIS, _xAxisRotation, _rxAxisMinimum, _rxAxisMaximum, &(data[index])); + index += buildAndSetAxisValue(_includeAxisFlags & JOYSTICK_INCLUDE_RY_AXIS, _yAxisRotation, _ryAxisMinimum, _ryAxisMaximum, &(data[index])); + index += buildAndSetAxisValue(_includeAxisFlags & JOYSTICK_INCLUDE_RZ_AXIS, _zAxisRotation, _rzAxisMinimum, _rzAxisMaximum, &(data[index])); + index += buildAndSetAxisValue(_includeAxisFlags & JOYSTICK_INCLUDE_S_AXIS, _slider, _sliderMinimum, _sliderMaximum, &(data[index])); + index += buildAndSetAxisValue(_includeAxisFlags & JOYSTICK_INCLUDE_D_AXIS, _dial, _dialMinimum, _dialMaximum, &(data[index])); + + + // Set Simulation Values + index += buildAndSetSimulationValue(_includeSimulatorFlags & JOYSTICK_INCLUDE_RUDDER, _rudder, _rudderMinimum, _rudderMaximum, &(data[index])); + index += buildAndSetSimulationValue(_includeSimulatorFlags & JOYSTICK_INCLUDE_THROTTLE, _throttle, _throttleMinimum, _throttleMaximum, &(data[index])); + index += buildAndSetSimulationValue(_includeSimulatorFlags & JOYSTICK_INCLUDE_ACCELERATOR, _accelerator, _acceleratorMinimum, _acceleratorMaximum, &(data[index])); + index += buildAndSetSimulationValue(_includeSimulatorFlags & JOYSTICK_INCLUDE_BRAKE, _brake, _brakeMinimum, _brakeMaximum, &(data[index])); + index += buildAndSetSimulationValue(_includeSimulatorFlags & JOYSTICK_INCLUDE_STEERING, _steering, _steeringMinimum, _steeringMaximum, &(data[index])); + + DynamicHID().SendReport(_hidReportId, data, _hidReportSize); +} + +#endif diff --git a/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/src/JoystickMHX.h b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/src/JoystickMHX.h new file mode 100644 index 0000000..8999f5a --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/ArduinoJoystickLibrary/src/JoystickMHX.h @@ -0,0 +1,241 @@ +/* + JoystickMH.h + + Copyright (c) 2015-2017, Matthew Heironimus + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef JOYSTICKMHX_h +#define JOYSTICKMHX_h + +#include "DynamicHID/DynamicHID.h" + +#if ARDUINO < 10606 +#error The Joystick library requires Arduino IDE 1.6.6 or greater. Please update your IDE. +#endif // ARDUINO < 10606 + +#if ARDUINO > 10606 +#if !defined(USBCON) +#error The Joystick library can only be used with a USB MCU (e.g. Arduino Leonardo, Arduino Micro, etc.). +#endif // !defined(USBCON) +#endif // ARDUINO > 10606 + +#if !defined(_USING_DYNAMIC_HID) + +#warning "Using legacy HID core (non pluggable)" + +#else // !defined(_USING_DYNAMIC_HID) + +//================================================================================ +// Joystick (Gamepad) + +#define JOYSTICK_DEFAULT_REPORT_ID 0x03 +#define JOYSTICK_DEFAULT_BUTTON_COUNT 32 +#define JOYSTICK_DEFAULT_AXIS_MINIMUM 0 +#define JOYSTICK_DEFAULT_AXIS_MAXIMUM 1023 +#define JOYSTICK_DEFAULT_SIMULATOR_MINIMUM 0 +#define JOYSTICK_DEFAULT_SIMULATOR_MAXIMUM 1023 +#define JOYSTICK_DEFAULT_HATSWITCH_COUNT 2 +#define JOYSTICK_HATSWITCH_COUNT_MAXIMUM 2 +#define JOYSTICK_HATSWITCH_RELEASE -1 +#define JOYSTICK_TYPE_JOYSTICK 0x04 +#define JOYSTICK_TYPE_GAMEPAD 0x05 +#define JOYSTICK_TYPE_MULTI_AXIS 0x08 + +class Joystick_ +{ +private: + + // Joystick State + int16_t _xAxis; + int16_t _yAxis; + int16_t _zAxis; + int16_t _xAxisRotation; + int16_t _yAxisRotation; + int16_t _zAxisRotation; + int16_t _slider; + int16_t _dial; + + int16_t _throttle; + int16_t _rudder; + int16_t _accelerator; + int16_t _brake; + int16_t _steering; + int16_t _hatSwitchValues[JOYSTICK_HATSWITCH_COUNT_MAXIMUM]; + uint8_t *_buttonValues = NULL; + + // Joystick Settings + bool _autoSendState; + uint8_t _buttonCount; + uint8_t _buttonValuesArraySize = 0; + uint8_t _hatSwitchCount; + uint8_t _includeAxisFlags; + uint8_t _includeSimulatorFlags; + int16_t _xAxisMinimum = JOYSTICK_DEFAULT_AXIS_MINIMUM; + int16_t _xAxisMaximum = JOYSTICK_DEFAULT_AXIS_MAXIMUM; + int16_t _yAxisMinimum = JOYSTICK_DEFAULT_AXIS_MINIMUM; + int16_t _yAxisMaximum = JOYSTICK_DEFAULT_AXIS_MAXIMUM; + int16_t _zAxisMinimum = JOYSTICK_DEFAULT_AXIS_MINIMUM; + int16_t _zAxisMaximum = JOYSTICK_DEFAULT_AXIS_MAXIMUM; + int16_t _rxAxisMinimum = JOYSTICK_DEFAULT_AXIS_MINIMUM; + int16_t _rxAxisMaximum = JOYSTICK_DEFAULT_AXIS_MAXIMUM; + int16_t _ryAxisMinimum = JOYSTICK_DEFAULT_AXIS_MINIMUM; + int16_t _ryAxisMaximum = JOYSTICK_DEFAULT_AXIS_MAXIMUM; + int16_t _rzAxisMinimum = JOYSTICK_DEFAULT_AXIS_MINIMUM; + int16_t _rzAxisMaximum = JOYSTICK_DEFAULT_AXIS_MAXIMUM; + int16_t _sliderMinimum = JOYSTICK_DEFAULT_AXIS_MINIMUM; + int16_t _sliderMaximum = JOYSTICK_DEFAULT_AXIS_MAXIMUM; + int16_t _dialMinimum = JOYSTICK_DEFAULT_AXIS_MINIMUM; + int16_t _dialMaximum = JOYSTICK_DEFAULT_AXIS_MAXIMUM; + + int16_t _rudderMinimum = JOYSTICK_DEFAULT_SIMULATOR_MINIMUM; + int16_t _rudderMaximum = JOYSTICK_DEFAULT_SIMULATOR_MAXIMUM; + int16_t _throttleMinimum = JOYSTICK_DEFAULT_SIMULATOR_MINIMUM; + int16_t _throttleMaximum = JOYSTICK_DEFAULT_SIMULATOR_MAXIMUM; + int16_t _acceleratorMinimum = JOYSTICK_DEFAULT_SIMULATOR_MINIMUM; + int16_t _acceleratorMaximum = JOYSTICK_DEFAULT_SIMULATOR_MAXIMUM; + int16_t _brakeMinimum = JOYSTICK_DEFAULT_SIMULATOR_MINIMUM; + int16_t _brakeMaximum = JOYSTICK_DEFAULT_SIMULATOR_MAXIMUM; + int16_t _steeringMinimum = JOYSTICK_DEFAULT_SIMULATOR_MINIMUM; + int16_t _steeringMaximum = JOYSTICK_DEFAULT_SIMULATOR_MAXIMUM; + + uint8_t _hidReportId; + uint8_t _hidReportSize; + +protected: + int buildAndSet16BitValue(bool includeValue, int16_t value, int16_t valueMinimum, int16_t valueMaximum, int16_t actualMinimum, int16_t actualMaximum, uint8_t dataLocation[]); + int buildAndSetAxisValue(bool includeAxis, int16_t axisValue, int16_t axisMinimum, int16_t axisMaximum, uint8_t dataLocation[]); + int buildAndSetSimulationValue(bool includeValue, int16_t value, int16_t valueMinimum, int16_t valueMaximum, uint8_t dataLocation[]); + +public: + Joystick_( + uint8_t hidReportId = JOYSTICK_DEFAULT_REPORT_ID, + uint8_t joystickType = JOYSTICK_TYPE_JOYSTICK, + uint8_t buttonCount = JOYSTICK_DEFAULT_BUTTON_COUNT, + uint8_t hatSwitchCount = JOYSTICK_DEFAULT_HATSWITCH_COUNT, + bool includeXAxis = true, + bool includeYAxis = true, + bool includeZAxis = true, + bool includeRxAxis = true, + bool includeRyAxis = true, + bool includeRzAxis = true, + bool includeSlider = true, + bool includeDial = true, + bool includeRudder = true, + bool includeThrottle = true, + bool includeAccelerator = true, + bool includeBrake = true, + bool includeSteering = true); + + void begin(bool initAutoSendState = true); + void end(); + + // Set Range Functions + inline void setXAxisRange(int16_t minimum, int16_t maximum) + { + _xAxisMinimum = minimum; + _xAxisMaximum = maximum; + } + inline void setYAxisRange(int16_t minimum, int16_t maximum) + { + _yAxisMinimum = minimum; + _yAxisMaximum = maximum; + } + inline void setZAxisRange(int16_t minimum, int16_t maximum) + { + _zAxisMinimum = minimum; + _zAxisMaximum = maximum; + } + inline void setRxAxisRange(int16_t minimum, int16_t maximum) + { + _rxAxisMinimum = minimum; + _rxAxisMaximum = maximum; + } + inline void setRyAxisRange(int16_t minimum, int16_t maximum) + { + _ryAxisMinimum = minimum; + _ryAxisMaximum = maximum; + } + inline void setRzAxisRange(int16_t minimum, int16_t maximum) + { + _rzAxisMinimum = minimum; + _rzAxisMaximum = maximum; + } + inline void setSliderRange(int16_t minimum, int16_t maximum) + { + _sliderMinimum = minimum; + _sliderMaximum = maximum; + } + inline void setDialRange(int16_t minimum, int16_t maximum) + { + _dialMinimum = minimum; + _dialMaximum = maximum; + } + + inline void setRudderRange(int16_t minimum, int16_t maximum) + { + _rudderMinimum = minimum; + _rudderMaximum = maximum; + } + inline void setThrottleRange(int16_t minimum, int16_t maximum) + { + _throttleMinimum = minimum; + _throttleMaximum = maximum; + } + inline void setAcceleratorRange(int16_t minimum, int16_t maximum) + { + _acceleratorMinimum = minimum; + _acceleratorMaximum = maximum; + } + inline void setBrakeRange(int16_t minimum, int16_t maximum) + { + _brakeMinimum = minimum; + _brakeMaximum = maximum; + } + inline void setSteeringRange(int16_t minimum, int16_t maximum) + { + _steeringMinimum = minimum; + _steeringMaximum = maximum; + } + + // Set Axis Values + void setXAxis(int16_t value); + void setYAxis(int16_t value); + void setZAxis(int16_t value); + void setRxAxis(int16_t value); + void setRyAxis(int16_t value); + void setRzAxis(int16_t value); + void setSlider(int16_t value); + void setDial(int16_t value); + + // Set Simuation Values + void setRudder(int16_t value); + void setThrottle(int16_t value); + void setAccelerator(int16_t value); + void setBrake(int16_t value); + void setSteering(int16_t value); + + void setButton(uint8_t button, uint8_t value); + void pressButton(uint8_t button); + void releaseButton(uint8_t button); + + void setHatSwitch(int8_t hatSwitch, int16_t value); + + void sendState(); +}; + +#endif // !defined(_USING_DYNAMIC_HID) +#endif // JOYSTICKMHX_h diff --git a/translated_sandbox/sbus-to-usb-joystick/photo_2023-03-30_04-58-32.jpg b/translated_sandbox/sbus-to-usb-joystick/photo_2023-03-30_04-58-32.jpg new file mode 100644 index 0000000000000000000000000000000000000000..12e0a3e0d9f73543c509386b85d532103a0aed9b GIT binary patch literal 91648 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 z z9}2Ifvm{&0(nvs1q^T$A$#26Hdlt22)5b~Y%?}Is+T!BTqLEbul6>qF<_GK6y(ht! z>*75TtmbBBL-M)EC-JHt4gH#R3q3kH?k#RC*C4ar+$FlHJ@X?k_53^fcY;4<-D||j zCB~EDe+thHxC-Ld;jg8IkN1QM;d6op;s;*1IL>s>Qx9LMs zifGw{Ws0aLgIELBDrR({CtSd9sm zSt4~PSTiUrdQ@`Hc#pfx4yTR|cGX$6Wnw;FF@eo7wLh2S_|~$D zu^hz@+E3wxegpArjbr}+Ae})L>rata<#?N@{{VovW%?-ft`9-BDKO8s<6igU2x9n) z@UdfQ8Lu?dEe?6wylzlE@IPNuUL~X1`FDG^mE3wB)yp{8)(2;$#G=VlrtW|Y)s(Sd z+^#X}-i;ap;d#MP!K+e2_|E=$B>LAYm6_cgiu+W559>unbwCgLlSMyhfb!70$)>U$ z!lyv0f8M2Hp#9!y+{}g;$!4hB+_DgQSE1@rW-b@&TrY|(i?(sx&|y6iA$k3uI6NP(Jk(cc1`*UV=t= zpd1=hP)VQ!pd3^73N{J`w-Ak;JJ5$T;xj-Pps=SPrqB*3CG0G%v!{AgIi|QTPKXhl z&?xRYn&zENl7hruO*|fHtTxlJKm{Re9-V2*GHFQpr~ui8&-oODa4GDYMpSX%+}zRo-gq{er2wMs0f<`OEhNQJb%3?RsR6T ztE961ndH-e{@C#zi>J5oLkqp+*v0B1^;40o?{{X;`^{uTjG}{=~Js-k)Bs)*ZEY`y6Rr)iA zBk=1@L^%%y@b`qZPZiuUX}WFJp(c4tcv@hf^yoq72dNz^w$Z<49}!QF?I|?954jij zA~whUa~V8)p7re0Cyl&x@!Fe>T1YSzVNAyg0oW+O{D*4P(0^vlQ&WI7!wY#NlVdFE zNT%uN5r(Ia>3;&eFQnW*_NR!iH6@Q5 zWMT`?DRO_UeQ%PQEO;aWs!9CCdIyESW&15Q2w5$p^CNO{9H?RR&MVjMJSz@~a2jT}ZJeJd?gt+A zaePk>jt`cieaa3<;AV@L$zzeS_%{WXoWY}t7|Gn=09opJ{u^nK>7VE#<0Ot4?O%LW z#ovwAa?BwL&A}=w3s%ezgVXj;vBW zvQ0I_%6?D>4WC-!?(f1wwZ3ff25ObYqDWT!#VKlm$m{h_8b)6t7~;s_1JbeYe0IT9bsr)E2!dlo&3{#BE4 zKG^rk^7GWUO2xnNedX9=6l)IC>z$zeYaZ)t&fb00o12wT{2FnEnUwKRinC_ctK!=` zM=_~s7>30mV+wNn9<$>JQn?H*$9XKkXi34Uv z4{`5WB(8E#FobnX)|*0Afu8#FX4WSLPNUcl>rf4UOVdVEYcE3VIX;-Ka^m%;pZAQa z$G@#rxx0mARSV`e;gj00l^j(wCe_imt9aE^x0et5D#UdM)AFpF&2IAUUnTCHeq5<7 z(0WxVE$*-G_bV)$oJNYEmTdF@bgee{X{-s=X0(wd+y>Th^5>y6)Kg~@#Z;5>GaB`g zl=+RjJ8(HIRGMElXN^>|WPz3MUWwuV0EAXk-m3V9@@rK&Dz;97Z-v*J5-)W zPW`>7z_sxu)wY-6e+yhgc^i494D#H|GL>JMqXFer@11~i`CqdaGiQrg=@*)(mxU0* zxJHrrRX+XC;Zo~f6q~~LIgrgVPP<^ZKo&CGXC1~p{cG#L*`xLix%l&}YZ_*o;|~w% zQg~tpmsXZ_^4{7&4nrj27%0HY1m}!bmUzG7-kad>6Y82Si=pW{#+#?zHJo~_@0#Li z6a{G`QUVm+oD;jPKW504Wd(L{J`C^%t>c{|&b8C-q_tNg0XbpEA&CLH9{g8TY4F2E z(=DcLbH!R-kL0d?%+4+@i5B$Jp(|AL1y5+>Sf4 z{ynjEpW1W9S8*`Y*G2ICx{#r?+a%sTk0E#bM&HM_FMvE7sC+^3JUU*LYim8_(Jk<1o6byK&e zi@gl}ID`55XJ$qL) zqM7sd60drjK z_N$%Qjh&A}{nJy(dP-Uqf3%2Fxl&b#=ARYmmvV(~yWfhT<|1xk_n745Qy!CbRSn>I=AMQ$+q;zKTeg!B(8TuVTX77Ka~`}XV0(aMJ`lX<#8vN-+MUr zsUANp)N!|+CNYhoq)5vqed(Oz8Fvq*F_f-7>SSC~j4hA;wE#kGnXq$Ggu;q+DY;wt zar)D|yoxRejFm;@b5RKc?!d+>!lwsyMZb8Q1rDNP`;0$-}+3Qth@e)Ft7ki8~y%Iy-JHkDIJ&CgwZxzrEq>joKPcCLFFm&4Z?xFhB(CtGg27T(lUkVK_hkwP%%Xm4Q>=ukY<-) zps^5UhZvH2YoM&nfGlSKKO7673*q`DR z;>9KAn`fch$TC|}y@uW6AMGK1-;kr)L!&yW<@MyR$j>Glj~)9`5y(^by*rxsYhT$5 zOVMRnHIExu&9#7NG`mS>ay$I&6$Uu|_IOYvD(8V`!X9Cs#}^%3ly$=>7)EJ z@Q$CfSa^3()#f~_>Nk6lvHs#l58vWwb#HJQs4)|W)#RdlJ4JlQR{j_Gu#eG5H z-`Q&8O|$YY;IXxA46`UD&o$6ke$L}Y3RSJ`*?UJA>Fvc)o2HMKTj1Ah*rRZ9zN*v3lQ1or%YGYdN0BFexD1#FsEV9VOw{5Fv^ zaars&zSEBS3vmr%nv5*2t=dDqhB$Yd_^sUr%Cz-tmyzF0g zeqT)0dz*%Id@swlKU#+Dt-2R!RaL)*yH+N-@dHiJtyj#HNhWq}3dgU04{8kMRV^8! z_YxTunm@X{9(c`GxVYIN63rU34E*0Hz^+$Z_?aQo+sl$Wc=Leld0;&Ui*!oe@=XI#~y4J=eXiHAbkflyk;~C9h>K-|s>fMqv3=Oz->H+Iq zP4|o%NeCWXd;ai@U?pVUYppVvdrtrZ&0$=ddlBU)?{@(yJC7OdQOT(j6G)5X!yv&>dC2tq>8)AAQy)3( zXzDtZ)!YPm+hT5@41T?8fu7zbg{5g(H|$~??(lKf=}_8OUftTON%ol`&&qMr+P1Vm zhF9ABb26>ENpAyOm}I$%Kb1;@g?0?*=IFV`IqEZN8l1AI-t5TGd`!Aa-nG4zoy3=x zvRcO13SF(s5t)~^KwNXjHB2nmFrSuF2w&Zj+d*D~ufBTo&3jLQ{{Urg6?{w9tzpn@ zZSSXKNMn0*%2qSmM6l@Zao8(tKs`4~2YR4WEbZykYj6hqIpMHw;&J|uX{!E##oV(Z4D+wB(HKHV*qy}B%D zO5+>K?s8vu-|dR=YkQeILp{!=ajak8Tx#y~YEv!YU$@Hc=0=rcU=CQf%EN)iFaQIl zOU6Pv#QP(_-?iVtzYKU+<70TMP}C;ZJW1kfhWj;)PaA5M0AeVjl?Vbd$0r!+?rY=C z55QMmA$yta^x3q1EzE`?a7Ix}7E$lPsT0EX16a~*^wisLEyBhjRooLk-Er+-NO-dU z0K=qUnwRyWE<&PJ5IlMI1@vYCD zbuyjnjlDYl70KJrBJJ7cNzPT6xuDssnD?JwCc;lF|WZ=l;~%MFB@ zlrbCYs3wV;S3+T!)El00w1+SUENnqFzGae1RkT1JlKWp;DbPu)KM z0F`{f@iWEITX^c~OCu1A&tS2pPnJD7uYd7}j_f=W@S5t@9Zq>AF&G(yM=s|*{RVn; zuab3(8N}v6xtc?qp1J=3Cbf)iD%MWu>h#YO8;!e2++@ZJb*)WG>(4%R;JG_+It+EM zGgxmSUBWp!On`<`&;-ok5T)Ri+ zaUeXC(x;Zib2AsoVoB$d`cdUJbBwQgwJoy)!*{@>n@*k2%BLJqPUH;IF~E-lw>2Ya zlW$*_<-sQhrCy6lXxD6qYT#i10CuJp(j#y~E;wR(&>XE9R`$%mgYx#ztxlFpZmJqj zl%A9r7=7K@B2xm9-Ocd6_C6=`19 z{nW=Y;I4lf;hyJwWucB?X6M$5zS?w~ju~;ES}H>4js-FPG~xTP%V#}3syT0WaLc!E z>s4mHP)-{aZZ|RKMb?!;r!~U9-)hR6PyxR1sAbmGKIs|usrGD_QrepyYO`{BRI4he z`@*@?t||N6wM6>SE--1TZsfYhMRxoy8?6?qs^fop=i9^>1NgtCB%URalL2~ks`hNo zSd9+e4PM^U?_;GyKZ~Pu-E(<~JPesG{+5 zw&5ok_pVWH450JUqi15>YPkt@uc6iI9xPK1)jqX_ajZ1Y_l_!(9HUUYiX$5`eWNF9 zqbck6Y0%2b{2$J%7TS34PtG>CrDVz}wvySGoaY0Ay%(!9gNw@V!H zx947ypy9hW@1gSU*jA8k z#&tF-xy3Y`)P!b}V5+&!By>nKP6HGXnx(i6^4Am*v!x5Uslq+ne-~<}ZlE>JDUva% zBpY~RwZGlR>64$+@$J-jKj2@CJ|T$Cjp2=ZP>xnmvqfVf!ZYh31y}Jst2Zd6dz}>U zvzD=gXDov>6t8{ozx)%c#@eLnx~2DrbSU}WCDdcMnLpqW_xj`UuSf9r{1el`I!pm| z-xO<_h0=_=SjQE*AEA&oYZ+rHM@D;CUKPx79`z)W^FBRT`1{|713!uBS2Rx!Y91uJ z`#zgvd8tm{b}L(UnVbIk&*&@fPY(PG_&@OW?k2PFeV(Cr8e`7X?q<4TPj*e-SN=O) zc9-!Q+rieYZ=vb>UWl$iVW-)}ZJc!GH3zxt>s+-nCA1>$eU4w@tg6}K>&89LihL9M z5qwVZ%EIt?PWH+fPx{?K*40z$9ESZX)VwkO00g+yqAw?jymjHdAyIcSS)*RazQh)d zNB#HD;a>fz{8+lxT=}=tHsRIeZasRM=jZWn+wRn~kv85ke()aE&F!%@Hb>Ud;O-a8 zl6bm~q`N1%$=H6yKL`9H1-oBd_?yKOqXQ{x$gHjAKAu`EhadLP*F|NkcvrwTC;k!N zhh7oUZY|Ctx%)FsbfdBJ8FQMoEEjtFNMczeUN*A~g&g|S-V*q6f8xDWY@mcJvJy_w z$phB6r$(&4CU9msj!{G1z~Rze-J3CW--zBL@myvPw>geu^G2XX0QTAe{Og~%@OA#H zB+ORgb=mWP zz@>((;j@O^Hycb}GkRz9tD0xS8Q_7+Tc6$yp@L%>uI|&s z4>gO%!qml{7%Ol5Nvxe)#B)Tuqn>8+*kK76C)*V_XEdfzPlh7WDEGtWNTUSEKJ7s- zgcb|W-OFaKy;X+ej{g9aO|E#o{?ez+ljgy24r`rFX|67$lW}6qMtWche9X#I(BAt# zn`-|6yPo3ccL74GpKtTptFMUdY#d0iuHa4#r+?{KH~OfK9LX_WxKZA+e%_8hiG4Yy zwQUOU zl1s}t)OKkw!`H7`Be@*KtK0W5?c6`w#}%6-@wdynIqUCOI>*GF4@H2QsjkL(`xMSBHPJO*AM3u~{SAtf#-bhI!Xjs&DHI=JsmbPTH z_fe{@a^J$gTJn8I;-QJZZDoqvN9MRH{4Gg z7Rg@qrIEu^FsB9PdX3-3JvPDEL%QP!0IPtl^d`BjZ{r-dhsn3MW@#kYyHuQek~lc_ zt~XBc2+{RBd#|x+*OBh>(%SQPlnMSLu#T9f$>KSGv~Ht@J9SvunZC_7*i@hH2INrQ zhn-V2p7Ad09x2qdX(W?uixe%j%Yv#%_)S@BXYv>$OIC;{@_Z>59)&&#jBA zKBiu$d|Knl4Zq3x3D1A)Ro-aflWV)k;Bt3y{(hBvQ_}pakMyaw$!?-2DG>6*9!K#5 z`d3TvSN3-CH^%vAn@7`aw-=WG0K0*+yDsMpv60ny^v~m8RVVBrp!^}elS}c&qkP)O*plh3 z?Fsvm2H5eC1_@z-zaqVZ#{U4a_LuuSc-z2!8UFx;e^0%>@pN{oFSS?;e`mDK5HW3x zsym{%V$7@#{{U**H1#%xDLooKCHQ&!JZs+&=l=jku)Gk43}zORN{$a*p-xXvPz8Gy zk^2E^ULDbG^-mK?Z{htGS^TuQ)MP0v#H$rlhy#=R7 zto&_l;fA@ipUO>6IT0D8WL>C7EL3*d-lnoY;HkG>BKRnu4mIgDTN|A>!u}+VEh9`3 zt6SYFTb$g?oEB$gU`8;x80srX($vyaV+iv$eCgoN*>l1dI?spf)qG8?U2FP;I$ed^ z+cux2`H~PfZhl#mZfp_(+m7bDFWQGg@c#h8Z;8wB_u;39b&33R+Olak7x$2Ss%1gt zEK9qU%Ld#=4}JxCcf~*3tKtX74-j~E^H{%*O&>wjZM8Mg^!sS-_xUoUg;bnms<9bt z{o`F9?QQ#XFUHT>qr*QFejj*7KM3oZ3~rKLYDF$?H9}L%NZK_lpsH>m*J}ZtuhTYFEq>2t!;jRgq~?ka@$GAJx+QG z`7_~H#(Up_e;d3nMhujOA<*_9FM`M{B7e;7ko{(Nc=_O z&3jn4OX)Qs46|*6?GiJWaSufM>@adT7y}iPKA#L#~9Akr+}-2HTZ_wyo#mCAeA7)dhXu*b=3-a^PDuya zzQ^#-{1OJ~J`~HXc$38j9a`%`mhRU~x3^1Avfi{_Vnj>vj3@`c?>?3ChLv?Uhc%lW zO5I}nMxAvX+&*FljItfuTz_hNJVd_P@)ztk4{fmAG=%2Iq?8~C+GBvHMYF5vzYdV|8K65IUSj)CcVG50- z<>c{SnjaDTL8W+?;&+NQT_!m#be&sRy1lT4N63*owtR<6EF7EGTn$}yZdzqtT z3nm0?xyjGz&sz4cfj_Zdfo)ddyk+8@NIWry+hjy*a7J z>K#)=yqw#>^31C(lD0M(30x7uY@501QHz9ZVEjYyX0G~dKW(}Z*vp9rmP)LQ zy?>ak4+VbDx^IiE7Vb?-HF*)4fcb<(V;KXJS10&Ktc!^k#JZ|Y_@to%{o zomb)BnQLRIT5FozgU*BOQ2y@94clEyo=M!K@=5DoI8Ub;S8|qIu`9{tc;>xR<2Q!w zJO}YdRMYKb+h^v9VvFv1B0;&3b;#UU{y$7+>3$rI^!AZsQyFYv^NN==SF>lC+*(Q> zcHfkJ(g){6u}!-lHr_Man)HkB2*p0di)=`_IP03r)x0KFGq>j3_)<>c?BumM)x5a1 z+rMsc+*Ru@7&FQeNY$4ehAA~G1{Uhio!vO%vF@F%*|v;*X}GHdWoN0n+P~W6-Hb0_ zYUEgT3|W1vhm%v360F!AuqxGtwC2hM%Kf*x# z>psK8ttbh#UPd*bnwqPx&xsd?9+f<;2QeZ#*}(H3`CvET`hqjZ(>3+G#d;wGT~0Psyc zLqYp{Tt?ap*xC?Vj7hOU&$AK!MPoM2qkf0xcA=_C1?#+d+DY5bZh&L(scigzb!u_B zhi641&@AM0Z8|G8=$4bYR;VIPUbt~~k;3)m){yjx;eoGJG zqL;HL+SDg+5i@Sv%~iP78ccTnwVqCCr0nTVFw~h>R?xWmgH(TMW;|3RGaf2M7!{{2 zjD4{0F|(Z0q?LvRM@|POfakt~ay!wS(~$u!Ogv_Q0OS%W!FTndHOo`6wT%D@yE;=? zaw*gW+|&T2cCXj1DlHhvrvZupX^l-g98kvyeQ9DFlb*B$cP{C2nC1F@mEHJfUsxg9 z&4I=%&mv}1#a)9`k`eO!-_o&^Z=ux}W4qV&XfGjs#1{J32diW4M+b^@`lOc#cYMB; zR4d5)xoixO04I*TWKg2fPFL861hpse?fxeFqjoxV>}##~eehSrzY`{3?0qKc>Io10 ze39i^C)QU052g-#8um{J{>FMAhwVJy7x;qa>f%9>W1~#A>Imu@X#)laBcLALX}yY$ z9&+e>y(@ z-v^F8MSWf1-5WyqcWkYo_+LlT%yI69esTI)2QffH#F81G?=&lx3h zN7ERp`mOY5baSOmS`o45{{ZlwYTBK%ZoZKtW6WWHKDBDYMAfw`MwyGpYuTBB-ado+ z*RN?`3p_ie%?#Rm|gJEX?5&G+rcQ(NtuXWBOy>x<01^&a0hPmaV_MWdIaG>%O;yt>gX8 z$&y8GN40EtQ%A9a{{Z(kX*8-a`@zO5rSU((y?eqQ5QkdUqfH{xmV&w`(4{#ei){vtF^f@JtsZ&`U75Q!9ZPplKknP4jJ6ErM z%AN};AxTJ zd#kAIEp4?eCK%z9?CG@_k_XqZ>+4FSY_4M}%XPWyULWuSJkiNDyGI;qcI164sJQrh zZ6p!N9D)}ka65Czty#6G?5wdS)ogMzp5%W)T+X}Wr4Tf5yDr>xHNz(EX6iS)EXAk8 z5m3t@+DT?0u1#b3lU9i(Wd11npHP4ORg0{6#^UANd6GKdU>50I{r0Cc#iV6(o~Ja4 zl--VoUlvCVqT8P!$}w`u^!bSSOO;KCZYF~24 z3WK|I$QO?MepTjPDE*}TKc?Tw96G0nHEBW;t#2Gqz}WT#pU)NNej)vBrlMGRhW~%!d8aHU z4I{~MCKXfojxmgmIHEh8^)Zy9teNlLApN5>eIga|WLv4bh|$RW2~ZEx@q?L%>T zWJ^syYU3g0AP|0nyvpB37n)VA;@w!mYdppUL}TVQ-{T--8P6X|m`iPFqsdjgzL5lG z7mV`zu%s{}u1{V#tq(q?XqLxCeerL^ULmw^o@qJB7SU}g2V;T$aa^XUs$E|0lHz8X zP1)SU?TjDc=e=m(-D;i#)NZWr?XGNZtk@@#CkzfoL+(?C2R%Du-nmH2Ls7n18Z)=%lw;&SDB_!OdnN3aQ*RK-9AhsV1!n916_q5#N0!Ir zWh4yp8@4|>iXAR%siB7~qvc$1$DH=+e+m~n=yFdK-t4^EtHXQeNhjJLc_YpJ;Nu-f zQ&sN#Nj9s0B%irexo~7vPcAZhe81yb8YjaoV*27lv(xURkr;<{jH;rZ<%n4Nt_-%Pi7zZ7rmg<35a}04nxN4*}>}KBhj)rQTmGYD4|HWoTt1 zqllCSUi>p0`(Wp`(>zE0iD4vjUP)zdBt!ik#4ItlvDyLS-1n`chjzOUtaLnIOZ}L9 zM|W>8+XOxxv5rlm<52mB9YUg?H2(nKzT&+L;RozdVeuo!dS07rf2wN9soX_lBgCs? zY@wUxa`H0B0Nc{zL%xiHk*0ks5GsA zTe^R?I;^j>lzAiC31n0qa2S)=*Q9^JLOd}S!v6r-S^ogEJUij-I>$os5N!)jhBQEJ z6?jHC8{4kpyqqsQSIWO0e{KH&h#$8jczeP&dQP99TD8c$ypF>3$M%^pLtIGM$W$jd zW4IR`z`^lr;l<^*i993Wzlfeb@rQ{u8~EBSC71X5exEZbM9RNa{o;&_vE=89(#amB z8ft5r5!CeW_$wdAF9rCA#Qq!AycObWePdMDG&3FDjjL}fY*l22V*dbj7m_@)`B#^I z*B`gMKecy*{u){MUq{q5J!`>s&|FWc+*|zd-$fFriGRHt6$d9d$F+Fgq2MXJ8RCoW zHb||SOL;&Hgb_N00a&g+>FO1;j%fbRV1IaU%6?tPHMiM3JVs?WNy5i>`%-?`em?!O zbd3(j#vj=FZj+)(_K0nCewTu8xEDC06bqZr{=lZ*;=&xQ49bqiYw^nGg2 zQ`EjoJ8O$Jx03D2!uer`&C4!*GCgQgwxbcj2ECYg$gB<+b*UeKm~6CD^RdyDma+V!6k2%~!M{rXFh7Mr@&0CI>$+ zBLcJR8cX?FLlKQZz{sruH<=53rA9_`SG*tL>+c=-!pB0=mfi2Q4gOlqa4pjag_!Ot zM{iE`E~2re95kftjMj%g!}opao$bsq!pvENN6QWd2Xaa5JJ)I9KZAFkGWdP*Lspwv zx6<#v9Hefx>1g**-+~#5^Fsi51bm=!D<@yI@b81Hei7?aGkAylUE{phw3u8OCEGFw zw?zBfh;o1ua#VZN`$N{FlGUE)H)(M;t#V`2ZLY4S@|s^RD9nr#7%!FMZVBuCD!!k3 z_jYX3FP@p&8yw_u&vA?nE7!gp>une9OYu5S1K7R2is^SSL#A9QMz>W(QdIO@NuCcF zab7FoZEw%C^CQM4Uo!-P$)3j?XTRe@sj0RrDE2YtiE8LHQ?5L{z4)p(utyf@7vy3= z`@KNx{!MLpYbs-J-cU&*u{DMA;*kp#O!CD`D)sc|`c|CD=y|Z`pcV5Q4J5!Ekf3zN2R`*T?N{P24EW09O}EmakyA^Eh|A-Xj<_98ao0U-W8r`7 zjpM(HUj+4!i24jVGWd5#FXu%*rXhD!&iC9C3VLCC*PmZ$*6C|x(lXr5aS{o#Fjel4ZU023vaO-9zu;o=)Y!IT#~^c@K~ z&pj(bEkb65TuEwtnF%OD4iMv^^5+tg(DdqE2v+DIzNWIGobi`PqS+)ZxY&ly>!Qr+(T^Jw#gbX0FWPd=~&41 z^^|ORot~MfT`H_r_f2fWK4Rku^%c9O{5-tX{HS5RX_iI`V=BOb>CYXzSAQE?9X;ck z-fMPQSb=Inlmi=cyMj9V)>fzS0hS3BTP-167}sXqxyCz#&pnMz>{Mv6gW+se_l+A& z)@-D!2;7NPnM&jqI2>n=oYdD^hL@vT#|)l*!&xA=SC{v$`*`H^^sZaP-Zf~ntJ}-T zq%qpU^UJ%Os*IEFM;Og{2C@4}UTb<(@8SI>@hwpAj(L=yF?NBBF9R%d&!rNUhLNLY zdv>+)0!U+q+8-*}WOK4IK4w0HHO=c9y~e3KM;i%<|D|KG2itBX^GB~Bej^~_{ilEA(;34bJZnQ?LOwLqO zTO2+2gIP;5e9`bTj_qrU>J+zirE0D?Qo^xHT-h{2RNgC~Ajo9cbHsis}_U*Pqg=4U` zTC3V8p^T|XY-d_rr1Cfn#=I zjE?7@!n|fb4oI6so7r=MLiIgI@~(sShrg3g{hfR*r8TrLymPdf4sw}R=N)P-W}JIa!(HC2RS_}=j)pmhD>dLlmH1murd72 zHU^dl`DBoN39MWSc$W7)vAh|iG0)o}=iE_VHT|P7{{WVf{$`4vR!_G@eS(n2rlfI- zZD?_V{Jkm6xD?uRngJzo2;fkoCX+Pi&L}jp906a(lW3)O`Djy-Knb@8<)k}#19|%KTq)mt)7=>r0UW6_S0VKQ9-#o9gKHlk<&Hg*1OV8 z%gZPv4{pED75X9Ydr(bh_Hp=sb!sxT{3*07YVsqJNWI(Ukb zO`kPrzp&)CcO+}xAhq()WtU4vnSuWRdDT>Z7@#8{r=cua#$@+1^Z{T-|D= zZrzB^50=2jr`!zwRq1-ShUSGRtMVL0}wn*eE%&`z~y_DmnE~}<#F5XqWs>G{>2nIj{{Ars1 z0EsPhrnoUQmk90~cVc$|!S>JVT;8YSxrA%v*~k=Qi6e&I z)fR2JjxDMeoRCj;<0sfxlUEnY?H$g#bZSiMIFmlwljxlJpO$)w$??C-FwH`$GIhlf)Y0%?6(uG&XiB<&|O#cJCcGd-bg=tpX1z zTwBKgR0)7KhV;lBS3~gg;D)W?%L5*#eQwS(!~p$yC;C=)x8PgzsyI`+7ULz4YUIP_ zl+}{ffLdAA@!O02DQ!?*9O^Hb}!Gou!D! z=U!{#D;BWPq>kN|Nu%z5Y!2rgPB`gXU$g$Js(4_@e{pX#OFEPTpmiM%4M2N*9qdE+5^LSJ4tUoq?Zx`aF&3` z%k{w@t$e%UUx^yNry!E*=2;|V1dYdO&K#m(Bp>ZuB=NJ|k47L)V;02&T?Vkt*< zeF3k2*g8ItU2OE5tI2`DGN+cmR>?o6E6)6N`(=2NNZD)!g{aR|h!ca*0!KB$Tj+9X zbI100q}_1hB@#H?%t62--xU$iBel9;K1k$f5Uk1$(F=pf%Z3UI!6+F%d%s5~NtpFplR>js>@e1KkUm^Z?h@W!$u+Uh5#7v zjQ6NlT5Fw1OZJP05&+8_O4wk3hXam3t!5Y+Nmh4d!tIc%uUvHCb?aRQi=g<2Rn}*` zv9P|4Y-7#T&j*ySE;GB4v~lg)w2e0OIcipd)w2rz`uA0uX_;A4-0Va#?P3q0^&i%% z_>p3^k_gsIjjI}{GNAJipI>V1YfVxw%pP@fSySs0A{DKu(oUI z@dP(a(B~7e$0L9bUOnr0;ono1rZN#%iO8>nuJw}}BI61KZb#n7Q;wY0zL)U1uOVid zXzjM(vq*kkJx5-Bt4C1rdfuh2yonvZmPB|*3&_qF7|GA5AdGv~Z2lo@+2UB<60zZ( zgN@4BJOEoY(N7B==L^P7yQEsQ@OF=)T6yz3YFCO|42iZi2cQ7++P1VW9A0QvF~ezZ zq{i@{-AdMRys?)50BMw-)hEK=hZ^_BkBV9kgmfE!v}>Lwx)#=pa2aBWk3M9LhQwpJ z;{>m*cb~Oi>}}$&**nK`Xgcntp=z3yt-Mza{hK4r94z~RiOB;Fn{q(x!nd>{yvn0T z6;|>~Lx-N$Vp>bdT4@;hj#)zkp1r{T01nk1zlk*KaLThoB#a7z@4I07Y(M%Du7~z_ z@C~2FFN@YXH;7x#(Dc#$p{Q9TY|VJ6K=Sk05`WJ%^v~@9;p;oQ3(X%((`|HX6-9>D z&d~yS0dPSib=;)q{o0jK^l;ftT9I;*@?MK`ec~;0+fUPrPjN9mUK?v{A9#;pmGrMh zZ`q&i_Hi}Wi6*tw8b2;n7CwA2zh-vGA$@C<_*3Fd7r@`N4!mw%Z0#nsYfC%HZOp4~ z!)cL82P1bFKVM4rE3b$?8`D*s-VI**V#3PW(SFkNU?|)2=Y}IS5}Vlc@Oeci7wsA1 z{{RdA6I^Ql03CH74S1nK!Qs1Mdw1lvBGgxMc|Za41z{*Xe}n6vq5MB!-gLahuj<<2Rlz*-Sg&WtA@kj z=|%F!@67p+PSkuppB6qPSWT$Dho^Y5+3aj}NCxo@7~BgVRX>pqu!&T(j=cCOvrs2mb{@GIK92Wk5w{3h{Ek*32ArQ-cs`rtzq z#;0!06l~4UB~=g1!;lH}Jt+SGg0uJoLGY4z7yB1M(sav})US~JlGsPSG(bjs5%)Ou z_cY_UtKua}n`s{#quyWL&3~v*B==KD@DEeFWC(yM0GvODDyhWtyUJWziMed z64`3dS@<8qzASBCKeR(8q7Lg)Fch*C$x(xbTy(5oAL*YFe`(JX$FF#b@&}1yHuh1% zrERS3@x*ZC=c(ns_W)#y=XEUgK9dKRN>H;}p3~s(gW8Ae$MI5MiQf~vMWp$f9{bB* zBKY0hYZoP0DCA^dvg01L^A54%>)#UU*V>E2G}qe2sQls3z!~D1Cetu5`x5X z2LK;`N~r6pRkHN7k+=Im{0i59XMJl)vDYp%*&kZ4d+65Ox0!E;18V|%0x|f}`yP0D z=f@wmAH)3)%TTw|ZZEYrRk^y8%Z#Xn*ry#>j)3(dx4&&~j(TtH74gQ~SkleJ);eyI zmRqHV%Mw23V}r~bBGr{03 zK6HI4;m_HQ`@)g_(%v1`Z@$su4FQ(M2yG^i9mY*#B}1cz9Q&947?Hh z8vF(Lnc=pv)NZ^bsN2Wl2+;okrAc(fUUgu^uqh&BewEpyx%{{U-&&(qSp#`0^M?Iz;Q+E23IY9DWvIYpA=Zr%7CboAq?>Pe{f zZ2Gv#LMb0n{9FB~{4?Pn+DlFGABAk=yteT^mpk}}<=Vtb>dW%4%eg^(fCq0uUpi}- z7P{}m-CAD{#?5Q0YK5gHufxzvAY$Sq#rtPanqXgf7#E%X(z=y zG%F7sbrcJ6ZsA!Kx+(RqEWNXNm3+B2 zki@HQ+mrpw_2>Fm(H|XP)--<#*=Z$Rbp1+Jm98W|G^BM09XgJc<9;3RGi!c1(e$G% zF4~pcP=ZwLjJs_F_TxS1yF6)N`B~! z1JlnWpMCFxi6< zXy%4bl&U#V!1cy?{`Fz}B$xYB#L`~KSz0h~Lma8>b4kmo?$f8s6q(Q2X*$P-uXJq| z;%kW}@ZHjW>g93<$0zb64tv+sm-;Z#tgO};SytM`5z;kgB$j44Vsq4!&-bgzzAE@* zQ1K<*mx(ku<-FH4;~$-Eo^D}7oR$6}zTBPN>zwgt#@`=&UGXeF8??HcP1Loi)+nNT zV__Z&k;}UAj12S7=UGZx9aQ6E({-zfC!LJnyx;R+oa5>%BH~7w{_a_Op0&B+zYMQ{ z?_$yo{jQ@mj4?xVa|`cRm>}~PIOhcQ_pBR{9Jyg57eYW@nXGx4-5rWLnyux$k;<#J zh8al8xbz~b+uGXM>8)>XYYn=yZaWkzw?WA1*nKMNN9P95$a{)}LaGnVkLyXdU?Lau zn`en;kz>d>2dU(LTGaS|Xwz%4e5~6mDp0XQwBRpe=xed~acs*Oko=4X-5lr8)?z-DkyUY3fW{PbFB6eJX&qXrWR2$rQHi zw`1*B^!XGw-p=m6)ts9yCVz@_jj^*T?NP}fS0^-P-d}FUy)#g>Tk96XWS+Ia_=?G` zF4;)`0Cd!pHYk=$api-%spgw31<&0fx{`b1q|?;|1LpacuQhrVRzEQN-1VR>eGIg= zYq>neRvmx?fNBwIBnZqMPUHMNjcdueMLS15$l{<|O{ui}yN-D8LUz#O5yD2oR2`gS`kGr!JiY4dUE6;5IK^Mr+kKoWN8NsuN~5rQ z6(?qSuA%UEN4Qqm17)*~ow`;H*X;iQr{AvVWRf-<5dOb~dW4JR%e!e-$-%1Q%kw@} z`B?J4hPnN-Ow;NxlCk9{_GQofye$>$UR;0k&A&56Y3+&r%!%>NN$dDgPG6dmMgHw{ z9w?OQ0VGmJzuu_;;(#MXUFH{I_*4P+Rm#JignDFC1LPfC0+DrAP; zpVELL3$&VY=e0_|AS^oe8zxea@W1{DRq#i^7Z%g&vv{Y*msac<;=j6EOL>p`P^jtbO;@pCel>|>i*mG! zxMXb!^JIU(iTr{5E6}_Z`zd@*_?>AD$A^9%_{UVWx>4oLZ>37npZ2$rfCf8?{q*=- z`#1bK_$wAXDc~Or=qz!WZ8Z4SM)b?$EJjb$KK0#Cb2ZdTqG=c>L?@2p{EC@TXC(Q;{f6#i@n7t%WgA_q zj|}TqHkVN-!L|~!O&d4+EO(6m0QIZr&-gCK?As5G{{UvIA0FA-@6|jDbsySZII|;K zN$OP@o}&i70sVx2E&l+*y7=gtJ=ELuUmAbJn(23b>`K`CESUF`YLn>3xhET* z)>BbYmD%>ji)R+7RVVpVjJ#)nPdj<~f%sQZrg%vegDh(bk5ilvU&gR>T`BBZK_qM* z-OO?Vqwfx<9_KaMXg3hNPqij2zyd(X6_>NNr?)DxmaMB`;igNaK2Vt(KR$YX6}6*y z9y#00k(pCJb%#o2mxnL4r;<3?io`s?5a5L!az85RbSrD1VuIj8rcsqFthfLYGD*NE z2lB0>Pn$!|tx^f-$+Vw_QtGh0ma|*Jmg|zzbUEq3e#}@~>9CcyxzmeAHZf@@b~)tZX~@Pu8v91W_DR3-2BB{>HOswBMA#8MdF2$&~!IplR8hoq}3 z9%Q7?lyCeg_6uc(NdEwRwYLRPc@NJd5HmElAqH*AV3Zj-1e~0l za4Xk;Wl!2O!d@HrU8s0h#TS)=_a(g^8DKv z)G&$q)v+(uT3@cPeB(pyi{G`nb*%`*AR7TKEs3}kXTcCMb= z;A0&=OY7^4cq5K4Id?bCPod3mTDR>3Z{f*fj!URC_|`_tupyfRo_qGMEb$NRUkHNo z;yEw1TX?X}%ExFdPCt?StHYy!#$sL4HK{6aSCc(2TGZ_9r7*`L%F3ntwkwaj(XB79 zjF(qSZ)(IACHC#keQU!nziE5x>zNYH813OCu`CNS=eM>$t#f`e_?4-6!XNDh^Q2fx zqedS9`f*=v!~8plp;fwviI`)lZ3EwRuM+rU!_&yN(p%~m7Vq+y+j9f&{&}U-_0RZ7 zEv73QM(gv8{{R+yeJkf38_c)WUgOJUlHmcsILZ7zwdvmvyi0YY-862CFp@El&T@L5 zE9@tOagC25R=c@xSN*4aJK)Rd?VC@y@dfO2{h6bI{J7z49PV@XamQnxYs>sY;*C$o zdg-|T0EvE;VLv7~^CZM`(a*?xb{MXs<9~v5-8;mQYxZmQLEWBcUOO zZ-o$_vNB53$K9rPiq2Si5CbeYmueFA+E!~4GK0}iWNTHY$-<;MymExPr zYs-scxuBW6*@ou%+n#?@T^5nytxD`Qae9WPVDhMY7 z9qXv@uk736Pl+BrlSgZLG@I#}mCentvo`VhhBk8)k_G{A%mFM;-+p(62F^K6*z&P` z{ii!@UB%q42N(yxKAzR9XKi`n8;G>{MeWtoFWF&)LRjOjK|Ff(uJrse@ZX1Rq+bgi zYsFWS8+%v{>`|nzbm8|ZqAQ&JPvU3@!ILYGS!nk>{5`1-wr+lrMW0o1xjv2#vKH*x_bW>Qw{o zW0E>_$n~mrx?YQ**rbmY?zJI@WTqEYNL-w5+POSnb?dvmdPb}8t4`2Gm|K?nitJNzw-R063y-$St@Fzs z0NAaB`9J_;j`h_X99E|dOkCQr&PQviY1bd|Ez)GLnivZ@Np5Atd||TSfJworb$=3T z*LJs;R~p^)wwIDJ-9c|F!@J~T7;vN^$Q?0`52>$J_&e~UQ2nDn)3t9Cc!I-Dy1Y}V zJY@>Ps0Pd{5tTc74mkI$PaXU=(EJgj{{Up!-(20>>X!m{y1kK9+(@9Rs6}EF1wDZK z!>tmuHd>u@GQ34-^F5C#)HS=Sjegd~9X@xskgc>9Q9lC8Ad zF5rcSY<3{yp4IEWwy(!~58B7#4X2Fbir>I`ZH>D5w$a*05s=_BU@K*b<0X!Ib>_L{ zT3wG@2ar;6Zll!sx4_;7Z-^c&x3Rdmn@zUdt9LT6Ng_hZ2pQlr41iAq2EKst2f|;5 zz7*2F$)NauOODpuwYuHi9oH96&siIBX2|5P9Px_z{P^eW{v_132<;l;&rm@Q!niU= zoU3D;6OQE7tG^guYTB)p)w^A2<4GwcmCH@J;c=cqeb5gaV+Zi5jHcbr>Uew=2)o(8 zGi%`&i*&yL{9ub%hI@-WI8O1#=;geWC+@2ZJ~$cr3imIGzZpCd+9PT}yw_Uh zq{cS2g!!<^6P{K~E(S0Taxu@neVzXR3;!c+|ek}2Kg!~^1ksa8C8SYVkyjWpV zAmC#?4@`4|;ve`ZKg5p(TQ$|Mg8Vb!8ygtRiD7n<$0xcLB8S z&T=t=D{I7`w5P*+FWK_m6!8_3UrD4!v1z(n7gUhK07vyXJx)&ssjHkY#5H?69!abI z-M<(A0BFw?{{UoZn#I3|^tj{mZso9x$(G&}I4$P3Pb7iC72#em{h*e^U%ZdQ6Mt!6 zTilo%SJaT+++8?7G>TlFGr2|xQMZtCDsS1h;vJuWHCv58T(_1@KUTI7%W#Kl#QUVm zI6XmDKbCrcYez!(WAM|#n$%a)>i3%6wVbag(?ok?BRy;#Yr(lR z&3y;Nw|^A=2}!E>lSQ?+)f-URWY&;*PjEvf!Us^qh9s%M{441X_$a4>yiMaz1Na6z zT{h!VzwqvbHnFX{$|KquD3y=Zn|A{rcZ^qo{5J8u*T#?9W5G81PM>Y3cyCM9AZRVr zgirw}7iUfj=N{GeZ^oY&Ylq{to}Z@ax_+gnYT7-*UpA*8TYG4hXCRj8j0QM9qa7%W zT4Z9BD#5FtGe_`i!oLBa&}{ruq}}+_#a<|g+(#5YyN=ZuDBJ<+cVHgeR~O-pMjzQb z_RiNP&|}kovahVav#<2arZcUx%8Jbs1CT(#>z}>tT}kj>cJZ z-#bHM{$Bq8Fs9H?3JC|(rYp_AX`c?k@bBaQ0En#Z^_jIu=88GYw^%Zxx{cAf&nyb{ z>rQvE%Y&m%8YAdW5%|MH_?TkUkB9Vof3#a0cW597%Uz@>8%SWPc>r4yh$ zV;#EGI?u)58hGyQn#FDOwY-ymn`vyuWCOCy$B)QY1!&2w523=!DW-cj#9?P1k2aws z5?Sf`eXizb+CzX3198bDkd*RDy=2k@&O6#ONvYkH%l z*0FIO?WTDz9Ns+G=LfL;Y6#$kC-W9Os{xW1U}6Rd03W9n(}%i^ndjz-Ib9lhR(ly#*Ad)&)9eW!? zbIXTjQTId%-7C>QPnQQWa6KbPcLrRyJuS`BAt#dRNh3uwRQ>`^8uO1)a2IxA8@@h;A#iFWOV#POtC-;?3uVwI;K^hDH~*SC*1|vqb!l`{(Zd6+eP(wGSI2+Z&6i zte{ne8c`H{7t{{-1f_TaF-FriyUrPmO-_6B>Lkuukf!={>;+1Hq>u3 zAOcQD*0}G8o)?ox)G@TGla^d`H~=5gy8i%&25l=!f*AtI89TQVpVp?Y!g@6H(VnrP z>J2^Q7Z&W+^2R|0306`8$31H2jC@yl;xx57g~Q%S81nqA(*a_8C zs;?Ln?PWLZ$or@;Ym=Fsk%}nZUc9UKnVFk*Tju7eO&%4QTMAfYRhY-MLnLYwXx+)r z9gQ`)WliYhV)5-K(eM4Y^r)&Px5`QB4C+Ir9$I7~~GVoKu#- zSGOweS90|EOAozXiQ!1sOVT5MyYd29j-#B{3uOWe-WTV{1xU`{{{Ua~uD`^3is_yW zxMlmx78jnCo7fKs_?dtGx8keTL%C8@isUaw>2~Z~*F&nwnVG!2AH3Y3n3}-8R+4?& zc8+j?|vRPR{0>NZUScndjc5jxC2P_yf&T zisR<{*bmn=VJ=ylZUZRjM{0uorSv3@TwG@uY#x<+QMEEz#@kDr2II9uZEGFLiB?Ul z&9|p&*=U-~d3#RKLhkmZEsBoj6p8105`n~9nCZqICVt$AYe%Od^7V^NsA zk+dgnPI^}~j-|1i_GO}mSKNPj-_nYZx$%NWpYzt0#&NV`*WRRSZzF3rEB<}y@JIH! zb1$a&uU?f()YwM`Tf07W$$NmN? z{hi7_De_rUjy+qhJvi!VXHO@WcKHJMhmzl*{6;7kHz^ z4dsl*Xd|$VkA4-43Y%ZH$)~&T*U$GlSHQhpl}X@Vov9$??zK%GfsXBMiO*`vLUnS7XyybS0x+N)kxt+Nv>E zEavcB=SCf@F^u=7Y)8x31 z?trV-hTVp@GnUF!+QV+c_l`PM+iOtqu~prSatIm!06x`nCW6uaSY)_m>bb!DX!}>5 zrbdbwTR2t5;y=&5X4`1LL!bDY@Y_%Lsqp(;@V2Gp$!X#}I()%`PAT-)i9?vmARFF0{5 zuaU=Ky*baPVPB3v@LcbL(dnPJ9+jja<4p~2<`MLH;5%K({R}!BgTr zDodI=A47i1t!?{4{2S4HK*DJ+HLDn|W@x@+9LNke3RGkMTgN9%U}M(3Q^DT}+9Y*b zcamr&@?{K4Y(0xE2^su)9+mUY{198>U9OelJ$vE5h^``AI~m&U8JPUBLo$!NG6DVS zlY$Q}Yxi^ZWcVN9{{ZaiZ>6`l{?dl?%_$bZA^B7dqyRuTC$B$+YYP)o5b4KL;2(#- zvR(I${86Ua{hw6RmT7}sU0PW@%M1VGE7GG0z;bOo8x& zc0uW!cjC6uY?Q*P+;PY(XYJ{$0r)}3{y&v|Pmn5fa)M#|R3!fj$vff!+qxyCrh zHLoA+`Qa}Q>Q*;W=(ZP{gfE!xE@K;E8^d9GE<3#d@r%Z^=(?uQoLA2#k0==K2a&g_tlx`&w7-fxM`3eyr%iPouA>rNUc+fRTcz9qLp+Gg%Alzz3Xf5Y zclg)iH^l+s-6P79O9rgTTXl`WGXNo&^ z3a`D1861BR9Djv*=D)0Yuuc7-Eia~#O4~Ec%O#|F4kSVdUBvDuJ#ak*cE7O<*INGo z#D5eS8NSP-LlwQVJC>1}Ml2bRLy%7&{c6KH#5x#ROUv`n+b&$yY<*#86nb`$8Vv4b z4u__G>i+;BE9XDjuj4EHI@UDnbu8Mpr5g|j&E;W_%ujAGE8n%-rjE&CUzInKcs`FXB&)H_d4zi5-QSK{4KWaK!!{Yx2C02P|GQl6@Pw^;pbLu%&cz`uD^e zt$zAziEb{YX`IN4(-{O=;f4vo=~Qg>*^o%0W{Mr46j_cNt}-+3e>&zyq_)?xKGlV! zB(MYToC>8K#P>IwS~c>d&nLbs_AD-2MwC*DUvcquvnkYW??bthR1h7_y;XwmWN)rA z1t`@8wZIC>$izFSZr=H>YfQPg7nv~1!(mN;U@^hkGt;lFbQ%SmaY1Y)ju_;>iPjk1 zw;kss0C0D32OYl}@01i((>XbtcV~6rE&843nG8(q&V4o6439ZPEuD#gm~w{i>>?zk*3^}XfBuPOW{{$;UEi)x5&i$ zanEY`Weiy7BML(F&t5sreMjO?4K{(L-dVH`s`jpg z^TKT)`{{R*)d^7NW!P*X!cy#zy&|F>Y`fhZs_E&#p(M zc0!UqVzo+F+}ijD@oN77;W5&@6XD$+?$^UwUCqtruWx-S$uzf8#$G3s>|qSaw1vUs zG4wg|eP`p|x2v}Jm>z^lh# zbDhS#_r@L?wec8by=VIiGhIa*%2?a6b|cV+9B?=tv0kkr9$UdDoUpYxdiT z7jg^&%!8mOC!A-}xp=$>apM(s(OU0X)jZGKY4+B$Pb)uJNZLaii==9t_N z@r>Xm;tw8!APgLLuc15z{{RH?_@nUzS>E0ypMmt%QE>07+#<}_Cm_VEO8)@Bh|Yes z+<24VSM1yHV^@yr;unsi@m8s463r%;ZE!r7E1dr6M(4(Q7RNpN4e6oPM+sJ1w0zH| z{AbpzG>eTY#!u|~T~gEREA~WYo=HJQF1vG_C?k!y&wkrp8vT&|E_`o_8MMC%>J6r4 zzRh>6A1PCI2Jf3Lcv0Mbwe1oA0KrN=8T>fZ4X?t#gqjA9fkbd$UMzO;WpIwKQ`>$hc<00a02977c!JO2 z?}yF4hi!1ymZBF$wM9}?wgA8fZbk{~+Of5-0ZpRVG}jjqO*D8`MI1M_d*k}mtA7{i z{vUO<(^k$K72?_}akWBp4UT}Y#&Opi)|K32#SkkwXjcaadK}a)#&xpzD7p1GIMPG% zk-9*0!5LB80QK)*TK@pSCw@HL{3!jcygOt4p`^`YaXdDX+Fv56nP+g0a#Wv}gTWQ^ zHQt3Ky~`|cEQ+J=cOQ>hc7p}f8tskkypvjA+sXTx;bJ9>;GC)aKU%`0u{mBJ-q8Jc z{{VvDe#q_OO$$ra{6D1Irki{uTiKx-8s1PD!-nh*#Te=Re>zjd*IH+SJSX-^uB~+s z4PJSc^Oi?=iBvo`Il~6xzLvT8*{ytd_${Ma>s~t7zq7RqDBkwUd3@$}LxM2b+nuBC z;=XnGvEln&63OG!m72ymH%3YYU@}ikd!NtgQwd!4GYU==u8u!g@ipeRePvqq;f!h@rVj8fD$; z=N~Twcj`zzdeUhg7}PbZpZJ&A&e321$c@-zlkNcgtEtoe9^D@nYZiKyxq*B+Gsk%w zV|G+!vGfIhI_0%5iu(79HOO?m4jao@ZYB{y1+V(a6doM?KdnrvD<0-wf}btrq39p8 ziMjCi?JeLKH7i!r<85js5)~`G`6@jQPxP;>{{U-WjQVfFkBVQ|dghMT+AoUqM_G1C zW10_~rqS4aPdxo=!oC}Lb5rqui~JYiTe(%WX|;$Z6G{i05Qpbt4^hVkx^MU?t?AT$ zJ!$aylOc~qk9pnll4N2($MLD=zK3;cYK=DTYktn!M}mA&W8)wAMZ7$^JK0z|#dUT? z)c$Ehf(v9X`mxi~+~vQpkHnt|i}}ZnybGcD+S#vUo>}Bbw;M@)ecvlfr%~)ina%9gk4Dx`hU9?4%&c zj;?dpl7By?V^Zl8fUOpNxBF54%s&DCI(TPS)Vv23zk~ci90F+VC6CB&Fz`a>A-WEj z$Kzii_&eZ+p`uB7X{$65Nne_6P$h(1#Z<1u- za@Cu!-dyN5^4?u}F*K?-w)Nas{{XG)*1Y<)@U+v_nf^KOHj5pq{h?*M^ALts z&einBI(`-Nwf>zAj-@rcI~7(|#uprR747$aFNa#)<=iaMDquGw72~?9sMhW_Y%9E+ zpMOg1!|1HfH#g;usKeDSCJ{+)7ih*Z0XwS!H2EW+bH>}U6nyK`p4Hm5voy+gG;zBC z&5nY)Z7ajtWv;Cn+t|UXNhknr9Ov4)o3YDon(yzld(96*xVMu_xVL@#nolb#qjKPWrnWperRh4N*`@W{eX2pkap(6y z5;A_gepQ^RI~}p8u6Y0tLGZqu{uYBq&~Dn}_l*k?$9(?)`m3MtuZk|bC#^xK>9T#6 z;?={a&5YpZ`hK^Js(eu-1(D9jjRL4M?ud@l`HOP z&2y;uo#XrOjGELMmZ>GfTtYuYdjBJeG@$T`5^2cU4@A}u2 z_-n$6tlu+7B*`9F0P1#;$4c+KGvg2VLt#EzsX4(Rahi!su~FRXKWpy_L#9DxByczS zL}a_5;NxyTnXftcPp;UQ$kJC;L2~H**$x9MF@2=3 z)6%@#!(Sbw(DXR%^%z#_Xr;tcM8S-JfwUDL#n(8l>p|8oHBBH~Y8K67HNz6IZ6J}@ zka-o1qhqQh%#92TyS`>Vl}`S6>@8YJ8*i!2UT56Fh^`-@uvJx@nx;ni}rhIH*PpM zHOJ~Yx1G6Ij=9JcM(=>lyDGRN+MrKk2UCqFX5F{|NF3H(+-n>;Q;@x@a{M#C6*9d? zwP#+~Ig9(h){EGKopP*qAG*2uMMWz7tNcuJg{!w3e#sm6ZI&aNL8r|mxY*w|GI2*R zZfC^{PcGH@SalwiBoW9NmAL1hdemPJw1XVy@~00B%^Lpz7Bk0sUeOew?o+(Bk5sZT zN!W~J*DtL2e&bKMW3^RZp|3->@X3}gyIUg}9cu2a;5NO}S$4+K0uNq5qn#J*+2snR zG*v98cL(1Ub{NQwM$NvM?_E#)AS-P&i{#1cl0NU!t?3>NF^tHL$lVS)(v+2ksk@n8 z8POhDZRC-7-I4EJgYg?iwXpDBn>2BSlHxtmoSsh=S3>Z~iKE)vetaVJ#&cTV7OmW9 zdR?>d$q>)KHOo?N$3-}vQ)M@qGe(~(999{YTa#7 z*P_L+4EN=_4xRpm_;33=_#fdllnddH1^8z|Xiv)a_DE+QnUR5S*1LOaO#Fr=?ehf# z6>2MGELW07Gm(n=IK^D~Zc7#3#pIJDHgVMRK++Y#-<`ghIQ*+h6#eha$8Aj-GrI-Y z%h%@ZT3BTpT{I+oyDXgtu=ez;5Lg6dP}`f-_N#*3retHcce0wb7J)p?{;fbi#MxX? zb_FqQPs9la{VI$38w>o;~ijT(lm*K#arZymgN`F4zx_|qX-Kj*6*zV(Wa9mB3kV^0sG+QY%Qypc1Vr(%!stg#uDn{yHBN$XBaWcfm!+kHmteso+77uS@> zh;3Fq-3xL>LmlLkF4mJ6^rTyMlyktV5nKGYUfp=0aomLy?;YP!j+4W)0C@in`eC=fea-8ShzFYqQf`op^x?k;0t^7OE+SgM4*#6R% z!qVc&_Q?Xwpd927M(lB4RY#>i>0^HM~D~g5nI}^WVVkas`H#N3<>nFXcyME+DhCc zkx6TD7;!Fml?cv3&v0wwzuDX3<*&nCFXAVL1ea1TgteQCdjQSmB(Wr}HjhFTm+OI8 z%3P|(bZSbhwMWvLuA60dcqP1=Ylnq!6{RW%*Pd#xg|F>2-AP0eMy20?GP}N~+qdIi zHu#_Ru>RGGXyRyY9vKQd=^+l1cZk zFV}ob_d8+oBa%CKggGY}_Z9T`Xs$$a)t4)=PWQ$7eTJ`#i$Ax1<%f|pjIpsO$PQG4 z!#Heb99Phv@J)Lrx%hqJE7_TR*45J6dUCQnNCC&UBaWQc%KFZ~3PT|lK4g)p46Hpt zQIDqV{uTDO{1byr^1o-DCUUX)n#QGdaCqD0;!i0~I&_EiubSfuoVX;G?%$c|WR&lT zZ1yi11%^>>TWk4vUu=-a`q$<6#Ge}{jyy@?OQqbNZmBFs{+b1HztgpTp8nBkXQVau zt8XNYC8n7z<3;JRCpaI7{cG}DMw)iCkIrO!i>7Ja)D5|2E&21G#=d`oXkM*KjP$sI zrKv_F*D(2)3p=u`Uv;yeYSpyU)?^Hq2_$fjF>(mcwN!@6X(hyK=SaMj&jz|bhu#;w z@rJJrov-@ITWm=n0a*9X(;uyVoy?;PpCjz~v^O-}3hMs*N|9q1P+ZD}Sj2!JTpqae zIL2$(eh~i5%=%1F*tPbVYZHm!GdG!u)R0Q<&l^rL)7rgT;E(LnZ=l&*$t9dWzKA@G z$(1?J-TXnXbnu6Q64m3|9BZ)rtXGe~bgv^3kBoiPdKi2q_cOi=d?B~d&zvERE|s`s zhz5~xI-kzIg3_%a)8LLKMU44ljkSZ|?GQy9#;Y3nY4^Q4)ZQxbYU!|SR#_&E0L^$6 zt2s*Nt4^9rl*9Ok;VW+xYB9#fG>+lCmLTJ=uk!qB;2lQcr7s-Gt!-w^GAnJ%GK`FHwanZ= z@Xxt_cja@tt}|YwCVqEPHf--aJFiD<@Wh*A^P)IlaI48AduKJ@*=u@!tD)Q4$+;um zBV!Wo9OZg`J$S!evaH6(2KT6a4Gyui20G0P!!!%Wt+xszc%39auc` zdCTV{L4IS55(p%Ib*Htl-IwLnD(h_xkA+$f!fy*&+j-g)mg(g3S-}c}mEijf^IqMr ze$W2^1O5YO^V`EDTAk*Z3qGZ(UrYA6U04wEoOjO90QIkvJbmIVA6l@wxbWSJEE;?n z6GZ~3h1fEZ19AyWayk5kZ41es^m6#YYL7Sgr}3x9pAzpbZG2DST}tBC_vR1_!3-#> zNZGYO1ZUTtYs0k@kC=&n)+N6_{_;ji^o*J7{Ro#)bfGS4p zoO6##&F*NSZI0{UcA;zHi?*?u-|bddk}?P1jAu9=+r z4=dY`TJW#g!{GhE`2PUlU$#do={knF9gO8?+Ehxc7pFMf7bDugMRgqkbbG0-tSwdu zm5U@xkQGl)uS({YjH&au*`G7q{5#YwU}*)k?AY$5bL;t4T`R+XykDCePI=*h?_X1C z-Yi%-@e61no%Xka$rU~&3aHBWh1 z%L_kZ+bQ@W%k5qavyo#UE<(A&g(9sdg(1{+D>!va7Mj}TY;8O&*&`qk&2e7^d`GHj zx|W|~adNF@C01x=j52~xOyf1~pSGpkuy{vBlFUbEbq(4W64e5X4VmX2gx56~NjtOA z#bXs(e6}*a7-)JQ!taUxAcdCSPZEfvv}p!O+JT81fFSYt3hs+%%%;?xqIuhVTD!LR#o|v8$*0FXmx=ElPqWGM zFpusJ$S*#;RlPUjPMhJImb}q4IPC8?Y+H#A=3iZ-p!{n80LKr7vV1A=`&s2~H2p#~ zp2d`W+gqxh{2%9B#5ycdN95ei9jwmVLmoDc$ME;6vDr?&Ygrz(`xoEc_?PyKx76?M zb99i+Bur3zy#dD_hO|Fz4-H&+1DsV4*;7T6z#kp-nJy37 zwEa#QZ3M{K@|dne^XrQDKM`wImcB2#nlCY~qLEe6QCXRB$Q*y1(PL@Tm00q~`HoN7 z<6FP*#nivMvY0^9#T1M;xdW0%<=57_{{Y#i#^3O#E-bYNnmb$gZOjk6@JD`q>#6vi z;y86y)-Nqt?BtRUDmdlBy0<>H=RXR6XWtWiZM!YBn*DFnJ$fMrHK6I`IH6T20=dcgi^Wf z#-y!dki50NlHB}NRbTs0nt&_W7HGs)xdZO4vpt{(2@MRLGK0O{&Km2GK1 z1MS#k#!Q15W1pJ6GULN3rrg@hu|yhJ!D7C(u@#cp!G_@NEHT=-Wl^5B3^g{jJigOG zxA25h?&AtV?&7(f3q+g6dZ*dhaTem+l=RQmyU&WYO{l{c+4jf}R2}~S8pZf+q`sZ1 z2_#il4T6o^6>*b$9Q7O{DO)m5&o>%@=v$ApUr5Z{4d<(m{Cy~ytzByYH!FGuSW3S!JPPQH7N`%(*ngY_iK~!HjDk0wSHa9#|!ORkfiQ% z^2XAzV*N5tG~YE^)RKO1a5(E$Tn{;y8(SwM(wNak@Qt`-Z_<>uG+UKgHC4~v>5-0= zUh)Gww&C*eiqP^JNPm#WS{B>wGNf$VbL~-kYE`eHjXje}6euK)fOn^_g03e|GELEg z(0bQ(qIg~?K4uG%j(uxU^swK<$8LYdqE!`x*`7~v;g)HYd12nH$DoK%uFhCweii7i z;mBqrw0l@|IqO7T7g$E@7GaQh>}xK2=xqoig|qOo83S$kSwZ}2^`?ZLS;KjUJqq-$ zx-SprMbFBh5C9!2WYI!Hgk8j*q+=AG#uk()K@?p?2eLPw`ho zG?@aGF^`+_rly4^aQl3|pj2FEH+!SUGp6M#>z|>jXGL36yK{ZuFHr0d$9`)$@jpeV0Y<$l% z%WNDeL&-Je-XpRa#pI7Pizk_roFBrosL@f}%F$?cIV#O%G~QYUhERWc031rp16)AN_hN4=jIs^`e*`tV2v`2wXAxRmi+QBA_gx zSJbeo-)WhC>usqdc^ws-GHvxeE9wuMEGD0A7I)la{{VFt{C}lM9nHO|1{+gwSEzQ| znx?DfF6CzDwt7^S@BkRFVtB#piY^7_@hs9V$l{9JcM6|(@ikTDl2Y5QBx2pOL~u0Y zuM5}aCZ>+q?b^S4wHGDqM+_%!56k}mvs9mCP%+a!f}}P+W3CBbUwXG`r~d5i`Mq;N zB};o$;W=f&>)NNXvGSw;0Bb(Ap$?ZM>4?|;?ki77@MY!Z-H2OvT=Dr(HMxrv7<^+R z=~G+Vt0xhtJ@9(hZ>0Pkzq;GH8JBVU$EGW-(Y^$%Ynjzf+;Z3y7I_`EnKMa<*KY2) zInUCyw9f|KUrV(jkZ$!}4SQCb;2j@Gbuuh_fa$@`D@Gkk(#U2QQB`;>SET`C%CujC zx7T5O!R6%gO?8$(1nqSAGb1dF-+S7+L$1j3Gbv5K!g^+_&v?@A$&q(=>6!-^yOnJG z1E%S*ugasXN37`9E2m729_Sbqmyh{oK@I%rBxyipT(Is*=~b>TOtBks=Q1lOIO)ef z`0nBO*F8qkH}-lTp58wA%i}MEpAdXQ;M3xN5Ph3Kz7X3JcI>`J-N}re>cD@%Y5xER zzBOxlb@r`qZ*>~QbjJPVcP%8WbGQ@KlaP7zsQ&O zcBSH0(W79_7S*%3kU7s<%S~cC2%=^Tv8d#dPBUEhi#$su%1s{V8aDff86t#`^=G2# zJ~~}S%|tnGljL^er}^((pTsS4_V#!E>ngNle5Znbl}Esro2_<|SgK>D0IT}#vAKgA zTg!|FB!3THwX`&5a*MI@r^QKUi^S6T7ZNKvnD(B)b?f!7J-uc|Z!bHcAh$WMT=>!9 zhdv^@x_P2of4l^0M30W3XYlD>U#dq9y3Dqq`ECIl{_+EygI`gDpSXBj$m@!#z4U7U!6Kek@gK5&N#nz%!`n~lBZ&Ve@guV{jMkTKW7gW zEsohSr?ic<{{X8+`I!DgAMh&pMmt1Of<7m-@%MtX`-@o`X#AlV47*tZ zvv5b_UX!G0%MexhoP*HzuZw@+oxdCA)wQ{ND|vHo_Qek+ur0Nx8P6H(j({L` zS~$<|Fh=9bk5A`cF^*Q1k9!W)j+!fWv(cVaUch5D=KeU;9$Dm%)0~d==$FpvrIC-k zy)#~St7%e8a>Vo|xDE7LoGz(nAc38SW62$>=HH5%x_`oBGR8huJ9_$8)!r_%5ZFkn zz+q3}Ul;sPpJ#}!e|V>4t@G9!wCb)*ePaw;5u*xL< z&*M87k%GVwao3)ES6@Dd#nZtmvOayW@QuEK;){EQ-ED0OHqtwug!0Rld~L64GHE~9R(hVLJ>9;W zB>r>T#?DGWWEkN_2N=dZNvJiS2-|5_J5^W9hXrF%#AmwuB%)h}Q;eWbu+uE!{;6;Y%JjO+aGIPC45uZ;=?BumucXwYd6>fg+b4ezWStFU7 z%#E9nt+(^6rHEEKA%wn+$+qzAt%T9+^LC?rtmJc$LC1QvX{D{G`BhYI+M#&fe}o@? zwI-)L5h;>pMTJ`==gR{e08hSq0(h@P_%-`2c&pp4!7U26 zEcoCYWAm&Xd+c;a4;U6dWRD9?;}48hI=;yN0O23-bf4OKh2yX8;*u~*N1yL*8UFx) z`V(JeUg}ays!KYtVypmW{yeB8fzuf#yf5O9jl4JTpWwaE!~XyRLQR}7Jh!*dE|3 z91MPyyd=r?Fiz;s@iwDz(OzdeY@a$)5N7 zE@+mw{x7$;jlA1^KG~I6jO`JmI$O?_N7DnA)@#@_%SUYxWqt&9XKOr#%Px z?^xDX%!tIZ?PHyQ^!$3#l{V3pJY-!#+R4x8D+Oq*A2;02CcXScBsBrKlpqxGYGR zR}ITot7$(8be&Jawzt=EG}28Nc^$ax+mA}oMaNT?w7seG-ksoU%}-C7;?5S4V{GjM zHMOjKHNNoIhhfziZel?wc>dlBOYl$HqJ^PlW?&V$%KkOX{A2NjhO^+(kxZ+# z@Vief?f6x5-$S43_B_*8_^ow)qJ4!}nBzR0XD7eqS(-%C>NrpK7hl3RbIo(q*zKiOOWiw5dyPX^vxNj^J%Di4r*EgnCDOgs z<9*yR1HrC4#U4I;y<$l1SS(AB3fE!qm&0x1O^tNLl~3oN{{U5S%F9#Hr-+`#$mFo{ zmN;$NOg07=IjZseG`ZKET_G@uCC4La$KhVl;U9)p@|5!7;W^K(c3Mw?;kQgOFAb5N z#*}I(>Wv&FH+GK?(>@8MvVk(smFP!L#`k#lRh&Jf+ zyOGJRb6N1rGOp!S5@&)qtS4zZv(lk1NZ9kAjGqRZ#C{i-P`12jq*c$7y)o}!D(jjf zY1*r8c5f__$&6r%`>IxN?54G41#yFpGhRvK{{Vp2ekfU6K0$MmV;EywQj&=>SA55q zcx&UEH-zK1`FBQk=eYx~70&pR#NXRD%_a$4=bkCQ5Iz%Md_B36Y)STZ7*{LTAO5=K zZDx{HUGKYhPiotJP)Bo8Yldv$eq+%806J})1~uBMeN9QES;;2R_nD6#)zxTz6*q)4 zbgZ12q<1iFw8py|QJufwJu9NoycW{|mD~s3&lvQsn@I4w#1~?X&EFj>e$&JM03#{; z+;h`4jO1H6iysaBnFM6BZt6WMW$@l5Z3LC}%6b%9xruzA_E)Y=Ri5_V z6SvIT6m&F614|PhF}rc;Rc>_EmuoTYgU4FU&Dhp3De9grwX%ngnX{3K#y&ofI+){V z%Mx?zR<%zK`O}p9yLsvBR3Xy#&*g;Qj_0*cv}JM`nxBYnucvmBP5ZhAJwBD4FZx;A zwZnJMf2D3}8gwDI2HL|sZK@*E%nkkS#L~MSh~@QllFCkpXZL{VSeleK5)#{*JaSYH zg1fn59$Tv>tBpT~3McUf$WsnVMF{4^EU7x#U`Qn=h83QMWMXBdu&{ z-VMCFol0A}@zjd;4LiX)Wq@7Kx2GU>`c|c^cA9fAjW-7AkeJV=C%7o(8V0mefDk$0OTLiwqm4rsVqjN*l{=fh)xO$^y?Hjc+VYde?7 zSr<$n=J|8e9qL~+6;);6)m(zByYr_-E*Od~7Dc8CtNc84_Nw<6Y#Z;hFQrE)^B?bg zy~nLav5z;~>qW*`nY_gQKcJ{hymBT!WH|tmI)ZS2O#XDZW`CFXed;@jB-{6RQ_fFO zQ!R#kS^oe9FYw%!{y6YHqSM>Nvs>M1@=Gb&yUXuTNFJE_ekQ(hxR3ibaFbnF$s-Rj zOfqg!fVk(5r$3c_oBsd>E7DqTggR!ckuF^d!O7XDkd$!bcm}Hmc%8ZacT>DlZh+}E) zOK#g54oZxDD&C8JqSodC6j3yiw7yd1OnL3M_(!KC)lE`mNW8}D$Qb5`$caYA*Tc)5 zv99S^m5u?&ZuQmcmk`DsQCYB@`+9#`^KS}xfg;paHEb(&&uZ*0uFcS9Qg|51?khy~ zGv7nTem^RphF$V)$@y`eq~g3v_QT17X2F(bEO1ZX2mC*+eFO2YOPXyWX(Lr;MgWHN z_OAiGk&^ezR%ZFnC%>q#p}|kwJe*VxXb-j8Mv_4rM*|s9NHVTKAgT1=o_(wAzu6bW zBg8+m#5QRn-OZxh%csgmMCl+=>^#HGe1R>aO>uF?=93^r{38H@ezXVO{?T0WD{C13)#UDIl~tIHyl0N}Ay>F67jl^J1`appx8sW5x$u{Bo1UdZw-5 zNv|WhpH07#djcY0zhxj0ppG%e^RFi|roJQ4z`L$ieT?_b{hZ#Xftu#^xzf@%WAkyG zS7`cdKiR6xMsc{D^!EHKgz-^@v71E zzZmM#g)U;cb>sL)7_YiD&1TuG>7~x@!j`?^?ff?wa?lt)*b3$IY4^tg_hoZy;GCbB)+1@UEXm)po$kyPN}(YpOST9}Ue? zoZL~|*m&k??hpL33@{3)0At##UPt|-F8LdGISr0YavEQWw`yCq?O1{1uj5-++U2aO zs+T2NO}j_{eBWM}{e3FAYNBS)a^jU=>)_*T>CanhC9Bjz9FP zaC442h8X-nKTs=+vC;R=lUwQ*_tB^uoaQ_~bpx*+z4Kki#%&$EL*cC{Y}IDGWC^hq zoZ|quBkA6%8=m}Sc%$e2X2xreE!~-+4%y8~vYkuNtCWNod-Bo6y``$|FfX-OpV9oO;&$%yvhSwu;X% zXw}=y7yupEKTf}ucAgLYoHaiYMIGJemtm)F9%aSEpelphFW${}6X~8E@D%?5XVS5% zUPqAE1wK?^)l~a>{VI;2ZoESmoivQRzP-29H48g)_NkzK@U*3gV5b1_o_lgDHgeS1cu%uO_j9y^*QGLc`(rXG z$8)%!(w>j!hIs%A+>UEIQSmz4#~_9^k(YvT(xO_Uhf9yO(v!|_H}{)}`^q`TrD;iO z*AR5{9>TIbKdW2nC0auMXJrSWHQMVw61vkgYk8C|>y4#AJpMnON`q|MnI&_~yk@$z zK5|;vG^&{S{N1|;bA$aWjhDolv!h$u-Q7tc7z&)@*C+DnUahEj7WU&-^K}N@Z^%^# z82q`a=TFi69jh7Q+bf0Jw0qY?T1v+Zo#%9ULwHi>Re`QAr)e4`C0BM>dhmGktX&Jl z(Wv;}QP{g%&UGg}aKwK~_gy09!@!9o z%_~oJu!K}R=ltTlPsQE_yw?0!(tVytR`N~TnEH}W^Q|fFabs4R9&>#Mopcv!v-|fI z8^b2{{sN~gRCLe(0IIq#82CPK3TiKJDc#qfYQtUM!;`m;wa|F-j<+e1C5$g5aQT@T z+}&xnZr72j$8O7TP#F$S&FRNaTCs8@bY0uNW5DD3Ris%Sbd&yCBJC#_;)|6|R%R*F z<$^e0%V^o80Asy-r-XFfb6oHYc5ufrfpT~H`t$8xUR(Vbt~VZ_`WpAIfL|P~{4wB( zG`q`xGjbiQRAe4|*F8ySde|8A>UeLCE#~m_vP820Z6@ zhW;H+{z)Q@R7lz7M|$%ci)C4PUoArtSbJ2)MwRMvJ2KD0-wdX;;;VRXWb$BXuv;Uk zuhEZ&{{Zkz9RtVz01uN^w7S$GzF2(8T2Q+qk7FI%M_xd$&FvEN`#$w%RxCsAQbm28 z@E`WS@i&Eh7Pj!;e5`^zvzBeRIRdh&Cu6fOqfTp?o-6T#_IQioM~kks^L(0wmhu7T zD(&+!0m)w7Yq0n$qpDh><7YVQTUv>q;&11s^%9uWY1M60!(e9m9 zuudzS=!V9yntfFmtU#*vtZi3Kk--YPSx+O9cg?b@!%CaXzgx&ajfc-RLis z7^A~C7Zc&WT=X?VUGQwyaTZ)T_BGI6>eDo8zjcN|7^)`jXXEb$=Lh(xy@$(v4mV!- zbN>Jdeur^wd2Svl00%#hezo%tj=l@scuU1|Tf+>}M6HlQ_OGWkf7%w?!yYpJ#ni2u z%3*>_oF)(5=ku-W-wpo&!c56^Z34)$;F(AatPiDHsL(oR$vzeE;`y7ryfTuZNjz6= z;r$far_8@Eap_&h#D9fx_+wSw2vqZlV~^qKT-D~FntUc5*=%uv)YJBtCN$m2V^y`c z`@lDPgzIWP?spD8wO-oJZBKI-3Bb;4OHa~cK(4C0n~uJfjO1zT*;D%t<5X?THmfOY z`eLcgr*F5)?%f~W2fcNzX2#f!+1xRKR94q)yIFDDIILwiV@StSlDV;0l|x7PWYwj$ ziWt>ZLihZue&<73Wh|_`_4lgsXz3sDl6nFUO2?g=*%<^|-9@}72Y|UeRRdztF=+n) zi?%ve)V8tNyB{y6GgVE@XZ>34Zu$NiT+C*D&YB+GV+s|UIXS4|(n2oQJBanILR2#O z*aA+6(yGr7+1z~FhVFipg6yqzr>hd|s>c{LopYmX{p4ROA3>Z}gx9Q$+ZS@=kEK_8 zi6f3l7oDS#PCJj8oX(|h97@d5Zd~AT-@RsPw$R4ARe8p9lUw_wxVK`>%ADf^rDJMn zhGDnn4V)?BtZQ8iKPaNN&GZ0PcB!n}*+9nSnmE^z)OepLU?-*VwgVDzT9E0)JiH^q%1W?-?gP{#)yXs;^rW&Z%4t^WXgiYmbVl&!oEr|IT4 z{n=sHj+LPWt-Xu0N3`z6QF*rxy=k!qE%&f1=-$WASsD}H<#wvzclV%bO(4S_*cC~n zVAwx5r7FMommiHq#~sP{@_PGoOfFG}%z5eWOlg${Pj23|65q749m};>r@a?6Ei9}U z?*9Pw)5N=ds+ZdHxq|)Py!EFn`{Uh>zJh=)Zr*-Y`qN}z?>E!7Dj4P5Dch8a06x#L z+D2{X(w!u%A>F%gBaBlK)my0)*{%#{k@BC`fGo7Ys;F(;Qu+Q_;;Tg{mA8IW=8y)U z37;?gUs`iqEGoU~w&kXr54%7XLy~thb?7}Q&V1O)?rpurRarLY``w4FEOM|dxc(lL zZU>Zp+Wr}D6@JaWF0_Y#odu8Dq8aMZIZY(_^%?-zvw2B(TR**FTRR zm1ed!sS||JZ6&t6FD0uG#BJic< zd`W4fU$U*7*ONzsA!$Ez{(hCR*yZYA_|gyUTZvR|xU+R5_d|0ddk&}YuQAlWXY0$o zJ*0*maH~0GD`V9CI*RliXU2C|H%~3JaM`FiPb6}u*^fVwuQ%~;#9tA`sLZXb>PlDE zcH|oLu(Ep`c!aHU16ueysAvk;7j}BA3ZpHXHo}imK_;g7ckvrd_;un7dyN*$&AMq7 zZm#YwK4gp@c1A$jdiBXXbj2he5IjK`{ojbMOnC*F+#f7wl1UlBs~$Y@P0GVAo2gp1 zqkPgNk>1Y)af2Bg7|H>Va&w&Y71dgwwWjI4j(jxvDk&db=w2eW@fU{SdpU&ANP)S| zHj+rsVtF;d{9O2b7mQ$#tjvYb$0pC>UO4)FE5|+(d|+P$>CbCD<-)_}e31y+QIo;J z&OqQ-wfJ+!wmOxRb4MoSVUv-J{-(b<#NcY+>p8^x3Nlsc=#QCvb?_tp5&cD^j?d19 zHQ5<#lAlA@{40!$;rlkJZD%#)Hmz|mQ8mFnTzSqno}qnDYWl~=dbN$zEw^g9INR5C zc+ZHmt9zTd)5-HZ+@mhs@O|s(vi#yrD9Gijkk+XAppPN(M~C$f25SwZ-$xtE3kgKPcdp9Q;ircz{?Biw*xpBNYRy0TUD%nt-K1yb0~iIp zdiz(Qh|E-=(>pLcAB>#Um5;pdemv-Q+DDkWlyXSi#EBDbb;jUZ+=dnBel`7|EOjJ* zv#g5PCGvRVr}eL%BGk1A?SlQHVdaI#&(vTK>E?cP~emO>{kqc@|qn9JQ_UvGcya@V8R% zDwk1^w+a9tAq;+Y0Duo1*DofU;vESilKRf!Z7z{yhIArCkyr*9 zb>nc|f(J|t*V>;8{{UefOJ3E}#ojB^W{%eC~t}1E(jBJw5B&e`Wswfc^mZTdv3AuNz#tvUbX8V1NHqk!kSK{sOmS6F0H47 zZD(ZtCT1#|z3?Buy;%LJe`%XPin^7(r-$qfo{wg`Y~+xUG>A_w%hQq%Zq?_14*Uyo z;@x)LOD@wP%&s{=K@3N}(t7%X)B+|uopkij^V{76%JCMVYYQX8Z+&qHZa#1(d>_Sj zpT@R4QLN44dzdu&t|WM@;t{MVCRGQp>D%-unB*5ZmdxOm~-Q9B=c_ zc%oC~y5oh)W?_Uo$+Ivz5x$Y;1- zy|K6X*K6SKgMJOrefH+BUfoF1oNiQBAs;+;?O4<6 z?F8F=?g!o~FnzOHa~#vC(doLM#5VgJcJb|HO!;vt?T#*-DCnbsz{g7F^;`R`a(0^L zS0_0joc{oxmCVhrw8#Rs)*X4xTk!6)HO2DB_n3X$_o*?JORF2UnnlIH-Mh<;x)OTS zr%ki5M%;YK8>LSEVT*Ods}Ht%ipjt6ot~K~`#OnF-6yUMHMz|rF2?#hKNZKhe7N^z zyH~S(N!8tSO*U(G^EV(XwR&{)uN&3cJ&h!-ADJM}9Z0W6@b|=Z)chxD3|7r7mg%=7 zdUUHMTNrZb8mEY_JnNaHiX|r)%HuTXyeFsVj)Jvvu!r`w3(`LKB7J*$%O)||Fh5*Yqfkeq?*RTpMwQ&{SF&%}L0{t_Kgrfs`h zAZ`3Q*EM6|r}KxScvmGn0H!qaZiPl zb8&#ZE7H6NH*I8%bJ408$-6Xa2a&TBgLi?__IM?yzxQrJBXGsOP@1-w7wt!Z@)Pfv>C z;xH9mi*y}02Nk_zqr<0KExojH#~f>bsxSp?8z%DAls}j16q8*40E|8)=zau&zqB zcG7EmSuJ$C7a>fo^E+|R=~yttw$mNklrBC}I0LpR%V3V>J8O3m%BrM^2qW7WtxIzu zV5=X?jAoq`#B;yOs;Z)v!%c&*uN485Hzf-o|&bVCB2Q3CRQ!ncBjE% z=STa@XSRFP)^-v`;A7e2OQ#^t`1rp#m=9(8zj0fIP{_|JMEBd3d_jmw5LxYS~dsEVlcpc+MXx~Ra9)M zaxyWxg&j!dFecEJ)!ZzByO7*|RhxUJHP_0!mv7|N&}vahcXrHyHuN=IBpW_BeQ zXRUaDj9|XjH_f@Xf*D4B=roq+L@70^G5#Uy_f2(+nIu@*feoDFJ*%60SgkFK7Cv)7 zIP^8Cs$ARwvguWsKp>Nzl?}It+VT^2!OLjL{sRim4R2B<7wZ$9e+ghL>;M?@{NUoA9XGUC$UR%%18$+$LZ@s%YnNaLFrXZ#wEw6LrrUso8~{A zManIC{V0;>2-xEtDyg{0`AE;TGI{rp_GoQ@`{&KF<+ps>i0y&azZU*4{2v|&{jvTj zNbY>Qt#R(6##G`#y}trYe#&1i`!@>wa;0<0$RfWtKX07{bU)goUZ0p-QnRM_SoD+tA% zbtR$J-F!l|(=8U?PPdV^f=QF+131P3{s*^+jG;cbSUU^74BJzFx|&)I2GsqH?>=f$wZ3MJM>}3FyKhdSxUUqz z&2-oewRs>mGhUV#bB?~pFBBhRxVLwX8J0I2qd)S{dLPQ2;-3;+c&AsE>gny6)mh2P5&_iNES z6QNyrawb(~#F#sjb?evjs$K-NL1eAH8=Q~;;<}l&6|h4iOp(X@UcZ2^lg&N(Sp8Fn za{7MBPD8G3ce=Ff8@>lqRocQ58b$leMmVg^L*lld70X1B$i+tvKpCt44Dptk;urq_ zO?I%1k+t|F{{WsV$o4aex<}T>9fHHJc)b_yPtFxkAw5T4)g7;$smiwS@0p|@aY15! zorQN=cZGaAs628rO>ke2E%UX9{{UXS6T>=9j-MQ6-qs6kpaHdc$JecL&k-dqR%2U= zu=L>ll5F!I3w#6d7QBkz=$0|#8?L7cK>q-644=al+V}t^LE64^_H?t-5H_KxTwN7B zt+IJ>zt?dj{ur-O)8SZc1C6_wXLdRK>zmf~g%gmfi@1;vQs0elg}n7g%Hz1B8#}l( zqxhK<_-DiVUZJP?dR?P=cPf5m`Pg?J`QZK))A;w}Z-=}!YWjVSk*I6hf{!Q4vxrBu zp1EVwt}?jkS-us!v4h82KBK8y++AtG9{of7yB#nWcCyPLQ~{ zxEg|_*9vi+%t3En0Uc}Pdmjs2d^y%#O!Aw{d4XwQn7Xr!^Si0!p1H58X4Iv73%h%t zmk}0>fzWYE$3p4?B5m+4)sZZ|VO4>#m=` z-Zy^_Tw!F{xE<(y!5n^Oxs88LeLGOxyG(K&>$i`T^e5}hOJ^Z@KoPG_54|{?bCXWz zw&{L5y3}CY&oeZj=jA;A06O5jJE+OEb0aR%gM-$!(@dKCGAldn zIRFl|oSQ0~n>MaBwU+}VhUhyArG0a?7jAucHJ>HDz?3(Z$i9cYYuM=id_kXuVfj>> z7&@k*BiilW;YLUU-m(wQ27XSz@G9(Q)9v653l@=^zXKJ_YqG~_b>yT+8R}0;+9wTd z$gQ-wnmG4;<|mx>u9HX78a5wi$DE_Cb6niI)Pe^=8lAWqC!fN%z8^Wcx%sALWB`_N zfODReMp4}8w7&~oYGi+CI7Pw1-BLl}s~amxV^~bm47Tz*)YEI0)_a$GT)6ACxD}Uk z;tSih+L4%}2aI6kQ;y@3(BphSvRum~-b|7CPqYBt2jg9r!fz7)0A^eHQO3_KgoO-2 z`qmGM^_zKZBvxOajxp5KJ`M3SULB2{qg~xYdYZGIZ1l}D!;(GZ+JwxIIOK|&+fcXH z;QK6!vOeRq9&67}#5=8G8DZSYjmfLu4g5mT_=+9OttQ~SjPXhAW~Hg=)^_Z%LvQ7X z*Kl90L-7MhIv$<&nEvuUI{Mb!x^&m5vnf@LU!D$DvwkmL>3Uy;FFw(Ft8pA*qXhiS z-%5*{^fI(fbm}&0f<4Sw4Z^YfacgjNi>$8iCoBOSYme}!#%1tsnKVCVYpIr9$N?Dq zYZu}l$Bk3R77b?{E2qZ9nM`Ar9Cau9QE@Yw);v@8muVUP=)p{4uw>T6tj)Bj?a8RF zw0SPinIw(n^iP}f{*?pit}r8R2T|)!nC6u>-h_i)5Vs3WlUr$D{bLOO01vG-w5&HI z#z(eyQ4Wg6Ozm%*z9{A#aPz*wYvKtZA(>9qJpTZ-Q))gdlIkT@i-X5Ks>QE_o=*P& z#4rf!S{8l>k;yE6ZP*Krm6WD-Q=>NZM=tj}U2z`fJ#mgH*B0_1+^W&4`keKy;?Ka* z$tUk2+}w0p*tYOIK60NgoOfO-RYq_1R`fiQO)lzZ+5x$%(yFD6xjq9x{ z)LQu~8jK8cj+Iu<&K)Y-WxR1hpyY_uFY=@g^11n0dykio#;`nB@gG3&jl0RHYPPoJ z56m}iKbKSZQOjdfqLSluc^KX9dekoFF}UuJ+>e*@uNU!G?VF}rNhCThoi*}-^4!XH zMo+NoUUTA4j2EH?5UBZn%d@#=9vA4Pc2;)a9Z_*t*DTR7Q9N~3vFso`zWap?pxWLEM)_flh;jlXmaD zp4Fpgt*kJv_`;|(1%vIbcJ1S$Kq#CUOTroQsS zJeIKy(){@2u>5(fB_qLYG*fgKHxRZ7yRX;N4JoEJJPZ|Y|uW4p2R`1VL z!+EC&%nx2F_2XM&6D!;uW)KUfwj>k1XVl-aVB{pJ9jtB$K4;{MQ&UP5_exQepVy>Q2zi5 zC@B5>c3EF>A4BO*l0al5&{bJw#5;RtgK_h1_WY~p50fnh%>?4A{iT%SKaZ^j<&W`x zlmTeZk=OL2%sJ~+&CyTxso!k#2g~yM&;_$7ZibNDWYs@6A2+2bpKu2>0dPySaZ0y1 z9MvB=nT8vV{7`PUu^-)_3zA%d-|W*?W+R`xDv`JVVDp+&aLb&x%-ueMfG>TaaZPEM zDfzx%PgFq!l1wmkNYToTbllb~l zWi8Dkc(FIXYK-5sY4ZHb=~;7Ms{j{sFgy}?AAlJ@g*yJ>wEI&$%?-S9jm*=^u*Z-0 zn2o=VYB`ruwR;w2oF~ova$qR*BJUS-$%i&A-&&_qF&1}lYph*G!OP|WV zkNB7SYJ4yFS@wwUd{u9%YEh=+W28p+(_r-gqKMZR9J{FJ__@c#zqFU_8GHLqd_}R< zKeJau(e#)e4K~!wlT9MA1iX?VE0eSxqo+B~6~Ty{9>;bboRP`PJeEx&x6lsF{{ZT) z>+MZ0g&CCYEUL#Ge=6W)u$kL)H}G`yCcP6!n$0{d_FId2CXu5IlO&sVpK;!@r!7vp z@v%jn5oBg3Yh$HVxSMVfWT|eVW%)6HKqY$pIi%aLZf&KQW2dEbqnOQ|BtLn${vLbR zJ>p36g^o94Zb+_<=GmNcXOsYTpjD@D8~J`T#xhV zPnHFFix%?2j4I&pKN{B5f&?GA^5a&<{N$Yf0Q##d5#BpT{7vL7p}qx z^shJ6;=ZxHX_*=A(2}|BTiQp&eJ=aK^4=}&y7_El`{47D$@iv1UH!QxNc6c>rsBUe3~_>fqdjZhzi2;;KMa3mPucs! zJ_7KLi=g#+Nif@q;Ah{biJzNhgRB2?>%p zflOY_9T#$wAW?z?ba?qQ^qByN@2;wMq3iiZ)he;km%;R)66VzL#q{Alh;Z9Ad87X*RYD zrs`<-6Pyln>rnPLTb$Oi(_XZGUgnbr0FR|$>bCPOzSfMr!yZO4v{!Yl>ozvCt4Fj# zaxy=LxW5wX%XNL_!H+G!i1#(D4l3K0zp^c?mdSuVZ_hnI!Y5>LYJ(F8p zTurm(UV2wM99o#4tkVa z_AJlhr!Dd-q6PjDPq*6ft0Ya=YHi5M0MFW~mlLxMyP1n|$NvCY zyB!Bck!{My4&0G~1~XeWe-7?73BG8_&MG~j=+nZS8PcMT1`8j})a7zXtecMt>KcsS zENrWTw~n>$wjT=ozwl zb_W^vrMmbl;>||>71cFWv9*}~@Iw(U2eBvzgZ~)$!v38C(|vwAz}81gxxZL zL{Rf1pHY*6k9sV8OQOlAB#q`nGxdf=+aNztkbewUct2*{4$!36ml}q!>mV4OK&n^V z41Sf->3#*!^gb+XQr~N52$^4QPbQ(%xx8o|b*2le_E_w6xt*9~5;$+tx(zGg_PKK& z=`G=f*m5@RuS5@baD2_n`;mYF?fp7dhKYOSknXH~aK@*dm+X%})4mN|-dg_l;3S#j zYSdca!F#Pb*CSH$*z^p8=C4J*);yyqw_7^E0|e=VOs=b9(k^-LH(@!Y2hyf*y%R@6Z0-CkjM6>8^d$g9Y0FxukPc4 zgkODBVDXdBrE{8uVpsC}MlhiL?0eD7ij6mOnAScg{8IRve$dZ({g-bb!4V?Gk?(n#e#TQRDz91yssrSmF$?dB*a0lQM>G*sC( zhw%RZL-6ZuTX8Qr9%~stnKgd@08qEKV;pga)p$?`3-qk-w#jsH7>|+1wkeZdPc5O2 zXxX;++6I3rm$6DZjJ%Pjmv8X5In6@yNfp=3%E0hR;}k)bhaxs@zWpj2n{{<;Gj4C; zG?wKwtVt!rdy2>NH>31FN{dcN=9Xb55%4$!QV`QU%j+#1SsOMFNXzB7w?j;QB1x}#SlIsnc=r?m&OL;3 z!z7K5lyEuXn`x#)soF9tVX?^|jkVHVY0Axr_AjUhtz+se_OQHi9jlxS3IMNY!%fn@ z#f|c0;ODJZg5h^EOx|AH2EZnz(j;q(P^=3ulLdw>=KrR;$4qt1BP9)BT!)!Z@_%^5l@2B;<3_rJ6viwU=~fsr9OqRfQL+n|-E> zLK&NK9OI6aQLf>$wJgjTf#-3+0vyN2;&`GHUr9(^m7Zg%XnGj26Vbjyh(@(m7gFeu%%!m& zsj9Z0Z;i#HVYo@l6P~qY{8=5{vcVcNA1o0fuG*nz2HTGzBxc}(u0Bvbs%un@C0M@Z z%;gyVSTy;WoR!g3>P?@yH~sW~#)`Q2i@5&j`u_lSiZ03IKYPsVSLQr+pwGB;BErGne2RdZEi8fX@1j#RE5U$_a=jI6k{1Z>MjM*b&5XH0s7W_)3*Nrm3Z$* z+H==v{Ajou2ILa7*Sf=1AGPDt@TR@i>MjN5yE*Gk7e_zNv)6&W?uMT>zohAH6^;usL8e%yO2Gh<aN6oVgN%uWzuWZQR0rN9u zm~dDRQ(V%;Uqp370~UMdkAL8z-xNGiY|v>x*j^L2ov^Z5K-X6&Jp|2^{6dQG-xYY1 z#9lPLp6kTkCf2p-44G)I?^;D%^g9L=XVV?3xR`yX%V=6o_|N59R`*gE!!qZv4agsb zVJeO3bGn`u5%n{)y9KhC`7o?;vYn+y-o1KstE|m;Zpyi5QG!Ux80pViy%wAn6Fi^7 zMiqVPvaE6LX~_INYY7|jqN>@**72#_&dG+ZyGw+wmuNh&s;bG8^JMYsT>C%o zW?X-(UK>3trtoWdo)oy7nIyNl0b^s^*0-a%$%xpQY*yX?vNIky_Nq5F(eA?TBb?^0 z-0HiVuJ4%S@x2OSNa(BUJ>P3}n|~d!;lo z{O&x*&Q3d2R(>4b8BCarcKX+JYw4lOI2_zMOu>T|!m5rvb6v-QY`)707-eQ$ox}N5 zR^A+p1q$1-jiR@->l71i+5uDG?R4jt zjoW z+*jH=6YHA$OZLOiejMNa%~~|tT-tfpWOzgQ3BE!=@QbmvZ;KZP_G;k9zOC9pO1I zJecI0_iA@Cp2CT2DrVirv~R5pi$9i(P6_HNg_YV(Ge_jK?8Ap6t#sP|0EYB^4p;JL z^DX?fZ=17s#bZsbrId>ut(!30!T$FL{3|YQ=VVpP3;zHQNjdUokIDIoQ}wQA#9D9m zCDN-%t;sBKJ-Sy>t$4P3%@Qf5Nc`m>6$g{au4Z`dd{e5aXjM_0YL4cvH8nV^({1QX z+O>_opA66|`N(qlA9}SsKjS++Lht=H61M%Yx!qA~egL}BZGX}&-ZcXt9)udz@CS!% z(iNWKRbU1cF`QP8S{O!*u1R(A20I&tTN`L?x!ai&Ja)(HTKYzlsCbt~n(AxDRa}st zbOG&I-X*YIL-#he{3`+o9qU_9(KSoEb&Yo_?ZF4$quL!2!<;?-khZ$Y0Ve4Bob!|3 zx@)aYJG}xsXkl+NoUvSfRnXXcEBVyTxm&Se(yeMEN$_z#e6g!XfKiCR{7povXmmpl zW0TQ54K35GgDM-YE2+~w1c{x@yHg!%Ehpka>VwJ9^t;VcUHfqjvowEL=&_u|E+ zvw2prO?7af?MT;gKZqDLz2Se^{@gN2sQKE2o&3i>Ry{}tyUz}MKmP!Pa38Qo1aad9 zVjEW<)~A@>FtOz8rTFv3cFJSZw=e4Nc0i=lUn?!Qs6L zjK@!Fjidti4qdz8<2BUi`X-y;OIabZg)PH;%usF5*ByTv)72&u1^YW07a1Jm{{Yuq z?2z4FT1fLpBC9hD4%q(y_0g*qi&Dk6h`j0EJ-@r_yVkRHE5oZnGe)6ypZ9;2T8BxI z(`C40u>%!hj%!Na!_!Y1B+y3~W$FzaqUJ{y?yeVeE6h0QpU$mX+WAn&3~eJkgq^)Y zfBOFbrEI>1XK#BX3%|^4bGC@AKF2$JvNE8@1CyFL3igIA@0o8d*o!k{0)zOe+G4sx zG=@h2xZ9EWin^LL#M7*C$03_`@Xg#-mB)woLS@~yPvTEc{{USawgppD68`{DE&i6a%~zw%wgKmw_ZN&Rg%UsyCi1i!fTZCcclBzdH(S@`U)?ugdCgZ#KQd)mn`ptt4_cD0L2j)IF6G=;jQwiT zTzMgqT&i^>^NM}4LFE{vX*a6_kUEMrOD{T5>n2yQ$7%{&l+-*<-b$8M`=*HPS1e{- zvNuClm_(l{t7ijlJ9^VoPi!+Xo_gfaP{{2Y%L=WL+@AEa?St?2?TVgzg==MvTWcx6 zKAEP)rWs}O+vk%R8ShlLCG1d=@kSf?SFast)OBWib&?dp=uSIUrQVhyunTb*O~>yF zfi&SIrZZge-R$yj|b)HDKiOIrgcN&*VFqg0aas#wn3aB(cf6YsjsF za5<=&`EAA=$+^J;(0yw~B6&w@Ix@_B;6#gzD|Z#2ajnCl!y&x?0FQmA=FcGZ{OYfW zyme>cD=#ujh{rhc$IZCl*Mj_1_|bpj2901oU98Lj`FK5l&lQ~HcTvJ~YIXkr5@5w$Zk`q*A`kqs z2dDL{-BFs%$8oV%4>tk8$vFQ2_16A|-)~m8kyWFYh6M5}JH+~XXwkA;$TmguDlyOV zto^0;H0802_P_W^u38f*b!Ir;cK%tZZnTAM6}Gj+UQ?0046h!zs_rK76`Dx|YaP^V zSO7TptF{{5)D}$(h>-0JB2evZmw7`49g96Gc&4AGx1u%4ameHyg9as!w{Vy+<_~UaXJFRbOyx z=^N1aU3wRV-Z8X&+F!L2Ni|A1=D2XEjN5wu0JZu9`3C$u@}CfXKlm5nGR)p0@n(mo zyd&ne7eZ^J^ocVk{yS05maL@-y)1T*c-hW=QPz?<%&q&q-uP10^52d>;HusT(V~%j zIpNO{c#>7fNv;5}w{zP&zI=bcSMlxQ-ZlRKf}H$W@wP4Wl+k<}Z6P~a&d==^0ej*} zLk2%UF`oURRiSMS;fI{GXXu3I?AEeeT|8Fy@Q!7cRgD+@=4=J&?_Ou)Z`&i`Z^Olz zZ~SSc-rT|t>pd)+%c4hM6m379esTEU#Qr4slXNEWH;Md9;t=Gr#e07KTJ+tBfe5+d zpzT!_#@|KL_gljhFvvoffCE33V=P98RB#RMeTUf=}GWGq|1EC)n2H7Z(i@#|wGNr>WyP{{Zz@ zKRME=TVhLlsNrReqmjD-+wnD~x_Gy3_=hgMH}PVzqtj%#+_Fr@MSPGr!1UslCAhou zW-BJuJ5;amfm6&sX7)8w*UpUo@!M}ePXp;mG_4Dxecqvo9Ys?*jEQj?#$s6ZgYzG} zd)3#zxHgWmK@yYC%a-DfV2wLFj)QEsa!8503I;*?;;m_VCB^Jvn{sU=lHLB4-wiaH zkYdrKFsT8YsRZ@uTKAFSCq+_n`8iBansbUa5ag66~JN`9yHukHzS)`bL zl^hx+#mt_2Zrj`win|4@e`rnEZVnWY{KXP_2P-ShYNid1@~nq;Gv2x{2Qu72b84J! z8_qw7io!Z4+HVYxA$9)XYyn*df*^|9UAK*Q29WGvPH+hS0P9wiGa(PDmJb*ws3i?cUmDaHrW1VInFBmq9sF9gSpUQd3WtB z!?_=NtVf`e56cSee{PlArhp>Z@-A`D6*K56M(?=YfE{Rfg<`#uI9q)K4i{%*+oerw zq_wn7{5wykb6vEWN1T~dz!(Gi(_2DZh{Emn>sk9`%8V_s#oSu}t+jbUizk4Rd?*CUzc}>s>d7>?ZPK zVH$;Ok~4~_tN3&KGVPtEWeiUMRlNiK6@F6e*e4tKKb>?&S{TUhycu)k&ZPDuBQ@@x z0@qKHBjIB!kUHkRdD1V9v!+`CloF(lKN|G!hrT0KFt+u^2q2o~skt%S_Hn4IDyU8h z^HjB9vRktrHq}i(#EbT2%Bwd_`*x(e)E4R{R#A?)&2vc6Bbo7is~st~e9g}_^Y6tA z$rDjn{_=ux+Z`+DZxh^kx_pBhcX^Jx5aT z)z#O9e%TGnO3A}S4+=eNgu2k-iN}>QHs9hsy{pwe9C#N}@s^&^L*}MTWsz0LD8p-^^dS0kM>;)9)cw;Q))iLr(=E3dHPqO6o=rPW^3pckqmF9= z4L(E>$>h4@?_|~Fw0nd*OJ|JxQ7LF}yT?>rx$#`OoxGl6vdzFAoM*R6mrB&G{7ZSX zzuDCg0CU`CsGAcrDxqdsuZY@b&bwz9C)g*vI%*Qg&B2rBYIMW`tf8v9PvC z_cX_X#gBe!pNH<_(zUt2bGcBGoOG_+M)+NQs=B1iE#vN6^s5v2cf~1E*2`MQM0%;Y`rmsc+rJ2qz}AG_M<6c#1`} z@YaoWsDeUyszKs|qutosInXyp4}m|p~Z%uXt0c8zpJO%GI$!&Xqjkislp zT%=JbRF6G)91h==S=H`5jX*l?ng%4Q1M-fYs*I7USs0@ntbnF*&#g_Q%`|PyEx|lz zc4`!L7djku2ATH888;pm=}o-9xDysx3|#|bqka`K+f6p19II~GX2AsZt8buvqWQL# zc;n7620g`JAzslL*IJL67!ce@(x+AjvFq(kNu#z;-v04e=aEzY0A;nL9%OA4aqik< z>c{%ksVuGS<6kgt8*&Ks>?)L6CCcSbwJg#si}LLSlmU*ItterV^3kSc+8Q!;`_*d; zozaM;C}irrFCS z$IUaz<|xM6(7m{t1l2D54~>E~-J4ZT=@4M8ry9Kp87 z9HaPH9!IWf9am2`F{+HL&5x8GqOvs$DKxvK!tL|})4c#{wdIt_v@`S1Vxo${8&GK#kC)sZS_<}tcB!V9v&h;u5J??s8D^d-RrYyo$_58-O4ODa zjp`X9+NH6_LMj{Eb{6tRtMdjYC$$mWB`pZzx@&tc^rEb--GMl&_pq(BN&D^4vB-7L z9>+B{rFgJHyI7x)ZsN1F{ZVdKXtB9eX9u-Zwk9u8*VgdgUhQc=co(HspJXwr$gW#F z5KT#K3`u^oE9FY^53NIYwj;VpHkM<_KPdXtnnvx|&4?W;{zlK7szC}5QhjTg_>b{6 z8!a;O+B_}lfK=n|^{!{)ckKrUg1kp2n{i`wvE(Yx67EMQ(ASvww^=t2HSNUr7VOSE zypRKf&>F^0$D>0JeaW?*er;b(WxktZ839)ZY01rUH`-0rt-ATmxnX}XRGrE|`h9C( z#2P*3tKpWuSs?SR4*vilhi_hb^rbSctKs-=Emfj2Z7&%)Qb%0ZJxLy&J4JG$ovaJ0 zOAWoKnk#}5tZ__=p`k{$;q^C}k2fttMG>{?JkZ~==1j*d2t>?B80q-( z25YYHXMp@otWGT@@ZPp;*-HkR*_JlWF@ov`Zp6`PJsL5TlG&V&k7CkWM>V(489y_p zrCZf?8#^sB;u&pZNe~ATumJr5uA^G;Cb6L29X{gD+f6tdBlE|8{C`@<@g|hIzL3`U zk+WPzc6_Wc$9g#}sZo{BKk*E0Zy;$gvg##hnTR<($F?~9>VE+E2Uz&4ty}2&Et<1# z{{Tvn!kFz-yPUF<(BKU8HEMqgHkk`YeQMWM?7^d#dE*^(wDH@eTe8zN3yaVAll`{O zb~8LKV_y6g9Mg{BEst2c{{Vt?cy=2nd*6!E+DOoo^TTNzS>x`Olo9xb?bE*Ozq8N5 zpMbhmzNK-b-FUlpAvdz-@-=VSzzIMpxoskB(Hr2fy^SX&cbQT`NF`=RV=cW3G6jlbZgpACF6S{)wWUh!q(=gTl!{fgPo zyUta>{{Xgrwd5W&{{VuYc>7fObUh2h-W!dH#G7Q)ZX+GA#Z>|N2K+J4fJ1E^qzv}) zs!UJIkMqSsbjH+7lD^&80gLiS(DnSQdEy(;^J(EAoz0IQ{ATgz#lt`L_l*2OszWKu z+Wobnfrp`qaHI0BR?AAYv2x3A^J5B&fzPgMdq~pbvx{@>k(bw;3Xb9kZHDzgyH(Vyyi{{Z^xLun;~e99Ox z$rWuZ9_AgfL*$kq?(6*P6+KP4QY}FoH#aLFPn8AQJhr2*>XWFjk#sn@@_m6o|qMU#S|ol;__v}k0&QM^{8)buA*$ZC~lho z=qqN?S46due3>SZv695#b?HfIYjbdn&k;8H8(g26v(!|`EVnUXkjrosq=rH<(<-&7 zwyW~0m5=+oN$cM=s=7RBFliP@R1V^&lS(gdwis8-&O;upQMlBsV||)jM+84N&z5dD z&(@!BY|%?HD>HS%1Hm=W4I{|0`>G@zIL#KibZKrDIQ+YY&Rh<@v~t+5XpU+h4y>iT z)+R+vk`6ZJx9l_tmdYiI5b!>Be3l*ft5)6{ZN#i$xWHr2*0mBpu_Sp_X6Sh7PCJTH zx+qPiTo_i`83b|lXJgd+Rm*)Dbo*aBZ_d5P@l~6nwZ;NopY4XXrlpeU+KDFV05WHI2h4j)Qvq;APE;hD$ z^{h`5Yj;{y?6)$i@wtSOjDO!a1b#Kf-TYOyn)sO{f;i9>0DRn^?$-3b zT!v!%^VH>?zLj#=;-f;&=f3FL-Iv09D?5!Q`dKgILbnP)!Z7sw&2gHSh;)5xTWgI` zT5q&X=1b+M-U;i9wFZeUwA(G!k7Dkp`TqcoUDLcLqxgDV*OSF0v5&iuc9Z(oJC>(o zh1HH5SkhNe*5+L{-e$4fe7)lgezl>Z{4&(_BD0S1f1?H!iv|kS1$f`2; zGpCgZ^!bnD*w&So!i{^yF#iC=!(NX~x53+QWSM96{oxomT>Y-Kg0eI zw?@=;3uSJ*ON^2|G0%Frq4<&YQnub0@a^sN(!SAf=wpR*-*a`ZOz^kCPYn2W$!?a@ z?U!+Y?Jer8#j)2J%Jb|ib5YjHd2qnC@msLUqOKHsU~npA-Ho9}D^z)XkHQ}o_=@31 zt*mMKOcG7yJU08NZ!E~z9N_e=2p{Aa?Y`0E2@))F!=*ze zy>5)61rVM~anRO@y^S6yWMG!;xjyEo>ayA05e>X*(zAibr2teKht21C(=VBj0jYGI zUQIi2W@c7w@Od;`>2mBRoZyjB$--2En8?AiaC;QylkC$h!J1E(7#{S=^ozAmK3&iK-1=1S;s~wh zSmQ;KHD8pn;2@~<+lPuJf#}p~^bDoMm?Kz@ik+ge*HgMVMK9yJdP9m%O zu+1PLx#(&*uH+@7V9V)`N{(P8xPnM!9%5}=ADl7oRc^0;v7lCyb42aS0au_cJYbdm z-rxx)sOom>c&!t^&%Y{9KnJ%<0Jmp)(pq_;l34fTW2geFYBQUQxgAE>-8lZV=vhoF z<%Lii4KM`nf$#opk+d0!?cJl4+ zU2x3{sri9n%C>mgeQIA0{21}aiTp8dc^8LSA=|b)kt)I)Zx|{@TaZS29C6;UlV^20 zG}GoP-)UFYwk>BZxAv6UiY%6UST-M=som44>0BR(1ebbjmN&3}q*^&7NTe8~9Y^8C zdt^TY@3hYj+unGCSWPnK2|;La7KPG*D`rehbru;3|bVwt*wYagG#^N8|E0R3E znCtaDE1=XbM=%EB9nbP2T^%U``M%z>jMdapUG z?~1V7>({S!4YWFa#jyaRF5w`+9Ffww(QOu$cMJkwvEN8ce=BWCIL`k7=|;kgF6_@@ zw*9Xq)AS!NL(%Q+Syy557;FG^`4<@P*EQxoIQ^)+X*RvOZ9so#xKhZF`D6~`JzGDf zJ?oc=?=-n&x|%C_H-}=OOpJ-ZIsSi*TGc#19Lr@46T@|Hd5KnG@{z|XLF0-gCu2`z z6{;lEh1ZGoZ?-&bHJ#$&E*zYOJqCL5{c25H;r;iDd_GzWc{Kk3EC_|k1(dqWS+R`(}7gAPaEr#+N|GbRW{O{u%qE580uG{sJknW zORo$rg`~%S_WN6_wFP9g+lAYJ6pvrxu6Faq*VFiU?A?~vbMH|as;&o6c+WYiJ|gkd znh%NWV!n-xch=%aq+}|sf^wdp#5z?twURY-x>bd?%B~}Exkp|OX_RI15(N)aIJq}qRw75H$%>lLmo0liK$^1H0_BOEJM<(dj8+C38kd`O& zsbDR4s4Qipnmc||JngBP(VzWamW?EXa|IlJ9V?-pM0X?_dd7j4Jf}cO`_$>I-49~Jaao+tN!yjWl@p`x7MW9ZdLmOU70qtY@7|v zoVQ+>si(4gTR+|AM;v32D#SMb0Ay8QyH$_MtbS|`x&12Sg5p#xpt7*S1?L}~OGvBR zQjVV++s3Ubjmyqg9eZciq|_(5j@U@Zs?OhZFHd^Ar&_(A?+h%=s($)|&1rp>;z(mz zBVDhK82ZwV;`WH=r@y$IEv#l1DnmJLxb~-N7uRciu|j5G6^P;q#Wx3tu zoxyXpdD?yJTSl>#`dF2gIOLQD$9_NkbtF1$+Jm>2vD@x#s;axUFR8ATB9}$8jS@Iz zlZ4;1k($0kIZUCcYaiJ9V_L;*?QtO?*pHNo!L_p8s6w|9vq;Bt58+i6xvJ^cM{s}Q za0>&Upv6t6>GEC%jhR;9@N@hKKgaq}$V_Fam2IJ3Tx(ukqW=J*?%n4W3KV@Stb;%n z3%W~>IC=m^@AK_ctu$}8Un=jB`2j-U1_HOWyIBUHm`NMUQSuYO#T>RPm=jC$ZC5dV z1MeTDT+=KXJ*pSwW&_LH^R-;kBsaFJDz3>S`BgFoF;;G_64C-$yt$P2!8!W%r7eJ4 zYZbQK@+xgoN0pD5eQDPAlHG=l78s&qmS!0~*sB&77V<(_TldY3mgJLKR(1-0UCSQP zyRY7?-oj;DeKBE+{UMiX{np#Jcdab38=b1YUzga_^NCRwR*%e&cGXgIim`B!hT6L_ zMtJQ}a(S6nYag;&?T>3oH=*f|{{UTM>iSyE610u`%!Nc>;`RQOy(BAX5s?1z@q|yU zQMa=%sYB)#`CB^x{EGcDc{@vzkk9_$7U`MQ(1}PIHAMhMk*&03f+3r;{i5O->_p$lbyuK&0 zj5KTI%EW<;=j%_}GdWX7%037EihLd63&ft+K(?ChBatkO_bxy0qD6Z*f_@MtpKlkJ zVDYSDYH#^~`g&J${{RVYnP%sxn|9m+a6Ksh0ED_5DI|X}zFZN2ety25pVpMBHi`CW z38#EMTeVwxuVsgE8e`_B}q<7?j`P4^ndmT;2w>O?z6Z^bjalnuL(fmJ$rDv|Lv8=I6 zy5XD<%m-Zh`qXxslSyqfVLZ0`s!wWdy_PK+JKNDAHr(2qQ`A!=+3Pg;BP%xo}bF8>ayP5$hI-Oo?{_rG4fI|jFH-a zG_G|Aw}e8wS8(5u0Y3cHcJR$SK5Ijmc@57XRhu-mzVhLXn5x16c|KNbcRyN4T1!ZC zBIUER0NqE@i?9tiwU+6jjXb#50b7zswKBvt zZ*6&DBx<2rHeLs&YLuP8sUpc`y%{&J3XFSo%`-}P#z2NZLnAlKv~A!rLm& zt+|+=%lg%??9a1WN4xiIGVXi!s<;tc$26LkmhG6-5=M9?m}~@^Y=$`3%o%Q;l`MBF zZ*;OL^CD&AC$4Hsd*NhUrsj52wmfn8(Qq&hpNUrBZu>)~Hv{)^?b5UwNawkRDYr-R zWt$&*qPdQ1Yqk5W<^h1cvr}qNx7$^N?pV|eU~`%Ppkrt*K6Uf0+3<%L&*eXGuIU={{7oBF8IcFnx{6V-eX)kr`;nR#yVn`GXllQ zl1p(XStIGrGAcE@H?c9?(Ul``$9jeV_JvjrBD1dJk<;l#%%*!KSX&B&?qDgc$$J+j zyl98+*`$~ZuH({~XKx+lxt`%naxwXaO;&g|By725llZgg{{ZW$H4AAT)m7yE+=m=- z&uXDZa;^QGme%q|mNDlew+G&+MW@H|x0$y9fu3=i(>G$~)5*BpB!`YWilcQpJ+m}& zc`&yPl>~x6#+0@!#hb&I1I}c9+emIZ){cWThIM8|Rsf71cT>g6%W)T#xuazu^VHE5 zlUv#{x60d#jPb=l5YM^`hGzK{j(opDI#zzGAi0HHZu1E|0mr^-?x}dv>JhAkV^vUc zKa5pr;hnPXr(R&~9^ws$^aGRiPP4Vu07`$@->H!l=eLfT=9OR z;r{>=*~Z#eou%9yOE{Du1dazh^UqI8#ql?WJT&^ni`{sUp4|Wch~KCJZ>2RpO!Gk>nbLej(ak5@x7=E+MjeGdbtAt# zvh{Yj(c_VJSsq~h`rrrVRyp?ZR;}XQBI+Nq+*;j7a$Y&1aOpf` z3=VxTc|7x7PsJYv+W3=C(lty;re4|FtW!eG#Nc3zdJ)e~PHMfUi{nJMjvYQ5cosh_ ztWl6hzdZhRXIZ$q@jjpAq|wN*fh0SCR%TPedy}8igEtEzg81FMEMvUV?OH)G^5l`? z5+f2hTpkBX=Ir&^yjK=H=wWMl42*$P7}%50dU00#YvG2r)72xKgql_|+e!%$ISY_6 z+ z0qz3)v5)T`r})%%no{Z>AG`9Ir27jNhG@C-)Msu7Qq9f)^rt4d4z>c_Td|!+#!;Uw zlyu1d02&RvT3kxj_V;$N$Vg8uh#B<+{oH?A2Q7|oU5?wtT6MbIUM>4WhD2xD_RKn= z9aN4oJJU4(01HVo`HH`}x?q{c;Tit+dJdiV=9%NWdmUX5h%~D^m|=n?i%~Cb{7IAZ znK=ww2eHmORlOfplfsd$_K&JZai`r|6uGdvgsGP}=V{3p=LbCJjB`p`1WRq43jSt3&oRy!z+T6Uel-!?a@h0J@XE%2-ZZPZ{$t7N zXs*-#5O+_P?e?E99HFALAk_PPyjH0qC+{7$DvmSjQ`p&89REB(=4-hb%Xrnr7n)KhLFElTrT9wf)}dt}Z@yaxstgN7MS(M4pF|(jhie2{)vk zXU+i|dgio7j+!zwtl{Q%z*SF~zY)_FCXubkVlL1tZ3FN6`&NdLe5<-iBXb*Mvz`Dw zu~iZoUjEWQ-Ihj1+sI?PAk%-dqmDS_g=UgOIaOBL0PmX6irsIWWJUW%(s|qy^YyFd zFSW+8pjhNzLDH(kN>0Xftt`&02kx7Xy_25wvNUquG*9NUMxgE;52b0tr$-Zsn{0c! z4ZU&Kr6Rm?PTO#SxC^(x)Y7sgZc_05lghGOP0I|J(ABL%*9wzJS*~OsDh`6QA5Zf3 z$+5RE#~lyWq%pu-b;O%W-~fYhT4fn_x65lP$0UfC2eBP0(p*V#BP^0O#Z!WvkG)%# z($?S|FeI`yx`+$3U{{TvdM@z4@58r*3KDb`^tqA2y%TN_Rnr{h-R(qp%`h8XSDnMr3kIXTB#yB3(!Tkc|l zFmky#W~H zK2>S%JjaK0dqy#iGoM;?mR9!Go1s>YNe`}Q5goMhNiUjLl_ZdQ1KOVyGD#LxDorb8 znD-TG&KV?yV~`ImK_`w$KT5NrMdqVM(5~$Ku5-mTxS6Y=J-x%m(rr&D1y$NPJP!32nDraFXX{Q|3Nm*z^xYB| z?eNUYDH#fR+f0MQzi7GhA3j*_J$>rcs^;WF9CJIU$&m6eYe!7ee$jZ)?%0YlHnHUU z)+O^ZEp!=-D#;vkFeIEYU!^`MWEOk;sa|aS!AZj6x2}-dOXQ&0@`Jd46-O=ng3(eo zjYAR{PXy6n^O(Zv=6%34XRrr9T+TWg66e8(73?^`g(4xgWt$;Tg4Rc~Uon{;u< zhyF50tz#r<3o?ZMA^SPrqW-3WBn2j4n2j z$zwz|Y*t3v7j_HdCjfLbMmm~GD#g3w{i$$6FpWtJMt=24c(9^JByp^A76>!x-xXDw z-s1i>hC{UgVlnykrPOtiCEC23RWr6AK>UBDY;(z6oh@O!xodsDyHmN`j1DXoExfaA`QOR*pwT5_?}puvoilD_ z3-c0sdQ;|xAn>z&)0P`X3HsEsT1eKh1y3zePI<=em78&UCAn#ta-9Gk)Skr3H!Y1i zHfdN!-!?X!XCAdB&W>Z#)s|14PJUC*<5B6?&3dZa84brOJf}I){@+w zQG@5YO!<+ZUtHwYzlZGPhD2tVGJ;4Rm739+6+U8io;c}S7E`Uw%EqgJ08nw$HF4bM znQ{*}yphQ+Q#*rFY?|^lhCGeUmO1H<@u!Ff*?g8iDmlhGpRG)x;gq+k{HN0usxvHV zRzeLvDHV4yI3v>^{<@=ljcWq!Q~T_lhrdd_RPq4 zV3r&YN`@;bC6eNJWL5dfWFNdof5w0&o)*+@W6#SXuqAL;um1q5txp?jS5j_nc9^|} zd(|+vPj4N>l6=vSg?pb$hflkiC7M0hX5I5+InF2oyW6du@}!b{(SGbMe)0bGX+?Ew z_8BC&c3HEqmFt22HAhAJj2h@W(xP*amsc1aE5yU0IwyIf#kdQb+{n!|NGEexM7 za0?1;<%?Pgn|Nkd%Hy2XT^{Z{s?CK~f4m1z!kaGmwFx`MTPx3M0MJkLz}R2jGL7e^ zG5$?ho_NjRg$~o@fHxj9T+P;{aVDW7TcIkrQlOqkf6A>%aIvbem&{XvpF`_+%oA`s zs2$lRsIkW+nNu9@M%|}0*{!Bvt0KqubDR!p8LswB8C8keIL__WG%F^jFlK^in}pu#weYT( zRy0YQB$hmyurcjqQyWH*NX?9?Ab={x{+DmdBCDxG}TPrg$nV$?(-`2A=ojwG(XmVswLF=tkTgqp9?+lS0(cQkN1ug&vdVTU6fd9FD~_b4R@ z*yXjo2X}$(b)6)=A70JuDm@cGj@C;VE>&c(n&IKPw*aK}skb|WV{2gKB?CV-YlR4q7P+KAvTENC{94e@b8UI2P4?Hfg+!6QHz@#Pp$DAx#Z2I7 zPN&&8-xK(MOz^$yHi>Y$wZD`l%R{k*K(?uHpal}Q_xCpqAb zq;(#g^V+w(IiTs2_*yI9v^Uxe-|2C{L}uDAm-o9*2d**GtyI0y^xN+n{{Uy)%{7C4 zr^|~QytgT}s-@`%Q^g%4O!| z20{9f$6D0z?}haio@o}?>auC7_meCiHe*%J@s6C3cpt;{&c>baakWp1dbfr3ozQFg zJ-TW-a>GBAHAs+<$h-0!oy)-K_=@6eyjiIHIoo4y*Pb7~`&@}_srhU!ZC#lD?avCz za0U-tRdU#uQ9TWh5?$%P5#Yaq?n`l~OK%^QeQR^%m}dYna~}%CgMt}*aaHuM0mnLj zY(Y3{S+FLRZJISuihFwGH$C%Pka*hP#2;hSd`02^0197tfXvqSH`a^fz3u=C(nWw3 zk7LjAV;tw1@pg~me+OOLtP$%!W7b`rY-E=_dI9JtChY6t(7YViI)tBW)UAZkCB>Vt zO|6Cfei{I{{Uu9Z+irDUTIpqVRj>B ztgbQKbRhcUwMnFRA(z9p^J_No=<{D&TigYPL2(xCg}XN2mmF5thctOS6RS(0_?pz; zwc{H|WQ2=(twWF_l?XT?SdI@BpW*)i7KhU=7i`U^sLkh+rbdTuLC75O*YU0WLf1`y z4_n+_m}Y1rH!*4`z_gaND63cC6174XF(_7ubBaxIhTzBbKe8v~n<8xt$JpCx5flFfknR6sJ z3$=*c#26779Ala& zs5Oq}3*5-Mgnu#Xj(M$>neFUuHZv~b6!X+`MHI~&b|Sd6j68pP=84Jqk8DbiHEgV5xw#R^8nQ-mp!Ppn z&$e7@k{*8f9cZF~Tnw!DR_a)lmE=|)pkp7-soZ?JZNzwAEnMJYiYOY~BK_T!v}?kb zT#wGRtm9jWzHz(eVfYFtqC1f$$n>OEnfU%PKML5gMKHGmemb-T}ZBcFx8Zog-+}tc~+$y%bcviaDr{mEs%3U%MOpqa87t zyr&k%PvSBGpJSZSMMKyLtQ12A!8q(OR24%kgA0P-o;%S+MZlI-^AcU$p z=4YI#JTqYN=|vS$+zVQt&wi1gy5j^6DjyC+x85VVhGFJLsGtIR4rrpZdjZ)&r@>*T zFoqb{YOX$9`uf*De|<7ZCfOKq`B6nE?gIHM9h7q@{o@q{v)453U-wWtuieNVzO+$R z1thYKbZ20=ZP>^(+omhzu;ZssYAB#m*w&o@w2O|UAI`I`*xJf`vR7;Ij@j!)6rRKw z_hWa7RX%O4$rUUCD_^K;-n`|t0mFvL=JoTcAg4V~(-xcqsi^pC8k!G1*eMqc? zIr+z)tAqG)T7EdZlTY#2jWp$;XZ50r=c%#o;eG=;>h4MO$Qhlt zEvo=Q!N&t1OcTd!*4M-zhq^tljO^~?v-0jN?rl7mSzHvt#>2m;9eVWWO%zu@Q=zwG z2T-$$e~1?rZ5kU@)YU|I`9R*S{K+}4A6%Nh9;DTH*FNUD63khU43hN+_;~ zobvdNN8x|O9ctHDlGSwyjji>Yw9z;Yjzi!a5I{I5k&4*TwTp{?i8@?yvc(>$X*IRl zq-v`?eDFXWefs;+MH1Yo?s!G@#F}mN&_e97L*f>&Ku+Qy3K$_Lk}`Yq`3m*l9oi+Q z!@JAqyvXjM(Z$M0uEP>5fEyXcKqOH`OW5A*&5uI0)cjefM{y6@BZZ)35;1M3Y%iWq zUBsI7e~wz5mXm5zLYC1@=fw}0mhr3XJ2E$I&vVaOD5SR;%xhQkc(dWp!%bsQe?L~T z@o2J!@Bov?51Ead*9RC?&U)ZxwEh?PhU4RR#2<*BAMs+^Ynnchf4b7%;?ghNkv`CO z1q@CJ%+YGPg`hdNYe6ZE zhTvEg!8!i`c>Z-)!#7gf$E;hVk}NUZ2$eS-s<_V{ocA2jMJKQ=&p`N{Y@P+twCS{Q z{hubKYa3j&M2|SLC^`CqYCjB*vV1YoZX*F^x}NPNa6V}jWJORKV(h>92y1OXxSii$`TkSa*D3aAw04NwqLML@uiTIHgKj8zc@F;zqg zDp3(pZjoz{OGfSrBFfz$20^HZpnp$t(VQALTQg z=JYQvs60}cvIzHu<`fmpDar~Q0f(ES3Z$JB_?OR=FI1+gP6Hy%R0kL2%>m-8sC)s0 zRh>E&Tpb4fj+?5fI(Olk&C|4YA5vR%Tzl=0*X~VU{7qKryghFuOUw`daBjv-9o_kQ z`b(D?FJH0J!g8I}*XuWI*=lF+uxQ$r_Wyq zzZh}pa^&@x8?iUzevVJLpY$O4ValV&so6QXdHL*ur-fzZ6_r)h&tKFuG&VK2w6?wF z3WQznyL);+eC(4B4Ude<#*p!eNxi1vR6eWqn`VE~OB3kz1?YpRYLj|R`62`yDw3_-UNgk}@QZlupLyiwfSQUFz~5#q;3V965t<3WOGcL9_~j%7;c zK$qYTcl?Nm1%z2S{OQI9tf71i|CbN_B(SBV?`2=R9l_l@CYkKPfvteSe{60w3gvU3DN z^?`+cF&H@8Ds}({d%#2k8KPCh?|~f;F_pObWF_v$t%|+i-X!olf7s+NWS#7UKd6)Y zL{W|{ya;_Vx2o1CY4X-+U~@G6Q~&(&aetQR7sLIn`rp0&4=4Y_`1)&i`Fp_s?d$(3 z%oYC;cm5gX_VEUIvBpND;~q+!=2YZb1R4{)1bVlV^aL0(U>1 zkA5XwTCx-%-ykj%K-{@ckLum_E21KoOeR71B;yy*orE}JY$0O~^a)`9C%6A0 zwEPwji?BsAC$ad>;(vq|7KkkC8;HLPEWlHwYLjtgE^%MTuO<`!S;)W8;}?^8RS+iQ z$~MLBf5Zh?_~joT^iPs}jtYP4{5cZ-tHb2)e*TrK{XMonQ^h~J*(6c?|H7XiLKT}i z%apkL)CUm10U#nt{!PRrP5ccE_Wc74AmNt`ZRm|<10?aCq_ZjDX4}b|{T@PmKyr}| zGtnxm<4PPL)`ZW*`cdGo#F{6a<8T@NaO)!=)-hlj0It`Z8hQ)6%mF{0{}p@%O5B|4 zOHglv68G%d#O=1KzGI{wGo-aU1>LGEr0|BEa!Z&USQCUTDv6NkDskuX{gt@9lfx07Q|KWYmcu8DOd@aj)^^5VAT-iMz~tB(oa3`IM>4xZ0OD8?Pv7E&dUS7QsS76a^5)83@ZPVgbXCu>f9#- z@ID)$waFT&YCqY)fS(L6N-xJCk{Ift6)ADEpG&9;9BK{50s_VYQSjCXSpJi#$e&EL zTV$I{v7LNsxFYXosD4}_M(gAL={g70dT}ZIS$QE)KA>-7N=tM~%cPMY3g{i|x889$ z4}s1BvVpN!0i5bjB1|y+Mw7tzQ_mcTK!Kv4y5K>L2AEoOZ&~wgG+yNk? zNygCvJYdOw`*tO6%S|TAXK~L2SD1{jtf$Ohzpt>5eoJWN7nQt4Wu^0iQ;)~!p1v<3 z$pGOqViG?g<|Tlb=RYAgNH(bgc$hb;)7Wp{*zd{6N@+vOKO^SwBx0^s;>w@UK7sly z0O|la76Hh_e}+uvXIOG=awlaNkTQP5Y4j6L!@qm#ByjwPPjvtfB~Hc$079RFgBZ0| z`xG4NG4)A&Tn<3#J7h9Afc#P^042LHyWEL4;QJdy*Z&I9r4llLX!Fky9Z3|l*#fKI zC0v9glMt;*-VOTXGerLq82(oC@7|mw7k>}hze0q6n{ToKcPafupMLL~pXk#+eDjpk zM~54ov9?ulfRKD9LZ9HWyBYX1c@hCQlL!EE{@PGE3kBz!sFSc%LPR3R0J$d586g8Y ziyvjq3%#{F!a)LnL$m~LqAshC3;1GnZ*cp~@qLg64P2|b05o~&g?ur+>>BDNF^Wq< z2K*DQ#vV$x3kfpKxYNM%SfXySA!$RZxMR$}0d6Eb&!LDW24B1Yp+6-t&+@(TJvnY)nJHQ6#ICks~mCULL#PB7oF{SN9$(Zr8YW z7aX80Y9EX1apK7>Pn$);#|Rhcvzm)ly&i{_JLVT7_g2~oj&edMe(}z6KF!By>99E^ zWi&MSAH?*O7gV~2Hk&!DDydQ8-mM3w7{sPwm7KYViEv$WZilX29%tW?t7if%uG+m@ z$9|cbq3DzS+^Vja2r{ZlXj%U1A?500-JQt?wiB(eBj+NQXUv}SpDg&P3p zMDYla16!G3)-fikqecIsF|t%;lep2|g{=q5!S&ys$T7OaTMWnE?F z8J9tkx(Pk^ydX)UV{2Yk$y5kQUZpSwzNG7Y`Jg?nst1ABINl zx&6T#y{g24E?dmGUy!G`Z%fEo$+}82sw~)Lc?-f;7p6HDjG7!t&|7?6Pxpsy8Bh10 zKJR&XJl;QY`Q0!6jR*b;#Lpv4vt5erR9wbZybCoGuDd5FS;;F+0QhvewLEy@cEZP@ zWS`9@n9Q`s846KwrApidB`$l3Em$u+=ZsLxmAKs2D>fco;*0DAmzYzEIIp|WI=y9- z!2Xpxyt7S07NxCJ;?%8b#{xzQBXKBIagja;DU#(NN%H+PtJjvyOPwZ)o0j!>sEjD^ z*ix+@t{8TBY#!$g_|byGEiner5;a z^UBGkVgKD`%NbO&IS048i`PDrWQt`bGFc>U`ThSh4r~v^|CuP+o<>4e>x%BlH`#SD zE^(Gf6ygh1?wIIxd*;23(!?Rbx~H+2v-2ei3k(n8bbJJJ#FOR+Y_0&K(lFB+n+0aY zG5v}Rs1y96F}$0O?NSpw0a>Yq7(ulfHDeigHOjweRpPETLciQ!{M-GkcZJK<*-z0I zAnY81`ESjpgOfGHLv<&FvM8x*MdHdP3lICMmwsaj->#E9XKST{HCdloMQm4*F*=7( zaXKOj<}=7sMm6?K4DTr^cx~t@?DJZcO)0$NdV>9uxAKt^ceWLb?NTmzD4bycwT0Lz zaSd(#Eku5&+4wiS0VPg}JB-2;2aazd`29JT^?%FHuCK_Fy|>`YZVm(G>ry0f+odjW zR~X*CG04Q!2OG3A1Y8p@9OqE~v zzTx*ywb|Odr|}$0YP<6zmG>}W?TGEl>Y~bLe}E_44Nq621|VQBcULf#xB+sU66d(u z1Ppw>2n@vPXn4RHK+MNuLHz^?RTsTSl|f2e7M-kERd5%d`{@4=)cAL!mq|B-EQe8T zh5#PeoQzN%q)FUPr!G@hQo~?wd&Y*oo@tG%GdXo9%unqqw0(}Y4BhIX6a}Nrqjofa zDXQz(KV$V1M(IyFY;Or5eFXAs?mnk>)7{Cob$6tDeDm%DV-ET`w4{&)yVN4lwTd*z z8=i`KOQIPAQb~2`2F6vIM~2(S5Vnz##NgBX--+0RgZ?;_tH_7=$?z9SoR>H{fmcmx>+Om=3keoW%S-agGXPkgHn@#9ofh1PQo2Z7^>WyN=+C+wm*tk3 zc1Cp|%FALP%`i5yZe}{!I+i!25DT0$LokB6eA>36B*i(KLrb7j2Wj(P%K#RH(q)`{ zfGQO9lmc+|V`81RP7=1jteiZRw(E7f+@6T_ANrm>J#OwI>m}d5 z7+#x3Aq(!}=SUnxInw*}vZB{?E#w8!r-Zn_$)+f+gSbQL$v*Me;b`4(uBXq>KUoxo zP$IYQjtAX-CMYb2j7M~3hOIV^eCn+J({TWQ!@4xwg`Ui=`gwhYLGAB0)l*E1)YbLk zt#Xg$e<(Vzw+8pDVQ#CUA5whn=_=~2hTfJxgYt~e4${n| zT4lBb>BaEx(`~EM+U$ZB94ikT8CE$44Q7kH@6I^MF6OknoJF~wo;g&u z4=;{D>}V&)6WC)FVlY$If%#9EIZhF!@fL=zU4cgBdv)#M$+b`vR+d&ho2Eth&}{lVM%MbLZuYUg?$=E z$x)uhQRQxQ7WE5%{W$Jw!^O@CgCWB%s-3pZKF+<}ckx8P!E)hlb)$7k+>=3&AxzF{ zO@~U00TF`VDsfolI5d(iEM{V}!Fu71RiW)zIauVnS?!qxLa7w0(E&3^B~Gr}4G2?h zBu>8L-$?ZTos)+D?Y20_!PvQlc#);dfvh0k`+kKjd0q-uO0Ce;dPiJsag&8z!Inpx zm}>`ll#<}V@w5+pNRo_!JOxvaY94{Ua6f7+B}C9x2*ejoFK``h_t!t>dL2m}zkYz* zeCNDnv8P)_QDe_L(GZ$DWw?HzTY9Dxo|{QCklf-^!-KZHijf|!t;l|$zhr{KxHu9( z%_^=l-*KrZd0*_jy}>;$tY$94l&wYX$am1W`izSl;{dBpErcZD2o~KWXdK{bxVp3k zf7@@x^^X05n?~V2G!AYbc5T=GD^|pb1jFJyM}y|}MDfseZs_oKL?Lw-=$78`cZa5j zCX#0M#m#ZJ|IYDy%z5D2k~fP@##7Vlp5|AQHvksRWDbQvc`SJgSSbCznAO1|(AG=D zmGI1WALuJypM>Uqi2ITLCZ#Wbx2Id(ReL1a#RZfCnd0b2J^~6wC09~h8VqiMkZ&y7 zXjxKr`S7)%Gtt>58a3sL)x}zq;o+QHC{OmKf<-*Sn-j{EB_Jiz)Ye@{TC!VZGLk)X zK$PAtav6`cdfAsT21OtNV|Y^I!Z*hb<*_eXp9wgrX{UWubMdCH=53Ov-p{u2lGK(H zHO(xFSaU+p*tKL@7~F#%);-#9_x(gznaIRqRUhr~G_{vS?!aH_>k(@rwkxL#lFvT+ zpAt4OX&C>eJ{qvN_5UwYwjS11p2Sfc!6a~&_R~$_R*p&NnSIiEh3@{l5wGfmhfx8c zmx^3z>xP#cYln*SMl!Ug4Dm|I$Wp5xAz$8{qil|$G^LuFg9INb$Y~hlEDNyG_o9T! zjouF0q(t8mFJ9d;&JOFFxE}eJpijqK`2shZ8;{}p~(fZs%KgL0Q8OHIl<*EKa(xiYa;?e|-!#W3PP8{B~>&kI$(4$e(QB%4@aW0kY&2aIp$H z8QF||4V5UaJp`Q^1ajJHcd(app_kFpr)(NLG`$fT-%zY2WDgvWFdTsfkC?N{CH2qp z6A2(qQCP*3uiZGigJSb=O(4m{rz4{PErKFp4+@bV3+HHmwURX;mN=;Q^P??cS@a=? zIjP$#PufOZ`Z_q%S$}TY5=HL%*h0c(Na9|PtheHapxR7qhFoYC?x`kWRfw!STP#g& z2Um>NZKzS--_R-WrscZ+kl*9{Y&>8z1=AP^zXwEGOPjKN-nG_pad~tGnApb6XE}r1 zxij{1lM?r$2-Q^L$`(5*ab1=JbREgXSiZ*>t=r$6EFn5H>k-=5!I*iM0j?C{z{NN za1YR@S*;6MHx@jm&RKEjr|k>QHy@z8q&0zpBHxdNm6G+cGtKd_2@>4NO|Np)vOo;BS$589Tt*&D?^IfEhkAX|~UxWBg zo>o!*UxF-@!nvf0tU}9^yOVj`5;Wg2a{hHc4nF zId6~D^WAGN23;|3r@=pqFoZ0gIfkD`+bQ8yWPH^D=A>_e`e}i~tIQS`>{jAvI(IdZ zE-4e+J70;DZ2-BjS2Gn4qgVn(fRx;|9#nT#vd18SGnIqO?A_uo1nPqOd8gTr zunhSozkEntwA5p5`R2yai;cmZg;$63 zCH1n98yx%RDT!n&sPi37SOmSji@(e<^;BIiI6C&`g^{d<1n!-{PGXT7+qlXT6v? zoma|!o@KF!=QrN4{_t?{x@PK{I7MndHVvJDl=BIioun?}RkDQXm*bx6BBSuzP1j^} zSJ#@|(#o-I0VxJtXauSym)!+Hk#sfWrmYR~WEIWhFdO2+GXrfF&%09SXp;S~R$TIZ zno;%m0nS)megQE8%7YjqRK(b)qzga&L*eQO8a&6RaWvX-ljOaI(fNntS*EWZwQSD| zToSqHC9k4gH4M*(+89-?#9Y^l*q1a1B+IH|J*p*Zk&K=T^=x%;vK+j&XHP>}W%9VD zZU7Yg068I_9U8;e9gsc(t5K{<6P9|PD|fUipW9sZBlYpx%R9v9U&I!d6o-jRHW5rQ z?&<0)wnV7ZG|%uvIUzTQ6}^ygAaeWYC7M=%PwR}rrS2|lAD8eXO8wK=18foXW=W3F zwE~JVQoY5mf7YQZ)L~jx;0bOXo}EZ%@1}5;`kSI3btwC01s;5{Z(G z3D5?bTT{C2Dw-banjXtd8wR-Gjxq=-dgsY$`)2zJ$&7 z<9vmrby18fbURHNO{x4hxgGi@?jD-)A@jD!&2@TufIgAQ?G7R!%T6P`0^Q0w<7%Ug z&0xWTbtO?hrYwOS1?3#hIpa=P?HswBqFMZ4pISw5xBq$VE%nra&nY&t4q!bhqGDXRL&Bl zy*@yvHTv-_(#3-!4eH!MKd=Vq>+B{WAuD`QZPzX}RCllJMSY#-IgMQ=R(EWMQeNh#!mI1Y{qi_&XpSPact#fiS&A36c7b%On$RrLBHF#w>bw)> zgdH5`__Uy7rZw$#VSdLe2f-#n8V3)2b0OBrlkD?hw}RY9v|HSdsA<~jaT;+M>$rs^ zDcF5J{3fp3bSS6wHDMOSufx9`E7y^*F57r@F|@bA{e}mQ(O&6hYq1enoH_(jc5>M( zBunl{JB++}h}t7@UG)UFkAtpLN{c*XFgz7V;MY630F%^Vtu}Ck?&o%3D z;u-h$_UPH$^U-!^QAnDiS>8|1V6t^l?G(Nk)nY%p9sq0GkbNK6wyY~WLIBI{@%Ex? z-@p}}8F^rJueTSQX#zNr1??m-!{yMc!vgWM46B0@e0b1ydi7ktRdt#E&+Br{YnT=W zY>KyiJ3DQc+E1u0xH^)yPjL;D0w~t@%YMw_w5}c@%xOOupnGi~vCr<@zRnMQ?aRjZ z%9|CY*ejxBFYz2Rk5KMN&i^4Ffpai!^+4KyZR_t*LFd< zw=|(j4<%Xw?wO4{KB2G16hdV;faa^=1p?2_s07F#VWk4`SV~hLEkl)Jy%FBK)AmyO^g_yaVUbmI~4-vj|yx&ryQ zlk)vV-@*R{766%J^MD|q@C~%(GTGMeL6aaO&HzyCL3&Eq50&o;RmU!dSz!}Ifdgu3 zd=~!T+X#u1uz5oex;8%x?9*-~jMWh&HQZ`ceh}hWKmo_8iZ9B=hZKx5Xhe7KphF8m z(v%2R)b23>rg0bunB4s{j%R?VkT)3!e%~th-DHe;B5#AU5E6E-?^mch#v3yC`;51* zC9EnC29RNwGlqoyxts!SefL)08ub>=Mxfl@=6H5qUX|FJ<)XL&`I?ATLa~j9`$d}7 zvv%H^&dn%r^&!U}UnQM$(O5%ucE-BnJ$ht~z2!SYzx}p*4|mzk-lk3OcW?S=7bcM0 z`;XIFzfA}Knpn;z3dL2#nOHq@)+kvwwDDjgY9%PqS-f%Z-kD|3DUCc-mG%tc3y5vS zR_JZ~c}U#cs>JEB=7SVlzDE)uAZw8{Kkp9VM#G)ND8)(+$oHJv29*{Nv+G62K|V@= zI7$~+8|g?b$0Cb8lET=#6Y-iJ?v+b8C)3Ina?|o$&f1DV>GMTU!vQkVU*o5NsFwy~ z=HSf(R&re>?#(l>*+Ss~UU`r(WQJT|%Rq#=XI{xeoWVX0=}D+!DV#-B%t!=v*kzex zN?a7E{raD`7ZfD``?xIAWI9qC_Kb%|Pq#c?`nY|qTWEtYI2`73l{m94V~=0wEGW%8cp%QlBdq{}skNkytQ~F`)9NqxP>N!l|^W>u;;N=EK|4KdbMiN-_ zse?+18JYTe_X;A9zS6gn4y4v}cGacn8>9MQ9Y__)9vhO5TrAx1HcWw@r{BdX(gX(+*<#st=5Ma*pjr5 zbe51G7qvQ<5DvJoRoBMDRfJrUuTR5+e!|$f!qs9#gO&_-zuo*~!=*?OAS`M1*lKtq z#E)U-_=YQSM+nGe0zk zi$AAAuDnV3r(d$FS;z*!z8xNcGE~h6SUonim;+Lda$!Syi1g!7?9&J*-=ShwTn{yO z9U@im#=yvc6G2WoU^5$x^gO8a6>*NOF}bX;_Z)q0y(~)g*0HF-mT^a-*sS)4t4&iT z4gn`H2bVgBLfDKr`69n{@F8}L&^S^ggr&AAIb+#7YSQ!j>V{YC&a@?o16e&O*lbYI zbmKYwH9@u(5*0fuZn;WhK+0pX(CNl=>@{${dvSpC3qe&0C_br&8HsqsZMrc^ms(vd z-kuyv-jXBfOdR5ocV<sBH$a6S8`T_> zfz>Nek93eqpzUl%HwUEj&rN6R_Y|#)+Yl~X(~+-DLqP?vi+8(%tLO%oo`g#AwmMi@ zqQQ^3EIccP9$C%WW3Yg!FFFgP9{!mFSbZ%|dRB5^2S0o{$ij@Rw66zB7S zGp`Y~p6lQnFv~=rKZj}6dypZTC*K(AAj?E7g?Jp&ZwIy)nhPC$^9tE_R4DJ#?}0+0 zSy5xLabVGI)BUr=J7i=DD0~~OM-~!Moumq84*6@E*z&5w%H4V+o+mmN zeGZ=QfG)6-J~FZ~mpnVc99JVlL%!qvEyXc15Z}+`(0ml>C!O%5xC$%sY|)52FMnI7 zYEz!ZT#EDeQ_cyUpZe)9Qj@Ix`bGK7YDHkJ94;6o3J-+x##aExsl*(_wndo-5QucW z4;yT$;u;q96vQ5m4p}fOhX$YinX}}He(?rK7S3!RTr_+?f4KG4bu)3Q?+G)t9#*e! z7hd#Z7yc?a+xW8WEacqK*d9r5q}g4#uqnv&gma5!sGCl7?4m?$kiWz`Y3joUTc3}K z)=uWwOlzTrl`LLDtsLeva0f%>&p7jqG#f@|?A_D0>YKu!BpLkZ2a6nPMfDq>fT@>z zHYOg#BR4&*upJPx2D+wD8JKs=H*sKBD>)0)= zcrX9gRo5QnZ@ptUW%`UxaSZc2{AiKcAjSu~2fVwW_bDLq>y8s%lW%fv6sgkZ(7^2d z+$-8KgqI%rjWoz)GJuyYPOD5iWu$j~sLJr@Vw13&qizDU->3cDdB5_nruvk8K}Eg} z=sNP#w#S0{i(lnN?%P&K`FQlj{O8jKu3RlXXWsS(V|y!j?+DUW#Z(j^hXing#WLu- zr0-b0WKb}2?gH&d1AWDdt{K?k(B8ex%sn1<-#wMuJ}5kRW``1&6g7Qt?(4E({^Lv6 z^`5?{3)5jrz86JAi_nt(OX!?&H~XAXPYlQzuIXq*}w66o^f*=GwD z9A^BL8dPT4wd~EIqfmaalc7kK0mb=t*wp^;W1H_$ zYloV&rYo($(KKhH{>IE%s2TO!kF97Jv61MR3uU~8LdMikM>7K@ZYdF+4?kDjcv^C` zjJy5eHLr{Fd_#h{sk)DseMvkTGnW&5Z|HsbSJnpi6p^gGrgcw{ zZsTt-5i1A)uz>Lj=`TMhzTj)G_wsN_Y7Ar54UU1QteLi>)g^3QFj%JT*@PjcPVk#G-yWNM$0FfI1fL{ZR6aS z$78F*IT-}j%EZQu#JHi2>X?xxpE*7Xs%D$W=nr?m?w)B9S5yvYRgW3A-ZKaUG`mM2 zm&L+tn|R1!LkBF(9mDcY<#*YRU|p}f`JJP5Kzh|cAw+p;@jNBY#*!%?)>Yzk9Z(yC zQu1*50l;V1K+>RIvZO+vfl6aAxjzulk}%$7tdKRQWOtEzlgB`6Y(81BQ4WyRC>lsH zT|z=7Ektn{1ZaABnGN{6jU_`aVWJ+VTG6jCu&Qd?0P!dezdPSM@OAz8Kqxh1)v>fO@HT~wx}WVNNQZbJUncwjR&Ota8e^dWgfRgTDI8`YhZI|| zum@ls$YuQg{7@BC?>IPnr@Gh`5dE{K%}|@grNrU#{lF?lj5VORtV-SoTDGqWu)fAaTG73eS0r|zqQBqs?XKY{oP*b)GU^wHB{C8(9I(ZYs1 zo<}zQxQ9|Vc94x(lMg|qFcYxra~AY^Ai6HPm@GfOadHQ%nhE`7D?F3Pk8`WaTe2$6 z2!6P=B41o$Hg7BiH5ixIBa0md6vk43RZ1LNtCf3%$t602RI2qE#}RIIRWI|c5(fmo zP%F0%>g;`cW4GNIwd*wCxvD1>Pl`9oZD`XQQG!I;LcKzsZx#_=OqgSkz!ipNS+-Ng zV;6N2f=vWwh?R=$05K~Loo59oYsj*sb*vzP!q`FX{0=_tmwfZoQmXu8+LdN7%vc;P z#1XXqBXUP--Q`-&icT0EI~Nk_`YhO!AVG?=8YsFUw~iMcxUU!}Y7cJ4=8dPt0nNXI zN{`S~%upS1S45=RkJw5}W_4N}!J)yl)&6p3ZoG31l|!-~TQSUfnXbgG?!(C!hCmfA zR0R*&7Yt^phTUNS5?^d4NdlICFDf#@n<^qo-JnPtJBS~u;}K919DHrNpkJ>&WWwa& zcu@jXwp;I%ym@>hko7teBrO*bP+heuHwcs=Wv*j%F_FE?>$HhWTap8?J3Xb;mFSzD zHNi=%dGT>QZi?AJ;@PwJe%R8Nf4WLnG;NeK{G7L< zvz>ErwfN@QuL%ZFX*w@!tio)*e?rS+0byPVmUVKBt!lG7IIX1p#CL&$5Z79wWHT8t zZasUFiI`Ybks=9dBOQ(o$QDVlBfn#=V_Iu5#cg7%61Rgg7(#JgK|TeQ{s873j;uDe zOjW9#NJyX}`;BbKh#hSyg$k-7%*h`36`o7q5u3#>V5O*tfh=hq@bHtX(aSt%NKCfi zW%Xc)MEB=$w}*>eT;`D$`&|b46?6_Wa*{e=v-^>>q|&Dk61sNBsVMF& zTb60#%9d$Oz||D9yjNH7Ph`@G`qD5;38S5Xg!%%nYXz@zfOkXE8lpgu2ppN|aRO7= zfr3DjdPop4N*WjP#@+%rxVWI1*c%V7jV7zSs3O;q25muo%z5HR@vlDYdrpb#Z3T5q zzcr^m*<8Rc&AoyI7eRBAV6G34rDQJ_3fP4GV;RjCZNfmp;U7+%1eKTD09UjvY*kDE z=)1ZbfXgfi8J*}SkM&K$IiOp!tWu$R0(uGHfkq#5xLS!@WNB0nuqA;BC{sAp$b+#d zA9xZ;y()nH%seHI4zRuJ#-H1Ey$ulmw-x|WolZfeO5F2khny~APYNIvhsYyipD@n~ zwJ|S+hWj%h-Xj?4Cj7bW*k0oAZb!fBd?A+_Zop9^ZTYx z)&K79-|2eB)*SPPeh+y6zuKxoKLrJmu1oZbtyBw4utWu5sv2YlPqK%lhM4nRujF~> zwdgnzx0V!qlT|sC{p@85u;yvl80I&Uqiqclhx@c+Qu{owux0mz(SD2Ee?Ih0yC$t8 zJic1G!<|AuM{naj@ytl0*AVAsB(Y=a3M8-YMnzDITg2qski?%?X2Oc(O`{us@V}L5 zL7tOSgYWcsy@@$7H}8zLR|Rv=W041u5>(6W2t1VsH$$2B7R@AY->@Lqk&xQ}3Ocsf z7%o_vl+!{u+JR-7fn-YzgqTvVX3zmOF5QP&hMp_4zI1GqJV)>F_Ok~xX+OvHaO)I2 zvFoU6n0!{BW5D92?7FPNjnFDs;>wt{oev=^NR@Sq?7Yty26zGTcJQ$OfS|266~JiT z!S$5nqT8p$GJG~eMj~2{_72dapwd`OJ5NdyIZCez2Q6dd#B$l(yS5p}O`+{3`c-F_ zbJN;fhp&O$7QmqwH8g-fStm%Kp80aX#0J(Q+kL;5&x{*m>hY3Sgh)uToy^cN-^3=o z#pZIFugx6f%HCM?@g#<~V7}!rctfa}bS}vd>{S&}?r`lTyvR`v)6Lkt{TazX;6pL{d>TS$1?l zH8*_V0JcPKc!ezA{zzr?Ut7xmM^+Y}2=P;x*@-3cKzbQd({_I7;j!(FdG$Je8NR;9 zA6r-Z8T2AGi=U9koYS5|{#0aXVw&6zDzz-eOYU!^Iy9nTlJ|avH=`e+Lw=%12W);w zCBA@P1aC_3^z0@JSWlPV#fM|_>E*D#?OKe>!((63f@1`nctY7meRmBNd&$-0kVn;z zJZdtpd%W9NnQP?I?7i|)#;|D+PqLTLwxyDsA5sCm9Xlv_^;n=-*Df$)n9`inmL*wa zy$GUeXRY5BytS`^{z0Kg!~J&|2zTcckv2}?e^tc=8?Z^FOqaVlo)r+MbG`I< zn&T>$tW~Zv76-1e7me)`jR(BMtmtK(DEidIS|L@5hKhT{fO?~Y{+)&t6B(n? zg@AXz>?_}y=^?rovW^Pv$XbS zNiuHezIj>qH2J{wr9olu20IE%63-I9qJbeh^)Qm8hH7=msFI!Mh4?S(r9{~o=|0b; z`Eu{(CO4zxd?ik#p|vAlv=S483fNS6d)grBGBh<1_Gi2$RS@v>rEY$OVb#&O2GPa` z81@Bc(gIv!_4MwZ+O3yAIIHMdK+B`M_zTb>_$^bGsknkI2!#X&eFQbsNg^&ABYQQ{ zoKB?j7;_vRju%N}%p*fa&UTe$@;Om zB|FBPIFiA;GT8UjAst!Fs*ghv&OW601lSIYs=9GN#V!}}F4!!TFZp1rC7pf#cz}dZ znG<@eqLq6kX0z>+#==??_tdR@bwxk0ett0&KAu+m2JBt6T~e$lg#DmP2~|0FC({Pf z#?ot{E@dWuJ~6wppoRBCV)ZTUJThXrB2W?VX$aSd_F^-1<(m)~n-MPHy@j2dZ0B&x z`9#f+V-w5Rere<)vfJj=uq@8&Xdli#j{7`kr`o5kJ*;~$mDr|I1?kbeC9Xo>aubjV zD3@;GX9z7bI7O?T_$5@Pr9OCFoV9hxZb-bc)*!4;zB&?2i@>|3w6+K%7}%E}A*;<< z;qN&k4~dt0m9`qqd_9sed#GpF;Wb6SxyvEo@}WoIx4+htpPv25 zn^N=coQbqu#zB0g3~YLll+hI-njr`?FD2@6rl5PCI`Z^D*?C+|vq-(inCrG|`*&M0 z9SBtD1dM?9t%;hgDxBO)^Ct+U%&1mdLn$TWfh6>thBe89;1o%Y8%u8uSeYK?e#~h| z(d>^)k~(5D!79f(R0oL@;?6p`Y6gd&g`i`tFY%Zs?FIbgY)6Py&jFKY>+B8e)t!iGb8mir2 zPSij*@;AC~Zq?au`EfME?Tp7augtQn)?Hh&`Z}ip-6myqjHj_$Ig3JF-4PAo_Qg#j zdU;V~jSrX&JLlBsgZ(Md4FMbFH8(wq*c1vc_$=`dXC>B%sUi!zNYjvz%Fd;YCk?4W zog_t!pw>FN(a# z%pN`vYtwpJZ_&FNUcX*Iml!dvyOPk0YDZu*hE>z)v=(^opxM%^#Q3DkZq=)66`ck> zGS(7BrmZf`3xI$r%?oLlZwYmEl8~y%XCZB4$NKr9Cw4QRH>bZnzZLPh+;wv*BZpY` zG&WBDjF3#shedIB>1EItfwl`nZ`nyhF6CaLQU=@_%iTho%;I~)9@T1XSY3%N>+odV z_wRChBcje-pXB&xkN0-hxy!v@O~*#*lf|V}C?M>N1CU^~RVCr#2Js~u%~R>NF~_}6 zq+JeT>eg(0-P*iot zw2~JeByYND>=J2THt0Qm$Jv?F_gbwlcAmrmoukslinjd?E+%@sCgr z@F{6bS2%n*&v1{tOWWnz!H;{m55D)K+lveOLTp96io9_vkY|jbQ9u@T2Nl&LgM$5~ z1nK;cD&B;}L!f2s50c46|vXi1=va) z_S3Hv_dohSIn7UJ;#KSkuM_&Ulv7$;EPMx_Us?AAB(ee|R+z@emWPV-AVlXgb9D!L zGwKRSa~#dv)Q;I_mvVZ$JDL+#I78faGCYa^gjZWnf0ejQagj)2hBNcy%7fxpuM$%- zf<6e}Wo0zy3|{U&1T5HlW&B%sV3(Sh0?p@1$R{;H9~~hcRV5eNY~xLk=0WaoR-A|g zz^UC`<|ScNFxBe~J7a}WQwtUz2yw4#*cK0k$L5qnv%y?q2sphecm>6cYHV`F6Of?d zeN$?|J9~i4DbQRZ|0Yk*4D16NP49`=7ir?*Q#GU^n+Pw=S({`fS+`&0k6i&*CXgj3 ze4jDf^9>BuDq5M6H2T7Ws+T?%R;1=zUC)x|w;FJ$a=&aCylAC`*)~?D#O0GJ&8}d2 zQXj^{{?l#<{rS&S(-!Ail9@>X4GzgTgGaSPFpcd^#Vf};zeFrgb*B!-=5E}?T)`Qu z)rQSYtR!ixxj5{Kg~;A;$1CfoQ}+rkdUsy87j*q}`mtx;4{!|Otu>}@E_Z`U=NFTy ze0Y9&Mu4Yo7{deA|4`y>|MqK-ULz?H)g!Q?y#*Z+OepJ;;h~jvxyJ~OM+q1Zo)GNS*Fo? zfs)CoPp9o_irH})J`7Nu;!;+kW=g)oEYX6S&D&?K)`w&!9EF*!!elsnEy-y;p!fS_4t1sKo5#{f) z;fGgV(&;>t!_?J13mevv~~X&(mpiw$y{3wSiduf9##JnKnu#*+B&jhwO`J;TKm6$7Yu!kT%S z55eZpMKo0;TDYRv%j(A#QMzT+{Ue25l;9`ZGFH?+XZ1wvUAXG*yjNf8e08eZ#%}-S z&5xRT-pAx6*TU{BlfjcdiF3NXKj3lDtD-UXw1vPeLp!BzW{|D!OX0m`nYZsJCiIQK zA1rAs`8MGFWR5mg3lo+gAwqTPJWu}?p094m>7cyge3xb4&7Yx{;-Kmr`}5SVr+OJj zPIy%&8s|tz;d!RMd*Uf0ie)YC?T_6b9JdeeV7%FEi4afS4fT~hMAk_Ag}g|c1A+{z z>ekZ(8zLe`&U74}ZkD-t_`u+vuMdVh)t8s!10HmP(6{nq zUwh;05gP;kf}Be$g=-E7nav;N8v?G6$zmTS>7F45uN;conn#C9-aOB)N(Y~{)7MYk znsx)XYk^*)8DBeD^U#_kXeX-f>NB>)I&xWkm%9M4B{_E}?`F0V#om5)zV3?{Mw2 z&pv0LZ}0D%-|wD#@A>ZfBS1ptm}9(il(#(Z^OhxOZ0-hWCH!m06}L7`-#>cz7bF?D zP1Zx~gb}c9NwF&#)H;n|?r)qIv>oBu&SZ*g($NgK^VEBPzw!#fS+5$j+^H7 z?eSjHk(ck@x_u=Q*K4L)?l?1>vFyxOkhk149`=EGs4rek(oU9~rK|e+f~}<6zO+Ue z+?BEmc9D+dHwfQLalHcIv8)EmlTk|9Ej;@LVr=~x>V>650|69>OYAqHQ_Pryq{f)$ zhG#F`C`%+Hup(e}-XPd){Y9^FQ2uvr z`0Q=`8TY}`6Rh3J;GEt1QLc6Ghzd(dzI)!qdq=TT9w}<)!#1^MsNz`eN4I-7wyebx zHB$ra3KSnRrDbo2nmN$stjsdIbA8gvru<2Lu15Q-uk+V>&#QgOeNxk~g};|2@oKW` zNo>Hys>q)i7G%6)3F@g2W^ zbnHFit3CGtX9=(ky+D+#d$fqzg{`sSY>86()VXM0I#6xm%|B=zYbb&iL!U+&o?*ZY+8&JkFuR z>o;@s88cPcLQjr(9a_51{qmx*{^i)9R~t8;aEn+yf6gZE>5W9agKEd+%qae3u4aupBPC`sB4aLE=Kn-I=1ab5~g1esZ?PqtYOx5u<&j zVM+-{5L^PG9LjdMkt&VBNr1eUX2+g|l9M5#XPLEMXogw-(MdsX2Kr^3RAp{{@cpzq z#0g_C=+v;!rrZ1+LmuoFd7htr@2 ztaWCg?l6jN>fW&c^%F;mc*}JAcG$o>Y>}u#oaVjiU@7{%h#x*Nu{XgT(zr*<9etc@ zR;kPFWnJRTGuo!j+4i*xik!^_&pa@BW=7P$crNGd(B7(NH=Eyy4;eLl>5z5+z}(a;#l5{CnThhHpnrrJGgL?&n8kTI+~j?7b8}mt^t2 z%Z6TZzx%|MY-6VY`@4jqa8~FrsvpVd$3FkC{J8fZ?bADy!{CWu$(@mnG|9!g6 z=3>pLn-Z0M+A6-qt-?IkWR^Ms$ z>u7!Z`j_6&jEVA6T0e0LojAtv2;&*-B-0AaA6=^XHODH0n3tTJcBQFNaCHCaN*~vS z!xTtViX2Wy0i*t^Axoj5EM#+h#yw;!W;1cKPcFt)Av3!*NGH~8bH&MDV(naaxjU@5rd_gQ z&t*2=R+NTU$LaDa1zJ-IT0LYhAHdxx(cs7`c%6MJ$@bg9?>khBREtTmm*b5T`Bx*$ zKd-!Btxrl$x+M`NZ@#JH`Qz&|i)PcYlgpGwy(N3WmThcJ>yZs#&yQXxkd3xIU160_ zb@a4Z*|aF-$eDAOUgQThO9c#4Z^F{J) zf;#8^+a}kWUa~EMyF&tX+-8pt8YfLwAnxB<>tsYdOuU!9Zrz33(QlKyRMI<(Y4qO# zX`8~a{{?f~ia9C({_aD4w2X04dr#&ZNHwCeMclVZrM(Z=Mb5gitGb$ODIteY(=GX= zG3QE0N_>Y-Flx($UeAtzFMWM|wePA|pWXXJa+P<^y(QbzURK8t^1}1r8L8src+WZZ zBZ$X{i@fw#laN&UJkEB<17@_Td2x@4MW|btjIB%n@EK~-7TO+xIL`&@L!>0I)ARKi z3faR`szT{k9}B&IANQ#V0z|9PsB^$ees>pR#QTqn6=9`nJHrz~BA{EfaNU+BMS zNRN{lxgfA|%bdjPaCFBX`RZV)5on7}>a)tU8x4aBanCt-;PvwC1SU0dhDbJ7iP0+2 zIB6YaSIK_Fv7N?CS0rvAwPmamXse?E#b*yO2e@M8MOnc9#)K2f^g*B=*f?^Ya~8wp zvV-yU9~sj^>TY<#>baaPRB7c!ct@{k)#hdv@!ByNgDNq=MX=>GFb9R)6AFz>s;saUlI9*f{;o2`k($8v=4Fx&Mk;rX_zJT_P)-YQmw0-OL29! zwsCknG$DWjG^qP|_%?+jqGIImYl0N4f;-4A$YzSK;59o)FJH*d%rTehvRI8e2>2{m zHDkm{bMBbv0R`CZ)u-U~D6II%g{U2wnXTn4&Gr+6UUyt0UPI()fY7xcCe{L=@G33{ zem)2h`eb3l86CjM-N94m)>mNnL>IidoJbuV=?nYr=4NY$CHcJ)cL!fJhOSd15XJNc zt;b0T(PTtE*1N&_%K{JWR`p2n^ORAZ%^guEsw$A?Pf7Q6eIIr-4MUa*wEqUQG>IvA zOC)gNEAza2%{Y~lh+l+Gg_o>k(6IQ)A20k4Zg*uW9f z2mb0lZ|AT1bt^hIPldU8i}3^DjkbclJh?h#q5c!y=GheuOpBA2onvS%3v-=RyUObr z)inJ9K351xIQbT2Q50T1s! z7J}n|FUsj1j;W0x=8;!1Tg?uTqf+Rc-QB1gw@m5`jxV8+OttGG~}MQQ#7yD9P3QD|(iqifvLYAX{at z&A8q0bvlLNkIVT2njLMZ3KeK|T1?U^>EG4Y1jzL_k4JuH_W#FfEq~o756@T|V~L*$ z_W;$tIBhTY7>}NRMX14hJv?Q(Vv1H;)h*QLNQ4A?Ke?QCrsuih*&Sw={BCQ`tndGT zYWG$T-n81Tw)Ji1OFKyk8}`gCt*zo;9)`QKDr}`QQzC-YI15yv00HH z>T=L3?BuTBsz6ZX0ldCA3;!u~KL;6OgdXw4IdIhL@1O4S)vyZ9FKX0JQMLayU)^lC zsfX(CyT!;mF!`Q&H_J_ALv0 zBTr}iywi;^d&vd&* z2fW&2^Ly9R-=4+#up-qaM=v{;x;d6eCY$->$FlkZM3#o?OyQDxGqUJ5`Bc_P0!`oI z{RQjM(UQy^$&uz~Ss~~dN>TvEoj7Y&7`b;t@_%S>_ThJWoid2sjDcXhU=7{LLk`XC6JBe|=2BsS5mTe#=e2tt9( z${cWXzGD2+ki~oyl=nrQ*zzzXYru5^6<~GAa?i()n(E1y-}@+wdfQPLb$OYD$GFo^ z9>?$LBxjzx9h?43)19}o>n~WDHGY3y>D|=052ud-3;#3c8;WfcpVdh|C>37pMrFP6zXWWw%E6cu}m?_P6f})rj9d zwKvR%Zc3LbE8C#|vLC8e0ipR$q?FPAEPOjbl59KzT$s9dJUr6sTaCYH$zZRDQU`6$ zZVPO}HS9UYG)!1Opj{i*=NT~G^-{rs8wC!SI#fjJ!SH%Od1EU1uBqo;<^-bUX1=;X z-Z61a-N%@VJJEZALgj_z?OS50aHhC~F5qFt3K*1ZF8Z9A-%j1c@rv*ZB@XNFBZ{h` z`hUwN-DbIY4Ad5HZ&;X&WM)5Ocw9(P!sY}!lol*4PA@xu73>m!yz69GtB;3%rds#z zY(duuQ`YD7FJ~Ih=(VR)X_a047_KqTOmG3~IB2T~GM53a@t*or5LnBru ztwgJ}-lx5Ct=uMC8~n3&TYKf#R;Mi*-)9h8W;z4CD7n3zt_d4Q!qB1F zkK%X4{c>{at8|NtnbWftr1fgPnrgtg*&pJFR>y(p!s=cyU2oFyEy&`wNb*L`x!w=( z;Zn|)l8UD#k$PPRoOh_k;cDN9uK1NRgV?`HY}{B*0AQ=t2aNPN^TVoN@H?>D49tC@ zl_-5pV;5AU*a_WyUDGhu|Dofy1OCdd%+&jo4{u8HUodj6!uhI#vU8#v`DnbUittpP z$Rh?B?PGVxR@VOFZ8MFl!N%Lm#}P$=ALNl-Z{8XPw9#?G1p%0n?}kcR9seZx$D#c5 zVE*rX9iKQRDGMn>i6*FvCG(nNZnk{;S-`Gufd6^Qo}hZlwe<(qBR85z@Q~H;Uf}Qx zI8yMd`KJ_LJA~q3%8-3Um@B-7Iu@qR^Y1SW%+&gn9Rc;)6 zzI^PC&A{HBU0ya(Ne@}gDjPH6bIZBc_b=hkSYl>6EVk^$Bo@OnlRPXW~AXZ#pkrE2Yr$>lYNsmZE4_O>#(%@%)sNjmf=ttvSD_U za4WAc3un#4r1LybY|HS>UL7Z%6y2Pvxc|fnfpVNfH*;XJI2Y~Dw-39P>J^qktBPAJ zE=%r9v$omzfIN7Of}F5z&<^sFmueP9kh5?Y)7l>cna+)^0d z3F)6ZZ#q27Y8H6o0@+&#Bg9{Xhj>t~r@^yZXusFH=L62VLeFMxdwtSk5`*o(D-byw zkYYlW=e2lEKzk=`)@jn0`$^8v?x88gBLDL+@Vy87`(LcL&Ru8Msx;`-GSc>5U;c&N z6S-{$x3iU*&FiyEdg8s*GXvd1hQeC_CN4p^)s^ccdgl_HAI!jqzn&yr=rGA-d`dW1 z5oN?qwkM zGC*gahD2L#t*;?j@d5+mk;yG4Xa> zQ}FPY;d|6sqHgY_cpm}Yj1|Q}9?kDDrQ+)cumbDH!r2j-=(;>YAne=^;(x*La=!Ri zA9#ZbCzpv}CHk|e4XJW$-xo<5>9rMa@7f#=DzlI+XdlaOXdUpl&S{OFjXpL4i)8dERGdA5L7Y02u?b9z&5$YxQ$NxHI9RB`!B2SQ_kx5oa>=i*OYKwGC@R zKkt-WDLUcVGBRvL@fPc~D(il9hJI7ToYx<8A=|0xcm+Es_r_8eViKF?9C_22uB)n@ zsnpuojFO2U|L<`HeT#X;;)iSlL%feG7X1(loI=F|P=HV}fm{?2w%8lk;o)1^r#_{IfT*`cbbch%EJCadDR^yStguIQ0x~1(~zodiEq=3OlM( zcl-6G$%aF@(iY|Qtf?u7tGBv*YG@kLsR{G;g9-@}H!pa_Uc+Zbj;375d09RXz^9R#Pad#mYNrpeA(JZepVf?W4XIb-W_t0#u)Rl`L= z))IwFst5E4$xZMk zozs+4izc@(8=d#6n0d*+R65PV_m&bzgZc80U6&xHxuUR=8WE!2(hD*}eZ(IWEb__F z@b?9@$*jO+k~g&jAU(<|0H`}Kga^Wx@94Vzl%1Th=S<5jjy|$yGCi^<^x64!rGt5m z2PEq68XQqNCy31P->Vfm5c&Sx0<+EfWo%Wcg-=zfIZ8tq{qVVXsr}3nEW1aYG&Tn^ zo#%;Sa2HD4Lrp5YZ#N1Urz3Jg-df|FUPU=?DS3#xnyT& zKTB*H&wlV}(#95FsC9j!Cbi@7tcG>bl3&$qkfVWbNQg?yUd#yhHH57!V__IXJx&bk zG<)d-YR(nA<&He*cn1^E7nwziqOXm&>3=P`0DCdCJZ_ z&-3(vgy#=vxhC~~=@e5sx6EZseK2cxaBnfj0MniXo-L6b{^FwTV7h#jhL7o#+BW|=elzci38%wKa zPA_erAQcYoJIoAdP`%JYs|iaRtRiM3?DMBZq`lu}J$(CV{TZY|-HO6~V8_b5>XBR`8ZMt3DE>aBg5)-sctiu%TL6(=a2e&9UajV{fEh?;yAr4gIEb3D?4s z3u$BcLRH;RwaKET1Relw*jAXGI3zE{)iob?f*0!D>opQ=*qfN%FEJqb)kdv$GCJm& zjO^}8hXB?h;OvIiZydoyqDr+Q@cXd#%pKXo4&)Px#}!hps-{X_R*Zg@5jm#pudx$% zH8_M-nM)Q$03T9S`>_Ia2e7 zjq|?zT_*Mswq8RT4ox!?x#r0XXNBBL%a?RHtM+8aHjArq2zoo>v^-?3ZA0=T(XIBU z7&7W}gG6QA1W>nDl4ELMV_xf9AGtl8>w$XtHlif@o0ZcDEX^`a9Ikh!gu2n?#6()dF0S6qx1H#LrzLZBTC>;Jr1{aBoMQ%QJm$))omjV;aEDSI3;az`>d7*^-IM<)Y)d@Y7PE*GO)f@>^AuC7IN~my zEW8R1%OS-WX?fh@KF>H;tdgiKbKE{@%{kkg#fy%ZRRTlJP_SiS5Uk?G*n z=anR%7Z4x+NiUtOnv?b5`zt$}Ir6FO&jj|!z>Vawete~|4&~F*9r3MmIPL0@+&Nc{ zO^(gWoD&K)W@p;%Z<5nxTmo+e1auRk4M;-Cjf_?jOT_LS(GSNR8j)B3fM3a8_B783 zI;iy3N`Am=^wrDP251Izns<)Ca1wyts6F8hs*O0cVwq}4v zHRNvULi)0_K33=pl{>Jg=H}sT=Y&QThjiL7o(b%p-1(Gik#;CM$1Q0>{Haf zA;CxbipAN8)P097Ml2&p8X??>WWRjxf_~t&D48pH0+I9L=7~ay7_K}oP~eR7<#h%z zr<|f45nHAXpY*yaKMWGf6xM7c zMfZZ4+1!ckcY`b5zIx#|`=+$59u+}Z(fPAr^coZ13XI!RIVz}0LWH+ViP0UsvUSJt}=JIU*&~|1{_!=nRZm~7=`eO=THc=+wlM4H=}_%B@la3tvpe6x zvblH6Tc8cEZxn1Gd^KdamovDW!`Ro0`4*)+-V3C^3JHUXH~PlR3FVcB)To)RKZ2j@ z*kJC7*P~>U>sC%pBGI-E8$jiSPBty`PD&!z52@f0RSY%)4|eeP5EVeWs5WwsOBW%Xi`{zZl+dlp%f}{)HFECNjv# zEkX;9cAczAtecYDHGXgC{I zWKUvGV8Y^iQx%dwv%mI0rSbG{BtN8A+iW1>rEjw)S89>S0`qWna|}0=m;H(-sKFoU zF;T#dn?7`ayd2JSVD8~M#QF|gh^aWk?}n$O)aaT6h(2|Ay)kmST41hK8%2ze&3sIp zDJjn{J(TU>KEj=JuADKNJsL^;MBS@S5}>cNH**fxohe~ne>>P+=9NA+)JsWrkmuXW zUf01o7HpxYS?5|me8T|D8>M%~fO45|&iGPs^7Fu0lZ#+9!EkNrMgYrJ5_(cNwT@x= z7)I+gY@W{dnQx>B<-}3?EkRLUTiGu!0v6Ye_5=9u>Peo{2oytLUjUpGTX5RBWF z)7!4tvZh$+h-(4yN_6kfMm?yceFLQ|WbsYl%)37)bg`-o6z+ZB2vTbe(Efzg$l<4s z@%K2DHA4q@37p_sf+Ui$ErI1|5udgzcbC4*W~yIjOTWINUTt6bv%@W*SU3dy7w>|3 z65It2u|C_#hGaI9uP-qAPXD!!d#P*?%yC!X(~W^D3xNlV)Y|>5wsw7YWq9*lmvO!ZgCeaae`pSOQ|1-OsI$ri!B zsWN1qfN4k!gS^&iiSKlyl{G6bM2)?yuDY2CJtwKBL@oIYB5x3Q%3%)#=Wr5iD9kU# zd%XIN(CBN0)F>J0DL8O0>v5=lntrn^T5YnaDStkM#&}}yeD#WPeCGqRxxu%K7WsM= z7LzkGcL71ywxXnJiMxQr4Sce`M5l9R2E$`XrcZV2ZCv9?AdD{ zu*DgcAI0x0Y>tF}!AjI6EyQF=mM3Am_5mn!e$bU-wZ>axj0op;@#B}NY#RWmzyODA zAA*Z+H}YaHYJu1^8evU(1P1GM#au(M)#O%H|Mi@jR=WsOC?SKMMFvik)zng6xj^2F zx*5M4J74Q^u-7lSPj@3i(s_r#Mtes{RGDd9l2UZp3y*Qc{xh`ZF%zJm-B)(TKB%Le zCrH9Nyy6j+@Dg_iv`!Ec`)18$T=Hlty72JpGd8yFSJ3`-=ts@BB(klyg%#iOws#pZ z^P-!3p=Ii727=UhQ%?n<%Qc5(2@O>ku9>sD zPd>tilb_S?ecKV4piy3_x2?692aTo)?7w?VHw#p;(p*z^T~Exgu@orP3`1ou?lV4N zsUeZcjdA^$rl`3BX&MNhlSRMva+7)OY(m{LUZN2a&2GCW9oFInG)}>_yq>w7b@LL< zKg2GPW=KNn`+Y-?`jxx)Xay?!R0|6y40UI8YL1_okTmaGrd zm7u~a&gTTSSN(w_ z3rDS6BH>E;3;+Y5z#a5?4jV)u*7hQV(Z>+obfG5l7r@`y&7cZpszKPz3IM8NJ|Y)% zvEV>mdlTZ=3g1ArTF4TTP>4GU4y}9;R@w``wUzw0#z?6Dml^|QtU=d^LJwSO=@4)pAkf?O?yS1oL#qPni0f$kNXpn5bcuBlIX5E!DL`0O);ij7V zx@UpT0b2kh>jMv}m+B0zYG{>8mv@33w2(^t3x)ByPp?F23|dTx%O7`IwOsWdloll8 z7S9w8BW?!$`792rQD2~Vq2pWth9D4uVb9Yq2bt2|$PsA*%^t>60Mv7M2xYMEP0{x+<0&ULO7DA|NdwDVsHT%^1ts%4DSkl8$br<)<8V%zX((U-h&gR zQ^&^{Z9t$%KH!J?v#Fm??N3?#IT`+S3I916{+tZ|Y%=_ZV+rh{|6#`mJ2Lfuzajs3 zHue0E%^n(O{&lne4Vg>*`!gZ80_5UYN_=jgxcfOS`&`;BbDxsL-E(vOMD{WA=Crq4NBGY-9jBAY;8v)UV$t|-l>u{ zJ_oQ0Qf;7*N*PdFG*PrnjDUdxP<_Ef9Zwt5;ph;GEkDL=07wl0Qk@R>tkMP*dci45tM@!~#HDXbf*ZG6uRz=c!PNIj(i6^&{X)=J9Tgg{T;D z<>E?9a$Fx2g7z!KU`=kQ>zwV6qo8KRLclTlw~ogAt!uV?W)|pA$N^B4JLUoRRlAXd zPu7&4!9xSRVuqK$@;$%G9)J5st)tq9bBYcNqbmIa5OUPvOzMs_;O`CfM2X=gg$LP) zN4geH9|DH-6E1R8B4>0yU3GBr_q1;;PD#eRpz6_+1KD5J_0!oAUW9ojK;_`UO&^+r zj52~8O0bC1#aC0=R&6|Q0s`C5$b3vz8(PJyVfUOuZS~ym&u!L=JcCgi=^4(^Db(v+ zdge4LC|$G=12Bqzm1`QjO+y>Tp+VsdZ>wW6&_B47J5>NuD4YsSXK7O0xb~@uy4Z z{Ga88e`eG@bg}@``;ULB{`t?5l0St2rpbRo2xq_?`s38N_PYGbLM8TmtYhEXThT3} zwzj7EKKA1X;g048yfUYOwL)-2xVDsImp$CJMtGegS*D;)?j$PojN261I&(LwF}<5A zpC$0fO=5y(^B(eE;-D!0qo8If!D2orU}>AV%D4QAyj6@o-HguelK8H@&SPB$L6gX; z;#vD~t=f>2TuZRU|=zM42sBb>seeHs- zg)|lOBLsCG1Njw{{i1g`6(;>Yf$c=>AIIXz^S)xYUw_$<|3Q5SQGL! zf96eGKfE%7Dg&wmICtPp@Et#yWMw?{H{N;!invaq9E-|EX*6>{8qri8N2S?i4B~4M zn_z&!sjk9r>B^mXvp4*NDRoj`bvNu55#By50d zsYMx80xh_mvX9eHEiQ#cxxDYz0U#fHQbnL}pDbXONsbEcKi1Np=*;S5wA zNWG2(QkBJxl;B~hBh1v0hszzAsVoqzxFa(bgx>2}+L1*0%CgjKp|S&MmM zA|r~U4i7`?cr_zy78}BFhg7OJ8&vxroi0#%z>=Fq`d943BvD-e?Pe<=Q3`xm8bh;$ zH$b35XhLE8YzZL@uh?+|ca#xa*^DZ-BnE9(Z@#IBNpuxWvfTSC5dqY5|DP=Z{!hx2 zvl0Ed+;wb-HO?M4@6hE^I&jAsPK;b0s@5R5BydQs>(XYa79|J#l$!5P_D$c(rAgIQ z0J;o7iPd|I`~@e4*LlbhOcbF+s`p9B>;r=Zm%SZ2Q_xz+32SF(kit`&f&}Q+LhxDQh0O|^)BTJsM&KA zx{l)Mx78qvGzlDmWjnmrry?wl(^=E2u*=+G;hQbHm7I%QP8%cWsGko2a2*Y2HlXTU zRZB~lUIM**V1filynJl)aKl5IF)UNUCd(SpicGbVo?UUS(>}|Y5j2y=h+k-`tF&vD z*APM%l-E%vEBi8b^_{L&-*FYs}^&Z z?;*aIs*eb3HWl7{v1c90=mlot&SI~>TqxcYs`-rcp)N~;+*+YBaDOvPpqf^y&+8vz zhogW0Ay$43f(;!+czMFWU5K;g)(^4y7YiI9y{7>U?XYH-_W@ zcGJ#jbgy5rIioM_334gQ{37-eyrEZckw>@msS-c^WzoqNorv^x+MZ_AelwGZ?}z>ogjvJjZWw=uAxHR$Ef zB5BJKXe2v{0C@a5mxYGN_s#I0&qx?*2j|Np(T#cI@AJk}bEdEYM&Jy6Np=NR3*h1q z2E_1!s4Ra_un-*sOMt9#4$XwRrENx9c=BbaNW4-gbQ7J@ww(Wc;s{RpA5%1@Dp{FE<(v*nIB9~5{5_<_BP z4L8$n5*rb`piI^s(9e)?Si&ChN5}u}17c0FAQF(6-iZO$SQo^;hIArr(BB|@1`>pl z0Ni{*11>2bLYHulrH%jg z?%u9dCpF|8PNIoX&^1e*T1r9#b=L&Yf^lvct*@~C)5#vOmnp5Qmm=}lZ8A~nXh9`q zF(frMC+kL;-eSR|Zrs^H1S07h?_~w)U7fnIFlmNh<0P;8%I{6q@CHytQtW>aOlyV9 zua&){gSIn7*P_CpbpNm;?Wt#w{smG6ASX^oist8L;CVa$9JQNwJOV7^ZCVbMuwRg#llatFlY>3^KLNIx;F+J7PiQG; zL*e6>ud2iO=-mM|S_0O*{Ukn0fW%rJ?_iY1n1#kl(X=Zl_TUnAd~-fKeE7zYdKZga z@bTdk zvM5;){f?93{qAi#M~AZH`lN^K!wx^u?R%hrSmIfbf2B?by?5q}{P7$*y9nMq4xez; z7xWV_bHtaFwfHuDx&j)bwNxxhb&hR3K-Jdk#w1dQZNKLWR?-j8h}uLy#E1_*jN{B= zUhlG#jW#j!E*NBug>bLNvd31E-~FDn7{p8~vZEv`BmfMU;c$a!^#Z8t1cn^La{xOb z^1DhJM7M-NhBNzvWB3x-RHzG3%?fYCU^x6ktk<#!ON2wL1>f$7P(ZZfB2^;Wb)N9%j>_>mpXxbgGj=IJ6?;vLbD>o-`WiEh@_5pYf+9b;-$e( zx`_Xt8V7o$4|=pl2lYpfl2vMn_vbWwx^h9XB9&sO}>Y;Y3cx{Z|vyFG+(noAha2h zKzB)hdQgDz#2?}5r@8RzN3=Hcp1oS1?Qn&V=!Vebkkm`dW{3tHt!eRslW!YEsaybX zwneA44wmQ6Pt_wNO;q5|$kI?k7)7Ze1IR$j{}ze0&Ec1Qa}H&>GlN28-4%R)q-Sdv z*CtQc$Ms`A^>}X(bUVe=V1KE)rh8=&p%BIHL5V}(-GQ8D!3y8tg9q=af4t{_6g}d) z4(e6)Xb;Q#V?91W`2}0eCGSJ=$C}?C?vCLFa$nIK5a59qwB_9bm5S1rKJl`D#o8Sn zjdP^>S^CCs-|>P+g%p*}-YKe3y{x0uFvPvXFxd+|MtXYvu-@peKBJq>x$C>~rmth| zj>_969*ZwTx@$$!h|_$|7RxQXq!IVdg3&(pCd(PbOgP9}=6S|!b^l$hiC{tV3KHm(v--t0%yW)cB};d~`Dth)pWC7Zb^ zsJv2iUDkkT(Gk(_sE<@}f6GTnrBva0@+rZM zZ_gksfY}GbtLeHyUkO7tHm;Lx?MLjkHO-OF1YKf6m6?-E(7uofhSnw;Prs(@F8Za< z=Bk(G+jk3cOYDkqjb}!^QRLF^gw!VM7v*m?Bro2*Xf_Y3xLt?pSKv+|7R4<^vT-1t z?8Ff&bJNTdRy*Ls9E>L1wqM8?gT4M$_P*fmes zJX8xlCE~`%&m(=}54s}M3TUGgHK9WXeyi6_)Fd33;IH*;`^V&zWZzj7*JpkOG@JpI zex~!K4nXYRlL0kMK4u+IrQ}SEc#(4Akp>!+gmkCc&OW2Nr{Ybn_s2PnxufZz-WvJI z?lz@|&6C#-PSMTH^Tk&k8Gh-GdXRe9-^=W@OVb<7x0p(CRxbm^pYKJoAUqlp}F8*HLFwr<_`Wciq)gLfF4#01v?1nxQvSSg`$qEwj!p0Guvse&In3 zLGn(_7^OJbI$@go?6cyTiiCn%5X{rQ)$YU2tX44T5t<9c@r@KIYS-e)SD=iAx);3n zy;H&ypD90n{JLbrvf_|gkS6JZ;m9#v(%5@+V&D1T)!9oQ+oGj!dg^T}B$s>cXtEa= z82Y-~x{}5Q%P5^26Fo}ZCn^f7=zY_)*+KNzsV954E~hPPf~soY*+e0K%85Gl72?=L z3H-4Z;ljI95N{JzXp4vNHFPN>GY*04&7OU1WC18SdeTQclZ1NDF{4hjTG4JnYx(n; zV(4y_-vBU$ns<2fTI?UmjLDW{S$qT;lCchPZkl!>(d>S1{1?3X)cE;A^Qqw0$KN#- zH;$<-((X7?OO7>EBP0Mtp9y9ZwHLRE6IS?BGi9SZmyKwP3%3lSj`WcZ{}7YF<#dCC zN!r9fcpeZDvYgI`GcKf4FOq^o`qR;s3A5-vRNBqYK2e{Gyo>UEp&+l!lk`uVgxm|I zsA66InQvO@@U2(^S|CD}}o5Hw5G zM-J!3Hgcr71a?n3@oQOB0puQK*RH~U>*PPb(_$Xi?*KBu$|&QC&5Y=JQ*o<4ZRVXD z*Fi;G$BnL&&K~fVZM>5!`ZIWe4Yc1s)3pUh6|dYSe)jSBKxL!E@1?4Cp;`WxJaZ$h zeGNY5SrciWVkW;&(|IhsXFsiG1M4!=7T%>ydm=bpN{x>7!CpTzZB4aI2*)Zo-O(Oq z)*qqx^dZQI^{^q&kl7Y)Z^OnsS|Dt@40b99x0^*k{lbQff;8m~(;H`FW_stFhdnqd zAGD;jB1~j?_XQu5T8vnvxcH4AE!AX7OVGWX4|cyUpf09(0d_jyM3qpXh0m67&R)|8 zA>EnF?@RYN=eUOl!bSvv22MHTlt*PZh=qR;oN@In@QQ{E4U=Jz*UUpnwL0QDv0=jqQ*{Q#)Cf9%!pq1`jaI*8Yx`c5#<(R-$$p^FQ_ANIl zu8uE8pEK#RUP3K?TD!1<1Q*BRFz19kqnpA8=hzk7#Y-{^C+*{y8V#I(U^m&qH{o9&1gABi*o#mZwaC&H5Tt zi&<6?$-!X$g&v0HjDur@3IHyk`iV^x#pn^1EpMTkTg9LgRE``R0V=xu5X*%a=Ly0X zQz7{K4b)DZr1LHTn_+M7eD~@9)4m9%LiKFLmPI;y-Q|9|f^yUkvB$mB;nUHAa}%ht zb<>^0gb12aN)I6eJ9RGHj#O6RHqYugzJ$Oum;3Opn$D%85&~#2AS@VuN+2l#8c^i$ z@ATDvp2DN(z#RmJPq14uYb{dS=kQE_8JWz~`#9Pacg4KOw_l&HkYOJ?QmpnQew%Z8 zNQbbk3%!6L#)7%YOd^RklmV-52VH0ZYW_a32hN;x{XfK30+a3$F$Mg%_Z$KQ#OtAF z3kZ(*Jdw|(vVlh>aWQpSzqb)$a|WH@P(ze(69!fUHAiQ_!#|NigxBhWIyUC8;#vzK zFo8cP!N-9Y?1z{kus*<)SQW!3IAYR5aL0vHuF4gQ#ADX`(PHK@EKh_kf_ zGoApi(3%6jGvO3p`j3lCeqOBgFBbz__a69uZ6}q%toSKPDsSh1>@@Kkinj}DS#A!I zn*!bmY|meXgn*TS2KI*pE&(0p1CYW9*tBa;G*VMhyw%iC$PvUi>eIhSyx`wR+zE^r z11l%M3c6qrnSUKb8mzeE-%H#8J`MWVAZ*K9YNt@n0XNx`Da68l@Q8<;8Vs+OUE?n0;Te!GQ010EuN4Acx-?l$IP|G0bsVB4aQD3Gm4Oz5{=I ziitI27iKX&`c*r^J z1hMfb_zHXo=y4NGCu-z<##e(ACGz`w1^0V7`x{#4GrS?5TNYQF9U|2R64zs>Zw`NpnjSW6vV_`Wx|FAbVmQ% zZErN`73y<<8$^jo7YBiMP}a+9q!NAdVmC4Qy8cE57Pa=Xlc1&bX91k=Zd4X$*eQ!d z;y!kL?{l|4M$*kDQw!s;ACeDSEMs6}TM$1VT-AmhoL#n>w~wq5+{LbS zL-*RZ>%T4mi{p!TEs}((>60Go!bnfK0?(0zbKyu!3M(Rf2)FvZy}lD8b4mNFkjgb3 zH5=8+gbiIRJp^c>LFFLH@fm0U-(w5M-4+MV9>!?x2`78+wbx$rT6^uzl1BHOl1(F9 zb_nz9&4qy7pZTL3)_h-Y<>l3qUU(mje$NG0gDyM_^%!0BB1Dp^uF{nH#0)x4+a*IF z(+2{!TQ4(fnA0yYc)HaM1K*Hd=9~|S+mN~m#0s_hNQKUeB?SwB{*3Ub<(RoJoZnPVnP z;cdu?7uuOJ^g5IRuXglCo;BD{x!}0>5Hw|g*jWRs3ggzxk{(*&yzu8S*O&z2E)139b&Lv;AUk1uQu-yjTI+gx;v+?c;8l~-^_ay5TMx9ySc*z>`lZ7R9qMNxsGnJBuogijS z@3d`I@92CIM1j6eZnkmH>K$!G$}t?VMas3t;h+m+~d|v%uFkY zz@nv9+puL|V3zS@@fOA*w=grCnt(9fNwM9=p&9q|GptRb9^*-2Z9Aag;2K4Cb&xM) z;gF562te>z@Yn;b7};0V+)&ESW)<2Ql{;(jzCvZE(?-+O8yeCGtO_hIWfr*s65+J zZ+Y(?jWnBKn}jtNO+@?fR-i4Zf%HQfZGQX^H)#b?d2rC=*)kWkn1;ikFw+iwv#a5D zpZ&c%;PO>&*BMqEyeZw-N6uDxLZ6KZY`hKxMmqU)QYAr;sIj~F?Q8rw+j;@!M#$2H z@N{gTB+|QtGv(>fQY^?h@`r3i!liWmpcmA*-D(A9iJpYrUvOuXi2)yGM#84KzdW_R7njhdFwmp{j=dEe|N>X-msp$U`h3mx`{Hl#ui zi~NhOy~l<+t^8}a!$bEc{Gwj7bMN!@kZf)Z-&Kp%!KtER`Xhrswi%=OrnHf(p-K$epy6K^x;% z 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%0D|-#^4fs)sF`f)5HeB( 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 + +//#define SERIAL_DEBUG + +//Joystic settings +Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_JOYSTICK, + 32, 2, // Button Count, Hat Switch Count + true, true, true, // X and Y, Z Axis + true, true, true, // Rx, Ry, Rz + true, true, true, true, // slider, dial, rudder and throttle + false, false, false); // accelerator, brake, and steering + +bfs::SbusRx sbus_rx(&Serial1); +bfs::SbusData data; + +void setup() { + #ifdef SERIAL_DEBUG + Serial.begin(115200); + while (!Serial) {} + Serial.println("Started"); + #else + Joystick.begin(); + //range + Joystick.setXAxisRange(0, 2000); + Joystick.setYAxisRange(0, 2000); + Joystick.setZAxisRange(0, 2000); + Joystick.setRxAxisRange(0, 2000); + Joystick.setRyAxisRange(0, 2000); + Joystick.setRzAxisRange(0, 2000); + Joystick.setSliderRange(0, 2000); + Joystick.setDialRange(0, 2000); + Joystick.setRudderRange(0, 2000); + Joystick.setThrottleRange(0, 2000); + //default + //Joystick.setRudder(1500); + //Joystick.setAccelerator(0); + //Joystick.setBrake(1500); + //Joystick.setSteering(1500); + #endif + sbus_rx.Begin(); +} + +void loop() { + if (sbus_rx.Read()) { + data = sbus_rx.data(); + + #ifdef SERIAL_DEBUG + for (int8_t i = 0; i < data.NUM_CH; i++) { + Serial.print(data.ch[i]); + Serial.print("\t"); + } + Serial.println(); + #else + Joystick.setXAxis (data.ch[0]); + Joystick.setYAxis (data.ch[1]); + Joystick.setZAxis (data.ch[2]); + Joystick.setRxAxis (data.ch[3]); + Joystick.setRyAxis (data.ch[4]); + Joystick.setRzAxis (data.ch[5]); + Joystick.setSlider (data.ch[6]); + Joystick.setRudder (data.ch[7]); + Joystick.setThrottle (data.ch[8]); + Joystick.setDial (data.ch[9]); + if(data.ch[10] > 1490) Joystick.setButton(0, 255); else Joystick.setButton(0, 0); + if(data.ch[11] > 1490) Joystick.setButton(1, 255); else Joystick.setButton(1, 0); + if(data.ch[12] > 1490) Joystick.setButton(2, 255); else Joystick.setButton(2, 0); + if(data.ch[13] > 1490) Joystick.setButton(3, 255); else Joystick.setButton(3, 0); + if(data.ch[14] > 1490) Joystick.setButton(4, 255); else Joystick.setButton(4, 0); + Joystick.sendState(); + #endif + } //sbus_rx.Read +} diff --git a/translated_sandbox/sbus-to-usb-joystick/sbus.cpp b/translated_sandbox/sbus-to-usb-joystick/sbus.cpp new file mode 100644 index 0000000..b019402 --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/sbus.cpp @@ -0,0 +1,291 @@ +/* +* Brian R Taylor +* brian.taylor@bolderflight.com +* +* Copyright (c) 2022 Bolder Flight Systems Inc +* +* 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 "sbus.h" // NOLINT +#if defined(ARDUINO) +#include +#else +#include +#include +#include "core/core.h" +#endif + +namespace bfs { + +void SbusRx::Begin() { + if (fast_) { + baud_ = 200000; + } else { + baud_ = 100000; + } + /* Start the bus */ + /* Teensy 3.0 || Teensy 3.1/3.2 */ + #if defined(__MK20DX128__) || defined(__MK20DX256__) + if (inv_) { + uart_->begin(baud_, SERIAL_8E1_RXINV_TXINV); + } else { + uart_->begin(baud_, SERIAL_8E1); + } + /* + * Teensy 3.5 || Teensy 3.6 || + * Teensy LC || Teensy 4.0/4.1 || + * Teensy 4.0 Beta + */ + #elif defined(__MK64FX512__) || defined(__MK66FX1M0__) || \ + defined(__MKL26Z64__) || defined(__IMXRT1062__) || \ + defined(__IMXRT1052__) + if (inv_){ + uart_->begin(baud_, SERIAL_8E2_RXINV_TXINV); + } else { + uart_->begin(baud_, SERIAL_8E2); + } + /* STM32L4 */ + #elif defined(STM32L496xx) || defined(STM32L476xx) || \ + defined(STM32L433xx) || defined(STM32L432xx) + if (inv_) { + uart_->begin(baud_, SERIAL_8E2 | 0xC000ul); + } else { + uart_->begin(baud_, SERIAL_8E2); + } + /* ESP32 */ + #elif defined(ESP32) + uart_->begin(baud_, SERIAL_8E2, rxpin_, txpin_, inv_); + /* Everything else, with a hardware inverter */ + #else + uart_->begin(baud_, SERIAL_8E2); + #endif + /* flush the bus */ + uart_->flush(); +} + +bool SbusRx::Read() { + /* Read through all available packets to get the newest */ + new_data_ = false; + do { + if (Parse()) { + new_data_ = true; + } + } while (uart_->available()); + return new_data_; +} + +bool SbusRx::Parse() { + /* Parse messages */ + while (uart_->available()) { + cur_byte_ = uart_->read(); + if (state_ == 0) { + if ((cur_byte_ == HEADER_) && ((prev_byte_ == FOOTER_) || + ((prev_byte_ & 0x0F) == FOOTER2_))) { + buf_[state_++] = cur_byte_; + } else { + state_ = 0; + } + } else if (state_ < PAYLOAD_LEN_ + HEADER_LEN_) { + buf_[state_++] = cur_byte_; + } else if (state_ < PAYLOAD_LEN_ + HEADER_LEN_ + FOOTER_LEN_) { + state_ = 0; + prev_byte_ = cur_byte_; + if ((cur_byte_ == FOOTER_) || ((cur_byte_ & 0x0F) == FOOTER2_)) { + /* Grab the channel data */ + data_.ch[0] = static_cast(buf_[1] | + ((buf_[2] << 8) & 0x07FF)); + data_.ch[1] = static_cast((buf_[2] >> 3) | + ((buf_[3] << 5) & 0x07FF)); + data_.ch[2] = static_cast((buf_[3] >> 6) | + (buf_[4] << 2) | + ((buf_[5] << 10) & 0x07FF)); + data_.ch[3] = static_cast((buf_[5] >> 1) | + ((buf_[6] << 7) & 0x07FF)); + data_.ch[4] = static_cast((buf_[6] >> 4) | + ((buf_[7] << 4) & 0x07FF)); + data_.ch[5] = static_cast((buf_[7] >> 7) | + (buf_[8] << 1) | + ((buf_[9] << 9) & 0x07FF)); + data_.ch[6] = static_cast((buf_[9] >> 2) | + ((buf_[10] << 6) & 0x07FF)); + data_.ch[7] = static_cast((buf_[10] >> 5) | + ((buf_[11] << 3) & 0x07FF)); + data_.ch[8] = static_cast(buf_[12] | + ((buf_[13] << 8) & 0x07FF)); + data_.ch[9] = static_cast((buf_[13] >> 3) | + ((buf_[14] << 5) & 0x07FF)); + data_.ch[10] = static_cast((buf_[14] >> 6) | + (buf_[15] << 2) | + ((buf_[16] << 10) & 0x07FF)); + data_.ch[11] = static_cast((buf_[16] >> 1) | + ((buf_[17] << 7) & 0x07FF)); + data_.ch[12] = static_cast((buf_[17] >> 4) | + ((buf_[18] << 4) & 0x07FF)); + data_.ch[13] = static_cast((buf_[18] >> 7) | + (buf_[19] << 1) | + ((buf_[20] << 9) & 0x07FF)); + data_.ch[14] = static_cast((buf_[20] >> 2) | + ((buf_[21] << 6) & 0x07FF)); + data_.ch[15] = static_cast((buf_[21] >> 5) | + ((buf_[22] << 3) & 0x07FF)); + /* CH 17 */ + data_.ch17 = buf_[23] & CH17_MASK_; + /* CH 18 */ + data_.ch18 = buf_[23] & CH18_MASK_; + /* Grab the lost frame */ + data_.lost_frame = buf_[23] & LOST_FRAME_MASK_; + /* Grab the failsafe */ + data_.failsafe = buf_[23] & FAILSAFE_MASK_; + return true; + } else { + return false; + } + } else { + state_ = 0; + } + prev_byte_ = cur_byte_; + } + return false; +} + +/* Needed for emulating two stop bytes on Teensy 3.0 and 3.1/3.2 */ +#if defined(__MK20DX128__) || defined(__MK20DX256__) +namespace { + IntervalTimer serial_timer; + HardwareSerial *sbus_bus; + uint8_t sbus_packet[25]; + volatile int send_index = 0; + void SendByte() { + if (send_index < 25) { + sbus_bus->write(sbus_packet[send_index]); + send_index++; + } else { + serial_timer.end(); + send_index = 0; + } + } +} // namespace +#endif + +void SbusTx::Begin() { + if (fast_) { + baud_ = 200000; + } else { + baud_ = 100000; + } + /* Start the bus */ + /* Teensy 3.0 || Teensy 3.1/3.2 */ + #if defined(__MK20DX128__) || defined(__MK20DX256__) + sbus_bus = uart_; + if (inv_) { + uart_->begin(baud_, SERIAL_8E1_RXINV_TXINV); + } else { + uart_->begin(baud_, SERIAL_8E1); + } + /* + * Teensy 3.5 || Teensy 3.6 || + * Teensy LC || Teensy 4.0/4.1 || + * Teensy 4.0 Beta + */ + #elif defined(__MK64FX512__) || defined(__MK66FX1M0__) || \ + defined(__MKL26Z64__) || defined(__IMXRT1062__) || \ + defined(__IMXRT1052__) + if (inv_){ + uart_->begin(baud_, SERIAL_8E2_RXINV_TXINV); + } else { + uart_->begin(baud_, SERIAL_8E2); + } + /* STM32L4 */ + #elif defined(STM32L496xx) || defined(STM32L476xx) || \ + defined(STM32L433xx) || defined(STM32L432xx) + if (inv_) { + uart_->begin(baud_, SERIAL_8E2 | 0xC000ul); + } else { + uart_->begin(baud_, SERIAL_8E2); + } + /* ESP32 */ + #elif defined(ESP32) + uart_->begin(baud_, SERIAL_8E2, rxpin_, txpin_, inv_); + /* Everything else, with a hardware inverter */ + #else + uart_->begin(baud_, SERIAL_8E2); + #endif +} + +void SbusTx::Write() { + /* Assemble packet */ + buf_[0] = HEADER_; + buf_[1] = static_cast((data_.ch[0] & 0x07FF)); + buf_[2] = static_cast((data_.ch[0] & 0x07FF) >> 8 | + (data_.ch[1] & 0x07FF) << 3); + buf_[3] = static_cast((data_.ch[1] & 0x07FF) >> 5 | + (data_.ch[2] & 0x07FF) << 6); + buf_[4] = static_cast((data_.ch[2] & 0x07FF) >> 2); + buf_[5] = static_cast((data_.ch[2] & 0x07FF) >> 10 | + (data_.ch[3] & 0x07FF) << 1); + buf_[6] = static_cast((data_.ch[3] & 0x07FF) >> 7 | + (data_.ch[4] & 0x07FF) << 4); + buf_[7] = static_cast((data_.ch[4] & 0x07FF) >> 4 | + (data_.ch[5] & 0x07FF) << 7); + buf_[8] = static_cast((data_.ch[5] & 0x07FF) >> 1); + buf_[9] = static_cast((data_.ch[5] & 0x07FF) >> 9 | + (data_.ch[6] & 0x07FF) << 2); + buf_[10] = static_cast((data_.ch[6] & 0x07FF) >> 6 | + (data_.ch[7] & 0x07FF) << 5); + buf_[11] = static_cast((data_.ch[7] & 0x07FF) >> 3); + buf_[12] = static_cast((data_.ch[8] & 0x07FF)); + buf_[13] = static_cast((data_.ch[8] & 0x07FF) >> 8 | + (data_.ch[9] & 0x07FF) << 3); + buf_[14] = static_cast((data_.ch[9] & 0x07FF) >> 5 | + (data_.ch[10] & 0x07FF) << 6); + buf_[15] = static_cast((data_.ch[10] & 0x07FF) >> 2); + buf_[16] = static_cast((data_.ch[10] & 0x07FF) >> 10 | + (data_.ch[11] & 0x07FF) << 1); + buf_[17] = static_cast((data_.ch[11] & 0x07FF) >> 7 | + (data_.ch[12] & 0x07FF) << 4); + buf_[18] = static_cast((data_.ch[12] & 0x07FF) >> 4 | + (data_.ch[13] & 0x07FF) << 7); + buf_[19] = static_cast((data_.ch[13] & 0x07FF) >> 1); + buf_[20] = static_cast((data_.ch[13] & 0x07FF) >> 9 | + (data_.ch[14] & 0x07FF) << 2); + buf_[21] = static_cast((data_.ch[14] & 0x07FF) >> 6 | + (data_.ch[15] & 0x07FF) << 5); + buf_[22] = static_cast((data_.ch[15] & 0x07FF) >> 3); + buf_[23] = 0x00 | (data_.ch17 * CH17_MASK_) | (data_.ch18 * CH18_MASK_) | + (data_.failsafe * FAILSAFE_MASK_) | + (data_.lost_frame * LOST_FRAME_MASK_); + buf_[24] = FOOTER_; + /* Send packet to servos */ + #if defined(__MK20DX128__) || defined(__MK20DX256__) + /* + * Use ISR to send byte at a time, + * 130 us between bytes to emulate 2 stop bits + */ + __disable_irq(); + memcpy(sbus_packet, buf_, sizeof(buf_)); + __enable_irq(); + serial_timer.priority(255); + serial_timer.begin(SendByte, 130); + #else + uart_->write(buf_, sizeof(buf_)); + #endif +} + +} // namespace bfs diff --git a/translated_sandbox/sbus-to-usb-joystick/sbus.h b/translated_sandbox/sbus-to-usb-joystick/sbus.h new file mode 100644 index 0000000..74a2d7a --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/sbus.h @@ -0,0 +1,149 @@ +/* +* Brian R Taylor +* brian.taylor@bolderflight.com +* +* Copyright (c) 2022 Bolder Flight Systems Inc +* +* 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 SRC_SBUS_H_ +#define SRC_SBUS_H_ + +#if defined(ARDUINO) +#include +#else +#include +#include +#include "core/core.h" +#endif + +namespace bfs { + +struct SbusData { + bool lost_frame; + bool failsafe; + bool ch17, ch18; + static constexpr int8_t NUM_CH = 16; + int16_t ch[NUM_CH]; +}; + +class SbusRx { + public: + #if defined(ESP32) + SbusRx(HardwareSerial *bus, const int8_t rxpin, const int8_t txpin, + const bool inv) : uart_(bus), inv_(inv), rxpin_(rxpin), txpin_(txpin) + {} + SbusRx(HardwareSerial *bus, const int8_t rxpin, const int8_t txpin, + const bool inv, const bool fast) : uart_(bus), inv_(inv), fast_(fast), + rxpin_(rxpin), txpin_(txpin) {} + #else + explicit SbusRx(HardwareSerial *bus) : uart_(bus) {} + SbusRx(HardwareSerial *bus, const bool inv) : uart_(bus), inv_(inv) {} + SbusRx(HardwareSerial *bus, const bool inv, const bool fast) : uart_(bus), + inv_(inv), + fast_(fast) {} + #endif + void Begin(); + bool Read(); + inline SbusData data() const {return data_;} + + private: + /* Communication */ + HardwareSerial *uart_; + bool inv_ = true; + bool fast_ = false; + #if defined(ESP32) + int8_t rxpin_, txpin_; + #endif + int32_t baud_ = 100000; + /* Message len */ + static constexpr int8_t PAYLOAD_LEN_ = 23; + static constexpr int8_t HEADER_LEN_ = 1; + static constexpr int8_t FOOTER_LEN_ = 1; + /* SBUS message defs */ + static constexpr int8_t NUM_SBUS_CH_ = 16; + static constexpr uint8_t HEADER_ = 0x0F; + static constexpr uint8_t FOOTER_ = 0x00; + static constexpr uint8_t FOOTER2_ = 0x04; + static constexpr uint8_t CH17_MASK_ = 0x01; + static constexpr uint8_t CH18_MASK_ = 0x02; + static constexpr uint8_t LOST_FRAME_MASK_ = 0x04; + static constexpr uint8_t FAILSAFE_MASK_ = 0x08; + /* Parsing state tracking */ + int8_t state_ = 0; + uint8_t prev_byte_ = FOOTER_; + uint8_t cur_byte_; + /* Buffer for storing messages */ + uint8_t buf_[25]; + /* Data */ + bool new_data_; + SbusData data_; + bool Parse(); +}; + +class SbusTx { + public: + #if defined(ESP32) + SbusTx(HardwareSerial *bus, const int8_t rxpin, const int8_t txpin, + const bool inv) : uart_(bus), inv_(inv), rxpin_(rxpin), txpin_(txpin) + {} + SbusTx(HardwareSerial *bus, const int8_t rxpin, const int8_t txpin, + const bool inv, const bool fast) : uart_(bus), inv_(inv), fast_(fast), + rxpin_(rxpin), txpin_(txpin) {} + #else + explicit SbusTx(HardwareSerial *bus) : uart_(bus) {} + SbusTx(HardwareSerial *bus, const bool inv) : uart_(bus), inv_(inv) {} + SbusTx(HardwareSerial *bus, const bool inv, const bool fast) : uart_(bus), + inv_(inv), + fast_(fast) {} + #endif + void Begin(); + void Write(); + inline void data(const SbusData &data) {data_ = data;} + inline SbusData data() const {return data_;} + + private: + /* Communication */ + HardwareSerial *uart_; + bool inv_ = true; + bool fast_ = false; + #if defined(ESP32) + int8_t rxpin_, txpin_; + #endif + int32_t baud_ = 100000; + /* Message len */ + static constexpr int8_t BUF_LEN_ = 25; + /* SBUS message defs */ + static constexpr int8_t NUM_SBUS_CH_ = 16; + static constexpr uint8_t HEADER_ = 0x0F; + static constexpr uint8_t FOOTER_ = 0x00; + static constexpr uint8_t FOOTER2_ = 0x04; + static constexpr uint8_t CH17_MASK_ = 0x01; + static constexpr uint8_t CH18_MASK_ = 0x02; + static constexpr uint8_t LOST_FRAME_MASK_ = 0x04; + static constexpr uint8_t FAILSAFE_MASK_ = 0x08; + /* Data */ + uint8_t buf_[BUF_LEN_]; + SbusData data_; +}; + +} // namespace bfs + +#endif // SRC_SBUS_H_ diff --git a/translated_sandbox/sbus-to-usb-joystick/translated_readme.txt b/translated_sandbox/sbus-to-usb-joystick/translated_readme.txt new file mode 100644 index 0000000..9d255c8 --- /dev/null +++ b/translated_sandbox/sbus-to-usb-joystick/translated_readme.txt @@ -0,0 +1,13 @@ +## USB joystick from regular radio equipment with SBUS receiver on arduino pro micro + +![photo_2023-03-30_04-58-32.jpg](photo_2023-03-30_04-58-32.jpg) + +Connect the SBUS signal from the receiver to rx, you need a non-inverted one. If you have a "regular" inverted one, you will have to use a transistor for inversion. + +![sbus-inverter-diagram-schematics.jpg](sbus-inverter-diagram-schematics.jpg) + +I use "digital" transistors dtc144eka or bcr533 and do not put a resistor in the base. As a transmitter and receiver sbus I use qczek, you can use any receiver. +Its task is to transmit channel values ​​from the equipment to the USB recorder via [arduino](https://docs.arduino.cc/hardware/micro) to 32u4 ([ali](https://aliexpress.ru/item/1005003622414316.html)), which is defined as hid-usb-joystick. At the same time, the delay increases slightly due to the additional +process of receiving and transmitting values, but you are not tied to the recorder by a wire, which is convenient. + +Sketch, a joystick library modified for 10 axis channels (the remaining channels are filled with buttons), [here](https://github.com/OpenIPC/sandbox-fpv/tree/master/sbus-to-usb-joystick). \ No newline at end of file