From b6677f10e33bfa49557dfebd0226928477ede56a Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 5 Aug 2013 16:22:08 +0900 Subject: [PATCH 01/76] Add files for onekey(issue #56) - https://github.com/tmk/tmk_keyboard/issues/56 --- keyboard/onekey/Makefile.lufa | 141 +++++++++++++++++++++++++++ keyboard/onekey/Makefile.pjrc | 110 +++++++++++++++++++++ keyboard/onekey/README.md | 5 + keyboard/onekey/config.h | 70 ++++++++++++++ keyboard/onekey/keymap.c | 66 +++++++++++++ keyboard/onekey/led.c | 25 +++++ keyboard/onekey/matrix.c | 175 ++++++++++++++++++++++++++++++++++ 7 files changed, 592 insertions(+) create mode 100644 keyboard/onekey/Makefile.lufa create mode 100644 keyboard/onekey/Makefile.pjrc create mode 100644 keyboard/onekey/README.md create mode 100644 keyboard/onekey/config.h create mode 100644 keyboard/onekey/keymap.c create mode 100644 keyboard/onekey/led.c create mode 100644 keyboard/onekey/matrix.c diff --git a/keyboard/onekey/Makefile.lufa b/keyboard/onekey/Makefile.lufa new file mode 100644 index 00000000..03cfd83a --- /dev/null +++ b/keyboard/onekey/Makefile.lufa @@ -0,0 +1,141 @@ +#---------------------------------------------------------------------------- +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF. +# +# make extcoff = Convert ELF to AVR Extended COFF. +# +# make program = Download the hex file to the device. +# Please customize your programmer settings(PROGRAM_CMD) +# +# make teensy = Download the hex file to the device, using teensy_loader_cli. +# (must have teensy_loader_cli installed). +# +# make dfu = Download the hex file to the device, using dfu-programmer (must +# have dfu-programmer installed). +# +# make flip = Download the hex file to the device, using Atmel FLIP (must +# have Atmel FLIP installed). +# +# make dfu-ee = Download the eeprom file to the device, using dfu-programmer +# (must have dfu-programmer installed). +# +# make flip-ee = Download the eeprom file to the device, using Atmel FLIP +# (must have Atmel FLIP installed). +# +# make debug = Start either simulavr or avarice as specified for debugging, +# with avr-gdb or avr-insight as the front end for debugging. +# +# make filename.s = Just compile filename.c into the assembler code only. +# +# make filename.i = Create a preprocessed source file for use in submitting +# bug reports to the GCC project. +# +# To rebuild project do "make clean" then "make all". +#---------------------------------------------------------------------------- + +# Target file name (without extension). +TARGET = onekey_lufa + +# Directory common source filess exist +TOP_DIR = ../.. + +# Directory keyboard dependent files exist +TARGET_DIR = . + +# project specific files +SRC = keymap.c \ + matrix.c \ + led.c + +CONFIG_H = config.h + + +# MCU name +#MCU = at90usb1287 +MCU = atmega32u4 + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency in Hz. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# +# This will be an integer division of F_USB below, as it is sourced by +# F_USB after it has run through any CPU prescalers. Note that this value +# does not *change* the processor frequency - it should merely be updated to +# reflect the processor speed set externally so that the code can use accurate +# software delays. +F_CPU = 16000000 + + +# +# LUFA specific +# +# Target architecture (see library "Board Types" documentation). +ARCH = AVR8 + +# Input clock frequency. +# This will define a symbol, F_USB, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_USB = $(F_CPU) + +# Interrupt driven control endpoint task(+60) +#OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT + + +# Boot Section Size in *bytes* +# Teensy halfKay 512 +# Teensy++ halfKay 1024 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +# USBaspLoader 2048 +OPT_DEFS += -DBOOTLOADER_SIZE=4096 + + +# Build Options +# comment out to disable the options. +# +BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE = yes # Mouse keys(+4700) +EXTRAKEY_ENABLE = yes # Audio control and System control(+450) +CONSOLE_ENABLE = yes # Console for debug(+400) +COMMAND_ENABLE = yes # Commands for debug and configuration +SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend +#NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA + + +# Optimize size but this may cause error "relocation truncated to fit" +#EXTRALDFLAGS = -Wl,--relax + +# Search Path +VPATH += $(TARGET_DIR) +VPATH += $(TOP_DIR) + +include $(TOP_DIR)/protocol/lufa.mk +include $(TOP_DIR)/common.mk +include $(TOP_DIR)/rules.mk + +plain: OPT_DEFS += -DKEYMAP_PLAIN +plain: all + +poker: OPT_DEFS += -DKEYMAP_POKER +poker: all + +poker_set: OPT_DEFS += -DKEYMAP_POKER_SET +poker_set: all + +poker_bit: OPT_DEFS += -DKEYMAP_POKER_BIT +poker_bit: all diff --git a/keyboard/onekey/Makefile.pjrc b/keyboard/onekey/Makefile.pjrc new file mode 100644 index 00000000..194a2b97 --- /dev/null +++ b/keyboard/onekey/Makefile.pjrc @@ -0,0 +1,110 @@ +#---------------------------------------------------------------------------- +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF. +# +# make extcoff = Convert ELF to AVR Extended COFF. +# +# make program = Download the hex file to the device. +# Please customize your programmer settings(PROGRAM_CMD) +# +# make teensy = Download the hex file to the device, using teensy_loader_cli. +# (must have teensy_loader_cli installed). +# +# make dfu = Download the hex file to the device, using dfu-programmer (must +# have dfu-programmer installed). +# +# make flip = Download the hex file to the device, using Atmel FLIP (must +# have Atmel FLIP installed). +# +# make dfu-ee = Download the eeprom file to the device, using dfu-programmer +# (must have dfu-programmer installed). +# +# make flip-ee = Download the eeprom file to the device, using Atmel FLIP +# (must have Atmel FLIP installed). +# +# make debug = Start either simulavr or avarice as specified for debugging, +# with avr-gdb or avr-insight as the front end for debugging. +# +# make filename.s = Just compile filename.c into the assembler code only. +# +# make filename.i = Create a preprocessed source file for use in submitting +# bug reports to the GCC project. +# +# To rebuild project do "make clean" then "make all". +#---------------------------------------------------------------------------- + +# Target file name (without extension). +TARGET = onekey_pjrc + +# Directory common source filess exist +TOP_DIR = ../.. + +# Directory keyboard dependent files exist +TARGET_DIR = . + +# project specific files +SRC = keymap.c \ + matrix.c \ + led.c + +CONFIG_H = config.h + + +# MCU name, you MUST set this to match the board you are using +# type "make clean" after changing this, so all files will be rebuilt +MCU = atmega32u4 +#MCU = at90usb1286 + + +# Processor frequency. +# Normally the first thing your program should do is set the clock prescaler, +# so your program will run at the correct speed. You should also set this +# variable to same clock speed. The _delay_ms() macro uses this, and many +# examples use this variable to calculate timings. Do not add a "UL" here. +F_CPU = 16000000 + + +# Boot Section Size in *bytes* +# Teensy halfKay 512 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +OPT_DEFS += -DBOOTLOADER_SIZE=4096 + + +# Build Options +# comment out to disable the options. +# +BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE = yes # Mouse keys(+5000) +EXTRAKEY_ENABLE = yes # Audio control and System control(+600) +CONSOLE_ENABLE = yes # Console for debug +COMMAND_ENABLE = yes # Commands for debug and configuration +SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend +NKRO_ENABLE = yes # USB Nkey Rollover(+500) +#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support + + +# Search Path +VPATH += $(TARGET_DIR) +VPATH += $(TOP_DIR) + +include $(TOP_DIR)/protocol/pjrc.mk +include $(TOP_DIR)/common.mk +include $(TOP_DIR)/rules.mk + +plain: OPT_DEFS += -DKEYMAP_PLAIN +plain: all + +poker: OPT_DEFS += -DKEYMAP_POKER +poker: all + +poker_set: OPT_DEFS += -DKEYMAP_POKER_SET +poker_set: all + +poker_bit: OPT_DEFS += -DKEYMAP_POKER_BIT +poker_bit: all diff --git a/keyboard/onekey/README.md b/keyboard/onekey/README.md new file mode 100644 index 00000000..6ccc9992 --- /dev/null +++ b/keyboard/onekey/README.md @@ -0,0 +1,5 @@ +Onekey +====== +Just one key keyboard for example. It sends 'a' key if pins PD0 and PD1 are short-circuited. + +https://github.com/tmk/tmk_keyboard/issues/56 diff --git a/keyboard/onekey/config.h b/keyboard/onekey/config.h new file mode 100644 index 00000000..c5bc64de --- /dev/null +++ b/keyboard/onekey/config.h @@ -0,0 +1,70 @@ +/* +Copyright 2012 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef CONFIG_H +#define CONFIG_H + + +/* USB Device descriptor parameter */ +#define VENDOR_ID 0xFEED +#define PRODUCT_ID 0x1111 +#define DEVICE_VER 0x0001 +#define MANUFACTURER geekhack +#define PRODUCT Onekey +#define DESCRIPTION t.m.k. keyboard firmware for Onekey + +/* key matrix size */ +#define MATRIX_ROWS 1 +#define MATRIX_COLS 1 + +/* define if matrix has ghost */ +//#define MATRIX_HAS_GHOST + +/* Set 0 if debouncing isn't needed */ +#define DEBOUNCE 5 + +/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ +#define LOCKING_SUPPORT_ENABLE +/* Locking resynchronize hack */ +#define LOCKING_RESYNC_ENABLE + +/* key combination for command */ +#define IS_COMMAND() ( \ + keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ +) + + + +/* + * Feature disable options + * These options are also useful to firmware size reduction. + */ + +/* disable debug print */ +//#define NO_DEBUG + +/* disable print */ +//#define NO_PRINT + +/* disable action features */ +//#define NO_ACTION_LAYER +//#define NO_ACTION_TAPPING +//#define NO_ACTION_ONESHOT +//#define NO_ACTION_MACRO +//#define NO_ACTION_FUNCTION + +#endif diff --git a/keyboard/onekey/keymap.c b/keyboard/onekey/keymap.c new file mode 100644 index 00000000..90f195c2 --- /dev/null +++ b/keyboard/onekey/keymap.c @@ -0,0 +1,66 @@ +/* +Copyright 2012,2013 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include +#include +#include +#include "keycode.h" +#include "action.h" +#include "action_macro.h" +#include "report.h" +#include "host.h" +#include "print.h" +#include "debug.h" +#include "keymap.h" + + +static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + {{KC_A}}, +}; + +/* + * Fn action definition + */ +static const uint16_t PROGMEM fn_actions[] = { +}; + + + +#define KEYMAPS_SIZE (sizeof(keymaps) / sizeof(keymaps[0])) +#define FN_ACTIONS_SIZE (sizeof(fn_actions) / sizeof(fn_actions[0])) + +/* translates key to keycode */ +uint8_t keymap_key_to_keycode(uint8_t layer, key_t key) +{ + if (layer < KEYMAPS_SIZE) { + return pgm_read_byte(&keymaps[(layer)][(key.row)][(key.col)]); + } else { + // fall back to layer 0 + return pgm_read_byte(&keymaps[0][(key.row)][(key.col)]); + } +} + +/* translates Fn keycode to action */ +action_t keymap_fn_to_action(uint8_t keycode) +{ + action_t action; + if (FN_INDEX(keycode) < FN_ACTIONS_SIZE) { + action.code = pgm_read_word(&fn_actions[FN_INDEX(keycode)]); + } else { + action.code = ACTION_NO; + } + return action; +} diff --git a/keyboard/onekey/led.c b/keyboard/onekey/led.c new file mode 100644 index 00000000..2d52fbf1 --- /dev/null +++ b/keyboard/onekey/led.c @@ -0,0 +1,25 @@ +/* +Copyright 2012 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include +#include "stdint.h" +#include "led.h" + + +void led_set(uint8_t usb_led) +{ +} diff --git a/keyboard/onekey/matrix.c b/keyboard/onekey/matrix.c new file mode 100644 index 00000000..cd0789c6 --- /dev/null +++ b/keyboard/onekey/matrix.c @@ -0,0 +1,175 @@ +/* +Copyright 2012 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +/* + * scan matrix + */ +#include +#include +#include +#include +#include "print.h" +#include "debug.h" +#include "util.h" +#include "matrix.h" + + +#ifndef DEBOUNCE +# define DEBOUNCE 5 +#endif +static uint8_t debouncing = DEBOUNCE; + +/* matrix state(1:on, 0:off) */ +static matrix_row_t matrix[MATRIX_ROWS]; +static matrix_row_t matrix_debouncing[MATRIX_ROWS]; + +static matrix_row_t read_cols(void); +static void init_cols(void); +static void unselect_rows(void); +static void select_row(uint8_t row); + + +inline +uint8_t matrix_rows(void) +{ + return MATRIX_ROWS; +} + +inline +uint8_t matrix_cols(void) +{ + return MATRIX_COLS; +} + +void matrix_init(void) +{ + debug_enable = true; + debug_matrix = true; + // initialize row and col + unselect_rows(); + init_cols(); + + // initialize matrix state: all keys off + for (uint8_t i=0; i < MATRIX_ROWS; i++) { + matrix[i] = 0; + matrix_debouncing[i] = 0; + } +} + +uint8_t matrix_scan(void) +{ + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + select_row(i); + _delay_us(30); // without this wait read unstable value. + matrix_row_t cols = read_cols(); + if (matrix_debouncing[i] != cols) { + matrix_debouncing[i] = cols; + if (debouncing) { + debug("bounce!: "); debug_hex(debouncing); debug("\n"); + } + debouncing = DEBOUNCE; + } + unselect_rows(); + } + + if (debouncing) { + if (--debouncing) { + _delay_ms(1); + } else { + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + matrix[i] = matrix_debouncing[i]; + } + } + } + + return 1; +} + +bool matrix_is_modified(void) +{ + if (debouncing) return false; + return true; +} + +inline +bool matrix_is_on(uint8_t row, uint8_t col) +{ + return (matrix[row] & ((matrix_row_t)1< Date: Wed, 9 Oct 2013 12:20:03 +0900 Subject: [PATCH 02/76] Change ADB scan delay 12ms --- converter/adb_usb/matrix.c | 2 +- protocol/adb.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/converter/adb_usb/matrix.c b/converter/adb_usb/matrix.c index 566592c9..7e585697 100644 --- a/converter/adb_usb/matrix.c +++ b/converter/adb_usb/matrix.c @@ -85,7 +85,7 @@ uint8_t matrix_scan(void) uint8_t key0, key1; is_modified = false; - _delay_ms(16); // delay for preventing overload of poor ADB keyboard controller + _delay_ms(12); // delay for preventing overload of poor ADB keyboard controller codes = adb_host_kbd_recv(); key0 = codes>>8; key1 = codes&0xFF; diff --git a/protocol/adb.c b/protocol/adb.c index 155d223f..f706255a 100644 --- a/protocol/adb.c +++ b/protocol/adb.c @@ -85,9 +85,11 @@ bool adb_host_psw(void) /* * Don't call this in a row without the delay, otherwise it makes some of poor controllers - * overloaded and misses strokes. Recommended delay is 16ms. + * overloaded and misses strokes. Recommended interval is 12ms. * - * Thanks a lot, blargg! + * Thanks a lot, blargg! + * + * */ uint16_t adb_host_kbd_recv(void) { From 59ecced486618161ab18ea9a95dd51e1414fedb8 Mon Sep 17 00:00:00 2001 From: tmk Date: Fri, 11 Oct 2013 10:12:22 +0900 Subject: [PATCH 03/76] Add ADB protocol files from blargg's work - --- converter/adb_usb/Makefile.blargg | 131 ++++++++++++++++++ converter/adb_usb/adb_blargg.c | 216 ++++++++++++++++++++++++++++++ converter/adb_usb/adb_blargg.h | 38 ++++++ 3 files changed, 385 insertions(+) create mode 100644 converter/adb_usb/Makefile.blargg create mode 100644 converter/adb_usb/adb_blargg.c create mode 100644 converter/adb_usb/adb_blargg.h diff --git a/converter/adb_usb/Makefile.blargg b/converter/adb_usb/Makefile.blargg new file mode 100644 index 00000000..edce82d6 --- /dev/null +++ b/converter/adb_usb/Makefile.blargg @@ -0,0 +1,131 @@ +#---------------------------------------------------------------------------- +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF. +# +# make extcoff = Convert ELF to AVR Extended COFF. +# +# make program = Download the hex file to the device. +# Please customize your programmer settings(PROGRAM_CMD) +# +# make teensy = Download the hex file to the device, using teensy_loader_cli. +# (must have teensy_loader_cli installed). +# +# make dfu = Download the hex file to the device, using dfu-programmer (must +# have dfu-programmer installed). +# +# make flip = Download the hex file to the device, using Atmel FLIP (must +# have Atmel FLIP installed). +# +# make dfu-ee = Download the eeprom file to the device, using dfu-programmer +# (must have dfu-programmer installed). +# +# make flip-ee = Download the eeprom file to the device, using Atmel FLIP +# (must have Atmel FLIP installed). +# +# make debug = Start either simulavr or avarice as specified for debugging, +# with avr-gdb or avr-insight as the front end for debugging. +# +# make filename.s = Just compile filename.c into the assembler code only. +# +# make filename.i = Create a preprocessed source file for use in submitting +# bug reports to the GCC project. +# +# To rebuild project do "make clean" then "make all". +#---------------------------------------------------------------------------- + +# Target file name (without extension). +TARGET = adb_usb_blargg + +# Directory common source filess exist +TOP_DIR = ../.. + +# Directory keyboard dependent files exist +TARGET_DIR = . + +# project specific files +SRC = keymap.c \ + matrix.c \ + led.c \ + adb_blargg.c + +CONFIG_H = config.h + + +# MCU name +#MCU = at90usb1287 +MCU = atmega32u4 + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency in Hz. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# +# This will be an integer division of F_USB below, as it is sourced by +# F_USB after it has run through any CPU prescalers. Note that this value +# does not *change* the processor frequency - it should merely be updated to +# reflect the processor speed set externally so that the code can use accurate +# software delays. +F_CPU = 16000000 + + +# +# LUFA specific +# +# Target architecture (see library "Board Types" documentation). +ARCH = AVR8 + +# Input clock frequency. +# This will define a symbol, F_USB, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_USB = $(F_CPU) + +# Interrupt driven control endpoint task(+60) +#OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT + + +# Boot Section Size in *bytes* +# Teensy halfKay 512 +# Teensy++ halfKay 1024 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +# USBaspLoader 2048 +OPT_DEFS += -DBOOTLOADER_SIZE=4096 + + +# Build Options +# comment out to disable the options. +# +BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE = yes # Mouse keys(+4700) +EXTRAKEY_ENABLE = yes # Audio control and System control(+450) +CONSOLE_ENABLE = yes # Console for debug(+400) +COMMAND_ENABLE = yes # Commands for debug and configuration +#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend +#NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA + + +# Optimize size but this may cause error "relocation truncated to fit" +#EXTRALDFLAGS = -Wl,--relax + +# Search Path +VPATH += $(TARGET_DIR) +VPATH += $(TOP_DIR) + +include $(TOP_DIR)/protocol/lufa.mk +include $(TOP_DIR)/protocol.mk +include $(TOP_DIR)/common.mk +include $(TOP_DIR)/rules.mk diff --git a/converter/adb_usb/adb_blargg.c b/converter/adb_usb/adb_blargg.c new file mode 100644 index 00000000..963758c5 --- /dev/null +++ b/converter/adb_usb/adb_blargg.c @@ -0,0 +1,216 @@ +// Bit-banged implementation without any use of interrupts. +// Data pin must have external 1K pull-up resistor. +// Operates data pin as open-collector output. + +#include "adb_blargg.h" + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include + +// Copyright 2011 Jun WAKO +// Copyright 2013 Shay Green +// See bottom of file for license + +typedef uint8_t byte; + +// Make loop iteration take us total, including cyc overhead of loop logic +#define delay_loop_usec( us, cyc ) \ + __builtin_avr_delay_cycles( (unsigned long) (F_CPU / 1e6 * (us) + 0.5) - (cyc) ) + +#if !defined(ADB_PORT) || \ + !defined(ADB_PIN) || \ + !defined(ADB_DDR) || \ + !defined(ADB_DATA_BIT) + #error +#endif + +enum { data_mask = 1< +#include + +// Sets up ADB bus. Doesn't send anything to keyboard. +void adb_host_init( void ); + +// Receives key press event from keyboard. +// 0xKKFF: one key changed state +// 0xKKKK: two keys changed state +enum { adb_host_nothing = 0 }; // no keys changed state +enum { adb_host_error = 0xFFFE }; // receive error +uint16_t adb_host_kbd_recv( void ); + +// Current state of keyboard modifiers and a few other keys +// Returns adb_host_nothing if keyboard didn't respond. +// Returns adb_host_error if error receiving. +uint16_t adb_host_kbd_modifiers( void ); + +// Sends command and two bytes of data to keyboard +void adb_host_listen( uint8_t cmd, uint8_t data_h, uint8_t data_l ); + +// Sets keyboard LEDs. Note that bits are inverted here, so 1 means off, 0 means on. +void adb_host_kbd_led( uint8_t led ); + +// State of power switch (false = pressed), or true if unsupported +bool adb_host_psw( void ); + + +// Legacy support +#define ADB_POWER 0x7F +#define ADB_CAPS 0x39 + +#endif From c18c52f551545b46a28902c69730eefbdb75577d Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 14 Oct 2013 23:37:05 +0900 Subject: [PATCH 04/76] Merge blargg's fix into adb.c - --- converter/adb_usb/led.c | 5 +- converter/adb_usb/matrix.c | 7 ++ protocol/adb.c | 208 +++++++++++++++++-------------------- 3 files changed, 108 insertions(+), 112 deletions(-) diff --git a/converter/adb_usb/led.c b/converter/adb_usb/led.c index 0e162f37..1e7911f9 100644 --- a/converter/adb_usb/led.c +++ b/converter/adb_usb/led.c @@ -15,12 +15,15 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "stdint.h" +#include +#include #include "adb.h" #include "led.h" void led_set(uint8_t usb_led) { + // need a wait to send command without miss + _delay_ms(100); adb_host_kbd_led(~usb_led); } diff --git a/converter/adb_usb/matrix.c b/converter/adb_usb/matrix.c index 7e585697..54be2b0f 100644 --- a/converter/adb_usb/matrix.c +++ b/converter/adb_usb/matrix.c @@ -67,6 +67,13 @@ uint8_t matrix_cols(void) void matrix_init(void) { adb_host_init(); + // wait for keyboard to boot up and receive command + _delay_ms(1000); + // Enable keyboard left/right modifier distinction + // Addr:Keyboard(0010), Cmd:Listen(10), Register3(11) + // upper byte: reserved bits 0000, device address 0010 + // lower byte: device handler 00000011 + adb_host_listen(0x2B,0x02,0x03); // initialize matrix state: all keys off for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; diff --git a/protocol/adb.c b/protocol/adb.c index f706255a..750f4b96 100644 --- a/protocol/adb.c +++ b/protocol/adb.c @@ -1,5 +1,6 @@ /* Copyright 2011 Jun WAKO +Copyright 2013 Shay Green This software is licensed with a Modified BSD License. All of this is supposed to be Free Software, Open Source, DFSG-free, @@ -43,9 +44,11 @@ POSSIBILITY OF SUCH DAMAGE. #include "debug.h" -static inline void data_lo(void); -static inline void data_hi(void); -static inline bool data_in(void); +// GCC doesn't inline functions normally +#define data_lo() (ADB_DDR |= (1< * */ + +// ADB Bit Cells +// +// bit cell time: 70-130us +// low part of bit0: 60-70% of bit cell +// low part of bit1: 30-40% of bit cell +// +// bit cell time 70us 130us +// -------------------------------------------- +// low part of bit0 42-49 78-91 +// high part of bit0 21-28 39-52 +// low part of bit1 21-28 39-52 +// high part of bit1 42-49 78-91 +// +// +// bit0: +// 70us bit cell: +// ____________~~~~~~ +// 42-49 21-28 +// +// 130us bit cell: +// ____________~~~~~~ +// 78-91 39-52 +// +// bit1: +// 70us bit cell: +// ______~~~~~~~~~~~~ +// 21-28 42-49 +// +// 130us bit cell: +// ______~~~~~~~~~~~~ +// 39-52 78-91 +// +// [from Apple IIgs Hardware Reference Second Edition] + uint16_t adb_host_kbd_recv(void) { uint16_t data = 0; @@ -100,24 +131,50 @@ uint16_t adb_host_kbd_recv(void) if (!wait_data_lo(500)) { // Tlt/Stop to Start(140-260us) return 0; // No data to send } - if (!read_bit()) { // Startbit(1) - // Service Request - dprintf("Startbit ERROR\n"); - return -2; - } - + // ad hoc fix: without block inerrupt read wrong bit occasionally and get keys stuck - cli(); - data = read_byte(); - data = (data<<8) | read_byte(); - uint8_t stop = read_bit(); // Stopbit(0) - sei(); + // TODO: is this needed anymore with improved timing? + //cli(); + uint8_t n = 17; // start bit + 16 data bits + do { + uint8_t lo = (uint8_t) wait_data_hi(130); + if (!lo) + goto error; + + uint8_t hi = (uint8_t) wait_data_lo(lo); + if (!hi) + goto error; + + hi = lo - hi; + lo = 130 - lo; + + data <<= 1; + if (lo < hi) { + data |= 1; + } + else if (n == 17) { + // Service Request + dprintf("Startbit ERROR\n"); + sei(); + return -2; + } + } + while ( --n ); - if (stop) { + // Stop bit can't be checked normally since it could have service request lenghtening + // and its high state never goes low. + if (!wait_data_hi(351) || wait_data_lo(91)) { dprintf("Stopbit ERROR\n"); + sei(); return -3; } + sei(); return data; + +error: + dprintf("Bit ERROR\n"); + sei(); + return -4; } void adb_host_listen(uint8_t cmd, uint8_t data_h, uint8_t data_l) @@ -142,23 +199,6 @@ void adb_host_kbd_led(uint8_t led) } -static inline void data_lo() -{ - ADB_DDR |= (1< Date: Mon, 28 Oct 2013 11:32:19 +0900 Subject: [PATCH 05/76] Delete MOUSEKEY_DELAY_TIME in config.h --- converter/adb_usb/config.h | 6 ------ converter/news_usb/config_pjrc.h | 6 ------ converter/ps2_usb/config.h | 6 ------ keyboard/IIgs/config.h | 6 ------ keyboard/hhkb/config_iwrap.h | 5 ----- keyboard/hhkb/config_vusb.h | 6 ------ 6 files changed, 35 deletions(-) diff --git a/converter/adb_usb/config.h b/converter/adb_usb/config.h index 4ce27bbf..5ce5c221 100644 --- a/converter/adb_usb/config.h +++ b/converter/adb_usb/config.h @@ -44,12 +44,6 @@ along with this program. If not, see . #define USE_LEGACY_KEYMAP -/* mouse keys */ -#ifdef MOUSEKEY_ENABLE -# define MOUSEKEY_DELAY_TIME 192 -#endif - - /* ADB port setting */ #define ADB_PORT PORTD #define ADB_PIN PIND diff --git a/converter/news_usb/config_pjrc.h b/converter/news_usb/config_pjrc.h index 92751d1e..adce014c 100644 --- a/converter/news_usb/config_pjrc.h +++ b/converter/news_usb/config_pjrc.h @@ -42,12 +42,6 @@ along with this program. If not, see . ) -/* mouse keys */ -#ifdef MOUSEKEY_ENABLE -# define MOUSEKEY_DELAY_TIME 255 -#endif - - /* Asynchronous USART * 8-data bit, non parity, 1-stop bit, no flow control */ diff --git a/converter/ps2_usb/config.h b/converter/ps2_usb/config.h index 4a2d1fc4..6fbf1366 100644 --- a/converter/ps2_usb/config.h +++ b/converter/ps2_usb/config.h @@ -39,12 +39,6 @@ along with this program. If not, see . ) -/* mouse keys */ -#ifdef MOUSEKEY_ENABLE -# define MOUSEKEY_DELAY_TIME 255 -#endif - - #ifdef PS2_USE_USART #if defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) /* XCK for clock line and RXD for data line */ diff --git a/keyboard/IIgs/config.h b/keyboard/IIgs/config.h index 0039cb48..842e404f 100644 --- a/keyboard/IIgs/config.h +++ b/keyboard/IIgs/config.h @@ -56,10 +56,4 @@ along with this program. If not, see . #define LAYER_SEND_FN_TERM 300 -/* mouse keys */ -#ifdef MOUSEKEY_ENABLE -# define MOUSEKEY_DELAY_TIME 192 -#endif - - #endif diff --git a/keyboard/hhkb/config_iwrap.h b/keyboard/hhkb/config_iwrap.h index 80a60888..747c7551 100644 --- a/keyboard/hhkb/config_iwrap.h +++ b/keyboard/hhkb/config_iwrap.h @@ -34,11 +34,6 @@ along with this program. If not, see . /* key combination for command */ #define IS_COMMAND() (keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT))) -/* mouse keys */ -#ifdef MOUSEKEY_ENABLE -# define MOUSEKEY_DELAY_TIME 255 -#endif - /* pins for Software UART */ #define SUART_IN_PIN PINC #define SUART_IN_BIT 5 diff --git a/keyboard/hhkb/config_vusb.h b/keyboard/hhkb/config_vusb.h index 37d3e4f2..44f7acd6 100644 --- a/keyboard/hhkb/config_vusb.h +++ b/keyboard/hhkb/config_vusb.h @@ -35,10 +35,4 @@ along with this program. If not, see . /* key combination for command */ #define IS_COMMAND() (keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT))) -/* mouse keys */ -#ifdef MOUSEKEY_ENABLE -# define MOUSEKEY_DELAY_TIME 100 -#endif - - #endif From b9fe36f237635db8e37fc94413a7bb7c381070fc Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 28 Oct 2013 11:43:45 +0900 Subject: [PATCH 06/76] Add USE_LEGACY_KEYMAP in config.h of ps2_usb and IIgs --- converter/ps2_usb/config.h | 4 ++++ keyboard/IIgs/config.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/converter/ps2_usb/config.h b/converter/ps2_usb/config.h index 6fbf1366..51cd271d 100644 --- a/converter/ps2_usb/config.h +++ b/converter/ps2_usb/config.h @@ -39,6 +39,10 @@ along with this program. If not, see . ) +/* legacy keymap support */ +#define USE_LEGACY_KEYMAP + + #ifdef PS2_USE_USART #if defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) /* XCK for clock line and RXD for data line */ diff --git a/keyboard/IIgs/config.h b/keyboard/IIgs/config.h index 842e404f..bc8bf75f 100644 --- a/keyboard/IIgs/config.h +++ b/keyboard/IIgs/config.h @@ -56,4 +56,8 @@ along with this program. If not, see . #define LAYER_SEND_FN_TERM 300 +/* legacy keymap support */ +#define USE_LEGACY_KEYMAP + + #endif From 1591764cfbc39e73c6f32e9b805d596379866ff0 Mon Sep 17 00:00:00 2001 From: tmk Date: Sat, 2 Nov 2013 03:06:51 +0900 Subject: [PATCH 07/76] Tweak time values of busywait PS/2 --- protocol/ps2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/protocol/ps2.c b/protocol/ps2.c index ed456091..4c6c2fcb 100644 --- a/protocol/ps2.c +++ b/protocol/ps2.c @@ -109,12 +109,12 @@ uint8_t ps2_host_send(uint8_t data) #endif /* terminate a transmission if we have */ inhibit(); - _delay_us(100); + _delay_us(200); // at least 100us /* start bit [1] */ data_lo(); clock_hi(); - WAIT(clock_lo, 15000, 1); + WAIT(clock_lo, 20000, 10); // may take 15ms at most until device starts clocking /* data [2-9] */ for (uint8_t i = 0; i < 8; i++) { _delay_us(15); @@ -167,7 +167,7 @@ uint8_t ps2_host_recv_response(void) idle(); /* wait start bit */ - wait_clock_lo(2000); + wait_clock_lo(25000); // command response may take 20 ms at most data = recv_data(); inhibit(); From 676d94d13791a99751cebf724fd5a56b150f344d Mon Sep 17 00:00:00 2001 From: tmk Date: Sat, 2 Nov 2013 03:10:49 +0900 Subject: [PATCH 08/76] Fix PS/2 mouse support --- common.mk | 11 +--- common/keyboard.c | 15 +++++- protocol.mk | 25 +++++++++ protocol/pjrc.mk | 6 ++- protocol/ps2_mouse.c | 122 ++++++++++++++++++------------------------- 5 files changed, 95 insertions(+), 84 deletions(-) diff --git a/common.mk b/common.mk index 5b70db94..2ca06daa 100644 --- a/common.mk +++ b/common.mk @@ -25,6 +25,7 @@ endif ifdef MOUSEKEY_ENABLE SRC += $(COMMON_DIR)/mousekey.c OPT_DEFS += -DMOUSEKEY_ENABLE + OPT_DEFS += -DMOUSE_ENABLE endif ifdef EXTRAKEY_ENABLE @@ -47,16 +48,6 @@ ifdef NKRO_ENABLE OPT_DEFS += -DNKRO_ENABLE endif -ifdef PS2_MOUSE_ENABLE - SRC += $(COMMON_DIR)/ps2.c \ - $(COMMON_DIR)/ps2_mouse.c - OPT_DEFS += -DPS2_MOUSE_ENABLE -endif - -ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE) - OPT_DEFS += -DMOUSE_ENABLE -endif - ifdef SLEEP_LED_ENABLE SRC += $(COMMON_DIR)/sleep_led.c OPT_DEFS += -DSLEEP_LED_ENABLE diff --git a/common/keyboard.c b/common/keyboard.c index 601e3abe..63a58b21 100644 --- a/common/keyboard.c +++ b/common/keyboard.c @@ -30,8 +30,13 @@ along with this program. If not, see . #include "sendchar.h" #include "bootmagic.h" #include "eeconfig.h" -#include "mousekey.h" #include "backlight.h" +#ifdef MOUSEKEY_ENABLE +# include "mousekey.h" +#endif +#ifdef PS2_MOUSE_ENABLE +# include "ps2_mouse.h" +#endif #ifdef MATRIX_HAS_GHOST @@ -111,10 +116,18 @@ void keyboard_task(void) action_exec(TICK); MATRIX_LOOP_END: + #ifdef MOUSEKEY_ENABLE // mousekey repeat & acceleration mousekey_task(); #endif + +#ifdef PS2_MOUSE_ENABLE + if (ps2_mouse_read() == 0) { + ps2_mouse_usb_send(); + } +#endif + // update LED if (led_status != host_keyboard_leds()) { led_status = host_keyboard_leds(); diff --git a/protocol.mk b/protocol.mk index 1442c520..0d5f06c7 100644 --- a/protocol.mk +++ b/protocol.mk @@ -1,2 +1,27 @@ +PROTOCOL_DIR = protocol + + +ifdef PS2_MOUSE_ENABLE + SRC += $(PROTOCOL_DIR)/ps2_mouse.c + OPT_DEFS += -DPS2_MOUSE_ENABLE + OPT_DEFS += -DMOUSE_ENABLE +endif + +ifdef PS2_USE_BUSYWAIT + SRC += protocol/ps2.c + OPT_DEFS += -DPS2_USE_BUSYWAIT +endif + +ifdef PS2_USE_INT + SRC += protocol/ps2.c + OPT_DEFS += -DPS2_USE_INT +endif + +ifdef PS2_USE_USART + SRC += protocol/ps2_usart.c + OPT_DEFS += -DPS2_USE_USART +endif + + # Search Path VPATH += $(TOP_DIR)/protocol diff --git a/protocol/pjrc.mk b/protocol/pjrc.mk index 27f908b1..5a446138 100644 --- a/protocol/pjrc.mk +++ b/protocol/pjrc.mk @@ -7,7 +7,11 @@ SRC += $(PJRC_DIR)/main.c \ $(PJRC_DIR)/usb.c # Option modules -ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE) +ifdef MOUSEKEY_ENABLE + SRC += $(PJRC_DIR)/usb_mouse.c +endif + +ifdef PS2_MOUSE_ENABLE SRC += $(PJRC_DIR)/usb_mouse.c endif diff --git a/protocol/ps2_mouse.c b/protocol/ps2_mouse.c index f796b2b4..701d9721 100644 --- a/protocol/ps2_mouse.c +++ b/protocol/ps2_mouse.c @@ -1,5 +1,5 @@ /* -Copyright 2011 Jun Wako +Copyright 2011,2013 Jun Wako This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -32,27 +32,7 @@ along with this program. If not, see . # define phex16(h) #endif -// disable when errors occur 255 times. -#define ERROR_RETURN() do { \ - if (ps2_error) { \ - if (ps2_mouse_error_count < 255) { \ - ps2_mouse_error_count++; \ - } else { \ - ps2_mouse_error_count = 0; \ - ps2_mouse_enable = false; \ - } \ - return ps2_error; \ - } \ -} while (0) - -/* -TODO ----- -- Stream mode -- Tracpoint command support: needed -- Middle button + move = Wheel traslation -*/ bool ps2_mouse_enable = true; uint8_t ps2_mouse_x = 0; uint8_t ps2_mouse_y = 0; @@ -69,85 +49,50 @@ uint8_t ps2_mouse_init(void) { ps2_host_init(); - // Reset + // Not reliable: sometime fail to initialize mouse + + // send Reset + _delay_ms(1000); // wait for powering up rcv = ps2_host_send(0xFF); - print("ps2_mouse_init: send 0xFF: "); - phex(ps2_error); print("\n"); - ERROR_RETURN(); - - // ACK - rcv = ps2_host_recv(); - print("ps2_mouse_init: read ACK: "); + print("ps2_mouse_init: send Reset: "); phex(rcv); phex(ps2_error); print("\n"); - ERROR_RETURN(); - // BAT takes some time - _delay_ms(100); + // read completion code of BAT + //_delay_ms(1000); // wait for Basic Assurance Test rcv = ps2_host_recv(); print("ps2_mouse_init: read BAT: "); phex(rcv); phex(ps2_error); print("\n"); - ERROR_RETURN(); - // Device ID + // read Device ID rcv = ps2_host_recv(); print("ps2_mouse_init: read DevID: "); phex(rcv); phex(ps2_error); print("\n"); - ERROR_RETURN(); - // Enable data reporting - ps2_host_send(0xF4); + // send Enable Data Reporting + rcv = ps2_host_send(0xF4); print("ps2_mouse_init: send 0xF4: "); - phex(ps2_error); print("\n"); - ERROR_RETURN(); - - // ACK - rcv = ps2_host_recv(); - print("ps2_mouse_init: read ACK: "); phex(rcv); phex(ps2_error); print("\n"); - ERROR_RETURN(); - // Set Remote mode - ps2_host_send(0xF0); + // send Set Remote mode + rcv = ps2_host_send(0xF0); print("ps2_mouse_init: send 0xF0: "); - phex(ps2_error); print("\n"); - ERROR_RETURN(); - - // ACK - rcv = ps2_host_recv(); - print("ps2_mouse_init: read ACK: "); phex(rcv); phex(ps2_error); print("\n"); - ERROR_RETURN(); return 0; } -/* -Data format: - bit: 7 6 5 4 3 2 1 0 ------------------------------------------------------------------------ -0 btn: Yovflw Xovflw Ysign Xsign 1 Middle Right Left -1 x: X movement(0-255) -2 y: Y movement(0-255) -*/ uint8_t ps2_mouse_read(void) { uint8_t rcv; if (!ps2_mouse_enable) return 1; - ps2_host_send(0xEB); - ERROR_RETURN(); - - rcv=ps2_host_recv(); - ERROR_RETURN(); + rcv = ps2_host_send(0xEB); if(rcv==0xFA) { - ps2_mouse_btn = ps2_host_recv(); - ERROR_RETURN(); - ps2_mouse_x = ps2_host_recv(); - ERROR_RETURN(); - ps2_mouse_y = ps2_host_recv(); - ERROR_RETURN(); + ps2_mouse_btn = ps2_host_recv_response(); + ps2_mouse_x = ps2_host_recv_response(); + ps2_mouse_y = ps2_host_recv_response(); } return 0; } @@ -216,3 +161,36 @@ void ps2_mouse_print(void) phex(ps2_mouse_x); print(" "); phex(ps2_mouse_y); print("\n"); } + + +/* PS/2 Mouse Synopsis + * http://www.computer-engineering.org/ps2mouse/ + * + * Command: + * 0xFF: Reset + * 0xF6: Set Defaults Sampling; rate=100, resolution=4cnt/mm, scaling=1:1, reporting=disabled + * 0xF5: Disable Data Reporting + * 0xF4: Enable Data Reporting + * 0xF3: Set Sample Rate + * 0xF2: Get Device ID + * 0xF0: Set Remote Mode + * 0xEB: Read Data + * 0xEA: Set Stream Mode + * 0xE9: Status Request + * 0xE8: Set Resolution + * 0xE7: Set Scaling 2:1 + * 0xE6: Set Scaling 1:1 + * + * Mode: + * Stream Mode: devices sends the data when it changs its state + * Remote Mode: host polls the data periodically + * + * This code uses Remote Mode and polls the data with Read Data(0xEB). + * + * Data format: + * byte|7 6 5 4 3 2 1 0 + * ----+-------------------------------------------------------------- + * 0|Yovflw Xovflw Ysign Xsign 1 Middle Right Left + * 1| X movement(0-255) + * 2| Y movement(0-255) + */ From 94823030f00e9293ffc7ae4bec9611c8224d3532 Mon Sep 17 00:00:00 2001 From: tmk Date: Fri, 8 Nov 2013 04:25:22 +0900 Subject: [PATCH 09/76] Add cli() to protoect ADB critical timing part --- protocol/adb.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/protocol/adb.c b/protocol/adb.c index 750f4b96..a4783f36 100644 --- a/protocol/adb.c +++ b/protocol/adb.c @@ -41,7 +41,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include "adb.h" -#include "debug.h" // GCC doesn't inline functions normally @@ -125,16 +124,15 @@ bool adb_host_psw(void) uint16_t adb_host_kbd_recv(void) { uint16_t data = 0; + cli(); attention(); send_byte(0x2C); // Addr:Keyboard(0010), Cmd:Talk(11), Register0(00) place_bit0(); // Stopbit(0) if (!wait_data_lo(500)) { // Tlt/Stop to Start(140-260us) + sei(); return 0; // No data to send } - // ad hoc fix: without block inerrupt read wrong bit occasionally and get keys stuck - // TODO: is this needed anymore with improved timing? - //cli(); uint8_t n = 17; // start bit + 16 data bits do { uint8_t lo = (uint8_t) wait_data_hi(130); @@ -153,10 +151,8 @@ uint16_t adb_host_kbd_recv(void) data |= 1; } else if (n == 17) { - // Service Request - dprintf("Startbit ERROR\n"); sei(); - return -2; + return -20; } } while ( --n ); @@ -164,21 +160,20 @@ uint16_t adb_host_kbd_recv(void) // Stop bit can't be checked normally since it could have service request lenghtening // and its high state never goes low. if (!wait_data_hi(351) || wait_data_lo(91)) { - dprintf("Stopbit ERROR\n"); sei(); - return -3; + return -21; } sei(); return data; error: - dprintf("Bit ERROR\n"); sei(); - return -4; + return -n; } void adb_host_listen(uint8_t cmd, uint8_t data_h, uint8_t data_l) { + cli(); attention(); send_byte(cmd); place_bit0(); // Stopbit(0) @@ -187,6 +182,7 @@ void adb_host_listen(uint8_t cmd, uint8_t data_h, uint8_t data_l) send_byte(data_h); send_byte(data_l); place_bit0(); // Stopbit(0); + sei(); } // send state of LEDs From 84b9ce7125d6a2a376419694ac461214333b12bc Mon Sep 17 00:00:00 2001 From: tmk Date: Fri, 8 Nov 2013 04:27:25 +0900 Subject: [PATCH 10/76] Fix ADB led_set(); remove delay - the 100ms delay causes keystroke drop; this is observable with pressing Numlock key on AEK repeatedly - without the delay LED sync problem doesn't occur now --- converter/adb_usb/led.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/converter/adb_usb/led.c b/converter/adb_usb/led.c index 1e7911f9..3ee64a8e 100644 --- a/converter/adb_usb/led.c +++ b/converter/adb_usb/led.c @@ -23,7 +23,5 @@ along with this program. If not, see . void led_set(uint8_t usb_led) { - // need a wait to send command without miss - _delay_ms(100); adb_host_kbd_led(~usb_led); } From c531a185a48a2084c20cc17c40e8274bc27fd734 Mon Sep 17 00:00:00 2001 From: tmk Date: Fri, 8 Nov 2013 04:33:13 +0900 Subject: [PATCH 11/76] Disable BOOTMAGIC and fix debug prints of adb_usb --- converter/adb_usb/Makefile | 4 ++-- converter/adb_usb/matrix.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/converter/adb_usb/Makefile b/converter/adb_usb/Makefile index 372ef6c0..21141674 100644 --- a/converter/adb_usb/Makefile +++ b/converter/adb_usb/Makefile @@ -94,7 +94,7 @@ ARCH = AVR8 F_USB = $(F_CPU) # Interrupt driven control endpoint task(+60) -#OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT +OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT # Boot Section Size in *bytes* @@ -109,7 +109,7 @@ OPT_DEFS += -DBOOTLOADER_SIZE=4096 # Build Options # comment out to disable the options. # -BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +#BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) MOUSEKEY_ENABLE = yes # Mouse keys(+4700) EXTRAKEY_ENABLE = yes # Audio control and System control(+450) CONSOLE_ENABLE = yes # Console for debug(+400) diff --git a/converter/adb_usb/matrix.c b/converter/adb_usb/matrix.c index 54be2b0f..d1b67d38 100644 --- a/converter/adb_usb/matrix.c +++ b/converter/adb_usb/matrix.c @@ -79,9 +79,9 @@ void matrix_init(void) for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; debug_enable = true; - debug_matrix = true; - debug_keyboard = true; - debug_mouse = true; + //debug_matrix = true; + //debug_keyboard = true; + //debug_mouse = true; print("debug enabled.\n"); return; } @@ -108,7 +108,7 @@ uint8_t matrix_scan(void) } else if (codes == 0xFFFF) { // power key release register_key(0xFF); } else if (key0 == 0xFF) { // error - xprintf("adb_host_kbd_recv: ERROR(%02X)\n", codes); + xprintf("adb_host_kbd_recv: ERROR(%d)\n", codes); return key1; } else { register_key(key0); From 821578293c79c5612f9b77e447295f2947fd6c3d Mon Sep 17 00:00:00 2001 From: tmk Date: Fri, 8 Nov 2013 05:19:37 +0900 Subject: [PATCH 12/76] Remove tentative files from blargg --- converter/adb_usb/Makefile.blargg | 131 ------------------ converter/adb_usb/adb_blargg.c | 216 ------------------------------ converter/adb_usb/adb_blargg.h | 38 ------ 3 files changed, 385 deletions(-) delete mode 100644 converter/adb_usb/Makefile.blargg delete mode 100644 converter/adb_usb/adb_blargg.c delete mode 100644 converter/adb_usb/adb_blargg.h diff --git a/converter/adb_usb/Makefile.blargg b/converter/adb_usb/Makefile.blargg deleted file mode 100644 index edce82d6..00000000 --- a/converter/adb_usb/Makefile.blargg +++ /dev/null @@ -1,131 +0,0 @@ -#---------------------------------------------------------------------------- -# On command line: -# -# make all = Make software. -# -# make clean = Clean out built project files. -# -# make coff = Convert ELF to AVR COFF. -# -# make extcoff = Convert ELF to AVR Extended COFF. -# -# make program = Download the hex file to the device. -# Please customize your programmer settings(PROGRAM_CMD) -# -# make teensy = Download the hex file to the device, using teensy_loader_cli. -# (must have teensy_loader_cli installed). -# -# make dfu = Download the hex file to the device, using dfu-programmer (must -# have dfu-programmer installed). -# -# make flip = Download the hex file to the device, using Atmel FLIP (must -# have Atmel FLIP installed). -# -# make dfu-ee = Download the eeprom file to the device, using dfu-programmer -# (must have dfu-programmer installed). -# -# make flip-ee = Download the eeprom file to the device, using Atmel FLIP -# (must have Atmel FLIP installed). -# -# make debug = Start either simulavr or avarice as specified for debugging, -# with avr-gdb or avr-insight as the front end for debugging. -# -# make filename.s = Just compile filename.c into the assembler code only. -# -# make filename.i = Create a preprocessed source file for use in submitting -# bug reports to the GCC project. -# -# To rebuild project do "make clean" then "make all". -#---------------------------------------------------------------------------- - -# Target file name (without extension). -TARGET = adb_usb_blargg - -# Directory common source filess exist -TOP_DIR = ../.. - -# Directory keyboard dependent files exist -TARGET_DIR = . - -# project specific files -SRC = keymap.c \ - matrix.c \ - led.c \ - adb_blargg.c - -CONFIG_H = config.h - - -# MCU name -#MCU = at90usb1287 -MCU = atmega32u4 - -# Processor frequency. -# This will define a symbol, F_CPU, in all source code files equal to the -# processor frequency in Hz. You can then use this symbol in your source code to -# calculate timings. Do NOT tack on a 'UL' at the end, this will be done -# automatically to create a 32-bit value in your source code. -# -# This will be an integer division of F_USB below, as it is sourced by -# F_USB after it has run through any CPU prescalers. Note that this value -# does not *change* the processor frequency - it should merely be updated to -# reflect the processor speed set externally so that the code can use accurate -# software delays. -F_CPU = 16000000 - - -# -# LUFA specific -# -# Target architecture (see library "Board Types" documentation). -ARCH = AVR8 - -# Input clock frequency. -# This will define a symbol, F_USB, in all source code files equal to the -# input clock frequency (before any prescaling is performed) in Hz. This value may -# differ from F_CPU if prescaling is used on the latter, and is required as the -# raw input clock is fed directly to the PLL sections of the AVR for high speed -# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' -# at the end, this will be done automatically to create a 32-bit value in your -# source code. -# -# If no clock division is performed on the input clock inside the AVR (via the -# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. -F_USB = $(F_CPU) - -# Interrupt driven control endpoint task(+60) -#OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT - - -# Boot Section Size in *bytes* -# Teensy halfKay 512 -# Teensy++ halfKay 1024 -# Atmel DFU loader 4096 -# LUFA bootloader 4096 -# USBaspLoader 2048 -OPT_DEFS += -DBOOTLOADER_SIZE=4096 - - -# Build Options -# comment out to disable the options. -# -BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) -MOUSEKEY_ENABLE = yes # Mouse keys(+4700) -EXTRAKEY_ENABLE = yes # Audio control and System control(+450) -CONSOLE_ENABLE = yes # Console for debug(+400) -COMMAND_ENABLE = yes # Commands for debug and configuration -#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend -#NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA - - -# Optimize size but this may cause error "relocation truncated to fit" -#EXTRALDFLAGS = -Wl,--relax - -# Search Path -VPATH += $(TARGET_DIR) -VPATH += $(TOP_DIR) - -include $(TOP_DIR)/protocol/lufa.mk -include $(TOP_DIR)/protocol.mk -include $(TOP_DIR)/common.mk -include $(TOP_DIR)/rules.mk diff --git a/converter/adb_usb/adb_blargg.c b/converter/adb_usb/adb_blargg.c deleted file mode 100644 index 963758c5..00000000 --- a/converter/adb_usb/adb_blargg.c +++ /dev/null @@ -1,216 +0,0 @@ -// Bit-banged implementation without any use of interrupts. -// Data pin must have external 1K pull-up resistor. -// Operates data pin as open-collector output. - -#include "adb_blargg.h" - -#ifdef HAVE_CONFIG_H - #include "config.h" -#endif - -#include -#include -#include - -// Copyright 2011 Jun WAKO -// Copyright 2013 Shay Green -// See bottom of file for license - -typedef uint8_t byte; - -// Make loop iteration take us total, including cyc overhead of loop logic -#define delay_loop_usec( us, cyc ) \ - __builtin_avr_delay_cycles( (unsigned long) (F_CPU / 1e6 * (us) + 0.5) - (cyc) ) - -#if !defined(ADB_PORT) || \ - !defined(ADB_PIN) || \ - !defined(ADB_DDR) || \ - !defined(ADB_DATA_BIT) - #error -#endif - -enum { data_mask = 1< -#include - -// Sets up ADB bus. Doesn't send anything to keyboard. -void adb_host_init( void ); - -// Receives key press event from keyboard. -// 0xKKFF: one key changed state -// 0xKKKK: two keys changed state -enum { adb_host_nothing = 0 }; // no keys changed state -enum { adb_host_error = 0xFFFE }; // receive error -uint16_t adb_host_kbd_recv( void ); - -// Current state of keyboard modifiers and a few other keys -// Returns adb_host_nothing if keyboard didn't respond. -// Returns adb_host_error if error receiving. -uint16_t adb_host_kbd_modifiers( void ); - -// Sends command and two bytes of data to keyboard -void adb_host_listen( uint8_t cmd, uint8_t data_h, uint8_t data_l ); - -// Sets keyboard LEDs. Note that bits are inverted here, so 1 means off, 0 means on. -void adb_host_kbd_led( uint8_t led ); - -// State of power switch (false = pressed), or true if unsupported -bool adb_host_psw( void ); - - -// Legacy support -#define ADB_POWER 0x7F -#define ADB_CAPS 0x39 - -#endif From 9d40be19908394e44cdda5d3c73d21e8d3795e72 Mon Sep 17 00:00:00 2001 From: tmk Date: Tue, 19 Nov 2013 03:20:25 +0900 Subject: [PATCH 13/76] Wait for USB starting up to make debug print available --- common/action_util.h | 1 + protocol/lufa/lufa.c | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/common/action_util.h b/common/action_util.h index 939bc2b6..f9d3161a 100644 --- a/common/action_util.h +++ b/common/action_util.h @@ -18,6 +18,7 @@ along with this program. If not, see . #define ACTION_UTIL_H #include +#include "report.h" extern report_keyboard_t *keyboard_report; diff --git a/protocol/lufa/lufa.c b/protocol/lufa/lufa.c index a230d5ba..04e8e78f 100644 --- a/protocol/lufa/lufa.c +++ b/protocol/lufa/lufa.c @@ -539,11 +539,18 @@ int main(void) { SetupHardware(); sei(); + + /* wait for USB startup & debug output */ + while (USB_DeviceState != DEVICE_STATE_Configured) { #if defined(INTERRUPT_CONTROL_ENDPOINT) - while (USB_DeviceState != DEVICE_STATE_Configured) ; + ; +#else + USB_USBTask(); #endif + } print("USB configured.\n"); + /* init modules */ keyboard_init(); host_set_driver(&lufa_driver); #ifdef SLEEP_LED_ENABLE From 44d2d5f5fda3fbdf73e311067807026bb53798c0 Mon Sep 17 00:00:00 2001 From: tmk Date: Tue, 19 Nov 2013 03:25:31 +0900 Subject: [PATCH 14/76] Fix delay of PS/2 mouse init --- protocol/ps2_mouse.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/protocol/ps2_mouse.c b/protocol/ps2_mouse.c index 701d9721..5e0b3657 100644 --- a/protocol/ps2_mouse.c +++ b/protocol/ps2_mouse.c @@ -49,16 +49,14 @@ uint8_t ps2_mouse_init(void) { ps2_host_init(); - // Not reliable: sometime fail to initialize mouse + _delay_ms(1000); // wait for powering up // send Reset - _delay_ms(1000); // wait for powering up rcv = ps2_host_send(0xFF); print("ps2_mouse_init: send Reset: "); phex(rcv); phex(ps2_error); print("\n"); // read completion code of BAT - //_delay_ms(1000); // wait for Basic Assurance Test rcv = ps2_host_recv(); print("ps2_mouse_init: read BAT: "); phex(rcv); phex(ps2_error); print("\n"); From 755e4d8b00a4f9be0c50c2b005d063b94c528f8c Mon Sep 17 00:00:00 2001 From: tmk Date: Tue, 19 Nov 2013 03:39:15 +0900 Subject: [PATCH 15/76] Add PS/2 mouse configure to onekey --- keyboard/onekey/Makefile.lufa | 31 +++++-------- keyboard/onekey/Makefile.pjrc | 31 +++++-------- keyboard/onekey/config.h | 85 +++++++++++++++++++++++++++++++++++ keyboard/onekey/matrix.c | 1 + 4 files changed, 109 insertions(+), 39 deletions(-) diff --git a/keyboard/onekey/Makefile.lufa b/keyboard/onekey/Makefile.lufa index 03cfd83a..2a97aa63 100644 --- a/keyboard/onekey/Makefile.lufa +++ b/keyboard/onekey/Makefile.lufa @@ -108,34 +108,25 @@ OPT_DEFS += -DBOOTLOADER_SIZE=4096 # Build Options # comment out to disable the options. # -BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) -MOUSEKEY_ENABLE = yes # Mouse keys(+4700) -EXTRAKEY_ENABLE = yes # Audio control and System control(+450) +#BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +#MOUSEKEY_ENABLE = yes # Mouse keys(+4700) +#EXTRAKEY_ENABLE = yes # Audio control and System control(+450) CONSOLE_ENABLE = yes # Console for debug(+400) -COMMAND_ENABLE = yes # Commands for debug and configuration -SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend +#COMMAND_ENABLE = yes # Commands for debug and configuration +#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend #NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA +PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support +PS2_USE_BUSYWAIT = yes # uses primitive reference code +#PS2_USE_INT = yes # uses external interrupt for falling edge of PS/2 clock pin +#PS2_USE_USART = yes # uses hardware USART engine for PS/2 signal receive(recomened) -# Optimize size but this may cause error "relocation truncated to fit" -#EXTRALDFLAGS = -Wl,--relax # Search Path VPATH += $(TARGET_DIR) VPATH += $(TOP_DIR) -include $(TOP_DIR)/protocol/lufa.mk include $(TOP_DIR)/common.mk +include $(TOP_DIR)/protocol.mk +include $(TOP_DIR)/protocol/lufa.mk include $(TOP_DIR)/rules.mk - -plain: OPT_DEFS += -DKEYMAP_PLAIN -plain: all - -poker: OPT_DEFS += -DKEYMAP_POKER -poker: all - -poker_set: OPT_DEFS += -DKEYMAP_POKER_SET -poker_set: all - -poker_bit: OPT_DEFS += -DKEYMAP_POKER_BIT -poker_bit: all diff --git a/keyboard/onekey/Makefile.pjrc b/keyboard/onekey/Makefile.pjrc index 194a2b97..0f0f7097 100644 --- a/keyboard/onekey/Makefile.pjrc +++ b/keyboard/onekey/Makefile.pjrc @@ -79,32 +79,25 @@ OPT_DEFS += -DBOOTLOADER_SIZE=4096 # Build Options # comment out to disable the options. # -BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) -MOUSEKEY_ENABLE = yes # Mouse keys(+5000) -EXTRAKEY_ENABLE = yes # Audio control and System control(+600) +#BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +#MOUSEKEY_ENABLE = yes # Mouse keys(+5000) +#EXTRAKEY_ENABLE = yes # Audio control and System control(+600) CONSOLE_ENABLE = yes # Console for debug -COMMAND_ENABLE = yes # Commands for debug and configuration -SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend -NKRO_ENABLE = yes # USB Nkey Rollover(+500) +#COMMAND_ENABLE = yes # Commands for debug and configuration +#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend +#NKRO_ENABLE = yes # USB Nkey Rollover(+500) + #PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support +#PS2_USE_BUSYWAIT = yes # uses primitive reference code +#PS2_USE_INT = yes # uses external interrupt for falling edge of PS/2 clock pin +#PS2_USE_USART = yes # uses hardware USART engine for PS/2 signal receive(recomened) # Search Path VPATH += $(TARGET_DIR) VPATH += $(TOP_DIR) -include $(TOP_DIR)/protocol/pjrc.mk include $(TOP_DIR)/common.mk +include $(TOP_DIR)/protocol.mk +include $(TOP_DIR)/protocol/pjrc.mk include $(TOP_DIR)/rules.mk - -plain: OPT_DEFS += -DKEYMAP_PLAIN -plain: all - -poker: OPT_DEFS += -DKEYMAP_POKER -poker: all - -poker_set: OPT_DEFS += -DKEYMAP_POKER_SET -poker_set: all - -poker_bit: OPT_DEFS += -DKEYMAP_POKER_BIT -poker_bit: all diff --git a/keyboard/onekey/config.h b/keyboard/onekey/config.h index c5bc64de..8403c9b6 100644 --- a/keyboard/onekey/config.h +++ b/keyboard/onekey/config.h @@ -67,4 +67,89 @@ along with this program. If not, see . //#define NO_ACTION_MACRO //#define NO_ACTION_FUNCTION + +/* PS/2 mouse */ +#define PS2_MOUSE_DEBUG +#ifdef PS2_USE_BUSYWAIT +# define PS2_CLOCK_PORT PORTD +# define PS2_CLOCK_PIN PIND +# define PS2_CLOCK_DDR DDRD +# define PS2_CLOCK_BIT 1 +# define PS2_DATA_PORT PORTD +# define PS2_DATA_PIN PIND +# define PS2_DATA_DDR DDRD +# define PS2_DATA_BIT 2 +#endif + + +#ifdef PS2_USE_INT +/* uses INT1 for clock line(ATMega32U4) */ +#define PS2_CLOCK_PORT PORTD +#define PS2_CLOCK_PIN PIND +#define PS2_CLOCK_DDR DDRD +#define PS2_CLOCK_BIT 1 +#define PS2_DATA_PORT PORTD +#define PS2_DATA_PIN PIND +#define PS2_DATA_DDR DDRD +#define PS2_DATA_BIT 2 + +#define PS2_INT_INIT() do { \ + EICRA |= ((1< Date: Wed, 20 Nov 2013 11:19:59 +0900 Subject: [PATCH 16/76] Fix to build ps2_mouse with both LUFA and PJRC - change API of ps2_mouse; ps2_mouse_task() - remove mouse_report from host.c --- common/action.c | 6 -- common/action.h | 1 - common/host.c | 8 -- common/host.h | 6 -- common/keyboard.c | 4 +- common/mousekey.c | 1 + protocol/ps2_mouse.c | 198 +++++++++++++++++++++++++------------------ protocol/ps2_mouse.h | 21 ++--- 8 files changed, 128 insertions(+), 117 deletions(-) diff --git a/common/action.c b/common/action.c index f7ae85b9..485abf81 100644 --- a/common/action.c +++ b/common/action.c @@ -485,12 +485,6 @@ void clear_keyboard_but_mods(void) #endif } -bool sending_anykey(void) -{ - return (has_anykey() || host_mouse_in_use() || - host_last_sysytem_report() || host_last_consumer_report()); -} - bool is_tap_key(key_t key) { action_t action = layer_switch_get_action(key); diff --git a/common/action.h b/common/action.h index d57f4a86..077711c2 100644 --- a/common/action.h +++ b/common/action.h @@ -64,7 +64,6 @@ void unregister_mods(uint8_t mods); //void set_mods(uint8_t mods); void clear_keyboard(void); void clear_keyboard_but_mods(void); -bool sending_anykey(void); void layer_switch(uint8_t new_layer); bool is_tap_key(key_t key); diff --git a/common/host.c b/common/host.c index 0703dba0..1eafef75 100644 --- a/common/host.c +++ b/common/host.c @@ -27,9 +27,6 @@ along with this program. If not, see . bool keyboard_nkro = false; #endif -report_mouse_t mouse_report = {}; - - static host_driver_t *driver; static uint16_t last_system_report = 0; static uint16_t last_consumer_report = 0; @@ -89,11 +86,6 @@ void host_consumer_send(uint16_t report) (*driver->send_consumer)(report); } -uint8_t host_mouse_in_use(void) -{ - return (mouse_report.buttons | mouse_report.x | mouse_report.y | mouse_report.v | mouse_report.h); -} - uint16_t host_last_sysytem_report(void) { return last_system_report; diff --git a/common/host.h b/common/host.h index c1a0fbac..8ff26298 100644 --- a/common/host.h +++ b/common/host.h @@ -32,9 +32,6 @@ extern "C" { extern bool keyboard_nkro; #endif -/* report */ -extern report_mouse_t mouse_report; - /* host driver */ void host_set_driver(host_driver_t *driver); @@ -47,9 +44,6 @@ void host_mouse_send(report_mouse_t *report); void host_system_send(uint16_t data); void host_consumer_send(uint16_t data); -/* mouse report utils */ -uint8_t host_mouse_in_use(void); - uint16_t host_last_sysytem_report(void); uint16_t host_last_consumer_report(void); diff --git a/common/keyboard.c b/common/keyboard.c index 63a58b21..2b66f20a 100644 --- a/common/keyboard.c +++ b/common/keyboard.c @@ -123,9 +123,7 @@ MATRIX_LOOP_END: #endif #ifdef PS2_MOUSE_ENABLE - if (ps2_mouse_read() == 0) { - ps2_mouse_usb_send(); - } + ps2_mouse_task(); #endif // update LED diff --git a/common/mousekey.c b/common/mousekey.c index 3068fc5e..017be941 100644 --- a/common/mousekey.c +++ b/common/mousekey.c @@ -26,6 +26,7 @@ along with this program. If not, see . +static report_mouse_t mouse_report = {}; static uint8_t mousekey_repeat = 0; static uint8_t mousekey_accel = 0; diff --git a/protocol/ps2_mouse.c b/protocol/ps2_mouse.c index 5e0b3657..ff730196 100644 --- a/protocol/ps2_mouse.c +++ b/protocol/ps2_mouse.c @@ -20,7 +20,8 @@ along with this program. If not, see . #include #include "ps2.h" #include "ps2_mouse.h" -#include "usb_mouse.h" +#include "report.h" +#include "host.h" #define PS2_MOUSE_DEBUG #ifdef PS2_MOUSE_DEBUG @@ -33,20 +34,17 @@ along with this program. If not, see . #endif -bool ps2_mouse_enable = true; -uint8_t ps2_mouse_x = 0; -uint8_t ps2_mouse_y = 0; -uint8_t ps2_mouse_btn = 0; -uint8_t ps2_mouse_error_count = 0; - -static uint8_t ps2_mouse_btn_prev = 0; +static report_mouse_t mouse_report = {}; +static void ps2_mouse_print_raw_data(void); +static void ps2_mouse_print_usb_data(void); + + +/* supports only 3 button mouse at this time */ uint8_t ps2_mouse_init(void) { uint8_t rcv; - if (!ps2_mouse_enable) return 1; - ps2_host_init(); _delay_ms(1000); // wait for powering up @@ -79,85 +77,119 @@ uint8_t ps2_mouse_init(void) { return 0; } -uint8_t ps2_mouse_read(void) -{ - uint8_t rcv; - - if (!ps2_mouse_enable) return 1; - - rcv = ps2_host_send(0xEB); - - if(rcv==0xFA) { - ps2_mouse_btn = ps2_host_recv_response(); - ps2_mouse_x = ps2_host_recv_response(); - ps2_mouse_y = ps2_host_recv_response(); - } - return 0; -} - -bool ps2_mouse_changed(void) -{ - return (ps2_mouse_x || ps2_mouse_y || (ps2_mouse_btn & PS2_MOUSE_BTN_MASK) != ps2_mouse_btn_prev); -} - +/* scroll support + * TODO: should be build option + */ #define PS2_MOUSE_SCROLL_BUTTON 0x04 -void ps2_mouse_usb_send(void) +#define X_IS_NEG (mouse_report.buttons & (1< USB(-127/127) - if (ps2_mouse_btn & (1< 128 ? (int8_t)ps2_mouse_x : -127; - else - x = ps2_mouse_x < 128 ? (int8_t)ps2_mouse_x : 127; - - if (ps2_mouse_btn & (1< 128 ? (int8_t)ps2_mouse_y : -127; - else - y = ps2_mouse_y < 128 ? (int8_t)ps2_mouse_y : 127; - - // Y is needed to reverse - y = -y; - - if (ps2_mouse_btn & PS2_MOUSE_SCROLL_BUTTON) { - // scroll - if (x > 0 || x < 0) h = (x > 64 ? 64 : (x < -64 ? -64 :x)); - if (y > 0 || y < 0) v = (y > 64 ? 64 : (y < -64 ? -64 :y)); - if (h || v) { - scrolled = true; - usb_mouse_send(0,0, -v/16, h/16, 0); - _delay_ms(100); - } - } else if (!scrolled && (ps2_mouse_btn_prev & PS2_MOUSE_SCROLL_BUTTON)) { - usb_mouse_send(0,0,0,0, PS2_MOUSE_SCROLL_BUTTON); - _delay_ms(100); - usb_mouse_send(0,0,0,0, 0); - } else { - scrolled = false; - usb_mouse_send(x, y, 0, 0, ps2_mouse_btn & PS2_MOUSE_BTN_MASK); - } - - ps2_mouse_btn_prev = (ps2_mouse_btn & PS2_MOUSE_BTN_MASK); - ps2_mouse_print(); + /* receives packet from mouse */ + uint8_t rcv; + rcv = ps2_host_send(PS2_MOUSE_READ_DATA); + if (rcv == PS2_ACK) { + mouse_report.buttons = ps2_host_recv_response(); + mouse_report.x = ps2_host_recv_response(); + mouse_report.y = ps2_host_recv_response(); + } else { + if (!debug_mouse) print("ps2_mouse: fail to get mouse packet\n"); + return; } - ps2_mouse_x = 0; - ps2_mouse_y = 0; - ps2_mouse_btn = 0; + + /* if mouse moves or buttons state changes */ + if (mouse_report.x || mouse_report.y || + ((mouse_report.buttons ^ buttons_prev) & PS2_MOUSE_BTN_MASK)) { + + ps2_mouse_print_raw_data(); + + buttons_prev = mouse_report.buttons; + + // PS/2 mouse data is '9-bit integer'(-256 to 255) which is comprised of sign-bit and 8-bit value. + // bit: 8 7 ... 0 + // sign \8-bit/ + // + // Meanwhile USB HID mouse indicates 8bit data(-127 to 127), note that -128 is not used. + // + // This converts PS/2 data into HID value. Use only -127-127 out of PS/2 9-bit. + mouse_report.x = X_IS_NEG ? + ((!X_IS_OVF && -127 <= mouse_report.x && mouse_report.x <= -1) ? mouse_report.x : -127) : + ((!X_IS_OVF && 0 <= mouse_report.x && mouse_report.x <= 127) ? mouse_report.x : 127); + mouse_report.y = Y_IS_NEG ? + ((!Y_IS_OVF && -127 <= mouse_report.y && mouse_report.y <= -1) ? mouse_report.y : -127) : + ((!Y_IS_OVF && 0 <= mouse_report.y && mouse_report.y <= 127) ? mouse_report.y : 127); + + // remove sign and overflow flags + mouse_report.buttons &= PS2_MOUSE_BTN_MASK; + + // invert coordinate of y to conform to USB HID mouse + mouse_report.y = -mouse_report.y; + + + if ((mouse_report.buttons & PS2_MOUSE_SCROLL_BUTTON) == PS2_MOUSE_SCROLL_BUTTON) { + if (scroll_state == SCROLL_NONE) scroll_state = SCROLL_BTN; + + // doesn't send Scroll Button + mouse_report.buttons &= ~PS2_MOUSE_SCROLL_BUTTON; + + if (mouse_report.x || mouse_report.y) { + scroll_state = SCROLL_SENT; + + mouse_report.v = -mouse_report.y/2; + mouse_report.h = mouse_report.x/2; + mouse_report.x = 0; + mouse_report.y = 0; + host_mouse_send(&mouse_report); + } + } else if (scroll_state == SCROLL_BTN && + (mouse_report.buttons & PS2_MOUSE_SCROLL_BUTTON) == 0) { + scroll_state = SCROLL_NONE; + + // send Scroll Button(down and up at once) when not scrolled + mouse_report.buttons |= PS2_MOUSE_SCROLL_BUTTON; + host_mouse_send(&mouse_report); + _delay_ms(100); + mouse_report.buttons &= ~PS2_MOUSE_SCROLL_BUTTON; + host_mouse_send(&mouse_report); + } else { + scroll_state = SCROLL_NONE; + + host_mouse_send(&mouse_report); + } + ps2_mouse_print_usb_data(); + } + // clear report + mouse_report.x = 0; + mouse_report.y = 0; + mouse_report.v = 0; + mouse_report.h = 0; + mouse_report.buttons = 0; } -void ps2_mouse_print(void) +static void ps2_mouse_print_raw_data(void) { if (!debug_mouse) return; - print("ps2_mouse[btn|x y]: "); - phex(ps2_mouse_btn); print("|"); - phex(ps2_mouse_x); print(" "); - phex(ps2_mouse_y); print("\n"); + print("ps2_mouse raw [btn|x y]: ["); + phex(mouse_report.buttons); print("|"); + print_hex8((uint8_t)mouse_report.x); print(" "); + print_hex8((uint8_t)mouse_report.y); print("]\n"); +} + +static void ps2_mouse_print_usb_data(void) +{ + if (!debug_mouse) return; + print("ps2_mouse usb [btn|x y v h]: ["); + phex(mouse_report.buttons); print("|"); + print_hex8((uint8_t)mouse_report.x); print(" "); + print_hex8((uint8_t)mouse_report.y); print(" "); + print_hex8((uint8_t)mouse_report.v); print(" "); + print_hex8((uint8_t)mouse_report.h); print("]\n"); } @@ -189,6 +221,6 @@ void ps2_mouse_print(void) * byte|7 6 5 4 3 2 1 0 * ----+-------------------------------------------------------------- * 0|Yovflw Xovflw Ysign Xsign 1 Middle Right Left - * 1| X movement(0-255) - * 2| Y movement(0-255) + * 1| X movement + * 2| Y movement */ diff --git a/protocol/ps2_mouse.h b/protocol/ps2_mouse.h index 4529ce11..305a9bdb 100644 --- a/protocol/ps2_mouse.h +++ b/protocol/ps2_mouse.h @@ -20,6 +20,16 @@ along with this program. If not, see . #include +#define PS2_MOUSE_READ_DATA 0xEB + +/* + * Data format: + * byte|7 6 5 4 3 2 1 0 + * ----+-------------------------------------------------------------- + * 0|Yovflw Xovflw Ysign Xsign 1 Middle Right Left + * 1| X movement(0-255) + * 2| Y movement(0-255) + */ #define PS2_MOUSE_BTN_MASK 0x07 #define PS2_MOUSE_BTN_LEFT 0 #define PS2_MOUSE_BTN_RIGHT 1 @@ -29,16 +39,7 @@ along with this program. If not, see . #define PS2_MOUSE_X_OVFLW 6 #define PS2_MOUSE_Y_OVFLW 7 -bool ps2_mouse_enable; -extern uint8_t ps2_mouse_x; -extern uint8_t ps2_mouse_y; -extern uint8_t ps2_mouse_btn; -extern uint8_t ps2_mouse_error_count; - uint8_t ps2_mouse_init(void); -uint8_t ps2_mouse_read(void); -bool ps2_mouse_changed(void); -void ps2_mouse_usb_send(void); -void ps2_mouse_print(void); +void ps2_mouse_task(void); #endif From c6abcb6d893f6ef843ed98be3d45bd804cfe295a Mon Sep 17 00:00:00 2001 From: tmk Date: Wed, 20 Nov 2013 15:28:58 +0900 Subject: [PATCH 17/76] Add build options of ps2_mouse --- keyboard/onekey/config.h | 1 - protocol/ps2_mouse.c | 92 +++++++++++++++++++--------------------- protocol/ps2_mouse.h | 21 +++++++++ 3 files changed, 64 insertions(+), 50 deletions(-) diff --git a/keyboard/onekey/config.h b/keyboard/onekey/config.h index 8403c9b6..e99a6485 100644 --- a/keyboard/onekey/config.h +++ b/keyboard/onekey/config.h @@ -69,7 +69,6 @@ along with this program. If not, see . /* PS/2 mouse */ -#define PS2_MOUSE_DEBUG #ifdef PS2_USE_BUSYWAIT # define PS2_CLOCK_PORT PORTD # define PS2_CLOCK_PIN PIND diff --git a/protocol/ps2_mouse.c b/protocol/ps2_mouse.c index ff730196..ea629655 100644 --- a/protocol/ps2_mouse.c +++ b/protocol/ps2_mouse.c @@ -22,23 +22,15 @@ along with this program. If not, see . #include "ps2_mouse.h" #include "report.h" #include "host.h" - -#define PS2_MOUSE_DEBUG -#ifdef PS2_MOUSE_DEBUG -# include "print.h" -# include "debug.h" -#else -# define print(s) -# define phex(h) -# define phex16(h) -#endif +#include "timer.h" +#include "print.h" +#include "debug.h" static report_mouse_t mouse_report = {}; -static void ps2_mouse_print_raw_data(void); -static void ps2_mouse_print_usb_data(void); +static void print_usb_data(void); /* supports only 3 button mouse at this time */ @@ -77,10 +69,6 @@ uint8_t ps2_mouse_init(void) { return 0; } -/* scroll support - * TODO: should be build option - */ -#define PS2_MOUSE_SCROLL_BUTTON 0x04 #define X_IS_NEG (mouse_report.buttons & (1<. #define PS2_MOUSE_X_OVFLW 6 #define PS2_MOUSE_Y_OVFLW 7 + +/* + * Scroll by mouse move with pressing button + */ +/* mouse button to start scrolling; set 0 to disable scroll */ +#ifndef PS2_MOUSE_SCROLL_BTN_MASK +#define PS2_MOUSE_SCROLL_BTN_MASK (1< Date: Tue, 19 Nov 2013 15:29:09 -0800 Subject: [PATCH 18/76] Add tap toggle modifiers Including documentation. --- common/action.c | 11 +++++++++++ common/action_code.h | 3 +++ doc/keymap.md | 6 ++++++ 3 files changed, 20 insertions(+) diff --git a/common/action.c b/common/action.c index f7ae85b9..38ee12ab 100644 --- a/common/action.c +++ b/common/action.c @@ -128,6 +128,17 @@ void process_action(keyrecord_t *record) } break; #endif + case MODS_TAP_TOGGLE: + if (event.pressed) { + if (tap_count <= TAPPING_TOGGLE) { + register_mods(mods); + } + } else { + if (tap_count < TAPPING_TOGGLE) { + unregister_mods(mods); + } + } + break; default: if (event.pressed) { if (tap_count > 0) { diff --git a/common/action_code.h b/common/action_code.h index c153838f..bd3652e3 100644 --- a/common/action_code.h +++ b/common/action_code.h @@ -34,6 +34,7 @@ along with this program. If not, see . * * ACT_MODS_TAP(001r): * 001r|mods|0000 0000 Modifiers with OneShot + * 001r|mods|0000 0001 Modifiers with tap toggle * 001r|mods|0000 00xx (reserved) * 001r|mods| keycode Modifiers with Tap Key(Dual role) * @@ -205,12 +206,14 @@ enum mods_bit { }; enum mods_codes { MODS_ONESHOT = 0x00, + MODS_TAP_TOGGLE = 0x01, }; #define ACTION_KEY(key) ACTION(ACT_MODS, (key)) #define ACTION_MODS(mods) ACTION(ACT_MODS, (mods&0x1f)<<8 | 0) #define ACTION_MODS_KEY(mods, key) ACTION(ACT_MODS, (mods&0x1f)<<8 | (key)) #define ACTION_MODS_TAP_KEY(mods, key) ACTION(ACT_MODS_TAP, (mods&0x1f)<<8 | (key)) #define ACTION_MODS_ONESHOT(mods) ACTION(ACT_MODS_TAP, (mods&0x1f)<<8 | MODS_ONESHOT) +#define ACTION_MODS_TAP_TOGGLE(mods) ACTION(ACT_MODS_TAP, (mods&0x1f)<<8 | MODS_TAP_TOGGLE) /* diff --git a/doc/keymap.md b/doc/keymap.md index 11e80a9c..3a549de6 100644 --- a/doc/keymap.md +++ b/doc/keymap.md @@ -526,6 +526,12 @@ Say you want to type 'The', you have to push and hold Shift key before type 't' Oneshot effect is cancel unless following key is pressed down within `ONESHOT_TIMEOUT` of `config.h`. No timeout when it is `0` or not defined. +### 4.4 Tap Toggle Mods +Similar to layer tap toggle, this works as a momentary modifier when holding, but toggles on with several taps. A single tap will 'unstick' the modifier again. + + ACTION_MODS_TAP_TOGGLE(MOD_LSFT) + + ## 5. Legacy Keymap From 416a5b849e9d579b702b92680a4a188962e4c130 Mon Sep 17 00:00:00 2001 From: tmk Date: Thu, 21 Nov 2013 08:10:09 +0900 Subject: [PATCH 19/76] Fix interrupt version of ps2.c --- protocol/ps2.c | 53 +++++++++++++++++++++++++++++--------------- protocol/ps2_mouse.c | 9 ++------ 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/protocol/ps2.c b/protocol/ps2.c index 4c6c2fcb..e5873a9b 100644 --- a/protocol/ps2.c +++ b/protocol/ps2.c @@ -1,5 +1,5 @@ /* -Copyright 2010,2011 Jun WAKO +Copyright 2010,2011,2012,2013 Jun WAKO This software is licensed with a Modified BSD License. All of this is supposed to be Free Software, Open Source, DFSG-free, @@ -43,7 +43,9 @@ POSSIBILITY OF SUCH DAMAGE. #include "debug.h" +#ifndef PS2_USE_INT static uint8_t recv_data(void); +#endif static inline void clock_lo(void); static inline void clock_hi(void); static inline bool clock_in(void); @@ -143,6 +145,9 @@ uint8_t ps2_host_send(uint8_t data) WAIT(clock_hi, 50, 8); WAIT(data_hi, 50, 9); +#ifdef PS2_USE_INT + PS2_INT_ON(); +#endif res = ps2_host_recv_response(); ERROR: #ifdef PS2_USE_INT @@ -154,11 +159,15 @@ ERROR: return res; } +#ifndef PS2_USE_INT /* receive data when host want else inhibit communication */ uint8_t ps2_host_recv_response(void) { uint8_t data = 0; +#ifdef PS2_USE_INT + PS2_INT_OFF(); +#endif /* terminate a transmission if we have */ inhibit(); _delay_us(100); @@ -173,6 +182,7 @@ uint8_t ps2_host_recv_response(void) inhibit(); return data; } +#endif #ifndef PS2_USE_INT uint8_t ps2_host_recv(void) @@ -187,9 +197,6 @@ static uint8_t pbuf_head = 0; static uint8_t pbuf_tail = 0; static inline void pbuf_enqueue(uint8_t data) { - if (!data) - return; - uint8_t sreg = SREG; cli(); uint8_t next = (pbuf_head + 1) % PBUF_SIZE; @@ -215,6 +222,21 @@ static inline uint8_t pbuf_dequeue(void) return val; } +static inline bool pbuf_has_data(void) +{ + uint8_t sreg = SREG; + cli(); + bool has_data = (pbuf_head != pbuf_tail); + SREG = sreg; + return has_data; +} +static inline void pbuf_clear(void) +{ + uint8_t sreg = SREG; + cli(); + pbuf_head = pbuf_tail = 0; + SREG = sreg; +} /* get data received by interrupt */ uint8_t ps2_host_recv(void) @@ -229,13 +251,12 @@ uint8_t ps2_host_recv(void) return pbuf_dequeue(); } -#if 0 -#define DEBUGP_INIT() do { DDRC = 0xFF; } while (0) -#define DEBUGP(x) do { PORTC = x; } while (0) -#else -#define DEBUGP_INIT() -#define DEBUGP(x) -#endif +uint8_t ps2_host_recv_response(void) +{ + while (!pbuf_has_data()) ; + return pbuf_dequeue(); +} + ISR(PS2_INT_VECT) { static enum { @@ -256,7 +277,6 @@ ISR(PS2_INT_VECT) } state++; - DEBUGP(state); switch (state) { case START: if (data_in()) @@ -289,6 +309,7 @@ ISR(PS2_INT_VECT) if (!data_in()) goto ERROR; pbuf_enqueue(data); +//phex(data); goto DONE; break; default: @@ -296,7 +317,6 @@ ISR(PS2_INT_VECT) } goto RETURN; ERROR: - DEBUGP(0x0F); inhibit(); ps2_error = state; DONE: @@ -309,11 +329,6 @@ RETURN: #endif -static void ps2_reset(void) -{ - ps2_host_send(0xFF); -} - /* send LED state to keyboard */ void ps2_host_set_led(uint8_t led) { @@ -322,6 +337,7 @@ void ps2_host_set_led(uint8_t led) } +#ifndef PS2_USE_INT /* called after start bit comes */ static uint8_t recv_data(void) { @@ -361,6 +377,7 @@ static uint8_t recv_data(void) ERROR: return 0; } +#endif static inline void clock_lo() { diff --git a/protocol/ps2_mouse.c b/protocol/ps2_mouse.c index ea629655..4702f12c 100644 --- a/protocol/ps2_mouse.c +++ b/protocol/ps2_mouse.c @@ -47,20 +47,15 @@ uint8_t ps2_mouse_init(void) { phex(rcv); phex(ps2_error); print("\n"); // read completion code of BAT - rcv = ps2_host_recv(); + rcv = ps2_host_recv_response(); print("ps2_mouse_init: read BAT: "); phex(rcv); phex(ps2_error); print("\n"); // read Device ID - rcv = ps2_host_recv(); + rcv = ps2_host_recv_response(); print("ps2_mouse_init: read DevID: "); phex(rcv); phex(ps2_error); print("\n"); - // send Enable Data Reporting - rcv = ps2_host_send(0xF4); - print("ps2_mouse_init: send 0xF4: "); - phex(rcv); phex(ps2_error); print("\n"); - // send Set Remote mode rcv = ps2_host_send(0xF0); print("ps2_mouse_init: send 0xF0: "); From ccbc1dd8e74e89624b6ac4ce6cf474ce6e9fc7ed Mon Sep 17 00:00:00 2001 From: tmk Date: Thu, 21 Nov 2013 12:15:33 +0900 Subject: [PATCH 20/76] Fix PS/2 USART version --- protocol/ps2_usart.c | 54 ++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/protocol/ps2_usart.c b/protocol/ps2_usart.c index 9ea6b778..40c46c49 100644 --- a/protocol/ps2_usart.c +++ b/protocol/ps2_usart.c @@ -1,5 +1,5 @@ /* -Copyright 2010,2011 Jun WAKO +Copyright 2010,2011,2012,2013 Jun WAKO This software is licensed with a Modified BSD License. All of this is supposed to be Free Software, Open Source, DFSG-free, @@ -64,14 +64,6 @@ http://www.mcamafia.de/pdf/ibm_hitrc07.pdf #include "debug.h" -#if 0 -#define DEBUGP_INIT() do { DDRC = 0xFF; } while (0) -#define DEBUGP(x) do { PORTC = x; } while (0) -#else -#define DEBUGP_INIT() -#define DEBUGP(x) -#endif - #define WAIT(stat, us, err) do { \ if (!wait_##stat(us)) { \ ps2_error = err; \ @@ -97,12 +89,12 @@ static inline void idle(void); static inline void inhibit(void); static inline uint8_t pbuf_dequeue(void); static inline void pbuf_enqueue(uint8_t data); +static inline bool pbuf_has_data(void); +static inline void pbuf_clear(void); void ps2_host_init(void) { - DEBUGP_INIT(); - DEBUGP(0x1); idle(); PS2_USART_INIT(); PS2_USART_RX_INT_ON(); @@ -114,7 +106,6 @@ uint8_t ps2_host_send(uint8_t data) bool parity = true; ps2_error = PS2_ERR_NONE; - DEBUGP(0x6); PS2_USART_OFF(); /* terminate a transmission if we have */ @@ -153,6 +144,8 @@ uint8_t ps2_host_send(uint8_t data) WAIT(clock_hi, 50, 8); WAIT(data_hi, 50, 9); + PS2_USART_INIT(); + PS2_USART_RX_INT_ON(); res = ps2_host_recv_response(); ERROR: idle(); @@ -164,15 +157,10 @@ ERROR: // Do polling data from keyboard to get response to last command. uint8_t ps2_host_recv_response(void) { - uint8_t data = 0; - PS2_USART_INIT(); - PS2_USART_RX_POLL_ON(); - while (!PS2_USART_RX_READY) - ; - data = PS2_USART_RX_DATA; - PS2_USART_OFF(); - DEBUGP(0x9); - return data; + while (!pbuf_has_data()) { + _delay_ms(1); // without this delay it seems to fall into deadlock + } + return pbuf_dequeue(); } uint8_t ps2_host_recv(void) @@ -182,15 +170,11 @@ uint8_t ps2_host_recv(void) ISR(PS2_USART_RX_VECT) { - DEBUGP(0x7); uint8_t error = PS2_USART_ERROR; uint8_t data = PS2_USART_RX_DATA; - if (error) { - DEBUGP(error>>2); - } else { + if (!error) { pbuf_enqueue(data); } - DEBUGP(0x8); } /* send LED state to keyboard */ @@ -293,9 +277,6 @@ static uint8_t pbuf_head = 0; static uint8_t pbuf_tail = 0; static inline void pbuf_enqueue(uint8_t data) { - if (!data) - return; - uint8_t sreg = SREG; cli(); uint8_t next = (pbuf_head + 1) % PBUF_SIZE; @@ -322,3 +303,18 @@ static inline uint8_t pbuf_dequeue(void) return val; } +static inline bool pbuf_has_data(void) +{ + uint8_t sreg = SREG; + cli(); + bool has_data = (pbuf_head != pbuf_tail); + SREG = sreg; + return has_data; +} +static inline void pbuf_clear(void) +{ + uint8_t sreg = SREG; + cli(); + pbuf_head = pbuf_tail = 0; + SREG = sreg; +} From a9c3f4750b3d703b8bbbc90db2566afd2aab0ec9 Mon Sep 17 00:00:00 2001 From: tmk Date: Thu, 21 Nov 2013 13:00:08 +0900 Subject: [PATCH 21/76] Configure PS/2 mouse build options to onekey --- keyboard/onekey/Makefile.lufa | 2 +- keyboard/onekey/Makefile.pjrc | 4 ++-- keyboard/onekey/config.h | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/keyboard/onekey/Makefile.lufa b/keyboard/onekey/Makefile.lufa index 2a97aa63..60a84ba0 100644 --- a/keyboard/onekey/Makefile.lufa +++ b/keyboard/onekey/Makefile.lufa @@ -93,7 +93,7 @@ ARCH = AVR8 F_USB = $(F_CPU) # Interrupt driven control endpoint task(+60) -#OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT +OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT # Boot Section Size in *bytes* diff --git a/keyboard/onekey/Makefile.pjrc b/keyboard/onekey/Makefile.pjrc index 0f0f7097..24ade335 100644 --- a/keyboard/onekey/Makefile.pjrc +++ b/keyboard/onekey/Makefile.pjrc @@ -87,8 +87,8 @@ CONSOLE_ENABLE = yes # Console for debug #SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend #NKRO_ENABLE = yes # USB Nkey Rollover(+500) -#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support -#PS2_USE_BUSYWAIT = yes # uses primitive reference code +PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support +PS2_USE_BUSYWAIT = yes # uses primitive reference code #PS2_USE_INT = yes # uses external interrupt for falling edge of PS/2 clock pin #PS2_USE_USART = yes # uses hardware USART engine for PS/2 signal receive(recomened) diff --git a/keyboard/onekey/config.h b/keyboard/onekey/config.h index e99a6485..1d2e052b 100644 --- a/keyboard/onekey/config.h +++ b/keyboard/onekey/config.h @@ -73,7 +73,7 @@ along with this program. If not, see . # define PS2_CLOCK_PORT PORTD # define PS2_CLOCK_PIN PIND # define PS2_CLOCK_DDR DDRD -# define PS2_CLOCK_BIT 1 +# define PS2_CLOCK_BIT 5 # define PS2_DATA_PORT PORTD # define PS2_DATA_PIN PIND # define PS2_DATA_DDR DDRD @@ -81,12 +81,13 @@ along with this program. If not, see . #endif +/* PS/2 mouse interrupt version */ #ifdef PS2_USE_INT /* uses INT1 for clock line(ATMega32U4) */ #define PS2_CLOCK_PORT PORTD #define PS2_CLOCK_PIN PIND #define PS2_CLOCK_DDR DDRD -#define PS2_CLOCK_BIT 1 +#define PS2_CLOCK_BIT 5 #define PS2_DATA_PORT PORTD #define PS2_DATA_PIN PIND #define PS2_DATA_DDR DDRD @@ -106,6 +107,7 @@ along with this program. If not, see . #endif +/* PS/2 mouse USART version */ #ifdef PS2_USE_USART #if defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) /* XCK for clock line and RXD for data line */ From 22e293696db661dc83f4c463507c0dd410b4c147 Mon Sep 17 00:00:00 2001 From: tmk Date: Thu, 21 Nov 2013 16:32:45 +0900 Subject: [PATCH 22/76] Add new keymap management on gh60 --- keyboard/gh60/{Makefile.lufa => Makefile} | 23 ++-- keyboard/gh60/README.md | 64 +++-------- keyboard/gh60/keymap_common.c | 30 +++++ keyboard/gh60/keymap_common.h | 69 +++++++++++ keyboard/gh60/{keymap.c => keymap_hasu.c} | 108 +----------------- .../gh60/{keymap_plain.h => keymap_plain.c} | 6 +- .../gh60/{keymap_poker.h => keymap_poker.c} | 6 +- ...{keymap_poker_bit.h => keymap_poker_bit.c} | 6 +- ...{keymap_poker_set.h => keymap_poker_set.c} | 6 +- 9 files changed, 143 insertions(+), 175 deletions(-) rename keyboard/gh60/{Makefile.lufa => Makefile} (92%) create mode 100644 keyboard/gh60/keymap_common.c create mode 100644 keyboard/gh60/keymap_common.h rename keyboard/gh60/{keymap.c => keymap_hasu.c} (65%) rename keyboard/gh60/{keymap_plain.h => keymap_plain.c} (77%) rename keyboard/gh60/{keymap_poker.h => keymap_poker.c} (97%) rename keyboard/gh60/{keymap_poker_bit.h => keymap_poker_bit.c} (95%) rename keyboard/gh60/{keymap_poker_set.h => keymap_poker_set.c} (97%) diff --git a/keyboard/gh60/Makefile.lufa b/keyboard/gh60/Makefile similarity index 92% rename from keyboard/gh60/Makefile.lufa rename to keyboard/gh60/Makefile index ad7d219e..108a85c5 100644 --- a/keyboard/gh60/Makefile.lufa +++ b/keyboard/gh60/Makefile @@ -48,9 +48,14 @@ TOP_DIR = ../.. TARGET_DIR = . # project specific files -SRC = keymap.c \ +SRC = keymap_common.c \ matrix.c \ led.c +ifdef KEYMAP + SRC := keymap_$(KEYMAP).c $(SRC) +else + SRC := keymap_poker.c $(SRC) +endif CONFIG_H = config.h @@ -93,7 +98,7 @@ ARCH = AVR8 F_USB = $(F_CPU) # Interrupt driven control endpoint task(+60) -#OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT +OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT # Boot Section Size in *bytes* @@ -114,7 +119,7 @@ EXTRAKEY_ENABLE = yes # Audio control and System control(+450) CONSOLE_ENABLE = yes # Console for debug(+400) COMMAND_ENABLE = yes # Commands for debug and configuration SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend -#NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA +NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA # Optimize size but this may cause error "relocation truncated to fit" @@ -127,15 +132,3 @@ VPATH += $(TOP_DIR) include $(TOP_DIR)/protocol/lufa.mk include $(TOP_DIR)/common.mk include $(TOP_DIR)/rules.mk - -plain: OPT_DEFS += -DKEYMAP_PLAIN -plain: all - -poker: OPT_DEFS += -DKEYMAP_POKER -poker: all - -poker_set: OPT_DEFS += -DKEYMAP_POKER_SET -poker_set: all - -poker_bit: OPT_DEFS += -DKEYMAP_POKER_BIT -poker_bit: all diff --git a/keyboard/gh60/README.md b/keyboard/gh60/README.md index 4dc4e5ee..9068c389 100644 --- a/keyboard/gh60/README.md +++ b/keyboard/gh60/README.md @@ -10,28 +10,20 @@ DIY compact keyboard designed and run by komar007 and Geekhack community. ## Build Move to this directory then just run `make` like: - $ make -f Makfile.[pjrc|lufa] + $ make -Use `Makefile.pjrc` if you want to use PJRC stack or use `Makefile.lufa` for LUFA stack. - - -## Boot Magic -Plugin pressing these `Boot Magic` key. - -- `Fn` key for bootloader kick up. -- `D` key for Debug enable. +Use `make -f Makefile.pjrc` if you want to use PJRC stack but I find no reason to do so now. ## Keymap -Two version of keymap are available. `Plan`, `Poker` and `Funky`(default). -See keymap.c to define your own favourite keymap. +Several version of keymap are available; `plain`, `poker_bit`, `poker_set`, `hasu` and `poker`(default). See keymap document(you can find in README.md of top) and `keymap_*.c` to define your own favourite keymap. - $ make -f Makefile.[pjrc|lufa] [plain|poker] + $ make KEYMAP=[poker|plain|poker_set|poker_bit|hasu] ### 1. Plain keymap -This will be useful if you want to use key mapping tool like AHK. +Even without any Fn layer. This will be useful if you want to use key mapping tool like AHK. -See [keymap_plain.h](keymap_plain.h) for detail. +See [keymap_plain.c](keymap_plain.c) for detail. #### 1.0 Plain Default Layer ,-----------------------------------------------------------. @@ -48,9 +40,13 @@ See [keymap_plain.h](keymap_plain.h) for detail. ### 2 Poker keymap -See [keymap_poker.h](keymap_poker.h) for Poker layer emulation, [keymap_poker_bit.h](keymap_poker_bit.h) and [keymap_poker_set.h](keymap_poker_set.h) for better support of Esc and arrow. +[keymap_poker.c](keymap_poker.c) emulates original Poker layer emulation. +[keymap_poker_bit.c](keymap_poker_bit.c) and [keymap_poker_set.c](keymap_poker_set.c) offers better support of Esc and arrow like: - These keymap supports Colemak, Dvorak and Workmans, use `Magic` + {`1`, `2`, `3`} to switch and `Magic` + `0` to return to Qwerty. + Fn + Esc = ` + Fn + {left, down, up, right} = {home, pgdown, pgup, end} + + `poker` keymap supports Colemak, Dvorak and Workmans, use `Magic` + {`1`, `2`, `3`} to switch and `Magic` + `0` to return to Qwerty, where `Magic` is `LShift` + `RShift`. #### 2.0 Poker Default Layer ,-----------------------------------------------------------. @@ -65,32 +61,6 @@ See [keymap_poker.h](keymap_poker.h) for Poker layer emulation, [keymap_poker_bi |Ctrl|Gui |Alt | Space |Fn |Gui |App |Ctrl| `-----------------------------------------------------------' -#### 2.1 Poker Arrow Layer - ,-----------------------------------------------------------. - | | | | | | | | | | | | | | | - |-----------------------------------------------------------| - | | | | | | | | | | | | | | | - |-----------------------------------------------------------| - | | | | | | | | | | | | | | - |-----------------------------------------------------------| - | | | | | | | | | | | | Up | - |-----------------------------------------------------------| - | | | | |Fn |Left|Down|Righ| - `-----------------------------------------------------------' - -#### 2.2 Poker Esc Layer - ,-----------------------------------------------------------. - |Esc| | | | | | | | | | | | | | - |-----------------------------------------------------------| - | | | | | | | | | | | | | | | - |-----------------------------------------------------------| - | | | | | | | | | | | | | | - |-----------------------------------------------------------| - | | | | | | | | | | | | | - |-----------------------------------------------------------| - | | | | |Fn | | | | - `-----------------------------------------------------------' - #### 2.1 Poker Fn Layer ,-----------------------------------------------------------. |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12| | @@ -99,17 +69,15 @@ See [keymap_poker.h](keymap_poker.h) for Poker layer emulation, [keymap_poker_bi |-----------------------------------------------------------| | |Lef|Dow|Rig| | |Psc|Slk|Pau| |Tsk|End| | |-----------------------------------------------------------| - | |Del| |Web|Mut|VoU|VoD| |PgU|PgD|Del| | + | |Del| |Web|Mut|VoU|VoD| |PgU|PgD|Del| Up | |-----------------------------------------------------------| - | | | | FnS |Fn | | | | + | | | | FnS |Fn |Left|Down|Righ| `-----------------------------------------------------------' -### 3. Funky keymap -This is my keymap(default) with HHKB, Vi cursor and Mousekey layer. - -See [keymap.c](keymap.c) for detail. +### 3. Hasu keymap +This is my keymap with HHKB, Vi cursor and Mousekey layer. See [keymap_hasu.c](keymap_hasu.c) for detail. #### 3.0 Funky Default Layer ,-----------------------------------------------------------. diff --git a/keyboard/gh60/keymap_common.c b/keyboard/gh60/keymap_common.c new file mode 100644 index 00000000..7b6379f6 --- /dev/null +++ b/keyboard/gh60/keymap_common.c @@ -0,0 +1,30 @@ +/* +Copyright 2012,2013 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include "keymap_common.h" + + +/* translates key to keycode */ +uint8_t keymap_key_to_keycode(uint8_t layer, key_t key) +{ + return pgm_read_byte(&keymaps[(layer)][(key.row)][(key.col)]); +} + +/* translates Fn keycode to action */ +action_t keymap_fn_to_action(uint8_t keycode) +{ + return (action_t){ .code = pgm_read_word(&fn_actions[FN_INDEX(keycode)]) }; +} diff --git a/keyboard/gh60/keymap_common.h b/keyboard/gh60/keymap_common.h new file mode 100644 index 00000000..2105caab --- /dev/null +++ b/keyboard/gh60/keymap_common.h @@ -0,0 +1,69 @@ +/* +Copyright 2012,2013 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef KEYMAP_COMMON_H +#define KEYMAP_COMMON_H + +#include +#include +#include +#include "keycode.h" +#include "action.h" +#include "action_macro.h" +#include "report.h" +#include "host.h" +#include "print.h" +#include "debug.h" +#include "keymap.h" + + +extern const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; +extern const uint16_t fn_actions[]; + + +/* GH60 keymap definition macro + * K2C, K31 and K3C are extra keys for ISO + */ +#define KEYMAP( \ + K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, \ + K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \ + K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, K2D, \ + K30, K31, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3C, K3D, \ + K40, K41, K42, K45, K4A, K4B, K4C, K4D \ +) { \ + { KC_##K00, KC_##K01, KC_##K02, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07, KC_##K08, KC_##K09, KC_##K0A, KC_##K0B, KC_##K0C, KC_##K0D }, \ + { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17, KC_##K18, KC_##K19, KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D }, \ + { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27, KC_##K28, KC_##K29, KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D }, \ + { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_##K37, KC_##K38, KC_##K39, KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D }, \ + { KC_##K40, KC_##K41, KC_##K42, KC_NO, KC_NO, KC_##K45, KC_NO, KC_NO, KC_NO, KC_NO, KC_##K4A, KC_##K4B, KC_##K4C, KC_##K4D } \ +} + +/* ANSI valiant. No extra keys for ISO */ +#define KEYMAP_ANSI( \ + K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, \ + K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \ + K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2D, \ + K30, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3D, \ + K40, K41, K42, K45, K4A, K4B, K4C, K4D \ +) KEYMAP( \ + K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, \ + K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \ + K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, NO, K2D, \ + K30, NO, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, NO, K3D, \ + K40, K41, K42, K45, K4A, K4B, K4C, K4D \ +) + +#endif diff --git a/keyboard/gh60/keymap.c b/keyboard/gh60/keymap_hasu.c similarity index 65% rename from keyboard/gh60/keymap.c rename to keyboard/gh60/keymap_hasu.c index edc1caf1..e648687a 100644 --- a/keyboard/gh60/keymap.c +++ b/keyboard/gh60/keymap_hasu.c @@ -1,77 +1,8 @@ -/* -Copyright 2012,2013 Jun Wako +#include "keymap_common.h" -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ -#include -#include -#include -#include "keycode.h" -#include "action.h" -#include "action_macro.h" -#include "report.h" -#include "host.h" -#include "print.h" -#include "debug.h" -#include "keymap.h" - - -/* GH60 keymap definition macro - * K2C, K31 and K3C are extra keys for ISO - */ -#define KEYMAP( \ - K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, \ - K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \ - K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, K2D, \ - K30, K31, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3C, K3D, \ - K40, K41, K42, K45, K4A, K4B, K4C, K4D \ -) { \ - { KC_##K00, KC_##K01, KC_##K02, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07, KC_##K08, KC_##K09, KC_##K0A, KC_##K0B, KC_##K0C, KC_##K0D }, \ - { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17, KC_##K18, KC_##K19, KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D }, \ - { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27, KC_##K28, KC_##K29, KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D }, \ - { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_##K37, KC_##K38, KC_##K39, KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D }, \ - { KC_##K40, KC_##K41, KC_##K42, KC_NO, KC_NO, KC_##K45, KC_NO, KC_NO, KC_NO, KC_NO, KC_##K4A, KC_##K4B, KC_##K4C, KC_##K4D } \ -} - -/* ANSI valiant. No extra keys for ISO */ -#define KEYMAP_ANSI( \ - K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, \ - K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \ - K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2D, \ - K30, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3D, \ - K40, K41, K42, K45, K4A, K4B, K4C, K4D \ -) KEYMAP( \ - K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, \ - K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \ - K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, NO, K2D, \ - K30, NO, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, NO, K3D, \ - K40, K41, K42, K45, K4A, K4B, K4C, K4D \ -) - - -#if defined(KEYMAP_PLAIN) - #include "keymap_plain.h" -#elif defined(KEYMAP_POKER) - #include "keymap_poker.h" -#elif defined(KEYMAP_POKER_SET) - #include "keymap_poker_set.h" -#elif defined(KEYMAP_POKER_BIT) - #include "keymap_poker_bit.h" -#else -static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { +const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { /* - * Funky + * Hasu */ /* Keymap 0: Default Layer * ,-----------------------------------------------------------. @@ -200,7 +131,7 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { /* * Fn action definition */ -static const uint16_t PROGMEM fn_actions[] = { +const uint16_t PROGMEM fn_actions[] = { [0] = ACTION_LAYER_MOMENTARY(4), [1] = ACTION_LAYER_TAP_KEY(5, KC_SLASH), [2] = ACTION_LAYER_TAP_KEY(6, KC_SCLN), @@ -212,34 +143,3 @@ static const uint16_t PROGMEM fn_actions[] = { [8] = ACTION_DEFAULT_LAYER_SET(3), // set workman layout [9] = ACTION_MODS_TAP_KEY(MOD_RSFT, KC_GRV), }; -#endif - - - -#define KEYMAPS_SIZE (sizeof(keymaps) / sizeof(keymaps[0])) -#define FN_ACTIONS_SIZE (sizeof(fn_actions) / sizeof(fn_actions[0])) - -/* translates key to keycode */ -uint8_t keymap_key_to_keycode(uint8_t layer, key_t key) -{ - if (layer < KEYMAPS_SIZE) { - return pgm_read_byte(&keymaps[(layer)][(key.row)][(key.col)]); - } else { - // XXX: this may cuaes bootlaoder_jump inconsistent fail. - //debug("key_to_keycode: base "); debug_dec(layer); debug(" is invalid.\n"); - // fall back to layer 0 - return pgm_read_byte(&keymaps[0][(key.row)][(key.col)]); - } -} - -/* translates Fn keycode to action */ -action_t keymap_fn_to_action(uint8_t keycode) -{ - action_t action; - if (FN_INDEX(keycode) < FN_ACTIONS_SIZE) { - action.code = pgm_read_word(&fn_actions[FN_INDEX(keycode)]); - } else { - action.code = ACTION_NO; - } - return action; -} diff --git a/keyboard/gh60/keymap_plain.h b/keyboard/gh60/keymap_plain.c similarity index 77% rename from keyboard/gh60/keymap_plain.h rename to keyboard/gh60/keymap_plain.c index 52d11256..3138c180 100644 --- a/keyboard/gh60/keymap_plain.h +++ b/keyboard/gh60/keymap_plain.c @@ -1,4 +1,6 @@ -static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { +#include "keymap_common.h" + +const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { /* 0: qwerty */ KEYMAP(ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, \ TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, \ @@ -6,4 +8,4 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { LSFT,NO, Z, X, C, V, B, N, M, COMM,DOT, SLSH,NO, RSFT, \ LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL), }; -static const uint16_t PROGMEM fn_actions[] = {}; +const uint16_t PROGMEM fn_actions[] = {}; diff --git a/keyboard/gh60/keymap_poker.h b/keyboard/gh60/keymap_poker.c similarity index 97% rename from keyboard/gh60/keymap_poker.h rename to keyboard/gh60/keymap_poker.c index 16429994..7a612ee4 100644 --- a/keyboard/gh60/keymap_poker.h +++ b/keyboard/gh60/keymap_poker.c @@ -1,4 +1,6 @@ -static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { +#include "keymap_common.h" + +const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { /* 0: qwerty */ KEYMAP_ANSI( GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, \ @@ -88,7 +90,7 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { TRNS,TRNS,TRNS,FN6, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS, \ TRNS,TRNS,TRNS, TRNS, TRNS,TRNS,TRNS,TRNS), }; -static const uint16_t PROGMEM fn_actions[] = { +const uint16_t PROGMEM fn_actions[] = { /* Poker Layout */ [0] = ACTION_LAYER_MOMENTARY(6), // to Fn overlay [1] = ACTION_LAYER_TOGGLE(4), // toggle arrow overlay diff --git a/keyboard/gh60/keymap_poker_bit.h b/keyboard/gh60/keymap_poker_bit.c similarity index 95% rename from keyboard/gh60/keymap_poker_bit.h rename to keyboard/gh60/keymap_poker_bit.c index 1b498351..b8870fdd 100644 --- a/keyboard/gh60/keymap_poker_bit.h +++ b/keyboard/gh60/keymap_poker_bit.c @@ -1,7 +1,9 @@ +#include "keymap_common.h" + // Poker fix with toggle and bit operation // Fn + Esc = ` // Fn + {left, down, up, right} = {home, pgdown, pgup, end} -static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { +const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { /* 0: qwerty */ KEYMAP_ANSI( GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, \ @@ -38,7 +40,7 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, UP, \ TRNS,TRNS,TRNS, TRNS, TRNS,LEFT,DOWN,RGHT), }; -static const uint16_t PROGMEM fn_actions[] = { +const uint16_t PROGMEM fn_actions[] = { /* Poker Layout */ [0] = ACTION_LAYER_BIT_XOR(1, 0b0101, ON_BOTH), // Poker Fn(with fix for Esc) [1] = ACTION_LAYER_TOGGLE(5), // Poker Arrow toggle diff --git a/keyboard/gh60/keymap_poker_set.h b/keyboard/gh60/keymap_poker_set.c similarity index 97% rename from keyboard/gh60/keymap_poker_set.h rename to keyboard/gh60/keymap_poker_set.c index e1e4d80e..aaa31fc5 100644 --- a/keyboard/gh60/keymap_poker_set.h +++ b/keyboard/gh60/keymap_poker_set.c @@ -1,7 +1,9 @@ +#include "keymap_common.h" + // Poker fix with set(state transition) // Fn + Esc = ` // Fn + {left, down, up, right} = {home, pgdown, pgup, end} -static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { +const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { /* 0: qwerty */ KEYMAP_ANSI( GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, \ @@ -63,7 +65,7 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { /* * Fn action definition */ -static const uint16_t PROGMEM fn_actions[] = { +const uint16_t PROGMEM fn_actions[] = { /* Poker Layout */ [0] = ACTION_LAYER_SET(4, ON_PRESS), // FN0 move to Fn'd when press [1] = ACTION_LAYER_SET(5, ON_PRESS), // FN1 move to Fn'd arrow when press From 4e7ec43c3f52e7588807389d6f8e5fd810b36286 Mon Sep 17 00:00:00 2001 From: tmk Date: Thu, 21 Nov 2013 19:32:17 +0900 Subject: [PATCH 23/76] Add SpaceFN layout to gh60 --- keyboard/gh60/Makefile | 2 +- keyboard/gh60/README.md | 57 +++++++++++----------------------- keyboard/gh60/keymap_hasu.c | 6 ++-- keyboard/gh60/keymap_spacefn.c | 55 ++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 43 deletions(-) create mode 100644 keyboard/gh60/keymap_spacefn.c diff --git a/keyboard/gh60/Makefile b/keyboard/gh60/Makefile index 108a85c5..6be0c107 100644 --- a/keyboard/gh60/Makefile +++ b/keyboard/gh60/Makefile @@ -118,7 +118,7 @@ MOUSEKEY_ENABLE = yes # Mouse keys(+4700) EXTRAKEY_ENABLE = yes # Audio control and System control(+450) CONSOLE_ENABLE = yes # Console for debug(+400) COMMAND_ENABLE = yes # Commands for debug and configuration -SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend +#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA diff --git a/keyboard/gh60/README.md b/keyboard/gh60/README.md index 9068c389..07ed40d8 100644 --- a/keyboard/gh60/README.md +++ b/keyboard/gh60/README.md @@ -16,9 +16,9 @@ Use `make -f Makefile.pjrc` if you want to use PJRC stack but I find no reason t ## Keymap -Several version of keymap are available; `plain`, `poker_bit`, `poker_set`, `hasu` and `poker`(default). See keymap document(you can find in README.md of top) and `keymap_*.c` to define your own favourite keymap. +Several version of keymap are available; `plain`, `poker_bit`, `poker_set`, `hasu`, `spacefn` and `poker`(default). See keymap document(you can find in README.md of top) and `keymap_*.c` to define your own favourite keymap. - $ make KEYMAP=[poker|plain|poker_set|poker_bit|hasu] + $ make KEYMAP=[poker|plain|poker_set|poker_bit|hasu|spacefn] ### 1. Plain keymap Even without any Fn layer. This will be useful if you want to use key mapping tool like AHK. @@ -75,59 +75,38 @@ See [keymap_plain.c](keymap_plain.c) for detail. `-----------------------------------------------------------' - ### 3. Hasu keymap This is my keymap with HHKB, Vi cursor and Mousekey layer. See [keymap_hasu.c](keymap_hasu.c) for detail. -#### 3.0 Funky Default Layer + +### 4. SpaceFN keymap +See [keymap_spacefn.c](keymap_spacefn.c) and [SpaceFN discussion](http://geekhack.org/index.php?topic=51069.0). + +#### 4.0 SpaceFN Default Layer ,-----------------------------------------------------------. |Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backsp | |-----------------------------------------------------------| |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| |-----------------------------------------------------------| - |Caps | A| S| D| F| G| H| J| K| L|*L3| '|Return | + |Caps | A| S| D| F| G| H| J| K| L| ;| '|Return | |-----------------------------------------------------------| - |Shift | Z| X| C| V| B| N| M| ,| .|*L2|Shift | + |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift | |-----------------------------------------------------------| - |Ctrl|Gui |Alt | Space |Alt |*L3 |*L3 |*L1 | + |Ctrl|Gui |Alt | Space/Fn |Alt |Gui |App |Ctrl| `-----------------------------------------------------------' - -#### 3.1 Funky HHKB mode + +#### 4.1 SpaceFN ,-----------------------------------------------------------. - |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Delete | + |` | F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Delete | |-----------------------------------------------------------| - |Caps | | | | | | | |Psc|Slk|Pus|Up | |Inser| + | | | | | | | |Hom|Up |End|Psc|Slk|Pau|Ins | |-----------------------------------------------------------| - |Contro|VoD|VoU|Mut| | | *| /|Hom|PgU|Lef|Rig|Enter | + | | | | | | |PgU|Lef|Dow|Rig| | | | |-----------------------------------------------------------| - |Shift | | | | | | +| -|End|PgD|Dow|Shift | + | | | | | |Spc|PgD|` |~ | | | | |-----------------------------------------------------------| - |Ctrl|Gui |Alt | Space |Alt |Gui |App |*L0 | + | | | | Fn | | | | | `-----------------------------------------------------------' + -#### 3.2 Funky Vi mode - ,-----------------------------------------------------------. - | `| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Backsp | - |-----------------------------------------------------------| - |Tab |Hom|PgD|Up |PgU|End|Hom|PgD|PgU|End| | | | | - |-----------------------------------------------------------| - |Contro| |Lef|Dow|Rig| |Lef|Dow|Up |Rig| | |Return | - |-----------------------------------------------------------| - |Shift | | | | | |Hom|PgD|PgU|End|*L0|Shift | - |-----------------------------------------------------------| - |Ctrl|Gui |Alt | Space |Alt |Gui |App |Ctrl| - `-----------------------------------------------------------' -#### 3.3 Funky Mouse mode - ,-----------------------------------------------------------. - | `| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Backsp | - |-----------------------------------------------------------| - |Tab |MwL|MwD|McU|MwU|MwR|MwL|MwD|MwU|MwR| | | | | - |-----------------------------------------------------------| - |Contro| |McL|McD|McR| |McL|McD|McU|McR|*L0| |Return | - |-----------------------------------------------------------| - |Shift | | |Mb1|Mb2|Mb3|Mb2|Mb1| | | |Shift | - |-----------------------------------------------------------| - |Ctrl|Gui |Alt | Space |Alt |*L0 |*L0 |Ctrl| - `-----------------------------------------------------------' - Mc: Mouse Cursor / Mb: Mouse Button / Mw: Mouse Wheel diff --git a/keyboard/gh60/keymap_hasu.c b/keyboard/gh60/keymap_hasu.c index e648687a..e6af2858 100644 --- a/keyboard/gh60/keymap_hasu.c +++ b/keyboard/gh60/keymap_hasu.c @@ -1,9 +1,9 @@ #include "keymap_common.h" +/* + * Hasu + */ const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { - /* - * Hasu - */ /* Keymap 0: Default Layer * ,-----------------------------------------------------------. * |Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backsp | diff --git a/keyboard/gh60/keymap_spacefn.c b/keyboard/gh60/keymap_spacefn.c new file mode 100644 index 00000000..8077dcee --- /dev/null +++ b/keyboard/gh60/keymap_spacefn.c @@ -0,0 +1,55 @@ +#include "keymap_common.h" + +/* + * SpaceFN + * http://geekhack.org/index.php?topic=51069.0 + */ +const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + /* Keymap 0: Default Layer + * ,-----------------------------------------------------------. + * |Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backsp | + * |-----------------------------------------------------------| + * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| + * |-----------------------------------------------------------| + * |Caps | A| S| D| F| G| H| J| K| L| ;| '|Return | + * |-----------------------------------------------------------| + * |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift | + * |-----------------------------------------------------------| + * |Ctrl|Gui |Alt | Space |Alt |Gui |App |Ctrl| + * `-----------------------------------------------------------' + */ + KEYMAP_ANSI( + ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, \ + TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, \ + CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, \ + LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, \ + LCTL,LGUI,LALT, FN0, RALT,RGUI,APP, RCTL), + + /* Overlay 1: SpaceFN + * ,-----------------------------------------------------------. + * |` | F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Delete | + * |-----------------------------------------------------------| + * | | | | | | | |Hom|Up |End|Psc|Slk|Pau|Ins | + * |-----------------------------------------------------------| + * | | | | | | |PgU|Lef|Dow|Rig| | | | + * |-----------------------------------------------------------| + * | | | | | |Spc|PgD|` |~ | | | | + * |-----------------------------------------------------------| + * | | | | | | | | | + * `-----------------------------------------------------------' + */ + KEYMAP_ANSI( + GRV, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, DEL, \ + TRNS,TRNS,TRNS,ESC, TRNS,TRNS,TRNS,HOME,UP, END, PSCR,SLCK,PAUS,INS, \ + TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,PGUP,LEFT,DOWN,RGHT,TRNS,TRNS, TRNS, \ + TRNS,TRNS,TRNS,TRNS,TRNS,SPC, PGDN,GRV, FN1, TRNS,TRNS, TRNS, \ + TRNS,TRNS,TRNS, TRNS, TRNS,TRNS,TRNS,TRNS), +}; + +/* + * Fn action definition + */ +const uint16_t PROGMEM fn_actions[] = { + [0] = ACTION_LAYER_TAP_KEY(1, KC_SPACE), + [1] = ACTION_MODS_KEY(MOD_LSFT, KC_GRV), // tilde +}; From 4e5bce22deeee879d063f8e4fa8fe7aa087bd57e Mon Sep 17 00:00:00 2001 From: tmk Date: Thu, 21 Nov 2013 23:23:57 +0900 Subject: [PATCH 24/76] Add parenthses ito macro arguments --- common/action_code.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/action_code.h b/common/action_code.h index c153838f..b08d3612 100644 --- a/common/action_code.h +++ b/common/action_code.h @@ -207,10 +207,10 @@ enum mods_codes { MODS_ONESHOT = 0x00, }; #define ACTION_KEY(key) ACTION(ACT_MODS, (key)) -#define ACTION_MODS(mods) ACTION(ACT_MODS, (mods&0x1f)<<8 | 0) -#define ACTION_MODS_KEY(mods, key) ACTION(ACT_MODS, (mods&0x1f)<<8 | (key)) -#define ACTION_MODS_TAP_KEY(mods, key) ACTION(ACT_MODS_TAP, (mods&0x1f)<<8 | (key)) -#define ACTION_MODS_ONESHOT(mods) ACTION(ACT_MODS_TAP, (mods&0x1f)<<8 | MODS_ONESHOT) +#define ACTION_MODS(mods) ACTION(ACT_MODS, ((mods)&0x1f)<<8 | 0) +#define ACTION_MODS_KEY(mods, key) ACTION(ACT_MODS, ((mods)&0x1f)<<8 | (key)) +#define ACTION_MODS_TAP_KEY(mods, key) ACTION(ACT_MODS_TAP, ((mods)&0x1f)<<8 | (key)) +#define ACTION_MODS_ONESHOT(mods) ACTION(ACT_MODS_TAP, ((mods)&0x1f)<<8 | MODS_ONESHOT) /* From beacd5872c525b4bad215d2b2a4ff9ec60518e2f Mon Sep 17 00:00:00 2001 From: tmk Date: Thu, 21 Nov 2013 23:30:23 +0900 Subject: [PATCH 25/76] Support GH60 Rev.B PCB as well as Rev.A(issue #64) - Port of col8 is PB0 in Rev.A while PB7 in Rev.B --- keyboard/gh60/matrix.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/keyboard/gh60/matrix.c b/keyboard/gh60/matrix.c index a2bd70e4..a6121515 100644 --- a/keyboard/gh60/matrix.c +++ b/keyboard/gh60/matrix.c @@ -136,7 +136,8 @@ uint8_t matrix_key_count(void) /* Column pin configuration * col: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 - * pin: F0 F1 E6 C7 C6 B6 D4 B1 B0 B5 B4 D7 D6 B3 + * pin: F0 F1 E6 C7 C6 B6 D4 B1 B0 B5 B4 D7 D6 B3 (Rev.A) + * pin: B7 (Rev.B) */ static void init_cols(void) { @@ -149,8 +150,8 @@ static void init_cols(void) PORTD |= (1<<7 | 1<<6 | 1<<4); DDRC &= ~(1<<7 | 1<<6); PORTC |= (1<<7 | 1<<6); - DDRB &= ~(1<<6 | 1<< 5 | 1<<4 | 1<<3 | 1<<1 | 1<<0); - PORTB |= (1<<6 | 1<< 5 | 1<<4 | 1<<3 | 1<<1 | 1<<0); + DDRB &= ~(1<<7 | 1<<6 | 1<< 5 | 1<<4 | 1<<3 | 1<<1 | 1<<0); + PORTB |= (1<<7 | 1<<6 | 1<< 5 | 1<<4 | 1<<3 | 1<<1 | 1<<0); } static matrix_row_t read_cols(void) @@ -163,7 +164,7 @@ static matrix_row_t read_cols(void) (PINB&(1<<6) ? 0 : (1<<5)) | (PIND&(1<<4) ? 0 : (1<<6)) | (PINB&(1<<1) ? 0 : (1<<7)) | - (PINB&(1<<0) ? 0 : (1<<8)) | + ((PINB&(1<<0) && PINB&(1<<7)) ? 0 : (1<<8)) | // Rev.A and B (PINB&(1<<5) ? 0 : (1<<9)) | (PINB&(1<<4) ? 0 : (1<<10)) | (PIND&(1<<7) ? 0 : (1<<11)) | From 4e36159be226e544dfebbe06b1955261951209a4 Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 25 Nov 2013 09:27:25 +0900 Subject: [PATCH 26/76] Add HHKB keymap file on gh60 --- keyboard/gh60/Makefile | 1 + keyboard/gh60/Makefile.pjrc | 8 ++- keyboard/gh60/README.md | 103 ++++++++++++++++++++++------------ keyboard/gh60/keymap_common.h | 19 ++++++- keyboard/gh60/keymap_hhkb.c | 52 +++++++++++++++++ 5 files changed, 143 insertions(+), 40 deletions(-) create mode 100644 keyboard/gh60/keymap_hhkb.c diff --git a/keyboard/gh60/Makefile b/keyboard/gh60/Makefile index 6be0c107..fd202c17 100644 --- a/keyboard/gh60/Makefile +++ b/keyboard/gh60/Makefile @@ -51,6 +51,7 @@ TARGET_DIR = . SRC = keymap_common.c \ matrix.c \ led.c + ifdef KEYMAP SRC := keymap_$(KEYMAP).c $(SRC) else diff --git a/keyboard/gh60/Makefile.pjrc b/keyboard/gh60/Makefile.pjrc index 0ea33ea3..9655ff65 100644 --- a/keyboard/gh60/Makefile.pjrc +++ b/keyboard/gh60/Makefile.pjrc @@ -48,10 +48,16 @@ TOP_DIR = ../.. TARGET_DIR = . # project specific files -SRC = keymap.c \ +SRC = keymap_common.c \ matrix.c \ led.c +ifdef KEYMAP + SRC := keymap_$(KEYMAP).c $(SRC) +else + SRC := keymap_poker.c $(SRC) +endif + CONFIG_H = config.h diff --git a/keyboard/gh60/README.md b/keyboard/gh60/README.md index 07ed40d8..5e0fc244 100644 --- a/keyboard/gh60/README.md +++ b/keyboard/gh60/README.md @@ -2,9 +2,14 @@ GH60 keyboard firmware ====================== DIY compact keyboard designed and run by komar007 and Geekhack community. -## Threads on Geekhack.org +- Both Rev.A and Rev.B PCB are supported by one firmware binary(issue #64) + +## GH60 Resources +- [KOMAR's project page](http://blog.komar.be/projects/gh60-programmable-keyboard/) - [Prototyping](http://geekhack.org/index.php?topic=34959.0) -- [Beta-test](http://geekhack.org/index.php?topic=37570.0) +- [Rev.A PCB test](http://geekhack.org/index.php?topic=37570.0) +- [Rev.B PCB test](http://geekhack.org/index.php?topic=50685.0) +- [Group buy](http://geekhack.org/index.php?topic=41464.0) ## Build @@ -16,39 +21,21 @@ Use `make -f Makefile.pjrc` if you want to use PJRC stack but I find no reason t ## Keymap -Several version of keymap are available; `plain`, `poker_bit`, `poker_set`, `hasu`, `spacefn` and `poker`(default). See keymap document(you can find in README.md of top) and `keymap_*.c` to define your own favourite keymap. +Several version of keymap are available in advance but you are recommended to define your favorite layout yourself. To define your own keymap create file named `keymap_.c` and see keymap document(you can find in top README.md) and existent keymap files. - $ make KEYMAP=[poker|plain|poker_set|poker_bit|hasu|spacefn] +To build firmware binary hex file with a certain keymap just do `make` with `KEYMAP` option like: -### 1. Plain keymap -Even without any Fn layer. This will be useful if you want to use key mapping tool like AHK. + $ make KEYMAP=[poker|poker_set|poker_bit|plain|hasu|spacefn|hhkb|] -See [keymap_plain.c](keymap_plain.c) for detail. -#### 1.0 Plain Default Layer - ,-----------------------------------------------------------. - |Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backsp | - |-----------------------------------------------------------| - |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| - |-----------------------------------------------------------| - |Caps | A| S| D| F| G| H| J| K| L| ;| '|Return | - |-----------------------------------------------------------| - |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift | - |-----------------------------------------------------------| - |Ctrl|Gui |Alt | Space |Alt |Gui |App |Ctrl| - `-----------------------------------------------------------' - -### 2 Poker keymap - -[keymap_poker.c](keymap_poker.c) emulates original Poker layer emulation. -[keymap_poker_bit.c](keymap_poker_bit.c) and [keymap_poker_set.c](keymap_poker_set.c) offers better support of Esc and arrow like: +### 1 Poker +[keymap_poker.c](keymap_poker.c) emulates original Poker layers +while both [keymap_poker_bit.c](keymap_poker_bit.c) and [keymap_poker_set.c](keymap_poker_set.c) implements same layout in different way and they fix a minor issue of original Poker and enhance arrow keys. Fn + Esc = ` Fn + {left, down, up, right} = {home, pgdown, pgup, end} - `poker` keymap supports Colemak, Dvorak and Workmans, use `Magic` + {`1`, `2`, `3`} to switch and `Magic` + `0` to return to Qwerty, where `Magic` is `LShift` + `RShift`. - -#### 2.0 Poker Default Layer +#### 1.0 Default layer ,-----------------------------------------------------------. | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backsp | |-----------------------------------------------------------| @@ -60,8 +47,7 @@ See [keymap_plain.c](keymap_plain.c) for detail. |-----------------------------------------------------------| |Ctrl|Gui |Alt | Space |Fn |Gui |App |Ctrl| `-----------------------------------------------------------' - -#### 2.1 Poker Fn Layer +#### 1.1 Poker Fn layer ,-----------------------------------------------------------. |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12| | |-----------------------------------------------------------| @@ -75,14 +61,32 @@ See [keymap_plain.c](keymap_plain.c) for detail. `-----------------------------------------------------------' -### 3. Hasu keymap -This is my keymap with HHKB, Vi cursor and Mousekey layer. See [keymap_hasu.c](keymap_hasu.c) for detail. +### 2. Plain +Without any Fn layer this will be useful if you want to use key remapping tool like AHK on host. +See [keymap_plain.c](keymap_plain.c) for detail. + +#### 1.0 Plain Default layer + ,-----------------------------------------------------------. + |Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backsp | + |-----------------------------------------------------------| + |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| + |-----------------------------------------------------------| + |Caps | A| S| D| F| G| H| J| K| L| ;| '|Return | + |-----------------------------------------------------------| + |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift | + |-----------------------------------------------------------| + |Ctrl|Gui |Alt | Space |Alt |Gui |App |Ctrl| + `-----------------------------------------------------------' -### 4. SpaceFN keymap -See [keymap_spacefn.c](keymap_spacefn.c) and [SpaceFN discussion](http://geekhack.org/index.php?topic=51069.0). +### 3. Hasu +This is my favourite keymap with HHKB Fn, Vi cursor and Mousekey layer. See [keymap_hasu.c](keymap_hasu.c) for detail. -#### 4.0 SpaceFN Default Layer + +### 4. SpaceFN +This layout proposed by spiceBar uses space bar to change layer with using Dual role key technique. See [keymap_spacefn.c](keymap_spacefn.c) and [SpaceFN discussion](http://geekhack.org/index.php?topic=51069.0). + +#### 4.0 Default layer ,-----------------------------------------------------------. |Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backsp | |-----------------------------------------------------------| @@ -94,8 +98,7 @@ See [keymap_spacefn.c](keymap_spacefn.c) and [SpaceFN discussion](http://geekhac |-----------------------------------------------------------| |Ctrl|Gui |Alt | Space/Fn |Alt |Gui |App |Ctrl| `-----------------------------------------------------------' - -#### 4.1 SpaceFN +#### 4.1 SpaceFN layer ,-----------------------------------------------------------. |` | F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Delete | |-----------------------------------------------------------| @@ -107,6 +110,32 @@ See [keymap_spacefn.c](keymap_spacefn.c) and [SpaceFN discussion](http://geekhac |-----------------------------------------------------------| | | | | Fn | | | | | `-----------------------------------------------------------' - +### 5. HHKB +[keymap_hhkb.c](keymap_hhkb.c) emulates original HHKB layers. +#### 5.0: Default layer + ,-----------------------------------------------------------. + |Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =| \| `| + |-----------------------------------------------------------| + |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]|Bspc | + |-----------------------------------------------------------| + |Ctrl | A| S| D| F| G| H| J| K| L|Fn3| '|Return | + |-----------------------------------------------------------| + |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift |Fn | + |-----------------------------------------------------------| + | |Gui |Alt | Space | |Alt |Gui | | + `-----------------------------------------------------------' +#### 5.1: HHKB Fn layer + ,-----------------------------------------------------------. + |Pwr| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del| + |-----------------------------------------------------------| + |Caps | | | | | | | |Psc|Slk|Pus|Up | | | + |-----------------------------------------------------------| + | |VoD|VoU|Mut|Ejc| | *| /|Hom|PgU|Lef|Rig|Enter | + |-----------------------------------------------------------| + | | | | | | | +| -|End|PgD|Dow| | | + |-----------------------------------------------------------| + | | | | | | | | | + `-----------------------------------------------------------' + diff --git a/keyboard/gh60/keymap_common.h b/keyboard/gh60/keymap_common.h index 2105caab..896badd7 100644 --- a/keyboard/gh60/keymap_common.h +++ b/keyboard/gh60/keymap_common.h @@ -42,13 +42,13 @@ extern const uint16_t fn_actions[]; K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \ K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, K2D, \ K30, K31, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3C, K3D, \ - K40, K41, K42, K45, K4A, K4B, K4C, K4D \ + K40, K41, K42, K45, K49, K4A, K4B, K4C, K4D \ ) { \ { KC_##K00, KC_##K01, KC_##K02, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07, KC_##K08, KC_##K09, KC_##K0A, KC_##K0B, KC_##K0C, KC_##K0D }, \ { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17, KC_##K18, KC_##K19, KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D }, \ { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27, KC_##K28, KC_##K29, KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D }, \ { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_##K37, KC_##K38, KC_##K39, KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D }, \ - { KC_##K40, KC_##K41, KC_##K42, KC_NO, KC_NO, KC_##K45, KC_NO, KC_NO, KC_NO, KC_NO, KC_##K4A, KC_##K4B, KC_##K4C, KC_##K4D } \ + { KC_##K40, KC_##K41, KC_##K42, KC_NO, KC_NO, KC_##K45, KC_NO, KC_NO, KC_NO, KC_##K49, KC_##K4A, KC_##K4B, KC_##K4C, KC_##K4D } \ } /* ANSI valiant. No extra keys for ISO */ @@ -63,7 +63,22 @@ extern const uint16_t fn_actions[]; K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \ K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, NO, K2D, \ K30, NO, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, NO, K3D, \ + K40, K41, K42, K45, NO, K4A, K4B, K4C, K4D \ +) + + +#define KEYMAP_HHKB( \ + K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, K49,\ + K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \ + K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2D, \ + K30, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3D, K3C, \ K40, K41, K42, K45, K4A, K4B, K4C, K4D \ +) KEYMAP( \ + K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, \ + K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \ + K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, NO, K2D, \ + K30, NO, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3C, K3D, \ + K40, K41, K42, K45, K49, K4A, K4B, K4C, K4D \ ) #endif diff --git a/keyboard/gh60/keymap_hhkb.c b/keyboard/gh60/keymap_hhkb.c new file mode 100644 index 00000000..ce1b816e --- /dev/null +++ b/keyboard/gh60/keymap_hhkb.c @@ -0,0 +1,52 @@ +#include "keymap_common.h" + +/* + * HHKB Layout + */ +const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + /* 0: Default layer + * ,-----------------------------------------------------------. + * |Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =| \| `| + * |-----------------------------------------------------------| + * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]|Bspc | + * |-----------------------------------------------------------| + * |Ctrl | A| S| D| F| G| H| J| K| L|Fn3| '|Return | + * |-----------------------------------------------------------| + * |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift |Fn | + * |-----------------------------------------------------------| + * | |Gui |Alt | Space | |Alt |Gui | | + * `-----------------------------------------------------------' + */ + KEYMAP_HHKB( + ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSLS, GRV, \ + TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSPC, \ + LCTL,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, \ + LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT,FN0, \ + NO, LGUI,LALT, SPC, NO, RALT,RGUI,NO), + /* 1: HHKB Fn layer + * ,-----------------------------------------------------------. + * |Pwr| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del| + * |-----------------------------------------------------------| + * |Caps | | | | | | | |Psc|Slk|Pus|Up | | | + * |-----------------------------------------------------------| + * | |VoD|VoU|Mut|Ejc| | *| /|Hom|PgU|Lef|Rig|Enter | + * |-----------------------------------------------------------| + * | | | | | | | +| -|End|PgD|Dow| | | + * |-----------------------------------------------------------| + * | | | | | | | | | + * `-----------------------------------------------------------' + */ + KEYMAP_HHKB( + PWR, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \ + CAPS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,PSCR,SLCK,PAUS,UP, TRNS,TRNS, \ + TRNS,VOLD,VOLU,MUTE,EJCT,TRNS,PAST,PSLS,HOME,PGUP,LEFT,RGHT, PENT, \ + TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,PPLS,PMNS,END, PGDN,DOWN, TRNS,TRNS, \ + TRNS,TRNS,TRNS, TRNS, TRNS,TRNS,TRNS,TRNS), +}; + +/* + * Fn action definition + */ +const uint16_t PROGMEM fn_actions[] = { + [0] = ACTION_LAYER_MOMENTARY(1), +}; From 04c950157407c32ef04a68a1b8180630cfb9d84c Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 25 Nov 2013 11:25:44 +0900 Subject: [PATCH 27/76] Fix Makfile and config.h for LUFA in ps2_usb --- converter/ps2_usb/Makefile | 127 ++++++++++++++++++++++--------------- converter/ps2_usb/config.h | 23 +++---- 2 files changed, 87 insertions(+), 63 deletions(-) diff --git a/converter/ps2_usb/Makefile b/converter/ps2_usb/Makefile index 0c644237..04bf28a0 100644 --- a/converter/ps2_usb/Makefile +++ b/converter/ps2_usb/Makefile @@ -1,5 +1,5 @@ # Target file name (without extension). -TARGET = ps2_usb +TARGET = ps2_usb_lufa # Directory common source filess exist TOP_DIR = ../.. @@ -7,69 +7,96 @@ TOP_DIR = ../.. # Directory keyboard dependent files exist TARGET_DIR = . - -# MCU name, you MUST set this to match the board you are using -# type "make clean" after changing this, so all files will be rebuilt -#MCU = at90usb162 # Teensy 1.0 -MCU = atmega32u4 # Teensy 2.0 -#MCU = at90usb646 # Teensy++ 1.0 -#MCU = at90usb1286 # Teensy++ 2.0 - - -# Processor frequency. -# Normally the first thing your program should do is set the clock prescaler, -# so your program will run at the correct speed. You should also set this -# variable to same clock speed. The _delay_ms() macro uses this, and many -# examples use this variable to calculate timings. Do not add a "UL" here. -F_CPU = 16000000 - - -# Build Options -# *Comment out* to disable the options. -# -MOUSEKEY_ENABLE = yes # Mouse keys -EXTRAKEY_ENABLE = yes # Audio control and System control -NKRO_ENABLE = yes # USB Nkey Rollover - -PS2_USE_USART = yes # uses hardware USART engine for PS/2 signal receive(recomened) -#PS2_USE_INT = yes # uses external interrupt for falling edge of PS/2 clock pin -#PS2_USE_BUSYWAIT = yes # uses primitive reference code - - -# keyboard dependent files -SRC = keymap.c \ +# project specific files +SRC = keymap_common.c \ matrix.c \ led.c - -ifdef PS2_USE_USART - SRC += protocol/ps2_usart.c - OPT_DEFS += -DPS2_USE_USART -endif -ifdef PS2_USE_INT - SRC += protocol/ps2.c - OPT_DEFS += -DPS2_USE_INT -endif -ifdef PS2_USE_BUSYWAIT - SRC += protocol/ps2.c - OPT_DEFS += -DPS2_USE_BUSYWAIT +ifdef KEYMAP + SRC := keymap_$(KEYMAP).c $(SRC) +else + SRC := keymap_plain.c $(SRC) endif - -#CONFIG_H = config_pjrc_usart.h CONFIG_H = config.h -#---------------- Programming Options -------------------------- -PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex +# MCU name +#MCU = at90usb1287 +MCU = atmega32u4 +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency in Hz. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# +# This will be an integer division of F_USB below, as it is sourced by +# F_USB after it has run through any CPU prescalers. Note that this value +# does not *change* the processor frequency - it should merely be updated to +# reflect the processor speed set externally so that the code can use accurate +# software delays. +F_CPU = 16000000 + + +# +# LUFA specific +# +# Target architecture (see library "Board Types" documentation). +ARCH = AVR8 + +# Input clock frequency. +# This will define a symbol, F_USB, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_USB = $(F_CPU) + +# Interrupt driven control endpoint task(+60) +OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT + + +# Boot Section Size in *bytes* +# Teensy halfKay 512 +# Teensy++ halfKay 1024 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +# USBaspLoader 2048 +OPT_DEFS += -DBOOTLOADER_SIZE=4096 + + +# Build Options +# comment out to disable the options. +# +#BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE = yes # Mouse keys(+4700) +EXTRAKEY_ENABLE = yes # Audio control and System control(+450) +CONSOLE_ENABLE = yes # Console for debug(+400) +COMMAND_ENABLE = yes # Commands for debug and configuration +NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA + + +# PS/2 Options +# +#PS2_USE_USART = yes # uses hardware USART engine for PS/2 signal receive(recomened) +#PS2_USE_INT = yes # uses external interrupt for falling edge of PS/2 clock pin +PS2_USE_BUSYWAIT = yes # uses primitive reference code + + +# Optimize size but this may cause error "relocation truncated to fit" +#EXTRALDFLAGS = -Wl,--relax # Search Path VPATH += $(TARGET_DIR) VPATH += $(TOP_DIR) - -include $(TOP_DIR)/protocol/pjrc.mk include $(TOP_DIR)/protocol.mk +include $(TOP_DIR)/protocol/lufa.mk include $(TOP_DIR)/common.mk include $(TOP_DIR)/rules.mk diff --git a/converter/ps2_usb/config.h b/converter/ps2_usb/config.h index 51cd271d..1ad2bd1b 100644 --- a/converter/ps2_usb/config.h +++ b/converter/ps2_usb/config.h @@ -22,6 +22,7 @@ along with this program. If not, see . #define VENDOR_ID 0xFEED #define PRODUCT_ID 0x6512 +#define DEVICE_VER 0x0001 #define MANUFACTURER t.m.k. #define PRODUCT PS/2 keyboard converter #define DESCRIPTION convert PS/2 keyboard to USB @@ -39,10 +40,6 @@ along with this program. If not, see . ) -/* legacy keymap support */ -#define USE_LEGACY_KEYMAP - - #ifdef PS2_USE_USART #if defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) /* XCK for clock line and RXD for data line */ @@ -136,7 +133,7 @@ along with this program. If not, see . #define PS2_CLOCK_PORT PORTD #define PS2_CLOCK_PIN PIND #define PS2_CLOCK_DDR DDRD -#define PS2_CLOCK_BIT 1 +#define PS2_CLOCK_BIT 5 #define PS2_DATA_PORT PORTD #define PS2_DATA_PIN PIND #define PS2_DATA_DDR DDRD @@ -157,14 +154,14 @@ along with this program. If not, see . #ifdef PS2_USE_BUSYWAIT -#define PS2_CLOCK_PORT PORTF -#define PS2_CLOCK_PIN PINF -#define PS2_CLOCK_DDR DDRF -#define PS2_CLOCK_BIT 0 -#define PS2_DATA_PORT PORTF -#define PS2_DATA_PIN PINF -#define PS2_DATA_DDR DDRF -#define PS2_DATA_BIT 1 +#define PS2_CLOCK_PORT PORTD +#define PS2_CLOCK_PIN PIND +#define PS2_CLOCK_DDR DDRD +#define PS2_CLOCK_BIT 5 +#define PS2_DATA_PORT PORTD +#define PS2_DATA_PIN PIND +#define PS2_DATA_DDR DDRD +#define PS2_DATA_BIT 2 #endif #endif From d5ecbb83daa13b806ee4879692aaf807b6b1b69f Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 25 Nov 2013 17:39:45 +0900 Subject: [PATCH 28/76] Add printf macro as alias of xprintf --- common/print.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/print.h b/common/print.h index 930e84be..a828328b 100644 --- a/common/print.h +++ b/common/print.h @@ -40,6 +40,10 @@ #endif #define println(s) print_P(PSTR(s "\n")) +#ifndef AVR_LIBC_PRINTF +#define printf(f, ...) xprintf(f, ##__VA_ARGS__) +#endif + /* for old name */ #define pdec(data) print_dec(data) #define pdec16(data) print_dec(data) From 9ae9742ac59b18cf989370f53d669daeb75bd7a3 Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 25 Nov 2013 17:43:26 +0900 Subject: [PATCH 29/76] Add ps2_busywait.c and recfactor PS/2 protocol --- converter/ps2_usb/matrix.c | 28 ++++-- protocol.mk | 2 +- protocol/ps2.c | 65 +++++++++----- protocol/ps2.h | 142 ++++++++++++++++++++++++----- protocol/ps2_busywait.c | 179 +++++++++++++++++++++++++++++++++++++ 5 files changed, 363 insertions(+), 53 deletions(-) create mode 100644 protocol/ps2_busywait.c diff --git a/converter/ps2_usb/matrix.c b/converter/ps2_usb/matrix.c index 4187ea06..a4c27f5d 100644 --- a/converter/ps2_usb/matrix.c +++ b/converter/ps2_usb/matrix.c @@ -19,6 +19,7 @@ along with this program. If not, see . #include #include #include +#include "action.h" #include "print.h" #include "util.h" #include "debug.h" @@ -185,8 +186,8 @@ uint8_t matrix_scan(void) matrix_break(PAUSE); } - uint8_t code; - while ((code = ps2_host_recv())) { + uint8_t code = ps2_host_recv(); + if (!ps2_error) { switch (state) { case INIT: switch (code) { @@ -207,11 +208,17 @@ uint8_t matrix_scan(void) matrix_make(PRINT_SCREEN); state = INIT; break; + case 0x00: // Overrun [3]p.25 + print("Overrun\n"); + clear_keyboard(); + state = INIT; + break; default: // normal key make if (code < 0x80) { matrix_make(code); } else { - debug("unexpected scan code at INIT: "); debug_hex(code); debug("\n"); + printf("unexpected scan code at INIT: %02X\n", code); + clear_keyboard(); } state = INIT; } @@ -232,7 +239,8 @@ uint8_t matrix_scan(void) if (code < 0x80) { matrix_make(code|0x80); } else { - debug("unexpected scan code at E0: "); debug_hex(code); debug("\n"); + printf("unexpected scan code at E0: %02X\n", code); + clear_keyboard(); } state = INIT; } @@ -251,7 +259,8 @@ uint8_t matrix_scan(void) if (code < 0x80) { matrix_break(code); } else { - debug("unexpected scan code at F0: "); debug_hex(code); debug("\n"); + printf("unexpected scan code at F0: %02X\n", code); + clear_keyboard(); } state = INIT; } @@ -266,7 +275,8 @@ uint8_t matrix_scan(void) if (code < 0x80) { matrix_break(code|0x80); } else { - debug("unexpected scan code at E0_F0: "); debug_hex(code); debug("\n"); + printf("unexpected scan code at E0_F0: %02X\n", code); + clear_keyboard(); } state = INIT; } @@ -357,7 +367,11 @@ uint8_t matrix_scan(void) default: state = INIT; } - phex(code); + } + + if (ps2_error > PS2_ERR_STARTBIT3) { + uint8_t ret = ps2_host_send(PS2_RESEND); + printf("Resend: %02X\n", ret); } return 1; } diff --git a/protocol.mk b/protocol.mk index 0d5f06c7..e3320087 100644 --- a/protocol.mk +++ b/protocol.mk @@ -8,7 +8,7 @@ ifdef PS2_MOUSE_ENABLE endif ifdef PS2_USE_BUSYWAIT - SRC += protocol/ps2.c + SRC += protocol/ps2_busywait.c OPT_DEFS += -DPS2_USE_BUSYWAIT endif diff --git a/protocol/ps2.c b/protocol/ps2.c index e5873a9b..4886b16d 100644 --- a/protocol/ps2.c +++ b/protocol/ps2.c @@ -91,6 +91,9 @@ uint8_t ps2_error = PS2_ERR_NONE; void ps2_host_init(void) { + // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20) + _delay_ms(2500); + #ifdef PS2_USE_INT PS2_INT_INIT(); PS2_INT_ON(); @@ -163,23 +166,11 @@ ERROR: /* receive data when host want else inhibit communication */ uint8_t ps2_host_recv_response(void) { + // Command might take 20ms to response([3]p.21) + // TrackPoint might take 25ms ([5]2.7) uint8_t data = 0; - -#ifdef PS2_USE_INT - PS2_INT_OFF(); -#endif - /* terminate a transmission if we have */ - inhibit(); - _delay_us(100); - - /* release lines(idle state) */ - idle(); - - /* wait start bit */ - wait_clock_lo(25000); // command response may take 20 ms at most - data = recv_data(); - - inhibit(); + uint8_t try = 200; + while (try-- && (data = ps2_host_recv())) ; return data; } #endif @@ -187,7 +178,17 @@ uint8_t ps2_host_recv_response(void) #ifndef PS2_USE_INT uint8_t ps2_host_recv(void) { - return ps2_host_recv_response(); + uint8_t data = 0; + + /* release lines(idle state) */ + idle(); + + /* wait start bit */ + wait_clock_lo(100); // TODO: this is enough? + data = recv_data(); + + inhibit(); + return data; } #else /* ring buffer to store ps/2 key data */ @@ -241,13 +242,6 @@ static inline void pbuf_clear(void) /* get data received by interrupt */ uint8_t ps2_host_recv(void) { - if (ps2_error) { - print("x"); - phex(ps2_error); - ps2_host_send(0xFE); // request to resend - ps2_error = PS2_ERR_NONE; - } - idle(); return pbuf_dequeue(); } @@ -450,3 +444,26 @@ static inline void inhibit(void) clock_lo(); data_hi(); } + + +/* PS/2 Resources + * + * [1] The PS/2 Mouse/Keyboard Protocol + * http://www.computer-engineering.org/ps2protocol/ + * Concise and thorough primer of PS/2 protocol. + * + * [2] Keyboard and Auxiliary Device Controller + * http://www.mcamafia.de/pdf/ibm_hitrc07.pdf + * Signal Timing and Format + * + * [3] Keyboards(101- and 102-key) + * http://www.mcamafia.de/pdf/ibm_hitrc11.pdf + * Keyboard Layout, Scan Code Set, POR, and Commands. + * + * [4] PS/2 Reference Manuals + * http://www.mcamafia.de/pdf/ibm_hitrc07.pdf + * Collection of IBM Personal System/2 documents. + * + * [5] TrackPoint Engineering Specifications for version 3E + * https://web.archive.org/web/20100526161812/http://wwwcssrv.almaden.ibm.com/trackpoint/download.html + */ diff --git a/protocol/ps2.h b/protocol/ps2.h index 83416535..b780d01a 100644 --- a/protocol/ps2.h +++ b/protocol/ps2.h @@ -1,5 +1,5 @@ /* -Copyright 2010,2011 Jun WAKO +Copyright 2010,2011,2012,2013 Jun WAKO This software is licensed with a Modified BSD License. All of this is supposed to be Free Software, Open Source, DFSG-free, @@ -37,12 +37,60 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef PS2_H #define PS2_H + +#include +#include +#include + /* * Primitive PS/2 Library for AVR + * + * PS/2 Resources + * -------------- + * [1] The PS/2 Mouse/Keyboard Protocol + * http://www.computer-engineering.org/ps2protocol/ + * Concise and thorough primer of PS/2 protocol. + * + * [2] Keyboard and Auxiliary Device Controller + * http://www.mcamafia.de/pdf/ibm_hitrc07.pdf + * Signal Timing and Format + * + * [3] Keyboards(101- and 102-key) + * http://www.mcamafia.de/pdf/ibm_hitrc11.pdf + * Keyboard Layout, Scan Code Set, POR, and Commands. + * + * [4] PS/2 Reference Manuals + * http://www.mcamafia.de/pdf/ibm_hitrc07.pdf + * Collection of IBM Personal System/2 documents. + * + * [5] TrackPoint Engineering Specifications for version 3E + * https://web.archive.org/web/20100526161812/http://wwwcssrv.almaden.ibm.com/trackpoint/download.html */ +#define PS2_ACK 0xFA +#define PS2_RESEND 0xFE +#define PS2_SET_LED 0xED + +#define PS2_ERR_NONE 0 +#define PS2_ERR_STARTBIT1 1 +#define PS2_ERR_STARTBIT2 2 +#define PS2_ERR_STARTBIT3 3 +#define PS2_ERR_PARITY 0x10 + +#define PS2_LED_SCROLL_LOCK 0 +#define PS2_LED_NUM_LOCK 1 +#define PS2_LED_CAPS_LOCK 2 -/* port settings for clock and data line */ +extern uint8_t ps2_error; + +void ps2_host_init(void); +uint8_t ps2_host_send(uint8_t data); +uint8_t ps2_host_recv_response(void); +uint8_t ps2_host_recv(void); +void ps2_host_set_led(uint8_t usb_led); + + +/* Check port settings for clock and data line */ #if !(defined(PS2_CLOCK_PORT) && \ defined(PS2_CLOCK_PIN) && \ defined(PS2_CLOCK_DDR) && \ @@ -57,27 +105,79 @@ POSSIBILITY OF SUCH DAMAGE. # error "PS/2 data port setting is required in config.h" #endif -#define PS2_ACK 0xFA -#define PS2_RESEND 0xFE -#define PS2_SET_LED 0xED +/*-------------------------------------------------------------------- + * static functions + *------------------------------------------------------------------*/ +static inline void clock_lo(void) +{ + PS2_CLOCK_PORT &= ~(1< + +This software is licensed with a Modified BSD License. +All of this is supposed to be Free Software, Open Source, DFSG-free, +GPL-compatible, and OK to use in both free and proprietary applications. +Additions and corrections to this file are welcome. + + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +* Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include "ps2.h" +#include "debug.h" + + +/* + * PS/2 protocol busywait version + */ + +#define WAIT(stat, us, err) do { \ + if (!wait_##stat(us)) { \ + ps2_error = err; \ + goto ERROR; \ + } \ +} while (0) + +uint8_t ps2_error = PS2_ERR_NONE; + + +void ps2_host_init(void) +{ + // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20) + _delay_ms(2500); + + inhibit(); +} + +uint8_t ps2_host_send(uint8_t data) +{ + uint8_t res = 0; + bool parity = true; + ps2_error = PS2_ERR_NONE; + /* terminate a transmission if we have */ + inhibit(); + _delay_us(200); // at least 100us + + /* start bit [1] */ + data_lo(); + clock_hi(); + WAIT(clock_lo, 20000, 10); // may take 15ms at most until device starts clocking + /* data [2-9] */ + for (uint8_t i = 0; i < 8; i++) { + _delay_us(15); + if (data&(1< PS2_ERR_STARTBIT3) { + printf("x%02X\n", ps2_error); + } + inhibit(); + return 0; +} From 9d26053f1c14da79336a64f800305660d1a71180 Mon Sep 17 00:00:00 2001 From: tmk Date: Tue, 26 Nov 2013 14:31:57 +0900 Subject: [PATCH 30/76] Fix ps2_host_recv_response --- common/print.h | 4 ---- converter/ps2_usb/matrix.c | 10 +++++----- protocol/ps2_busywait.c | 11 +++++++---- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/common/print.h b/common/print.h index a828328b..930e84be 100644 --- a/common/print.h +++ b/common/print.h @@ -40,10 +40,6 @@ #endif #define println(s) print_P(PSTR(s "\n")) -#ifndef AVR_LIBC_PRINTF -#define printf(f, ...) xprintf(f, ##__VA_ARGS__) -#endif - /* for old name */ #define pdec(data) print_dec(data) #define pdec16(data) print_dec(data) diff --git a/converter/ps2_usb/matrix.c b/converter/ps2_usb/matrix.c index a4c27f5d..aa0c38c6 100644 --- a/converter/ps2_usb/matrix.c +++ b/converter/ps2_usb/matrix.c @@ -217,7 +217,7 @@ uint8_t matrix_scan(void) if (code < 0x80) { matrix_make(code); } else { - printf("unexpected scan code at INIT: %02X\n", code); + xprintf("unexpected scan code at INIT: %02X\n", code); clear_keyboard(); } state = INIT; @@ -239,7 +239,7 @@ uint8_t matrix_scan(void) if (code < 0x80) { matrix_make(code|0x80); } else { - printf("unexpected scan code at E0: %02X\n", code); + xprintf("unexpected scan code at E0: %02X\n", code); clear_keyboard(); } state = INIT; @@ -259,7 +259,7 @@ uint8_t matrix_scan(void) if (code < 0x80) { matrix_break(code); } else { - printf("unexpected scan code at F0: %02X\n", code); + xprintf("unexpected scan code at F0: %02X\n", code); clear_keyboard(); } state = INIT; @@ -275,7 +275,7 @@ uint8_t matrix_scan(void) if (code < 0x80) { matrix_break(code|0x80); } else { - printf("unexpected scan code at E0_F0: %02X\n", code); + xprintf("unexpected scan code at E0_F0: %02X\n", code); clear_keyboard(); } state = INIT; @@ -371,7 +371,7 @@ uint8_t matrix_scan(void) if (ps2_error > PS2_ERR_STARTBIT3) { uint8_t ret = ps2_host_send(PS2_RESEND); - printf("Resend: %02X\n", ret); + xprintf("Resend: %02X\n", ret); } return 1; } diff --git a/protocol/ps2_busywait.c b/protocol/ps2_busywait.c index 1e292588..5ab37787 100644 --- a/protocol/ps2_busywait.c +++ b/protocol/ps2_busywait.c @@ -104,6 +104,7 @@ uint8_t ps2_host_send(uint8_t data) WAIT(clock_hi, 50, 8); WAIT(data_hi, 50, 9); + inhibit(); res = ps2_host_recv_response(); ERROR: inhibit(); @@ -113,12 +114,14 @@ ERROR: /* receive data when host want else inhibit communication */ uint8_t ps2_host_recv_response(void) { - // TODO: // Command might take 20ms to response([3]p.21) // TrackPoint might take 25ms ([5]2.7) + // 250 * 100us(wait for start bit in ps2_host_recv) uint8_t data = 0; - uint8_t try = 200; - while (try-- && (data = ps2_host_recv())) ; + uint8_t try = 250; + do { + data = ps2_host_recv(); + } while (try-- && ps2_error); return data; } @@ -172,7 +175,7 @@ uint8_t ps2_host_recv(void) return data; ERROR: if (ps2_error > PS2_ERR_STARTBIT3) { - printf("x%02X\n", ps2_error); + xprintf("x%02X\n", ps2_error); } inhibit(); return 0; From 263c462656646a90295b4368d96e3ea09739bedf Mon Sep 17 00:00:00 2001 From: Shay Green Date: Tue, 26 Nov 2013 15:21:43 -0600 Subject: [PATCH 31/76] Fixed handling of ADB event with key down and key up for same key all in one --- converter/adb_usb/matrix.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/converter/adb_usb/matrix.c b/converter/adb_usb/matrix.c index d1b67d38..40539186 100644 --- a/converter/adb_usb/matrix.c +++ b/converter/adb_usb/matrix.c @@ -88,12 +88,26 @@ void matrix_init(void) uint8_t matrix_scan(void) { + /* extra_key is volatile and more convoluted than necessary because gcc refused + to generate valid code otherwise. Making extra_key uint8_t and constructing codes + here via codes = extra_key<<8 | 0xFF; would consistently fail to even LOAD + extra_key from memory, and leave garbage in the high byte of codes. I tried + dozens of code variations and it kept generating broken assembly output. So + beware if attempting to make extra_key code more logical and efficient. */ + static volatile uint16_t extra_key = 0xFFFF; uint16_t codes; uint8_t key0, key1; is_modified = false; - _delay_ms(12); // delay for preventing overload of poor ADB keyboard controller - codes = adb_host_kbd_recv(); + + codes = extra_key; + extra_key = 0xFFFF; + + if ( codes == 0xFFFF ) + { + _delay_ms(12); // delay for preventing overload of poor ADB keyboard controller + codes = adb_host_kbd_recv(); + } key0 = codes>>8; key1 = codes&0xFF; @@ -113,7 +127,7 @@ uint8_t matrix_scan(void) } else { register_key(key0); if (key1 != 0xFF) // key1 is 0xFF when no second key. - register_key(key1); + extra_key = key1<<8 | 0xFF; // process in a separate call } return 1; From 05792e2b83ea99009d895a4caad0e40b5395aff3 Mon Sep 17 00:00:00 2001 From: Benjamin Gould Date: Wed, 27 Nov 2013 00:24:57 -0500 Subject: [PATCH 32/76] Added bluefruit protocol and converter for 70% M --- converter/terminal_bluefruit/Makefile | 113 +++++++++++ converter/terminal_bluefruit/README | 37 ++++ converter/terminal_bluefruit/config.h | 112 +++++++++++ converter/terminal_bluefruit/keymap.c | 227 ++++++++++++++++++++++ converter/terminal_bluefruit/led.c | 35 ++++ converter/terminal_bluefruit/matrix.c | 262 ++++++++++++++++++++++++++ protocol/bluefruit.mk | 27 +++ protocol/bluefruit/bluefruit.c | 202 ++++++++++++++++++++ protocol/bluefruit/bluefruit.h | 28 +++ protocol/bluefruit/main.c | 116 ++++++++++++ 10 files changed, 1159 insertions(+) create mode 100644 converter/terminal_bluefruit/Makefile create mode 100644 converter/terminal_bluefruit/README create mode 100644 converter/terminal_bluefruit/config.h create mode 100644 converter/terminal_bluefruit/keymap.c create mode 100644 converter/terminal_bluefruit/led.c create mode 100644 converter/terminal_bluefruit/matrix.c create mode 100644 protocol/bluefruit.mk create mode 100644 protocol/bluefruit/bluefruit.c create mode 100644 protocol/bluefruit/bluefruit.h create mode 100644 protocol/bluefruit/main.c diff --git a/converter/terminal_bluefruit/Makefile b/converter/terminal_bluefruit/Makefile new file mode 100644 index 00000000..83d68fc2 --- /dev/null +++ b/converter/terminal_bluefruit/Makefile @@ -0,0 +1,113 @@ +# Target file name (without extension). +TARGET = terminal_bluefruit + +# Directory common source filess exist +TOP_DIR = ../.. + +# Directory keyboard dependent files exist +TARGET_DIR = . + +# keyboard dependent files +SRC = keymap.c \ + matrix.c \ + led.c + +CONFIG_H = config.h + +BLUEFRUIT_TRACE_SERIAL=true + +# MCU name, you MUST set this to match the board you are using +# type "make clean" after changing this, so all files will be rebuilt +#MCU = at90usb162 # Teensy 1.0 +MCU = atmega32u4 # Teensy 2.0 +#MCU = at90usb646 # Teensy++ 1.0 +#MCU = at90usb1286 # Teensy++ 2.0 + + +# Processor frequency. +# Normally the first thing your program should do is set the clock prescaler, +# so your program will run at the correct speed. You should also set this +# variable to same clock speed. The _delay_ms() macro uses this, and many +# examples use this variable to calculate timings. Do not add a "UL" here. +F_CPU = 16000000 + + +# +# LUFA specific +# +# Target architecture (see library "Board Types" documentation). +ARCH = AVR8 + +# Input clock frequency. +# This will define a symbol, F_USB, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_USB = $(F_CPU) + +# Interrupt driven control endpoint task +OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT + + +# Boot Section Size in bytes +# Teensy halfKay 512 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +OPT_DEFS += -DBOOTLOADER_SIZE=4096 + + +# Build Options +# comment out to disable the options. +# +BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE = yes # Mouse keys(+4700) +EXTRAKEY_ENABLE = yes # Audio control and System control(+450) +CONSOLE_ENABLE = yes # Console for debug(+400) +COMMAND_ENABLE = yes # Commands for debug and configuration +#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend +#NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA + + +# +# PS/2 protocol implementations +# USART is recommended if it is available, others are for reference purpose. +# INT implementation will drop simultaneous key strokes. +# +#PS2_USE_USART = yes # uses hardware USART engine for PS/2 signal receive(recomened) +PS2_USE_INT = yes # uses external interrupt for falling edge of PS/2 clock pin +#PS2_USE_BUSYWAIT = yes # uses primitive reference code + +ifdef PS2_USE_USART + SRC += protocol/ps2_usart.c + OPT_DEFS += -DPS2_USE_USART +endif + +ifdef PS2_USE_INT + SRC += protocol/ps2.c + OPT_DEFS += -DPS2_USE_INT +endif + +ifdef PS2_USE_BUSYWAIT + SRC += protocol/ps2.c + OPT_DEFS += -DPS2_USE_BUSYWAIT +endif + +#---------------- Programming Options -------------------------- +PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex + + +# Search Path +VPATH += $(TARGET_DIR) +VPATH += $(TOP_DIR) + + +include $(TOP_DIR)/protocol/bluefruit.mk +include $(TOP_DIR)/protocol.mk +include $(TOP_DIR)/common.mk +include $(TOP_DIR)/rules.mk diff --git a/converter/terminal_bluefruit/README b/converter/terminal_bluefruit/README new file mode 100644 index 00000000..6ff1bc92 --- /dev/null +++ b/converter/terminal_bluefruit/README @@ -0,0 +1,37 @@ +Keyboard converter for IBM terminal keyboard +============================================ +It supports PS/2 Scan Code Set 3 and runs on USB AVR chips such like PJRC Teensy. +I tested the converter on ATMega32U4 with 1392595(102keys) and 6110345(122keys). + +Source code: https://github.com/tmk/tmk_keyboard +Article: http://geekhack.org/index.php?topic=27272.0 + + +CONNECTION +---------- +Keyboard ATMega32U4 +---------------------- +Data: PD2 +Clock: PD5 + +And VCC and GND, of course. See RESOURCE for keyboard connector pin assign. + + +BUILD +----- +$ git clone https://github.com/tmk/tmk_keyboard.git +$ cd converter/terminal_usb +$ make + + +RESOURCE +-------- +Soarer's Converter: http://geekhack.org/index.php?topic=17458.0 +102keys(1392595): http://geekhack.org/index.php?topic=10737.0 +122keys(1390876): http://www.seasip.info/VintagePC/ibm_1390876.html +KbdBabel: http://www.kbdbabel.org/ +RJ45 Connector: http://www.kbdbabel.org/conn/kbd_connector_ibmterm.png +DIN Connector: http://www.kbdbabel.org/conn/kbd_connector_ibm3179_318x_319x.png +WinAVR: http://winavr.sourceforge.net/ + +EOF diff --git a/converter/terminal_bluefruit/config.h b/converter/terminal_bluefruit/config.h new file mode 100644 index 00000000..8bf139d3 --- /dev/null +++ b/converter/terminal_bluefruit/config.h @@ -0,0 +1,112 @@ +/* +Converter for 70% IBM Terminal Keyboard +Author: Benjamin Gould, 2013 +Based on code Copyright 2011 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef CONFIG_H +#define CONFIG_H + + +#define VENDOR_ID 0xFEED +#define PRODUCT_ID 0x6535 +#define DEVICE_VER 0x0100 +#define MANUFACTURER t.m.k. +#define PRODUCT 70% IBM Terminal Keyboard Converter w/ Bluetooth +#define DESCRIPTION USB converter for IBM Terminal Keyboard w/ Bluetooth + + +/* matrix size */ +#define MATRIX_ROWS 17 // keycode bit: 3-0 +#define MATRIX_COLS 8 // keycode bit: 6-4 + + +/* legacy keymap support */ +// #define USE_LEGACY_KEYMAP + + +/* key combination for command */ +#define IS_COMMAND() ( \ + (keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT))) || \ + (keyboard_report->mods == (MOD_BIT(KC_RALT) | MOD_BIT(KC_RCTL))) \ +) + +/* USART configuration + * asynchronous, 9600baud, 8-data bit, non parity, 1-stop bit, no flow control + */ +#ifdef __AVR_ATmega32U4__ + #define SERIAL_UART_BAUD 9600 + #define SERIAL_UART_DATA UDR1 + #define SERIAL_UART_UBRR ((F_CPU/(16UL*SERIAL_UART_BAUD))-1) + #define SERIAL_UART_RXD_VECT USART1_RX_vect + #define SERIAL_UART_TXD_READY (UCSR1A&(1<>8); /* baud rate */ \ + UCSR1B = (1< + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include +#include +#include +#include "keycode.h" +#include "print.h" +#include "debug.h" +#include "util.h" +#include "keymap.h" + + + + +/* + * IBM Terminal keyboard 6110345(122keys)/1392595(102keys) + * http://geekhack.org/showthread.php?10737-What-Can-I-Do-With-a-Terminal-Model-M + * http://www.seasip.info/VintagePC/ibm_1391406.html + * + * Keymap array: + * 8 bytes + * +---------+ + * 0| | + * :| | 0x00-0x87 + * ;| | + * 17| | + * +---------+ + */ +#define KEYMAP( \ + K08,K10,K18,K20,K28,K30,K38,K40,K48,K50,K57,K5F, \ + K07,K0F,K17,K1F,K27,K2F,K37,K3F,K47,K4F,K56,K5E, \ + \ + K05,K06, K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K5D,K66, K67,K6E,K6F, K76,K77,K7E,K84, \ + K04,K0C, K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B, K5C, K64,K65,K6D, K6C,K75,K7D,K7C, \ + K03,K0B, K14,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52, K53,K5A, K63, K6B,K73,K74,K7B, \ + K83,K0A, K12,K13,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K51,K59, K61,K62,K6A, K69,K72,K7A,K79, \ + K01,K09, K11, K19, K29, K39, K58, K60, K68,K70,K71,K78 \ +) { \ + { KC_NO, KC_##K01, KC_NO, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07 }, \ + { KC_##K08, KC_##K09, KC_##K0A, KC_##K0B, KC_##K0C, KC_##K0D, KC_##K0E, KC_##K0F }, \ + { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17 }, \ + { KC_##K18, KC_##K19, KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D, KC_##K1E, KC_##K1F }, \ + { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27 }, \ + { KC_##K28, KC_##K29, KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D, KC_##K2E, KC_##K2F }, \ + { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_##K37 }, \ + { KC_##K38, KC_##K39, KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D, KC_##K3E, KC_##K3F }, \ + { KC_##K40, KC_##K41, KC_##K42, KC_##K43, KC_##K44, KC_##K45, KC_##K46, KC_##K47 }, \ + { KC_##K48, KC_##K49, KC_##K4A, KC_##K4B, KC_##K4C, KC_##K4D, KC_##K4E, KC_##K4F }, \ + { KC_##K50, KC_##K51, KC_##K52, KC_##K53, KC_##K54, KC_##K55, KC_##K56, KC_##K57 }, \ + { KC_##K58, KC_##K59, KC_##K5A, KC_##K5B, KC_##K5C, KC_##K5D, KC_##K5E, KC_##K5F }, \ + { KC_##K60, KC_##K61, KC_##K62, KC_##K63, KC_##K64, KC_##K65, KC_##K66, KC_##K67 }, \ + { KC_##K68, KC_##K69, KC_##K6A, KC_##K6B, KC_##K6C, KC_##K6D, KC_##K6E, KC_##K6F }, \ + { KC_##K70, KC_##K71, KC_##K72, KC_##K73, KC_##K74, KC_##K75, KC_##K76, KC_##K77 }, \ + { KC_##K78, KC_##K79, KC_##K7A, KC_##K7B, KC_##K7C, KC_##K7D, KC_##K7E, KC_NO }, \ + { KC_NO, KC_NO, KC_NO, KC_##K83, KC_##K84, KC_NO, KC_NO, KC_NO, }, \ +} + +static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + /* 0: default + * ,---. ,---------------. ,---------------. ,---------------. ,-----------. + * |Esc| |F1 |F2 |F3 |F4 | |F5 |F6 |F7 |F8 | |F9 |F10|F11|F12| |PrS|ScL|Pau| + * `---' `---------------' `---------------' `---------------' `-----------' + * ,-----------------------------------------------------------. ,-----------. ,---------------. + * | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =| \|BS | |Ins|Hom|PgU| |NmL| /| *| -| + * |-----------------------------------------------------------| |-----------| |---------------| + * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| |Del|End|PgD| | 7| 8| 9| | + * |-----------------------------------------------------------| `-----------' |-----------| +| + * |CapsLo| A| S| D| F| G| H| J| K| L| ;| '| #|Retu| | 4| 5| 6| | + * |-----------------------------------------------------------| ,---. |---------------| + * |Shif| \| Z| X| C| V| B| N| M| ,| ,| /|Shift | |Up | | 1| 2| 3| | + * |-----------------------------------------------------------| ,-----------. |-----------|Ent| + * |Ctrl| |Alt | Space |Alt | |Ctrl| |Lef|Dow|Rig| | 0| .| | + * `----' `---------------------------------------' `----' `-----------' `---------------' + */ +/* + KEYMAP( + F13, F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24, + F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, + + PSCR,ESC, GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, JYEN,BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, + SLCK,INT4, TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC, BSLS, DEL, END, PGDN, P7, P8, P9, PPLS, + PAUS,INT5, CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, NUHS,ENT, UP, P4, P5, P6, PCMM, + APP, INT6, LSFT,NUBS,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RO, RSFT, LEFT,INT2,RGHT, P1, P2, P3, PENT, + RGUI,LGUI, LCTL, LALT, SPC, RALT, RCTL, DOWN, NO, P0, PDOT,NO + ), +*/ + /* + KEYMAP( + TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, + TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, + + TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS,TRNS,TRNS, TRNS,TRNS,TRNS,TRNS, + TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS, TRNS,TRNS,TRNS, TRNS,TRNS,TRNS,TRNS, + TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS,TRNS, TRNS, TRNS,TRNS,TRNS,TRNS, + TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS,TRNS, TRNS,TRNS,TRNS, TRNS,TRNS,TRNS,TRNS, + TRNS,TRNS, TRNS, TRNS, TRNS, TRNS, TRNS, TRNS, TRNS,TRNS,TRNS,TRNS + ), + */ + // pseudo ANSI + + KEYMAP( + FN0, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, + PSCR,PAUS,PGUP,PGDN,HOME,END, INS, DEL, LEFT,DOWN,UP, RGHT, + + NO, NO, ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, GRV, BSPC, NO, NO, NO, NO, NO, NO, NO, + NO, NO, TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC, BSLS, NO, NO, NO, NO, NO, NO, NO, + NO, NO, LCTL,A, S, D, F, G, H, J, K, L, SCLN,QUOT, BSLS,ENT, NO, NO, NO, NO, NO, + NO, NO, LSFT,FN1 ,Z, X, C, V, B, N, M, COMM,DOT, SLSH, FN1, RSFT, NO, NO, NO, NO, NO, NO, NO, + NO, NO, LCTL, LALT, SPC, LGUI, APP, NO, NO, NO, NO, NO + ), + + // Momentary Function Layer + KEYMAP( + TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, + TRNS,MUTE,VOLD,VOLU,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, + + TRNS,TRNS, TRNS,F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, TRNS,TRNS,TRNS, TRNS,TRNS,TRNS,TRNS, + TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,HOME,UP ,END, TRNS, TRNS,TRNS,TRNS, TRNS,TRNS,TRNS,TRNS, + TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,MS_L,MS_D,MS_U,MS_R,LEFT,DOWN, RGHT,TRNS, TRNS, TRNS,TRNS,TRNS,TRNS, + TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,PGUP,PGDN,TRNS, TRNS,RSFT, TRNS,TRNS,TRNS, TRNS,TRNS,TRNS,TRNS, + TRNS,TRNS, BTN2, TRNS, BTN1, RALT, RCTL, TRNS, TRNS,TRNS,TRNS,TRNS + ), + + // Mouse Layer + KEYMAP( + FN0, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, + TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, + + TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,NO, TRNS, NO, NO, NO, NO, NO, NO, NO, + TRNS,TRNS, TRNS,NO, NO, MS_U,NO, NO, WH_L,WH_D,WH_U,WH_R,NO, NO, NO, TRNS, NO, NO, NO, NO, NO, NO, NO, + TRNS,TRNS, BTN2,BTN1,MS_L,MS_D,MS_R,NO, MS_L,MS_D,MS_U,MS_R,NO, NO, NO, ENT, NO, NO, NO, NO, NO, + TRNS,TRNS, TRNS,TRNS,NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, RSFT, NO, NO, NO, NO, NO, NO, NO, + TRNS,TRNS, TRNS, TRNS, BTN1, BTN2, TRNS, NO, NO, NO, NO, NO + ), + + // vi Layer + KEYMAP( + FN0, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, + TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, + + TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,NO, TRNS, NO, NO, NO, NO, NO, NO, NO, + TRNS,TRNS, TRNS,HOME,PGDN,UP, PGUP,END, HOME,PGDN,PGUP,END, NO, NO, NO, TRNS, NO, NO, NO, NO, NO, NO, NO, + TRNS,TRNS, TRNS,NO, LEFT,DOWN,RGHT,NO, LEFT,DOWN,UP, RGHT,NO, NO, NO, ENT, NO, NO, NO, NO, NO, + TRNS,TRNS, TRNS,TRNS,NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, RSFT, NO, NO, NO, NO, NO, NO, NO, + TRNS,TRNS, TRNS, TRNS, SPC, RALT, RCTL, NO, NO, NO, NO, NO + ), + + // num lock layer + KEYMAP( + FN0, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, + TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, + + TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS,TRNS,TRNS, TRNS,TRNS,TRNS,TRNS, + TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS, TRNS,TRNS,TRNS, TRNS,TRNS,TRNS,TRNS, + TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS,TRNS, TRNS, TRNS,TRNS,TRNS,TRNS, + TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS,TRNS, TRNS,TRNS,TRNS, TRNS,TRNS,TRNS,TRNS, + TRNS,TRNS, TRNS, TRNS, TRNS, TRNS, TRNS, TRNS, TRNS,TRNS,TRNS,TRNS + ), + +}; + + +static const uint16_t fn_actions[] PROGMEM = { + [0] = ACTION_DEFAULT_LAYER_SET(0), + [1] = ACTION_LAYER_MOMENTARY(1), + [2] = ACTION_LAYER_MOMENTARY(2), //ACTION_LAYER_ON(2, ON_RELEASE), + [3] = KC_NO, //ACTION_LAYER_ON(3, ON_RELEASE), + [4] = KC_NO, //ACTION_LAYER_ON(4, ON_RELEASE), + [5] = KC_NO, + [6] = KC_NO, + [7] = KC_NO, +}; + +/* +enum macro_id { + MS_UL, + MS_UR, + MS_DL, + MS_DR, +}; + +const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) +{ + keyevent_t event = record->event; + + switch (id) { + case MS_UL: + return (event.pressed ? MACRO( D(MS_L), D(MS_U), END ) : MACRO( U(MS_L), U(MS_U), END ) ); + case MS_UR: + return (event.pressed ? MACRO( D(MS_R), D(MS_U), END ) : MACRO( U(MS_L), U(MS_U), END ) ); + case MS_DL: + return (event.pressed ? MACRO( D(MS_L), D(MS_D), END ) : MACRO( U(MS_L), U(MS_U), END ) ); + case MS_DR: + return (event.pressed ? MACRO( D(MS_R), D(MS_D), END ) : MACRO( U(MS_L), U(MS_U), END ) ); + } + return MACRO_NONE; +} +*/ + +uint8_t keymap_key_to_keycode(uint8_t layer, key_t key) +{ + return pgm_read_byte(&keymaps[(layer)][(key.row)][(key.col)]); +} + +action_t keymap_fn_to_action(uint8_t keycode) +{ + action_t action; + action.code = pgm_read_word(&fn_actions[FN_INDEX(keycode)]); + return action; +} diff --git a/converter/terminal_bluefruit/led.c b/converter/terminal_bluefruit/led.c new file mode 100644 index 00000000..e5bf41d4 --- /dev/null +++ b/converter/terminal_bluefruit/led.c @@ -0,0 +1,35 @@ +/* +Converter for 70% IBM Terminal Keyboard +Author: Benjamin Gould, 2013 +Based on code Copyright 2011 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "stdint.h" +#include "ps2.h" +#include "led.h" + + +void led_set(uint8_t usb_led) +{ + uint8_t ps2_led = 0; + if (usb_led & (1< + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include "print.h" +#include "util.h" +#include "debug.h" +#include "ps2.h" +#include "matrix.h" + + +static void matrix_make(uint8_t code); +static void matrix_break(uint8_t code); +#ifdef MATRIX_HAS_GHOST +static bool matrix_has_ghost_in_row(uint8_t row); +#endif + + +/* + * Matrix Array usage: + * 'Scan Code Set 3' is assigned into 17x8 cell matrix. + * + * 8bit wide + * +---------+ + * 0| | + * :| | 0x00-0x87 + * ;| | + * 17| | + * +---------+ + */ +static uint8_t matrix[MATRIX_ROWS]; +#define ROW(code) (code>>3) +#define COL(code) (code&0x07) + +static bool is_modified = false; + + +inline +uint8_t matrix_rows(void) +{ + return MATRIX_ROWS; +} + +inline +uint8_t matrix_cols(void) +{ + return MATRIX_COLS; +} + +void matrix_init(void) +{ + debug_enable = true; + //debug_matrix = true; + //debug_keyboard = true; + //debug_mouse = false; + + ps2_host_init(); + + // initialize matrix state: all keys off + for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; + + return; +} + +uint8_t matrix_scan(void) +{ + + // scan code reading states + static enum { + RESET, + RESET_RESPONSE, + KBD_ID0, + KBD_ID1, + CONFIG, + READY, + F0, + } state = RESET; + + is_modified = false; + + uint8_t code; + if ((code = ps2_host_recv())) { + debug("r"); debug_hex(code); debug(" "); + } + + switch (state) { + case RESET: + debug("wFF "); + if (ps2_host_send(0xFF) == 0xFA) { + debug("[ack]\nRESET_RESPONSE: "); + state = RESET_RESPONSE; + } + break; + case RESET_RESPONSE: + if (code == 0xAA) { + debug("[ok]\nKBD_ID: "); + state = KBD_ID0; + } else if (code) { + debug("err\nRESET: "); + state = RESET; + } + break; + // after reset receive keyboad ID(2 bytes) + case KBD_ID0: + if (code) { + state = KBD_ID1; + } + break; + case KBD_ID1: + if (code) { + debug("\nCONFIG: "); + state = CONFIG; + } + break; + case CONFIG: + debug("wF8 "); + if (ps2_host_send(0xF8) == 0xFA) { + debug("[ack]\nREADY\n"); + state = READY; + } + break; + case READY: + switch (code) { + case 0x00: + break; + case 0xF0: + state = F0; + debug(" "); + break; + default: // normal key make + if (code < 0x88) { + matrix_make(code); + } else { + debug("unexpected scan code at READY: "); debug_hex(code); debug("\n"); + } + state = READY; + debug("\n"); + } + break; + case F0: // Break code + switch (code) { + case 0x00: + break; + default: + if (code < 0x88) { + matrix_break(code); + } else { + debug("unexpected scan code at F0: "); debug_hex(code); debug("\n"); + } + state = READY; + debug("\n"); + } + break; + } + return 1; +} + +bool matrix_is_modified(void) +{ + return is_modified; +} + +inline +bool matrix_has_ghost(void) +{ +#ifdef MATRIX_HAS_GHOST + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + if (matrix_has_ghost_in_row(i)) + return true; + } +#endif + return false; +} + +inline +bool matrix_is_on(uint8_t row, uint8_t col) +{ + return (matrix[row] & (1< + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +#include +#include "host.h" +#include "report.h" +#include "print.h" +#include "debug.h" +#include "host_driver.h" +#include "serial.h" +#include "bluefruit.h" + +#define BLUEFRUIT_TRACE_SERIAL 1 + +static uint8_t bluefruit_keyboard_leds = 0; + +static void bluefruit_serial_send(uint8_t); + +void bluefruit_keyboard_print_report(report_keyboard_t *report) +{ + if (!debug_keyboard) return; + dprintf("keys: "); for (int i = 0; i < REPORT_KEYS; i++) { debug_hex8(report->keys[i]); dprintf(" "); } + dprintf(" mods: "); debug_hex8(report->mods); + dprintf(" reserved: "); debug_hex8(report->reserved); + dprintf("\n"); +} + +#ifdef BLUEFRUIT_TRACE_SERIAL +static void bluefruit_trace_header() +{ + dprintf("+------------------------------------+\n"); + dprintf("| HID report to Bluefruit via serial |\n"); + dprintf("+------------------------------------+\n|"); +} + +static void bluefruit_trace_footer() +{ + dprintf("|\n+------------------------------------+\n\n"); +} +#endif + +static void bluefruit_serial_send(uint8_t data) +{ +#ifdef BLUEFRUIT_TRACE_SERIAL + dprintf(" "); + debug_hex8(data); + dprintf(" "); +#endif + serial_send(data); +} + +/*------------------------------------------------------------------* + * Host driver + *------------------------------------------------------------------*/ + +static uint8_t keyboard_leds(void); +static void send_keyboard(report_keyboard_t *report); +static void send_mouse(report_mouse_t *report); +static void send_system(uint16_t data); +static void send_consumer(uint16_t data); + +static host_driver_t driver = { + keyboard_leds, + send_keyboard, + send_mouse, + send_system, + send_consumer +}; + +host_driver_t *bluefruit_driver(void) +{ + return &driver; +} + +static uint8_t keyboard_leds(void) { + return bluefruit_keyboard_leds; +} + +static void send_keyboard(report_keyboard_t *report) +{ +#ifdef BLUEFRUIT_TRACE_SERIAL + bluefruit_trace_header(); +#endif + bluefruit_serial_send(0xFD); + for (uint8_t i = 0; i < REPORT_SIZE; i++) { + bluefruit_serial_send(report->raw[i]); + } +#ifdef BLUEFRUIT_TRACE_SERIAL + bluefruit_trace_footer(); +#endif +} + +static void send_mouse(report_mouse_t *report) +{ +#ifdef BLUEFRUIT_TRACE_SERIAL + bluefruit_trace_header(); +#endif + bluefruit_serial_send(0xFD); + bluefruit_serial_send(0x00); + bluefruit_serial_send(0x03); + bluefruit_serial_send(report->buttons); + bluefruit_serial_send(report->x); + bluefruit_serial_send(report->y); + bluefruit_serial_send(report->v); // should try sending the wheel v here + bluefruit_serial_send(report->h); // should try sending the wheel h here + bluefruit_serial_send(0x00); +#ifdef BLUEFRUIT_TRACE_SERIAL + bluefruit_trace_footer(); +#endif +} + +static void send_system(uint16_t data) +{ +} + +/* ++-----------------+-------------------+-------+ +| Consumer Key | Bit Map | Hex | ++-----------------+-------------------+-------+ +| Home | 00000001 00000000 | 01 00 | +| KeyboardLayout | 00000010 00000000 | 02 00 | +| Search | 00000100 00000000 | 04 00 | +| Snapshot | 00001000 00000000 | 08 00 | +| VolumeUp | 00010000 00000000 | 10 00 | +| VolumeDown | 00100000 00000000 | 20 00 | +| Play/Pause | 01000000 00000000 | 40 00 | +| Fast Forward | 10000000 00000000 | 80 00 | +| Rewind | 00000000 00000001 | 00 01 | +| Scan Next Track | 00000000 00000010 | 00 02 | +| Scan Prev Track | 00000000 00000100 | 00 04 | +| Random Play | 00000000 00001000 | 00 08 | +| Stop | 00000000 00010000 | 00 10 | ++-------------------------------------+-------+ +*/ +#define CONSUMER2BLUEFRUIT(usage) \ + (usage == AUDIO_MUTE ? 0x0000 : \ + (usage == AUDIO_VOL_UP ? 0x1000 : \ + (usage == AUDIO_VOL_DOWN ? 0x2000 : \ + (usage == TRANSPORT_NEXT_TRACK ? 0x0002 : \ + (usage == TRANSPORT_PREV_TRACK ? 0x0004 : \ + (usage == TRANSPORT_STOP ? 0x0010 : \ + (usage == TRANSPORT_STOP_EJECT ? 0x0000 : \ + (usage == TRANSPORT_PLAY_PAUSE ? 0x4000 : \ + (usage == AL_CC_CONFIG ? 0x0000 : \ + (usage == AL_EMAIL ? 0x0000 : \ + (usage == AL_CALCULATOR ? 0x0000 : \ + (usage == AL_LOCAL_BROWSER ? 0x0000 : \ + (usage == AC_SEARCH ? 0x0400 : \ + (usage == AC_HOME ? 0x0100 : \ + (usage == AC_BACK ? 0x0000 : \ + (usage == AC_FORWARD ? 0x0000 : \ + (usage == AC_STOP ? 0x0000 : \ + (usage == AC_REFRESH ? 0x0000 : \ + (usage == AC_BOOKMARKS ? 0x0000 : 0))))))))))))))))))) + +static void send_consumer(uint16_t data) +{ + static uint16_t last_data = 0; + if (data == last_data) return; + last_data = data; + + uint16_t bitmap = CONSUMER2BLUEFRUIT(data); + +#ifdef BLUEFRUIT_TRACE_SERIAL + dprintf("\nData: "); + debug_hex16(data); + dprintf("; bitmap: "); + debug_hex16(bitmap); + dprintf("\n"); + bluefruit_trace_header(); +#endif + bluefruit_serial_send(0xFD); + bluefruit_serial_send(0x00); + bluefruit_serial_send(0x02); + bluefruit_serial_send((bitmap>>8)&0xFF); + bluefruit_serial_send(bitmap&0xFF); + bluefruit_serial_send(0x00); + bluefruit_serial_send(0x00); + bluefruit_serial_send(0x00); + bluefruit_serial_send(0x00); +#ifdef BLUEFRUIT_TRACE_SERIAL + bluefruit_trace_footer(); +#endif +} + diff --git a/protocol/bluefruit/bluefruit.h b/protocol/bluefruit/bluefruit.h new file mode 100644 index 00000000..4f9b5883 --- /dev/null +++ b/protocol/bluefruit/bluefruit.h @@ -0,0 +1,28 @@ +/* +Bluefruit Protocol for TMK firmware +Author: Benjamin Gould, 2013 +Based on code Copyright 2011 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef VUSB_H +#define VUSB_H + +#include "host_driver.h" + + +host_driver_t *bluefruit_driver(void); + +#endif diff --git a/protocol/bluefruit/main.c b/protocol/bluefruit/main.c new file mode 100644 index 00000000..871062ab --- /dev/null +++ b/protocol/bluefruit/main.c @@ -0,0 +1,116 @@ +/* +Bluefruit Protocol for TMK firmware +Author: Benjamin Gould, 2013 +Based on code Copyright 2011 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include +#include "serial.h" +#include "keyboard.h" +#include "usb.h" +#include "host.h" +#include "timer.h" +#include "print.h" +#include "debug.h" +#include "sendchar.h" +#include "suspend.h" +#include "bluefruit.h" +#include "pjrc.h" + +#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n)) + +#define HOST_DRIVER_NOT_SET 0 +#define BLUEFRUIT_HOST_DRIVER 1 +#define PJRC_HOST_DRIVER 2 + +int main(void) +{ + + CPU_PRESCALE(0); + + DDRD = _BV(PD5); + DDRB = _BV(PB0); + + PORTD = _BV(PD5); + PORTB = _BV(PB0); + + print_set_sendchar(sendchar); + + usb_init(); + _delay_ms(2000); + // while (!usb_configured()) /* wait */ + + dprintf("Initializing keyboard...\n"); + keyboard_init(); + + // This implementation is pretty simplistic... if the USB connection + // is not configured, choose the Bluefruit, otherwise use USB + // Definitely would prefer to have this driven by an input pin and make + // it switch dynamically - BCG + if (!usb_configured()) { + + // Send power to Bluefruit... Adafruit says it takes 27 mA, I think + // the pins should provide 40 mA, but just in case I switch the + // Bluefruit using a transistor - BCG + DDRB = _BV(PB6); + PORTB |= _BV(PB6); + + dprintf("Setting host driver to bluefruit...\n"); + host_set_driver(bluefruit_driver()); + + dprintf("Initializing serial...\n"); + serial_init(); + + // wait an extra second for the PC's operating system + // to load drivers and do whatever it does to actually + // be ready for input + _delay_ms(1000); + PORTD = ~_BV(PD5); + dprintf("Starting main loop"); + while (1) { + keyboard_task(); + } + + } else { + + // I'm not smart enough to get this done with LUFA - BCG + dprintf("Setting host driver to PJRC...\n"); + host_set_driver(pjrc_driver()); +#ifdef SLEEP_LED_ENABLE + sleep_led_init(); +#endif + // wait an extra second for the PC's operating system + // to load drivers and do whatever it does to actually + // be ready for input + _delay_ms(1000); + PORTB = ~_BV(PB0); + dprintf("Starting main loop"); + while (1) { + while (suspend) { + suspend_power_down(); + if (remote_wakeup && suspend_wakeup_condition()) { + usb_remote_wakeup(); + } + } + keyboard_task(); + } + } + +} From f7db144959461d9b817752f7c6ca34b34d275cff Mon Sep 17 00:00:00 2001 From: Benjamin Gould Date: Wed, 27 Nov 2013 00:32:20 -0500 Subject: [PATCH 33/76] changed tabs to spaces in bluefruit.c --- protocol/bluefruit/bluefruit.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/protocol/bluefruit/bluefruit.c b/protocol/bluefruit/bluefruit.c index bdc3de3e..f991e4d0 100644 --- a/protocol/bluefruit/bluefruit.c +++ b/protocol/bluefruit/bluefruit.c @@ -45,14 +45,14 @@ void bluefruit_keyboard_print_report(report_keyboard_t *report) #ifdef BLUEFRUIT_TRACE_SERIAL static void bluefruit_trace_header() { - dprintf("+------------------------------------+\n"); - dprintf("| HID report to Bluefruit via serial |\n"); - dprintf("+------------------------------------+\n|"); + dprintf("+------------------------------------+\n"); + dprintf("| HID report to Bluefruit via serial |\n"); + dprintf("+------------------------------------+\n|"); } static void bluefruit_trace_footer() { - dprintf("|\n+------------------------------------+\n\n"); + dprintf("|\n+------------------------------------+\n\n"); } #endif @@ -103,7 +103,7 @@ static void send_keyboard(report_keyboard_t *report) bluefruit_serial_send(report->raw[i]); } #ifdef BLUEFRUIT_TRACE_SERIAL - bluefruit_trace_footer(); + bluefruit_trace_footer(); #endif } From 532e100450615ef1e63e2eed548c38d0c4fa688b Mon Sep 17 00:00:00 2001 From: tmk Date: Thu, 28 Nov 2013 10:42:41 +0900 Subject: [PATCH 34/76] Add ps2_usart.c and fix set_led at USB wake --- protocol/lufa/lufa.c | 4 +- protocol/pjrc/usb.c | 3 +- protocol/ps2.h | 2 + protocol/ps2_usart.c | 146 +++++++------------------------------------ 4 files changed, 29 insertions(+), 126 deletions(-) diff --git a/protocol/lufa/lufa.c b/protocol/lufa/lufa.c index 04e8e78f..eca51c87 100644 --- a/protocol/lufa/lufa.c +++ b/protocol/lufa/lufa.c @@ -148,7 +148,6 @@ static void Console_Task(void) */ void EVENT_USB_Device_Connect(void) { - led_set(0x1f); // all on } void EVENT_USB_Device_Disconnect(void) @@ -172,8 +171,9 @@ void EVENT_USB_Device_WakeUp() #ifdef SLEEP_LED_ENABLE sleep_led_disable(); -#endif + // NOTE: converters may not accept this led_set(host_keyboard_leds()); +#endif } void EVENT_USB_Device_StartOfFrame(void) diff --git a/protocol/pjrc/usb.c b/protocol/pjrc/usb.c index 84c99972..393b36f7 100644 --- a/protocol/pjrc/usb.c +++ b/protocol/pjrc/usb.c @@ -662,8 +662,9 @@ ISR(USB_GEN_vect) suspend_wakeup_init(); #ifdef SLEEP_LED_ENABLE sleep_led_disable(); -#endif + // NOTE: converters may not accept this led_set(host_keyboard_leds()); +#endif UDIEN |= (1< #include #include @@ -75,18 +58,6 @@ http://www.mcamafia.de/pdf/ibm_hitrc07.pdf uint8_t ps2_error = PS2_ERR_NONE; -static inline void clock_lo(void); -static inline void clock_hi(void); -static inline bool clock_in(void); -static inline void data_lo(void); -static inline void data_hi(void); -static inline bool data_in(void); -static inline uint16_t wait_clock_lo(uint16_t us); -static inline uint16_t wait_clock_hi(uint16_t us); -static inline uint16_t wait_data_lo(uint16_t us); -static inline uint16_t wait_data_hi(uint16_t us); -static inline void idle(void); -static inline void inhibit(void); static inline uint8_t pbuf_dequeue(void); static inline void pbuf_enqueue(uint8_t data); static inline bool pbuf_has_data(void); @@ -95,14 +66,15 @@ static inline void pbuf_clear(void); void ps2_host_init(void) { - idle(); + idle(); // without this many USART errors occur when cable is disconnected PS2_USART_INIT(); PS2_USART_RX_INT_ON(); + // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20) + //_delay_ms(2500); } uint8_t ps2_host_send(uint8_t data) { - uint8_t res = 0; bool parity = true; ps2_error = PS2_ERR_NONE; @@ -144,20 +116,22 @@ uint8_t ps2_host_send(uint8_t data) WAIT(clock_hi, 50, 8); WAIT(data_hi, 50, 9); + idle(); PS2_USART_INIT(); PS2_USART_RX_INT_ON(); - res = ps2_host_recv_response(); + return ps2_host_recv_response(); ERROR: idle(); PS2_USART_INIT(); PS2_USART_RX_INT_ON(); - return res; + return 0; } // Do polling data from keyboard to get response to last command. uint8_t ps2_host_recv_response(void) { - while (!pbuf_has_data()) { + uint8_t retry = 25; + while (retry-- && !pbuf_has_data()) { _delay_ms(1); // without this delay it seems to fall into deadlock } return pbuf_dequeue(); @@ -165,106 +139,32 @@ uint8_t ps2_host_recv_response(void) uint8_t ps2_host_recv(void) { - return pbuf_dequeue(); + if (pbuf_has_data()) { + ps2_error = PS2_ERR_NONE; + return pbuf_dequeue(); + } else { + ps2_error = PS2_ERR_NODATA; + return 0; + } } ISR(PS2_USART_RX_VECT) { - uint8_t error = PS2_USART_ERROR; + // TODO: request RESEND when error occurs? + uint8_t error = PS2_USART_ERROR; // USART error should be read before data uint8_t data = PS2_USART_RX_DATA; if (!error) { pbuf_enqueue(data); + } else { + xprintf("PS2 USART error: %02X data: %02X\n", error, data); } } /* send LED state to keyboard */ void ps2_host_set_led(uint8_t led) { - // send 0xED then keyboard keeps waiting for next LED data - // and keyboard does not send any scan codes during waiting. - // If fail to send LED data keyboard looks like being freezed. - uint8_t retry = 3; - while (retry-- && ps2_host_send(PS2_SET_LED) != PS2_ACK) - ; - retry = 3; - while (retry-- && ps2_host_send(led) != PS2_ACK) - ; -} - - -/*-------------------------------------------------------------------- - * static functions - *------------------------------------------------------------------*/ -static inline void clock_lo() -{ - PS2_CLOCK_PORT &= ~(1< Date: Thu, 28 Nov 2013 14:20:00 +0900 Subject: [PATCH 35/76] Add ps2_interrupt.c --- protocol.mk | 2 +- protocol/ps2_busywait.c | 51 ++-- protocol/{ps2.c => ps2_interrupt.c} | 358 +++++++--------------------- protocol/ps2_usart.c | 23 +- 4 files changed, 124 insertions(+), 310 deletions(-) rename protocol/{ps2.c => ps2_interrupt.c} (51%) diff --git a/protocol.mk b/protocol.mk index e3320087..7f561e62 100644 --- a/protocol.mk +++ b/protocol.mk @@ -13,7 +13,7 @@ ifdef PS2_USE_BUSYWAIT endif ifdef PS2_USE_INT - SRC += protocol/ps2.c + SRC += protocol/ps2_interrupt.c OPT_DEFS += -DPS2_USE_INT endif diff --git a/protocol/ps2_busywait.c b/protocol/ps2_busywait.c index 5ab37787..05dd7b27 100644 --- a/protocol/ps2_busywait.c +++ b/protocol/ps2_busywait.c @@ -35,16 +35,16 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* + * PS/2 protocol busywait version + */ + #include #include #include "ps2.h" #include "debug.h" -/* - * PS/2 protocol busywait version - */ - #define WAIT(stat, us, err) do { \ if (!wait_##stat(us)) { \ ps2_error = err; \ @@ -52,6 +52,7 @@ POSSIBILITY OF SUCH DAMAGE. } \ } while (0) + uint8_t ps2_error = PS2_ERR_NONE; @@ -65,18 +66,19 @@ void ps2_host_init(void) uint8_t ps2_host_send(uint8_t data) { - uint8_t res = 0; bool parity = true; ps2_error = PS2_ERR_NONE; + /* terminate a transmission if we have */ inhibit(); - _delay_us(200); // at least 100us + _delay_us(100); // 100us [4]p.13, [5]p.50 - /* start bit [1] */ + /* 'Request to Send' and Start bit */ data_lo(); clock_hi(); - WAIT(clock_lo, 20000, 10); // may take 15ms at most until device starts clocking - /* data [2-9] */ + WAIT(clock_lo, 10000, 10); // 10ms [5]p.50 + + /* Data bit */ for (uint8_t i = 0; i < 8; i++) { _delay_us(15); if (data&(1< -#include -#include #include #include "ps2.h" #include "debug.h" -#ifndef PS2_USE_INT -static uint8_t recv_data(void); -#endif -static inline void clock_lo(void); -static inline void clock_hi(void); -static inline bool clock_in(void); -static inline void data_lo(void); -static inline void data_hi(void); -static inline bool data_in(void); -static inline uint16_t wait_clock_lo(uint16_t us); -static inline uint16_t wait_clock_hi(uint16_t us); -static inline uint16_t wait_data_lo(uint16_t us); -static inline uint16_t wait_data_hi(uint16_t us); -static inline void idle(void); -static inline void inhibit(void); - - -/* -Primitive PS/2 Library for AVR -============================== -Host side is only supported now. - - -I/O control ------------ -High state is asserted by input with pull up. - - -PS/2 References ---------------- -http://www.computer-engineering.org/ps2protocol/ -http://www.mcamafia.de/pdf/ibm_hitrc07.pdf -*/ - - #define WAIT(stat, us, err) do { \ if (!wait_##stat(us)) { \ ps2_error = err; \ @@ -89,38 +56,38 @@ http://www.mcamafia.de/pdf/ibm_hitrc07.pdf uint8_t ps2_error = PS2_ERR_NONE; +static inline uint8_t pbuf_dequeue(void); +static inline void pbuf_enqueue(uint8_t data); +static inline bool pbuf_has_data(void); +static inline void pbuf_clear(void); + + void ps2_host_init(void) { - // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20) - _delay_ms(2500); - -#ifdef PS2_USE_INT + idle(); PS2_INT_INIT(); PS2_INT_ON(); - idle(); -#else - inhibit(); -#endif + // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20) + //_delay_ms(2500); } -// TODO: send using interrupt if available uint8_t ps2_host_send(uint8_t data) { - uint8_t res = 0; bool parity = true; ps2_error = PS2_ERR_NONE; -#ifdef PS2_USE_INT + PS2_INT_OFF(); -#endif + /* terminate a transmission if we have */ inhibit(); - _delay_us(200); // at least 100us + _delay_us(100); // 100us [4]p.13, [5]p.50 - /* start bit [1] */ + /* 'Request to Send' and Start bit */ data_lo(); clock_hi(); - WAIT(clock_lo, 20000, 10); // may take 15ms at most until device starts clocking - /* data [2-9] */ + WAIT(clock_lo, 10000, 10); // 10ms [5]p.50 + + /* Data bit[2-9] */ for (uint8_t i = 0; i < 8; i++) { _delay_us(15); if (data&(1< Date: Thu, 28 Nov 2013 14:42:41 +0900 Subject: [PATCH 36/76] Fix pin configuration of onekey for PS/2 mouse --- keyboard/onekey/{Makefile.lufa => Makefile} | 4 ++-- keyboard/onekey/README.md | 2 +- keyboard/onekey/config.h | 4 ++-- keyboard/onekey/matrix.c | 18 +++++++++--------- 4 files changed, 14 insertions(+), 14 deletions(-) rename keyboard/onekey/{Makefile.lufa => Makefile} (97%) diff --git a/keyboard/onekey/Makefile.lufa b/keyboard/onekey/Makefile similarity index 97% rename from keyboard/onekey/Makefile.lufa rename to keyboard/onekey/Makefile index 60a84ba0..78732e47 100644 --- a/keyboard/onekey/Makefile.lufa +++ b/keyboard/onekey/Makefile @@ -116,8 +116,8 @@ CONSOLE_ENABLE = yes # Console for debug(+400) #SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend #NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA -PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support -PS2_USE_BUSYWAIT = yes # uses primitive reference code +#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support +#PS2_USE_BUSYWAIT = yes # uses primitive reference code #PS2_USE_INT = yes # uses external interrupt for falling edge of PS/2 clock pin #PS2_USE_USART = yes # uses hardware USART engine for PS/2 signal receive(recomened) diff --git a/keyboard/onekey/README.md b/keyboard/onekey/README.md index 6ccc9992..7413f388 100644 --- a/keyboard/onekey/README.md +++ b/keyboard/onekey/README.md @@ -1,5 +1,5 @@ Onekey ====== -Just one key keyboard for example. It sends 'a' key if pins PD0 and PD1 are short-circuited. +Just one key keyboard for example. It sends 'a' key if pins PB0 and PB1 are short-circuited. https://github.com/tmk/tmk_keyboard/issues/56 diff --git a/keyboard/onekey/config.h b/keyboard/onekey/config.h index 1d2e052b..bf1d2b1e 100644 --- a/keyboard/onekey/config.h +++ b/keyboard/onekey/config.h @@ -73,7 +73,7 @@ along with this program. If not, see . # define PS2_CLOCK_PORT PORTD # define PS2_CLOCK_PIN PIND # define PS2_CLOCK_DDR DDRD -# define PS2_CLOCK_BIT 5 +# define PS2_CLOCK_BIT 1 # define PS2_DATA_PORT PORTD # define PS2_DATA_PIN PIND # define PS2_DATA_DDR DDRD @@ -87,7 +87,7 @@ along with this program. If not, see . #define PS2_CLOCK_PORT PORTD #define PS2_CLOCK_PIN PIND #define PS2_CLOCK_DDR DDRD -#define PS2_CLOCK_BIT 5 +#define PS2_CLOCK_BIT 1 #define PS2_DATA_PORT PORTD #define PS2_DATA_PIN PIND #define PS2_DATA_DDR DDRD diff --git a/keyboard/onekey/matrix.c b/keyboard/onekey/matrix.c index a0a14ff8..29df8683 100644 --- a/keyboard/onekey/matrix.c +++ b/keyboard/onekey/matrix.c @@ -139,29 +139,29 @@ uint8_t matrix_key_count(void) /* Column pin configuration * col: 0 - * pin: D0 + * pin: B0 */ static void init_cols(void) { // Input with pull-up(DDR:0, PORT:1) - DDRD &= ~(1<<0); - PORTD |= (1<<0); + DDRB &= ~(1<<0); + PORTB |= (1<<0); } static matrix_row_t read_cols(void) { - return (PIND&(1<<0) ? 0 : (1<<0)); + return (PINB&(1<<0) ? 0 : (1<<0)); } /* Row pin configuration * row: 0 - * pin: D1 + * pin: B1 */ static void unselect_rows(void) { // Hi-Z(DDR:0, PORT:0) to unselect - DDRD &= ~0b00000010; - PORTD &= ~0b00000010; + DDRB &= ~0b00000010; + PORTB &= ~0b00000010; } static void select_row(uint8_t row) @@ -169,8 +169,8 @@ static void select_row(uint8_t row) // Output low(DDR:1, PORT:0) to select switch (row) { case 0: - DDRD |= (1<<1); - PORTD &= ~(1<<1); + DDRB |= (1<<1); + PORTB &= ~(1<<1); break; } } From 8b4fa599cf485f5d06314938a228a88dabb0b7f5 Mon Sep 17 00:00:00 2001 From: tmk Date: Thu, 28 Nov 2013 14:44:59 +0900 Subject: [PATCH 37/76] Add included header file and fix debug print --- protocol/ps2_interrupt.c | 5 +++-- protocol/ps2_usart.c | 5 ++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/protocol/ps2_interrupt.c b/protocol/ps2_interrupt.c index 355d4e82..259d2540 100644 --- a/protocol/ps2_interrupt.c +++ b/protocol/ps2_interrupt.c @@ -40,9 +40,10 @@ POSSIBILITY OF SUCH DAMAGE. */ #include +#include #include #include "ps2.h" -#include "debug.h" +#include "print.h" #define WAIT(stat, us, err) do { \ @@ -241,7 +242,7 @@ static inline void pbuf_enqueue(uint8_t data) pbuf[pbuf_head] = data; pbuf_head = next; } else { - debug("pbuf: full\n"); + print("pbuf: full\n"); } SREG = sreg; } diff --git a/protocol/ps2_usart.c b/protocol/ps2_usart.c index 27947143..c2d9d0a2 100644 --- a/protocol/ps2_usart.c +++ b/protocol/ps2_usart.c @@ -40,11 +40,10 @@ POSSIBILITY OF SUCH DAMAGE. */ #include -#include #include #include #include "ps2.h" -#include "debug.h" +#include "print.h" #define WAIT(stat, us, err) do { \ @@ -188,7 +187,7 @@ static inline void pbuf_enqueue(uint8_t data) pbuf[pbuf_head] = data; pbuf_head = next; } else { - debug("pbuf: full\n"); + print("pbuf: full\n"); } SREG = sreg; } From 10b2b1ae431b31b2ae29228dcaccb5ea292bbf9a Mon Sep 17 00:00:00 2001 From: tmk Date: Thu, 28 Nov 2013 15:50:17 +0900 Subject: [PATCH 38/76] Fix key stack and PS/2 Overrun --- converter/ps2_usb/config.h | 86 ++++++++++++++++++++------------------ converter/ps2_usb/matrix.c | 33 ++++++++++++--- 2 files changed, 73 insertions(+), 46 deletions(-) diff --git a/converter/ps2_usb/config.h b/converter/ps2_usb/config.h index 1ad2bd1b..c9bab1b0 100644 --- a/converter/ps2_usb/config.h +++ b/converter/ps2_usb/config.h @@ -40,6 +40,52 @@ along with this program. If not, see . ) +//#define NO_SUSPEND_POWER_DOWN + + +/* + * PS/2 Busywait + */ +#ifdef PS2_USE_BUSYWAIT +#define PS2_CLOCK_PORT PORTD +#define PS2_CLOCK_PIN PIND +#define PS2_CLOCK_DDR DDRD +#define PS2_CLOCK_BIT 5 +#define PS2_DATA_PORT PORTD +#define PS2_DATA_PIN PIND +#define PS2_DATA_DDR DDRD +#define PS2_DATA_BIT 2 +#endif + +/* + * PS/2 Pin interrupt + */ +#ifdef PS2_USE_INT +/* uses INT1 for clock line(ATMega32U4) */ +#define PS2_CLOCK_PORT PORTD +#define PS2_CLOCK_PIN PIND +#define PS2_CLOCK_DDR DDRD +#define PS2_CLOCK_BIT 1 +#define PS2_DATA_PORT PORTD +#define PS2_DATA_PIN PIND +#define PS2_DATA_DDR DDRD +#define PS2_DATA_BIT 2 +#define PS2_INT_INIT() do { \ + EICRA |= ((1<. #define PS2_DATA_PIN PIND #define PS2_DATA_DDR DDRD #define PS2_DATA_BIT 2 - /* synchronous, odd parity, 1-bit stop, 8-bit data, sample at falling edge */ /* set DDR of CLOCK as input to be slave */ #define PS2_USART_INIT() do { \ @@ -82,7 +127,6 @@ along with this program. If not, see . #define PS2_USART_RX_DATA UDR1 #define PS2_USART_ERROR (UCSR1A & ((1<. #define PS2_DATA_PIN PIND #define PS2_DATA_DDR DDRD #define PS2_DATA_BIT 0 - /* synchronous, odd parity, 1-bit stop, 8-bit data, sample at falling edge */ /* set DDR of CLOCK as input to be slave */ #define PS2_USART_INIT() do { \ @@ -127,41 +170,4 @@ along with this program. If not, see . #endif #endif - -#ifdef PS2_USE_INT -/* uses INT1 for clock line(ATMega32U4) */ -#define PS2_CLOCK_PORT PORTD -#define PS2_CLOCK_PIN PIND -#define PS2_CLOCK_DDR DDRD -#define PS2_CLOCK_BIT 5 -#define PS2_DATA_PORT PORTD -#define PS2_DATA_PIN PIND -#define PS2_DATA_DDR DDRD -#define PS2_DATA_BIT 2 - -#define PS2_INT_INIT() do { \ - EICRA |= ((1<. static void matrix_make(uint8_t code); static void matrix_break(uint8_t code); +static void matrix_clear(void); #ifdef MATRIX_HAS_GHOST static bool matrix_has_ghost_in_row(uint8_t row); #endif @@ -84,6 +85,7 @@ uint8_t matrix_cols(void) void matrix_init(void) { + debug_enable = true; ps2_host_init(); // initialize matrix state: all keys off @@ -209,16 +211,18 @@ uint8_t matrix_scan(void) state = INIT; break; case 0x00: // Overrun [3]p.25 - print("Overrun\n"); + matrix_clear(); clear_keyboard(); + print("Overrun\n"); state = INIT; break; default: // normal key make if (code < 0x80) { matrix_make(code); } else { - xprintf("unexpected scan code at INIT: %02X\n", code); + matrix_clear(); clear_keyboard(); + xprintf("unexpected scan code at INIT: %02X\n", code); } state = INIT; } @@ -239,8 +243,9 @@ uint8_t matrix_scan(void) if (code < 0x80) { matrix_make(code|0x80); } else { - xprintf("unexpected scan code at E0: %02X\n", code); + matrix_clear(); clear_keyboard(); + xprintf("unexpected scan code at E0: %02X\n", code); } state = INIT; } @@ -255,12 +260,18 @@ uint8_t matrix_scan(void) matrix_break(PRINT_SCREEN); state = INIT; break; + case 0xF0: + matrix_clear(); + clear_keyboard(); + xprintf("unexpected scan code at F0: F0(clear and cont.)\n"); + break; default: if (code < 0x80) { matrix_break(code); } else { - xprintf("unexpected scan code at F0: %02X\n", code); + matrix_clear(); clear_keyboard(); + xprintf("unexpected scan code at F0: %02X\n", code); } state = INIT; } @@ -275,8 +286,9 @@ uint8_t matrix_scan(void) if (code < 0x80) { matrix_break(code|0x80); } else { - xprintf("unexpected scan code at E0_F0: %02X\n", code); + matrix_clear(); clear_keyboard(); + xprintf("unexpected scan code at E0_F0: %02X\n", code); } state = INIT; } @@ -369,10 +381,13 @@ uint8_t matrix_scan(void) } } - if (ps2_error > PS2_ERR_STARTBIT3) { + // TODO: request RESEND when error occurs? +/* + if (PS2_IS_FAILED(ps2_error)) { uint8_t ret = ps2_host_send(PS2_RESEND); xprintf("Resend: %02X\n", ret); } +*/ return 1; } @@ -464,3 +479,9 @@ static void matrix_break(uint8_t code) is_modified = true; } } + +inline +static void matrix_clear(void) +{ + for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; +} From 0b9c0f6012a90eeb8cced9feccf3a65d8b4e5535 Mon Sep 17 00:00:00 2001 From: tmk Date: Thu, 28 Nov 2013 16:00:16 +0900 Subject: [PATCH 39/76] Add new keymap file --- converter/ps2_usb/Makefile.pjrc | 75 ++++++ converter/ps2_usb/keymap.c | 379 ------------------------------ converter/ps2_usb/keymap_common.c | 30 +++ converter/ps2_usb/keymap_common.h | 174 ++++++++++++++ converter/ps2_usb/keymap_plain.c | 50 ++++ 5 files changed, 329 insertions(+), 379 deletions(-) create mode 100644 converter/ps2_usb/Makefile.pjrc delete mode 100644 converter/ps2_usb/keymap.c create mode 100644 converter/ps2_usb/keymap_common.c create mode 100644 converter/ps2_usb/keymap_common.h create mode 100644 converter/ps2_usb/keymap_plain.c diff --git a/converter/ps2_usb/Makefile.pjrc b/converter/ps2_usb/Makefile.pjrc new file mode 100644 index 00000000..0e175f8b --- /dev/null +++ b/converter/ps2_usb/Makefile.pjrc @@ -0,0 +1,75 @@ +# Target file name (without extension). +TARGET = ps2_usb_pjrc + +# Directory common source filess exist +TOP_DIR = ../.. + +# Directory keyboard dependent files exist +TARGET_DIR = . + +# keyboard dependent files +SRC = keymap_common.c \ + matrix.c \ + led.c + +ifdef KEYMAP + SRC := keymap_$(KEYMAP).c $(SRC) +else + SRC := keymap_plain.c $(SRC) +endif + +CONFIG_H = config.h + + +# MCU name, you MUST set this to match the board you are using +# type "make clean" after changing this, so all files will be rebuilt +#MCU = at90usb162 # Teensy 1.0 +MCU = atmega32u4 # Teensy 2.0 +#MCU = at90usb646 # Teensy++ 1.0 +#MCU = at90usb1286 # Teensy++ 2.0 + + +# Processor frequency. +# Normally the first thing your program should do is set the clock prescaler, +# so your program will run at the correct speed. You should also set this +# variable to same clock speed. The _delay_ms() macro uses this, and many +# examples use this variable to calculate timings. Do not add a "UL" here. +F_CPU = 16000000 + + +# Boot Section Size in *bytes* +# Teensy halfKay 512 +# Teensy++ halfKay 1024 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +# USBaspLoader 2048 +OPT_DEFS += -DBOOTLOADER_SIZE=4096 + + +# Build Options +# *Comment out* to disable the options. +# +#BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE = yes # Mouse keys +EXTRAKEY_ENABLE = yes # Audio control and System control +CONSOLE_ENABLE = yes # Console for debug(+400) +COMMAND_ENABLE = yes # Commands for debug and configuration +NKRO_ENABLE = yes # USB Nkey Rollover + + +# PS/2 Options +# +#PS2_USE_USART = yes # uses hardware USART engine for PS/2 signal receive(recomened) +#PS2_USE_INT = yes # uses external interrupt for falling edge of PS/2 clock pin +PS2_USE_BUSYWAIT = yes # uses primitive reference code + + +# Search Path +VPATH += $(TARGET_DIR) +VPATH += $(TOP_DIR) + + +include $(TOP_DIR)/protocol.mk +include $(TOP_DIR)/protocol/pjrc.mk +include $(TOP_DIR)/common.mk +include $(TOP_DIR)/rules.mk diff --git a/converter/ps2_usb/keymap.c b/converter/ps2_usb/keymap.c deleted file mode 100644 index c97783fa..00000000 --- a/converter/ps2_usb/keymap.c +++ /dev/null @@ -1,379 +0,0 @@ -/* -Copyright 2011 Jun Wako - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -/* - * Keymap for PS/2 keyboard - */ -#include -#include -#include -#include "keycode.h" -#include "print.h" -#include "debug.h" -#include "util.h" -#include "keymap.h" - - - - -// Following macros help you to define a keymap with the form of actual keyboard layout. - -/* US layout plus all other various keys */ -#define KEYMAP_ALL( \ - K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ - K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ - K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B,K5D, KF1,KE9,KFA, K6C,K75,K7D, \ - K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52, K5A, K6B,K73,K74,K79, \ - K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K59, KF5, K69,K72,K7A, \ - K14,K9F,K11, K29, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA, \ - \ - K61, /* for European ISO */ \ - K51, K13, K6A, K64, K67, /* for Japanese JIS */ \ - K08, K10, K18, K20, K28, K30, K38, K40, K48, K50, K57, K5F, /* F13-24 */ \ - KB7, KBF, KDE, /* System Power, Sleep, Wake */ \ - KA3, KB2, KA1, /* Mute, Volume Up, Volume Down */ \ - KCD, K95, KBB, KB4, KD0, /* Next, Previous, Stop, Pause, Media Select */ \ - KC8, KAB, KC0, /* Mail, Calculator, My Computer */ \ - K90, KBA, KB8, KB0, /* WWW Search, Home, Back, Forward */ \ - KA8, KA0, K98 /* WWW Stop, Refresh, Favorites */ \ -) { \ - { KC_NO, KC_##K01, KC_NO, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07 }, \ - { KC_##K08, KC_##K09, KC_##K0A, KC_##K0B, KC_##K0C, KC_##K0D, KC_##K0E, KC_NO }, \ - { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_NO }, \ - { KC_##K18, KC_NO, KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D, KC_##K1E, KC_NO }, \ - { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_NO }, \ - { KC_##K28, KC_##K29, KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D, KC_##K2E, KC_NO }, \ - { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_NO }, \ - { KC_##K38, KC_NO, KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D, KC_##K3E, KC_NO }, \ - { KC_##K40, KC_##K41, KC_##K42, KC_##K43, KC_##K44, KC_##K45, KC_##K46, KC_NO }, \ - { KC_##K48, KC_##K49, KC_##K4A, KC_##K4B, KC_##K4C, KC_##K4D, KC_##K4E, KC_NO }, \ - { KC_##K50, KC_##K51, KC_##K52, KC_NO, KC_##K54, KC_##K55, KC_NO, KC_##K57 }, \ - { KC_##K58, KC_##K59, KC_##K5A, KC_##K5B, KC_NO, KC_##K5D, KC_NO, KC_##K5F }, \ - { KC_NO, KC_##K61, KC_NO, KC_NO, KC_##K64, KC_NO, KC_##K66, KC_##K67 }, \ - { KC_NO, KC_##K69, KC_##K6A, KC_##K6B, KC_##K6C, KC_NO, KC_NO, KC_NO }, \ - { KC_##K70, KC_##K71, KC_##K72, KC_##K73, KC_##K74, KC_##K75, KC_##K76, KC_##K77 }, \ - { KC_##K78, KC_##K79, KC_##K7A, KC_##K7B, KC_##K7C, KC_##K7D, KC_##K7E, KC_NO }, \ - { KC_NO, KC_NO, KC_NO, KC_##K83, KC_NO, KC_NO, KC_NO, KC_NO }, \ - { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ - { KC_##K90, KC_##K91, KC_NO, KC_NO, KC_##K94, KC_##K95, KC_NO, KC_NO }, \ - { KC_##K98, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_##K9F }, \ - { KC_##KA0, KC_##KA1, KC_NO, KC_##KA3, KC_NO, KC_NO, KC_NO, KC_##KA7 }, \ - { KC_##KA8, KC_NO, KC_NO, KC_##KAB, KC_NO, KC_NO, KC_NO, KC_##KAF }, \ - { KC_##KB0, KC_NO, KC_##KB2, KC_NO, KC_##KB4, KC_NO, KC_NO, KC_##KB7 }, \ - { KC_##KB8, KC_NO, KC_##KBA, KC_##KBB, KC_NO, KC_NO, KC_NO, KC_##KBF }, \ - { KC_##KC0, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ - { KC_##KC8, KC_NO, KC_##KCA, KC_NO, KC_NO, KC_##KCD, KC_NO, KC_NO }, \ - { KC_##KD0, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ - { KC_NO, KC_NO, KC_##KDA, KC_NO, KC_NO, KC_NO, KC_##KDE, KC_NO }, \ - { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ - { KC_NO, KC_##KE9, KC_NO, KC_##KEB, KC_##KEC, KC_NO, KC_NO, KC_NO }, \ - { KC_##KF0, KC_##KF1, KC_##KF2, KC_NO, KC_##KF4, KC_##KF5, KC_NO, KC_NO }, \ - { KC_NO, KC_NO, KC_##KFA, KC_NO, KC_##KFC, KC_##KFD, KC_##KFE, KC_NO }, \ -} - -/* US layout */ -#define KEYMAP( \ - K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ - K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ - K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B,K5D, KF1,KE9,KFA, K6C,K75,K7D, \ - K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52, K5A, K6B,K73,K74,K79, \ - K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K59, KF5, K69,K72,K7A, \ - K14,K9F,K11, K29, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA \ -) \ -KEYMAP_ALL( \ - K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ - K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ - K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B,K5D, KF1,KE9,KFA, K6C,K75,K7D, \ - K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52, K5A, K6B,K73,K74,K79, \ - K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K59, KF5, K69,K72,K7A, \ - K14,K9F,K11, K29, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA, \ - \ - NUBS, \ - RO, KANA, JYEN, HENK, MHEN, \ - F13, F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24, \ - SYSTEM_POWER, SYSTEM_SLEEP, SYSTEM_WAKE, \ - AUDIO_MUTE, AUDIO_VOL_UP, AUDIO_VOL_DOWN, \ - MEDIA_NEXT_TRACK, MEDIA_PREV_TRACK, MEDIA_STOP, MEDIA_PLAY_PAUSE, MEDIA_SELECT, \ - MAIL, CALCULATOR, MY_COMPUTER, \ - WWW_SEARCH, WWW_HOME, WWW_BACK, WWW_FORWARD, \ - WWW_STOP, WWW_REFRESH, WWW_FAVORITES \ -) - -/* ISO layout */ -#define KEYMAP_ISO( \ - K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ - K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ - K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B, KF1,KE9,KFA, K6C,K75,K7D, \ - K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52,K5D,K5A, K6B,K73,K74,K79, \ - K12,K61,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K59, KF5, K69,K72,K7A, \ - K14,K9F,K11, K29, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA \ -) \ -KEYMAP_ALL( \ - K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ - K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ - K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B,K5D, KF1,KE9,KFA, K6C,K75,K7D, \ - K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52, K5A, K6B,K73,K74,K79, \ - K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K59, KF5, K69,K72,K7A, \ - K14,K9F,K11, K29, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA, \ - \ - K61, \ - RO, KANA, JYEN, HENK, MHEN, \ - F13, F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24, \ - SYSTEM_POWER, SYSTEM_SLEEP, SYSTEM_WAKE, \ - AUDIO_MUTE, AUDIO_VOL_UP, AUDIO_VOL_DOWN, \ - MEDIA_NEXT_TRACK, MEDIA_PREV_TRACK, MEDIA_STOP, MEDIA_PLAY_PAUSE, MEDIA_SELECT, \ - MAIL, CALCULATOR, MY_COMPUTER, \ - WWW_SEARCH, WWW_HOME, WWW_BACK, WWW_FORWARD, \ - WWW_STOP, WWW_REFRESH, WWW_FAVORITES \ -) - -/* JIS layout */ -#define KEYMAP_JIS( \ - K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ - K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K6A,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ - K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B, KF1,KE9,KFA, K6C,K75,K7D, \ - K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52,K5D, K5A, K6B,K73,K74,K79, \ - K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A,K51, K59, KF5, K69,K72,K7A, \ - K14,K9F,K11, K67,K29,K64,K13, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA \ -) \ -KEYMAP_ALL( \ - K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ - K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ - K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B,K5D, KF1,KE9,KFA, K6C,K75,K7D, \ - K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52, K5A, K6B,K73,K74,K79, \ - K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K59, KF5, K69,K72,K7A, \ - K14,K9F,K11, K29, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA, \ - \ - NUBS, \ - K51, K13, K6A, K64, K67, \ - F13, F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24, \ - SYSTEM_POWER, SYSTEM_SLEEP, SYSTEM_WAKE, \ - AUDIO_MUTE, AUDIO_VOL_UP, AUDIO_VOL_DOWN, \ - MEDIA_NEXT_TRACK, MEDIA_PREV_TRACK, MEDIA_STOP, MEDIA_PLAY_PAUSE, MEDIA_SELECT, \ - MAIL, CALCULATOR, MY_COMPUTER, \ - WWW_SEARCH, WWW_HOME, WWW_BACK, WWW_FORWARD, \ - WWW_STOP, WWW_REFRESH, WWW_FAVORITES \ -) - - -// Assign Fn key(0-7) to a layer to which switch with the Fn key pressed. -static const uint8_t PROGMEM fn_layer[] = { - 5, // Fn0 - 6, // Fn1 - 0, // Fn2 - 0, // Fn3 - 0, // Fn4 - 0, // Fn5 - 0, // Fn6 - 0 // Fn7 -}; - -// Assign Fn key(0-7) to a keycode sent when release Fn key without use of the layer. -// See layer.c for details. -static const uint8_t PROGMEM fn_keycode[] = { - KC_SCLN, // Fn0 - KC_SLSH, // Fn1 - KC_NO, // Fn2 - KC_NO, // Fn3 - KC_NO, // Fn4 - KC_NO, // Fn5 - KC_NO, // Fn6 - KC_NO // Fn7 -}; - - -// The keymap is a 32*8 byte array which convert a PS/2 scan code into a USB keycode. -// See keycode.h for USB keycodes. You should omit a 'KC_' prefix of USB keycodes in keymap macro. -// Use KEYMAP_ISO() or KEYMAP_JIS() instead of KEYMAP() if your keyboard is ISO or JIS. -static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { - /* 0: default - * ,---. ,---------------. ,---------------. ,---------------. ,-----------. ,-----------. - * |Esc| |F1 |F2 |F3 |F4 | |F5 |F6 |F7 |F8 | |F9 |F10|F11|F12| |PrS|ScL|Pau| |Pwr|Slp|Wak| - * `---' `---------------' `---------------' `---------------' `-----------' `-----------' - * ,-----------------------------------------------------------. ,-----------. ,---------------. - * | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backspa| |Ins|Hom|PgU| |NmL| /| *| -| - * |-----------------------------------------------------------| |-----------| |---------------| - * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| |Del|End|PgD| | 7| 8| 9| | - * |-----------------------------------------------------------| `-----------' |-----------| +| - * |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return | | 4| 5| 6| | - * |-----------------------------------------------------------| ,---. |---------------| - * |Shift | Z| X| C| V| B| N| M| ,| ,| /|Shift | |Up | | 1| 2| 3| | - * |-----------------------------------------------------------| ,-----------. |-----------|Ent| - * |Ctrl |Gui |Alt | Space |Alt |Gui |Menu|Ctrl| |Lef|Dow|Rig| | 0| .| | - * `-----------------------------------------------------------' `-----------' `---------------' - * ; = Fn0(to Layer 5) - * / = Fn1(to Layer 6) - */ - KEYMAP( - ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, - GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, - TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9, - CAPS,A, S, D, F, G, H, J, K, L, FN0, QUOT, ENT, P4, P5, P6, PPLS, - LSFT,Z, X, C, V, B, N, M, COMM,DOT, FN1, RSFT, UP, P1, P2, P3, - LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT - ), - - /* 1: plain Qwerty without layer switching - * ,-----------------------------------------------------------. - * | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backspa| - * |-----------------------------------------------------------| - * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| - * |-----------------------------------------------------------| - * |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return | - * |-----------------------------------------------------------| - * |Shift | Z| X| C| V| B| N| M| ,| ,| /|Shift | - * |-----------------------------------------------------------| - * |Ctrl |Gui |Alt | Space |Alt |Gui |Menu|Ctrl| - * `-----------------------------------------------------------' - */ - KEYMAP( - ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, - GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, - TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9, - CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, P4, P5, P6, PPLS, - LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3, - LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT - ), - - /* 2: Colemak http://colemak.com - * ,-----------------------------------------------------------. - * | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backspa| - * |-----------------------------------------------------------| - * |Tab | Q| W| F| P| G| J| L| U| Y| ;| [| ]| \| - * |-----------------------------------------------------------| - * |BackSp| A| R| S| T| D| H| N| E| I| O| '|Return | - * |-----------------------------------------------------------| - * |Shift | Z| X| C| V| B| K| M| ,| ,| /|Shift | - * |-----------------------------------------------------------| - * |Ctrl |Gui |Alt | Space |Alt |Gui |Menu|Ctrl| - * `----------------------------------------------------------' - */ - KEYMAP( - ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, - GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, - TAB, Q, W, F, P, G, J, L, U, Y, SCLN,LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9, - BSPC,A, R, S, T, D, H, N, E, I, O, QUOT, ENT, P4, P5, P6, PPLS, - LSFT,Z, X, C, V, B, K, M, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3, - LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT - ), - - /* 3: Dvorak http://en.wikipedia.org/wiki/Dvorak_Simplified_Keyboard - * ,-----------------------------------------------------------. - * | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| [| ]|Backspa| - * |-----------------------------------------------------------| - * |Tab | '| ,| .| P| Y| F| G| C| R| L| /| =| \| - * |-----------------------------------------------------------| - * |BackSp| A| O| E| U| I| D| H| T| N| S| -|Return | - * |-----------------------------------------------------------| - * |Shift | ;| Q| J| K| X| B| M| Wl V| Z|Shift | - * |-----------------------------------------------------------| - * |Ctrl |Gui |Alt | Space |Alt |Gui |Menu|Ctrl| - * `-----------------------------------------------------------' - */ - KEYMAP( - ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, - GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, LBRC,RBRC,BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, - TAB, QUOT,COMM,DOT, P, Y, F, G, C, R, L, SLSH,EQL, BSLS, DEL, END, PGDN, P7, P8, P9, - CAPS,A, O, E, U, I, D, H, T, N, S, MINS, ENT, P4, P5, P6, PPLS, - LSFT,SCLN,Q, J, K, X, B, M, W, V, Z, RSFT, UP, P1, P2, P3, - LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT - ), - - /* 4: Workman http://viralintrospection.wordpress.com/2010/09/06/a-different-philosophy-in-designing-keyboard-layouts/ - * ,-----------------------------------------------------------. - * | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backspa| - * |-----------------------------------------------------------| - * |Tab | Q| D| R| W| B| J| F| U| P| ;| [| ]| \| - * |-----------------------------------------------------------| - * |CapsLo| A| S| H| T| G| Y| N| E| O| I| '|Return | - * |-----------------------------------------------------------| - * |Shift | Z| X| M| C| V| K| L| ,| ,| /|Shift | - * |-----------------------------------------------------------| - * |Ctrl |Gui |Alt | Space |Alt |Gui |Menu|Ctrl| - * `-----------------------------------------------------------' - */ - KEYMAP( - ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, - GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, - TAB, Q, D, R, W, B, J, F, U, P, SCLN,LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9, - BSPC,A, S, H, T, G, Y, N, E, O, I, QUOT, ENT, P4, P5, P6, PPLS, - LSFT,Z, X, M, C, V, K, L, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3, - LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT - ), - - /* 5: Mouse keys - * ,-----------------------------------------------------------. - * |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Backspa| - * |-----------------------------------------------------------| - * |Tab |MwL|MwU|McU|WwU|WwR|MwL|MwD|MwU|MwR| | | | \| - * |-----------------------------------------------------------| - * |CapsLo| |McL|McD|McR| |McL|McD|McU|McR|Fn0| |Return | - * |-----------------------------------------------------------| - * |Shift |VoD|VoU|Mut|Mb2|Mb3|Mb2|Mb1|VoD|VoU|Mut|Shift | - * |-----------------------------------------------------------| - * |Ctrl |Gui |Alt | Mb1 |Alt |Gui |Menu|Ctrl| - * `-----------------------------------------------------------' - * Mc = mouse cursor, Mw = mouse wheel, Mb = mouse button - * Vo = Volume, Mut = Mute - */ - KEYMAP( - ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, - ESC, F1, F2, F3, F4, F5, F6, F7, F8, F8, F10, F11, F12, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, - TAB, WH_L,WH_D,MS_U,WH_U,WH_R,WH_L,WH_D,WH_U,WH_R,NO, NO, NO, BSLS, DEL, END, PGDN, P7, P8, P9, - CAPS,NO, MS_L,MS_D,MS_R,NO, MS_L,MS_D,MS_U,MS_R,FN0, NO, ENT, P4, P5, P6, PPLS, - LSFT,VOLD,VOLU,MUTE,BTN2,BTN3,BTN2,BTN1,VOLD,VOLU,MUTE, RSFT, UP, P1, P2, P3, - LCTL,LGUI,LALT, BTN1, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT - ), - - /* 6: Cursor keys - * ,-----------------------------------------------------------. - * |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Backspa| - * |-----------------------------------------------------------| - * |Tab |Hom|PgU| Up|PgU|End|Hom|PgD|PgU|End| | | | \| - * |-----------------------------------------------------------| - * |CapsLo| |Lef|Dow|Rig| |Lef|Dow| Up|Rig| | |Return | - * |-----------------------------------------------------------| - * |Shift | | | | | |Hom|PgD|PgU|End|Fn1|Shift | - * |-----------------------------------------------------------| - * |Ctrl |Gui |Alt | Space |Alt |Gui |Menu|Ctrl| - * `-----------------------------------------------------------' - */ - KEYMAP( - ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, - ESC, F1, F2, F3, F4, F5, F6, F7, F8, F8, F10, F11, F12, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, - TAB, NO, NO, NO, NO, NO, HOME,PGDN,PGUP,END, NO, NO, NO, BSLS, DEL, END, PGDN, P7, P8, P9, - CAPS,NO, NO, NO, NO, NO, LEFT,DOWN,UP, RGHT,NO, NO, ENT, P4, P5, P6, PPLS, - LSFT,VOLD,VOLU,MUTE,NO, NO, HOME,PGDN,PGUP,END, FN1, RSFT, UP, P1, P2, P3, - LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT - ), -}; - - -uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col) -{ - return pgm_read_byte(&keymaps[(layer)][(row)][(col)]); -} - -uint8_t keymap_fn_layer(uint8_t index) -{ - return pgm_read_byte(&fn_layer[index]); -} - -uint8_t keymap_fn_keycode(uint8_t index) -{ - return pgm_read_byte(&fn_keycode[index]); -} diff --git a/converter/ps2_usb/keymap_common.c b/converter/ps2_usb/keymap_common.c new file mode 100644 index 00000000..241d2e33 --- /dev/null +++ b/converter/ps2_usb/keymap_common.c @@ -0,0 +1,30 @@ +/* +Copyright 2011,2012,2013 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include "keymap_common.h" + + +/* translates key to keycode */ +uint8_t keymap_key_to_keycode(uint8_t layer, key_t key) +{ + return pgm_read_byte(&keymaps[(layer)][(key.row)][(key.col)]); +} + +/* translates Fn keycode to action */ +action_t keymap_fn_to_action(uint8_t keycode) +{ + return (action_t){ .code = pgm_read_word(&fn_actions[FN_INDEX(keycode)]) }; +} diff --git a/converter/ps2_usb/keymap_common.h b/converter/ps2_usb/keymap_common.h new file mode 100644 index 00000000..216a8dc0 --- /dev/null +++ b/converter/ps2_usb/keymap_common.h @@ -0,0 +1,174 @@ +/* +Copyright 2011,2012,2013 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef KEYMAP_COMMON_H +#define KEYMAP_COMMON_H + +#include +#include +#include +#include "keycode.h" +#include "action.h" +#include "action_macro.h" +#include "report.h" +#include "print.h" +#include "debug.h" +#include "keymap.h" + + +// 32*8(256) byte array which converts PS/2 code into USB code +extern const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; +extern const uint16_t fn_actions[]; + + +/* All keys */ +#define KEYMAP_ALL( \ + K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ + K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ + K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B,K5D, KF1,KE9,KFA, K6C,K75,K7D, \ + K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52, K5A, K6B,K73,K74,K79, \ + K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K59, KF5, K69,K72,K7A, \ + K14,K9F,K11, K29, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA, \ + \ + K61, /* for European ISO */ \ + K51, K13, K6A, K64, K67, /* for Japanese JIS */ \ + K08, K10, K18, K20, K28, K30, K38, K40, K48, K50, K57, K5F, /* F13-24 */ \ + KB7, KBF, KDE, /* System Power, Sleep, Wake */ \ + KA3, KB2, KA1, /* Mute, Volume Up, Volume Down */ \ + KCD, K95, KBB, KB4, KD0, /* Next, Previous, Stop, Pause, Media Select */ \ + KC8, KAB, KC0, /* Mail, Calculator, My Computer */ \ + K90, KBA, KB8, KB0, /* WWW Search, Home, Back, Forward */ \ + KA8, KA0, K98 /* WWW Stop, Refresh, Favorites */ \ +) { \ + { KC_NO, KC_##K01, KC_NO, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07 }, \ + { KC_##K08, KC_##K09, KC_##K0A, KC_##K0B, KC_##K0C, KC_##K0D, KC_##K0E, KC_NO }, \ + { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_NO }, \ + { KC_##K18, KC_NO, KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D, KC_##K1E, KC_NO }, \ + { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_NO }, \ + { KC_##K28, KC_##K29, KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D, KC_##K2E, KC_NO }, \ + { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_NO }, \ + { KC_##K38, KC_NO, KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D, KC_##K3E, KC_NO }, \ + { KC_##K40, KC_##K41, KC_##K42, KC_##K43, KC_##K44, KC_##K45, KC_##K46, KC_NO }, \ + { KC_##K48, KC_##K49, KC_##K4A, KC_##K4B, KC_##K4C, KC_##K4D, KC_##K4E, KC_NO }, \ + { KC_##K50, KC_##K51, KC_##K52, KC_NO, KC_##K54, KC_##K55, KC_NO, KC_##K57 }, \ + { KC_##K58, KC_##K59, KC_##K5A, KC_##K5B, KC_NO, KC_##K5D, KC_NO, KC_##K5F }, \ + { KC_NO, KC_##K61, KC_NO, KC_NO, KC_##K64, KC_NO, KC_##K66, KC_##K67 }, \ + { KC_NO, KC_##K69, KC_##K6A, KC_##K6B, KC_##K6C, KC_NO, KC_NO, KC_NO }, \ + { KC_##K70, KC_##K71, KC_##K72, KC_##K73, KC_##K74, KC_##K75, KC_##K76, KC_##K77 }, \ + { KC_##K78, KC_##K79, KC_##K7A, KC_##K7B, KC_##K7C, KC_##K7D, KC_##K7E, KC_NO }, \ + { KC_NO, KC_NO, KC_NO, KC_##K83, KC_NO, KC_NO, KC_NO, KC_NO }, \ + { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ + { KC_##K90, KC_##K91, KC_NO, KC_NO, KC_##K94, KC_##K95, KC_NO, KC_NO }, \ + { KC_##K98, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_##K9F }, \ + { KC_##KA0, KC_##KA1, KC_NO, KC_##KA3, KC_NO, KC_NO, KC_NO, KC_##KA7 }, \ + { KC_##KA8, KC_NO, KC_NO, KC_##KAB, KC_NO, KC_NO, KC_NO, KC_##KAF }, \ + { KC_##KB0, KC_NO, KC_##KB2, KC_NO, KC_##KB4, KC_NO, KC_NO, KC_##KB7 }, \ + { KC_##KB8, KC_NO, KC_##KBA, KC_##KBB, KC_NO, KC_NO, KC_NO, KC_##KBF }, \ + { KC_##KC0, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ + { KC_##KC8, KC_NO, KC_##KCA, KC_NO, KC_NO, KC_##KCD, KC_NO, KC_NO }, \ + { KC_##KD0, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ + { KC_NO, KC_NO, KC_##KDA, KC_NO, KC_NO, KC_NO, KC_##KDE, KC_NO }, \ + { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ + { KC_NO, KC_##KE9, KC_NO, KC_##KEB, KC_##KEC, KC_NO, KC_NO, KC_NO }, \ + { KC_##KF0, KC_##KF1, KC_##KF2, KC_NO, KC_##KF4, KC_##KF5, KC_NO, KC_NO }, \ + { KC_NO, KC_NO, KC_##KFA, KC_NO, KC_##KFC, KC_##KFD, KC_##KFE, KC_NO }, \ +} + +/* US layout */ +#define KEYMAP( \ + K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ + K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ + K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B,K5D, KF1,KE9,KFA, K6C,K75,K7D, \ + K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52, K5A, K6B,K73,K74,K79, \ + K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K59, KF5, K69,K72,K7A, \ + K14,K9F,K11, K29, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA \ +) \ +KEYMAP_ALL( \ + K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ + K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ + K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B,K5D, KF1,KE9,KFA, K6C,K75,K7D, \ + K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52, K5A, K6B,K73,K74,K79, \ + K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K59, KF5, K69,K72,K7A, \ + K14,K9F,K11, K29, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA, \ + \ + NUBS, \ + RO, KANA, JYEN, HENK, MHEN, \ + F13, F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24, \ + SYSTEM_POWER, SYSTEM_SLEEP, SYSTEM_WAKE, \ + AUDIO_MUTE, AUDIO_VOL_UP, AUDIO_VOL_DOWN, \ + MEDIA_NEXT_TRACK, MEDIA_PREV_TRACK, MEDIA_STOP, MEDIA_PLAY_PAUSE, MEDIA_SELECT, \ + MAIL, CALCULATOR, MY_COMPUTER, \ + WWW_SEARCH, WWW_HOME, WWW_BACK, WWW_FORWARD, \ + WWW_STOP, WWW_REFRESH, WWW_FAVORITES \ +) + +/* ISO layout */ +#define KEYMAP_ISO( \ + K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ + K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ + K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B, KF1,KE9,KFA, K6C,K75,K7D, \ + K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52,K5D,K5A, K6B,K73,K74,K79, \ + K12,K61,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K59, KF5, K69,K72,K7A, \ + K14,K9F,K11, K29, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA \ +) \ +KEYMAP_ALL( \ + K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ + K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ + K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B,K5D, KF1,KE9,KFA, K6C,K75,K7D, \ + K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52, K5A, K6B,K73,K74,K79, \ + K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K59, KF5, K69,K72,K7A, \ + K14,K9F,K11, K29, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA, \ + \ + K61, \ + RO, KANA, JYEN, HENK, MHEN, \ + F13, F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24, \ + SYSTEM_POWER, SYSTEM_SLEEP, SYSTEM_WAKE, \ + AUDIO_MUTE, AUDIO_VOL_UP, AUDIO_VOL_DOWN, \ + MEDIA_NEXT_TRACK, MEDIA_PREV_TRACK, MEDIA_STOP, MEDIA_PLAY_PAUSE, MEDIA_SELECT, \ + MAIL, CALCULATOR, MY_COMPUTER, \ + WWW_SEARCH, WWW_HOME, WWW_BACK, WWW_FORWARD, \ + WWW_STOP, WWW_REFRESH, WWW_FAVORITES \ +) + +/* JIS layout */ +#define KEYMAP_JIS( \ + K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ + K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K6A,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ + K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B, KF1,KE9,KFA, K6C,K75,K7D, \ + K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52,K5D, K5A, K6B,K73,K74,K79, \ + K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A,K51, K59, KF5, K69,K72,K7A, \ + K14,K9F,K11, K67,K29,K64,K13, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA \ +) \ +KEYMAP_ALL( \ + K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ + K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ + K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B,K5D, KF1,KE9,KFA, K6C,K75,K7D, \ + K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52, K5A, K6B,K73,K74,K79, \ + K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K59, KF5, K69,K72,K7A, \ + K14,K9F,K11, K29, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA, \ + \ + NUBS, \ + K51, K13, K6A, K64, K67, \ + F13, F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24, \ + SYSTEM_POWER, SYSTEM_SLEEP, SYSTEM_WAKE, \ + AUDIO_MUTE, AUDIO_VOL_UP, AUDIO_VOL_DOWN, \ + MEDIA_NEXT_TRACK, MEDIA_PREV_TRACK, MEDIA_STOP, MEDIA_PLAY_PAUSE, MEDIA_SELECT, \ + MAIL, CALCULATOR, MY_COMPUTER, \ + WWW_SEARCH, WWW_HOME, WWW_BACK, WWW_FORWARD, \ + WWW_STOP, WWW_REFRESH, WWW_FAVORITES \ +) + +#endif diff --git a/converter/ps2_usb/keymap_plain.c b/converter/ps2_usb/keymap_plain.c new file mode 100644 index 00000000..9c6e7d9f --- /dev/null +++ b/converter/ps2_usb/keymap_plain.c @@ -0,0 +1,50 @@ +/* +Copyright 2011,2012,2013 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include "keymap_common.h" + + +const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + /* 0: default + * ,---. ,---------------. ,---------------. ,---------------. ,-----------. ,-----------. + * |Esc| |F1 |F2 |F3 |F4 | |F5 |F6 |F7 |F8 | |F9 |F10|F11|F12| |PrS|ScL|Pau| |Pwr|Slp|Wak| + * `---' `---------------' `---------------' `---------------' `-----------' `-----------' + * ,-----------------------------------------------------------. ,-----------. ,---------------. + * | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backspa| |Ins|Hom|PgU| |NmL| /| *| -| + * |-----------------------------------------------------------| |-----------| |---------------| + * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| |Del|End|PgD| | 7| 8| 9| | + * |-----------------------------------------------------------| `-----------' |-----------| +| + * |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return | | 4| 5| 6| | + * |-----------------------------------------------------------| ,---. |---------------| + * |Shift | Z| X| C| V| B| N| M| ,| ,| /|Shift | |Up | | 1| 2| 3| | + * |-----------------------------------------------------------| ,-----------. |-----------|Ent| + * |Ctrl |Gui |Alt | Space |Alt |Gui |Menu|Ctrl| |Lef|Dow|Rig| | 0| .| | + * `-----------------------------------------------------------' `-----------' `---------------' + * ; = Fn0(to Layer 5) + * / = Fn1(to Layer 6) + */ + KEYMAP( + ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, + GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, + TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9, + CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, P4, P5, P6, PPLS, + LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3, + LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT + ), +}; + +const uint16_t PROGMEM fn_actions[] = { +}; From fd7833388cdf8b15728d951b63e78571ba2edbc9 Mon Sep 17 00:00:00 2001 From: tmk Date: Fri, 29 Nov 2013 08:42:40 +0900 Subject: [PATCH 40/76] Add new keymap framework --- keyboard/hhkb/Makefile | 8 +- keyboard/hhkb/Makefile.nodebug | 141 ++++++++++++++++++++++ keyboard/hhkb/Makefile.pjrc | 8 +- keyboard/hhkb/keymap_common.c | 33 +++++ keyboard/hhkb/keymap_common.h | 57 +++++++++ keyboard/hhkb/{keymap.c => keymap_hasu.c} | 107 ++++------------ keyboard/hhkb/keymap_hhkb.c | 62 ++++++++++ 7 files changed, 332 insertions(+), 84 deletions(-) create mode 100644 keyboard/hhkb/Makefile.nodebug create mode 100644 keyboard/hhkb/keymap_common.c create mode 100644 keyboard/hhkb/keymap_common.h rename keyboard/hhkb/{keymap.c => keymap_hasu.c} (76%) create mode 100644 keyboard/hhkb/keymap_hhkb.c diff --git a/keyboard/hhkb/Makefile b/keyboard/hhkb/Makefile index 94078702..89d05ba1 100644 --- a/keyboard/hhkb/Makefile +++ b/keyboard/hhkb/Makefile @@ -49,10 +49,16 @@ TARGET_DIR = . # List C source files here. (C dependencies are automatically generated.) -SRC += keymap.c \ +SRC += keymap_common.c \ matrix.c \ led.c +ifdef KEYMAP + SRC := keymap_$(KEYMAP).c $(SRC) +else + SRC := keymap_hasu.c $(SRC) +endif + CONFIG_H = config.h diff --git a/keyboard/hhkb/Makefile.nodebug b/keyboard/hhkb/Makefile.nodebug new file mode 100644 index 00000000..f63083f6 --- /dev/null +++ b/keyboard/hhkb/Makefile.nodebug @@ -0,0 +1,141 @@ +#---------------------------------------------------------------------------- +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF. +# +# make extcoff = Convert ELF to AVR Extended COFF. +# +# make program = Download the hex file to the device. +# Please customize your programmer settings(PROGRAM_CMD) +# +# make teensy = Download the hex file to the device, using teensy_loader_cli. +# (must have teensy_loader_cli installed). +# +# make dfu = Download the hex file to the device, using dfu-programmer (must +# have dfu-programmer installed). +# +# make flip = Download the hex file to the device, using Atmel FLIP (must +# have Atmel FLIP installed). +# +# make dfu-ee = Download the eeprom file to the device, using dfu-programmer +# (must have dfu-programmer installed). +# +# make flip-ee = Download the eeprom file to the device, using Atmel FLIP +# (must have Atmel FLIP installed). +# +# make debug = Start either simulavr or avarice as specified for debugging, +# with avr-gdb or avr-insight as the front end for debugging. +# +# make filename.s = Just compile filename.c into the assembler code only. +# +# make filename.i = Create a preprocessed source file for use in submitting +# bug reports to the GCC project. +# +# To rebuild project do "make clean" then "make all". +#---------------------------------------------------------------------------- + +# Target file name (without extension). +TARGET = hhkb_lufa + +# Directory common source filess exist +TOP_DIR = ../.. + +# Directory keyboard dependent files exist +TARGET_DIR = . + + +# List C source files here. (C dependencies are automatically generated.) +SRC += keymap_common.c \ + matrix.c \ + led.c + +ifdef KEYMAP + SRC := keymap_$(KEYMAP).c $(SRC) +else + SRC := keymap_hasu.c $(SRC) +endif + +CONFIG_H = config.h + + +# MCU name +# PJRC Teensy++ 2.0 +#MCU = at90usb1286 +# TMK Alt Controller or PJRC Teensy 2.0 +MCU = atmega32u4 + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency in Hz. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# +# This will be an integer division of F_USB below, as it is sourced by +# F_USB after it has run through any CPU prescalers. Note that this value +# does not *change* the processor frequency - it should merely be updated to +# reflect the processor speed set externally so that the code can use accurate +# software delays. +F_CPU = 16000000 + + +# +# LUFA specific +# +# Target architecture (see library "Board Types" documentation). +ARCH = AVR8 + +# Input clock frequency. +# This will define a symbol, F_USB, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_USB = $(F_CPU) + +# Interrupt driven control endpoint task +OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT + + +# Boot Section Size in *bytes* +# Teensy halfKay 512 +# Teensy++ halfKay 1024 +# Atmel DFU loader 4096 (TMK Alt Controller) +# LUFA bootloader 4096 +# USBaspLoader 2048 +OPT_DEFS += -DBOOTLOADER_SIZE=4096 + + +# Build Options +# comment out to disable the options. +# +BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration +MOUSEKEY_ENABLE = yes # Mouse keys +EXTRAKEY_ENABLE = yes # Audio control and System control +#CONSOLE_ENABLE = yes # Console for debug +COMMAND_ENABLE = yes # Commands for debug and configuration +#NKRO_ENABLE = yes # USB Nkey Rollover +#KEYMAP_SECTION_ENABLE = yes # fixed address keymap for keymap editor + + +# Search Path +VPATH += $(TARGET_DIR) +VPATH += $(TOP_DIR) + +include $(TOP_DIR)/protocol/lufa.mk +include $(TOP_DIR)/common.mk +include $(TOP_DIR)/rules.mk + +debug-on: EXTRAFLAGS += -DDEBUG -DDEBUG_ACTION +debug-on: all + +debug-off: EXTRAFLAGS += -DNO_DEBUG -DNO_PRINT +debug-off: all diff --git a/keyboard/hhkb/Makefile.pjrc b/keyboard/hhkb/Makefile.pjrc index 5a781dd2..b6ce9c75 100644 --- a/keyboard/hhkb/Makefile.pjrc +++ b/keyboard/hhkb/Makefile.pjrc @@ -13,10 +13,16 @@ TOP_DIR = ../.. TARGET_DIR = . # keyboard dependent files -SRC = keymap.c \ +SRC = keymap_common.c \ matrix.c \ led.c +ifdef KEYMAP + SRC := keymap_$(KEYMAP).c $(SRC) +else + SRC := keymap_hasu.c $(SRC) +endif + CONFIG_H = config.h diff --git a/keyboard/hhkb/keymap_common.c b/keyboard/hhkb/keymap_common.c new file mode 100644 index 00000000..67b3db85 --- /dev/null +++ b/keyboard/hhkb/keymap_common.c @@ -0,0 +1,33 @@ +/* +Copyright 2012,2013 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include +#include "action.h" +#include +#include "keymap_common.h" + + +/* translates key to keycode */ +uint8_t keymap_key_to_keycode(uint8_t layer, key_t key) +{ + return pgm_read_byte(&keymaps[(layer)][(key.row)][(key.col)]); +} + +/* translates Fn keycode to action */ +action_t keymap_fn_to_action(uint8_t keycode) +{ + return (action_t){ .code = pgm_read_word(&fn_actions[FN_INDEX(keycode)]) }; +} diff --git a/keyboard/hhkb/keymap_common.h b/keyboard/hhkb/keymap_common.h new file mode 100644 index 00000000..ec922a32 --- /dev/null +++ b/keyboard/hhkb/keymap_common.h @@ -0,0 +1,57 @@ +/* +Copyright 2012,2013 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef KEYMAP_COMMON_H +#define KEYMAP_COMMON_H + +#include +#include +#include "keycode.h" +#include "action.h" +#include "action_code.h" +#include "action_layer.h" +#include "action_macro.h" +#include "action_util.h" +#include "report.h" +#include "host.h" +#include "print.h" +#include "debug.h" +#include "keymap.h" + + +extern const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; +extern const uint16_t fn_actions[]; + + +#define KEYMAP( \ + K31, K30, K00, K10, K11, K20, K21, K40, K41, K60, K61, K70, K71, K50, K51, \ + K32, K01, K02, K13, K12, K23, K22, K42, K43, K62, K63, K73, K72, K52, \ + K33, K04, K03, K14, K15, K24, K25, K45, K44, K65, K64, K74, K53, \ + K34, K05, K06, K07, K16, K17, K26, K46, K66, K76, K75, K55, K54, \ + K35, K36, K37, K57, K56 \ +) \ +{ \ + { KC_##K00, KC_##K01, KC_##K02, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07 }, \ + { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17 }, \ + { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_NO }, \ + { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_##K37 }, \ + { KC_##K40, KC_##K41, KC_##K42, KC_##K43, KC_##K44, KC_##K45, KC_##K46, KC_NO }, \ + { KC_##K50, KC_##K51, KC_##K52, KC_##K53, KC_##K54, KC_##K55, KC_##K56, KC_##K57 }, \ + { KC_##K60, KC_##K61, KC_##K62, KC_##K63, KC_##K64, KC_##K65, KC_##K66, KC_NO }, \ + { KC_##K70, KC_##K71, KC_##K72, KC_##K73, KC_##K74, KC_##K75, KC_##K76, KC_NO } \ +} + +#endif diff --git a/keyboard/hhkb/keymap.c b/keyboard/hhkb/keymap_hasu.c similarity index 76% rename from keyboard/hhkb/keymap.c rename to keyboard/hhkb/keymap_hasu.c index f2c6caf4..0297d3b7 100644 --- a/keyboard/hhkb/keymap.c +++ b/keyboard/hhkb/keymap_hasu.c @@ -1,57 +1,13 @@ -/* -Copyright 2011,2012,2013 Jun Wako - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - /* - * Keymap for PFU HHKB Pro + * Hasu: my personal keymap */ -#include -#include -#include -#include "keycode.h" -#include "action.h" -#include "action_macro.h" -#include "report.h" -#include "host.h" -#include "debug.h" -#include "keymap.h" +#include "keymap_common.h" -#define KEYMAP( \ - K31, K30, K00, K10, K11, K20, K21, K40, K41, K60, K61, K70, K71, K50, K51, \ - K32, K01, K02, K13, K12, K23, K22, K42, K43, K62, K63, K73, K72, K52, \ - K33, K04, K03, K14, K15, K24, K25, K45, K44, K65, K64, K74, K53, \ - K34, K05, K06, K07, K16, K17, K26, K46, K66, K76, K75, K55, K54, \ - K35, K36, K37, K57, K56 \ -) \ -{ \ - { KC_##K00, KC_##K01, KC_##K02, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07 }, \ - { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17 }, \ - { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_NO }, \ - { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_##K37 }, \ - { KC_##K40, KC_##K41, KC_##K42, KC_##K43, KC_##K44, KC_##K45, KC_##K46, KC_NO }, \ - { KC_##K50, KC_##K51, KC_##K52, KC_##K53, KC_##K54, KC_##K55, KC_##K56, KC_##K57 }, \ - { KC_##K60, KC_##K61, KC_##K62, KC_##K63, KC_##K64, KC_##K65, KC_##K66, KC_NO }, \ - { KC_##K70, KC_##K71, KC_##K72, KC_##K73, KC_##K74, KC_##K75, KC_##K76, KC_NO } \ -} - #ifdef KEYMAP_SECTION_ENABLE const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS] __attribute__ ((section (".keymap.keymaps"))) = { #else -static const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS] PROGMEM = { +const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS] PROGMEM = { #endif /* Layer 0: Default Layer * ,-----------------------------------------------------------. @@ -69,7 +25,7 @@ static const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS] PROGMEM = { KEYMAP(ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSLS,GRV, \ TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSPC, \ LCTL,A, S, D, F, G, H, J, K, L, FN3, QUOT,FN4, \ - FN5,Z, X, C, V, B, N, M, COMM,DOT, FN2, RSFT,FN1, \ + FN5, Z, X, C, V, B, N, M, COMM,DOT, FN2, RSFT,FN1, \ LGUI,LALT, FN6, RALT,RGUI), /* Layer 1: HHKB mode (HHKB Fn) @@ -87,7 +43,7 @@ static const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS] PROGMEM = { */ KEYMAP(GRV, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \ CAPS,NO, NO, NO, NO, NO, NO, NO, PSCR,SLCK,PAUS, UP, NO, BSPC, \ - LCTL,VOLD,VOLU,MUTE,NO, NO, PAST,PSLS,HOME,PGUP,LEFT,RGHT,ENT, \ + LCTL,VOLD,VOLU,MUTE,NO, FN9, PAST,PSLS,HOME,PGUP,LEFT,RGHT,ENT, \ LSFT,NO, NO, NO, NO, NO, PPLS,PMNS,END, PGDN,DOWN,RSFT,TRNS, \ LGUI,LALT, SPC, RALT,RGUI), @@ -192,7 +148,7 @@ enum macro_id { #ifdef KEYMAP_SECTION_ENABLE const uint16_t fn_actions[] __attribute__ ((section (".keymap.fn_actions"))) = { #else -static const uint16_t fn_actions[] PROGMEM = { +const uint16_t fn_actions[] PROGMEM = { #endif [0] = ACTION_DEFAULT_LAYER_SET(0), // Default layer(not used) [1] = ACTION_LAYER_TAP_TOGGLE(1), // HHKB layer(toggle with 5 taps) @@ -203,11 +159,12 @@ static const uint16_t fn_actions[] PROGMEM = { [6] = ACTION_LAYER_TAP_KEY(5, KC_SPC), // Mousekey layer with Space [7] = ACTION_LAYER_TOGGLE(3), // Mousekey layer(toggle) [8] = ACTION_MODS_KEY(MOD_LCTL, KC_W), // Close Tab + [9] = ACTION_MODS_KEY(MOD_LSFT, KC_4), // Shift stuck test // [8] = ACTION_LMOD_TAP_KEY(KC_LCTL, KC_BSPC), // LControl with tap Backspace // [9] = ACTION_LMOD_TAP_KEY(KC_LCTL, KC_ESC), // LControl with tap Esc -// [11] = ACTION_FUNCTION_TAP(LSHIFT_LPAREN), // Function: LShift with tap '(' -// [12] = ACTION_FUNCTION_TAP(RSHIFT_RPAREN), // Function: RShift with tap ')' + [11] = ACTION_FUNCTION_TAP(LSHIFT_LPAREN), // Function: LShift with tap '(' + [12] = ACTION_FUNCTION_TAP(RSHIFT_RPAREN), // Function: RShift with tap ')' // [13] = ACTION_MACRO_TAP(LSHIFT_PAREN), // Macro: LShift with tap '(' // [14] = ACTION_MACRO_TAP(RSHIFT_PAREN), // Macro: RShift with tap ')' // [15] = ACTION_MACRO(HELLO), // Macro: say hello @@ -268,18 +225,20 @@ void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) // NOTE: cant use register_code to avoid conflicting with magic key bind if (event.pressed) { if (tap.count == 0 || tap.interrupted) { - add_mods(MOD_BIT(KC_LSHIFT)); + //add_mods(MOD_BIT(KC_LSHIFT)); + layer_on(1); } else { - host_add_mods(MOD_BIT(KC_LSHIFT)); - host_add_key(KC_9); - host_send_keyboard_report(); - host_del_mods(MOD_BIT(KC_LSHIFT)); - host_del_key(KC_9); - host_send_keyboard_report(); + add_mods(MOD_BIT(KC_LSHIFT)); + add_key(KC_9); + send_keyboard_report(); + del_mods(MOD_BIT(KC_LSHIFT)); + del_key(KC_9); + send_keyboard_report(); } } else { if (tap.count == 0 || tap.interrupted) { - del_mods(MOD_BIT(KC_LSHIFT)); + //del_mods(MOD_BIT(KC_LSHIFT)); + layer_off(1); } } break; @@ -289,12 +248,12 @@ void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) if (tap.count == 0 || tap.interrupted) { add_mods(MOD_BIT(KC_RSHIFT)); } else { - host_add_mods(MOD_BIT(KC_RSHIFT)); - host_add_key(KC_0); - host_send_keyboard_report(); - host_del_mods(MOD_BIT(KC_RSHIFT)); - host_del_key(KC_0); - host_send_keyboard_report(); + add_mods(MOD_BIT(KC_RSHIFT)); + add_key(KC_0); + send_keyboard_report(); + del_mods(MOD_BIT(KC_RSHIFT)); + del_key(KC_0); + send_keyboard_report(); } } else { if (tap.count == 0 || tap.interrupted) { @@ -304,19 +263,3 @@ void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) break; } } - - - -/* translates key to keycode */ -uint8_t keymap_key_to_keycode(uint8_t layer, key_t key) -{ - return pgm_read_byte(&keymaps[(layer)][(key.row)][(key.col)]); -} - -/* translates Fn index to action */ -action_t keymap_fn_to_action(uint8_t keycode) -{ - action_t action; - action.code = pgm_read_word(&fn_actions[FN_INDEX(keycode)]); - return action; -} diff --git a/keyboard/hhkb/keymap_hhkb.c b/keyboard/hhkb/keymap_hhkb.c new file mode 100644 index 00000000..1df16e13 --- /dev/null +++ b/keyboard/hhkb/keymap_hhkb.c @@ -0,0 +1,62 @@ +/* + * HHKB Layout + */ +#include "keymap_common.h" + + +#ifdef KEYMAP_SECTION_ENABLE +const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS] __attribute__ ((section (".keymap.keymaps"))) = { +#else +const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS] PROGMEM = { +#endif + /* Layer 0: Default Layer + * ,-----------------------------------------------------------. + * |Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =| \| `| + * |-----------------------------------------------------------| + * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]|Backs| + * |-----------------------------------------------------------| + * |Contro| A| S| D| F| G| H| J| K| L| ;| '|Enter | + * |-----------------------------------------------------------| + * |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift |Fn0| + * `-----------------------------------------------------------' + * |Gui|Alt | Space |Alt |Gui| + * `-------------------------------------------' + */ + KEYMAP(ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSLS,GRV, \ + TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSPC, \ + LCTL,A, S, D, F, G, H, J, K, L, SCLN,QUOT,ENT, \ + LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH,RSFT,FN0, \ + LGUI,LALT, SPC, RALT,RGUI), + + /* Layer 1: HHKB mode (HHKB Fn) + * ,-----------------------------------------------------------. + * |Pwr| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del| + * |-----------------------------------------------------------| + * |Caps | | | | | | | |Psc|Slk|Pus|Up | |Backs| + * |-----------------------------------------------------------| + * | |VoD|VoU|Mut| | | *| /|Hom|PgU|Lef|Rig|Enter | + * |-----------------------------------------------------------| + * | | | | | | | +| -|End|PgD|Dow| | | + * `-----------------------------------------------------------' + * | | | | | | + * `-------------------------------------------' + */ + KEYMAP(PWR, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \ + CAPS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,PSCR,SLCK,PAUS, UP, TRNS, BSPC, \ + TRNS,VOLD,VOLU,MUTE,TRNS,TRNS,PAST,PSLS,HOME,PGUP,LEFT,RGHT,PENT, \ + TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,PPLS,PMNS,END, PGDN,DOWN,TRNS,TRNS, \ + TRNS,TRNS, TRNS, TRNS,TRNS), +}; + + + +/* + * Fn action definition + */ +#ifdef KEYMAP_SECTION_ENABLE +const uint16_t fn_actions[] __attribute__ ((section (".keymap.fn_actions"))) = { +#else +const uint16_t fn_actions[] PROGMEM = { +#endif + [0] = ACTION_LAYER_MOMENTARY(1), +}; From e3bcdd8211743607a8812f2dee78ee8ae6965209 Mon Sep 17 00:00:00 2001 From: tmk Date: Fri, 29 Nov 2013 23:52:29 +0900 Subject: [PATCH 41/76] Add SpaceFN keymap and JIS keymap --- converter/ps2_usb/README | 122 ------------- converter/ps2_usb/README.md | 76 ++++++++ converter/ps2_usb/keymap_jis.c | 273 +---------------------------- converter/ps2_usb/keymap_plain.c | 18 -- converter/ps2_usb/keymap_spacefn.c | 61 +++++++ 5 files changed, 142 insertions(+), 408 deletions(-) delete mode 100644 converter/ps2_usb/README create mode 100644 converter/ps2_usb/README.md create mode 100644 converter/ps2_usb/keymap_spacefn.c diff --git a/converter/ps2_usb/README b/converter/ps2_usb/README deleted file mode 100644 index cb7ba555..00000000 --- a/converter/ps2_usb/README +++ /dev/null @@ -1,122 +0,0 @@ -PS/2 to USB keyboard converter -============================== -This firmware converts PS/2 keyboard protocol to USB and supports only Scan Code Set 2. -This will works on USB AVR(ATMega32U4, AT90USB) or V-USB(ATMega168, 328...). - - -Features --------- -Mouse keys - You can emulates mouse move and button click using keyboard. -System/Media control - You can sends Power event, Volume down/up and Mute. -USB NKRO(actually 120KRO+8Modifiers) - You can tolggles NKRO feature. -Keymap customization - You can customize keymaps easily by editing source code. See keymap.c. - - -PS/2 signal handling implementations ------------------------------------- -Following three methods are used to implement PS/2 signal handling. -a. Simple and stupid busy-wait(ps2.c) - This is expected to implemented with portable C code for reference. -b. Interrupt driven(ps2.c) - Uses external interrupt to detect falling edge of clock line. -c. USART hardware module(ps2_usart.c) - Uses AVR USART engine to recevie PS/2 signal. Recomended and default. - This is required to work with V-USB, preceding two methods tend to - miss signal edges while V-USB handles USB. - -To select method edit Makefile. - - -Connect Wires -------------- -In case of Teensy2.0(ATMega32U4): -0. Connect Vcc and GND. -1. Connect Clock and Data line. - For a. Clock is on PF0 and Data on PF1. - For b. Clock is on PD1 and Data on PD2. - For c. Clock is on PD5 and Data on PD2. -2. Optionally you need pull-up register. 1K-10K Ohm is OK. - -To change pin configuration edit config.h. - - -Build Frimware --------------- -1. Edit Makefile for build options and MCU setting. - Use 'atmega32u4' for Teensy 2.0 or 'at90usb1286' for Teensy++ 2.0. -2. make - Just type `make` in a terminal. - Use `-f Makefile.vusb` option to build V-USB converter. - Use `-f Makefile.jis` option to use JIS keyboard. -3. program MCU. - In case of Teensy use `Teensy Loader`.(http://www.pjrc.com/teensy/loader.html) - Otherwise you want to use `avrdude` or `dfu-programmer`. - - -Demonstration of Features -------------------------- -In default configuration, you can try several keymaps, mousekeys and USB NKRO. -Use following magic key combinations to enable some features. - -keymaps and NKRO: - Magic+0: Qwerty with mousekeys(default) - Magic+1: Qwerty without mousekeys - Magic+2: Colemak - Magic+3: Dvorak - Magic+4: Workman - Magic+N: toggles NKRO/6KRO(6KRO by default) - Magic+Esc: sends Power Event(Power button) - - where Magic=(LShift+RShift) or (LControl+RShift) - -Fn layer function: - Fn0+(hjkl): Mousekey move(vi cursor like) - Fn0+(yuio): Mouse wheel(left,down,up,right) - Fn0+space: Mouse left button - Fn0+(mnb): Mouse buttons(m=left, n=right, b=middle) - Fn0+(zxc): Media control(Volup, Voldown, Mute) - Fn1+(hjkl): Cursor move(vi cursor like) - Fn1+(nm,.): Cursor move(Home,PageDown,PageUp,End) - - where Fn0=;, Fn1=/ - - -Keymap ------- -You can change a keymap by editing code of keymap. See common/keycode.h for key symbols. - - -V-USB Support -------------- -You can also use this converter on ATmega(168/328) with V-USB instead of Teensy. -The converter on V-USB lacks some features for now: USB NKRO and System/Media control. - -Circuit -------- - +---+ +---------------+ -USB GND | | ATmega168 | -=== C3 | | -5V <-------+--------+---|Vcc,AVCC | PS/2 - R1 | | ==== -D- <----+--+-----R2-----|INT1 RXD|------->DATA -D+ <----|---+----R3-----|INT0 XCK|------->CLOCK - Z1 Z2 | | ->5V -GND<----+---+--+--+-----|GND | ->GND - | | | | - | C2-+--|XTAL1 | - | X1 | | - +--C3-+--|XTAL2 | - +---------------+ -R1: 1.5K Ohm -R2,R3: 68 Ohm -Z1,Z2: Zenner 3.6V -C1,C2: 22pF -C3: 0.1uF -X1: Crystal 20MHz(16MHz/12MHz) - - -EOF diff --git a/converter/ps2_usb/README.md b/converter/ps2_usb/README.md new file mode 100644 index 00000000..65e616ef --- /dev/null +++ b/converter/ps2_usb/README.md @@ -0,0 +1,76 @@ +PS/2 to USB keyboard converter +============================== +This firmware converts PS/2 keyboard protocol to USB and supports only Scan Code Set 2. + + +PS/2 signal handling implementations +------------------------------------ +Following three methods are used to implement PS/2 signal handling. + +### Simple and stupid busy-wait(ps2_busywait.c) + This is expected to implemented with portable C code for reference. +### Interrupt driven(ps2_interrupt.c) + Uses pin interrupt to detect falling edge of clock line. +### USART hardware module(ps2_usart.c) + Uses AVR USART engine to recevie PS/2 signal. + +To select method edit Makefile. + + +Connect Wires +------------- +In case of Teensy2.0(ATMega32U4): + +1. Connect Vcc and GND. +2. Connect Clock and Data line. + - Busywait: Clock is on PD5 and Data on PD2. + - Interrupt: Clock is on PD1 and Data on PD2. + - USART: Clock is on PD5 and Data on PD2. +3. Optionally you need pull-up register. 1K-10K Ohm is OK. + +To change pin configuration edit config.h. + + +Build Frimware +-------------- +Just run `make`: + + $ make + +To select keymap: + + $ make KEYMAP=[plain|jis|spacefn|...] + + +Keymap +------ +Several version of keymap are available in advance but you are recommended to define your favorite layout yourself. To define your own keymap create file named `keymap_.c` and see keymap document(you can find in top README.md) and existent keymap files. + + +V-USB Support +------------- +You can also use this converter on ATmega(168/328) with V-USB instead of Teensy. +The converter on V-USB lacks some features for now: USB NKRO and System/Media control. + +Circuit: + + +---+ +---------------+ + USB GND | | ATmega168 | + === C3 | | + 5V <-------+--------+---|Vcc,AVCC | PS/2 + R1 | | ==== + D- <----+--+-----R2-----|INT1 RXD|------->DATA + D+ <----|---+----R3-----|INT0 XCK|------->CLOCK + Z1 Z2 | | ->5V + GND<----+---+--+--+-----|GND | ->GND + | | | | + | C2-+--|XTAL1 | + | X1 | | + +--C3-+--|XTAL2 | + +---------------+ + R1: 1.5K Ohm + R2,R3: 68 Ohm + Z1,Z2: Zenner 3.6V + C1,C2: 22pF + C3: 0.1uF + X1: Crystal 20MHz(16MHz/12MHz) diff --git a/converter/ps2_usb/keymap_jis.c b/converter/ps2_usb/keymap_jis.c index 866ccd91..02585150 100644 --- a/converter/ps2_usb/keymap_jis.c +++ b/converter/ps2_usb/keymap_jis.c @@ -1,175 +1,9 @@ /* -Copyright 2011 Jun Wako - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -/* - * Keymap for PS/2 keyboard + * JIS layout Japanese keyboard */ -#include -#include -#include -#include "keycode.h" -#include "print.h" -#include "debug.h" -#include "util.h" -#include "keymap.h" +#include "keymap_common.h" - - - -// Following macros help you to define a keymap with the form of actual keyboard layout. - -/* US layout plus all other various keys */ -#define KEYMAP_ALL( \ - K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ - K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ - K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B,K5D, KF1,KE9,KFA, K6C,K75,K7D, \ - K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52, K5A, K6B,K73,K74,K79, \ - K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K59, KF5, K69,K72,K7A, \ - K14,K9F,K11, K29, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA, \ - \ - K61, /* for European ISO */ \ - K51, K13, K6A, K64, K67, /* for Japanese JIS */ \ - K08, K10, K18, K20, K28, K30, K38, K40, K48, K50, K57, K5F, /* F13-24 */ \ - KB7, KBF, KDE, /* System Power, Sleep, Wake */ \ - KA3, KB2, KA1, /* Mute, Volume Up, Volume Down */ \ - KCD, K95, KBB, KB4, KD0, /* Next, Previous, Stop, Pause, Media Select */ \ - KC8, KAB, KC0, /* Mail, Calculator, My Computer */ \ - K90, KBA, KB8, KB0, /* WWW Search, Home, Back, Forward */ \ - KA8, KA0, K98 /* WWW Stop, Refresh, Favorites */ \ -) { \ - { KC_NO, KC_##K01, KC_NO, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07 }, \ - { KC_##K08, KC_##K09, KC_##K0A, KC_##K0B, KC_##K0C, KC_##K0D, KC_##K0E, KC_NO }, \ - { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_NO }, \ - { KC_##K18, KC_NO, KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D, KC_##K1E, KC_NO }, \ - { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_NO }, \ - { KC_##K28, KC_##K29, KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D, KC_##K2E, KC_NO }, \ - { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_NO }, \ - { KC_##K38, KC_NO, KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D, KC_##K3E, KC_NO }, \ - { KC_##K40, KC_##K41, KC_##K42, KC_##K43, KC_##K44, KC_##K45, KC_##K46, KC_NO }, \ - { KC_##K48, KC_##K49, KC_##K4A, KC_##K4B, KC_##K4C, KC_##K4D, KC_##K4E, KC_NO }, \ - { KC_##K50, KC_##K51, KC_##K52, KC_NO, KC_##K54, KC_##K55, KC_NO, KC_##K57 }, \ - { KC_##K58, KC_##K59, KC_##K5A, KC_##K5B, KC_NO, KC_##K5D, KC_NO, KC_##K5F }, \ - { KC_NO, KC_##K61, KC_NO, KC_NO, KC_##K64, KC_NO, KC_##K66, KC_##K67 }, \ - { KC_NO, KC_##K69, KC_##K6A, KC_##K6B, KC_##K6C, KC_NO, KC_NO, KC_NO }, \ - { KC_##K70, KC_##K71, KC_##K72, KC_##K73, KC_##K74, KC_##K75, KC_##K76, KC_##K77 }, \ - { KC_##K78, KC_##K79, KC_##K7A, KC_##K7B, KC_##K7C, KC_##K7D, KC_##K7E, KC_NO }, \ - { KC_NO, KC_NO, KC_NO, KC_##K83, KC_NO, KC_NO, KC_NO, KC_NO }, \ - { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ - { KC_##K90, KC_##K91, KC_NO, KC_NO, KC_##K94, KC_##K95, KC_NO, KC_NO }, \ - { KC_##K98, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_##K9F }, \ - { KC_##KA0, KC_##KA1, KC_NO, KC_##KA3, KC_NO, KC_NO, KC_NO, KC_##KA7 }, \ - { KC_##KA8, KC_NO, KC_NO, KC_##KAB, KC_NO, KC_NO, KC_NO, KC_##KAF }, \ - { KC_##KB0, KC_NO, KC_##KB2, KC_NO, KC_##KB4, KC_NO, KC_NO, KC_##KB7 }, \ - { KC_##KB8, KC_NO, KC_##KBA, KC_##KBB, KC_NO, KC_NO, KC_NO, KC_##KBF }, \ - { KC_##KC0, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ - { KC_##KC8, KC_NO, KC_##KCA, KC_NO, KC_NO, KC_##KCD, KC_NO, KC_NO }, \ - { KC_##KD0, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ - { KC_NO, KC_NO, KC_##KDA, KC_NO, KC_NO, KC_NO, KC_##KDE, KC_NO }, \ - { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ - { KC_NO, KC_##KE9, KC_NO, KC_##KEB, KC_##KEC, KC_NO, KC_NO, KC_NO }, \ - { KC_##KF0, KC_##KF1, KC_##KF2, KC_NO, KC_##KF4, KC_##KF5, KC_NO, KC_NO }, \ - { KC_NO, KC_NO, KC_##KFA, KC_NO, KC_##KFC, KC_##KFD, KC_##KFE, KC_NO }, \ -} - -/* JIS layout */ -#define KEYMAP_JIS( \ - K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ - K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K6A,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ - K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B, KF1,KE9,KFA, K6C,K75,K7D, \ - K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52,K5D, K5A, K6B,K73,K74,K79, \ - K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A,K51, K59, KF5, K69,K72,K7A, \ - K14,K9F,K11, K67,K29,K64,K13, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA \ -) \ -KEYMAP_ALL( \ - K76,K05,K06,K04,K0C,K03,K0B,K83,K0A,K01,K09,K78,K07, KFC,K7E,KFE, \ - K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K66, KF0,KEC,KFD, K77,KCA,K7C,K7B, \ - K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B,K5D, KF1,KE9,KFA, K6C,K75,K7D, \ - K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52, K5A, K6B,K73,K74,K79, \ - K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K59, KF5, K69,K72,K7A, \ - K14,K9F,K11, K29, K91,KA7,KAF,K94, KEB,KF2,KF4, K70, K71,KDA, \ - \ - NUBS, \ - K51, K13, K6A, K64, K67, \ - F13, F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24, \ - SYSTEM_POWER, SYSTEM_SLEEP, SYSTEM_WAKE, \ - AUDIO_MUTE, AUDIO_VOL_UP, AUDIO_VOL_DOWN, \ - MEDIA_NEXT_TRACK, MEDIA_PREV_TRACK, MEDIA_STOP, MEDIA_PLAY_PAUSE, MEDIA_SELECT, \ - MAIL, CALCULATOR, MY_COMPUTER, \ - WWW_SEARCH, WWW_HOME, WWW_BACK, WWW_FORWARD, \ - WWW_STOP, WWW_REFRESH, WWW_FAVORITES \ -) - -#define KEYMAP_JIS_COMPACT( \ - K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K6A,K66, \ - K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B, \ - K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52,K5D, K5A, \ - K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A,K51, K59, \ - K14,K9F,K11, K67,K29,K64,K13, K91,KA7,KAF,K94 \ -) \ -KEYMAP_ALL( \ - ESC,F1, F2, F3, F4, F5, F6, F7, F8, F9, F10,F11,F12, PSCR,SLCK,BRK, \ - K0E,K16,K1E,K26,K25,K2E,K36,K3D,K3E,K46,K45,K4E,K55,K66, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, \ - K0D,K15,K1D,K24,K2D,K2C,K35,K3C,K43,K44,K4D,K54,K5B,K5D, DEL, END, PGDN, P7, P8, P9, \ - K58,K1C,K1B,K23,K2B,K34,K33,K3B,K42,K4B,K4C,K52, K5A, P4, P5, P6, PPLS, \ - K12,K1A,K22,K21,K2A,K32,K31,K3A,K41,K49,K4A, K59, UP, P1, P2, P3, \ - K14,K9F,K11, K29, K91,KA7,KAF,K94, LEFT,DOWN,RGHT, P0, PDOT,PENT, \ - \ - NUBS, \ - K51, K13, K6A, K64, K67, \ - F13, F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24, \ - SYSTEM_POWER, SYSTEM_SLEEP, SYSTEM_WAKE, \ - AUDIO_MUTE, AUDIO_VOL_UP, AUDIO_VOL_DOWN, \ - MEDIA_NEXT_TRACK, MEDIA_PREV_TRACK, MEDIA_STOP, MEDIA_PLAY_PAUSE, MEDIA_SELECT, \ - MAIL, CALCULATOR, MY_COMPUTER, \ - WWW_SEARCH, WWW_HOME, WWW_BACK, WWW_FORWARD, \ - WWW_STOP, WWW_REFRESH, WWW_FAVORITES \ -) - - -// Assign Fn key(0-7) to a layer to which switch with the Fn key pressed. -static const uint8_t PROGMEM fn_layer[] = { - 1, // Fn0 - 2, // Fn1 - 1, // Fn2 - 2, // Fn3 - 3, // Fn4 - 4, // Fn5 - 0, // Fn6 - 0 // Fn7 -}; - -// Assign Fn key(0-7) to a keycode sent when release Fn key without use of the layer. -// See layer.c for details. -static const uint8_t PROGMEM fn_keycode[] = { - KC_SCLN, // Fn0 - KC_SLSH, // Fn1 - KC_BSPC, // Fn2 - KC_NO, // Fn3 - KC_NO, // Fn4 - KC_SPC, // Fn5 - KC_NO, // Fn6 - KC_NO // Fn7 -}; - - -// The keymap is a 32*8 byte array which convert a PS/2 scan code into a USB keycode. -// See keycode.h for USB keycodes. You should omit a 'KC_' prefix of USB keycodes in keymap macro. -// Use KEYMAP_ISO() or KEYMAP_JIS() instead of KEYMAP() if your keyboard is ISO or JIS. -static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { +const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { /* 0: JIS LAYOUT * ,---. ,---------------. ,---------------. ,---------------. ,-----------. ,-----------. * |Esc| |F1 |F2 |F3 |F4 | |F5 |F6 |F7 |F8 | |F9 |F10|F11|F12| |PrS|ScL|Pau| |Pwr|Slp|Wak| @@ -186,7 +20,6 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * |Ctrl |Gui |Alt |MHEN| Space |HENK|KANA|Alt |Gui |Menu|Ctrl| |Lef|Dow|Rig| | 0| .| | * `-----------------------------------------------------------' `-----------' `---------------' */ -/* KEYMAP_JIS( ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, JYEN,BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, @@ -195,103 +28,7 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH,RO, RSFT, UP, P1, P2, P3, LCTL,LGUI,LALT, MHEN,SPC, HENK,KANA, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT ), -*/ - /* 0: HHKB-wise - * ,-----------------------------------------------------------. - * | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =| \| `| - * |-----------------------------------------------------------| - * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| Bsp | - * |------------------------------------------------------` | - * |Ctrl | A| S| D| F| G| H| J| K| L| ;| :|Ret| | - * |-----------------------------------------------------------| - * |Shift | Z| X| C| V| B| N| M| ,| ,| /| RO|Shift | - * |-----------------------------------------------------------| - * |Ctrl |Gui |Alt |MHEN| Space |HENK|KANA|Alt |Gui |Menu|Ctrl| - * `-----------------------------------------------------------' - */ - KEYMAP_JIS_COMPACT( - ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSLS,BSPC, - TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC, - LCTL,A, S, D, F, G, H, J, K, L, FN0, QUOT,GRV, ENT, - LSFT,Z, X, C, V, B, N, M, COMM,DOT, FN1, RSFT, FN4, - LCTL,LGUI,LALT, LALT,FN5, FN2, FN3, RALT,RGUI,APP, LGUI - ), - - /* 1: Mouse keys - * ,-----------------------------------------------------------. - * |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Backspa| - * |-----------------------------------------------------------| - * |Tab |MwL|MwU|McU|WwU|WwR|MwL|MwD|MwU|MwR| | | | \| - * |-----------------------------------------------------------| - * |CapsLo| |McL|McD|McR| |McL|McD|McU|McR|Fn0| |Return | - * |-----------------------------------------------------------| - * |Shift |VoD|VoU|Mut|Mb2|Mb3|Mb2|Mb1|VoD|VoU|Mut|Shift | - * |-----------------------------------------------------------| - * |Ctrl |Gui |Alt | Mb1 |Alt |Gui |Menu|Ctrl| - * `-----------------------------------------------------------' - * Mc = mouse cursor, Mw = mouse wheel, Mb = mouse button - * Vo = Volume, Mut = Mute - */ - KEYMAP_JIS_COMPACT( - GRV, F1, F2, F3, F4, F5, F6, F7, F8, F8, F10, F11, F12, INS, DEL, - TAB, WH_L,WH_D,MS_U,WH_U,WH_R,WH_L,WH_D,WH_U,WH_R,NO, NO, NO, - LCTL,NO, MS_L,MS_D,MS_R,NO, MS_L,MS_D,MS_U,MS_R,FN0, NO, NO, ENT, - LSFT,NO, NO, BTN1,BTN2,BTN3,BTN2,BTN1,BTN2,BTN3,NO, RSFT, RSFT, - LCTL,LGUI,LALT, LALT,BTN1,FN2, RALT, RALT,RGUI,APP, LGUI - ), - - /* 2: Cursor keys - * ,-----------------------------------------------------------. - * |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Backspa| - * |-----------------------------------------------------------| - * |Tab |Hom|PgU| Up|PgU|End|Hom|PgD|PgU|End| | | | \| - * |-----------------------------------------------------------| - * |CapsLo| |Lef|Dow|Rig| |Lef|Dow| Up|Rig| | |Return | - * |-----------------------------------------------------------| - * |Shift | | | | | |Hom|PgD|PgU|End|Fn1|Shift | - * |-----------------------------------------------------------| - * |Ctrl |Gui |Alt | Space |Alt |Gui |Menu|Ctrl| - * `-----------------------------------------------------------' - */ - KEYMAP_JIS_COMPACT( - GRV, F1, F2, F3, F4, F5, F6, F7, F8, F8, F10, F11, F12, INS, DEL, - TAB, HOME,PGUP,UP, PGDN,END, HOME,PGDN,PGUP,END, NO, NO, NO, - LCTL,HOME,LEFT,DOWN,RGHT,END, LEFT,DOWN,UP, RGHT,NO, NO, NO, ENT, - LSFT,NO, NO, NO, NO, NO, HOME,PGDN,PGUP,END, FN1, RSFT, RSFT, - LCTL,LGUI,LALT, LALT,BTN1,BSPC,FN3, RALT,RGUI,APP, LGUI - ), - - /* 3: HHKB Fn layer */ - KEYMAP_JIS_COMPACT( - GRV, F1, F2, F3, F4, F5, F6, F7, F8, F8, F10, F11, F12, INS, DEL, - CAPS,NO, NO, NO, NO, NO, NO, NO, PSCR,SLCK,PAUS,UP, NO, - LCTL,VOLD,VOLU,MUTE,NO, NO, NO, NO, HOME,PGUP,LEFT,RGHT,NO, ENT, - LSFT,NO, NO, NO, NO, NO, NO, NO, END, PGDN,DOWN,RSFT, FN4, - LCTL,LGUI,LALT, LALT,SPC, BSPC,NO, RALT,RGUI,APP, LGUI - ), - - /* 4: Number */ - KEYMAP_JIS_COMPACT( - GRV, F1, F2, F3, F4, F5, F6, F7, F8, F8, F10, F11, F12, INS, DEL, - TAB, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, - LCTL,1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, ENT, - LSFT,NO, NO, NO, NO, NO, NO, NO, NO, NO, NO, RSFT, RSFT, - LCTL,LGUI,LALT, LALT,FN5, BSPC,NO, RALT,RGUI,APP, LGUI - ), }; - -uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col) -{ - return pgm_read_byte(&keymaps[(layer)][(row)][(col)]); -} - -uint8_t keymap_fn_layer(uint8_t index) -{ - return pgm_read_byte(&fn_layer[index]); -} - -uint8_t keymap_fn_keycode(uint8_t index) -{ - return pgm_read_byte(&fn_keycode[index]); -} +const uint16_t PROGMEM fn_actions[] = { +}; diff --git a/converter/ps2_usb/keymap_plain.c b/converter/ps2_usb/keymap_plain.c index 9c6e7d9f..51b2fddb 100644 --- a/converter/ps2_usb/keymap_plain.c +++ b/converter/ps2_usb/keymap_plain.c @@ -1,19 +1,3 @@ -/* -Copyright 2011,2012,2013 Jun Wako - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ #include "keymap_common.h" @@ -33,8 +17,6 @@ const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * |-----------------------------------------------------------| ,-----------. |-----------|Ent| * |Ctrl |Gui |Alt | Space |Alt |Gui |Menu|Ctrl| |Lef|Dow|Rig| | 0| .| | * `-----------------------------------------------------------' `-----------' `---------------' - * ; = Fn0(to Layer 5) - * / = Fn1(to Layer 6) */ KEYMAP( ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, diff --git a/converter/ps2_usb/keymap_spacefn.c b/converter/ps2_usb/keymap_spacefn.c new file mode 100644 index 00000000..6b06bae2 --- /dev/null +++ b/converter/ps2_usb/keymap_spacefn.c @@ -0,0 +1,61 @@ +/* + * SpaceFN layout + * http://geekhack.org/index.php?topic=51069.0 + */ +#include "keymap_common.h" + + +const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + /* 0: default + * ,---. ,---------------. ,---------------. ,---------------. ,-----------. ,-----------. + * |Esc| |F1 |F2 |F3 |F4 | |F5 |F6 |F7 |F8 | |F9 |F10|F11|F12| |PrS|ScL|Pau| |Pwr|Slp|Wak| + * `---' `---------------' `---------------' `---------------' `-----------' `-----------' + * ,-----------------------------------------------------------. ,-----------. ,---------------. + * | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backspa| |Ins|Hom|PgU| |NmL| /| *| -| + * |-----------------------------------------------------------| |-----------| |---------------| + * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| |Del|End|PgD| | 7| 8| 9| | + * |-----------------------------------------------------------| `-----------' |-----------| +| + * |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return | | 4| 5| 6| | + * |-----------------------------------------------------------| ,---. |---------------| + * |Shift | Z| X| C| V| B| N| M| ,| ,| /|Shift | |Up | | 1| 2| 3| | + * |-----------------------------------------------------------| ,-----------. |-----------|Ent| + * |Ctrl |Gui |Alt | Space |Alt |Gui |Menu|Ctrl| |Lef|Dow|Rig| | 0| .| | + * `-----------------------------------------------------------' `-----------' `---------------' + */ + KEYMAP( + ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, + GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, + TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9, + CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, P4, P5, P6, PPLS, + LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3, + LCTL,LGUI,LALT, FN0, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT + ), + + /* 1: SpaceFN + * ,-----------------------------------------------------------. + * |` | F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Delete | + * |-----------------------------------------------------------| + * | | | | | | | |Hom|Up |End|Psc|Slk|Pau|Ins | + * |-----------------------------------------------------------| + * | | | | | | |PgU|Lef|Dow|Rig| | | | + * |-----------------------------------------------------------| + * | | | | | |Spc|PgD|` |~ | | | | + * |-----------------------------------------------------------| + * | | | | | | | | | + * `-----------------------------------------------------------' + */ + KEYMAP( + ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, + GRV, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, DEL, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, + TRNS,TRNS,TRNS,ESC, TRNS,TRNS,TRNS,HOME,UP, END, PSCR,SLCK,PAUS,INS, DEL, END, PGDN, P7, P8, P9, + TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,PGUP,LEFT,DOWN,RGHT,TRNS,TRNS, TRNS, P4, P5, P6, PPLS, + TRNS,TRNS,TRNS,TRNS,TRNS,SPC, PGDN,GRV, FN1, TRNS,TRNS, TRNS, UP, P1, P2, P3, + TRNS,TRNS,TRNS, TRNS, TRNS,TRNS,TRNS,TRNS, LEFT,DOWN,RGHT, P0, PDOT,PENT + ), +}; + +const uint16_t PROGMEM fn_actions[] = { + [0] = ACTION_LAYER_TAP_KEY(1, KC_SPACE), + [1] = ACTION_MODS_KEY(MOD_LSFT, KC_GRV), // tilde +}; + From 119c34e0949b154ee948534a6c3c64640e0d65ec Mon Sep 17 00:00:00 2001 From: tmk Date: Fri, 29 Nov 2013 09:13:29 +0900 Subject: [PATCH 42/76] Add SpaceFN layout for HHKB --- keyboard/hhkb/keymap_spacefn.c | 75 ++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 keyboard/hhkb/keymap_spacefn.c diff --git a/keyboard/hhkb/keymap_spacefn.c b/keyboard/hhkb/keymap_spacefn.c new file mode 100644 index 00000000..b77e9edb --- /dev/null +++ b/keyboard/hhkb/keymap_spacefn.c @@ -0,0 +1,75 @@ +/* + * SpaceFN + * http://geekhack.org/index.php?topic=51069.0 + */ +#include "keymap_common.h" + + +const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + /* Layer 0: Default Layer + * ,-----------------------------------------------------------. + * |Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =| `|BSp| + * |-----------------------------------------------------------| + * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| + * |-----------------------------------------------------------| + * |Contro| A| S| D| F| G| H| J| K| L| ;| '|Enter | + * |-----------------------------------------------------------| + * |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift |Fn0| + * `-----------------------------------------------------------' + * |Gui|Alt | SpaceFN |Alt |Gui| + * `-------------------------------------------' + */ + KEYMAP(ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, GRV, BSPC, \ + TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, \ + LCTL,A, S, D, F, G, H, J, K, L, SCLN,QUOT,ENT, \ + LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH,RSFT,FN0, \ + LGUI,LALT, FN1, RALT,RGUI), + + /* Layer 1: HHKB mode (HHKB Fn) + * ,-----------------------------------------------------------. + * |Pwr| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del| + * |-----------------------------------------------------------| + * |Caps | | | | | | | |Psc|Slk|Pus|Up | |Backs| + * |-----------------------------------------------------------| + * | |VoD|VoU|Mut| | | *| /|Hom|PgU|Lef|Rig|Enter | + * |-----------------------------------------------------------| + * | | | | | | | +| -|End|PgD|Dow| | | + * `-----------------------------------------------------------' + * | | | | | | + * `-------------------------------------------' + */ + KEYMAP(PWR, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \ + CAPS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,PSCR,SLCK,PAUS, UP, TRNS, BSPC, \ + TRNS,VOLD,VOLU,MUTE,TRNS,TRNS,PAST,PSLS,HOME,PGUP,LEFT,RGHT,PENT, \ + TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,PPLS,PMNS,END, PGDN,DOWN,TRNS,TRNS, \ + TRNS,TRNS, SPC, TRNS,TRNS), + + /* Layer 2: SpaceFN + * ,-----------------------------------------------------------. + * |` | F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12| |Del| + * |-----------------------------------------------------------| + * | | | |Esc| | | |Hom|Up |End|Psc|Slk|Pau|Ins | + * |-----------------------------------------------------------| + * | | | | | | |PgU|Lef|Dow|Rig| | | | + * |-----------------------------------------------------------| + * | | | | | |Spc|PgD|` |~ | | | | | + * `-----------------------------------------------------------' + * | | | | | | + * `-------------------------------------------' + */ + KEYMAP(GRV, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, TRNS,DEL, \ + TRNS,TRNS,TRNS,ESC, TRNS,TRNS,TRNS,HOME,UP, END, PSCR,SLCK,PAUS,INS, \ + TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,PGUP,LEFT,DOWN,RGHT,TRNS,TRNS,TRNS, \ + TRNS,TRNS,TRNS,TRNS,TRNS,SPC, PGDN,GRV, FN2, TRNS,TRNS,TRNS,NO, \ + TRNS,TRNS, TRNS, TRNS,TRNS), +}; + +/* + * Fn action definition + */ +const uint16_t PROGMEM fn_actions[] = { + [0] = ACTION_LAYER_MOMENTARY(1), + [1] = ACTION_LAYER_TAP_KEY(2, KC_SPACE), + [2] = ACTION_MODS_KEY(MOD_LSFT, KC_GRV), // tilde +}; + From 0b917d4f109637f7e2d584d04396a0d6396fad33 Mon Sep 17 00:00:00 2001 From: tmk Date: Sat, 30 Nov 2013 12:32:47 +0900 Subject: [PATCH 43/76] Fix README.md of hhkb --- keyboard/hhkb/README.md | 51 ++++++++------------------------------ keyboard/hhkb/doc/V-USB.md | 39 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 41 deletions(-) create mode 100644 keyboard/hhkb/doc/V-USB.md diff --git a/keyboard/hhkb/README.md b/keyboard/hhkb/README.md index 3959ae85..92136482 100644 --- a/keyboard/hhkb/README.md +++ b/keyboard/hhkb/README.md @@ -1,8 +1,8 @@ Alternative Controller for HHKB Pro =================================== -I wanted to add some features like vi cursor and mouse keys to my [HHKB][HHKB] but its controller is not programmable and -firmware source code is not open, of course. This means customizing this keyboard needs to replace original -controller with programmable one. This controller can work with HHKB Professional and Professional 2 model. +I wanted to add some features like vi cursor and mouse keys to my [HHKB][HHKB] but its controller is not programmable and firmware source code is not open, of course. This means customizing this keyboard needs to replace original controller with programmable one. + +This controller can work with HHKB **Professional**, **Professional** 2 and **Type-S**. See [this thread][AltController] in geekhack.org. @@ -46,16 +46,10 @@ See [this document](../../doc/build.md) first. Set `MCU`, `BOOTLOADER_SIZE` and other build options in `Makefile` and `config.h`. ### Build -Just run make after intall tools. +Several version of keymap are available in advance but you are recommended to define your favorite layout yourself. Just `make` with `KEYMAP` option like: - $ make + $ make KEYMAP=[hasu|hhkb|spacefn|] -Use `Makefile.pjrc` if you want to use PJRC stack instead of LUFA.(LUFA is recommended.) - - $ make -f Makefile.pjrc - -Use `Makefile.vusb` for [V-USB] controller.(not supported actively any more.) - $ make -f Makefile.vusb ### Program First, push reset button on board to start bootloader. @@ -71,8 +65,8 @@ Or you can also use [FLIP] command to program. Also the tool should be intalled Use [Teensy Loader] if your controller is Teensy/Teensy++. -##How to Customize -See [tmk_keyboard] documents. +##Keymap +To define your own keymap create file named `keymap_.c` and see keymap document(you can find in top README.md) and existent keymap files. ##Hardware @@ -83,7 +77,7 @@ TMK designed [Keyboard Controller Board for HHKB Pro2(KiCad project)](https://gi See [this post](http://geekhack.org/index.php?topic=12047.msg948923#msg948923). -###2. PJRC Teensy++ 2.0 connection +###2. PJRC Teensy++ 2.0 version +---------------+ | Teensy++ | | | @@ -101,32 +95,8 @@ See [this post](http://geekhack.org/index.php?topic=12047.msg948923#msg948923). - NOTE: PJRC [Teensy](http://www.pjrc.com/teensy/) -###3. V-USB connection - +---+ +---------------+ - USB GND | | ATmega328p | - ~~~ C3 | | - 5V <-------+--------+---|Vcc,AVCC | HHKB pro pro2 - R1 | | ~~~~~~~~ ~~~~ - D- <----+--+-----R2-----|INT1 PB2-4|------->ROW (6-8) (5-7) - D+ <----|---+----R3-----|INT0 PC0-2|------->COL (9-11) (8-10) - Z1 Z2 | PC3|------->ENABLE (12) (11) - GND<----+---+-----------|GND PB0|<-------KEY (4) (3) - | PB1|------->PREV (5) (4) - | | - GND+-C2--+--|XTAL1 RXD|------->Debug Console - X1 | TXD|<-------Debug Console - GND+-C3--+--|XTAL2 RST|---SW--+GND - +---------------+ - R1: 1.5K Ohm - R2,R3: 68 Ohm - Z1,Z2: Zener 3.6V - C1,C2: 22pF - C3: 0.1uF - X1: Crystal 12MHz - SW: Push Switch(for bootloader) - -- NOTE: See [V-USB] documentation for more detail of hardware and the USB stack. -- NOTE: [USBaspLoader] is very useful for firmware update. +###3. V-USB version +See [V-USB controller for HHKB](doc/V-USB.md) [LUFA]: http://www.fourwalledcubicle.com/LUFA.php @@ -135,4 +105,3 @@ See [this post](http://geekhack.org/index.php?topic=12047.msg948923#msg948923). [FLIP]: http://www.atmel.com/tools/FLIP.aspx [Teensy Loader]: http://www.pjrc.com/teensy/loader.html [V-USB]: http://www.obdev.at/products/vusb/index.html -[USBaspLoader]: http://www.obdev.at/products/vusb/usbasploader.html diff --git a/keyboard/hhkb/doc/V-USB.md b/keyboard/hhkb/doc/V-USB.md new file mode 100644 index 00000000..7ae86f45 --- /dev/null +++ b/keyboard/hhkb/doc/V-USB.md @@ -0,0 +1,39 @@ +V-USB controller for HHKB +========================= +Not supported actively any more. + +## Build +Use `Makefile.vusb` for [V-USB] controller. + $ make -f Makefile.vusb + +##Hardware +###3. V-USB connection + +---+ +---------------+ + USB GND | | ATmega328p | + ~~~ C3 | | + 5V <-------+--------+---|Vcc,AVCC | HHKB pro pro2 + R1 | | ~~~~~~~~ ~~~~ + D- <----+--+-----R2-----|INT1 PB2-4|------->ROW (6-8) (5-7) + D+ <----|---+----R3-----|INT0 PC0-2|------->COL (9-11) (8-10) + Z1 Z2 | PC3|------->ENABLE (12) (11) + GND<----+---+-----------|GND PB0|<-------KEY (4) (3) + | PB1|------->PREV (5) (4) + | | + GND+-C2--+--|XTAL1 RXD|------->Debug Console + X1 | TXD|<-------Debug Console + GND+-C3--+--|XTAL2 RST|---SW--+GND + +---------------+ + R1: 1.5K Ohm + R2,R3: 68 Ohm + Z1,Z2: Zener 3.6V + C1,C2: 22pF + C3: 0.1uF + X1: Crystal 12MHz + SW: Push Switch(for bootloader) + +- NOTE: See [V-USB] documentation for more detail of hardware and the USB stack. +- NOTE: [USBaspLoader] is very useful for firmware update. + + +[V-USB]: http://www.obdev.at/products/vusb/index.html +[USBaspLoader]: http://www.obdev.at/products/vusb/usbasploader.html From c9dee36e42ca56bda91d07071bd4251dbba23009 Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 2 Dec 2013 12:04:50 +0900 Subject: [PATCH 44/76] Make ps2_usart default and fix SpaceFN --- converter/ps2_usb/Makefile | 4 ++-- converter/ps2_usb/keymap_spacefn.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/converter/ps2_usb/Makefile b/converter/ps2_usb/Makefile index 04bf28a0..db0912eb 100644 --- a/converter/ps2_usb/Makefile +++ b/converter/ps2_usb/Makefile @@ -84,9 +84,9 @@ NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA # PS/2 Options # -#PS2_USE_USART = yes # uses hardware USART engine for PS/2 signal receive(recomened) +PS2_USE_USART = yes # uses hardware USART engine for PS/2 signal receive(recomened) #PS2_USE_INT = yes # uses external interrupt for falling edge of PS/2 clock pin -PS2_USE_BUSYWAIT = yes # uses primitive reference code +#PS2_USE_BUSYWAIT = yes # uses primitive reference code # Optimize size but this may cause error "relocation truncated to fit" diff --git a/converter/ps2_usb/keymap_spacefn.c b/converter/ps2_usb/keymap_spacefn.c index 6b06bae2..7f537bfe 100644 --- a/converter/ps2_usb/keymap_spacefn.c +++ b/converter/ps2_usb/keymap_spacefn.c @@ -24,7 +24,7 @@ const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { */ KEYMAP( ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, - GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, + ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9, CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, P4, P5, P6, PPLS, LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3, From ac1acca8d749092d2a4beffb6da327b5288f52b6 Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 16 Dec 2013 21:56:44 +0900 Subject: [PATCH 45/76] Add description of keyboard report in report.h --- common/report.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/common/report.h b/common/report.h index 91982840..71543cc2 100644 --- a/common/report.h +++ b/common/report.h @@ -94,6 +94,26 @@ along with this program. If not, see . extern "C" { #endif +/* + * keyboard report is 8-byte array retains state of 8 modifiers and 6 keys. + * + * byte |0 |1 |2 |3 |4 |5 |6 |7 + * -----+--------+--------+--------+--------+--------+--------+--------+-------- + * desc |mods |reserved|keys[0] |keys[1] |keys[2] |keys[3] |keys[4] |keys[5] + * + * It is exended to 16 bytes to retain 120keys+8mods when NKRO mode. + * + * byte |0 |1 |2 |3 |4 |5 |6 |7 ... |15 + * -----+--------+--------+--------+--------+--------+--------+--------+-------- +-------- + * desc |mods |bits[0] |bits[1] |bits[2] |bits[3] |bits[4] |bits[5] |bits[6] ... |bit[14] + * + * mods retains state of 8 modifiers. + * + * bit |0 |1 |2 |3 |4 |5 |6 |7 + * -----+--------+--------+--------+--------+--------+--------+--------+-------- + * desc |Lcontrol|Lshift |Lalt |Lgui |Rcontrol|Rshift |Ralt |Rgui + * + */ typedef union { uint8_t raw[REPORT_SIZE]; struct { From 696a7fbc6f1fc1e48948dd56c5f45462549b329c Mon Sep 17 00:00:00 2001 From: TiBounise Date: Mon, 16 Dec 2013 19:53:02 +0100 Subject: [PATCH 46/76] Fixing a typo --- doc/build.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/build.md b/doc/build.md index ae856501..2e8157e0 100644 --- a/doc/build.md +++ b/doc/build.md @@ -40,7 +40,7 @@ Move to project directory in the firmware source. Build firmware using GNU `make` command. You'll see `_.hex` file in that directory unless something unexpected occurs in build process. - mkae -f Makefile. clean + make -f Makefile. clean make -f Makefile. From 8fc26a1360a4856bdd13fc14caf339fb6841b4d4 Mon Sep 17 00:00:00 2001 From: Yann Hodique Date: Thu, 26 Dec 2013 21:16:27 -0800 Subject: [PATCH 47/76] fix compilation --- converter/sun_usb/matrix.c | 1 - 1 file changed, 1 deletion(-) diff --git a/converter/sun_usb/matrix.c b/converter/sun_usb/matrix.c index 717c131e..a61e3a2d 100644 --- a/converter/sun_usb/matrix.c +++ b/converter/sun_usb/matrix.c @@ -63,7 +63,6 @@ uint8_t matrix_cols(void) void matrix_init(void) { - print_enable = true; debug_enable = true; serial_init(); From 8e9498f066185b2bb5165c4478c681b79500951a Mon Sep 17 00:00:00 2001 From: Yann Hodique Date: Thu, 26 Dec 2013 21:52:58 -0800 Subject: [PATCH 48/76] fix hard-coded keys values provided to macro were not used for the "K61,K49,K33, K30" block --- converter/sun_usb/keymap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/converter/sun_usb/keymap.c b/converter/sun_usb/keymap.c index 048a863c..3d724a52 100644 --- a/converter/sun_usb/keymap.c +++ b/converter/sun_usb/keymap.c @@ -77,12 +77,12 @@ along with this program. If not, see . K63, K64,K65,K66,K67,K68,K69,K6A,K6B,K6C,K6D, K0D,K14,K6E, \ K77,K13, K78, K79, K7A,K43,K62,K18,K1B,K1C \ ) KEYMAP( \ - HELP, K05,K06,K08,K0A, K0C,K0E,K10,K11, K12,K07,K09,K0B, PSCR,SLCK,PAUS, MUTE,VOLD,VOLU,PWR, \ + HELP, K05,K06,K08,K0A, K0C,K0E,K10,K11, K12,K07,K09,K0B, PSCR,SLCK,PAUS, MUTE,VOLD,VOLU,K30, \ K01, AGAIN, K1D,K1E,K1F,K20,K21,K22,K23,K24,K25,K26,K27,K28,K29,K58,K2A, K2C, K34, K60, K62, PSLS,PAST,PMNS, \ MENU, UNDO, K35, K36,K37,K38,K39,K3A,K3B,K3C,K3D,K3E,K3F,K40,K41, K2B, K42, K4A, K7B, P7, P8, P9, PPLS, \ - SELECT, COPY, K4C, K4D,K4E,K4F,K50,K51,K52,K53,K54,K55,K56,K57, K59, P4, P5, P6, \ - EXECUTE,PASTE, K63, K64,K65,K66,K67,K68,K69,K6A,K6B,K6C,K6D, K6E, K14, P1, P2, P3, PENT, \ - FIND, CUT, K77,K13, K78, HENK, K79, MHEN, KANA, K7A,K43,K0D, K18, K1B, K1C, P0, PDOT \ + SELECT, K33, K4C, K4D,K4E,K4F,K50,K51,K52,K53,K54,K55,K56,K57, K59, P4, P5, P6, \ + EXECUTE,K49, K63, K64,K65,K66,K67,K68,K69,K6A,K6B,K6C,K6D, K6E, K14, P1, P2, P3, PENT, \ + FIND, K61, K77,K13, K78, HENK, K79, MHEN, KANA, K7A,K43,K0D, K18, K1B, K1C, P0, PDOT \ ) From 92cda14f7a30f14bb3836c2369d110b2c8b4cf75 Mon Sep 17 00:00:00 2001 From: tmk Date: Fri, 3 Jan 2014 07:05:41 +0900 Subject: [PATCH 49/76] Add ascii_usb ASCII Serial Console terminal converter --- README.md | 1 + converter/ascii_usb/Makefile | 82 +++++++++++++++ converter/ascii_usb/README | 33 ++++++ converter/ascii_usb/config.h | 70 +++++++++++++ converter/ascii_usb/keymap.c | 42 ++++++++ converter/ascii_usb/led.c | 25 +++++ converter/ascii_usb/matrix.c | 195 +++++++++++++++++++++++++++++++++++ 7 files changed, 448 insertions(+) create mode 100644 converter/ascii_usb/Makefile create mode 100644 converter/ascii_usb/README create mode 100644 converter/ascii_usb/config.h create mode 100644 converter/ascii_usb/keymap.c create mode 100644 converter/ascii_usb/led.c create mode 100644 converter/ascii_usb/matrix.c diff --git a/README.md b/README.md index 536cc753..bca1c136 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ You can find some keyboard specific projects under `converter` and `keyboard` di * [sun_usb](converter/sun_usb/) - [Sun] to USB(type4, 5 and 3?) * [pc98_usb](converter/pc98_usb/) - [PC98] to USB * [usb_usb](converter/usb_usb/) - USB to USB(experimental) +* [ascii_usb](converter/ascii_usb/) - ASCII(Serial console terminal) to USB ### keyboard * [hhkb](keyboard/hhkb/) - [Happy Hacking Keyboard pro][GH_hhkb] **my main board** diff --git a/converter/ascii_usb/Makefile b/converter/ascii_usb/Makefile new file mode 100644 index 00000000..408aa423 --- /dev/null +++ b/converter/ascii_usb/Makefile @@ -0,0 +1,82 @@ +# Target file name (without extension). +TARGET = ascii_usb + +# Directory common source filess exist +TOP_DIR = ../.. + +# Directory keyboard dependent files exist +TARGET_DIR = . + +# keyboard dependent files +SRC = keymap.c \ + matrix.c \ + led.c \ + protocol/serial_uart.c + +CONFIG_H = config.h + + +# MCU name, you MUST set this to match the board you are using +# type "make clean" after changing this, so all files will be rebuilt +#MCU = at90usb162 # Teensy 1.0 +MCU = atmega32u4 # Teensy 2.0 +#MCU = at90usb646 # Teensy++ 1.0 +#MCU = at90usb1286 # Teensy++ 2.0 + + +# Processor frequency. +# Normally the first thing your program should do is set the clock prescaler, +# so your program will run at the correct speed. You should also set this +# variable to same clock speed. The _delay_ms() macro uses this, and many +# examples use this variable to calculate timings. Do not add a "UL" here. +F_CPU = 16000000 + + +# +# LUFA specific +# +# Target architecture (see library "Board Types" documentation). +ARCH = AVR8 + +# Input clock frequency. +# This will define a symbol, F_USB, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_USB = $(F_CPU) + +# Interrupt driven control endpoint task +OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT + + +# Build Options +# *Comment out* to disable the options. +# +#MOUSEKEY_ENABLE = yes # Mouse keys +#EXTRAKEY_ENABLE = yes # Audio control and System control +CONSOLE_ENABLE = yes # Console for debug +#NKRO_ENABLE = yes # USB Nkey Rollover + + +# Boot Section Size in bytes +# Teensy halfKay 512 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +OPT_DEFS += -DBOOTLOADER_SIZE=4096 + + +# Search Path +VPATH += $(TARGET_DIR) +VPATH += $(TOP_DIR) + + +include $(TOP_DIR)/protocol/lufa.mk +include $(TOP_DIR)/protocol.mk +include $(TOP_DIR)/common.mk +include $(TOP_DIR)/rules.mk diff --git a/converter/ascii_usb/README b/converter/ascii_usb/README new file mode 100644 index 00000000..afd2e47f --- /dev/null +++ b/converter/ascii_usb/README @@ -0,0 +1,33 @@ +ASCII to USB keyboard protocol converter +======================================== +This converts serial console terminal into USB keyboard, tested with TRS-80 model 100 TELCOM application. +Target MCU is ATMega32u4 but other USB capable AVR will also work. + + +Hardware +-------- +Connect RX, TX and GND to UART pin of AVR. Note that you may need line drvier/level shfiter like MAX232 to interface high voltage of RS-232C. + + + +Build Firmware +-------------- +Configure UART setting and Just use 'make' + + $ cd ascii_usb + $ make + +Then, load the binary to MCU with your favorite programmer. + + + +Limitation +---------- +- This cannot see key up event, you cannot hold a key. +- Alt, Gui(Win/Mac) modifier key are not available. + + + +Scan code +--------- +ASCII code(0x01-7F) diff --git a/converter/ascii_usb/config.h b/converter/ascii_usb/config.h new file mode 100644 index 00000000..0908997a --- /dev/null +++ b/converter/ascii_usb/config.h @@ -0,0 +1,70 @@ +/* +Copyright 2014 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef CONFIG_H +#define CONFIG_H + +#define VENDOR_ID 0xFEED +#define PRODUCT_ID 0x5C01 +#define DEVICE_VER 0x0100 +#define MANUFACTURER t.m.k. +#define PRODUCT ASCII keyboard converter +#define DESCRIPTION converts Serial Console Terminal into USB keyboard + + +/* matrix size */ +#define MATRIX_ROWS 16 +#define MATRIX_COLS 16 + +/* key combination for command */ +#define IS_COMMAND() ( \ + host_get_first_key() == KC_BRK \ +) + + +/* + * Serial(USART) configuration + * asynchronous, positive logic, 19200baud, bit order: LSB first + * 1-start bit, 8-data bit, odd parity, 1-stop bit + */ +#ifdef __AVR_ATmega32U4__ + #define SERIAL_UART_BAUD 19200 + #define SERIAL_UART_DATA UDR1 + #define SERIAL_UART_UBRR ((F_CPU/(16UL*SERIAL_UART_BAUD))-1) + #define SERIAL_UART_RXD_VECT USART1_RX_vect + #define SERIAL_UART_TXD_READY (UCSR1A&(1<>8); /* baud rate */ \ + UCSR1B |= (1< + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include +#include +#include +#include "keycode.h" +#include "action.h" +#include "action_macro.h" +#include "action_util.h" +#include "util.h" +#include "print.h" +#include "keymap.h" + + +// Keymap is not used. See matrix.c. + +/* translates key to keycode */ +uint8_t keymap_key_to_keycode(uint8_t layer, key_t key) +{ + return KC_NO; +} + +/* translates Fn keycode to action */ +action_t keymap_fn_to_action(uint8_t keycode) +{ + return (action_t) { .code = ACTION_NO }; +} diff --git a/converter/ascii_usb/led.c b/converter/ascii_usb/led.c new file mode 100644 index 00000000..d1c39bc6 --- /dev/null +++ b/converter/ascii_usb/led.c @@ -0,0 +1,25 @@ +/* +Copyright 2012 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "stdint.h" +#include "serial.h" +#include "led.h" + + +void led_set(uint8_t usb_led) +{ +} diff --git a/converter/ascii_usb/matrix.c b/converter/ascii_usb/matrix.c new file mode 100644 index 00000000..e1ea8e0a --- /dev/null +++ b/converter/ascii_usb/matrix.c @@ -0,0 +1,195 @@ +/* +Copyright 2014 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include "print.h" +#include "util.h" +#include "matrix.h" +#include "debug.h" +#include "action_util.h" +#include "protocol/serial.h" + + +/* + * Not use Matrix. + * + * ROW: 16(4bits) + * COL: 16(4bits) + * + * 8bit wide + * +---------+ + * 0|00 ... 0F| + * 1|08 ... 1F| + * :| ... | + * :| ... | + * E|E0 ... EF| + * F|F0 ... FF| + * +---------+ + */ + + +inline +uint8_t matrix_rows(void) +{ + return MATRIX_ROWS; +} + +inline +uint8_t matrix_cols(void) +{ + return MATRIX_COLS; +} + +void matrix_init(void) +{ + debug_matrix = true; + serial_init(); + + debug("init\n"); + return; +} + +static void type_key(uint16_t keycode) +{ + if (keycode == 0) return; + + uint8_t mods = keycode>>8; + uint8_t key = keycode&0xFF; + if (mods) { + add_mods(mods); + send_keyboard_report(); + } + + add_key(key); + send_keyboard_report(); + + del_key(key); + send_keyboard_report(); + + if (mods) { + del_mods(mods); + send_keyboard_report(); + } +} +static uint16_t code2key(uint8_t code) +{ + // ASCII to key combination in US laout + switch (code) { + case 0x01 ... 0x08: // Ctrl-[a-z] + return MOD_BIT(KC_LCTRL)<<8 | (KC_A + (code-0x01)); + case 0x09: return KC_TAB; // TAB(Ctrl-i) + case 0x0A ... 0x0C: // Ctrl-[a-z] + return MOD_BIT(KC_LCTRL)<<8 | (KC_A + (code-0x01)); + case 0x0D: return KC_ENTER; // Enter(Ctrl-m) + case 0x0E ... 0x1A: // Ctrl-[a-z] + return MOD_BIT(KC_LCTRL)<<8 | (KC_A + (code-0x01)); + case 0x1B: return KC_ESC; + case 0x1C: return KC_RIGHT; + case 0x1D: return KC_LEFT; + case 0x1E: return KC_UP; + case 0x1F: return KC_DOWN; + case 0x20: return KC_SPACE; + case 0x21: return MOD_BIT(KC_LSHIFT)<<8 | KC_1; // ! + case 0x22: return MOD_BIT(KC_LSHIFT)<<8 | KC_QUOTE; // " + case 0x23: return MOD_BIT(KC_LSHIFT)<<8 | KC_3; // # + case 0x24: return MOD_BIT(KC_LSHIFT)<<8 | KC_4; // $ + case 0x25: return MOD_BIT(KC_LSHIFT)<<8 | KC_5; // % + case 0x26: return MOD_BIT(KC_LSHIFT)<<8 | KC_7; // & + case 0x27: return KC_QUOTE; // ' + case 0x28: return MOD_BIT(KC_LSHIFT)<<8 | KC_9; // ( + case 0x29: return MOD_BIT(KC_LSHIFT)<<8 | KC_0; // ) + case 0x2A: return MOD_BIT(KC_LSHIFT)<<8 | KC_8; // * + case 0x2B: return MOD_BIT(KC_LSHIFT)<<8 | KC_EQUAL; // + + case 0x2C: return KC_COMMA; // , + case 0x2D: return KC_MINUS; // - + case 0x2E: return KC_DOT; // . + case 0x2F: return KC_SLASH; // / + case 0x30: return KC_0; + case 0x31 ... 0x39: // 1-9 + return KC_1 + (code-0x31); + case 0x3A: return MOD_BIT(KC_LSHIFT)<<8 | KC_SCLN; // : + case 0x3B: return KC_SCLN; // ; + case 0x3C: return MOD_BIT(KC_LSHIFT)<<8 | KC_COMMA; // < + case 0x3D: return KC_EQUAL; // = + case 0x3E: return MOD_BIT(KC_LSHIFT)<<8 | KC_DOT; // > + case 0x3F: return MOD_BIT(KC_LSHIFT)<<8 | KC_SLASH; // ? + case 0x40: return MOD_BIT(KC_LSHIFT)<<8 | KC_2; // @ + case 0x41 ... 0x5A: // A-Z + return MOD_BIT(KC_LSHIFT)<<8 | (KC_A + (code-0x41)); + case 0x5B: return KC_LBRACKET; // [ + case 0x5C: return KC_BSLASH; // + case 0x5D: return KC_RBRACKET; // ] + case 0x5E: return MOD_BIT(KC_LSHIFT)<<8 | KC_6; // ^ + case 0x5F: return MOD_BIT(KC_LSHIFT)<<8 | KC_MINUS; // _ + case 0x61 ... 0x7A: // a-z + return KC_A + (code-0x61); + case 0x7B: return MOD_BIT(KC_LSHIFT)<<8 | KC_LBRACKET; // { + case 0x7C: return MOD_BIT(KC_LSHIFT)<<8 | KC_BSLASH; // | + case 0x7D: return MOD_BIT(KC_LSHIFT)<<8 | KC_RBRACKET; // } + case 0x7E: return MOD_BIT(KC_LSHIFT)<<8 | KC_GRAVE; // } + case 0x7F: return KC_DELETE; // + } + return 0; +} + +uint8_t matrix_scan(void) +{ + uint16_t code = serial_recv2(); + if (code == -1) { + return 0; + } + + print_hex8(code); print(" "); + + // echo back + serial_send(code); + type_key(code2key(code)); + + + return code; +} + +inline +bool matrix_has_ghost(void) +{ + return false; +} + +inline +bool matrix_is_on(uint8_t row, uint8_t col) +{ + return false; +} + +inline +matrix_row_t matrix_get_row(uint8_t row) +{ + return 0; +} + +void matrix_print(void) +{ + print("\nr/c 0123456789ABCDEF\n"); + for (uint8_t row = 0; row < matrix_rows(); row++) { + phex(row); print(": "); + pbin_reverse(matrix_get_row(row)); + print("\n"); + } +} From 73ab537bfc47263a11c5162bd5087203ef346a88 Mon Sep 17 00:00:00 2001 From: tmk Date: Fri, 3 Jan 2014 08:05:19 +0900 Subject: [PATCH 50/76] Add TRS-80 model 100 instruction --- converter/ascii_usb/README | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/converter/ascii_usb/README b/converter/ascii_usb/README index afd2e47f..b9c7ef25 100644 --- a/converter/ascii_usb/README +++ b/converter/ascii_usb/README @@ -28,6 +28,11 @@ Limitation -Scan code ---------- -ASCII code(0x01-7F) +TRS-80 model 100 +---------------- +Use TELCOM program with setting: 19200bps/8bit/odd parity/1stop bit +To set this configuration push Stat(F3) and input '9801D,10'. Then push Term(F4) to connect. + + + + From 22bd315b6459ea1cc0d1af456d55fb4970f36c6d Mon Sep 17 00:00:00 2001 From: Thomas Russell Murphy Date: Thu, 2 Jan 2014 18:37:20 -0500 Subject: [PATCH 51/76] Spellcheck of README.md --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index bca1c136..b76b7fb9 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ You can find some keyboard specific projects under `converter` and `keyboard` di ### converter * [ps2_usb](converter/ps2_usb/) - [PS/2 keyboard to USB][GH_ps2] * [adb_usb](converter/adb_usb/) - [ADB keyboard to USB][GH_adb] -* [m0110_usb](converter/m0110_usb) - [Machintosh 128K/512K/Plus keyboard to USB][GH_m0110] +* [m0110_usb](converter/m0110_usb) - [Macintosh 128K/512K/Plus keyboard to USB][GH_m0110] * [terminal_usb](converter/terminal_usb/) - [IBM Model M terminal keyboard(PS/2 scancode set3) to USB][GH_terminal] * [news_usb](converter/news_usb/) - [Sony NEWS keyboard to USB][GH_news] * [x68k_usb](converter/x68k_usb/) - [Sharp X68000 keyboard to USB][GH_x68k] @@ -91,7 +91,7 @@ See [doc/keymap.md](doc/keymap.md). -Magic Comannds +Magic Commands -------------- To see help press `Magic` + `H`. @@ -122,7 +122,7 @@ Following commands can be also executed with `Magic` + key. In console mode `Mag **TBD** ### Boot Magic Configuration - Virtual DIP Switch -Boot Magic are executed during boot up time. Press Magic key below then pulgin keyboard cable. +Boot Magic are executed during boot up time. Press Magic key below then plug in keyboard cable. Note that you must use keys of **Layer 0** as Magic keys. These settings are stored in EEPROM so that retain your configure over power cycles. To avoid configuring accidentally additive salt key `KC_SPACE` also needs to be pressed along with the following configuration keys. The salt key is configurable in `config.h`. See [common/bootmagic.h](common/bootmagic.h). @@ -142,7 +142,7 @@ To avoid configuring accidentally additive salt key `KC_SPACE` also needs to be #### Keymap - Swap Control and CapsLock(`Left Control`) -- Change CapsLock to Control(`Casp Lock`) +- Change CapsLock to Control(`Caps Lock`) - Swap LeftAlt and Gui(`Left Alt`) - Swap RightAlt and Gui(`Right Alt`) - Disable Gui(`Left Gui`) @@ -211,7 +211,7 @@ Architecture -Debuging +Debugging -------- Use PJRC's `hid_listen` to see debug messages. You can use the tool for debug even if firmware use LUFA stack. @@ -228,7 +228,7 @@ Files and Directories * converter/ - protocol converter projects * doc/ - documents * common.mk - Makefile for common -* protoco.mk - Makefile for protocol +* protocol.mk - Makefile for protocol * rules.mk - Makefile for build rules ### Common @@ -264,7 +264,7 @@ Files and Directories -Conding Style +Coding Style ------------- - Doesn't use Tab to indent, use 4-spaces instead. From e0a95d4075b972ef5d623aa125e009c28e0edaf8 Mon Sep 17 00:00:00 2001 From: Thomas Russell Murphy Date: Thu, 2 Jan 2014 19:05:52 -0500 Subject: [PATCH 52/76] Spellchecked documentation. --- doc/USB_NKRO.txt | 14 +++++++------- doc/build.md | 10 +++++----- doc/keymap.md | 36 ++++++++++++++++++------------------ doc/other_projects.md | 2 +- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/doc/USB_NKRO.txt b/doc/USB_NKRO.txt index 4751bca8..d9f1d122 100644 --- a/doc/USB_NKRO.txt +++ b/doc/USB_NKRO.txt @@ -14,7 +14,7 @@ dfj's NKRO(2010/06) http://geekhack.org/showthread.php?p=204389#post204389 -Terminogy +Terminology --------- NKRO ghost @@ -26,7 +26,7 @@ membrane OS Support Status ----------------- USB NKRO is possible *without* a custom driver. -At least following OSes supports. +At least following OS's supports. Windows7 64bit WindowsXP Windows2000 SP4 @@ -37,7 +37,7 @@ At least following OSes supports. Custom Driver for USB NKRO -------------------------- NOT NEEDED -at least when using fllowing report formats on Windows, Linux or MacOSX. +at least when using following report formats on Windows, Linux or MacOSX. USB NKRO methods @@ -47,8 +47,8 @@ USB NKRO methods If the keyboard has 2 virtual keyboard with Standard report(6KRO), it gets 12KRO. Using this method means the keyboard is a composite device. -2. Exteded report - It needs large report size for this method to achive NKRO. +2. Extended report + It needs large report size for this method to achieve NKRO. If a keyboard has 101keys, it needs 103byte report. It seems to be inefficient. 3. Bitmap report @@ -122,8 +122,8 @@ Considerations Compatibility boot protocol minor/old system - Some BIOS doesn't send SET_PROTCOL request, a keyboard can't switch to boot protocol mode. - This may cuase a problem on a keyboard which uses other report than Standard. + Some BIOS doesn't send SET_PROTOCOL request, a keyboard can't switch to boot protocol mode. + This may cause a problem on a keyboard which uses other report than Standard. Reactivity USB polling time OS/Driver processing time diff --git a/doc/build.md b/doc/build.md index 2e8157e0..bfe5de9f 100644 --- a/doc/build.md +++ b/doc/build.md @@ -71,14 +71,14 @@ Or to program with `dfu-programmer` run: #### FLIP GUI tutorial 1. On menu bar click Device -> Select, then. `ATmega32u4`. 2. On menu bar click Settings -> Communication -> USB, then click 'Open' button on 'USB Port Connection' dialog. -At this point you'll see greyouted widgets on the app get colored and ready. +At this point you'll see grey-outed widgets on the app get colored and ready. 3. On menu bar click File -> Load HEX File, then select your firmware hex file on File Selector dialog. 4. On 'Operations Flow' panel click 'Run' button to load the firmware binary to the chip. Note that you should keep 'Erase', 'Blank Check', 'Program' and 'Verify' check boxes selected. 5. Re-plug USB cord or click 'Start Application' button to restart your controller. Done. -See also these instaructions if you need. +See also these instructions if you need. - - @@ -95,7 +95,7 @@ Or use this command if you have command line version of Teensy Loader installed. ### 4. Program with Other programmer -You may want to use other programmer like `avrdude` with AVRISPmkII, Aruduino or USBasp. In that case you can still use make target `program` for build with configuring `PROGRAM_CMD` in Makefile. +You may want to use other programmer like `avrdude` with AVRISPmkII, Arduino or USBasp. In that case you can still use make target `program` for build with configuring `PROGRAM_CMD` in Makefile. $ make -f Makefile. program @@ -135,7 +135,7 @@ Optional. Note that ***comment out*** to disable them. #BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality ### 3. Programmer -Optional. Set proper command for your controller, bootloader and programmer. This command can be used with `make program`. Not needed if you use `FLIP`, `dfu-programmer` or `Teesy Loader`. +Optional. Set proper command for your controller, bootloader and programmer. This command can be used with `make program`. Not needed if you use `FLIP`, `dfu-programmer` or `Teensy Loader`. # avrdude with AVRISPmkII PROGRAM_CMD = avrdude -p $(MCU) -c avrispmkII -P USB -U flash:w:$(TARGET).hex @@ -158,7 +158,7 @@ Config.h Options /* Mechanical locking CapsLock support. Use KC_LCAP instead of KC_CAPS in keymap */ #define CAPSLOCK_LOCKING_ENABLE - /* Locking CapsLock resynchronize hack */ + /* Locking CapsLock re-synchronize hack */ #define CAPSLOCK_LOCKING_RESYNC_ENABLE ### 3. Disable Debug and Print diff --git a/doc/keymap.md b/doc/keymap.md index 3a549de6..7ef7430c 100644 --- a/doc/keymap.md +++ b/doc/keymap.md @@ -68,7 +68,7 @@ On the other hand, you shall change `layer_state` to overlay base layer with som Note that ***higher layer has higher priority on stack of layers***, namely firmware falls down from top layer to bottom to look up keycode. Once it spots keycode other than **`KC_TRNS`**(transparent) on a layer it stops searching and lower layers aren't referred. You can place `KC_TRNS` on overlay layer changes just part of layout to fall back on lower or base layer. -Key with `KC_TRANS` doen't has its own keycode and refers to lower valid layers for keycode, instead. +Key with `KC_TRANS` doesn't has its own keycode and refers to lower valid layers for keycode, instead. See example below. @@ -155,12 +155,12 @@ You can find other keymap definitions in file `keymap.c` located on project dire ## 1. Keycode -See [`common/keycode.h`](../common/keycode.h) or keycode table below for the detail. Keycode is internal **8bit code** to inidicate action performed on key in keymap. Keycode has `KC_` prefixed symbol respectively. Most of keycodes like `KC_A` have simple action registers key to host on press and unregister on release, while some of other keycodes has some special actions like `Fn` keys, Media contorl keys, System control keys and Mousekeys. +See [`common/keycode.h`](../common/keycode.h) or keycode table below for the detail. Keycode is internal **8bit code** to indicate action performed on key in keymap. Keycode has `KC_` prefixed symbol respectively. Most of keycodes like `KC_A` have simple action registers key to host on press and unregister on release, while some of other keycodes has some special actions like `Fn` keys, Media control keys, System control keys and Mousekeys. ***In `KEYMAP()` macro you should omit prefix part `KC_` of keycode to keep keymap compact.*** For example, just use `A` instead you place `KC_A` in `KEYMAP()`. Some keycodes has 4-letter **short name** in addition to descriptive name, you'll prefer short one in `KEYMAP()`. ### 1.0 Other key -- `KC_NO` for no aciton +- `KC_NO` for no action - `KC_TRNS` for layer transparency (See above) ### 1.1 Normal key @@ -192,7 +192,7 @@ There are 8 modifiers which has discrimination between left and right. - `KC_WSCH`, `KC_WHOM`, `KC_WBAK`, `KC_WFWD`, `KC_WSTP`, `KC_WREF`, `KC_WFAV` for web browser operation ### 1.5 Fn key -`KC_FNnn` are keycodes for `Fn` key which not given any actions at the beginning unlike most of keycodes has its own inborn action. To use these keycodes in `KEYMAP()` you need to assign action you want at first. Action of `Fn` key is defined in `fn_actions[]` and its index of the array is identical with number part of `KC_FNnn`. Thus `KC_FN0` keyocde indicates the action defined in first element of the array. ***32 `Fn` keys can be defined at most.*** +`KC_FNnn` are keycodes for `Fn` key which not given any actions at the beginning unlike most of keycodes has its own inborn action. To use these keycodes in `KEYMAP()` you need to assign action you want at first. Action of `Fn` key is defined in `fn_actions[]` and its index of the array is identical with number part of `KC_FNnn`. Thus `KC_FN0` keycode indicates the action defined in first element of the array. ***32 `Fn` keys can be defined at most.*** ### 1.6 Keycode Table See keycode table in [`doc/keycode.txt`](./keycode.txt) for description of keycodes. @@ -205,7 +205,7 @@ There are 8 modifiers which has discrimination between left and right. ## 2. Action See [`common/action_code.h`](../common/action_code.h). Action is a **16bit code** and defines function to perform on events of a key like press, release, holding and tapping. -Most of keys just register 8bit scancode to host, but to support other complex features needs 16bit extended action codes internally. However, using 16bit action codes in keymap results in double size in memory compared to using jsut keycodes. To avoid this waste 8bit keycodes are used in `KEYMAP()` instead of action codes. +Most of keys just register 8bit scancode to host, but to support other complex features needs 16bit extended action codes internally. However, using 16bit action codes in keymap results in double size in memory compared to using just keycodes. To avoid this waste 8bit keycodes are used in `KEYMAP()` instead of action codes. ***You can just use keycodes of `Normal key`, `Modifier`, `Mousekey` and `System & Media key` in keymap*** to indicate corresponding actions instead of using action codes. While ***to use other special actions you should use keycode of `Fn` key defined in `fn_actions[]`.*** @@ -230,7 +230,7 @@ You can define these actions on *'A'* key and *'left shift'* modifier with: #### 2.1.2 Modified key This action is comprised of strokes of modifiers and a key. `Macro` action is needed if you want more complex key strokes. -Say you want to assign a key to `Shift + 1` to get charactor *'!'* or `Alt + Tab` to switch application windows. +Say you want to assign a key to `Shift + 1` to get character *'!'* or `Alt + Tab` to switch application windows. ACTION_MODS_KEY(MOD_LSFT, KC_1) ACTION_MODS_KEY(MOD_LALT, KC_TAB) @@ -272,7 +272,7 @@ This sets Default Layer to given parameter `layer` and activate it. ACTION_DEFAULT_LAYER(layer) -#### 2.2.2 Momentary Switch +#### 2.2.2 Momentary Turns on `layer` momentarily while holding, in other words it activates when key is pressed and deactivate when released. ACTION_LAYER_MOMENTARY(layer) @@ -342,7 +342,7 @@ Turns on layer only and clear all layer on release.. ACTION_LAYER_BIT_XOR(part, bits, on) ACTION_LAYER_BIT_SET(part, bits, on) -These actions works with prameters as following code. +These actions works with parameters as following code. uint8_t shift = part*4; uint32_t mask = (bits&0x10) ? ~(0xf< ## kbdbabel.org[converter][vintage][protocol][8051] -Great resourse of vintage keyboard protocol information and code +Great resource of vintage keyboard protocol information and code - From f7bb7c4fa99e6bfae311bd6674b6a2bd8537ea73 Mon Sep 17 00:00:00 2001 From: Benjamin Gould Date: Mon, 6 Jan 2014 14:43:59 -0500 Subject: [PATCH 53/76] Added NeXT keyboard converter --- converter/next_usb/Makefile | 63 +++++++ converter/next_usb/README | 45 +++++ converter/next_usb/config.h | 150 ++++++++++++++++ converter/next_usb/keymap.c | 177 ++++++++++++++++++ converter/next_usb/led.c | 55 ++++++ converter/next_usb/matrix.c | 269 ++++++++++++++++++++++++++++ converter/next_usb/next_timings.jpg | Bin 0 -> 407936 bytes protocol/next_kbd.c | 204 +++++++++++++++++++++ protocol/next_kbd.h | 63 +++++++ 9 files changed, 1026 insertions(+) create mode 100644 converter/next_usb/Makefile create mode 100644 converter/next_usb/README create mode 100644 converter/next_usb/config.h create mode 100644 converter/next_usb/keymap.c create mode 100644 converter/next_usb/led.c create mode 100644 converter/next_usb/matrix.c create mode 100644 converter/next_usb/next_timings.jpg create mode 100644 protocol/next_kbd.c create mode 100644 protocol/next_kbd.h diff --git a/converter/next_usb/Makefile b/converter/next_usb/Makefile new file mode 100644 index 00000000..51d9de6b --- /dev/null +++ b/converter/next_usb/Makefile @@ -0,0 +1,63 @@ +# Target file name (without extension). +TARGET = next_usb + +# Directory common source filess exist +TOP_DIR = ../.. + +# Directory keyboard dependent files exist +TARGET_DIR = . + +# keyboard dependent files +SRC = keymap.c \ + matrix.c \ + led.c + +CONFIG_H = config.h + +# MCU name, you MUST set this to match the board you are using +# type "make clean" after changing this, so all files will be rebuilt +#MCU = at90usb162 # Teensy 1.0 +MCU = atmega32u4 # Teensy 2.0 +#MCU = at90usb646 # Teensy++ 1.0 +#MCU = at90usb1286 # Teensy++ 2.0 + + +# Processor frequency. +# Normally the first thing your program should do is set the clock prescaler, +# so your program will run at the correct speed. You should also set this +# variable to same clock speed. The _delay_ms() macro uses this, and many +# examples use this variable to calculate timings. Do not add a "UL" here. +F_CPU = 16000000 + + +# Boot Section Size in *bytes* +# Teensy halfKay 512 +# Teensy++ halfKay 1024 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +# USBaspLoader 2048 +OPT_DEFS += -DBOOTLOADER_SIZE=4096 + + +# Build Options +# *Comment out* to disable the options. +# +#BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE = yes # Mouse keys +EXTRAKEY_ENABLE = yes # Audio control and System control +CONSOLE_ENABLE = yes # Console for debug(+400) +COMMAND_ENABLE = yes # Commands for debug and configuration +#NKRO_ENABLE = yes # USB Nkey Rollover + +SRC += next_kbd.c + + +# Search Path +VPATH += $(TARGET_DIR) +VPATH += $(TOP_DIR) + + +include $(TOP_DIR)/protocol.mk +include $(TOP_DIR)/protocol/pjrc.mk +include $(TOP_DIR)/common.mk +include $(TOP_DIR)/rules.mk diff --git a/converter/next_usb/README b/converter/next_usb/README new file mode 100644 index 00000000..07ac89de --- /dev/null +++ b/converter/next_usb/README @@ -0,0 +1,45 @@ +NeXT non-ADB Keyboard Converter +------------------------------- + +Cable connector inside keyboard case: ++-----+ +|Black|\ +|Green|-\ +|Yello|--\-------- to computer via Mini-Din 5a Connector +|Orang|--/-------- +|Red |-/ +|Brown|/ ++-----+ + +Black - Ground to outer metal part of Mini Din 5a connector (not used) +Green - Ground +Yellow - Power button signal +Orange - Keyboard Out +Red - Keyboard In +Brown - Vcc + +ATmega32u4 connections (pinout provided for Arduino Pro Micro): + +Keyboard out (orange) : PD0 (pin 3) +Keyboard in (red) : PD1 (pin 2) +Power Button (yellow) : PD4 (pin 4) +Ground (black) : GND +Vcc (brown) : VCC + +See attached next_timings.jpg file for a detailed illustration of NeXT keyboard protocol timings. + +Power button signal line is normally high when the keyboard is powered/initialized. It is pulled to ground when pressed. The converter automatically translates this to a "normal" keypress with code 0x5A. This connection is technically optional, the only side effect of not making this connection is the power key will do nothing. + +Converter is based heavily on Ladyada's original "USB NeXT Keyboard with Arduino Micro" tutorial (http://learn.adafruit.com/usb-next-keyboard-with-arduino-micro/overview). If you build this converter, show Adafruit some love and do it using an Arduino Micro (http://www.adafruit.com/products/1315) or their ATmega 32u4 Breakout Board (http://www.adafruit.com/products/296). Arduino Micro should work fine using the Arduino Pro Micro configuration above, same pins numbers and everything. + +TODO: +----- + +I believe it might be possible to run the keyboard off of 3V; during testing I observed that the keyboard could sometimes function even without Vcc connected as long as the ground connection was good and the Keyboard In line was connected. If that works it should be easy to do a Bluetooth conversion and run the keyboard right off of a LiPo battery without a boost circuit + +Utilize second LED as status indicator for good initialization; also try to make hot plugging much more robust. + +Figure a better use for the Power button. Too easy to hit it by mistake to use for Suspend or Power Off - maybe move cap to different part of the board and consider that + +Figure out a better use for the lock LEDs. Right now they just light up when you press shift. Lame. Maybe implement proper Caps/Num/Scroll Locks + diff --git a/converter/next_usb/config.h b/converter/next_usb/config.h new file mode 100644 index 00000000..b3d188b0 --- /dev/null +++ b/converter/next_usb/config.h @@ -0,0 +1,150 @@ +/* +NeXT non-ADB Keyboard USB Converter + +Copyright 2013, Benjamin Gould (bgould@github.com) + +Based on: +TMK firmware code Copyright 2011,2012 Jun WAKO +Arduino code by "Ladyada" Limor Fried (http://ladyada.net/, http://adafruit.com/), released under BSD license + +Timing reference thanks to http://m0115.web.fc2.com/ (dead link), http://cfile7.uf.tistory.com/image/14448E464F410BF22380BB +Pinouts thanks to http://www.68k.org/~degs/nextkeyboard.html +Keycodes from http://ftp.netbsd.org/pub/NetBSD/NetBSD-release-6/src/sys/arch/next68k/dev/ + +This software is licensed with a Modified BSD License. +All of this is supposed to be Free Software, Open Source, DFSG-free, +GPL-compatible, and OK to use in both free and proprietary applications. +Additions and corrections to this file are welcome. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +* Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#define VENDOR_ID 0xBCBC +#define PRODUCT_ID 0xBCBC +#define DEVICE_VER 0x0500 +#define MANUFACTURER t.m.k. +#define PRODUCT NeXT Keyboard to USB converter +#define DESCRIPTION USB converter for NeXT non-ADB Keyboard + +/* matrix size */ +#define MATRIX_ROWS 12 // keycode bit: 3-0 +#define MATRIX_COLS 8 // keycode bit: 6-4 + +//#define DEBUG_ON_INIT 1 + +//#define TEENSY_CONFIG 1 +#define PRO_MICRO_CONFIG 1 + +// comment out if you don't want the keyboard's LEDs to flash upon initialization +#define NEXT_KBD_INIT_FLASH_LEDS + +//============= Start of Arduino Pro Micro Configuration ============== +#ifdef PRO_MICRO_CONFIG + +// this is the debugging LED that flashes when a key is being pressed +// comment out in order to disable debugging LED +#define NEXT_KBD_LED1_PORT PORTD +#define NEXT_KBD_LED1_PIN PIND +#define NEXT_KBD_LED1_DDR DDRD +#define NEXT_KBD_LED1_BIT 5 + +#define NEXT_KBD_LED1_ON NEXT_KBD_LED1_PORT &= ~(1<mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)))|| \ + (keyboard_report->mods == (MOD_BIT(KC_RALT) | MOD_BIT(KC_RCTL))) \ +) diff --git a/converter/next_usb/keymap.c b/converter/next_usb/keymap.c new file mode 100644 index 00000000..d844f8a4 --- /dev/null +++ b/converter/next_usb/keymap.c @@ -0,0 +1,177 @@ +/* +NeXT non-ADB Keyboard USB Converter + +Copyright 2013, Benjamin Gould (bgould@github.com) + +Based on: +--------- +* TMK firmware code Copyright 2011,2012 Jun WAKO +* Arduino code by "Ladyada" Limor Fried (http://ladyada.net/, http://adafruit.com/) \ + released under BSD license \ + https://github.com/adafruit/USB-NeXT-Keyboard + +Timing reference thanks to http://m0115.web.fc2.com/ (dead link), http://cfile7.uf.tistory.com/image/14448E464F410BF22380BB +Pinouts thanks to http://www.68k.org/~degs/nextkeyboard.html +Keycodes from http://ftp.netbsd.org/pub/NetBSD/NetBSD-release-6/src/sys/arch/next68k/dev/ + +This software is licensed with a Modified BSD License. +All of this is supposed to be Free Software, Open Source, DFSG-free, +GPL-compatible, and OK to use in both free and proprietary applications. +Additions and corrections to this file are welcome. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +* Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include +#include +#include +#include "keycode.h" +#include "print.h" +#include "debug.h" +#include "util.h" +#include "keymap.h" +#include "keycode.h" + +// 32*8(256) byte array which converts PS/2 code into USB code +static const uint16_t PROGMEM fn_actions[] = { + ACTION_LAYER_MOMENTARY(1), // FN0 - left command key + ACTION_LAYER_MOMENTARY(1), // FN1 - right command key + ACTION_KEY(KC_BSLS), // FN2 - number pad slash & backslash + ACTION_MODS_KEY(MOD_LSFT, KC_BSLS), // FN3 - number pad equals & pipe + ACTION_MODS_KEY(MOD_LCTL, KC_Z), // FN4 - cmd+undo on layer 1 + ACTION_MODS_KEY(MOD_LCTL, KC_X), // FN5 - cmd+cut on layer 1 + ACTION_MODS_KEY(MOD_LCTL, KC_C), // FN6 - cmd+copy on layer 1 + ACTION_MODS_KEY(MOD_LCTL, KC_V), // FN7 - cmd+paste on layer 1 +}; + +/* This is the physical layout that I am starting with: + * Note: there is some strangeness on the number pad; + * the equal sign shifts to pipe and forward slash shifts to backslash + * ,-----------------------------------------------------------. ,-----------. ,---------------. + * |Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =| BS | |VUp|Pwr|BrU| |` | =| /| *| + * |-----------------------------------------------------------| |-----------| |---------------| + * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| | |VDn| |BrD| | 7| 8| 9| -| + * |------------------------------------------------------ | `---' `---' |-----------|---| + * |Ctrl | A| S| D| F| G| H| J| K| L| ;| '| Return| | 4| 5| 6| +| + * |-----------------------------------------------------------| ,---. |---------------| + * |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift | |Up | | 1| 2| 3| | + * |-----------------------------------------------------------| ,-----------. |-----------|Ent| + * |Alt |Cmd | Space |Cmd |Alt | |Lef|Dow|Rig| | 0| .| | + * `-----------------------------------------------------------' `-----------' `---------------' + * + * Keymap array: + * 8 bytes + * +---------+ + * 0| | + * :| | 0x00-0x87 + * ;| | + * 11| | + * +---------+ + */ +#define KEYMAP( \ + K49,K4A,K4B,K4C,K4D,K50,K4F,K4E,K1E,K1F,K20,K1D,K1C,K1B, K1A,K58,K19, K26,K27,K28,K25, \ + K41,K42,K43,K44,K45,K48,K47,K46,K06,K07,K08,K05,K04,K03, K02, K01, K21,K22,K23,K24, \ + K57,K39,K3A,K3B,K3C,K3D,K40,K3F,K3E,K2D,K2C,K2B, K2A, K12,K18,K13,K15, \ + K56, K31,K32,K33,K34,K35,K37,K36,K2E,K2F,K30, K55, K16, K11,K17,K14, \ + K52,K54, K38, K53,K51, K09,K0F,K10, K0B, K0C,K0D \ +) { \ + { KC_NO, KC_##K01, KC_##K02, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07 }, \ + { KC_##K08, KC_##K09, KC_##K10, KC_##K0B, KC_##K0C, KC_##K0D, KC_NO, KC_##K0F }, \ + { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17 }, \ + { KC_##K18, KC_##K19, KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D, KC_##K1E, KC_##K1F }, \ + { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27 }, \ + { KC_##K28, KC_NO, KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D, KC_##K2E, KC_##K2F }, \ + { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_##K37 }, \ + { KC_##K38, KC_##K39, KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D, KC_##K3E, KC_##K3F }, \ + { KC_##K40, KC_##K41, KC_##K42, KC_##K43, KC_##K44, KC_##K45, KC_##K46, KC_##K47 }, \ + { KC_##K48, KC_##K49, KC_##K4A, KC_##K4B, KC_##K4C, KC_##K4D, KC_##K4E, KC_##K4F }, \ + { KC_##K50, KC_##K51, KC_##K52, KC_##K53, KC_##K54, KC_##K55, KC_##K56, KC_##K57 }, \ + { KC_##K58, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, }, \ +} + + +static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + + /* Layer 0: default + * ,-----------------------------------------------------------. ,-----------. ,---------------. + * |Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =| BS | |Ins|Ref|Hom| |` | =| /| *| + * |-----------------------------------------------------------| |-----------| |---------------| + * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| | |Del| |End| | 7| 8| 9| -| + * |-----------------------------------------------------' | `---' `---' |-----------|---| + * |Ctrl | A| S| D| F| G| H| J| K| L| ;| '| Return| | 4| 5| 6| +| + * |-----------------------------------------------------------| ,---. |---------------| + * |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift | |Up | | 1| 2| 3| | + * |-----------------------------------------------------------| ,-----------. |-----------|Ent| + * |Fn0 |Alt | Space |LGui |Fn1 | |Lef|Dow|Rig| | 0| .| | + * `-----------------------------------------------------------' `-----------' `---------------' + */ + KEYMAP( + ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, WREF,HOME, GRV, FN3, FN2, PAST, + TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,NO, DEL, END, P7, P8, P9, PMNS, + LCTL,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, P4, P5, P6, PPLS, + LSFT, Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3, + FN0, LALT, SPC, LGUI,FN1, LEFT,DOWN,RGHT, P0, PDOT,PENT + + ), + + /* Layer 1: extra keys + * ,-----------------------------------------------------------. ,-----------. ,---------------. + * |Grv| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12| BS | |VUp|VMu|PgU| |` | =| /| *| + * |-----------------------------------------------------------| |-----------| |---------------| + * |Tab |Pau| W| E| R| T| Y| U| I| O|PSc| \| ]| | |VDn| |PgD| | 7| 8| 9| -| + * |-----------------------------------------------------' | `---' `---' |-----------|---| + * |Ctrl | A| S| D| F| G| H| J| K| L| ;| '| Return| | 4| 5| 6| +| + * |-----------------------------------------------------------| ,---. |---------------| + * |Shift |UND|CUT|COP|PST| B| N| M| ,| .| /|Shift | |Up | | 1| 2| 3| | + * |-----------------------------------------------------------| ,-----------. |-----------|Ent| + * |Fn0 |Alt | Space |RGui |Fn1 | |Lef|Dow|Rig| | 0| .| | + * `-----------------------------------------------------------' `-----------' `---------------' + */ + KEYMAP( + + GRV, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, TRNS, VOLU,MUTE,PGUP, TRNS,TRNS,TRNS,TRNS, + TRNS,PAUS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,PSCR,FN3, BSLS,TRNS, VOLD, PGDN, BTN1,MS_U,BTN2,WH_U, + TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS, MS_L,MS_D,MS_R,WH_D, + TRNS, FN4, FN5, FN6, FN7, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS, TRNS, TRNS,TRNS,TRNS, + TRNS,RALT, TRNS, RGUI,TRNS, TRNS,TRNS,TRNS, TRNS, TRNS,TRNS + + ) +}; + +/* translates key to keycode */ +uint8_t keymap_key_to_keycode(uint8_t layer, key_t key) +{ + return pgm_read_byte(&keymaps[(layer)][(key.row)][(key.col)]); +} + +/* translates Fn keycode to action */ +action_t keymap_fn_to_action(uint8_t keycode) +{ + return (action_t){ .code = pgm_read_word(&fn_actions[FN_INDEX(keycode)]) }; +} diff --git a/converter/next_usb/led.c b/converter/next_usb/led.c new file mode 100644 index 00000000..24db15e1 --- /dev/null +++ b/converter/next_usb/led.c @@ -0,0 +1,55 @@ +/* +NeXT non-ADB Keyboard USB Converter + +Copyright 2013, Benjamin Gould (bgould@github.com) + +Based on: +TMK firmware code Copyright 2011,2012 Jun WAKO +Arduino code by "Ladyada" Limor Fried (http://ladyada.net/, http://adafruit.com/), released under BSD license + +Timing reference thanks to http://m0115.web.fc2.com/ (dead link), http://cfile7.uf.tistory.com/image/14448E464F410BF22380BB +Pinouts thanks to http://www.68k.org/~degs/nextkeyboard.html +Keycodes from http://ftp.netbsd.org/pub/NetBSD/NetBSD-release-6/src/sys/arch/next68k/dev/ + +This software is licensed with a Modified BSD License. +All of this is supposed to be Free Software, Open Source, DFSG-free, +GPL-compatible, and OK to use in both free and proprietary applications. +Additions and corrections to this file are welcome. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +* Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "stdint.h" +#include "led.h" + + +void led_set(uint8_t usb_led) +{ + +} diff --git a/converter/next_usb/matrix.c b/converter/next_usb/matrix.c new file mode 100644 index 00000000..fd6eb9d6 --- /dev/null +++ b/converter/next_usb/matrix.c @@ -0,0 +1,269 @@ +/* +NeXT non-ADB Keyboard USB Converter + +Copyright 2013, Benjamin Gould (bgould@github.com) + +Based on: +TMK firmware code Copyright 2011,2012 Jun WAKO +Arduino code by "Ladyada" Limor Fried (http://ladyada.net/, http://adafruit.com/), released under BSD license + +Timing reference thanks to http://m0115.web.fc2.com/ (dead link), http://cfile7.uf.tistory.com/image/14448E464F410BF22380BB +Pinouts thanks to http://www.68k.org/~degs/nextkeyboard.html +Keycodes from http://ftp.netbsd.org/pub/NetBSD/NetBSD-release-6/src/sys/arch/next68k/dev/ + +This software is licensed with a Modified BSD License. +All of this is supposed to be Free Software, Open Source, DFSG-free, +GPL-compatible, and OK to use in both free and proprietary applications. +Additions and corrections to this file are welcome. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +* Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include +#include +#include +#include +#include "print.h" +#include "util.h" +#include "serial.h" +#include "matrix.h" +#include "debug.h" +#include "matrix.h" +#include "next_kbd.h" + +static void matrix_make(uint8_t code); +static void matrix_break(uint8_t code); + +static uint8_t matrix[MATRIX_ROWS]; +#define ROW(code) ((code>>3)&0xF) +#define COL(code) (code&0x07) + +static bool is_modified = false; + +/* number of matrix rows */ +inline +uint8_t matrix_rows(void) +{ + return MATRIX_ROWS; +} + +/* number of matrix columns */ +inline +uint8_t matrix_cols(void) +{ + return MATRIX_COLS; +} + +#ifndef NEXT_KBD_LED1_ON +#define NEXT_KBD_LED1_ON +#endif + +#ifndef NEXT_KBD_LED1_OFF +#define NEXT_KBD_LED1_OFF +#endif + +#define NEXT_KBD_PWR_READ (NEXT_KBD_PWR_PIN&(1<>1) +#define NEXT_KBD_PRESSED_KEYCODE(response) (uint8_t)(((response)&0xF00)==0x400) +#define NEXT_KBD_PRESSED(response, mask) (uint8_t)(((response)&mask)>0) +#define NEXT_KBD_PRESSED_CONTROL(response) NEXT_KBD_PRESSED(response,0x01000) +#define NEXT_KBD_PRESSED_SHIFT_LEFT(response) NEXT_KBD_PRESSED(response,0x02000) +#define NEXT_KBD_PRESSED_SHIFT_RGHT(response) NEXT_KBD_PRESSED(response,0x04000) +#define NEXT_KBD_PRESSED_CMD_LEFT(response) NEXT_KBD_PRESSED(response,0x08000) +#define NEXT_KBD_PRESSED_CMD_RGHT(response) NEXT_KBD_PRESSED(response,0x10000) +#define NEXT_KBD_PRESSED_ALT_LEFT(response) NEXT_KBD_PRESSED(response,0x20000) +#define NEXT_KBD_PRESSED_ALT_RGHT(response) NEXT_KBD_PRESSED(response,0x40000) +#define NEXT_KBD_MAKE_OR_BREAK(key, code) \ + do { \ + if (NEXT_KBD_PRESSED_##key(resp) > 0) \ + matrix_make(code); \ + else \ + matrix_break(code); \ + } while (0); + +#define NEXT_KBD_PWR_KEYCODE 0x58 + +/* scan all key states on matrix */ +uint8_t matrix_scan(void) +{ + _delay_ms(20); + + //next_kbd_set_leds(false, false); + NEXT_KBD_LED1_OFF; + + is_modified = false; + + if (!NEXT_KBD_PWR_READ) { + matrix_make(NEXT_KBD_PWR_KEYCODE); + power_state = 1; + if (is_modified) + { + dprintf("Power state 1\n"); + + } + } else { + matrix_break(NEXT_KBD_PWR_KEYCODE); + power_state = 0; + if (is_modified) + { + dprintf("Power state 0\n"); + + } + } + + uint32_t resp = (next_kbd_recv()); + + if (resp == NEXT_KBD_KMBUS_IDLE) + { + return 0; + } + + NEXT_KBD_LED1_ON; + + next_kbd_set_leds( + NEXT_KBD_PRESSED_SHIFT_LEFT(resp) ? true : false, + NEXT_KBD_PRESSED_SHIFT_RGHT(resp) ? true : false + ); + + dprintf("[ r=%04lX keycode=%02X pressed=%X CTRL=%X SHIFT_LEFT=%X SHIFT_RGHT=%X CMD_LEFT=%X CMD_RGHT=%X ALT_LEFT=%X ALT_RGHT=%X ]\n", \ + resp, \ + NEXT_KBD_KEYCODE(resp), \ + NEXT_KBD_PRESSED_KEYCODE(resp), \ + NEXT_KBD_PRESSED_CONTROL(resp), \ + NEXT_KBD_PRESSED_SHIFT_LEFT(resp), \ + NEXT_KBD_PRESSED_SHIFT_RGHT(resp), \ + NEXT_KBD_PRESSED_CMD_LEFT(resp), \ + NEXT_KBD_PRESSED_CMD_RGHT(resp), \ + NEXT_KBD_PRESSED_ALT_LEFT(resp), \ + NEXT_KBD_PRESSED_ALT_RGHT(resp) \ + ); + + // Modifier keys don't return keycode; have to check the upper bits + NEXT_KBD_MAKE_OR_BREAK(ALT_RGHT, 0x51); + NEXT_KBD_MAKE_OR_BREAK(ALT_LEFT, 0x52); + NEXT_KBD_MAKE_OR_BREAK(CMD_RGHT, 0x53); + NEXT_KBD_MAKE_OR_BREAK(CMD_LEFT, 0x54); + NEXT_KBD_MAKE_OR_BREAK(SHIFT_RGHT, 0x55); + NEXT_KBD_MAKE_OR_BREAK(SHIFT_LEFT, 0x56); + NEXT_KBD_MAKE_OR_BREAK(CONTROL, 0x57); + NEXT_KBD_MAKE_OR_BREAK(KEYCODE, NEXT_KBD_KEYCODE(resp)); + + return 1; +} + +/* whether modified from previous scan. used after matrix_scan. */ +bool matrix_is_modified() +{ + return is_modified; +} + +/* whether a switch is on */ +inline +bool matrix_is_on(uint8_t row, uint8_t col) +{ + return (matrix[row] & (1<DZLX}Pc=~4ux3xqCB zdhb0D%87eF&vV}WUhh}@bN(C_moUf5NYvyuM2|xwYyjAQ z`2g_WZ_oqq(C2QWZ7}*DfPMr03;*}%=D0!N27wy{ZV`hx`DLx3ihKouxbT3ri~-MS4$mVbzO5`J99A$4v-WPp`^FCw}Z2TrMnrkw}ZW-o47ad-d`^+jvoI$&3{iy z($(UnxVF6FzdXNqKuk=G|Dhnipdc^WgV)W+(cR3O*U^pj zUoRkU>1OU~H0Ram$UNehF z0=yQF9$7pV77!JDDe&UnzbEM6{GZGJk4T`ehhCDnoU5goyOXP~lasyFAGK$a{Qv#w zlKj6X{9hIz_4gSxCg{(d*3`}ZdFn=Gve`BE!Y+UT$2R<$? z4lV&cAt3=i0RiD{lG}v0h;I=P5RnlPlaP{>nQ2UjbzJxH{MXER1^qOfn2CGK}l*00#6|PqDEu(Eka>e-3OMTs#acd`trL z!vUlK^o7yW#=*TsLX3AClL7-13mbq#hD(meB0wRdg-?0U%!TTX;H$VSg1fA;+DR3y zgF~a#Y>y!N1}|LWlT#{(NA_sgg@omFboI=G6B66z?~BO0Wq;mRu&}gp_Xr6M%dPsh zD5_|fQ_ZR58J_ojf#b1q`%ABg1N7zT&=W&X?!Qj&_w~^eL_a7=2EfF`!2S&k1}-iD z5AB74Nrr_@&LSX#L!pJ97%r8d3+p3U?N?cM;?VQj!xPeZ;X1!B7k@noxQ&H@MgfZq z00JyK2N8K=Xx@ru&IQ-|NsD1Q8G;r`cA!xnt;jZOt-x6zS`g5?xE3sN>^rmKr1#px#UG8J9`blz-@T?*J*g-h>YBW zf=fD;$3RJT{;+F+^e*GTiI(j7h0>1JFCc6yJM0)4GhLz{-!`2b;VGe3res)lzLb{fq#~aniDdXbIlk)<30|_H`?69tTZjUa((H zn05$>jn3M^wh@8k*8qF?A}zpao@9z-@qYP$;$^{=AP?^a3(D-mVvJ^OwwkF!0U*3b zwxxuk3cZTh57_86#bEpntuWA7gHr#>#0d{XSlk{nGTc(y*OL2(C2hulR}Q7r3?#gayy7lUlG$Qvr(_ClK?76-a6{EzC0sTfm6iGF zpX!-Bz1qG8{Izy9S}d6F3^sjwrhZIL&6EV`JOAu%-{K-9_LzU%{S69*A?G12JAUe<@W@wd9V@ zcH>NpJ)Nx!qn<1LlR)9;{*)-toywMAAS_Dy*7_x=N3*$Q_#*GW3^9`Y1-37QW6CsY z_j$OH=2J*Jrl&Bc1x-v}bdaM4e*r^~1zA9y{eX_OUB=c6T}{jem>KFwY%k@?Yvvi@ zMnJ?a;;*21xC2_ke}lek5%}iH3#C~8Pcw+_l8h0(-p>YB#epLM-yz2Tv^DQKWkYRY z3)!#s^iVn%Ms#bi$$Vr%rax66`dN2^=+|~D2I?A)R`mnQptUAX|6xkw6`@H1eP^wt zg|a}?Pl&Pjvf@f0i$Q5S;lcuO*D5Cv9TKYW7CEH~(AJpY-xM)}BL=rLP(lEZEK@bA zBkW(Sz+00$Y4JwD5u;oB`})$B{co=U638-$J_4mNTOv027iD_RnQTx;xFj;$sP!x$ z#eTrp8W68`_fzQ6Utu6AMgP%~ZN|^pL}NFi2@mGP2ms{=ubD!Ru28bSiGpap2CQG6 z1ofQ9IL+!kzhFZXgzz5*fQbM^J?;2vRI2p?vi1)H!_;q=ka{m^3$(2XZ#oUTg#@Ds zQGfv@K+le*r~8r=rLmu6VEQ**DxvaH!xxsCm{57f!BaaTe<44uQ!+!1wU9}vZ8Lay z47w(9V!%rNDp9QYXF161%7HOIvI|`Z+3>~Sg_iU!BwygDsf%6;r~y4|&{PTkTs=xJ zpdIq`YV&VK1obr3qb$*shzW%{Tp_ZaJ-w{F+9*(J1JzsutTnMr4Y!r{;|#3ka(>1% zME3sE#Oj4+<^PnLD}kXw2es>&wIGJKn4BRRYqlp$3q?UaSA^Gq{wtoO6mgzOcwIx= zf3vah@;gu4vF2i|uO7KG!kA_$NrHhn$UX!B$%QUY9wB>5pZD!p=l&{O=mIs+o+;>y zjsbf5u*;$H|2+))mJZE71Cz8dPSS7wCQKmd2?B2%&9m44V!`>+g{ccAM^PYu-3&&^ zh@aGfwW-b)DDb}w(ZnSPY)6NI>iphi(Ustu+dThIv~oUq=@K4D8&G%+co{^4RJ#UzxX{&4ZmvBkyyCVS1`)Izf+8ai#>cKkLG5aQ z0NWN@_(E#@-qtnXo3Yn6TGtAFb4-oklf}qSxs4LnfM_)4Q!Up3-DAsws|`~`m7kQt zdcUvhVDHt6;x(YaTIcl!uxd7+SZF3E|D=-tQq_G977DCBZ7@D}4^)L;16Ecq)$)4>)ox0$UDtq+^QF^t*@NIVQ(%1vpC99H7a9npMA zi8wMnBHl+&(2|lL{ylJ+VR7QBhZBvIaO#syJaPC>ctbU?|)uW^cu_W_WQxA`% z3t=d_nsWo7?w}e_haUbVnbgSTpwcN?g8pMkn`M-u(AjHXw;AyIiks)bu~IdY3srb? z?N4;^2%^~2*oIDIL2+g$;X8b<5Le@usnmnBFRm6gRC0#XpPkfS&EU=RpY))sL%-!T zG!b3QW6DgolTOuS0JCjqwdhbY%ZNgu%Q?gtDR=S>*z?z6QJ~ zhas-`n+)ydSbxTx@DN;*ETBdJ|Ed>;ZgcR9-GzDseRS^fAklrp-?sFvwSfG~B8g^D zb1L-@dhdVh>+R?_$d-3A=D+L2*d}YX5AxpLQ1Yx7c4U-n-T zyVsH*xk1fL(xy=ruz}a6gl>E?FIX-mIhhEU&?V&4>xbg`KS7Z*c<}bqFs!105M(LB z_rla$_m7p;%|&Sp`X6P@y=ynmIvI1qX|)MNM}yODKGS#bs+}mn>UV#`dG{Y`N`~;m z+gHGwEAdS_rP9P0*qJ@oIN2O(sNXi7(K8#^Y58q(OHQA_cZ!1W{wf@{;ZmO`V;1kd z+Kbt4nao0$s2p@09{y8Gsgj!sfv-^oC6BwYqzF*KpMs!nplWm(v4sBJ-*lcnLQ9Gs zM1Kzgb-2*y#z>JOyevY!&3bk<+ai0;|GT76Ay9#r056jD<1RRBb|8PljBnT1)yv2C z%B2W@TR88TaHIy>(cz4-T7=-WYM=`WHHQmRl@ z-teF5D)%3CHTb)JFf5{D5=k-oyUIuZO%^~|{?EWm;=dZ3Q+=8LfBL$A4XColXc;8i z)<6mWtK+o%w;4zQT?zR9KgjC~Xk;p0t3JBru;m4~ zgYYGBnpMO4D?Gg9Oh)LclO5(yru4fbEyyy()(kS$Sf6X4p1lM$Bbs5uC+_?$=TQGl z!RDN)(@_Hu0cg0bvblw65kk_&G~9+xGPF$7{j1abhe1w=n)TLf3H__>3=7z8gn^MLWSO>2%+$%DH+v@ zrSOnN1-SZq`d422PfO|tP0)Sk81=tQcy<$-EQQRi>-(4c(n!`x(7Tzx1eeL^|4C#K zf#?R57r+P`ZbkPD`PTsV5>9%w;A&Qa@~`4EvHqj7=*X+KBzqsHVvp$_lJ%S>c&BA?(R7F?Veogow^|t0I?O&A6e3%o;KNP5C(gGBxP-#rvni`{Y(P#*- z!$N1zVC@P%Xk~eG#chqXsfW^oQjVlV!1l*xQC`=8jf{fvvEq~b-zqElTV;3u7FqLu zi>#te#WetT8>?-C61uZZ>#TxfupTly6l)_Luxm)Js9YnDH|9T6)RK}XG`UfRL#)$v&^hh2N4xa#=`D|}TDs5cN-Qi}yrTl_9op4Ib=vV^hx*KdenETr5WaX~ zW4$sZ{xa&v5vah=rX(rHl!ATTN}qR+u0B5SUW`JD2jS2^XUt&C4a73!lI-ffd$yUB zJL5>;(E0UY@=z1sue~{d-(wi95{cF`eYS2pJ(0wi65EA?Amlj&+9G$6uY_Q*F3-** zL-FO0wY2f@^e?BkSjNoo??oEf7?9{-CAS)s~mcWce+aAwT*siq2(ju%r$ z32Z}{+8Fa_UD(roW2mJ5RaEnAmws1e!2=y`U55MU~Ou_6FfsFx> z9{*eD2vL@e=lN8=Slin|O~%Q=z$`VBuT8+&2Q3JE=D1Ng8oaGAvrKJLN^$!EexpZ+ zSh}G=g+h88^?OS_A6ZjI$CRap!8y|&IR)D|t??o2q<6~Dnf>}jOPdCQn$-tPN(m5E zm%au(204#uQ%$%-TsHTLVrQzw4LLpiI0;u9#br)zkGQV-j`WoXwO?&Frftg^#|Da* zv}h^tFDM}%4?;P83BRt$)>zDNTRItMTSf9Z% zbe3?&S&6J~l2*sIM= zGzA9oDmZBFGOV^U1&ta~i6>O3+CNLv)>^Aigu8S;SX>k;%y(4VRUIGi;+D`R4IrBq zKfkhVxsYQL;5>3whzpix@Ub{WR29?5`z|7{0ik*tes!Qbte>9sXirTgCW;$F0*&5& zYf9p`b^Kfj5u=N2At}nb%IRcWuw&A2>P8T|Enk8f0x8Gz>f&O)pq$#cqn~t}PTW_7Y$5W#paTFv!nzq zL@z@7fKBL|!}sRC+r@+urnj`4($@QLTRn5&a@`fOdVkA36em^)y5{CGcQT41ppgin~`*CsApt)p4MOmt^5=j8WnsVDNFfGVh zU<;tQ&x1F_8rymeu-hAhP=a66NAFw%CiuTBQfZqwmIw$We;bNb^r;uHK?h_4Z16>B z)0#_PD7x8s{p@f9y+HNO0y6F#m5TxpzP@Te`u4Ds6A5N95o?ESy%)%8~7QhIVv-_{XHA_Jc;|4AU zWn?2EfDNjc*elw%ow}~FPh+bveNQ$9Vgjt|)Kv|A^6GMP$)bNAc6LGno2cj}!H999 z_~UmGE-~=k{n?lX9yW_QMVF*S(OvG&Uq$tADw+5sdvfEImmrm5+MldUDoJw-MVI39 zcwk4%2Jn$M(>api*>Hn(W^!MmnN_A|8(Eo(Ls`9?C;n_Bj6%f-O*R&lfxNwF9B=Jk zp5jSTuCMv%v*=zacXIy%6|k_o>#teVReJU)Z?!U+&CF>bdGNs@Hq!!Y(JfT6EKd)j0-P9*5(?_6S!Hm$ z6xX5ja(wI0OMP#$r>20Do;W8KInWL1-i(b20p(mI2%B544u20E-_y(nbP&7jdky=M zv#Z$4KNblGQp7&$NvX%NH#Xg7FzSh5&t0XeJhm2fa6nNM;fLjx-37JYw3->^h&wcnn%r)Pe>xu>~Xa#nLI{Gn+j*X%w04Wbud=ckJ1KE zoUwIsvoeUEe^~?UXgr8EfmfU$X>DV-YS@#P8dE-SAAx;I5=w=hS(X%jo9Nb5=GbuL zqVn+_b&nVX#X|%Meaxq}(6#7MFxAZd;SwH-V--24$%nyC44Mj!cbk;VGhaaViEc8o z${^^0&31-l*ssU@ywX^*gEL0`Wbmg0{1gL}I*Q+pC9CL>y_>(8JH1-5>mo;>9T?5toNrTQa^3{Ru0ge zMbmp6n;9%VAE&C-Rxz69tsBAEWCQdmrfNvNK((n*TJ=R&xe{g1pJT_K?Y1U(!iC_Y zO1s;W#}Tdm-oSQ?%W}*iNQR*XbQ?NrVC`W1JmeVWLW2s=>9DY57M&c+4f08GNtL}= zD|ojaXxF73y)-}Y-oHiId0;FXhCgHdaXtQINSh+fm7sfIO9#ox1sU?IIlUUoNv^+d zAKo}v-9QdxE1f3yw^>-xT}Y(BQG0OP)kQ%JSu}VYHF(8t5(U54&H~;hPo$4+yp0T7 z+=-;e+lct&_rxmY84{KKUfa>^?jZyv*Uhd9lzOD*N&!90W$Ph;?D>g|;7g*;#!Q>? zxF^AbB4yoi*i>AG^aBsh`|vw3W1i$5qBlRYPqtg!Z1<^WQni0KYgtwgFj;R$S=n}nkRFYQ61NKcU zo&-`w!|vv~;FB@B)H$-nt;HuDpU}#0j#~)jDTY>+a1_#y9>CU9C(cL6*E)<|rW+h& zf~nSyXJX=@;gwbCxr>dL=kGipzu`M+CC9AEFKkl*cv+2}+F9TXSeiI-os#PY02@1i zRt*JBu2Q7YA1>mh3I~`mRuA&`Xxm)1GcL?`YLP^b-w0xBFTRTk$$u%s=3f;w!x)Pn z`8_u6Tz(FHf5Nb|#V6|79bd?~`4uq&zf-+sB@jynJCkgHu_3DG$-34^$g1^`4<*vS zIxj?^2C?`^g5f>*TVz|5{^|Q`Kq7nyO{sFQD>?MjHK2{>mdffHY<)72?1{Xx16(x0 z#l^gp4XVC@sDF~z_{q48Y1i`m;?8-qZ^Wk7HGqpmmGg|Ph^Do5`5LedZ3vFn6{83_ zJSgDpSW9wnNug)xWvDv}Xk7EtRtTS@*lAS2zPMM<$_e7tI$zR9%DYzvs&wJG22k`e z{6b$IBc}=I*SsKw6gI9e;vJ~F)1*(s!5mt3uD+`;Y}K3qEXbc4C< ziI$QWq-rT!v#Nsh@$xYIJI}3t-OPknaWg3XQ#~aPh{8)bYul|J?S%OJ9j?yK5OrSL zFUEbleul<01Q6vXBe1k$A(Q5h=wwbRn|N75uA93Q@+E&e1>HbK4;rd$K;OaJxZgKy zUUJfF6IX^zQI_=bt_ze$x6z$jy#8VrecbCr^MSru5-(xWsCibpB4*sw9? z?2OUk@F*S~O`MV;iQGn_Ic+SuwwV^tNw^=z^&#Iy-|KU8BkOBlv*jY?G3RNE;KV|& zi~)H0O4j)heBqf*-PT%oytIngSA6u|2|y|q5|vYM`MS(siR{Rl{kvT+IVB$OG^}{{ zd~^6had1b$g?L}FEk3K>*pcr!2{E|O3N>^MU}aq|J#i;|MPQn(C|eP?p^qx&!-`N= zN0bfIET4Fzvg>P@sD*mfu`Al&iqoiLXr#mG8wuasPkXuuC(7ZlS*R|r%g9yH`n?kZ zALlRNG^f^m&eVI=7}AyGjVz{$#n+brsQ21@FNM zQ>)4UwQymjD-jP7(>bk&9`yhpFRhEb!r;IIKjl}3sz^BeD!{Z z+|BsHSesmLu)2U`eXO>)2NY~sRY?ELI|D5{ro+u|$MVoO<{ngC0}}Ez<25n5MH#+* zh3JM%6em9<*+=X1a?2;VS43iyU)ob_slUzJfd@sm39OrgXN zb(^#TStNtCTk%%)9;qC(%|D3l!$lRuPrha=ekr<@U9K3>`Z77?gx`;s)w z&It!Qlf(4A&Z;|3b{_=ZQoz8|GI5Tji2oKT87_A2UVi4_tcC&IOFc=hkf06#Z;tLyAjOiJ=?bXj?-a&FN`JlCN99Lj@_*;hx zv2ism`gW5AJ#0Nv=jhb=s2HVFRGxKt4r}PW2>rc|^n5M}bwRv+5YAnRgsy`QAK#A` zgk@MCmIpIOZhJZyr5(=J^>zsCkG&6knkrD8RK{0e&uFmi#q@UQ_+k|F`(*+^OXt|+ zu0WU%C zY2RIqnKAsz*`PGZ;}{bJ<_1ts%6-u6l-iFe6AopUv7RO-(D33fy#@sMug5Ld=Ht)M zb`}!QR~8m`_S<0Z@*)S=aC!BQ(C;F7!@q47UiLsQ1p}%A*lgIi*mCDtun%_HI2||$ zj@-I|==a~g+O2&2WmJ$<&1Zx9sW@%~7Ch{+jGl-7zHjjb-P zl83HWY|33D{#yjvBm%Lzwul3tDB)&d8}@W1DOHA&+5XK`2AQkcZY)-|j26xktBpw)F^F$8m0$#AIFrHZ}Z*w{&}Z3DG9{WmNS z|4};+HMPm>O;$AxE;dI(I{-4?FHBzha66Bv?&u*TA^ywI=)qzV_v`AYZsQXL$GfeK z#T=tu+GPjRZTF$H`#@WfcF%~MX9$u+s* zb+@@|e!GpDBZivE=kb=I)t*@S5s^=thJlx^TI(=R*`Sl#u7w#~NX6zQgT3|+Eg7x^ zs0=4Flb|~2t@;C#)%OLKAJfm83TX^$@{H@Fw+OA?799;caOKT@68;i5z*;8=Bl<=|yOh2@L=GJ9{eg@s{DL28d!>S23bp=`hU)!6-f>srSoJ$mFOdLpX$yr4)(-Hd3^JZ>^WXZ=-S)H?<_y)GhRQW zI%PJt`7(3j@UTs3f~M;$h`jj8W_n*cb614R(nBgLWdr?w+XDSNqU!n+U*J`HK!Cgl zr`33Go@07PAVoVEf6T}Q40e{d!(e|QZHY5Y`091(0D0E@P_@J|Q>&+L=GeGq z#v8sm%%&v$oF8Y_lVX`U3az${oScDvqpGHoIJ}v7wIA}G+{+YMKZJ>ZwMo`uSU6xY z0a`>py3S!V_xc{>vBuhPe?_*g?vJNj6nj6paQ$JR?_H$HT=;-X{-Qe9{eyMMXLIWo z``wu##8U}5eEY+;6?dt|h4f2ABSS&_Xhl_q5_zlWncLF>IF}R^Z^yS`50$MBLM=*w z&-f?*B2iN(<7nCH4I6HKeznAW#%2%G>>m>vUNmF(o|XnN%K{ixRoms3Ru4vAoNVs& zsgPwrNQCb#P$X>7+%5C;>!nt#(WJ<8f@4R&)s_a4uBur0y!c7R!u|Fe@3LH+AKQhG zW)9*d@|KhkQe5bVKWSp;hpt21wRlies=>D|_miT?Dt5KRcLSYy8BKN{B9dKcxs+Bc zNw7F#^?z~fjOQ#D^M23oLt0^AupQ`xTEQYb?u39^`Lzhe9ajp}+Gl8LUZ@z$k}h>(i8$qDT%+IXsX z4V@p5;^AuSfG6rBbuG9OJicn9wqO+yM1==gE~djqP~P3kT{Ex5qA2+0EX-Bn7sTHx zVf2ng{@tq%ZjPxqmBD4XPV5@FN2LXO6BzXC{7*)DzZxY*|9r8ukq|xkOY4i&J9eff zb(b9(1ZGAp`pr`<15{zz-E-TE>{k;zOOR`Tjgu2qn2)ZH@|Qi~x2)Fy9ck2P(NU>_ z`;%%HC6A|fEQF_o4j|`Z%z{Dh2xo}+mMa$@!61(v`Pj@%?sBC2U!`}>a@wVSeq=J8 zIxSvF4r@{-q4r+Mq?J@`173Jt~#kraG_tyfz&7vSjDBDp3wm!f^uEg2h#bY+>_@C?pzeG5=_wzo#FVeDv^r*$_>ze zBmOSf3PdHlsDm zec*SA?|bmOq@$ByZy9)22paZ9G(MI31ZV+u3wxOY8|#``MFEf|^fJq=L<289%pr&Tb!+YuCZ6rEZhz`wOjS`7v@qn zD&u#&j7)yCy#oDY=e1%#6+zN%BIZH3dN2x_|B*7mGeUMG1)}nHqT+E?tghi|DW}G^ zxHu~%ulv?k-Oit5G(noSnD(Q9DY_Y2+xFAA*CsB^JdW9XRVb^B+-R&kQ3|sn7%W4B zN@@lT4;NKRHTSQ_bo`=JkR55hHz6&#m$$luWpMr+DIHbl^}6QH;h>6&)|oR;1X=5* zAZcbHq1McL9ydWJJe|ual-9q2?xozEJIA2tS<&95mR$aI zM8-CCq2rF@l8B7h$%XiGNbC0f*re=x9luO-=wniogxeVS!h)6_W(P=L9D4`C?A|_t z6{ahA9rPXeCENv4=x#i=Ov~#SbrkKa1qJ4iHGZxm!8t)x1bQ?w^qvAGU$5^a&FcEr zspNU)I27h`;iZ0E$=b~8b54-M@qF`{-Qutr7ycTP%P+!AO3@2unh#0lZ6I&jS{q(_9-l$_CX=R$*&sL|(GbYLLjO$es$0y9k zk6zX$pNH0U4YaG$4xhVZQqF{P>xu;#YV@VfTxGN$XpC1d4ewEAq9g@W>AR28(fe-I zJsl;|#wxx>X@q_N8IN?~!<{WYF(VVBw~~pEv0sIRVILgpCN%*qW6OG{f5JsH6e{0^ zd0Xv4#vgdT^)=S!wSQb~*d+~m43&9e@+zFXswco7hIhBx!N^cKyg!@UhKtaMv}#v$ z#TgImBmc3DR*r1ji;eVE-vdkVNy5NNS>3P1Jhg{yZzGm3(j+0!-Mj9OdW~N6MoJxoc?IPoMOHy5egN4Np)0NQ8C?tjh&I7Z%Xp)nJ-aCn+n^R@%}|V52B_DtFNhC4`$OA z!GEed(PiHlgh@#{E6lFSMzNoIKx@NAN86>Jv&G2RuNT^MOM}&PdZkX@Xks~GnTn{B ziu%c9NL{Cdk7nmtFG%=>X)<1tPVY8N7*$DHqA&(;uD|?Yp&5Zg<2?y305jKH6snV7ia0&kNki=tQw5ZJGu+VcaQtQ}?Ac9uf`{ zHGMsA;?5}LJ>bUM2(e~2Xw8KS6UA!wg4G3LpGgh`Fy+jbg^XL2;lDqKKWI7y{g_B4 zoiL$X5C7>RjgoCXzULOr2#GEzcdDeD_JNzLfF4qb8A%ASe5H!^!5CIq5=y~yoYQ|a zz|Hnb3#9yQ&(O|Qcmh|Sy0L`b=;P_Q=$(GSBqBIy@PVIq4VRWZkz#m3O0J* zv(=9L4^FPy=$j+-{XQ?M#IY=P+rCOgN{bG(8(s~*k_sMMI_R=qfF~8dHo0P*Ay2-% zN5#&ZcA;0;%yy;+iaYycf~nm9WR#@-l}?K0ogv+t{@qHn#+X!>B7g8^<}kVJb6~I=wy-BuwOmJgP2 zJNYZre4IrNWFh?mBN^u{+o|5g*>}p&H~;E<;dRZ5rge z1k-LYQeGgYd za{>0q-5YM_h|R4pD|>6GDKQEhgs3bJGNWwRl7wQy>Q>uwPPTYjoeE*yrrfRH%SBYi z^>K18(pK?igbRJGOu|kg$Gn8jLpwo48f~v|o@7ZAuabjsZg~wVgCCoBR3t|b?tw@8 z&UmWV8H_6GX^ZB_;iz>}P>u?0P&^{%Jlb&e3;U^9+`uQ>4oyzN$qg9>B@Y`PZxzT= zak9(UTctP9P@uX-eB)_|zmLptK^{+r^D{T$#5KF%k$kGaqY9}2)#4x&UqqwC~2v=?SDhHN=qM06$N}ery<+#4-jCQrdi?Ew?W08m5 zX1k~_L~>+x@Z4(C%ww0P_ZsoLi~hiy@$^ULoQOg$0v9`oSm2wnMg~lTmW8CtI{*Q; zzsEzJN>9MtvH@g2EccLsJ0K0ZOzb129P(7utVO0X0PA?Fb=7Ekenf$yX-HcPg?E3g@Ul?IeGP$5Yf6n?o`aUO@YE74s&~4_Xym68IOde+FohDRUIQXhFMM)r| zxhN@#OX)+Om2dn*fY^Rf<3rPV)|r%U3R=S9AVNyz&3KX-;kc~QR{0vthhi7>OkcEP zeU1oDAQ7%pc5NeGWC39{y(gXa*)nuE|d)x%B7kz(DYxds4m9M$|j^ejQl7 zHcrVR&`vwK1VB)%N-R7lrgA&u$U#{@^QY*p&7x7>LC@$@Ev;Tm90#dOu5{iLjW@Gd_SIGVmO5j`k}Te>Yb*L+6Q(TyP$;ygvO zSqG^$d@dST)RVH+E*ci!7#t}6^%xR3eQS#Da(61G&6>%<# zF+&A_vZ(~&uqQ>u7|aPxLZ%&hfL70w&TpHfd72>)@mdY@<#S~ud@QzwgbBtu`5txp{&dNz3!DN{It7o3r zfVv*tiypO|HN?j!3Y?h9SNC7T32Ry%e0XzXjKl&q4Dx4NaoBt}Rg4k?1YIDSlMVOC z>_>RZl^%vZM+zeevOL$`DEbMJssrzLF}c=IL_Z&o&kiK7loV9c%eB+%N;7gmih(gC z>#?4keo=L3cUkK(@{E4Pe17n#2bQRaK`0sR5~=Eav|UCKUb1?3+x?9;Qhc@h zl6&MSZ*>n;yVq$wiZ zf7$MuFOQy{P%Dj)me8-l*dI6Y5v_rW^gY~IDjdqc?=Kuian`1xL3nm$;%3PcMNg3j zTDVO4Hr*9*4e+w9SO%74)XZesFbK_l5INAhZxP=8YsK#s5XW~Y zcb=T9vj(=$?HSey2V~ws#u68ciP;=9YVy|i^APp^848u$iiEfUupPMC)Qdb*fQ1`g z%3Pj&Fy8Bu%(=AF=#BRaoy)gUx-+MK0x`r;ti3ys@8#ix)m$19-G*K1k~#Nv>hE##O^Y^JQ6&bEU0ohzB!m87~D z(>ilL$SGl8N@zb zC>t;-?!&TxQHywg`fbKZZQ7&w%!J{18*^~XMEGew_hx?ruX=4Yoyn08|Mgf@7R zF2=how4|@*!#cOB-2;&fgMK9eFlkf>1|sQrMT|+$&VfK$QyFNZ!y6o*Px3%7(K>ue zQO3=hUFDYK8|j_W5*8I14PlC3cD=SXO16~5K)u?*9u;u3B$4T7VBg&b`DBeag>;?q=Yli8pd$jk5`Q+ZQ80&)MBGeQUc`OvUEqrcWZlc;`kPt+jD(#T^Vbu zXO2sw1tXLc$bH;2B@b2SQ#|MWg98Z+QKPw{tZu+sDu&>Za|wkYf=Lq4GbgimEUuK9 z67iVMfkv9Gmi=J;m)T;mu0)Q!TsGXMUc4cV-eX-HFNAr_=qgn@RK!ZVF%;NuM-YD- zabGo7<>hqj!X}~J8`2HZpC|~k1e|Zk`z;-P<8f%qPFuSD&bQcHjZ+jBb}S1H0xI|^ zE^*kZ?5+51nqxdEkg7-`4wNh+cgh^B#HI8TiB}XOFEUBwW!^Dm8NVFON=yr@$~x9i zjv;iGF;ct}#)B2HD<_fq=v*0{Y6Nn`Kn!k! zA6MY$_Uk2fAnw*Kwi{-3C};kpy;)}V!ZeQj5yLEl<#%?ON*SlIIIwo8rua`S~Yr8L+#qq_PwZxvT3C8aNM0GFI|Iu0?r zGAqk7+bJ-#u=GJ5K5x9thK4hvaQ5~+AwOpiIa|^|@`P@swwnGAp}E)$JqF-lzYd>K z^P;kbDXm-Yc$ok{6!P{NjmR_o@bvc7C9alTY#)_qyaxvkB3Ain;+Sb|M0 zKH4A6hE8!$M^6Y`b|5~V_NT-cRQM}nP^uwihRlY zc2y=F2ceM{#iGem0^a0QE)2;x!c7lKYW$@0=*eQm3A<|Zh`7|)Ay`A#lavT6g=186vOUj|x8jz3eXQr@ z=x!ufrg)T030Bb}1Zqe^YIUP}6u)ZYK3cGI5B~~T%Ed|pNNmbYy&=HL8c;ufbMV&4 zKb2PY8H-8}*fq_|`|`Z!!*nbq2FKU2? zY*k&FnN3e{14mm;{GIH0N)5^JFkYU?2^`VgqDmtZ5-u#WZE_3_W{RQ42Fm2bnxR+) z2d@|EGhe#a{My-*HI3M<4aJuAc>Rgm?X)A4VpY2PIE=n1eGwD{bRTP{D2gmm9?AysQ=-N*XnZ33C+Pp?Vifz(|GNF}wt(<_u0;$BP{H5q7)0EZd5UY{hXu8gSMJmd1odSHfi2Vs1moRfBe& z=Umspx*~2wJFBT9#?wi=V4d0ivLxCdf}HGjypk%NNWU7A;b6HSs^NktMCBSf@{0WeD(C?;yv0s0SmQsXD?V*g1g|5*4zu z)tCE5+pgHuuw#7|)nuJAdNVtoQkf``SYxif;< zkYJRUcAx?NxR~(7Gle5w+m#SkL;SEBWFC2vHB|0-=>_iZ?agV6PYm*MyI=M6<1CI( zKd}<{S7Ppiv?cuy{@I1VPL7o#l~0l1*IHP|UbbYFsmN1PCN^i7Q~hjKueh(csGh7k zwrVWr*pJih26#`-^F}gy@!qrKeTL1poGk;E${mEpY}u~^&*~<+cjqr;9T|$B<+kO% zp=-TBZ`>BoidR9=Zr;U87&g!0ekZQtsE-syZUg1^x=K9|-Tb=T1aA4qGo)JaBc{Uk ztBpb>Wcs5YyP-YzhOJ+bTisSiI{!3lzlX9zeTfo zX^ED}`zd`|Y*?q0q1k2A&MPEprIF^=`nsw-7@UbeAXUGv$}T#Tcy}^A6O)nztSOXN z1NJ&=C1f(n8dxY1?fS{!Fr>1>pkUS!KY`Jr!qL)E^RVaC^CNDX7-Knd<`eNEj)$_w@d7NF`nygMr5#Fz`pBei`0>Kz-Tq^Owu|bmo z`K4On_6{6kHUQ#?7Fd+8QF6k19L&eh z&Q70tBen@4Rsl!lsrxlr_Uy<d9#Yq-NKaE`j7gL}iJqnh27rCJBIG^>8&93NfDX)?QVVc&84E?(FBrzVy z!R}qD@I)w!g2l-Pyma2^oQb$JFZWHAAn=$(;S=ZF%#cOnD&y92HuLw42p%p)z1R}- z)g0KPd1LcL97i{1FD;Ijz|U?x+r~&P6%E<4^Z!NBc?PoexNSI;nnkVJqojz@)~Z;w zio_0L1l6LpiXE${QHmNtYmeAMk=Rw#-eT_+dsOY#ul>K?&*xjthm+@d?(4dj7UQVS zrzjL{4I9)J=MoXx0?#Ms5$bwk7-25E9jvwzu6@9kkG3YmAUCbo9H|sHQ}lj7s~z7v z$C{qqsZY4w6hE8y3(|&B&0)@aET5k0wmg&eTGRZes&r4-{XEP9tZ&eTH7d%lk&sVK z9uvxSR(C5V=>aMy6Q#@~Kl*W}QgtbbC8C(i(b-ij+*w{p!NIOp!DM$MM%Rb88yjd6 zkIXw{Se^ZbWf!>E>1=cNm!gB0XI6BIf2?F*1;EgKb}mpxmNi!w0igf^YSHbYOQEhB z($<#)>8~4P+dm%+Hs`)m5_14q*z{4SP-#=NG<3XC!1C)WVp>laljJ`!=@j)jOJIxT z=C<&B!rqmULT9!c3=tS1TQaWA91nHcCis311Zo`7{vV-foJ}9Laihz%t`6YsM8Gw|!Yz{laV0p-qmm#+HCP2M%maXR{Eqbu)QGNP^ZA2iAxFCw~~I_ntW zRlZv@MM&$JGA9>>1VsWIX6Q*LPr#IG`#QOU_(YwQdeOK+f4aG(f+@Qb_%uIRIi{RI ztsf!~_H=fmlBH0n!v4cO)L`$-IINgK-hNh6V}mRQ*o(+H!22Ldb-l!h4@@E(21pb} zDI}$`H#4eRVyq-Hs_HT!3kwXX-@l9OWNv=*F5P<3I`*PZJhr;!Oy53@p*}Yz1N7^! zrg%HO!Q=(wjSza}Jf9<9>4p{gg;C&mov!?8*cVFpgv{Q(N4soL|OX0VxQ(z_epmaCnj zbJYFYPZUO+yR2C&*EActc+Bhx1`SyyXfgq>lniDR08F?{LR}ufSaPjeW^zYTcaPlz zjDEZ3hNPreC5*|IWF4_;E6xAJy628>+4~g7*;mQOAUal{sGW53hln7E_VJd9xL*KF zEv2p~d`Wc=Vx{ilCeIB^NkSzLXPR@0KsZgPTR2p3Nng=T`)Aql$#K#5+?$|XDQioC zr&WN$jrSN9y6AZB0d1mwU~cw-<&|(wTVmjL*^q!zE47gt)e;@O82pPwSQ=j%Q+zzY z^_9&SVOb%8-6bRtt%6LEqwg*of_Oexu^%QoC9_y3X_)X2n_XkkJa?}`E&Oqe+> zI`-*9>{6bS6>ugmEu?Lxw6+NYuyTv>zK=36XXch*$22~l8oV)NJ9~$;HiN8jAW}A^ z7^teC-6t@LFR!U6pBCO>`!GUQM9SRkB=~#B#uz ze`dLTmWi{%ho$%#98hN|!=Nzq2n2y8(T#(BunKUg-O3tNg&q?^BN1m5Ss+-_mZW8* zLun)^e8h(NNPz^RuFF~;-$hl~!nK8Jpdh`95q(U=(^d8Gt}q5oMXpA9#uqCS{0TY|q7I3$IrPHUaMk+ad+I!U<@%SKapDJ-X0IOB1L;jbehG^v?)C zfi5(fSKCpUWy?+kd|mlUOX6{1Q3@sqXCpF+ZWg{M_d~OAK__qpPDkT>z=y7M6qaUQNM4FY-XFOF2zsLWAbvW7pmQ$H~iuNvh{wIudn)Z z#6K_9=Ziq1JWQZ600UM4b_a{8rcM2+>=@`R`7UI_F^8!C@H87h9~O#xhptKdFF+%` zDK2_TWJ_GOe<@e<$LjJ}SNjh=k^4CyITC8{MTqg=i(g}j65VOt84pOIIj&2)pUsUx z*Met82QO8tV=m_wz$bmTVwwU9Zq#fY1I6x_G1a)!JJw_*m2S%$%;8@ zbr)zfgew8HwQ7?B!;mqjPbu^%PImws(-{|-X4h^FByU_@IE}v>f<)Y_@zFEaHZ#-% zcNA~qw)0TN7zH78!Jhb|e4f_@+P==C#5H#_T|yYlG-2)bqT=>i)V(as6U@QkOfoV^ zF6e({D)?b(WG!J)OWC3-o7S7_z&Kjv<cp8UJzv?DkKC_>BI3J0_=TJu4FGx zh20v`$i;~MLGMbO%_;cEN%C|SA)M~6$`K@Fw2rN_P)c=5RYX>{h`{s|{9I^E^PfGy z)hj6yms4>byDOsT@b)~Ltw(ss)rLZK)yzmL=E3W!B(xg{B)7K;ecfO-UwMbzs`CV+ zo6e>BHqR;VIOiN6Z6mZFN&z~#-d|>B(b6ixU@_$OVIii?BvgYO{eZJR-P!0MrLY2x zor-c87ZS3-8b&V>qGx$sSW`dcmzrHeCd_3EzYLNQ`C3?2dP}`YM?FFJv%{&l5+o8? z_+*ow7+C$|sC!Y{(y9ck9p(!o8TeJKSAZ)PUGSci!Q5T6{L4t8%M-j8B+{i%+FnM% zzicTCl0suK3AIJCQIYw=Rq@1JHFU2|dD6o2D>inr>j`#r!);1?d8ztrGy{lsBNMYL z8?z!Xe-X#*Ua^#9c?v$o2cNy~Cqx(ZJ!XjRJ&}ZPUtk(ABGhWo?8UwNV|jHMUzr;$ z1|!hbF8#eqcs#%JoyV{6=o%Nb4`vMw(#iAreS^?&h1P_i!_Oi7v`-e&TFC@YAEkfo zZZKgq!D9c2K#j6Z=Cud3C)uZ?$i=6U0=*6p%sN>~0G?bWYC{4W4ZRzD`yaL6X;m$E zng>ilLkP@f;0wi=_2-l@e8uHsskpC4fJx<0cM?u?3bm@%LyGDglcesV+AaiS@lze< z>H$|g^e7p+tc8K0B0@qdJ{ICMB}O%Kc^V<+?rYhsef|;})4bi*^q~I%+*63Mu&jit z%U@Fkx#RDARC(AcqZo=FxfNTB|9qzG0c~g=P;Yv_{E3=y&W=1JkfmF`x*ET|{7zaj zhBA(o#SurylMXt?bFwoqGWT|%`*MxeN`9uz9xqUlZKI?~QKYQlrx(R>zJyxw-!8_@ zeJ=a4FT-w1Hy)MDD%0(=%MbMb@mQ&mOrOnZ_@im*Dn|{t{!N^yDmgs;`Xdm|mpG?i@B z*Lsl-?lp5L+zQC7zKx^xB*nyK#lKkZs)px+j9fA}PSlhC_j#nrGofd`;6SdJQm@lVN{wiuK z;IZ;Q0LN^7AOL0vSJ(%R>qnm6>3qRm7@_A1<#>DkfMww-8S&D{ILZOCxNK=saFSBR z^Urhy{#z#gnW&V2OA3_{?B>8&n`*$!;10s({!oCWtY?@C1;6%a71RrCfCjL+e zEGN*CzDWWK5K-?Dc!I3cxlH>4&*JA3tyA6dFhFRX(YML4y@d&DItq?k;c`UzP*)f1f9miw~OP`GL=3!X} z@+*gR1&d0E2;I_Qx%l#_GIwXy&_R~W`X3|ZS^->9PQ9pLlL9>JqM@(z0A^4^kXT^; ztLItWYukuimD4KUnjmQO7QafsY_?F}#)$fF>8F}V6>9LpLUUjxjZTFX83aQg!=AuI-Xwpt&IN!(p{V$^Po{wZEL!Ji$y~@lujpU{NxHtlyY&L=I7@PU zA@DYf`M_D{>w#0{+-~KE*6V}1k}-1%cg8MJW`}wqcTQ2(^=Hn6-H)saZ~aoAp|w}X zhV650lw5b{Q`L%u;>NVnm(0|MYh2*eVHc-01vYvOer%f!>7SPnL7Y~Z00%9vdQweo zij5iyquyevBF?5yUjG#~kv3RSZHB&w@T=It)D*vodC~FK*Q76bX+#H6w3%#T=2w;Lo-@`p)09k84vmwx@DQWX`x;BlwRs z-SF&OV0(%s$}TPUWl11fCUt;7tl{z8 zsrcD~U@@;X)Spx`In|OAP$d^BTtvq5*Td8GN2T#6{u1V=iNQAq?0)oKm!$nlQmHl{ z6L-c#zD5OeCF1vbIW5&}$c_#yZv?R+g{MI&^qxgNMyDg4pgS&Ikb|VBns7RbLPb{~ zP_8SMWtaFz+N~MuN(sn4i=X}KseLhypuXefC6zfUS%_R6ED^b+-KfnC=#a^oXS-XM zvf_!i>z=M|1_G#+<5070xgBBP`AR>9zot8ZITnKirYW*Gd`VpUm{1wH zV#fg@W&H5{=R3K`Rf|t4_zUF;gcZDx3GI8Qz2Y}$WyOHDsg!P-HgLp)FREB6R|}Qz z=c4d2mS+_IHL0i>L{!v!_**jN6m_qlr(9e4Q$rX5ytQQ4>K>$~t$7>jiLC56E3$Jn z{1Fzgjcbv%%BQ|Z#$1|<%7!m*=^vXFDjHACsOX47r%svCcf#lsT-4(eN&^fe&J61W z2TGzoymV>N>2LZPkBKCmk~@v3}`QaQ)`nEClTP_R97fl1$0)0jN z4nL?@@~P2!`5}a4Ov#7Vo1|#)TLR)0ECr{V^pzsWg{8{z1sA)Jb7R+8TGHJWYtew) z`O4kJ$(@}u5hOo~ovd(054^JYGZQ;DhG4>;FFMxyGQn%=C_Bq6Qj!&T2>L02h11>; z_2laVSN&o#p!oaN5=|HB9N&^uJmr;2l9xZ9-3Io<1`nD~T-U0rlkb%P%fwFs@v8I& z^i?G0M#SDxL9h&@q7A?MG}n~!CA0J?glBVUMn%qyKa*>tI#;v%QIEIf6p3OV2eD1k39QmM?PF|CFEHI3U8WWdO+e9YDgwPCAq z*;FqVsvEDtit>Dr2>H+CrvGzK`+XPOrhBD#xXl;h(@e_=<1a{ZTe|EIV?!Z2o4jBvSnw2n6~aW&K9=mGh}pe6fNT7sv)2k%EL4eVYel zsA-Qrb2Ejx|N3DgI_?-18hb()O6_SE&!vWd90tH*m~w54e~gyMM}9${OdVwe`0AF) zah_8EMfmLLHiroq9S2MS)Sg(D&;x#0HY-=t6ARKoHkn68ah3T&6@PB!&OS*H1!+@LW3gr_9tD#)5s6i1&g@N#HqDY8NBO5 zXmks`f#>g=);j(C4NA2$`wh2(y?>yA_#(0$SsWREeIc{AxRdsyioa*?KvejMdEK+% z+kT&)Hw^!x{c|&WOSkXkqH#DMBS5TDaAqiShS#Yt7U=d?&UYmHGBH1}f5g~m>9i?$ ztLaj`wd5S%e|2>=vlugJzN>BZ4NT+I6>;kb*c>rsn)29n6N~k-6LD64Hz};^i?uu3P#aGQ-1)bn`9;VAKcB*$v1Q~W8sK5MkO@ywq@w^$IGQ>& zHe?8CN^q5G!ybwVl6uc4g|zL7dLEM}j@-AI%lAS~?bIw+`@Dm$&PXW?X3_{d9Z`&O z8Frp@fJ=JJzo7p-)IF_mrR?XEzns24?@`V#>fIWYx2lzklKh-l4zSzAf?`Bp$2xaZ zuZezsQ0lWNh+0L*BJUMjr8JXO^74Y-ddwC$%Hg#)69%8ZQ6k0kcQtzpYa|t1 zxdvI@iS{7#%hs40D-+;}d@u^xGsM$bv0jRJ`PhwiTBA@yV?UPENg$4&Uz_aq*AwlaY(6{c!{> zG=V)sM?8@lKih+&ICn>lV9BqwXXM2dOt#A#dB#4I9G?9ak@~Z$(J&vhstcq&JFinM zQ&5!B*|+amcet2V+T{m@P?6=L`ur_J8ayR#e1m(UI*01MNsJ(fMJct}GcSXJIeLvg zkxq7tbGCw}o{}1b8i42-&KW5FG55-ysEw@@O9p4k_-Gt^zd!9tPuQdW9Dk!^YH5`} zFLniii?qr3$@DT_whf&{=o65wvvAM;v^r*{;MAh-1hPUy83D&!Fu(bTQ%1KnO`~gI zES}4&+xOxG%lhqp!Q1=l*oAC&cgCSbUTUb7Hv657hE!KQsY2#sHST;HRfNr#Ol;Gzf7jD^3o1$_iE)U9e1s}q|xK3b(Z%Hkals=%<0GVL!$sM#(0teBoCmleUy zB;pa5%lBSp`o+>1>VAxf){?Ftz5&lhAq}*I(Xt*o<~#Lu?0wbfgOGa_IQ9Du)<%VX{cat1>~$W2z9?w z%Lj|r|HKN#1)7VM%}Zzr8k zcZ4XqXJrrGeB>xtJu{qiBB82Z2AGBS{}15nYQ`w`!A3JL7lu0ZwEyo`HyAcMYL9Cb z6)_Y7+2uY#eKLF83N!V59{Z3c<#Ws2DiTMbAc%V=W~ZF+mQpst=##yOl>uHX?-}8W z^l2W1xXH_3L%m@|ZYxzHRI2#9Ew58A^|;aXm09jkT-QW1zG2CpD8@*+b69r1?Ca-T z%sl3-qX~U3UsT3b30A63u#pRRM2F;$lFN2RDc|wlV}A||RD@WvyvHmPrAF3jnnW5v z7djus^jf7CV_{+QEbJX}-0w<3Nvb#-U;+7vl_A{k@XW-+Y{24j5Ly^L&-FqSrb-A) z9rqY`E)#V1m%k$|XvC=FXFz;#n8|Tx*VRu^%Czd@I?qr{Gy_ZcRO+FKz@lO9qq)b5 z%FUF&E(A_rxAf(_@WG)kJB6qrV?C!c2L_-eyKg>`S|5zBUgdyDj5;_6c7DCL(QNt- zQAoxtjxI$3JeAriLhc^$-vm1@&>kW&!opwUiQ!|VRZ~nK%$nVoAN>A($>AKyjO&6W z^lh-DNohA+OWzz#eeOCha_%1xf$W^Y(_FBS>>}Nw3>4&fU|}6TWLMfGEAkRXQK(?` zpEXFU@VvclmT6Pvy|R5Qy{2SC`C6oGWC|5XX(ykX$T1co1r62PG}-S$InVWZ_Wwy4 zTVkuCImTN`=E(O$p0DlSoF92lJP=p#G5uuJEK@!b)@ZIf7REA3fb=5uJFRpwv(nK|0wXRe{CEa4lwE%bNL`9ojF~zP|Pm_?ln0)$Hou=4Q@jrgk z9KYTsOMOL+JwxJ^3#%um$A09%YgTxZ@FLBO`b;>$-mbiF#a2_bhVq6>WptbQ^0t%e z4FG-i`@pi))eBo9?E~<927De}_(TBOBwhY<2%SE@YmaFvgeY}k8onuZQF^(FEJ`)v zkU9(WF}HUI^xLg4IP}&cZqi}(+uOOy`C-@ z;7F*waINymo3}mvAE4Oqw?FHuC45p_$1!OD{HUI!vHHqsrYugw4mdh2Drh&cy!sbB z!+2vYrCF7h@iyFE$=AXB1m+CBW%UJDGpR0`GM9_bwOWst;LL+|h=(Az#w8;vHIfDJ zRZ6v5wtHac@PRO>5vaxY$9CsD~*Brv}so*mG^vp1imvGtkZDD#)swOg@ooUkAlQL4~|J_qy1S{8R-wr z2HQ}ZJ$$WYhMLHe785Ux-#P}xUyt@8<7(wXx_0m-RgHU^J1^o7uc6sI0SQ@8layK$ zLFsvb*Uu=g&wo0RgQ-chy7251410H_>#!cbWzQ@55Rdo^aK;J>b9+kOZksrNEnvVB=8x<=PethiSx<=gUtTVoUds>C=Fg!D#8DziHOn^D5pL}(GXbi z*Z5RlH0-4v`~{3_0mB!WJir%_I+MDWL;tg4(d+w?kO9Ien;3BTf(G?gn9+cLn6B*? zLRc2dvaI2}7((EraeAd2#u8b^G<-z>KD1d`0BahB!2&NzTN@JaKhOst)1C~3z&@;Q zGFD$IC+_@qlP7Kb@F+QpyGkY_i!5P%92TMy;cbD(pF&eY*yx90zZNh=@ADS3{6n0b zBqzHZpdwYfv3=>qh%-pTM;NG8BSpX!8k1Npf(!)#j751VV3yQW~!xOrxIu_!xklGJPJMZh+Au^OBhNgFrr9VQk-?(*4>}~ zJqXuQ+~I27^BH1kZWv@wOk&grjE(7~iX9lgRibwZ9!Wa=?z(zakudpK;{H)jucd*5 z5|x=j1a#3 zW9osoyM%I2HF=u=U3wt`ejT0Wqnlx}p|Vc`W6UR^NHhBL(SU}#%d{kz?L+GQ3+WxZ zhzL(gf$0dvK*#SSazP$(U5F1ZKvidIH9_va9{Z5}t~XuKPD$4K#4MAVJZ9qG=5jh< zw9!0v+FhIMlMYvf!g2iE81`QI@(6cWF?654k!4K8-OnX0amD+sCEe(>exg0II3GQa zU9q!N;ZJQxoUr0x2b}W4YX|D{chq#@%mZ(g=i5D;KBPsLb3=UsdxAWDZ(WI;;BeV; zkiFd5yOCD#Y5FQ4d-E-|&#S%4Am6LX0m8SL_e2YH)D!CvRi7oHm-wYe`JD@=Hlt~4 zdJvF$uKY4RoJMDD^EqJpOBH`-<7)LxlRvLw0$tFr`4HS6Q8l=lzNe(;U46i)Ct%A^ zA%Y>IlqroHb4FryHlEo9c|myAdt|;c-MdhtcKb6$c(=Y9xaD${gpVEy-WX^WmDR9l{(TF$~j}V;6 zieEm$4;dx%y>JQY4A5~{t>97TwY#dI=ru1{u5v&K>}6q-vE{J!VWs+@PqVmv6Sd_1 zJIXDGL*Z(P4)Q+UEf_!bv@e%q;UZOdWl;89tEF0JCpq!Ikm*NFxEQ|z+tX`nkj%RX z>spDm$t)WW9Xn6UI)B>ivuc#ObHz>Tg92Ruu4Fs{@AD7}>8ne7@gCW1wP7i~0M~6! zeK7ZwyZ9}lyZFZt@0klPZ$*KwHiF%JKrt=b8{qw`I_cD*Np58OZ>V!rp>B|_$EXe^ zjj^yFypQ?Ty^%gL*U3wJwv)L>=+QfcJNHz$(RS4uFs{) z?kTt?9HA(hDx-l&Yu}TY_K!TLs$C|ZX*I-P#60wS?2q-AY$wGm(;o6Gya+w&uS?yL z{VR05k3uMNOFIRipcY^1Kz3v!IoZNVqlBe+dXGL zPOjFiRahUr0{;&#{#iy$ul<&&4+EVEy^3qA0r&p=Sh~L0HpMln>_`;p-dbv-2H{L$ zWu`z1C|y4XzNpq|?}QB&TFe-&q!0Yd{slj-eEjt+IrGb+ra|FU?r?#=pgq7C7vTH5 zO|2EXe`X9BG9K+S zen2k%r3&H=z;+8Wq8XCIlqJ$uSvXq2S^nCa2itiwe*RuFRgLZ0UZ95JI{KI=E()TC z2RcT^bsqQH7H!jhx0wX;c?%MKdO?HJi9oMq`sPNbE(H75Q9sw;kPF11PQ^3$B4Q+J z!6A*oE5$GVPUiODp6o}v^y3lPe~+xHB|h63Dn@8^-Or@lOTK6yM8*2eJmXxlmT{Ug zV26#ubSUQ*{ElH`5)tKFkp)kotcE!W!8{g9pDW)+R`oXh(&uF)70dv3zFD^>m}r&^Z*-qG;4fW}pY;xDdLitciwAppEuU0Zk09!`0a>U3 zMJmW4Cxz3lrlKaj&7WNx9-XNN?vy@t@E=b(??sK+bZtDhs}-SO+gm*-d%$#9dnDoa zqHuqrS;T^@tn|P@YLcz5l4Va(gsXn&3ghid@T+aC*_Yqnmre2GRS#9(k+;q0cGq%l zl9)!e*d(1m;Z^zq$?Ri~;ULwrXRkIem1N=+R4b}r@blO50n@0ObOPQ2Su9Dqrp5g% z(E9VwYOyQ2FB7boy~1E@z*%6({Enf`pn^(dvZo;o<;5bst`zq_K-E#w+h-rE3(`al z<<`O(#kLX$aB_&Q>7~Mat@<3pkt%Mn)0b}Yd5UC$@4udIC9i1t$@|Z~`YnWKRS3K% zX|qIJR*;j#*AP6QD?Wm2w&E(XPdD_POLDIUtmdY`f(@hOdv=@X3<$CP+$Rr&Re&3@eF`@5mE0A++lzkL^)z*!Q6oNU;^sGx%`ulb zhL5o_F3mDPi64b<@Ng2Y>m%WtUg@P6v-*18J+9eRHR-E$*H`qZ**mdWeb1YihWQ!F zg*2=T$?ngVG7ssqIAk}t2`ETBU7}yAeziuJKJG1a*6|U^qN#vtVbH>gjLOO(uJ|Sc zuh>`X{b@V*e`Fkdq)Om)wp`KyQ0RnttLX>+quwVB)aOZ?1ae=PQQ|mR^Z!c_C22Mg zyv&VN;Gnuz&$Ha36LtRfnA*&lqmLa^AN@glK_~2wieraQ_4%ylYxN2KdHr%|QuHKS zQ#J*)5->8G=tYzo>TME@BRI5_q8s9Zw3yZWN!4O|Q9G@(Hqr1UF=7vOvgtChP7e)*hME>4 zXECkAe+#x0G&)z*)g}z@$9RY$Ns7SYK=kJ9^h>_#s;8-7Z@~|b znqJSWqZq`WObt0h{cputAOO*h`-Kq)VV3-_NI>%o9poDX2JwSh4fc#;mC{Ug&9zjn zEZ^HCBjI63s|*!qr+ycv#R|{i};g z_?0^6O(TiL`j2-f$B$p@1YzsI$NIPb$&~oCR%^r?9o@y-xW#`cbL+M3ek>{UII^{s zE^~@cy?w0qKY+$#-nvfxiG3NdNkaAqs5KJ*fgierAp=eo_Xzm~(~CLQJf|+l(avk* zbnrrU@S)1&l`L*|S@r7rh+9zx+pUlAG+` zvEg1~XnKw%abw_76aRl|&5AK-Jg|;SXhM*=ipxjoy85;jfjB1@g|x=&IK;3H7{AiM zuwYndgYUY-(kq@n_ox zuv^oqW^=01*F2xC51k^gTua!4Y(`nT68Y^G$LQm3SDoEbxBV=(Mwdifxpk1O0VXAh z-m}m0>}k)cqesAkJn)!I>zlauc~7rzi70haSCN%rAzm(uxj{uvPSAHxV^wHCO$wG+ zr*j{}Hj=VwUlj$g^7dEV^U$VfqK;B3zsTHb4R~iZX4NRr%vM&J!YPoc((!BGE5xVU zSHILs>xgFBj77}{w__hlcUfD{zJp$~o45Y@(J@QT4477St%aQM`_g!c_q3V+maRR8 z5iG9Vji3@Bbo5iCQ*P;7sv8YczxX!KouyY*p+T&ifK4UWQr}hy{OS)ls~C`vxHUq! zBRx1Gc4VJB2`X^U!VOJOX-V>2*{1?na}Ed((ktfC_Tr>5pC2+QJo<~8_nxpF!Dda9 zUh%$71Er_eNYm*@y>GS;?(Lbe5vV>a5ax8k?DM^q*{a!3S1dkuSCU_(rwo1Spld5J z3p<`B`Fefh+UWSgPm1n&I~Thobo|4Cw-;l|6PO8@FSI-U&p}LEEIg0)P1;h{6OeL386crZ`d+1l4PXkCrm9QGLoJPeH}j|VsXTLtj~yw!~3Yt^?q_{ zSzwM*LwejFz{I}N__xOkM5S&xI$qNR^3vdkMI(c(yGFYO`1K`p`*?M#)ZM>N3{K^0 zm4UbPIKCT81e5q75r-^9zmcSd!ngOspr9X>}$8EYv#usvndnWo_p+sVFpMpgA$4K@!r~2}TPnq+q`5SvqAJ;^Cf-0R_%D(06E2Q3tyDdx4O%rBsyM^)X0ANaRnU z34Nj}SA}{YK|ZuAY@}k7e||)<|2FLg6weRyM9vDxP}F-K#3Y)F(eM4W?Y>#=F)l)N z550ZGxJGn-EX%&6eUB(u%ys%TVSb>rm6{EqTM#{D@Bk(#NzH86lose-76ENY0`S@0 zQkeMtz4UG5R_ofvKVap*2QM@G9vy!o*&n!-h%&K zT)j%c`y`J=xSv2c{RKC{KTp`kJ^Z!;okfo?U!vg{XZr*ss}<5URrO8QB7cN z1>-6E_-k*aX{3_`=YG0%d;3Rbg?QFit#`>ThScl^QCi~IVjdT{lS@+wnNw^^Nu|}` z6t?NizSm=F4k_WGVl+TS0bpSo%a>8uFvmBSyC064m|xmk6b8jF#z7zcZs=g$^dKku zIc9WHpZSBSA-+z6Dk`%lpk7c2UbEDi=k^(XqecimwhZT7G30Z5n-3Wf6uhRcYAa(L z_t(dM-gl<*fRmm)^VUbv9iCU(EI!s9nBd@f(;T|inqrmoL6d>H3A7RcTl^>iv@dn3 zOC9=RCN*x{ZWJyN6lRBYaVWt&QFxuZNCkyH3!{*v3u&#KOVp^%Zd&(ZF=wODTbPa) z?t7aN+XG*+J>qCncN3K5iDxbjk{Yba5!}d|WQ}14|8DV8imkZ%c$A8aJp0mT3j@Dt zBVHjC%oahS7Gy0o+F;zN(Y{o;ab=)T^WB-H7dqZgrRuCc`7Kwv4wa$m74Q+T}Jkun_?6Q?#)$*k{zT7}qVF9~^ z6){Klu#~HWXQz&q!0iP@V8%JiN@@j{*n%E$fCtjWLK{p40*mle`%2@Y08u1+bk+)$ z^`uV+x)9bwom*^ZTw=}2Ui~@)}H?boZJ1=Vbhc$*qm2dXC{oXd1N#DS! z?tiQXI$4$gZIfsDXyeL#GFx?I1{ztJqKdfcVF+{aVxWO21slKl^C#6-!5l_1@o2gG zwLvK+o~XZnG8YjqzXf$Wgu%`!NKF&%H;dK8>)<6RcTJLlqLD{RE=UKXtA{}}M@$PE z{$#h<^Z9SlMruvQcc=l0h7Es*nipi7c~B(bLvIx>O1SO8Q%X44i(mbiFBl!+VzO9C z-Mie^*PDIr#o(KeMpyG%_p+|)<{j_0%s^Ib4w9JHH^or6$1d-2hsMLV>!5vi<1aJY z2z@zDSvlYr_OhT^z{4adpV39Of%#+VVP&dwNVjlq?#fx7HRK2YNGXVTI#_bwX=h+S zq@HQ#sKM*mtyQJ|(|1#U_Rl(28rg)q!?&;@Sa!&w^dN=f+$Y*BD9~{1@ABsDu`nG-VRc|`1iZ$lRODRFaz)Za!2m*l4yKJjg{lqSB|u+C0Y#w3 zdr7E2wPV|5SS+v*#`^SAVle|ca{3pqdCDl)Meb9Gj zrKtVmPQLp>rGp@(H-b8&n9JtyW0@;>Yme5u%x9{cqvE=&nR$RHS}*RVX_Tf^cK&n~ zLCO>#LD7Ie>!<2GmcjE8?Y+1Tk}+-x988TdJs%A}+$=8p*h*)o?$==2b&vJ`Tb8be z@v+7@%UD=>roD3|?htrcg6Afw)U#o=1#cBQ5FOC(|Rl1Y-q*}?&Ie}0wDU(gi3?83|W zX8YR7#ns2vT~n30TSCVlHwqcEXE^FO%p*)Rq0O{{#J~@Iil**e@Tu*3H5d;4P_(IY zTZIKQQTmP+zHxWFGWB=Iwu%tTGM%mGcB`P2j6coH(4mdu%Kq;*{$FD1$azM>S8SY5 zi^;lkaby`r%+V24?mIoWikfDUm}y3C_4x|F9Tn)hk3a?p9=hJTpO{u47lf>=I0y`e z7h(gHmfdLzY#pm%;Yd*>hYFUJI{)Hxx9?l@307xv%6t<;|iVb`9W0mx9GyWM@*~r#4}<@4bzVl>?>ap*=WHOrTaem}4P&cetj z!UgIa1~Y%$18zl@A|2B=0%>cuI*JtyC;atjLWA^|i`7Hb3hJMoHSXGqc`qiK_mj2| zQ{tYYLy7QH>w9H2^@74TuDXu!N_~u%lm=!&xlH?-uZd#4#+yXfJNxt(wjutW6t?aG zo>lYrC&aglfn;vU{SQpbDK91DNWYA#L3W=2ZqnYOo^(EN_xFs58SnZwXaNzXfpigI zbSS%7Q#M4o%DqV2GQnf8V&CJYP|KG8(pcFy#5?4U1QD;|F=J>flYqA z=2LYnvB%t(_^;TsMX|w1q#1eq2#V>U;{$eU>9|5o;EcI8i6jSB1?55?(Z69o9C$o` zBPkExJG+zJi`Awv@6hJ{>+hHg`G(j05FQZjbH!_;AZmm-8fa4to81A7ZeFk`f-hS= zpJ+uH`oowpN)e1zVz)1tC*V$#ecrCi@8=mpvbl>K?#E=ycKoOMf4jxm66vSC6 z!(u@lw*{zAYLDm7XX$>u&KQ^q`3dUEONQQm5=FpZ)_X4g)>d1gN54(=iF1Bm&COfD zH@56{(2xn|>9m;zxFqr|OZz0dL(#h)8&iE4nYRuELxed@)hvMKH*&w4aYEFAW1|Ba zLT2>^bf?YU40TVc$hYnCd@{j`XoVRv{%G}(A(pdOlfJu# zvEQiU^x4j`hp|USEY!<%&^Tq8Uj*ufX8{1V`Wci#VM`xlp@jF1BwB12Z%X{1Sqw*K zS+43lR^p~RoMS~;Ch1R(fJH_@{78YI*dxheAapFO2X$&yZ*?p9vH9xWTkR&9p|;36 zcOYV5SUsX~d+wDEo|;NKa_>zkem}Y;mD%#;KwsqHoI#M(cvXsJ8vkE|2 zZGhp<(cYp!0;;|>S>RfAeCT$|REQ8vcHUv9@(2q~RDL@2^<1=YUCN4T<_S{L8c;vB z6w7yOI%W6Lzd+1r06xbZYC~{BT6nCdIqT@t1@Qr`HuG)+yh~^tbR4VCpGQI>>FPZk z^XZPY(w<3Ad8EBYB=$!Zh>8K!k~ewch)z5C zlW2_^ZN;U;?A$G@rc`_KGhDlSDN@~2>r#}gU=ff#hNm>HOytJd9=5o^)Yj#5Y>7Dw z2qgRkRc@p*RN+^mTy^pY9L`-M;;TZ|R*g|>%JwZX2@1w?J0Ae9^rY8kHKZBAR~T^Wd5O5S-(S`d!Vr z5;MnOL)hpk;r6> zk5zhlX;w3vQ2C;d)@~OiIU+(I5*#bed6F}e-GPo=s;Ijp7gwI7fHDt_S^DZjvF}$H zQ=KoZi4HcW0mo>tq7E3yk1KqMrAgO0h)IO?>ov9qtu)Pxpg7ThC~fI3D;$w+j{9bMgJ3&Mgq z9}ZQ?DWxQIN22@S3e_h`LrX47bgJ_xhMGZbXi`f=29}MaFG}0mzgw^P zmo3nc`kYs2t))oq6jV>3Qg9EAa~}!amu}Ed=iA&{HxYT6=Fc*(O%9Zx1p(8RdeyIW zyj*sksuKMqXZf$jHxzYt)PTPF=3qUFtWK>+Y2}OM%6OtxGFY zocR@Jp~XSu<+WWBrj)d<(=hD{BkKn~hNkz{)xF#^wI`fjkXw9)$DONXqLpb%;IyThKjNC-*P7q!p z!+O}i{K5=u}jEK01hTvQll*9EjscWyA#*TL*fcKuSnaJ=~Sw^Ha`` zpB`<3+YKpVL}P1^+t))ZCFlz(Ctz#q@<0_?@e=&>*|8-)(o6k;Le;x*dmv<=4(?sm z>dzyifkNfEl-{Udc8@k51gI-$LbjCSIp%&p8iDZ{_a#$gkfo_I`hPo1zb;ovl z>T{?XLW9mJ2h%DicPw%w`+O<^uh{IhR`ODWF4+}HK+aT>j$a*cY8lmvUwP&t6y}nW zwSkn)OMJbR)4osEr}Z9~;mjR34NHz@PMe{D-6gJ| zq0~*sOm~#4G=;o}lmRV=26hhffKDr~G{+Wf3`c{h-IFc5((Ng-xe;ujp&0=^vQ>b7 z2u>62t#tF*(UxaNKx@Q7xM<+h(iXWgT1zg6-be#zz*tEH1M3`zg>X+B{{TCcA*MoB zq1oXCE7IIX?0`GM{!v|Fs4o%DgoP3qdmuR`U}4m#ET@qtIX?)32ZeHH5)@`F)|&dO zi6JOZISS;SK#u-r<*!OpxKYiDEy$_3meWbrQ&NNk62yEY_bahRO*HDnArUQ&l9eUf zX$vJM2>|mwdx0n7rye7++BKcUY{^Tg0hDh_@^=Q32>Ekbb%U&`HIH+CfVY&m4=uo` z0zN`(!^-M*dJ%#}wV+crZL>(TZ-FhzY17T6aa&JlvXs2)Qs!}uq!Y^-$m`u#W{SCs zHT4c&1gLV@#{SiSf`s^l^dArzsw+TUZuZ?fq%PJQtBk1@G{t@Bu4TsE?Ubc9v5r7) z82IW@BU9X_PgMJy=`$v+BQClMiNWy$m3HZ}@N(u(%a@7MAwIVrDNODa{qPL=`y6(d3iUjt6as+bd0X)T4 zyg)HwaOYOJHb{)AX|^I8ZhR>&CPI|32Zy9`Yh6Ut(9=b$Y=PQZ4kq%KMjdW4-N{$O z8?b-rZa&Oco*s5iYlvO517LwCkaGv%WP5s2yAPX~mv)>XTOln-IP|gTfDgno?WWxY zIs{#HYI@-*F&Qm9*>yvZB?KgVXBFj5w9d!OcsfIedMsTu{kG(r#mqf9pyD=J3yq;z zJd28R9RT{#QXN03XTfGu@g=&c5gj`jd0PXCNx{hOJo+Sz{FPK%7`mn+V>3G96R-eS zkiD27d=Qg?%o>+kW854KwJIdds~Z3fl268Z^cCHLZF1SkIJP`-DrzP?1WwCl!0V`G zT#{5d_3s9`+lpzDjcp+kUoI^%;&UUG(1c>H{X-H&ge|sWIMF~U-s*yL+yUpvX9wb{ zM~jyWb;n&xZrgBfP>&icXPj%&M`)BIa0kBzuc*kS(KsT}5Y%Z3pClei?E;cM#HT7J zzn-XTf%FeSAop1>S%44)oV&f2X#oz6>O?%YB_>4R673iWQ5yJ&kH zRwu-dHp-Ppl^RQ(nRA|Z0(-qLnAa2a4W z!5P-yn3lp?TkfkQHR=PuzN0>9ENtk(j#q4Q;SzgmHPNKJaEXnap1j)wo;i0?-YF#e z$at)ri4E@MNcbpx<4)b3N;8=em&{`zwhcY;Kq-0>T8e+VvaX-9uRj7$8)lhWbEA~j z*4JGb>Z}n~g@qwnYfGso(t6yW;KmLT_TWWUa#Y!r=R%3Ug6GZ9U+mbM&GmqMBr;L<&6lg3W_bmZQA=qvw7|$xX_*s0mSal+t{D##->L+RU+Y?lKqY=;AlDGCJR0M(18^;MCSB~M)&XOT$X%;N`_^zO*6 zEN|q#PFDw2Lef#JdKX1ZylX2lu~_Har!yurl__%?OqW#KOtzkB%81-fRm|fF&3b`( zREv|BRjJlwTqG=Ka@2-~;79=S<_P9_YTWLdDY7*P!!Y*pb zBN^pYB@bY-Jc&(%!{TDl@G_mLnuY`Y-#3Xa(z7>Y^> z0g;|SV;#q>Kzyjt9f+D_!ELaTB()iYtT?xY1bS+sR;PZ>wm_ zLXm(H$3A^dareG@gz=Sz^KVfH8&}L4nP>$qdJ@j!mQ=3IX&k?1aq|j^akmL(&9z?* zP6B>U!&t>sS#BJWQTA%(leDElT+e>dpPw~8h}w~-tPU+9Vc5#Z2N*q~{{Y=klG-!c zEq@6h{r>>IYs_ox*a%AvzuF-liV{yGjFZddHRshkIv-`LXWXXJt)V&Rikw)S4Xih? zsH}4Iu~ck+Bd#VAyJA+Zxyk#~?H7$#2%MwX;&z|qRG@KP7^h6icvQQjKH9jY+KS&D!Rnn3m>T3-d_%+O-aO zQTpzAKOQPJz0bY8r45gSd$FE%Z1YlF7sCyTi9U*HOSj%s&3lcaksy3O~I(m zNl#|tV>g8n;7^Bjbz;bogz>%BFw9Y0xe7{&`l5iy$j(hTX+nneHK9u=?9nwYDN8s@ zX&yAt!kjFCvaBbcKBlnZgK0U*BzX1w70;4NQ?ztNQD#oq)zWeh^JMwLmNpEe=dC-y zD^>|3Xg$d}s+u;Uks0nskncTBIkChGv`%S5YtLNttH&ZJ;@NguA4zl$!Ae#@NK$~w z?j35l<9gY9U8zl=;THB%Juq-U$2w&^R@Cjcwlk4qB|`^mV30g&J0{^G<1NWk9#hXc zk(V)y0nZgLDsiME8j+-pz^BAwrp>;~wmUm5K9?63FJ__kK9xeiNc4&1IoE?R)&X2+ zigKKcduyAb{T4N_l^hV9pNgbV9!gY@v@Bzg*a@n7E~L3I*;j77k5wp6uf7jKyUVPl zT(Fe$tHr7!i@#9ZlGnHp)}USYS(Ub&bLOBbJ$yrLYrE<~6upjg9LVv_SDJqLaFwYn zrflaW7Oo7Otz7>AL`_)wraD^UE#)n*l7{kpa%)v5B}~CWrX$O7@Rft#y(`Gb zBcCeLh{y^nDak$Nwj3m2bTu6t)eUf+OnrM|aRJWNGLQz=qKFy7|0*fs!*2=}XD@dw?Um6r3qP1S`}z3fmoPWbAQ3GnC&$pDxX@*ZXSnm=00lfj#$DJ&P_5NnEaP1-sXe$+`ETPo0V1Mjw{6*-`W zv*}qcL#EOJ_H(UDnCgfQ;RzVP?i8bIZZo}TSM9UPs`68`O(NppsWP-) zsfLvu!d!Pk!U<3*LB@Gw9*R%56))oEqO@wwQr*(R9rIT0Q6Q4wActE|JZHNlUoCUx zn_B8U8!6|k^TR5X&`XF~cQ)cd2bjh)$b9s+ZxnCWAfG#G5W;zF+?-_ibosMey+-KK zgreKDN+;kPIFbf1Ml+i8ZkcV3rZv=gb3+T4XJv@VP{(M#+a!ER&&yDm8ouEyg)J$DJgQ zdH7O@%1++QqXc&f<;d@%&2wX}n3~<2Q(A5-Y!J-GR7$!5zn*?7?de+5&1+K^N!mr} zlWp=GxZ7qxk=Zu>v9RN+Do{w}fs$|l z1H+X~WL zx~s{%kg+AvEY_DRHOlcF%S*4VEL$T-eNLwXwn{LdocC^0u}usm#N#cIk%Bx8G{%sx zfTDJlVD3D|J$^Lo%Z0}hlqpKe%DMIHRL3OV<7!pO*!(Nhtjpn6pO2*P2{K}`{40w{ zll6G+ZY3)y$n<%Pdpvr=b^QHDeY~#WsMh0>HYKnfbQa1}$YkcZj^QqRD~tVa;u6H*i z=-FdSk=0w2g%kiVk4T=GtKWb+vrTE+w5w*MxrC=8yU{{T;AD%8=|(^j+)g#|J}FytYe0*IabA4njAta32sLe018ViD@Gzc6lo#jl-!QB`dcrQP;WD zZYOp~IXOJZ$HYEL!c%fqXr2&;a`B{(jlcP*oyNcl}|?A$2qih)lvfafvD`pBw0@{w(c5=*YAUHQlmz{G1~ zPBOqL#?ZBHQ2A?pl}kjlz12Yr01w*a{mP26A8XTFfFDF8EnQEmq#q)k-V_ZY;fK`tdb(noRhQ;&|VXuM6} z+90N5JWO>GO4PMQax#LFNC1@_bvPd-a%9F=6>BPBp}>130!j3F@)d^GK+kK_Af;Fb z)y(rhEo`&6a3YgB7g2FjhpTbJ4*Z!J`rgGr`$bpNxS<{svK`Z`yXO*PI}o`cDG2Ob z7*^blwO=TuIMqEOIcLU1`K*oG~xz#6{SxAf{AGwZfp(=oboTY|4 zJ;Z`=4>U+x~vQgr*QUo(u6Yl^RW&j zE0zOGPd|^9ZSTo&$czzS>K-gvrYU9}xz#B^0^@@Nki|r&>I;UXx*LVS?r}|_meMhV zp$WkGsg-tzhE!OTtPe;L%RaJm^H;XpbtNr^z{ndyRCCv-s7nI!V9iL=UkO3a15pt&0z zK+mPix}ncl=eX*V=C1{)?i*Fz-Oj9=k79Jovft%7VQL(+H-)j?b!{yTsW%0sw5Sox zqrB(UQLDcmCcc!rA4furTUf%JeQpwZ_0Dls+BD7iB`R*$DOt+5sY)v5bIYGfR-GxR z)P~lZ6!zBgN}E%RsS0s9_(;gYlZ^B0>#IDHQQ)1Z+jZ93hWy&0Kejw~Kn^z3Y5`z$ zNx|vz(!DBB-PR(ObGJD((7h{p3R0T1{Zt=JZW;U-`049PS?0Apx8@$fkPh^$9mzGF zPHU1=j9m<7^jUEnQjoNqeR0V3gWe5J;rT}E*zKvAEm>YF$JHEU1#SXvtG7Okmo&O()+3=x`{W|?IOz(W=Ag}Up+mmF5*6)PmF zr5d@_s^4W&ibnWEB%XuPq>*@Ws^z4XpeZN>?(`ISW3Mh>HA$}eD&=&xz=+&Qh1hHq zp-N?YNbelQOM{xSZ9WS2$*J%9WaiOxkq9W9gdC+=<&}45ok-$wZ-^08gvQh>1su02 zAm=_jxz?9-16Y6@9qJ^P5)@RB?i4V5Gxw^Cd{}Xd zR4lsjn~8UJ5XHk(yjy4~2@N0&C%g_`%8N_7-0!cl?cU(@qSBI39#JV7Q0d`PncO~H z0lr1%8e2+2_7_G@X){_W$p^Hy+?bM<$SQYfD9$^G>T`}>8KZK26>(AMa??)_F`e2i zB|<8KhH_6cP>G|qa48v909Z*Jl6#F>8h1xr?UCI;wM~-q$stNh1dh)gLGkp5FKsi; z;YIYkWHyIdK|cZZNK!>;u}Q|trjxQD&Zg9mQh^%xEdc|XTXc+5oPHo{*0ws%thlxk zp@jC_{w&t{IwcVuG3M%ck)8($ZEc@R*;`Yf%13Cc^euq}MQcF-W8P0@{&hE{K zx##1Oo`by8^{0i><%AIWr3IV>wSlOeihrZJS6W|CYC8o?zOSDOhXOK~a(Ip_sO zUJeDR^2%EYINgl(tG?&Ky;rD;3pSU^!2{|}q^pqVbJCbDoDjWQdsi-Ll9VAk)P}%X zlkLYN(zW(wMRz3mD@Ir85S1weeR@YDUehW<9!i*$`c@WJg@qAebE+86EY{eOvzI+&e-x$k`hjN1$PgcuRK{&`-?|vREuYUOe5Som|FcME+?Wn zf45D0+qD1` zBXK$0v(Q!53x-yCSZ&7GOP(Ex-Pf)&(xfo>8>bbW^3juyU5EZVw2=XNf82A1S}=7wC5mz zYry-} z@eHdQw{ioWG|EblOI?zRj!p||?)j>6sgA>p;dYH zRld<{Iql$u9E7C-Cn`Q1ja4P&tg@)^QhkG}!(^ZCWx}RJb0v zX5eo`T0(N6y~L5%9+{?2Fk6)_HKiMY2yxwm9M4L8;W$FHOhB$`OoxZF)9FY!%(Du^ zY?9C*huml${HZ*?K*S^5IS>45Hro_c_XsD>U3HgTx7b-?liZ{u9fW#>`y*<9R0Pz`DW~{-L3cqq)UMbgUt-=1QJZLx6#w9}3wf&2(U^vya*|zI>Jj zJF3>=D{-L5gFZS^gsuL;Wg`O{dV6zK1nZ2)q@2lhDBM5+T?T6TA+;JtcC1RPMZ}O- zACkIZT+Mp-3TjihMk(&d>+#c_k{TrjGDXeoG7+wjVP=9JH&|( z!+tz@LD=OCNiL^wQwto_2gqxkD`syk9R76t_mUeC_mwLksGL%Uw4KQdPj2HaHj|yC za?iBY#R<60Ik_w)O3yIhc+)IZI1lpplY5$mxpO7#k_>+0XMVl9Ckb zK|2S*B}vEKrk7#KLN_O~Dexwj-X<-{F0z*tls2-~(0X&N7Kn(MbdMQo!*4y=kW_P3 zmOYHwJ639D(K0~Trjk~Afw2F zU7bjV7{XgqWRbK^?A=%}u;SVTeqr?hvf%+mF zI3VN`k5x=@^J2=AKHSvA_Ki#AvPv*5(s`ec7_S>w7PCa&DN)9{P~%Qn zfAeHt`iAPB*N3#?CaHLC302wAvu?$M;z8wC7M1jL^_K&swjuuj-P@{vU%LFRBkF}Z zg{9MYluA~hr6&i+rG2mJ4tsQDRE?YpGeiS!dyA4 zCof_E7KuFjv#``dM8l0H9EsBQ7ZCE&2~Qw*9{QO>dgRJU*%3{$b3mj+Ss>#$txnr! zkba`-Pb_lv^{eV{4lnU-FfWj;@ovpra`Z+mas%&dNF{1gI{G*yj{s?hQ)sqEs~{mPC8N-SGmD}G2v6}#IklWwP+q>uQ+kO(a%V8!2`qD_$dIgJ@CV< z5(gpL^QZMW>7goY9m!BR6yJMx>yIJUk}~q+>~)vQa;z(FuDXAPHp_are*UMtMHdK~YRKi>TU;Ac zGC@|q|RZaH#`uKwbb)_vy;r1yLD!x!^eC zsOA!^s;;d^cuu+DwZ~RmtXAlEdlkYnF(ligt~(PMk&w2?SHmgniOBFd>ME_CmXwtz z1gLJo1D7oF`=2dmC@8u_?oANKZL4kKl*>bD&m_1qK&35Nmi7|V=&DvZ4wUD1j8$!E z;e?euruQ6l2?mLX`5p7B#Ub+y+*tn>#nB>aW>^Wuq6J#Bo$Wg2GwR$$e`(*U1PH@*5{qdA<_W| zLOp&o+jzCWW#vj)aj>DeNlG)fCafK2It1NQdXa37#CU3$@?*Bp!b3?>NXNu8Q5l4; z-Ev=4vcOn5&Nm&koT8F1d|1efRh?@|P0951^mbFtyFfX3lO6@7*JenVzRiuJ;b*Sz zWiha|rL>^r?MO~fs;+M)gXg?JhY^&i$C--zfgR(Q!q0H6wAj{1MP({hMQ&UR)Hb$? zWToXT8`Xp*SQtpod3O^{OzA;okR3`qe(Q%&7@W`+(oYz_Mdys9Ej^` z>x5wDn9&Z@q-EbbN{aD}4pk;Ys(yQ1_N1&NZs}3!%iD95l%GK|6p#moE1xYRWIILD z_DN9HDVvk7p|o!)Cuu*i=bm+C+WeVsmq_TE!}Fao8xL)68k`NN^g`4K8TM6IY|6vT z0HCF8NWzCD72xvrSJG?B?G|1ZAYZPUhS<}0hMMhdDncE~S_B1mk)C<3ym(WF;|)ef z81Qgh&J?$0b=12$LSK%*sxs?4RN8^TN`dFjo38exNseJSv;?DSQI5FJPgQgel(A_% zNRabmEIR@!nNcHqsVMkP6!lk)Q4^hPtfeYRB|x8GJu5jS(HP|1NNcg9LU1(gy=qFq z&K5ANQ`L^uXuQ1Ke=;mcSi*9lgH6|*Hi!WFTiPmDtDjo+rsSoooDHLz9tUx(eW>n8 z+Aa23{50UDyNOPy$7*6hmSDzVl_g7gzzJH3=#T&>;>UeUwRe(0(N@EEy+pahiZ*O{ z*U{+(k`k-~k`4&?#XR{sMtV+zea50b8(rdJT6M2QNmfFNcMfBrt0T%i*onAl){K;^ zu+uQNFqikGrIe?UA7nQlp1oX}c*h!P95bAh&SQ}a+%^OoWW}X{oME6;tc-YgR66Mt z!wQofmRut$SaBI7clD{Y>PbG4QRk2jY9nz5RA<;ojKZ zl+Cq9*m;tX&#$Vcx@ya8)LOpPq?(G$KIr97IE3X$Y#@>bax!oSt2J1(M&x#91PlT^ zaaRWk8cKMrWNqZSqHT_?MZV+N@+afK`0Dr}7b+%lq*%!Ee6g7}SP}HI(_Yk!?}Gbo z;irjTrjm2$mecUPbr8Aet2K&Dm{DOE%8dHhaVdLpLeg=_{Qm$QbykJDs?)-~P{c`0 zu1r=#*2Y{$*JBq3*NaN)f;!{Axw}(s4lJ~krAQxC0B0t;vSLW&SsP_5 zgUv*PljBiAE?v6fxqb1_>h==aKko8+UO@yh>>ZC1+-N z^2QJ0t{kyZXJ$2Ify=};ZEi|T2+5K;dTkB4130U@g&YsGYAq!rQ(P_aZid?lsq;7b zBzCG8ZL#0i?$f&n>6^g35-`8QncOVU>jB{FEYyQr*DeAZ*%*yweo z1*Iz^;DUFI*Itqlk)EmSTn(DLfm%CH*sWTk4xED)9qFgrU|@$^QWSS?=hTc3im5x* zqRzlvc3`%a$=sCWs{^M~?5@A!_=jrH77aNDZ5Zo~TRq#5TaaKzT$bXX1a3Qy3BUx3>SMwC4xeV$)XQzAQf|pdYQt z_+2ZRyq*G%s=r1;h*Pi@jl-BJON4w}hCV9q5p~j2ay@b805y?Hu8)w6&7oA=JgTMM@h_)Cf-BZbelWTYM7XWor!ufPhe}W5TWeDilVa zFfx)zX}f$!?lKTNSyCT-`Y2C; z_EpmV01k9ioetKo(e|aLG9L3eQD?N0`wH;~zvInSye!plENQ&hH7&iz^!}l?+tWD_ z9Ni^{8&2jQLVOA8JH2&twRY34=ymCB804`9D>7wDxh+0%Eo=BE2b{us~$7Kmn45UyU@r?s4fjWZ=EYwCXKv={3=pHcDDYL>%XPj_QAn*DNW%W{Mztf#UL zAn!R&c~paf@LB5 z>pjw2x9csr4f(W1NJCDv-)e=p2f+$RP~GAH@2s)3hIu>Sl<4y&deX`i;*z9=4XzaJ z!9B;PB9s1gV^+qK8K)dB6TKuQTe3=NPLXyp*hj);PNfCMoJk8w2?3r?1_pJ4nWmb?xA+PG@pQPHmk0 z`L8!qQIXk+y|gLe{7=sJ=aQVbh^+?koTn@2%y(c{LQ7&h+IvT83se@NiEBy_KFhJK#=DA>zy)a!6?nzNU!UOGNgHf>h{i zq&RW`JoBFOQ#}_7UCA<27D5_!8QmdnoE^EwKV(Q9-ZamzVnl@{3uqSGL#a_t+$a)9 zQ~f&EuNd4c;okQgqcNiwS<8yibswJ}3JF)LqAx7G`VgJqhk*;vT#?s4(^E-#JVcV( zkg^v&>>T$HY85eUqYfcKBmxRgG6*A`c=_Y^9*#ELPMqOXOx?AM0HJG6m~~meRyKs= zuYL_E({bD^u+~xlX(MqQjYIU*jYVj1T^CvtjY9FBT(t+4ivJgwPbTJ+7m%K&{27iA@6{Y@(6_o|5Umx8ABeZE4< zyEd-MNGm+Y)b|iQSvA#qP6NkJ6~I?y<_J<<lL8BZgWER=di zy=;+E#caSjrMRVY-hM7N_IJQyz@UL5(@yLADWa&gG zS!{@i18*&qw18EBPW*HBimvV(Tev)q&yy|@?d4VukWw17Sr@%PGNi3(AQc^s?l}Jd zGnIK6ZDe$JNz@U1H^QfEjGK%4wiA|kGF*prl!3HHd7yCaS5Y5Ur=v!S+Mj^h%Zc`pasan8$Xb{>FZnf2FJoy&J8oj1F(rQQc1MoNA(4Dz`+~fZRBMj$DvA{tDXFqBB8G7_F77 zrqqm5y{H3d0~8IJ$_WY`#N#zo_@a%pB{t~kB}tBgv(%IKsTqvYR#NO%)=B#wlVg0-X*N4&l^WknHrAk&DL{gxkbXS#tTV1G-X8^sga?~|KvF{CGD!+P z1P`2wxHx?aOxt3@*VCjMLl)5N8l?J&)z0~G^N5PJG8E;sAtVOeBhfh?tk)||(<_=jSm^GU zg{M<(VG^9Y%9`VsM<>K@^O%O>$!RFhFs+y>&v~dP9UE`nL}D9J0_xThI-X|)czY_u zR-=Z!KMoFxyUDjifY7nIXp+!Vt~Sx;>0VD#qH*lyP<}W^VV)Yil&H8{ofz*2B%e!| z@I0~dSE-GEX4%CD_i#3FkpUVgA)-o}n)oR_QhM{GymCsFqaiOOc5~832YxAU2YUgd zoJ@77l+JUsC&d2%*lTwhBct9AYN7CEAoKN#mY0%Fk8bGWy?NlEn;1fTOf2?nusLuSV^zSDkAJL+d`S`})u5Iz)a zDD^oCU*1u!bh$Q@+)8}vMZ#pOjMe4&a#s859Mo1$ej$_4a;J!D0mP6oo}Q{@xAO&L z0yh;Xlh&Q1I@=3Lb2vQHfy%aukj5$Sts z`Qi+j68Kv!&d+a~&S^69Y=rIAcMGeLz_+}O(QT!nf~I-rpRXew0IE+%5~FfPPxdb3gZm*; zOJd63LV`Acq^}`a=Z>|E5<%lqCNV>5Xgbmq;abQi7zx4f_0;D_L~2`uden@eKqR9* z$M94l0)pEsK_NLDx?~QOKG3ASDF{~dq=n??)m@lm&U~pygOu-)yw>$`XE_Lz;U2sy zyxQC;xXP4+sH=NU(uCO_$Xe5tL1Q7xC#@SAgT2ZCd zklWshx%YTew1k`xd+GUIjPw6^FyanqQurT#_tm*(o;93jx^%Hv5JiVgtxIrScX+*i#_bd;vprMb+7B#wCR zucZD%<zohcCx)sR4;0K`w;=e8NXj_bbiT*SQvrqUtnpUX}jD&rhK=cbEwZ>BUnaITvs3u&s!rcAufPP?GQpi9r&OqDT172=ckQ(-ksf$I7vwx z`e9Y$WaXbvTv=i8kPm$qGJdwnAzZtT!%@B-2R+7p)r=0^!P*xJa0wv%-QE2vN5Vz+ z+LG|F&_P9&^UJ&h9MpG*?W^1uQO}#}JdaLw(F$f#e3oX7;>_I+)wVMlI@fVkiIpZJ zs(7;ccQ_Ub(w>M>8+MMl!Q@Rf>#izI*N_FGPMeKuF1X9nTxs_dr;8z7juL$oC(=DU zDn9gWxe5f6%_NL%<&65Nt>%**Eu}n?IUr{|ySejv$`f68b@Rn3dqkvnnkLxCPE=u-3cAuvr5WP78U}5QQORN z@%z+|Q~>0tXKBJ=AbjSq$jx6vQqjo?BLjC%2gYjeO{M^Jzbg#TJqQhIL1IYrYF>tHdn}l>cwM{KXH_K8n0>s)e%7>DUhSyd#R}% zp+c5i3EZKzVL8C>08_2)mc7llt8$1_%PIj}z7I-fE{0p|`Rqbkl5Wd!rxLKB7M9xd&Pdu5%c<`;t(v2YoJo69%GGab)T-}r zw|k2Gw6s!{LcvHtPcKUZ^P_;yMvK9D?Z;D!lRD_{)B=vpn-UK$gnA>F-Kd_aZGEeW zFE0m{Tuv3!nCLlr@m{8;nn@gLJEd%d%t}E@H!BGkJC0O+wAm?0O``J4NKs3XTHLP; zI88cCYtu+lLPk1wQ*5^zV!?Y#Rq3ggl8;#{=U!~zgQhFPBj|M{1zFm1d3<$wc_29* zz9uPoOv+!W&}2|{)w zI0))eeRX_sku6KQ&zRFscCH=DTdT^!C!kkcda8`OvO}sl>Pl&;jmfi@PTylP6keFx zUO640_&lkC;zDOiZ2CnmEk_;a6#T*iQ`aXT8f9=Qe9aH#^og^YDcQRdDvXb zi$4hOZ?7+}ub^B;OP=7i+mFd&BcUa@?8pUU3H19_07}R{Ij?g?6)ZfQ`RmEbI;Kp8 zI_Y*o-#n9-Us{L&U;&fdDhV-bF5v|sO6At4+L9;*;FJP4C<9O#dsDk|Nl@<<=H*)^ z(R_czXumiMHpG@tm5Apn3hT~|Fr^#RMnO(Xp!!0MONQgxo7#V|N%`wunqOsqgCQ;y zsV*pur=LzkonpC~HCB$L@>X@_SkoPGkmDZf&s(WZRyUtTDoRIHZX=lH2R`au#sn!B zXI7YznsGl-bFxy_fehZibC%^!nKw-a;-$?wJB6;?bZKjl{^AmQMpyJ&PHs>wG z1LMmd9y{x25?E#VQk;&rS{JW@K?@*n}+&AA8ak;)uyg!(a`$@8_Og2AX!g%P*BSsOh_fv6-4i zEVzw{V?CQmLO@$R>PhHMPknRlu#V$19%*S>Qi4jk=LbDH*G5}hiyuiPz!m3dj)b>` zk`s~5Wk;S*fv$blNn3K>4<*h@z{W=6d(Vw}+3Cj7#TB*DRbCamyh=8mgcSUo>LGVp z#r|MI(g9jik~8(A{q;7zB<)*d0<|ch9`JlB6Lu0C)H2)J0>h2&NgV-5=kprzb49bd z387+%8WLNIa1PEwa8fa!L#1@j2~^p$T9CtQalbK+{{Up;V`5YWc@xXP*D^bSqGqK| z1Bp$e9p@AdK|k<0yFiL@u*_DoilTJU?6$ybn`s^FB)pl{gKrWHz?sNDfZId>lM%8cvoj|{vrCRA4~1D+e7pt zwN0pwLj%-BaYvKeiep!56gGgT3<)X;9MnN`nFG4JgM*T-$SjqZNkZG&`eZlhsN(>V zLCN^5*wDDq&8k$bl;;!eZ^x54*BrVLZ^YQPl zq2ld^Gzrp}ZbxjD$SP0=BeUm>daIjtR6^tELu_*kLc+GBp~a#ZfvE*CO2Iy$obWnQVlz>wMc;D8jj?!n#{Sc8Jqxb}?N7S5gQd=j(Bbp!LgPttC6Qlo?Z(W;-Ny zrA5^3!o431ch?@aOToUGHbpeAXYNj@A$uK7w<*Bx-PWZ16)xvgme@#BaGE0-!a#W$ z$B$D{Jtetu@2c$qO6^{fyazngr-CgrD&?pxDSNZHOMrn53Udf?z~%I+kNoGJAYYJ|fkRh!d8FhINj>$^n*JYa za*WwfX--RF0!)M_VhMSFRB#-U*uqICyEV?b+50q&cY1!sb#CDU-Dg7*+XrNXWgxhK zu48sHob)y4YWv{o!50)O;u1%?v&sri*vTZ7<35gY^H)o7{`EROh1YWI*O_pg^Bp^v z;=kEA897RUUr?V*2X8-%HO+iTLRWO0wj<#RjM)nrBw-jNf!)r!8;1ItHL3)dQ0-Rj zTV~XDt8)@Uj;s@HkKq+l1 zIYLTRoS$DVUZYjSG?S$!7RcBp$56@t048e2;&hu!8dBqLeoJgzWnUo(QHaXiX&CL6 zu4fo4A3ayGTG^& zMN*mz1;C&{@lUj3ulPEnP~GkJt7M4wh%jwMMmsi^Qp!uJ11nk2JcG{_7^tRB3ll`! z+mQ58I^gO85<3(!*eY4cIM0vAO*~GR!qxgW+Dp zCm(OKi*Ma$GU^SHc&RCrwo$TjfI#lbDh)j;56Dw##uTG~dVs8R`6^p?zT5BINt1Q7 zyV^y1;q@nq0#fc1f=b6vTUPfuDNc6GVhX+D%pHjDC*D=w2 zd9+wB*5)lY#>pinJM9qL;XOAru#>x}-Q89kJ7d;OK`%<7sIo=AON_SjYYJ`F!oH@j z*%CYaL9Tn#y2nfe#!;TsFk+%R$dI54h)78rv7Lt*Dd>9DuVB@hQAusTeYQkxDI~7q zjQ5_TgWhrBR>e5k&6YBe)4D+o$%umLN>bZuY1MTch5Z*e5@YeH2Ta+cbO7PzT7JxFy)C+4d| zS_hY*FIfX`n5eJSfmL^tIdO5NAt^y7&eGOYG3f^~Z~(_rYTecBrCK{sCB+n{-1h+o zm_Cn%WrLWq*%#i9AG!phfOCl_2QBpF!s6oSu zP$vZXsvqR{^-V<$y~uMm+29?#f!d4@W=X4RGDd&I);6MDWwdrnQm_F~86DN>Oeszj zsVOPPBc65X4@i|LDOl<1tz-tUu#y}-M};3HlVy9xmlT~O#u5P&04KcqCb{clh38h4EP#@d z5`e4^3>xU}GURA=Elq_HFkp`EM!CttrLAZP>YikB^>RKqC+Dm)bw@@rz=;Y>J0+4t zgefh*9EKJGQVId-$bU|CD6zO>zJ)WjrIWvS1bSG;ay#mxx8LrO8fF?~2P4G=EVSy1 zlGrCCARb5=>Jxx^)7(xY++r*PY>wePvRqit?oD9d2-Z>G!Ft&}7Z3}9O58rEvQ_B# z9M(A38@1td`Dk%nn=;}A1L%-TobmAk?9Z;MCV1nhAt0tUo3xduB`SBdbC~sJnl+~w zHI}}D&7$`zD=-^U9P>DADWs`;(~aAXIb)VReyZw@br@}CKE~M=p9R}U()T8DgYJmP z2Ot80{{H}$mvN~@d_IuQ(xA+yPDd<^(`N!C2kf_ndI3Ii(y$Ina?s>{N_gVh7WWRW zVXy|r86c0_Ryet_DDrc1R8oa2X~Grt-0}@f?C44?)}@&(IlT%b4r*)#9B0CzPavtF zbA@9*+S1L&Og7fkP0i;S+@e9}*A;}G)@r%nwjn$h%=eCi08@iXdns5+C`NJLgH=>* zXQ-njtq#W=@-WaH-W9y@A5;UDrLc|P31T)>G3!y=^Hrgh65!cv>twt*X*q5s=Fq7P z5~W}z@7j*Mx*u3IMaf7^g@l}poElqs)_RXrmKeU?mnEcn47G-WQlZf8P7*#ZyGT~k zt*oW=sS57|Oh z?DeeOj_#?vE-HhKna?RI_8$6=x!Mer4@tcCN7wZ}zbUUxH1S%TaUdnt;W^JTd-_o8 zfwX!%kM#cla%q*@vutbaqH{KEDVI4fTOBUPacLuP2{_rG9~yFkr<4+o$6`RL!G+9G zQi94;+>&|LTz=|35iQkY_FSty=)9tf%GAV#hW@6s1gn`|dX!1>O{^jixMV zsFL##_AEBALUMW%I@NNSHwUoO(wBsD8BsX)SE%vSv~Ovmgfwuh1C#3~!nKZCjR?{< z5s-3roOouWv8G$zwZLt;3okO($B^a#JkBxCl}3r%l1@mZit~lIR+qEt&OUm^eS*k< z5b{zG09SU^0)BdWY=)7C(yh2B(kKHs<;-)cfJl^->`L>V;G>_I=DaRL{L&mz$URG* z9XXs;;K#M&9bMY4FAwetSqWSOBN+8_su`&6$U##v z7V!vCQn{U{9rbwXx4Ug8!mkfyw1aYVVJPxxQb2uWT!M;-?(Y<|qymC+ zQU`Y`ZJg?pCC#V3 zd3W9$ssqzgG$v@+<4Q|v{NW=fJvn;og7u4GR##L)$wMOc_hfV73BK@FYI_<^C zg~{M{jvmcBU`XmS>*Zc%v-w4uMGUpDM`TPm1e%!PX5Ms_J`Y#s$#w)>OxnmbpxCC?z_kwx|6!S z&r!)Nxgwu~k4=IYTX9s_oeEDy0zu`Hzv-q8UFM(-aQ zt&QUHNetYbUoL)^O4aVQ(Q3=H-cCEkT3M5JTiTK=H6F>b4&0N_(nnUp2k40kC%DuN zcRP+rGMrbfRq0Y>Jjih_dPAuuvX)fcg$B7MF1xt|cB#e=Jt5Zyn{@@rsZ&@nQSc%m zr5tzl`_&jj(h7I>=OEI^>ss5~SD(F9+@#AhY6wcgO17)(apPC)JxO7?Xq!K|mx#!c z#6&Rkb+2lYuue$!{pz5aY`CzTsAs9K4##zguaJ_Jsbgse85r=ch)-(Zjl16^t8kMI zE;+huN085?I+~8lnGujPEx$yQ%=}~SR3**FAx|v@U2<`n!-;sd8{F!4^(q<2tmQX$ zM#!hZBfVW9Pq#w0Mv1mWXWw~m=K*1O019eHWJ;2xDJgAvIT^?VkDi;t9Y{*BrG*ej zKMt6uBshYS;?Or>fRcHf{{Y)mQ)*U6nlEk*aUV-t_;V{nT<+{zXR|5Cqd4fwTnb7v z&$#kGH8koA^@+z^Lsyt`Qce)0t2wG_;Q~Z1$u6w8l_Ppd?gzusOo0AQ<~FY<1HU4p2xGGu3Q~r8 z^7#+1)mTy%9o*Z%BoJ}o%fI5qVLjGghtTYwssfRZ(G+qAEM%IvJeYW;WZ|a}6LHi| zG}X548Ow98EgO=_Jrtli`wdeOrZ(D2Rq0^z3H8&2`(oL)GV&SPR(B~mIU~f@*mFEw ziSrhYjN&%F;q}_)`Lyc@vl@A^f{>sy>d$plcWd31*GgKrHH>5dRmxdONJ%pm(HMGwpE!!eGgzJhwWK+gbjCyqj&o1!yoI8*mTQ&oFB|l9Zm}V3JgY6E0FN zt6@(s`xzxE0Atao8wdjR4MgExsZM+iG^WpV#`N3e?dqZ%Jt|G7EcYc{*_!NES#6-b z%36NA7#_-`X3=`0;ovWnW{Ba2D0n492d#N(47p1tAdz&S# z-3V`*y`O@*rK*!ujHQErD3sp#jRNMfu7g5{6rI4=0VQSr!=aA+A9Wmei zJSuuMmFIedD{GFD zFrSR_r#)4pZmU}_MT%T3wi_*EdR)5l`93;~ZN-*!(Q-lZ$+j`4H+%$XL?Z*Mj}?4|tETj>p=~NawiLM7+7PF4iW}2+=YrCRY>v+x z{;8e0@g3bOrdej!1|H0RlNL|n9J#7d5SeQ^Bat{g)Y%H)g%N(gn zID2++l%=_m+({dWN)}QFfg{;k%6TWz5sV@=+_gQ%_Kwbcl@@}+`y~7ldx@zAjawGs88wAp4NedAI!^#qdJOtwi%`;>Ff81Ah0 zzb5gN9~MKc+Jf_>^+T7NB*!C5ZcCvn9MZA8`U(T8agIloTslw6_lVj`V>4c~ST1O6 zsYqq!RFI|Pyo1nns^)H%vfnQ2U6WPY+YaSxL!+vXGmmMaPYtCq*%I$o)>E8?Ixs5u z@;q;YImR>LlO0#(SHzuUU3zqDGb(xT;ad^NI6U_A=gORYRDt!q(Iluk;Oj{g7}cfDZSEGkk7OK}`HKV8qIJ2k`0GF{reYS~Itxk*f794EgS zr~9N{9?G*fXq$fxJpr@k?xnNL5zjoUI(|eS!4%URPS<))CzxsL+tK2%Hlc?;sFbI{ zIp{r=YU%#~E-pOjoj&z}nRW;K<-a%c*;eiH8u1ArfPPA^lf!lw3(uR?%}8lKqCCq4 z?N{HXR&?#2Y{!^|s2_W?SEi&eJ3olkv1Xc7jT|ET9JLo5IG3p;s!iWgtlZj+ma_k#U&#=37a|0qN?ei$4vlcV^mI0X>S6prb+8%(=YToFR+m{xz zJP@Y)h6g|UYf89PYOp`&Dzd3TDmxOnN;^l64@$SQl4{vl<%@KP7PoO?e{8mjikm=6 zPCPwy$qMOpwYsxwxXg$g0ZI+8YC-s_ajfRs6)7=q8g2If0KK@|+0Hxb9`>{%Z6@%! zQo{&qbBIg85^_0Wqics|kbA}$yhY+9HTLl}mDz;>j?oXFn!H`OiNs6$As3Blc9?`C zZ>J!P^Y9p@FyrZKoX<9kW1JKQGN}XrJbh;!)iaI4+cWL6AlToG)4&FulJkKp@yCr> zWS>ZhG`mGcg-UWjlH`>-=m{I%UiFem<&(~(7S$?UihIaOQ*EuFtoI*JBkon0&jBs+ z0-kO(eTh94C0%@Z^{p2jJpPooy>DXEYLL=$djRefuM_K|#VK;gjMbE+l9%04Ks?9; z2DO0WK(@rm4W9%!M=zG9_Lp>Z=HuDS(}pAATT&42Mtl3|uJv%UTcy0!ro$D)N5T?a zSy57ok380U8gyvsp^Y~?yJ-5I-f&6eaV21%kkTj7=OJCYjwvcRR`rrpM~+Xft{Yy9 zgsAPiakj&4PM|rp4V5c#9Y3dyI3q-9wF2NoCG8%Pdmt1Ku>4ig6(*?3#YOT|x^_d2 zT;Vp})drnHu%u@R2cAA!^Qag$yMxi*Q3Wc<&OyK(emc4#X=`KvnQ;3C5PcOmrcgjv zaL@bcz-h}|_Yft^Y1fmGvY73al=tl!`?Z?Wx*p<3G@ZQG=|&vRJINXFp&`D@nHs?I$01fO=M&&KuxFra0c78gH@e0c~ zNm$y{mRXUO)K}YXY*{hUouqP7PCC}VO_452$2?^r`^knBh{~N2*Ax^i$zIiU$7xqK zr%G3(?`Tp8TbAd_N3j)Bc|BemyE z>&YqeX6;iFgoDkvTZrfEteYPZ$`%E#a&V79UTO!;n&QodQ=Od<$rh-u4c}57rAnGh zL$79edpS}^ebShs@|l|Jgy3bf_$t!(t;AK3u?pZ*x6%QyD_PO}L3EX>6#Rjaxd2vA z4AFnJ6@nmLN^mWbi5~nSnM)y9 z<`3Sfj|p_J4+;?JssKK4ym2*-<2w;}z1H zuHQcOr=?n8gm$kfB_&4yV?Tzf@xkp>=-%?101O|hXPsf0SP3A}zRup{l~&bok5S+SsxooV1)9riH&aNe+tSnb9^Dc0 zMn|QLej3+a@|a6)sArfw@NxGl&{qd8%JkPRGip97uPfla-R9KUyGPo2kb~fR z>KrWxm00b;GM246frijj6D6_;9R}0>>Xd8LA$k()89)%Fv`OzCl_bzQHT@A5;)yRM z#7l5z2f!c0OEtMmnil$6Z7JCu3+8#89<_XN*o?Psl^pAG)3N(wvgsWIpCz7SnWU)G zaf){f%wvwbK{)I956?)B*(bJ9QBcVMo~ERFX3Z{ei5AgsRI81}^v90EQ@gZy{1hv| zC~n8CKM}%cx_elFX$IDkp>$Vh4^GV2qokT1mz=tyMn6F+`RefE7Z0o&23DViV!E#B z=N8iB#d>y$KI>6iS{N&iJy5W0Z{{elbpQ_o_{`SfPKR){?YT0 z21!3RvbCHxBG~1<7-~EfE3pz>TGTQyo|L7%Kj#Wh=Yo|1@JBTti`n-mvL&Y`IN?wL zHga)Y2NK(+Zrn6x$)(j`dj8dwS4lD5jzqN~z3O#HUrdDH8suu&d=xW!I%C8V3bWjL zk5w*D4&<$#-R2x|2<>TEQQNO?pL0Zk+_RX*h0xaOUn_81)*qcpECsX|w8U{K@Yz zC5J8Sp>bmN&jdWaMJ=9KBAd0{oy|Y3?v}aBVQ+T9=FDX6N>Z_u?MHS;UsY!a?h_;l05*NgT(0Ni?*p zV-G`>c!H_yw6VREl9IIpkgSe;hzH`XXUTUajY!jsCBmh_Ty+DnNq7{vo?UU^dVF-b zy&)OoWVDh`B;@t01ButIBYM9(Cr(=Y)kHGm@(h(f+bgri(T+*MAoK9?rYKGjgsJ0_ z2qbjJI?@p-?nsVZZ8Ef_zEkj!-pAV5zeF4oIn>JX+pFPk4#wj$+7l{WYIq&vX_`jiK)>G}8M}fOjq%Ow#Fp^460*7D0U9t2tiwe5v_eWxv zJnC{v1d^o;L6P;p9dT{>DOH|IRgz0;z{YvkVf_o>%bJ5uFU}e+H9B&8KQ}2O^Mst? zRpskf@n(tJI`Vn^==bdv{{YOdh2_8qe<{WfjGZ@CZXl=X3qbem%4Jx&69I!h9{`!P)`U_Ix!-n&VZHY1(WyPl(f)ub6enM*U#)?6` z)-}1LS$EKBrw~!;6oj6i7kz0)mqM}}O7@OKxBuuik!Op4DkpRMy;RqSWp_B4gqo-gY2|a@Fp`K?0`g^nDvPdo-UsDOdSAOnw0M_vBur(#Z+i5K>EM){CO)q*>N5W87cqgS-+le0I z@ZZiHE}e{$qqS~d zXxu*282D<=K5EkC#v{%JJ#B0ct|3Gkbh?lrID7eE)Oo_#Z#|e=(s|~oe9<;b?3!v7 z`crXj_T@P0(4~;IdI?AwB>Mb5I$1YH8)PQuKWc5r&N^94l&qHAa~}iLaZbD%VoZte zwQr7Il_D`^kWxMxh}tlE9F9i1V~UndH+A6!=Y-a6O>4N_v@8~{NP!tSnwg0p$tzwk zKud&Tx@QETXEdbu9CY-1T2LGo#(Cs^j7T^*<;t{)EHa29ozzY}v`K=&Iogm>k`IMHSm4CG%83>=y_Lz3=V!G1 z1Y~nslb-KoL<(C2a@*!saf+Mpbglj&TAC`!3vjjvB32Mc0QVEj1M98ut?Z=wEem&( zZmzsrm2t3H&C!^vT1&`dVxDmWD@=3{J4Fl-d_Vk)%oDp66C3EHxi5=P*CRmXb9OKoZ^ znj&9K(Z6&bN-i16m;;I(u|4Hq2%hpusmzw+7|HfCyFE;&5m6Wvd=R$CPsvCZsIMkS z3o#1EcF#m6x40X1NonT};;){YUQ(Kzq;=1Kbz;{CT6>W90`9}{q&oCSYI-wWvQpYH zzXxqzTsZQ7ldrV1x|mD1wjngjvK1xt#YAMfkfze2zDJP)xym{~enJQsTxSoX)Mpjj z8dpiLQ29P;Z6M9k+Qq_hERvaS#woLDJ4MgIjROAw6K^VuFgU2M zO7mFJ8&GH!<0@OEa|p*g)W3+F6}D(-El+m&ZJFl}DW5mD-aO@P?L7Ab@IW0+E%HBl zG&{^IoY|3tICpnewK{zk$!w3Gq4idHr>qmH=cFAmr)>?unD*6L+Sudh-|$v^0Q9TA zaZ!rk;kUS_WwM4`?AUeSj(7@u9Mpd9tAZmhu$d$!pj1+qIUkyy?h-;(wQEv{PUMc@ zGfXp_Q;{Vve$<2#Pla$~`(2}A^>gVy* zut$828fqs%+IStJBG{tdwWaztnu9Jv*tVGoRHtUB0+qd#^GZO;KA=u2yVrUuHjlnd z(-VwW-hk#&DkIC->J&1S0C^5Xb?03nYrffT7Ck=XonsG7U-W2{+iQ~mNNMICC1f_A z9$dd=ileyktLz%rUQEB~77K76io+>an~3UlX-*ckG&v_HopxlywBdxMzL`>76CDI8 zZa8ocRp*uu`>HE*ZRk@`vSXNWq%ApCHjbRWT9D5!2HaBA2F#CX!KnT0_Ose9HH=3` zG3>5Mu4wK;(|5YLVwC|>R^nPGYLv26GCQlGxCO%ReOh|pn{#qeaD!#{Q35MntFj+f z(3C4Z2Q!apu4!0OpwD$hK?n&49eP(>c|Yov>8lLU9k~gUcCj@IGpwDZ3;0`#ySah$ z*4kWqn@qTIqc^r!9AV38=58TcTZ&P5H3{2}bkG_;apm;WiD^QINEU5e2=f zSHMW1n(aD}$ zcqyyuwk2($!?`|^oXGTu_EZkwwp?G;kW|}+DR3P3nx1Od^BC=%c?v-El0tyo2;_5B ztg>8l4lLs+>FrHdGT@v`iy&`CWr_0}N%R?zpn;t7%{gib%asDz6@H3B4$?dFtQtXh zY&U+mrKdRwj^>r>Ci@81XHm^PfLFKbgOzhG=<0kUvA99NlOA>W3sthqmbeqc zZK3r`d8ZTyRHZ2>`SVr|rc##r+VfI_s_S7jB+phA1m}x&3 zX;TgmTxDD4zjS6gdw6#iWH#f8$lj5=u6`=V6HZ05H{j^4Qx3}mi5i~O1(@;TMxM5s zVm2_^(~l2bM>R~wPV}TB(?|>2*xnCzYEh`TnR3@{Dm3jer)|<@IA4)E41JER-lUV? z?WjJXhuH;}94jhFAxP>^uDw+of#<0^q6K)8+NB{!v?Fj%GDm-_l~mDQ>?I*>toFg| z@9zV5O13UU2|$iVAPwDfRS+&JLKe|Z3*}e?!ByqvlTMM_gwgzW_LIXytfhpM7l#m19{ z+d|3a4hG>~qe?M2;~I8R{7en16}iO?$V%KtFh8etM}w|8qb><8@=etU3FXZ=2Olt} z{wO|_+o3jEKcla|pHB*ovJ~EfxIKe`c0d_D`%QTn+is6i97PLs18H_;#Y;xw>rJIf zDbCPUw;w%pTUyfp0I95Y%`rKc@nG50*|b_t)vS&~KCV^Hd_GIQc{M~JhZ=7ix+L!$ z>i5&O+nZLjUXuymFp`Ksiz#9OwflHwWzXCgYNkFEIXvDdN7Qu{#SlB^(x$>f|K zpFMhW#~*Id#cy|KGrI9>SIP~5F*#`&85lizQ)SI*Zd;oa5)0|w>rU~WRO>Nh>zP~D zRr&t_Dg(IqQ$_a(ojH5bkQ`YX`jfa!(l5*iW9V`53L@a>>Tu}U?fR(E;rdJ zMW&C2KBk`k0B<^8%F=$P*`%GMBqpZ2Zj(Dx%T#`y7;G*m;VJ>)ZDVy(wk`%0ZV+Ok;3S1aBz~>$HHk2XB4XX>OE360nw(kOA-HGJagsjjZe;#zKPDwE@4Ean22I7vRQ|WVO`C z9h0a_YEw!nacLM!i}6U$%}}l}LM?FSezduIy4$A2u> zRO8PFEO~s0OQQN~hvQSD7T1bftDo<UY&7rFum(IM$_Ms?eOW#)mbhj!lfld;O*&J98v9dwiE#z>a8m+ zDgCCfk_o})I#!p`8%a{ZB=`){hY17GPDt*guJ$hi;=_Qa>qT?A+)*aJ<4V-hG23k! z=t${aTuZ4^2WFK81BD9Mrncj=NeMq?%+|GnrG)@N9I`sqay4b-w{njmwV^;Mv*XX5 zZEtybB?-art!@>c(G|@chI}j7bPa{JfFr8Av02rKn97xeB&T`LTvn0Lsn9niSmj%t zN;hx9az}M*N=7gRLoF+_TEI}s&8F0YTos z7yY#X9`ei01TP1WrcGkgXGdR>#t0A=6iDc4?O7X@*nAK=Q%<2vtJ4>xb|fXp4`)8l z`)VX@jiZwzIFCiNxKyA}dUWN|ry2`U-E_LGx~ET15pH(buC6<)M&yIAWMktM14>of zl7J9-_f(rqy4bO(D0*UW<};D#^85A6KFheMq(v@T!05T84_0&4fwG^BVUEU+7N|xJD97qWCH)ED6_>~ouI3zmN9(BWO z;#cVeM?%AYWzW93jIFeVHsL(L+B`W|R$jk6aQ^)rDMI%_IPoMJY$&M-LIP5fy~+a^0G{*f z@2MrF&rJvf^{BiwqYb#Tg`66bTApdAQlgTP&!4Wh#^~piN}pV1ol7+;XymO&+sdP^ zEGyMg-Y6llt0bi>Jkpcw$>8p#7UU`nq-HiuIk?Y4S z($rihT;?ux`AU^0LxtB}bE4ec%%19w#Pp)ZCBm)k=hEZ{ww_=q&`=Y!r1kKsVsu0M zNfZRBWEb(UsE?^~BiT&cR&QmR*zsu_P~)RG^v|QqCY>QI-qQ`NAOqbK z*-ODu>w-C)*IQ|#u;x})2|c0#DIgDDPl}!`D+Vc6)R0$<9(ep7%4i22dQ*+5z{3h} zv)qz%ob;|o!J}J=3{{hiI!}2|iS_(c^BHF<#zDq2ie-vP3E70_<)^s8D$d1q9P{5= zLD@!?8}ANwwi)R3Qr}=sJBa||mc?-|`8Qf0$^x3cx`3>AWS_xW9cj51nT$G;a>Iw0 z?M-a5WzQzZT3S?0Yw;i}mm-1w`sj)%+DRK{0*M7ET5_P0a6Lk^9STA8j&oYxJ)#<0 zXaJOgPsLl?3Lzy%xpH?**RD+$bZ&z9805;-53CC6@1bb>&TDHcW_!C4I%>;A@>wus z{m;K#t8+&Ce2_**W^1Xwg;V?W)F|sidzqgwg%u6hFr{=I{VR)A58`Pac`GY77x>X| zvOtwTj5@V$OoqenEKW|+ryAaQZSm#t*D_u^1ZrFJN$B0uSV&hq4fS~Glm7q*Z8#-A z*0`sUKj6)J{{W_Hhr3}qg7k*TQBBTPTt8j)Ltjhlc;Ss=lviiY`Yxv?e7R#cbj@DB z3Q))>eJKSewB?LvttCgKq@`I2Bm<8MRD~e{MUbFCASi>&*IryXm7e|ZS=>2!E4pg3 zq?5NyCq?xLAiB^fWzN+>NJk)~B$LS}?q-t=q+tbMqa*|< z^3NmBJ#owDp_jJqB^gloIj5IFyQ$*l=}Z?}WSxP`f4-Tr zl!Jge^C#GA7OmMOx1kz(%ImXX$W(X5rI*=tD%w!ul&mOv#@cAQ-EM4LX3UQ|V^St5 zX_D$5J*18JDhoYGBy{Oc`e3~MotYc9lWS?SySxItRCeSZOUhcC=2TVVU6bY%WhHEn zyu7TXBLHL(jD5~kn8c+{VER3R$xb=@Yr^@B$C8e64|h7>30oPMrQi=YSSJ}Eec|h_ zHt5x^hL*@vhXZH|Nd))ut3S!rriTz>I^tM3jQhj3BVj2Vf$tv`Rm|*APSb=Elk;?| zYstY8r0Zz$pW1O1`~o?JW022wYkec8XPfLqw_l_|l{Op~*B%?o{RxMZ8DB512{>1) zJ=If9OKh(Wv^Qs8 z9q>ZCV~BUp7Nr8OH&92bDj4~*T~n!|#&b+r(upmFYPP}jNK;XegtUXW1OxyH$EzIc($h5Yvzt(oR>~&&%0h}; zWe7mX2m=XDdi1F5f}O+A3FnVSraFnFwDZ6y6O5j95|Y~|Z!G#_zPPeQ*%&1k9tJCl z`$n1U+yg7`74Fr&%bYgS;YeGlBX@T$`t^81nrbgWbQry_D6l4ce zk)Ksl8@X_8+0eWRQ;le=vXsDarO$AJfDY#Y$K9`Y*ywgl*#;?WqyiFq$nG@Zz!(Bf zfpJNpNalA`QgVW#%xxzM4f6)17jzJEaH6x{&X{Eh55&5=4li!pW_LVL zcJ^a;c<-+(EK}&{jXsFGO6=Lf(bI7__8PS9{hORY;rl9Vq$!y04X5FKO*#Aj04-H* z1vt`_5|U2ut{lD>by{`_EY8>34NbgDO~h#j>LoxOiN`VPA2n~J;$-Ew9t-yIfoMww zM5zT?3c?8W*nr9~$o;2#=~UL04tL@aF~ge4&O?LUH_ zE`dr@iAOb@BqS@TC)Z6Hnk&}({D|vlA#JeIwv~mBX~$9D&!u?}hI(eS7Y?4gI9mll zOyr*7is}9p1+i$fJsLZXG9xyf!FkHI{fO&ayqO6ae(Dx*7L*koxe3R471ca4h~pM( zJf|W_b(s)YEk6|QK_GMZIRJ|7&{Ll#8KTrdA|crmeT#X-vG!(8Iw=0CVS!y-z;>0E(z>NXST9 zgK8ixK$M{=Nk8WI*IuSkXEqqL`72#Sq^{E`N&7Tpk8NnsY^~i_3$kS{C%_C+}B}llgFWlI{(VFB+0N zs3JIy(h@<)$DM8;#;%FADbz4!$ZWP-DGa2m13O2geM9fpKkzMhu}#$d=o9Cg)lOCy?z$A0Yc>sV~n%RorX(Ma#e`D$^f?JZ1< z*ovlJeNoopTuCVjZ6gHj@Es4Xnlzr2yTiJ(ZbhO(9xI93rMH`PGFVauNK#2o(b{wG z7^^>1S(uk-k$H;+mY8QTnK0vErK9lD3ceSm&vkp)8hFnyE$=xmQ^I%#*5N|dK?=tr zN3yH!TH1w@5DLP)`QQ>yGlZw0@2gi>Tf;BRgShx5wzu^-d=>M z4qRor;{_ziZ9STBr7xieo&X}eokW)Y4vbDnVYDMQ%hu0L#^7>Kcj%QX;PihwP0K1# zD3IAwGt|#p~$%iw~t*)_(6Zuwy8HL_lvqM@+1^0D~_WrD0{I$=C zr8{RtzUbM1Sgj52Z?;YfQc4IM!5tDS8miQ^DNZGwn~(~IIp&;nt>;Y4lLjrnR_Ue8 zm;h;|-B1<@<&^@iUmYsqEQ?i!Q}FdBq|;0-N>66wdzgQ3F1bc)+Ea>w=eWsCqVF-3 zhsgl%TCff}9~!8kgt*~%2MLg)w2WW}e+64N-EpI$%@03%P0}g}3TiWlE{^nqdSr6= z>YYr55T^I706evZ$j_jo%OrC+uOm?7yMxffX>v$)(`6dP;=oYfA%{1lj1FU;KbE>b zgw~0-Tio`Mr>*y*i#(^xQ(f$uX(>+cI6?mSF_44aE1ET-LulrncpkA#JVCd#rvRToV80(+a<&kTfM6u@`D#nU zE7pac&~>gNXxQ;>P7vXhdP_xV*m1QgM(=`p=W(LEGLUr;sT=A2ykJsffS zc@^;SWZY#bT(%%BJCmGYVC0JEjWKn)O144M?oM?U$g&K^;-#ztwRKVU*EVQfLuRtx zW-93&N@`4UmS5}U>fAjdJNw2xb#-X&A@Ke(Qryj72?!u9U85^X(tFP?wYE8~j$H9? zlyo(s6gOeC+i61IaXq?+FrlIn@VM#P=u4@;Ig=Bhp@ac_l9T%|#>YeuhaL{bV{ferMbNXAQH zZVUiP>(8ODUFL_kO`NdA+>y_B0gZPwZQ6YN9A~=&oipke982?t#FQarc|Cp?Kbo9b zn2W}*dg8+^M{ZQmv`6g%%P1$1Djba?)a`i)^%7|$ zU*A(pt+ti4jIhC2S1e_eW9G#y4LjK^waqCUlz>RZKrNhN(o-!_Tf9Jp3-ert&uH7QCTe)wHT8;Q51m3VR$(~l%#j%<;3N!e5QK?+g^ zG1nQai1J7(Lkdby*Nhy~JG@NNEjB#nUD>8U$n7m#MQHrkxLl~{D%3Y52FVHx+lG4j z>#jMXX0f?&NmUW_fM3HaY=;{wPCHIrG2A_L=WJ^m1MUnKmg{3~GIDYO@8?j*xYNRv zwuc_SY8eif0KtOZTW=WYocjJcb59+(V8R*+zUrxQ+e*-sdxqHAp8|cgWs)uSXY9!` zdu_Gm5PhxAE4BKfSx$DS_bhegP269!M{9&PmztiJR^v%X3r@u-r1QW$>Ny*Z{27S> zq%Psa2PDUFx0wiIvO|mAlgub21dij%p9du)$E-G9L#v2FV z_-|wTaM%tfH6*DLyeC?K#rXIs|$T=LXhA=0Q2S2xu(~G+glkB zr6ptv^jDP*e6va(ZM}+HY1}i<*GZ;7Z?`g+E*BWk!dP>PAbJ*x12YD#r}nM136T80_!Behn1 zJNZ{Ur4vU9Y@xyD9a7e$D*-szK0bdoYavVIt=z|4QzM$cO19=4zr+aZkl;Um+49zf zYwa49c4)uFB=YY3HG-5`c->I0T!`?29$c zf}MlS9Y`Q`9h#~o(2r*t_RB#ST1Zw8KWY2esXmtsIcT}Osm!I(H3bmJJ)*|WYX`%- z;;6)idj+ksg?v6-v4MeF7N;6fd8D`&4mT&lxTfgsid0&*VcRdWMt9&Hxb;-l*%IPb z+8T)N>Sm z3yZpe#6xZPueRA+sS8_$7)n6TO5}2&poBM&5Yke2b+-Qm#Y_gShg7a)O?H2{oxpT9drER<4C99V?wmi|oH8u>x!rHia(d5j#NY;P9uo zT8BzSSLe+|9kh;W$ED0w6atlmCC^9Nc~_$y-J}Agg!AT2UO6bnaV2{0`)a7~z}iMtk=KuaKPDs zIntIb@?KV4ZD?t;&?l*_H$MR-6T(i^1#jaqYDJ1j4NzcVuw|$l*@O3S_Ay2HJBz46*N7WWBg2?3vM>!Bz<#<^;NIKR#vVIYe-?_sc~hoARKoDkbdoLjmr5k z%9LnO;!xaHR@qq!K;}=Xw=n0RjgZ3QSnKNJdo6;>+e5O-jy*r@Ie5XYe0vLF&dsp1u}22F2k2M6 z$I}Dm#!QCZE=nbgp-rz4<#q2)Gt0*{$*b^Q55ZFD(~UK0Bm7qv{{V(=s7WhRw>yi@ z3s=D6SdGgU)AqAqs=q7<(^f0*g;&3#9&FS8OpU(i3l&HX@} zsAI%d*!`bq6zYlzO1t@db*8<8gOE32Cy}on2h*flnjJ`CdgYmsk8AI9v~57`DM)2G zA1-RI)0dbQ`%_V-ud#3fKnf?(J?5yQD(`DSJEgQzJOx3M9U(jWC8z_`px2j}SEaQI z^s#_bio@Kp>JjXmyM45Qlt@R0M_Nvs)F22l5x1^;{%VMZKBLW?pHMlkEHW0oi;m{f zJH=W#D1{WAlBX~B#`F2Wv6)eX6fL~Vx^HI*>xoaRuTqaP`zOR?0SMdT~03cIu8Ozhe&>T$Ft zHsV%<Rvb5?&&FurC)-TAd<*? zcu6YB0Q#yGD_KU6SGAW(J?5H?g7Mm&t+Y}G2h{~_7CWfIeAz$ds2a4hxiXN7MpdYG zY;~rT+R%GIzP&n9bS>GADaD=3S=^OtyeD!E2%0lfj(9N#vq^$E~#%V34 zQ+t|mZG?c5q6al#44(6vh*_+`w7#2*$Z5w$1_(PnRMPH~oS93G)9k#2rzvqn436sE zW_aO7a$Co%uM*~65>@U?EENo7D4JoBs%1z=q}WfeSFd{4VvngJF(>?}tfxv{J3Ohj zn*en#VyPUiToq7JTnU`GIX9EbA5!=U`qA-L`0OjUZIuADmE}c83J2L+8qzbA+LWi` zrAR!}yZUCGZJKRyWTr&hg9<`&LRwZy`D!Xj+6t_C(L8e0{5g$$)9@icn{T-+0UlAy zaTSr58^=7WpDb64#~P>J9a~Yfy{_98)L|{MO3D@W%G^g)cvB_QOGJ?|a^uU6623sJ z;N;VLx@k?i6z%E~_9qxf_#(D>WaC1Ub|{&wrb|iA(2>inHm>(I;Jm)Fg)0jQiiWuSqHdC}$jq?yqrlg}4H#7qn~#(@I*xx`IAF z?~a~tHoFDl8&Ov|Os+CU#ddk+;flJr@>g||txx5p#|>cARNbd(g(@-%L#)_ivbP6z zN)S2xeCoctac5dymbo+K!0i?N>LO5nT+(NB&5fXr(^NH{zp+g>{Qur3VJ8!l- zYb%uLmUlX(H-bCxDXHB%pxFAe*9q;XaS94+q4=tHdU%{?mB`?#N-09lxNfc0-vGSIDIB(nKgTs zl;ma2m>E3*uXlYnr7Y<}*E&nB6=eko1xg(He23(z-#K<1QXy%VDQFHmx!vmKO80!i zq&iK+9Z79*B|&BL@R7&>k%RM^dba4h9l^9d#irz>zv(0?VI@iHyB^Ar!qZlJ6N`E- zo|GJHVGkGgVE5vo!c3&5qUft{D{)r|DN$K)KJ$%$N(xj$hIw=Q9Cvl82A|^p02Oq@ zW-gcFKB2Y8NKWjRPweL`M(ynCWes~#cz=MmZdszmEh;Q z=Epj)Et+FTTq3zK4ofYzjqYTCw1MJ$DHJGLQtd6s_UkRd_T!FjDeM80$y~lls#zrH zl+r{+r71{KT~{;Im1mx5`%y28D+Y--s;(hK^2+LE=Ftml$O;SM%*O%yRc@($@pdLgU+N#Gx5GLsacss;&xAy6Q>qmE@i7 zoD=Nr1va-O)w-3xCFQLcQcm(f$;Wn2Dwtla`d-;_ObE8QQeR0*JvVt0MLojN*2hb1 zD$In)UslYOEknbQtSVBKvKmkrY!JNuEzTTanI2>41A+?tDjy^%w*o^u6qM~!NdpJK z`s(nvTV~jq3A5TD$HGc*;!g6c{dRl(RGLe!w;@ub>3cKIIKAX8836oPt40kGYju>; zR*j^UB`Z9_GE`CEHv`hW6`^=8DZbMgD%w;}vnQ=hr|OvTr zmuket!akk16*#hx(vi=9f%SdLzUNe3#eX8INg+ED;xL1_6NK~i(x@TXeUw%Zw_RJH z1O)Tz*B&0em1Ak!)T`r#*m`2tly590-#6T>j-VuU<=;|x7W>odQxO`qKz$1Oqh4=? z?eQSgdriAVRFxH;ytY3Y=p22Z660-@kTL-Y!Klhmke3U|2LqW&^s(zbPq3Q4{KHf> z6ot>XC}fSU#s@zcsQv2uf3ik&v23%wl;vbc8OD0i<7CCB*-{}KiqwW&PDfCow0kqR zHS4oOdF&buqpsv3Ir)xi#?xBLE$ULDT&%X>w+0$?H}%-g4~}tp z0KUxuQNiANRPCPHY_%jpP=^p!6dWm6BA%po{2rj3RK^9C@gqk~K4Ria&!Ohhv@3eH zg<}J+QaV+sr1VDxEuhEX;XOlPmN!lS`Yw}rI_XQ=a=Oe@lw3h}$Y>?&JLJ$ZF+K>)&&%2&!LLt1c zgYMMjD|rb3qz-41&N|he2DvEnry_$kE3sHwZ1Xm!nMh$=&Uthl-Dz-RR2+7VTvh3F z`jXS!KV&NIV$j0V&i8O9aSfWZp<@J?&mv~`8i*s&IJ*ViHSXCAtrW>2P9dPNM4EvOQ_w`P!(qX&0n zDN;0srE#S!S|qI~z}>rQKpcS}Ro>=?vi4oOR>@_&Wx}ZnXHKwIqEe<^m zaRQuQ)d}5|WK=yo*Cp}gR!F>8OUXeyvT!g#?=`y$CwFVjDY+sazc zP&xcnnnu)@W)kbfEhz}vtc|H7HC6dQMP0_hhu+LN4~ zn5e^TA36>xXW;?N=QTft8Zsk|=xHbolCnoKoO)k2dUNov9m?$O?F}tjno~fHN0fuf zC}Bi({{VRTJG=6`GE1dPyyYqT80tSR4PROxgchrol9hPWm#Egelkr%e5*kz%V8vU3 zww;oDl;}!SM|Ltg;-VKDJ=V!}muH{Yy(SW{w=u2LOuOA*6Py?NB!(xbm$e zrD+O52qV6x$UQccpoYS6kA>~nR7C zi|ZLa8;vZnp#kSva0PGlaycnHv&j1SisH-J*tkN*wEPJOZPx8BIFZPxJ%QG@jUtDa zhAg@8`o3z?;!VEL#iv2uY}OX7QSO#CIJO&jt9yu91w{CswH%1xNJ>ET!N)Poj~a+Y z6muf-bZo10K6@s_qRLWETXS(9+C?tu9k{_uXh=aw4WQ$f$L-BpkUK|OQgS}3+kwD& zf-pe#bj49~QsXif&t?#oRwS{rO;BR%9~QQpmWbdSBhT+T|S6a)yWoq(U}Y(E@LbN1(&;2$0+nb-QGy=u6U~~LYcE6?4?pxoQwjH z4QRaEm28jOF(Ja=!BHS%+fGpy5Rls~gq5feLF5K&8kM5uiSiuI4o^DX3XxI*^w->Q zsJYX)jz+ygGb93%`hy7cmBWx2ij?Ul?rh)7)pv%rVcPNIT7Pn%~>t* zNu}t!<*}%Z4a}X5Lqa=Vp!qg9TMp93KG~&K5>8a6DnHHDJh=kh!lnsg6N!ov6 zc?|mMVH;*Daw?_iXfnfzDtWhyeu;2_yW*!#7f1g9_jSaGfy{Zk2vUIQfKE@{rXpJ6%2Fb0#P45aq2rpkyKY&cm6F}@NxZXjsF0{HB=_ms#Nl&_Nz>%ij|B4O6vO4 z-|=SFfACyy{u!#E+i*DSp3~6=OQa=T{-24(eMhf<94E|vpZ@;px}Ft)#ZNR zOi31$zoRt-mTpT*TZW6FL63CG96OkG8Ad$}{4Q9@Pyo|S=Y!UpRjE^?>sXN_C5x@Z zMPD^0ELVhbjEvx^*4*Sdj?iQQwzFw2%G*q-1)xX;TfhlBeH>Sn+Zboj?N(KfRbja; z7LwweLVHAojj9Bk^8>FwUKQyw8F$j(&p78)eDrM|c{F*0SU*%=ek$~cU7CW>>cJiP zt*$m!db+*)iqn*Z- zBe5z8RtgVM-fB`7HOWiukUL|~04v6jm+mN1)+W3HeI2>Lr-?~v$I}@H3EU1xJX0j% z;$%otP7sx29yK-cK;vMY5-g=E=-aNTO{}!G)y)dWf2yp#Go!Rj$mn-gY6mUlwVD22wI@GsXN3cM@$WEWuF6xNV51hYoTP3$$kgV^{ z;5lSxpyZ%2%O)nZERJCZpG1s&zPdOTi*gul5glV{(4}CWoBG$N@+8Ds9_E*r)h)!2ag{hRXN4SO&5S)GA$ZQl$iU7;A>jfv({`w5S;%>- zNSwDNq9a?Jb+m-xk}yZ4K;}96@ly^iaWc`w>t(v-b+fx{)V7H#g$Xf9RApL7!cek# zg`@$TS4M1UK~c)@aY!oP5xnd`0CyD=kB*q`@me6b3c%bzDJP{!WT++e47S#CR5Qq$ zVz{`Fhm;l+l=HyOIoBMk$EfKY5^19KcS7*~$i;>q6mD~^ z7rjFPtCAyIVyCgP#B<;&^&VvSft4h4Py(sDyhyMnNrGj?nwZjDLvrH!4Ze=KM}9HP za_Lu&pwzr3)$ZCgrxCr}V)<)=#9Nh?3_z&6LB?McD{z6+a{GT)*()eER@2%T`5 zaq}pU1i5ZJh;e^Hj*sq1N2w^l=bx6h$r_V6BAa7O#5Uu2TYJG!7$c=dmeXQfgdrP} zpRMurRDwc+h#R`~8KxI8=MOf4u|W6t*E^EBI%5`);LOQrw#kUon8pfJKC?Y4_S3pD z+N~dOHmD6IWvU!`fuMj=>J{+vPkv2NaGC}T_td@HLn%&2RcDZ{o#F1MItx=mzqx8f z(i?FT7GzgCNN->mBc~(Ix-nziXO-78yya+oYx{fmpILwqZf!ZjHbv2s{&og$2re4~YRsl%pL9cp?Bt;A6 zH=Nh4BEv6gJA7rFWzF3ES+09G+en*mg38tVS3ez0B~Lwai21_jJ(-Ji*cHJh&b#A`QzpO{+&V zoyv-mZ))HwbqVRu2d*iC>9NLC(_ke85~Snd8hN^?vaU{TN`?mIWna?(XVxk`Ex?5< za>B;L$amIR6qgLVRS=kmvy!IHz!K;ngUtF|soLn|i7>4tU=6`w;QC*p4u25MGqZ#* z3BmN#K*u0*JL&S~f{6NDB_Npu=bxlT@saF3D>x^((Ys9S9Sxy$cA?dCH zM_aQ`=gHQa3QH%r1q}7T%|v+TY=x&aV>W2kq}!Dm#Q{$;oPw7Ne9FCN?qZ`a>b*?W zk`9$(P>T}TaW^RLHOb^ZfsCIHSjWvsc!RFBFA%TNwMMR+9qXKy8fis@6on-T0B#r@ z$4_7t-zX>}hF01k_ZdzSu&|@F^xd3t^;9!Zkhhv%HlAel=krvmV$0yT6NBCdjYM?< zl3i;(+0QEEn`@J<55T`pxgij4?6l!2b{+`$;;4gjjFNvwIL?IB6@;Bv<-VARus7n`=6>~%esS7mUwT+FEMY{+fE-q3wx z2fN0j3v!Ul7q-sR)7&|*M&c%>*Xy%JHl0ImQf!fnVNJ6!)F~1G9L`hb>gA4Ir^j4- zBm^?xLBbnxX&m#BxZ~!l5Ic`Ms*vgYSjFvSU_YbHsqbf)sGTNlm~#tS2rT) zPbT)Hbr{AEfgUx`@ojsV%a4XJ-Cu3UPqeX(&5_J^)q4@Nr9nG@Rsh|f1yt_lq_~F= zv4W%&{9~;_SlCpe6OuU(-B&hO_gUDO@EQ;6wvwW(u0tRwlaGQcrg&?tbhes?^`h&i zT#Y4C7PMdCBq~Zl<=K#+tdZPtiss}p>srndTtOqYWn75+5mxMEq&~N|9jI{S!|5b? zxpMxUE29KfLYY~<;@DHNBr02y!sMxKzW)Fx7LEDbq4rp)-OX*5fpuVZeH4yczFLvX zKrE+W-RbiysLkCZx3ysk2{^#5axJ|W*<0$>tyeakAFcN6XlWhtJ~=9HAHaHv?jua z{tjj=6YU+sth;lqB}rEF6UYFr>h04j?BmHMg6KCShq;V;IH(Sy3<&a*u;ehHLH1RH zcx}+7a|J+T1oNl``?FkWMP!!)D<{XHsMOR;Vv{SaG)cNdTOj_9f&lB`UbOKD)Ugoa zmK4kCJdaXI`D@;m?0xXs!hu2-=G^yh!R1MNrS~JK_+zcF z8g|b=Q=#W(y{BUPon?w}+<5Dgkn4^la#nB$KJ^Mk54UbGP5~_-wzUJuq@4ZT!lRlh z&wbRl7wopAG@mwr<;p{@zP8vy4J4h;jNq?!HjeZ0W>aocZZedYQk3?5vNowh2qdU` zRm5lA($$g0di4HKAlAnf@D4-Gu4g+)%Hob zGLq5*tha(W0iLz8IxY@4+^EVSNmfrjSftE^IfRv@r9S|8e?yvfiZ>58^OTJGM1=SF zR-0FXawL@)maDDBVP;9#;&9_^-~o@a&)%rkvW(%;m!z#g6vPEX9|Y&6Od*CtZYAQR zD660<=ktB~Y1Qq;_pyIzsZJ#-gOirY&p#i-Nu{*Q9A4tN@?}|Pi59{GiVKvX=%YPY zUpnh1ooyolIoga6M}}*X{F>h^aYD|p^NHCkgs;SQ3j@@8kCM8$NeakXir!L|6s@@Q zbL-_?`X=0%)Wx%1!QJUX5(ZSBXO}8(C_qY+j%S}*S0%RG2<;Mfbljf5hPAxPSyp#u zy$SYZ2so}pqmoABgX^tsq0PlP$1LZ>R@YFK^V`4Jsz&nmf|WJ_Pft&%tXpW&@@Zco zfzYcJRry9Tr}QKx=OL?*7|%QrpSf0&(T7r?jPB+=Dy=yDl>5L>)d*0yv~U3EZLiwMF%SC3A84Ohi0J&{^+0`j6Ndu}`9Hd{_P zV{(RZ%Di;`^S%A3w|G8?#?i#9Yp=FUjUa@jPr2!DLcvEhd@KQg2QWxI)YSn&ankBS z$#n@>Dm>3#Mx$1x7Ll|%Kq(_?Nls2VR}lkXyosBg&a9t9C9cGQ*8qhPf$?>%HqtR>`A)dpuHDV9l?)W_&M3o5ZBe%4mh6g7 z>wu*wYt}0#JaUl#$QC zgIXhn2EtX1qZqGHp9`4T+Ax*lAz*#eQ&x+^gO9H1?631%DaYrRN3icTvedOAOU?Ww ztDZpgfgT?%8l2};-8P&Q%y{4se!TcryHlleRke5bszG~#nAGqpVqJJw=Uhg*h zRj%PYzZTBXViF1f4Fw#Wp1(D1gtdjXw?4RYR(hIdgwo16o@Sn-B;}-ok`I4DSH@>0 zT#}n28+XukTN0$;tNh}A;6E)`3-54n3aPVh62Ig$Pt>dw2u)ro{Ea>Z8Lt80yFCKg(0-1 zdzI60$mCClbyl2*PgmWkR1_e#g%xcfBOAJOu0*$XZq=drQ>I*IKXa2O&Lv5Ew0Xx) zR91PZK>JCjYh#PbP~uWZ11H9qEzFDoxG0{uBNYDt0RS%~ZUdGwE21eF(8tBL)>yW= zw;P&Rs`GMGoxSyFabL4GTXVpSC0jC_kUdpbdOOOHI@L39Z4utopyYJ(Kqz#mDFp5Z z?^EJldva9c#Y@|;sPoA1sO^-xLc$b~H)P>GDfueS3P|VDu!N|DI>sSxHdBF&a;0~M zvtyT(qiS05=aJ78iZEJ~l7Zu-u>FurZBe;~SduqpV>CE%+t>95vR;-SDjzJ`v zantRoS2EjfVJmHaH$S~i%Rg0ENXbgbBjcr(Cl9*ql&iU54<1IbpDv5-9@_-AfU*_1 zC?AmH?^C=Z$-dMDEF=u{rk1&nP$!tDSc>G@z{u%S2TaYDC-t zejBbQKj$2L-*TLysVxn=vz~O{rcvAJxXrkvg*PG4aq(m36uK*E2~yOruG%wM&L!fh zSgBhNGt3_EU0VMDLxtC4`D)l04=pHpo0jAO=&Xx$vNP<*FKtxLkE!y{QPQn%q1=TZ zE*&bM(~844OsOZ)Ms1SuyW8FDHOHMa|Ay0O6ae0gNatuhLg)v&*>Wt$jDIJ}@6I`hWZU-_+bxez%o+ zNoBRATZu}2C45!j^5sIk5z{=fYsd0^KZ3#0s8O=(lIT!UY)VSNJxB(k8cF$(W5ts*eajN$h( zRQC`y`_j=p{atV_GVV|tZ48Fa3UZXADFX^n<&5O==S|-JHLH%4yQ(e^Jo8V+aZVu$ z9h=T?e01g{hjQatK;hfV1fA&(B3jn52>6qOQ>^Pc@E& z^cCo>3kq@KqUP*nCzS;%Zw)vwjo%0#Re4fEl%Ubv2Zt_IJCP@+WUa)8{ScAYmoq|E zTzM*K1Yl!mKRtL2FQ^y?#DktF+p1JR)iEg1vY$aJyG}o90A9aNdo`@QTwcfh_5o0EGr;m z2LODO`*2DWj3L5t(xdl%%tR$b4a!J9HRjD54Czvm+Oy1_hONFDAtLV-Bn2p0)_y(p zR5F#JE655+C(-e%V}u!(c5S63hung+Fv@wj=cSw_J?6L4u57HjBp0pCwvn|;?Ky<2 zpU?e1UUdYxAt01&PCz{S{dHqsqr6h!Q!k-R@;llo1p2d3TcZf`l7u16!^H%B+UUxy zzD%O%jx8Og)sj+2K}?HVes?6fl1RuSmN8H6Y*eHpwM$9KP*RQuDvllQmshwrqNR+1 zT#hu(gvkY^i0iW4opI*^vd#j0GuPW!>e&rPO50xYTS*(0lki7}D(Bk^jG?!idBB#| z8d8dnB!I4Y@UD`ZXq?dPnY7DHXIepJa1`|m0~Oh(M?QCGuWyM$ltYbN_G7bDU~D(+T@qy z>AonjxKXe*sGd)x5po#hGt4XSik#g;U7Fo!6s1FM!bt_>;e(Ln_$!+Z8%`K0jzqqyn z$=SSPs=3r==Y+81*a;vjH7&g~>qD{Mw+G;nj8t0SyK(Jf%euE178XLWyV3)uD~~+6 zG{-H-g2hNG33bG@N{YGnjEq#4S_w{;Qq%}3+K&8?zI?t)i^js+Z(?$c<16M*Jmh?p zB9SqcA!)fXg3!!Y6ylZ!cBiyRC*lguE0z=cm6|lwmdlJh{Dq{Xfx9Xrzt`%f`-D%b zfWujE=Ol`mL4_9KHOM-8`D3~yZCg*bH4O(_BbUQGi0DOX)izn0a!Zje?%Sfglm&t= z4ZG-`@JBBi^(54z*~u%iv3fGl-cC21^gOB^eFx5)E&vG!81+=z@prT~y{NdybtGpf zR&aULCsazd%$XQlgU>&5qjwnVkGZvi5^{1*YHb0y zw>vxcSX!q{3v5InzU$Wx&19$oovq_1krfNQ-!$&>k$<( zG8#}TS_TlMr8x>v2bXqheKeGNBQ#s+kj()B)`2A{Un7c&-Vj?^LdMdiWM}#cnra)i zg|xwqG43U4*-E&haBd)3TL<=Ix~rW-u5^1#TM+IJzO*B9R@-C%J~7s|%}=ItLA}(` z2Gu|tgJ}TdvKBdVBDaS}y=TsL?YX5y_zj(D7NomduNMX#vc!EYvl%IQ$5pvbKb)<2 z`qcB}DO*VcNy(7B?DO<)PkH6ixIe{bVJP9-`)tK(QS@ZE0!q2Lk!Iw zd$h`fF@S|U%#>ki3K<0Wa;ir_YYic2u)l7-GcCKK=61qL5*F8E-ht0>QRV^W2Z8BV z4Tp$23i%<&ue?x0v(_``cP3m?*UJE?f!Dhoz*lygBv)rXTzAp7>kNj}R-)M_BP!}U zzI;`8r~}1`DqklH4xppIl6m98r}~>&@XFj-VXh^>xfd8ayv{p>pl9HWimWd@LDC{j zvdU*%P~%Uw!+T3WEy1-aaP#C253~wuDqS*|V$-HVbk0|Nw(eIyI&3G_d%*Sh*NE!u zH4_U-Z9%z;+>&#gsPxBuXHU3>?^fdCLe!U%O4505$2?MhIZeLsnXW}{Q&Ht5$7APj zXac%t!noq7?2RL#trxh~%>{AO&|Xo$YB|XFOtuLv!D!?)kzv$IRY~pr}OREy2PmF@;P;Dp<_F$at2O#6yQ_B|>_&S#N-1Q~;7iY*J zn|M~??ag*!oMG9?k`C<-I+4EFNpXhvp|Q)CBadz>p4aK$a)jbr0I7v9Dmc$Si6ga`e3`no7o_au6phY4fI-OI2>dkl!!)hP_rOR2OKEv0#1a0%rc0?w(^j@}OK5r5 zK-+)`+y3fLqP4@CK1IX&*%Ii)_}*-`oGJySB$Ab+j)&4U%9^u$t8(DEW4x@NNbXJv z0Otc7f$*Ppuu5_Om~c6t z04t;2i#eqSR87ljURI)@cM*Zm9;fcs)(IIv7zdFmsAP^Rz*B87oiG7Di;DB?`hDu@ z;eqj1&&^Walr1jlgl=s+Lj3bN`Mq_b%?H6n22B$fr1ph7@%5{-g*&`o%y~pEron_Y${)UiQTWTmtn5_1l%E%n?S6Sl{-qfYh zWU|_J1fm(-2}-fokt3CFEjG)2s#dUkH(>mASF^`xEu}rahHc~}K)TxIsU=6a=ew3G zaq@+T*;3>1;@+I}-7#wAT0>C_&QBa-g&nXQy}lwE&T^ER(efB;fPrE5jE#(TaN+4gdxL3gkX2@!al5UfW!k zRk;D&I@(k~<;^FbwxrhBjxPlfR(rmt4o!3GTBlPm0grf)f%_bfp0~5DwXA1}V^rK) zQRqXM=jyJgX4+@$?k$cji4ipIv6%>40qKR*Hs%8MfB`#CFg>EAToWbD9dm3X1Pimf zRIXr>k<;g{cAa^?U0+O_&C+DY8&=)Vx>vMkn91?0M@4ZVS{@YJOOO)iRMREAs{r}{ zV2_Td@+nJ_9y(NA^3R*LhP@tq&$f`Pp$IDGJb6?J{yH%7!-}&rl_%hZ@(1Ol4)K^3 z{{U+nKtHqPT~8!gMFP%4+nY*?wT{A6(rZZM-dl0XPjx>lDs z<1w>_Ezl4KGD`Um>CUSrmm^_wFr+F7}I;VU+YgbLN-a zZw`svYrGW!iAhNvcM+O=i*&aolBZ`!NF51qRYp=nr_xi1Ke_p93T&ZWnU1U;stHjw zRh6y_${UOR$*DBN0Mz-Kq5>IdVP&$QrIHSL0i1IcPwMIL?)r*t#t#0$_tducczb=I znqW*+pcN$rM>zN-pPWVR` z)SZWUz!kDG*4*gMHsMG^sZk#tWZT`zG)UR{n%3CDwww@7Ia8!GhaEx*OK4Kkoysa9 zAeB4FQKzc_^N| zk2+VP)|U9IF@%6qD$wdr?nmIJcx@=SfQS7R0ssRTr%fE%n&Qp9V1iWv*2k|Yu8ePY zW>e#Vn@fP39Mm?W=uU729-^KZ`l>dR;2`p*jX0M)&gmUKjwiUTe%gADTuW+7$UMR2 zRLd$fT%>_WSZzTr08TdK)vM$KzAu-ChCl=+Lsw9u70Er zO?h?j;VC~0-F)&n{?gCy>D^qjR;;pIksUsN;H|I!05wMc0O6XheTuJ!6ab+>UcY*{ zvytttg0K(xD{TJ&%~AgV_-5;$ARWyUuqf|Y)l{JU(kQ~jNjB$d8lK?y|u|p zD#s+8dd@4wdI?H_O1bjD_ScVhBkC7Dlf51i^^aXXpFk$mu%w>)tK;8ahQkdc1dX6% z_f?&t+(N7x)3iQ{t%Tt9!O5!4sBAe2x7<=f&nzDdcvZ7niJDtw!MRuYU9RMVe&IMEs}QQU>xh8do&a~e06ya zsjZ#F3i58}vN-H9)NmfA*3M$^3F5LwY2(P$O_zgApy)kWdw*dvu z+|^|k%S}cih_1^GCB-EmV;g}Sy8N_; z(zYTdH+jF>z8AFH<=qaW?`zVV%Ex z(_-(lTq+2fN=HIl#d}S<&Ja|)jHGw%?D3J~%QShNszO4WyE*{+)ia-*ijI3MqL78D zDtZ0yf~9?!&pKL`99ojuNh)xmEu4e(#H;3|(d;qg1G3_f0L}|Z{1vVv5n|3l&|Gt| zJg}Zb_tg|yc1s@ZTus%QL`c)t>(^xrEl0C;4Y(2s$iPv^&U5k7X-z>xZs0nQ3fI$qth1Sttbjj7~8>S#^7b^=>`W0yYa#!bG-;PD(Z z;#IXOQB^rPGUKO>s`F`)A}qGhwI)+8ZE**{E5GBU@oj=To7T*NJNeV3rN)~PxGvh> zQXBXj!N<>9M&rp%zb4sSPu5o!Lw7x0dzGI}McFFJUxy=2FJIRn?vXa+;=ajF176i? zw}mNA+a#ewzi|9Du@;C9Cvq*)$o0KZDY-JP2@&-?^TlLIloC%cpbxgUF(Ix+eWnsX z7#OFYaN-35+!<;Z>Dy;CIb({^?GiwG|(-Cp|vQEMLqfW zseB$P>&tbm7N&J}piEXh78ymwL4+slQh<^G`KfykHk)CG9@L~IT-+;PH6H3|HYlX1 z3wzjE$-~49{IzwGP%9{@E=)hIF0)n~pL4uOQoENYq4i)2XrFMD`nR~c3M)<>((Rro753q9SUyN2Cd~XGAG)@O1q7DZv42rQ_ zY1dl~``odE-b+0GY*L2YmeVDcwBDUgMhe#tem#dd6?Em%n|0u~jxjAzKjE)aSaBJe#ws?HybM ztelV{rCoh>3mZpMi$NyU$q7$CQKgXEc1c4iONw>HgaC2e zuBN8RMcfdxHYg->A{u#o_3v%nwWUqmljD%e0mrJNVKI}kJFD%JnYtDH{m{qz#+cgYQt%h5o|`_-jw-k-vsy~$AtBa%R= z+QjBph(oR?I~*LaSG5S`@hI1{!IZo-AilJLgS{n3?$rH}s5?&08lvD6{{T9F4Q+BQ z-TwfpuK72Ai)%_g;!RtUEp|ZKwar4e2vXFqg4j%T43p4wsdv3CLf)2oG^<>=^BizI zh{|DDQgPItc&+ZjxUC6oT88F-^#1_vt%!wj2q4~WI3o((Aw-ew&nk*!?<@ChS0uQm zp0~;XdMZz3qEdW%bgxK*aZ^Rq+h!FGyIUY*#P|GlIA+YE;){0~p+2T9QvwC0O|@$5y z65{A-ha@G{DQWD~2q64)_3k1Q=(b;HcP+uiADGl`Yj0YnmYaRVB`1=@r2X2NIz*_U zDY0G3i$3K`E(Go=+l+MQkVR}7QvRY=-I7|8k?DF(8rI162^_R>BM9B3c< zBQ&BWmeeXGe&(qGWR1=#Er2|7ai5DdY@>(Jea$z=Yz-l-6J9A z6og^)v=kfXw1l5uiKfjrYmIfiq9g2rz{`XlL0HFt^;HyDmqK?ms)|&l-|Z&{o*&Ky zYWKFn*R^_r*51S%;blaRmag3^!*%N<-I>!mde*hspe}T@yg`5Myk3L?ilQ+Qa zT+~}!<}_Rfnz$@7(Tq@{m39btk_ZCp3YFcupjTFR;1v!8t!QY--D9 z*aMn^GE^0{Cj^h2bFQblXq(NB*%s}4(ePtNnlgokl0hBW^m-obR4Z3lZ8uv?geKDj z7SN@nhComw*eNYLt7V~*-7*=&+gwXs+S>b5kn&%+M+MX;(d4w89}Zyn*ILPSUUcw7 ziTxE#tY?=aisHT=y5PUD87nw1GOfAfm3G+VJGo}NBJ_saxk--N01ACrAoV#s>$^mh zOmz)D4rk)qVV)u0+;R5fq$waclzKMDV1np&^)MR&fVEZ}s zt?k8}Q?U`Rdy|dH4d*1BU>=ola5se$__L|i5vPlGi##zp=zDONpJ)uBgbeahvx4Er zqsZc>O5l$XU+ikI1VfMeBqAL2?3^Y#EB#;hrJ!ZM%CXq*zYv|_ZAx(;fxcnVJ z(lB@KLNSi~`duq+vNg4CiA}#P{kzh%y0PeBRn4gE_lphX%N6QOS6_@1+Ih5q`$Z?H z+y_2csy1r|E~vRM$UApBum?|rQ#RCX7T>>-9Jtzb=gX)}#PcOvR6hEvM0mER7nH%f zJA;Ijtpt3WsS<%%3MU=-_SCyiAP9&U7$YXKjd?YUxS^m~VDtX~gO@iHNWm_I_xo{5 zThmK(a7K%sw4bjs0msO5Q&^yd0#ua(ka6EqTYGB3D0d!+I0qT6cJ6!>ZKhM~Mz-6X zajCXBP}Y4AUS3jZRq9ofwo1LqL#lTw%9eZ*JH3@I;%&Vy*hJMKExgmAAz<^zK2=;z zDnsEVUXoCgk~@f~$hHLA;M!zCanyD;78I|70C8PuN1I4FaTZ9Z$id6G6q?K#GhE+{ zbU9HO<|^9Z_J_9WxKbs~;vJJrI~mQ1k2R8|IzGuePfw5HsxEmFdrJBZs`R&!8LdBU zapx7WER`v0B=qPp^Y>QS+H+DtfV+#@a@72F4a+DUqKE{I*dGI!BLokF-_IRI!tNMo zE3Dgx4lcY*(^ts1##Hz*p|~a6oNLnark~Cm3CP`(%n{cHt4UsM9(C5&7Ur9jcuQPV zOKl)GAt0*ml~#tC5jw8I{4^oA6*;slB=iIkis^IMMwF4- zm3D6ed3dV1lS?+3n$q4DMiF#u_+!#F(z8iSwUCj5;5i4l9M*NVLoW>HE+SkWw`$9+ zz7Rr>oUKJm9RWG0dsFVNJ=iiC+(97rX(S#%9(=izQcf&|t6$ud+P39jl=_IxFk6c) zT$wA$$N^yVDbGxLvGdh4@gmSD>;UFt_~P4x^ae<%rI9Xb5o#%Z~(t6rH3D zs;Z0UVvFs`xJwIRxvwRh53LJ0_WNpa#WG$>V+pp;KT|h_3?AlyuSvB}#us>#lio4Q z*-i?Oa1dJndWB?T9FH$uX|^QBTZZ)5R`Y{(&Ojr3X~SKEssQD|mHn_)vTE;DjD035|-T29`i?p?xKeP!-+?xqW=0Iw&< zzP7dlU?BQfJ>ry7+9CH#dzKX;#-A!_!?ZfTOBEk=*B(-wQnFQ3eOVnY+X}`}u0k6)m-(0KRI)OeEde zxk0yE*s{cet8xk)kignxde#nk)W0I7kX&C^Xbm?MoO>r|#Jcg2@`wk-oSi#%YnXZKJ-x{Q2E_oU4VPbvRf}N^F#pDCanLO#@BZ$J1 zRB}4zkup$=_4YFfN<(iGj_`6tD2^I!L@(ie`p++ApvC0u8Ob2{RjcGQ57Xhp6$Frz z?#DCUeZ`+uNO7{+31}~uOmeGZ$Z4b}%bSJoCB22ic?1E=m6CVitR}cLPm&j4{{V`% z!~Xz+V}J0?S3W@@O(9vp1wi`irR|zWT-)^QIMVoQuGw}iy@sC((ico2X=$`96Xy8k z$miB8nk|Z2;)QMHl@NO7z3*Jh44%|s{uAf@7fq7}Y|_ZMZ-G^MZ9AMwLB>=DYt4E< z+_a}S$pXA|-Jd{Bbh;4Eoz~0vE*o-Fp6`NrR93|b3T=p*>nU|xcI5N)h`<1Nl0f+C zTcunJ(VEwBLa_iSDEkNFkD8;pbcF(A*Bv$llA2;>b(MJisRe4t>?8e+o5JQMp#8mW0I; z-w1FX#TX={pB_Nsogs01SXkUDZTM?O5R|2Cj3A{L7(Kv!+D$8q8meWoU9oS(OLN=o zmRmsz_$51u&oi`<@zzsHFM{!Vm5`$ir%(#efTf)D?gN*~56w+7+e=TWq>O+w)}0*M zR94#0)}&{t0XU|o+zNR_k5yE$>Km@1_R!jja;#O0VzePlMvD!Qr{o}ddqG#i?)hrF zjzE&h$Jb`8hU6+FIIE8NY4%c;Aw#H8Ijvz7`7_9yTnZ%G8$Bsf=+Pt~V z3Fqk_0ZAIwSBPprW^%b;q$wFl$Et&>uSH9BGaSpA4x}J$T26A4p6+!HJQ4k><(_Xa zT7cr=xR#t-Nk&RJ@;E$?u|wskbIE8v^KC4Rt`L-9^QjfW=O%20OO)MJpc6`TmOM~dP=FpcNw%{5HC&s;$ z4Y)0&9|~ODM-b>xWm`)*{{T9NBNc+bt`#2M(yC3mViJX*c@1|dqYk&rv; zt|PPOPVgd=EdW7H{XVJIUY5~4B(jeGMIU=lzW=juKcWdc&KA_O4-d<-7!n)F%< zBhgNK^WRGtiiN9b!8yPNl?!{B7;GGL!Rb)p$qs5RnAQ+M!Vn6Fhjn2MIIJyb9R50X z^ChH}Z6J})2Q}fSuatn6xn%P_^&1G@ga$gk7iK<6_R|g|HL104kLWKWI|l zW9i^y10ee=MUA9ad`R0(5ZG-&CvU2O8L|l}9L5JOl_PG?xx(9RjAP*e-`+khwXwSp z$tp>}>T%uUQS6o8h|_UfZ1Mz?)Ef8LC8u}nBR#}&sUwykb}gasvJszEZ*Iurt>JBz zI1&y8Ti7N!=!%wB-~}gWNzO4|(H&~&+2`UaPK`Yyc-+&8<q6MY1=mYJ5rc z(P`wwvc!p)D^DQPYCU=i_vT6?;3WJ)rY+c=DIJ?jB=uf83RUlQ^r()(dqTE@fl>7G zGWSsf^F+}wU>PnKLoN}uzG>L{-$gLQ)m1H=Q4|RB41qG{adU6DHs~PPLAh=_?l_6+O;uF+XrD%Jg zj2vl>*eDf#$tfJk`2|*3B@$j$7FR+G%WWsI9dVP>+g0AMY{tJG%z&jekTc7}HPPPj z=O!e1O`sIIc_<%4pDcX!M{&N9Sbft)8Vc8yIPljp+*H z;NO$W#Yr1}N>FuE=(hQaBBi203Ueo)qL5B|xul<7>WP(=1R&rHlAIode?dxGbz#lV zJW5l`r(ajiSE#QAC8Ug340V@yl{Or>g^}7m&~LZga#A~p=~ZtM5`(7Dr*bhlq@H=l zFI`wqy|p-Pt%UQaHxg2X>8G5?z>>+vKD(V~l`W@UmJ1&Q4&H@I(h{-F4a-UfP7gqS zO7o*!&Z225K~hwe4`+YhuW-~?r625^DOi2Hgp3aUw3kXdw@}5}Pc)Elaot=Im9wr% zRhJ^-D6@U$~aw({ejT5Q0(= z$!IdPa_>@5lkKX43dnDfJCaUw&YjqGE`jw@3J4$pU6A2f$2h0aKX-}RzGJ3Ki-w0) z8Q5(FB&ekda4#Is*!R==ILE4_L`)^cwzt{IQ_5b>MFV!;UF3oRJ^)o*)RUB#P7;L- zdOd%qI$Yb$?hD>Ig=6F8Td1zeRT8W2u)gYRJ-*R+c?xFR^+p4Hf%_5hR7T>!M0qWN z)rF)U{)e3{4(yH=UL|1k+sINGt~l}(km6EGR0%w?HrA6%V=W)#iYG?6W9lB&Joc%j zZt)@N>}ir5UB%ZFph{g)>C>66Hq%8S>iQ6!sX~;X4?(ru{{XXHe<59@=g^brt13A4 z_g6NR{l&8`Z07DiHtU+^a+C-w?2k{_)DqI8?usxlM?fmWFCvU zYEfc)Pc1vP924VQy3TS@(~tNTMvl~1ttEQ5>RTl8#JIqfgq$JvmCa49BLIaCMB~{` zw+RvMcbRucup5Hhw~NS#(~2#$Ro5K-zb!>A-I@@DkTy1*r270SL2eA7ZUH;JXS$fW zDwU4OK~y{?o zsUDItGI8~rdRCcvjR+96Za@ShJBP{6rPe14aa#i!?E2J3T2K_N#aT{3+wG|~o*~FA zf-;aWu6ZDMf!=*x{VSi3C6lI2boIJ@=IF(m-r5|OEn+(>A zXeMMAj8}j;0bui{jTHQt`ku{rOh=1wE|DIP<7wR7Ww`1KZMdQEP6spGNFKVG>+5`| zoJG~n7!N8uYvSVeT0+;uqC=G#+=Nd-kY@2G91_K|T8^*g%w`l@FHEx;Vw5`2F3 za>3ax_#}3F?aIRj>jKd%#6|8ni7`wdCFQgUJ5sUDBbm>ReN^XdWF;MpWR}4gOJHFj z1c8t|PkHaOx#b4TrsAXyR z1gS@#O4yysK8eSVuDqp50CMYI&n#e6#o2YwX6XC3k=QxVRhJE{Q+M<7&^6Q3MbbN*IIDQVs7j_FUsj@Ta%rwFbM_{Umr zXhri_4>c(VEQGk9u}~c;bbm!@Q3oEOnuxj&q3#NlrpP@(*ly_XR$O_bp-Czd;gbDx^FC8DJs&0r-UC?9Q8Be!Lv5n~N@TgL3>t`8y5 zN0#>sR(aufum18*s&NmeVmBm=k~8C1Kam4ud2Mj1&OjG0V11;WSjpNhl^;Rx4Ylrc zwHDerX-fDB_(VCoyT6~xYvGlV!kc>=+H8V@gSVeSUvw`g`q?WzJ0*R`E8&f-e_NyN z8OuN)kXL5A`KDJGu_^>-rFu?x4Y=#q85Q9qj0|LV*PwECr0uR~^<~MHnUwpwQ(Oe0 zw54#<^|{BUFSlXk?wUdw&+&T)%igCAi2g1DfWYr|oERsRfug6VFR^_Ppns#8e^3;;@ zQMDyUalocl)TIsT01dsAY^S{XxWDOM1kRbN6|ZOmoI2npTk zW~Zh@E};uf(41f#^{rzhfQ|K}6@sI=SmZ~+#%UX*E7NfYkjCz!lt?Z1rDM`3*GZJ- z6bh0@hdQ&F8(FDMt;Z6w;z#+|$gd7aLLO2`7#x5~sD0%jd&2=lbUU$09DQn1mZX4r zXFTvT<5g3>$=WF^b8?m#Q3**To_wjSN-7BL3IJI-9;$XsX#JFzS2YbGEU93vX9_+8 z6&gW8+fFmgawKA^@-B#qNOre7n~^C#iB13>s+qFWYXKX!U=CRIR2tk;%dW{%vW6SU zsarSb4xzVD@)8t;@;<>@Mrf9-a}kb8O0Yj`L5g$my_~wzb9{iH54sGbj-xfTH|s$J zu4815m1fiOWp2d{HQAt~qa^bls#e=g7QrjWE|k~rlE?@OoYs5kNYs`f*P|&4IPjvc z44zoA4B=$9a0vSDmFY0gYPA&*oKt#r9g(k3&l)6-iZ#6&w!wm@E=+|VtmjvcK1ilH zqbUG-L<-cnfRe7!DF@X^(W?Nx`pd>)j~Rp=-G$p6@`AJ}S4l z71JfDK8KGn1s$SNoD-f(2Q{_0S!iu%qK7TbzoF8nYl+fslc`Cx1=bn_XLS+aEQ1+&o5ycG<&?$Q0`n_R{kC@g! zG<_783dPz&kWfh4!5sWDYIi`bOnhS8qO~lf7SfKYp|W&N_FDVyvYCuN;`@#hLEWZ>cE>PB&#Z+wJ+OTY7oYfcm4A?BrCF=%k-rNB;me z-3%Stn70L$q=$Z>2JzjVe5+GjZqcYhLKwO&rj@uOu^8Xu@T$sK$@b+$p>{yFlG}~6 zTu(xU?k1E&(@2@=Z8!rB;aDnI>z`IJQKQGr9NH4gRvCq_go2pi1uD-ooSc*KR!5Xh znr2InLerNt?-(A6Q_C1Uk3&{Z5n7oqx9MccStv@BQs8W7m{C3yxxEx#eJSi?t!=GM z>`~Z4hl%IQr*%Q2c}!X(b}St+b#a)<8xh(dBr7E3j`Ppt0+vVeqOc(`7%Ufbde; zB?)UgLWu{_%7{GslqwMu%Ck$fQ8HXlNQ znOAJyz&pZ*4&(bQ{8X&@ed-3@Tk&{k!%q#02hLK4k20(P02${~{g=r4e2z;;{v-CpsYj9Bwo*hC|riV4E;EkuALdeH8i~tp$UKM!z zOZ-KipDXCO8sII=ITmw_H5G5N7=6XQklM5T(`SdrQmDR8!IlgtOh$G?EA5u+yNa{B zZr;z^>#lom=#Oy;rW$QLJGJ&r05a_LI-XvUkbQoT2$Ru=Ix2GAfd{5|k|{ zZwN{`?OIQIiB2<)waYJk5$-GrLHK$jPBONfDt&#bl%@Cpr1T!Hb*XXt#}#F!p|>~lezRkIP$eP zw-cutO433%GO&anvQ7^(P_yItEVQzT*b3m|-gOYMVC$$Pl+!2G0M;+d=M6M26 z94Ls~R+^NTey9tWD`a!!fyi>_&zQ)rD_@t79o?Phg5h9Wi$OxvVl4cG^sNf=+}Fn1v5kVsF~oa3HP zjw|QqmnDh4IpqZ^(mN327MQ!x+ne?rtC2nD$E7H9%Qufmietmow)kKys4g@T3Uk!+ zJo$R+i_~|!#;Vj3^(Ff5_0HpRaJwc`>&li&im(SgpcB(3xpjGAI8rskhuf92VwB^S zI6x#^iH7=NZi^jl>Boq>plK&t!ZhhX#G8 zo@=r>pkpj;J16nvuO&gUk-KVfkBrjcGjm~TbQA;?s05RYc;FllZarP~T%IV&8%ff7 zdk9Gblcal9)B0wXer*y}9^TV@KhX$sBDaSGMY-A$(61znb3D81{`3OI-z3TFp?N_? z)E&tMDBd%-$Ci0}aZ#;$+8)t!=Afx!uZS9}Rz+qF+ThEOqq<&h1bAtW94M!1mZT#am5czRjAE%g zv1qc!&o=i8wB5m_bqZ-mksQGzmPbyW-o5mnOXXUc10}U~j&Dj*oDy&cLDZVfs2_XR z1feV1+8YTc1dyK+FbVb3Olglpn#`6Ysh62pai>rY^q*ICadh}LNhM6TBf6AsPiUko zBoMR|D0+xJ4J~F$5|BGgD4um%Na79pONxGEwq?9klH%iYKE6a&@x;sWFoXzYU$TmG zTgNh7GLIUOYPBWD5K;n_k(3aHk;|_^j=s8D%;y@|3Q@d{Luvc`{%WU>6g6{7DQn!& zSM{rc6`z-#DQAqj&nhjOI#xyky~u4qU}LGR{rJ(7!pm{%y40m1^(&SR)V8c2+=E`@ z0eE>(+iA_uDO**sVJJdScV$XQ867s&Ovf8|g%N2nr`nL| zl>+ao<+{U(KTwX+8AvC)DFc=}sVziYT0vlKiEO0~UgiduxCA-?9y`gdvUS9+9wBYpqdmOr*CdyreqAdjgZs;EuIjG`{OI%?BPz zL&^zAI*Ce-tdfS${Ti+9X+)c>MxT(>L^}S}y7~H>L&v*!%~n?*3X`am^F^|hL_(A6 zIK@;5Ei_c#!cq~nDM7+><5_Bz&e66hTv24kZ_U=^XUOf4vJ_HxAxiNS{cTApO2P># z7y&!E{MAmT!2%v(&U zN+c~UGSL`4+llBrYPQwk2-eQUG8=Km+D`D!)g=lk-L$K?`l=E&4dJ8PCi!?^r6gsk z>P|*F5#Q{sx@{%vqi;0Y-olc%7Eh$2205PdSDtHJA`~`>rIUpvJiR4#>rxFi^FHS` zJ8;^{_OG8b1IutVAGj~gWICA*>{jA-tHP4`?`Atz5Ks@oDR5%BcUd&Nm%k1*)$c^= z2JZI8qt1&Z@gCu8eZ9=jK_K>OPjkS4LivO0srM0hi+19cq;_Sp$Zgg(R2+$DX&6|0 zZXA8o;BRn{5OqGJ! z10IeD$B(wP#XYXbc+*Ei>zh=IPKmnDzqFVE<^YV-s!CS+yN1o%hsb@kLeFtZLQ>%+ zNNG4w=%7Y%@nVq9xZJNY8gAh-<8(L(N1Z%gQhkaeAXBZz)iM)of`u&X^v5&(4PQQ0 zB~(%{r$}zLt~+y>aqp?N4pdJ;>#3|cEjSdWWV5gwrzaU79YI|xc|oqgfze)x>GD^S z#I2zLgR~x5&rh1UqmiawQArlG2`ud;$IzVP>ywY1kH1ozd-kIpQr^DWVkND)Q?pZ? zbIuYv^dBvA@Mcn1j>+IWc5bg?**AYUyw5zA0Y5GdE224?D;OygO+h{t!&WX;vEuVR zvm0atl%dQlXKs4`0NGs;CF9#IeV|GPI;%axxn|c5=!}^Tkd-OclAPoccaMv^xC-fK zWhrUcLJuV8Cq2TEl6;eqBvO23A>C~#rwU4&M={)S)~n>Wpa@Db0SZy?I5lK(Y7E)h zo=m970SIja1D1JJdM%eUq;`t7Dpq%77HP zYXx1wt>1r@MZL+mEf{SL=O?PMpPIHJ$#rxRrV>@)6e^BQ8Y)PU9Z6;i+vg5o5ARv6 zV^>-^ozG-<1XCI`-PzO>7|BT|IVu_Zm6N5e;b{qE0gtl(0Cg0a1L)Q^vx3`G2?Nr| z+B5CvURSK(k`#ziHx6SYFYZ%9^p)r+xS^c#1f-BZ4Q)n}x+%cKi4C?7M^rrl@fx$6 zWHg^<+orO9L`P!BiRrvHXB|C%?x^wtn@$v*6nynHg`%wR6ql!6mn}*D@W~*2dHd9k z>!(orf!ksoZYq$s|(NImJ>)90+d;!h~lk1#UmNzX5XiuS!@bwWX5O_uyX<|}d2t0>&Jo51D) zuRix1Y=V`cNms&1Bkawywtz1gN}7N5TZ= zmO!;eZbK4F#irX@T)-a)0y-1W)UFw4$|pCsRydh(R?bdG$Vuu!$NQ^#LfT4^f-;1s zmw$d~9IJ~rO=i2CBJp6x*_SX>2m+L>t8#ra%_#}-t2WWeopDcbAZdq67tKTwuX2(D9RV7qPcF&+U zpY3G7`KA5GYvF~Z!{!l!Ml#xZ{GWQh=iYy{lK%kam-ij7g_hN9x3HBB*-CNh=zjfo zYoqs~upCOT4monH6s5(4?!YTZC)#UU&bpG2gk&p`IPb4%ONmknuoPTD9JAg#tA#q? z(3k1wkTiC$b;1%?8MKdSQkDMIR?j&tv9*_7NGkvU4Ru_{CC?PbSYB(uzJPymmu+&TEuaxIX86}~7~8s1<*D*o4{q0}U*uA<*$ z5r<^F>UKJ^q7L8(E`QL{h|-%_4Xs;9>za{24j2H44P!lbW|FQ9B`q!pjHCnCnfvt) zG{B9J9#CzyB}C*>H=mOgcgd4MomA$b<27uP!13%L{q3qDks7 zJ}(+mK#u#ZAOM9pu3xgC+!eDfIHe5ts-MhzXX4%@Vq$e2pYha0QLwj6`!-uXyfIlTR zvIw(sR)RvDSxSZo2fCHBHVGJ72dkYuq8+uzFsR8wK0R2GkBeI_@0;yed7u zK!)EPQwzG4&zF}X6jL+e<^#bEe@_$$`^qml_e0VnWPjOE_g;`>KhaloYH5U@G? zlnb?)vKFY$5<9ok+ia%vSB*%q<&1>s!C+-rJo z76xD$nHtU+^X6YU&$6O0DZw--LIo;P?+ltsE`+D(7Wtl*%COW$&tV!VU=Vtp0dM)Rf!7 zT}BY9vYXV_0F%2?7Y@uIM|h-XkVzG5`|s1}3GB2Rg-Yb5ZF2+X9=h6%RRm-=pj=WD)q5BC z)b=Jl!lLZ1E`Xmmk+nSlNv)zK*Cj$cu%&hM5BuudPOFZgm2lvtJyNqBYtOUNt&M92 zoJl8!dy07u)-eaCX$cVpg(O(NTQD_5H*A#$i<4&m5JBMMy1_(*X9$*xH?JR3mYKI`l76Wi z-n%X7CvMp7sYB8NLU$VWn_bi|u**BK%$LSKQC%#>-^wMn8%O4K38gFzs8m+6MmmCX znq3N4l)@0=U}&3bMD@!I?)k-S^l#*SOio`$oV=`u1F=<(e^Zc^40|y^)AyAm5~$>N zVa|UhE2%r737Fu%8sRvY(f4PiDMNE?$K)dhPnn(D|uO?>7%B__iZG)sFN zaj;XK>?J(u`MVF5u`IToQKgznc7Rgik`d3L!UbFCU&$XGw0z$Lw8*8x|(;imx9!rnw?J*TixB^I1svUa#4t~nZ+Dpo{ z49%4H6ZHEIv_NZca2W%oIT>6b)#ZCU)>1|?NVZAGv*6dC%#T=t zrFpF7oQM=@=5419d6Y(5O@ znGdD5bnWqF%}Ut#o>pP zM7w~Dt~{{Y4dG?nKBZ)g;5HSHm!%$xPqK?qZ<33X!EI=4OxoMf`h`mwCBp$j3aHuO zClbqt8e;NRIe%d*r^aigCUCEgE$jozA-7cG$y;h^)TtnMfxn;h=SYtS`0T>grnu%6 z+7J@1#q=MOf6tmnMA58uKLGW^GS!!BkCVZW^l9iNu z+q>-}>YHH^pAM(nSZB%ihqg~E)oZ?>Xko5BI{DB%9TD%{6Wc2xf9cm@+0up81i=3FFa7YeZjrG zRoSFu_;WRCKjiPNl9KzpSqcZP<{bQEN!8@@s2^;ld{bJ08`KdQ&%!?CN6|=?szf%~ z!OdB3W%vrx(w4)dmsY1+9PmA7!kOLR4ybX!>g;bcg=I+|aM%ERwPJlQ*KR=ZEn8GN zE-J=;Gg{A+%!LIf^Fp7?mnI1rA9|?ttuj6SY^~A2oA*~BsT}*IxA%>2dx2Lb(2}L{bqW^-$FIhIiJtzK97x0+u$i$GOcZLDI|~**#vX&2NmIb z3WmU2hgRK>q%c&FbIYO4OVe;!=cQx>@PZ;hPj3kzb5hkjZu^z!@T$}ilPUoR1pa&P z_JLD_!B~y7zErh8F-yaoQmrxj19qQ6kcd`%T^f|A5*rLH=C z6sbZ%QqqmYDE|P`t8E&;Mqv!Ks-d=q)!E@mQBsmQ1JfM^LXXdG!yerY_%9ZYyOkh4mXq^U}BGV%5;?84s#$OjT@uOx`Gr{C=3AD6mhEgSnCGw_{{UTXZrN%FZN2pkwB(Lrm-Sg0(ISY5OkKC+-TK8HFk+ zDIk2`HFz=>LV`#sJ;ags>b}?^Y0-M#PCF}|xd*(df9|cx;qJKDqV?+A>M6>qUfcbE z-_zQo&*!bCN}fnk)<9oOcvZcmO_0{K7P4)nc6ycyK^~A&6i6qoD?+$&eN$;NbxS<@ z;j%`4I-6x^aOYq^2bn*2ohL53;KI)$bIYKn#AgQESuR~W2pSZ*OhR^ z?#)@&3R|A2fN3FtX*+hi}?*%_y%bEU$umLJ63K;OL#UYtmX2yLH0V?qYM1x+@r>(6x z12*=OjAHp}#GJSO^gxl~9tqM><$?+q)uU{enew;29?jt5;;~csVaIO_avy>%E zl21mK?k-L%3$gKBi0UvhnQt4SD|7O8)?wU)*-S728SkIQs}5 zf_nQCUv+N-HpxT$lD^}W@S5Jf(gSNwQd&Y%bK(H}71gb8dMgj(V}jPQg#tNsIP39O zw$!B~ZV1T7q$|TNcAk&`W2J35Jk|2o6u4#ACzjPAD|fP1#>pxe2aw0MwyU&pAh_y@ z9W!1>Bg>X+-bv-kwSy9hXO$$S1v}QDp@Wh>@XcW*U|~us$4vKf#d^xg{a* z6pUIuHrHxGM^bal(zj!_$On2Ao=0{`A0J9Z&lnZ8t^I<={GfB@DyX^X#v-6)wS_5M zvHd-jwJ;kD;1UZ^K%BuSA#Rq&dIb^B=C2MW z65PULs3)f*o^|CPiR$@0ga(J&02xzTiHWpE9bihk?C0wBOa(H z#Adc7z))RM2m{BhVG~z)v+-mo<)@6wgMD44u_%fqKR|J zFd@ZhK}c@{+gn_Y+ltB?LF74+UPm$3x3cORP90aGdSk6iX%O388XAwdk{L%M&XpK2 zT=bP4IX=3>jw9<5k`>>cb+sEYv~tIAt5*dapTVI}qXUN9N^wdUjM2k;0Vlk46_jAB zr_ERg3Mw3ls7S8nWpJZ|y-l)Q9S$qfBPGP;Y@VjHYXo)y$F#|*t?^P%TK>EG4t5HN% z1B|oij>S118PDCNQBoaAN=MYkA`W@{^o=riD`5h+GU;i+kU&bh@~HbrYk|cXLVE=5 z#_WuaU}M`#Bk~RQfhu1?lmmnD({t{nOHK-R4}w7MrA){OC`-ebIptPLCJnxa0+*a{ zxTp577&}r1N6AW3rKv$B^XQDzS|2->cb>kFEb^rbmX#FtDajbmD!gcz!{l-LW#*yDjz*JG*;?>Qg*10c9kO0DlX~DHC zC6p+7T-Swkt0+g{iWqfB@J>2 z-_2gLOC!sVxg)R&E9cEz>hOeLgBe;L;<}cJSEL+B0kTeV4LG!*jjaW`^KI?}7#zvx z&Y4=6%VX1FWjW>7tu2i>B%HQX+VY|Z=8EZ9;qVZmEvf=8{_7zU4236YLY-QYf#Zz* z%6nz9x0ab7R8BGqm(H1*kjhq#f$*?% z&bBIJ>?NY(JJ-0W1osaLorokWOtz!8VkL(0l$8*K2Sa(-;*tm+ z-c(3R<%BlCDO!{kqtKpxDN|}pcty3ccBt*ZJxxP`M2X&7-ykIkO1xYdO1>kJ_b87I z3vIxJBbnT!lzKq@mU@p4r>%Nif)*M}VJc1u2fmhets*#a=0X-%jHkY<7{!)uyBig4 zXp-&#Apt520YHrM{cl9i})%DGn7 zAKIn0*@ribk`<5*V>r=v;%St&_Z_NQkOoRZx%*BI(%jRb{&%2pO~2}*hV z)Y>0;Je1g0@>DtJAax%&p*JNp^(hI)?r0xk4F`%8I~fh{A(SVW&rW|Jq`)Y;q_1fq zIZiT>j}AwjdTrDxAt(!3&T?ra*IeFQY=i{(Q=(wGG&tXDfTq$0@^QHR{L(jLA!SQp zk?60|&JRC~R%A*!3R~M!u6fUY^cASDxhhi9zNA!bi+q|s5#iF80ZXl?s32?~FDgvq zYEy1(Z3!L9!hZ#ATKin7qCFo({8W-d=?$p?l^oViF;9ZDXnm!I(h8bBBsQLZH6&XK zaX4+kfOCR`)m0Myo1xD)U|KsiU)M?@mpunJbdrocXs>)q?5tf>krWIR+{O1X~XTRTJr zDN9pjJ4o4_5;4xSB1>sT20G&;X0T9@prx%Y4)8fvRPuHx zFgdHPYf&j$M#Sw}ejkCXo3lodxtEM(>;wd_rz-a$fD^q-1xJ}QkZuP!$p<{^YNQZK zmYkE_;ZRI!j|EB~f-(m~;aO+l9nLASkA#zh)K`$8u3%%^Lh@09JL(xpI(!>lLyoCr zscLNmV|x4R3d&LdS0T`P>kE;)Atz`cCj?Luc7UYk))iGv6BOSjQl+Q@wDR$+paiK~ ziBfrEHI=O?ZyS1dXPNd_mcpDI#?<$W`d=MY_h{KB(cq-5%yLLQ4SOqC1qpDJr;(w1 zakr@MC#_?%DfF*7D|C@P$8z-TGpkmFUK1Tl8EM3*cbwOSU99NHcIy}bJuJCe6MM0i zyFqt|k_o^rdg`0k$qmX~AyI83Ef*42dIAl25u}8c)!F(ds07xhH7=hC34Y}m^5#;i z(4AqW!b)4aHVS!sBU8D2l9L=eH}a!_tPqH~f`j2feySCNh$M`aQLSv=F-S^!hZ%WnKHhBHkI*Sb&@ zA=yp^l=2&CBRcO)BhU+fd%S^2&JAYe7v!C+ldT=2iC9j|b=qrBnzYh)1e2c=QIo`d zKFB6BFYRC14q~;v#QQk(QyJBJMO$<}N!rOe%F>@ia_9%Hg)p*$^Uf4)PERmuCU}i* zD9Wwx9QS7&tHQXQZeVsk=DEyu9QjoiNUtP94n(Oeu0wgiE@!`&FBL-_$l9cC><=tC7*4ESg2#m;31K}YA0Y#D@Boh0z+AXDpI{MHQIRxjQ$yRUB?0Qw- z%WH>sGtIQSdGX{u#hgCr6-QfmYp!(@!S^i^Z5xTE~2W=(43U6E6G; zJ{k7cZ>nZk=MuPKy;36xxt1OUSO6(VcqCgw5-&s7zA~{oVa!Y^RI`vNE{u=b#(m}&z zwUgbwKZdngpySIUYZm^Pv(noa^$*EEl}d!mwrpZU~*^Vfp6z87lP^_SC+nyc@@ zc^g>e9c`h_r9ntnBhYtNt=zdDStL?E*-l`Wm;@Yid;!zfUevjXNC-7iPQml$gqNEIOHu~zV-6r< ztMxGXB|-Tdmh`qp%WF?dNH2N7W%J`G~9iUNWu>ld`;$ zrKvo*U>e3!Nx}K*INQ^=_GQTFC$8xUA2ulMZVenEY$;x+ff(`5Dju&NmPfNE;E|UQ zthT2%6!OW&D+o|picr6Tai1SuM@!RzQ7*O52O-?n#J@B+Pn@(9oOK7E#Z>ytOUW|E z+M+|*kbNb5^}P?IG(dHGyfIO-E(-qc53m~b`TeoEPoy7={mQg;c%|g3#K}Tsg{c7} z1M9g~ROEH9vfq^_zM^7eus0%F6P5fj^LsyySwoV^-kB|^`$bvm@khw^9Eo=EkE&%j z=Zf{)CvreNd}<`8ZU>{o9eQ_smFKsZ0X}-r$Jsgm0PNJQZZDEv2@?fLN=OPPt~m}> zmfi|Hok+)aY91e+oGe@!!S3IXf9Tc(iN2E6Esk9I6@DoDwLe>n;PpM#UWeu+eNyEeIp`EgIj>{S3J&Y5DepK*$INOMsA41OsIbv;WaUY7 zI2{44tle8G03N++vohUfDMz}|bDSt8E6?4pXfLf>+q*WeQbVU7AT=x0ai?}e!tAx$ zxFNM1FR*$M{1QpND6TOtp-E7N+n&DH4khQlC?_yQAF{o)CaqHD9J z;p*!{&4%RNVgw~eYLfbS50;#wYTYWf63VqC1t^s%S$GVN;A@i`;kL1mu!y>6Q||=i zBE;gk`wl5vJQw0qsR?I?`qACqmgHC;89nEcf8AO~^#(48{k^lRqH7H-^04jx3qd@F zA5Azpu5=)Z+n)PivW?j0=r|+3xg2m$h-y-|aPL~UwGqqQMT{Qjx~qQskFtJ=okZsmbX#qw{uSDkw11QvzDn@V5p*YR64tV{sAoHt z=00lV)Nn_ME;+fb9_qc#eU-c;cgCU(JVx?s;{DIFTYN3n9-sZ}(8WJ~#LWJJ`#P1L zDe(UQv0JWci+C<8kVAlwM}2#1i##`V3qtjLAf$8(UtITBHnHT3#+geI;&7u?1%b5% zYmA|+aa)ImKv>n*!nCIV zc7Oq1j~4h~r%IjHFcRBiJA<6FT(XZQ9xvel@UHXJdL~3*Ppjb?eTU?6#|h;kKM3y| zUE~VqMnY5VBytr;>-cB(qTfMBLdxR*01JCm6zbSZDdweaIK^u`ZsB`OJ=*HHswhcP zP=#kcJpGkS#PSg1^u;f+;atQ75xBp9h=6};HuI+Imys_YE&G)344h8ocgIrP4!dVfq*B>4#Oo%Z+pi))UeJrM2O zl1GmqDJ0J#UN1*p#m2FuF9#;(yaESGq`y#O>7qV@GX5mh9#UK}Q6@9e(zK3wLC0Fs z=ah#HS$DT=NOK9=Qb!_BeMA`YDB`j7Toxa1pSZ7?JnBNPq4~vjpr&h+bhBw7DFDiS zMEruX{q`Oaq;x7PkbBBMLm+mMT6tq7E5HLDG?~vR{SKzE7=6G_0+sN+mFZqVTtkin zj$bsmI0U6ClzE?OFliJ1L|WyidnM{UG9BELk|iEo{1H@tsNo*bWui=8k14$i7=SI) zl%SJf<=JJ+)EbSjLr#qj} z=F|}aeB+2#MJZ#D7RB=U>VJQ=X%e(3fiKE8OEjc~*&cV1&g={yS2{)X#MoTHMXpl2 zz&x?){PamxAts$#J$#K4+ZvZPx+y5wPWmU2uglTpSxR6kmihK=0VjLbeH%1QQ?no+gzj3aU`bM-Ne`B}(Mt1YUnPoh@ehK-_ zZdZ{P4U#vjSY69%lT9J22ju&t=KrANb`D$xG`8D9V;7S^|( zgp+|?RIeh=6g00-RB8+)XDM4=kp0bQ`c8O6w|2F1)Jsu445o%hk4nN`zbmRVdKmC> zyPRU2LU&qPRy{|ZB|KBOIFb`>P*Lm4opuyoBYqMA+Q_(S2H78FJsbWZj90h(miQR~ zssQul`njcBv<5h7=?vB(Z+z2PrIQTz3c}Ej(O&|v0f>v^n zQPb63sr0MxRh1{rY%&%V$oA6$e&M9gc{A{WEBKM88fml0X5=zHLs>stYl<~mP7W@U z#5?+cSb~%**;>ZG)Te5L4CCjnri{pNMp?XxAE-DaB7n0k&b@G>%fpbbq-=2Z$sIX^pfvPE{gcsK zBoA&gTal&Uw4mE@tr_n}ngpN^QQO!3^%C`5zXe{IA2t`G;->*t?8@V0afeg9$E8o4oBsu|NJ>k+i_HovF^zN^xn2MZ6aztc|?j;S7 zernYEpLJz$Le|PgJsc#D-BdqR&+tmdydN}~;rAAvNO7Acp>Upf5m)!=Sm75MW~*W} zweYEY&(s#5zh6mXHva%@hYF@1T^-t>53096I#Lzsx{x!2m2LZisr!ak%M!+tv*!a` z0^@7MHSb#OoxH$8hcArQqvZF-H(l%(rY^ZpEGY#)IW_co>9QV5+imvuCjcJQoc!3P zneuK;yi&KrsUQugc>y08z~}d|ReqzDa71yb90J#qHyNK=TRLJ>T=|7OGDpi#5&V$2 z$tMb3sSRhRX(2iIz^>I3B6fg2{0Q!({{VEE%O4TWekyQc{{W}p?mp?pb1 zTcNfg+@xd>ODwCecQp)r)Xe?f==_B=#ggQ-W0IvI2_GoOv*M`w%&gKlV!1gE7m@C} zl<*JTt&#Kahi$tbAg6Ts6Kbu*d+4;J9(_)6T~%w2;z~uvLs1r^kP#pxk?ZI8>CRFt zah+Pc{J2y-1()&&_U^3yvpJOX%e2l#N0A1kB&|BK&~P^?STvOR9o$=SNq<+sWdo|a z1t=5o8tS!Pw37kWS9A&~$xuobqr1Fh9(?JPT`W?R;w`~U6=yC8=PLO{7PBMlzAZ9K zlbxb@9Wu2kGWD!v1#{e(%2&^deU0QzZ6ud9qlA|GPeK;V4-RBd%+uTorAd+`_=(w`(PF2kWR zH6((pWTdj3r`K1zwmSnTEjg{Fw6%1~QVlYTWv(QG>laz~WrKvMtfz7C$1GL7?B6A$ ziVw1{i{!JzhTjI^d$_!=QvB~azRS@msO5cZos(tlaB4vmnOkS zq<5u6jC1SH|WA2mn0 zl&s>s47RQSaFv{gEK*!0Bbv@h`3-Fx2I1>!amF;uNkVzy?DP5RVHK??!czRX7nUB! zFj;XST(Q?YtJ{ugHdEUPcM=aW1FjtWxv5gf`(;+x_Cwy_-w&g<6yA(wWx<7DXXB>i z@T)_`d@=7fB9eKMRfCTTm`EC2p=(9X?$|z(iexBZC*s96iB^V=*ikN1Sk8Mz$jKwe zo<9vu%jAa@K7u}m;iN={5uu?BCnZ@6ApG>MHNQwQjKI^ZBeOUOOGz0&C3!+r;!2UH zr^jfFg%qgn9?|$|9E+`~qFY=WmO#c69P;(^H4aVm$oA6Vj>dFo>?ktRkcxSL%2Utd z6=V4>To&(?4vt|-Qn$H0m9GT<0BfZmy;RC?5CT>8M_NjO0J_iJt2fCtNJo@ri)-Cz zZ|-v9P=sVHL)^)E}N(Z=$>EcD}>pJBs9osBxavl5|WiA zIRFoXjN=}>WY>1gIF9M?N&f)mR~g3CNoj^2a^Qp|)THi9{jWTD<2CMj{{Y(J(T(2w(PpO(G*k1!9oG{Rhwom41 zZ9=>qinQnd0J-A4qlK14B`#a|W2as#<^qsXeslp+R&UKRg$K+O5z%d-#qRYAdx5G} zsOUs^lClm@=R?od4OQx8L@X=dg|ow04i7_vc1`IRUhtETU)ktHoa3HzWPCU? z+B+S7imTYUf>XNXV^K)}kpWoGw-s4xW{bxHlC*@4aF>TABe&9a93Dy7%1#g8`KiIK z4(J516s;X?e1pgc4Gv$rKYEwjZ!yA2UE0W_xQqx(z{m9Yse6}bNM*;%ZSEVDPTcT*ZDYhP;`39FVcYxG7!-3pDo8-R^ri9~n(} zdrIjjq_ZoBnoOL06CH$+_bPs8NG*of7D(sSeGe}Bi(W1-H8~xUoV3}``GqKAQe>>D5?tn-0p@^uUOdH9>asHLPZYQsKQnC_17t$eyOwYgm@%+E zN>LMrIvr29Y)z`f{GvDd7S_%Ofg_bVOm)a;Gi}dERMfM8+L=g7PJ6jyog<3YptMLW z!zJS9ru&aA3EHF20OO@uY9-{$+vbI6;bn!7ICeIP)A9n8Ku@{s4te#el)=!kqcTeP zd8R_Q9z}@4mD;a5f#%!_RCXOgi+Br3N|Fvb((@wn3KHy?h#BNc^XT_y6)!tu*@)3U zPFi5M+DXt_Z5ikNi5WxY#U_Z(ky=y_53L15mJw-TT>ddm*B>~2m8x8p9BCwt&AHi+ z!%^sLThQ+R05wyAXQ`G2Rp*p?COBfnM@;GYs8Exn;k1=6Aqlj%wzt6H-i`^}bfh2; z!Ofw*Lbov~fP^rZ9)R(<0u4GcCC;tGxth35Xl6{yB&T!L5w4|(CEiI*7 z#%-~UD`SRQVd&*av)Z3g zxpR9>&B!Nl4r7_Wx zG3ylP6>PB9_1WN+E8roP5&r;7BAaH)wYzp&C(4YqAbKOxN&f(OrSaxkm$hxd+DOMW zl0Hg>mm+jMgwGRg(Qh7<>tjh@M5nWB82JTmji7CbY=+s4l`qmeqa%>^;auYRUHhB`*3T+>`jK&_cX<{gn_#XY~c6(ZAei8*M?N7 z3>~;TMn}m=B*A>|E0pJ;IR!Khep=R3n~j+$M)?~Wp3nitwEQnw!VV9s12p8-@zU67 z5fDm<`kGU;f!~bgnVFRPD+rGrl$5CMC9Z1zoc>x~sgg(vcd|l$xTP3BcClHrB}U5* zCahIG$x~3KV<)ptF^~x<_TY+cV$-TxXeAfomUkR1WG|0&5`$M8Rc)F)DqxUqp2=u zYg7AB-a-1hmT}xkQO$W~?{SXup*eWm=>TrRurLQKj=mJ7I=amfoz3by8$mu2(dm0| zY9Xn0c8y!@sOsB5Dmg78ViJOVeDW)1Lg#Bc5(;^S)iosJ)N|6DAn}8QkzU;^ zUg^fbB%|uvhu^KR&T`?Rv&D_`WS;dJTe1|ERNQ1J5^*^0N%a5$`DqjzeZ%TIZq5>q zg@Si0J|}N8P4})eaI{23<~XCK7q}Fbn@|c*%~3Wu<-w*UHr(zeT9l)eDM7)4q1(WH0&tMmZE~Bj3IRz=>d42&DaTbryu9#wCZ(4pt(!s%?xY}idT3Cp zrYDp)0uth6{%JO3kN`hbUq4?;Ugwnu0T#oI9xK@fMid<0K=xNsa@ku5p1!ame-P11CC)+ww&wa64Uu}03Ni*3=OKrD}yYbgG3Do+H`L8~? zsFt8k@)>y{W1mi9s@eWpK2E7~Vl^Cz0|zQhRUUrYVV&i(R66uzFbTKvZr!R9GjF`f~Fl0(l`8q-$mnV|E_8E5Jsjg@pkZ~mGsj2{x+&m^wq}>aeI9_!bQaiaGRvZboy}9j0b4yI4wQ<#0<^zwho_bE2EOD;%`LK<2JOn6ru^s>b79BkSdp+Dqzq^tLwEl-!9>G&voBDDyVhx_iA3#VX$VS3X ze?weHX!;-#t&b_zxL+k?3~euvJ-sW`&!Q)N?MaQoq!g&<(r~Ebmbc{h_0Bt~j^@O$Qe)fWCDkjUSliR4Pfq&fX&*!vSh%2K@V%rH z@O>qZy-l(_ytshl-MTn)87_Aftz{tAIW$?aKjK+t!lPDp=9|=4+iXD@^uvxhg()zJ zUf)uWqJBzCc9Mzjsrc_pc;pO`v}4B|)yC)OfpI9pOAPSJA&|9UPL;1_Jwlq?^5Ww3 zgeW6GLk_Re1f_d=_g0Tds8QOGj(khW+Kx1*9#ben$?NF3>h;rI$`ge?lqGhA?MC;L zf_-(y%ktFYLyE$5O}z_m(IB$CpOo|KT3YhU6f0Cv6sb zoL(8)_G?Amw35_v&QuGkM1WG1_uzlJo~AA{NJ^o&?o;s8qDenBaKb#b{G!&-4QT5_ zX$Pucr~*D(*YxN4N+=XFr!5272!Z@+>iQiFlQ2 z7OTvJgf@hzh3)}+d3vx#afR;S>=d0{L+xueVgv&j2#Tq@_4 zAC*?Z+SM5i9;CwM@d`xWl$VtmDoYchq$x!}`IzZem!{^f5oezpJKa`jNeNP3Qc8Uz z^;I1FL{^!Wm!504g9Q!+aw;x>N64Dt52iE9u&k@yW&l_H=$@Y)Ab*bDRBHO1|oiA$G-aa4GjBNLrVSggnlDRl&;R zua!EH*htm#8Bd6529c|b{!@j`!(GTo@CZ#y&}Zn6sK$=%dfc{10uf7YubZyS1p6?R z3NG4WQE9%)JTwK7>6q$J_6(d4X|4}*ik?ymNh#NI!79k~Tl^G)R=o0sl&$Y;`+!*^ zI9LFWi;%3}q-T7h@zuefLStJVipmI&Z7(EXty>aOJb51K_WZ{cwGOR@(vgkLzq_BX zbFZC?)_i>`Njm!C03iA=X1ya?@#vDIaT4MY;o5inm1XIAhrs%rX!;cO#zyo;OX^yQ z=Y%K#Jadk8D#db=;Fi?2ufjoJfbwB^k^ z$34nG2p+8Fo9ADfbg2=;(i4rUQ%P9)HspNO^MJ+I@5e2okvgEm1Rx>F$OUjb#7sY|2idy;g+D@)RS?@U=g3(n$WdH5mh_GTHwCV3A)r&WcKa{PgI@i>j?l(QK8J`O3n4H>l_5qx7d`zNq>z z{{Rzoy9rKpcA7$YkOkQQ4u4`#Dv4h8=8L#VTAtThbKvvE(my|yRl=#zvD1YKPAm2y zM!k&_5Tunp>VIRNm1XH)lCM&%?Pyw~gp9POrD|ot!(e070Q=Q%+aJjHlIZJ6 zK2V$?Wz-@)^^%Z~7F?L6P= zd_uBx)CH|6OJ{H$%H@iF-T5cqXID()*9;wDOs`VeT;1?Wr7LzmB#KJM9e7azw$jb+ z8%k2WB*dAt`*#%XKN+rD_q7Es2Q~r^EFb$T$kVV?tRaNsJo8q5oW4vRqDNt~5Uo38&YsEq~!EaIqn{+ z%3hyJ%lplp_^VC%#pO^X6p$31<~x9-^f}KzimeYO9VsRU9<+VdWJD!F%Yg);0Yf(F zAoM54x~U!sOTX%#8Cq^>xWeAsL6h4_SUkJyp*)-|`lTFo(ofEl8OW(z;J(UU@PDoH zap<33E6>Mp%e9(sxY2J-{>FFqhr2)DD~94OR6fmZ+hh~40At&`G^pe3Ts7RY24lEC zVt@IS^CORZLX*SiE!GV$B11P>Y!}~=A;PY~vCCp`M&n-Rt-<7!B4?v?q+PM*-q3)L zFuNs7=07_$l265&TM^wshYGCs)nz0VB`pF6k6PiUIIG09s5-rAH9&O8BmJ&b;l3yF zD7Y8z(&C(+=>UDseJ=y_nKs7L_f9@qRNI9OB?4j>=>GtLFq87+R{^J3YiR{!>g%aL`Dq#X z>si#Ap~n)Jbw$|Y3Oi?a4rjb~W~m=ZmtpIamejdB-dbn7u!)OSIV2%XHk|b9-CnbK zU;!#(P@cPe*GNBi6~fwkN%0?6vitgC4x_xa9HqCF0S-z^R7au|TRe#YUBrAKZxh>z8cLBLJr3O`f zw=te!D!rvjQT7AN+e+qNU`I+^k#~lTsM=4u;a|o$t_Yu`H65x13zgOd$}CHoOR%Iq z%8-dD2||jHqIvRh2N>wA^2avwZ7Vw+kl_j$!CH^Y-HOS2E62+<$LcZ54beNKYF!`O ztjg7K!C%87Yf1omk4o_Fzv067@u)GoKM# z5#<5HC{8cWIIP@}jCu^Xq4QT73w%P>LR&ty6Pm&;v6gnX9SQa2Lnf^K5-XNbYhCh= z%X7+qgiWalI?eT=Bba6*pdXLMo8|dY@NKyPOSoQScx@{{KM}4Ee@szxFOI9!kGDsg4Bk0g&9<|xkpG|)T(X=^kye#D8mkFrpd%`II zG~SuLNmkBGxgkkNJ~^fp`D0mIcP#0r)WGCDES!5ybNb>mrWR0ua6Snc!S;1N+}0b2 zhXzPWPh4ZK&r|y}E}4Y2tmv0~wJl6XLLulW4uW@XQ3E5|E5P#H5uWX0aPj@lb5`dv zIrwL~x%rEGYupPcT7e@UbLX#XfgP13qB~s1d8Bf!Vd&UeDfOQ$zNdL;n}{u|hO8@> zGUS3e`wcg><%>EhJ2rT4YfjE+E0U#W=Bi=1K)RGAmcUpf3}Bu_tKg1!0Q%`mO|sY< zc9a8vd=5H$Ye(pqq9d+PqUBGP_Mt%K!y5?4a=TjEe7JSScEsVvpGrr6)eTcCZ9I!@ zg@QmC@6Y?O^4E}@3ny!Y!G8S^Qd@rLGp7vO&oH=MhTz zb4bUQ2OE-*mc^wc^u$08eMh>XkaX?F=+vj}wwaR=4WjgwGQnC}Yyx*Ef-nFCliUHM z>W<#vP}l%Z0eu;`Nb44Ssx3xY|H*?DGk8b)Yxj{ia5*Tdf=C4cgz4D1z zNLAi3Kp=pqO?~lDWH8uPd4M^C*Z$sK8RyowEtb;v)uV*{cF-`P-T?LmBxmmOHMD&% z3*jyaddB>c#ran8=1ZI2nQ2nWx|@4h>FO2Z>7(Q7oKi*J+>PI3Z$QV(%9vPfqBDgA z0yz_!*cyxoDQFz@IPvNDeS)ESP9)4;x^e7xK2hFKjvei4aE^JxBen<4UXPStl#v7t zX8Hr2HZ+QBVGV$GY*-_rw)FA!9(^fVBR00utOaACCvt)HcjCHX=~$?bt&@G4EtQeEIRl{t^8TEuQ*5IQ*c&&ErwFDpO@8E6D$Iq-H=MhETw%u^(>1RmdPmzQRWn)2IJvd zN7Hoae-b{jemr6iC$_jAWC?nl>KWAx23SG3Mv zpx^d)$x;pw-CPAL)GsX~yaS(}wl~3!(LIu{lG3$vJCX?avsR*tzy$8+kA^NCaT|t7CnjASWemD*-qs09BTQ5`7iPshi;ym*yX7L2c0{M&utzt0Z&pr9*&L z5EKmr#tk`Nol)lUAhmbk%{{XU`RSH8$Wyw&SZ4Wov1g)-XZ5S#j z!SsOi2Rw2J9QRhAMTh*SH1(3ilqC6OOy2;snw&}{u4qX-&uL1U;3khqSRz4A>;)J5 zs>V}KHUdfze`EKWyltnflE(nXeeKO{*yD@DaZkk**DwiGdyvJ|CzIdbVq)ueQT zB)ra@h)TH~?WB?MW9IAXt=C;iZL~7<)lGD5P}+gbOBu!z22OH7z#s2Nd(qro)Dha9 zVTo#M&090mXjAC(*)1oT8vw{Va!O7)0&ob(^7S60hXdIpUE;{r;ldu5uq~xG4%ZPI zKDV$&Rr2^&)M@K0VM%V-%2r0zm9&x%vlP*0yt{LGA~d8%O4v+}&12vk?ORypHzf1+ z4Cgf~VFb1?=_*e`dLLzWU=*E&Lz7<{hKDpthteQJ7$wr9q+vs9bP7K}7~PH1Ad+JP zrE7#RdNfL>beGbIbW5n;zCYr9&pFR?-`C|iLVlvr56iZEQLy^_jX6Z;WBp=jX3f0p zJ!(71tDClE@WouV4W3r=-nl_^^9?kGfox86a1#|6m@)!CScbp??RoM>GH1L00lMS9 z|5c+5&J1mEbDQYY+c69a3^1;>#@h2!EiME{07~V*xs9}))JBlKXZM+Fq+vjVw%lBK z95rPB7}_V1>+^V7EJTmU5>x~vL?uV00Di$`(wnKL%rxOv6mQ9NUM6L4;o8~c1Kf_| zvbW$$4V(H}rygy(TV+OqSvKCM0T~jKd;)$cu@ZpX&v^JR8OWX9G8t4YHV`ywdjXh3 zL&}4gmERv^2N1GHRQk}D_b(D^ZRM2jZ|ccAG-lS$MdW>V>&kY@{{KQyS z5R}L-g#r$vV(GGnkg~nkmiY%L;TK^dTavJq3-!&NQgKRV?MGn32`-pDUhG#tSBPgO zAoSjj^4f(mL>~$s18|iCZ!1*F+~ZMFT>#o-Xh7aFXlCl5WM`GLQo)`N&#{Z0fZmQ0 zUhvbC<$@~78h36xY@Jw2loPpRR)2%EB~tSc zsYFbkmY;QtHwW7FQ(gI8uHxk1cPk#ViEkfpBXlLXWy9oV&D6?I2bXkHAiPhGw&48h z?PoCR11)zL(!enLfp^k614yutiy0bXcXqk1f_4FJ$W&>wq+FC#z9v~MOi4*G8J9i{_EzzD6oR1!Z?fS$ij!= zbdc@VWZ|!lK+H%mBC428nFHqAybK4CknPSFjDpOy2nlRGW&b`F=7%jRLenB}1)1T` zv-FKWo<(4m4X6{0NC<3M+WDtqzMEF!C;6&b^n>xjM|P_DNEP@CD<0%Z)m)JXRB^Lc?(=2G&+m?r~f-7VKs z(D>Ce>q9B1KS$6g+*GhYq4IK2yupYeX@ZV=@OsXoj&>*cp=WQ(1Md;=Q>>u7?G%vG zHOOox+Lc&-2`5`gB9bV!yZyDNS7*VLUZb-o=hDW@9KK{1L&TVaX#)Us`)tFms#G>HIDHHEGPyb1S|D9)40=EhUwNAKzu;t~uge)p_O7$(MT4_e$b6+&`Z^Z0wx5h1a(Ka)aQE~=dq zqmDdR@^mqdQ1c)$HzTjNj}viZ1n}>A1;(vh-(8t6lziR&Ylp^b^3XGF!=GoBYro@V zUTS2YofPP_D)}26!y82C$E%hmA{V8gon&$VRuJqXpKf-p|xAlv=3Zc!IX{Vy&T`Cmmj#n@?-gDCdj*N5%G>lFC*j%ckVI9#VQj^wIs_b%YnYuB?r%Z=^7({iA#-o6+4Z zU*Zw@FKd876}!K$QyYQ=;np9IDCzS4+J_{aeYElT9qpD>IBYQ5%v#yNj4u~RfxYZ@ z=N&s6FAP5YbM{5?Mx}Wx>1i))t+9W^*}C8pn@8%%L5%ZHIpu^2P{h?xVdKzG16;oi z>JoJ%w8fUa-$xLTq||6ZWzVS+RSM=of#Rb1gI4rdY6r&aD;u}eJ?jMkAmfJWp z$NzxCGe{edy)J?eVMrJ;M^u>uVBK=#GX;q!bL_3Y>aRq>>djTF#4@_Urz_nC!NMp9 zKC=nMi&%vq-*V;^gSDOb$;_C(?p2x4R~SXQ?m+(s5=Lf}Er0ACKFnx7YQ|q`&65qaW42dd!=k5>Q~`A+aH-RmPFx zcOlp7+qtU?xtE%DIlcGj%Xs$TX_ep4qTq7FpV$c0 zG=@P!g6y?HAjQsZ^?Ye#F?5XOteG4y#xGT>U$FGC;duyS{Rzc@$876}mphG1ru{{K zG8wgUntf~IR83f6wl7axX^iMAS=+Vkuc~|eYS{YT4uv<~{VZ9&iy#rk6x}AO>|#JD z!^%&Y@S)YAsl|Z~!Q*<17k;rm*DasX#3@@|$X9mghOm4|y2!!2*b&y?&)mJCuZxZw zKd9wRrnja3w}gEuap-3%QY?doKqb&l3QtUj&%ZrS2hZ%}=1P4geYY=Ilw7W3l&dyl z_^z6Le)q&UzDp0Uv#3Q?YA+!*;ZCs_Qi z?KW^GlhGiCU)r-erXngf*q3i z4dfLu9?hw}#zzS1fRDE3Ys-yjm52?0kS1}d-Fm-z*YUILgLbY7rew3hWb3)|j1t#I zTq3umd66uo8%D7+8{Xun<{uF1D!%uZ^QUGhxy{Ls*D7u33NaL<=@m9+rUqT!=W5~+ zmE`~{Lp}KeI%%}Q6F*pZ}R*;xqba%3APsRTV4y zJ@j|&ddO{c{372uHbiWmN#ZVa{bG3rvgC;#LiF`%HD@fiVq1+Q@S41s{qe7WUTEn^ zMUM=%JuS|l8J%CGBA4VXlzd|9pKdEUB83Ed1&WE5m2$?>&1Hi4Tq(tT8!suuViIS} z{A1?Y?$WSaZv@^y7L$k)WkL6Xco(qloI<=nFR&gkdm~e-pz0u~bs%40ZVq_W>h^7m zAMpduS=W)GHWzPDSNzw{n@m>&JP2T#2c9T@MBD0=&TnVxBWDEv0jB=}fWyb#RV=2y zJ0BZ6Jlepemm!kuA1-}3=aTbFhLat>+3cJTy|fU1p_LgN>DMprhjBLN+h*%RoA_=E zMlgA4;0H-mq7_(xk0{z=6V(H7*?hlBqgW>2mT!a8etKm3Q(2nuSIEMbogh8ngQ=lG zc2-TPf`KQk1FH2U7>32#D*Zd+=hc;BNC8d|9{IXmwO2P~7x5%Zt!^ngeP;^dW4LkY zVzpx9?prQ#yZiO#VZ#7H<=EZ_iGt=uak*dG`TFh>vpHIVR8Kq}EP8v%J*9!xrI6v8 zom{?r4IZMe>ihV=Bfq}NuCQfr_bZUEnVp+cLa%gz$`qB6SQ4TriG)<MQ?QWlzuhM-+V-&U!VMv;{yDRFLYCqfN#{Ui>gN^%&~YGPbXS`!2bA?q#<) zkDhKJUN^sRjFwazPo_A1uv+Fe=_;CUK_>f4Gznxc1yiF>U)Cc?N=%M!&P+I!9_<+w z49+QT*m6GjP%K{anEQsDPZZ=$rVs5_Lar$ac|Bnc8{k{|`(-l0iJa+sPW{TH)AT&a z{KKf5Uz%xea4;+lB?~V1Hx@GWdqEtw|J5?hGe!KU6d(Nu&|k8JxW2D5v#=XhQvM95 zW^|+nKt(&66tcl^)jy2*g)$Br0}fHK%_37;}r*SRuC2^rWEXgam}urKHx#c1OgJHE!W+ zh!de2oU0_qrmjq;T`OzqD$R3J@5<5j-ccyO4V{b6&k12Ik}qpD4Lg1 zDo)%cx?*O2pvk<$0zCe1U~q0i$YGbK;fpDXo6~fs&z%o4qo4hKHdD$|xDlhP)Fvj8 zKmW#XWl=t3-m5BZTt^6`FU62GBiv%=x2@fBfBLsK=D6EjNo@6O4_@!2seGk2&(qL~ zmP0l&LCoe7o4F=1j?QdfAS@&n27n|A6qIQx!AsA7<}scuW@9U|y|fd5*WkvyFaXth_(`dGS!>AlMvdrChY zr^fq$&2gMU8vd6BE+d4>diUn~nd{%B8FXL#rX8w0#$YpClav$+jT;c%3t!>)D_H;g zv3_615c5gWKYu0v=8S5D`-V*0vz8O^DAz%X!{D98uaDB1M#yNlXz_*xfhq;WMM@M} zr(#r?8tbITuIIl_kmn9XiTBCqOaC1TN&bIdW7>wHh0Ig1G&n1KSOQ}nTPV-a6FFVQ zZQloyHo#Dw1SN1WmMl9NkKae@H~ZQ%Uh{Ri3amm(!waeyu3!mKuL($>Q|f027U57tZbiYTuG_Use-~_^&==#>2;5>n331;YgR+foG|Fgt3P0XMb9} zpTHZkpE>``DOE+;wz_yN~+A zgTFjB*pFD!kr{pY^i?4+F95_Js;)@QB|*{-FcBnPe$|3glE6(`o`4z<6c9`?1h zAlL%og896D&E3JOG|=-D4UI9vhSUDqWsSW{(7r>3)o5|W?OTZXlF+zQq|3+4&zF8G zjha*3UFNDKB4B%-Y1tbaDcN#{#QKFxgOOone|1iC7-HnP>UkjLb)}6d7h}KYnJ>uI ztml0A$=n{BYVRof z;iOPSJ_reHwgF?6E>b6x=(rmjIo@}dW2fJCa{RY@dBkr}Z=>(Ou6N<`%2_xIa4Zv) zlmn#01%h-EJSw|B8+~q-SX19?e*aSHBWG{ZK#q`0%h*uLhGv~dip2_5)PWu;Taw{~ zzUmJ%jaD;G_y_T-s|M0h4V3)FCLzS;Aq7Z~8(YoC>rzUPtm@{|S-LN{y{gzt4)F>v zIig%fn{(k}bC}}t8O|X>Ck5r$bXJ#ywd{+cfF{^~w3j5dUO4>6%~=$~ju_?~`oq`d ziKHW@vkBTPJTqXn^4k^F9F0gF;sdd?uo>1J0uwl@fQ$BwZxE1GxJrHF{iIh_h?0y4GaYXxh_MX~M}o?NMlQ0z!6mPX)*?gQDq< z&(|K3S>N+wAIyV5wTljFe)=7mCi+JmZu*XDv-F$i^^sFbL2O69VD3k7dOh|J09?a&H@fb+o4egn_pjx0LkrFW_ESCH>jZnpW-od&cC10tY$pr)pu377uZfw{P7HVVwOcdXZZ|5UlJW;#Bg3#6>b z4;%YFq;doeVmn}RoYA{D|Jgjy;J6=oel&(?$>5nPtL+|w4Qlw5TSru@YA~{d9|@Nx zUYJRBXbr!}UY-B*4^Z93iTD$%-CZxo2V9QAC>S-@7D$E1&>-o{p;oH}oc-tD96WZM z{V;DtutG?8FAEp=UAbn~i)Lb%JNjS4u`3vu!(ysi!>2iC4D;$j+P0hV1Izpb@VE&68|vXp{$gjLR`LpLL;VFXwX zppCYp>^a1YD#K>b)?Vt}WZNbRx1%M+qEWX`p4HSXlGt(OdG_l=P2%>00}1nU3k>(D zo9dv7J)yM5KCME{N`9IC|79ZO@>Z0q5mBg5ja12u zxn?|fZP<&sB)`UwVD5z^my*oo2pF9bLq0exkO?FHy`@z(=CF0%(V&1e^uv35V9Y8@ z|0PA#%$=U}j7UlYve5{|dmWj%y9(|DXSyf&mw5@1Fytu8y=omVgk=nNv*D6QxUr;Z zripFWuiG~`GPQ{5Yy2M%tBsZ$^P4QIPw7^cxhGp-W&xp)7ZmzAvFk2+1h;V&653fE z@YT0}s$(fe^||pi%_UJr_Q_0;+jwXi z+*6O6VS&84#A3S{7YpmcKk_LTT-x`UnA=(gzG_~1ZBAYF%5+-X%ErZJ24VWr3Y)BQ zXhi&+>?Y)UUYdE1)=1>)+|I?lx0$1cTZc|^$t7|~LIrAtO7jl=V9+9iT9!&jEjQCu zIYDPgj|Qv)Di~G;KMk81Y?{NO%4?$SdAOQqeXF0D&HFU2x_R%&*v$%DHTIQr*-1v) zKUXDXi>K3XPO!^G-t`b8R_Oaf#4O^D--IEwnO+jVtUIkPpR!KMC3~1Qa48UQx&>t? zxDl*&+s+4;t{v|FAq+gHS~A!WS;I|n72v@E!%X&_=#Fd_pG%|83|4!Pz5@Z3U$&3< z+;3UbPCvF+unzTQOxt^;L=IIzq7<&{&Nzr?aWmbM>b(cD<8lYO5fdQ9rGCTd@62Iq1c@U*z2u=5cW@Kt>C}m}%{<=#LAjq9Fd~W-+tT%lW>35G zH3!6!{$5mM!#(v6GYbN`a;b5P07^1HFVR7HeP$tjKH|h<4V4M(CzSQ`}xH z%~;-!_S&o9Oy{S~m~DC>@Hbfzcbmwuh-BrF4p(HtR3HUK-)qC=+qAxW*Y^cGJ#v>IqIK>+$!O#km1aWY=Q_13J~+E~x3luAi@;=fI zn(-TyWq=}-oe1RySe>RlJEB}y;Rc1eELL#i;*7WEEquprMxjR-i z3eW5W>^`V(zDFhauiYcrV)E7QnLgt62?jTw@9r14mMfIWgeT~x|9Oxb>b#T!C1DMk zm>z%1(WwXaIIDgtJzO(EHefNg(Syc4k4+cXtrgVEvc2a!EGY>5^W_dr89xDkmkVy<6C*%x8 zXl$QO6$aPl8N#{UqQz>PI+I%r-@IRDT$br_e@G;nZih5v{@d68tv$Ig9v zMJQ7zZIn$NmHETUD2mOFW%gOQhn3!0qE2iWYl^l^g{dI&FjRr}+GsWm@Sy$6lBS|L zjq$2(9A*G1nLxnJEw!J7+Fm=;X4X}&oX=k;U+=0_PU(Z2@O7UV{}Ok$HeB zAJCWn7v%O771fxJSauwrKi{*Gd32$>eal{zpVJ*0E9We}_saG56VKFf(VN~Nab}`( zMYdD`o+2@U?E3 zhJBI=VIqjhhPY}P%ikNNg+UnmgXYL6&QcH*f!=*?%FG@Q!=ZAs0u2n`$+>M*@JyB{ z_2VyUV3pR!IR%#9r$+idBM?~qpwbXm8>_RyKLC_bOWsjyS@D$hPG52q!g)!hTQkoLwBB%%ZC>5siEc}iUIw4$cSy;F7fGj zYqRJO;o!d4HREr8bv9DHr_8xA;I(;|8;S2+Z3C{{q@~Aza_?AsZbo<17s!xt-|LsD z;$_nRrFU~NRoxT)uEcOZ(Xj?s*<{(|2okBC3)uM*T@&sBQBQV$=G|dZfxi&LI-Js!wtA`SrT)38h9SG5 z_*^Yi)*CqY5e{QDhbj=t-6z3c%io8u8f1h}Pe$c)bMrBhNg0do;SVO;5a%%ROz}(^ zi&K9O3H%4pM&gg72(Hh?VXvRTXuoZ499`LN?VZi_Hd9rtQNAVVJZ9Wa-uuNyYl^Wx zh}Rg2=Qt9gUh_W3Ter%#Bbqu|E6Tn+zMM~7Rtt3KO_;}4cn2On=unjEgS+JYbcV*g z)^E$l1akt z4@>{FU=m$D!REp7EeQF){I68YRigh7t*?eFbvHHM631)lUFi9ZyG2Vx!1RA!ytEMg zBYKG6-6%{kMXIJT)Cr)pcM@t06(=xrCW?IoLveEnrltNsE)6eH}TXciTSQ zd^xnmdYZ?-AG*=G*giAT9kzrabInx)Ty9xc5>1j%-;xjNaT5bs7a4E<0rGb@%^6~l z5j8=+JH)G7>P;CHvisdL(R6f4Z~)T<8^6`)dr~=wRC)0TL};?9$-1^43rO8i<98-; zElB&88_P0KvAug(8J$leu?TOGLdJNFCAm zmsEF9yd`IqK{Ah>tiz0-(2`jh%HyUZZ_z?=v^hSIp_pd~f(so=*)(K_a1dV%yzGF$ zlx-9{S;(HScFDKTEo}O$a@e->qs`>#1`+=u=^mkoa7sYD&3P1GLf8VgMt5+_BinrW z6{c5%T(aHCo^t$-5B;Y|0j2G1hCbd88C9Yqpu>KJ!XBchIG#xz3cEy*JF&G}z7H`a5wcf#^e8gh z8|~m#WBBcwooPyM<&Iza#QlxSZ@8zhP`$NZKKH=WQ9nK;GJ6eENS~aJHP7!)L~^1z z2~{=u_)KB%$2RH;>2z=!lgg+=#vRd-r;X_d7|OwMT&M1(U$tA~;y8=mk0axkPoqVu zdJpstDFrA#{%*P8*~JXm5Gp%8pg)O-6>S6W@5{Y~UPKfm6cK{L7tUejqsbr=YkZ(H2>Bc=NmNRdN_zJPmM#S1jf1z7{{F@0e3VU=N57uV8#iBa zMHcY!aLa~&ZgYuFW@B$;%~D~Q$|pJ;Iyz!Jy4ep%crdkoo3A^pMqFh22CM-RqQaiz z_rl^Z4W$vt;j`jRJQKF>sFzV@CG%^=gECwpefu|u3pEA=gu;9LhhU<7gXym=~h zi6lqqe`JBt*K=FcwU)V^+1ZD`_-!G2{Uo@21@o=ZenkB}Q=}G`!_1&dfEQ-x2~>2s zQ4aM*G|HZ$W>G8HL~Xnrjk`&fitx9q^jiOl%xWpkv)H6>(c)>)rA(;EJ+8gXvv+@G zy{E6(zhZLi{Rtz&%|HfFV)RICYdyc4b*_SH+McLht{8$HaLEobGjnKDYIEL)c4NkU zexH8;zoVhh(9D&T{f>N7s6@HB`Jn7+-fQh&hruH*E1WWfD6!%SLcKXK=$(Bs+3t59 zI3$DFvvq0N_eR1{5Nb!8v1pu+r6jaHGX7K<+nlt@@A>&zJ8*+A*3wKM=%JCv+dhB3 zlyB-g!dSJyrq*Mh>#!7USx@Z{&ERmRrOh(;=lhA~MM9ob=USwC^iLlRm_n2xaF-yi zOeM9WGw?3T`yYV(5`7+<*^<=}Atq_z$Na6d$=zE8#4T4MGlM4wR~Kfl}di1b>X=P6pnt1Ez~66AGbA9V4JTUk_0 zf+ZkcPO0>038U2Ms;;K(;xX|WZfEEN`XOLK_Ef$kutZ^{Fz~;2*(oH=vRxzIEsm}1 z`pS05PT~s!V6Ki}$mz3X9DfxO(>_EB(c|Y~*>gTcB9A=h26co81g0W8SNV_E9FT zeMrgi`2?SWJ~s&0xOOJ- z{&6ylz!8cXM*=A%lm@DDXn=}`+26yc)RXzTm-L=cM4rwa#{J0oDi^r0@P{0HHRr8a zr;l?yYPBFkWBHUeuB1wqNdPQ4?d8fx8qm2Zy72LCEK#J152(rLE!Os9m6MRf3Cr=jO(EZ&}USYPonK$uBM~7EKDYh{Vf*M+b9VFCVj*V>+vm)+w5na z==$aKfUahFrN2-zr!@nr>>ON!`n^Qs`)4R@Ua~TF5xY6QwJW;W7|PhWl|16b7>BV&H!dllsn{T$wLcH*qI^00aW8UdHtW(;$hu*0Wo@=9iOYas%qF6wcZa5(Y{^nT2t`Nh$EHC5H7O(iIq)x;|f=d_h zzxs$ETQMU_Xv!!BP%wB#MBnVY(uem;36yNNFuluxvc0i(-t2hfx2h<&FcjUceCvty z^*yq-KOzajwctE%on4G7OSsO=xZ&|V;bt~GNeYp}#ixEdazq7CUd@OpMo*n4%Zktm|`V1?lN=qG>YAQu-KeN+^R3hTN zudUoh4YNl}N+EI8dqNEosA9i&`~^x@M4uh}6HGE&2irqN^rhM0Y3GjYc4c#AkiSBvb@O_ilikJJynkh+f<}Aozhk-!7f{daNL}bH( z4)n)$W|Qp#$jEQAj9L)|dDljC9-`S>^XZlkw+GoiRfnV~(TVPtC9^O>#YPhmMa?vL z`}>vUj+*v(mZ+@Pz9BxI1zF_}G0ZPsv0Ivv?5mF9I%GV*gC z##1yI7#g!aP0Tu5q~;Z@wQgV3!mF+G8L95+OsK=faWMdW73~Mro^h8Nyr>^*YCL!L zxN=(f4&LoYGeV8ro$Jgb8^dx2h(Ty_kd1nN8c znYMk63;lRHB(E&l)!>2SvFXg$f(8 z9QkD_!W>v#uFFcu4R4%|E+yr=ocd|sd$h6{z=i)Tnwddt35HlRg0{r3L;<4d#1QC5 zxZ!7}{1&c%s&Nr~O@S=nRew`z=JVX~YVQ4K{;g#eOwMOd6>c1zIgobqe5yapCt4!B z?FpASrXj3bcWnhBN7)V6#4DMgQY2tOaoA;I>jtkUAd(d5_RxAM*1Fz6=wlAsLjyJXWK;DKIcHK%%d~Qn}`BaiieC)(GXcv|n6b zQW^|vFq#lOc49e@frBm#DH}~=7#`+ieY4fDeI5Vc1HWsh_E~nORllZ&e?93#{89_H z+Y`jJ5TVp0)bA3<6^Z>Xiraxvualbx?Us4M&G+-FthR@+@lI<*4~UzAJ#8%UYbYz{ ztW8|pO*45aL!w!xgz!dGUS7d|NL?UG(wCt9fhkV9O&9ekKshA2Cq?o~wfhjv81*h{B5r`7w9T7$^_vzIe`)b;NESS zuM|g(qi+u5XWieLkcvEg0F8sTA__(r#ce$9hJNTdF(WMJoL-UODO_nipN4%I#=%%A z1dJIys<FG@SH?sfxRiA#UNeB(4k<1$kcQPA3tYL zvcmPF%W6t6eSiP~-esQ?DfseDtAS0T#~aK^|H6qT3;=zQvc80+4$m{R_e=?P8=cS{ zTE+z-`AKpZQaDq>kQo&f$FD@aN8Uj>s&&+ZyB3$hO^x5G z+VZ#nj|=!Kl-_GAse83|%&1Og#bZ}r%>4#;!+$K5!IP4-I=v|>9N+BwrW z!{Pu6sI(nG>1{;{)DB&^A=dPJEAZtmt2r)Y2dZ;;y!G~cc?&QQH$7HGpPhzk-Mu$N zmNShfIsy+U?+ia6PAnz2EE*Nm{&dos!Jt$yv|ZZj9HK&R@5KpLutVV*&66=SXoPY~ zWI`e^nv^MfGqV z*74iXP5@+l`JhUH$arwhom*s?)l1Ih{}NUu;?GzNCeCa~O}@#gKGWH%X%ciBFOE0( zGnh8*6sCvqF)`K5Fdk$jvCSCLx-w@fmL;+fJmz~+%?XAW%d3|il|)wi7?J7we5~~C zwYO#G`GIlXAWH0nzdxs=AB<#FK877kDmKc6?-yu55&nP>(cz-8{X-6@QN~U+TM|Ao zt`Vf|o7yWVjItK@+@61QI9Q41vl$4#0Ysex@YWoC$GRYV_--U%HaR{pSDcyYHc^lN zBie}sBa8VZ({2=~BK64~e$?gw>eZV?6OVyDiat(aINy#2J2xB#g9VSiXzSIIrvDQw zmf%3(A24O_NzvElW3JW1lTX%VTuuMxU}=&I7cV2*9miR|y_vPA6p8T{_3}n3h6^!Q zLj|@~hErJn*JgDFAMA>L+;Ti9`w_vsmd5hOQ%-u0PC=2iFz%8p;jg3LMPwFBWNvIj zHBKA4z}s0X4GVHJG)BVY&NT28Ik}zoFS~1wn7q@8q1I~k3HcV5C~LMz&+YU1w2Bpu z>hDW)GD(lq&JEne>QpwjAzl5l>SlA1NCc^IpI%Sp8z~%*O7D)g6`N@2!6%oV+j&gv zFOAcoerOuv0@B;QlRsTI`5skm!#A`yT$JP#+#QCmLlB|SKWn#9vs2LCT1<2hMwR+! z)btMJV|oUeZ(4>Re=)1)`{ym3-yy%bWxlt=gRA#P8=euZwg`n^+!Iy_%>|-=OTwx+S6W{WC~}V^8-yte{Qme_9E3d!<~=8y-fdD_ zCiAm}eD_RIQ-x?%zM~Wid{DV5UO?$L&PxbLp?n&=N8d>J_nf~rTtIG-qcUo9EvW^q zu~LE;Ac4gZK7robKXi{GqS*{k^(O`-dkGV3w;%cS0BoD_Lkr0_;9Ya7DY|S70se~f zGfTwRXDYQfpNCv8H5AN+=opF_#@-5HFKCCVmbt&k?7fG3ZIndpL_hw%f(Yr>7UAFh zkyc!G_4hfN#+JBEEhBQV+~h{uc=9XH{Na?;B6^o!poy4i_OT zeJpH`l9YEjl0JNSKm2>K-?-%Ydw+=%bgu^WhP`Zz93JjnQrv#i7UjEyYvG?ZCDs9l zHb(b`po$?Rd))FR{my%G%GnblJ@=-MV8}{tZCAiO3fnk!8)-g6Kc5*CKT#<1pw%I- zE?tFs*Z|ENZJlgF@8Rf)<(l+Z^X{{c>S&IVK-re*ihoghT-zWK&6}bQJ!AezarMcE zM!4Eudq=UQuG@kX_k3nK9|QXvvFn%VyEGbp1(xN;)D(FnM3N8YvqTu_&-1YRqn?>p zOCX1wKp=cS$e8FvNPk7Epy}tn)G58k(i2vz`yiA3bt@TQ1`W17KYWDoxVUhW8wxt` z%HH&3WD`HoOhG>qLHUQ!kkeuvi;H+$5s!0PmQuhJ*suo`O2!~{FOyFE{h^gmS~ImHneAoQ%CZvc@3e@#Vl9wan+@Vfibi5U5&yoLmGel*wD5t9`*X!R9~uks5EeS zYzFWXvJ%MFfMI?RiJk#cN01IkC!iV9&0+Pz0xY(*dQUEO&oE?Wur)--q6@{4smErs zfA$0C5|MQ61n#pTGfQ}eKgP8}PT28qt$Z|I@KAQ>JD-%bk}H;Q@#yCgG_c2e9WVD* z17&)H);(fN*)r%F7}pcXVuhq9F>WROtRfwL9k&^-xALKeBK%wGS*~H8d_s7Ou?hO6 zZF9)3IGNDmgLu|h5Sj}#XafRo|2UoM&v4K^$Z62@Y)HLjf=Pz>>XaEn5EtjrrL}ad z^y)2Vi!#9XHve9{<*~EAHka!XK-=qWS&ICjN^Vn^V8-&aKgX~l4|YMZbBrj^pm4cc z&_;Tt_je|d7ZWmt5u(rOJoe&e?vd?wRn&G`(WkQ4TxpV7W|?G65wuQ_F|x13(o5nL zd9tfBHFqkJi0Eo|$-0j$6B)sp@#lxMVqPqhoLHVR#=+wqus-l?#*l7sik7ArP!yZ? z&4Km1)Xgt8Q=Ub~weM8~H)fGIgYTiZin>T(iZGw1syF~hQS*Wewfq*~kDmRI#GORvr^oQG^c~+TI z)PXtamzzfhZ;oxgngi*-t^X0ehkhrF90r%U#F?k17%QH+)w$b-r3Sr$bz?Kr#2 zX30k;u>R)kuCGbP6km5R_dW!%qN^33H}C<(St@XBJp-LrUcc+dbKC{0o;g3rDl5`| ztJg}Ht1*4O*;b-#x_{?nGLIBWP@=-_nQwlwf=~e7Dh?Vjye*&eYcfd3v>GbQBRa+& z;+Aa0NiRziIh{Yu^Ck;1*9)Xt;CrPV@o9HW%kHyRE&Uq#sx@5H(KqQZc$PG^RZw;- zeTCUg-&I%qk$Dz^KBy`d%VoEs3&V6NDO@Bc3mH8X8zH z=b^yzQ2S;xxF0)xlo*_6WX-|W+PTiNYj88406O)cE&gm4`xZeN8Bw+ZVp8JUqEuxV zmgmjV5yHq%te3TUyd|&s1Ww+1;smI9<2(ttzC_ko8Axx zy+*3lc=Gy5;$xMeT{isoUBEN=mD1a-A2dSlO^@qfk$O+_{n?K#*ETl_ ziCLS&%L?l8s(77D&Xyj+W>Q&*bq?N^9^R;W|9L0==4`?)!C&h1&qL~5@G0wTw0NgV zMNm>7P>RI(oi8Y(UmGNgtfB-=O&Neu1%2zvRV1uhMy)#WD;BfTWu}55`ZJX(aouPQ z1dFp@FKc_O!_4e)v5k}FY^&VWCPuvXE@a@5$5|DrONP2$1BGF`sBElgPfcuXua&s` z$y*(~sm5^pH0`j^_Sol14ZUAakMtADPMG+XG^3#k35CXyDe7E#>D5}0ZXBN7JA0mK z=8vi%cbXsUf#{HSCX?f^nPK7()QO*IBE}{o0j`-ubD-|z~%hC%rUweiG`DdVL77X6;0a=qz$%aR?O1?^-AnHQ! zG4!->|3GSuuE}z9 z6(K$B4|;mmiJuF&09;=FZrfL^^VGV!-_St{=1nOf-&He*>-MYjg{~hHp#r8KlPgok z{`72iN}AzlM$c+cJi#s2$dj%l14lE@~vjcZd-+gakaNrj0|plU3TArkPI;(drsKw5*4t^6pl?41r(S*jqv2fx!YwHp>u=Jw=8FrPsF+KxJo`ag zR;82$djRR{&2vLhCheBZ1&*65)M;x1iE>979Z^38DQZFFJN`;XBTs3CIF){BbKg?= z1veSu4hKJ7b_}iyYA2N9^j!E?s4OM$hrHb= zf6z!u-2jt}bWV1k92)6a8&q;jC3119wBD6)gYTmJ_VKV3+MZA+)K4?Yl(V4p%(bR0 zS$d`QE0!Cxy^?Y37_Pvd!`>k2D}0OX!K-u3TcxTzbuv&l0fd#~9|v+)GwKyG(R!6) zLw3fQX{(CVrO8{VNlJYV?p%rG%hg*)9A)I%4sBXpoHFkTZLKzyI}cf78A$gb%#q{L zqwBEn@t2-uGIc|e5aL;Ju>na^6noBkSJZ>3t+yDektIzv=4^zW(eMho5u9SUE6XW} zI&+G4tL2U$wx;n2zcmR$fOBf_RgUFzHKerh*yk2mZc?eLBCz;HrY;OOA|>i$N1;p6 z$WnQ83g^^!(tS_EO%E;D)HSU=STfYdl zroy*;w1@0j!DYWk@3@{J{Vmk0vO?i-P4XqQ|)s;8O=^@R&7H3 z*p`uLxF&VY!lsycqS#S9%9YEKQa(XfMxN0+k4;68_0fnj+K=@Dwp`z_eRm&=@K*R_ zvPk95;weU-K|Oiutq&}=JzA&EF7^y&^rI*jP%lO}D& zQWDv6JW{qnCp)q^f!=GWlflg_h*9I%^(bcY+*akyM3*~$(Wg?7+Ji~voH()5!ntuv zd!ufHD7IxFxmmvXtL+b0IN#b7$cY~3LuXDK>q+iPq8c)`K^Z=vT39wb;4DX%eZvuTiCUmzO!=M z5#}P7-z_wyt7;lN@(Q{Pb|BB;%KTR=!iIh!>`eHSa>A zNl8%|-bu;lYYB^hfZwT=Y4x3y^?)%lXsWKWu@)DuQ^ZV5k)^|p& z*C5rhJ+j{&EhTD6V5vn%t`2(C#>E-6>8oneppqjrdUYE)W96#ni>gysi0ExA3Xs51 zB=p5_^ja$24NvRqnp#8q5?q2EOHn<{xv1DwhDuXanCgO`#JblxaAp3Yh=qFO}mod zhwDpS*Gxi>a9*Z)*peLCxFxWpta97!IH)v@Wq5T;Qg1G7Kt7hl5`IBeml~T=bR2mL z!bhK=rwQe|Xi-PVL8>X&RLa!ii93|8?qro5oO^RqsElL8Suw{rFTHk1qTe+w$+Gl& z+u|}*5~2`*LXSbxo^5U1r=QOnnroRj!b*DjvG?htNl8eyyxg|gS{t0pt8r)~g!lng z)!$O+D~_IBrpq0c?h0`VX=d7_C}8u$pVQl1uwGVHe1=s=SnaBM>0yiJhuWEnK9Ipjoq?FPs?5yxm_-I1}&D?h_Lax^U8oS=Dxq*zHl804Vz0w}JE48D;lyUB#!iM25?z z@4AXZ@Z(6AAyHXWmy%uD8*Lw=WapMTob)`Yb-zqNn1mPRN^lY|K`E!pWzySb(Np0- zl!e{36x2hKhSTXrfXUpReZ@}aKe6ubuU5haGNj`pBy{!U)J3TO04Lc+igV@){0d<3 z%EK@g6)I0`zDOa`Kqsa}SDLa6eKmTMXAGBJV5EhW5y?;Ln~ zkI7YE7}yQ*4tr@CP>#aI+UG<(j83R96THpC_7oKq`Fbwq_E;Xq*Hud1IQ=*=|m=+=}h5Jx9f$m6fX zX$(11C(3q2hm`E8PVaE2@>-lZ__^YwQ5;UxDWz{JMn{24vyZrbO19|TS$B&gjitfn z*QO!qy;*B^(;%UXn-4bg3C|*w`sy_kd3thDg(bNJ0D6kCE@eo(={0RjW3+j&dF1X! zD!q!H%I$Y&Xd7gFe<#aYPi&(|ueUsE=BU~?xH6{kgImy)goLR%J~iPr>>)(+C#7?2 zBF8QXEi7@e*}3P@yp)c`VJG9yUy#?+P5^f4<3^ipQ{Q#4?7u<44u3ev@4)+&^4CGU zxI9(0yRo$b;0Lr)f^qB|&3zv7VN?^xohp_fA+`3Ck7$>dgP0OC=&HOeTvE>#bYry= z?wOA_b0;2w=l+tuG4XB0NaC&i$kJ6M2~%5LS~i6a%pB}E$6EV2Foef&k;o+f0P`#3 z4;JO3;l*7`aY_`FE<ETLvT$C?a$1b#`Bh8jhJ(=ZJKLW!I*d0`zk#sC5r4)p*mE%TEWd)>tx= zD&r1JXws&sDJopG%Z{b?XPNYSZKMxpI%Bh;Iv0dcwLP}m4rSKqaVeDSwi5Sd*;}9h zm1JY;XzD+@@~NcTj)k;oTaKE%!PDpuTqCgUts0kdCFS_Y3hg^E?$qr;RvTBM!jz-9 zoy`!{3c$qZdS{9@Ej@4&TNfBC&PuJRceBIGj<-osC(%9Rl#G%>RF92oP@yf?cW3O2 zKc{_WFJZ@P$5y;kyXVaiK04T9S?+dA!=G+Led68NXMmBd*7M`}S%T6-5(%WDJhKfOOWF&Ix?{MUr ze6;H=F{1Qy&&y4==W@MET2*QHK?TO6jlmnrkW>Oj0N$Q`+0AcOw$d8!M`}$byG5r< zwA@8Wie0)T5!WF~Sw`Hp+ERBVBLH(4?yn;(^%K;4@r$JE{ST?rVDzj$k1tQ2NW7Cx zzB#`flml~P6(ugPwPi$Z-g)yN{{R$xwK(B^i;Kil$ntt zI{b`pQ|?G*J2&$w_+Pd!Ff^U93V<70=kQ4P8EG~_Cy7Cl16 z+e+Ud-8J=^!FIXai>Q)`s$gXZjlI-%%WcAymY0H|oUD#SC=Zj&wGSNB)jLP+I$WNa zEp`cDlp0vt) z@Jo@KDoDl_k&dU=T?2c+SghJE<70b?QT1ic;!@qYD18s9rwI65oN%WElg|U?Ip@hu zsWW7yu!IuxgydyI(l{MFFllyt9@BKI)>{4UhZV|1X zXw-GhklO*)+ZakztP|J5y2ekFu9mpjL~Splm~dO1ixG1aq;GjoyRp)wl?(*(8TF^U z;PM`f3-{-z)D|})=)!`QG6CE@91eW_RoxorP};QpzD=q{y3*a*cLpVe$PPEKb}tmI zE+=vF)kfo{a*DQod5SQ}s)RC1qS{UV3VTp#4JoIzezdS#;alCf z+SyQ(B`gi8Qnz+t1mxtUIUlzNr#g)3%SM>e8a`hTZdMj%-DCTZ^?yUW<9Q`HB1Jg#c93E_P?_w_PO6OUuw&lW%_B5`-Zx`dD7$$btapo`)E!$_2_=UJGlsgDTTYdFr46c9CWDn5{8#Le^Nx!%w$_GabYdzBcU!KW@KZtBcU6VG2iKUa-C@y z?yJf3OI#pY{O)2QV0p@lTV+acg((gO+*4qIk3=Yp4qVPFd(Nt{+4N)9tM;9M$C*CN zNLGV+34UlymQ;ly-pQ#7!q>Q+idUd>j(czGpHuEZL2#Pr^*=_hPL7{5&or_)$y4#i zhBIl|uyp4RF1P;xaxL>5V(Qy%nGA;zum|?Wq{EMYP>) zdmY~u0Re6EZ~^TZ9P{vLZk~3OzI6?W3tbgGCS)M9%(oY2R2yLbB^Q4HAO zp^POcdp_H~uXjJ|@Ko_`vlv)+&K@oTlg)gOI_MuJ_1hfO({&ZbBM-l6w?=vjCAJpZ zPP-v(7mw`%ioPo64qg2{b<*BR0heWJSn^}3VMYmE-mW>QCIl#mLWM&&b%^C~19 zd?8;w>oCb3Pq_~M57B={<_rE-P1deJzVMs$15Z)JFZZRTWVq?=pt8Q+VGU9yz@YSIShvLQ&z4TX8UK-ZB5ly zi+s&A;`?^)a}gOUY@sPu!bsktP?L`Wd+;j0<0h@PYfWG0c4?ixx(r6)MwC#brQnsg zwG?Cx*jvRpJ;^?*^R%lZv#Ck7+3J3z$)cC0&JmP${hLy&TylA^T<#Lvjb#gQZKmNI z6z6eJ+?W}7cU3}`^9S^v*4?0Jto=4yidGpUMe#2jNq>J|3U7wER$GT3J z{{X_RnyB`xfO7O&OMZUUy@1)=i7z;?gp~8=wJTb(IeG`4aZp=>O`a&a(~Xs|ZxEX; z>?H|6ixEpkKhIbFrltCZbYrS*%aLJ(+YuzCh;O-db%ipA9BX@lfgCnDjGVcSxgb<3 zZmF?c_@2!BW0tW79LSDLx-)bVQzc~))Pj?MmeA8l4XA^;N=8;nfdk_8Q`JjVE$P)Y z_&;9Je$|iCutyZ*xlK3o`5rZG%UW74Qrxug!ohKY8*-B+z|i`TPU2Jwf$vv$cP#R% z4#hfQeNQ#FWQDEYse%B?j#8gcsfQA^?ea#TxJ9sQTa(u3-diY4E1Qdoq$P$<5~QnY zxvgM;a0tahYzV}H*loN5NalBuIsyFxw=5TX}HoY4g|29!XX!1P7<<|IlrHHDjd9V%QdRo?xR{JJi9iZgLay!Z--cx zl;E}t%L62*9-13R{*Y1~O?a|ew3HhgmYYO-fs$B(X&0qswIvP&NGb?Ri%L#OPR*p_ z(#arVEymLRj)P`AM?PMjjiM-3K=Ki?dCJo)i12IA-P!$ zyL@SEGZyP?hJ`x9np2GV^i(Z8#!6L}60Z^tGLi|r_&suhwLrE#F{Q3^Dp5j0lahHP zfJVh~?qzImL zz1}>kxZ@4mR-!C>ZRbf@;6;$?9d6>n5{DhyoR+z*M;JNh{_3AOF4*3jk!6vuAnA#c zXLjh6sfmvHY!nl)spJv~O2Ie;6OQcFamBb+HAIbdw{cm!ux)KO9@s9%V%v15>W+eB ztl;D9M_gCT!OB|OpU>p`jeEy0L&qFSnuj#w{{T+NVk8GNi_N^@2t?4L5_`LVHP`-1 zR`yiJg+#=mU9E!SA~He;=-s2rN=ZElT9uDr?yf{(36Z5=bTmN|0th_vamePncY(>c zN7B4Ae!}g-Oy}*drLM)5C&3md;m3OHBd4`(OqDX0pIP{0J4r%MFfst~ zuFlf)FV?+3d$nHe4yxw+YJ0L;5|wTw^GL=5Nh;4gcUK(o?o256i)D#d7;RkLxTZoO z6bS26es3ewOF1jp4=vcoPGdF6>o~JHLnb%EX!@_xy4^Cl0()^}gF@)j|#BR~HmwLzo(rl$Pc=GSg}YVOL@|ZO4h`YOuH5 zuNRG59(Bg$Dr}+)W=y#YeZmu*BkF}-hV?7%*Mp_g=6b2-msj~di}fd~Xyxg6v{)ZI zV|`WE{K;np$TxjJdqg9$vO2Vad5kJ`( zk7qv$;;sul5U$`88<0z`B0H-1K#~&KQifDqE;>m_qafe-abtE>rq`<> zOpK_>MCq)|Zb>p;PTtkmQdE^GMGgakpp>N?#zyaz);UiuMTXK|K2O=bCF!tf^zhZ~ zl;vL)8eD(-BN~;)^*;{px0|#$#_4EwIYaF>8$FYS1qeOo32+aKzN+m>y||HgsYPN6 zNXK>oHDv31)|9g7+qR#xY72eR<9b|Fc5oynNJC8q!CQqTK?CYwV<6FGP zam#551D~bL51fv5ucdEWw=?FyTjav>;*2TFZ`{|-mv)D>+b(YD7?W?p(8iZHn(9* z3rffe4hNj>RtZl&pb_h<(}#ChMr#kbE;4&HWTOBhJ;g`;_4L|!+O&Rkm$Oc)x>{S- zUi9Kw-f8xLenQJ?Qc6@)vnwDca)OBo>H%^JbdeJdAsh2x_wlk8D>+e4L8fYYxfJ)Y&IdjHH&UtuM1;X3Kve#sd zGUIfC36`w3b(iGHN)iHs@D-J$5J@9xI5<8P^7`y~u*)ixn^bAS9*w?s3b_NZJmZCO!DK_@)(ocDptr!iHofr?SYAq`o5#^Fqj z^;GgDu%z|wJgUIc4QRd^H7f4c5g=*@+lSaji4dV`PTon%7;(}vr2)9$a^`vD*Ze(s zQuX|KPPp?+c0B0|?66Q2cPOPw&nyy0eRKL&{{VVTzqg9BAJ(&sv{;n(`>DIzU4Nl_ z@bgmMnA4XXD{q%8%LAicSCusAhw(%bRD1A)QO5Qn`o=W;2tXTdO?%4S@gxKtElMT>G;w zfpmh+is32gaHB(pk4@!`jkelW2_?k=wIGAYoOI+eH+#OKo=r3MogXFoPgjFU>T&vr zrw7M9FP1g1<5xXB8tHf3@PqD(-f>wVhNnnCN=`Z@v?L6ki5!XLRh93F_DOd~ty<4T zLvkCt+;OMA17av)@56<}Dd_UCkDHdYZP6z8sramMiI*s1aWS_(20k}-lZ z4ss4E1*&XZC~Exm_f=~stA>UdVK&AVl*vzKl!TQb8E_MX{b>0s#LK=jUh{8+eu1LM zzL~F0c-P%6+pDh~l)j)=>$K@H*jq?khgKO{vZMsB&;;^H_^YS5R&&&oCOPdwu3(|vSaUz*OmM5WCy+ZbWimf42W z9h+OueyNW2Wal*0?-+Q1`~}(MU16;onoxUTD?n@mgr4ww$?wfEnSjSBPUWdXAO~=q z_wvD}&c#m-(X^{0ISDy9?>xZvV!b$H;PU3<@nnYi#w*^iTJ&W3&bnA8=P3=f*`Wz> z18Zf#Ig$=ik;s)Snr?%2ze?eTn!h}-sdFswrVt$=$+8SEr98EqV3!ng-Rq30osL7#wV+!4CkMyxqnx|E0 z+Y0ZeQbxQ>kk|>d#f&poVjzZL+rxxPC1wI+%4r;CP;c@qMPL@-yMiLWlaVlxG zm7%on9I|?=*HZNBE*L|A%UW*a?EC7H+EeB_vPIrQ>j}Z^BX*1I%9aARWm^V2vrz9W zSQogK?j6b0ETI=+XDYe&ZJ{lh7)f{|o=QT>vFgQi{+)Sak0O^(ql5ndh!N7{jtrQZ z-OZ(6_B8Od(wha-U@A$tfzPS>n92C);<4YPiD^nm5>kMZ+%}O(_(B!#6~%<^C8>?{ z^|l2s;+ZSaFDZD)lGx|V8RcI7Kj6>Hr~J-gD;=r+^bbECwQJ}m)Z#Q#Bqwvu!cZz# zEGB9)53~bSF>OKD5JnOWT2=%lHVrc37Ec^RPcHx$oDPnBcI z2}(ATFHLK#ua{eBpJbmcSVTtet18UDDc0 zY8ePAi1qIBUZ4+pSs;!WJ;RPx(H#oWdkVQ5Yz5&$vlcc7#%C;9CbLb zyb-r2FZMrL$1h6MdX^o2cL-yI6Kbtr^h7(3@+S=ieuFdxAxePzZmG=dJ*f&n}V&IX_hRBryrB#KUl*@EqBytq@@|F z=rEr@p3q8Hx)Qz@RG#b}>a{d2+Wl|T5w2QU*>ZI(oI!>XjqXTN+bL})Af$vS z?)0z*+~i{-tl{x7uaf{meK<=g3OiD9;t#H_&JM`6!qrjPx?CHE-NppFRB7YUL@6>F zP-()it=vkQ2d-Qg=0$hl;o3eYQ?^j#yoJw*8e>Pqc75Uwr_@(c>}z$Z-4VYuRHR6d zz1!Of-hkT+kfY2i9*#~a%FQEEv!QM8+aE>t=;Gr>GA-R>jVZCY081VG`tEWLM~9%}^_hn-s6Sb4V9knj)`*+;_M_5w(8JKUz~O(wfk zh?6z-w?-NFS0#oVySD;JU@gAcpi=v51z{&DO1AoZiNO{18fjx+V(BlF^POg!E5fFs zwaQ7gT_yNlD55;1bq>BZL|C;y59}6rZ{2%H_lRu-J1n%7ZW!$pKs&)8jP$N>mZc9^Ue*ZCI}-ZizqPbHML zu-ukZryWv~o?~y_?(6HT*6FDRoxWN$d_7G)w%Lr+QSH&xR;f-F!k01riclp-8;?$z zu76ZmFW%UTcbeoVZW!hH31B>?T2cn>o{1$}asbCtD&^AJrq!!12G*S!1s3fy5l>pK zlVzWDSdQ0Kyzl`o1!r+e$O!4myq#`2lO5>`3rH=6BoJ1m0-TeM zS;r{n6m`Cov*~Np2pYCU=HqgX<+Zzdr7 z4@WI7X&Xpr1#Mwonn1w?N+YL+?0i)R<0C<}TZmGDQWcyE`doJ7Z2VU*IiAj}s~QP$ zg(bodB0=fT9IDaKxAt_jy*+!mTH@Vdm~J;B6oKfh9q9lc9IHR(imMB2QgDT21#>Fy z0A{DK+Qo{*Wi*b*|T*n36__>BEcGJqFEZ7HRWuEx83w20!ajor*}T$ zdDV$6Y4bfcyUJps<#L*s>q=0TyGAyxYhJ;Ru}J01D#u!c@a?@ehmF%w-R*Gv*DgeA zeAd`Y&i8Y0k3@3GNK(87J+pYVuTaImY8`#2F4LWSM~@oSb3^@uK_z9jnmO7%5~AXY zK_MeKIIkO2=RHMZw9)#Hq01HzN>bL;l%LxkK6_-FQ#pHFiICviEjK7}K=W%G#k9$k z3wZN^k-O1Z*at2_c_Wo_4aM&`ogzqxn2B4fQe(CVO8}_hun#a3@J4(quP)cU8KNt|c-HA|s3znrw~kBYKL`0r){GAOa0?ZlSofdDJ&M%yzprr_6d% z8s(Iw#g!x+XPyY}H9nlPMqk=KOut-DNbtf~8dTjSPl{gy#*{+j+3qS!fD|nl$mVKs zq;JjX_NGpL$i>cBXR?H++`}w7LdjBw2vHbl;P(}JsuQCdefwS6#4u9ZU7CuB@6A|T zHif6;-VBXbe73`l3+m0HWW-19)=wmbuc9%5=z@7yr>T;T2IPEKp+ZvE!D4AXt@Mf9 z$uGB|ZTFo*%rsq{xHQ~g+el}%Lyk5vu^?m6QCA>x60dDLTQ3(VcDs(GzTZ%&5K^_6 z%|K-VY3^(g3FtuOp0yFb+?lxD(|x;ZttmCemLuD(w)@9wSSxTL0Vx2f!lJMg?;`izew z@=1V87kMa9I}7V81C~8J^6=%#u1yhrm#H-qHmg>bx5Kcp9Vl^*%?`M%f_Ihe$jMN^ z9ZB|8Qz?y?S#7vd+Jo!dr5pj1$mXqi4%zK`Z5ne(@f$`%5^`=+oxe7R)}k<^HH?6h z({bybg1paDX~9M-pZXtb`Z7CbJlUF1k2S@=z`IIzavQ&=O~qmRq84VM#=Ot0pn2CAKjk4iEK*+)0o!BYrbAil?vF`#@jSmjP5k* z%&80pROooN22!3`*rlr-eF5t=2H})lF+T3(ol||bLx~Y7aScqG+X<4dumMU*BRI(K z85tSKebuuVxZF{HzU$2+DY)(iAlvPCQ6R=ciU`6H$xBhlDq6Bg9YRt;@pW6WXG#t5 zew*l0j+@eDlRZm!3Os+SWr2H%sT-SPvFV96IE4*|C3(ncassfBr8d&RBL_VBRSD+L z#lKym%8=vlGWHyC#DJw7o}>Ugc~!E8cz0#Gz`nDo?RMnEby6QmlG&x zbZlFR%1282S>)vP={$GREYEt@@ZURoj3gz+V&5ko+WC`ieNeUihEq!aLo(n^yR@YY!ML*W*7{a=blbKu7kUoj) z{{W<~i=0bJ*ToG=^R35@p)4n}YbC#co|&(-a}FcANcz+N0L-t897mYkt|MxPm@c6X zO$7*Zs2fvXMXg`kM9&BCf02nt3K<>rt)`Nuia|J8z{iQ{S{Nu+L!A-N9yqOsdX$+7 zI7UF*Nf#!(Cqsu=wAuhEZZn&Tx^iralId8iKf?C|jUi3Ba(o`qJAgSj7(IUFM>tGW z#JS%N2sUW*PK_l0{zP%h@-JCgjWE$hOoykZ*BPsX+K}p6r z@kw~eW70V5 z1ol&ad7nn1sT&jq{k-v$%wn>2!ipvR^WA^*FRv%)iI<{vYiuy<>T&iOZG`Rx#dc(b zjl9X`o}JmFU1_`CmAE}vDAid!Tp)hLWC_L))7f5OS|@2!?{Mw`|}E~&8HnWY5-%qTie>|_jskCfKQ z!zDnFIbe)pwprL|dRK@UaR^YdH?R|ezp9*p>*-!@NXE9KtKD*`IXf$|3R?kDi+}(! z3b3AC*--<#pdTM~)#RJltBF%b)b^&-@miJ3vl&l3j(oqTbyCf=OO65B02H45WbNjE zr-fb~N%0z;t+fGl$8jFQ^Qiy~6S+K&Jz1@^DJIP3xVPIZ&3VI3Ng@=h)61~TxHA}C zU9;~=n&cmXsQ@b|!9Yk@1QLw$@2WQD6s0B71{4#5v?Q+uAo@UMC$2Ns9FBgv_0}?N z7VRrBohPd8vFQq9M21hg8Gx2Be)J5%zdB*?)F0UYC#Q0{V zt6upr!%ID)6j$jUT!lnbcf9#2!7i&j^WRuDqN~BCNy>7z$9)sC-`1RMM+r^Qg%h5M z&PfNyCxl5?DLBe;xII%-ys;YyMetgq@oVMiSE zoc+%qUS=2P;z_vNCquTkZi^~(nM^`&;KxIbDPghf-HL}?P?d*Ll>{wm+I?KB&y-fyV3 zh$CE@mIbCDaV;wWrxKMCg?hnWDTY3F1CDr3eoBlgF`7ux&Qo_MXM6C#&v$})O4!Lu ztiKUq&Bq9ijpuWV&M*KO9y#Tjsra#IfnwEH3pJYL{OF9f+lY0|!A>cB$tm1QfW}8O z^ccnlEFKo>i?xe{I%WF=vm{H1{3pE-;#+Yp6R|+_9R*iBP1QGzW2hXuT_Pef!WoQ~ z+iPburv&>e)XMj-lZ`n;BbVT-CauO_?HgG@B&j47B!lCSP(FHNy%n7>`d0J6dB_TB zPOPK>-RYHNdul;&1tlP%AP%KT$@zNI1@7T#PLi1!_Yk|2lb9`}k_kpVFJ*bNhBeOK zP2rYmJ0&MXP!binJk*~{rbjOt=>GsFq|5AeE3sj+`DV`n!nYN*DG8LU@)gbNS=dVm zJAn8;KC0-CCYkJc_43Zm(YEJIvM}^mYEW;_gHjahh)F&BQa~N#;<~g_+V>HbR~`<8 zP<5h|wn#gKiL1 zIr&9!$}n8lCuDLu*(o-@3Fivb+AmQZj`3ka=?N%ve$q0aIUgGB`#+gl;#_WXw`4C;W}Z)FR9!SZl4xH&<0A9l>&PDvt5O!^`*L8**7~L zrm@{E7YBXNZ7)2OJi?TmpcJp*sC4CCo}VI6t2uH($^EQ=>v=A*cbyVW*zZJ;<8C4< z$`X}+#DkQQ4tWv=Gt>-LS4R+D2ew;^1e}6F1pRPNhpL~3{H4D-?E&Sy zO4hLYRHCv@?bz$xRekR11*csCdjo00N)^xBT)8Q`NYfv=9-E>ks@*O(XZot#b-3@P zSQsA+XKoHLocDag6qif(rtYLPl@r;OU=!iq2j8uli%~?oCe>+**bQ1*kjQa8TQL79R>VMtch1#{-1fn5Ip#i=88x!aSn@8IpyWrIV+y<6VdDmCI_*-BbUlJl5s zB^`N#lb)4tUbVf(DYWUGL3M{BMVm6NEhZuoq`dkGN)S`aVn%rn8t48JYdtd`Pb*8^ zZ~o?7;$0n=8Ob9IY;idBPjMRtd~zz{isV@g4MXqB!z9U3E;zX<4zH3y-JfSKX|GB- z6ywRu9B%CptLaLdd$U^0Y6B|;UYO{41p%LJL>`pt9k{JZLK3S?#H)VY$pt)!J3#~- zUvWNB29V(q7+cCDrIaNFO7wv!18GnMl-J-aoWz|<^mntJM(96kTUsMQF zTTjVY>1qw|X_`~Z_g^Pz={J}*OHH^3({O&*BhBB59C?r%vP0_X6fw&Otyg?c)QY=Z z8MsN_^Q&jGkd-A#LXO-30u+*xxMzJrH~k zkBu?v4Pm8Lq`vO8x5`?wv;?f3p!Z|dUHjCzXDoNZ+I{>HTkw18?zHoPO5eP;LPXj)@JJ|>km6a6?g(s02TE~uRO{n$ml~SBcS^cYv2uf1cakOVY zE@}mT)N9oD#oWBrF@htv6||$hC>R9S7Fa<_;*Ft`Eo_{=(eB$FV~6q-t*196`e8$# zqJ5umS55gTT?L-eqfrrul;z6Ja)4CSp2^}1&X8MK=&-e5Czl`qJu8=EDc1BXrj(MV z+qorKC#l6gaQBRMy)|Turu99g=?vQ>t;>9PcR6*FLX`q1uCvI!by_@*!R2 ztvFJa;t+s5Iag!Or60KG$BpCu4XX>SzFeIdtQ>;c%zJH_nGPVfOJTJ>g=67iDJcpV z+vCcs?JP<)L?tMdDE7Dqz|xDi6s}hrb;`wR4?~A}VW@Wvs|33pvy`CtXC{+rRJd<3 zUs}fGsQi_~ImQ0~6m=yjed(45(3*Q`lEcw+&vy=o@?h#pI6=VRq$S{6H9KbD`ock zpN^$v#@G83-QkL{;dw>CX^oEPH6lnDY1U+VN$|n&2cN}O$C(`Ya5v=d{Y$APv!Nlj z-Tqo%c}_U$-Ak%*2}t-YsXKPII)jsfIdiT);>5W(C!dohM3ubK&ca+!AgG0W5_u3x z@JEU3UgY^{S`}&#SmE`{;5gdQ^xf$wRxp5jfIRA=)jV#Mc5s_@g}B2z!FA%b6&{&B ztn{vonQ=AzRh5i#rk>}=*@AYqUJ? z4)x2XW_G69mkOO%rd2TE1D~gYwGc2ijDdhKA~!!MZBH&cY{k=-XhnqW+=j}xf}!){ zH3`0JJxQxl)H|HS`J)a6_6&`vaHT|{N*&~HII85!44tD`Dd1^tbctn+uHCD`*5<{c zBZ~_FBX^_*LPtZ_m^}xskZ|Q_dtTcbKy4*)-azdR)DJ_LIPWLFt!&e3XhWQ}tDl*v zvODlU{{W*Kd9<;@(4DMcFNo=jHZ zC(mQ1tVd;blvF{^N$(jc2fIA^*Fx~RTnm>Ew5sj0RV>?>R9UU1N3>;Iim(!K=;34I zCb{cZBW=z@XK^c1Pd=E~lS~mWHw#;?xon*-7<-z-E))an_SP|)PSPPk%b7bni7mLI z*kuyiLOEq=0Me*z$TJXFan&z4DGldvt}2VJb+7>pYTLRJJYnkd65)VA52Dgr_#OIa-+1^@to1u~+LT*EhmomO#AbLcOXCQ4>NgH|`^{W?5PmvAT zk)>`#RPAxa_DXLgVC+fVgUs^6d^z`5%v5m`h|TWoHTCTZSHdWiMtJ~!TnZJ$?j$Xe z%Jtr%Daj=!YQ|N|n86t7T~O9yN~v-~$B`;h{{Y{?^|Ir5a!s(xX{ls3+JYO9rD0Bv zT+z4$e%ve{5nLhVuYR@9ziGWN&E5>@wpg;2Eis={raISx8(PW1Q0RNX9Kf!Bo5W5a z+*|B!TH{cT^Rr(SP6 zUU?&?1BwIUt$}ZLd)Bwg!N47=ut&>Q$Ce4&MQ4smHEplzb;lnyZj`fd=I^G()(iKW z@QBM%VLTiSpaL9u#UlgYo?wB}xwBOk-F`Xk(x4-x0uO-hsMA3uw>K4~XOU8leO!-R zda3^A!;G^L#RQSC1eFe>#;=nvyt*$4$}!vE^QCSPZ8wF@mR(b8VN8NPw>|vo&eKvN zN^LF4R7or?0jCiD;McvD{ZVRJ&yO=* zIQ5do`#GMA9J@r5Nu2wJJpFCc3rAmYGxJ zsfh_~2qj858S%*V z50acLC|SC+r8T**52T^XJi2&Qn`mUGEXZgl%P3x~>Enik5ep(-q?BqaJH(m(I{ zDkH|ST4K-=pj6>>XW5U#Qr;SEIvUiKq$njzNyl~;e+@@?&jZfl+EUwl15Q1Yp6*BQ zR;libW*e?WK4X%#DQ75FEifEk!9y2ns64 z$;z9HX(Q8LGm7Ciljh0v4k1~g0GCY0NdTVBX#oD%9G{R>h7TKTFu-w8uP-S%2`DKC zzq}r4CmH4K>T^%I5h230Wkd{P9o22e!#rlj~ZN4m(ht-#E;k|ZT5b-a?3gWLz- zr(1rqYB@+;H}aFbl&@yud%11+b$64#lN&(d1_DsjEMMHQY$CfwxR{!LBD zT&BXxK~mI7C%m5e$$4?y4x!~Vv=2dPI3ZtUOQhQ5Mg>V_TSr0#AaRLBBXm_QA99kD zYS{^K!05)Qd`VKD-15lumZkMH_Zx{u64F-@*HnUiajBHtQG1#V$vl=J2jj(Iuw`SKN6TW!wUFR&y#k+x$82dC(Xt5;fu z#o}DRo?&bwIsKLu_v>s?j9t-OlAcQ3+e2WAR6?CmKC0hZ1SxNww*-iU1=#QUyshenZeQE6gX3?^S{75#6K@UnU1 zyW_8ym(-<;t)=9vAD){z+mXnQ<6l*Lm=z7qBWR~XQG0bV`ht+yO0nh=GmKYdP*Qx7iMry?Ga2K zB}-{bBbrDBAzse^0GAc*pFP5m>}NKdV0GkuwHIrGC2(}fHj(00&q6yf5#g~SHNmhS zVb8Jy0ZBeQ&&p|ht|>>Hgr$ob*c(PdUFEoUpTkkMY>&%|r)089lgR|A6ORsb-|jTh zw76Jwji=GvI#!P?;*u*UDG$>%r=0D?LVyNxPI76cP2xnZ(0WL1#9*Z=ATQD!kE^XF zHks?#TV-J>>YobQyG+smZr>ryf->3)m66l{IsAC;tlMvrn|U_xLyJlpbPQ*bkGJRN zPC8dvY7GUbTEFSp%8xO&$`351X+2V*-=7L-F>Z|kmYr8+=>&v&V>rku>PYL)sPWFLX-LkyNPEtu2NFd<)N73uzYd03+;x?t1wGKYk72uF5zD@q- z_)?bW-Op-=&s)9isczvnXl@LUoE~T9r9Sg+nGFX}z2qUZpeUCK?oJYU(lGZOBPgW4 z;hrR*RFo(M1^PR&f(ZM+?x#Stj4K50P#s2T;ocYOsA)%^KwMQMoaBw?pV;$0yyK;7 zg{GdgNiN)!@z|ZgwE9I{mywQGAg2U)kyn$T9Tw4yHlL9-+3UQRU zcB>$B!5HrKSE>9>)^{_yW}tn-6SH?9dH2zKwL@I9C8apfBoYg1`0EwwztTy%vfcXGkU$5OCLYSSUkFno~6+e%cT zvxR}5WhvB8&Wg>JLLOT$F$68Q5Uea^#hjq>BO8J1;ZN$}mF56Tu1kWp2>=$=xDnsX zCz1B_uXn35W<*3}wi{ajA*GiFN;7~mc@y7(>c&l3J*m?)r8UsOBVB8$Z+5HIw^fmV zk|eBQIKav0NMv8N6o(32yUCDNIhCla{I#_<>vVPYFFz>s-cZOmB`2PDW8&`XPS&kC zY`c`A44Eask~TPy2|mD0VeU^O;LF-kcGVGgmoI4Tq$z98!MNumuS!<|=Le-Fw>GDi zR1OFoI*(!as>afM85l&Z3WiR#MYrYi0S=)jB%$4)B=k7w z0q)7HWcKvU;dAOFQ4Y8drndq|aVHtAjw$stcOaCUVMC=!Vtd_^u+)oVtdgUJ7Y8g3 zpn_^oWziOk<^JENtch)ja4!0Xe9!DL?a7UbJE+adDSm%PE0r@)DlG=M@mdGhc^!AT~^Hl9{ zG_zK}brWPuiby0hR8miY<|@t59#7D9U4gwxc#9~;j>B^#sw0?0R-8CMR&YwQ+yNZ= z*G4=upKQs^V^&cNxUj%wv*^mo5>8a5bkBE6ch{`F?u#KwOK3!Pk`yz{h;hf{da{iq9*CTHGH;i3eqrqPoi{wlE@^+90 zPJNj)seoBfNK%u`VM{#EvaDSnY-3t#d2oz&BU5+eQi%kIa56?mb`LBJ9~!N$T7DyH zS|YEqUof4i3dznp`c%&kx6?FIl&LtrN_{N6(vX#*)!>qFg?HB8&Bst2VGDByYJyNo zLi>}`B>Yt*dr|5e9ok*J`AohbI<^*`%?D^t!sZF+2YSIa!u^4vgr8ykU zBQ}YvP$CSMIpcC#C!fV#C98D4p0+90Emr26X*mlFJGgKA93}yzW}u zvq|gq$=jb-Gs>lwO>ucmo>Cok-#CiVb(a({RE3ZM!5vQIkUO$PEa6N=YI~i^>wJ|u zTH*+$ly;d%XzK8#l;C6v#U$0ENA|u*TNZ1h?eA&}i9ue~IIIMx)z+n2g3&7DYqd1P zjkzW)a^A$OD4u!fJOIsgwY!G8awXdJYPIT7KIf-mdDPhN+IF_KzyzfWBbu;zc;cJy zEn37b)*YJOmlVeJ6tdDtNdwYPLQ+XebK-G|>cfUI?8#0|)KSKRNZtD|vlnkat~mR? zx=`MXzpguPDlt$XoHnHNtFrq7G|3FLCKF0+!j!E68x#Rn4hK`qJpudmNizJa9;=-d znMZ6nuEtUnvOo!Nrv!I&@5d}wd0?R`Ox7`+`D=rF{6EypkL)i;Xi&<5Cq2Lq>B^G1 zq;AZ-8$)e4w$w~Ces#4Vo=3JSB=}%p(%5W2bdr98{ed|PoVaC%lB{LMR00pIW5dR~0?jQ=$qGb*!c?p(LdsH*vOc$WBhQzrne}T^V_{O_ zt<*k4cyTEqz*U{YJcz(oFi7XuJcnx1!)>-_zG-f*4pxoB>5euR9`6;vp}2EA{%T7* zOEqrZsaJ?-DM>jQCj+l{T7B$IpH)h?#@N$dc_9U}$N|p)cb{M#-l~d7E;^((uy?4E zvRf(Zx0Vk&^Rq=pRE??9m3BEo(Q{_D7aDU)L&WV;kbNRKa;LbQ7u9pX+T%_2!CxWB zKy9$ z@y1PVGg*10tft)Ze$|XNiEiC3=}7=%wi)>drkNTFHI8B+-!8q2g*%#2Pt@M$(JJq* z!?x&@`-$g{7JF2v{X{4d2aXRc{B=lqNL$v%l(WojKASf+G}EhSrz1HDCl~AqL#?;0q|A-; z9g*588rKrl%2s&I1`baa>i+rT9&8QN|Z3ZgyyV$DuCUN%oq!h z;bb7EU>R9>qz{i3<>hhrUgNWE(26e!ku@N+ve7?e?tb+=Mc@>NiBXiDz21>I__5}0&c zk=i7nDM}s1Jn{(7PI#?x#}t*fMpAiNq@A4KsQ76UMYfq&wo8$_RJGc)vQm{Eo4c`1 zmsD9ELoB${jx9*s*=&HMfN(iyrChvgV{ZTw8c3LAdq`UBcBLexsPmRn%#h-KPPMFCZS8`WZSwbh zZe1C!gE}Kkp&>}Jq!31MzP`LxHIOk&tb^pdWIqcd+2)xFlO3=DDyZ(6i?uV9I1v__E{B3kWMw$w&F zFAkMZD3Fb~9FU+sO#SN5BzACV2e}exHYOfzwakjb7UDyLXy^?{?fN#r>Pe7}%{@7D z&TCr;CAceXU17Am zs~e0znOSabqO645_-UpdLYs0bi8v|+T?d6S>m4O$(kqQFDhgvrbFxW1#(5gIm8K=> zlM*hYogJIR$DMf=)?5n+gjI&!3+SM+oM4fJ)IW}qnfI3%hl&!_*|0DP^hY7x-?;Sf z_Gh{f$L;P$6gymkb-BwnJw%M+C-7?0g zklPlL6DCPoHzi@BwFF}wR5vHCF}tTAu1&3)P1>=_^~1xYF9Oe~7=`C*h}@!voel({ zW6{YS{KqO=Ytx!}<*T=V(Mov?bIm1}a(?%ExL@TY2WQM%ipM0O1e_rOAmJm?2?rQR z9XbaqdP-J+lYxwpjC|F+BVC!wO+;qamWUP>&^i^Tuj(q+zOJiW$H{npnbuxq=U?)m?aT#rBHIZjybR(RaE^OY4f$!7ZU> z1a;|1E$zs-Pmc_(MKTnY)H93|(zAA9ac>ivaQbMJ=)msuu|=hQh29h4DLW)K2QoK* zzPa@gr?qr-W9YYZZw_qNn=Ch9yGupV^y=HTHyMR3k=TrY^6`w3G%`Xj_A$95`4(;IS#$bHm= zA;hH(seFjXROcOPGtan;`o>4eQ>{0tuX<(UGfqvB3CWRC7lb8XVT*44`?aRn#m=krti93707#t7$*y(t8ZLwvuy-2FjtdUS-KG?lG{pd~r!==G({ zkjUJjwcoABF`o?9(W0-5{0y8&g3J|I=ErBUE0UC}*M$m_YtRo7Quk8yM%UBD2>cYm z#H7jhzh|1IjI}qrpLoql_2xbM+FU9Hw=HZd+I9i=t5lI2zD9r)4~Qhz=;=z5q@JfZ ztwm)AB;zVqQQewSz)D*yPcnWw=k3vF(HGT8DKNRHVdR{ro;iy8OXPWZeoqtle;LWe zVQfkPvepR#-6Zv|o4UCx^ERGN)Rx^zIj^QZMwcja^@k3Wq{a`HB!u>3(m1!s&&+;$ z^0m=REKQ;OOS)miXHV=;cl_miPu7pOBVB4okjhiO=J~^I_F*HYHg|lr_Qqc*?*7#O z0P`#2hOjDDzSS=FMI+s58A`e~T*ix*~NJ#tei?VWHaZV7W4Dd*fy zYNl~5Zc1C|I(sU@m2$MBf}+^e=*f_8t*N-3x&ytQTEPwHaR6tYD!)((aDq9G@m;=| z43Sb1JVImB<>@+n{Lg&8cRuS*HRSL{{V)18h7l2 zjwBFy0tS3dBh>g3;w41kaMF2uf8AZvyR+mQ;71m8sH<((-Nsdnm1n!xT`|FZ2^Un^ zZSt;2?4U-5CR|=&Sdk&e9N60_KU$R@M2?)h$Oo34Z7rn$B$2!3u9VX^r!1T}gRgsY`T)?N9^&F`k5iIf~aLoN!6Ob4Q`+Sny@k!|Gi|`8;t+%`mMO zYQAXud}blJdD@ku;g-_OpronZs!m%{f%WpuN9-Dg-t>z$o73Dqx5&y6nXg=#OOCnd zq#cV2B?CMCB@SK`>#VO@R!0l0*4VcG!e?yYg=uQyg6ucZ=Sl4x10_hp2_pkNpdQtF zdK6tTrPnu3>Mb&zOL0I`uS~kKkrf9A2}vZA@J=u?PljvdBaGzbvdc#iwl6Jy|{ti6If2aR4B6K~rIBM~J~zIsDZKkJ`s|Dj7jm)P-*3 z53Zy-)+_eqh;uH`t`dChPe^_oq{u>+v;}^Mo~NJ1(xZWEP;i7~B}gDEkWj^a4u&;? zF|+c|T9h(tGPp*Qd>t3$?{2kUVW8gBwLzP9L}rp!=F&X-zl0#~)LP)6M6JkC1x?yBp64G26YnLVUDmrdnQGT=${-Aip?1JGmF z<5Fv8zKwC$R}1a>8m%&?BWu$oT^sCD5UiwNgrPYqCmXrqv-RwGVTv)w{>Q)i5*i<@ zd37?4{7a&t(ih8RvRl$6>Gv-Z-P;=98EQ#y&Xf)mK_KI_NX7{uZ^t!Lmlv(^qv)#) zo0WDRuGVtkCF$QFN#I!Z?eHm7Zw&t!=vErKD^i2Xkl$OeoLJv z7bbOo6D&4+3r{5JtpZ{FYO2?opGCC?My5Oj-6Teg)2N8u$tv?kQe!DiJODeEq?D(a2XaXxxO~^C z<Uw6m?c$L&)OKUC4+L`nWaBl^T31|XiSl(l+FS>1E=hp3O7rWYM{eHIJ0`(O zaITwsg-|zlVmWk_?Y<)7#xFRgSzDpSp#?!r$khq1zRL7f}eDzT>)q`l9Z*f zy(s_?bAU>2d!9I((Po^yeeZtH+O?{y3Ll`<){)GYI$PK?|LQ1V@i1_ zL#ZhWE;w*D?kBs#s&6HkW8T|#_fX(vH=Bf#y}%_3NQKUO}yIYmXBh|KtcfsQ79xHLms|W^d746V$wfpTW8Pyo`#brsX^-Ilou}i{1vwo z+_jsIn|=#zMu#>F@_jAkf9NQ=EcN1gk+Vg0CU@gC0OJzBu`&# zqgY1O=UiJNSek$mVLLG?bqWLEmIiW9F5!y&{{Sn_vBf*SPusM=wd3_1`*yYVzANLO z^f}i2n_6`h(YrI7;0ceSFLqECpq^i~2tOTJTqR(hD%n=^;g^lE)o(c^KT;r&06g{; z4~*4qf4D%p>RXl0*%eGdl{M#~ppJ+tIOW~w?H?6dd?`zfafZU)a`V=wHj*)qLp}bW zN5@}j>5p~W zZ=Od!l}%b=+E=Jq7e`FF_fOAcJ~tlBEdg#2d(@&ZbA$03vL)M$JtoY!MaHAZXf=rC zTV4w0px_<^U>c~b*I02iyo<%^){8`?B>_`qT)|`|3qn$#O$kF_uL{QOU>-)W{XnwA z5{?!9S@eJWKEdhlROhUc-QhBxvuazM8&eWd8qGD?QP^ARxm(jG;I+5}f~0|xq$fT& z9EMFg@pk7L%VUG4CD|+p)E5%mnGf5oXk^8Xl_g0=4o2dnsVAVoSmrUES}pxOJ5}1G zd82mQA`sh=#JOou4JI;HRN{^RQkIn~2LPR^8Rt-~d#F{YIDvk+2h$~=Ix*XEFK9{Y)~bW<9?0)D~niwp=K5Bqs_+;nO68@mJL7o0ZY|rnX#gU)*7YbpHSi zw9SuJILlHkNSh*h5K=^T*5cNT-VBayJ_TGLRw;dy>6u;unNN6 zV5219=L$Z~Vy=EH+i!EM7N(bKP09%gep3$I6w=h_aUlv>*s|(ZxB?C^5_8E_O7R-^ zWp?Rfg9(P^-D5C?JQ<#sea~leMQB)D-4 zsU)YcA((3^ORiv#s-46SuIr3=*J5ZZLr*gFAd?*qN8i0jILR3AJkLIr_BgRg;FFKR z`F14;>oLlI#`*sMnNZEXzjxO&Et8mnZSfL@6oo`eopEYq4{~$hp$SUUj3loqK9&yZ ziCQf~+?(v^_NFd38-2msTx8q|l+sI21i0&*@<89a3MT<4o<{1DUk;tonxgME7gJn`3#9^jxWI)bb-FCQ8y4RyYK)2T5)$0t zQZQ1M$v{pB@AXtKSE(%8Et?dE!`9p=oZt+c;~uPhgTky1H0nzltd>nDXSy+Qm2Y*~ zFFg%mY_QoY32ZE25CW5rQbkw#%}t#>X(WJ6yzMF&&J|wYrOtlW+|}NlS88SyyDI6_Rq=)}nEY9%7=l%fl|%?w9RjY0{2aEedf?vek(x zQ_hs(C~qz)Az4~eoujT!X~&7$n$35J&7Q$=YI~}fXUtSJcC9nFCkjyS%7>%PLmb6I zc(Hf2+jwnc()R0&WlEJR&So&&l(_19JbsD+%1P}LjE;MKRr5_sShh<0;h&;q&4W*? zmTl2naa&5cmxMs!&ua4KroAo{c&d<<%}iL$hMI44&MRO_0&tY6&=N6>4ZMX*_z;#M zqf=a6j!&8keioMwLIb!_3Gc?!^VBa%wi~qSb+&e?7W}Im%Kbd@%}Mwyt-krv5T%x) zFiK8)olZ$3+w<4Gq{X#uXXM(gN4=7Hn(XX5rx0$Mzf;V5745^PTydo^%HyG>DJV$v zRICz4M}NdY<{9D2zulbF7j#XC&7#ipcE(|%B8O_~nqoqZH|;_|lHVc}qO^m!;}nNP zFeL!Ok(QK$xD&XmILPJQjP$MYbsm_|7EM=Z)OTMrop!hjn=C98Jo6}GD|kz13t7Zn z$q7mHlrlm=Bb(J@I7xR^#eAQ4`X*R@ou-qP^><&wosgv~-5X^2cB@o5cW*s%Hpy-8 zKrOynTCgy1oGDlw&fEeIF;elq-(rBP1Br(cCGGhu^R^jmlfIH%wTJ8AH<4=xJ*lno$cV@(S6gC8Pj$v70H{N zn{&m-CC6A>XpW*nP*>h_j1K@0eRz1jp=u+(&#Lt|ppT+tSaz;Bs_y>)=VUWp2HKxA zDL^Y@YDq}u2*wEb@m(jw$u`@)k6LM)o!NxBceB8L3M2rM^X#L0i5&XuO28csbKP9k z#2v}H%)*qSmI3ht(d%6|!+XS=29(yCn$a2qw6N%1`;3lJ|ini z%EO3A+(MMRZS=d653JL!nP9pRZV{37bSx!GT6YYqBw%#T4?&uZTs0+!Lc*N}<2kim zku~|Tp|-8^*0t@z5XkhfN_vsXyuVmkqm?+exc>li^zYFhN%T$0EzVru`DlvTQRmtY zUCt$<+i;U2Kz<4?VGE8Ggbb-GAvsEWRRf->6<6zM8jdVyhN86F?InkzMrtL#5@Rrg zB@Qg81d!7!Dk*TCs^&J+ zFBI>V`@Bniy3un@&6^YyM3*tOWw)Mlvr=%cu0K&)kAZ%?+;22>NzL7z{<5^1k4L<5 zP*Ccc`?>!Bu^r*_vK(tshSXA&$7MlDARP9Y<_JA;T@N65PF}GYG zT;x2bLEMMUH zazQ1>4gn+pJyqalo_K29p?81me#N21>G?e(IP$oxZVLW)Uq6yLd$8Co8fR6=j?{TK zW~HFNB}_K*np=+}>S$7vl#r5h-|1I7O8SS@BP=Tl-_IG|2z<{K(QddC=0J(i>jZ<{e*PDXjp{Jx>ZGs!+)pSdUO0qH2u0Af6H*MGL zdS!<#tj1LN(pk4Oxon3J-)N!K91=PF9z#6y+#}o|yTfx?FHBzJw%wao+oRdukmye6 za#n%ZJPL=RG6Hi_sg~9)aYmlLJeV?c{naXvWG`Y|46I>$h`>qPyE*T!uT$KyrnNr3aW>SaHq}T z_M~@+48n}+9DY@~mH^(vtt5!$YD$l2rIVew!Z!>M5^-d3=45SQ#HHUf!qqwjmf0yH zOIY)FoqbIn&9{0e{XhePK;O)Yhiffgq3i7M`#v&*LYq!a}{2BHRMB>wW&ZiYKy%evP#H5Jz3h*CqZ7&TRTh@1Ixp|=C7>L zT(GG#@jYaA=i45WXB16BTAt!_yKBELD%asW1l?ZKvE-z!Dc>PSc?vy()bQnw@SJ;d zRc+ZVqU7?O9*Ug$-vd^U3MR+34Lf?2>FmgqhY98o7L@^?9B&7ec>bdX<2JiKhtPeO zufVf^8&_r8X524Y4*d1b>cSYGc9`Qf*x^7pBB-HqA3OG}t<-JXu_FKxnsL>aomHuI z1)j-aj}Z_=c=s7j&uK0tfLK978fd5}DMdt*dH_!_F;&~Q4K<~p-`isE23-59pYv#t z-449rdDSTHZ#hXy)KmLV38$rBVcIP5nR8Uwz1wy)c z2nUje(5!eZC!&Vf9|PGgT_!irVYaxE2X@y$CZ_tFX;*l2t1Z?&OB(q-7UWL3OJ(%D zr(SW#K`QL`BoKzwfHQ!Uqtt2>z-0wp*MzKg_PJ|0?@w!!_bcnPahI_dk@9|5`i~|& zzN40SVxpVr7V0CRBPks^sP(T&4lO&|P$>rlch>ZeNlAO^Wm|?YNa0bC&MJj$ZuIe$I+bL141-+-##JG`EgemyjLgD^`G&dR7aNej zM0ROT24uH)(d& zryw0iJ!^HR;HhzeLR1u@g!NfUF_H+$CaBALUrnaSr&3Z=2sF{>g{3My$L^}yvfW`n zX46t(Y6v#D`hHT}Dw`z?q=kir5T)`wlzCT&>aFdIk5|d}f1_iG%QKa4ueQn6!u2XN z^QVL>8lW+2LL89yCu6nsY$-V$leL0MhB*O%FiloGcez5kaJttr%JZs+ChXE$Sw_`3 zklcjs+IfIV0Z*$3pDKQG?*~+C8FTI7Qy@i-#l5#y(u-0ymAJoJlb5m62X9;wDTm4m zb+$H)w%LuwKcBI4Wx*4*Pn;IRPmrS4cMPd`7#QXN9IFUp&aq<2Z->$B<<)w6&8)!~ zM%;V<0G9~y!V=liZ!Jr0eXYUOoF@PkBzF%{81_~;)gQFbVd9bXDXGRfa~Q2W6Jco5 zv)LmGO~3^p

@XmJKcAQ;0k~eV`$yn*LU$ki9w*Grb9 zMAgEXbp^f54s0|+Qk0~T&uUT4UNz$5&zf2198T!{D_iNlor^(-CbAo4DJo04^4Raj zrW0h)ku6)4>#_=_g(QO5LryT-fjo{$l7cWgB=g7^=T}rx^MwlNqy0U;J=y73{{R=- zQZzo9X$m`0V|1-&(kJTH%&4BZJdSWVo>kA%5K#Jo#&eU?uYb>7`W*Q(>Gx#qGv~ik z>2%sZQkE?us8X->NRa5)Tv)jTl8?^Y@;ZZ@e3dxSHaItT<;$0Jk8O!>WXO{x)Otj1 zD*BlEDn<(D5~s_`NRs19O13wjh3TOMN*stnKse`8YXi}Ab-lMd!4fYwlz|Q#8w#K5RJD$b^YJmr>$!ubd67Sk#v2xrmkblea6mGRnH+lI3#i- zo+>`ImY3S4Aw_~tJC*Q%5ZALAOC%Jh+4-)zIB{xc9X~|j-p#r4lDzhT)dY}v44yewx?PH`|-XOtU6IN*rxZg8|QoRUCRK`J;K#dE_|o)gBLuFs*5rFwR4CaGe> zO-|y(Zof|15h(&hg`}?z6pw+p z9OvswcXcBUnrdUWSQo8V?}Et+`+1P2qoQo)*)dxwLKL(Da#RqIfO!z45>5^)!dl#z zXEzQ}`j$V_`aM>k3&{luw{3s+{(mfv@z%&R-G<+3M57=U{PVO3N)S%)m174dndO{v zt(y0G{+3{bjv>1Im)aQc&sPRKvj*iu74FwRT44&?E zp@vl67OY`>uq#@U6zcPYf=Y&a`H}ajVMqZA-V!m>u4|?CeBE4Vi)&`TI2@@UC1B$j z>&m{8c@Z|*)Lb`py`?^HE1H_YAJ+HBBh$LRacg$kcF^;?cL9QOcHj#74fH?P73;SS zT!*R}k+l;NsmvDI{QywW%9+>?GjzuS_=|aCocWAxCNItO|*`X0EoDM+w#ysjmx2bQIYi z$HB%n9FtL=ABC$=JPNQ2>*PE0QeG1_(>k8;8Awhv^pc=Yc|oY(4;%)-QyjF`yEz=0&=ASv&ke30tYWwhCl4W2b)q`Q%)1y5u6+Vl_YiOt))4|JIh0b(xS8x zjzCjn#i7LR1SwvjgGUtIvRtH3>SD)jb}2X`*)*EHc2>7+z6WPB+#LuK`aBH0Y3;#ynpDCMwD z;08}3F`W2QSSVq%v)UDqpibe_o(UZODt5m~wn(;H;>3`zKWW(ul8v}R8d65wc=V@Eb{Lz0%Jq+K3MOeBR7gtiYZxaHlC zZ9=soNOfhR-=YdqwDK9}jDzWN&vJqF)Q5pryGz_DnPrINF?xkH)$Mt}+SHYV5>W6@ZcgazMw1K?moi z_tCRX-&VEnbFyf2%8xUSdCBR4)b#kN!s6mL?Jl7p4utcj8-%zCvE3q<9aQNlVKFw5 zux)ge=f{lFBYN_uE=OxkyRCA2F&n@>(wKX-Fff`lzdFs&8^I z)5)l~E||i~cF#j@C@l7&M1?Dv&r{;BUw5vf)7Hy(IX;$sH!`3z^3(qSo!i)&+T|pa zG_1H8QOOruL`(kyr+#qD6Ext|l_FgEr&eJUrM42u$NNZ}apF=ob$6d#)c+tU) zL8jnbboUS~5*n1-Z7M9Frsl+RvIS)+UJ?L2xnu8FwV~8SVWx3si`{2EYAAt9e<;e7 zwQlB=rANe!bm%GvA+)EG7DAf=C_6?~j(~xKfIJ91hdP>StxKhfoJ3pfS3;I{>{&Sj zzvHU<;d;0BitJ^Dg>~i5yxiLy+g?qfl2L-$;7h1*8MUP<3ni22rQ0V89Fcf={a=X6!sP{U0n35?R4$m*(BWm3J`grS9D#ck!&;uVY{qS8i= za+_{PQ~58)dQOm2mQ^Wo&DLpKOtv$#;V7NQX~sMI@k%(N7bE zNyt_dKm!#W@@nGO2Xyt3{T;-;0GdE$zfE+~cR2Scb7J1xVNS+1VM_!~> z&LQ!igZD}67HvqG2nte6mf|fT&^z#>-|eq%d7|;CzE3wU8BTwKvb{ExzNLhYrz<29 zJGu8`2}u|Ookis(3yE|}wv4i;0+h4xNgT#<6g_wyX~zEmtu(}DAY>>X31DoS&oL+o>2Mn{eDN1=;0ShmxA_xT!{?K?H8DeTm-fy{yc z@9WU=tKWmrO#UlcfY`PBfb;vEQQFSb4@i;f{2lc}wzIQysZj|}Qa307JGy-Qs?4%$ zS)3%|EsIlLG})TUZD2ibdBBd^8^|dtN|H#5*RocML{s<%^d!-v-umBni0^73-C87MzDUu}9h^FmSEE>k%mr3{x2 zAITlNAt^(r;Hg1K1ZM{XD5A&n=24N3 zd^Z!ab+w{givw~aLysi3*-D&f;j`$BE7Kz*$C%Cl$lIFbePI!>>#V=ptssz&&;{=1 zGq@5`aok36%bCSb^#_)33FhfE+U>e`Si2@eU`b)_$VE$?;R8E>z)vjW=c+eSan{Fm z+T0y0J)qFSOO7{z*Ox)#{`&3J>R}~RzwmSE@#K#_2CYFIZfUEN#iZlTm_mwij$;|d z3Q6VO4L4|3!`h}1P}}J%kpO*Z!Q=oOy;ReA*As7%RRJL}qpkEl;zkrywEPpx82RaT zjY1Qs?S)RCsyb9T)R%cZ1V`03)w?1vL2_D+Nv=^2wk4#LC=Aq%G!BG*FIp$N6mlgoP11ROpcyzB%L!Ciwmq#|I z8J_sn;oyA4Y zdx~&7^U!+-F;YEy<$V)ay&>paJ9-O_x=0ePd%{pU4oCw&%vDQp;)T-c_h{TU*+5q! zm2Mzo;RB9-+NP@}8A-(@$i}lOa(#8k-K-fzO<8?}grP0BFtm0IljwzR>(rHc{yO!o z+Xlm9TcDJp1BwU7o@t}bB+HWQ*-jO{`7b!L%&l3-KYQY*T|>3&MTxgomA2eBH=#$G zhkic=dC^gVsGUzM$lRN@bsmRmd`YpHn5CEH+b!<)j{%SiMM=WGyTh0JtEY5MMwTQ+ zQ?5J|m9*l5qlAw20q}jC>*r>V@`2WRRvdeBla?zI(lzaq}&vp-uU3yE) z?OJpB1;+lm7rpy`4UIMio9zOqk^vDM8a+3b>gb%!zN7 z5}5552I!=OtsoPWI2NE(PohBQfII4w*3jgqNL=1^vXCy3TUwk6+;E>jdoj45SQM*S zc~5H%StaF4vs&UZ;<+~3ojp%dTv1Yp$0N%FmMXKk>YJ_fCOy&gme8)%w$Ly;OpsOb z8sXGrgq1}aV0lw+ZMz&ax||Vp3KB9EYb1a(oGYd(TfsKvIPR)qJE6x>0V_)hM&8i& zsV5xyk4BQbeUNeaM7>OuJ`*SXvncS*;7L@3erIkgxhms8LcbI#14gO8J~ zaOJbg7l}5x8#}w}{vI0ik$VuFDfRa69pLmTKP&kjM zVmRbgu08GcR^u-Ajg^G}u!k{~fTWN!k&NPt=M%Nwpvvw#iNfFkNK0t!(pFSdI&|i+ zbKOyv%Prs}4ECu~x8+0)#|I~=#xkz|0FJTGmKh%E8whu~==FJvXbZ)1^h#7F$b=KWmZ{TU%)=DJm&HW7C(9b#sokd@kUn zySSxHAw3BPau56ICZ6I3tkP%^?6-i18wm($#1-ReN=7s4QLJF;S)SeJXK5)7spOZ` zu^k~Hw%sY-q;tmZW1mix<*pQm8AA`V6>cq(T5$^Pl9XWKJojLO&zP=HwfRYLZpu<2 z-R;8(9GrxO0n4a9HMaNVJH}l@9Sq36$A*HBNWzMQZXNaBv*VhnBC(EGJ+PBRmx)lL zxuS0J#Dq3|+qbgH9V98ywB=2w>vn}DCm8GNx895y{8-;?4= z&O53(aMTz3%(my>u1?Q&wFQFjG^CXRamac{VCmsckQ`IC8OljglF(>#$;JUr53iMZ znc9@xtCM^_UU#Y>v#b^X{;x-Qb7Z@ zDkI}PeoE6GO6-i0w9(ue9hcmc!qhGfn8jH`Y_DrX_p2id9X%7vms)A!EtcpdGafui zvfq&E4Lv2nuOZE6X~ zPc)>3bLZYlyQ&j*J6w{btwfF8ITA{<-`A~d({7?I#uIHv3Ju5`NXl{Jli${h+;?JJ zWHjI^!qfpNDJmK3%dL6xo0D#il-!a{mY$oJZ;tNh@DvogeNy592 zJQ}#H$h=QlCM~&=-%v^x^41(HNB{(qatHtck&c}QO5(*OYf_Z7y4p690NfIzo?M6f z>w7OvZ6U`=a?iq-h&<-JLkG79$aNG8`^A;41+nD>xjI zM&3n0W4TqyzEZcFIj|c_uh#i@xtCN86L zAT|iJrzL$z4jgCJYUkAHL;6Peg()Dp0qiHc0SE9`Mv=L~*~^vG`8Y=ChXj?U2Pd9t zNu@PSy{mLfYwrl}#9NvB0Zccz>S9*+PQbJRoP&d!LlWpxl2EjeWX^RPx%lMe zIL9ttHOVW~&c3#vkqX*W$ijO_pkRNRX$0$toTa+rVt{#VWuHerIL%CQ!Z4{t6CAnR zw<)yFvEwfgIAdqgI*L7`SlcgGd;B)7u`RY{_cY1@JKcTNWaILg7him5_yD#qy5!+ z>NnDfmd2BEcG+~TDC~0L2?|#*71F(}X$<29BOJVI&;Z~lWQ^vMEV`$5m0=m{j+N6D zX&jAx#tAMTs;sBLkH20*Lr!lBAacMpys3!gAfa6Q_VTSu+WHCY@OzVrJ`3{52N}bD z@s{$_os$w%k6KN0sa6!A(Qv30XK#4N&DOeWiZO%w9ro0at+G%^@His5%6+Qg9n~`2 zM;!E(g(W<&asKM(&aNj$CrDchSzOTu-)WkUI%3w9HxVTpdnBmj0GKRw#$@sDM}Jj zOtsON~16(?`SK=Qn>PpL0Ft={2@RuQP7)ez z2^~3*26NBGn2wUX1onkY93E%1z^?~NOapq|iO-kl*f_3i8hAoZYqQqW`nI!GjbhD_ z%DVgxTC<6Ims_GNTceD(4ig46c&xM#hLEDllmST#K9dPPmU-tG7!?^I#jQ?l&frc- z#yR^3+^4vjHd|>##lIO%AzZsR0dqMd=jZsbUavOC66t*s**lvF^o}#jsjjF&LOWuP z47!=>UirI!_!)fV))ZWAVJZmOl%BOC)0|h;dPKP8j$3h-=s;4G!X3y-&mihlkbPhS zObNGwFu6=_P~?=WJpGmES!O&Ew02+s22_O}e;37E`7y?8WQo&ia_Mp`m}KK6q)xbo(p0YQzPf&wYiX8SZ?|m) zu8t^ucXc%Rv{j|Fu4)u3s!EpA%yW4i$k!I-JQ7)TK^@BJk8Mqu5mR-EwWKMelWU4fQbI=1dmQ7@ z9sMvnxyA2#^Hgd(oSVhg?Bt1Zh+BlEC{9v@r6iyvAs{6Q$OE1`vqWnG7PP+1mt4+L z6c!41W1oM9X=u^Dat;fmkZ=OAS!2@TR;#nr&Ffm+@r-h1Z*Nxm5o(=zsWqEc=(qWX zLM^d`Sjkf@v{KqYz&jE*{1JsKCzV>7snsh@aN0p6VlhhnMJodyzMX2kk!d z+s`K$`7zGBr|5NFV93;Z1`td_?`d%C)QG7{$q*mT7mSWx1a zpT*0acJI*AFTZoquPsx{Ns~D!?ORV~2!kg)$1&7bm#tLe{Y_Kk>Z!b#Uw5js<-^q&`0FcD!(zGwYYHTD1tU9o z_tI)hqYAn5WqQ+54@fwL6U&l%R*!xcmEd-br^hL!59xxG0~$dGVOdr&frEq30~w_L z;Ivdjk{fIV1C?hxNXR3mNax6Ww8pYa!K2BF95yF&RNYFwCjlMgRvo-tT}No!hnHUJ zR&?Za5F|}$80Jb(JaZZ3PkK);VehTOPDe_6A30KaX8@D!_VpD>LnUrVs?Ul~ZSpb; zwaG(xc|Z(EmpH(_5N=EF4A6|EK$Eeq|Y1Z3L5b^bL>r_|d&}~9g z>cTl3oOG{EPPxF5Au(pjVIg0kp~4aesV9{!ax`0Ofyo8M+;=DIBlWLT{-6% z<@f7!ttTEJ#FV^+^~z5#W^vZ6@X2y!<+q6uG`zA3)=pNW;{%ybfu-r#rq=Spk)K7v zM_&qZU7pMk90Equ%yS=tydf4wRFxR7xE0iI$mPsdYnENdZ(~%5@~zGzwIvS_N>qgu z)|aQLBYfAl9~F~><4=+=R;htLb8lX8gp#l^^3#MH9kzLl+YGql(i9qLr1MhL zd=E<1MdWnIZ*M4vpvntTdPD%IT7Fp9Xq-nbrZw2(H`P_ z5lD|TmQ;d50(tZ6Tjs!17WnTpm8mLowA@F)SF4>nyv?pAQSNJQr3V{3O!Mo{HLdML zm$opgLJ9%e8|^!&qT#|OQBwOz;+uK1fTfhRH;(>U40Fj>m02;HjXOrfk*YFmp8S6uRrd#E(=j*df3W$W^OKBr`0Qw`I zdi?b%b5Oq(w&Oy#FouUUZ6NOIIpfz`t=D*Soo$J>*vUBV=UQV;DnZrMh=-aXDb5Ej zgbMPe$_dU-LDRmjo*L*GJVd)L1PH;1;p9hWvuCt+LxlVkr#!wfQr&0d`KdHCCT_Z# z)hgW*Q^AIuki%ng@K15?#y(ooT6uPJ`|2{<&T4IC3j`#C-GNeVF3XZ{QC)4b*)$a4 z<=={zNP^T=t%gbz0OYR4I6XaHznoJ|!sm0gMNx|DNC0J6Yz&U>g0hx5V`i>Tx*~Jo zOJa0{I+EFW?hQ{2bXas?boMWX) zWy)Nq?Y8SuSo5or&>L{J4`z~jj1FhJvAYF?hq{rJh$N@CeZhGuW4Q?t<*BFL z2xYd4!c?uhQbJOYdJGd%X;&MpHp*DJtqA9xxCESX?#)K7SKUb-ZpjxnRtsrbaC)SI zd5@BjgIzM#)22t7i75y>;z+|_gSo7gABbkX`IW(70dAGd1L+I_?Wsq;xyrIg-kiMJ zK`TJY$Rn11I=DDL!)LVxg5h;r?XFe6*lzOtf<$?^h!lZ^;|TF{&faw(xea+1BxFPTGOL15@TIkjO*?#rw-DUub(hZ zN6A>PvZ&SDR{9u`r8NWYC9?tSgp~x8fyh?W=^O6Uhi%Ep1zE~L#ZEYTZTHoy=3K7} zTk-ADyHLkzge6K*3D15y=h!Qttb9AQ+;olSQ8gY4MU6;FZ)Wb$tmB#R<^KBUhBud% zR#_Z4T^x)wP4Nx(sJDZHI=G(tmFayca*1$mb;0Pcn~sp;O5GcZvyHWBUhPmBO4<

uw+cIC zl7duo^W^+=kshm9HMoNJxC(c0I zj-dN1rg(e6S8qBy-D?CBa=9^ik7Yz9Ag{Js+U*>DYX{J62;<1MHkO(`Sc^9PZwp{8=>nLSI3rgGyvHq@w4N}ht0;1cJY0-k+y z?5S1LLP3|Od# zVs*|WSBh1I4do$R&yMP@C|lcQvc0|VMN`8KO7Kb%95|E{xkyTsdV4g#$`k%G?O2^3A5!)nuz7%jzD;im0QwawKEF1eJsDW=aX z;Us~Np1KD@S*`MC%z-);%42bDu00w(xw4{_Byv-nuo60x;44f}Qgl}=np_ntd=ixP zy{Fr|O>#otQWlRj$7YWl=CaQVW7?#l%apmwZMB>vGC^0ax*pQQ>V(qYNhK|#ao>=4 z5C<;dk~))7-DJv9%pX5qreH7|D^kiafy}is8u}oE>nqw;mX?>B&+N78ap((s=-uGx5{>E*D0aq_r0DDa9Oe?0Mk# z(_V*Zr>0MFU@RrHY~(P2NEpw_T^y}RX}#&|Hk`I;R6>5#pR3CV8Fg6k@2xSzaTCd~ zrGGHXtH?=5pDmyPBsMS<49{rw5Ufp5Q_sL5Z z`?R)3{B};Go_=2HZM;X)wt25Jx^$kwBXW>JK_uf9;V&X4tdf|-r3jX$!gI@=HC($v zE#S0*6(t+8udNFi`?crE#w_cO=B=W4Z{hX6bY#eOG^Tr0CB*M|4~5e{%u|whS!q%V z)7v_Qf?HRdV{jc$Dz&sz7B^?!S9ocT!Ud61T0_SuO2UFtKpe`jNydAs#fifH7(V+q zm#>Yjxf5dt7>ghwDauj;N>ABjm1DqktzihhOfo)rInLX|$QJhzDVS|O;pBxp{{SwW zzCPhgrSRs_dT>jf0y>x3;l&qJ0u$3Dk5((BTHuEdBC6qjyxm=oWoxu}Moi==_U-Og z#9-%X2}sXBg;9-pq_}Hk(6O%e8ICu1VNjI&3zQV4`Nj!A9R3DC=UXf`(ncz7T@;7r zH)3_d+F`;w5(Z3#5sY&Au}jgwyDQk+763RLgNijNilQ6b`zT=2)s4R^9w8yRVY)unr zV*Bq>-!=zm8hyr=pr)2jBZF6z$nn5Jop2Hrm)k4IO8iAZ_`47zhqotQQj|=H>M1z^4Ry$2zW=Zs8M~nOVlp zUKyHz!t~@7t)$^4)c7Azq=iTbUd<^49hpa>dHmJauGqBVR#zU$5wH`3v7wsKVOzqB zW&~U%I3H0I$)r+|5Y%`%JR)&kCW1fFCPk21!(XW~} z7!ny}xYJOTsT)u?HUJ+gF;^O!j?hacJ6Sz2fuCi1T7p{%ZI+Rc3b28d5zypxsE(W4 zm5EN#;Z7B9NF0IXTAl2gLG3*vdIMPm^BAo!Hv;L zjMYXop0{x)vSL$c>QjP1C)@0+zcoEq!j_w^V$w8QdhYpYC%cqf~?jq2Jaz6o*(M> zk{oS`V?D}N1!`Xnb)(7JVyQj*in4ki!&l3PdQuKk*BCXWl&Co3l?1#O<)@8wQgki!w3R8uG=~m40F&0F%4sjMkW_Z#k)}Om z95lIuQYNW#6)9yqasVWA>-Xu>%?&~zl3R86AH!`n zR7qQkI7(7G@^PO4X^o;V8!8GZAw0W>O0alqsNT|(EV{ZhIFp{VTuZITl7gfyeV!4^ zp&;ap^)<^gX5G>z`rn05@ZMFH-F255T)U08&!jZbt(_P(ru1%aD6D1vD@hxZvb`-xX4_-cFlm!%2V0}ZAnqj%g(mT6&NWR;d`RjkzJx24$5Bc&nRt62iaHB zczI!GhB5E<%T$Yv-B$F^b=D`OmO;)(W7hyDcdDp664GRt=@{)0q^OSrR}P=zJ)+ZO zajSlhX}wDAwRUrHFW~|z(o&)u&o%8PSd?PAg^u#^?~cDJ*+ae zRTe-cw*g8(9P?3|Zp5LMMo2;vjHd+h9LVwJJ~L8lN{Dd;CnYC1@UFaSD}yQB(M@V+ z5XI76y|8eHk0pAkwJe0FrAp?X0Z&@h4Wm)q6jQlNby(fda_;$RJX8rJBnVWh;3y8c^?dZ%sw_sss_quaFoXp(`7FjN z+(HQ4k`F`Z(+-N(vb1!ElAC-v@u#%kokp0F;&(Q3gDoJm`u(O0G zBMSTU!^LJ8_afNoY$%~lCw@rX)bg&qk)pBwWpWfYVM*kAky2eS-I_#*O1sH&EJC1O zTWQ>&psq>Bcs)Kkj3lI>6r3l#Q{AACHx7^nTNa-yz$j!%H@r+CUw zq!IPl+xUKQ^45^!fmV9et*z}dEiPcFX9W0Q)5OOUCxJR1N>#a0=RV08#s>5FDZcar z+J1TvoyiPtB=YG?SnT9^Iaws3Ia4>M8y=u?e*J2fJPTWC9%idAtploSbYMFlgmd3s zXQfTPuc-mN1DyJ+5dxEtuJKr8;?Z$E^|Y?fASmYuBy+CD`WNiDtL~a~f|N5pdO-7x z^@As>YmYB&DR$@Z5_UGDgU-6k=v&B;y=`M?C6u-&PAeNgUVO$*G4t1-tc~qPi@Q56 z;mRBM`vrgVE8+FbCENYk=T=-_x-vc&?W^t#{{ZYazi6-iWqd=NtlsYlTcCk(lgJO* z*Qu@kaWccfp=lYwPd@H-vO9@wY2K9_C}iXuR;4RE@mrZdOMwNnob>0=(mcqyXz`8VPu=IUG9;zj?$Yit zmWXIrb+jb5u#lywsbFmZL}w?KYoN7cJ!y2*v9zv$;#HqcLW2w@bVm$n7Y5raDc+`* z+loRGl(upTMpmFQ3Ukac_5QDwcecp6>bt^|1$~ea%V36GT0^P`+p$h<9Ek@VNHuC{ zOUDQ}ZF^p;uyHqaqs>d~**ip;i+#q{0#?&)p(zOtZc0Kx3cw)tU=LeEDD7%T$a?-f zvDHH?FLYN4D^L1}IDcj17L-lDMrlqbL4g&;w(^-a_MX`5s0jhZxZ0GJY-cAY0|U_n znvVHLYo+Q9M;k@4EplV&R4zNxl-O-@<*RROqLhTEVoFjI=;Y;RI3Nce3GpJ?X4Lwt zS!!G0wfXc}a++dPje*w|>YQznxbq+{XaJ00;E-`t%B49e*)!h?Q@;8schTj#eJp6Qz%d%xsX&!IV)~?p8OiE_`xlyd{NX6Lk+2>kjq6)k+dne z%^_TYJ?TC5!|D2r)6KId!QJ|w(exT`Opbj#Ql^q?zPYltDCfz{0$`Mk zJ3WC*a|>&MU>yEsLKECROv=X8MRuqtM4l&lOzbB|oO5!9ZBr>-{EWG~IEQR_h zINCFV>&<;Wk#1+@a^UKzI?6VQ(VB5`?{}RgG7M*~P?r_>=!te{mz1|&ZNw=~xRjwo zVp5~Xa|DFfJ#l+THK!UHk}I+hCfwyhlNx(%rE#R8Ztp^aLt;o%4y1&sU>-qA#^Yuq zQ1M#DBI~F04z0dLwlyU(B!!&pg#%sO<`{>T89S_5gAt z&M}g$-8rO^JzlTDT^n|_XGuXz6e zYPUUfwd=c6%t(uPXrR8%6qP)V@#;_`I9GqG6~m?0=ANbQx@W!X-==h0e@BbKx7>nG zRQYfJ0MS)2NK~XF&@M%Eg>K}pNPN}WT2?|Veoy+5nR7028o-@9Fk%bJo6iq$^Lc$F2{v0@1=Mws&` zkjhv-HJDf{PQ7KTt%Cpbc(xy75eZnKQguvm0 z8l5SE$P!e>^2SQOq%zWo_$5G&=ZO*4SKfbY>Jnkf%W-+h0fNS*4c@T;C_< zzpHdOy+76R;lipn#T`rJX&r59dt=T>|e*QY9%wAJnv{iYdZE=RaHqUwhCWH^N-DJ2hYNpEOQcAdnL%dK_#+^3IBr3X*J zujtJ-4Mw%&)Z$W$^86Kzhf6P1-=@NLdrZc)IQN~%Y?TI*hYM-IIKe7IhdjU=d33Gr z=#Cz0SaVs@TJWxGEU2hVT6+Zn-c(y}BbG9Pym!<6iqUIY^|pu8(?VR7&zeMaPlc;_ zZEIE(NXoMzS?ARU!k}$%gI3)lPi9@cyK8A@J*1_Swy>O$wMAZ#$3vc3@2{KsyqU5m zl6BGc`F$5lp~9o5(=4gET(7UeRraoy9cgX?q-WAf%8;Rj437cmnwn|W+(xR=?y0nu z?rmEM0AVL1=N~md+ijMbEw}D4h+ZFSlmmPWPfGN117oROaWDN|5@1Ae^9{c^Jo0 z)~WtD$hXS7v#TN7qd-mKHqSMV`X53ZX*~8gms~+lOoY0;9z>E3Cv&2#Tim!c5-f!_ z;ZudsIfUe-k@eW`80ng=_?Vv8O51POb%otah8jabO)|6;A4x3|c7e4#`J7;M0=&Oe z&6ftIE)J3Rf2X}ON3ZnRd$>}RdVf6{wHArtb&=#-ueze^5=-&SfDye&OKRK@qEis0 z4artc?+;n3!;1PvdQVZsWio`=GUINEB`R#CX-O$R1#10|G862pKZ{yRQ0hHF4OXig z^4LYDD+_t1ijtLf@=5fujzM`RxFF@8Nh)MKP{>#~HImYZVJAw|Ho1GT2{kWVel ztb>u9leAZtq|cRRkKK0pN44wzm!*b-Jz!Yth+@f9L2T@Qj{So8Lq?fZq?AV zb(ZUJROB-@PM>XvA#H~Pj}?LwgWZARE00pNt54kI6s2EOZy@_Cr}$FiQ0;bufI)`Y zD+tfloQ&Y(+5z@g*=b?-SIPM9d2U=5hY@w8y>X&+#g^%JVe9J?XGxfm5Jzc*6sPKh zf-*6&KCI`UBv9JQ${W>f>1$%#-65tF9g=rAwYuZYfTRSco>)md`ESQ{P56yI)XWIl zMg2z(*4(U0oQZNU^Q~c6Z3P|68F$>Y1~phA?zJ1=RHGTm1{k<#A*Kk&X3hS6ZF=GUXu)&qNOJ|w(WHM5!;^( z^v0o=cG8xso!K{dEC-C2ns3bLL%ifp&1c90)UXMNLH8^iw zSL5V>Yq1vG#92%QM^yOEI))@2uBAxZxF`Tpk~b$KCm1;)e@q4j0*WF>a`goju4Z( zcSq~X(!C==Ek=1pDO7gaw6E}U{-#xxI;QI0mz63_us#b8No=<1%SbB(6r}nq-kyUX z1K(J_vZkWi3Chx@LBQ_xz@*n{j=O!j%5^9!dSmWvZF|ztQi%ylh#3G7Iu4x&N?)p+ zLr|=0LW+l)jHkal>*zGLl2YvacV6K<(r{c`J8y$rQ-4HgS^9TQPYvoR+L|Pj9p=8J zD&N`R#?-F`C%kPwzUpY>4dX-GTYBYcmo(b$&Vvrv&txPv^V>_%TR&c$y3&Hu5wVq~RvuYy>ep=2p2%>dDFIl(DJsg- z(>riMCmB99hKu1HoSPP<)fec>g!-P!T2jvb76ZktE#7<~uR@jXk&jxL(68>H9Zq3+Q%^eOlF`a)#6mZZZ%V#|`+lH=b1 zyU3xnoH(W94V-Nq_*FjeTI?;?fp$wp$8Fa*vimhSpGXWHppUM~X^Qh2YgY|g<>JhX zOYS!0r!C;IF)2|5{eoJ$T96J*wv$q_<2;J7clhfMU7T+i1 zKCZTE=Sr)=(;BN*XiZl#MdHVyozvHwo9dY^<0j+Uwvmjh&^R3ji1ySqhAjHc+05zp zu8%E(w$V7DwL_BPNlKE^)6GCD0FqOU#DbtH$4}W(`>mBM2XnufDM`nP?)HpgwQB3M z)}587w2Lc|d3gy-vzFODWP_B2g%Ec*0{s*X#B)-P1}fgKnpk%GQ)#p4e@5sqYcS<{ zoJvrQw*3D9_@W(U)A~y3V0TpBr`%hP)RvnDGIwPz?Cgfng_2J2k_SAFUKIz`JT=nD z(??lw{{T|Cc!?3w=S@1aslYcUDi}%>fHxDhZTR!67B!kv+%KJIv_*ORTp{_pY__Ek z(pL@5zz$fzS;_e-HDXH(J7*w_~aVC^u5yQWw=W=>9eCe z`)Y{dqXf3MTTlmThfTcs`m%6ph}SI$y3#^ha1bOkq1*`Nj()M4=w2RMU|uhiV&1J6 zc}=DR@)F&r({-nUG8E=|GzT(ATw|fHuFflOK*OEXZoEiNZ;2!h z(4~C)b)e^9DL#rY205N}#-=?N-xWI%l?E%SZRJ2 zI`n-rsCBckCx>tn$U=~nFFuO?rl5~vmAHbQL!DQe$4nzeTCTQ7F43+lMCkInMn@ut z0>XC;oE^U!V_VDB)0Qx>}E5oVWL|LZ7O^;Tlfk| zIaeY{sVdvIw>jLJ|qI_Oc# zLU%Tix4(lap$mcgkbGg zGD3jmk&*%B&FZ;*oEzflpHuonNgZaZ*~yJcK5xSL6W#5?)pa(q^NU+4Lxehmovs%W zj+n_VF!B#By~3X#j~>L!@?uSS$x(wQLQAPBVJpbpw1M80W1n_SH0dZ;dDqE$lKiwa zC3{?30Fcv6vftEMLXJTx+@}}M9+K1)tmc*3ZrUaqJtJEd-q(Y-J9x20<1smVCSERCop>Z{8C09qfIQ_MFFx3IN3 zlK3Gw+=0~N$2Aq>Uu<}5czh|vCBDhk0Fmh6;~y12TOzvLF)mDi9%*Y%^?FJhJAfF# zz*jE(j$*WNg3oY|!aLN5i*6}Qr*Uo2y_h{RI{SP5RrfeDeMX&Reo^>-uTJz@scGM7 zwf_Jj59Fk$7cTtMBYSS!UjZdJ!Ar!0_iLh_PQ|5#G!v9zM4oxgb9a(DocDU-(xhQh zEw7|^ER3N<r z$puPEa1V87XHuP`+QJk{)S!0vfm)X7N{eV9r9&7ZwV`-c-e42VSG6g*^I2?)rv~^4uYWiP?6MQoo`!?t?h_e+Iy5KIVwWSDgfu1tR@sxc}A5ol@Cbo zPCL0~ysc^qN!y*N+5t7`=bRx}Ym#xae07G^g(XB}_1bGL%^ZEm(SOsQ`s@%?Mv_4BGNlxGhNlMHp<-e3WC4`krlCFw*gAr>D(()HZ-vL zIc+?E?&tpiWmTfpN4>2e6s@v5H2Z0zQI?LHzO;nlE?eBsFI7D_M`ENQeL*{^72xjE zmzK^QKIc8p9X$em^&dsx_MCRvQe+1k0AwXZW7SfvG_W-CobNJ;2YXxm5(!kxH15$l64d<*^Iq7IBG<$<(P89%m>;nNkafJ?lg1IKX4yeZJ{{ZzC z&keYE{-8>3m#yqTaFD~HX%0Slfv_wPehKaXV00NH8hy(mqszKq?;_g*Dps{`QdHvh z?;!{yky#C_^dpuz5-ZmSr%IEoEv-zrNpZL_WFj*~z);v$NhuyDb`C+KLR#Ouy2N;) z2o3gy#e|PQ1rxiL2@_oCE0BCOo#B?3Mw-+Y0t_>G5=~sMRu6 zsx5P1ThOSM3p{6JCG{t7p2}z|VpE=thX_{V$heV$Km_u-)-u>h4g|DD;4zbv-Ca6N z)61uFo3-HazgB5<+C6M>V1+tYU0;z!nMhRj$R#~MspgolT=gX6S*=#{A?zvAl;HXS zSW=X6xFlzp9P`LzbEplgvqiy&9#}#*dPI+cDsgYQ$%gcY?6-HLxgi~ad6jKZYjOw~ z?)V78z7QL*aa&~F>@^TnRa^O^GQS0x_zVRc=M_9ITo~21>m+Eb$hWl!0djB^N^~p~osJA_ z#?isYRUb3Fd0o;fD&PYGBR6^V&tX zIxy1MUR`+S1dN3Y1IVPLob>RjeT$v6#D*JRWVTodbP?a-R__CD@@`t<+RUqqud@mR z%|&Tz0Su!covH9SImk7^u9iq)-v`m@{*}X_&93&nLK~Coz>iELPpwj))c2J+4}Jdj8jQ)|dP z$1b77sT*_+p5=9$+gW3^CFlx6%VBP%8^T;s+Iz=5bH;FaVx73GrnLtLlc+9o8fsO# zLRf-`+vBkKE+iEO3FNJg6m!lJ))RnoFv+ON43KxjK9f)Bnq1lqQkEo~Z)@}4$w<~*FLKC+_x?d z&Rk==Yv{Z9Yr*yEDD7SKKb%3gKG=3Io4AndjzFzx-V_1=P#MQEq~oZ{E*NQ+HG|7` z=C_%O%r82S?0-b1Uebk(4@h8u2pF8e#TwV`E5kAB0C9nev54(_~X$} zaLx}pZQ*RaWNi}{p`Ew(t;2|^PB_wBbqPyn1tW0g6q0#^)K`g?dG}>XUkB-$Z6Bmc z8a#^?rscVI+f-@P3(|6}vSVphuX|S0>vh|Mu{MUlJ9ed|m7JV)NCTfUS}dw*-zJo{ zr6?9P0-BpmiK3x8F4;Ub(Hq6@|V69Cd|c1pqm89Qk{5P@O9AmB1U!AnwIS zyax{~fE1ozaQv0(`d*>s$M<+XQ}vdDIvsLY>YB8Ys{AobgSfWpQdQ`uo^#z>n^9Ow zw&3*XN!Hqt9y-GJ0@wuSzXG?%K7id_IeBNyOO%XUkQV|-2MR4HWcLpG>TjV|T7O(Y zP+`*KdGin!0Nal-m5k@(u3VacxX%E3ppJbjqP~S>x0S}2(A3+zQuMXu4t-5OoaGOL z*PphzwQ9DS$D_J#KiF^n(O>+^_;)EOZtrwgGWWU?LdW_2Ywi`y;tYfSO<(-V_;4RD z&6e`IDpSfUA6=DKezkq^F^4C-lBA?4b0AWt6x(hWlBBHU1f=(xOhC?lI^7*BTCfT; zw2ok4@~OweqRkejhKSsIzN~GD2yib;?n;nz%&?q_fN1q+PPQB>1acV_I^psmrCR0J z5aSX(?u9e}!cvgZLHR+d^GDB!nt0f|092)t2no-MbCaKxo_*zBHK|TCztEgzS?>-f@Yjyflpjgd1N(80yIIO# z44B2Ia#qdCI9C2c(ZSC%^8Wx&T_bT@my|h#;}}m$-t36meK`$dA7x0>A(UipZ`-=7 z29l;sV)<;?wG|)&2P4=pHAi38a^vpm$z)pR9jXO`cL|hXQhJkmqDqDeFN3-x#SV=;AZ~+|g>o~{XswZxV zMY*JtPSjW#y+MfRaf4#U9f4k0}+X_)i9&;%N00V)JW5$x` z?OSTM$3?F8x0wPcX{S-s10)0cs!MRa+T<;2VtZ>!k1X;(9ch;i8Ko&JXI4K@)!>h} zk0VR)ZHKRQ&9>fcmhDq;Vizr}pvO)%nJN;}W3A|({k?5yK9K@oMtMB*pq@XFgytrq+cR1 zw&h15)v~SlUrhHJLgVY2^4?Mbal%xffy)G>({SbuyH$PwwnlYs#9Gl_kWL zr6X|1KS)1CO>12+Jo}IbGxwgU?aZEUsq1~wiaNV7t<2Wf|dhCFjW- z)h)@LJI?Nx36tMx1ueNP-Rf;8xOWQB_YigCO@z0rC!s1K7~G5moD6&)Qh#&nri<4R zEK~O_h!T*sb>6X2$r`1X(df0%NqDXk;v1Rf0JgYop8HOYU6pE zE^Md3`m?LgPT)EL@lsoAlADAjZXkB4$@OBiNV+?64K(IL8u&gnnCMq(+8o?BEF89w zdUs%&j7uICqZ5xVeA=v!E?HY=O>inJYtSzVPQKrr&yXXw*vgba^hwXG(oIo1?;JSW z7mJKE6q4#%d?cw|IgEY!g7Bx0@i=W|y=i&&IWw4j!mD$PI2v{uj46=YP7(VW#(~t^S5Vz}>VDo|o7sW867_sH({i(wIM6U!V;Wg z9F*y?P6x6|&K#GKHs37jxy>mN-BP7Fv0Ks{Y~Z0or=&B3 zRPL;RwazoA&zCjrs%^KVJXf(K=LsDL$xk|)%M#IeZIf%@Zkw{cp}JDzPmo)5k<

{Gv)?tUU9FJ)4KVEBQ`#{F6xwVY! zLKL1rs~`_YBbhY@)TPwlb;UeNmZc~XqDl3tlS|d|P&3h4YwJI_<(m%5}y>nNQ&hTdUo%0ZUjyNX7=|R!^+@ zsRirG!&ly|QJ^)YG>j+NQ7=o67?&N+J|Cof4mx!|6bA3bJx_TqEU^)^sGRl@w&&N* zt*M?IlC>3O@nzLw#_>jOpX7ekI*U|I(=y_{siv4HaS_aAJ+&%H>M@L-o;4rPGZAdn z5ag9?X)QY00QFLl=;PxiqjE0N=Aen)qJdB#DLY3he9~bn)ONM)$nDP}IbbI>=Eg9^ zCgP5)+U-W8`{}t?R#+SjwmWd2tXhtjUw#~B9_-n{P-H#}j`Qjg0p-@Z0wYnS+MYz2 zWxcHgpf;kH3eO;+%hjJ%afot)k%k2_e_eTyH5G6iC={-O8+uE#+Coy)hjz zBit=>8*M5`UCII^FDlMX{iNp@>)nd}vmxij(18D&pazV$9J?bO`+HDP~Dnk1wHmCqFN#%@p@~S8ICUf7~(bd{c z*5ntHZgGd3Q_GIjh98ct;4CK!0DDKuD$LeePTb|K=dI>U81Yf&jXaq-Q)H|j)PbB7 z<8QY$#dc39&MfKWFt%_0a;6fL70P5fwICE=5_zA1j=y4jYFT&k#^V*{#TvkdtdOF% z;+%2#_Vl*5@}h8{6XJRL{Z;D2CLEadPm`VxQK!l7VU<6?w@}#}fpJ~X&6O&8IT=p6 zTssFug>u4s`2p+ANA)hW*H)c7Z@4$9?#W#F(pXCSbR4#Xf(K?(%bJMKeL}AsSk||N zEfb$%vf(8|u|f`gcuhy7U9NXYEjd0)*0#O^ezbb}dWCrz@M)&$K_0H3)qP77b6K6s zzsVwxbGY6We!Si0yE1IZ06ih>6)iz%NcCfC5IT1nm2f=ATi2G&#fD@BHsegVu#oY_ zIcKLTh}vTBw%uAn)7uDp)P-`u&UVyEPZrdbwCaMAke&NcoQ{Jgrxc-%xH&Rpo@uv{ z+@F)X^!<`-gs@nJE!U;CP|#sX+^q8S26LW#jw!cQXbbh3PQ#OQ)wZ{hosG)4A+hj! z=N!Fft#Q09N2qP@H98gg;~m)NEI8D%6pVe3K2)mltu#)pySO+LdwEIQIc>;P(l&$ z=BbOuslRG9qD}JmCgP?XS{n0(a!Pj(Ng!Yh;-lp<97fcItOXU9RGvydVxmtld+AF# zTS!q#cP(i`O3*W$^Z*+3<%bmVdx|`ri`8|n0>LbgYVl-)SjbSns6008EUd4oEsebW zeu+H0>!q}H)yr&wdeJ(9JF#wd#ao+kFQh24;&9+nNy<)n4D_yM)~q_+=X33CT9De% z7NL(tJh7f<$Kt5_1=c}vFF74unLCg%yC*!(?zyh4Sv|ISvxCT}@69X2OP;cg4m4R8 zmgCx%TaxXvYjMCNZc>W5Is!oNS^_{B>Tr4U&ONm#xAyXMZOL)awF51uLV>^` zDPPT!E6;`qsqTzYH_PfeoVe67O|-sPqlc3%G4FF2x=u05;}IRq4XRjJJp4HYRqduw zi<>MkjZ*Esr20rO?hUq{eMtl!b;|BK&!mJFGNI{|5>=kO@mXm}ZGQ%w#0>(Bj_Y?0H>DM|~2t552h{1S48R-09E1Y`02k>H6b?%@e0-#ibQcTpamwPb{w_t+L#;>zxyMwnmX2_|!RO zD=3uA%%=)MLJrb9y$`!jEb6T)8!0-r*a^TXQivZtb2;ooiBD_GIVo}Oe2;(~Ki^LW zP)xxkO(h`UC^i&1cXAbYY8-euXNz}7M=Mk5MI*8I$z~jm)7s-6HJ5b_ne>TF@m&y- zl!Pe^+)@w%dw|+V9r)>JIy731Mu|6ubk3W4Zjn?OhHn`Z@VTkBR)bg!w2@i9c=S*5|)BicIP1HZ$FC_ zSo;u8Djk>0tJP(3a>)4P>>CcQ;q8jr>et5`TarBK6W(pci|bmsZ3!Dj0OT?2H4)=? z6?9yk8s?MH8i-$JT;3^rv5KZ6L}@3dK59M#pssHSlA;^z)ap<<0#-(R2P{_M4d9m$ zm~L-K0ZQzNBzFPJAXf3!`*7I>Nao28dndV(+kQ*)$sR(S*Do-Z0@NW+2qa}eA*86B z`$sD2W?OVyk8FTe;y_P6{C~XHGkGanE|GQpu$LcU$!**ea)L0&WPy&JC$0y!x@DN8 zG|HDDAgQD&J6E5r9QoH?l6%)DCTJxg6U_sJxbjo&<!P zhcJG)XYSGo4lP^5pAV+cFe|mX;O3;6QrfJb>C1D=(!xdACsI}w6#GgXHk zS93+PPd90HN=uJOLy2W&0YM`pBvx%Gt2D=rNz*I`6avGlklJ!^0dYL(Fp|)arxx=^ zJdPX{%<6YmI?@uB!d3wQu2Bc>);!x)?Zb|NyRIeY@7EK|nY+`bbc?Stg_ca_6W$bE z72#5$B|t80e2)IqS2uZ{qf!c2agGtl`f@q-<@1ADmjd>uh*an;g!igJ0Q`N`m%Gg( z(Zu7zIz8#o7IL|e_a~SNbOVashZ=D}v=XMs1uIF)RqQp*NrQA+{Wl^!KFTzW{oOj| zuRa^NmoycD&D+Uk{oL|F4gt=mefCm#_Pb=D?mmKgbv5l_O4{bq6VPY8*0lXsJ9E>R z9Zha=M3kcnP6t9N$(42B)TSFliF<#htn#5CdO)OYA3bE`f*To9dipu7TVF^~Q)wk# z0LUlCq=VA%rixMC4n0(!VoTOrq;w6cR5x2E9YI0OC}jl=_CdXeuQOhpQ){=(^s%{z zQOI>A1XX3xYPzF~UvFmQEFPn8tH17(SWL+f98=9aQ=D!9@;(HQmY?pn+e>=`v)*aI z03&GbR*LwIDp!0>V#GoElqe z;#^>Oj3R#Ab_=TAtHHWIDF_5-WW3X+%JYXxxM(1Qc^T#(w>DLlkhwY*z+) zjb2?|P5ETo`62GRv!aOyySlsyFE)3fYCt2oc&E14r&F{p8|uejNR0gSq{p$idq!=| z?NG{FanDQe)@}0at*F=FYq)CdRd|hWgFgE$_N|f3Xh|yoGSNy>QV8zC5$(XID11)h z4ZhNB(Dh{Y;iag z>5oYIt2d{Fl2mlZ)b&t%p*FwnLz{^7mdwu7fI$lQ`ulT}SWyM7p+|A>H7k?m_T(w2 zVs>j!_aog=^DZ}}R{@@VE1^L~6mai(Ch|%0#?`G(B}FO$JxiO0X?~y7_kAxtH(fhE zTp7tikRNRNTUFF#=fa(B%&z9}j|R#gdm#yBhD(c5mG&u4cPMx5rM~0JVP-trLlGQo z?OSg$Q0r&*VEyXJV~qaS(WEClQuiSFT@lM|_V;U?i>kOl^MVxO3?Ezz|pjNgx=oYsq#waZH&tFR$wJA!&q zX`v}@Xx=`ft5A5ix_zP^>b7JaiS>1)$$xT66oRh)oT=JOlH-Rgvw_|*&b7l+uP3rg z4W$V?iuNbc^>pP)MM2rib;;*X>bvfen!ApcxIb@@<0dn%G;pQ1cAbYKr=Xhgr|i$M_|zW0ZoZlcTKX!wMgMnqJaNoQVsKEw!i&5ZY1`$a;rbec^m}j}5qs92}M# zWT`%}o^`$)afjO#NaWUPC#iep+kYk-E-Kjp#Uudibi0A#NgsNZMp9N2&XB+79z)Wvxff6D2^jwNul{9xHe@)i*>V6254pH!mUnp9rLKQ` zOz`k-#(8+xuv-UrFpw}vJnP1B>2=3C_7a{z{@dcJW9D{UmbQ&~OP8+YOleJzdnLV{ zQn&PjI8oV__IHyWflsuv`Il1zq;3EwmPa~q z96h|bi3!t}1*CvfTZpm>R0#xnC&1QF)5>b%S0=9<8cnMpJ(lKot;bS8&O)e0*H%)u zmO;h|Jt|`xOUk*Omg{ zd3!2e8Kt?PwOHJ?ZddR^65jQxBXJ2h$UR4mWU!?xvuLLTbSEaIzUB{t63Fl5n)KDb zvRH8qFcd#yRNBpmiy)z3G!|426ber&aBXd=C7^{VL>@!9)PO^IE;!;tN!&Y=kytFr zOKRHOa--Dj!KqLs47Yn*%tB%2(D6`Dq@JYo#y)y#?3{3HQ*MHug)L(rCt8-seo-Bo zyD+Q)lh9(3BI|K&Yr`?pgmuDs)pknC%dwFWke`Me-H(Jp73~cv440Zis#f%?8%gQY zyVp{S48|l&P`b!dctVzx_CTe4xeWJns~1S{re3pee0lNNTWpzX?NktefzWO|w{_+0 z@u-_nS0-zR4ouFW7Rqg(I2#gTJa-UzAd!+!EMqyR#pwrEVHXssDVSIK3dRW@vG*!} zuQ+vm;my(&y7wu7{OHDGMmxz~)a6?WusIS^p^s;cM5V*IrG?2WmKxj=WMM@+&oVQN zcXX<`B$K`fmY+0~lw#YDWH7>>mG*vQ`2&&kdK&lUk`i*bPY-Kk)0DYaDC3Of@55bdV+>77(h~{ulZ+*dkyeg` z(o*&Ow!2G*nKdF>VKQ=%lCqrh$n}bMy>OoMVztk_T*SLtEz`}jW3PQt_etiq!0Mj- z()ZJvkDDrUOnq)({-zR55{{4phkPhUFeom@rD*NjsL> zNe7>HYHEvAxelyGRLL7baa&MSpq_lr-hIcFGu=hX8>>i`^Gj^)AcCE~83&zKQ;Xp; z{{T&%G51^@e9*?LJ<%xKZPJM90dBC>lH}rdvu=4<>*$_d+E~TL=F--E)Ny4wD$0&C zQkw#v)Yn)xsS=)y%FteU#*Plub*-@D-~5hww4=I2MXft|aVsf+;x?RmYsNiC!2G=a zN_MnZ??zHrIfEUP9Fkn?{_5yUPXpp!Z8n+Gu5h&Tx`m?Unk3g;Q?D{PA=fYnZ3b8ejdnrwF%n+j5*y3c4_!>R5`=%8v^#H7`lJXxt!9X_3R{RmClNlr7~ zeU|%HUORyb7(M`wn53@hTl!WK9__l_@@mAF&t&9-TYs`uC*Mb%_-bC&z8*tpx1_At$@! zs{>f@>L!|M*BR)?&Mp@Ar$|oKghx_|A*`OKZo~1KhfKFZb=J#Kz$Xoa44uUE<>Sm# zd=y-_8$CW~y{-=5;D|3l-kS*p+i*uSkt-zoIndsSyA-U5@l*%b2e$!Q^&PEN`6v>Q zwp3I>ZNNs=U=T2WVxWD5R{cFPTx*neS;uDT!U$13^HqvcSK!J~aCFr)VOkdOve{bT zG*`(xoB*Gewl$$H&B__M+Y(dokXCtt-`5>+@>Hvb78W&bt9cg&)hTI~%qG%LBBvCf z3P((Wk@MB@t++3zEOs4BbF^9S5LKq1LOkMf5L%wDNiDPh&sC`N`xDQlONxiw%0_Na zYUP~y2TNO+vdD)v_Z`P2VD3*wz&Rg1HJ%>F^irK&ZVAsUD1tq>sny2Vme7SeYg;Kw zIc{iy8o- zsnwSCJB;PQxD50Hv|Mx?TX@CB_X!C}BeW>=N33(_Orj)+6I^CoXCu7Zps5Q&lAs9% zInV4=pO&2O6Ca%t)RiN6dpp7CaNr+s)nT@7k(Na9$;Mryd`%5$l-hd@N>tjEFj|JQ zxcagxMQPHSe#d-8NweWz*yG<`?%^=djI?FB}K$NkLe!O7R)=`lu z(#&|Pbxr&Sai?%x$0#YNHiNN<*8QcrujQRxO7dYVJdHVT#5#0tUBB79ShzPj_K z=E-K+d0`<(w1>D2+>))>&OMc5`77zWPNLWPe#?G{9fxthvl?dHWpU8jmf|vb`al85 zgUYUwR zw}1~r^{3~i?aoWr4W-vqqPLky&oS^tbgvC#@WD+y-lI6wsC{9VZkwF9_GDlHl#$GM zR=Dx07)jR!Nno_W(+NY->@y}QP4jWb0ZYHJPTD~Imq)oJ$+Gl)$hVSqB0)$V9Zgu1 zAxwSQMJ*vjNm@6-Z1ze}&O0%WKzn>DJ8)&m3Ji87Zly&9J4)0_F`iidohtW@cG0)e z>SW_6!TsHES8^TU!*aVRI&SF53ONFA!5+@~e0xps>6=S;G{TnqE_6M)C1<%fCltr4 zEjNYS+kJ~1^(Z&bWLFdk&$6^T9ZhJ_Jgi+0j7FxmdH?Bbpcw?_xklOU+wWTI~mxrwvLiQ=gBya4`aY)Vq z_13-*A*Li+*0$}*Xj~STOyEpnk%Q@h-Q()bU3%I69LZ)UyogIx-43VS3GvXO3PL;E zX$t3`U3Ee*inh)u@0`83t8A(#z?pGMMcYC`n0f-_j4TgTM=oPY*rU2;@X9*MkVaDe z?Y_FSu5q1hDpHzT8&Xxcq@j3+Zk=x02*_1Q5#92|T)hd&v0exhIAZ z+}{UoEe5V~*&K4e=tnGvhu7y`h>b2{z7d9#+WIOx3FXh#NhaNNOHzy|8Zi>e6b4*( zAxEY;pBiVfGb#nzA|yg`I+W{cLvFTGuS<814hF(LGg`FsZLd+nE7`fX)TJkGbCOBT zWf?|%qdCTS<+mcHSk^s0i=!qd&i zDF7fN0eR*+_hPJ06LAV|ozpi5r1`M2>G(^Ii&F{R?zGuFkX6af9WP4K{ZdJ&u>)cGM}-_8VkLvGmohdZw}4M^dwlW2ZCJ6%71T zi%OMh1xPJvy9{QWu>*t@jR)n4bYlOpL=B3-G$Z{E&SOaMU41{F$JjY7$W#Bfvy0abZL4zsj zQQ;wp3MmSZ^J-SrAF)bMRm&Xfslh5aXOe01Rn2MH3JM67XKQkaQd@%FdUyIgYeSl0 z@Jf?$j8qN)5D-Vq1wWLo42Pn~Zx6+J$j&c$!j{^~6h=F@B-fzOQiFvV1o)C^?8SY| z)nv3WHKwMIhc-G@f^+5#0gsI)l{Kao`EPEbKvB*^aGC&r(eNUl8;<CLC9B4pi+^yy-jg}{ zmZf#Td6FWwG5-KYhct6(M)YcFTaZ(+AB`8-Rl_>XQ zER)ayTG*8#nFx}@8H1u$O~q(d(vj)7o@YHN07zDI=(JKqlg$?dl6tt6qGJg$CqFZ96j@b;U#U&evD!@FtXP;i5gRMduK@Nu!tYtuB z#;hwmX%_{@g%UfjNP7Xc(tZ&f{%mLBuL~s9Ewj$J1d2^>lS3io8 zu=suAg^i#bWDf5d_S}>Q`$k75&!R}{T@-P(N2v`V<%RB90H1^C{M~C&TYw?P8^A$1 zD)_4s%!B$g2;4*d@gk;sH7BD5mF%xzHpFBwPD`ale7Wtx zz^xJ1m+;z_pG0#$CblwH=Q~CgLU~|&Xw{=w9CLMaJ#~I(2wv=G0P9Q;PObM~m| zmqop;wBDZ6@U)E0D!Y>6UM(V1tC)?eQ^8nYuzH3CG{bO!mm6~gl6fee`tx5LCht3oC++`1(Uug_t;!{EBx&8a&G z&OMbx%~?aHIruC%;&Yz9naAL(-pYdVN*Z3(6t4&3?*5(?M&3IyI&@@$c1(Eyve>@`Ug zxTU8G2})EmR?dXtZPP^Brs?>03oXhe&Qo$9MCQo~SWi=f=?rqg^n1w9I^l8qsT#k# zp(COiZW7gKST^$|)IuvsIF1%Wc^kaP2F*$vbl>> zg^20e+k1|7pm!u>06T!EYip?~*yBVWgsgP~*IiLbQZRPE=tTIL9Z@C4Q5g>~R8$8& z-Zcv;N!!cd^s5VtNLOWUSWhJ|-~+!PRe8IgDy~IFuuU?3!`YX}mniP(RAypgxY^h; z>urSPYGb>!N#)3UDrdz8R;hM7qllCdaJHpeCnpn0LE2W}=t=ll>*0aQs?9$(Top4q z-6i<4yL_t`MRf>k zC{mQH;AigFjZ}pjE2C!M7M^+Oo~FFV^xSN1#&8F+lwH|UtTNZJSnPuSI^H}KNp5uc zD>Wn>ow*?L@uv$$OHr=XDT2SQu_gP&vm2?;cX}mcsQJuBbf>6dDQ~aR9Z+{KnfUG$6oG~^#=+-4up)SZZHTVu0B$JO1u(ATPw14sBSh{ zT8U3sVxfzBO|;udZ$6R7q*b1|rVblOOFDmv(UH8DAt_k@06Ul7uTa8Jw5S}U{N}O4 zrJ*u-i4AD@c4tT)uydc9wvS}Kk2c_a?7}HgDoaFTJ_}I$fKu3-@SsmlpCvWv#f541 zJ4}!k>tmOK&->}lGWLw%16gG3w0J_PJ(`-%NJwwe_0`YxGUb^5S5YE_0GTPAGv0Q< zlzM+owMwW3H-a2-&B12wUc1WmGeUyf7CC$Ur$hXSI)7|U%tD8S4yn8-}-FaK& z{{YP^?m1r#?d#slio#M{b;HZ{)%POn{jQV$05q?-<$N)=hJ!(Dq~IxIne@IFjdyEb z-iknQC`yu`q>^xYSEVhoK|*na5PS`43Q#-|1Hie2 zt*|n$MDoURF`BwKfX<}Wvb@8Dd|P4{xo}DZ7$w5X%WXiY84akmm7qAvb{*v%u-rf? z#Q_(N+Q;2{Ovy0q0tKb`h@|KLKJY5YqQ3F4cc#s;uXJA zTwjvKt>{r~V%GZPCD{(C*AJYlET5_ckB5(jkXMc4($VFFW3`_x>)Kq8Qw-QsZ7w*q z{-RzJS>Doo5xQOD-y>;jimr-*BI_Xq*CQd2gzN>Ol`r8BN1kdM zxp2zhT_VOUDrQ1=7dH}jd=r35MsvuLDAK%B&|14eU$hSrZc;SzuGcp&49-M%Www_b zbAH7ow3iMDujx<@Cc>2-MZ`{y3pZP$++mBO8EkT)C>abC9rj4LGdtfZ~x+Ihsdv;>t9a8e34ZVF1h5;0r#rP9ZA;MycgNEMN-PFHzc)!Zc}P zA;WcD-_HzWMRcVo9aY+d6msz0@e1-jpER*!mpndCvwo?h$E?<3PA)S|-{;{Kt<_Gt z>p>YibC3@&xkwxzJjHK}I~E zbNVY&4K!!&%_#H3{{XM#hFSGStVBjMc9Llj-jg%5^SH-kmAQurYqU~|ap;8{bNZe; z>u;0;w)U!<$ppXw-B`EKGGC0p^OYv+lO!# zyVGIa#5-z`Fb_XSVxX<5Aq!4QkB)Lr$KUO%Q-+PSo6J?Xf=9V4R!4B%UrT{h>2!W& z87x;DI!93I8)mz2PwIHQK(y)GbVguCzgyIx)b`5&wi3dWy}g5^3@htYrGw0NbxUjO z{JlHGhp%kdLqUW$v`cU5Z@4>6&SQT(6(nc;pRSzlCrCMH{{V!qNVm#q-qE@KVEnX> zdH4udUtLFaMz7M^hf-PbMoDbPkcSYAE_j={oNw_{yQP7{Yy~;GtI0W?FRLR0*yS(MloDTf>n!l#TSmh|mc|70Nnv5C!mkB9LZ#B<1@;X6bYKt}H zl#QuvC&MK2uAkwx>d~h43ro~(I=fu^V23S8NmjwLAwfOl99J{iVyWvr&O)T6uoS=m zr=iVs6m=##S#o1$L}a0@=t&6NHu&UY<*%SoP7Sl+aX0V6noiXl?h~(99XYEe%etcR zB2y|{7!k@`auQU68CrlRUT;ji3X5nM&>>5<>I>6K4qWbOw%X&7f~OR;rRNe) zB9?;4-O#CH832&-txu(Nr1`h&6IThdiUK0r({GTJhclFwJnB^1y)C4j!@n6g1~FsT zlH)yOhjg=Prx>(|@Rc*%_nwg*meho)#H=_Da?+Ncsf?8zWa7R&*FkVHr^BPNxq>QaCuWo|WIGdgeQjpjnT(j4udpU8!SYGdg#nEq$vmdtU-)3(Q zUf$4mhi1xZ_i&Qp7Sk}++S6|e=Y{%NN{A3ni6y zuaKxLqb)T2yx9s@(b*j@cL`YjFul!0#F7-QQ7` zTH(Cg3}&yl3AS00vdpP1HuU7lYi`^Q&n>n|=ge|YIL-k-5iLGQ!b#m<2kqavX(OH! zjN>Wor_cQP`5`<)vuaBwu$GNeb6v(`>Jk$*Pj-S!0PI4-y@)BtQL>TGZAgiyLPk4v zDEhIyQ^yqbqBw`FJ=lW{#;wgqL}+SvA#S!DacWV>9agoRcMYS$o8_U`QKh?71SBWX zBmQ%rs=kXsyJUB+Ps#mxV0zrYPVP6^eMjO==FO)p)(bNTi6X~#H%6v7u1n>Op29LI z>i+=5{Y}LUe9obhCf%lO%)c2f!&9kClF2|wWhznHqCyrzN2Tdx1#JSW*Tc(_vV<)J zoE+pNa_*#Hu+WQ5T`!o#oCkk*aKpuD?^3E%N z67@azO6a(HLgjazaJuRy!?PDD-q5ngLWG0UC%?a+g%@2-7XJXm2)FsLU$$FVc04p8 z&;#mWr%83yHUU~s)rJrf4#cCGTvtrvyLLv9~MSZ86}K0Z|f(xDB*zAGmp527)Ql4?`Jt8{J3c`4f_D7o_exYio{{gQi(x14iDt3+?wWa8u5y%w;@)NpPekT(Vc`)8J1+Fffm!~x1rO$SIzg3j{7a_-nl#p@tKuXRB)~g=0^*&duV92v6 zV@}V~KS*ly`hQQF)=nxdHP4Uq{F2+FQ?0if4YJXx8M1{%DrOg(DQdVZ0lg~0+5kZt zNhI&?$xU<4v`z49JIK_H#ZAp}7SrBnke1WPY*T4QGBJgN%OPFHt^1|_076{umTgmg zx!f(Y?G3btV!S1L|$9YsLzW2p!q!UtOn5$@xU(OmL4QRNSXqY_@sL!j8sQh~V~;6cX83UKDrj z!=8$M9`y9bJ+SA&pT;K{wsvbo7F65YHk5hMZQ|krv*~&voSwV#eWd%fqS#3GI14&#iI;72d~L~2IP%lxPa`{)NysoxMoucbDQIbT8(g&s$TDp2g zngc$4cWPqP&~FH86qnpC6X@j#$s_#JUq_mwhU(9S^pz=Vpw#xipMz$j^UD^9LwCD_ z*9)A9OrkiDl@%40r?eR65;g^#6#y~@X~INJcRx;9Q==!wV=xw(A;$M9&FMfuPoTY| z?r>+8GL!6#UX>C|hp*QQmGbR!D@zeuYf4;LLK{+mDQmPsP>?qjDN7+J zH=AvW-pfjo^{(47GD@Pl8g0^uyLPzaXiC%wSi*O0=6Z9lk@`%TV;OYYe0(3UOZ5he zN0T#BQm92HnzsD1F{xzh89Y;u2VGnvy>*HiVZy=?mWC1AAt?bMoC!J4uy<4@0*W;Z za#BLP7{BOn2|=O7MVtaI=fuMpOzbqr$iR8S_Xc*aQd zk4pMIJ{OA`PqXq3Zl~(=%Qf)XcWHMoZ>jA&Ws4?DuC}SqM`Z;;#5K&kaqvgM&-t}C zw9B0A%W9-vqg$<(_YoZ|B|)D*kf4+y1xw_91Arv;DhHr6$ENO0Xq+8Rp8$SWTQ9L8`t z)?T58Qp3tUztP%{q}RF5dt>E4B8wW|dgFDv&V|^9%ZrAWN^%=Y8v%TY$x_3rPJXpX z6$ZM=m8p0?dYgBBbEiaHc`0?%xS>v|2Wor(3&tu*A5%$P_UV1R+a<$;Iyz#v8N}v8 zZ6_s8sT;Rsm4So3TTqmeHtjGyU8?LBZ4)C$X@@1;WZc#Rl2-tgKx)4U*r`J;kiEW| z5*31!fr5H>SA_6tH!pEN6n>FEQS{ZN%M5dl-@e!7^jFt(v+sJ+f>cr(b+Ub7MC0Tj zd{rgkLbuy4#Y-t#X1BMrMo==IS^dpMZmA(?{YtZGFq+=_T>cTDxv)*%l3|I}Ns!x!EUhSx?t^r$0R;m&W~dK3qp$ zO}*bRn;zuKJ0)R7gscQB1CmHmhI|xizK;8ynQSQfJ$dJqd%<@K*i?k8a0yljSBS3e z(Z?va%RR|^&!tGXxZ4dGk2x(!U=Y$&>Whj9&rk};_T+a^+k`Bv2q}~vR2`8OG(H`QW-%DR(bLm zIUw}SX>&`}PxJXOE$nQ*X(t@(u z6cVmUWw6>55)@G8QW6rn_3=*}VHG3cr=-*^UPT2hvb%NT@JRKf3H(Y%r1!1G2WMNN zM?_bxHrJkQm9ksd=njvmx?CY-k(>dv^9G^u+*629WoY`YTqixppCjHW{f$+jv`4!4 zeFnSb-sL%!#)B0wBs9!4ETo01L&;NWM&bG(TGUbi!v6q8R6f}ScB^zaVq#Px#%Yb{ zP660}oz;jZob43VN)wmbdLDxe_+u<{PhzUIPx3uNLQ5{~bF*0Kp0v-ap@F2Y z%%S#i=7mZm^f~ED1fV&PwPboq08)F|W?r4W7Lc5Iiqx&(WSrL?MNoEqG!m0VapctE zTjFh;l{Q=Rr4D@3Ph#Qe?a#|yV3$&)snrCfN>YN5pJ}c>;2f_v;suFFe+u_SIpyNt z;3m5D@Y7NrS7XSnLwZgL=6TmPirk$H*y)L-wiHs0+X99P`r@>>z)J9?a;=YjL?tUb z(0n=8mmTd>l@x>R73j%7g1^Qlr;-Nkt6#-Qo_lB;iuVK0m;3A6(gRDu$p@}E(pf4B zR_0aA^#_+PjAZm3$kMUWxssSq!aYkh9S8s{4<7 z#}1?`vrCR5V@H=zqMrK0Be=7p68_T8WF+rvB!E^kRz97$Otw89eXc`@kkV8Tq#!Lx z+>(+&J@`?TlRpnfc3A#9KmbETaXo4~}w&Iep+7*U^ z)R32m2`d{;NY2mU5d=pV#fqk~f z+-@(R?mY)1_o^er8138iv>!HGuchmfopNf+uBuAUBBi=g0X@U7A|<}x;pT`Stbidb<+9J@#7-m$F5uhrzug;H#s!T^G`4Y&mfBg4kLAdR>JNr`NPe}%W6OhKu}Tp9QSu~14=2Cfg5mF8d-sjHM_LwhRopv?0BdxH)NbFfSB&%uUNzYO8)Oyi25gIw{g5=YURml@ z-JJ5xEC^1X;bNbQEw*H8DPkXQ+LQp$R@DHb%z7bN_8*VNhNCR7Cgk@veuVuy)8Xp5 zV+>LDqXjO1p#kEnw)t>kJ!@O8#cE5eGWv#lcGI7#f1S6G?gPIyR)p+YlzI;8vpA`A zv!=msw7|H+dP{E)sJ5=q4+D|V@)cVZZtH=bweHEaj+^BC<5Q9|%;g2Zy34x-0SY85 zc5~fV2M%~gKUp}5mq7FzQ=g%@k(V7k2}n5fLC?jCrY+YNU=?=FZtYXC7(EBBuC4&; zsrRjOZnH|d$Xt7L2b*R(h8tlUvQ$TT$;VHRzP#ObT#&-$kFvNnK{NazJ~M_ZHXF{b!u(?8Ri zDEeNbG*WpZ%H?pZ=J!;UDPy=Oid(1LQf}?`X8@sD@%Sd2afK~loyu8J1G_Y;)~?Fx z!^qBZQ}U#bzh2D0m7kkQZ6s`|3mrLy9(3st=V2qhnwV)R+=VEDm5`!3=A7X)D~{ir{Bw~M|?NNCfjF6pSb^i|uul09IL zznXB2(B@XWl%2HErHhT}`7NnOb2FSuIrPmuG?co6ka2^!`*Bf{sMEBK%k)u%_mC>p z`WRLfG*+LAetIaRatKAv(fmo|)HJ)mw|7e3Tu z(Iqyiq-W=@JkI$o70L8s?ftHk{{S?vxb1v0wq?kuTD}=1k@45u+qd?*RzJNf?m1r! zElbQ)ZzDMH^$P3O*7%vgTShfgnwDo zI(K5B)+d)9)WAxJR?fa0>RqJ)a?h@uY~>#1EH9sRR?DBRDU) z*&=ym;I`DEf$(|q2Rk7O?1P$sNxpNq*?j&2WYfkJOR`^LhuQU|^IplI46w+^PHR$?#eMY^D z%w4;S?hN--??euJ-BXC(oOW({LpbDoK1ybiLf(1RC;(P=;MUaYDCjCEXt?Gu6r<9R z?+&Zb$E0#`-fJm4c1z)KJn2NOcj#$K6h~?aQh9A2B=~x&=)4dl6DMj=PSxP!BqU?e z`2KpMEw>rg*VOC>gKG#mCz$2WrAwdU zBaO_qryNmImA@!ZBbiD2-mhDNEqFW`2HG>*!a14)7ItbsaBYm2BWD-Wp0(FO{9`~^zWooxP+;$lp@~5 zcJ}31c}JhByJeL)6oP5mHe6d$TN_doK;@CRcOMR!N`6X?-3pnB%>WFIys^*K;CZW` zjcSvu6iG;I6%u)7kV(0_JSTbDka?!K@@>0C>TPn&umA)&-V@UxVy&JLl}WmG&8Py4 zdYMR2=$-x@YN~B1TX{>MmHHrNp6!~N^P*>3bp@^Tq4wKY*y1-ZvEZcl{B^z;weB*U zl#`7X{p|oHMU^MCZ|l-|{M81!$4Go--N7L^M>Dr?!Rg>Jj(oeRJnk~;OS?o&ZpzZ# z^pvJy?E}?O=^C0$)h+eUVJh%LBz@Y`E?8ZY6zZ7Zwu`b5%S8?^C0lxA9%rXcgZ=dx zCB?07gajxlX-Ee-Bf68jcAEN^i9;O%k&toi6_~CkXmKv>0O04wxouwsoy)dK>^mK0 z_>QcUK3ORw<35)&@mE4mWii}bWVq=|ZJ=S!MJH(P@2+TJ!ri{&TJ*5fXv%pMZaqP% zlpiR4aMhMQren5g4Z=@k(x0{^Z4yDKy9akgV1H4rBm_{~P{I*R6^Qp~{PYao&v z3CBFua^;6eyl%M`>J&WO=!tQ&lG42(Mh8>zoRxL)KD_$VkFF*11A!!v=EII;Zsnhg ztuUGHxS-^T3t0z{H1TA8q~0MF9JaSXR!QZ{)m*#PaBFm^vp7?Pz|@JsBi$saKqRR4 zT)Y?r0&rxWNPjQ{4?u&x+#ZAAk1*J`u z0uzEfQV+yw^6$rvDBjv-Gj$we*rcEY#cdmhi6C<|-yKrfM)M_ct6*DuTkPCGPzTb=l5y$S>Ad}ByS8h90derDjNYD!4%tevrdb>676$ZeXJ-Y=3Q@YbJI8@ zkvzw&c;lX}db3wqRleJ)F0n`(QsZ+-BOL}wrB}^)uP@IT7rj?`n!Sle=jCr9Aau`$ zYrW=+;hg&G7gn^>Q=zZV7+aE?FDJ*fN z=4D`ao^>$b(TM$)bI6q+wvTeyrd(POu!S@gy&(J{laGs~Lo}*LMakBb6u&f5Mh7e& z>WDfVE}?CxrD+)6ln_bp<~>x!mu!<{$#F+sN3!4LLQ|2f6XeBg2Op5oB?u%860zu< zj31cu6%xO)w769x2-}hrw-BXg*?>FGbx;xY9;vs$dIT%=*)ZggU1g~XN>z?SaL=ld zJ3iqdXj8LaSJ?egSRW~_x#}Y)W>LVB<@Q>WjhvU5k#>y*0t}6=FA6JKPy=jjA7p(K z;sy^YuA(fh2`xEvvm_61B0AC+47DpV92i;jlyRP24rx?JR`E{70H-pLI&@WX z&S|?y*+nZ}86lGFR&{(tOPBdzAKbf} z$dw>QloHgnHOU7G=#1c!d5Y)FTEmfUK~JC~C~snj9K8WdAf;(bji?nkcVMp|pBxIl zEW0}*P*PNN_4i6#t&p0Va<<2d9_XLWuBvk?^Mqihnn62xDMQBx6%EY|1CBVPpn8Eg9~F2dB$T>9S^D$iThBCST=Zoe zc~f6^2$AZ!wwG><3q`<8Qer2zQX45tP7-%CGsuC@oo;OaX=$oX3u>N)sN?`n-19$v zqb=p3l{|$Fy!rA!7mZ3-jV;|9B}i>sRVgk86gH@UJ`e`Ex_liDd$^Y*lZJD2v}*#} znW&<~xwmrqlt-1ZXk(~+WNls#*x_dw3I_(S*ix@L_Twh|bh%oj-Q7Z3d(9qYproK- zDL^V5fW|=NPg>&zXPYGj03M`r2g4PH`!JCDP*75KgPvp8TEjYmoUoZM%Gm?=${ShtstKE=@j?r(vP(l)s@Kfn+ z+vWY2;)K-~uv8BbIZD*XImEza{zJa3T5T=hnf?fgPtj1J~JJ^vroPZc&?JE4xs= z>RC?EGCA|Dcl%tsb;3h$GQX-gRD|p&Demd(tW#y*D739Qt3@tLkBv(SqPG;5+aD$ zb!#NWTY!$Cm2&kQ3fX3HjWuN)FPo#K^-i+T_T?CCYl~Eo$susw3mq}YB%j%2p6aKy z=AzU0d&FU2l_GRV@%txVAfW|$_$~7#NggMiLd1CsBM{te3FH(QP#+&E-v$KYq1eNa z>bZocu~APy0o_^T%<}e$gd+}9B-c!hD{GGHgl&1}5}s=;{+aco+of(R-4 zkvKf_ipEoyWt~j4<8cp9K6B>RH3j-bVi5rM9Bm+0!>=^qcox$jMYGkP4&=_n{@5!UhZW4EDyjd%B(t_*UCKB zNjb{Xzm|QUC0%NzMjqNu(Qw7$&kxdj858b|6Y$oUia7Zd&b`Fqw+%a2T7La`OKv5? zl_CKhsoH%KGtiu8*;LWe+KeQVZopcw08q_i-o^P&r!mu%^8FDbAAYU%5;pdsTc2gh z&l$LM;BCoIU)R0B-b;;-S8ENjawPJ9d_m z5;?0bBo9~3UJ<8nkG6NVfQ0vXz{M7-Ymyc?cFTzI%ZIEsvfh}~FBL1$N~EC~Pp`i; z)vCDPWu0JMqe$s1j44w}TYgQ-aC9M}o@qi-I(PzVu=lria1^Dsg2y~|sp<09q-m>* z$x1s$Mh_(R;2)Bc)XGt&QN}6SC7cnG%w1=1p0ud;Q{pHnoaAF+<=vcg_19?JHmYmQ zB}9Z39DH@iTs5$+(WoFfAx(wIog82*BOz$VKVLfQnNBFoboNOqTGZQ^Jb}+T>d?C6 z%TUCQ&$Y5v#LLCKq6SJ_d<7@sq%L1{`cSj(^}k^8m;UjcJ!BmIeKAGC5{oRIw zo>*G(kBL01m83lDM0R%=iP(1f0Y{(2C=(PCb8}Uh#)f>6?y?lM>H(jPtL|X=y@9-lUGCdn%tyyl(!xu&|&(9fH3FDv54s z=UbB^;~nNU9BfCyHH`CIS)z<$_#!V9COJ+>%DGaAdYbPDCAM4(N;+=t$4`ovPP0Hu zs%@*gWdU5lZ1OaeTJ3zpmyn!zGNLPm+vwdtk-?55U!v_yc-Hl8R^h#^-1=wa1LUU| zoMYF}-o!=Pwvb3lt>A?FGfWAz+5q0Gqsk!i+Zf>1?{jShL@HF(p5mCK0rJ(;oH`QO zCru;Xq}SS`S<8(6qMpm%Z}m2i)KJnJNj&*<&n~rSaMOrZjVWiHXu2WbrCgNyc7Qi0 zU>|%{VG<36N?3Y(>LWNp+uNR0<9dr{Y3<9F@>Wxnr5!paJkP~Smu!nny5(_mM!kiB zC}B7W2fmO!#ceQ7)UzuDchw%DXhVrRr@8DRy{%E)B~8Sh;O+wzx4hRycB1H46>JDW z3xg=2d=iCVpB&ef@uyG5!D`bi+7t7>pOIDc;8F^_d-O!Pq?`2IGN*jJVigS4`r*Dc= zn&&M9<8d`@hD2vo^;yVH7IW1qu9I!D%%l~#32EKLW7kS;ntNV(=4E%+F+$e;cgio z!Ro9%wYzfc>iU_uEK+AAYx{HQh)FDT0BLa2xg3xbW;; zbZ4m4PdvBH+acNA=zu^UHE40XuNx9KU=@mfH_R1?aX<=m#oaZ6jr=B;NI)f~#a4JC<>t8q%wmpTo-Dep|)wKk8t zd#|S6TuI46Z4M$j6n36i!#6l7r-g2@-lnbic9#6!8cRuU zvPWjx2s;o8y%t*lsQquO)8u_S5!CPP9U~aVd%A(~*Qt6@hS^-mkGvFw6)7q?=n1RG z1SHdIqgd;6#Y!q%OTWnqd9*Pr;b0W)#chb{o1GY?10AAs>#q|4a#?vqou_UvC}`o< z$UPPh&sLMEQHtlXO4-b}@_rJ}FOHod0qG~FG4WGRX5wFPBxPzKkB*&TseJte5zyfC z29!VlM@nRFMCwFUZc`D`by$WiKt*s{s=Z-{mr%MaI zZN&XP=tG4vW4hQF{g3;;dg#R$T$oBqPLR>3P9WT)Y&(;1bo*)MAv+G{_L^a`yz(U7 zS;~UE^&cRF5w19Ju0lsc5^W zcKmJrvraub^N))aS8qyrDy>f;pr5D1hFelLtKE)&`x1R&HE7W@=)K?jTPyx)Uvb*_ zUu1857F}OGsmCsT!oKKT{{XeJzvh+q9j}HKVf}87v>m>V4iBhTcC{_>Gl0At9OF2z zNCja;FJQstk5zcAg!YOE#^R%ZDu~dXXmVWB`rsUZyL$8fa<_lFs`Oft^fup4P6jY4 z&eF|>Y#QC{s1pGxPlv%gsvTsr#(o1*kEUcURmKRP5ehusX-*{xQh&}+2jZqV8Zz${ z;TA=L>dW46W0btnRv!Z@NCUVhpNAviT+R|*4ePbjB0k_tY$;A9D;UP$zCeo7Z8H9~ zNl?$h4&xrbyHfuEdG|ou342f6TU3Cc*>Q!1l9SJwJh9)J#m7e7BB`}KVxE@XWIWkR zVM^@J*AbsrKWM7$n(Vgp-qc3UoSY(g+fGF6-B1`00<7Tj`M%{OZrLF_m@3*x_#s<` zJ{wGTQ`$6;oSYnT2Oh5KZhkqA`D?E(^F_-f(#?``k=k|*C!CC zdQ+4MPcrLiX!=C+=iO6VMT#4&GrlSxl`S{{S;AG5j+LY#yP)3Q%FxAMPSL*(Mz%2- z)GHg1Q{FSutr@yuC|Vee1~ckHSD!XdRi_()`F?Xr&Xk?A&J(AkEeb~DsJGO2j8yFW z8T--fh*{Z;WR(f$J*?HRwsc5fa$ZwHWc>(I_&*mKjJa551>^rh5#g`40qVE+bPcoC&+gbM! zZ(y}L3c=@+yi}s;VvhmOGnWXq`Vuz+FhM;%wH91n$hd~GJ0)Yfjugu#n4z6HB}yf= z#w8<}O8QplQQMDjYtAHxI|c6Kj;9so47YMyPI5+0DbgG^63}#{Z(d0!+G^3p$r~?m zZL%b)Qx3F(;mWcGbJOorb9ScG3d`YO^gDV~w`xj44taM9#>9?X!SAES*JNFEMNw@= z6_-$U^2tY9&$+EQl2Nd$_LVFVf>ai!aD&X8b+2oNgXuMZ4>62YTnKY$jX;K$oB_!s zC%kOwPWKgB=G)qWsSXzyK}r?NzrP(Rau8MMma~ps1t@K#p=fY}%Cy?jqGJ`=7B;9G z%Z^;#3P0rVYbmotCoSAx_W8X^mV`KRyp!q!@K>}ljh=#t`0GDy`6~HjPuxhTa3xaY zFPHbf_t0#S+E7uIDJjn^Fn;fKOExxvkdl5X${P##O^vQ($G(lfK{w{L(67wgL#qQAc_1uK~1R?j(3%RaP79A|`b7Q_FPo?P&w< zQ>}(HXcEkyG?eR^0UNLaeRTKc>QWM-HYe6In%t%vE#U}4fb|^I`z2l3AHG^4&Uj2z zIgKo+m6Rzw{#*(|blebuwYz}??&aB^zf%y~YHza%AbfeRNsQ1&)gJteoPXO^jwR%> zQj#IQ_hFIgLzoA8%gE{M74ANmg};B9+#P4@lpe>)Q`j1M?R1V^wb~`V+D;1Fhz<{q zM|CG%wbjWHe9hH94$|Ldpsf5@`<0T*it5hC>H58@dmTQApSTug-0c%@xfJribGsq@tjnKiwu zPL%AnuSC4-!914i^@MJxz}GH>`tx4fj+H1ONKhSlR*N6W$;$FZlV-J){JoC&EhX_P5R+Og?pkn3KN9WI3gf)kFXpT&xmj6KXnZ;&m~7Q}li zY$bRq2zzpmsGkaKlLeO)U2{u9N|Z?C-&iolR1!jcRT0Hq zqON3c+tIrT)3)Rf9p<*T8R*ZY*w#yF!OrC5k@C~>BOwRVAw$E$y`nM__U>h}Gqm&` zsYX5LAR88O|*;=;B#0^ zM{+R7$FNh|i!7#}L}%Qo%^WIogLi*o*cF9aZY9I{{abO*4WmCbOB%M9@>VcY>cwT) zPm;8xl8`EWsQ4=8{E;T(TpCW;_Xkp^GlHSYnPuH?F(m;aTZ>aCKUGgZimU+)EhygE zJ5NDS9a`H=UliWef~03}k1C{=(&|a_J=}E?4XQQ5GfW}*0}4AZc~*3*cfCd1y6yGo z?6HtqK<2a8KOi+5meR$J3&~jkl_ZZ=N8qVn4;*P0r_enTCWR!aIU9yf54WXSH6skt zb-@1Kj(N!DdZ%BN6L!M?0KsS;r=4tXOxd=ii}clwp*^@NR(cVRSj|irxLKD9-rLfy zg~;(lM{U3lHgP?s{?SPv3#UqWPNHG8?~4#V^N3nrd2oVC&JM)kT>$0J6{^OLDP@{e zhznK=GKmjdrYR$-OXM7N9W&jN*1e4(rkd=OZZ{z6)KVKV)RDWmXCB{@tR}T3y_K}v z7Swh-k|ZT8pr|Cd>6GmqcIT~ci+{C5f!V^0zdZn@w_Rvu1xZIyj=O@t-C8^iI%ws3 ztkLc)te2rQ{It6CbzKyea%2_ESqP|Jw6Qy2VVkA0;WvX?iUfG~5<)}u@|c#`jTlLb=bf%-Fx3&BuG>ONkTz7k8?I#XEmTau7= zk72B6)wY}aNd)dFT2r4_Uy8Y_nmStGo?EzU8tlxrtrlyY&&(njvx`p-(UuZ_MCP%9 z%=5>0#vB#GV;NANnWFCKMD?YXT*{Olbw~>d029>*Jx@xoI7`GUMuLlUa#od*cY5sb zY2~*oVm!p4rEREq60H1HJGb%X*4vR`qf1!r}S}~houhRP9uY=%_JZp81 z*9Sc3TohbB9%=c9d`$^;l$TC2mYe{rawr`8h#;R3Y0}BUyEWzb(XD(txytjky4xqQ zKAVk9*W5?1j zu;Qkv_rj!YNl7azJNgWQlaBh)U~%P{`>m_!qaESCmSvV@NzqS3L*#}Q>t!KCbs6dG zrVUraZ7k)jYqeTK4>lCy97D$gZ+EV*EnTnW>g_jbvMK^0i*Kf*yLSD&kaLcFy48C= zDqD{sgO5qF00+?kBbUckmIb!UMsJJqQ(Qi{zAq4=xZ{OBbj!#=`obIu>+0oQg>`Jk zn<1v1AziYGCz;MoagK_7Mbs&HsFK>yNzeI2lkw)e7Ue9xb$Ry+P90MD`%PO*!y`X~ zm^j`YXI@;;T*6&aSDpCf+50L9XJfROa?)_5c9`xys-N-wPC2fpIi01|G{5>a1GIl^ z652Nm^R8`U`_7yWAr!-iMhBx**ib}MtfX466Iox!-Ih|#gnyPKz@ZS@1Xq~DpQ zwN=T~SomS6owud+A}f+%AUdX!c7-p%nqc8a5%m`g^#eES8-+2SXRx`#9VW$B!Uxt5 zPFc<=`s2hMTJ6?bwq0eanYOy=b|iPFxE*hwAi5j@ewqx9c4EbC+k- zT4~F4wt`apIW0Dow1slr%bzfLRWRUs*MGRcX+$!Wtff7`Vy+3(Wn4p(X3TkV6rfb| z%L`h)M+cThbJsOhT$B^6r=Wm$6%3x7)7ScV*4c6Wyb_}0#E8IKfnA{)1e|AAQu3i-y?(owjks~$mOkkw= zo|PlFMd!5$Z6JU#)L_(p+RT}g5fUV4BuaV3A+{SyDq4=r00w=1aBu;~I+H|gQPlHK zp>gC#QDNrPyeSJEMmn5VR3rXknG&~5hH)y;z_oj;79xjZT~-b~m5g~UE@R(ELuel-YyH&D(^{E}MZW7ehpe}TFGw%Ml8|tM(ESkyARi3+ z>H~0sWqZRBoE$)khOK9@S_ zY0hQEl_+N&fuRe_6J3u3UF8=SIx~ZS}7KzeaIl7|7rSy~-P$RnwQ(xyn)Bwh9 z8p8=qf%o%S-Z7Eq$+7>|hscx9p8mmjilLEnbR7mob zx#X%k9SKnwQ;8&Hvw#6U%4XiBD7dt#OIa&fSsRLp=bUn@V_sO2ZJ6zuIUSDG4yPu9 zqtx|2zF&5{FJpwS3L8!i+!LPfWjQNN>K5Rt6Xows5y1u;S8#;789} zC)qEyWF>c7MA#@^&crvr7lS+u`cSaR5)nK_wik#)>@z!>X^T|QRJ!g=v zY0YEid>Y`=<<-k(7`Zj@Y>MG%ovJ-M`Fxb%wRVw;7Jo%aN6X5ZAvEuuDmh_gyK>T!yqIK>do(U%6VxJ}hpWjp6CKypi1uZjuTs0eq7d)oy$YL$mVHv;SIHMl!1()-dOe073XOwJqCVCWR~e#IU3u0ycTYZ z(G&HR;!J4owH7RBsFNyFi0wNRW0>3Z#2>lSzMbzn7+N&@TAtZ|k9W09ceC@9FywNT zqb=vNaAySV>7Hl0ocKV#-%IPXG?UxEr`rfhdXi(w10JqpKD<(hTcYq1VU!dEo6{p9r4elk0}X@3)v@|UFB zPW2(n0ukt*sv)7>%bBIR`}3{Oh4H7QDW1ct?SLNy6to9U?a6Ys(ra_PvE1!5FI)6q zOT;dN^T_vN$v?loswmAm z-u}?%BhmI%$K*Tz0M~bgpSQhr{{YOBs|j>nMW<)b>&N!8SNzhx`fm4Le4J>Wyx4WDR?-N*>OjZM(hGlATwQ6qK_M# z;zXM-6ShsTxomaG>TQqCDQLE$+Q8b7Rgr}PGqC!_dO9p{$qlk!>U_8A4B2$qp(r)B zE0uka4GqOj9UDarNyH19+_>A^ZHP9g4xc(J?2;7f6_A`Ltw*0B>2sxAXS}hcbe*?R z>DbN~y2{>D5X$`;DMCk}pnA85f#d+ra5-k994_H)vsdcN?y;J~?&#YM!b_~R5tTmd z)TPxHnr$ctccZkNcMv)eQT{&bJy)#nQ6*foh1*YAAfa(>G3G*XfS@o`tgRpwV`w2c zzyqfuX`dWng}HyBo()c1-k}&`lcoH*{{WOq$U4@N=U};*p$i23TXi^@YhiS&TvYQuPjvpA`alS2CjcIWR32iwDASh)c2+6@2&2!VGWUOay zcI?18NzYOEJL{mdV))=z*}iDmVm+z7FKb%kVXjuJz6}Wtom(^5$Gvt)r~l-ZLhPoBh1_@x*(le=f0wV5+&u*xZ@zSsJEobhzKuIVY+t}xpn;(!}( zqC!#O#(p|%OU*hE5-^n#F@)}swbOaFMd6S=ID@=71g(ULFE_9-9BRP&zl(?Mj&oN%Y3evH(jCW$4OCc)> zLEKL>SxYW<#a@pw;a00EhSr%v9!fSJ(D(BnHEeP&ce;-r>UcsDme3s9R6FtCT9+3a zyDx%z3T-PFQsiwzXK37!lUZ^%YMrP^3Qsa=(G0YZ0)ltv#NGfos+&*P5#VSvbZ?{2awdk#1R8 zN}EpIyV86{arf(DZRZdUUZ3=RwnHcJ<`+i zmg{Z@Qse;Iopb~B!Ns5edJ+#RRd3XnHEOe}U$&+!cB3W)Sf$?4!q6o}OTocW+(rj5 z1_3#*mDK3-<;^K#i|GBA(mi8ErO{!It1MemPyITkBXyaU?FFh>hp1oGPf819IG2>M z9nzA~aa+11cAM}rGTM3bK$1GzN+331F zkW=1|nf-a{I&EG|anngUi@N@#N6nqa11Fz-Y!F=KgU=bMYnCusOP+3~+#HHjzF4np zX@$yAQgYBz2vB;?fMKAJB)cJ1vF zLwF=-cTh3w$@wW-bYqUX)5?yuAQc0*ktf3*+}4r6-vizt3AgW7Kq?zbbLus{7LY(f zTX0|i26^+|*um;Kj-ssbqNc}eNRb4w+8xLW9YVQs2f$-Arap=*A~0<4_#mYR zDnDDwt?aUW%jBt?v8WKFpe_FHmqjc-!vWO%6vsfrg#DI# zhpL>|;gjviOnFSV+cw)xNJv;IKygK6sE$J!0Q&07Ov7`WwsOO zU>-p2>U=8gxA2ze>KtwG*>SQ}gn_(|P(6MsagD({w6gk`X`axb0xV<6Yj@!SbJLis zeKBXKjEW(6>2z}_(};PX^GrD6daS3A9=glA zRm>HkgM|A2I_eqR2Dw8*WJ^k6G`0h(T2Ym@RDBc?@K41{;Q2dClBUbdxY``TQrQ_H ze_XSUdr0o7`goDdJE&TXy98JZo{$k`NM>qmj7edMB-QiyQ-<({YhD-h?HD zlsu&<45vJ{j=el<7S0VnFSKFUi)K4ul}J+YwF&5;4>C_eI@J9Fy4PA7#&TzNsa90#XRV2YDE+k~k+Fxb29k zaJsda>qpq9BP4o{O#0~b$h7h{xH$;vDdID3DTNfel>xOp`WmNr!*6oatxO3Ft)-?K z9srNCQ8o0Lt^+?FN?3LZ(*dmQX-foj>KD+Q_X^>^EsG19XO52A7TTK)T9{ZuhdrdL z0Qh%THmeTU7Qs0=QBb;6tu+u6m3FJgDtyonEI^RS?vRyq>Tqg4!DBNZ2GW(}1JnJ~v7XgK43!lSb|pN@mybsS zzn(hOeTN%B-PyWaCkK9T1w2}xajT3aHzf@_=M5>c;($OWp+re>ZF8rh8ZqY&76R6mTn%8A0@(x}^$(NUoMN&r zJ3b#ztIO?V#g=@oZu|TjIE7}lX=(Q6t&Y0#E_U?X8%&gq;W%t7pcu~a$z2FnerluQ zLn>C6c|ksal+nrW=6Y4h#nBO{x@%BRjFz^bmJ*Dj_46OpJVauP4uvK9){DJT{}x z)ULlZC(=&#dVzun%9FH%-ah zVKwCWK8d~yS`*4CO2R->XTWr+o`SOtQK{|rr%Q%0E;|1JWbC z8Q|F`wo3Vt$d9>Gt{AUXzo<(ZDtrjnN29F`s%FxXH?~MhR0t=L=Z@<1w5l#iGsg93 z&*^6Ix^>v~t^MvIxu)`jfRs8+smoG?mHPot_bEIb26_Q|g4ZqT2l61CC7Q zkd$r-x#?0}a7BqFnCercA*RmacBdo&t;)$6Jk5H!AqZsr zQSz9znyk7hD8J#`?#S$U3w|=*?2v#RaUccf0V^r%f#Kmu?hZKO9Ku3^lChru0D@@* zdy`EtrWUj(WA6i%5ATZct*tuD_k%Ir-us7ZNI?obii)`pReAa3xk&phEx1L=@=>~J zAvZ^vLWUB(+4ee|{rc<~E;;9~0CVXTgW;2!}zHKKIF8ZsW>C zuT9LC0&+Y770IWP+;rt=pg8mvb&KzT1IBfd!pN zw^9ik8^$~R8m_GkKR)FO1TqxtmF;CD;BWCO?yhZL^R#qhYi}sBv@L;pp7jdMx5@(3 zxk~Uz`ro@#Mr_(r=WM;pv#xt;v6Z3K$aS?QLuk(T07wet0R!1l{trBuTHZTz71%7L z_KQp8P`oK1+L!3cZqL6aYVGZtu2F$0+Qa+KXlubYoRx{wDpZ^(+yq9NlXQ{`p0Ft4HTu+ zgnC1AQ;<(RiS^Ze#`~OU+)`@LkP!s6j4_#QiDbvnt3!FwKr`Rl$tU*lUWaZjwgEa`{yu zo-juFzLDux_$C*Klc0)J9qW zprZj?H=yYu@e9P-SS?_p^xi?>Q z(pI*q#qc`Gx=x>8RWH+!F1%k+T$c~^YwuOG#z$rL;5{kt?aX>#O2F}?&7-Bf8Fe3>YyXhq^-nalB?%f&!bNCU?UcWWL0RdeKG2rR87M#XrL>OHJ667b zek~<4MmZ{@893SIV$8hVRrEUQi~BPE9)D=UxP{XykXwJQs%qx57)PQ&z@Cn@LRelY zoF^gYdsy+)(dC3PF-Htx67*@+9v(4Je`9|8Ud?9WtVzV9t~3WOk|cquRTHe8JoNPh zH=m8tE9Dv`F1h7?IBY>;W}AA6oVR_8ku8(2Uzte6Eo%d|DYNISd%YTazuhorwT)Ck znLv%;+ztC1%m~a7W?~J@>xWUKAVF{`1Ce{8ONl#Oi}GqJ69n52h2`Q0M& z+0Z?C)66;6Lm`&?wRwaLNEO9cty&%Oqp7_G?g^rx@>H{W>#OXkbEkV0? za^`&~5i$RMkFmh!>3&)I8NJQ;^KFg{3^NviydLRh%s){ptBm z)5uK|q+rRV0Xt^U2Xg7NymiKH?8+Nre0}9xM)<31()ZPKbR(2qr_;!@!H+1%bzh7? z9dAT`XQyQA6bFRmYfEe5DtLAM6yW#@A3v=?!93=$!^5bsA|tg@JM&yZz}T$83GPRn zjOLJUID+lL=n*(__Kq9lIxgj#P6cKg@Y$4)D`X;h_kU`=CX7^ktVt}1<*r-WTQy zWUGWP#*>~D>fh<4%WjxUTAy-`Bjxlu9vxOeJ_UD?X1&T$k;ut9B8@lv<1 zJ4f~)1>wVA(!uCp-ZcnA08eZ64Ui|nK}&PToN%R$lBj zVfd%6^w+$~jvwTf>*=*ydt8D#9h0Nc{W&bkwva)GSJ))=kN5mdCTqXH>-nUEBAb!U z*56KkWAyAaIX=odzU+j0JqOV=_jS3=dtToqn3Uz=9D#8CcUTrwJ59fFg>>8cXE%tv#|f;hH+mSdTfRUa8d%%&bsxHrvB2(CO`ZnH8P&*aPGV66g5QISOT>0Dt0 zd#Zvi=UJQxD+hUWerl@MTk+`mfi&!_`I(h106e#+9q10EcUGOy#MME*^^5B#POqri z>$%7r$y@gPXDQK<^*SJroUOn+XYZ@a9Q;?eD2 zTpXkJEt!Q~cciznzSEp^8YOU2+T&L_Eo}4B z)yqGgr{V0%FYyo7QZ=i}@6SwG;)GU;=BbG<8;)GHjG}NNf&*5zTrUfoboRGM-N?YK z96Kr=&F51F$-i{mO)(wpP6i=Zcqs|zh~uFb%DjJW=HZ?K=6F7j9+Dx^vLYF3VdpB(^A^Vxa-90PoU;=TUBHP#VK(dQpfVre!=g348D&0i|*&s&I`Zg1`;JfeLKWsgUS) zB$n09MJhAi)prhb5wS{dDwEs(GJL{~-Efchj*0->KE90bm~i_@3?YJJH_hQE`)3nb zdM6tq)xMOngjY@_)CJ@|55Wo)_S_)w)yfc4+18ReZIfk@jU$b9<@U~eJ^fIyG!QRtS1gpIus0}{Ne{>>T%%0Yhjc5EMAfrygbN8cA&>qb>52l@b zg|nD)v)+`{D*=nIRTqo?Av<2&gIfL)R`6oycwewwQKEZOxdwgz|D`8@&-WPp;=(F}o-#skB?2%X)a|308MJo;0YNRzcg( zWyQrrhNB*ytmg}Lzm^5DY~+&^m-Mq2SRu-{9n!Ds-7R-hk%~wKBWj{i-G7*Fh~o0aVq<6;3yqFZ&6&(vU_k*l=2YR z9&e+GBl{L$O|T&llF#MY-TR6nt&H&v%i+GZOGEw8YoNf>y8OKkA}~lx1%jO07^Sac z)-2h#_G8BWevDFGRZP$fZoH`nCAn{^xUK*Oh(n;Se)m-t;`eUwJ2TfQDk0$DRNbmi zJBfn6P~5{2FEm12qr`wfsohJK@P!zqK-#W(VlkX<*(l&$^-7Um>xoO5Q=oj0<~|ms zu>Bbqceex3^zB=dr%lfkmYND&MG5m63Z+Zyfy>a?{P^}e+V3+6c%~dk6JfZpuKjYT zz8cf1PTPh$i76YDj;sXx&IT%fx7187^{?xm=M%yQzDb_YADSw3T(kDb!bx7GvyG1c26&c&Vk%VPiO^PLE z0h)pLahj#q^u1D~iLT6+Qb+8MhZY-OqxszKxBl*ZJtQon%eWfT^DH5|&pA+2`!Xn} z6wS}e*PZ*=$a9sm>?h+y%Vw;jqZnDg#x-@wqK`*Oq1r4lxxkB8zk{jd7$qt}S6R@D z*wb=zkA}68R+oZz-+3@$z&X79J^GGU+?1(P1zgyFL<>iK$epY1o?nk8(!8j42Bx9hyM)~RSyj=>sT*IQ>pi;>^o zFqZxWjIcFwZ+^Hl+hy$8J>(C&S3fq(4{uvoE6sL$3{Tlwt$_UaEamFCtjO-QR-6t ztP#WEt;P3{VeUo7cn*-=-Dxi621D^WVVuPlf#7B3REhSKw^0&m;|6wwGW7OakQ|@>#$CZ?el><-}&&7h1mZ>nkQ1QEyk3MfUU|%G1 zeDcpUJ$pfNM2`1`b+T2 zUqGF1wWxhzDk@rpASkx3!-WaJuEP<_-XJcp+(l3=$yz^rVh%MVw19t4a01Py-K;dk zJh`+at6$=tcL{Tf$c5eLxJ9~!am$B#XfP7;W2CD#FEukk)zWh{+J`LpFOCD1Kgk~T zTx>-y(7j1mN7$)T2;ng>xUt zQz-tGw3o~ZMwq4c$dqf!ab0}QAv^5SC}WC<#_1C6yS~{{Na6XJ*-ni75kNvF2lK0^>mEi@msWV?#pS2^x`NYpd^gXhc3aHrI@LZiDE#6)}lghqcCO)YoE) zI-{X``z1MC7PX|vrZ9CMKSb_LRHa2HV6S!1CRbJ`e-cd^X=x3$PWtqVmR&rYYX}FEw4AML(snMt2t+6N@87PJ^HrSHy>72b-uVp1k)!Fvk$Br0g)<@c6>q^J4ces9<$T3^ZR&$>2ZM_Bq`yIozJgH z-dH;sTKFiVtmmjkj;*FBTZ8cDsaLiK1oB?;o*^us#zl(Cc>UFN-t~Jn!YJ%5E5)#zv;rNHm`!#m6%& z2A;(QC+=Ae38Jo(gfq6tm>UcD4TgVvxz|<*jK$=y9`y7sGuDv)r$ z6U?nWv}eMBu(jd8jUXLwI`9lp45fZK=AsyIbTRqkw>n;JkRr4P0ZMyv8honJ5buAx;329W>Ks``s=#R?>9ob33DKVj4XNgcZMec+AN8=6lNRb zAV*F;_(Ws|r5v+UuJV@%$-q3D{*Od68Os4(mzbH>Mfxi&z=V66T9Fx zBNPc!(=-Bx(KpfR42}B}*pT*$&5UKY13;G{dY0+LFo#HyV`Q_)t~=vhVV8||MgA3I zmvpzAU6J&Vnv7EsXKieY@iU>;pwFc|zhVtY#gJDj;hS6x-(%B_<t04GNkEU9ku(pu&_J4|LE|hXFiq=J#0_7(rB)6B97C?+zy@bz&se7DmD3 zy2Umoi{DvIlBXV?dKXGTGf;$G;S1l$eWhJ*4yC?uosn^c-P^PMEUagUDr!bP08OpY4K0qFb zgEJid0*pl#6cXCe#ze$iqB%zytMILgL9ytB1ekX@;#;NRt3(M!t{)#MiJ^UP(cyZ` zl$6-vtTbbxY;lpCRq+1afu{Hw#dDfum0sSQU#I!z+t zr1>cUH`GWw#!ZZz^O2bEXUTvfMh2PWshlQIx=Q0q{XZXZvDr|Kjil-Mf$3>^KiYg~ z`e=#2!h-TajO|DlvG@L#eDxpEXMmF;8U$mt?{goh{h$=l7QT;3s)x}RWQBx5V;7;3 zPvIwPY;MD!gp7|XJ&(oU(CdOX^*t3!PsSyCHO9L2;ZCxI`CY!M$jFa`=Pr#rsPEs2 zN(Qz*^X^%6e_aMNYkeWPj<>ttvR|$KED~pT~uH2z`Ivnj|LjXrZzLV zW(g6&*Ej{^6RE}G$<0^Lydog_9(Ip$La=@{rw5O7I5D)M>^bZ3;&Jzqveox2pwXec zcO=pm#sw&|TiPc4Q3idAAC>ng#Hw2+?Eo*){VaS%CwB4cNzZTh^gY9$m+}A3?rh87 ziCnZO>^!`cb~JV=lbNaWKjFDXPPO*=DT=nySIqeFgG&dj3bMY_K4JViLkX4)G53@s z=c#LF^8F>eHb?#T>RD4}yJ$pAY{c6?Qxv|5hNmjU&say3!>L1)?Gz%a=wt_VRw6vK z-@(6{eQZn3ch1+_LVQgX3#pwoN8Q!tl@(UkJ=OXKN9Q>l(p0WXQm+xzcfGSrDqVQM zt$YZtqL z0%rLNei$%rr38cz^B&d!)e07xcJ}jLW%CNBi_h0ClCDl_68nDD1S*opOV8tJTN^xp z+C6P7_UnFtST(R6YG_gi2f4%SwALCN zOQtRyKdNiYtK8mlDZB5LLvDxI=u_|~eTS5%uv{iu7#z$s5W`JuTTy&6-+=a}rFS<^ z)N^3CVey3hc770WrejJsyYEHfVC?*4OS9qv&&h^%gO+j{C_40WU^-vh$C;qBC=rh%9f1NOr@3=EGR`6J8;yy!0-WM;|^V zz7m~@MVb=03J2JHI(X4@wwm6iS?K{L zS=2daM$W&D)Y2%tjm63=D`vmH5~)!3w;n~mpZgF`)YLcDZTx}lJ0a3iLB#f1?B%wE zGNW70u~0bz8?6egTIp;o?6B(9S5eG4lNiu{TiWB4$yV*li@t^M(0kXA`u3hr6sam} z8bmJ_*-Ji{qHbyuvyq)$pT?Ut8bHob!PxTfDV?WiZ1Zb`O}rEKI8uMu(|q^k2XROj z(pOtj$w}KIkEZFIJ`CBy0u@ba9~iOQY! zBp)<1ZgKcLNXFv}r^C{H2oYlN)mxzy3S?uIsC{5XJOCx=CKT>Rrlm^|`Ri}*_&ICW+ z7$64ROkf@%AJ(R>{}z^YI+gdjiI=jQw!zxunL!nb`D10heOM1i1TaTCaV*7zUbH) zDknM+aaWc5=;k5cKymF_{Zs9qCA>jVx~vF3-r!1cu9iZN_ah)W_@=xzIV|%czTvm= zeeEqg&;kQsBlatv^md@R z{`c&KsfBzE+JuTTHt$#T`~`6SY~-=Rgpv(sLQKY>WRPdRcvYob{+sm9g+Jf z^;!Wn6)?jG`ox;uSD)8Tu((IB76-O1Ht=`UaCL$YOa0c^Den)NDgQ|MHiZCo&Z^px z4&9%D#4&knOik85`8td$S(kLmZ6*em$Ew@Bq7#RW{xW4RP;|2(klkqXfR~T>-B;Fd zmJlCPtsRAz5`rBK1K}8%*puZrBzi)LRMXY05_8ud)+I3KmOj>zI26K#&ImsDk^DJE`$pkxYGJ zUQgl7=F)&wNxxf{7AIJIg~a?f>;f`#Fp;H)w}8Z(WN>$vjrh_Ej=G`#V|MJ!PA2D> z&d8^5{NdC0hk;qWy|(%$RUQRFPy|UGc_-f z@2-Ao1BOde-bJE;i+a77mD#_NDjgH$7{}{+#BWd{@u`LfZ>~RqmB!4)UQJ zg4;b`TDn|jQ6)xK)3^S#c-cR3$Khu4c?b5TAwV4}kj@N=?)nBiRIHrk%5orgD;oD4 z+hT4ZSF4DND;4@QT6HODaZ13>%PefliFa0eP~uLn%lQ6{$qWTvl{h=ZWKcsRL3{Kb zai?F^RaE7V(jGIxaa8WS=bIKKSqhDo5`j$MyRQ4dRx$e?f-<<1^U=le1{7_i$!|pB zDuNv?x~u$x7h;)7C$GcD(XSZ4%Mv!43w@$$%t@4@Tso|Lt!$v|Z}qhpNDSWRC@8AC zc199VT}?(uyrq)n_ZhIal(wr;k%&g4SvaJA6?h3R5j=|l_d54x#$~FEB)>pUq*>TT zRYnlv>P-uQFLIIy{HHZr zG3iq6_?!y(8wVZ<ihrl=@}rG<#H9Y&Tgg?Q9q#Ojj`|{hN@N1<Q~vib-*Z;~2pirsxF}HFc|UakiNO zIUHK{52b%p#cXapaRsESJZ@Rj_Cl=wti9$6%Bcw;|rq$O6`zdhx zN;o`6(FH7fB%5v#P9+b^rN!HZyQKlY%ntLyMr90`}@*fOmRitI>T{yjNYFwxiij|R61#AV0NDg z79xqyggjj=(C2C8<#KZ59|@;SEW3KNEnh0rD#v4q(JLO|bd)7f*fhdd53j*Ktkw{u zV8$CGt~|Us;w7?`kxqCivaj{^5WI zhX|W}iuZ7nEYQj{Q-SCPBM(z_Lugp5LRi_&Q4IrB;6#`anf#RHh5Q&1=h;;vcQy<1t%_%Zb(PN8YWlQzazI?|GNppU@ zDW)4z`{^hI%g{gtF5_qA&sg!I2zy+J@p)K1gzG3u;@D5VtY)d*N|l3KYR&pFE}l{8#kCz1cm)cdDtnbea=Ix&Y@dd-rBxgZlw zO8y}uN2~HZ6R)%SLBv!jyh0%iEdOAf+_RV}+ChqSM>tbm5(IOjEX}5gOHG)0*Olt( zn=tBYnbT{q7{^Dy%@=v)p%EutJ`;j(`(*1k!j5>lq)Qi5!6e$UziCadGVQBr&@Be;d|^Fg zKEu)&j3pPWEs4aSawLhGy9acRaJM5!o@2sj}4oD(I-D^ z_k6f&@-KrRjFiEvL1QTE{efnnBa<9U2usve??qUd%UJS#xcZn=(3?-kH)f=O9moYY zQ!)JN^0}k48Ov1jTnMnGVF}*+pdp`d0+g+8LjWYN4*uv#b5`c(Gs3oA%;bx+VTg+S z@uXPizUGi9%}%hM~v21h6ec>2w0=@oYyGqTCByj@+hj! zfIgx3v17^Jl}YK6MzRrD#7wQ^{u~jb>_)iJGA%YH*#4b_a}=GO*=FWD9@oZvC-_qL zL95Y){Z`l)tE^eA& z$<|3q>S1XNxyxKSO4(FA^g$DMH{*H*b-XhqRE9*}j<-6ncXWys3Bj$d+I`VEUOQUj z%(ZvVs)jj6zSQ?@(`nn1N03fAOF}4$eE6Y3gBupX@!_3E0W91UyE{#=R3Hb+#sfvS z24fEFuXp_GX`)XQP^s!t5Sl!S9x8Zdip1*~+6z%; z(ucf{rzwy#A>n8bKb`3flLOsD5tD9M8JRxljt!^0<~Gt|B~U1(7N5ul9$Srp;10x3 zwhWTyGz`F!*C!zF*F9pMGWFD%brG4_q556F4rt7UkKw9I%-xvvk8GetoTb#3ajlqGROw}k4aWA7T0(iV_WoTTEV{RnEzbQIj{ZgiC0fcRj7C5k_-x`&JMd7M4~huNFa@G5jIVtzv`b z4cO{)Q*acxq^5H#xsc<<;!*Pe9w&39$9>&T7@AnD;7WIISDuCDO<^nyxB(mK(z|qX zeM`Q{pMPbhjPbn8cz8IA2o=~GP1twrq|P%S%zZ^tkzyR1+Nu`C*8^;g?RLc+3#%)g!x@NG_R^6hPi}+|qBE=hBn$gm5tIS}L6Gs~;RVnf zq2`oO@4(6406~HLT70^(09}&(hr~6q0t*WXJdEjb`7TwlKbIoyTYj_dIp2RN5MyL`2*)<@( z@a*9}hy5Bt+W>IoV+IscVvokb1rBpy1vC&p-gPZ4-78)(Sx@e&U^>FwVdHqRPskWw z%STh#$~YsgCVr!oXn+@z5a%W_PW8jw0SNjFs3}qW`a=QPiwDD`4^c`%FM*XVWb>EH!GLlNmt%xoqXGy>A%)t|og8g8X&7ldiHsY_xFU6lw9vTA5Q z9#aJz?~Vxk4K2*0*_P^j2)*|$@rh}X!>_9sF~{Tf!T#;sMwG{^BQtIgSm$5Br`X>{ z6H;Vo{`v(HUut%Cr1s4Ga{sdSNg`(tk8YOswx`coqcI;vPP%I*>Q@V6h3Cx~{nXHP zX0-&3#TkK41WP?j%9UA#6>yO1rTpSb`5Rh7yv$0Xq*Pzef zW8WlCY+)L>?N6qXjJ?R8CyTuhDcQWV<*P~w>W_iUYQLYd3}H3%(9^{tWEy_y{HD^4 zDANcV%E8;(I-Zm|-KuEoRJ&RT?&=-YVU@h|$}vsn!*;6qlddXJkd~$Ef;C?>fNPsa z0UN~;@1?>e+bO=BEOoK<>Rj9vpD&7or#(3Gr<9d5!s3RnykM^+n3S~*$P|5P4Rzuf zy3Q){J`{UIjRBhRGyX>S?Qy;X6Z6%EkoBnb}PFyrdL25mZwmt`rjp55z#^b$Xw$s+eW%i&isum;a$dC}k; zT1k7L+uklie{8A;n?~@l1cBo_)akLgaylKH4pdcyTKzXV#%|IG-b{|g*g{LtOb)7e zHSTy$;^I>&l8_UhG+KbbldY4}+Wrw?u@OVLLZb7D;`}j;c#f>X+ z?Xl(R&a3Xey}{ip&q=l8YM$;AcX~e0JR4=}9At_OHcG}}OK6+lIUBzoHeOb`t;3Sg zLJ3m4>C5}lBcDZIgXmSlNu-w8$ElC{Dtp8Za;FK@B(vN;g?r+TR&x1V42E}98K`qgC7G%w9E0dFZ*1*afe}`oIzG@iPpFmJ`{*D z-HvM$GfNnl-$mj|H~7eH;ZtkeAm}k@j}X06ypbQA_@U@wgvw(k2nm=h$DFNHV(Tfx zI}~l?ZRX%ho!L44&)G9VEoXs0bkK&{_W8lk;^)GNb#%MM?+=3Y*3?)rnOxkOVuWoI zh;H>}4M<#BNLpY~h@&wH4rR1&ZWE?Mhq~+mee;FBj;3kQv2C?dAW6VR1bm_~#0=uh zIL}>uGoEt-vE8F~?bek^!!U6S8i~ltg16#HyuTY^LjtdOqq8Gx!A!y-1P?Y-l8Y1D zXTSNh!<8L+iphb-keBPlhiBiW=jckn#$a-92oNnP`;LD1!X$F3qZ!HRB2t34ATNw~pXMtzaC* z*e&Xmh#MVkHr*XF=GX6$o{=e)CmQP+Q^&+APR~+rXWf0b3&&T!urB##%_%@&@+j)k z-GJm))cI{tV*Z3isA$6Gued?_u^I_=Urb)b^7}bbVeVa$d&F`YL+#Rg3KOzXcE-Tg zPvceO-Dwlt5}z3fJX}Ffh#gQ8iIaue)1qj0H``a9nwqU~SPI&3#1L6+!>jur#ym82 z`8v>~6MngDGycHPp7FRuqBDEk#%i5u_R1=AQ36lyjlqm4ho}f!L3*zqCk=^o?SGvkQ1 zNQ~OGNZPZV>N=_$Lk=GIzErQvk7{tMB5<=a zWOJRKIpOW zl_T?fxtJ&oM8)7zx>RIa{%w`!m9l zghzfs19ZVTWSr3GXHo9}l**?1!jsYxQR2XW3>?y z94BGt5L4zrLg_aX-!HMCc%5>|se(2EiU+ng9p_2BX<}4nhUyNG11Ll-?})5-3dm7SidmSC+18e*|Ce z_T1d`8w0&Fi46@+yO9e{z*R)uA$6F++=GUYf^200l<=% z7LyFGYkspE*!@vNL^l|aHs-=}xXik!R!Xh_EE^xzJlH29^Myk~RknB%YJLnUdJE^? z|0Cw4odFyFV8Ach7}Sr?o@V%&sXRH)vU~~`+W+$tN8-9`uJpL_4PVW;X)2>Q!AcpZ@~F^l$oV&3?C~3Y=%jENe&Am?s!QrBj*@I?U{< z1GXq%E?b($WVh}=ak&}%UkN>I2~)8rz6i3Ied?x$-+D7qpOb9>pb2+ z*MrE3natU}r6TtG9};S6#J!IVEvKj`d*^M6ZOsf(ka{oC9)g}H{n+qWnSxZ*0$Vcq?Z$sUB_tI!ze?Q-*sa2rvszAk?DCs<3{B%-GlwQK zF0`$OJW3K7Z4h&Y!^V*3NH#LubWomCGfOac?%H~6k2S>8oJ3Sc>X9U>dvhs@%TLnGhn{MMJqARi1vO5pgn?T$@UON(4QxT5425r@E>kmK z|MN%tJ#4%juGM`1eb0u^{L?5O{N$!z)cSYZyrBQNs(*X&-3LPvhER(Cm4I0(xz^9x z3zm`)?PRFdYHHQkN;P8oZp9(SJ-NY z{{p53{sO3Sh+KKP=hVlB*l0FW$d#WKJsT}obU%5yRAb!#zY^q64u3uT3)uhP<3Jly zz|xNcfuULN@81-t8o1la`%t)?klc63$S1iBG1SThCB(yj3<@|O`bg*vO7BCiiWi9o4^1uB# z;Nf_czV#EMiB&R5IO_4~;OAxjpe6JqP0ws1CED<*0TXf-g6v)DI7w95)(V5kDYNfE zdUQ2n2J^xkNz`F-OxejCR$YrxcOM$Xy7=&N?_Vl+QU2JF91yEzh@%z#i(g%(;+%0+eVLZVdG`g^4J-5H5aM$;i>YLNXL0ydPkYj zQI#>&i&kFd#9QVIG!FJ_<`ZkCi^f*=u1Oc|x<74&kaPsJWmH6Nx2E!<>Qad>R)J;s zN6+M4VpfK~VN?u>bnGKW$?qL1s($ zNHyzUKxNVm!Y?b~PKh;if%X#{;cLC}zkqMpm(5Fe!3>?@-=l8-tH@jjYp?|$xmYCq zd!{~TnJ>zXjASU^bv-9+Qk(%+bF7dK){mQHL|&UkSagHwVr)w!C5A~>U8K{+cD|V~ ze}U0)*}&LBLm8wyrIsy!o7dTxTwqoY$3o3xhQ)27ZpN|0E+O22`g8YEI=Ni;FrD?D z3Uip;QX)A~%hFvkTl0*`9T1$4E(d)lYhyl0TVj^U{729`+;| zYi7IFjoYw3;znvr=3m1goal1Je?rQ(J#+p3`OJSJ(i$cH+inPFLABCTeo=!q*0E5p zxBk2T{Gal=L7U9@|E;7a>-lBE;ZWK7|I-LpN%8+9A>-*^K$1P_Pp$ttObx6sIjpe% znCb#0YW%l{KR<>31#~QYz1Czt;=v1<6S`GD?cz_L{8t$)oRjEZn~ld$RB!)j71PE< zPo5%$HBSHO>Wr+HmtP&G&Lpw=U|+n&LhokhQMh#f9|L=;@gTEJn!$wWQ0Vu6Y`yZj zc^fi4=`OkJ&dTJ7TSWzQ~2-jfqPbwq7KK<`xhx@ch8> z534ILFnidMpS`%bL+6{Yu6!+Yt;B`%)nb4}+|oewFJK&TgSZzlN(^5@+bsTn%)NC~ zTVK~M8j4e-MN5lA3V}k4yL<3p#oaY%acwCM!HR2ehu~7AXmQu#TA;Yoliz#pci#6q zRvPZJ^Uh>Sjvgdl{GjG1KTHVy2OUq1S#1~vN@xOMQ7QKA?7l3a6+DU~G z9J7nwyHZhfz6qtTc&pc3e*rfUzn)5CyL40FT-{Gp8Hlnayt?a>#RvyE zJVyC_vpFT**rx(yWB)6zUmjTv0j0b*pwS2iFcBeKQ$SzuI#ZB7Y=$cOYRi{1Zo^d(G zt1#@_@m+}{zu!TAZ($fSDT}$SN+B61F ztgoC2Bd0l%<3pL0Ay8$>VfrE2Pd3OaV~3f0rDcZ+*AGb)YW~fWsr_lqFtJlcF;esJ zYjJ~$g#ks(V~3t&!9Ao_#5-sKL9(QWBt#jZ?3(>M?#Ei+>MPiU@`p(YS*<>d73jmy{y4`lZ6hB(8k|l=#$9!zu8)ZLqVytAm zm1^BK`jKw%OJa0J-EF0EB>=)2Zo2eVGTauKH>clzX!9Ls86;`zPz?*UFSETZ{*=89 z>^-LXqYt%GbG{lB4gGTyUc6&{O@y)Sk_6gWa1`=Vc&;zA1Z9Tmd6EDP(i+hnr3a1A ztmm;Qnbsb!Y_epm~Fan`#Pw%cqa*>x^laAnf= zMvLcN76#UG79Dx#O(qYIiYquYY`(8hUgIjA1}tZS`~cGZZWUTJ)&l$8VaO zK`8R*j1gC(QZDpAcQiVK43%d`@%7)Q)t*#TdH>QqFt1qte@5;= zYlM!})oe-7d&q0TV~iCDP|-bF7HisDN>1(MEH*YUmUfgJ8E{C^mBaF!=%Z2_6G^h% z?=wP&9AQ6HRHP}dZ}s%P{6L$MWy8!sR6^`gG@^G$EH#LSM8N0C5|t>iZ}f zzwj@uh_rh<8C%g-B;9Ncrh;pWmMcaTq3lL2bli=0vD}%Fy86&Dxvl8_SA##}yhsix zjp*J{iFkqS4By&(a?!~?@i6DBrjv&ahwE92o6xFoeJHQ@BLr&>b{z1fu9IgQK zD;5KkR(x1ly$zF8X=(;Gg!B(*jg5~58+OYS}`%xS?UkcZGT4Q zf;{C$e^b8ie}07KX;n=AT;>l)o+oj1^GUJrZqVy8122nHp8W#EXvKPOq-Dw!)PeWj zoJ(N%XY$JV*B=B0^?&XX82Oijvlm{Nbc7!a7|dxL+ALa0|M_KP+lbJ3BKK0+ZwKPv z+^*1VqSuDyS1N>{xTuCjP^t~8$!KUGNXmp9r_($?LOBhk8g7+uhD@j0qWNWdX3}*O zFN0#tXAj4=E>>ioD-$u&SeVNWWo&(}N!v;hQul@h&4}C^O&cqfw+uE;y!hM27J(0q z6nIT<0!H#Z@PPP0ljm{pA{@D1)4za1H|_Yp0NCwX;xI<_hGy+K)uCmhM35B+CCoh6 z;-!(g4sO8-)=|=M+ge2RLo6Tb`@jd(DQ~)q$|+U8#p9IS>5d5}{jD-YoYwlzIymw5 za|T#)g0_+%=Qe{}(_kO@GHvbmR>^hV7u=IY^6WEYa=I^_{Y74AXl*D&hvtKp;#4?< zY*GErTH1B&XIZ*^6F*%GYZs5oYsl%U6)}ja&M3!t##1v!VcOmMX-i`g|w+5#PKzk~2RKC@YfM8wsM zk@FfHP!{gmredl}hBGe#!^l&p^lYFhI;tQj8_*ao2jZiNa>tD4T2mXx#r0Ho%$vH( z)HH9h$rQ&fnH?^dH6DrD6QnkoCgxk{7eWd%T(3=cs6B7x3sF|C-ODtLX1x$~w=9`f z&1-L1hodsLS$`F5wJ5t=2VTwCLo%Rts^PR7aK;SHO`GGUp~R-BN>?Rrh6dQ#Yv-oW z_o&X`A&3UbC^lH0;*S8t4nMPI-$%*^Bdt#Fh;-ft6pMpqE*mq>P#nq=NSFbW|9+sv z3fjUP)Xe^4ZNxaNP|-Prs{Lm-a(09_H$gOXQ7`g!#A&&SOlvF7QMpNE+H#8HS3P+q zlLi?>tu4^h9*-x_hUP4V{n_X0Jtw*nU&}Ke4NQmPnjR}9pGA(a{4^vZPGpOtU-!`M7|&6~bSd2m$xPSMB;69ePeQ>ntv zWM=Lh?=3vFz0{!8S~i(HXVi#!YG~8fVc%56a9opp5ZD`T+dVK;H<{C+%JZBzi7`=> z;6{faY%z|z$LFxoK+`wd(M7m<$(wMhIB;=hPf;orua5yY6b`4bf}bRY4O=)B-`M@| znYkb27%Ar~DPetmt-b7SaD4Bz+6Z4Fu!38?!EVEGYE#3$MAp|81QT`)EGZOjt)*U{7@CmScB^pc zKwEN?Z97Hw3zWq^ZwnQg9j zqM2?<_m7#OQcb&8b?%sAFHyaaLU6odvhi7nxyTW;T9Ci{L1oO~vWNwP5)De+`fNzg zMd-iXoGn?8olR8U+yqzbN1V3sdDhAT>`~`8{QzR*^@yG+wfc zaJwuZCvVs_8U6mkV#SQqjK|&ySJ>oo;{#C~7ejH0*LeKqHdo7=Y^bBgASF>(a!k=)`Jb#A?z2 zHECj$|6gAk$7n|9%#|`TQF-91zCicRE1=@h@(5&^A;!#Xd(@2M->H*kq5_MT6T9@; ztq@}dM@3o2{4~a$YXOO!y^OiziMW)OM(wgs$QVanT}vyWqKF9XeJ`I7GkX?=GeV5< z!Kdtv*G{{dm>1LTY&7B^A_6mm0H@1|k-tL3ZE_WwC;)2+giI21#JNVr{9e2K0|#tb z7Wm_$ZFWcJ)pxQcV_X|ZU~J_xtEv>_Bj{5pRcJSCq?x;R9o~pX|?+^5n?OewwJ45vqBB!5mI$Yg+{t z-+qMwHZ)9}XI-=margpjabhC*dV9EPx^Ov57G|$&$Rbfx2^br7QHA+pu@tl- zh*@~1kn2kU&(hD9l-FLgN)^oL%<|-DFQ;FI3|%Ggvg`Om zb9qxij>Si+x~c6P;R)T3enp8JdhRT&ET-KW_%mjFd_pl;e3ua`Vx~c(^#h5$p5zX5 zs-K10qv2pcg`P$pq2TCr$w$gT?iz&o%Z$VfD*sZ{6_Ry3K+vk)PaE7J6T(;S_zg9Q z6*xFJR5TH&4rbhG<6B=sgWe$I+~ruXR`!X5QTPs{;y4d;cqa^1a|%A=-_6h|yiAAg zu1G4?!w?m=*w}Ihc`D8ngUDZelphj5B`+U;HDZ~7ZC}wJ7ZwNq;Jk)IF20CQ5VQ#K zx_$|^eiotpyO12j)`DavBr+nGD9;&F$X)0&a&r5u|5>4e-wKuz3Q;X#gek-mOdsi; z)xckTkpPj^kMb@?=hDIk5Zb9^)TWGgXNf_-=OsFltExaS4Ry%>3?Ta;?FF@QK(N|k zgT)yV0x`pLIPmSb;bC!Ss+)G;@eK)BLGcS&C}x}SwbqXp7)nUUjZY`*dnwXxfqHY< zK%kEdK%GVC941cJNms=MiZrlEIn2p|gAr^g2zGCfSaGHW_LC+ri7}QYB7h)Da3Www z+R=Vj)RUqZFY*7gch%w$LZa^f=$H+WsssER?dllKPMXd6ReR%+U!%cg`ZbpNW8*}E zwc6<^{M3?&h1U4(EDh9a-4SQ2re88-tskA81NJ)aaD@BrKKv@e#}CN+3)o}AUkn*m zGpH7A{vooeP?UE2@S|w2?M=aSV_B0B0}%JBw`L%u)lwvP?6Ac1pW9rlca2>bJ))y5 z-W3qIejAd#8d~`a=&MsPgZtKEAQW5s8>`dJ(c1Qs7FvO| z66wlBw-e?Wm*4wEjFhIMRWt$@BalP2^u!o zcK(T!y(1HSo#wVTUHX}ZV;e!Ek~-LzG3vWL(hqAPf(c8Zjs_-EB~CyAM)vcRWb{v! zwQ8l`MYC9`_Y59v?J_bIok%N=mn4R=n0gex-=&V8DD?Dn1SZXrOl=ZREgbyU6RMG| z#+$3Kj1vn0`;y zv*2{8z8dAXf(w)g)X>x3%U^NqZmPceO33Z-Jx~-e?j0}+E=mjUlPSC&5wvR<-~HCR zte~*eSRda=mF)VbZsn(0N2ZUk_R~via87FNH5 z8~6h2w>*$8B1iDFD~=y^uBtZ8p6^=bFW@gALoH$Rc2XEhcSJ4o5}QS3-&1~rq`s{kS-#BI@{gU!g05BrmnyDA!C2=Mio#rQ;~SppHsE@ z+OxPaU8aynu03S-`|4CZ-_&O#tjq2iWxuSlzW}WIfLzzpVgf?wNdp0!|E?nPV74Io zQAF2^k|pG!^wa6K5$aHlax-7yeZR9UHwcq_PYT7#?_NIEGlx1-;+ z$G*Gll>hwBd2RRZ{Znw@k)I{eiOhY|GvSe>j2jPdQO(pQ_xaUdfYlw_e$8_9u-2a- zH8k0%z$HnjlgUbKvHMb*^Yxp(?xzes{-?;lfSeq`(bS`eXSZIjo(}pSA$H;a%@CPS z&aA_?jb8sM(L0N6wJy;<5w#l8wzBYxi=AhLHH5m3`b49QCk~fwiN!V`IGw z^(wL@YF{E?$%qE!(WU9)FJPFeD1S0f*WA_&rWs?aMq~{8pV`J$0@y03q27m9JsAjTKy=-CTd!75^qvhvcue3&s0UtS@QjN- zVYmH%TUwxN{2glQJ(1Gg$AGRf831(#J@V1%N;ZD4i#ckGj`;dTi<_seHA0k%)XP+K zhuM~1#By4h>f3bZWQG9NKaL7)CR<~RlW!}=b<5N=zW_Wni0!X04p&4dm&*bF@Eo^TeW`c_d{VTj8>0@js|oi<0x~Dvi~uc zcGKb0g9xUMqZ+xR%`*phNY=uugUZw{k@C$<6lS^aRpY(LYW1Wc4rP2tWxVGu6$GU!) za@*Zh(SJM_6cHlAU_hn9Au?NMuqfvPyV@J10X5BsL^hNd?y=M{*?a=G&B}m- zwB#0vG5C)`#~7L2+-jo?y2wL8FVE9rOj8W;!U`I8_>ttRUYX{AG!}G$Iz9qjpXMtz ze_@{eP+PO2iWQ{w{7UDoMw*Y9!>d7@KEFh?($p2eK_9>CHUG(7UzzZ~?Wv@qtEBzB zU*2V2|D4f}X7cLy(VOk)g;D6icP_NbZ*X>HNp%ozY6K z>urs^uY+iZZLGy$6nOR3wK0QUOG(C5fmX@lIl%5ZC6w3yqt=CIfxa zZUF>`N&Q7nA1}Qj+#ltI+wpY!xZlp>6+e#9aiAvRIm&aY@jq~h zk{uy>YD1ct z>D^jMFAyaUp4iylS6wNvaFO=A0iQ+IcCeI9N!G)SMZ$8`c(FH?#T1ml-xS?QiC=*u zp&ys53UAm@)p`RdW&5FK=S117N=yJQM06(322I}KJv!LMIaXmc^5cr@LFoCaTr<_x zA;&t9c~*ho$yS+3ABjX)2n<%ZzAf4!M&fJll^97GO6S6&%>|L zS2p#mIO>%=$=zB>Bmi-S-@(g+^eMW$1TRO+I!AWHsGb~_g&Yt058)G|-7Mvcmi*`t zT<(#VKd0->fScq9f!FFm-BB;H%sxb`Y=`tbSHYjDDrah6p5hqcxwMMd{<8l<`Ae^* z5l6(_i{#w+w;YNyj3bi19%Pw8WKxe0e^`dJD4H&IQTQIGET%sy}eX{VHm@Ey}Es3osCORbH)tp1faS-NPSs zNL);uPix3@s5Y?2)MEl->4kr!Z3{+CmbY{4Vn`cZ^QK6v)b96x!&{zjt!ZG@?2>#y zpS!iN!~DiYKX#Y(hl{awzb*J1lbftw&}33hsJHd7W9r$rb+)ql^yxR-NFk#6xsq4@ z+h*BLie;vRLrHA>upYlwV|g=Xr%&kL1!m%WNxy4BbxsPB2Y>3X^*75Xl-Q~>d11T5 zxvG;Gm>ea(L+}Z>ik}hCp}@`h0+A7t{}vgs)9x0b&$O?wcoW0FneB(NM;wPmSC@Db zVR>C-uU$~$8I@&4mWm|6q|3Im7~L4`9!-yJTjO@=D(AJn$Q^9@z7~r<)u+C}%t)m4 z-Q(89#D%R3w~^Y0%*#0AWK_=kuZWVGWNY6(_Gt8D6E_kfE`mFS%xxutcDo z7l;IA!j^^Nh{5XnW;El})5d2;kHS#Fqt8`meki|$OMS`iLvBF%N-Xwd-EnIp-O!x{ zinjf!M7yr={mcTX)hnclaWTp07q*b`Tq;I6yhGXX|!C>0S;Yk5wnw zn438wA!O}bEkAkXhy-7i{4qKvSStrjZ^r%ep%Uu}`F4_kxqle` z%bqnL;Sh80gVzUq|EH$(tM0j5k-%e0s+?$$1vqXE)F^{SIzV$Je|%izE)d6w2x!t? ztIFnipR>6&=vk{*>3C@PmZv#hC$6Ay-L4xvPAq%XStMZeC`0g;`26*5cqirmydzd= zUs==pI%ia;FPsY*E-otXHs{Xo_BRnK!N_Ed0Ce9Qt3BRZ4ngk(d##2IW676h9VEw} z>lm6EgQypuj(_^rx86ljDf|T#RWkZjBaoS^z)tCAy@#mxt&qCNnc{@%H3B}W(t{ZC zL?qczPuQzfIY-ZfP$vvw~q;%>7z4MfdnQPhjl=>x=T5 z!qw?stRoo*g?5Ey$l@~;L48y{xjn#`7!x+`X9kX1xf{k~ZLCN9&Bh^>VRUJnt_{LJ z67pl0L#GDS?Tq$|>bu$*Ovc$Bg~)C781ZAVYESuA;8gId?wFq8W!Ouzu{NV^ee*ow zAryN-M*F1DtGML$T&H5ZVMsNGhO#_rORL7s`)kZU>cXeu+HbJ2oR6B`!QL=ZXEG4r z8`vS~F2$YyLXYRa&?5=G!>3Y=vsj|f*MqW3xWPZvI+C^(U{Jc!-~HN{rzS_PIlOoC zo6#|zaZBcR2cu(>8EBm%oDt@Ka10*?N{Ai=oFnF$($UDjJP1{D~<{Ug3dox@c%I{4^F}4D&nUoEB}(v@B%x@i~8Qy>Z~3! z)4U*)(N|9OX?ExYsX|}sjV?l8A?0qE+SoTm7M7mi!R&|@hH+nyC;~Z1Sui`pC9^+> zV##OZ&Yr50>Jvq*s#g@18(J%UuNJWk{s%9& z!T@ir&OiT`lXA-}$Gx3dyNf>fXRy&sIjmz*m(BVFPdC@=)ZD^JjF`;StWsRFseuoe zTE8QUA&x}j&m7NSIO?G3kkBR!=QtNHm^?!<%peAa*t};uzdCS2-l!x(e%d1s>k&iS zKcIc8PxfnZMmw()*`eJt=_R|Ufk9p`uL~a`4SkEcy=7e>d7%^afTRKeS4A=ZE_=TPUgJg+4g}iD zcEK}M?C%OeH0Boo0(|{qZ18Mi6zqer+wgOzj{ErS$MQhY`|_5d`lLDvICA<&p0v{P zZCZWON;ifIRwSgbVsH)Ms7Zp1B5|$^-t^dvs9Au)0m6samrAb-ik4mXQEqqMKl-@u zt|nDI{4-wU#LbnsjWloWrc9t#kPAK+u{pyUAMp|5soR(__D z)}NtBGS2Cr_nt6|0!N7qUrixJg%o(_w&@5RKD@6hR3Io1g|pbC5bKiP?eY}OC5+7$ zo@JbwPEe@&gub4N82iYL>yerenR(#*sgh@dx1bQb{M&T}p@1pe-}bztJ9k$*A&?XL z&x=Zj>(8@N*~n$L+CLr>g%q`d1sP77itc#&?rfz7g{z71;9cvjbt*MT5`sw#w7VBr z4q)+aI`OhH5}yj6h|8WjXqKo^ZfEydEp+6dVKx-1679o}Wb<(RzLu7z zKN>x(^+j5TWzS{JLsP^UKr|H7o013jq^(nG2$>A8YnmbGRbV{H-WbmzTSba4G$k%f z7mCkQ4|*Lyz&i1Z9x7{hZ zX51AZS7WLl6jN9VN!SAR!0D=GIR+OH!0=aR<3v;!h+g9HI_m@?P;3vxR1=N>OK*5EDT@~6Jm-kdc{ZyN&z$Zq+N^1Y&+9GLQlF` zCMG?qvCqr8`l0Pe&z1I%Yj|v*X{Gy3oF2LbNN+0$P8@QlS!YAZU?5cCaFJ(bhy!j* zQpyf1o@peMIz*t0&T~RTo*=@Q@_Ot;|NPJTwQW*zj~w5wQNx%!wvd5M3Y;#T=AUWnGZh zx?h|)u?8@kTE+P06NUR4qhi!_pJ?D^x`Z4WAB5d0>h^tHXN#4a-yRchStjPZC;X09 zKqV#^bczC=DX94NkI!yJ`fQZ1K#_Y#Swe0)b1&!` zolTFJC`uOi$??r&rA+w0?*?+X9R7z-Mk$Jr7P-oG!F+o8QS|bAQNln3On$q+$G1HfObEt&i{kHu^7WPn7AV#!Qg6bcuxCM1?Y9*R&)9C33eS~VIT}tz_rO_R^I~#zftbzEyGy` zYv7}w)|&yeBxFC6q50$cyADdM+?LHZC9hV9J1OgbYtqXfsB5^Ged9RWg!3i5)bMJ9 ziLdA$4ah_QvZDp7ah0BL4YMCTFXD1UR;WsU-r)C&3t69WemPdO;p$xj@f*k_xgQW# z@Qws1TowrTQeN70FtZTUAUCw@AQ_q=wWIg;)Rdb_8R3Dkrf|t9hUS2f+%PDt;PYo5 zxvd=WF3c2xQ7f3mlVOaH^809BGOH0}L4a}KGbjX zUfQz8mm)0yl(&VQ%PdUA9pF1}Owy%|4A52J!HTJQ&eONh$F4yoaYcqJZA=ueuiJPW z>o!zzP-fciNr{s_Cjf@w@NO!q4?UCR-uPUf=H4uBaZPUb#$w58@V@GTOfkUoa$tm6 zKPk3B7>}q~zqKGyL~GXBakoOWj2_PXQM)89HBm^;4>t`{UIgKP9y@=6oDOePxvv{M z>|x}WmIq0{wXJ2(F6O^M1eKO&`d%79M+LJZhqFf}CgLTcTQO^i%@KLcDKtM~N*Kv}v8O+O_!k*zDc@z`-!h*zOM( za#2;!r7P|YB)2}4*X#-WUgS8&7a;@XlwJ80*@sa-M}VkoK{P*;(($g{b()@9405ob zeeSsW(_;k}+vUXzcyPkPhh1w3={XDhTnm=S6m@&!q}J!ih9_`~?(;rL`@HdB@4*v)S#DKffK=r7=87J7}$gI66D(r1gdX=R0>AG@cv zOO~*D*tq5lv2StpoW*^HH$psl5Wz2qVZ^-V#uKMq&l8o~FLf|n+4VaI1aIo+iY|d! zLcHU@5e%tQq?o3=T^cFGB8}fe6n!x|462qn8;08qGMn3aCfDEk4CA<{+si@g`QQYh zp%hEO>EqI^yn5{AYT zC);(3k*Qo(v+I<_QYk9tdTJB0BJW}NGVjnH9YVXmB{BdBqLq)rab1bgDLomiJok0K zhbQ~jwb*_K6mfDlqO~f+%4V7$$8;i2MKhPL9;5Bd=r#4daNqb+z&lbaC!7G>vX|Oi+LKRw>bs^ zv5aUS2l;C0om^GSKk%xmfI4I&SEDa!CN1}v@2$^b_s*STOT>B6N-h6~Qu>#s zGA4bAUqo;yQPa%Yanl?SL~m0^=V zqKsxY=O70uw8IkLbr;ehiYPsdaWtq*aX`s6IZ$Yi!7rQUpjA$?$tZ>;e{ta4ZWwl= z`JC?>uZkd!1M5PRRpB`C&XSN7_iW4y<%;%E#f7;@T=FUf2}t5FWC7gj78)2wF=h>T zh4P7#shJ?CU)feq%7;NKBQd9-;24RLwEhu}arVBrnDq?*hr_<3tF8HP5{Fr+yhEr0n*L zJ%nUO>K1Grw0aFNF7JQajXkch%{}{Ct2C36t`$9gm#*DCoAU8M5@Vv+N+R4gtQBA1 zf}658*GDC9-e@nzL}-$jNhNr6MmKqkMPZe`2BZL8@(raG4hdmqjl<+R+mRNC);1q} zX4_2t$1{L5jd78(`p=L-^isxBdYrwJtVYQgXl^U9UzNq(Di!i|P}nt1yUP4yzV-cb zw7S3dptUJ(SmClxMw7CX2@|kia!*xV4?{u&&UIT*G}X?HDtFR-3&abGJP(N%InxHAxhO-_4@ z4MVUtzqj&E+n&$iS$NY^uz1z;=-X!2J}cn*w2=lQ;_*4GM(U=#e?&z-LpKDXQy>-d z#geInGq*|BbnQYal<2Yp@Q}oE6D`9%vN2~~U3%)7)hnl3DCsSE@*b}~bkIf`EIdyx zdYnri+tEsPgWT$8mLGKSOKXgue2wl}vm^DJI`h1?2B90mDPI<;){8HF)7v_E^bc8M zG?K|LH1ZJzv=AdL2tYxxm?EL|StaK-YtJP6iEBi5mq_VDrWn|5HNQ?e@LYKiLR=QQ z9W>A9LIRpW{o~UebhE#F&`K&=NA^^?yD_6)B$UtRM}=A<5DAEvar~?*o+D|2?H4vS5*E`b3^4XaVdCuMywbDe^&QcTUE~o{u%CwLQ>K!d zZ+??^rkZmSvgj^SY9a`)4WHy7uLiNenC3S&K$T7ZYyXqWv)StzyUPsZ&>>(Gj7%s@j>oS*S`QV?`S~nde3Ld_m0)h z>Z(f@c(u=Ca(Wu)7xZ~wf26f$@3PMI5)2Lw6ESDu8g@E!{cJT$n!Zw}_0#r;V-o4k zQ4(~rldq`;&w0tWGjmYZy!}Ue5gU+s82}P__oUV)WO1Jt9TI*>pmc;WN_>!H?7@ml zedtL)oO?`{k+co!=|R>%{6!)f?5BAvkjqRHB6bGWpyU@+HsFi;vC#ONN0`;Ya<_0p zKH?i`DnTcC3410aJrVA4fY0P%VUVVg^|L6cq>JhmeJF)sP_FJY;qj4#Ua8I8^u7Ws zNUEU+<&5hcR8S#f)<`BNjGa%-l^4Q(7&8zVj z=RspAvMpIe+blg@**CmDlsilQnL9{0t0qi9-S$#A9$tbN8G^|PzSa%v73(TJGK91V zGh?p)B0)y1Zt^w#l?xxax8L;4d;6~t&+}!~PFqejR}vq;l%qnk zGd(&Z=-5-)z*p`xhn2RpT*~EJ=cVUA@Dx5?ai2=jvuNL?O5nl$`kU+3M;55HE+iv9 zP@ZpBGxkMW%_nFMm*$er;ADn^SDBP6t;68@Y+m3Z3=55%(3m#4)5Ri|cWjC8IpvI%_~UHw%L*}7^v5@fFv6n?E;R&Z$NNhN%_ zyhEPGv3%6AJVjbz#~x-p;Kib{Tc)6xY>r;xu-0$Aw=$=hTT4!jH!bApf+PEp8HJ1CAbbS=InN zvirj@En&X=(9mqks~FX+$r-aQ7h8^8QqC==JfVRTJ_z<=XgLW50nYVFWzW;A&I^2h zR{nLyl09EgP&G9YsPvAYn14Ft z{(LLcm%%B>9j0k_di>?bwB(=MLbo!yt&B915*p;LsrX2xR%&#{?II^X z59&WZkX#zqQ#*~9(MGO(hYlfQSx{tAca?ybIW!cqor{J0H_=jYMWpGM(HnxmA}r}i z=2;gp3K$GJy@|@0B)>G{K@*2N<3@e<56t-ru&3Ao$mH5k9$X*4*>FgM4AH^y4?r^I z@e&lOBoU`oP~;NiAisSYw5b4dJ$0#KChyuEs?AEoEM>|IM84Jn@*L|4%P* zjnyJX{zbli^*#StoixfnY~=qtUN%XIPop`?*+#=GoPy|R`!I)2H(yzPwn5(8N_&r$ z#jkD@Tk#tizlb~K1zaBDBa`v9fCUGvfr5z+5}xkL;}gtpvJt+o!oQ*H@q5psXXr#H zoh%q;>X?eFS>IW)}_(TSd=b7&Zvw7x7rNWkVc$wOX4$u8k*mt+YI17t z7+2olny|AP%jO$2CJEV`Ok<+#sQ|Z`Fem%E1`+T7KUzt_^;*?$qaNx>SR=vx6Sorb?CNxe4N=fB$hx^IyR4 zF`IntvSi=b=lD)8o(;$1+YwJ(BG;021YszU9vc;a78EqjST8qYxMvutWv4rs0jq9> zO%hgdTgB1wGr#f3D8pn1^%24>hC%4`g-Tq=Ksnj(82>#a0jaCM1QpGJVp&+5#h`n= zFxm>DWWsJ?uoPfEx1juCaSJOmZ~VgtSRMu@^DplJjnoF^*%6!PN?jHOk+5mvDsJBw z8fM$5HflrS41oen@$B^7sa4CzS^&()2_w(PeY!xCnMH+Pm#HiKm3*!R+$1HJw2ob^ zqPx%)2r+SRVdmF@;*g)_E`0QvLR>o)76r8{!9PPA;u3+pR?dJe%qw2D1AnJ9@zZ_r z!#F0aeKa|VyZUEJ zc@!r~e>x`ZbM+T64HWXO?JReiz^4+j$h@?=#l(#ayLz1FcW7B7e1NaLWhp`#6leRR z@TT1ib?H`-qg7eaiC6u1v=9O+uky}bEvE(~iG!yw{k|nvl^%XCT)~%)C+RTqqD9SM8E zDNg;^4+4Y*+x@yxNkSP+cWg;T+2CsMr53*1cEYQ_0P@y{#q4HPZ`Bv=Jnn=h9dz?Y z`1E7DFm0%=@+RwKE;2$$57Vj0z<&A30gM!G=o3`? zW2yZYz?NAjCcA7{%v#J}R35I(AMff){}kFy3SRsN-q zY#*N%njaR^-La?b5Q&4;3rn(2)RWSK-L6ads2R}dwNE!1JzP_zoX7lq0kx(`{%N*j zpyJ}?M-^5<^Ly))b6w)&(q&$oLz-8j*J`V6NV$x+r$t+9E+h$2t~s=`X2l6~hw~rp zkBNBMoSMo_{37*(UdF6Px$^Ndm;ng47j3I1w_}g;vqwsl!tR+bk$h{>TRim!Yb=Ak z10sO z?0~x<`dM3J6#<(`q52=?0jtpg#H!fW2mk6@I$sr?K zEGFvE$sCTv3!&SX(BPEp1(NeIGBCyy=Lum zt!wY|T#JVJr`~3xm(r}+glnfz_u|jiBtab<)(T6O8qnh(_06u(HHn?aW-KdSl(z=O z_V1dEDbvXWOb`6XjPnZhsESnOsO%Qg=O7$x%-GCKq$u6$?K$!KGEcP6EW*Iq^_`;> zLal?R*hN~6v255RWUO6kC|ax)Ynk~rsjpW!mBx1r%V;~l(f&Tv9{@Cu51+@~mJFhJ zc#IETtZ=>>GXNt$JX7@!U;S+e6E0!I-WV7iI0)GIg937EemH-frQ`)xBuF)lO%HV6 zd+~OtY1h~e&szvqTY@tX%F5ox%=#-{;j`A(=fOM0*S9W5r%sneUbC_&o|kgKd*ESs zmV?Uo;?KQ~KjVJJhJ4I?fM}RFDHSVlFu1+01u<-Eikf#rii!sO+&gWuWEKBrF=I@m zGHE5hvWz!gHW@xyxF9l3=}moTI7i*k6@*LI7+A*b15a^DV$r|d2(5Ogy@-zHW|rFF zbyPK_jW$eQC-x0Zz!ueEB?~Qv?hJfdkH6A)IhRd8@lD+RFK8=!jBwhJOGtHrN95GB zb_*+$$#nFi^Z=(yiDRZ&K|fQ%hASz{{pOEX&qBvyVy=E8PoG$A)GfHu#`6eT=~?!h(fBC5YnE|EMLYQa$(K z9lA_S`sa&K`ox+@>}%G{YYZlKCwKiuS)PagK;5s}$4B2b%THay0m{Y~=ucD&4;m$e zmsa=7Tm4FS>q6Cvh8dlYV(?DSOgL-+bCTCduQaomO_r;tTQxnkQNkZzUYcn)ndT_F5GnL#)JGfm6Bp`)O{cNX zYCanhjp^?VLZhF+bogJq96X9SZFn4eT8a_QAO2!mpduizB{D8eF!UGe%@=Nl?XTjI zwC_B?M0$p>7SE1S@;GQ;?-w|cw_!r5y|m}YUlT@>Iu>$~{>2sldD-^&9=EGpV06kv z><>zQ_nckPa+&ABw;%#j%NR>XjfvY+{a^+F}_}RTQti(-AtBdv&b%7aLJM zT6N0DMGuI#%U_9NLtNt53|#`wM%Q4q<{2at)CZn_P!P&(=JYo%)gfPNuO_hYdv7RR z#eLEr@3gGp2B7n)b@zU*cLhjPHd~10iHd;pmE-t>#5<>bmCyC+!a0is0}DlRi&)JB@hE(h z8qCe)9n|vF14VEtGdpy^SbhaskwGp(q_rHu2j;qs3cpm=MK3+eac^Gu&4ZTvk($c2 z7FItzXjVzUHY)O8)HJF#QJK*b2$d!LCi}AUeAbmPrG@OpvLCvSEPreh!Zf0s!dvH> zO3>-3sj=n*30|Hs6R4mS{0!em4mNY z(L*sYd=1YvTcU}Wdkm%hFTZa3Xa!+|l#vH_s8dgZPL|2F_HN()EL4aPKnOuDPRK~B z$lpeK^-g8uqE6qyiTtjukK-Ay`yK?DQ_pxZUavh89uMdtr^fZhpp6%RC_(+r@3|WF z%W53ZGmT#ZogAHyi>rLg#!8y!vS{FA+GAN<+8INnxVW-XsoV)NIU+~EpbsrlFYc?P zKN?BPbpS~bw-jFx@X5UTXj(ZqoqKujAXpG;Q9HWAiqxO&r~A!byZGRP+9gDk`{tmt z*EK_;{Hnb-L*DN2CnX&lZ35wlus3x#FW?=E4@QADw?L>mFtpy$Fhp4IG{008`#duK zLndy%?2EH1m<-;jro!3B6#m@fhfSFnuc^aG#_c}fHPwLE5b&SzEa;!;p>9BXP-hk5 zjvRQ{J?qO>YBCowf5gwzSOVVo2gQPs>S30#r@ZT9i9m_}XRp19x`Mi*7p8c6Q=wey zFkyDlO{Mj9KUW5Uz5iGb>PhdQZr{Kkl=c4hfOztK3q1+lZ|c!fbP8RW-X_M{&~})r z+-c&3;W#1vY*tE+_eAQ^bfn0^XVNKz8fy`pSd}$4DeGnSjM1e?)?^+hADsu7hnVQ6h{U*LHhX#+24k?(^r2PFfuTFAOiO0aXi9}dwK&Kb9 z;sPTw_`rBjb2#cID-n_XS$AN^iXqB*2+$WJIX>ChBz}PFeUoD=K^c8rr|Y-}Si4SQ z*TolBu+Hl88jk}VKMUHwWo~r@sO;E$sv4fcWC^d&_ zD>Dz4m?0QOn* zrm$}Ie<713;A4u1+>C{%v8>G$@{73*H>xvrN+W*W;wK?a93ki242LKGvc}{L*vB=+ z01?Ht3_@1A;ulZ`o|omSnWD3cHzmvsUn9#2!~q!WN}PlP#L5j|*PwP@0&=J~8{fJ; z8yLBUo=a|yEWN2~jsv$Au{+W>(OHcFFYZQ?ivXfZ1BhBuQEN~(RxR*zRRE&y1nsp_ zajX#*L~uCkI-@dSkg9gHBdyE4U8UFl4T2*1z~&A9_vTf36@*vY>d~Nh<0jIXL=Pz_ zGJ}?Kpse4R9gj7q1K4>lWZX7Acjx33R^nZ4_#waC$yAN_H1@(tZ!^?_7G-U0>j#O9 z#}=?)z=pPeZP>UqsN1isea+!u&Rbr}0AA3Z;9c}F{TGoKnJA%}?0PYxccA9lBhb~CR@9!iIT&jHxoW1JK}VUcJP zvi}D(y)jM;xj*=#?dor?$M40iuhd_}KGiKA!rpbqkz7yG+|tTm+}oJHx4)kpoFd9I zUN?O7xJ-48W(=W`_PZyom87| zYc@96>pmI*T+9LUy*JLd-&<A2oOOOk-Nj#taEk z$m$+Q`9j?>MNtQPR$=I_7|$sh^JemBk6|*)-^@L z;^dpzdx~t%fcT@|PiNEdd??x|TdQG<^Gpv~}%78^K3*2-a^~ImR z_PYEE%v*&wM4`E_aK-IK+8SSdYMLdYkXHsJ6`cPEh2^(uj+l?oBW3Z8`JBH%*CAJm zi%t^MbaTqG_WL|&4sd{sYf|>aHLg#8P)^HEnO``0kM8VzXZe;0hW|7QOS1^Uit4UP{|PGmAoS7~ZdAiW2E-D{p5) zNt3dFru+!G{<~ZiZpOdHT(o_QsZ5u!9H zyki$cZKWTw6MU}%mq0vZ2jb!6 zjKNQ1pd7gQf**KJJ9Q(cPG2y0j9uLHi(bISA#;V9f+Yf_4uo|Nh?<((p^R<0&6=cIaE6Kg?kSA@F~tR|P~tc=fcc@{wmt$DyhDD&C@p@dcS59IWUU2_Hgg$rlEunuHmT z|D6b!-qfp==*+KwRCn4>Bm^6@NjW>I!8=sg{lKIu^uHK!(c=Fz&6xaRIZ^{n`zjGw z@unx|-9#yEbVvKn?~?kUo9(0Ve+9d;$F*>nFaEo^NukIx4Q@7$j8WEK4+EjH`2z8c zCQ7|dm;L^Uo4$ROxAtsyuKSK03+3jTd_k|XD3Oz~cn34~sTV*SZ;WiC9U(}q)A(NQ z<+o|T-OexCXhJ`FFpRu%+%CT@b`S8m=v$h$SV(NzAr}wr?WFFL{EoH=HYnu;E4lgU zgo>%02XOL!hiD;rD6kU`Zo+5TCYD{|i}42`P6WbUv1=dNr7@nVCFhTz!`xAexlD#t za>Wh5xb*j6T?9ya+`8ch=7pM)0xV_n53#efFs13m1*}p}ME{WJcpymLx~a*i*5crl zPR*|vUsXPW{d)w=<5)Lb(@Vzx|L^_PqY8hZK4@Au>hJ@&#d?~Ky~SvGtRmwRg?`M@ z)0H_T!mhg9PX?QlK53-#d-3GOL=A;DB{klp&qMLw9~eqWFJD25fx|XD2!*6>x8dlc zd5@Oer)6Uldx?jnS@N1f>H3xKF$wQ7JyfB64*OjJ1}C?Qz-eQM)|}lk)2=FULUU#v z|M8QyMwyzy0Y}Xo6q&OR1dkK5WxThvwGhqWT?=IOc_#8Ew#?1W*y+#s-lfBAD+bG= z~qhrD; z_Da;F)lAKNVPq+X9!zX%872)Rg&Fqdx7P}iiY)IvVQyRs{5ZVwjyV$!yV&lIwy0;AKRh=n5pKZnJWr)~j>FZriU0K<<9J`Ba5gckT zFba{7@~;RY&eZHR!cQv;k|cApKCH>6k!!;R#X5-ck%Mkf13Zt1%jp^9*}hrYLMe#n z{RS+`?4u>HhOUrbr(#hre;_Dzt3nJr%IPg&! zc~rF=5?rGih&uae#-!RT(!DM6Ub?Q(t2Pe4^tF4!5tEuoCce32X_Yst?Z&D3s5;D~ zmN97y+sEQ_;NL>x#V)OePG6>JnNA;HM}GW-gPL4<>)?W~cG3iAW0 zp}IM$08l=kAeRU3$&4v5+r7wN^b^WYD9j?``!j&Z{zR#_m!$@3wz zQl9Wd2v0=I00Vs-L&H;UhrBw=NVVFjoN1;uF4T7+?JZ3x?kB zpMKXU+rjo^YA|7uIGkketT449d_MMQDhggOr`>?sDI#ndxmd<9Uby*V=14AuMRb~%|H{Y_cPiIT~jtZmdJ8YXD_ZG-7)IPhF47?t4LY#bb(64^LdTB(% zDr-_)%`CDZ(`GVGlvYi%#v;p6e8F`&Fq%z8$)h2HJAqGTYe^C17ES7^{8v$iASGHC zY-btm`&}(rq-XPogP*DuB8cLK+YvUwZBGj#i$5r>8q*fMjsXNe2SJDDR`m;}bCiS@ zIq$}I*u>vyBO>vEc2zAjXl@kV4AHBE>CyJnb5h;KR)T)@-xk!nYomWKk24dHBkBQq zy{~J-$98+C3I1>=DTyQrc$=voo-`D`yw0gxbZF=^Kcn6h1YuvqW_>o`5}pgnd)#-K zfK}p-NTt_$I*59U*qoW5(t#P=MGI5VI2Ocx0Z-(RO4^PPe?{>2JD=CPS6_aDJjfMD zJR31#kDBv0PnUJrqxe+c?3;0$$UQa1R8^0*>jstQP*b}VO4nTFk6^V&(fwh1KICGn z8EJF+{)kCryiC*1!2{ivgA)s#*nf;b+_SkJl49_HEZ2!94)2PUO5pHP+_&wQjjMex>#6QF&48o zH)W}8^Z^_?fAEfd%&XaTt*I#m1RK$F6fAG14n`UF_M7Bh?QueF-c72b1WY#>M+nO?Ssjym#o&3tM(t z5RwJ4bX#=&+P(XZok}?kN*-`lqb}EeW5);{FAm*ubdCU0oU^#^AfPms&Ncxz!JYP) zn68P#tgnV0Vt+1t!C<_Qd}-;&%!Z@UT;6y;7>9aYrSGulb0F+471L{drL*e~%BEfQ zH4S`M{o|sqBZqJ2nuB-{KSzH2OaD74c*p2AIvFcO2A%5r z@w^8hvN-!g`k|igqQBng);HBxX6ztk_U_@+E6C7)oYlV0cIn6>OU5VG&t_Nk+F38) ze87opU!2h;q6|VVESiE+^DNgApi(p2!&x`>5SVl_!wHBd`R+0#Ej>t2W^i&zk(AnFqe5Tq3}y)eFA_ zce@221=Ll$y`>hzBNh#(({A(_XDyf-z-7hIqj!Puea!3 zd$=^$qln3qZM}gGtKAae%}MJe>)#ho7OAB)13~*)uVqbwHccg;WDUDr67FZiGamkH z!SI)j7UaQoDUO$<6%z@`&~amSlC-|uIU>U@bqdPv1JjGIBi6f~cDN+6^bbc4iR}wf z)RrjCdm_jlX>HSQmQM4e<_%OAE>crTXU(lknaCq~{JeMOO^kulx30(^^g{##cdl=$1R`Cnooh1@8Mz(~yM1MfvsO^={JHd8HGt6=!Es z7Nq+qd?<4Lk+jSadVE}|sMz<;#_yFsqN&r9&&qU|8@=LE*U|Ay>%z+h=Cf?k;%ZBD z7Tj=a$(pS^YEsuSdvq0SC1MHxdZ9PEs+4M$deDQ$--peIB$V>@^Y?o-_qRp91wDD0DT3PHKuV}Msg>n@2V1WR0|MNue zxMF-n2!^@~m!~W}4wV3gm;Z_G$*b2JuOQj%nv}Uj!$7MAhj~|uY{7&ws2c+tu_!qkBbzHNEAq_sP#ZWU_=xXTgc3Y7U_MbJe%QVf(*L0s(BNq

Hq@hB8@oP|n)f@qlKCBa%zJ`i8O0!k8ip;tExX8&qflAn zVk+Y6v*7kM(3fRa&^Q|coxRFHPexRPT7&^Jzd{v6@j*X)9Jkx1uDjk8QaK+@NT&oI zB$8KL7_st0m52-y`;|5L0rYLV`o?NXZ<{qPc*vUeTFdE7OMgH z$iO-toVBW-ZAeK{uwn95&Fay1y+vL>=!@g}Lez25BiX6xfr3Vfwn^IS{8(AC4N8pnBf1S*rFXUD-xgf=oQVCj8kX3V znLcR{>(Nos#fL1HTAnWiaS;g9gC}SO6h&x=7I=>H>-4-L0GAp9s)hEAkk%3@oJw+} zs>bh`UKuDi`7v18JeXYiEnn??>n}H+B>vd@lArL1oD-D#Ytcq(#2rNqHzAKdl67rL z!nr5CaWN4RQdKFk8#I!o_79?q{Y`L_w=M(%ADJlgAU6u5nQnLL*8iaNy$;MQaQZlZ z)rvT*w{(a2eZZgp|xCE0+nniS$#?r;wr--OEnh)iNR$F=SJSA&?cehho ziZPCSqk?H0{i=&F|8s zb$?J)GQK-!$LEL_doWZi$(8v1w#i= zr5NkI%>%_k_4L9Fz=t}kD&9kzKABLXA2{@p?6A>lFcZ46)_@K|)dEySSpSvlYQ0B> z`0!>UqC%!V-wB{elgWs=5;HMgDO&9fXE%+$0M{kG88Yr?p-g$YLx!Njl1fAs-4?bz!7L~<=MBIV7(^!glg>L}g=bt&$#gSC3$5Npk{;l_ zPsl(hp7DD8?$qE>9SYL>-*KW#4IFZw%j`M;rJ2cNiT)|gEb;8`2Y@Dx`CNia;J@oK z0c-~HUu%*|TFe8jQ;2-lgi_lp+;^oUacsLHG|F}N|DJ0rZ-rljEog%@2nGV-h3;=aLEV!94~d&K&c zM^|i(L3yai>eSw#njb`Qp&6qeie+H#ThdTVM71$^%Q$~BoxC$2^P<{dQ8ymbIxu_Y zVSr8c#N};Lk?XhUUVF--y?$u9+iK>X?4GMYz}xaGXbH{uXRxjPqOUN4n=nzJp#a1q zg<2<9WG=UtxeC>5H=czRT_934SfOfxGN=I|R=7ErFcCDU{z8~n{J5E$WUv{bAY+%w)PD|qAdG-E7@6N++HuJe`@o2hBP;@^fSFmK(n|^68L9~;o@J1S?;ivj> zKAYoi6TXepZ=U}Wm7KP&=fHJ;|C7yC>Tzh^95I481HA;HCJ2J9raRLYerasIzIY@l z^eT`Al#_D9O{B_t$Y`3thuz21)8T2zQgS#Wx-lz%B>D#h>mlvO|5P9y@i@c?y&0 z#ug#3`d#{aLa)p1CWVAy4s+_G5~W$zTBmH!PmWVG7PfDWwbycK-KI|VHVW(|(>c6T z66A=@MbSJ;tV18sa$+S=KV*+LrE7$57W~?yZTy2WD*xbSM1hyaY;oth{`P*C^3>nE zh~})s$xCsLxM~;ozys#74HC5z1yY7Xn@Me6_Od6Ll&;ehMi-wdtV@g+Y!y!73%Chm zBmDBG|n!jOZ~}wW8TG z#R8U_SR)B+-t57|pPAjaW$vsq^bV$BrJ$HRTp^})8q4TEmeM2?!iq*Mo>)u5WTfn{JmSk*7;76WwKP@0*Zfwe_u(pt>R*h!{<;`4J5_3@}e^6}3!q85<>f5m7hM~=Ldy;j* z1>ej-6xRu<1lzwE8&!NVe~2WPB~(;xJ36W*q{@*+aIifIu#tG)cx9{`HU7$eOAC#A$U8-hz@ER;GoSM^}9w$%~2tMZF`e`Jd z0@NZW&N89`ntHMhUNLh%p}40?*GgXOGEl5tz~yNYB~Wb;OEu{Cd92wZAH|`H(@*er zBqJ0x^unmk(P_RTl#z?B>vW`^u58C zChl_oPKv@jyZp_su!5CPJ{gX)Fe;sm3}SOuRf3bsQ5&;s$-Q|}P|_hR3CR=R8AdEp zJD8T{c7eTbdX^PTFTkyj7etFQE_4gH6l8a6!)u`G5r1YbAzgW+%}ptz zBG&WUE7q>aBEI^xZL#PYtCbsP{CEA|p4}zU%vs;uSPrHFsmp_C6+j7oJU&U% zl)5~$h51A-*ngd{_5!LN?1J;;WOODC?p%8tPx*5AGA=3u?)>kfI!nq$9nLI$7zupP zD4HX#ea$TizGIT^eeAZ=kfMXCXyt|SC8v_1poC@l@Fm)0AHmTqZg}j1ZMdV3eZTx!gCU`f`b_!*j(K$>sFOnZ2XkE%0j`!iBJ`WM# z!R{7wkQZn#Se_%ftIRhsQ&%(JQ!lg6LM-D|C9R`C@mmFsdTLy4r>AC;Fcr>0thAj$y5{Pk0^;<-SW^bQ zCQGyLb;Ch?0u}{trJ#5oX}hO`I3F23254{z`aMA5xbZF(M1_h;#iW5#A}XSnN|ai6 zh`eBKqO>W(>?Tq&!H>%<$cbFftt`t-pzhtUhJW~=`%6r;&tEpT`K^(=vEO^vm@6pz z!*?>d(arn^#x8;#9*%XMj?j>-Ej>IIa5x z&BPN9FvdS<8C^cwPRtJacOdzL;#VA#M^pFFAHsFX2{wT7yEl6FYQL6_Pe;}j@nAUa z#Y%Ap=_)TlQpF9wtrWY04+wi+`6HImeyg#9m>bh)>A&a=WZ)y%YT?N_G0g&#aQ_vl zx?0KZrp056;_*W-%$Eyh3Z5(}A8Z$0n2=y}+wzw!-1nmt zIIq;$Z7y-p6C#6;{Lm=EK#7R0(8Q93X+=vq^eI}d|8#>i`hVH78@+^x+Q3R|UUp}{ z4xXtmsCBb$dk=Ck&`vHd8CwpBo@com+(cI;IO1xyMN=lC2gVDoLMtDLe zs%bmld<=-0(=-eNM{Xh~l0g$bOYy+i?{2(lVr3>sf3fBm#`9#gm0{_ANWQZ3lRKNs zq1vs?*jP#(5TufUAmx;f@gtPHq`Wr^T1#}@YHP%!+D`NBP)TU5GAjOo@qS_VRZ%?l z&-nDq$VX-0wmpZnMyTn&y@+>p&hp00ZhX;OIOgrM$u@^Etf$tpWM0#7*rlvX-H4ns8xt2Nl@^wHBjVm$l zu>L2=XF|+>(KF3eC&xIu354f6`vOj{=dkV3%__0_I62o;ucpit3@exsZe~5xs$@3F z+pOjJRrW#mg|I;2m@KCz6&mZKqy!~0C|WqZKJrj~ucZ76IP!`doE(y*GAEE=u3O?> z;2EPRlcn!*CE*^Kg$>4FxPUetfWal&XFLog~%Ooe`KeUQZB*Qhy*jzCI0-I0jqJADnl7`$kelDT-6lsp+P(T*{aIN#!R~9X^-WMf@zq0HJgid9ZYpZFd9U zfK&r&jV{P3v5hG`I8)d9`^Wb@T+b*Ezd(kehVS|ej$L4wVu$+%qWA#c$p<19yq@2% zyH^(&@C^C~Wn~9xFl%3p;N_7nKI9{QPYSQIc+JzRJ6n{@Wy4`GhDkWdW^{y=Nr|00 z8^^tyX2L78bWY!^vgo7!g5}w5Jfv3KBiN}QM_$#s2Be0e$dp;YYNw3)v_$JEm5JzA zzoX~-(<(Pj7j=b}1=4vub=W!hh@wjT?aIrlkpZOCHdJgH za%Zh=nfGlVobhQgo7ZK{_;2{J0R@m>o*pB6iGkwM6|Sblah0eKgG=x7ZPu5~dq4k? zrscRS>#~NBFE%p*AG;%&b*>!!(|ib4XvyXe)nDPxJuf92G8k}$9l|!7U4ivhad#uy zbI8P6E_av6-!zHln;g@U=EX-e>y<%+a)x=g%G^rO>5ILktW5h)LS7Lfcd68AT|6L7 zkTDNBgq=h63|CihJkD1r+Er{k;>n7q4r-Mu!<%a=6x)-Xuwj;RXR8V`U09~2Z~O2i zl{`Rl1R^}A)3}g&_^)q;=NkRFhY`oMK<3t$ysdNgiJg>|+NF=mf-kn>RmG}ylloFHt!-~Z#K!~EL0!w-=m9&8M|z@mJia=@IT)46 z@kMLs37WE^YVI-%xWI&S+`Qq1G*>3#4@oPn@$$bMwThPK$` zjgdhap#5(QvKl}#B?jiI^iuiQzW|S8FXQJneEO>oTx&k5O7JY1BP~rLPPPl>*J+*} zP32Hm^THcyy1UV={EJ7afPGjbZodfHRW77By(@5 zr6E0dM1N3%^1RO{$`ZHN8ER2i1q)YbwZ41YYj`E6Sh{?Cx2RxSz+ouTuXZxeA)cV3 zjefw!#KEZvw*5JC7^5O}$Mfr#w-aON9~9<$ei_MdwhVT7J2&FC&|MQF!=5>kkTt^0{P7Y@6v} z`u#XS2iB%tg*sfb=UsaR1#36q3+;Jyk{`}f>8MzE?D*LR*6f|_Ls^3xT2U{K<9mvd zEtwcuqIeClznp}O2c;AAKBG?TE8>-2l$6T|DLz=YyIJ;LKFodqht3yCRNp17%Q_ZH zYAM7Oum=d0Cj8|GNo2TnLw zZW=8-tg3Yh2sp{3^lPLyxP2Sra%fD&Wry${0(0$RH3$j9YG-pefTCP!ef^>r+PHx? zlvk#VI~W3v#fgtme;2=edl<2H!*rCq!zjpe*=7wi9tZAV4U~TseiVLH)rfO0>JYJV zDd#Y-maB{d+eQ=FMnNI`g_6U{5JYtMBK|D=vn#*#muvecx)Sh*pcjL?ui=@})*TO3 z{~o3ILY$A+0N$NPtR55aW}jrox=IP^wIw4BJ(K=jCq0JSk%@N)0>(+YT?Ps-MKgtz zu>98czK>#@QxDMrq?^jWa)=$S6Lkvqi_GA1Nv^TjJgDI`nu_9|euws__1?(p+%vzb z5=Xd{i#opBopy_>1@#akI1~$Dc`BQ#n_5t$kK-Or?>P+1^0#d;E-JobB~WjK%#Qyp zP%pg2YNcQAcxwbGh6>!7t8j#aU;{o17aDmaa#jjPvevY6$?F*jFZwd@v+js+egD%w zIV4V>63MNTlLu^*suSE9ziNnGpK)&u&Hf!HUe9R1%m@K0dHHlg$Xdl3hhT7=&muu23RBR%WcaQmyiOo(O2pCX1oQ1_P7m9;Rcu?V#?HHwI;#c3AuLR*jod9 z(pYC38ouK6iC#wz=2@h$i8E%Dig40wL91W*p46;s-;f`qCq#v1{a2Jb%@caaf~pW5cjZIOw%5+rtTuq~+#>Y$P4Ai^J5=F! zeN=|}4Mz)TL~KoE{%|gMt?SY($;|_UK&)^QYJ!8!v<|9aXfxqLV2xa!@Ucj%|KFWl zYYC5s1(pfE`9M4HShnSK>Karx=k}5mLD7eU=EtYHqq#O{)6c?q|LP2DzDJrS_a?iK zs1M*GHNX7WP9PGM-;uEAgmH&(geWkMN+^o{LD8M>8$AEE)3zvmhd{agPberXk}{D} zJy<*(7Tv(h>2fWDMF!OMkiQERIctF$#P0?`se|hmg>R7nyS{K+O2$IzaM9Hx6}TNK z9H8>Z3HwAB=0Ym1a17L>|4+1XZoPgDeKz=tpCmBXoA$%$mGfNsJo+ycS@sq0cJ{-u zkpCLET=s_TL48T6LIlQe{n|rh9PeZ7>iTF!&%qR?LY`0!Zv6 z{k6$zh`8FG(hJ-VbQg)7=2@9BnU}v*iM!twGZ_0mU6n$x@DU_s@}P=Na@PGX0Cry< zsXsA430d<)`PzhxY2mJM5-)|AKUwj%waQ2I9=RY`>Bn{_=L{>f|82$`q`OOs} zL4Lz3rA6ZxIfpxoJg8Tpq}H`jR!fdr#2-)rhYvJ{qI}JNxZIasRbkxiyCcJ#eQXV< zdt}Op{s+aIY`O5Mf@XRR0{jW%xe*o@TK4OV814J;?{EV}7^a-2v^dLe-QcuJW4duT zqR}B@H3cV75o=XqlzK-T&nxbT*ei;g>Q0}7Y^R;m7 zF!AqHlKdVveMik0{`rY9_rPQ-g}%c(?esvl2nv!K4$XlDncgSvd;z~Dp5YK>1L+-} z%{^0LrViheGF%*Zzmx~niM#i~=x5WT;I0SOu!qw44h@s6Zd=z8y~Vu8PN(m?JdI>T zcyma`bFt92jsv~j7<-pLpc`O6+66OsGuth1oI;VWQ%C^Mo87e|F7(r7g&o zjKFsiNrE9s%lJMP1;2d4gXT{2T~cvQ7IkmeRsHdJ#8xX>00vKV`%wwyP1cf{_owY0Qx3l zp-i+;{zJ5#KuCuHOdOVa%~~<`{{C^d!kzcly_Opb@6>G}uulLjP%`G;G61sy+wb8m zx!z9(p7xrAwpO?&Y^q+Fqx^pc{`wd9jz7m31KE;QVwk zk0lK_R!<@Ft|l-kwdmkP7r^jAjqmWtuYjG%kW}sLe!-KBF-iYCL-d}v$?fuQ>Zma$ z5gPb$w1}xo3q@edc3+jt#7{cBpe!`$hCO`pWQ6qSKkdri0Cj@0H9t~^Tq|sobG$5L z!ds(eeS6F4{D7=aOx+6_4`~XyRvYKv4uaC~6I|-7-xgjnBcAz##X>^{v?=4@ttRC( zzLQe)16-r)vT=Kw%o9LUPzcbvmd@&JmRa${a0Kd88+z$)xUa@;3^ioN;b|lS_pL?8 zIm&kM@3zDdY&8)Dw)P2+GAWUztf+^qgsr2ASI^K%o+{APt><%O&;~MRu2B;X^dYmQ zq8=#z=3Lvp>U^~t-3a3qGQ2>+hzsmFGNkPxlTD%swd558+3|nuccrV$r~FN>G^Vhz zWI>EbBejloo=R0|V)TjP;*ksdLHjhUGg<8iwmHxX?|tPbbE|x{mZgvsp#iWOxpzzo zYl0YAQMh;q(|NJD5FUxj(?OJV{MURElF5(O)#7$I951G1hDdXqtwalAO%5ui=j7{q z;_{yBjdQ57bTNSoVsZaB_0h+wjU)+BOSxK*3=(a~kMub#@bSgLwpqPwit~%NE4?%# z0Ywc_rQQ#p>Kd&kbWGBr4KHv~B#J2zm}7ebDhma<$_}EPfEu*hS7h|N`c?|QB){|Y zoN*@TNuW}hfr43pqwpZhRI;kDP@3z^UU~go*?OTT4}k)vn6U|7n3^wd9O~qKp~~S! ztbyNJp6Z1m#kKHuPmLSx{^`as&HDO*=9@5%?P}{;8_olcl3SNDwHH=Z`%!o|gy>G}hFtJ;R-$ub;U2RXrP7Q&HdX#>sf>+-IZs zMZL&Cfe6Lm%k}506n%zHsxqR1way^N&UBvQZyi(9%D{nZ1JYlkWeze_?UIBB=C0)w zm5f=yeHo4CLCOlBY3Ac6Kl ziXS$KYsDc6vXYatEVhL#8ecYiaC>PlMV~ebQ1Nv#$2~!dsN(*TVU9c8NoiL>xkN&>ll|w>Vx^)Q;AT#V@Qe@ z{&9fmhSlqcypL;*r;hjx_9msr{*9MMVnOMpx~{TD6=HY3WX!gnleh6m=>Kr`)=_PK z&DwB~LZQXIxLeWUUYy|GCO|3D;t(kA*5dAN!HR3}ws@gPf(LggP~7=_>GPbk&UwCX zt#`fa`!g%azW2TN%r&$3%v{sPSHWSi>^HEuA(-&7oQ$|dWTZ3m_$uA$_AAhAC)-!2 zW+BfsZR+O>eTt{iQ*NP+9Tq>y%ND%IQ%3CO7HHnvFIu%WNJN|O0d~BB-3lY?#Z5G0 z)A?tb5Mk6YsFSY8oA2iuB1d@**=p~&)6}t0G^L2Vip90a zZxU~o-Pt3O^QS@1hRe?W))mJyDrVe+m@D^w;~WBsf-|d$_TwjO_ zAh?@ZSHzyDDdd(-<6e1tnAx?Aj#`E-<4JNc{W zn?MLgSpEEGd1;0m_20Bf#v#%qv)^X=&S(Wp-hV51`!rUw#+K&sGLwAR=upk8MGexh zPNh&YK+wNjbvU=m%87~pt1r$=(pR`Z-bEF4|DvK5|4CN~=Pzd;Hz;y=Q~NWwwf8q{ zAqqNK|0T1!-%|9C$0{AOd~o-ThnKQjd#j{zZ^?p6@=oNGn9O)_x=nIkfcBet zh^`pKNl7gO1l6y_$00|12;RJ7lODC%_;b`TG`$K5mp(BaI<^y)jr??+7}tc2<4^X$ z*~iP~Ep2t)lWqRhzpXW;jO2#C?34S`NlhkmR-l3LPgIbixwcXdmSj$O{qe6_C zZgX?h%Q!GCgZZ3oEYN~8Z;dwCzmf1Kb{WGx(Zf;DI^W-s0xz3k6{m|RDz3=~U2RUp z&;wooSKzJositSG)!TO3Q<1_O^@2*^m!5;GhfwzpCkxjsSPTye`Jg1+43ExdiueaCtHIMYfd z1J2*fI-DDA$TfDk%>t0`n#w)iaOHN01a=i)F$Jwk=Kq~t?vuHO?$0}9AX{HgPOdg| z{@44CVnSX_EoGoee=~ln$rOAp-wCw@!rJI}T_Bp%s!8dzT2AlubgWA-Pn%B9byD5# z_?{b2JgNKfS(1h3^qMKlL8F0JbYq@5w;$7o`JPxBt?%75*=Zh%j>8_Jzt#4rR^s*; zVVu&LX*6qgOCzOkty@wtgUC*wHhAMs9oQ`MjBD#s_#C^zva2azQ(yQdO&Wo^uF_NC zj(Thg3?42JOL!pC=KKcGo|s!NJb9ddR4ec&lI8s2T3guI|2ppY0JT`hLJeaA^UU*2 zu2r0$alcF@Cf*UrxzIN5hTi~x1dYB4RB(%`X_%8Vf|^81olSutz`#oGE$M#%3p49w zBX0M}rd`mt))E1fzbF3~F3Joc>KyZOlTo5c?l-bF*0hmMD-#ij@3mAVm3kf8i*zs6 z7;k_r4Ip_Ok|M6iz8JDzqq3hk^$CN>E|ALWM#M7lcO9-6bZ52L{{YkpZhX!dO9yI# zN(upYxk9e=Tg>`1a+GA`Pva^(P3RD!DdJG47^n*iL$!UBJeuQM-GvjD=WYO!@dTmY ze6ueD`wj+C&1y$xgws}hjC=C}wo!y4m4;F~>3k%5Sn-}UfhGU`0m9^2|91-CqJgyb zs_Gd}78E%6Yv5b;gpTCDyl*3WIdsgF#S=+)xI9E_Vkvd|peBSRz1;SgTuZ-)x-{c6 zd3$c~X@&4Q_`5VSw&I_!Mk^nX&7D+7$}QhXOnxU5+X?EEwl~EdiRAWEyOzXk2Km-9 z3yoAvgujje4d-nmABGB= z#&CXTKMYkcjgj4w-0DY|2%dWP%w5zzZ#FD)TNrZ)Q-OUWq~(bqe6dKxsaaL#%gfBj zDw$N61ATMo?CGSE-gyA~2LSJVG;7{to5;3YWg$4o9W3L!v7fq1a3ugnv)s&YwTec! zzZ)S5&4EmGYfBuMs!Yzj?ds$-2Lh6BeKPJ(ky|pcpmm z!BP1DPEKL>8B+%HLbXaxG8^jcMnHBeFgr+Xh~vp)(=0EHp1|4RF1 zZ4t#5AO0-<%fP~(eih^gNynCLClw#P1oQ?Tv7MOHn%jg?cmAFVk=JTRG=&~-4msuEJP@BuXB~_!c>j2S}>G><(^0SjTr^!w?y!P)DqNAd{=js>0n2QZz ztj?shbXy z@xL>AK(arm3&bM+s$*XaL1BHreBdQ&c7qp+_hkmk$0&7F3|>3>yS<7HC`@&Gh^XTE zOe!$f;@kbSKn#oEFKR`dPYa+BynHP{#co}#&0o_r3v1aZ&m<{%d>|EtNB=e=)&Djk z9X{Vi&^34VRd*n=AlXh~t%qd#<;lB5IlqVeb9p~#$!Lqz6$+rUxneoBT9TaJ8S1{D za(tY+<^gV93c>zPbOJz+g2FF@cOP%qIzBv(U>%eNl*AdcKA`%YqbF;tS?5?bs5IJa z$+^6_WeU&_JCarS7!^AGfWibd9(qN-pCG&%7O{K<->CQo1c!pt_NHeETDWV|Mn35H zwD*bJrRvrls@a-asd7ehZ0u>otjqX!Qf#9Cwub-pB1vC&!@Sii_ZPSP@gBKY*JuZl zmYv>ka=m81)6aW@u~GAg*NA99RZM1?z7MV3cu?v&^j!hTb_>fvh;Es>_1m`2g|Ew1 z9ufD+hQ_HBsVXV8DSR02d^l#O80%?SO2?x)uDj))oSbnP2+9;S8zdNaJo|7Mhn+SC!Wf)(X(uDarIO4X<25c3!F z>OSG3y3iL%0f6bz7zjQcu~UuTH}7MxJ-80uYjp;ee!1@w9_loaK0z)@810g0xCSX- zcciA)sbRMcz67|ss!z`X1Eq)1aA$V}8^eNz8W?uRT zM4V82YAzN*MUl+eORnO;C?`k?(XK>sYDyS7DgrJ_TE<2Ep*EeR#8P!>ieKPDHMFC4 z_pv8?UNZ+3--veUxi6|ih4a)ED=gp4@%x4YLTG597J0D=1#O5H$$U zjdD@;-fobSwxK-wS0wGpUw$}UCBT2j%KpzE&0|8O?1gk*biC?dNbvpRGud?gH9xXC z=k6C7$Q)5evhtfH(JaI*#4T|JEONWc;AN1g0G0@t>c9O^`hg9Zat&EkOYBmF^*-}< zWVV&`CsXwbjk&cVcH!^&_$oy8^4jQEa{?CE>snl9%$x~A6`r3DlhxTu=4_Q}Wca_A}f-0O6w z*$Y0dfXBFA00*WViGH<9A(=&So4#DjKf0 zs{C}lI2R|*&z8fVo>p=&G^kf-QGt5H{voz~OC@mDCDX^*pv^Pe6DC%28Lx^PO2w%c zM9F!sm%@kx)JY&AVoZ*JxTAHO!1*BZy^yP_Z!8>yovw%CmiZ$(yo@K4Qm;CmeJE+& zhZYV)%mpOq;sX?oH&r>+HCxtAe@q$GJ*DNZS=9s)>eTufn}o^>fY?%ZT2Z| zgZU{Bopp26@-YD!PuOKVCa_t1hlrC@ys%5%R4>M=5_?C`oAFMsP3>DhFbk}`O=r?b zUvd#a@`$91^4Nib0G^1;3II5R`=?wR_>02q_}f9x^BX(i0b16I3)YZ%Zsq=9wv+dr z-#Z5)C4d|C+;v_&nmkj5cFwNyL1z7jEVN~m#lOR6nLj5?5epCGe5w3&361+r9U|If z+Fa2}C?91IUZ}Oj1xzYQ@FBE!3=zKWO#pZH+cG(fhRbnnv$Q4O@_A!!zzD@JN^%(B z6uD#ttMeB)F-|p-OjdpUdTG5*o%=aFg+M?`nTx6}h8R1BSlKV3)Vq9^605sHSz9WM zJD!dBwyQP+$s%1G_&vDg0MA-h;cYW@h#$SwQ|~*H>Vcg1sv2**9ZuZryTVcn%S7^( zKGNJy<@tfHJ3&8=b%8(g<_ZBp@fA6n9-X&_&b_=O2TP)T9B}8~3)G0L_e*+*MH;qR zZCvZlqKX>Y4)AQCWyE24lgma|WlHLUx>K*CNpkj5J|{ao@uKW*vVxH?fbB$Y<%crU z@N|3lbg90cbp=d>-I^x@5@N^(F2pDP{6alqxp7!>&}3>d&3Rnt3uuZkwF8p_JoZ#N zu>JOXB_e)Nbe*?aUsQ%hz$#fpE2nGkEsrURNdkg|L1Q%36r4Q5p(?}XVIIL=hhXF$ zXhu?}0c1YEpf|I~aX1J}9j)L{Rb{zebt}U3`Q|inZr!rEb<6T522AC3S%<^ZLWL{N z_&tZcVhf%LbL_ibG>8{8OYf1I&8R5a5PkNn-jqioZZbV76^5G)!Q|woi6|SoG~DMU zSE;9H;aYodCu$!~LpF#r4q;{&+w@PxUo|GUcue21;3okXi;}nxBoyb zo$u6K-7=*A1^)XoH#F_yqR8aS}wk0gL9Z5h*3W2pz1 zKjN`=PA|biaZSMmM+>pzGFgnr-q9pAN})UPHA1rD?!1m4TN9A6tsQHeEUpLo5v$xr zizwdYu@EgiZ+|1BS7-MRlKW=NF6r;~@tH=l%`L{Nr7LwysXKlq3(RbR!;3c0n>~0~ zn^_;1T0<3hh37e+j8`7bF)k&&mH5na{nm_l=DQ4l|K`q3Uz)p|6qI2B|~c) z8Uq5}RDDuNTN2C|IKba==v1@=M>(c1g^OpJM$IG?&AAAc-f4cFGa#$?TF{z!U3g)Y z$GA7(E|S+%D6r(AXxPj<)C;68wcU-kyJ(a4jjs4v|)qh>*^g=htr+0@YjOPawG6X#X@fISxO#I2h#*}HCM^ECP0FtAsxQ#%A*8_!~& zT^bQn1|p`ZYtL}%gzL0sIG%3z!@^+mdMW}igS4|3x7pzd;+}Dx<8PGb*l~=rhFJ0| z-G*=}w|>dp#=4ck)N2p#K^ix|-VUS$d$-v=ZKO_FFYP{W0Xf%!pVWo1K6xfx00B27 z){70d@D&E^?w#b{mF)0(%jTehtR1yW`=$gemJy(nu@~UNUtLQp85d)3g0aYIe*A88 zE%DHjDrte!{A_9J9pnDaQ@)eNd7!!FB416U7%Ej+igEatdwqU zb<>01=)t9Ha zZj7~ITM(v%Ksm}gf&iGC=ih~oL6~>r-KnSAZApy@khoz}?@v2gu4~OA+>M^O6Qt8Yvd81Vw z+G6$Z3|8jnLTgUZfui=6x;`6nQVO4^l&dehBm-MCY2arKAApUpA3+$nXdP~m zdMQ;g3;-3O;b#6(j(&v%*!Lqb`n;^WjU!*%HFU|Ei%)TMZxDW6X6X#ltT5f8Zw+m1 z1{L_kga}Q>Un9ET#r|NW?s1>TLP`tls>LgrWu4mjBL#8{>s5{VKjEr*GQ^pOj=Gf| z@$Q)#2DHo_wR4emTW@GC7cXUm%jm7wzhvOyvejm7eWvnk=-r1-%hj_X{qIY(o)dnO zjkd_MDoMBZNo}7+)`z@5y8gfol9W%88>0E*3FI5Hs1_xE{OT7nz5GgzWXGC2$Uu#F zX?Warq8tUVPtcaK91-oOY*o|k@rt$&wz#IVYNbpy6-w3q*;uc=MCRVvH>+bwW{0RP zxZvX}seQ_Fb4VPbKS&*N#l}86m_Jy#dN8CzNU-f#ua8yDaDAZm$X-hNg~j!PMSO>- zWHC1ZT5JQ9@4SFMK?kOo3{eh;&(V}B_C#O6c&|vSnpvO$7ILb$d9P_}rA{v`itaVm zyIR8{KX-x4O?A@xDh?F6Ng51aJU9JpG8jT5o#UbK>j})81(w%VF?GJ9v(QBxP{@b6 z$4Rbij9+}U&Q_a{osK`(pqlIgZ#|^tp?J&79}#OZYKT)lhs>?F*4461h?|g*sazgc zeI^ZYN6*l`3LtL4S8dH9T6vhA!4vwH2x;1#Yi(PIqY)#ljz~FO3evXtNrkJci|@(e zCR3Bj9O|T5iJ+VL4sleB$=KySPbn#6WM=PNbt_*Q(USfO174;%$-PH*=bf>1>p?Mj zhVJAeHdQf0<5cGLZlBt%jT3{{{oXd5AMRZrw92Ge^|!q-jb@}qDpZ#jI$<rv z!Z==dNB=eKd8_#zme?fd2uN5Fr=}1iM!qBk>WsZ*hG!tch{>lZ}>+)$!eoDD-)fL2PQTN|s zP1BoKUuvKQqVbB(r;xq>g;Z*-2#GC}W6#f3x<$;6QJ1UL4M=~i*tEeDWj3_KlbicO z>%jja-Uc$e;=iLa@?0nkX3%QlJ%f}-`3APMH&r&V`s@)BkXX&KW{d!bv-kn9p2NZW z>r+a12bq!Tip9c#W!ouE_Chtf#;+*9;UB=)b3H~|kM){EhfWY*-F(`9)(3?;-skEs zdHSGAb-UJ@m)XX3ReTmFO&g&;D!R6`tgJ8U2^Ual44&%0XBZ_~iw8`G3tcm;PW^2 zj%gIuYTkWKt!a7-G{ZQyWhT12#NqUYK)&zepU!v3WNVyU#fR^=xYHSbAB@cA)z!SR zIfVFTmkP@g9A176AJNuGX@1?N=}OI4&qNwA(pzo|4`@*gumwEp!P=h z)$%&Ic%j=H%ljBP;p3?WOv>b2aI8}F-(-ODiiH81Sy^%`xW=%wu(0esaw0M%fJ?MC zMuX-pp)n?=KI6dU+C*f-b_X`PVS_!TY4|zm=;8f$Xv-( z(87C>G&HGoQ-u)c4c$TQ4qf%nBtM@K;!osFcE36Fb8*|R+z6t1xlSILhP=IqeuY!F zd%zaia+k?Ddw-GbonS0J(K0z#u{>R+@?>np?y++F$f&nM=GM|lo6jxpNOlDTbLY>mhYk)oav2+$bxL!l_s*B;_j zgqVp;PiJd$A)?kV6>cAGBR2WAog$L%+Dx}9ZAi4%N+BzR{B^7iQo5X#)w*O`ojy?S zde+EW^0x?J4ft(QP8<;86P0=*ZKCL`xHOJi2r98ltt$cRyC<|TL8l2tt8E~3bY$h1&2 z7F)dH!xAYdf;EAt@O<_&Jv1)cFi(xG>Huhb)c+?2)$6Bq9J@BFe*g0N;<_@k&30K* zZNo3u6S7vC+5>V_=l|5|SVbShGij7SpJsWNv-*nmC){vhjVBD%t7IBx(%?r9J!LBZ zGGaSJa_%2!*a@F9nic?dns>!rOF#(Scju;13Qus`a>$ChjH4A|Od~-MXA!K>h66DF zTB>?dfmNVARY=2)zCnGUeKo10CHwZev0Ny{U;GEsu^s5-8YS&+|Di3`!NR*OpIA5}c1EOtm#9t}d6Y8jVSq_P-wF+mr#s0?Qq2)-58L+*d9uyn&d-=CzRhm;#hwK->@t&*QAKz?9@bQ!g+UP2=(t(Z6APj`_HXN~M`OzlU5{#&Bf_e$CVGMHnk}SyNzIsqXbi;4 zst0n;5|TiUBcse_V(;W_O*h%L3*&t61#Q_A3%InI)$IB#34PJc_s!hO)pQD1ar%Ro z+B@#?``v%sE{NBU7vAKL?Y^ET5-QCwz1DEg5>-IcrQGACH$klJK7nCx_vCmi@QH5@~IW(T`UQ+jj`^I=?&#yo_7D$<9*it zm8N>xT%F{)3-T1ib8v=%zoet{**RNx8BxzQDGZ8-lTLPc>ZpSRc8E^w2eG~Tv9QqQd9{jrY-lG| zu9slGq^8Eqv~Yt>hsm6awz2G#v=hr`Lv?V|U)x{$OB(uVH0Ku3y`2lfO#g+?*s!oOOOw7&XO?*!C0-2+XJ|TE6`PW$m|Qq*ZoN zfnd@QDgib>nI$q~tAhw$2AVgc8hpCIvur7%_0MQ=d#eCe0HWl)G$R>$NX%l31lM$-OUCiI zAobFkMUtSz`blcyEN4QypPZ6u5YR&^ntuRwAo|~k56M#kRPalW7|EnNv6swl9#=Cc zn*79+a)uBB2u;NHE3GnpMT|T2!^;MhbsfCtw$g%Ky3*mcNLxq3BC!<8>O)}4W^CVc zbCP;0X@Am(h~C=HB^ETgi$k#ifo+}uzN-7Cd3qfst+KqUjKx3Y0)&9pZUbDC#3cPj z1|J3N!kw7awb}o9AvxiFY0gsSw=A6lxh+CXVPO?S)M`|3ursKRZ}x_4mRO{TN_i-0 zu`^Jsyiy^IX);2RH6?CV z^V!JWM!$>J^sMGA1?OAYc1bz_>GMh?67lND6UimM6n?M9n&!HwJ6joV0ezQ$0@C6neN=z_D01Ca0?g98srd9Vl1P~*S3 z$}aiNVC$-wxfexvk z?fCMCBxC5Y1za0Km^DOK+|pL|(|BYgyjzP#z0THD33?H`f8x@pmcaAW34dXDaYa!*o*-F*87G@jN{X zEI=)v4Fc=ps;T}|l{yvQ$>;LaiiNAGs=_aWuo*DP+XxnCaqS3-kUzkwQCnznxF@#F zz|Utm5D%|HPQ3|vH6~-mapcb&>`DLC-G2Zl{{>UJp{>%}dwlTb;{1p8*>!|z4{$Gh znYUWJ%+XF=-I_z~^Ze5%1*#a%jCt;Z^wR!UQ2$JeMNBAk>`RKF=P(a|qH z-P(NrO~&K54*#mZ@}is#U$E1lSPs-i(zq?*3@yWAE5N!uQzce0tE>!YivWy-vR6f) zJ_{U!CR9u)dCc=^90zP0HTEfE!7D16i>VKgoWDpp2<4o%WTYHI^$dB+uo}WS4@%=y z>wDG`c;r zd}Dd~c_ul0r#92KdWgzT%e5VgM<=YRAIK`FFLcH>OI}_c*wCbKyk|*_NkGG#q5lt? zLtA$g54W)fDrYv8VK5VB(f@|iikF=CE(FXSEI7?Hci^Q~1H0OU{B38p~F zPP*>WQB%W9^Atp*O{zb}nO=nsp_y|l?+N^pFq?R~^ALh6Rr@%rNz_!DX;uXrG|Fuy z&kn}xW9WCbGeRX`>rj4U5sAs`jtb~|zXkfYtq6P=O13Hw@r zZ5wQ&;-)--V~fe)rN82XlHmkKHIy{@piJJx#-&W*sc~V2MPQI=_l)X25Wh4sLF&h0 z@`hvL#vKr?^e^JVdCPsZkmOXk^95YYAMJd}JZnm7--~|z4`2#4yluA~Wi)IqecO}e z()h{0!IoU!B|$fpUR{ie0o?~(p{M&zDDx=qV$Yv{nUT9+aKFJWU#)3(I;&aPTcKI# zd0u96SvB0s7HJvRM%7$xAAu4cJ$yB0md)gxovkwc3JdrDMq|!a4ZEk4=ND~%5tZqc zc?x(%PrFDwgeXMXG8M3KEUJdr^9O_&q3k1X3!J?4OPM=LLD1b;4qSEE|L*MH5%JFU z^~9z|dxMNwP0Z`u`(GAQGtQ2(`=+>S+n8Uff75dD>guEKN3r=F*8@Zb?RpSILR5{z z2V^!8ctPGno_XPvhR`|hTG!B&b$q}3$Ep(%tK`^R_`W%zq#U5ut&bG4raZ73(MX=619bWPVER+BH{$Pu(DgPn-6xr@G*VN33_g8o<{Fb2R zuA8F7kde%B{j5({xln9AU-BHQ{NHT#`HL5*+G>|7`l8t%Z_a954gUqgC5(L~Z`X+d z)=lP*KAWyNr$^U&y|=ZCv=54~j>|Omvr3Hm+AMty!BPI1+~xu<2agCvB%-#9lV zh(>4yPW4f)4Qu>$Eh=+L*Z#yloVQ1*H7uEkl078nt%@~IdZb|%#}M#T?*3wybnU_T z=zq`}4GElF(8s)+Z`#2Od@p?6gUA)y>*6W3e(gX1B4BR+VIn8?;PXP<)QCF{73VH7 zy4(=}4G!CVpco_IAT0|qF&n0&pFz3h72PA}sE7diiv`b+#kX#shMm!)rIcJ<6{0b6 zY6`e9y>9DlZm`|Is@MwVaBG10v0r|-$9Rkt9)>SiuCP3Pys8dwWm1ROoGD*csDS~* z0wHpGLDI?_>-KTllYXlwnD{slU)h_#i{b3M+v<|&33D5N;?+dhXNyNlEo9nP?MRv+ zbwK$8-@hp6sJQr3{yU$`{J)abqy?9FTP|p-oZSpnv$ew|L}C)+<9p1K2O8dm_LQen z1i2d^?sEIHKvtoiI-LbLB%c53Y{#L z@)Bb0;#sLZizcV!P5n|HKv@RUv$xoouIJwFrH*9P3`(K z7QKSxX4I`xXoyM`0^TenN3ip(RU!VsDxP3LC$Wev8NqH~!px_IBt^I|iG@+dra;v_ zwAP80(HNf&(|VLiW6?hRwfg0&H#(diT54LOL9YDT z%;Qww%bfk{Wxw&R*s}z%qLHtQWFuxCWQndtxIcMP_%+l)o5`9unzqKcXkIh80TZCC z3Wb=VLsO~Mv``U1^($Lxi61ss1anhv5wkFa(7lm9@oGr+VIqp~a2qbq3rUgVQhlPx zjwWrOiYn@^;Py%4kbfQOzAJn5*LsrvsC&y3$BA^zd#+S1X;8{s*r2}(lpBKXQL6wI zaR2n}kRo+UTl8|auH%|yn3{rYeYAYfMRo{gYl~besI|Le5#>;}PDYmESUE19DG~JO~ z{4Tb8&Ebnzq&Unu0?zdFnLd}}76YRlV}rpQt7Eu`Q3^Jp!Ea(9XBJyo!`KuBEg!K( z`ln{)SV1st)S%U9xKx^9XY3b9+%W^{4vhtGcx;617Fm8+ZTcIY%EbK>!r{`?az)Cc zYK%(6Vr5l8rJ2UP5vJ%*w5%q>3+>Ov_ykWB?yA*eGK}*dkcLLa^6w|LIsejN%SN`k zjHVWLCI;vBg@qKH1x$-L3XltpZ1yYLnGB^}8qSF|lx=n+pO@jNF>ua;wblVovYv;TmIXm`m_M3G-(5xB-@3*P?%iQ1M8}~KgE4Qt+pJCpp~p}SSS*z zFnZhVy2uHyuKn5w5>buY&+?{xgLw!d6%BH}f0b!Dw!`QUnMEb)$;69J_iRLKFAU1&=umy$i0WBH>VM@> zfV6}Z2M>D>hD%z`*s{A>W*d8DWFk>cI|`ag~6`A1aA zU?^SIdHlUk2EyI+jzUE8qaQ!T^M z1y@0FSCkz^JIAW4$)~J&_V?k~2hnSMe;@sNt!y%o)~^Vr;r$OFh+tR<+sS6?5N;$# zO#Gxplz|_6DtS#C7ZB%l@J`l&M&g#2VD4~i;l2Q-Go`}VP`+n?8S*&_O;vU#dGtAc zX*wO%1I2O8Y1A6$zh))pv8jDM@3Qw$6Tb9lWGFQ|KH%kkZer|{gfP=FVOMPGk87nl z!(7u$m9Cdvs5<3zIln!6+*--ZpA33{_@Synb?B39@Rz5}sWA)Wm?!pSKV*5R4%qKJ ztbBQ=G{)05dqk(x$>tt*xESx2RCOzduZ)O;LGv?fCj-QBP9xU%zaMNfpK78l+XFVr zUTz3YzJHussgLn3h&#T6OGBvEYA5|wN_sfrNVsWEwlPqJBdvdScH1O*H!}isa@ZXQ zpsd6=tz`(eI-78U18vQ4jE>cND}n-pUjeFyKfkAhMn~Po<>ze95X;^%axYc>?{S=kV+Aa+J6`L+IGxC;|l&ivL*2&|cYM z09HUoHwpdUZ7z_s2eLeKyH?e5GA0>9L-hjo?L}&<6xQaaY0*BAUs;GbF6&5fIM(xm zNXgKcc_UFYd4YDmvz_s}G#wRz+qUQL5PRG|xx-2b?!KXhllBHysG<5FYO><$X~V7r z5=Ro9Og+G*=t6ewxf5u~FbfmP`e%*jxlTg1mx?EO>e6ImZWf58A*n7MD zMAh9y(x-83#m-U10_7`~Gw61}=(ov7lSv^*hu7 zOyeKG#-?HDU@Tg#Sn792_gCzCRjsCNPQAv5tcVy zYX2h3sn;#1l;B!_wEUlgxJ9m(J*0yJa=n8}tGaYiFPBl>bp}e()=y_ALpy~HX9dWO zN0i#UJNdDNxC3K%+*h@)>-WkQ-CaEDny@kVj$&^{$qnLnM~9}*I|^?-`SD4Eh?!?r z>bsae5WJKX*!*_rFFLG^UZI^6X9??IjiLZy%;JK63t7YXACRVcbdSO*$eKqh0f!lh z#E^Gl6BzE#v@eg3SJtM)zFr{tz>FRafFPt!Oen=rdX_pYqf5g^dCae}nQv(RXLh%{ z4E`=f1t&Gm>+G-k93Eg_YVMR>_V(U~8l1e7t-cq(<#m>pQalY?du8WjG&tV2N4@xa z!V`rMb1890`Lr+pV?uHs(+`Zsn$o+W(Mh+#BWF2zDX2r|No{^QFA62FN*5AEe-eb_ zOKdi?aiUN{a{HKA`=abOMrcnaY3F|;1F95mHw&Y4h`Mn^Xu2eDy}!2XlGzkXrpcJ_ z@k74SIS~p%h?BfAwlUKG0TkKNrhk!D8q+MLzC1=P#Vaz0LX8&3y(b*szHQkum(>K_ zVrU!%AJ>Nl=eyiQTdA6)vU0S?BUtn{1g4po=YTs zk79o+_e!mr79&qU)($*V1Mb9n=*VWM`4>w0HV%v!I+JpI_^Br54UdZ_T=oP*>mR^X zi!|u^A+Zt}a!X?JXCt(os=4^Ed@E}{Ij*}xnf%J6>x)K2eiS_nL4C$06D z6fGJnw8~)~p6cdqqfErbX#MDMGg^~zbLR2t?5OKtcABNm6{CLuasOIMh@22a9a~cY zoARpH9F>~X1We@z$Zf?0kF1xo6J<_uB2Jzkq_)jGEHyZ)>liJB=Issqo=)0tNa!jl zqtbc8P?GxtIOT6#N4n(5IfPBOBcby8@g4F^hk$D^u%RKxGF7zi!{ry8wy}^qU#+P| zB1b|$SJOALtbE#m68}GF48r|LexnHa^=Uq?Rv1HUI(uKQ}8jY-3(06@QF( zZ5H7Eg=wS{Xz>ZIx8mjiq+&~(Cu7#!wa6&e- znoFbco6hWQmoG{-HZPd=+_Gh6_B)puqF->I(j2m1y5wuykkK5<>ov(3fETGz>^Tgg zqa;z10{fSfXa4|tFlh#MaKsQ68V|BA$>viY_ASNm_SiB9qkhoamNxWbz?h@M2u$tm zvuIjAmX-qCx#R>I2yM0QcQbVD>3a@1*O%{d+Qr%R4EO0}I=T?UNP$A#s*>gQt*VApKeLt^Ew0ZRrDXS~OA zL=NQq(hR?4_%S5X#?+a=`p{V7AQfz*d@JEaLq2v-j1gw{WFM(ln^%0TJI6_xB{y_@sRgOW+(5V|Y4eyL` zo}|+H^O_fJj=4<#0A4)i>T?;8$>I(;*hFjvzb~6PO=F`VwJhMGD7E^Ma#dhHA%;=2 z44)Lb%v*c4KyTcC)xBIgt9x{LAzto8#4gx+#QC1va~wzCHUAZRVMUM8Tw02mm*|3N znm3L6V}3~Ed|q22D_QwVP|H%U6ZLStO9+sCFMH7zao!(i-N~7dX2l5aO|lXiiQp9@ z$IVrb0$y=AFD6o_+RTV{i>a(Tt^{|!u@FLj*%$DY-mUeyhyXyDwwp&~Z<0m)e(8(NC?-BCP?SJ6M@4u8b|C-g8Eoaqi zsbLwagpDWC!fazX=cS83gK;?hOOrnP`j0sSbqvWM>qQ@&zrnr%yv`aVYUubBrI|voN?gA zK7r4JtCtW`Wd+4$hLIS?KWR2=S!XMnnh;jbYgB2ly-G&Q?us@t*%lUAO(kMXyZey2 znC8vu#Ljt0s)M8N3{Ew!IV6wt zi~t5LD)Kuf90@+5A>vW**K>dQFnz~+5OoOH^6pq%2k}foS3W4mnI-Hxa=G_a*a3-g zQ-C_f!9yfbB8l9o*8dM@ZyDEi&~=MKfnqH##l1MR6btTzP%OCCa3@%S;#M4j7Plb9 z3M9A`cMb0D&=&XJ^m)(w-gCa4d%yD=Ci}nlnmsdX*2-95+_Fp;>_qO62q<6ndZMmg zjuoyyIEQyXry|vQ8|Yj=;;!EJjhwPnJ@4Cd(V`iW*0oZAlI%}W7Dn1gj~@oSCmr#K zMv2llR%}d^oSgk{Q^5f2*O};vQ<;gwQz9~{0*#Dv(e9s=IRZcAz zTCmrb6g=m~TKC+6KXk;Xyq+hdkvQ-CqGFu{tDLG(M^rmn!0C}6f2Y?vQhP5f?@X=Q zId^^c@o)r3Y|Tr=+3ek$+Uj#ev6<$-&O9X}FFa+Z?Ey7^HN?bM90fPgb5Z^SZS?^ z#eV+wTvyIRbxcz7l47zEGwUr-@f3URk4(UX9Z!Aaa8SW$kCNiMky?-z_L11*vfyzm+C7t&r1JavTJ!i*O6R43Y}G~;uvZ03 z+A#phPsaDm`Z@FQ?er7(!L6e`y$0g!HjqUzn`+XOWwYWhEma%s4pk;DO^_~vOAj5T zM+A~7puCNu$hYYfK}G`2e{lbfl8rRs8MlvFIK=|2h@F0&H`j^m|H zhYs)^6K}qqoi1MHMs4{zx&NZAZB5IXZ%C9Clg`2l_lv(F1st{QfAHB%C6eglgnUv1iq)3QG{eul#Oj3e;0L7Z+un)!uL0)cFkYOVKB z8{J$3rs%-EoK0%?W35ds?&m2}WzW1cnk5+p5f#9O0XZ4WT{OT@ypXZ8@z+!WHj}q% zS}?QfqV3}2rn-Th1*l1~xP4|ZG^7m|=qT?Sgdd?|{Had8r);vc+M=BmW%2Aa_AvVG zFPb4WD!0x@6bk2f_ov3wj~&qo*j^?Ui%{DBTHc^zjL;d6!Ta zh;vTa9JL1}BX9^TK;q75J1S3NCV!}?M$iFoZ1U#{@9Mn=!}p>;J&@QEcjEW$BT*(`$RHXT;0M*1U<4Ch-*6W_#<`p%}JFN4!4s9@LAg{#x zTO>b2LwNTfyd^v}t2T``ix3s3zAfr)^Xyc4of#h?Q^ClQt9 ztWKyYBRP#+wsjMt4AoYN$?y}fjO$=EXJ{OVMlBA{*D9E&wNKr(BZb5(9Y zFB$AR;?L@DU&(O)Y3f`ru7;cdS;y^@vQN;ob*e447EcU;#;T+oC^PQ735m`w+{!ke zcJGR10nMb3&pS3b%uyJZw$MofP%u2Z^>SW(c=;?W0%+Z!;{GEUkc83x@qs#OCtR^Z zNabq4c1KzUrLHhk?6Ci*By&XCQSEl2AF>{91XXtgM>cwV?m%Uc)Tj2;P=$uZ@5bwe zs+bvm-`dO+H?<7Q<68Jhj6dSPsnlYkTrzat3Vo|I^OMUEJ0FZ-bHmrVA~H1S-$`5r z3N}qc19mAj%S8w)qvu55&U_9#IS{Br__DtRjyXucpiX_<8Lqxh9!QB}KB%g^SbB3t_ae8KC>*vR_zw=hdK0+swq$EhN-*(a)TT^__vL6o&dpo1_Os(@@$%~g7Bv?tBg>~5 z9%k7Hnm3-!!A-HBAcnf5suOcZRG6^t`nk(ka^4ppWUY4%Rz?Z@p*7>3b?A~n>LxoX zk2E`TWF(r^8`!Z+M49shr{g-f@RjEYk~o19DC@O~>jH?Aj17|y+<3>N5_%$hC)xJq zYQVl`YXC|0b;5mQkkf|i3$FzyIEbjC6#RoQn{0`=%B{H`f4Rw_^4PJ_gr{CK`kh7F z5ah!EL~IHfs>0>)0p5T@Vnsf72)N=W^HGq^2P1{DQ4QmWzi1`4DD1etJz%r?VQiA% z0a|MCRrmObH3;0Ega4~0fTTu=r><4e=LEj1?sgwi!LAATa;NDGs$5vWZz0+>4x_^1 z!NXf@xbLj<=T#$Fg*`E$SQ_cJ)4lLzwiD97njH}tHy8vv zj-nq1jaOVzvByU+$=e)D(pzi14pLHady6V_V@j3R69*neNgWiJ+@9 zh&)d<0Z%M&iyO?v6Zr}iv$DJ3=Ne}~fdJalVinQAB8N|mer|Tx`Dt#lHHQvN7Sq)k z&3%r4up(N6PEI4gaRa&R<49TgPwc~s3%%0mT>c@lavoHM;DbbM zzc)&v@`vi3g4>8-L*B0%X{oy1_CxCL!9f!8Io`Rd&I%0waOv@3vcgzPi0ix6sE!c)R%n3|7=)Z>? zle}$Khz_zQU`3Jfo1!#8mScbszEG5HDC|XriBoM_bUoS@tqYc|oa+<}^Y(kwT5Qow zi&933ZW;XeJ6$@GL#}?A$GdX(by;-CmJ|_#Lt-_;o2C~GbHosR88P>T0;M!3V)v_% zaJTo*(Ld|Q&jgISleA4!>a)dbe7m1*9LKuA;~^h+IcU9_*(W873n4I9$vHZ-@5K?+ zWf3T4pA-iw7`!sQl|}2Vs>dbmjEJQpXGlPtc-oou2Q@fSJOvchpv4OVxO5j44`5A~ zBteIt;5^Rt>`3ooiC;$0wmm5Fr+Y6Uog*oo#fz0?S0T_!#SSDNMB?^Jo1OGU)4l^I zYOe^>wOe(1sxT`=U)&)3b=VvRa_KyjMJ5FH7rz*j3d(C!;js{nW&jerV|%l&OXy0^ zr3Y*@@u^0gL3`)Yl4pDu4a{RXsPHeMEVfX0pO%Xu)HGorkX;hTPF;MO>EOuDJy+-m z(utYV0&8<1z5OsQcc<#D$nitYV^TReUZA{!1u(Ll6aKZ*P&L)H&;fov#^@7zG9<4G zb~nGc*cm{u#V06}2i3D?`5Ksi~L%7Y!7TnSTC~v@|64OQRcbH@TRj zXNZ8AY4JGwJUwViu<(}csh}HaU_z+Xx>f0jaVR`H_shrH`Ql0}l3a!L1MW|rhl!DI zPg9NKqK&smghMaTTVh)ue441si<}4VZeZ^|Cw|=YE3XH(m4@k38G$4Udm_haKGxKK zOeLD}GfIL0dwMX@OB{322TIyq+>TMBV-IL=5!0!ZRKyvl;VPWn+~POrw#gAp z4cRD{`FcS#z|Lp`WYgVtYB^siURJ2B@TVC5*y(Hd+0YGdssA|eVSLjL$0a{Bx;R}2 zhoyvZs#rVl#163i0I5e2Q&G$;IWGtUo4g(+CTaL@w=2T)LSAk>-5u-jRwva&`-Fvl z_nzd2jUVGw;3Rc4)TS;Tw&3^RWXl?s^lk0C+qAdv4gOD^R2@LrpB&Y+TV(&)Q&66q{s}u-o!OG)SVCe-{|gj{_mA7JQhm$JPZ(Q8 z8Bo%b?KH?W1Y6_OvM>m-@fVG-+{DmQYFW4R{5(Xa!LSfmZ89}m`X!5e zV|R1c=PI8qQ4B|EYcb%~_v?WTarG!tetWrTZg~-Ft&r|TvExq&wtg3SnVb5$=4t09A!(H^YAzQXMG)dj0=5XO?C!$Delk7*E5Bt1@cUi;#^8Wo2p zetJZ*rfqWAY{jL#YucVfj0O#%Fms!4+EpGG0A`+kB#SYtN415LZzJ(CP+O5};gCa1 zE)W#JsmYiC_SH#>dR7p4k>&50?tX;K4(@|-XJGks8S5s7d%G^NnmVO=3A`L`9BEKR zNQGMrB{Mm-Yy?r`sOudBX~sVRlO#p6;n_Me{(0c;emcm;} z0z&x-mEndwmTc^Sx0ht>%lN;0U7YO+-d$ySr%n?^jv~7pgse8?o33q5f#=d)#pxrR}4#+ShU9$yKl@nBDEDO^f5S4T{&1&!(&08k(`KkQtAQrDZWnKO zbI4*^$?r{swv#~766jmffpf02M~N$t>6cPH46X#NwO-`*{P3jXiDZ+Aol{ahz5^o@ z8;ExsB#tUobq%Am5cbZX1=nG`0EP3*+&ZC;(Ot)CY`B~T6gT)PgRx#={VWXRvJDzt zrhv}U8nyx*Tf5zhN`jm^X5Z3@6Zh{_U-}}0!em{a%GHbQn3zpDvRjwQgYwulx+U0Qxv9s3hqygpN>4?RNBO&J3SH zvarRDNP|e)RZ*~TDTA&{p=f-lML|gR`0fjda4~2{+752=YeCjIvOXCv?WFA6FUUF;r-OI!#7S(Y zc1RtYg)ObmNFOB1D4tLpi%Wm?P-m9p`W@jRt~fb7?6$Dw;V1&QCKQGFs)|D$Mncv$ z@%3B-7Fmx&IW>79;Ca4^`g+4s*vz|SFp_8Yf9@XvUfFUU)dKjeoLtqDNUg$Ee@r%^Vp z?gC5?(j}sPF}$9ZTMf0xPcXAbF*B2Rv!WK@_0emmnwOCoKwMP<(pVM2WmqT5T;W_g zlLhtUt0=#md>3CZv>Cp0$QRG25Kldefe{q*r25^)k=$UmB(09b?C;%ms=pT+>}%Q{>X zTACVtT{ zU~ZACGq?_inIge_BF%Q$?s)4Y_QuBBbG6JWwmMcpdJ~|_mM-%=8JIjo2ZvRwE6O1% zJl%rYw=DT&pK0FJ(bZ}Y(Uxkdn#?pn*p!J77=n zr6ie1;bC8L{(JL&jFJhmPNVgGH}6&(=Y{m@fr&E*0(^ zYUwgv0RJ%ei!pCTCzMT1s(KhAs@VY)5@|2QFUq3obyQ`zOG@{`(FlEEN-W8<^KH_| zaT<2ayG%+jLY(%xD`g*~C2x(ZqQ$$du*rG_wWIcUuyay3-t4!v;fO>!qC3UI-F8Ht z_G=yvL!>&njOU91jN0l6a_VV_Ou{3*IQ8tW1$x8=zvIFdJVSo99C{aMzXLf4KLG4W zkNM(Uk6-yX34MizDV^qsn(dklMRkgh!gaQnWgV`1yVl?I6PY^E@AfZePt^YQk=RT% z%fkL#YS|qdlujq-d(o$kecAf!wzou1(V|<5#%7e!_G@~=vRbKwLy}yadnm=!zU^MO zikT-JBDqFqWfr1>Qt)Qu>fhFu)bd9(!ub9eDl88LvK3y&zjFW_O+D2s>eQ4r&qt%Z zbuA5$b3yJDsoA1UQjW*VUJ2^~JTJNT6-u@EYu+3KH$C^Q*Rxf7b-V(IJIQLA z`~&SIQ+miMU}H>zW+o&wvtZ&mtoufK5;Eco4Sl7IdO(EH#5|#f7dRV-gt*}l7ZkA2 z{wSX=u4d21eupP6cufe6(EO4hZkbmn;?^RXCrvQu@X4V~E>>bWVGNZ_oG6Lou{?4^ zf)}gIE~vd@ca${s#ajS%;3fFTeV^l09LGLzzSCxwIhCkW{o*~nox2?XT&w>)m(aZ` zfFO~Ew(&38z_;Sq5x}1K-S;nHs10iD!r7}qV(Ezts!4LE_(ZrU0ib^NQc?pH{wG!G zO;4F(jJvbO_;vyqsTitWzGnb4opVlx-tEmCLpve-3VM5>yj(ah6@oDbH-dz%rss-p@{N1Tx`-F#Ad2_6Y7ec4qWgG;`&&KMy4+IS(`5zsN1+180S{W zl8Tb^p868sz(r5_d-S4L$R%Pe#xQ8Gs7sh$s$cC#S zt7l)KY%dmz5%?y^IGmUDCM0H_`+YQf?Ern8<|_ck?=TA=5_DEVN6vgrm1*IhGP_Tm zOsvj<4^#P|+DKX{|F2?Q8n$;%qzL+Ky>IeEq0cJ>A`+0iUGSkrX0gZeq$dly7ZKWN z9YztE3n(4;{g6d|%AtxKAFY{19YFGQ6iRX=zp@u zk~yj|GbGzz0KU#@EZ~_HvPQqx31TAz8}*hph#6;tONfbHJH-Q06nIG1HwK*d@#wqJ z$9nXV=SKdmCT-ILkLrjn;MKA#-O8@qU$ly34P)(f85z+yzrZ&dJ(l9G^-yKNYxMWz-Ya96;2a%^_IJqV0Id}$=T4qnq*3D4X%~bi-4W2V11h*K|D7c zd9N%ZI|QxhY-Q8A`zmXjQ`EV5=u4`^L(OTYf(8HAn{cfM$jSGp0wK&S{HHw2z>!Mh zI_t^P7k=JGTCw4h!Vg$tM1)1z3b!f;tmG92%ZFqrt|P|-}vL;)fW+b6wB z5bta7>WJ!I`(s@jsqYVl6z+P)gkO=zu{#@aR_vUc*1vP5-n*O)p6x-MDS-;pneWz$ z@pQD3&})t29rDW~ai8yakt1mqCI(qQFoxIh96HT&nGa zIodCXE@>s#$y0Nr3_JVku==|@lnB&yb`I4Y978$NcJ+@?@o`4Z$bPXpaB9Vh@wH7| z(#`$Y1baiM<5{W*tAtY(VTh!=$uoSQr!+ zJm%7P?@{(*5aR4*eo?HeG9BP=Qz31?B>h-rII+(;nIe-bOR=}C^vZ`7+0;mI`-Gk9 zLE~4ti(1j*f>*Rm;kOe^%y3o*Cev^MNO|-2Na9uU|hEN zf!a$zP|I|zie%u@D{Kh@^JvIGa@m|8mrZqH(WW1l3QZ-BMBls7gguN=A*<_jolG)DNjmjqmrs9vt?7yKjL55ADzt3o9%47i0f&q0W5p%&H>zvepZk;DU<3im8ZBb_E93+?Jn$l4gEDHMh#x#&akwy zucr)PK2AJ&TUk8K$L8$!R==rDZ%TbBPkz1pU*%PYNWIr?WBv5+q`Oq-oJ2x=1id5Y ze=l7y#}e?C4<`q((~|XBy?9yM_q*?e?3^4Lu&ADZVZtGD(?7L?vwI1@<@&6rXy32Z;~jbUB%iR=NQ9*vK`ktt^01yQ zQ~ZFY9ikq>{-A_`vQn-}KN=PJ5V42nP;SQvU7TIr%$|E)1>%v!QfNG(I)TO)BUz$IC;@exHBt zZ>stW@#p_VyIr_eyZq^AP`UIi)RtRo`}SGYqp5_0MkxAOpOMSeUe%r&lg~_3)xcrM zc=-(em#C~xV7i`B^pLGf4`$JcPCijGT`6Yf`zLm=mW0p6-Sn?+0M=$KD@W1yK{w=EeS}C`S)gLklF1oPpvs#i99)8d1-WJd zTY#R@(j=pR*Xl$CvPjT2%1}9VlPC zMsP^m)UnaKFr>3L)Mn4qczIx?xFjwKIJ*S%6ji(pZM5N#Bg;4M-Fm8W+r;tQCZPN++u;EF%e-upN_7UO`W3#Z9h0y zQ}SG{wY!nehiJH{aGe=at@xnB9hO{!lQD}iJl1}*+Kzs%H3E+DEd8r!rva`en% zHIzbv6Mr{R+f7<)dt1(g=BY5Vm?XVY&gUSMa`_*SFRFhx)upZc66tXKmNINYawLzg zz)QTDps|m~ZD5Rt%0jRy^ltydNaW&)&%ko5;W71gI!1p&nae}be}!J#Oh40XhL+?M zGAp6@5PmHy;yJ$Nk#-UjSZ+`bszapR$Y$Jg4S1%{<4c;9Q<(F$ zusG$8aqMv+_(6*6Nya4Yms=jAUn=wNZE2?->k`dUdG$(7i>q(&E#@YvRV#S%Je>=- z@l`qlSVS4AJ@2R5qW+>C+O3N$qThUM@*EIiMDd&5Q2o)|(<~Hw)!rL%S=*DEu^x{oNyP@(Gr+PZf43qu}*M-saSP{nZ%HT`s`?_G7$ZL+ZJ4`qz#3|A2Ig3X%jm!R>eMcTs0g zUV`8+B^=QCjExJiiEHp3SWIRfSAC|5=|j<(O}qm(oc;$te){jCq7dKQU6sFm(yg4j zb=aB6_ImX>%QD$I5S-2}z37)4LeRQfrFD*3`2MuW%RsNRj^5ymvlZo)$1+Z<@(-*3 zqRq^9I@MvE_ShwM|H{8S@-+4tXb$O@i_eAm3IBQzW(!mh!WBxa@PM&eFqA8^z#+$3n$9eEK3{ zSN;R{Hfm9K8cy`Y|89u}8J}e*VXAZAW~?gqsK6Ihvp*4WzVr!1XPOrW>VFu{%>36R z=y{2I^_HWwK8^h58}C*&i|F+cvCMc!jU{yI6b;q8XX zag$B5C-|J5pt?|QsYn$~yj~=mt$HaZx^R@%PmHXA4its$e71+jXCX8p=UVX}?YRX- zdzO`<8u)pa^hDIjENLTj@Yze^`UxIY?ZO-bUKWhmbhGR%4#QqO{~;>lFiXW})HP7{_7BCc zlB$Jv9Xkf`HsPrf8k=-<3N(E-phIxJamp-(@KA%!aJWw#flMdn{jbRc6b6 zEc4<=alh&n7Sk$zo2j-X&v#KDB9ny3wMlADTZg?am%%fOpE+Czwm7wE{1Y>T8+q|P z$~}0j7qX)6HJ1cf1-pzKnz=q*=Kb`H9pJxQR4#lXE+wnWU1siwI~u&v_I1P9b$Q}! z2ly7V<}lmS?i)73Vl96-tYy3C&XV?Mwt6RM(X7WotD`W*kAJ^URGTzPEQv<4`qJ3F zHvpm?;o=yUVF4G8o!-^kfG*I;Tl7@e$bofaUiq_Ev5UuHp6DM|Ahiwn;tp^quAypW zZ!?Ut{Ww1J*{4$S$wOh%i{uh#W!x^GT=boh_G?xYR1<2yFE@K6`HsJjmn8Byc2Cs2 zfOhvM8YR+!^_mO5`a+F3+~G{2ynOT{GfC*!vzUddl~P(utcZO(zcP;p*94SIbLmGx zI!Q>Xi}JVf`d7_ZX@^OJpBgZnID4TfCPqZ-pp=kOy~s_aw3*bqlslUR-5~I3{!u#MV z9ARcVXu`#3e;coN^o9Hr)$U~3A$!tj)wH)?AGfm2D7mdq>*M2b${P>*mzA3ivDEd= zLY?=$4&Sw%FcAU$7V`L@$e)aq#`TyD1-vm1MGi}9lhyD#xcAy!b@s%mX?ExK>-oQE z=0$s9QzW^e45OP6Sq)~-=k<!g{)rPcD}4Ta)LQnv^Px#|CH$}!wjepsY-~9IUv_wCcT7WmDzDp_q%%C0Tbf9X)i-d3o%Swe#p0L2AxZ(TOxpF|uKV)s5>R*owv} zHly&3a&O}Ty}uuNwHsGRsC-<`celTE)Nclrw<7xLLB^^PQR1T{VKgp0ZyLFyPs6A2 z^s+WB=oZ+V?Q6Z1I$GYnw7Ia+FHi}u&@HUl>P~8zu(_xgYAq3uFQBttkm(Ex`=y*U zIFF~k=A90Ec_YU3pjeEcbuepy@-#Jh6nH)RN%OJ?8vY0CeS^z<#TvW`x0m7xwl%Qn z+fH0ug=xs5Fv_{)zid1#0FoCqEu8Nm{khZ+$K4Xcca<8U1Ao!_3Rb41|Aa0cC;ml? zGa9X#EH#uvNM>?MBt6@yk!(xl(+xS~<&IgoIoizzsM}R(T})Fvz1Dk5+qN{Xb6BDZ zjFqLt4g}yI$kligzz=`fvR`)|U;Z1oD9xzq?aMpJmjiK4hndX~{xKtT1N>2flh6G( zHbbjLNxLZjx1;-}9BI2$o`=*>Ag4b!AzK#JHd9xI$JgoGL~utqspjGd2ZU^`SX|B| zDy|IH9av*D#u}VdoGtL2<^kwP>Q{MhcIQrWgYbA+Fx_OP)*AAWzlG$BA6cPWm-96S)3ugz&O-Tr}r4eu@3T^t$!(fd9-^*7BBQi8qI8 zR<}=zm&Lr4=Yz=CWun`0!b=e_Y2x9_=7QCfBy@!XJLQ7evpbXaeQnF^>GY2hBIB3& z2;nNJv>)U`xgOtDBeB=rI2q%#Fg0miQBx!%@Xx5HY+F`*bO2gB;5t$uAoX4MOAU3} zZ0azDl}{E-9Q}Q}PV|UnY{PxQ0Nv7KG$O)FS9!)DB)qgodOH*n$_fX;--vC-v!fWjoW4ypW`W~ohgRA=beGWE{jpi$`1=M_Y2L|c4{2z z6QvbYqG(=sCa2C)&3(!5?IgJhLw$B@k6E90x*A9^m_A6lVdL-rMa$#uT!cj~x_HK# z7}*bn4Gqfi69<8H0?G+Tm!EopQEiI+?>vb*pVsc_w!*jeycbZEu(ao65>S{ z{Ims~(5I6)jF~|=EZEq|;@pNduPP#^E<-XmpSl`83ZZwF|BHd-mt@CxwAT$J!@#jn zpK2Nx?WoU08X0bMX?^hP$$$UIIpe}}<7%;Fb)>Ai;9yxmh-aVv+QBy?{-bd6&87vL z3PhHXZjKd;ou#S}5f*n=G*vtE-fY#&y7n-{j~OxvKk@!awG{)Rn2HVyuuEL6Z8@e`jPA9 zx;vPeSPoDBiZeA6+?@8rRRLukSo1qqG~t~bdnk(Z-si|~McZEW+CKwK<20VUZa$x? zq~FKK$10zaLZs~#ll-Jh-TcvG2eMB8Q-ZsRpmtJW?I1&%Dd*_2={-ZuZ^nDKd8_Gk zi*NO?#u5h`Rb+hKK>7+rj_?Nned_B*E-I>>M3fKf?rnSvDp&u7UIdk^kXw=#o=}0A zPSNci1TJ){GqUP+gbeYDnewhIQCsus}3sq|6O^gUvuOuUM4u@!>adgO0Q@pqzs}j zl&if@I>z;TS6$xFMk4N7%^D!ekdwaSz2i03 zQs8vp{AgzYirkEcdb%@lG5U2Q^JdaD#C^}^@BM2R?rozm9Ltb@Hus~32D03=95F)! znu7;bx&8ckeYuUel+{mqK3}VwOxM0uWH89Gv!fi>W!JQ=s;=&PRXAP z0HT`=NHl6!wM(*$J(3wdyvtem^MC*f`z(Y%zWT3uea8w6=ex2@7CXRD7a&pWSkq1E z*pX|zciTk8_nbO=)XVMc(vQEgXwjo$@_6}Vv`T9M8lEzkp`RlZ8Zd{A?J4z%wj?WX zab@^_5M3uO*%Mk6eF`1dtDq^n5H1O%Ab%w9Ky+r4wIPvl(Nd`-PY1XGxY&%Yy|PVV zwUcQ}?!3A5^7LP3wULL-`&F8@Bd?ih-KtBD)rrMu3SZhOgy24hR)Y4Psz_l7Q4jzg z3q^2I_W_RlzD@th8F}YSS6YvaEB<>SN)#-QwM%kdEToTPd+zSEQwNuyr-337Lb(oG z{?bB2i~Eq$8oYM{A_I0xUZTGbHuD8z3#O3kLsRO|q-BnTyXC^xPpf>s89?I|HHi|WTH2||h z&s1LDfsIqz_5ArN7CX&1%{Jr6M@fV{=0uQ%<0ZtC0hgd}qJvHBilss{aF%{7F2(g` zb9X!JjkM17H7m+na|5+-fieB&=_j7^=@ZsrEffS-R^4NWBSif zRNyoDC`SI}uN{i&yyx-%pcd+KEG5xge#pz-z<3ZP!+L(UQ+w~Eb;Fr2T#jVXUShpl zLxg1pK8N#<8FPZ6ThPMbX3PLMRP0v1TPGN$s8{;D(`kA&YSpp8U${`DDv!Oh%ngIH z4dCKnE;0D3dHCb2VldRdx;bzRuJ0OSRrnX}?PZ(+>B9Evr5P9e`4Ml~F~_KKE%F#1uIN8Fjx`ya$@zP60qEaZ=Wau~vsIfSLb+*lg{E{Q$qApTS4WA(^l3Z%HzF(jR&VT!x|| zh%Hh`P~f~zFoHL5e>}XcyaijG3SE~zIPUpXuhpKR|7jj!`OQ*sTHTh$NWQi{_gjUx z&5;om3XX<74`;ia+HC!U(POmopBHw_NyC-$&0|qLxxbrt1|A zLW@27#*o#t{X;SY8E{K<IdaNKhghd=DJGd-8us#~giowQ&ruV@lnv^7HEZBrCV1J9&xdG2EgcP|_LCyQEzP^jx5>GlO6bZe?KdA7N`2HmlNS#tC|Js&iUd|Iq)jmx?Ii9TFa&8si*r- z_6-zvh@!9qk5CBpiBT$tyJ@Q)?SoTC@f-ty%aF z^0L1mXPnIy)iqx~2|;>4o%U>P#eX}$Zdf3C+|ylQ-}~WN9tek1X(OdW9Q;(}CmrYA z|K1gc!6&^KZKI_5+H?MsyyOYx@X9y8vPU5%kncj*nj(*s2Wf&62#ekwAf46aaJ0&)=@p2mMx8cYp!jUF)d~*h@Ii7X|$-{L^_MmrcvS4sn< zSF1rdrs)*~vWcPAYFjdRg`fA#6toTp^W3XNQa$L>Hu$3FdwVuH##RBnjRL9-nXyH+@Y%*ji@Cja-__yRxgbgQ0f2# zvj``%X&Ye@#p6gNbL-VinuNDSDZdH4xvA>SrD2|9;ny*t);Uajf~mNr@tL-C9zcaR z`t&Kb?AVKeVyFLJY&0Gv-*iuVzqj=XNwyU?uyJO}UpJju0Wh;~nw#|4g) zNrHOeB?^_pQ^pBO;pXUn(fI8Clwdg@9m%?=3vs!Is&IClF1vk+)S|kW+={l0?`)sv zbL1?u*m#D>6HiKEW$H}2j)yt}E@1lrvi~0^lhh+*Pb)%5)a{titWu4x0+q0hh?Ru5 zwBYDRRXRFa>~VO)aRh!shfiYR*7UE$Hn(zFzqtRhF2Lw4jKj`E6X3x8{j&A_XFY3< zQ%#(n_k{!|hs)$-D&--u@AaIsGY@C5LtoI7GyVx2*Ds8IhBt~GYWY80gcc5Wp%VnZ zvz|;Y)rI$h`nRTU)G6v&Hm`EPClfP+rU3!-FXdGCj2Uw+-s#9C>}>@-ow!XuQYH7-x;cK>Y;QQpDKB6(%}}Fl6Q_sb~R2qiiw9$RGeCh%uB7e z0e!qhus#ul66Dgxx)Zmv3Vgx>U3IzBOb?Va>;P#q|9sbucqJP1y`h~(*||O@eP`;> zE=pPxL7X9;(oBn{M01O1?VEk6-h(Op4xLHWOWBqLnKA|N{NvYHN+H@~QF1qFxyFwE zd3XM7Oxlu**!|RZz2{78YAWcAUGN^WLwZM=2C1RczZUIJOh48Q#dTZU z;L1&nd*NG)f;|c=@PXh!PJPgqDagf>iX*4$KBu#La&xuSeO$E<(r6GaG^+;Jj$YjF z@V!|I0JWW-wU6)MJhzi=*DMwqNH?j3tPW3y0EaOM=Y{0?ml}N>`!&D9wgW%f#S`kt zJxA?yZygc#B(~aD0=J8*Fb;II5>_i~TrRwy81acV2o4#j+-#g1d#sf+_UOuE4pCtW zw|(nttBB$wYO&QPi%!;WsNcN#5yI$6SbG1Ut|C;X(cktJLbMz!FkXs;yj^Y?PW61| zVU@>f)n3K3M!m*|ml(3}%WU~N6@78EHr1uxwhvKY*}G-kZ#l{{TePmM<6aliBp1NxSa<)g5o`2g@AibMxP`>if;BvhZQ^$B5?WEm5#HUm{Gke zh-dky+D;K3EPiX6sVB+MH|n0ap4(;)3iF>ru_S+ZoygV9k7`&A?T+9mzT4(5L-b_z zRxHTBYcG`O0@|wSHO44KUuCvCDtsIw^w=}{GIx2Xorg{kPmGvpJZUVa#HBPA#7_!K zrJHwI^i|`z1%jctvKK)>AU?qe^9|w12-DjZRlLF(2yc1OaublOb|I<#ex_htid% zU)WqbDeE?dJVy$L*3Yv(E3RcU_cY%u7E{iL3)P0dX8k!qD~>Q?8TPODeZ5=q%j^{{ zm#ip8yt*?sBNoY4_ypto65HmlSSH86y-q~??6{ko7q7XX8?kM(Gi@A8`j#``KvNEO*)D2t%+ZMzunz zC~G3QJyfkUsc_CBdqUoEn5-oDH*!_W3}B0YnYn(tik$W2)wWvUxpZ-sS8Lc3-dXz8 z8?o}>G1&y}xH3t9HG-2AJE+8)Hfa5Vn{zzZ zis0T1S?dfe13cN{`S1kpn&Jw z9vEu5`LSg>F#6KUlZW>7F!t!1IWr6?cJ)qWQ@|v(!lEB;a)Gt-GfS-GPsryOh1j8( zw$QLUzwzXfDxXMMe08E|^JV=>-|-(GrlXfk&{%VR10?;6HMyioWsP`mNA-!;oma+Z z3es0UK6JcEUf^X#^Ri#S#RYOxsFyKANyq!^`vWssSw-X5(LtLc2Ul3w{8`GfIj3E8bh2Q3 zDQx_SjvSI{t+%B4(2;cS*woKGl}{v!6#&ipfc329U_nJY2IYW20f9$nvdMqzwHrlD z{Ah@>rl7OQt*AHP^b#OitS8USn+hU)cO$x(s(f=RHzB(+*uibhmX;1`28UbNIK%{f%?v$329Hf!%kZvT0?h=8a zQ|TT;y1TmszsL7|&pE&E`|Esva$U?b``LT1b>Fl1eXmtc2LgfIRH;XGUAFZQahdXV zyebouPl=KkgPCJb89-hxa<@D-nV!Cly*66=jii~RG2-vJD#@cL@^v?c9d!*Odrg91 z+%$<-VCSZtgUp5f)C=e^7t>?<8x`Z5BG_gFS|V@ zbLI#8eH`SSQLu$2-lIG+9mlYt{oH}ID`XHkWalySTJr97k*`#T*{Q`Z zupm~Z(J`a3)7&EqJYR5EAvw_!EB}h#*c~LiGp>{0D(37ui?}!!d9Mm4*`aI(IrZJ~ zCNV|mV6KwLv6==|?pLk1vZqWw<+753CccDvLGDz}#4GV1q=YK#fzU_CWAPw5k>qAfG zC@*n@N98?%VkK^AzwqdjH{M@@=FeE6#TAI%mi;f`6O;Cd)T@9wUXekDkySbr(7VGNk6r9zj6C1KS_lJ%n&CRV>D0 z94qz|g=&#VrLtp_3&`xOL1pRh{4b&*jc#s}C^2_2VWft`g?3Hvj`8M+hD{4U7-YD_ zUxelkwdt)kQsl!#$>!s)ww2_>Tyw}$=IU5dSRY-`>ZJOqJal6TU_u+xlV`FAx27p? zoJPxF&6|~4`5_C~M=|i>=%I#$dFbp$P+t^HBMz@{(G>nWMBuc)8lo0`tq2=U)Qlqk zl8*|JB*8XwACj^%v?y(hq|V|2RVO(V)%BE+T8OXwP>hTu*yDaqc(YLd(fcpP0HXgO?to=y&zKuCQ*i185CX+=q-q_ zQm`4QtZ5Dpj^3g{Kp0qh{;I%yI+wDq`wxdzxVGV9IfkFYN9GW>g0u z_j_C}s}EWCrH4&h$K9S1WtTZ%1-?opt*Z{YA|L^%jaSpanmHP4Lky5#1*@ zV}M6HzCPl^&qKLjpInEz89K{{n?+_gOujgTWT*0boLv?|0oPgMZ=SjHiVX+cMT@U~ zIBa$2C|>2jr)H1E#>g3rzmv(Sv{(9We4E!2z*Tjgu4nHR$hD4~T58IuAL2i*Jq z`2}qVQ!DXc3^Dnr2DLv!yK85NLC`N23~ zI%EuL(w@|s=Dc$Ii;>iE*L`RWmK<&GNB6nN%pV(Ypb`Qsr%IPZAWN4ZL1mg0C4ZjY zqmdU8g2^;`{lrIfuT)&pX3>`?l0Bor#!8(R*a<~e==9=E0~sribjH+x|nEWUHsBgnTt z;WI8$&KCIP3xWon!$f~m0ByIxa~!K5pHvoWao{^S0yA}(UC$f!MEZ-Q>6RbPdW{+! z0<%m`=C@nwucFRJEoOK(V;a@y(N+Utv&0z2*!>G*osnC95En;U|-V2nG;$g|E` zQMNlmvS-umy(4O95wjB$7M8NqN%x6-fW1{F+f@8CNdy(&BAXn_Y7BkhZ?#=`#iN9C|Qa6O0$yQ}aZ* zFc@F8^tgX*{s-K|pf02q@Ca_5tz!PP^w6#*4d(%eeHqEtJ^*Dtf0u{!M5lTTWx({~yEw^Px_oom(!(R zxh$am^k5lPtLY|oW6^p~Yxk>!b$*7X|D7jC9U5?oUtj~A0qB{}ThFpS92IOT{>rP6 zQaArF+#%Pp2$S$uhEe0WJ8do|V5e?8beG&k+f~GMg&`k1X4t81@Bl;nM0bcbRX`%E z_0%7cE3yO1J%FLb6cc7IP$`Pvt&+uRL7HN&Cn3=(&a<`52~v$yy4G^^oD1TGX+f7g z>-5I5*3TJJDXu1q2&F(Gw03gwv86t3@{?E}DeuXhpKuqrAex@U35hEpm;J1O>UluA3TX(k*vAOTUC_03^46(q8GZ^l;b>4DVV2! zn~tNcu{oDpTzyqX zlM&;E*JY55bz+u7p;>mA;>4*yfXX|uDQ$_GDsSQg0$<+YyEXLgs6mRyrM*h$7!a>p zHf!7`51yc_eT@crhiU8=jWqSsb&Ta9BdS9s5_f|A3?(J`C2p72yyy!u_d$GCa)Q_K z@mfFw)@U-`6ZTPtuf4pL=<)4m5e?QdkSKAy6dl;st8Q$UiQ}@W9qdgfaS!x>#En(CKfhFkWa?}wDY@d^ z>3<)L|E4-mwUyw%aiID8-F~#)z6^F^-x+{-Hk&Ry-i87{L0Le?iFT+^0Rw&rMtK z!?YTo8cDp}F|RuRuODWB^hcvX4nsGYlu&Ks%O06*A)uHCNs>_Iuam<6UcTdh_0L*> z&TvMC+j+%gXQlH)x2EN=Xu%uu(&v|!fR@u86U3Q0KzZ!oESoOwLhf@u(hm2+2;_n7{bP|u65#7#TNZBA z(D|XJjDHZkoeUPI>%SWN78xMRYu=$ zt%fM8>_d|X3d#N8wDYdVM;B>5r84zmL}=8@cl9M;dZbquV{hkMMAm-C=-a2RmHAzN zG3fSs%E=P*{CUWHxcY#+A51pDvD{AEUX_Md350B*$U`l(@ZBSY_OW~>(718s52%~0 z_g|kjyXU-EVzJaJX-sM;st3#k^|~+x?0fJ$oJLtQb})@Ev3lLumlYmY7XE;gcziE_ zyXn~MUv{4XspS9qizCnBSgr?hV*BYXAJGVkBn{gYU>QDSvv9U9OAuJ8uAXQ4scwl@ z8=II^t)a%@ry*C(7w?WJE$2~ioPOa1NQsC3Uh=yn#P?2l9&-=FeyrCNbiB2uB^|cc zD#{w0(texsUwbjEbV+$$f}QH0~+&x2NH7RX?`J;#sXRA+?ft(p(nNskt% z2&L|qT!fR!HWA!9tjwDFODGoEYp;S}3NBz%;U)*gkZr_r)Osw+1*6x4Z?+0P1FE`Y z7?MM~S|;VVu7Y=B-Vi!camZ zZ^x+qIsC3Bl086aBB9|~ogB3tCN-u#ZSz*Pf2_ku>d){kNADYhUg69{VWWqxYFi$K z_2sB#n6EiL&^7Ot&26O`1;L^ErhOVE;CMNyt~guNY8Jk)Te>qqm=H2=2bS}u9V-d& z(RI9jvVG?O{K5ccIT&fnbeOA*+O?8~YI^tULbP^@Me<)l8U{XtiLVHdr^WaZqpcV2|6e3r)p)}^ zv^xw%D7OZ7avpXKUuOjltzT%k+|w8dAH&4w2TX9|SGl#vsn;S7dc*fCIrA67956+h zWS<;Jzhz$?ZAJU9bx-VT!-~A|CDBC*pLM(lkHz47;p5flbaDka zV|Z#o+VZZ&QtQZuNmN6v10NiMoEm(CdH#UR9ndcY1dDy|&GpqDevY2Cs`_ZR;GHF% zsg3J8=?$Fit|eF6otCWW;1KECsRSBBg>T$ydC+S_BcCh=u3FHNPQ^Xp0MZH$TeP458Q#!?nl8WQ0nxNXww zuP3=Q`*V&WS5Opxf-lVZBAsdYN>LS;@*3`}> z03^$bd<==6r+jR9{a^>xE#1s|RPbsbB2H8$ zR_*fZOH{7qc@Th3#{*({7~a&#kc=}fV^FC)=p`6UoTKge{LB!36*m} zEeP4qHNPYv7hN=73H_ZS60-{Ghj6nH$ZFKk`8G5V=s{zxDf{yh|7pR@Q;;}L}Dh%Ub!qZ`&DW22lSn+V*}C% z%yXbgV*q|T_BV=KYbyACZy9Bmw+4DM2D0XM%EQ5`gUtL{S3|1o5AV#{s(R>eJi+6<#*L(I-J!Bs|o}7S5^v zM&^3TQO9v5KbYm2So#kgtbw;ZSka65jDOLMh8lbFMw=s^D|o?aclPfN_)Kj^4rmsD ztRmh+R-$|fwF8ZtEGU1o{=TCep!B`*fFii9j;;2cDy+-W88x)}ptX`}YTVHxz{CsX z!$^^J24@uUfXnoTN6KxXKcM$h?*BwOSM$e)`>p8Fwz4d*{>>C@2e)-kQ#%3NhV6Kd z4ZP1IBFT{^UtLOjTd}Vdux+zF&hEnRfPS@kJ;{*mn45Kg-zD*Hv9_z&GQ}$z%r}yL zP-y47Ty7DK7gBdyi;;yV)h?6;SymB(aSCL0tgb=28ieuL`H977AbwlH(d$W{o&OHT zTgR9!Us{Sk=X4EI{HWTCaFCmGF%MYuI%l2Ox=weW{J4D3tn8xR{>cjNI=TI_V^^(x z&($5+)mH-z1@{rKO%D|Kq4M{m))Uua^ii@7raz$8)ZbKGf>-6f-qJ_GUcZAcgar#J zQ|%*1$EnuhwSENA{6y7neWwf6Yp?$UG7;HcJt*+~f0zRO)832OgX{;*_QN2fN~&e_ z%B<#(zJH0K&1XS4v^{Z1YL?BLK$z)`08PCb_d*z!nxE{p+mYZS)BhX(-I}sK&^@S9 z;8RO-SZSvbZ-?4OrYHSaDRw^ZZTx-t0|Il{(^?j~{_E{q!#JJCzhBT7&B`-Q zu@-?zu*of^>WJb<<$$Hl+&%-QHx&Hs2pC`lZ;9}_P&E;b(qDOB>Is)e-bOA1L#6fD z50eHGoWI1Ecq;P;lnx{zGRt?AOX@6(Yuyluh;Yg6ytXxRa3g_V5+@<-u--ihD11s^ z7V$=5;|RRe@Yzw*OBjlE-5e&g!OMH>=?GICw2p-jbR6 z)piCF?6ehWv7RVcC;QnDNrlshyDi1T%y-{h zeZ-oEc-Y>sq=7pVpo<`k2-YWS$N!)U++Iic^Fh3&|0^dUZ73L36zAP7E~k39`l42E z|5WG$Ra&;7RGm^p(Hj3%e#3xl+bkJwOIW{*TBSogG1g1jg?O=e%sGu%Lc)yv{`4CC zN!ZPzs}g8u5`uplj&!hcnQhvXzN+_8+(F*wmfv2@p5TrIN%-4reIU&0C!3PPh~MS^ zehF7;xu#f zx_4hXis~ZQtn2Zbp3 z8^z^Q%=FZLwow2QRuwtkftlaS9CvD#4j9~W;ZHM5l`9xFpO+M#5^UqG7X3=ewbP9% z(@Z-m*^PR|V^#QSab7GhIY491-|L0ejjq<-^XeQdU51)x<9Z<+Bh`dVX)A1rSU1y$ zj~sUzv#?qYJX;s;->Eo*U%;%%2I5tc#(2mt8ERwZdkj}}y*JJ)k_}mxsqIO7e=sMa zF0);8;5}z2*fYshm{mi(jD;i1SXILbw5o#%vl$DpwI-Rs5v&v)IO8p*e483#UfFev z)AaQ}^KazwTW?w~*_o-F-rt6;U| z0#kCsDT9{usxooiI|hHpiJD`ax#VQhL0J=i;+b5jsn~+&yB0#1PvAy3Q{02O2Pv%7 zr}&CWQ~YTP7Te1eO$O>gQnqL2paJSai4PN*=7I|pRrL50ACdx#;V2_fD{fQnoe!$M z?N<90aE%33p!uh4;X(M}Coau5KK7YQFqYigpoT)N8JlllX>0PiL}=A(&0K6M2pS3&T|#xGo&kXy3y-LGVZc$1zl#b(fvQ@X)x)T`it8vgAR5oc2D!{ zH}@-*lYUfkx(XUi+b&(U*nEr)E+MZ?S+yFqk3Zl}`NfT)+EDT%me5n9phhjb!1N{j zhVZC8sc2hqCZP@ypOIP@c2^gHt)>TMRMPPOs5W;nsUbZ@G>1IbNC#zNFd38~pSJ1# zu>Nw#W>J>rFHUV#U-HqeS0rr|F=R2K8XmvzrSuTb_3U9A>`_ zT*i&LFo}8V|A^Xq$9}{3gwd^xx7~n3bMC3wd^ABG4T%==d9=?rrKRIv?Y%0HY1JF6 zHXIBKmBm<-w_^o(U3Zfq|~-QrEClr&VR9wJWHrF-r(NT z5aAyDx`nj)c(;T4@DxHz4Y}*w%_?d={!xY!Daf?iPH@p8PuxCEtoP7b_OnTjRw*o0 zPrl7Q8SW=-IJ~V6Lo0Th)Np_1{%Rda0V@OV6=qhlN!v>?H_Y!=E=C8g*VN5J2eY0O50G_E@}LJ1R21Uk{zOGM9Jok{irh0_L@SDCO*MGxP;qJC}#9{sqD z%N%_*3q{-K7B(w|@?T_j7h=(?RVbCmQP18z*y~zsdY*#YKBbJtA>evuiS8o10rObS z4WgdODk6{D>uRPOk{c0si_TPYAAQldM$VYd6zoo|%_)_23AxW;OK}!9SV%3AXGfe* zApaPy7XCQO8HZroS0RqG)|z6Ppb0lH} zrIE1o+uF@ix=M&u;gSiC>w>8Ij{?!!0Acj7B904@-;sTrn`ni?+U*423%tU;63ng2 zBuWgGJ&0zq{3&{g%LH`PB0eNh8pv|)RlS1Hsc>90?LcaW9hj90 zB^iB0w>VLU!urbk*>A7&g@Co!O13D#4YaTsQ%-*iTy2JE?mbaGtS&WE;S8AgL1NtLWYI1#zz4e~{6h|-fV3)MNkiH4 zg*Q>(frqPvZnMBezSjj84I63Uv(?Bc|6s(y&qd!bLkIHMe^05e27cdAmZ6HS>EE3; zB@7Iy|6#SqI#%Ud# zV7Oo8{R7f?-ZyyJxeH4={!!)e3E1E76r*X+yt15`qrnW0Nfwp~yHuKd-gJgC?G-bk z4}~@-D&*1IFFzafu;qU5$~5j~fkG#VWzs0k(6@Tj0u}q@wL=MKnK8GX?pt(E5MAgS z9f*KF{fh*wizeC>D3t~I)+F=PEDdpXnJFgTVD6ikF`Gi0=8}HZ%4s~2(sTK7Pn@%? z4T5)~P?}RcJk2KIf^LmGrnJ5ro+F)Z_5vzWyirRe3qIgbww1cQxF?3d?f*qF&F@8n zqQIWIG}RbzS?Z7u>MOaQg0Gj+seY;6!H!H%R7k!5o5m1|ZI>2`TSse0WARB1BNJw{ zSa-4HjW>wn|6wIgy${`*duIs*e3%ZActai#HAT?s(L=;<7nBEcs*nbOo%SWDl0AcX zMRU1kK^FD=f|F^#)+7eUSuP-0)opOP_0+fH>mQI51Wlx&y~~dDltWpx#sOVi#|8C? z-5B6g>BY%EXK*O)=|@}HORnTa>}81s{2I*8k}|5qSNL7!Lyx`#z{vCusGRa&``z{b z!pSYbY`{^~4Zo!lY|Ry5Q6fZ}5v8;$b<;u?#3~=GUf6`B-V4?*(g5geBHM@G86tt- z*BA3x{V#rEMEC%kt|q(b0LIXYwU!|4`Jr@VrV~(~jzctpQGS7c{r!UfqR!EkY+8br zHm~T6*7;3_0dxgd+d3L%fvgS9?^Fv9QW^iGRV{OOBKOy??xE2zh6*e)ml7sj$;@)b z=+T$J4aFIvXyU)guN@6Eay^cG#-S%Kau$f-qxK&@-qOHFMdyv}h0#>+foJd;l_u9x{2ExY_uV6oQBEH9C) zmKAIsMk@XrJKpiRi(17*0<1YhHn`q**s3UOeFGq09IrEM;zi>D5luhZU+T)+EKzF# zzCmPjV?X;50X#jIA>d_+`QR~fgr|_v_lv0fN+RDNqpS+tU~$EmsfWI zJQDuWSM4_{0Bj}ZH+wyXJ1McU5BLqp){6h+Y{jOCzj)&+Z>H+s7OQXPjn3@QnTC$v(y4AzU zo{Y@oX8p|bAB^p1STBO)NA$nA{LB5rK3K@ipU-a300r8brctWeiE&EDMdx6lo&2BP ze8Qo#EVS!IqJKk+AE3E`Ug!hFmWY`+?Rcjb%w)E=LY5jdxBJksH;2Yn=dxIxn^&^3 zH^KZxeWCq?bSS`-k5(wK@3`y$iNK)!NgLQj{YJ6p6A6*oxe?RqKxMI%oYHO($OuZ@CD5$9A!T;QA+-6j1Q|F$K z@pEK+X<#3BbDa?-0ost4FwTWA?E|Kk>cId=1po+hT93YJr@PTLJY{7_m=1z&eUNpi zD;ybPRI!qHHdsupLI9y>9?pWqU!%|Z9OA;CWjpVv5#J&EUvooLl$q-Ok*B4m&#Pg^Ml!lLi_^lwXy?Goi}x>X_R#MJAh_IfAG$QBZ*bmkyfQV0s8hylfAq!k z;dj3l#=m(^wSxfCLFU7~k#&`BH%qx6Hv~F#+!A9ljN^C0pzCpAn2;r|Sv$K9@hRt1KQC%J# z8bKCV$$S3$V*&Wph`YlRER1u;2S{s7r^1{T4*k5LT5hk-wcHBFES`wMXQa~)_~Cwz zJonE?uC4zyc+S37osj~#&`}G^m(Vw0L;FZ%ZF2vac67>ad{<3Uxi0YG8sT*RT?G-h*UB=?;aPjJBRa{zLY!8#@Az zoO8e0BEQt3Ql~PpM0M3$Olnpjp84#T^om0ykOmZ3?YJ)wc*TjB8D^6^J@!klR%r1) zjY?Z8kcgHIA7}VZ{(!VsPzvv$y~lzW9Rst1f+IhiNm{rD1gtLHHd5q>9Z(5t{{sKz z%a;_hgs1-#meO-NLyv3L5^y82ooS%i(jsr%`Q z2TRYJi3YPtQfTI%rNg3~}fte-FPwu;BEW(4})1 zG|n2zE0+}T&t>@2B=H7=LzJeHKq?q0T%@p##?JYQNrNL|&!I0gwz5o48jF*`N*|eC z)!DP$PIvR+)c;bLz=_SLF&?W8o@(`96(#?sl7!y>L>j%pXSreEW8Xe@wc+L-wo~M2 z?8L83@XTUtc0MmwY@M7JIEjd>t}7}XB;#fwY1M=9k~?JK&6KJu-AmDeOH}8(nlm#q zjLq%@Im)1};AHewGj^Pmxb~GYE-G$hb}LHzMmZ%;jW=6EoepO(6b+An=3kBEiby+G zJ;(T6Tj{!-g6dp7PkX&oHOG>^m1}&j(|(_8HR7_aPxGiL-C~yY5g%9ls{LX(*W4TWYd-_&_k*w2opslxmq=`!`|%QU zs@J;2>_J-StQu1&{YAkiEaxn^w3@AUi36kxVBP84*PJGy>E1=O?+$*xVjkunw6U5- zvE$4~o=aG^RrN;@fy(J_1?^i8A$ACdLqG#atCzl!656b)zp{|rXy;mUuXDQbO0V-; zjN&uzS$8E3wmle{T`;PAq8*Z^cKt%t%A0k#(w2c-!wL6#7Fs`p$N8?q3L7^>0ORch zZO|21O@r0i>TaU<|C}!}XGN@(ng6$hh5$yzvHWl(~*(RuqAe1d|B@a43CIa(qz3 zQ?U^>C0yMbNX#IQH7kA49cM0ezeHY;`_p?XM)I185G)7~?nk~A(~x<auzWG%0FnCX$$)M$cKB+N5i&`JXCvvsr4Fg|+EtC?z$4?Rco1 ztXwI#PTNr*jL7esE;zT3E~ltr?lTElfwiHle?XAv7NFGlJ1THe5W;cE+qzURL+{`& zEY~7=7LZ`N#+|jgSwU)TCViYDPzejSOAB8M%28c=B{s+UwE{HmV)gz|BauC8NH|zI zUXVhlxJsJ=Iz&GVb~bbWO=Rb=lP*h;Mk5FloD@N6W_n3&hNx)2)>tch$j6$}+xF5EE#Vo39hKI8pZiq1(8oj0wut0D(Hk2)@ zba>nDS&D2VkHk`eZ6t-fr;3aats`V+kXN>sXH@x2dZUar?9BbzXAf`L<3(f~Y~1+l z^baV}P4(yjVW~2H9hhWFQO>qab-b;AxtU~#_)ZG1(w{YGoE=G-{C0>Nw(t3|K+mCd zL>=TPae#>#xn{qIZ!=pWkdzgUs94ag>99VjF6ob+FemgPIKjlG{%nUD0~Omy=@={k zCbG6Jr{1}4LX6Cx0_+YqKCpi>fgEClj`|_e&)x$saqrW$K_{*B5}xP1j49+zB!V=x zv9(KhWJH6Zu_!id@hgoag2a?$J7b+>8$qP%P9uVFAZx7>osEN5Gc8-#nJV-mkS*`!=I0fG;A(P*5yP-3Ta0dF^1Lz;wW!}5#>_#MtcTj5t7i!H9z{@1{DLi?Y#f!uE#LiFhTJ;TT`mBc8oUNEJ z2cre>t?lzKyB{9-)MJ{j6{6;Zk1~777ega|s|ho4@jX_{(>iP{2|TuPJvoaHUub)- zY^N_dSoeC{((#%Cx5UbIEIrX&Nxnq6+jO|QwMH`$oHfOaMiH0FKJDxe1cf@!{HUMYZR z?;$bqb#xI8WuS=c%p0^)suNI}jOk7HwJt8Vj+~pLrq|rXpqZsKWz9up)P0=a&k?k(SGiHiCz~vWLkA4ExvbhWkKpJ zqm>@Osia%z0xf1xKCf}g7<}({jOf&g;=uRtSjYaQEg08OxZff56|AQ_Dt|( z^XOsJ^)J%TH|M$@9VDVXN*7{1<_o>(w(rXgeG$i+pL(OXS<@myc)q{d+O4e`>Oaa(uh;9A>wWyY>DaE%T#d{AYMH@VXKcpTPq!hC*Ksi2q zw@*NGByq`?jZ~d~S3obqLN-xrCrbmE2V_KB(I$}EO8uzi zF8#V&FvpJnEOEb7&9%6p4lF;i36|91Myp2gYVnVe>=9^gCcG$l@~zm;g3b!NvjhF& zz0nA`=?}=Gp&5_YO>U9o$1fYSUgMQw8QY*UuXBcRidovPFS$^gt!DDvb*xzAw^MY) zK88%;u&}n|5tFJ4C?7xzCy<|NRnGoo5oxHg*HW36u^XNA3yZtj@YVkiozY&Cwt0r6 z*(B2YuQ(=l;`wc^8^De9e?ky}K=XV32UwPn_al*>yS&u5_WW|D=@XL7JkveKPu5!W zy@zY8PnSpJKZEsXMuv(R2{#yMV~ZdR7zxJqdh$}Kl=8S?vgaS^(9p@EM!$&#w7v-$ z5Jm6MC^F-b2vt}*V(IW^v9ifqAKhjwfg7(p2T!OEpAOR{X1yO!!X%*|+aoJPQi^FV zqfMp=J-v)uMBII>v&vR1RZ;2W!H(Sx@D+x{q(fMo;0c$NOT8}(o1wMtm4#+|IhC8Q z-_7eMHF_-Do)@g|m7e>`aj#XxT^F<#^S*^~%K8ko>Zf?a8Fy`Ri9^g#>kUF1-4D*B zr|$3`-M84Yw%Oc{a`e1+49=u{C4>9iUXKX zVuzOKV09xt)j>2&h#CPOOz`md6;fLalXM~X9LmC4_=;F;Z;G)B&LxRzWP1^*Pe)yZg+0Q3 z*ojV3;)T}#is!!auv(?3 zdghS;J}5L+WaAG=%^mL`Zpfw5XKl0o`I1V75dWCbR25%=Qe<-Rpx(DxyH&6@gvTDg zgyFjyPHcSUK}mjNBMq2>p+xD;9xVfbiN~#bx3khz4Ce=;6)mJf7b5avi#`B zB>!U8pbX3XQMR+{rWMD3hosyOK57cJ*I0%exi7U`kF|I{jo;Jr&exkQnlO17iflAI z+ETF5i{vPTs#UAWl)H0CMv;YBUsE!q?OwCZz@0bj$Dz2oM2@k={)rz@rCDMN)nW;f z2?x}WMUY;Y@pQiVZdfUk;Bs(LH$IGTW2FD(ZhOVz!F1Pd7}_2mDtO^=-RaWfy}bn5 zy?evj3h83k`F8Ge0ysK33qtxh250nVy2~_MtH3X^A}rMThnqtRoHRz*r&F@(d4GR$ z3OtHS%KM<49!&5wi2o_UJMh+*6Qh|yAlfm%H2m6_4YyZ|B|K1QQji7xGuj~^9zD$P z@(Z8vnc+>mylIrVd1RXL*>*rIMf+ANp~S&%$tw+WH2#2+G+3DK`PoP4=GOIVO<(Z& z?0tX7mLYMN1Wo=L?w*S!a~`lX+~Id>76}GZFQWB3M2WfxK5Q-F;a~p(SgToasq)S4 zz2i#+4Xs&*i{3vM-f|K;9xO@v{F)85c{zzuUkks#^0TTr%W@Q7ToUB6TRub>w27N}@4 za~7_`|EQPQsxOsqeCz>NTzlS!>sozX>>73Fo45WFpJweRrZgsstmeV+|?EW<;Z;fW%y|IF4 z0m`sQaZzal^e4?KnMGZXEi{_vs}I0qH8|!C4RBOLo?-Ts(HdnO7 z3XS0V{uVTgTH;1t-cjM7rtMWmyVE%W66xN{O&k7sRYLZ{W!R}b?mnNdro9)N>1p}- zPx#g^WW3sRh)CCy3&-ZfgPRgm9A0<*JXh)oX&0)8AaSU^B_K$aXOhLUQYA~JJ?JcU@J{15|_8QSSI zSEWtk*uuiEyHm#puBipKw&iWJxHTY`tq-cyAyL`R@Y_Cm_=PML(^AIUTZG@;3-2{F zI@*>jqTDw^lIciWc5_Q-2c(!cmT0Q_ZNl1A<16mA6;GDtGT9v?n=5+OO}-qp<+i}9 zzmW?UHhWqG*~(<{^%wfiv_|;$^ok*(q^g@D;FDnAo}mz>QZW-gwaBXIV5i z7yV6nO2b9Q;n7~BQ^t;zkXfQ*6&xPa>-#(s=RY7ujvMQ|v)U)KBJ(0(?2VKDxRReZoIk-mPiJp0L5Y{(cH6hwnbWNg)|Ydy+7(}A12>d1WI z*#i7NYE4TP+gSK?{oySqbSL8>gMDy4?m^hvHpQ#qel1{kVn(9kX+cn}VQA}ziU2vE zsz@A=qjVQ}%sak_0NVafh7Mz=SU(FJJd3KHZVp5h9NOEm(=2R2l3q*p$i+?=FdGt+ ziY564=u;=evt8=yAG3s#%Zw+9z$;f{6-Sm4`w(SM)iRU3NZ9NaduH60{MuW-ePr6iWL z%OWX~#9|nq)F=_J_`H@ZXKC20u@HgAIH7Gp@O3z!g|)k@LuO03YV5KgyxqXvw`0E7 z&{s3`_gd0>rz1g}d|wle-=gyRFG0_i7u945LOmPqw;OmlE5_wDFh0~$d}#&oF zqqK$}m~FG<*zT&6NnjqCQVb-xM#UgC4V_+OvY70E#ayUn~O2pQT(2nJ{v-3 zRh7Qq$Zi<}2UQKC@wxMyDGLy7-WsS7wfQPWIQ!fl8ZXWc<~9*#*HEFD=3qz0I-u%L ztF$)b)kmvV)&3~6?Cm~fhHZm-_SmTB2i!WhzuZ(7IonkgvAlkF_f9F_2y#DMsWDSj zaUJ~AU2!>aPGZ;3|7D%o7gl6PFD2zNUh+~Mm?p<=;KL`cmGg$tEyx+%+K9Th(QPbN z=$tKHgesG)a6Y){^k}M>=`ptsyb|nQDn!ohG}tcOl=OVBFg@ULqJe?Y--Dk`V!4b!42pu7*5 zS8dh#DwbKg7gc*M)C^#DJ*8tsp|uQkn>J*~>Z>z6U@cCnJc_qE8Ii82dKLM%VdAPH z7T53Y<1*#GFZlBF>=l-=G@UiVvol5V2}eZiZ%gqm-OB*&LGd^gl$1Asb6%-n6IFcL z8wt+>-%EW}nD#dB zqdol97Vb*Ye*0De*14-Mgdro2mN@sRUJT&LXuM;fTNQcM8?|Wp)$PUat!1Xq=qci7 zD$2qzE+j%k@_g5UgT_dfpbZ-e}j{ zqpOirLkvvIkx*=BuN$j=sU}R5QxEe+S$}7*_2`3|H6x|>K->9ziN-sp0Wyu5VwUTm zE)tKOw7H_>Fm|zHtq1JvJ=5DBVbR{Er=IP{$t5CamAA3pXH^fX zO`Y{dB5Kk3I-~5j!)+SpFwGBH2Dox7&nS58noFM#+Wjt^V13>*{t|18zKPJ$ONQyv z0wqbnGsPPdW%=DL2vR*?#jg@*>kESIXZ8Zs2!ntJBCx~Mpa51L>RvzA)NwFa|DK`@ zqsWrtC*N>6DS|j22g2Gk|A0z)3=3g5vex_kUksMdosVIfl1Oob<_GU;TBQm;IQ`yP z<`*wKoJrcw5qW2M37jlO2yJPc? z)LLw1@-Kq;le%XfrI!7Hc8z{T_KIs4>*fHoTiN&iI29)RcpE8Zha@}fb^3Ri3wKy4 z&-ZRil1bZFqegod`d*UkUg|ib=h(FQN&g*Z30!e5e9>L9IOWrxz3XWYjus+eo)$gD zzq8ke>F>hqWu)_goZgwlJRU7VP=?dSZQ2}#Z(sCn-#=?d(E)HX_()KG)_X1g9wQ%Z~kcU6gHhAb=$URarHM&$01W6 zyBt_A|9~>Q_`OBb+(t`tzr1?U?7jN@z*6(UT)u&k#?acoIxHTOcc)S$l8XEiIrCwt z?Rny!H2P!V;^%hQeqrVx(1?_1>@P6$agpb}UsB!@yT{y;IZqWr;h~&|jke2^ z6F46So^2ItjYk4xbnSGhQJv*2Y;85cKx#5I`RHsJ81pL}trOt4GoVN+qT}eCyDoA7;?^PM*=}Dzz+jT+M0VYBlh>vZ^lz0@ z{TB#cS%?}fVxJAH=}Te6Z4pMs<)Vk;t7au}#FnjT&{lZ_+lS6Z?}lCFwk;#jX0eut zujL~7rw0hB(P6OR@o8Yj*+h31pa!uOQSwLSqnu{a&bzxG0QT-4_K_lPYOq&kI zn+vz_kL(Cv>*ZYJ^$nApewyu~-m=MR(GrUU=aTX^QIl8eREzo61k_v0&Vx{PoC9h5 zu7?Ayu)6&@<9_G`K~iSFbP)cx*qVt)AC1%vXS)QhhYr7P9u#oWq8Hy68S+RgG;ULR zY1n{+4&2?Z>qSKBq1epP6+2d-$QGD_# z4kM~00;A|W&LF*vw-sCsW>{qh7`)?Vav!^cO`g?pc205gFm>eYMMG{SNr zu0SoOe(Br>&9dz$j58Oer<&u;lBc5G(ri>XuRJso)8OaXFT6ifew2^A_M2A{RulVe z{lfkJiQ*BPYwB<`Gwx|4Z7nhm z!LJgi&+6TLcM4gNDT>ack|OQjy|rpKvF6UMQFKUA_|^C}N8wrwHE)crRk(P4Nh?b1 zAzZh8lKdVv@AL7cH{X}2gv0{VH&H6n^$fM8kKvli2`HQ`8C16#)qX|X*ELgxE>TIb zIFcK?gL(sJH=nTF2q9XN@{Y`8^J6UX5IH9(x~t-dlu{kPeMiK;ia$|fT;}sT;1{imRLUy4WrLIbyhBv-Z|14PXa2q{ybHl zvXt+#ah=|VKh zc^s2gVSL&pc8P|2Pt0Tu=`ujc&43o6pXOn;$ZZXy8U+DXi2x8sn_eku+bZ?oXfN{rm}X@atrl%pP4|0MvHt-IK)llyc^R)Z#% zzMe6A_}JOWP&(1CiIHtFSdtp(vkXj41w8Yvq4&jg$*G_M`flMPuQ(IH!F-mKiu7vC zQ$UvqqFbfVe})Fc7RSn{2=f}FJ(Fyy^L~$u~Z@l8Nk@`RD=vx$;7g~ zoy%~wVo-Dj**J2YjOol6!I5-`_~I2ga;INO zZ&~b;g8AxLtn?ic6ArJ%!N$}pwK%sf&Tc98aDRp z`?#B(e*0Ild)RU@ZC}Ig9iojDYM6+5NrA=x#2PN{y`lbPSDf4HzhqO%?ST%F-eQpI zt~8f4&t?YBQB7qL2M0>}P>W}NI1wmzkE)B`F{{Z)?H=F6OXzG{uB3 zTbz7radRLyahBMkr#1fpCet|KW54*vlk6|h{Qg{#9iIeLp|`tKY%fuc6ej9=r|r1o z8+YJfJvEj|T7mg7W(YKPAt7K`rK9&kxC~hn+FHl@(Uc$m%}tPqpR+vAQuMezP`WtI zGgZ885IPvef54bfTQ2_uqBj3CPJyWj^Z zAYVsudabar-sgW`@#@*j7v;a{yRGmkhC}T9w_@k5jCytr^^L%*slz{VrB^S`ag}nGej`Y$+D~c{N zp_&q~e*y9AAA?EIvk1b5xmJ;~?0;SR`(&#RcuvmB(UEGiU|BU5;f3u=}|h85Ht z*48aIu;Aq2&0@N~WDf~0gP+Hd1heB-NvgOCMH1&lDU2uC#yQ_~RQR1+$xKt67S1l4 zB7bovI?KPJ@Adii=axGvyG4vX1Hkhj_E>8qC?eW<_Rq~$nzK-_()ILQWYkKj6+HWv z2A$qu)Tm|7H!V8c@>cPIjL@Y@6y~(sf9nWhpb_kH;rogsP6M(;UHXUC(`!;x#8#w! z)7q?KD(SJ*Cuw2+aOj`QcTa-}x+YwQ?!let_S$)ck$&Y;l*KPMDoVU~tpxgFnL!nO zUHETJn5Sh0=EPN8Vvw0g>M?x(EExuHEabq;!R#TldOpO+3g`{->i9~YsYIWXGMnae z5ezq~S?|8)`D+zSq7Ta;pkhqU}y`ECw!lV3& z3?#fZD=IKmkxx`=Ex^EX$XxK0g#kPo?>>S?)+Urw#s#%xTCeDL2Tk_hko7N|^CgrQCG6p)AMPYD zu*e@lph6|am4QA9^Y4Q1G3>Z#KnSHTzk7c*GIalkW~PdQL5Fc2&j6fA-LRr!%}_uV z1T-_xhJqptmC=nwK@W*OvZW786}^E#Xiwi$-DY&z=>g3Nn%VuS3Z^?EGN{KO)}@J* z_YbKY6O-L#%q|foRGNlVRC_~2=fc@l_74~wu@bFuP!DU~E9v8Xf zXFL71x;0FY8LMPMBF=eH)NMR(9#4488!IotP$V+{nYG(e<(BHI3}_+uUsp_j0MHq5L4FoqySI1ibB)j)?b)8lwNr?Nz$ zJku?+dk%ctpAGcBTBq+Mn_H(>7)XZ1>e$xJ_5c37Y)l5ppG!A490k?<&tLzJZ8^vg z5t0raZz?nLS6LgLzu8EPBc?5L{d)wqssVY% zN_`<>tE{!U@bF#3kuZ-AHhzrvLYV3m_{+6SR2K?2UVE6gkok@bMe7M}UZQz-BJgle%@0+@v&>fo zh&t80eg;KmifH~aWBxVayq|~Mz!1l^#?ZZjA%T(Yrj*gwLv}CwtEkiI@$Qj*OC$^ znqCq&cK5FyMO_)1_K&Bkw`;rVD!xS|(lhW6Ok(!^lF&0>f0MvheENRMa}M>vjQp+> zF5cbWm~0?wd&a975?RqQf3o<51@`3-IUy*rudl~ZaiN}2<1%BT5a~GmoGJS%Tyk%z_Hf|vps>3(L!1S1*bXC|u@bz-&?|<>m;$cd#p$2NNQ%7*FZ{Dax z@-nIFmkAntc77V<@YXB8wjpfaXo{%N5WZo?Ktod}c*N6mz@c{DT#MeKHn%Fx>@VUs zF{N*DQ|#zGkfygwh4jPsC1lknNd>pO>GH~juXmb1I_dnbo10DX5`!VQJ2KkduQ0` zgQ%@&EVlA$Zf>;)n|l*Pt4FmBaLXEOHqE*W!Q7mx^SK7W8Ps~?$2@mS_Ot<2u*Iwov%-kRHTL8cmFWq# zUqaGso_F-c7hTBa)meexxK1V4PYyK=V%|mc;>{)HzZx{NW2U7^#7oE&C-B5^t(4xo zqi!8f%CIQdD8AD?qTpWTuS=TMm+QWoxwH#rDN+(Bb&eA3cFu{{t5mJY9RL>FU-LrT8sLPY{S4e%OS_Y?%L@&NAk?? zhu@SFBLYXASEDIiitH0{B3JG|lsQ`HpZMBiRn~p5>kcZRF$mUfew9o_#?Hp_g>X(V zzxEqsFq~z}nj*VV@CobY&+v-t<=$a358>S}b3ek9d%;>M&iF|6WB9u-v{dPzpvC2) zA#HhRu=N*)2^-HSw#v zqjOOT!LUIkhjs;{^^fKC^dQh+CsAj^5EguHD7 zihF+*@|4{oQ+}uXs89agA$~PTKlqe?aigQ_k*a5k(!Kda3gU=$JDrk24m5^K+7ypl zBhmF0oJASyqqS0{k8FKqUHNW=b;$9D@2itI(uBjKju#)@)9#Ykq*P7HQ`o;lGxVI2 z^6i*Au?WzmFNQS50!N}oau$n@dZS@jzdcdbg!Utk?$y>gsd+7)HN45K9dG!smA6{v z`*P1_v5nOzH9_!>y_THGDj{#LD=`rzfk1GwKF~8cyhZTTzuAM^k?oVp{&mzY&puep zFO7_SL{TA?PCk;U8tEx*H$q+&1+&w0YCn~BPD{_*V*Mj-13CgW?XA!-5MtwN;-Kfm zgN^{(H{eW$&O#ELgGQd;lvIz48nwM`>Q&dPsWC7UoaNX#HIa6@FinHMo0$}cXCH*d zMD8(-DLXmB?rSv)$`&{rtDx;etUVHxpU!6{ItxU#1celADj6T?=3IX=kAuss(lRyYT2zI2<6s#_I7yzH zPsJ59F0}7Z?>jU=TNoug_A-UP550gb?)qKVFs;6;MLbpNY7qlQQ+0@QCF!q^s7mPz zZ0}?CQ^;5$%PvtSsgcgzK?B_3Nf~DNkNh4AHXKAYy%qK!dA4%KSp-G8YU%k*WPLyl zzu8%8(UHHk>M~K;Z^ddH2}KwBRF-*`uvJ_qBO0uSLS-vbH#Dq;&Z&4&OmKweRKB!E z@VU_+U}=N*I_217Q@7xbLQ#~^)7r@es?iqvtUR7Ha>$gYn`UFEQOx*sJ&3D5KOf!0 zUTq{dc%6)~G*YgDKgeTzPCax%v%R*6m-JZ+;A2WP*u;PkyL_UCU!PK~l=HzJ zk?5TM)2E0{KfUg2eZ4@Vg(pGqDnBX`?7aQOhgqS1lTcqMDO?jgme0$Yy>CwOjtlSy zAkK*G`{CkA3--*8I&@E1N7Ny3ozvK*9fvrij*$@C3eOsw2c@noHWon}`8|cVJHAxA z)5#y~M1?3amR3Wm=4OH#*=5BIkx*IA;|-od<16HquK`2n@0|Vr{aEh*cTwX1$B~JH zegYOC8xEI4z!B@h2S0&U@ie0r9|KYiqUS#CnG6N=JUYYYZhApC%e&r`@a>rXP27#& z{4-CLmUy-*yyR?JiJh%?3ofKB!2@oD{{Cl*W)N|YkE*Zg!UHv+f$pdYX?e!Oj%U+u z0VBj3#jGz|(ibc5Q~2W@W`&N;%mmj#*)}?>KC~GplJqos?As&4V`Ns84=GF<3n^JHh}` z1J{ql&)=mT6?4snuA#axU=lK_##Qof}OYP)&+D0kY3a)h9|={CV0p&m51# zv<6-4!whw}Ifkre$13XNV``+?Oo@J4U8Wy0eEqSU`CZBy;?D8}%b|!xy!h!(IakN# z?h?OE6c_7#3V5GFsbm^lz&OHt#w(iJHd7-~@E3?*xQ@wgsieR3jpY#$oUET%l$krW zRxFmW&9&7e_u6rj&SPAdcX~gA)i+Tlls$K{Si#6z=Zn5n+1ElWtpe!loK~TpQ#ome zc!|az%4EBl)Xh#x{V=yFk~yY=6;_h1 zDq>X0K$C3C6)lMx5o&vZi0~%VYBeFt(_-t8p7;Jjt0!D&N390lb5Eo;B}EbRQ3ILt z4sES{d+BNL^x94?cu+f!`T=HXnQ z(B_~E*CnRLU-xjtR`2k&^5xa~K6k9wAvN)~@$XH=d>QZb#iEwD#cRwSFI&|I-#x72qn;voPNXR737z#k!?>9o0+&z`G^g%PwGD? zY(acrD7s$HFS}G?s!SW3vBACt-x80xnd)~^nK;U`^Y2?~b6<2t8KF+8yPis}R}z`z zDR@ZV=q+4ie$+ec&oHjBdJgkjB$(?AdQIQ!XvY#_d}NEdai|K@@V6;H83DLb1d4L{ zwU)1$r)DBx6yd6sECDZMW;sbT^kAPHP8mO~fH@Fdmj+*=K=P8+%_R=3@srfD_YPBd z^bW^r9!7feEvG&(uR}CHFN2mup zUKXo$%zX~I9e>ztFShljSX)@4T;kcrWshAQlBxY%%F(q{!&11`r-~CaAIr;u>q0i-GHBdbQ_u0NYEGg}9nBY@2 z+Q!t7EGD`-RrnKWs^VP(Pq|!YSRIa4Kgi@cJ+8Kt>I{XiLYwV&C9N{HL4(BiK^xEF zuuqe7u~W;OjLsSPHBG;%(o{H^oaW8IZ_*zuRB$576~wVnaZ-*SvnFQstPf{(daVIP znf>)2^`HO0P?#PxnKkh5n}9n>II2}ZOB}gcMh27{&MN+Y^B_8xf4nQqWu`9K&$MjF zsCfWC5;aN@bkhH;M!KD{N5uJEVpU3Z>~Z*U^s%Fl&tPFhIEr30->-$WPN)U}CVxNB zBE&S{WF|XckZ7nRTx7@upxn~~N*s=R{GNzJC7^Ld`4Vr|t8PI^h>%$5see1jb$Mu4 zznwElCmngj&lI~Vv_y~pNj}wzWF?t^Wat*?k!1$w8FPGGnr*^Wmh-z2MEdniOW}Lj zH1Whb5qfBbRG(sb85rpQq=6%Wov<;s2U2JcZy?)ozPM}g09$nqmpQ+Sk`$`PB%>oX=`HEpnsE6ea&w`pM-h*lRr zq*{&Q$BUcEA-B}+QL;ivFeT=)ai#nnd|%@BN)C8Ev|1JXh<33Ds^6aH0pxOEC?iId*)TV_fa>0kZV=xZ zmAGSV2>m(D2Kj{&xymD_)I&*ogw>M&bfGFGcA|eSmj5x03Dfoqux)`Az1M+1*U$L^ zfYC4^^4e+zKPuP%_x?~-h~Qc$p1%fy&>uubf3JCz!kePfN^#`ZUDbT@(64bR=xy#l zWb7!vPyan%s$iRXexHeapoxe>g}21aoohjIhoOY(}(O=c>$@X6Q5i$VMIiUp#0cT zpr)Gs+1GD(gi3RInW;4|0Mq6#P=A5H3ls4wPF*3i&X2E+{2sO$Gob(psyOO;Oin%C9>KZ|mSm`8K;O%t-^GRUe%)S1 z?%T4!4S3It9zLzFVl`_|aniulPT6?B*1GXwLMY$sz}RnPyM3QLo7zUNl5c=$zZ65t zxY%0QA7mPTqWx7CUC?yepNiJ!`7pfd<6j^rP0)>uv6dyarR!5@TwPL7Hb3lg zMm6R-{h{$O&Oa&fPw-^Cv^zux%*KN$YygTWOno_{yOTYnqwpTN$p7kf_kZFWWzG!; zK<8h6RW`Cb9yH6cf4P?bIC}pV+|GtRt9?XuRGx8(EG>&0|1M6>xvdIVS@Jt;v4 zZd%?hp&U#fw}yt>siH<(ZjHh;?JVxVxz&Ac6s^KgK^nV$6zn&c;A?9n1JqcR{ceBo z726y*9+edwi(MD@zP9ysQ0Zl)pf*k*9xw zX4W6|D>ehgRS@dz7M;O@&J!*zCn(`gY>fQKc(>wIjy1L}7)zXI-lD~$v3F3P_uO1uC7wEU zb8vZ5YWb0^N!yqHnai=5o4@(%izu-gEx)=7po4Znxd@%+ONxicg6SRZEvjMtbcqF1 zfrfWnec!d9I8NEfpA_gZJy1GR&U-JP0@;Q@InE=?9LfMfSQ|=_x-k*vxlCl5dggEQ4 z6zFq~m0X6gZBiX&^0?Q0KbQGcm<@}v$vtWhNWIv!?y~wU_`GIr$yUOcw%3k>uQr=6 zqXeo>iD0Ee%_l&jN0t+G(`bF~_+U~U{ZMv%W<4AUI778Wbsp=wH=|D#3gaVOvR~ro z?|m!YF6Q&nb^rN3gnl6%6Z4QBPHSi%r-FzPM?pb7;&(f1HF<6&GMu8WRag2U> zN7SfrVyXEL>*x9vb=Na`?r}hpX69$!1bMR#0e_N^d=}P@)(ulUkBG_bod&;)S8aaV zrP>c4DvDOKI4F0G?)%XnbBNFhDkHLF4ly|dHX1uOfZn@Go%|?N+qXCBDzttq6(Wu! zYA5b*PgJCL_BGEWm)^~9%G5Q#}uiO*TUel?3}^VW@NpsM1k=W=0;5;tq~K z^HbTe34Z)&@fS!}g`LCb@m2C)pk=mhq5QonTkvheflA8t7Az^!9#2Y3e zN>STuTIt>aaRq1qC=Qyi@`M;O6g`C7$gj@RFZp52$Q=MH|L@6V0&CqCJt_}Vz!n-0 zObd@RxOrdUx@G_&-NoVqmoiFIr|g$aPRb=pNvtNiW`Avgs|y zfU5XZ2IRmQJi-mnQx*$z;xAbrxe9G@u~0q=mk5{KBhKX#qM}wvK@IA8mA54qh4cn> z`r8esFRbi@E_jHWv9XC5m-hOhGYw!G)P!5xpol+r^u>c#gQ4H$pG#XBHv3q5h2fa> z7wBVL^Mm%lu{eN(C|l8_-bHO;09`x3yXUmN@~PWuVxE$W*)x4cMoA-ed7nu+1&sHn z^*CCmXwdkGjTO_V^_8~vnRNM;$Ivz6UX@>J-0Hif23ruF%sVB-EEl=QI}CLWqI{N4 z5SuOvnVRrk{w?DQ?n`AlN(;6sQ`eD;J#5`21;C8yun)R#zeAd6e>jL1SGoV^9w<4` zTjwtxmCEE!*CtlaF=#U(t9o(y$I)$yM|tpX4?f?9F5qHW*7?~T>wmk@5?H^Fv&8+M z4m0gOQsbT6;lX81z-uxEnf~sKM~5-_jwlg=vcQULXHcdl=jQ5}I$t4w&o; zBRZoxLJBiVmLNAjD7}~ki7ah@9u?P|*0FGl4R*3B>6^W?!g@CQAITC{IVWzqDT*j*`c7 z>flIrTWp~JeV5R*zS5ibTcS+4x@Q6Tk6s^4@1=S&<0l>_DNPE8#HA0aTw$gLUKHSR z>7ggzOVj)rd_L=9z7)&n3W^W<8R3N5uhJBn5-*ivnqxb)y zHtD0bfzV)izt1vYbb6|AiA%aJeVc+Y$yj4sKBm+{WV331HkAn4<77AgdR@==#N%7f zVZ$&EcRKk>6#k9o17QXD_v1`OgUZJCkEaz$sZ{2u2#6vCs_SZ7#KLJXuR{wjGObHr zr!fvcrWP|f!&>79EQj}RqWo^tYNdRzzRSfjhN2h60+#A=dI@sF{jWBl!eC!_)$jHm zxaYCnhPU9Yt@)@Mj^8biGk1d6qt7pL>}1!Y-MMD$1#b!89z|bk^@w#J`%UwTJB<9N zT7LW`ci$+_nQnXwwyDx5Z@PKq(2AExyb3nl`O3$m>Yo02OD=D?E%X`E^p}eQwAi+o zTHJlx%AgsMxF%H!Vm9q3MQ==Nh&B!x0Zr`Ln|50E&&|)27140IP{pUvkJLy@+_bEj zo33VQ-8Ja%3TFFiGp2w)yc$8(i%uV5jBMcjPbko>F> z_`hHI=wAb@5wE7gTKxoNlNy&_axu>{$>~MS|0sbFZhtlg7xf0}ryc2J#^<7yyP|aBNmlJAJpsxpC99R#hPp8P45=_on1tdymVpCHZAQ2qzQw8M zbQ4#aEgZY++Tjk)3m?BKJR)}_q|&fdfw(4vcMoHJG7)Z{5+pQD7C@8M>3M4r40DC1 z@rC@yokioEV~D-!Us`GJrPIO}!)UQ-8;%f#lk*|1(QeA+;0AIwW?c*|;(_?~P3%tQ zCbe?Q#}XIVV$uQq+U%==!&EX?G-jJ&w2r`BJtUeyc~tW(x!Cg6A)^vr={8zjjicNE z?>d(A-DHtbpW=xx37rK4`co;^5lJZ6tJw5>;t;g}ttT^qg0+#7mo;O8TT{q)M?;+} zy-m~TOr7{!JOh+wJ!&i=#a8U}h_0r9A@Llk=igAh{YTi)5r=wo&9y1KyeE6bQ!U9=R~spBN>UV*9MhlrG0phGNq=<2gsJ#+8oI510H z(apRvLtS1mCeEc&uVO%_q#^cd4q@_!UvVu}oMy7#$qSWby6$hgcT|bVE}rU?+*V(T z-=-XrK?v^jLzff{Z4;S9Qg!)X3ddALMULMV^p}C38QBsNzod-pU{zPNvVtm4F~A!V z%AZ04p0LWR(gFGR;X%LMKPvsMm+l@1e`eK~80mN9(__>6!mL+8d}z*QZDj6`L7f)G zzRn8kXDkE)!~ctz2XV0i{i(=BU2U;ArPIh_Hib`z!`YSRo`}T8Bba(c;8CpEuRvvO zy1MK|C~_db`2n&L~n`ZAnK|kxzxij%?nABYTE)(DXxU__CwoAwzwVhSWE{LsihTx3KE9 zfOU<&ThccpGsQh(bx$9)nt($1y+tr13Ug#JoTEs^e-*;Sque!U1<~%@At1_IK`JyU z=lLXjVUP|`s~L~1t5Rw{D5e3{#LeXTi+N(8n}3g5o23aDy@Ns#SQ;Vx1bGfxYQd)Kd#w*_ z4N&a4n;BG(@R55MH9D=Gdwi(zzlN0zi(LkZMM_M2N}pa$SbV1w%bL5l z-%Ujc1&Vn`ds-H3wPyQHf3Bk-zvVN;ez{U!ek3j=OSQutpg1zx)EZ?0jOb@edSC8_ z6F-$|$dOVb{pV4IyW529_!hW6o=WzyGZUQ`;<6p(Zob;iPCN!|H~&`S5PrHn}&ezbeK&R zG3EJQGxhC<+ob9BaEwlTf!w^1puzDA^*GmpIDwv$s?tmW6`PYHiNhh$T3Y!xcWp$k zd@C}u8Y^gBT2$T^ohFG%3vwzNFu;AnFrUY zhlqUxx(WDib=SjcO zN~_&BJnjq@eVhDO=Q&4zv<%gLV`*nUdc~8BM2peDhLS@0^$`4s7&^Py`?u&(OT4gwS?hTHAlcz+o@08;41=z*)vbGK!(;QP4PdCwf|GT+~!I@(Fq4*b>`C$A`=rqeWHXKDwSCNj8ZKXK0_`u%NMrA__5SP!i=JJ`%ExP3WV=88$)Gvo@!_Ya9HILo#@Zb-=1Ip>!hFiNs*jhbgmM4SU83-3eGF2Hn6cR_{;j1 zE~aZcMOx(xW@rKl!A1Z8RiKrQ?=&w`J45FP=8s86i9Mf!@fteEvmuFDcf_z^Mn zUq_Hn>X#Gg5k{6w4BSa{$xT_yCkw>>TBiiWLrZyXa%I}iUKis`6-Cv?{t{Ob6@VKw zLkXxn-%Y`%`*a&Mxy2;q60Bkx6F^&)_qz!dA$^C9)Z0GU*yh`+%=Pf~U-EMmkp=$O zr`ow*;8+uYrS|PVIQ)S#;&Pr)jH?-oEpA}r*ELW=ZLOcL1&wqo2PeHBWmyg(6X4W=}kT;k|sEq>I<)uldagNP73aFj{ z2pP}ae-8eU zP0Pxib9xqI(k*WOS^ra=^nQ%R*%iX(cJz%xiE@`PA)oWvQ|G@xF68&tF^=3>l1G=p zED&II)F8ko4xq4t`R()Ml<800gqvACBta)I7rxKob=fSS6(8;FA$OFfLHTk7jdhxU z+H;UT`Tpwf;&!FILpJgboA=5^HGKOHzu=bomy&T`=Ooa__i&uW9cKYt|N7dy_TLzQ zCK?Lfbf1kuPqHWNObH`fTWMhP44l5k6w}-hdM$UDXz;VuEZ>cKLSy!;;Fgz8&uic2 zA3Rf}npQ~{Z*SNpwMOR-f2S#ir%!jYa6lMnwo^klwl6#V*N^x9p-iMafX66O^>V!d zLRbZk%akRo@p;+z(S>HwY5wI8Gjo6yzN4*yvl|2QEGNmppX|NO%D9k`NmP$`e zAlD%|M#Gm>9Etu4WQimALUQj?j`QDQQS&0l)$73%z?k=cFlMZ*CUXs~xSDX{PNYKG zLd;+<2R0&~j_bo`tbhXi>oLn6U6sktSe=;pN=^lZYzz%3xDM)qwE+M;c{*M zhp}<{Q0me=!$ufkEu%`KMC~brqh2DKHML6c!{-zXO#3L-_FnI)z(@aNyvyP3zH=(eshKAC@%F%=^RGlU_qLSmT-pQpF8G0%Bn?;L4n*kJ?a9cf|A#!6y;C8oLZ3_7IfUV}zvh$T4B=UPPO2FAi?6X`0+ruk^_6epF zoA1+}Vq{lS{{p_Et8E|#rKDwlaoJApZ(FOIv^jqMtJQ#Tb^y*GF&S7ne2|_cm$Dsk zjjJi-71%!UWd7l`A4v*4wO;X!Yje{Uq9zAdQF0zyfenyhyQwGK>i0l%4iyUhd_Bd^ z|6>xg!NXX2a}rK>nWHo+GWCA`fnLOK&x!i~T$EMnRjEr&=sPr5Uc`9V*rHbdK^z_> zYSFC$sGsNXctq|owQPC+kA&@N5g&^E4m_M_1Pp8*tJ2pSdilj~O7lz>F?TzuAhPP< z$?a4X?uhs$WvemRgj{g^ammocy-3dE6t`8mE+S9D=QS?_BJt+_;?T)UmqnvcE78PV zGLb=QGDlotMM8sWm)lGpOW?^Ba@}nxXj9P&yXn}r`ANl$a~Lm}&3cOJyotaYXQJBDajMoV zP^k&@T6ktLImCY$x-rg6Uy9F_PQBa9j{eR`OiM1EZ(TsX|2CH>T5cTGyo8g9Ob{Sz zXm+2uQfAvLSIVt`*9<2{`h-|n?Y_;AYc78EP8JG_O}J@>EG9vz)dqLrpH&QYeBN~V zu(*uQbs}%;a=v{YzgD35)9s+B(Af+Qeu}B}Dw_y7RHBcbq#VCfiRs6Fa9UDUN=cTd ziBEjnf%SgtB89u%fEu4-v1FAffw*>MN|8jB1Sre7RfWL5MelRY zwQjGEiBsw<>BnfeljH_O-HtYaSf!5#TWuA5kw;|B2Mg$<9d+jsg9FU%)qC zq6n`G3Z|sRRM-F&#;#QH^7#xIgFQrd=9_7$5J%?3mE8=NV%cl*}c0x9ie2U?Znj^IJ zqr24Oc;XimJVS4C^rpBjWV#!MjPO*?aD})Oj3(z@gJS|)@DheR=#r3Pd>eI(4rkd) zPBqilTtClz@r)XNSZ!bpAWN8|v~&I$3R72r44TzszuOdU-Bnvcn!{y2 zVqdxz`+hf^JE48ZY1X{JQO#brI~RKU*@Vli-xosWk=t-wcNf`MJ3bL6WtJ}pR29Iq zEasj{{f<|%wz+>mo@#xQV)uS;o|Ly==SP#`Gy5DAEyu_fPg1c zc*2u^4Gmc}S2mT?B%&g=wmc?X@i6+~!$VTS_4L%M(8cn;PgngvZ{I|F>&!@);92g1yyjt4VTac>ASGLs|(-1V3n z6zU9KLah1@5OxTqnEZys`rw4v7&+lB#Az}5YPugnxbQlx>qx+W-=OfizH?t4`Y>yb zQExrXNkH4sWlnBci|@8YnULSKQ2)d1e1nt-L6Qo`U8Y27vL38qyXf4ktVkVvD>qkazW7pvVzvqiR7BBF)w_WGXI z8LBe&$z^ouRW{X4<~LwKl35kBFqmp}=!3#_a~j+WuYG@hx%HKK*!bzn*;d+<->^j5 z@{B4<*=H)-GY*RTT7rp((cri0quQgYdnU$?-3#vblb)=DjOSm58_K0h)NDK)*J~y! z`R45;;y&Wlb*903x@nd9@QCUOLj?T{Ppo{#YP+>yGzr~O=SGnWVOg(nkezk6X&!JG?c?Lxpt_#$p>~&aWCBuR% zGi6N!rA!lI!KqlA<#TK7%|iRF_0UOeCFk;W#U;@0x%)vZ@!vo~v3^6}q%g6Qltwz?1Gp>?GcDm1^V2Mf*w z`6?&pmW_T-!<%@E!}vZq)RvhgAx4_|@X2GFp1D>{sBK7?ZBLiIP8zMpD@^xcznp2@ z*BmgtA`NAbdjDEAFdxi-^&!zt8KcjYpJoHk6N>#JyCyW?Bgb;yK{+h!j+1#=eo2TYb~~xBQO_3UH-b+I(XMamtsb`704Vy1oL%ZSv9c)R6el)Y34p z2=Y*s*?+AVYJ)%8FU$zQ7{2jM=bCVFBVB#=}kWHi!4c&;#NND?O}YT;2M zv|(51hOS*4>nuAF<(r9Z4JZ1JZ)Md>p$V&I7#u9pWu;6URW;>J$2ey;ZLd;d>`n>l zbr$mNY+p^7v9WXr91P1zVo;ZS{0Ws5IdwFQJ55=aBjCBIo~>=Z(o5h&$osDTP>c+H zV0bC)77J90yS(iFGy(b0uxm>_wctMx7o2`cT=koCT8Y9_`b1dSk@IH4wm4X*>FKtg zxklBJZ?7XAT}uA#$H04`DH3^4&wYz8wBKXyzdTyGreJRrUliNtxBMt_Rcb&G)J^7w zoC9x^n1s`^G2mwsR$orw_KApuJWTAH=5o}09H}QAd*6A@k8{O}`$_Ft;m+=-*}^ZY zPv}0942n-Wo{z6dO^@j}GAQv1Kq;Sz*=lcxq>yY4QcMyuG8u=Ix+GIHU1PbHcW#z) z)K{?X8R!+7=qH+0GoBIr8o0Bx(Q|(BGysQB)o9_nWZ+j5{<4hgw~sGy&t2fEkM&_@ z@aB#De#L4pZL9?Xd~8mO@!tH;F7)Rc&*h(!J?T~1ofl20dpYth_+^JwrD#&%WDEaU ziEFo+be2MQxq;V>69^g6!TH;ALPkniR@EVdWD-e072UDpyNIAmZ;hsINAdmJ*vbo; zwu>%`p05*iZgchW4f=94O`gxtu zy>SE&#sC_clM3q<@&x%3wIT<^D7|eXB!ytn4@-9-&`XBxy)cC`URJq$NnxK4CeZCA zQtK~}{QAOfmcFuYF-3;NhmN9)$Bao&OhM~ov?od1#qZ}UR&7c12jE?TUL*spXzDx2 z`sYa=478M!woKXO?nN`;-Gg7@cUZ~-acgs`qCa_j)nJt{yTPJF(2{W&;|y_S7KSffzP3uK$c zxgneOxq@HENx#m@XGjb_bFhd0h!h375$f3}Y(VqlfcFumo}9oZ9d{LlXG11=wH(D+ z#fgYY%OHXiJ|1(^zIT0U8*r~7m{kaWNXxgRIa@cgm~4a{Y^@ENuG;Jn9eUfW{_6rQ zty(|JO{D7C-NOmVv!`NEZrvBx0)-+)3q^yr6t^Np5{d;Y1SwFQ z;7+OFE&=$Aio&d!u+7>AkXup$h-*fIb#+{+vOBmOc8q(a1h&t7O>Cidc;2uAhm^U36q61-un4Q3^$LzTDl6gA6(SiqTD)2 zevkSYY0g$Ke((@YayU#bKe0Jl!QQw`c#Dn&qa)RU$DDg+L0V(+WMzw zkG&za-;+^+htn%o@sZmwuCw;-Wfp2jB+B^fJl z!n!*&4@Bh5Xt zbmDlpjRC0N&4%+2AdGGT_#QQFg;ztBh5fVY!`ozPkIZ&uR_9hB`aAqQ+j^3@Mm?-z zZOc{8+1tdcM#pNOQ?`uJ0bQPAS-QahwAlz00Lrr* zWohMCO`{N3pgB5nkiZ`8U?%UI37_W%^JW^QTpD}UfQBT5A+EpIAm=rwadL0%00Ep(ajCaju zz&{|c=Uw&viOL-Y5IdY$pv#12GL;CxwF1IJh?f|%gVXL!IkbOp^!AE5<8~8qzjhT+ zsYBN+hET$;O@$x7G2Y>KeE~LbSApcusH2t2i-3Jm$7$ERp=@vJW?!pydM_HfcXT%; zp4^kgT#D4a(0d-&%)iUw*hi%l$T%9o4pD8zk_u>9S%Mf=9d@4X&{qZXApD;x%UAnr z<~c6hhc#D8gT-JRuGx|hXpWtZ`jm+wRc{&+2PTK>bW6!nod?lcVs7T6pH9>}l3C#p zYtR|@5f71ODA-BiZ~)HKZn*F#-nbqBpz?8q?EbjXvptrn^{hmd`67LAuC3%&P#!fQ zl6TRxh{i>XeR2AgBWVxbAQTe!TJ^~ZTkVTgkH?ENWLgEq2q#xx7B{;c@&}MRt6VE* zH9UjtG%)!4C`54Qh1iiR;-KqU4$_0&v&hLVaNqkbPkHkb^Y&+jiAQYgKu8BmqheO$ zGpGXR`b4y!O_2(4I_r3J+=C?)E*%%IeN{>l`{XF+GFp{7^49Ez z!q2D;F*48LcX4G)nSK1c1kBB2tVZ%u-HW|8T+7hmR?C*z$E9fRNPi8Q_H}iB4JSqV zY-Mrld?Vfx!S#*CG+#fSPRL5Jm&q%+%q)e`)4DB+01@7tIN$?L-7EFq+gnJ79rwDD z5Ks!I>H>%CxZ&T=4TJ*Zo_f5O-ANVzc(RUyPc!! z;akj;*=x2sF<5Z+S1#M;{!RXcKQ5_E`#~KZwf^@}V-T;mFB|EhEdug_6e~@KC(?}| zJ{d$)x;qX!mT+`|{0tw zz7Iz1C92=-&R~&aQ)TuV(DB(i%`iz#r8&DF3}N{ds-qJrW`I|!f^}(I2!6;1JiRO3 zv;j>GNa6+hszX3i>u0X|LpI=&()|{Att+5M-@Ei%L4;b)q{a_f7oOUbl;*HMkN^Dm zUH)c2r184gD^>UYx!)FgdLr<2AapjwCI?m0y$LFnA%c~*sk|eApHHGsd@D131 zY_DGa7t%yREkxzVR?L%^y3;Q6^hWL}JiXC^FV>uT?A|T8ik0!j>!xHP2mz|gQ6$Nj z&;9$}*Bt?t^la8(P*4HI1PwRdqnc~g*S0b`|!rEC?baTDjo65J7{MHP~Aat{^}xtf1Zb{2&Mm-S7EWlD#gD5&Hv)gK-HH8dV1|F~0elPN3sP?Djgq!my(p=}s_GSrgb zQ=(KwQ~A+=&1oi5X6SeEan{hMzqg@9al^cW`5tK;XiW$$Km@!qnnrQ|+&bLz{ZG<& z;r_&N`n0|VEsHh(H;54bT~hFWnkIq&Eb)C#9~+%Ro5PVow+GuC$2*nIi!4Q)IPP!x zq<>Gpwe$b>sk>}r-V0-f*{~kH2x>Xc)6p@!Z=o+4YRuftaq#D{%dA3>x%Z9X=-e4H z)U;6fv5H@qUbh3w-m7s)a~KIl7^_cZ4mKuYI@_=kB(rGg)tYy z!H=1SeDF!6_q77gz}U}X*+IXez08<0ONEt}s)#yk>SRSU6HQ%CSlznpDgzjY7Y@T0 z1{8V#vHYEQ6&Nd}>9_TU~asKFK>3C~r}3_=YpNVT>Rh z+z>d&%_9r*MIFq&y<6iMkNhWb%Ek14=4PP!#nK0)zd-ikss#v4|0cKLE6~(^t-AU0oi2 zHxRzf%U5+$+=4qeeWCoStH+P+w>)|zu+?{1F*mm}aVMB{`Im~o9nEY6 z03KEneFE-KMZe>P4fMIOV)`&1 zZ=LTsWGC5rnx603?BS{!X)C&EtLkQ(<)u?>!a8(+{si+ic zmocJkw?ES2j4zD540>mST&q%M#FBF<6S)|sdAO?pbb`XzQ#y~k(GNSw9xz=&R4%<{ zW&S?gk2g;oXk$qX@2c&09Qi=1Bl0{uk6I)E7FCU}Ex-u5*G+>bvq)1sM%>Zf&DQ#j zIBRIz;-Dp}M$~B$ur%Ij@#IQ}3g_#BSu`LQj1?uz29N!g%xn^H-E+%jhMWau)-qUfWeY zAX=*Rcawb;MR-fJ*Z}$64D3;oYnxTjyaKIhwrAz0qQFcS_*SF<0-afXXlE}%3pwSF z27;**ym`=!x>1blTf}uz+6?D0T~wMi4j$tYE7(gF-7l1Go_8)^wqLnY8;Rz8;1T%& zmW3Jt80Jv#C@6@@d*K{&`M=N~2AESy3i~nUsfw-1%1{(`TX;x(ZJYTHLO-baOl$O& zyy9EWEnjdp{Zc7Nl$<-y*~BM#l}_xpUvN{Excbb&0>djTqGF%yU>i+(+yT*SI85fR zpA>j#xz;)sc>PuvD%-@gMOh{tze=+O0b!DvOBLDU4Vy5f%e+fXoyQ4h%YR3^ zrd1tW>Yx{kHNrw%GH*tk(fx}x13HfzXwNK$>hTqvI_4T8L*Wg)t(RPuzAWlJHzP`tv{bx`ZWA@@Q|L0rt9+36X{JVQoMb4gg z_r>p6w`@;vX|}tw=EW?QB6CPct+IPY%tan=oHr@%`$f+vO~el#_*=oDOX*leIah>*`*!Zk1Tjs)pTMHsFqG3P0)y;@+#i zx;C?YKn65y4%8EsrPIlDB0Noy;RAA7;O83k?J>}IS7)1 zx3`j1i7Cxa=I#m?;T3-=7;pRe3jTc)*AEGElEfo#wyNwkbkiY}J`*G2>DXv=2QA+Q zUwQp`q*=yB+-+$EIqX+63RkI_TvbOM66(A03Y}BV|7(-~N>nO)%(J0IVbT*f2DZje zRliHErj4p>bP9kSI8P%lYz)rX>d&h}lZj)!z`2AZxGNf2tvfNH;W=SY7$^dv&1^Zc z-x5A2P%qf}Ih0`eQOznimfG62P=ZAdVh1>Xi1qSVaaO#qqQ077Vv(9f;sq7q_B7g0 z*w3f=V&n0ne%L3g%z>tpaWq~%0!9HCCf^}WXWg?@)c+cR#_V3+7GU7t>Fbr$?JPs8 z(II*V;KTOz+b!n9UMOW0Z>y(AD-{TQCiJ4{KoLBXi7jVfXa`nz!aVO?=!!j?vQq4X zd}v-0Gi)_IFix0bHt_4A4t#Xiq>{OgUrik%7zq5KY@W%u!$<#q>S|8Ztpl_5&|m-C z=8``yN35%OUeSLP+PLq$er&Om(rUW4Ip9#IR2-l=t2GquTu6V2Y__%v@DDydV9$zw zlApB)WnRHRK4-8_&GnYG@O&wL{%*9uRH#sr|s~4mOY5OTntt~jW5O>o;$J5;C>foH$8w+_;=nu81hhdNFNzwVq z4`1nn>^!UMM>4DJTy>)dh$D13h2^)q25p}FWDbt)zaj04Ym!oqHE9+WNludY2@L@e z-OFfb>a&xV2ij>`tq@Aq1Ccp9Zp9(B2@)t00C`o;!#fjG9?=7L+X$T>FTG)QjH~)Si|~RlJg*a80AG5q53N zOi|PBlQugR7%n?dbm!;{HJAAI9Z-84F6Pi_o7nzw6?O7=V+4(xCS*BJoJW222<9KS z$D!c){A{-np)1#`W*mB2IlpjIE_;7PGP5I~e!K>8AY!@O^nt#xSr;vJhExh?VIcXy zju&yHjH^~6EUU6pa)-&0&cQY18b0K<2PnBb^GY58tqt5i>Mrm(^bcxM1k2P zq67i=1;&n*Y8z)o4ztPn5qG!c+x#|g8+%Llku5{dl~iL+W*kt5_m$%B9z$y7J7NZ+ zHs^i}xnu@TC`7?&=ebhAbtYfmVgEr8&z9BY<+X`u;$RKc`pGrNCw2BrA$%;BXS3mJ z83km=f}>$w=ZYkE--2|IkznMhvP1AsrZ4U8qbTOOmYek10rkd}R-OQ~)Owc=p!^FG}(6eOknUn(-o<282V=yjaYXe>l zrUW~L8*LP>kV0i!0}8m&I`kee9VFvVKMI7|kfj(XnV#$_>tc^9gigsAA& zm+AmMgK0zjtAk#C6I=aVQtJg4DSB}FvF)+^m|L)NK&WH;bC)0|T>B6p?lv*u_^6a> zXuj#%81}eTSg?bsEGSzVHSaz1YYa`dH{^R6;5p_C$cv4x2YnZ5SU1iiyc(YaeJtTRG_s_pjT)5I??JYDIiY`V;NX zVz-eK4JPs#t5)9;uaP-O`EJX;t8q{nayT6F`Ko1 zCxQtmEt|#k_Y5w^78w&Nu0AWnmDOP_@I0U?(b(M8qxA9If?CMbNLUDv(#y~7y!pNP z)x#SF<6v@DMla6WnyO9Gn>e&SH}1--51$z^=sJ0pzw+S>x)z3wDRhNvgQ#E(jFnA@ z?X-KteidPrnUM?y(~h9`xl#S%f%u=e|EcSoxKzOu!8GQoCVwKyi|*#XlIS%rzu~r;WmL=#5 zu7ew>`P#5I&Lzku?D746uHWjaIK=q9kr^YgHeV^m2E@3t+z01dzJF5SAy=_tsr4rw zswO0MX13{i@^weUBg^URw*u`y2&i6nSht7Q-~gmKo^)UG>;xo=-EQ z0kF>|09z%A>YZbXCCW&nU`K5^(;P9U(0Y#!REl4xu-Sj6FRd^h^%ONx=GkuPci9&P zK)dJXB*)Z1+{`%rO)d9n4(x*?1!7%SU5%qp- zC|oONy-79KYc{+1WVy}Tk@KOPR)CRUL%56M*YBPHAv4AjI%$J0EM!ypFjfSksb8Hx z;I2|?KZ)i0@@8p;-PLNY`Nuq`a%7J|R3^Wk7^xZ%aPP0MT6lHS)`At$#zJfMc}J8; z3!PF*ZVs8pVo2aZJ$Uk7Y7+*HgaLX);N+^OH|2R&&kAm2jDZOyHBRS^E zLxbQZfeU7n;nk}RyO@VoAy}{2H2?C(?NRiKe@s^gw!pi35GMjvyDBVuPe~XIHcle> zn0>^dBXO;zl*{r*a3G#WB0;uG8=gH_ffm*D)z1qvhGg8g7_nT5>DShE@m1LYFc`+J z8V?$KVyr4g;0T?=B}>UwHbr_|`vJKTn=(q+Waq@87Hp@0UoVU4^1EA@EoS?oXJizt zK7AqtqfPxlYJ-3rha^vQT$4MLivX2W2~&T zMA^%(yTVFwu31&3KnZPs4xUMA<{_eYX7ebj%rfSv)o#5-$PUib$Lb)iw02uhkLatv zP)bFfuQ9V?C`UkAT~W`3e(U79tWkl`CX&lxM69Ds`@sl0T1+v_qFK*}W$uecU0Xml z%Dw`!`K*ztX?Lk~50=AmC(6rkv^k;ht3R?FtkW{q@uY6rKqza z)7}`FJ}EbRKUnAU#q>nY2q4*Odl7yTs8}YIe@C?gWQE>P_6~eqmByK+z_GaE7$cws z5k8B%(~ZpyDVtqyhfx)L{TRFUyxrWurFDPRnrG~|*F)r@dqWzHc$Bl;F$(=%4YEo* zEceZIK1fm8S_Xm(z}ZcnozBP*Za)=i_ZBqS6=fi|{29j+I$%Us_h z%9)JR6!U~qQc+N@XyNHy$ylX)jH@%PWB$dsn=es*;P)!$NnZuKQBRY=560g`TV`xr zTbZZSOrGfT_VnKuPt#d8@|FoVFR`b z$eyF<(V|e(;p5Cvp;#!C!X53NYOKgj3n!L^JaZG-GzH z9Mu5BM)&(nj1)A75lT-!VaqLTXS_Ft;^}X~9^%^BGFW%1X{Fm>84V~OwA^;aJa<&! z8u@-0U%X+-NI{phzvsE<0%ZnQ7L@~<Kd^gt0xQ5?Nel%q(pM#I^9RXL(xF%7j z62(Rv##%gPl6S)EiTz~mCzZFf%3MALGw;4ez30wae@Xu>&3H7oo=ca5x6PL0Q-@dg z6Q18mlW8kZHTi5l9jAkf`5bFUIeep} za<}G|T@5Yb4*iVQ6_gooJ{=Yl0-stW@w)8ToL>_A3*^m&CTeNA9V?L4ir4(unfWRH z`h%NK$!J1x_&`U|7k=)Oo%cyEO(V2LsUDA}rkSy6kKkgi#ZSh6EplCoZ_h8+E*7qQ zZ+2FyhT>MxrS6cEx{vhM#$hHpSAy&?3a`TL#$HO~vV}}-^PLxVIOx%1w%^j(@J6rK zpC~2MV$~f3#k0hkepmpFcv+>rUY!#)Pqt@jJY$Ko;+kI3O(*j#WeJ`Y8wsdz#7ZzA zVbtOT9FF>fKCMW^G0@nJp9H~|1i#yJ-t1jksOK^N=osyiy1YG*&%hV9y- z`dwPLG+K_;GR?#gNM7W&L|ptxh_cFUStKH1>J6|{WhU>TOil-|)9Qqx)e@OvO&^rk z*LXWL&ph{FZAb;?rU_n)R7xC$mM_8oL__IF8!5CuUw>N6iK77^4CjBAl z%yZd$4l7e0_4#lk}lZO#2{=%B^n?TY@ii#7+b7E zh<*_2ms-^xvG%3{GU7)I7+{18tku1wjpwK~VQVHN@F(grvZ$ss#M4vw{!>y#|1Fqm z#2BUHapHrTtc-Z3%PXTiVkxsH2U5iNSECn#|1xIgb`MW@Fzty&9TrM8%1)uw7N&T;wX=(xH*VVBTy zx(tse9LgtwS5t=cXYp}auyRyqPw&WX?^TIU)tPar{8-!Z#SDA$$@xe-c3p0Fwvv>h za2f-;mhlAq+%O%2dj^(Uk+1nSUtwl3$-T!sHE<1W2hPLQ6wymoH8arN%6uabkZ=8^ zQ(Nq}P;c`{zs_9D+kV#-zG>f9W7^5=`Qu|{njn(S`3XbU9zHadl$(c8cr`Ps^8V)< z+iVTD>BVeL>ukF-=30aTjNq6JKg>_u9s zf6x3%FO^E|AzRP>V^SlmvPy0`U>g50i@-eIkrD)YbTj6>dsfM~WVvQ&3Cct;PlEiK zeagr3w)#1BKl8xlqyjFAI22DM>@}wq!fW0CCRiFfYC&eGW*Vr}*>!-zCuD1y3eS(4 z8uZDZ6jKe$@h%?J3%(s&I9beyrIS9#X=S3^Q@B?JUHij620ap$SvFia1J~1aHkt1t zku4vaKx4JE{4Ek8pva+&kJ+@<^S2Q655M@l+Q|0$z_Lim@S3we#jTl5$?aFA`Wl)2 z(SY3*v8?tSSrQ>0ASFNbLoiyc@?HbuM;j3;8*he6h!eMH3T`I7}_wne-z2((2OkWEDH{T+n{Wb^?L8$Onocb*7c9c zlFm_gCct@6v5>?ntcX>ct+OUE9WvPzAoz0R<0V1jnSLp$1J-2 zTJ=p2(lDH9G>yg8ug@mDYC#Nd`Xf5waNV8o`qydSuW^>RD+8yQoVNB*e|HoAmDLWdnBzf(Jl%<3(Gl0S zCaPWW0HNbJ9yKDw$M$abKg0VEG$A&=Prd|9qEN(n$=(+V`)n#pDFR*gex_tk0%Z8Q zb2;0<%}eAXeol|b{yLM)rAwUx4-$l`|8wWy|H{?+Z&ULB1G_!=b`^JCc@+{ixKiqs zX`S5T?JWexv7Wcz{XfrFumh)#@?T z8x3U_3)leqXY-hswiRE#=^LWNo;vSsL}9H9dCsdiLiIfYShZ8%3Ztd=s4pDRqaEfx zfyR%?iaPfdt@DIut|WwY=@igJ`9o!C%mrM31N@ITM)qvf6;IuMS<9Mu7nTqA#ZSL3 z@~1(J1*T>6i?h4AAO9t7I>iN1n=Xj%ZRhYPnZU^1aLBt&%A_SCHEPT`guxC2F~M;Q z$W3x0%#*$_Xg%+6%0$k)FSSu^;xzB=!4R(obwjf(J|go@S`F!0M?nmsDgj4vn~^_G zL|{7sJ!&3#hWXm-9+TK?jcv8D%wRrr$vu#5nfq3cSkR6CuC@J6`+b!x)mF$Ww-kI@ z{nk?}XBz8l09l3N%!-QlM(3VbVbjjWATOJ6cEVso7$tZRNRaTYZ!$Y1Ok^}8J!#$z z!+-9(n{^t#DONnZ6=y}C#YNW*)nrLIbOW0n=VUF zFc;M>aRvN+ll%rkA~pqEN8zTG{+uW;M*m(1iw)P-hkW;a6ZN?@g+L4hs$kz=%96kV zs}<;aAZC*;{V3&*>(@tGRhp;?3r~$3hx%s#pI6oOQ*_!v`I*rU1ZjHya=-~+pN&1SNA?!Q}twvMh3TWA}+gW3*(55Cn*`R-J{ z+#aE|EkXt4<#uL#PG@4)u)a-asi;;!S8#hFLzA_qGJ0C6t|r)Va%CD|f10pPTm4CE zrrkM(<7vm5lY&L6=lkmQ;mosl42CiJ{z%YgrFVkqSMQo6!%g$t;;TH2PnwTVH!GB~ z?B>pUKUrb1T!~mgUq!Q-AlWvh!F5Ubqy!(4b0BetiWJ!>0A+nL?V00+wi5Sw2x?cU zn!2CPL*WbQL9|z3f$~0fr~(Vh5iE9ons4UslrzCSqnDSO!Jt#0)S@nvNGT)De}|~| z9|M-Y*vlJ#nMW-BezX;{2@dB?vFZw6`n?}-d8Wk+l&~p;ywd;Rselka^%RYxw0lZ9 z%Nz9SuF6;-8QojqL{0`_fD~Zbx!=h{5SPxS;Tn*W_rj7xJq8S~Vqm1;j-aKGJ_hxy z7!L>Sr7>}@YRWE4WG8F5#J*{;=2nfTSV`$B9=k8uvb}=k}ub}6-{Vk9pq_b4CF4S7q)!YYLhHEOQ9foyz8V)ZrFF#E z2{7xPrg|I6ylUUU^xe$IXvuu_8SZfrEFLh^;F&`@;HJ*`vi%md1_V#Fz!eU9O-g72 zl=mVE9(@}A^fYwlaYZe7^%#w-3K=r_@C3Q>o_+>aC-^eqGd7K(B!Zcd5xM-y+dSqP zM!L4@KRbpC>qJ+*`o!j+JCorDt+058dL_BZnREcLgL^u<$dMl{W;z<`#MGPl9f?2u zSqwhpRPK#iG0pH2b*DbbZ*!wq$PeAMvKxr#&*s2x2WWYMba9MuNj62`(R)KmBYacW zfSzmB(JfoXfU8Unw*BDOj@yfco44(Y6uV zV5UsZlwkNiu8Uq1RL$pljSw0M_~5gqar7&Hjxl=$1k#@=#4v6}*lKtY1iYzOu#$Ik z`dBdEd+gS==6{=?_&Cb!L}1lFgH$pS2!=%~tGBv?}gd6kZKlS zxH}@wQgRww!dP&ZqHe3bcdH5MZWHp%b{-#dxdu7!EKeimRm7?jU$pnxYc?o8Hq7!l z+60{Oq4BKChU~G9d!Js?RBf(xb@oq(Y6E>f8VwW&Z*qjohA0$kYN8L=rJOzPImEkKDC$*O%aH1gzyMqkMjDyD(~Zxv9I$pcc`tFpbCPR z&7B%!-8aH{0S2U!x#Pdww4Ih}S6hZOUv$~l#4<^F!WORUzFKcwGCM&W4p`GZq_j11 zP5XILNR&xJUbTPDUqb4Ywp0s2!x&6TfgZ2*w;az*_7iO~H@Vt#SmKxyF(~T`<_`_n zVu0Q>`p4sB1#qrd69^-1tp1=jGuYeBh zbZ^*k_Z2YhupTg?k6FoqA-WM&(SCdgxmUA)^+h-nG5_bwHR;neIVX+aMKtlgeNUYdW$56CML0!;-dBK!~e=8_Am1k<$zOz--hAmJacY}VR;=A=MRF!dw+|R zc(?zAclAu)Ql}45^WDEyhDEE-QYZULG;;m@KyAWmt~EEKwWsn`T%$q~xSp7X;bo2?Z zhvY5=+o<)Zqe;4-=A*ji?uAByQwq)&6Uh|;a!tL>>I&A(K>A$B8*ir$Nw8;p zxQpc+wRN6ROha@s4k5!O^ix=?6Xh+lQLT|z#?{iM?4Q5ub7L;m8F)`RI=j!V!F+F_ zN?(lPppBo3T5Ef0@u?s!-I_E}0Oz8vP8PsP1h(w^Q?3uwcAvIqzfsXkw%}9-9{WmW z^E8vQA5LE=*2kLkGtAg0))?aPWwoC9D$jF)TMliK_{_ODgepK6N-80@9oa?f%aCnJ z2;!A?Ykl@>!gpPuV$*=~N@M$b*oS^WY0eCb7iAX3vlVy_&%$|F)a_NOb~p;J?sj>X zz0I-`Ld!}k7u9e#iqb58^V2<#28=WEB8bUh?d4B%gD>3%u>!OA)n^Yb<;}^mC^R*E zty88rVX&Kza+}~RQdHeZn-qCQD!H74%2(fM1x;_O=3XmmWBrv~U3=`U_KxPX;cgvu}yos|HZ{jyH>*Z`WYW_h`>6y3iJuKO&1@Y&L_*Yiu zZ)!`rc2%W*1^zjCZ}b^P!#n`bChS85ems200Xp{|N%WnS{LF!|J@K>hTn04Yrt*D$ zQycq?YM0GW8Ah1ENvfZHP-$JSq?3C$o~#fvEiEZEmgqaKf(y*|C?-Ib&BnV~Y3HRy z;X80#XrVUuFr3vr3)oWw7}NIa@d;UCY;tfuvtv)8MIBqtLw5cOn_xFcnk7yRJbKrJ z5(Ju4<@Pj_^kPinqqT|+&}xyOJAX?f)emJUIif#8-8aw)73+S)lY0<;`M{f-A&?t$ z7{zS|AmQf$5IzJcP~A{nm#%*rurZf@m?-!a4e_OrSm`7{it}@;%$Ru**wQJd1g(dHT z#lB=Jy+ieWiAYZ1z9qF&ji4Z**PHmQ<_$&a|I zuU1*kWHBP1F_FLs3Fe|+aMVg=^L;~8B&~3dIz6+XLG0SN+CeeccL1=7{9UzS-gFXh z4KaD{fP)LC$UNRW&|Kx#Fx1$r^3$^!tnYqxCF(34`DiWgl$8Jjm%(GOqZyOdIbOX# zWaLbF=fH8ueVJD;+UY&R(zcj6Xz#$RCrxN9k(XduuHA~`R99b#JF8b>!pTIK?5ms1 zLQHZv)CWi3&aOP)IBBx0R?x6<9h(Jn*KCeuAGU-5e1)xzHP5pbN-Fx0NKyyDO0=Ln zi7DiiQVY+`t}SFAs%JV3H};)IDLXrv?ykVIOY$>KpDGBKX=i>&&(}zRG-l3K#Q76s zLxP96DWnEN7{NGCWg^UY5Oz;Q*4V@l@I#E6Oak0ohGTd`lirARg&W zq9Vcr7_^z??9UH1k@dX$rh1=xFF~`Mvbh7xKNY1r_U>>?NJuZYY+jZFu+g=0Kpu2# zfyf*T7~}GtD}D#2LC@D&zRZ{Dl^pu+$of=ZXpu=ZY$M)x!uZq zEVeWam%5dw=g{_;l>i_FCm=z}u-*>NT>Z^W(c4Hdra9gU^*>y`8!Q7zU&GLw_mXvF^enq%n{b80+U4a z>8dZxC`)Dm+=W4)F8Z+`Zas~v*I9BAUCNHBukxMm9fiKZxhHLl0sR_vQvvDz8Zdh+ zo~E*1n7ELkZsRuU7l%eNAJn4l<7-QsqK&^Z{3mu*qePYHj(KD_{$iX%lLG#!u zM0#86D<;m$Z2c#uU43Kfq_ui9dj1>G19pigUWJ@s!AGpm0Xo_6k+jnw0ZE1`iISX0 z^5wZym4TW$DUm($KP_~3a{e6 zi-Vv9{EWsqs~rw$1YPER?8SM5;zafDU^Y1*JpH7cv55}SOHz6V~wx2 zsH>M>|LT!2aYsrOr54_HWOt_UOGb{3qVe zwWnYq3`o2e;tO$jHR0egcosuM$;$Cr+Cr*><4Q;|6*hrraY@X%g9-6zfwUx{pys)O zJ_^=d%r{4@NkE8^bzD>zmuTw~Ogpx(u}CC3*d1`mC<>cp#KJ#@mMT<8EzLYI z?UhV-v|ouUlg&qzq*mYSR0%}2qV9%0FKwF?d?OBQ=*!?&FjJmk|COsnT5G6}e)#OZ z;c616-gMQQAewoWAd(?<#=DFoX>hr&88O8jvDe8p0m^7=7YpyBU$`4Hv&x1u;WK%W zW{tvKFBwLY)>uA;hyzuv&8X{r<8ISCJu`k@mv7isp^Id9SR5c+g`A)aE(ga!Yg)cE zWyZo`f+~(XLGkrON2xBh{Hu0e8_7701Kdvflam#h7MC3UA&GG>RNV1^`>{qfbf~OO z&sEq1DeR+Mqd%iQ9@%?LUeB{ChZoPLy3aC?LXzyBwfr&YRJ(n|h?aeO$S zkDoDBP+!s(I@)N@E4$V+DA2hN*CV`aXH=V8SvvfGl7K3m-GG0e_TaO$Qbc6}{CBM)sVsP!p zY((C8In=VrmPX<@tX#%Q5R!J_@Mv_|*j49w4lFyfQg@h!2+ZvJB+Yf4xm)wv_`T@2 zLO}I&zwT?@nCL(dN#xTA)RoJI3>wN1fVsT>MRU|3EEw8oHomh|gr-q3@D z)E`AX<@JkgMyq$Na@aEfMHqF6M-~*I3xW@Yp6B0A6o+U3;4RKv$dY9|X@=z<-%8%y-yMl}Z{O|Bmx< zzHI#m!Hn6P+^4rX|8>WZ_1aSI?X}Zp&X12ZpM<8*TfF~4a6UdDv0-ca#;7j*(c7!E z&B^cX_`iGke&jz0`eT{jhS~n%CoD#k$KuVDJpph3wJQ$IlH;Yrw4#51eYysz{O{}i z@B8`xmEQ|vYG&%x#`NvmEX0;ze0%RCw6XJS_MY#j)qs1a8u?^{;WN31J}C@9OT)4d zB8owYZc=YvP{`A7!&qM6*H-8ZpFe^!@E-(k(v?;DU_|UjcOJz3Kf?< zcy$`~Ru42+z_^ISd8I0iO<36pP)#@RMNEO?yzx9jEixsyi}hG8fAa_anE6m){$Elr z)fp4J8kh7v2gC0+5Y683!Gx#*92sAKPQCV1mxn)KOZ1U2zv-LKftoI{%#$XytUc)( zxSL7mv_llGIvrvBbAfW_M-5@kg=gt>ntv29Ogt!TyeIGyk~GTp44vVX#oJ8k-Uk3L z=}?b0rl&{fM7q#QxntJ!E!`6f)EWf#-^`s@!UmdFmme{9z)`$?P!Vx4_P5GXWvzGB zB~8-Q^jMx*yxtDa;^-c&vQRNWB$`+tz1z=kcRzHGcJ(}4x;cJs>HIsh)l(SzTRaT{ zl1B+3;F01^M3N%r$mDGdy(ED}W)Q8PbY?@>L!% z+=?E1SC-E5)z9#BvN5tT_{!oXoiC5|_l%b7S=Jcd;gCVtmKYG=GoQf*>LA>QOGl2Y zfAB1Nk>@#GbAiguDHn%-!*QP8=H!L9-jvK&59X)gUWNiJvv^2Zjkalz6V6??IcZr6 z{Oe9{B#Nqic8EibJ(n#uG{?v76A!a_Drfx@_vPY*3arlxSJSj#uJbBg@>L>3Rg98` z<{F_aHe5ExsHxjv7TtnMRuD9!D509taqzteSp8narf=Z@Z;=ai!AtYPK1{+cfXi$# zAMejuEo~N=?>h75;%G69&s;`cazkLt$5+%BA!E8sO8U61RnX6BL=XY|zGj$Ho0<_* zx+NYz!@$-7;T@-e)H^g$24pej$cl2yEj(Js+e&ZC=gAJF@}E%bOf=~GP1J<3a54og zR!=vbi;aF|8u@538(@-c<+Ad@j!yZ3z5Xqqgp1#LHBheRFj2+uwZ^n$@Q7zq{^Ji7 zn*(Mr-JjV(3f$5HUT#D~9&Av@BbrK%6nUZA!jk>%qJwc0ai5D^?9o2cHyrFZd5ylJ z;1hY?org!Y-bMG1;*VtlLF$UOkyy^I{<$E7-=^|!W|LMwN!HFm3TMO;!c!KuuSR`0 zxK1ibGy(m!4kXMuT_U^bk(1KgpC%N?Ukds4?3=7rZ?0Zn^yFeEH9Z<^#98vg3lfuz zB))J2ZmyW4WwH?BjM1V=qQt{{Oib-RCm}z&P5TTE(c$NlO;%Qbbcg0&o>pb~BsVa& zBSq8fB3jh|uJ_(mWGUn>$n@9K%>Kc=ozr8zZPz_JmW8I3_zHwr--jSb;i2K!Y#pv_ z%^n~WszmOD9OyP-h>B|3(iEYzv{r{1k4g1}pN^y=%B%yPcRd!^ayb+6z!>IR-p_i_ z;s)B`p8=t(sZv`=Dp|?-i1R|q^h-#BH=C5(YEo8rXkNChlr1~B-c+{BQX|_*g!)T_ zpN06`>Hh+p{H9|^#}xG4Rp;tOwE^{o^`x;yWr zZ`~I{2o~Jkord5}aA~}88Vi~R8fY|V2*E7`cXtiY-8czu0fIv}5WtsZN3*IHvf^Y@@B%T~8mt)+Qukk=?bO~USF17I?d z$=ST7sS-E0IC;^|$^hO6dsS${JocwHHH2EmqbokKXa|jpq*(2ScFG9O-i(XO{%})e zb+#q?VWb(3l!aT1Yu$BLyGV>;4sx%b~{YkCUvt(Q2DRG1ukLQ2A z@J*hbkrC4Oy3n$`R8NnzN4fuaPsI;}>G812A6mwNGW8zT&9n?Tb_%`u-kdp@jW4b8 z&RPyT#*x`}q8v26RnBtbYXm8t_R>L?a)Asi?a7l%^viIHhQSldstgX62c@5;k>8&Q zEW;H+x}a~f`B6Uc$6C0+cwioklMhoRTZ%h-k9W8v-+}vrbFqSjOzeIDBj52?=kGJv zN#8YHeFW|IyT_ZzvM|-0>zddg-AcxiC3d~gC|*(~?Xz`G1lB(3nkHDks8&J?Rg!Dh z`AZ(mRi|QJx;oJ5qIF1(&>22;Rz1r99eZLt`+3QR4=CAP`W0kqr34g7_aG?QI%EV7 z$V=9G(j`flz3PUVww-k5?D!j4%!+V6o10cNN*cG~IWs7&!F~|e=~a-GBQHES8us;J zWl0iHJo`o5h3io7sj{FSWep;BZ$!wm7UV*QGCQDXy9(I+mZPfQHCo4sS={KAAx!(# zSCJdDwCSg7i)H{%F3QPYS%L8#I`LPF%Eht*1FFxZgn<+C#mOiGD)RT!43q3}I|KdS zBr*Xo`5z)XS~L6Vg#}8_^pY#-jC7Ezg>!HfEyz%@1O+)l)xO$Vwh3VqzfIIJXBiyt zVROai=U`|v`%WdIV%5G(=aW%Z6mpI?HOhZ7F*7}TY-Ra6I3HLC3@P>-f8~9d_nMKW zL%n?(u144CUBB3l>}VPU&lYz`8=6r`sU%gg8rESuH~tne86dFr2ey zeZ;Kj=}%XxAnmt$I)OemDGW&AeKll!W~sN_gHfgSCW+DXj2_juFrot{=7Eo`EwBqgYtmRYK(IzHv-uS(LDM@?zmgiX0lGB&%S)3wt5#D0jld8SlZ zzGp|AFuA9fA6u|MX%4JrO2wxM;GfrcsiWIyzDRZYPWG*N?K@+Shkj8E)kDBmpUdm& z>}A3=%#BJE@-zjUl+~(3s;+E`XP5X3-)#98>E=iVGd4QcJamm2JEyXs)?E{#cjInP zJ+srFRg5NXk+m6*9_NFBT7Hg8X=Np6X(HT!@iw?Fc1F376vtr%W{I7_OjHX~p9z zJX*Qbl=q|f`|{K^uYL?kdFBz*kP;nvY)+!Y7-AYG9w(b`coNCKDTmKV837` z&E?hPv&?M5t#c~R9s5zwl`RgJhsk`Q+5A)7VsTnfYqC!rEW0FiUnD z_|$i)7YG#4#Gu(#=POswJ+ENTqW)>SbS2fE{};w>SnGGU@w_YB&DUq1u)B|nVDmCc z&~Mav<-OTY+dKNz*FrP@B>cCngYK2Yn;AOfF0|{gf!DQ5yS2tG{BpTE&@g_O!mypO z{Hx<_&5vjlBpp7XrScM!7l`o*>l4x8)@#1zOEt0kIaMMY*I>P}_K#dUKzQUwV$lc^aI+7|)l{Kq#85$MxfJ`N{~!zW~t{c9|XG0k2l zBt9OsR*DY!+hlb6R`B?}sM}=`82gaA{-iAyTUhzl*VfC{&cL zpkL?S`U!kLw>ODTjo(_Gwduhy>jFBxzniX5 zl{SgxICg0w#~^%q6ye8yC16}E-YID!lV^+zg;pI4!Nn#mcX?7Txa5(d&rZKswDsvW z@AP#8-<_sE+giN{?4pu8X=$_N6g*X9hOmQHy*Bd|O&F42lblxO5R}SzwG7 zBChxyLF3+m2;UwB-eX8qKN2=03jTJeGz31UwLSE}`341DuCxrT6ZZQpNM=|80w5$6 ztvqTvpvpoB1gxaP!m6c(saVIdGt2)vt%=~IGk&ec-m;4GD8Lb}ZZfW1D)Spk^`3JN zf5M}e9+ZZv;WXziuz))nE?cGV5OWHWg7Z2=2DQ)UU~iwGHlShIn{66VEMt+eYI@A# z7XiuF31DrFjSUMK2`U&uW!DQtR8CD-hCS)LKNJQyepR_bEBG1+(xo%Rc&R z2smJo_f};` z)zeHaEzQR7Ii?h(UeJub;CB4t+{5`r=-_8R9Fddiw&!iG(UUWI%ApK)NdvR{rYr{< z)d7ZgQGK@3pL&^Po6H8C`tm&zQn@pAhyKD4z4$Iha(Ah|wh}m$0Z;FfI9nf6(0gtL*9*{+bCdH@kig9iLD&wh@$3$ZmrSFIrjmFE** z)hWidfybh-7-y$NM~U_T>gDV#RER=WWV(PX%D;wye=XG~Z7PRyXQlt9K6(rm6VO2| zC?eQ2SrnMT=ANU6UTfnWacpo}!i_!8)!Su!!^7LBtceJXXg(=pi|4aV^?yg!K(u^C zR1s0>N8TBIB(=UL?OS+&7>fw!y6)SHH)3IkA`SmKvVi|K>1a&j?NasUVTrDuZjJD@ z8m^U~3_@URCWBo|DLRf%Ipren4L8ixBvsUm2aA@Ok%m!t&9F0$uRyeq2g$@O+{6Kl zxRm88bkI5YHaX~}l|;cG9IX@8{ZY!$0F#52p3GGGyP?P_!?%T(bp$C+6CO_En-V6A z2LNOj$43$ETE7KOT0?CJAFeVm9fW?V1&UpD+`*g=c4N;1a(|5(`xfjb9xnXvZ#|$# z|5elG|GBuliMwjVrjGI{o|D3$Y5sfGVKlVZ%5qT=1H)TO9s{Guln`n09WwvqV~SPxpNgwXT3z@D})L)ZaZZ3(C%;u7&A<~a29Vq$QiOI}LQagG~J5eT!-s@2+1->!vl+Q-~ zJ32E152AxLt@5AX3g6y3wT>=C?HnCNWy7b~NvbbondoVQ$Z~G^9r6jOnn~N@h&l}u zQBi5dv-?18hYcI2@0v@|vKJEZ(GxT`&J9`9zV7`zcb$+o)ddY->koNPJ1rKOMMjY> z_X`ubzFgcgn@&YOjp0*4Rv*M}>Pk=49OUXUHFxlyZxQLyL`5gW>MnI-7b8neMbZY= zu2W7A-;UGL+kLB~cka5>860D_PWmlSIHSUo5bX*5a5AQ=>ALfI*ro^v0iv>Uwgg)c zNq5<2me&xmDzSM5mx?0J7|<)EFs`|iQymKaC8mjGn_9i@;I&cb*{!8F&}%U4-7T$a9-*{x^~nK;Q{ z=aM8L@=`FmS*@*fl}`JGmV0~u6jq)xk$;9=bb6o!jN@AwM1%OU{s~joOXtw|4R2-o z?0NGkvE%vf_CqMK)K*Fh#q5|SOLcV=CiB~Rc~r}F^D=d{+8E%vd2XMV&##-(LvhOZ zS!#W<`QsZp$L1g08m`iG@qpAH`};a_bJRF=%IPTM9seB;iEgNuzekxYez-#19-$91 z_S|@J(hFt%&Q$$FYt8$9v|eJHmCAUk{p1TX^n>xby|EiPti zT7n@JWq~~A(j0F$3j%AH=g7ZK%-(d}zWBAHmSr%sFzP+W5J9o+0f);iVsIm%TD-iY z2JB*aQD%hXew)aw_Oq|W2WH1-3r>Vlk4vfT3x}j^D{FxN>~fxUO#OyM}dpXdfeK zNz*mhuX5k6d9Y0<$@7&wGZKPH;Kz@vembKiNDgPH-{vey& z`WHsN;bondou^Ad4qEL z*AVl+2AEJo6QS9LPaCrhBR4}ne_$H_8YqH|O|<`ZvVTtfUoH6ap2Hp?yADO<1_HZt zLvYKORg_Pe&Nw2U^05cIzlhAMcz@*-1AIMo5n=<4ca7~A<0{`gytb1;@Ky;zC9heM z<5Z?FwxjiM`9JWaXop_z)?B+t0qt!*SCk!;gZ^5_nWr}`IF3n4 zb+a}&O7rn+udK&C*_$u5iw zQvpPHFl9Gn;O&GK#DmR>1G4NN!2HoFo$^KI=Nh74Xg5Mixze1c-@(>zYoE;q5RR?j zbOj3h@V}{hl@J=#XP5ZkqIos+c8b0WWB$sjQr#c5m8*>jeSyRc@JS{?kmYln)WLko zWN|k13UB1rriziVnBb>PvYyQw`OuAm;u{C~t9F})CvFm(e$h^v8m^zcZi6*QueJ2N zjgA=V3jMg#?$4&TmJM+KzVG7XXA1-tTTv?ST1MVd^u+H`!Wm9j5}7h^=DS~S z7N&Swb%phOWbitOofZ0|6sT6N3FUWb?bmlVrb@vIPX4aZ#McP7eT?vHO4M3>Ad2S0 zRb2Pkjs=@Jzh@(vqUU%K=}+dOb3jByCsC}j2C2G|KRm~dVmqgXH4_d$}}L-%2Y)&P^;sLub;u6e_L*d zlAU+4QFcq^%fPFfFnH|nS$xAaf-`DWc}bXcRD>=j^jY~{aE518xM6Zgt>dkV zV%p-1uT_Op-P1x4mgO7JrEIh46G)-MAQaiCnQkxfOBq?gqXjf+rDaIPVI|qZ!ECP> zlDeV)Q#{uh_V{RWSkeEp;3)tJJ(x4&ce5LV!ZYM{;tn~rfc_HYcWf*8?^q6)LxWsa zFV~35khuI75Rs6R-qCs&UV)HY%sql)(B`9;b(;JDZ+)%(EWws66lu1!H)++NNl?S z-r%W(I z868qS?81exgIdGdgE`+Wdg2hmXX{Lvgf>bQk@jQQ2s%&NGA#sMIv(w1X9Wcq01@ab z!Y0+V#%FtM9LCasN+_w5Ea2BuO|!hNgUL0~k+PJn3)mL7&C0p4oz5Ox?kODvLrnnqLkVB{~ZeYfU+C;TPo?YS7#vVt6<)~hkxh&=LULF_|}K=z~YJ6f84{0xtflms(h@)PTe|u;G4%r zL#nT!#r54HGZNNVmGid^NS@f}@j@OVisW;8Ws+2r4lqe1EB#p{GQH%HtS$j0c8|&&xqVgg2~oO&6W_Es!Tva#wRY~=Y0R;(CjgstixTj12y{&r| z*Voi~y-!&0 z-$CP}>5{W+6d6Vduv+G9HuT5MDm=IrX&;kUZn_XZ@@sVVj z#NU~*S;Qjg>0{t^-^Vdz+E6OY<>W8b5eT6`GYGDw;C}t-t&j<7#{JpqvqpuzA*1(B z>>+``)SW&eSw6kMv6S%$Bof46Nm4}}k_YeZaSK{#V>GMf1b=T+3dyO;e@`p%-B)g? zUFpn_QN)`TLZcN@T#ubj$ti1~es29i?G1+Hptb$(>5PKFgx{|#ux%b*`;XPc2|~_M z;5!6BW(zpMx!s;2WAfJMHHYu?gHnmF2ge7g`cZifm8Wo-%&uCOF~}qgc!xt=JmZ@K=vK;0_{b^a#CqxpLOi z`B4>!w$>}j%=yZhon}a@O3F?c@6kYY1}w%Wq55~QH@C9Cn7*j80op5#a*(FNy@vSN zmN8}by&(@wa28;%`pf!TT&B2d-jjrdwj&N*f#Igk)rP{oE~XVvm=Op#mYMoH)}+_c zIJV?2{ZZ1UlKRqI(B5RNXV!1doEpI-smqtMmG1g^QolcQDMBiuoSXzY`{!Y8#KqV= zQICh~yLoNiCcwHOT}jhMhd7tJor6UoH&MKzI+QxFiqUi$*rzsz{2#E%WNvz8I-t>q zny(rJ=3n;-+-30aRa)%SGzz<8to-;>K$4t9vRS5ccAS+7wMK6;bAjol`Lk&{bxz^$ zbu6cCUM4eI%AXzGJ2=dl_AUqno@{M>=D9C@aD*xw2L>=OJl*;F)9Bo7APy&o!_H6N zHaDSk$he6AIcK-e`TNb6e_>pVuiW(n-MZgpezeLWcpm1zv0FO>B$4*;XPI|TFJBFoT!KfC|`G33iXm;B$n$`jpAx9kc!tE?F>3>GujAVg;u z_1%Bob$#lT_29u{^=v`^e(M6ej8V|QSQzS?dhYf1-8DCY8P~5Hpn@;^riL+|0rKsL zomCKi2trONjIl3(UuAuoBLCqJ%?u#F6mK;SUWY9;%$(L3$4*LZDH~U47z(s&VuTvv zkNESsxFH_;f861|b3??-Up`PY4&YW z9~p&XT${cm#-rK6pgf|?{Zy@qp@}0!du@n#ZqF}f{FYul2>;VaR8YO$D+4BV(L}%c z$Z((dDV!+h@IH)0`|cFXDgHG|3Sx|>=R+=C3pRBa-a|YzpLWz`?3+h@X__>u_$D>w z^7%7GPwFWWFByKB)f@P%8SXFvMJK+S5;!K3$Y&h8^v0WD4S#k?;cAJ5J|>E(2rf-m zd)Q6`()8B%a zxGD>w+)Rbrln9>&#k&)TW?8FXO|1hmR|!IOO9pYMO26>Ro)s5+`{dSmgn_IA5C_>l z)YZNTt%Arp-JcZTFXLq+pte!|5COcm&0EErvDuY~(u4caU?gP<)y z4=vBY=wR^|U-KE!3RKU0lB0_VS-Y)HuC;a0lWS+6X@pnPIQuhrSj#zTT>F){G04LS zO|6N!nO`Qe3dKkiXs+kZYjv#YX!CfVtv6@XxC_q+Zp9{BndT4(4a3Txqou}-ba@57 zx&w`O1Gn`vh)LU_C7F9!TQ+YNB=f8QDzCgl%$3@ga2NO3Ix`Iz(lZC*L}pR56VvsZ zoIKnJ?NIhAaU8r#+sc>Lykx62Ezoc6tL%z!{tw4Yn#&xWnOz)GZ~<_8PZ~@k^xv$|x|3#{s_gRT=1&w5BI>GrxS0{$iV%++s`jbLqBIPNl{C ztnZGtw&~R`RD{^?0I}!$O0)P~8WI#wewEGQPqX!rzq34aT%UgXbefB&&Q@5Q z?0m<}F0*>-3(zSgOvTwCW7P~#I{SIHX&*%Tr||WWrTp(OSucc3_gL8NuQmo0&#PLlyrcOsujzAKse{2u zpAq`S^qy9`Bzq5&TXu;{g-;!-RKM0e<|dSFjK;N#ad2Uo;U_a6+VgofF5sty`Sv}} z_0cRA=eL0B9X{>Ffw;$7AGO-Z>Ms|iwovAu4{6F9sn_HM zBUhaC<}wWfI>cs#i*s=86uOhuhR!tv@_%A&#QQTG;SYZmR@Qsm7N{KzkITq&nl!sX2TR!+LtJa?msp4_+9$wpL1w-^ooQh1P`sD4aIAuGNeg;2o7To@T z8oUbD?qc|E5}!JVVe9^?f(=}?SicT6{kY3>H`l&-yCV3px6bxF!~HLeJdI!Qe^UNG zSQkExQt=oPzsF;SSFiD$A?g+{0a@$a1KCVAVHny3oN^sI=QY8p=BkmyMkf`!i58^8Lk6QH9p0 z8!tMh<|G^+fMMG*$Na&qAv0v_KrI!ut&ArT>5l?VSUev8Ot$Uv+K%Io;Njc z|FW45e9q+e0v7_W0D|WASun;pwllSAMFP@yF3%iHVcs(X^z|QuZ}5I>q7x%OY|ofG zD&&BSw={A~bncDpBQl>1LLdI9C@pp0E=<3fI}KsoY3{YI9kf|n|5Y`YC;+b{oI`C{Xynw1NF|Q zjtrHK$NpzGG0e$d6_uRME60tNyOp*C^EV3`#nGUIgrv#bwO)RS-@zA-&sjeK!72ir z9y}=-zWRPGX?9oCFiQh?rqDlqd%iJw68a@=K&c0!Z zZ=?EVVkr7`sLjYy%A`WzwttCfDIf~+j?P$uqx04rP{IquUk$wCg=i|;*aq`&T$#OA zwK~svAkHCNC$PJWmp6pajc3_Kq+1aYI{{zyEs$5G7>W)t z%@=F3UOLryvGm3}+Z zEv~n?aqai3z>WzIex?i|WSK-s2#)Lh)e5JJT+MoLSEmZG+%mil?&YQ*J6gC0&|at8 zh#iYB?>#U)NU3rpskX;cp&nTr{v3_wer_0@l~`j?tpf_!eoTz@=grxDD^xprSNf4^ z7Ci45>i7H)^X>EnVy6^8Q+pXE=cNac}EQ3Fb6A90mJs$6fNkxe5 za1qFtBj+CgAxIGXL`(Y9r1Uq6%&7BMTRM$Q8HZ4|p)O0Xlp$o!lsC;qO$dAn_+7n< zG*6=iUYG#lNLP$2$#7LZ6;~q-1U9&*7$@eEVXVtmY_FrPt(E-ZuX3lVpv#cTlh4oE z$R>Mk%0?zey{;iS)`}qAez+jCq-bv z>XJcZ1qF`)14(VhjhD%N1u20BY7XVm1A+K~YS1)${k~Z(UUSgH=0qoXC?Td6xF@* z%GG`s&4in^B1fNE{wVWp98Vx&#RE7EpN2bofBVL5!&%PtHFiUOg44NgbCd4ssTHhc zqy^m2Eef}IVcR50@0eo=nHM~B;*EofO&As=ey)Do2B}Pu6^jHw+;frLIc2Wk#n`(= zzlVjP1-h&30K6AbygCTV>H}918h%WOlby7HL^-Rb)sk{5WoIMd+s42`)tg0S;dOmv zmQJ0ilQ{Dt%Kv-K$s@Gml4K7rM`y;b`;uzC=WrLE!R1+6RPeM*S4w}3+^BH8mT!kr z>p;-1Z}y<(`#iz!-xIhh5Jq6!4o+hU6+dQQBl~t%hCYP?e^};Sg2mnNt9Q4D?Pb>= zwZqh^d#Wa?#)?2N&`jSN_h77K-N}k)36V0VSN78pzg=pM?G}a{0}P&2&E2U+W49#g zB>ojKD)&Jh0$0S|J?1eZO8Jta3TAj&PJa5rrC}6uCKputA*tqe>^$~ z6KDD(W_Hj!@uzob+kk}lpHcr*@@BSG@ju;-`G29$<4~mFmwT?Of+bi#d(HUZrWK@N41TXL6Oec;J!1t* zjaf18&ok7*@1w=RsSI&NyxEy7b?=s4x|3+O@_@Z?yK#{P+;DX8F0Xr!y5R}|R8O#^ zxw$`z3vF{Ge72!B1Uv}n1oV?D13WS>)iD~>sUWX1M%1l z-GJuE!qjp>m|Js(Lzk$ZXRD@xpKb+&uuh&VpwOX+ui8&2m8)o8##^GmrWTwe?EJl1(3 z-XOEBEhqzqjvj`p*wL;o{&DRWg&T|9RY~10#N*^F!-s}{1hs*`H?vu~AEgP$>IuWV zm1)E8XJxZA-k%1Uw8&QbvTjFP^ITR4n*WsXj0uva!%|&=oA<5?G3}^$@Kvoc32LU6 zoaI}lYjLEl>tSMXQ}R^@5M0%TC~aOPSj3dboQz}Xk3E}Veafau&#X+&i7W&f99pR} zLff8v=EY-)&t8aCdO#?p;Z(47^;?fGh^(&uGBDwcYRM5cCcD5^42P59;?s_f$_)YJ z`FMvc<^UnW3vIH#S=-}r4*9={J~T8+Y?)gCQ@o!QEB1}lKLPA6qLz;8RzExfi-~{wrqT%yvE5l(A2igMGjY5EP55ginwr@wk z9bIblQ}Yy?_?SJ{Sl|gOSeacvAFVgxBtri*%M@7{tDN4rf(QKhRb*1`Nvl@-M+Lug zw|>21?>`sTxg-=@$0ultMGe(sPx!R;_=qBJNg;-7UJ)0}m4r+$wLOvZM|$0hG9 zqG8aIihGNdW;#oe51`^qtHROaG^>yd^BY0NG<}%h6(oGe&Dib8nVpQ<|3<+gbs`GL zYzUgKD48t7R{|>1D+z@toCnO^NpAs`tStp$^OJo?>6KdqV(L4rE3+ZH=g0G9Q_Mgs zqn=#jVv;QXTd-05`pE9{!Ql0H22IzwiWS64I~2N@rRnkE&^k-d(gPR3rkMhcp+)qo z)CFp#sHm-5MI8F{(=U;#S8knDSslKjK1xdd?&EpWw>UAN62!f?hyhJF6ouM$!1kzHhFKo<^$+6N*COr)su4IAl(u( z?f_A~5UvebIvB6AlbEvJT{{@iIFaFaK9xNkN8#L&JT|=k{3w>p>E(oa!Ub9(rtMIp z!9$F@_J>#M?o9gNJ3h`n!!jfSZHSmWSC;ioYcH;C2qXHTfAJ#0cQF%_a*gVIt4vQ1 z%6}pVs1;!hJ=a1b1mzr#v3R{j(Q%`A{%SK0ApV}xh0w^8#w%!o*Mn%vCW$w_bM7t6 zrltX}+$XsaKLH%Ez6L)=v^Gk9uH{?sdfj_e#YdkLVr9r3!)|cp1Au-e*#W-x*^cQI znK98Xf%<+p#&eR||uW3T=RQ2JC}Ymrc91SHBQHaIWfLDkp^*cL+uKP@xd4dzDL^ z@2=G6zJCiQ9x}21uS|`-r9tAwh9P2PklFbH#?@ud8SxeI7v`R7+p(E{4d#UYmdTuF zOY+>ZjY47Nz;?nIYiai8)ARY~iec9!uemk;HPHF^x6CkTh~mBLs=;rUiq`-GVq5Kv z2kSM1d(7XcsJjB@zeOT{{x#R|Z%0)It0%o*qf0jPcPrY+pPYyY zBrovc$Oen!q$n}W{uZdqW+BbTbYXcRe%OuFQXJi%?fGBW75$fS75`xnhWWJBq8koQ zZ#ZNgzeW6IyKHp^!D_j>pU>yDLXYe|9E70frN8?|mt1rHR}(ddFMrg#Rlnf9*7^2_ z(AAo}vV5H9859|ZobZieZQ~#@$Pk%`!mbda;c(}>MSYO!v3pnh%DV1yz6-jz%XH*e zfc?$C%3yvB(Aob5nQeJb(OzC1nKnvpbyY8B#@JraU$l`*sw@I+uZUU zhi!h=sY=yox=jUBKF%C@8QFkuy0BxSpy`^0qlxlGM%ni{wJl#>MRifuJa9|jQPJbY zQL;WavT`hTcYj=c0>an{WT5lx_R5NEJCcE4eUI)0Zo7enOFQtbGudY*gjZqiEXc}n zAQ(K&i#JSW?N$D$EL)*!CU+WiHWJ-wbGWw75jlxytA78YQ!5g#q3Ra{aulmv2TDTM zBGPh8Jnw|Io!Zn@oCO-WC_lbznQo6-6Pz1ZQf>2rE*9uO>OVX6dI9ey?KmO<(2fiz ze-u{@J3`<(K`nZLXu=Vx)&_=tMvyURCYDsvJak}@C@35wot2dr4+A451p~vrpccFD zP0dn&DEIf_C7HEgwL*R$_EqP=)p7tJGW7yY+B5sCq9B%2O|gPIrEsB>_21BpI&@k- z36K0*jOpuNp0jE?LA9Kf$&mRF6@1`qF$kn2{g_0<(n2R_c7y4AxsZR2sngm@p2vH} zi690bC4c~`^{~1bSzgUpoQg3mQ{Ty?=~37bsPH3Zx?uMF@(F_Kw+|}FwYcNa7EQ!Y z#(HWA%44Tbr~r|ARh_OPvRV=6UyO_%3aDax^&u;!D2=slK<5)~2U+3;vpUMmC& zfRJukQoz-c9!b4J^OBZ1KIULYq?ea4;{+d~@*ni=ahvQA&CsP84#cFIvjl?|s zC@qVjMmRx9!HqP7FuCH2HxN|fkd@;x-qFAN;i4+i!b+Nh6>l-A(bMd zM6c#_I?zHp`B6)0DOIt)Xc0*}VIRLoX8SkrYaFOx{1RjwCC>N&Ht4$gXN*Q_$OR**6XVEcn@sCrxKi;jQ8t&{(P*q*m(MJ*UTEDgm}kS^xhuEci!Q1teHk0s9T{l`nS zXN{$$)*wdGUKTg{0Ak;yZSytu9yak7z763OG-}Kz73|bA$Q_&jqSw=;PtQ*gaZSkE zO?$LZ(txTA@nArnY#0_if8zQojdW7smyY;2Y{L&Uw(@~hx2BCoxeF97iCv+7u$4vJ zz+n8Pt(SS-8lcuaa%}n)N_6dtPbATTjx+LzY{270l$SVo8&lxFi4g8r0Q9@=hQ1lH zmRqdvwOYyX3AL0TLfIzI8!;k{$k&Lapytahht8*bdblg!OyuCVL}NXFVZ_t9sD3+g zZd$w`C#-vy2ag2PzV|(G>`WSSl}et?f1l4-0f;EZ{4~WUO+Fs*mYPOT4`KVAnk0(` zTFC-QsLy#I-LAqA>dC84vYai^Oq|0YICqP=AvOp0_$E8=T&|FwaImFexghLRZGZWM zAstMF%`O|`l6t_h3s%I!KQeKyKbP_ZL1JZsY-;A(DEeE#^}7jsspMPId;MRZCY2g_ zJM<*H0m#y63&JZ~QBo8jfd$(UOj%Q3-57%vaoyCl8nKgc`TiyU`1x<3WgBp4j6nu+ zOaB#!DubA$WLpnGzB!!L@vVW>aWdj4M%!2Q_RAa< zVs60f+tF#7ar!WIoo`-Xpss((ha*?@t;D2H9#gA{m!q|#g5yV;zf>Xj4rKm~2=JG^ zXrww}lc6Zjn9f8T$l!%i@_?JwK#z3_pkPW43(DHBB%&=uFXi;wu7loCnxb+=Y7i6K&+`IXTPe_zY$zWY%IAQP>_BnUXAzLW^341i)dg1Bc*n(h0 z>n=l)^xCEtx(%WLCOdS+l{hbx`zIcwWKLbq8|H^Sd0u%hWm?8&6^t0f7w9^_m#yaC zBaLYRZKMYVJEd|+Gw3@n;KT$3AhPMI{4THk!|8)OsQueM);ND;mhN-z2PeCWo#7R$JS=&hP_20v_QU^mN1{wNTQ4fV6ebXBjq09@ z4mbNxmihBD?)HyBTsfThj)9%lycf_RMZ!(#)dlu3PZMk3jSkDVvAJP4!bIq7Z}9=G z_AUW*hy>LHY!5sm&jpGz_fylqwk~_gnnH#RByJhEO(({~jC>bbEGg43E|m&BAAGr( zI(LefT6o+g)j*;48v9BzL&ESZ7H5P|YU#yR46Yw&lVRdX0}MVhB>gxwiz$?Oota4) zA#9ZQP!{W^0Bc!~b~d&CvE|_6S+Y|0nw=Wm65#OKF7K)V(bo)CRSY;e2;%WrX>+)s zhs&v#t09SB4eh&{Kv+BUXnys(xb@h`fKH5MJj#(i^-E?Pln3`R-@?#D^RA#hG-z{! z04mXAA)>RUD_mJ=%cbyNPrz|Q9%kHsGe z6WzWrD;Cy~nNxn*%VsHmdbGysG@n_zW%I1@`r3Kqg#65GMJ|KgYpicr{Xu)lrUBpX zW=>hE{~ZRb8A-KG-FTfALlF2E#(j?aALZ7|ieG>~ZA4UmE*^XrjU$$(>+jNC7Q=wG z3h7Op(~Fz^8|zN3zwrMaJ^Cl@|E~qXoQq!#*_3=-VZOXo*^*R6TD|Tq-l;mAPrB-d z$*E;jqow@{ABUe;zp;|;wc){u3FKYa?9Gwi9-7A~4*5%W?8O&_q2V!LFT2(EA^no2 zorWRVq-fP%`iGy58+)VNjy&KIXF*ry*^@Et=j=0Q_L;qB-ala7t2}GwS?gZc{kv9u$eX!c%_E}~iN{Ne6e2FNC2rQFjkTWC z@0C1jMsw^E2Sp+yQ~j4kr$f}$!9+D?|NqiO|FN})WjgBIie0zdk-#N*f4KN?O}2Ep ziD9NHQK&{R9MsCY9YAda7E+! zx|n;={7k!8PQ$1nG_#;9 z@i*`9;t@(LSqrbsR410r4{Lc+Wv5spp!D#KSsO#`1l3Me_=5Cywc&1nK8%qLD3V-; zZoVAI1*psNdlFcKWMm?=9tJVu(~3C`M>ut;=wlz5+0gn8DfXm!oPvAf0};@IiJxhV zaxm=#DAllMUY^8}R$=P&c};WVO#_PG)ztV2`$+G0uDa)Wl5d0NDM!S0v%d!QzVmFb zC4N^?e<`s`hi#I&1sZO!3goqzf50m#Qx0Zr?g$V=qQ}zfrjWTDAbI5uvZ7f-k|Wds zfKS*)r9^<@Zm~wFbj96GZ4ZUux;q~xCN{#JuN@=HY1xbwZqc1|ehXQfsY~f%r*NEk zU&><=+SHp{x^C#)A$PS7huQ|~4o7s1}D|wGtAK+LL9ZTHKp5vc;(&K?4 z`K8dHcMP$27qScr#BNwE%djTe*hH6M4XS4;XupnX3amWY@$%C2WA@W0b>zR8HzXj0 z^`0W(o&)J|ww&YFd%K2o3ogs6-K~pLIwK?~y6OSD0v4O>sXU`4O<6iE=7fpXMQPJM7DTPdr4|z9#Jd&P|Gs z#)`>|cfB*MTWOb*1j)|+ylyKF&ZzXCfYjpxR=#>9(y#~_dp`8FV0cKjSPpegR<^Q3 zbn_q5L#Gx4i^qCUFvSm*QuEf!JZ7BsZzPE)}Pq`Vj70GKZ4Pjs%S1 zqNKZ(d4j?_i^4xqT3f_w(f5<@!=xxZ% zucr@QPi#tSlEd9Y3^Mt3O~~1cY^;SJw_a>sbzn4eM7&W{0DNr&!6e8gaE3)ga*?VR z<_?4ES3pNAW!V6?ZIC6a<%lYyqwVORcK>HHt$xEdSkgS;_m-c4b0u@1%bpfI_<&>g zaVoPgMrKhlV7fMEl<$hVY}K0&ZDa+TLKNKOOIc+b#xL-gp6(~pnUJJ`v5y05RBS); zU$8VJ)yPKE%lfB9-!OujC_+<-z;G?oTe?{j1=7cWon0n_zbZl#E;(hv9X_9$4 z)5MGd?w5qOX--ssKu=RgkV~1bHti&k-%!3dKVI*6%W!puj!bRK!uDp={!7hEhSHPB z`lBF0;`8b175-oDc>;lT7uByC?p~;~G-*L+Ei;-D^X5TPXu%s+-_Cv+xF1PiNV_A# zZ6&8vhbjj%%HA_lG_wBQWB+I{g8!g_I&%@%gzX4hx~#FLAqiA+UT#f}(%e)Dh4okE z*V*mtmul;yN6zIhvrW#1zkQ#eW_TINuJL;Svq%k)P!<9t?BtBElyHdsB_dOd{guJ_ zcscnG*Rk8rfAqHW`Kb72=d1FM|BCZJY<==rLh?wv->nWB|0R;D5RYD8N^lq^iNDC%qk&`vN0)83mRa5< z>5RjrFXEiLVPCVSf|T;#x2sgiC=W8Erv)`zyXiNzvLsf8GCiwkvH?N{@)8fbq|>ow zbnKoL=lPY5?l8gUGq`PAt@;k1bpPB^ytt6W7ZBW4m~ASknXbsEg%4n{?O=+tOOMS6xr#Ohf>`qyz(1@8KmwBHwc#$6_Z z8sn(g^ef&|S2S$?M+VYiWD6?IQM3Q|L zfv(3_GX^!G(Eu>Gh`TUr`-g!PPYAJqALr+}v47h)e_S#tBlghpIcsDGe#Bj1ikcqeNgOhjD=1}O=HdwL_)bS<@ZI8=_Z zY&>$RQyM*4B|btj^G8^-n9#q*Edk11Lx~IQ;H5-sHKSbGUwIu1js&zxR z9m8QBR_|_^U0QgIlh*Upo8BMU_VLzyl$FK`T+aC-{eOw(l1DVzN8~~ zHhZ2dfzJKKFr1Up$%b8y_$!S)uYWg7;;<9DUlKhlW0r6Nls6-wfDGpQ+UBv$TPB;*Sn-X{7>k z3|jpb7depI`I%R8GyBL}le{5LkcpxbJ7KS?Db#F|Vz0h!iB3DAVGE!!I4hLs6)rxwcLs5Pa%f5~X_?X4UI`Bbgjt{@Pa zAV72*ym-L#IBlM;aArzlDSJVWlho>^e+t{3q_Trn^r3{i_CBsfG{LKxU5i{&;N$#4 z>3neG-1>ws0Blwe)?#vI|4SIgUi7TJW?hx#xJEwV={xFJ3uosRT@M(#sfN1xFhe(; zQp!&MgcT;crNq9SZ`?`o3aCi|>E8hFj_~Zn+geWp2XVM6dS<+9cK?kY%(%4^@I6;S z<|0-9X&K^@uB3G^t3=R+laRp>81xaD)}X|ZZ`)3^%60?ne+>*{%1!1 zKXP6jGTj5SkUmx=SGLo>?Z zz6dJ+K1*F+j>)YX?&I&ZPawe9O{?BbC5VK|Kb!p=@aCNtYd@;$JfW!Fbe z_qM$1@hU6^F(~z89o5v}n?Du!7%o4+LSejIqZ`UA_;w2{>j2#(#>exPIiOxGBpxuo z-_93e7j7_ifL(e|O8p9aSrh&XHkXA5yZ^dMQTNk^6&YSb zYiB#N+O?LUSjHimxEejUPZlRRH)XH2v3qmLD>E=n7F`VGt*u*M+I>2MlAh$Er;*9+-r*W7eqV-A*+X zOQiEgn#%-qlRIfsP5WBuKrvIfY-0CN9Xthb8>-YrY7^f*+O-&UM`uVW7l14on>L41 z4g~2;fKIp`Bsp3>3dsu}m>}~bU#ylqLd)fR&9l5GUET_f8!>2Cmn&a}!;+KQmJln@ z_9($nsWRe6iwdU|BvWkT@2CQA=&=73$8c41l_j8nHrBMyhb`;Mxv%oGeueAyAA|v~ z5#j8=zABie+nTL45J>VREVGyJV0@S62o8TQDA{!|u_S~4YxYWePajD%nqPh!MQm+d z*>npTeESepX1r7N0^9hp2Z^P?>>e#m@EnZMat3BGhp+DJ+j%wW$HRrmK@*^czWdY4 z0c-i0Ynq2L3RRdaN?t0SErBhcX6=x8E};VMthPr3Gi47;Z@J&FCLi&@jERYjn~3Vr zHN##^y*LxIRhtYJ-A3`O9lGd$2u6q0Pte7-@x8BU0GnlyZa@Jfw71J+s!!6!7l3R! zb_;{$i@%4NqyBs*7`}ZB<(H0bd|QUS0UCS_p!xyPU3||Kd*_;X6X!`ZWnyczb{dLN zyn8?>Jpfk==ZYoUF+KiEBu7-<_H`?~bci^3!~4cpNrTKodIH|p1z6ns1}_I`0?5;F374r(3ZTW^U3m3vZfBb z0{ESVSf*Xb*J5Obe0sYPzmlK-qBYF+#bkA3$!-;JP}d+9?ngR8e{I*KlzEinKTC8n z6YmNAn!y|`BqFuUJGn^9gs={r+s6u3o-eEVs$qbfkd_`5s^z>ae&6Dy+48m9hJEUQ z%n8neFd3jQ0ohK@#h1Tpq%?3VnnA&myHW;QY=l2JfGioz9Qeo6lGI63$@e*JwG#Jh zfaJH*B61Vg@1sZ&#kf4?Zk?Fc@oK3SN{=hWc@KYC97Fa#vItTMf;i?a=7KX{Avtw3 z5~-fFySGDbL9DDks;3ADgO>@1oV>gbdXJk+U3B~#z+<-1uZu7(3LA1YA@BsaSXP6x zgRH?GEIO^n{U4`s|6dDJ?9B;RyCV*164Q9pljHXR97U5XVJ5nDwuhM)8yYPVdr9KF z18Q@t5RiUcM~_)Fzau>iY= z2E)kj4eF0@OKO0Cxyj?b9OfO}RUd0=k2cKg11Qm!KrOOa{wpuD2YBImaxWxF8xhux-tn*FR4Bj_d^daWBc|~SCv3GQD1RNw2r*d z15|}iKFDT#kP;=6c?@Nw;E$R2e6tDZ?i>_Qjv?(9*G*7lT49HH-@E}+#=ioJ%SEC- zJgexUD5J(?_IfGWIviT&6wAiJ8Ra#-TG!1A%Gl@Xkx8-gpp?proRmzvk$E)x^n;(; zXBN*VNXKy*@N^zAh)d>Hx|Dw!w{mk*p|72u2@IChN7x;Pf^Gc1X@N)Y^p?+bC1twjY+5u2u!!?gl5jQ zLkQ@H1yom;+yb|V5OuH3d;nh+6hiQT))N+C640@@F8McSExpLciYJ}dmE$at`d#67 zRDzp85%?-Ten23aO9**NdnYRl1gHT#1ZjId0C`GQO#EnlZM=?O`X%RAX1@m}X1MCogr z92;BL#nw3!i>_L`-}yE1*l$Up+HBzKCx@_J3O5u1v9^uKJD}!&fgE#3_3YIoE}Cdb*}| z73wqk`S~X)GYm_RO76V_D&|_e%uNduDd|n%H`-~JXz4B>*(AP1{xtsJLU01k#p@^n zSUEwrJeu%3oK0rsq2CuLKKL;jIL-AqMY4WRgfwn26{k*%8LDGGk5KS_WEzj`+ey5< z-wy%X$Xf=Fu|$Fw%*FSo%=?ba~+Mq=|Ryx>tz0Oww$=Q*zJp&?AdIjBFW07!d|fcCU`@hpS1#%Z$k2sypG9 zK5P3pF^qdT%fPqeW)i*R?EGhOM{ivXB2EWhaJqn|Ccx|f5mu0gPUlCSW8%L=Ve5|# zx#xJT?I#(T9(TQ_)y<5__FMR}C;Xfnt4xvL8&Sd)0eD1Eg5W8REZ+ZO8ES-*HMXal zRBXuUbk*4|x2{xATC%v9OYd6xzU&s2+H|UDo(msGd`uX3R=NpUM^DM~g7aP&6};?FkD`7ca%Z^V-A2&xwz{(*t75 z1@+T|+jQWJWI%(@mq`_|lRjXibK`32swl{!sY!^NqRK78M&HDp-B-Yt=f%DUbz z(l;4@{er}TM~O-P^a?XV5*-tKi&Z(k+xn6*uIW#>-zR|%Mr@-cdNx<{SQDTZ2f)^R#DAMRGOJ7FAPtv!s6IIv!Sx z;;jeBXvd2;FX_HuWb(4q7AP;ThnM;);6NC5zSMSQvHG2H++=myAgakRI1Rc-QxYH>iS_f3zFUs(ssj!@CGzZd0=t#swiJzBRw?y8QRol1s0hbS5=AKOMW# zszy>8{O)}9Fk^)AWwQLc-y$9<19ah{x#E9`*x;%^&89h#LYMB(EU(4Zb&i}WKD{+L z8#}7`ZQYf!`o;96L;*G0KYC>&S&(2ljVeBg<^*k1eClO0x~7-W*#bO7aS*PC3G!*b znLK>H(uGSai~c2Ifb;&8m|7VUy18S!7W{J~{x4ByY5DI$or#vt@5jCO{t`tSnEX;t zDUFSOxjw@8l8hziS2U*qHQ+B%cdqXB9T~Y(0MVtTyxq0@`pct=N>w3~f1YXaPT`uv z&xUx;j+lQ<^j}}}zhdhGVpBe8Bt(Dk4>PEHV7r$9`#8uwif7k3t8G29hB6t7-0NW%yl;DSa#af3eUu@h zsLu^uWM~A6lJm+d;8POK=K1I%sMMHilx~>tog5W#W&Kg|pN&=9l}&AX@;>WzNCxc_ zx>$8{GE?^a@$)r5nvhh9^ii~q)#|~)$J_4qjO_stn+IaoX`zoJEK2h)c)XaY4z>_x zJVLx&{z8IGTRyJ`(M)tZCUnUjQyd1UwMifYMSeCUxNDEqp#Qf`Vo081-gGc`lPk=~-S}DP^i&ZztHNEr*uL{N)Y;^|8M&$P;N8u^K)@qk;9vx8 z_IJU0#D;4)0+2T_WlGZ$!gnn4s~nrxv-6@hZuXBV=Dp-`K<A7U~-9{kAum2qco1Zk+IY5y;c3x!>BfM_~dfeoztJK~;M~S8&2!hXaV%of#@I>zb~X zwb*SF1sL9nrmOZ62k;o(lnF={XnV%UN;9cH4cv?RbZ+X;NMdd3d6ziIOCNIY6OPJf zK2r%;7A~cI;x%Jopi)MPIw*5!g&HUoV`?}0sc^KKIlL(tH4q4p0}Zd+pQ6EXA%af1 z&N6RBGtqOQ1$=!hwN}$vcm`$reiT1BX1ERul<#f_oA^HNWdZ1WT4}54S`4M{&`4=% zo%^KYXr86f+U;2xOu$yWX9btCeKgYfAgBnjdk0=URK>O7Lv0E^Ki<~h3pgj5V}HiAxZ6&Wa>8h2r^!D7kAGj zcB1gxtRpgVX)-Tl?sl(;z*uokfWxiB;p5DimReUi=tPsg=d2uCOyidp4~8e=thB|g z+j5bMCNR7jWkGt;?QEL{iR#cZWe;eX{lncC*UUYA4W&YjD5hV$p)G25jw^q)py z!R|F`ZwKOa;aM~#7zIN*DRO2KnxM4NJT1o~huGRinXB0AtwmRxz(-+A>52yrZRfXU z2s!k#-aIoL{ah1X4HSSZY~<$`27x7e2aP`*IomEo&ks7}Ta`&yzW(9UvVg zR-t#xnKE8&vq1O^GwbwF*A2Q7Fq~zg!GB??$}-K8)_nFW^#@|TO`0R zl+BFiW%@gEfjS?Td2cuewkwHjMT)ARMI)O&Q+bse2zsK<>B9rru?BVcDqvk5`EFx- zyjy?wHaoc0?gG`&f=f>!zbZsqcYQ`^!OM~xh(p7||X3a0BnReHkHs&a) z>h9=M#Z1;p=f8dRHmJ>%oRE0k3w%U{HWaJy7Te5_#|nFbkp%l`{_6r;rs;dw8o*h8 zWlNjnPL`6g+q)OG0&A^Tc_{V#eS*LRuOAf@ukVdvHIv0a7m8IXPSgoJxu~})!XK~P zaUK->onM|gH@$`@?&|@6yzvP$Oj5p=l`+G-@hcMZwjp0~k175ltzlijAI!n+iL zfiU^a9yQn_OjIMq8{a_PMax4T$C(HpAH0GX?luGP5pvTH6Pnk zcN6H@suoUb?eUz&QfOfV`3USij^+@B9bDcxgQv#6&ZMHgaZ43vf=r7XYvNVyfxZ+y z`~@gqkLm-q*@6vH$X(PZ(@s(FEUY|WByN(W?m3&`Yhq;zrQmSqf`b~ZB!I|vVTI3d zBhawt=^6*`gu_8D{9H)NoV&5{)d1qSZGhT#=OJrvSoHIk7vVEbyGluwzaB1mN8L|| z8ZsAP;k#|5)7%`(3BOTp;>^EU2sJA|)b#B~#-^8llHj1PvbL4kK)rzAl-^@)`5Of*RFa#GknA=C{!3C$BB-SAp-h3o zr8(Y?2)?EPRvWy&u&*?2QQj+Bk#?5Z1Wr`o$hpr9qr#7}K+_-cEHI020<=$(WT(C^ z9+HTEY6-z7ewUnWrWWCBlA_Gbfahe;uLL8wtq&zN2Auh%u8zxLOu_5TFoXssmt-M z1Eix_+9DeNTWtnarUAtZ-oyTGlg=Is$i*9AEaVTu4pOT+@8B|HtxYRTbv=~wkb$z! zhX)Q+vgt9PxqNhSVEp~IHV8<>FkYIi8lg+_^XQ$vratc?5o+0olDNat+ zH=Oq7Ru4@SQOs8OP`qyf)%0dr2dj30ec5aDHjhn_s<-}&?~57qH2EtFU7F5(wQ;-R z7_F#6pf@*!7=e&eJF#0mqmapaF~>!#BjKjM+lkj21PJL))?XlPq3qKN1><*f_k z1cP&a0>B2fBYx`f4;PlS#`%Z`J7KDY7%+YfDIcU?Soft)BTbT4Py#P86s<)iQ8rc< zRBanA7E7~%?xt@xk0!O{Ttk;d{+6vhS|2E>mdO-?8WyH@a)f|HL#7(Z_4ObLHj&UX zDT4nMwukylZ<2Fmo?@4fvHUEOF~g;zmxa zAO|cfbFM>>8-3P8=65@-Pj>8U>BK{kK4|fuVdYOxL|?;lwJ!yA20Zl^WZvBgSfpe* z%_4TfI{@d=QD0I^6RS{6Z?8lEw}shJau^{!FYm?tA|K;lX0S7Poz4l>zeIeCs$5eM z^ZPkhB)=n)`#;qh^@)^UeAzO;O!LM4)N6jBR=h%;VY#c-xw0m(_KWNl_DbNoLzSzz z-e>>b37}Ht=$HA65?kOktv6??`#&`-0KWJ~JfVLNUYYXzp}9i^BgM<8oY+m4e{M+O z@bB@I{t>+LpZomhhQzb~8tnh5l@(yAiBVRWWmGa>v2w2h?z+ZztH46nZd3r`*6T7F zEvTQ?Xol)_Y${A4l%HC8$qo?Hk`d{4o9F+0UilKt!SI)eT#mX=hI`!7UdkYk|0Az^ z5~piira$|j`1_0ixVPIXh6?{AN|0G80vXnHF?P>aLJ|>K%jhQh^r}?`3!uwNjl`9=tZDeFR!Q$QMi?uM9pWs$afHBKw zg&y;bnTE#vQ~Ph_1tB0^ncX)+uS~S)xkLvL^obXil|s}?Iw1n}WQ0KwBvSwPpfCa| g+#s~*)n_Iq!dm?&#B~JD=zj-|-+%jIsQ#V*Ut$S*L;wH) literal 0 HcmV?d00001 diff --git a/protocol/next_kbd.c b/protocol/next_kbd.c new file mode 100644 index 00000000..a5a07a7a --- /dev/null +++ b/protocol/next_kbd.c @@ -0,0 +1,204 @@ +/* + +NeXT non-ADB Keyboard Protocol + +Copyright 2013, Benjamin Gould (bgould@github.com) + +Based on: +TMK firmware code Copyright 2011,2012 Jun WAKO +Arduino code by "Ladyada" Limor Fried (http://ladyada.net/, http://adafruit.com/), released under BSD license + +Timing reference thanks to http://m0115.web.fc2.com/ (dead link), http://cfile7.uf.tistory.com/image/14448E464F410BF22380BB +Pinouts thanks to http://www.68k.org/~degs/nextkeyboard.html +Keycodes from http://ftp.netbsd.org/pub/NetBSD/NetBSD-release-6/src/sys/arch/next68k/dev/ + +This software is licensed with a Modified BSD License. +All of this is supposed to be Free Software, Open Source, DFSG-free, +GPL-compatible, and OK to use in both free and proprietary applications. +Additions and corrections to this file are welcome. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +* Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include +#include +#include +#include +#include "next_kbd.h" +#include "debug.h" + +static inline void out_lo(void); +static inline void out_hi(void); +static inline void query(void); +static inline void reset(void); +static inline uint32_t response(void); + +#define out_hi_delay(intervals) do { out_hi(); _delay_us(NEXT_KBD_TIMING * intervals); } while (0); +#define out_lo_delay(intervals) do { out_lo(); _delay_us(NEXT_KBD_TIMING * intervals); } while (0); +#define query_delay(intervals) do { query(); _delay_us(NEXT_KBD_TIMING * intervals); } while (0); +#define reset_delay(intervals) do { reset(); _delay_us(NEXT_KBD_TIMING * intervals); } while (0); + +void next_kbd_init(void) +{ + out_hi(); + NEXT_KBD_IN_DDR &= ~(1< +Arduino code by "Ladyada" Limor Fried (http://ladyada.net/, http://adafruit.com/), released under BSD license + +Timing reference thanks to http://m0115.web.fc2.com/ (dead link), http://cfile7.uf.tistory.com/image/14448E464F410BF22380BB +Pinouts thanks to http://www.68k.org/~degs/nextkeyboard.html +Keycodes from http://ftp.netbsd.org/pub/NetBSD/NetBSD-release-6/src/sys/arch/next68k/dev/ + +This software is licensed with a Modified BSD License. +All of this is supposed to be Free Software, Open Source, DFSG-free, +GPL-compatible, and OK to use in both free and proprietary applications. +Additions and corrections to this file are welcome. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +* Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include + +#ifndef NEXT_KBD_H +#define NEXT_KBD_H + +#define NEXT_KBD_KMBUS_IDLE 0x300600 +#define NEXT_KBD_TIMING 50 + +extern uint8_t next_kbd_error; + +/* host role */ +void next_kbd_init(void); +void next_kbd_set_leds(bool left, bool right); +uint32_t next_kbd_recv(void); + +#endif From 3ee5f565ae98cc68b6dff24225b6f8f069f6e20d Mon Sep 17 00:00:00 2001 From: Thomas Russell Murphy Date: Sat, 4 Jan 2014 22:45:52 -0500 Subject: [PATCH 54/76] Spellchecking converter README files. --- converter/adb_usb/README.md | 4 ++-- converter/ascii_usb/README | 2 +- converter/m0110_usb/README.md | 10 +++++----- converter/pc98_usb/README | 4 ++-- converter/ps2_usb/README.md | 4 ++-- converter/sun_usb/README | 4 ++-- converter/usb_usb/README | 2 +- converter/x68k_usb/README | 4 ++-- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/converter/adb_usb/README.md b/converter/adb_usb/README.md index 5301557d..d9efbfab 100644 --- a/converter/adb_usb/README.md +++ b/converter/adb_usb/README.md @@ -71,8 +71,8 @@ Notes Many ADB keyboards has no discrimination between right modifier and left one, you will always see left control even if you press right control key. Apple Extended Keyboard and Apple Extended Keyboard II are the examples. -Though ADB protocol itsef has the ability of distinction between right and left. -And most ADB keyboard has no NKRO functionality, though ADB protocol itsef has that. +Though ADB protocol itself has the ability of distinction between right and left. +And most ADB keyboard has no NKRO functionality, though ADB protocol itself has that. See protocol/adb.c for more info. EOF diff --git a/converter/ascii_usb/README b/converter/ascii_usb/README index b9c7ef25..02fa064e 100644 --- a/converter/ascii_usb/README +++ b/converter/ascii_usb/README @@ -6,7 +6,7 @@ Target MCU is ATMega32u4 but other USB capable AVR will also work. Hardware -------- -Connect RX, TX and GND to UART pin of AVR. Note that you may need line drvier/level shfiter like MAX232 to interface high voltage of RS-232C. +Connect RX, TX and GND to UART pin of AVR. Note that you may need line driver/level shifter like MAX232 to interface high voltage of RS-232C. diff --git a/converter/m0110_usb/README.md b/converter/m0110_usb/README.md index b3fb8f7e..1c344f1a 100644 --- a/converter/m0110_usb/README.md +++ b/converter/m0110_usb/README.md @@ -2,7 +2,7 @@ M0110/M0110A to USB keyboard converter ====================================== This firmware converts the protocol of Apple Macintosh keyboard **M0110**, **M0110A** and **M0120** into USB. Target of this project is USB AVR controller **ATmega32U4**. Using this converter you can revive these retro keyboards with modern computer. -Pics of **M0110 + M0120** and **M0110A**. +Pictures of **M0110 + M0120** and **M0110A**. ![M0110+M0120](http://i.imgur.com/dyvXb2Tm.jpg) ![M0110A](http://i.imgur.com/HuHOEoHm.jpg) @@ -31,7 +31,7 @@ Note that original cable used with Mac is **straight** while phone handset cable -Close-up pic of handset cable. You can see one end of plug has reverse color codes against the other. Click to enlarge. +Close-up picture of handset cable. You can see one end of plug has reverse color codes against the other. Click to enlarge. [![4P4C cable](http://i.imgur.com/3S9P1mYm.jpg?1)](http://i.imgur.com/3S9P1mY.jpg?1) [Teensy]: http://www.pjrc.com/teensy/ @@ -43,12 +43,12 @@ Close-up pic of handset cable. You can see one end of plug has reverse color cod ![Jack fig](http://www.kbdbabel.org/conn/kbd_connector_macplus.png) -### Pull-up Registor -You may need pull-up registors on signal lines(`CLOCK`, `DATA`) in particular when you have long or coiled cable. **1k-10k Ohm** will be OK for this purpose. In that case the converter may not read signal from keyboard correctly without pull-up resistors. +### Pull-up Resistor +You may need pull-up resistors on signal lines(`CLOCK`, `DATA`) in particular when you have long or coiled cable. **1k-10k Ohm** will be OK for this purpose. In that case the converter may not read signal from keyboard correctly without pull-up resistors. -Building Frimware +Building Firmware ----------------- To compile firmware you need AVR GCC. You can edit *Makefile* and *config.h* to change compile options and pin configuration. diff --git a/converter/pc98_usb/README b/converter/pc98_usb/README index 23f1b614..a010dee2 100644 --- a/converter/pc98_usb/README +++ b/converter/pc98_usb/README @@ -16,7 +16,7 @@ Connector (receptacle) -Wiring: You can change this with ediging config.h. +Wiring: You can change this with editing config.h. Pin mini DIN MCU ---------------------------------- @@ -34,7 +34,7 @@ Wiring: You can change this with ediging config.h. Protocol -------- -Singnal: Asynchronous, Positive logic, 19200baud, Least bit first +Signal: Asynchronous, Positive logic, 19200baud, Least bit first Frame format: 1-Start bit(Lo), 8-Data bits, Odd-Parity, 1-Stop bit This converter uses software method for testing purpose. AVR UART engine will work better. diff --git a/converter/ps2_usb/README.md b/converter/ps2_usb/README.md index 65e616ef..8f06fdd0 100644 --- a/converter/ps2_usb/README.md +++ b/converter/ps2_usb/README.md @@ -12,7 +12,7 @@ Following three methods are used to implement PS/2 signal handling. ### Interrupt driven(ps2_interrupt.c) Uses pin interrupt to detect falling edge of clock line. ### USART hardware module(ps2_usart.c) - Uses AVR USART engine to recevie PS/2 signal. + Uses AVR USART engine to receive PS/2 signal. To select method edit Makefile. @@ -31,7 +31,7 @@ In case of Teensy2.0(ATMega32U4): To change pin configuration edit config.h. -Build Frimware +Build Firmware -------------- Just run `make`: diff --git a/converter/sun_usb/README b/converter/sun_usb/README index 7b4f95ca..ee59fc75 100644 --- a/converter/sun_usb/README +++ b/converter/sun_usb/README @@ -34,11 +34,11 @@ Connector Protocol -------- -Singnal: Asynchronous, Negative logic, 1200baud, No Flow control +Signal: Asynchronous, Negative logic, 1200baud, No Flow control Frame format: 1-Start bit, 8-Data bits, No-Parity, 1-Stop bit AVR USART engine expects positive logic while Sun keyboard signal is negative. - To use AVR UART engine you need exteral inverter in front of RX and TX pin. + To use AVR UART engine you need external inverter in front of RX and TX pin. Otherwise you can software serial routine to communicate the keyboard. This converter uses software method, you doesn't need any inverter part. diff --git a/converter/usb_usb/README b/converter/usb_usb/README index 2ffa46ca..d0547cde 100644 --- a/converter/usb_usb/README +++ b/converter/usb_usb/README @@ -6,7 +6,7 @@ Hardware requirement Arduino Leonardo http://arduino.cc/en/Main/ArduinoBoardLeonardo -Circuit@Home USB Host Sheild 2.0 +Circuit@Home USB Host Shield 2.0 http://www.circuitsathome.com/products-page/arduino-shields/usb-host-shield-2-0-for-arduino diff --git a/converter/x68k_usb/README b/converter/x68k_usb/README index 5f1c2072..516fcd24 100644 --- a/converter/x68k_usb/README +++ b/converter/x68k_usb/README @@ -12,7 +12,7 @@ X68000 keyboard has ALPS linear switches. Hardware -------- Target MCU is ATMega32u4 but other USB capable AVR will also work. -You can use PJRC Teensy as dev board. +You can use PJRC Teensy as development board. http://www.pjrc.com/teensy/ Wiring: @@ -83,7 +83,7 @@ bit 6-0 following scan code Data from computer ------------------ -- LED contorol ON/OFF(0/1) +- LED control ON/OFF(0/1) bit 7 1(fixed) bit 6 全角 bit 5 ひらがな From a86c1e2b713e8adace45cd3c1cae397a908b261e Mon Sep 17 00:00:00 2001 From: Thomas Russell Murphy Date: Sat, 4 Jan 2014 22:52:19 -0500 Subject: [PATCH 55/76] Spellchecking keyboard README files. --- keyboard/IIgs/README | 4 ++-- keyboard/gh60/README.md | 2 +- keyboard/hhkb/README.md | 8 ++++---- keyboard/kmac/README.md | 2 +- keyboard/phantom/README.md | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/keyboard/IIgs/README b/keyboard/IIgs/README index 4f9cad1c..820d7711 100644 --- a/keyboard/IIgs/README +++ b/keyboard/IIgs/README @@ -1,4 +1,4 @@ -Replacable USB Controller for Apple IIgs/Standard(M0116) +Replaceable USB Controller for Apple IIgs/Standard(M0116) JeffreySung(nattyman@gmail.com) =============================== @@ -32,7 +32,7 @@ PJRC Teensy 1. Bypass #31 pin(from board) to E4(Teensy) 2. Bypass #30 pin(from board) to F2(Teensy) 3. Bypass #6 pin(from board) to A0(Teensy) -4. Refer doc directory +4. Refer to documentation directory To Do ===== diff --git a/keyboard/gh60/README.md b/keyboard/gh60/README.md index 5e0fc244..510cb5c8 100644 --- a/keyboard/gh60/README.md +++ b/keyboard/gh60/README.md @@ -80,7 +80,7 @@ See [keymap_plain.c](keymap_plain.c) for detail. ### 3. Hasu -This is my favourite keymap with HHKB Fn, Vi cursor and Mousekey layer. See [keymap_hasu.c](keymap_hasu.c) for detail. +This is my favorite keymap with HHKB Fn, Vi cursor and Mousekey layer. See [keymap_hasu.c](keymap_hasu.c) for detail. ### 4. SpaceFN diff --git a/keyboard/hhkb/README.md b/keyboard/hhkb/README.md index 92136482..7ea9843a 100644 --- a/keyboard/hhkb/README.md +++ b/keyboard/hhkb/README.md @@ -24,7 +24,7 @@ See README of [tmk_keyboard] for more. * No risks: Everything is all reversible * No need for PCB trace patching, case cutting or any other destructive mod * Can keep original controller intact -* Can change all HHKB behaviour as you like +* Can change all HHKB behavior as you like ###Cons * Void your warranty @@ -54,11 +54,11 @@ Several version of keymap are available in advance but you are recommended to de ### Program First, push reset button on board to start bootloader. -This command programs the controller with [dfu-programmer] if the tool is intalled and configured properly. +This command programs the controller with [dfu-programmer] if the tool is installed and configured properly. $ make dfu -Or you can also use [FLIP] command to program. Also the tool should be intalled and configured properly. FLIP GUI app is also available. +Or you can also use [FLIP] command to program. Also the tool should be installed and configured properly. FLIP GUI application is also available. $ make flip @@ -70,7 +70,7 @@ To define your own keymap create file named `keymap_.c` and see keymap doc ##Hardware -You have some options for hardware. Development boards with USB AVR family(ATMega32U4, AT90USB1286) like Teensy will work while MegaAVR with [V-USB] library is also cheapear option for DIY. +You have some options for hardware. Development boards with USB AVR family(ATMega32U4, AT90USB1286) like Teensy will work while MegaAVR with [V-USB] library is also cheaper option for DIY. ###1. TMK Alt Controller Board TMK designed [Keyboard Controller Board for HHKB Pro2(KiCad project)](https://github.com/tmk/HHKB_controller). diff --git a/keyboard/kmac/README.md b/keyboard/kmac/README.md index 8cfe0971..dc35870c 100644 --- a/keyboard/kmac/README.md +++ b/keyboard/kmac/README.md @@ -18,7 +18,7 @@ Move to this directory then just run `make` like: Use `Makefile.pjrc` if you want to use PJRC stack or use `Makefile.lufa` for LUFA stack. -Booloader +Bootloader --------- The PCB is hardwired to run the bootloader if the key at the `Caps Lock` position is held down when connecting the keyboard. diff --git a/keyboard/phantom/README.md b/keyboard/phantom/README.md index 8344e160..368ae97e 100644 --- a/keyboard/phantom/README.md +++ b/keyboard/phantom/README.md @@ -33,7 +33,7 @@ between 0 and 255: ### 2. Sleep LED It is possible to have the LEDs fade in and out when the computer is suspended. -To enable this feature, uncoment the `SLEEP_LED_ENABLE` line in the makefile you are using: +To enable this feature, uncomment the `SLEEP_LED_ENABLE` line in the makefile you are using: SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend From cb3a547ebff8e09401c7d635ed24585a7521bb19 Mon Sep 17 00:00:00 2001 From: tmk Date: Tue, 28 Jan 2014 10:55:51 +0900 Subject: [PATCH 56/76] Make modifiers 'weak' in macro --- common/action_macro.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/common/action_macro.c b/common/action_macro.c index cc7ac18a..d85aee37 100644 --- a/common/action_macro.c +++ b/common/action_macro.c @@ -16,6 +16,7 @@ along with this program. If not, see . */ #include #include "action.h" +#include "action_util.h" #include "action_macro.h" #ifdef DEBUG_ACTION @@ -39,12 +40,20 @@ void action_macro_play(const macro_t *macro_p) case KEY_DOWN: MACRO_READ(); dprintf("KEY_DOWN(%02X)\n", macro); - register_code(macro); + if (IS_MOD(macro)) { + add_weak_mods(MOD_BIT(macro)); + } else { + register_code(macro); + } break; case KEY_UP: MACRO_READ(); dprintf("KEY_UP(%02X)\n", macro); - unregister_code(macro); + if (IS_MOD(macro)) { + del_weak_mods(MOD_BIT(macro)); + } else { + unregister_code(macro); + } break; case WAIT: MACRO_READ(); From ebe951a445b5d774542731d6165a9c5cd56beb2b Mon Sep 17 00:00:00 2001 From: tmk Date: Sun, 9 Feb 2014 02:42:17 +0900 Subject: [PATCH 57/76] Add Initial files of 4704_usb --- converter/ibm4704_usb/Makefile | 93 +++++++++++++ converter/ibm4704_usb/README.md | 31 +++++ converter/ibm4704_usb/config.h | 73 +++++++++++ converter/ibm4704_usb/keymap_common.c | 30 +++++ converter/ibm4704_usb/keymap_common.h | 73 +++++++++++ converter/ibm4704_usb/keymap_plain.c | 28 ++++ converter/ibm4704_usb/led.c | 24 ++++ converter/ibm4704_usb/matrix.c | 179 ++++++++++++++++++++++++++ protocol/ibm4704.c | 150 +++++++++++++++++++++ protocol/ibm4704.h | 111 ++++++++++++++++ 10 files changed, 792 insertions(+) create mode 100644 converter/ibm4704_usb/Makefile create mode 100644 converter/ibm4704_usb/README.md create mode 100644 converter/ibm4704_usb/config.h create mode 100644 converter/ibm4704_usb/keymap_common.c create mode 100644 converter/ibm4704_usb/keymap_common.h create mode 100644 converter/ibm4704_usb/keymap_plain.c create mode 100644 converter/ibm4704_usb/led.c create mode 100644 converter/ibm4704_usb/matrix.c create mode 100644 protocol/ibm4704.c create mode 100644 protocol/ibm4704.h diff --git a/converter/ibm4704_usb/Makefile b/converter/ibm4704_usb/Makefile new file mode 100644 index 00000000..bc0f9fde --- /dev/null +++ b/converter/ibm4704_usb/Makefile @@ -0,0 +1,93 @@ +# Target file name (without extension). +TARGET = ibm4704_usb + +# Directory common source filess exist +TOP_DIR = ../.. + +# Directory keyboard dependent files exist +TARGET_DIR = . + +# project specific files +SRC = keymap_common.c \ + matrix.c \ + led.c \ + protocol/ibm4704.c + +ifdef KEYMAP + SRC := keymap_$(KEYMAP).c $(SRC) +else + SRC := keymap_plain.c $(SRC) +endif + +CONFIG_H = config.h + + +# MCU name +#MCU = at90usb1287 +MCU = atmega32u4 + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency in Hz. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# +# This will be an integer division of F_USB below, as it is sourced by +# F_USB after it has run through any CPU prescalers. Note that this value +# does not *change* the processor frequency - it should merely be updated to +# reflect the processor speed set externally so that the code can use accurate +# software delays. +F_CPU = 16000000 + + +# +# LUFA specific +# +# Target architecture (see library "Board Types" documentation). +ARCH = AVR8 + +# Input clock frequency. +# This will define a symbol, F_USB, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_USB = $(F_CPU) + +# Interrupt driven control endpoint task(+60) +OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT + + +# Boot Section Size in *bytes* +# Teensy halfKay 512 +# Teensy++ halfKay 1024 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +# USBaspLoader 2048 +OPT_DEFS += -DBOOTLOADER_SIZE=4096 + + +# Build Options +# comment out to disable the options. +# +#BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +#MOUSEKEY_ENABLE = yes # Mouse keys(+4700) +##EXTRAKEY_ENABLE = yes # Audio control and System control(+450) +CONSOLE_ENABLE = yes # Console for debug(+400) +COMMAND_ENABLE = yes # Commands for debug and configuration +#NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA + + +# Search Path +VPATH += $(TARGET_DIR) +VPATH += $(TOP_DIR) + +include $(TOP_DIR)/protocol.mk +include $(TOP_DIR)/protocol/lufa.mk +include $(TOP_DIR)/common.mk +include $(TOP_DIR)/rules.mk diff --git a/converter/ibm4704_usb/README.md b/converter/ibm4704_usb/README.md new file mode 100644 index 00000000..1e29945d --- /dev/null +++ b/converter/ibm4704_usb/README.md @@ -0,0 +1,31 @@ +IBM 4704 to USB keyboard converter +=======----======================= +This firmware converts IBM 4704 keyboard protocol to USB HID. + + +Connect Wires +------------- +In case of Teensy2.0(ATMega32U4): + +1. Connect Vcc and GND. +2. Connect Clock and Data line. + - Clock is on PD1 and Data on PD2. +3. Optionally you need pull-up register. 1KOhm is OK? + +To change pin configuration edit config.h. + + +Build Firmware +-------------- +Just run `make`: + + $ make + +To select keymap: + + $ make KEYMAP=[plain|...] + + +Keymap +------ +Several version of keymap are available in advance but you are recommended to define your favorite layout yourself. To define your own keymap create file named `keymap_.c` and see keymap document(you can find in top README.md) and existent keymap files. diff --git a/converter/ibm4704_usb/config.h b/converter/ibm4704_usb/config.h new file mode 100644 index 00000000..8c2d08f6 --- /dev/null +++ b/converter/ibm4704_usb/config.h @@ -0,0 +1,73 @@ +/* +Copyright 2014 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef CONFIG_H +#define CONFIG_H + +#include + +#define VENDOR_ID 0xFEED +#define PRODUCT_ID 0x4707 +#define DEVICE_VER 0x0001 +#define MANUFACTURER t.m.k. +#define PRODUCT IBM 4704 keyboard converter +#define DESCRIPTION convert IBM 4704 keyboard to USB + + +/* matrix size */ +#define MATRIX_ROWS 16 // keycode bit3-6 +#define MATRIX_COLS 8 // keycode bit0-2 + + +/* key combination for command */ +#define IS_COMMAND() ( \ + keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ +) + + + +/* + * Busywait + */ +#define IBM4704_CLOCK_PORT PORTD +#define IBM4704_CLOCK_PIN PIND +#define IBM4704_CLOCK_DDR DDRD +#define IBM4704_CLOCK_BIT 1 +#define IBM4704_DATA_PORT PORTD +#define IBM4704_DATA_PIN PIND +#define IBM4704_DATA_DDR DDRD +#define IBM4704_DATA_BIT 2 + +/* + * Pin interrupt + */ +#ifdef IBM4704_USE_INT +#define IBM4704_INT_INIT() do { \ + EICRA |= ((1< + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include "keymap_common.h" + + +/* translates key to keycode */ +uint8_t keymap_key_to_keycode(uint8_t layer, key_t key) +{ + return pgm_read_byte(&keymaps[(layer)][(key.row)][(key.col)]); +} + +/* translates Fn keycode to action */ +action_t keymap_fn_to_action(uint8_t keycode) +{ + return (action_t){ .code = pgm_read_word(&fn_actions[FN_INDEX(keycode)]) }; +} diff --git a/converter/ibm4704_usb/keymap_common.h b/converter/ibm4704_usb/keymap_common.h new file mode 100644 index 00000000..8955baeb --- /dev/null +++ b/converter/ibm4704_usb/keymap_common.h @@ -0,0 +1,73 @@ +/* +Copyright 2011,2012,2013 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef KEYMAP_COMMON_H +#define KEYMAP_COMMON_H + +#include +#include +#include +#include "keycode.h" +#include "action.h" +#include "action_macro.h" +#include "report.h" +#include "print.h" +#include "debug.h" +#include "keymap.h" + + +// 32*8(256) byte array which converts PS/2 code into USB code +extern const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; +extern const uint16_t fn_actions[]; + + +/* Original keys */ +#define KEYMAP( \ + K00,K18,K19,K1A,K10,K11,K12,K08,K09,K0A,K0F,K1F,K0D,K0C,K0E, \ + K04,K05,K06,K13,K14,K15,K16,K17,K01,K02,K03,K1B,K1C,K1D, \ + K20,K21,K22,K23,K24,K25,K26,K27,K28,K29,K2A,K2B,K2C,K2D, \ + K30,K3E,K32,K33,K34,K35,K36,K37,K38,K39,K3A,K3B,K3D, \ + K31,K41,K3F, K40, K42,K2F \ +) { \ + { KC_##K00, KC_##K01, KC_##K02, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_NO }, \ + { KC_##K08, KC_##K09, KC_##K0A, KC_NO, KC_##K0C, KC_##K0D, KC_##K0E, KC_##K0F }, \ + { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17 }, \ + { KC_##K18, KC_##K19, KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D, KC_NO, KC_##K1F }, \ + { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27 }, \ + { KC_##K28, KC_##K29, KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D, KC_NO, KC_##K2F }, \ + { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_##K37 }, \ + { KC_##K38, KC_##K39, KC_##K3A, KC_##K3B, KC_NO, KC_##K3D, KC_##K3E, KC_##K3F }, \ + { KC_##K40, KC_##K41, KC_##K42, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ + { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ + { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ + { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ + { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ + { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ + { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ + { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ +} + +#endif + +/* + { K48, K49, K4A, K4B, K4C, K4D, K4E, K4F }, \ + { K50, K51, K52, K53, K54, K55, K56, K57 }, \ + { K58, K59, K5A, K5B, K5C, K5D, K5E, K5F }, \ + { K60, K61, K62, K63, K64, K65, K66, K67 }, \ + { K68, K69, K6A, K6B, K6C, K6D, K6E, K6F }, \ + { K70, K71, K72, K73, K74, K75, K76, K77 }, \ + { K78, K79, K7A, K7B, K7C, K7D, K7E, K7F }, \ +*/ diff --git a/converter/ibm4704_usb/keymap_plain.c b/converter/ibm4704_usb/keymap_plain.c new file mode 100644 index 00000000..0ca4f14c --- /dev/null +++ b/converter/ibm4704_usb/keymap_plain.c @@ -0,0 +1,28 @@ +#include "keymap_common.h" + + +const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + /* 0: default + * ,-----------------------------------------------------------. + * | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|???|BS | + * |-----------------------------------------------------------| + * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| + * |-----------------------------------------------------------| + * |Ctrl | A| S| D| F| G| H| J| K| L| ;| '|???|Ret | + * |-----------------------------------------------------------| + * |Shif|???| Z| X| C| V| B| N| M| ,| ,| /|???|Shift | + * |-----------------------------------------------------------| + * |Ctrl |Gui|Alt | Space |Alt |Gui|Ctrl | + * `-----------------------------------------------------------' + */ + KEYMAP( + ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSLS,GRV, \ + TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSPC, \ + LCTL,A, S, D, F, G, H, J, K, L, SCLN,QUOT,NO, ENT, \ + LSFT,NO, Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, \ + LCTL,LGUI,LALT, SPC, RGUI,RCTL \ + ), +}; + +const uint16_t PROGMEM fn_actions[] = { +}; diff --git a/converter/ibm4704_usb/led.c b/converter/ibm4704_usb/led.c new file mode 100644 index 00000000..f76545f0 --- /dev/null +++ b/converter/ibm4704_usb/led.c @@ -0,0 +1,24 @@ +/* +Copyright 2011 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "stdint.h" +#include "led.h" + + +void led_set(uint8_t usb_led) +{ +} diff --git a/converter/ibm4704_usb/matrix.c b/converter/ibm4704_usb/matrix.c new file mode 100644 index 00000000..796e2d06 --- /dev/null +++ b/converter/ibm4704_usb/matrix.c @@ -0,0 +1,179 @@ +/* +Copyright 2014 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include "action.h" +#include "print.h" +#include "debug.h" +#include "util.h" +#include "ibm4704.h" +#include "matrix.h" + + +static void matrix_make(uint8_t code); +static void matrix_break(uint8_t code); +static void matrix_clear(void); + + +/* + * Matrix Array usage: + * IBM 4704 scan codes are assigned into 128(16x8)-cell matrix. + * + * 8bit wide + * +---------+ + * 0| | + * :| XX | 00-7F + * f| | + * +---------+ + * + * Exceptions: + */ +static uint8_t matrix[MATRIX_ROWS]; + +// scan code bits 7654 3210 +// R:row/C:column -RRR RCCC +#define ROW(code) ((code>>3)&0x0f) +#define COL(code) (code&0x07) + + +inline +uint8_t matrix_rows(void) +{ + return MATRIX_ROWS; +} + +inline +uint8_t matrix_cols(void) +{ + return MATRIX_COLS; +} + +static void enable_break(void) +{ + uint8_t ret; + for (uint8_t code = 0; code < 0x80; code++) { + while (ibm4704_send(0x80|code) != 0) { + print("z"); + } + _delay_ms(1); + ret = ibm4704_recv(); + if (ret!=0xFF) { + xprintf("%0X: %0X ", code, ret); + } + } + _delay_us(100); + print("End\n"); + while (ibm4704_send(0xFF) != 0) { + print("Z"); + } // End +} + +void matrix_init(void) +{ + debug_enable = true; + + ibm4704_init(); + matrix_clear(); + + xprintf("------\n"); + enable_break(); + //while (ibm4704_send(0x8C) != 0) ; + //while (ibm4704_send(0xFF) != 0) ; +} + +/* + * IBM 4704 Scan Code + */ +uint8_t matrix_scan(void) +{ + uint8_t code = ibm4704_recv(); + if (code==0xFF) { + // Not receivd + return 0; + } else if ((code&0x78)==0x78) { + // 0xFF-F8 and 0x7F-78 is not scan code + dprintf("Error: %0X\n", code); + matrix_clear(); + return 0; + } else if (code&0x80) { + matrix_make(code); + } else { + matrix_break(code); + } + return 1; +} + +inline +bool matrix_has_ghost(void) +{ + return false; +} + +inline +bool matrix_is_on(uint8_t row, uint8_t col) +{ + return (matrix[row] & (1< +*/ +#include +#include +#include "debug.h" +#include "ibm4704.h" + + +#define WAIT(stat, us, err) do { \ + if (!wait_##stat(us)) { \ + ibm4704_error = err; \ + goto ERROR; \ + } \ +} while (0) + + +uint8_t ibm4704_error = 0; + + +void ibm4704_init(void) +{ + // POR + //_delay_ms(2500); + //while ( 0xA3 != ibm4704_recv() ) ; + + inhibit(); + DDRD |= 1<<3; + PORTD &= ~(1<<3); +} + +uint8_t ibm4704_send(uint8_t data) +{ + bool parity = true; // odd parity + ibm4704_error = 0; + + /* Request to send */ + idle(); + clock_lo(); +PIND |= 1<<3; + + /* wait for Start bit(Clock:lo/Data:hi) */ + WAIT(data_hi, 300, 0x30); + + /* Data bit */ + for (uint8_t i = 0; i < 8; i++) { + WAIT(clock_hi, 100, 0x31); + //_delay_us(5); +PIND |= 1<<3; + if (data&(1< 2) { + xprintf("x%02X ", ibm4704_error); + } + inhibit(); + _delay_us(200); // wait to recover clock to hi + return -1; +} diff --git a/protocol/ibm4704.h b/protocol/ibm4704.h new file mode 100644 index 00000000..ff8a5b77 --- /dev/null +++ b/protocol/ibm4704.h @@ -0,0 +1,111 @@ +/* +Copyright 2014 Jun WAKO +*/ +#ifndef IBM4704_H +#define IBM4704_H + +#define IBM4704_ERR_NONE 0 +#define IBM4704_ERR_STARTBIT 1 +#define IBM4704_ERR_PARITY 0x70 + + +void ibm4704_init(void); +uint8_t ibm4704_send(uint8_t data); +uint8_t ibm4704_recv_response(void); +uint8_t ibm4704_recv(void); + + +/* Check pin configuration */ +#if !(defined(IBM4704_CLOCK_PORT) && \ + defined(IBM4704_CLOCK_PIN) && \ + defined(IBM4704_CLOCK_DDR) && \ + defined(IBM4704_CLOCK_BIT)) +# error "ibm4704 clock pin configuration is required in config.h" +#endif + +#if !(defined(IBM4704_DATA_PORT) && \ + defined(IBM4704_DATA_PIN) && \ + defined(IBM4704_DATA_DDR) && \ + defined(IBM4704_DATA_BIT)) +# error "ibm4704 data pin configuration is required in config.h" +#endif + + +/*-------------------------------------------------------------------- + * static functions + *------------------------------------------------------------------*/ +static inline void clock_lo(void) +{ + IBM4704_CLOCK_PORT &= ~(1< Date: Sun, 9 Feb 2014 08:25:23 +0900 Subject: [PATCH 58/76] Tweak keyboard initialize --- converter/ibm4704_usb/matrix.c | 57 ++++++++++++++-------------------- 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/converter/ibm4704_usb/matrix.c b/converter/ibm4704_usb/matrix.c index 796e2d06..0bfda2b1 100644 --- a/converter/ibm4704_usb/matrix.c +++ b/converter/ibm4704_usb/matrix.c @@ -68,34 +68,43 @@ uint8_t matrix_cols(void) static void enable_break(void) { uint8_t ret; - for (uint8_t code = 0; code < 0x80; code++) { + print("Enable break: "); + // valid scancode: 00-77h + for (uint8_t code = 0; code < 0x78; code++) { while (ibm4704_send(0x80|code) != 0) { print("z"); + _delay_us(500); } - _delay_ms(1); - ret = ibm4704_recv(); - if (ret!=0xFF) { - xprintf("%0X: %0X ", code, ret); + _delay_us(2000); + ret = ibm4704_recv(); + if (ret != 0xff) { + xprintf("c%02X:r%02X ", code, ret); } + _delay_us(1000); } - _delay_us(100); + _delay_us(1000); + while (ibm4704_send(0xFF) != 0) { _delay_us(500); } // End print("End\n"); - while (ibm4704_send(0xFF) != 0) { - print("Z"); - } // End } void matrix_init(void) { + uint8_t ret; debug_enable = true; ibm4704_init(); matrix_clear(); - xprintf("------\n"); + // read keyboard id + while ((ret = ibm4704_recv()) == 0xFF) { + ibm4704_send(0xFE); + _delay_us(100); + } + + _delay_ms(2000); // wait for starting up debug console + print("IBM 4704 converter\n"); + xprintf("Keyboard ID: %02X\n", ret); enable_break(); - //while (ibm4704_send(0x8C) != 0) ; - //while (ibm4704_send(0xFF) != 0) ; } /* @@ -108,8 +117,8 @@ uint8_t matrix_scan(void) // Not receivd return 0; } else if ((code&0x78)==0x78) { - // 0xFF-F8 and 0x7F-78 is not scan code - dprintf("Error: %0X\n", code); + // 0xFF-F8 and 0x7F-78 is not scancode + xprintf("Error: %0X\n", code); matrix_clear(); return 0; } else if (code&0x80) { @@ -120,12 +129,6 @@ uint8_t matrix_scan(void) return 1; } -inline -bool matrix_has_ghost(void) -{ - return false; -} - inline bool matrix_is_on(uint8_t row, uint8_t col) { @@ -142,22 +145,10 @@ void matrix_print(void) { print("\nr/c 01234567\n"); for (uint8_t row = 0; row < matrix_rows(); row++) { - // TODO: use new function - phex(row); print(": "); - pbin_reverse(matrix_get_row(row)); - print("\n"); + xprintf("%02X: %08b\n", row, bitrev(matrix_get_row(row))); } } -uint8_t matrix_key_count(void) -{ - uint8_t count = 0; - for (uint8_t i = 0; i < MATRIX_ROWS; i++) { - count += bitpop(matrix[i]); - } - return count; -} - inline From 54a06c2520f6de4b33558b2203d6706a988d291c Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 10 Feb 2014 06:43:43 +0900 Subject: [PATCH 59/76] Change error no and clean debug code --- protocol/ibm4704.c | 41 +++++++++++++++++------------------------ protocol/ibm4704.h | 1 - 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/protocol/ibm4704.c b/protocol/ibm4704.c index 26441ed5..d3fbcc54 100644 --- a/protocol/ibm4704.c +++ b/protocol/ibm4704.c @@ -20,13 +20,7 @@ uint8_t ibm4704_error = 0; void ibm4704_init(void) { - // POR - //_delay_ms(2500); - //while ( 0xA3 != ibm4704_recv() ) ; - inhibit(); - DDRD |= 1<<3; - PORTD &= ~(1<<3); } uint8_t ibm4704_send(uint8_t data) @@ -37,44 +31,43 @@ uint8_t ibm4704_send(uint8_t data) /* Request to send */ idle(); clock_lo(); -PIND |= 1<<3; /* wait for Start bit(Clock:lo/Data:hi) */ WAIT(data_hi, 300, 0x30); /* Data bit */ for (uint8_t i = 0; i < 8; i++) { - WAIT(clock_hi, 100, 0x31); + WAIT(clock_hi, 100, 0x40+i); //_delay_us(5); -PIND |= 1<<3; if (data&(1<= 0x30) { + xprintf("x%02X ", ibm4704_error); + } _delay_us(200); // wait to recover clock to hi return -1; } @@ -110,10 +103,10 @@ uint8_t ibm4704_recv(void) _delay_us(5); // wait for line settles /* start bit */ - WAIT(clock_lo, 100, 1); // wait for keyboard to send - WAIT(data_hi, 100, 2); // can be delayed that long + WAIT(clock_lo, 100, 0x11); // wait for keyboard to send + WAIT(data_hi, 100, 0x12); // can be delayed that long - WAIT(clock_hi, 100, 3); // first rising edge which can take longer + WAIT(clock_hi, 100, 0x13); // first rising edge which can take longer /* data */ for (uint8_t i = 0; i < 8; i++) { WAIT(clock_hi, 100, 0x20+i); @@ -126,22 +119,22 @@ uint8_t ibm4704_recv(void) } /* parity */ - WAIT(clock_hi, 100, 7); + WAIT(clock_hi, 100, 0x17); if (data_in() != parity) { ibm4704_error = IBM4704_ERR_PARITY; goto ERROR; } - WAIT(clock_lo, 150, 8); + WAIT(clock_lo, 150, 0x18); /* stop bit */ - WAIT(clock_hi, 100, 9); - WAIT(data_lo, 1, 9); + WAIT(clock_hi, 100, 0x19); + WAIT(data_lo, 1, 0x19); inhibit(); _delay_us(200); // wait to recover clock to hi return data; ERROR: - if (ibm4704_error > 2) { + if (ibm4704_error > 0x12) { xprintf("x%02X ", ibm4704_error); } inhibit(); diff --git a/protocol/ibm4704.h b/protocol/ibm4704.h index ff8a5b77..618cce6b 100644 --- a/protocol/ibm4704.h +++ b/protocol/ibm4704.h @@ -5,7 +5,6 @@ Copyright 2014 Jun WAKO #define IBM4704_H #define IBM4704_ERR_NONE 0 -#define IBM4704_ERR_STARTBIT 1 #define IBM4704_ERR_PARITY 0x70 From 89c7b9b0974ccbcec8255ff2dc56adc7d3e82a71 Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 10 Feb 2014 07:02:48 +0900 Subject: [PATCH 60/76] Add README.md --- converter/ibm4704_usb/README.md | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/converter/ibm4704_usb/README.md b/converter/ibm4704_usb/README.md index 1e29945d..f38cdd16 100644 --- a/converter/ibm4704_usb/README.md +++ b/converter/ibm4704_usb/README.md @@ -3,16 +3,29 @@ IBM 4704 to USB keyboard converter This firmware converts IBM 4704 keyboard protocol to USB HID. -Connect Wires -------------- -In case of Teensy2.0(ATMega32U4): +4704 Connector +-------------- + Keyboard Plug from front -1. Connect Vcc and GND. -2. Connect Clock and Data line. - - Clock is on PD1 and Data on PD2. -3. Optionally you need pull-up register. 1KOhm is OK? + DSUB-9 + ------------- + \ N 2 3 4 5 / + \ N N N N / + --------- + 2 GND + 3 VCC 5V + 4 DATA + 5 CLOCK + N No connection/No pin. -To change pin configuration edit config.h. + +Connection +---------- +In case of using ATMega32U4(Teensy2.0): + +1. Supply power with VCC and GND. +2. Connect CLOCK to PD1 and DATA to PD2. You can change pin with config.h. +3. Optionally you may need pull-up register. 1KOhm probably work. Build Firmware From 0f827cf94ccd6bef490ba889bc86c61483b1eb80 Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 10 Feb 2014 10:01:42 +0900 Subject: [PATCH 61/76] Add keymap_hasu.c --- converter/ibm4704_usb/Makefile | 4 +- converter/ibm4704_usb/README.md | 2 +- converter/ibm4704_usb/keymap_common.h | 4 +- converter/ibm4704_usb/keymap_hasu.c | 85 +++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 converter/ibm4704_usb/keymap_hasu.c diff --git a/converter/ibm4704_usb/Makefile b/converter/ibm4704_usb/Makefile index bc0f9fde..112b0012 100644 --- a/converter/ibm4704_usb/Makefile +++ b/converter/ibm4704_usb/Makefile @@ -76,8 +76,8 @@ OPT_DEFS += -DBOOTLOADER_SIZE=4096 # comment out to disable the options. # #BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) -#MOUSEKEY_ENABLE = yes # Mouse keys(+4700) -##EXTRAKEY_ENABLE = yes # Audio control and System control(+450) +MOUSEKEY_ENABLE = yes # Mouse keys(+4700) +EXTRAKEY_ENABLE = yes # Audio control and System control(+450) CONSOLE_ENABLE = yes # Console for debug(+400) COMMAND_ENABLE = yes # Commands for debug and configuration #NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA diff --git a/converter/ibm4704_usb/README.md b/converter/ibm4704_usb/README.md index f38cdd16..852a4448 100644 --- a/converter/ibm4704_usb/README.md +++ b/converter/ibm4704_usb/README.md @@ -1,5 +1,5 @@ IBM 4704 to USB keyboard converter -=======----======================= +================================== This firmware converts IBM 4704 keyboard protocol to USB HID. diff --git a/converter/ibm4704_usb/keymap_common.h b/converter/ibm4704_usb/keymap_common.h index 8955baeb..c55a8172 100644 --- a/converter/ibm4704_usb/keymap_common.h +++ b/converter/ibm4704_usb/keymap_common.h @@ -39,7 +39,7 @@ extern const uint16_t fn_actions[]; K00,K18,K19,K1A,K10,K11,K12,K08,K09,K0A,K0F,K1F,K0D,K0C,K0E, \ K04,K05,K06,K13,K14,K15,K16,K17,K01,K02,K03,K1B,K1C,K1D, \ K20,K21,K22,K23,K24,K25,K26,K27,K28,K29,K2A,K2B,K2C,K2D, \ - K30,K3E,K32,K33,K34,K35,K36,K37,K38,K39,K3A,K3B,K3D, \ + K30,K3E,K32,K33,K34,K35,K36,K37,K38,K39,K3A,K3B,K3C,K3D, \ K31,K41,K3F, K40, K42,K2F \ ) { \ { KC_##K00, KC_##K01, KC_##K02, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_NO }, \ @@ -49,7 +49,7 @@ extern const uint16_t fn_actions[]; { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27 }, \ { KC_##K28, KC_##K29, KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D, KC_NO, KC_##K2F }, \ { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_##K34, KC_##K35, KC_##K36, KC_##K37 }, \ - { KC_##K38, KC_##K39, KC_##K3A, KC_##K3B, KC_NO, KC_##K3D, KC_##K3E, KC_##K3F }, \ + { KC_##K38, KC_##K39, KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D, KC_##K3E, KC_##K3F }, \ { KC_##K40, KC_##K41, KC_##K42, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO }, \ diff --git a/converter/ibm4704_usb/keymap_hasu.c b/converter/ibm4704_usb/keymap_hasu.c new file mode 100644 index 00000000..7545b092 --- /dev/null +++ b/converter/ibm4704_usb/keymap_hasu.c @@ -0,0 +1,85 @@ +#include "keymap_common.h" + + +const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + /* 0: default + * ,-----------------------------------------------------------. + * | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|???|BS | + * |-----------------------------------------------------------| + * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| + * |-----------------------------------------------------------| + * |Ctrl | A| S| D| F| G| H| J| K| L| ;| '|xxx|Ret | + * |-----------------------------------------------------------| + * |Shif|xxx| Z| X| C| V| B| N| M| ,| ,| /|xxx|Shift | + * |-----------------------------------------------------------| + * |Ctrl |Gui|Alt | Space |Alt |Gui|Ctrl | + * `-----------------------------------------------------------' + */ + KEYMAP( + ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSLS,GRV, \ + TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSPC, \ + LCTL,A, S, D, F, G, H, J, K, L, FN1, QUOT,NO, ENT, \ + LSFT,NO, Z, X, C, V, B, N, M, COMM,DOT, FN2, NO, FN0, \ + LCTL,LGUI,LALT, FN3, RGUI,RCTL \ + ), + + KEYMAP( + ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \ + CAPS,NO, NO, NO, NO, NO, NO, NO, PSCR,SLCK,PAUS, UP, NO, BSPC, \ + LCTL,VOLD,VOLU,MUTE,NO, NO, PAST,PSLS,HOME,PGUP,LEFT,RGHT,NO, ENT, \ + LSFT,NO, NO, NO, NO, NO, NO, PPLS,PMNS,END, PGDN,DOWN,NO, TRNS, \ + LCTL,LGUI,LALT, SPC, RGUI,RCTL \ + ), + + KEYMAP( + ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \ + TAB, NO, NO, NO, NO, NO, WH_L,WH_D,WH_U,WH_R,WSTP,WBAK,WFWD,BSPC, \ + LCTL,NO, ACL0,ACL1,ACL2,NO, MS_L,MS_D,MS_U,MS_R,TRNS,NO, NO, ENT, \ + LSFT,NO, NO, NO, NO, NO, BTN3,BTN2,BTN1,BTN4,BTN5,NO, NO, RSFT,\ + LCTL,LGUI,LALT, BTN1, RGUI,RCTL \ + ), + + KEYMAP( + ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \ + TAB, HOME,PGDN,UP, PGUP,END, HOME,PGDN,PGUP,END, NO, NO, NO, BSPC, \ + LCTL,NO, LEFT,DOWN,RGHT,NO, LEFT,DOWN,UP, RGHT,NO, NO, NO, ENT, \ + LSFT,NO, NO, NO, NO, NO, NO, HOME,PGDN,PGUP,END, TRNS,NO, RSFT, \ + LCTL,LGUI,LALT, SPC, RGUI,RCTL \ + ), + + KEYMAP( + ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \ + TAB, NO, NO, NO, NO, NO, WH_L,WH_D,MS_U,WH_U,WH_R,BTN4,BTN5,FN4, \ + LCTL,VOLD,VOLU,MUTE,NO, NO, BTN2,MS_L,MS_D,MS_R,BTN1,NO, NO, ENT, \ + LSFT,NO, NO, NO, NO, NO, BTN3,BTN2,BTN1,BTN4,BTN5,NO, NO, NO, \ + LCTL,LGUI,LALT, TRNS, RGUI,RCTL \ + ), +}; + +enum macro_id { + ALT_TAB, +}; + +const uint16_t PROGMEM fn_actions[] = { + [0] = ACTION_LAYER_MOMENTARY(1), + [1] = ACTION_LAYER_TAP_KEY(2, KC_SCLN), + [2] = ACTION_LAYER_TAP_KEY(3, KC_SLASH), + [3] = ACTION_LAYER_TAP_KEY(4, KC_SPC), + [4] = ACTION_MACRO(ALT_TAB), +}; + +/* + * Macro definition + */ +const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) +{ + keyevent_t event = record->event; + + switch (id) { + case ALT_TAB: + return (event.pressed ? + MACRO( D(LALT), D(TAB), END ) : + MACRO( U(TAB), END )); + } + return MACRO_NONE; +} From 902afcc509cf5d84b24f71297591cb7cb3d7493d Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 10 Feb 2014 11:05:18 +0900 Subject: [PATCH 62/76] Add doc 4704.txt and protocol comment --- converter/ibm4704_usb/4704.txt | 147 +++++++++++++++++++++++++++++++++ protocol/ibm4704.c | 38 +++++++-- 2 files changed, 179 insertions(+), 6 deletions(-) create mode 100644 converter/ibm4704_usb/4704.txt diff --git a/converter/ibm4704_usb/4704.txt b/converter/ibm4704_usb/4704.txt new file mode 100644 index 00000000..db584970 --- /dev/null +++ b/converter/ibm4704_usb/4704.txt @@ -0,0 +1,147 @@ +4704 Keyboard +============= +Keyboard Models: + Model 100 6019273 50-key (grid layout) + Model 200 6019284 62-key Alpha(60% layout) + Model 300 6019303 77-key Expanded Alpha + Model 400 6020218 107-key Full key + +Resourse +-------- +The IBM 4704: lots of pictures and info +http://kishy.dyndns.org/?p=648#more-648 + +Brochure: +http://ed-thelen.org/comp-hist/IBM-ProdAnn/4700.pdf + + + + +4704 Keyboard Protocol +====================== +On powering up the keyboard sends keyboard id; A3h for 6019284(62-key), for example. +After that firmware enters FC command mode and waits for parameter data from host +so that it doesn't send any scancode until you send 'FF'(End of FC command). + + +Keyboard to Host +---------------- +Data bits are LSB first and Pairty is odd. Clock has around 60us high and 30us low part. + + ____ __ __ __ __ __ __ __ __ __ ________ + Clock \____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ + ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ + Data ____/ X____X____X____X____X____X____X____X____X____X________ + Start 0 1 2 3 4 5 6 7 P Stop + +Start bit: can be long as 300-350us. +Inhibit: Pull Data line down to inhibit keyboard to send. +Timing: Host reads bit while Clock is hi. +Stop bit: Keyboard pulls down Data line to lo after 9th clock. + + + +Host to Keyboard +---------------- +Data bits are LSB first and Pairty is odd. Clock has around 60us high and 30us low part. + + ____ __ __ __ __ __ __ __ __ __ ________ + Clock \______/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ + ^ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___ + Data ____|__/ X____X____X____X____X____X____X____X____X____X \___ + | Start 0 1 2 3 4 5 6 7 P Stop + Request by host + +Start bit: can be long as 300-350us. +Request: Host pulls Clock line down to request to send a command. +Timing: After Request keyboard pull up Data and down Clock line to low for start bit. + After request host release Clock line once Data line becomes hi. + Host wirtes a bit while Clock is hi and Keyboard reads while low. +Stop bit: Host releases or pulls up Data line to hi after 9th clock and waits for keybaord pull down the line to lo. + + + +Scancodes +--------- +Keyboard doesn't send Break code for all keys except for Alt by default. + + 6019284 62-key: + ,-----------------------------------------------------------. + | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|???|BS | + |-----------------------------------------------------------| + |Tab | Q| W| E| R| T| Y| U| I| O| P| ¢| \| PD2| + |-----------------------------------------------------------| + |Ctrl | A| S| D| F| G| H| J| K| L| ;| '| {}| PD3| + |-----------------------------------------------------------| + |Shif| <>| Z| X| C| V| B| N| M| ,| ,| /|???|Shift | + |-----------------------------------------------------------| + |Reset|blk|Alt | Space |Alt |blk|Enter| + `-----------------------------------------------------------' + +----------+---------------------+----------+----------+ + |` 00|PD1 04|Caps 20|LShift 30|Reset 31| + |1 18|q 05|a 21|<> 3E|Rblank 41| + |2 19|w 06|s 22|z 32|Alt 3F| + |3 1A|e 13|d 23|x 33|Space 40| + |4 10|r 14|f 24|c 34|Alt 3F| + |5 11|t 15|g 25|v 35|Lblank 42| + |6 12|y 16|h 26|b 36|Enter 2F| + |7 08|u 17|j 27|n 37| | + |8 09|i 01|k 28|m 38| | + |9 0A|o 02|l 29|, 39| | + |0 0F|p 03|; 2A|. 3A| | + |- 1F|¢ 1B|' 2B|/ 3B| | + |= 0D|\ 1C|{} 2C|??? 3C| | + |??? 0C|PD2 1D|PD3 2D|RShift 3D| | + |BS 0E| | | | | + +----------+---------------------+----------+----------+ + Bit7 is 'press flag' which set 1 on press and 0 on release when break code is enabled. + +NOTE: When break code is enabled the key sends scancode with setting 7th bit on press +and without it on release. That is, '`' sends 80h on press and 00h on release. + + +keyboard command +---------------- + FF Soft Reset(0008h) + FE Resend(00e8h) + FD Buzzer stop?(00edh) + FC Set Key flag(00f6h) + FB Soft Reset(0008h) + FA Reset(0000h) + + +Keyboard response +----------------- + FF Not exist. [Outgoing buffer cannot have FFh(00h in fact)] + FE Overflow(key event/receive data) at 00c5h, 0346h + FE Memory test error at 0224h + FD Command out of bound at 00d8h + Key out of bound + 7E Read/Parity error in receive from host at 00bch + + +Set Key flag command(FC) +------------------------ +After 'Power on Reset' firmware enters this command mode and waits for data from host, +so that you don't need to send 'FC' and it doesn't send any scancode until you send 'FF'. + +Data sent from host: + + bit: 7 6 ... 0 + en | | + | `-----`--- scan code + `------------- enable bit(0: enable repeat, 1: enable break) + + 00-77 Enable repeat(78-7F: invalid scancode) + 80-F7 Enable break(F8-FF: invalid scancode) + FE Resend(011ah) no need to use + FF End(0114h) exits FC command mode. + +Response from keyboard: + FD Out of bound - Invalid scancode + +Examples: + To enable break code of all keys. + + FC 80 81 ... F7 FF + diff --git a/protocol/ibm4704.c b/protocol/ibm4704.c index d3fbcc54..10e229fd 100644 --- a/protocol/ibm4704.c +++ b/protocol/ibm4704.c @@ -23,6 +23,25 @@ void ibm4704_init(void) inhibit(); } +/* +Host to Keyboard +---------------- +Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part. + + ____ __ __ __ __ __ __ __ __ __ ________ +Clock \______/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ + ^ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___ +Data ____|__/ X____X____X____X____X____X____X____X____X____X \___ + | Start 0 1 2 3 4 5 6 7 P Stop + Request by host + +Start bit: can be long as 300-350us. +Request: Host pulls Clock line down to request to send a command. +Timing: After Request keyboard pull up Data and down Clock line to low for start bit. + After request host release Clock line once Data line becomes hi. + Host writes a bit while Clock is hi and Keyboard reads while low. +Stop bit: Host releases or pulls up Data line to hi after 9th clock and waits for keyboard pull down the line to lo. +*/ uint8_t ibm4704_send(uint8_t data) { bool parity = true; // odd parity @@ -85,13 +104,20 @@ uint8_t ibm4704_recv_response(void) } /* -Keyboard to Host: -Clock ~~~~___~~_~~_~~_~~_~~_~~_~~_~~_~~_~~~~~~~~ H:60us/L:30us +Keyboard to Host +---------------- +Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part. -Data ____~~X==X==X==X==X==X==X==X==X==X________ - | 0 1 2 3 4 5 6 7 P(odd) - | LSB MSB - Start bit(80us) + ____ __ __ __ __ __ __ __ __ __ ________ +Clock \____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ + ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ +Data ____/ X____X____X____X____X____X____X____X____X____X________ + Start 0 1 2 3 4 5 6 7 P Stop + +Start bit: can be long as 300-350us. +Inhibit: Pull Data line down to inhibit keyboard to send. +Timing: Host reads bit while Clock is hi. +Stop bit: Keyboard pulls down Data line to lo after 9th clock. */ uint8_t ibm4704_recv(void) { From 47d812bfd67c9162cd0a491717cebb191b538ba3 Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 10 Feb 2014 23:49:57 +0900 Subject: [PATCH 63/76] Add connector pinouts --- converter/ibm4704_usb/4704.txt | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/converter/ibm4704_usb/4704.txt b/converter/ibm4704_usb/4704.txt index db584970..c17d172a 100644 --- a/converter/ibm4704_usb/4704.txt +++ b/converter/ibm4704_usb/4704.txt @@ -16,7 +16,6 @@ http://ed-thelen.org/comp-hist/IBM-ProdAnn/4700.pdf - 4704 Keyboard Protocol ====================== On powering up the keyboard sends keyboard id; A3h for 6019284(62-key), for example. @@ -24,6 +23,22 @@ After that firmware enters FC command mode and waits for parameter data from hos so that it doesn't send any scancode until you send 'FF'(End of FC command). +Connector +--------- + Keyboard Plug from front + + DSUB-9 + ------------- + \ N 2 3 4 5 / + \ N N N N / + --------- + 2 GND + 3 VCC 5V + 4 DATA + 5 CLOCK + N No connection/No pin. + + Keyboard to Host ---------------- Data bits are LSB first and Pairty is odd. Clock has around 60us high and 30us low part. @@ -40,7 +55,6 @@ Timing: Host reads bit while Clock is hi. Stop bit: Keyboard pulls down Data line to lo after 9th clock. - Host to Keyboard ---------------- Data bits are LSB first and Pairty is odd. Clock has around 60us high and 30us low part. @@ -60,7 +74,6 @@ Timing: After Request keyboard pull up Data and down Clock line to low for s Stop bit: Host releases or pulls up Data line to hi after 9th clock and waits for keybaord pull down the line to lo. - Scancodes --------- Keyboard doesn't send Break code for all keys except for Alt by default. From 4ab0ebb199601c37b5fd542d8425247b626bac6d Mon Sep 17 00:00:00 2001 From: tmk Date: Tue, 11 Feb 2014 00:37:19 +0900 Subject: [PATCH 64/76] Change pin configuration --- converter/ibm4704_usb/README.md | 6 ++++-- converter/ibm4704_usb/config.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/converter/ibm4704_usb/README.md b/converter/ibm4704_usb/README.md index 852a4448..6541dd6d 100644 --- a/converter/ibm4704_usb/README.md +++ b/converter/ibm4704_usb/README.md @@ -2,10 +2,12 @@ IBM 4704 to USB keyboard converter ================================== This firmware converts IBM 4704 keyboard protocol to USB HID. +Keyboard initialization process takes a few seconds at start up. During that you will hear buzzer from the keyboard. **You need to plug USB cable after hooking up your keyboard to the converter.** + 4704 Connector -------------- - Keyboard Plug from front +Keyboard Plug from front: DSUB-9 ------------- @@ -24,7 +26,7 @@ Connection In case of using ATMega32U4(Teensy2.0): 1. Supply power with VCC and GND. -2. Connect CLOCK to PD1 and DATA to PD2. You can change pin with config.h. +2. Connect CLOCK to PD1 and DATA to PD0. You can change pin with config.h. 3. Optionally you may need pull-up register. 1KOhm probably work. diff --git a/converter/ibm4704_usb/config.h b/converter/ibm4704_usb/config.h index 8c2d08f6..befed0d5 100644 --- a/converter/ibm4704_usb/config.h +++ b/converter/ibm4704_usb/config.h @@ -50,7 +50,7 @@ along with this program. If not, see . #define IBM4704_DATA_PORT PORTD #define IBM4704_DATA_PIN PIND #define IBM4704_DATA_DDR DDRD -#define IBM4704_DATA_BIT 2 +#define IBM4704_DATA_BIT 0 /* * Pin interrupt From 776ccd3e675c2aaaf6e5711a58ef2aed5a94a550 Mon Sep 17 00:00:00 2001 From: tmk Date: Tue, 11 Feb 2014 01:40:55 +0900 Subject: [PATCH 65/76] Change keymap_plain.c --- converter/ibm4704_usb/keymap_plain.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/converter/ibm4704_usb/keymap_plain.c b/converter/ibm4704_usb/keymap_plain.c index 0ca4f14c..a121634e 100644 --- a/converter/ibm4704_usb/keymap_plain.c +++ b/converter/ibm4704_usb/keymap_plain.c @@ -8,21 +8,31 @@ const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * |-----------------------------------------------------------| * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| * |-----------------------------------------------------------| - * |Ctrl | A| S| D| F| G| H| J| K| L| ;| '|???|Ret | + * |Ctrl | A| S| D| F| G| H| J| K| L| ;| '| #|Ret | * |-----------------------------------------------------------| - * |Shif|???| Z| X| C| V| B| N| M| ,| ,| /|???|Shift | + * |Shif| \| Z| X| C| V| B| N| M| ,| ,| /|???|Shift | * |-----------------------------------------------------------| - * |Ctrl |Gui|Alt | Space |Alt |Gui|Ctrl | + * |Ctrl |Gui|Alt | Space |Alt* |Gui|Ctrl | * `-----------------------------------------------------------' */ KEYMAP( - ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSLS,GRV, \ - TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSPC, \ - LCTL,A, S, D, F, G, H, J, K, L, SCLN,QUOT,NO, ENT, \ - LSFT,NO, Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, \ + GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSLS,BSPC, \ + TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, \ + LCTL,A, S, D, F, G, H, J, K, L, SCLN,QUOT,NUHS,ENT, \ + LSFT,NUBS,Z, X, C, V, B, N, M, COMM,DOT, SLSH,NO, FN0, \ + LCTL,LGUI,LALT, SPC, RGUI,RCTL \ + ), + + /* 1: HHKB */ + KEYMAP( + ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \ + CAPS,NO, NO, NO, NO, NO, NO, NO, PSCR,SLCK,PAUS, UP, NO, INS, \ + LCTL,VOLD,VOLU,MUTE,NO, NO, PAST,PSLS,HOME,PGUP,LEFT,RGHT,NO, ENT, \ + LSFT,NO, NO, NO, NO, NO, NO, PPLS,PMNS,END, PGDN,DOWN,NO, TRNS, \ LCTL,LGUI,LALT, SPC, RGUI,RCTL \ ), }; const uint16_t PROGMEM fn_actions[] = { + [0] = ACTION_LAYER_MOMENTARY(1), }; From 294aa396da1111838050d6476ec25f0023885d40 Mon Sep 17 00:00:00 2001 From: tmk Date: Thu, 13 Feb 2014 09:33:34 +0900 Subject: [PATCH 66/76] Rename a file --- converter/ibm4704_usb/{4704.txt => ibm4704.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename converter/ibm4704_usb/{4704.txt => ibm4704.txt} (100%) diff --git a/converter/ibm4704_usb/4704.txt b/converter/ibm4704_usb/ibm4704.txt similarity index 100% rename from converter/ibm4704_usb/4704.txt rename to converter/ibm4704_usb/ibm4704.txt From 428b23646129aeee5eda20f34d22846fc54a86d4 Mon Sep 17 00:00:00 2001 From: tmk Date: Thu, 13 Feb 2014 09:45:02 +0900 Subject: [PATCH 67/76] Add converter/ibm4704_usb --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b76b7fb9..a561b38e 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ You can find some keyboard specific projects under `converter` and `keyboard` di * [pc98_usb](converter/pc98_usb/) - [PC98] to USB * [usb_usb](converter/usb_usb/) - USB to USB(experimental) * [ascii_usb](converter/ascii_usb/) - ASCII(Serial console terminal) to USB +* [ibm4704_usb](converter/ibm4704_usb) - [IBM 4704 keyboard Converter][GH_ibm4704] ### keyboard * [hhkb](keyboard/hhkb/) - [Happy Hacking Keyboard pro][GH_hhkb] **my main board** @@ -62,6 +63,7 @@ You can find some keyboard specific projects under `converter` and `keyboard` di [GH_terminal]: http://geekhack.org/showwiki.php?title=Island:27272 [GH_x68k]: http://geekhack.org/showwiki.php?title=Island:29060 [GH_hbkb]: http://geekhack.org/showwiki.php?title=Island:29483 +[GH_ibm4704]: http://geekhack.org/index.php?topic=54706.0 [HID_liber]: http://deskthority.net/wiki/HID_Liberation_Device_-_DIY_Instructions [Phantom]: http://geekhack.org/index.php?topic=26742 [GH60]: http://geekhack.org/index.php?topic=34959 From 01f02e8457d01266c6ac2a015953f0796ca335c4 Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 17 Feb 2014 16:41:40 +0900 Subject: [PATCH 68/76] Change IS_COMMAND macro --- converter/ibm4704_usb/config.h | 1 + 1 file changed, 1 insertion(+) diff --git a/converter/ibm4704_usb/config.h b/converter/ibm4704_usb/config.h index befed0d5..4f82f49a 100644 --- a/converter/ibm4704_usb/config.h +++ b/converter/ibm4704_usb/config.h @@ -35,6 +35,7 @@ along with this program. If not, see . /* key combination for command */ #define IS_COMMAND() ( \ + keyboard_report->mods == (MOD_BIT(KC_LCTRL) | MOD_BIT(KC_RCTRL)) || \ keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ ) From 48d27378f4b1c6c26e42c1abc5f6af5229582c22 Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 17 Feb 2014 16:42:43 +0900 Subject: [PATCH 69/76] Fix README.md and ibm4704.txt --- converter/ibm4704_usb/README.md | 19 ++++++++- converter/ibm4704_usb/ibm4704.txt | 71 ++++++++++++++++++++----------- 2 files changed, 63 insertions(+), 27 deletions(-) diff --git a/converter/ibm4704_usb/README.md b/converter/ibm4704_usb/README.md index 6541dd6d..ce9e34eb 100644 --- a/converter/ibm4704_usb/README.md +++ b/converter/ibm4704_usb/README.md @@ -5,8 +5,23 @@ This firmware converts IBM 4704 keyboard protocol to USB HID. Keyboard initialization process takes a few seconds at start up. During that you will hear buzzer from the keyboard. **You need to plug USB cable after hooking up your keyboard to the converter.** -4704 Connector --------------- +Keyboard models +--------------- +IBM capacitive switch models: + 6019273 Model 100 50-key (grid layout) http://kishy.dyndns.org/?p=977 + 6019284 Model 200 62-key Alpha(60% layout) http://kishy.dyndns.org/?p=894 + 6019303 Model 300 77-key Expanded Alpha http://kbtalking.cool3c.com/article/23272 + 6020218 Model 400 107-key Full key http://kishy.dyndns.org/?p=980 + +Alps switch(vintage Green) models: + 5954339 Japanese 102-key http://deskthority.net/post87127.html#p87127 + 6112883 Japanese 102-key http://geekhack.org/index.php?topic=52888.msg1194489#msg1194489 + 6112884 Japanese 102-key http://geekhack.org/index.php?topic=50437.msg1193047#msg1193047 + 6341739 Chinese 102-key http://geekhack.org/index.php?topic=52888.msg1176566#msg1176566 + + +Connector +--------- Keyboard Plug from front: DSUB-9 diff --git a/converter/ibm4704_usb/ibm4704.txt b/converter/ibm4704_usb/ibm4704.txt index c17d172a..877d8fdb 100644 --- a/converter/ibm4704_usb/ibm4704.txt +++ b/converter/ibm4704_usb/ibm4704.txt @@ -1,10 +1,16 @@ -4704 Keyboard -============= -Keyboard Models: - Model 100 6019273 50-key (grid layout) - Model 200 6019284 62-key Alpha(60% layout) - Model 300 6019303 77-key Expanded Alpha - Model 400 6020218 107-key Full key +IBM 4704 Keyboard +================= +IBM capacitive switch models: + 6019273 Model 100 50-key (grid layout) http://kishy.dyndns.org/?p=977 + 6019284 Model 200 62-key Alpha(60% layout) http://kishy.dyndns.org/?p=894 + 6019303 Model 300 77-key Expanded Alpha http://kbtalking.cool3c.com/article/23272 + 6020218 Model 400 107-key Full key http://kishy.dyndns.org/?p=980 + +Alps switch(vintage Green) models: + 5954339 Japanese 102-key http://deskthority.net/post87127.html#p87127 + 6112883 Japanese 102-key http://geekhack.org/index.php?topic=52888.msg1194489#msg1194489 + 6112884 Japanese 102-key http://geekhack.org/index.php?topic=50437.msg1193047#msg1193047 + 6341739 Chinese 102-key http://geekhack.org/index.php?topic=52888.msg1176566#msg1176566 Resourse -------- @@ -16,11 +22,19 @@ http://ed-thelen.org/comp-hist/IBM-ProdAnn/4700.pdf -4704 Keyboard Protocol -====================== -On powering up the keyboard sends keyboard id; A3h for 6019284(62-key), for example. -After that firmware enters FC command mode and waits for parameter data from host -so that it doesn't send any scancode until you send 'FF'(End of FC command). +IBM 4704 Keyboard Protocol +========================== +On powering up keyboard sends keyboard ID; A3h for 6019284(62-key), for example. +After that the keyboard enters FC command mode and waits for parameter data from host +so that it doesn't send any scancode until you send 'FF'(End of FC command mode). + + Keyboard ID + ------------------------------- + Model 100 50-key A2h + Model 200 62-key A3h + Model 300 77-key A4h + Model 400 107-key ?? + Japanese/Chinese 102-key A6h Connector @@ -113,27 +127,34 @@ NOTE: When break code is enabled the key sends scancode with setting 7th bit on and without it on release. That is, '`' sends 80h on press and 00h on release. -keyboard command +Keyboard command ---------------- - FF Soft Reset(0008h) - FE Resend(00e8h) - FD Buzzer stop?(00edh) - FC Set Key flag(00f6h) - FB Soft Reset(0008h) - FA Reset(0000h) +Keyboard accepts these commands from host. + + Description Entry point + ----------------------------------------------------------- + FF Soft Reset 0008h + FE Resend 00e8h + FD Buzzer(emits a short beep) 00edh + FC Set Key Flag 00f6h + FB Soft Reset 0008h + FA Reset 0000h Keyboard response ----------------- - FF Not exist. [Outgoing buffer cannot have FFh(00h in fact)] - FE Overflow(key event/receive data) at 00c5h, 0346h - FE Memory test error at 0224h - FD Command out of bound at 00d8h +Keyobard sends these bytes to host. + + Description Entry point + ----------------------------------------------------------- + FE Overflow(key event/receive data) 00c5h, 0346h + Memory test error 0224h + FD Command out of bound 00d8h Key out of bound - 7E Read/Parity error in receive from host at 00bch + 7E Read/Parity error in receive from host 00bch -Set Key flag command(FC) +Set Key Flag command(FC) ------------------------ After 'Power on Reset' firmware enters this command mode and waits for data from host, so that you don't need to send 'FC' and it doesn't send any scancode until you send 'FF'. From 7474e14d068210242b9cb59b21afce25f66e2a6e Mon Sep 17 00:00:00 2001 From: tmk Date: Mon, 17 Feb 2014 16:57:02 +0900 Subject: [PATCH 70/76] Fix markdown syntax --- converter/ibm4704_usb/README.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/converter/ibm4704_usb/README.md b/converter/ibm4704_usb/README.md index ce9e34eb..a3af4ab3 100644 --- a/converter/ibm4704_usb/README.md +++ b/converter/ibm4704_usb/README.md @@ -5,19 +5,20 @@ This firmware converts IBM 4704 keyboard protocol to USB HID. Keyboard initialization process takes a few seconds at start up. During that you will hear buzzer from the keyboard. **You need to plug USB cable after hooking up your keyboard to the converter.** -Keyboard models ---------------- -IBM capacitive switch models: - 6019273 Model 100 50-key (grid layout) http://kishy.dyndns.org/?p=977 - 6019284 Model 200 62-key Alpha(60% layout) http://kishy.dyndns.org/?p=894 - 6019303 Model 300 77-key Expanded Alpha http://kbtalking.cool3c.com/article/23272 - 6020218 Model 400 107-key Full key http://kishy.dyndns.org/?p=980 +Supported Keyboard +------------------ +### IBM capacitive switch models: +- 6019273 Model 100 50-key (grid layout) http://kishy.dyndns.org/?p=977 +- 6019284 Model 200 62-key Alpha(60% layout) http://kishy.dyndns.org/?p=894 +- 6019303 Model 300 77-key Expanded Alpha http://kbtalking.cool3c.com/article/23272 +- 6020218 Model 400 107-key Full key http://kishy.dyndns.org/?p=980 -Alps switch(vintage Green) models: - 5954339 Japanese 102-key http://deskthority.net/post87127.html#p87127 - 6112883 Japanese 102-key http://geekhack.org/index.php?topic=52888.msg1194489#msg1194489 - 6112884 Japanese 102-key http://geekhack.org/index.php?topic=50437.msg1193047#msg1193047 - 6341739 Chinese 102-key http://geekhack.org/index.php?topic=52888.msg1176566#msg1176566 +### Alps switch(vintage Green) models: + +- 5954339 Japanese 102-key http://deskthority.net/post87127.html#p87127 +- 6112883 Japanese 102-key http://geekhack.org/index.php?topic=52888.msg1194489#msg1194489 +- 6112884 Japanese 102-key http://geekhack.org/index.php?topic=50437.msg1193047#msg1193047 +- 6341739 Chinese 102-key http://geekhack.org/index.php?topic=52888.msg1176566#msg1176566 Connector From 5ca3bde10aa5d8057895475840800544599ea33f Mon Sep 17 00:00:00 2001 From: Ralf Schmitt Date: Tue, 18 Mar 2014 20:06:24 +0100 Subject: [PATCH 71/76] Support for Lightsaber keyboard --- keyboard/lightsaber/Makefile.lufa | 125 ++++++++++++ keyboard/lightsaber/Makefile.pjrc | 101 ++++++++++ keyboard/lightsaber/README.md | 110 +++++++++++ keyboard/lightsaber/config.h | 43 ++++ keyboard/lightsaber/keymap.c | 77 ++++++++ keyboard/lightsaber/keymap_winkey.h | 12 ++ keyboard/lightsaber/led.c | 24 +++ keyboard/lightsaber/matrix.c | 292 ++++++++++++++++++++++++++++ 8 files changed, 784 insertions(+) create mode 100644 keyboard/lightsaber/Makefile.lufa create mode 100644 keyboard/lightsaber/Makefile.pjrc create mode 100644 keyboard/lightsaber/README.md create mode 100644 keyboard/lightsaber/config.h create mode 100644 keyboard/lightsaber/keymap.c create mode 100644 keyboard/lightsaber/keymap_winkey.h create mode 100644 keyboard/lightsaber/led.c create mode 100644 keyboard/lightsaber/matrix.c diff --git a/keyboard/lightsaber/Makefile.lufa b/keyboard/lightsaber/Makefile.lufa new file mode 100644 index 00000000..6982b51f --- /dev/null +++ b/keyboard/lightsaber/Makefile.lufa @@ -0,0 +1,125 @@ +#---------------------------------------------------------------------------- +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF. +# +# make extcoff = Convert ELF to AVR Extended COFF. +# +# make program = Download the hex file to the device. +# Please customize your programmer settings(PROGRAM_CMD) +# +# make teensy = Download the hex file to the device, using teensy_loader_cli. +# (must have teensy_loader_cli installed). +# +# make dfu = Download the hex file to the device, using dfu-programmer (must +# have dfu-programmer installed). +# +# make flip = Download the hex file to the device, using Atmel FLIP (must +# have Atmel FLIP installed). +# +# make dfu-ee = Download the eeprom file to the device, using dfu-programmer +# (must have dfu-programmer installed). +# +# make flip-ee = Download the eeprom file to the device, using Atmel FLIP +# (must have Atmel FLIP installed). +# +# make debug = Start either simulavr or avarice as specified for debugging, +# with avr-gdb or avr-insight as the front end for debugging. +# +# make filename.s = Just compile filename.c into the assembler code only. +# +# make filename.i = Create a preprocessed source file for use in submitting +# bug reports to the GCC project. +# +# To rebuild project do "make clean" then "make all". +#---------------------------------------------------------------------------- + +# Target file name (without extension). +TARGET = lightsaber_lufa + +# Directory common source filess exist +TOP_DIR = ../.. + +# Directory keyboard dependent files exist +TARGET_DIR = . + + +# List C source files here. (C dependencies are automatically generated.) +SRC += keymap.c \ + led.c \ + matrix.c + +CONFIG_H = config.h + + +# MCU name +MCU = atmega32u4 + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency in Hz. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# +# This will be an integer division of F_USB below, as it is sourced by +# F_USB after it has run through any CPU prescalers. Note that this value +# does not *change* the processor frequency - it should merely be updated to +# reflect the processor speed set externally so that the code can use accurate +# software delays. +F_CPU = 8000000 + + +# +# LUFA specific +# +# Target architecture (see library "Board Types" documentation). +ARCH = AVR8 + +# Input clock frequency. +# This will define a symbol, F_USB, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_USB = $(F_CPU) + + +# Build Options +# comment out to disable the options. +# +BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +#MOUSEKEY_ENABLE = yes # Mouse keys(+4700) +EXTRAKEY_ENABLE = yes # Audio control and System control(+450) +CONSOLE_ENABLE = yes # Console for debug(+400) +COMMAND_ENABLE = yes # Commands for debug and configuration +#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend +#NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA +#BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality + + +# Boot Section Size in bytes +# Teensy halfKay 512 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +OPT_DEFS += -DBOOTLOADER_SIZE=4096 + + +# Search Path +VPATH += $(TARGET_DIR) +VPATH += $(TOP_DIR) + +include $(TOP_DIR)/protocol/lufa.mk +include $(TOP_DIR)/common.mk +include $(TOP_DIR)/rules.mk + +winkey: OPT_DEFS += -DLAYOUT_WINKEY +winkey: all diff --git a/keyboard/lightsaber/Makefile.pjrc b/keyboard/lightsaber/Makefile.pjrc new file mode 100644 index 00000000..1c5a9710 --- /dev/null +++ b/keyboard/lightsaber/Makefile.pjrc @@ -0,0 +1,101 @@ +#---------------------------------------------------------------------------- +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF. +# +# make extcoff = Convert ELF to AVR Extended COFF. +# +# make program = Download the hex file to the device. +# Please customize your programmer settings(PROGRAM_CMD) +# +# make teensy = Download the hex file to the device, using teensy_loader_cli. +# (must have teensy_loader_cli installed). +# +# make dfu = Download the hex file to the device, using dfu-programmer (must +# have dfu-programmer installed). +# +# make flip = Download the hex file to the device, using Atmel FLIP (must +# have Atmel FLIP installed). +# +# make dfu-ee = Download the eeprom file to the device, using dfu-programmer +# (must have dfu-programmer installed). +# +# make flip-ee = Download the eeprom file to the device, using Atmel FLIP +# (must have Atmel FLIP installed). +# +# make debug = Start either simulavr or avarice as specified for debugging, +# with avr-gdb or avr-insight as the front end for debugging. +# +# make filename.s = Just compile filename.c into the assembler code only. +# +# make filename.i = Create a preprocessed source file for use in submitting +# bug reports to the GCC project. +# +# To rebuild project do "make clean" then "make all". +#---------------------------------------------------------------------------- + +# Target file name (without extension). +TARGET = lightsaber_pjrc + +# Directory common source filess exist +TOP_DIR = ../.. + +# Directory keyboard dependent files exist +TARGET_DIR = . + +# keyboard dependent files +SRC = keymap.c \ + matrix.c \ + led.c \ + backlight.c + +CONFIG_H = config.h + + +# MCU name, you MUST set this to match the board you are using +# type "make clean" after changing this, so all files will be rebuilt +#MCU = at90usb162 # Teensy 1.0 +MCU = atmega32u4 # Teensy 2.0 +#MCU = at90usb646 # Teensy++ 1.0 +#MCU = at90usb1286 # Teensy++ 2.0 + + +# Processor frequency. +# Normally the first thing your program should do is set the clock prescaler, +# so your program will run at the correct speed. You should also set this +# variable to same clock speed. The _delay_ms() macro uses this, and many +# examples use this variable to calculate timings. Do not add a "UL" here. +F_CPU = 8000000 + + +# Build Options +# comment out to disable the options. +# +BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +#MOUSEKEY_ENABLE = yes # Mouse keys(+5000) +EXTRAKEY_ENABLE = yes # Audio control and System control(+600) +CONSOLE_ENABLE = yes # Console for debug +COMMAND_ENABLE = yes # Commands for debug and configuration +#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend +#NKRO_ENABLE = yes # USB Nkey Rollover(+500) +#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support +BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality + + +# Search Path +VPATH += $(TARGET_DIR) +VPATH += $(TOP_DIR) + +include $(TOP_DIR)/protocol/pjrc.mk +include $(TOP_DIR)/common.mk +include $(TOP_DIR)/rules.mk + +winkey: OPT_DEFS += -DLAYOUT_WINKEY +winkey: all + +winkeyless: OPT_DEFS += -DLAYOUT_WINKEYLESS +winkeyless: all diff --git a/keyboard/lightsaber/README.md b/keyboard/lightsaber/README.md new file mode 100644 index 00000000..dc35870c --- /dev/null +++ b/keyboard/lightsaber/README.md @@ -0,0 +1,110 @@ +KMAC keyboard firmware +====================== +Korean custom keyboard designed by Byungho Kim and KBDMania community. + +*Note that this is not the official firmware* + +Supported models +---------------- +At the moment only the TKL models is supported. + + +Build +----- +Move to this directory then just run `make` like: + + $ make -f Makefile.[pjrc|lufa] [winkey|winkeyless] + +Use `Makefile.pjrc` if you want to use PJRC stack or use `Makefile.lufa` for LUFA stack. + + +Bootloader +--------- +The PCB is hardwired to run the bootloader if the key at the `Caps Lock` position is held down when connecting the keyboard. + +It is still possible to use Boot Magic and Command to access the bootloader though. + + +Keymap +------ +There are 2 different types of PCB. +They each have their own keymap file. + +To customize a keymap: + 1. Edit the file that corresponds to your PCB. + 2. Specify your layout when building. + +### 1. Winkey +This is the default keymap. + +See [keymap_winkey.h](keymap_winkey.h) for detail. + +#### 1.0. Winkey Default Layer + ,---. ,---------------. ,---------------. ,---------------. ,-----------. + |Esc| |F1 |F2 |F3 |F4 | |F5 |F6 |F7 |F8 | |F9 |F10|F11|F12| |PrS|ScL|Pau| + `---' `---------------' `---------------' `---------------' `-----------' + ,-----------------------------------------------------------. ,-----------. + |~ | 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backsp | |Ins|Hom|PgU| + |-----------------------------------------------------------| |-----------| + |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| |Del|End|PgD| + |-----------------------------------------------------------| '-----------' + |Fn0 | A| S| D| F| G| H| J| K| L| ;| '|Return | + |-----------------------------------------------------------| ,---. + |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift | |Up | + |-----------------------------------------------------------| ,-----------. + |Ctl|Gui|Alt| Space |Alt|Gui|App|Ctl| |Lef|Dow|Rig| + `-----------------------------------------------------------' `-----------' + +#### 1.1. Winkey Media Layer + ,---. ,---------------. ,---------------. ,---------------. ,-----------. + |Led| | | | | | | | | | | | | | | | | | |Slp| + `---' `---------------' `---------------' `---------------' `-----------' + ,-----------------------------------------------------------. ,-----------. + | | | | | | | | | | |Mut|V- |V+ | | | | | | + |-----------------------------------------------------------| |-----------| + | | | | | | | | | |Stp|Ply|Prv|Nxt|Media| | | | | + |-----------------------------------------------------------| '-----------' + | | | | | | | | | | | | | | + |-----------------------------------------------------------| ,---. + | | | |Clc| | | | | | | |Caps | | | + |-----------------------------------------------------------| ,-----------. + | | | | | | | | | | | | | + `-----------------------------------------------------------' `-----------' + + +### 2. Winkeyless +Layout with 1.5 unit modifiers. + +See [keymap_winkeyless.h](keymap_winkeyless.h) for detail. + +#### 2.0. Winkeyless Default Layer + ,---. ,---------------. ,---------------. ,---------------. ,-----------. + |Esc| |F1 |F2 |F3 |F4 | |F5 |F6 |F7 |F8 | |F9 |F10|F11|F12| |PrS|ScL|Pau| + `---' `---------------' `---------------' `---------------' `-----------' + ,-----------------------------------------------------------. ,-----------. + |~ | 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backsp | |Ins|Hom|PgU| + |-----------------------------------------------------------| |-----------| + |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| |Del|End|PgD| + |-----------------------------------------------------------| '-----------' + |Fn0 | A| S| D| F| G| H| J| K| L| ;| '|Return | + |-----------------------------------------------------------| ,---. + |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift | |Up | + |-----------------------------------------------------------| ,-----------. + |Ctl |Gui|Alt | Space |Alt |Gui|Ctl | |Lef|Dow|Rig| + `-----------------------------------------------------------' `-----------' + +#### 2.1. Winkeyless Media Layer + ,---. ,---------------. ,---------------. ,---------------. ,-----------. + |Led| | | | | | | | | | | | | | | | | | |Slp| + `---' `---------------' `---------------' `---------------' `-----------' + ,-----------------------------------------------------------. ,-----------. + | | | | | | | | | | |Mut|V- |V+ | | | | | | + |-----------------------------------------------------------| |-----------| + | | | | | | | | | |Stp|Ply|Prv|Nxt|Media| | | | | + |-----------------------------------------------------------| '-----------' + | | | | | | | | | | | | | | + |-----------------------------------------------------------| ,---. + | | | |Clc| | | | | | | |Caps | | | + |-----------------------------------------------------------| ,-----------. + | | | | | | | | | | | | + `-----------------------------------------------------------' `-----------' diff --git a/keyboard/lightsaber/config.h b/keyboard/lightsaber/config.h new file mode 100644 index 00000000..b8de6adb --- /dev/null +++ b/keyboard/lightsaber/config.h @@ -0,0 +1,43 @@ +/* +Copyright 2013 Mathias Andersson + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef CONFIG_H +#define CONFIG_H + +/* USB Device descriptor parameter */ +#define VENDOR_ID 0xFEED +#define PRODUCT_ID 0x6050 +#define DEVICE_VER 0x0104 +#define MANUFACTURER Duck +#define PRODUCT Lightsaber + +/* message strings */ +#define DESCRIPTION t.m.k. keyboard firmware for Lightsaber + +/* matrix size */ +#define MATRIX_ROWS 6 +#define MATRIX_COLS 18 + +/* Set 0 if need no debouncing */ +#define DEBOUNCE 5 + +/* key combination for command */ +#define IS_COMMAND() ( \ + keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ +) + +#endif diff --git a/keyboard/lightsaber/keymap.c b/keyboard/lightsaber/keymap.c new file mode 100644 index 00000000..398e51ec --- /dev/null +++ b/keyboard/lightsaber/keymap.c @@ -0,0 +1,77 @@ +/* +Copyright 2014 Ralf Schmitt + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +/* + * Keymap for Lightsaber controller + */ +#include +#include +#include +#include "keycode.h" +#include "action.h" +#include "action_macro.h" +#include "report.h" +#include "host.h" +#include "debug.h" +#include "keymap.h" + +// Convert physical keyboard layout to matrix array. +// This is a macro to define keymap easily in keyboard layout form. +#define KEYMAP( \ + K5A, K5B, K5C, K5D, K5E, K5F, K5G, K5H, K5I, K5J, K5K, K5L, K5M, K5N, K5O, K5P, K5Q, K5R, \ + K4A, K4B, K4C, K4D, K4E, K4F, K4G, K4H, K4I, K4J, K4K, K4L, K4M, K4N, K4O, K4P, K4Q, K4R, \ + K3A, K3B, K3C, K3D, K3E, K3F, K3G, K3H, K3I, K3J, K3K, K3L, K3M, K3N, K3O, K3P, K3Q, K3R, \ + K2A, K2B, K2C, K2D, K2E, K2F, K2G, K2H, K2I, K2J, K2K, K2L, K2M, K2N, K2O, K2P, K2Q, K2R, \ + K1A, K1C, K1D, K1E, K1F, K1G, K1H, K1I, K1J, K1K, K1L, K1M, K1N, K1O, K1P, K1Q, K1R, \ + K0A, K0B, K0C, K0G, K0K, K0L, K0M, K0N, K0O, K0P, K0Q, K0R \ +) { \ +/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 */ \ +/* 5 */ { KC_##K5A, KC_##K5B, KC_##K5C, KC_##K5D, KC_##K5E, KC_##K5F, KC_##K5G, KC_##K5H, KC_##K5I, KC_##K5J, KC_##K5K, KC_##K5L, KC_##K5M, KC_##K5N, KC_##K5O, KC_##K5P, KC_##K5Q, KC_##K5R}, \ +/* 4 */ { KC_##K4A, KC_##K4B, KC_##K4C, KC_##K4D, KC_##K4E, KC_##K4F, KC_##K4G, KC_##K4H, KC_##K4I, KC_##K4J, KC_##K4K, KC_##K4L, KC_##K4M, KC_##K4N, KC_##K4O, KC_##K4P, KC_##K4Q, KC_##K4R}, \ +/* 3 */ { KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D, KC_##K3E, KC_##K3F, KC_##K3G, KC_##K3H, KC_##K3I, KC_##K3J, KC_##K3K, KC_##K3L, KC_##K3M, KC_##K3N, KC_##K3O, KC_##K3P, KC_##K3Q, KC_##K3R}, \ +/* 2 */ { KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D, KC_##K2E, KC_##K2F, KC_##K2G, KC_##K2H, KC_##K2I, KC_##K2J, KC_##K2K, KC_##K2L, KC_##K2M, KC_##K2N, KC_##K2O, KC_##K2P, KC_##K2Q, KC_##K2R}, \ +/* 1 */ { KC_##K1A, KC_##K1C, KC_##K1D, KC_##K1E, KC_##K1F, KC_##K1G, KC_##K1H, KC_##K1I, KC_##K1J, KC_##K1K, KC_##K1L, KC_NO, KC_##K1M, KC_##K1N, KC_##K1O, KC_##K1P, KC_##K1Q, KC_##K1R}, \ +/* 0 */ { KC_##K0A, KC_##K0B, KC_##K0C, KC_NO, KC_NO, KC_##K0G, KC_NO, KC_NO, KC_##K0K, KC_NO, KC_##K0L, KC_NO, KC_##K0M, KC_##K0N, KC_##K0O, KC_##K0P, KC_##K0Q, KC_##K0R} \ +} + +#include "keymap_winkey.h" + +#define KEYMAPS_SIZE (sizeof(keymaps) / sizeof(keymaps[0])) +#define FN_ACTIONS_SIZE (sizeof(fn_actions) / sizeof(fn_actions[0])) + +/* translates key to keycode */ +uint8_t keymap_key_to_keycode(uint8_t layer, key_t key) +{ + if (layer < KEYMAPS_SIZE) { + return pgm_read_byte(&keymaps[(layer)][(key.row)][(key.col)]); + } else { + // fall back to layer 0 + return pgm_read_byte(&keymaps[0][(key.row)][(key.col)]); + } +} + +/* translates Fn keycode to action */ +action_t keymap_fn_to_action(uint8_t keycode) +{ + action_t action; + if (FN_INDEX(keycode) < FN_ACTIONS_SIZE) { + action.code = pgm_read_word(&fn_actions[FN_INDEX(keycode)]); + } else { + action.code = ACTION_NO; + } + return action; +} diff --git a/keyboard/lightsaber/keymap_winkey.h b/keyboard/lightsaber/keymap_winkey.h new file mode 100644 index 00000000..510fa7f7 --- /dev/null +++ b/keyboard/lightsaber/keymap_winkey.h @@ -0,0 +1,12 @@ +static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + KEYMAP(\ + ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, DEL, INS, PSCR, SLCK, BRK, \ + GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, NUMLOCK,KP_SLASH,KP_ASTERISK,KP_MINUS, \ + TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, KP_7, KP_8, KP_9, KP_PLUS, \ + CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT,NO, ENT, KP_4, KP_5, KP_6, NO, \ + LSFT, Z, X, C, V, B, N, M, COMM,DOT, SLSH,NO, RSFT, KP_1, KP_2, KP_3, KP_ENTER, \ + LCTL,LGUI,LALT, SPC, NO, RALT,RGUI,RCTL, KP_0, NO, KP_DOT, NO) +}; + +static const uint16_t PROGMEM fn_actions[] = { +}; diff --git a/keyboard/lightsaber/led.c b/keyboard/lightsaber/led.c new file mode 100644 index 00000000..9c98f9db --- /dev/null +++ b/keyboard/lightsaber/led.c @@ -0,0 +1,24 @@ +/* +Copyright 2012 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include +#include "stdint.h" +#include "led.h" + +void led_set(uint8_t usb_led) +{ +} diff --git a/keyboard/lightsaber/matrix.c b/keyboard/lightsaber/matrix.c new file mode 100644 index 00000000..e3eca84d --- /dev/null +++ b/keyboard/lightsaber/matrix.c @@ -0,0 +1,292 @@ +/* +Copyright 2014 Ralf Schmitt + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include "print.h" +#include "debug.h" +#include "util.h" +#include "matrix.h" + + +#ifndef DEBOUNCE +# define DEBOUNCE 0 +#endif +static uint8_t debouncing = DEBOUNCE; + +/* matrix state(1:on, 0:off) */ +static matrix_row_t matrix[MATRIX_ROWS]; +static matrix_row_t matrix_debouncing[MATRIX_ROWS]; + +static uint8_t read_rows(void); +static uint8_t read_fwkey(void); +static void init_rows(void); +static void unselect_cols(void); +static void select_col(uint8_t col); + +inline +uint8_t matrix_rows(void) +{ + return MATRIX_ROWS; +} + +inline +uint8_t matrix_cols(void) +{ + return MATRIX_COLS; +} + +void matrix_init(void) +{ + unselect_cols(); + init_rows(); + // initialize matrix state: all keys off + for (uint8_t i=0; i < MATRIX_ROWS; i++) { + matrix[i] = 0; + matrix_debouncing[i] = 0; + } +} + +uint8_t matrix_scan(void) +{ + for (uint8_t col = 0; col < MATRIX_COLS; col++) { // 0-17 + select_col(col); + _delay_us(3); // TODO: Determine the correct value needed here. + uint8_t rows = read_rows(); + // Use the otherwise unused col: 12 row: 3 for firmware. + if(col == 12) { + rows |= read_fwkey(); + } + for (uint8_t row = 0; row < MATRIX_ROWS; row++) { // 0-5 + bool prev_bit = matrix_debouncing[row] & ((matrix_row_t)1< Date: Wed, 19 Mar 2014 00:21:45 +0100 Subject: [PATCH 72/76] Updated Lightsaber read me --- keyboard/lightsaber/README.md | 92 ++--------------------------------- 1 file changed, 4 insertions(+), 88 deletions(-) diff --git a/keyboard/lightsaber/README.md b/keyboard/lightsaber/README.md index dc35870c..bd2b3fb5 100644 --- a/keyboard/lightsaber/README.md +++ b/keyboard/lightsaber/README.md @@ -1,12 +1,12 @@ -KMAC keyboard firmware +Lightsaber keyboard firmware ====================== -Korean custom keyboard designed by Byungho Kim and KBDMania community. +Korean custom keyboard designed by Duck. *Note that this is not the official firmware* Supported models ---------------- -At the moment only the TKL models is supported. +All pcb options are supported. Build @@ -20,91 +20,7 @@ Use `Makefile.pjrc` if you want to use PJRC stack or use `Makefile.lufa` for LUF Bootloader --------- -The PCB is hardwired to run the bootloader if the key at the `Caps Lock` position is held down when connecting the keyboard. +The PCB is hardwired to run the bootloader if the key at the `one above backspace` position is held down when connecting the keyboard. It is still possible to use Boot Magic and Command to access the bootloader though. - -Keymap ------- -There are 2 different types of PCB. -They each have their own keymap file. - -To customize a keymap: - 1. Edit the file that corresponds to your PCB. - 2. Specify your layout when building. - -### 1. Winkey -This is the default keymap. - -See [keymap_winkey.h](keymap_winkey.h) for detail. - -#### 1.0. Winkey Default Layer - ,---. ,---------------. ,---------------. ,---------------. ,-----------. - |Esc| |F1 |F2 |F3 |F4 | |F5 |F6 |F7 |F8 | |F9 |F10|F11|F12| |PrS|ScL|Pau| - `---' `---------------' `---------------' `---------------' `-----------' - ,-----------------------------------------------------------. ,-----------. - |~ | 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backsp | |Ins|Hom|PgU| - |-----------------------------------------------------------| |-----------| - |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| |Del|End|PgD| - |-----------------------------------------------------------| '-----------' - |Fn0 | A| S| D| F| G| H| J| K| L| ;| '|Return | - |-----------------------------------------------------------| ,---. - |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift | |Up | - |-----------------------------------------------------------| ,-----------. - |Ctl|Gui|Alt| Space |Alt|Gui|App|Ctl| |Lef|Dow|Rig| - `-----------------------------------------------------------' `-----------' - -#### 1.1. Winkey Media Layer - ,---. ,---------------. ,---------------. ,---------------. ,-----------. - |Led| | | | | | | | | | | | | | | | | | |Slp| - `---' `---------------' `---------------' `---------------' `-----------' - ,-----------------------------------------------------------. ,-----------. - | | | | | | | | | | |Mut|V- |V+ | | | | | | - |-----------------------------------------------------------| |-----------| - | | | | | | | | | |Stp|Ply|Prv|Nxt|Media| | | | | - |-----------------------------------------------------------| '-----------' - | | | | | | | | | | | | | | - |-----------------------------------------------------------| ,---. - | | | |Clc| | | | | | | |Caps | | | - |-----------------------------------------------------------| ,-----------. - | | | | | | | | | | | | | - `-----------------------------------------------------------' `-----------' - - -### 2. Winkeyless -Layout with 1.5 unit modifiers. - -See [keymap_winkeyless.h](keymap_winkeyless.h) for detail. - -#### 2.0. Winkeyless Default Layer - ,---. ,---------------. ,---------------. ,---------------. ,-----------. - |Esc| |F1 |F2 |F3 |F4 | |F5 |F6 |F7 |F8 | |F9 |F10|F11|F12| |PrS|ScL|Pau| - `---' `---------------' `---------------' `---------------' `-----------' - ,-----------------------------------------------------------. ,-----------. - |~ | 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backsp | |Ins|Hom|PgU| - |-----------------------------------------------------------| |-----------| - |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| |Del|End|PgD| - |-----------------------------------------------------------| '-----------' - |Fn0 | A| S| D| F| G| H| J| K| L| ;| '|Return | - |-----------------------------------------------------------| ,---. - |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift | |Up | - |-----------------------------------------------------------| ,-----------. - |Ctl |Gui|Alt | Space |Alt |Gui|Ctl | |Lef|Dow|Rig| - `-----------------------------------------------------------' `-----------' - -#### 2.1. Winkeyless Media Layer - ,---. ,---------------. ,---------------. ,---------------. ,-----------. - |Led| | | | | | | | | | | | | | | | | | |Slp| - `---' `---------------' `---------------' `---------------' `-----------' - ,-----------------------------------------------------------. ,-----------. - | | | | | | | | | | |Mut|V- |V+ | | | | | | - |-----------------------------------------------------------| |-----------| - | | | | | | | | | |Stp|Ply|Prv|Nxt|Media| | | | | - |-----------------------------------------------------------| '-----------' - | | | | | | | | | | | | | | - |-----------------------------------------------------------| ,---. - | | | |Clc| | | | | | | |Caps | | | - |-----------------------------------------------------------| ,-----------. - | | | | | | | | | | | | - `-----------------------------------------------------------' `-----------' From 526d988a0caadc1a48bea862f605c9cee90c3dd3 Mon Sep 17 00:00:00 2001 From: Ralf Schmitt Date: Wed, 19 Mar 2014 23:58:08 +0100 Subject: [PATCH 73/76] Added basic led+backlight support --- keyboard/lightsaber/Makefile.lufa | 3 +- keyboard/lightsaber/backlight.c | 56 +++++++++++++++++++++++++++++ keyboard/lightsaber/config.h | 3 ++ keyboard/lightsaber/keymap_winkey.h | 3 +- keyboard/lightsaber/led.c | 32 ++++++++++++++++- 5 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 keyboard/lightsaber/backlight.c diff --git a/keyboard/lightsaber/Makefile.lufa b/keyboard/lightsaber/Makefile.lufa index 6982b51f..25816ac0 100644 --- a/keyboard/lightsaber/Makefile.lufa +++ b/keyboard/lightsaber/Makefile.lufa @@ -51,6 +51,7 @@ TARGET_DIR = . # List C source files here. (C dependencies are automatically generated.) SRC += keymap.c \ led.c \ + backlight.c \ matrix.c CONFIG_H = config.h @@ -103,7 +104,7 @@ CONSOLE_ENABLE = yes # Console for debug(+400) COMMAND_ENABLE = yes # Commands for debug and configuration #SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend #NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA -#BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality +BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality # Boot Section Size in bytes diff --git a/keyboard/lightsaber/backlight.c b/keyboard/lightsaber/backlight.c new file mode 100644 index 00000000..b2820080 --- /dev/null +++ b/keyboard/lightsaber/backlight.c @@ -0,0 +1,56 @@ +/* +Copyright 2014 Ralf Schmitt + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include +#include "backlight.h" + +/* Backlight pin configuration + * + * Alphas PB1 (high) + * Numeric PB2 (high) + * Mod+Num PB3 (high) + * Backside PD6 (high) + * TopRight PD7 (low) + * F-Row PE6 (high) + * + */ +void backlight_set(uint8_t level) +{ + // Set as output. + DDRB |= (1<<1) | (1<<2) | (1<<3); + DDRD |= (1<<6) | (1<<7); + DDRE |= (1<<6); + + if(level & (1<<0)) + { + PORTB &= ~(1<<1); + PORTB &= ~(1<<2); + PORTB &= ~(1<<3); + PORTD &= ~(1<<6); + PORTD |= (1<<7); + PORTE &= ~(1<<6); + } + else + { + PORTB |= (1<<1); + PORTB |= (1<<2); + PORTB |= (1<<3); + PORTD |= (1<<6); + PORTD &= ~(1<<7); + PORTE |= (1<<6); + } +} diff --git a/keyboard/lightsaber/config.h b/keyboard/lightsaber/config.h index b8de6adb..d971d038 100644 --- a/keyboard/lightsaber/config.h +++ b/keyboard/lightsaber/config.h @@ -32,6 +32,9 @@ along with this program. If not, see . #define MATRIX_ROWS 6 #define MATRIX_COLS 18 +/* number of backlight levels */ +#define BACKLIGHT_LEVELS 1 + /* Set 0 if need no debouncing */ #define DEBOUNCE 5 diff --git a/keyboard/lightsaber/keymap_winkey.h b/keyboard/lightsaber/keymap_winkey.h index 510fa7f7..9d558ae7 100644 --- a/keyboard/lightsaber/keymap_winkey.h +++ b/keyboard/lightsaber/keymap_winkey.h @@ -3,10 +3,11 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, DEL, INS, PSCR, SLCK, BRK, \ GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, NUMLOCK,KP_SLASH,KP_ASTERISK,KP_MINUS, \ TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, KP_7, KP_8, KP_9, KP_PLUS, \ - CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT,NO, ENT, KP_4, KP_5, KP_6, NO, \ + CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT,FN0, ENT, KP_4, KP_5, KP_6, NO, \ LSFT, Z, X, C, V, B, N, M, COMM,DOT, SLSH,NO, RSFT, KP_1, KP_2, KP_3, KP_ENTER, \ LCTL,LGUI,LALT, SPC, NO, RALT,RGUI,RCTL, KP_0, NO, KP_DOT, NO) }; static const uint16_t PROGMEM fn_actions[] = { + [0] = ACTION_BACKLIGHT_STEP() }; diff --git a/keyboard/lightsaber/led.c b/keyboard/lightsaber/led.c index 9c98f9db..c3f85427 100644 --- a/keyboard/lightsaber/led.c +++ b/keyboard/lightsaber/led.c @@ -1,5 +1,5 @@ /* -Copyright 2012 Jun Wako +Copyright 2014 Ralf Schmitt This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,6 +19,36 @@ along with this program. If not, see . #include "stdint.h" #include "led.h" +/* LED pin configuration + * + * Caps PB0 (low) + * NumLock PB4 (low) + * + */ void led_set(uint8_t usb_led) { + // Set as output. + DDRB |= (1<<0) | (1<<4); + + if (usb_led & (1< Date: Sat, 22 Mar 2014 12:41:45 +0100 Subject: [PATCH 74/76] Lightsaber clean ups --- README.md | 1 + keyboard/lightsaber/Makefile.lufa | 6 +++--- keyboard/lightsaber/Makefile.pjrc | 11 ++--------- keyboard/lightsaber/README.md | 2 +- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a561b38e..6596dc33 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ You can find some keyboard specific projects under `converter` and `keyboard` di * [IIgs_Standard](keyboard/IIgs/) - Apple [IIGS] keyboard mod(by JeffreySung) * [macway](keyboard/macway/) - [Compact keyboard mod][GH_macway] [retired] * [KMAC](keyboard/kmac/) - Korean custom keyboard +* [Lightsaber](keyboard/lightsaber/) - Korean custom keyboard [GH_macway]: http://geekhack.org/showwiki.php?title=Island:11930 [GH_hhkb]: http://geekhack.org/showwiki.php?title=Island:12047 diff --git a/keyboard/lightsaber/Makefile.lufa b/keyboard/lightsaber/Makefile.lufa index 25816ac0..b430efd2 100644 --- a/keyboard/lightsaber/Makefile.lufa +++ b/keyboard/lightsaber/Makefile.lufa @@ -49,10 +49,10 @@ TARGET_DIR = . # List C source files here. (C dependencies are automatically generated.) -SRC += keymap.c \ +SRC = keymap.c \ + matrix.c \ led.c \ - backlight.c \ - matrix.c + backlight.c CONFIG_H = config.h diff --git a/keyboard/lightsaber/Makefile.pjrc b/keyboard/lightsaber/Makefile.pjrc index 1c5a9710..58735a7e 100644 --- a/keyboard/lightsaber/Makefile.pjrc +++ b/keyboard/lightsaber/Makefile.pjrc @@ -56,12 +56,8 @@ SRC = keymap.c \ CONFIG_H = config.h -# MCU name, you MUST set this to match the board you are using -# type "make clean" after changing this, so all files will be rebuilt -#MCU = at90usb162 # Teensy 1.0 -MCU = atmega32u4 # Teensy 2.0 -#MCU = at90usb646 # Teensy++ 1.0 -#MCU = at90usb1286 # Teensy++ 2.0 +# MCU name +MCU = atmega32u4 # Processor frequency. @@ -96,6 +92,3 @@ include $(TOP_DIR)/rules.mk winkey: OPT_DEFS += -DLAYOUT_WINKEY winkey: all - -winkeyless: OPT_DEFS += -DLAYOUT_WINKEYLESS -winkeyless: all diff --git a/keyboard/lightsaber/README.md b/keyboard/lightsaber/README.md index bd2b3fb5..9dcd6930 100644 --- a/keyboard/lightsaber/README.md +++ b/keyboard/lightsaber/README.md @@ -13,7 +13,7 @@ Build ----- Move to this directory then just run `make` like: - $ make -f Makefile.[pjrc|lufa] [winkey|winkeyless] + $ make -f Makefile.[pjrc|lufa] Use `Makefile.pjrc` if you want to use PJRC stack or use `Makefile.lufa` for LUFA stack. From 1482fe92a0c5af6f0a84396a3f9fee73d59bb48f Mon Sep 17 00:00:00 2001 From: Ralf Schmitt Date: Sat, 22 Mar 2014 13:13:37 +0100 Subject: [PATCH 75/76] Added Lightsaber FN-layer --- keyboard/lightsaber/keymap_winkey.h | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/keyboard/lightsaber/keymap_winkey.h b/keyboard/lightsaber/keymap_winkey.h index 9d558ae7..59ffd4a8 100644 --- a/keyboard/lightsaber/keymap_winkey.h +++ b/keyboard/lightsaber/keymap_winkey.h @@ -1,13 +1,21 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KEYMAP(\ - ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, DEL, INS, PSCR, SLCK, BRK, \ - GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, NUMLOCK,KP_SLASH,KP_ASTERISK,KP_MINUS, \ - TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, KP_7, KP_8, KP_9, KP_PLUS, \ - CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT,FN0, ENT, KP_4, KP_5, KP_6, NO, \ - LSFT, Z, X, C, V, B, N, M, COMM,DOT, SLSH,NO, RSFT, KP_1, KP_2, KP_3, KP_ENTER, \ - LCTL,LGUI,LALT, SPC, NO, RALT,RGUI,RCTL, KP_0, NO, KP_DOT, NO) + ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, DEL, INS, PSCR, SLCK, BRK, \ + GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, NUMLOCK,KP_SLASH,KP_ASTERISK,KP_MINUS, \ + TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, KP_7, KP_8, KP_9, KP_PLUS, \ + CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT,FN0, ENT, KP_4, KP_5, KP_6, NO, \ + LSFT, Z, X, C, V, B, N, M, COMM,DOT, SLSH,NO, RSFT, KP_1, KP_2, KP_3, KP_ENTER, \ + LCTL,LGUI,LALT, SPC, NO, RALT,RGUI,RCTL, KP_0, NO, KP_DOT, NO), \ + KEYMAP(\ + CALC,MYCM,WSCH,WHOM,MAIL,MUTE,VOLD,VOLU,MSEL,MSTP,MPLY,MPRV,MNXT,TRNS, TRNS, WAKE, PWR, SLEP, \ + TRNS,TRNS,TRNS,TRNS,END ,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS, TRNS, TRNS, TRNS, \ + TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS, TRNS, TRNS, TRNS, \ + TRNS,TRNS,TRNS,TRNS,PGDN,TRNS,LEFT,DOWN,UP ,RGHT,TRNS,TRNS,TRNS,TRNS, TRNS, TRNS, TRNS, TRNS, \ + TRNS, TRNS,TRNS,TRNS,TRNS,PGUP,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS, TRNS, TRNS, TRNS, \ + TRNS,TRNS,TRNS, FN1, TRNS,TRNS,TRNS,TRNS, TRNS, TRNS, TRNS, TRNS) }; static const uint16_t PROGMEM fn_actions[] = { - [0] = ACTION_BACKLIGHT_STEP() + [0] = ACTION_LAYER_MOMENTARY(1), + [1] = ACTION_BACKLIGHT_STEP() }; From 13fbab9d8b2015f4b81316bbdfba0705d459a480 Mon Sep 17 00:00:00 2001 From: Johan Isacsson Date: Thu, 27 Mar 2014 23:59:25 +0100 Subject: [PATCH 76/76] Show correct function name for default layer set --- doc/keymap.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/keymap.md b/doc/keymap.md index 7ef7430c..3d78fc9c 100644 --- a/doc/keymap.md +++ b/doc/keymap.md @@ -269,7 +269,7 @@ Default Layer is a layer which always is valid and referred to when actions is n This sets Default Layer to given parameter `layer` and activate it. - ACTION_DEFAULT_LAYER(layer) + ACTION_DEFAULT_LAYER_SET(layer) #### 2.2.2 Momentary