diff --git a/.github/workflows/arduino_cron.yml b/.github/workflows/arduino_cron.yml index 88e5502fe..bdc40c050 100644 --- a/.github/workflows/arduino_cron.yml +++ b/.github/workflows/arduino_cron.yml @@ -61,7 +61,7 @@ jobs: strategy: fail-fast: false matrix: - arduino-platform: ["cpb", "cpc", "cpx_ada", "esp32", "esp8266", "feather32u4", "feather_esp32c6", "feather_m0_express", "feather_m4_express", "feather_rp2040", "feather_rp2040_adalogger", "flora", "funhouse", "gemma", "gemma_m0", "hallowing_m0", "hallowing_m4_tinyusb", "ledglasses_nrf52840", "magtag", "metro_m0", "metro_m0_tinyusb", "metro_m4", "metro_m4_tinyusb", "monster_m4sk", "monster_m4sk_tinyusb", "neokeytrinkey_m0", "neotrellis_m4", "nrf52832", "nrf52840", "pixeltrinkey_m0", "protrinket_5v", "proxlighttrinkey_m0", "pybadge", "pycamera_s3", "pygamer", "pyportal", "qualia_s3_rgb666", "qt2040_trinkey", "qtpy_m0", "qtpy_esp32s2", "rotarytrinkey_m0", "sht4xtrinkey_m0", "slidetrinkey_m0", "trinket_5v", "trinket_m0", "uno"] + arduino-platform: ["cpb", "cpc", "cpx_ada", "esp32", "esp8266", "feather32u4", "feather_esp32c6", "feather_m0_express", "feather_m4_express", "feather_rp2040", "feather_rp2040_adalogger", "feather_rp2350", "flora", "fruit_jam_tinyusb", "funhouse", "gemma", "gemma_m0", "hallowing_m0", "hallowing_m4_tinyusb", "ledglasses_nrf52840", "magtag", "metro_m0", "metro_m0_tinyusb", "metro_m4", "metro_m4_tinyusb", "monster_m4sk", "monster_m4sk_tinyusb", "metro_rp2350", "neokeytrinkey_m0", "neotrellis_m4", "nrf52832", "nrf52840", "pixeltrinkey_m0", "protrinket_5v", "proxlighttrinkey_m0", "pybadge", "pycamera_s3", "pygamer", "pyportal", "qualia_s3_rgb666", "qt2040_trinkey", "qtpy_m0", "qtpy_esp32s2", "rotarytrinkey_m0", "sht4xtrinkey_m0", "slidetrinkey_m0", "trinket_5v", "trinket_m0", "uno"] runs-on: ubuntu-latest if: needs.check-if-needed.outputs.answer == 'true' needs: check-if-needed @@ -97,6 +97,8 @@ jobs: git clone --quiet https://github.com/adafruit/HID /home/runner/Arduino/libraries/HID_Project rm -rf /home/runner/Arduino/libraries/ArduinoHttpClient git clone --quiet https://github.com/arduino-libraries/ArduinoHttpClient.git /home/runner/Arduino/libraries/ArduinoHttpClient + git clone --quiet https://github.com/pschatzmann/ESP32-A2DP /home/runner/Arduino/libraries/ESP32-A2DP + git clone --quiet https://github.com/pschatzmann/arduino-audio-tools /home/runner/Arduino/libraries/arduino-audio-tools - name: test platforms run: python3 ci/build_platform.py ${{ matrix.arduino-platform }} diff --git a/4x4_MIDI_Messenger/code.py b/4x4_MIDI_Messenger/code.py index c2f9f2f7e..e6d8dbaec 100644 --- a/4x4_MIDI_Messenger/code.py +++ b/4x4_MIDI_Messenger/code.py @@ -8,6 +8,7 @@ from rainbowio import colorwheel import keypad import displayio +import i2cdisplaybus import busio import adafruit_seesaw.seesaw import adafruit_seesaw.neopixel @@ -50,7 +51,7 @@ i2c = board.STEMMA_I2C() # STEMMA OLED setup -display_bus = displayio.I2CDisplay(i2c, device_address=0x3D, reset=oled_reset) +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3D, reset=oled_reset) display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=64) splash = displayio.Group() diff --git a/Crickit_FlippyBot/.feather_m0_express.test.only b/8_Channel_Solenoid_Driver/Arduino_Solenoid_Driver/.uno.test.only similarity index 100% rename from Crickit_FlippyBot/.feather_m0_express.test.only rename to 8_Channel_Solenoid_Driver/Arduino_Solenoid_Driver/.uno.test.only diff --git a/8_Channel_Solenoid_Driver/Arduino_Solenoid_Driver/Arduino_Solenoid_Driver.ino b/8_Channel_Solenoid_Driver/Arduino_Solenoid_Driver/Arduino_Solenoid_Driver.ino new file mode 100644 index 000000000..19640f150 --- /dev/null +++ b/8_Channel_Solenoid_Driver/Arduino_Solenoid_Driver/Arduino_Solenoid_Driver.ino @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#define NOID_1 0 // MCP23XXX pin LED is attached to +#define NOID_2 4 // MCP23XXX pin LED is attached to + +Adafruit_MCP23X17 mcp; + +void setup() { + Serial.begin(115200); + while (!Serial); + Serial.println("8 Channel Solenoid Driver Demo"); + if (!mcp.begin_I2C()) { + Serial.println("Couldn't find MCP23017.."); + while (1); + } + mcp.pinMode(NOID_1, OUTPUT); + mcp.pinMode(NOID_2, OUTPUT); + + Serial.println("Found MCP23017, looping..."); +} + +void loop() { + Serial.println("Solenoid 1!"); + mcp.digitalWrite(NOID_1, HIGH); + delay(500); + mcp.digitalWrite(NOID_1, LOW); + delay(500); + Serial.println("Solenoid 2!"); + mcp.digitalWrite(NOID_2, HIGH); + delay(500); + mcp.digitalWrite(NOID_2, LOW); + delay(500); + Serial.println("Together!"); + mcp.digitalWrite(NOID_1, HIGH); + mcp.digitalWrite(NOID_2, HIGH); + delay(1000); + mcp.digitalWrite(NOID_1, LOW); + mcp.digitalWrite(NOID_2, LOW); + delay(2000); + Serial.println("Repeat!"); + Serial.println(); + delay(500); +} diff --git a/8_Channel_Solenoid_Driver/CircuitPython/code.py b/8_Channel_Solenoid_Driver/CircuitPython/code.py new file mode 100644 index 000000000..84edcdeea --- /dev/null +++ b/8_Channel_Solenoid_Driver/CircuitPython/code.py @@ -0,0 +1,38 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import time +import board +from adafruit_mcp230xx.mcp23017 import MCP23017 + +i2c = board.STEMMA_I2C() + +mcp = MCP23017(i2c) + +noid_1 = mcp.get_pin(0) +noid_2 = mcp.get_pin(4) +noid_1.switch_to_output(value=False) +noid_2.switch_to_output(value=False) + +while True: + noid_1.value = True + print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}") + time.sleep(0.2) + noid_1.value = False + print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}") + time.sleep(0.2) + noid_2.value = True + print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}") + time.sleep(0.2) + noid_2.value = False + print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}") + time.sleep(1) + noid_1.value = True + noid_2.value = True + print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}") + time.sleep(1) + noid_1.value = False + noid_2.value = False + print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}") + time.sleep(2) diff --git a/AHT20_OLED/code.py b/AHT20_OLED/code.py index f281abf66..c9dcf1016 100755 --- a/AHT20_OLED/code.py +++ b/AHT20_OLED/code.py @@ -11,6 +11,7 @@ # OLED import displayio +import i2cdisplaybus import terminalio from adafruit_display_text import label import adafruit_displayio_ssd1306 @@ -25,7 +26,7 @@ #OLED -display_bus = displayio.I2CDisplay(i2c, device_address=0x3C) +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3C) display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32) # Make the display context diff --git a/AS5600_Magnetic_Encoder/code.py b/AS5600_Magnetic_Encoder/code.py new file mode 100644 index 000000000..232d0e64b --- /dev/null +++ b/AS5600_Magnetic_Encoder/code.py @@ -0,0 +1,43 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT +"""AS5600 Encoder""" +import usb_hid +import board +from adafruit_hid.consumer_control import ConsumerControl +from adafruit_hid.consumer_control_code import ConsumerControlCode +import adafruit_as5600 + +i2c = board.STEMMA_I2C() +sensor = adafruit_as5600.AS5600(i2c) +enc_inc = ConsumerControlCode.VOLUME_INCREMENT +enc_dec = ConsumerControlCode.VOLUME_DECREMENT +cc = ConsumerControl(usb_hid.devices) + +last_val = sensor.angle + +THRESHOLD = sensor.max_angle // 2 # default max_angle is 4095 +# you can change the max_angle. ex: sensor.max_angle = 1000 + +MIN_CHANGE = 25 # minimum change to register as movement +# increase to make less sensitive, decrease to make more sensitive + +while True: + enc_val = sensor.angle + if abs(enc_val - last_val) >= MIN_CHANGE or abs(enc_val - last_val) > THRESHOLD: + # Calculate the difference + diff = enc_val - last_val + # Check for wraparound + if diff > THRESHOLD: + # Wrapped from ~4095 to ~0 (actually turning backwards) + cc.send(enc_dec) + elif diff < -THRESHOLD: + # Wrapped from ~0 to ~4095 (actually turning forwards) + cc.send(enc_inc) + elif diff > 0: + # Normal forward rotation + cc.send(enc_inc) + else: + # Normal backward rotation (diff < 0) + cc.send(enc_dec) + last_val = enc_val diff --git a/Ada_remoteFXTrigger_NeoTrellis_FastLED_RX/Ada_remoteFXTrigger_NeoTrellis_FastLED_RX.ino b/Ada_remoteFXTrigger_NeoTrellis_FastLED_RX/Ada_remoteFXTrigger_NeoTrellis_FastLED_RX.ino index b41056b7c..83ecdb670 100644 --- a/Ada_remoteFXTrigger_NeoTrellis_FastLED_RX/Ada_remoteFXTrigger_NeoTrellis_FastLED_RX.ino +++ b/Ada_remoteFXTrigger_NeoTrellis_FastLED_RX/Ada_remoteFXTrigger_NeoTrellis_FastLED_RX.ino @@ -15,6 +15,10 @@ #include +#if defined(FASTLED_VERSION) && FASTLED_VERSION > 3010001 + #error "FastLED 3.10.2 has known compile issues with SAMD boards. Please downgrade to FastLED 3.10.1" +#endif + #define LED_PIN 12 #define NUM_LEDS 20 #define LED_TYPE WS2812B @@ -372,5 +376,3 @@ void FillLEDsFromPaletteColors( uint8_t colorIndex) colorIndex += STEPS; } } - - diff --git a/Crickit_WobblyBot/WobblyBot/.feather_m0_express.test.only b/Adafruit_DRV8833/arduino/drv8833_onoff/.uno.test.only similarity index 100% rename from Crickit_WobblyBot/WobblyBot/.feather_m0_express.test.only rename to Adafruit_DRV8833/arduino/drv8833_onoff/.uno.test.only diff --git a/Adafruit_DRV8833/arduino/drv8833_onoff/drv8833_onoff.ino b/Adafruit_DRV8833/arduino/drv8833_onoff/drv8833_onoff.ino new file mode 100644 index 000000000..b95db1801 --- /dev/null +++ b/Adafruit_DRV8833/arduino/drv8833_onoff/drv8833_onoff.ino @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2025 Carter Nelson for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Basic ON/OFF control of DC motor via DRV8833 + +#define AIN1 5 +#define AIN2 6 +#define SLP 7 + +void setup() { + Serial.begin(115200); + Serial.println("Adafruit DRV8833 DC Motor Example - ON/OFF"); + + // configure pins + pinMode(AIN1, OUTPUT); + pinMode(AIN2, OUTPUT); + pinMode(SLP, OUTPUT); + + // enable DRV8833 + digitalWrite(SLP, HIGH); +} + +void loop() { + // + // FORWARD + // + Serial.println("Forward"); + digitalWrite(AIN1, HIGH); + digitalWrite(AIN2, LOW); + delay(1000); + + // + // REVERSE + // + Serial.println("Reverse"); + digitalWrite(AIN1, LOW); + digitalWrite(AIN2, HIGH); + delay(1000); +} diff --git a/Factory_Tests/Feather_RP2040_Adalogger/.feather_rp2040_adalogger.test.only b/Adafruit_DRV8833/arduino/drv8833_pwm/.uno.test.only similarity index 100% rename from Factory_Tests/Feather_RP2040_Adalogger/.feather_rp2040_adalogger.test.only rename to Adafruit_DRV8833/arduino/drv8833_pwm/.uno.test.only diff --git a/Adafruit_DRV8833/arduino/drv8833_pwm/drv8833_pwm.ino b/Adafruit_DRV8833/arduino/drv8833_pwm/drv8833_pwm.ino new file mode 100644 index 000000000..163888dca --- /dev/null +++ b/Adafruit_DRV8833/arduino/drv8833_pwm/drv8833_pwm.ino @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: 2025 Carter Nelson for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// PWM speed control of DC motor via DRV8833 + +#define AIN1 5 +#define AIN2 6 +#define SLP 7 + +void setup() { + Serial.begin(115200); + Serial.println("Adafruit DRV8833 DC Motor Example - PWM"); + + // configure pins + pinMode(AIN1, OUTPUT); + pinMode(AIN2, OUTPUT); + pinMode(SLP, OUTPUT); + + // enable DRV8833 + digitalWrite(SLP, HIGH); +} + +void loop() { + // + // FORWARD + // + Serial.println("Forward"); + digitalWrite(AIN2, LOW); + // ramp speed up + Serial.println(" ramping up"); + for (int duty_cycle=0; duty_cycle<256; duty_cycle++) { + analogWrite(AIN1, duty_cycle); + delay(10); + } + // ramp speed down + Serial.println(" ramping down"); + for (int duty_cycle=255; duty_cycle>=0; duty_cycle--) { + analogWrite(AIN1, duty_cycle); + delay(10); + } + + // + // REVERSE + // + Serial.println("Reverse"); + digitalWrite(AIN1, LOW); + // ramp speed up + Serial.println(" ramping up"); + for (int duty_cycle=0; duty_cycle<256; duty_cycle++) { + analogWrite(AIN2, duty_cycle); + delay(10); + } + // ramp speed down + Serial.println(" ramping down"); + for (int duty_cycle=255; duty_cycle>=0; duty_cycle--) { + analogWrite(AIN2, duty_cycle); + delay(10); + } +} diff --git a/Factory_Tests/KB2040_FactoryTest/.feather_rp2040.test.only b/Adafruit_DRV8833/arduino/drv8833_stepper/.uno.test.only similarity index 100% rename from Factory_Tests/KB2040_FactoryTest/.feather_rp2040.test.only rename to Adafruit_DRV8833/arduino/drv8833_stepper/.uno.test.only diff --git a/Adafruit_DRV8833/arduino/drv8833_stepper/drv8833_stepper.ino b/Adafruit_DRV8833/arduino/drv8833_stepper/drv8833_stepper.ino new file mode 100644 index 000000000..572e33cd1 --- /dev/null +++ b/Adafruit_DRV8833/arduino/drv8833_stepper/drv8833_stepper.ino @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: 2025 lady ada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +// change this to the number of steps on your motor +#define STEPS 200 + +// create an instance of the stepper class, specifying +// the number of steps of the motor and the pins it's +// attached to +Stepper stepper(STEPS, 4, 5, 6, 7); + + +void setup() +{ + Serial.begin(9600); + Serial.println("Stepper test!"); + // set the speed of the motor to 30 RPMs + stepper.setSpeed(60); +} + +void loop() +{ + Serial.println("Forward"); + stepper.step(STEPS); + Serial.println("Backward"); + stepper.step(-STEPS); +} diff --git a/Adafruit_DRV8833/circuitpython/onoff/code.py b/Adafruit_DRV8833/circuitpython/onoff/code.py new file mode 100644 index 000000000..104405fde --- /dev/null +++ b/Adafruit_DRV8833/circuitpython/onoff/code.py @@ -0,0 +1,37 @@ +# SPDX-FileCopyrightText: 2025 Carter Nelson for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import time +import board +import digitalio + +# Configure pins +AIN1 = digitalio.DigitalInOut(board.D5) +AIN2 = digitalio.DigitalInOut(board.D6) +SLP = digitalio.DigitalInOut(board.D7) + +AIN1.switch_to_output() +AIN2.switch_to_output() +SLP.switch_to_output() + +# Enable DRV8833 +SLP.value = True + +# Loop forever +while True: + # + # FORWARD + # + print("Forward") + AIN1.value = True + AIN2.value = False + time.sleep(1) + + # + # REVERSE + # + print("Reverse") + AIN1.value = False + AIN2.value = True + time.sleep(1) diff --git a/Adafruit_DRV8833/circuitpython/pwm/code.py b/Adafruit_DRV8833/circuitpython/pwm/code.py new file mode 100644 index 000000000..d1f542eb4 --- /dev/null +++ b/Adafruit_DRV8833/circuitpython/pwm/code.py @@ -0,0 +1,48 @@ +# SPDX-FileCopyrightText: 2025 Carter Nelson for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import time +import board +import digitalio +import pwmio + +# Configure pins +AIN1 = pwmio.PWMOut(board.D5, frequency=2000) +AIN2 = pwmio.PWMOut(board.D6, frequency=2000) +SLP = digitalio.DigitalInOut(board.D7) + +SLP.switch_to_output() + +# Enable DRV8833 +SLP.value = True + +# Loop forever +while True: + # + # FORWARD + # + print("Forward") + AIN2.duty_cycle = 0 + print(" ramping up") + for duty_cycle in range(0, 65536, 100): + AIN1.duty_cycle = duty_cycle + time.sleep(0.01) + print(" ramping down") + for duty_cycle in range(65535, -1, -100): + AIN1.duty_cycle = duty_cycle + time.sleep(0.01) + + # + # REVERSE + # + print("Reverse") + AIN1.duty_cycle = 0 + print(" ramping up") + for duty_cycle in range(0, 65536, 100): + AIN2.duty_cycle = duty_cycle + time.sleep(0.01) + print(" ramping down") + for duty_cycle in range(65535, -1, -100): + AIN2.duty_cycle = duty_cycle + time.sleep(0.01) diff --git a/Adafruit_ESP32_Arduino_Demos/SerialESPPassthrough/SerialESPPassthrough.ino b/Adafruit_ESP32_Arduino_Demos/SerialESPPassthrough/SerialESPPassthrough.ino index a8e9d91bb..f6fd2a323 100644 --- a/Adafruit_ESP32_Arduino_Demos/SerialESPPassthrough/SerialESPPassthrough.ino +++ b/Adafruit_ESP32_Arduino_Demos/SerialESPPassthrough/SerialESPPassthrough.ino @@ -109,16 +109,32 @@ void setup() { digitalWrite(ESP32_RESETN, HIGH); pixel.setPixelColor(0, 20, 20, 0); pixel.show(); delay(100); + +#if defined(LED_BUILTIN) + pinMode(LED_BUILTIN, OUTPUT); +#endif } void loop() { while (Serial.available()) { +#if defined(ARDUINO_ARCH_RP2040) // Neopixel is blocking and this annoys esptool + #if defined(LED_BUILTIN) + digitalWrite(LED_BUILTIN, HIGH); + #endif +#else pixel.setPixelColor(0, 10, 0, 0); pixel.show(); +#endif SerialESP32.write(Serial.read()); } while (SerialESP32.available()) { +#if defined(ARDUINO_ARCH_RP2040) // Neopixel is blocking and this annoys esptool + #if defined(LED_BUILTIN) + digitalWrite(LED_BUILTIN, LOW); + #endif +#else pixel.setPixelColor(0, 0, 0, 10); pixel.show(); +#endif Serial.write(SerialESP32.read()); } } diff --git a/USB_Host_BFF_Examples/Arduino_USB_Host_BFF_DeviceInfo/.esp32.test.only b/Adafruit_Feather_ESP32-S2/Arduino_BME280_DeepSleep_AdafruitIO/.feather_esp32s2.test.only similarity index 100% rename from USB_Host_BFF_Examples/Arduino_USB_Host_BFF_DeviceInfo/.esp32.test.only rename to Adafruit_Feather_ESP32-S2/Arduino_BME280_DeepSleep_AdafruitIO/.feather_esp32s2.test.only diff --git a/Adafruit_Feather_ESP32-S2/Arduino_BME280_DeepSleep_AdafruitIO/Arduino_BME280_DeepSleep_AdafruitIO.ino b/Adafruit_Feather_ESP32-S2/Arduino_BME280_DeepSleep_AdafruitIO/Arduino_BME280_DeepSleep_AdafruitIO.ino new file mode 100644 index 000000000..aab5557ac --- /dev/null +++ b/Adafruit_Feather_ESP32-S2/Arduino_BME280_DeepSleep_AdafruitIO/Arduino_BME280_DeepSleep_AdafruitIO.ino @@ -0,0 +1,105 @@ +// SPDX-FileCopyrightText: 2025 Limor Fried for Adafruit Industries +// +// SPDX-License-Identifier: MIT +#include "config.h" +#include +#include + +Adafruit_BME280 bme; // I2C + +AdafruitIO_Feed *temperature = io.feed("temperature"); +AdafruitIO_Feed *humidity = io.feed("humidity"); +AdafruitIO_Feed *pressure = io.feed("pressure"); +float temp, humid, pres; + +Adafruit_NeoPixel pixel(1, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); + + +void setup() { + Serial.begin(115200); + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); + + // wait for serial monitor to open + //while(! Serial); + + // turn on neopixel + pinMode(NEOPIXEL_POWER, OUTPUT); + digitalWrite(NEOPIXEL_POWER, HIGH); + pixel.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) + pixel.setBrightness(10); // not so bright + + pixel.setPixelColor(0, 0xFF0000); // red + pixel.show(); + + if (! bme.begin()) { + Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!"); + deepSleep(); + } + Serial.println("Found BME280"); + float temp = bme.readTemperature(); + float pres = bme.readPressure() / 100.0F; + float hum = bme.readHumidity(); + // shhh time to close your eyes + bme.setSampling(Adafruit_BME280::MODE_SLEEP, + Adafruit_BME280::SAMPLING_X16, Adafruit_BME280::SAMPLING_X16, Adafruit_BME280::SAMPLING_X16, + Adafruit_BME280::FILTER_OFF, + Adafruit_BME280::STANDBY_MS_1000); + + Serial.print("Connecting to Adafruit IO"); + + pixel.setPixelColor(0, 0xFFFF00); // yellow + pixel.show(); + + // connect to io.adafruit.com + io.connect(); + + // wait for a connection + while(io.status() < AIO_CONNECTED) { + Serial.print("."); + delay(100); + } + + // we are connected + pixel.setPixelColor(0, 0x00FF00); // green + pixel.show(); + Serial.println(); + Serial.println(io.statusText()); + + io.run(); + + temp = temp * 9.0 / 5.0 + 32; + Serial.print("Temperature = "); + Serial.print(temp); + Serial.println(" *F"); + temperature->save(temp); + + Serial.print("Pressure = "); + Serial.print(pres); + Serial.println(" hPa"); + pressure->save(pres); + + Serial.print("Humidity = "); + Serial.print(hum); + Serial.println(" %"); + humidity->save(hum); + + Serial.println(); + + deepSleep(); +} + +void loop() { + // we never get here! +} + + +void deepSleep() { + pinMode(NEOPIXEL_POWER, OUTPUT); + digitalWrite(NEOPIXEL_POWER, LOW); // off + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, LOW); + + esp_sleep_enable_timer_wakeup(300000000); // 5 minutes + esp_deep_sleep_start(); +} \ No newline at end of file diff --git a/Adafruit_Feather_ESP32-S2/Arduino_BME280_DeepSleep_AdafruitIO/config.h b/Adafruit_Feather_ESP32-S2/Arduino_BME280_DeepSleep_AdafruitIO/config.h new file mode 100644 index 000000000..3585e138e --- /dev/null +++ b/Adafruit_Feather_ESP32-S2/Arduino_BME280_DeepSleep_AdafruitIO/config.h @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: 2025 Limor Fried for Adafruit Industries +// +// SPDX-License-Identifier: MIT +#define IO_USERNAME "your-aio-username" +#define IO_KEY "your-aio-token" +#define WIFI_SSID "your-wifi-ssid" +#define WIFI_PASS "your-wifi-pass" + +#include "AdafruitIO_WiFi.h" +AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS); \ No newline at end of file diff --git a/Adafruit_Feather_ESP32-S2/BME280_LC709203_Adafruit_IO/code.py b/Adafruit_Feather_ESP32-S2/BME280_LC709203_Adafruit_IO/code.py index b98723522..f1abce54c 100644 --- a/Adafruit_Feather_ESP32-S2/BME280_LC709203_Adafruit_IO/code.py +++ b/Adafruit_Feather_ESP32-S2/BME280_LC709203_Adafruit_IO/code.py @@ -3,6 +3,8 @@ """ CircuitPython Adafruit IO Example for BME280 and LC709203 Sensors """ + +from os import getenv import time import ssl import alarm @@ -14,11 +16,21 @@ from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError from adafruit_lc709203f import LC709203F, PackSize from adafruit_bme280 import basic as adafruit_bme280 -try: - from secrets import secrets -except ImportError: - print("WiFi and Adafruit IO credentials are kept in secrets.py, please add them there!") - raise + +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) # Duration of sleep in seconds. Default is 600 seconds (10 minutes). # Feather will sleep for this duration between sensor readings / sending data to AdafruitIO @@ -78,9 +90,9 @@ def send_io_data(feed, value): # Wi-Fi connections can have issues! This ensures the code will continue to run. try: # Connect to Wi-Fi - wifi.radio.connect(secrets["ssid"], secrets["password"]) - print("Connected to {}!".format(secrets["ssid"])) - print("IP:", wifi.radio.ipv4_address) + wifi.radio.connect(ssid, password) + print(f"Connected to {ssid}!") + print(f"IP: {wifi.radio.ipv4_address}") pool = socketpool.SocketPool(wifi.radio) requests = adafruit_requests.Session(pool, ssl.create_default_context()) @@ -90,12 +102,6 @@ def send_io_data(feed, value): print(e) go_to_sleep(60) -# Set your Adafruit IO Username and Key in secrets.py -# (visit io.adafruit.com if you need to create an account, -# or if you need your Adafruit IO key.) -aio_username = secrets["aio_username"] -aio_key = secrets["aio_key"] - # Initialize an Adafruit IO HTTP API object io = IO_HTTP(aio_username, aio_key, requests) diff --git a/Adafruit_Feather_ESP32-S2/BME280_LC709203_Simple_Data/code.py b/Adafruit_Feather_ESP32-S2/BME280_LC709203_Simple_Data/code.py index 5b8e69d73..3c46f3c2d 100644 --- a/Adafruit_Feather_ESP32-S2/BME280_LC709203_Simple_Data/code.py +++ b/Adafruit_Feather_ESP32-S2/BME280_LC709203_Simple_Data/code.py @@ -5,8 +5,8 @@ """ import time import board -from adafruit_bme280 import basic as adafruit_bme280 from adafruit_lc709203f import LC709203F, PackSize +from adafruit_bme280 import basic as adafruit_bme280 # Create sensor objects, using the board's default I2C bus. i2c = board.I2C() # uses board.SCL and board.SDA diff --git a/Adafruit_Feather_ESP32-S2/CircuitPython_BME280_DeepSleep_AdafruitIO/code.py b/Adafruit_Feather_ESP32-S2/CircuitPython_BME280_DeepSleep_AdafruitIO/code.py new file mode 100644 index 000000000..ffa8a970b --- /dev/null +++ b/Adafruit_Feather_ESP32-S2/CircuitPython_BME280_DeepSleep_AdafruitIO/code.py @@ -0,0 +1,110 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +CircuitPython example for deep sleep and BME280 sensor sending data +to Adafruit IO. +""" +from os import getenv +import time +import alarm +import board +import digitalio +import neopixel +import wifi + +from adafruit_bme280 import advanced as adafruit_bme280 +import adafruit_connection_manager +import adafruit_requests +from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError + + +# enable power to NeoPixels. +np_power = digitalio.DigitalInOut(board.NEOPIXEL_POWER) +np_power.switch_to_output(value=True) + +# standard LED +builtin_led = digitalio.DigitalInOut(board.LED) +builtin_led.switch_to_output(value=True) + +# neopixel to use for status +status_pixel = neopixel.NeoPixel( + board.NEOPIXEL, 1, brightness=0.1, pixel_order=neopixel.GRB, auto_write=True +) +status_pixel[0] = 0xFF0000 + +# Create sensor object, using the board's default I2C bus. +i2c = board.I2C() # uses board.SCL and board.SDA +bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c) +print("Found BME280") +# change this to match the location's pressure (hPa) at sea level +bme280.sea_level_pressure = 1013.25 + +# temperature converted to F +temperature = bme280.temperature * 9 / 5 + 32 +humidity = bme280.relative_humidity +pressure = bme280.pressure +print("\nTemperature: %0.1f F" % temperature) +print("Humidity: %0.1f %%" % humidity) +print("Pressure: %0.1f hPa" % pressure) + +bme280.mode = adafruit_bme280.MODE_SLEEP +bme280.overscan_temperature = adafruit_bme280.OVERSCAN_X16 +bme280.overscan_humidity = adafruit_bme280.OVERSCAN_X16 +bme280.overscan_pressure = adafruit_bme280.OVERSCAN_X16 +bme280.iir_filter = adafruit_bme280.IIR_FILTER_DISABLE +bme280.standby_period = adafruit_bme280.STANDBY_TC_1000 + +# set status pixel to yellow +status_pixel[0] = 0xFFFF00 + +print("Connecting to AdafruitIO") + +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("WIFI_SSID") +password = getenv("WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +print("Connecting to %s" % ssid) +wifi.radio.connect(ssid, password) +print("Connected to %s!" % ssid) + +# setup socket pool and requests session +pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio) +ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio) +requests = adafruit_requests.Session(pool, ssl_context) + +# Initialize an Adafruit IO HTTP API object +io = IO_HTTP(aio_username, aio_key, requests) + +# set status pixel to green +status_pixel[0] = 0x00FF00 + +try: + # Get the feeds from Adafruit IO + temperature_feed = io.get_feed("temperature") + humidity_feed = io.get_feed("humidity") + pressure_feed = io.get_feed("pressure") + + # send data to the feeds + io.send_data(temperature_feed["key"], temperature) + io.send_data(humidity_feed["key"], humidity) + io.send_data(pressure_feed["key"], pressure) + +except AdafruitIO_RequestError as e: + print(e) + print( + "You must create feeds on AdafruitIO for: temperature, humidity, and pressure" + ) + +# turn off the neopixel and builtin LED +np_power.value = False +builtin_led.value = False + +# Create an alarm that will trigger 5 minutes from now. +time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + (5 * 60)) +# Exit the program, and then deep sleep until the alarm wakes us. +alarm.exit_and_deep_sleep_until_alarms(time_alarm) +# Does not return, so we never get here. diff --git a/Adafruit_Feather_TFT_ESP32-S2/LC709203_Adafruit_IO/code.py b/Adafruit_Feather_TFT_ESP32-S2/LC709203_Adafruit_IO/code.py index 1a3add4b1..c3cb3537d 100644 --- a/Adafruit_Feather_TFT_ESP32-S2/LC709203_Adafruit_IO/code.py +++ b/Adafruit_Feather_TFT_ESP32-S2/LC709203_Adafruit_IO/code.py @@ -3,6 +3,8 @@ """ CircuitPython Adafruit IO Example for LC709203 Sensor """ + +from os import getenv import time import ssl import alarm @@ -13,11 +15,21 @@ import adafruit_requests from adafruit_io.adafruit_io import IO_HTTP from adafruit_lc709203f import LC709203F, PackSize -try: - from secrets import secrets -except ImportError: - print("WiFi and Adafruit IO credentials are kept in secrets.py, please add them there!") - raise + +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) # Duration of sleep in seconds. Default is 600 seconds (10 minutes). # Feather will sleep for this duration between sensor readings / sending data to AdafruitIO @@ -58,9 +70,9 @@ def send_io_data(feed, value): # Wi-Fi connections can have issues! This ensures the code will continue to run. try: # Connect to Wi-Fi - wifi.radio.connect(secrets["ssid"], secrets["password"]) - print("Connected to {}!".format(secrets["ssid"])) - print("IP:", wifi.radio.ipv4_address) + wifi.radio.connect(ssid, password) + print(f"Connected to {ssid}!") + print(f"IP: {wifi.radio.ipv4_address}") pool = socketpool.SocketPool(wifi.radio) requests = adafruit_requests.Session(pool, ssl.create_default_context()) @@ -70,12 +82,6 @@ def send_io_data(feed, value): print(e) go_to_sleep(60) -# Set your Adafruit IO Username and Key in secrets.py -# (visit io.adafruit.com if you need to create an account, -# or if you need your Adafruit IO key.) -aio_username = secrets["aio_username"] -aio_key = secrets["aio_key"] - # Initialize an Adafruit IO HTTP API object io = IO_HTTP(aio_username, aio_key, requests) diff --git a/Adafruit_Feather_TFT_ESP32-S2/TFT_GitHub_Stars/code.py b/Adafruit_Feather_TFT_ESP32-S2/TFT_GitHub_Stars/code.py index 9e879ad02..b0122b99e 100644 --- a/Adafruit_Feather_TFT_ESP32-S2/TFT_GitHub_Stars/code.py +++ b/Adafruit_Feather_TFT_ESP32-S2/TFT_GitHub_Stars/code.py @@ -3,6 +3,8 @@ """ CircuitPython GitHub Stars viewer """ + +from os import getenv import time import ssl import wifi @@ -13,12 +15,17 @@ from adafruit_bitmap_font import bitmap_font import adafruit_requests -# Get WiFi details secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) display = board.DISPLAY @@ -38,10 +45,10 @@ display.root_group = group # Connect to WiFi -print("Connecting to %s"%secrets["ssid"]) -wifi.radio.connect(secrets["ssid"], secrets["password"]) -print("Connected to %s!"%secrets["ssid"]) -print("My IP address is", wifi.radio.ipv4_address) +print(f"Connecting to {ssid}") +wifi.radio.connect(ssid, password) +print(f"Connected to {ssid}!") +print(f"My IP address is {wifi.radio.ipv4_address}") pool = socketpool.SocketPool(wifi.radio) requests = adafruit_requests.Session(pool, ssl.create_default_context()) diff --git a/Adafruit_I2S_BFF/CircuitPython/WAV/code.py b/Adafruit_I2S_BFF/CircuitPython/WAV/code.py index f6725b3c2..37b3dd42b 100644 --- a/Adafruit_I2S_BFF/CircuitPython/WAV/code.py +++ b/Adafruit_I2S_BFF/CircuitPython/WAV/code.py @@ -11,7 +11,7 @@ audio = audiobusio.I2SOut(board.A2, board.A1, board.A0) -with open("chikken.wav", "rb") as wave_file: +with open("booploop.wav", "rb") as wave_file: wav = audiocore.WaveFile(wave_file) print("Playing wav file!") diff --git a/Adafruit_IO_Air_Quality/code.py b/Adafruit_IO_Air_Quality/code.py index 734b97695..cc2b74441 100755 --- a/Adafruit_IO_Air_Quality/code.py +++ b/Adafruit_IO_Air_Quality/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import board import busio @@ -22,14 +23,22 @@ # Interval the sensor publishes to Adafruit IO, in minutes PUBLISH_INTERVAL = 10 -### WiFi ### +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +### WiFi ### # AirLift FeatherWing esp32_cs = DigitalInOut(board.D13) @@ -38,8 +47,8 @@ spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) -status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Connect to a PM2.5 sensor over UART reset_pin = None @@ -142,7 +151,7 @@ def read_bme(is_celsius=False): # Create an instance of the Adafruit IO HTTP client -io = IO_HTTP(secrets["aio_user"], secrets["aio_key"], wifi) +io = IO_HTTP(aio_username, aio_key, wifi) # Describes feeds used to hold Adafruit IO data feed_aqi = io.get_feed("air-quality-sensor.aqi") @@ -150,11 +159,11 @@ def read_bme(is_celsius=False): feed_humidity = io.get_feed("air-quality-sensor.humidity") feed_temperature = io.get_feed("air-quality-sensor.temperature") -# Set up location metadata from secrets.py file +# Set up location metadata from settings.toml file location_metadata = { - "lat": secrets["latitude"], - "lon": secrets["longitude"], - "ele": secrets["elevation"], + "lat": getenv("latitude"), + "lon": getenv("longitude"), + "ele": getenv("elevation"), } elapsed_minutes = 0 diff --git a/Adafruit_IO_Power_Relay/code.py b/Adafruit_IO_Power_Relay/code.py index 2361eb69f..1ccc118eb 100755 --- a/Adafruit_IO_Power_Relay/code.py +++ b/Adafruit_IO_Power_Relay/code.py @@ -14,12 +14,19 @@ import adafruit_minimqtt.adafruit_minimqtt as MQTT -### WiFi ### +# Get WiFi details, ensure these are setup in settings.toml +ssid = os.getenv("CIRCUITPY_WIFI_SSID") +password = os.getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) -secrets = { - "ssid" : os.getenv("CIRCUITPY_WIFI_SSID"), - "password" : os.getenv("CIRCUITPY_WIFI_PASSWORD"), -} +### WiFi ### # If you are using a board with pre-defined ESP32 Pins: esp32_cs = DigitalInOut(board.ESP_CS) @@ -34,19 +41,19 @@ spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) """Use below for Most Boards""" -status_light = neopixel.NeoPixel( +status_pixel = neopixel.NeoPixel( board.NEOPIXEL, 1, brightness=0.2 ) # Uncomment for Most Boards """Uncomment below for ItsyBitsy M4""" -# status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2) +# status_pixel = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2) # Uncomment below for an externally defined RGB LED # import adafruit_rgbled # from adafruit_esp32spi import PWMOut # RED_LED = PWMOut.PWMOut(esp, 26) # GREEN_LED = PWMOut.PWMOut(esp, 27) # BLUE_LED = PWMOut.PWMOut(esp, 25) -# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +# status_pixel = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Set up a pin for controlling the relay power_pin = DigitalInOut(board.D3) diff --git a/Adafruit_IO_Power_Relay/code_light_sensor/code.py b/Adafruit_IO_Power_Relay/code_light_sensor/code.py index f37f9c727..bd33d75b1 100755 --- a/Adafruit_IO_Power_Relay/code_light_sensor/code.py +++ b/Adafruit_IO_Power_Relay/code_light_sensor/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import board import busio @@ -14,6 +15,21 @@ import adafruit_minimqtt.adafruit_minimqtt as MQTT +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + ### Sensor Calibration ### # Appliance power LED's light level, in Lux APPLIANCE_ON_LUX = 30.0 @@ -22,13 +38,6 @@ ### WiFi ### -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise - # If you are using a board with pre-defined ESP32 Pins: esp32_cs = DigitalInOut(board.ESP_CS) esp32_ready = DigitalInOut(board.ESP_BUSY) @@ -42,19 +51,19 @@ spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) """Use below for Most Boards""" -status_light = neopixel.NeoPixel( +status_pixel = neopixel.NeoPixel( board.NEOPIXEL, 1, brightness=0.2 ) # Uncomment for Most Boards """Uncomment below for ItsyBitsy M4""" -# status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2) +# status_pixel = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2) # Uncomment below for an externally defined RGB LED # import adafruit_rgbled # from adafruit_esp32spi import PWMOut # RED_LED = PWMOut.PWMOut(esp, 26) # GREEN_LED = PWMOut.PWMOut(esp, 27) # BLUE_LED = PWMOut.PWMOut(esp, 25) -# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +# status_pixel = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Set up a pin for controlling the relay power_pin = DigitalInOut(board.D3) @@ -67,10 +76,10 @@ ### Feeds ### # Set up a feed named Relay for subscribing to the relay feed on Adafruit IO -feed_relay = secrets["aio_username"] + "/feeds/relay" +feed_relay = f"{aio_username}/feeds/relay" # Set up a feed named status for subscribing to the status feed on Adafruit IO -feed_status = secrets["aio_username"] + "/feeds/status" +feed_status = f"{aio_username}/feeds/status" ### Code ### @@ -122,8 +131,8 @@ def on_relay_msg(client, topic, value): # Set up a MiniMQTT Client client = MQTT.MQTT( broker="io.adafruit.com", - username=secrets["aio_username"], - password=secrets["aio_key"], + username=aio_username, + password=aio_key, socket_pool=pool, ssl_context=ssl_context, ) diff --git a/Adafruit_IO_Reed_Switch/rpi-pico-w112213141.json b/Adafruit_IO_Reed_Switch/rpi-pico-w112213141.json new file mode 100644 index 000000000..03b261628 --- /dev/null +++ b/Adafruit_IO_Reed_Switch/rpi-pico-w112213141.json @@ -0,0 +1,27 @@ +{ + "exportVersion": "1.0.0", + "exportedBy": "tyeth_demo", + "exportedAt": "2025-05-02T17:08:03.857Z", + "exportedFromDevice": { + "board": "rpi-pico-w", + "firmwareVersion": "1.0.0-beta.100" + }, + "components": [ + { + "name": "Reed Switch", + "pinName": "D13", + "type": "reed_switch", + "mode": "DIGITAL", + "direction": "INPUT", + "period": 0, + "pull": "UP", + "isPin": true, + "visualization": { + "offLabel": "Open", + "offIcon": "fa6:solid:door-open", + "onLabel": "Closed", + "onIcon": "fa6:regular:door-closed" + } + } + ] +} \ No newline at end of file diff --git a/Adafruit_IO_Schedule_Trigger/code.py b/Adafruit_IO_Schedule_Trigger/code.py index a46feb49f..73b6dfd9f 100755 --- a/Adafruit_IO_Schedule_Trigger/code.py +++ b/Adafruit_IO_Schedule_Trigger/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import board import busio @@ -13,14 +14,22 @@ import adafruit_minimqtt.adafruit_minimqtt as MQTT from adafruit_io.adafruit_io import IO_MQTT -### WiFi ### +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +### WiFi ### # If you are using a board with pre-defined ESP32 Pins: esp32_cs = DigitalInOut(board.ESP_CS) @@ -35,19 +44,19 @@ spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) """Use below for Most Boards""" -status_light = neopixel.NeoPixel( +status_pixel = neopixel.NeoPixel( board.NEOPIXEL, 1, brightness=0.2 ) # Uncomment for Most Boards """Uncomment below for ItsyBitsy M4""" -# status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2) +# status_pixel = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2) # Uncomment below for an externally defined RGB LED # import adafruit_rgbled # from adafruit_esp32spi import PWMOut # RED_LED = PWMOut.PWMOut(esp, 26) # GREEN_LED = PWMOut.PWMOut(esp, 27) # BLUE_LED = PWMOut.PWMOut(esp, 25) -# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +# status_pixel = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Set up a pin for controlling the relay power_pin = DigitalInOut(board.D3) @@ -89,11 +98,11 @@ def on_message(client, feed_id, payload): def on_relay_msg(client, topic, message): # Method called whenever user/feeds/relay has a new value - if message == "morning": - print("Morning - turning outlet ON") + if message == "1": + print("Received 1 - turning outlet ON") power_pin.value = True - elif message == "night": - print("Night - turning outlet OFF") + elif message == "0": + print("Received 0 - turning outlet OFF") power_pin.value = False else: print("Unexpected value received on relay feed.") @@ -110,8 +119,8 @@ def on_relay_msg(client, topic, message): # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", - username=secrets["aio_username"], - password=secrets["aio_key"], + username=aio_username, + password=aio_key, socket_pool=pool, ssl_context=ssl_context, ) diff --git a/Adafruit_IO_Stepper_Control/code.py b/Adafruit_IO_Stepper_Control/code.py index 2066deb87..1c9020398 100644 --- a/Adafruit_IO_Stepper_Control/code.py +++ b/Adafruit_IO_Stepper_Control/code.py @@ -99,7 +99,7 @@ def stepper_worker(stepper, numsteps, direction, stepper_name, style, show_steps time.sleep(30) # Stepper 1 - if not st1.isAlive() and int(stepper_start.value): + if not st1.is_alive() and int(stepper_start.value): stepper_1_steps = aio.receive(feed_step_1_steps.key) stepper_1_steps = int(stepper_1_steps.value) if stepper_1_steps > 0: # stepper slider is set @@ -125,7 +125,7 @@ def stepper_worker(stepper, numsteps, direction, stepper_name, style, show_steps st1.start() # Stepper 2 - if not st2.isAlive() and int(stepper_start.value): + if not st2.is_alive() and int(stepper_start.value): stepper_2_steps = aio.receive(feed_step_2_steps.key) stepper_2_steps = int(stepper_2_steps.value) if stepper_2_steps > 0: # stepper slider is set diff --git a/Adafruit_IO_Template_Emails/rpi-pico-w-potty-training.json b/Adafruit_IO_Template_Emails/rpi-pico-w-potty-training.json new file mode 100644 index 000000000..8eec8ca1a --- /dev/null +++ b/Adafruit_IO_Template_Emails/rpi-pico-w-potty-training.json @@ -0,0 +1,83 @@ +{ + "exportVersion": "1.0.0", + "exportedBy": "tyeth", + "exportedAt": "2025-06-10T18:13:03.071Z", + "exportedFromDevice": { + "board": "rpi-pico-w", + "firmwareVersion": "1.0.0-beta.100" + }, + "components": [ + { + "name": "💦 Wee Button", + "pinName": "D18", + "type": "push_button", + "mode": "DIGITAL", + "direction": "INPUT", + "period": 0, + "pull": "UP", + "isPin": true + }, + { + "name": "💦 Wee LED", + "pinName": "D2", + "type": "led", + "mode": "DIGITAL", + "direction": "OUTPUT", + "isPin": true + }, + { + "name": "💩 Poo Button", + "pinName": "D19", + "type": "push_button", + "mode": "DIGITAL", + "direction": "INPUT", + "period": 0, + "pull": "UP", + "isPin": true + }, + { + "name": "💩 Poo LED", + "pinName": "D3", + "type": "led", + "mode": "DIGITAL", + "direction": "OUTPUT", + "isPin": true + }, + { + "name": "❌ Didn't Go Button", + "pinName": "D20", + "type": "push_button", + "mode": "DIGITAL", + "direction": "INPUT", + "period": 0, + "pull": "UP", + "isPin": true + }, + { + "name": "❌ Didn't Go LED", + "pinName": "D4", + "type": "led", + "mode": "DIGITAL", + "direction": "OUTPUT", + "isPin": true + }, + { + "name": "🔔 Tell Adult Button", + "pinName": "D21", + "type": "push_button", + "mode": "DIGITAL", + "direction": "INPUT", + "period": 0, + "pull": "UP", + "isPin": true + }, + { + "name": "🔔 Tell Adult LED", + "pinName": "D5", + "type": "led", + "mode": "DIGITAL", + "direction": "OUTPUT", + "isPin": true + } + ] +} \ No newline at end of file diff --git a/Adafruit_IO_Template_Emails/template.liquid b/Adafruit_IO_Template_Emails/template.liquid new file mode 100644 index 000000000..06e1fbb9c --- /dev/null +++ b/Adafruit_IO_Template_Emails/template.liquid @@ -0,0 +1,72 @@ +🌟 Daily Potty Training Report 🌟 +Hi there! Here's how our little superstar did: +--- +🚽 Successful Wees: {{ vars.wee_progress }} +{% for i in (1..vars.wee_progress) %}💧{% endfor %} +{% if vars.wee_progress <= 5 -%} +Great start! Every success counts, and they're building good habits one wee at a time! 🌱 +{% elsif vars.wee_progress <= 15 -%} +Fantastic progress! They're really getting the hang of this - keep up the amazing work! 🎯 +{% else -%} +SUPERSTAR ALERT! 🌟 Absolutely crushing it with those wee successes! They're a potty champion! 🏆 +{% endif %}--- + +💩 Successful Poos: {{ vars.poo_progress }} +{% for i in (1..vars.poo_progress) %}🟤{% endfor %} +{% if vars.poo_progress == 0 -%} +Poos can be tricky, but they're being so brave! Every try is a step forward! 💪 +{% elsif vars.poo_progress < 2 -%} +Look at them go! They're becoming a real poo pro - that's awesome progress! 🎉 +{% else -%} +POO CHAMPION! 🏅 They've mastered one of the trickiest parts - so proud! 🎊 +{% endif %}--- + +🤝 Told an Adult: {{ vars.informed_progress }} +{% for i in (1..vars.informed_progress) %}🗣️{% endfor %} +{% if vars.informed_progress <= 5 -%} +Communication is key! Keep practicing saying when they need to go - They're doing great! 📢 +{% elsif vars.informed_progress <= 15 -%} +Wonderful communication skills! They're really good at letting us know - that's so helpful! 👏 +{% else -%} +COMMUNICATION SUPERSTAR! 🌟 They're amazing at telling adults - that's such a big kid skill! 🎯 +{% endif %}--- + +👻 Nothing Happened: {{ vars.nothing_progress }} +{% for i in (1..vars.nothing_progress) %}⭕{% endfor %} +{% if vars.nothing_progress <= 3 -%} +That's okay! Trying is what matters, and their body will let them know when it's ready! 🌈 +{% else -%} +So patient and persistent! Even when nothing happens, they keep trying - that's real determination! 💫 +{% endif %}--- + +📊 Daily Summary: +{% capture total_tries -%}{{ vars.wee_progress | plus: vars.poo_progress | plus: vars.nothing_progress }}{% endcapture -%} +{% capture successes -%}{{ vars.wee_progress | plus: vars.poo_progress }}{% endcapture -%} +{% capture success_rate -%}{% if total_tries != "0" -%}{{ successes | times: 100 | divided_by: total_tries }}{% else -%}100{% endif -%}{% endcapture -%} +{% capture bar_filled -%}{{ success_rate | divided_by: 10 }}{% endcapture -%} +{% capture bar_empty -%}{{ 10 | minus: bar_filled }}{% endcapture -%} +Total potty visits: {{ total_tries }} +Success rate: {{ success_rate }}% [{%- for i in (1..bar_filled) -%}█{%- endfor -%}{%- for i in (1..bar_empty) -%}░{%- endfor -%}] +{%- assign total_events = vars.wee_progress | plus: vars.poo_progress | plus: vars.nothing_progress | plus: vars.informed_progress -%} + ({{ total_events }} events today ) +{% if total_events <= 3 %} +💝 Today: They're doing such a great job learning! Every day gets a little easier... +{% elsif total_events <= 5 %} +🌟 Today: Ayee! They're really getting the hang of this potty training thing! Keep it up! +{% elsif total_events <= 8 %} +🌟 Today: WOW! Look at all that practice! They're becoming such a potty expert. +{% else %} +🏆 Today: INCREDIBLE DAY! They're absolutely rocking this potty training journey! 🎊🎉 +{%- endif %} + +Keep being awesome! +With love and high-fives! 🙌 +--- +{%- assign event_mod = total_events | modulo: 3 %} +{% if event_mod == 0 -%} +P.S. Remember: Every expert was once a beginner - they're doing brilliantly! 🌟 +{% elsif event_mod == 1 -%} +P.S. Fun fact: Even superheroes had to learn to use the potty! 🦸 +{% else -%} +P.S. Remember: accidents are just practice in disguise! They're doing amazingly! 💕 +{% endif %} diff --git a/USB_Host_BFF_Examples/Arduino_USB_Host_BFF_HIDReport/.esp32.test.only b/Adafruit_NeoPot/Arduino_Rainbow_Pot/.uno.test.only similarity index 100% rename from USB_Host_BFF_Examples/Arduino_USB_Host_BFF_HIDReport/.esp32.test.only rename to Adafruit_NeoPot/Arduino_Rainbow_Pot/.uno.test.only diff --git a/Adafruit_NeoPot/Arduino_Rainbow_Pot/Arduino_Rainbow_Pot.ino b/Adafruit_NeoPot/Arduino_Rainbow_Pot/Arduino_Rainbow_Pot.ino new file mode 100644 index 000000000..76084a460 --- /dev/null +++ b/Adafruit_NeoPot/Arduino_Rainbow_Pot/Arduino_Rainbow_Pot.ino @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include +int sensorPin = A0; // select the input pin for the potentiometer +int neoPixelPin = 4; // select the pin for the LED +int sensorValue = 0; // variable to store the value coming from the sensor + +int readings[10]; +size_t count = 0; + +Adafruit_NeoPixel strip = Adafruit_NeoPixel(1, neoPixelPin, NEO_GRB + NEO_KHZ800); + +// Insert an int value at index 0 of an int array, shifting all other elements up. +// If the array already contains 'maxCount' elements, the last one is dropped. +// 'count' is the number of valid elements currently stored in the array. +void insert(int arr[], size_t maxCount, int value, size_t &count){ + // Determine how many elements we need to shift (cannot exceed the array bounds) + size_t shiftCount = (count < maxCount) ? count : maxCount - 1; + + // Shift elements up by one position + for (size_t i = shiftCount; i > 0; --i) { + arr[i] = arr[i - 1]; + } + + // Insert the new value at the beginning + arr[0] = value; + + // Update the element count + if (count < maxCount) { + ++count; // we added a new element + } // else count stays the same – the last element was overwritten +} + +// Input an array of 10 or fewer int's, and a count of how many have values +// Returns average of the values in the array. +int average(int arr[], size_t count){ + int sum = 0; + for(int i = 0; i < 10; i++){ + sum = sum + arr[i]; + } + return sum / count; +} + +// Input a value 0 to 255 to get a color value. +// The colours are a transition r - g - b - back to r. +uint32_t Wheel(byte WheelPos) { + WheelPos = 255 - WheelPos; + if(WheelPos < 85) { + return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); + } + if(WheelPos < 170) { + WheelPos -= 85; + return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); + } + WheelPos -= 170; + return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); +} + +void setup() { + Serial.begin(115200); + strip.begin(); +} + +void loop() { + sensorValue = analogRead(sensorPin); + insert(readings, 10, sensorValue, count); + strip.setPixelColor(0, Wheel(average(readings, count) / 4)); + strip.show(); +} diff --git a/Adafruit_NeoPot/CircuitPython_Rainbow_Pot/code.py b/Adafruit_NeoPot/CircuitPython_Rainbow_Pot/code.py new file mode 100644 index 000000000..cee3c0d18 --- /dev/null +++ b/Adafruit_NeoPot/CircuitPython_Rainbow_Pot/code.py @@ -0,0 +1,36 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +NeoPot NeoPixel Rainbow Demo +""" + +import board +import analogio +import neopixel +import rainbowio + +analog_pin = analogio.AnalogIn(board.A0) +knob_pixel = neopixel.NeoPixel(board.D4, 1, brightness=0.75, auto_write=True) + +analog_smoothing_buffer = [] + + +def map_range(x, in_min, in_max, out_min, out_max): + return (x - in_min) / (in_max - in_min) * out_max - out_min + + +def average(values): + if not values: + return 0 + + return sum(values) / len(values) + + +while True: + analog_smoothing_buffer.insert(0, analog_pin.value) + if len(analog_smoothing_buffer) >= 10: + analog_smoothing_buffer.pop(-1) + + knob_pixel[0] = rainbowio.colorwheel( + map_range(average(analog_smoothing_buffer), 0, 65525, 0, 255) + ) diff --git a/Arduino_Nano_RP2040_Connect/arduino_nano_rp2040_connect_wifi/code.py b/Arduino_Nano_RP2040_Connect/arduino_nano_rp2040_connect_wifi/code.py index 06d799abb..63d7865e9 100644 --- a/Arduino_Nano_RP2040_Connect/arduino_nano_rp2040_connect_wifi/code.py +++ b/Arduino_Nano_RP2040_Connect/arduino_nano_rp2040_connect_wifi/code.py @@ -7,6 +7,7 @@ https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI/ blob/master/examples/esp32spi_simpletest.py ''' +from os import getenv import board import busio from digitalio import DigitalInOut @@ -14,12 +15,17 @@ import adafruit_requests from adafruit_esp32spi import adafruit_esp32spi -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) print("Arduino Nano RP2040 Connect webclient test") @@ -51,7 +57,7 @@ print("Connecting to AP...") while not esp.is_connected: try: - esp.connect_AP(secrets["ssid"], secrets["password"]) + esp.connect_AP(ssid, password) except RuntimeError as e: print("could not connect to AP, retrying: ", e) continue diff --git a/Asteroid_Tracker/Arial-14.bdf b/Asteroid_Tracker/Arial-14.bdf new file mode 100644 index 000000000..ec7950b7c --- /dev/null +++ b/Asteroid_Tracker/Arial-14.bdf @@ -0,0 +1,27564 @@ +STARTFONT 2.1 +COMMENT +COMMENT Converted from OpenType font "arial.ttf" by "otf2bdf 3.0". +COMMENT +FONT -FreeType-Arial-Medium-R-Normal--19-140-100-100-P-94-ISO10646-1 +SIZE 14 100 100 +FONTBOUNDINGBOX 34 26 -13 -6 +STARTPROPERTIES 19 +FOUNDRY "FreeType" +FAMILY_NAME "Arial" +WEIGHT_NAME "Medium" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 19 +POINT_SIZE 140 +RESOLUTION_X 100 +RESOLUTION_Y 100 +SPACING "P" +AVERAGE_WIDTH 94 +CHARSET_REGISTRY "ISO10646" +CHARSET_ENCODING "1" +FONT_ASCENT 17 +FONT_DESCENT 4 +COPYRIGHT "Typeface The Monotype Corporation plc. Data The Monotype Corporation plc/Type Solutions Inc. 1990-1992. All Rights Reserved" +_OTF_FONTFILE "arial.ttf" +_OTF_PSNAME "ArialMT" +ENDPROPERTIES +CHARS 1419 +STARTCHAR 0020 +ENCODING 32 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 0 0 0 0 +BITMAP +ENDCHAR +STARTCHAR 0021 +ENCODING 33 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 14 2 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +80 +80 +80 +80 +00 +C0 +C0 +ENDCHAR +STARTCHAR 0022 +ENCODING 34 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 5 1 9 +BITMAP +D8 +D8 +D8 +D8 +90 +ENDCHAR +STARTCHAR 0023 +ENCODING 35 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +0880 +0880 +1880 +FFC0 +FFC0 +1100 +3100 +3100 +FFC0 +FFC0 +2200 +6200 +6200 +4600 +ENDCHAR +STARTCHAR 0024 +ENCODING 36 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 -2 +BITMAP +0800 +3E00 +7F00 +CB00 +C800 +C800 +7800 +3E00 +0F00 +0900 +0980 +C980 +CB00 +7F00 +3E00 +0800 +0800 +ENDCHAR +STARTCHAR 0025 +ENCODING 37 +SWIDTH 874 0 +DWIDTH 17 0 +BBX 15 14 1 0 +BITMAP +7830 +4C20 +CC40 +CC40 +CC80 +4880 +7900 +0338 +0264 +0646 +0446 +0C46 +0864 +1838 +ENDCHAR +STARTCHAR 0026 +ENCODING 38 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +1E00 +3F00 +3300 +2300 +3300 +1E00 +3C00 +7C00 +C6C0 +C3C0 +C180 +E3C0 +7FE0 +3C60 +ENDCHAR +STARTCHAR 0027 +ENCODING 39 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 5 1 9 +BITMAP +C0 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR 0028 +ENCODING 40 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 18 1 -4 +BITMAP +10 +30 +20 +60 +60 +40 +C0 +C0 +C0 +C0 +C0 +C0 +40 +60 +60 +20 +30 +10 +ENDCHAR +STARTCHAR 0029 +ENCODING 41 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 18 1 -4 +BITMAP +C0 +40 +60 +20 +30 +10 +10 +18 +18 +18 +18 +10 +10 +30 +20 +60 +40 +C0 +ENDCHAR +STARTCHAR 002A +ENCODING 42 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 6 6 1 8 +BITMAP +20 +20 +FC +30 +50 +48 +ENDCHAR +STARTCHAR 002B +ENCODING 43 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 1 +BITMAP +0800 +0800 +0800 +0800 +FF80 +FF80 +0800 +0800 +0800 +0800 +ENDCHAR +STARTCHAR 002C +ENCODING 44 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 5 2 -3 +BITMAP +C0 +C0 +40 +80 +80 +ENDCHAR +STARTCHAR 002D +ENCODING 45 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 2 1 4 +BITMAP +F8 +F8 +ENDCHAR +STARTCHAR 002E +ENCODING 46 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 2 2 0 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR 002F +ENCODING 47 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 14 0 0 +BITMAP +08 +08 +18 +10 +10 +30 +20 +20 +20 +60 +40 +40 +C0 +80 +ENDCHAR +STARTCHAR 0030 +ENCODING 48 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3C00 +7E00 +6300 +C300 +C100 +C180 +C180 +C180 +C180 +C100 +C300 +E300 +7E00 +3C00 +ENDCHAR +STARTCHAR 0031 +ENCODING 49 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 5 14 2 0 +BITMAP +08 +18 +38 +F8 +98 +18 +18 +18 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 0032 +ENCODING 50 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3E00 +7F00 +C300 +C180 +0180 +0300 +0300 +0600 +1C00 +3800 +6000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 0033 +ENCODING 51 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3C00 +7E00 +C300 +C300 +0300 +1E00 +1F00 +0300 +0180 +0180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 0034 +ENCODING 52 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +0300 +0700 +0700 +0F00 +1B00 +1300 +3300 +6300 +4300 +FFC0 +FFC0 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 0035 +ENCODING 53 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +7F00 +7F00 +6000 +4000 +4000 +DE00 +FF00 +C300 +0180 +0180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 0036 +ENCODING 54 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3E00 +7F00 +6300 +C100 +C000 +9E00 +BF00 +E300 +C180 +C180 +C180 +E300 +7F00 +3C00 +ENDCHAR +STARTCHAR 0037 +ENCODING 55 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +FF80 +FF80 +0300 +0600 +0600 +0C00 +0C00 +1800 +1800 +1000 +3000 +3000 +3000 +3000 +ENDCHAR +STARTCHAR 0038 +ENCODING 56 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3C00 +7E00 +6300 +C300 +C300 +6300 +3E00 +7E00 +C300 +C180 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 0039 +ENCODING 57 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3C00 +7E00 +E300 +C100 +C180 +C180 +C380 +7F80 +3D80 +0180 +C300 +C300 +7E00 +3C00 +ENDCHAR +STARTCHAR 003A +ENCODING 58 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 10 2 0 +BITMAP +C0 +C0 +00 +00 +00 +00 +00 +00 +C0 +C0 +ENDCHAR +STARTCHAR 003B +ENCODING 59 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 13 2 -3 +BITMAP +C0 +C0 +00 +00 +00 +00 +00 +00 +C0 +C0 +40 +80 +80 +ENDCHAR +STARTCHAR 003C +ENCODING 60 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 9 1 2 +BITMAP +0080 +0380 +1F00 +7800 +C000 +7800 +1F00 +0380 +0080 +ENDCHAR +STARTCHAR 003D +ENCODING 61 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 6 1 4 +BITMAP +FF80 +FF80 +0000 +0000 +FF80 +FF80 +ENDCHAR +STARTCHAR 003E +ENCODING 62 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 9 1 2 +BITMAP +8000 +E000 +7C00 +0F00 +0180 +0F00 +7C00 +E000 +8000 +ENDCHAR +STARTCHAR 003F +ENCODING 63 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3E00 +7F00 +C300 +C180 +0180 +0300 +0600 +0C00 +0C00 +1800 +1800 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 0040 +ENCODING 64 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 17 18 1 -4 +BITMAP +03F000 +0FFC00 +1C0E00 +300300 +61D980 +47F980 +C63880 +CC1080 +8C1080 +883180 +883100 +CC7700 +CFFE00 +67BC00 +700180 +3C0700 +1FFE00 +03F800 +ENDCHAR +STARTCHAR 0041 +ENCODING 65 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 14 0 0 +BITMAP +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 0042 +ENCODING 66 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FF00 +FF80 +C0C0 +C0C0 +C0C0 +C0C0 +FF80 +FF80 +C0C0 +C060 +C060 +C0C0 +FFC0 +FF80 +ENDCHAR +STARTCHAR 0043 +ENCODING 67 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F80 +3FC0 +70E0 +6070 +C000 +C000 +C000 +C000 +C000 +C030 +6070 +70E0 +3FC0 +0F80 +ENDCHAR +STARTCHAR 0044 +ENCODING 68 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +FF00 +FFC0 +C0E0 +C060 +C020 +C030 +C030 +C030 +C030 +C060 +C060 +C0E0 +FFC0 +FF00 +ENDCHAR +STARTCHAR 0045 +ENCODING 69 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0046 +ENCODING 70 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 9 14 2 0 +BITMAP +FF80 +FF80 +8000 +8000 +8000 +8000 +FF00 +FF00 +8000 +8000 +8000 +8000 +8000 +8000 +ENDCHAR +STARTCHAR 0047 +ENCODING 71 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0F80 +3FE0 +7070 +6030 +C010 +C000 +C000 +C1F8 +C1F8 +C018 +6018 +7038 +3FF0 +0FC0 +ENDCHAR +STARTCHAR 0048 +ENCODING 72 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 10 14 2 0 +BITMAP +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +FFC0 +FFC0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +ENDCHAR +STARTCHAR 0049 +ENCODING 73 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 14 2 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 004A +ENCODING 74 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 14 1 0 +BITMAP +06 +06 +06 +06 +06 +06 +06 +06 +06 +06 +86 +C6 +FC +78 +ENDCHAR +STARTCHAR 004B +ENCODING 75 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +C0E0 +C1C0 +C380 +C700 +CE00 +DC00 +FC00 +F600 +E700 +C300 +C180 +C0C0 +C0E0 +C060 +ENDCHAR +STARTCHAR 004C +ENCODING 76 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 004D +ENCODING 77 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 13 14 1 0 +BITMAP +E018 +F038 +F028 +D028 +D868 +D868 +C848 +CCC8 +CCC8 +C488 +C788 +C788 +C308 +C308 +ENDCHAR +STARTCHAR 004E +ENCODING 78 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 1 0 +BITMAP +E060 +E060 +F060 +D860 +D860 +CC60 +CC60 +C660 +C360 +C360 +C1E0 +C0E0 +C0E0 +C060 +ENDCHAR +STARTCHAR 004F +ENCODING 79 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 0050 +ENCODING 80 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FF80 +FFC0 +C0E0 +C060 +C060 +C060 +C0C0 +FFC0 +FF80 +C000 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 0051 +ENCODING 81 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 15 1 -1 +BITMAP +0F80 +3FE0 +7070 +6030 +C038 +C018 +C018 +C018 +C018 +C030 +61B0 +70E0 +3FE0 +0FB8 +0008 +ENDCHAR +STARTCHAR 0052 +ENCODING 82 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +FFC0 +FFE0 +C060 +C060 +C060 +C060 +FFE0 +FF80 +C300 +C180 +C0C0 +C060 +C060 +C030 +ENDCHAR +STARTCHAR 0053 +ENCODING 83 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +1F00 +7F80 +60C0 +C0C0 +C000 +7000 +3F00 +07C0 +00C0 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 0054 +ENCODING 84 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 0 0 +BITMAP +FFE0 +FFE0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0055 +ENCODING 85 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 1 0 +BITMAP +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 0056 +ENCODING 86 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 14 0 0 +BITMAP +C010 +6030 +6030 +6060 +3060 +3040 +10C0 +18C0 +1880 +0980 +0D80 +0D00 +0700 +0600 +ENDCHAR +STARTCHAR 0057 +ENCODING 87 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 14 0 0 +BITMAP +C0C0C0 +40C080 +61E180 +61E180 +612180 +233100 +333300 +323300 +321200 +161A00 +161E00 +1C0E00 +1C0C00 +0C0C00 +ENDCHAR +STARTCHAR 0058 +ENCODING 88 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 14 0 0 +BITMAP +6030 +3060 +30C0 +18C0 +0D80 +0F00 +0700 +0700 +0D80 +1980 +18C0 +3060 +6070 +E030 +ENDCHAR +STARTCHAR 0059 +ENCODING 89 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 14 0 0 +BITMAP +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 005A +ENCODING 90 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 0 0 +BITMAP +7FE0 +7FE0 +00C0 +01C0 +0180 +0300 +0600 +0C00 +1C00 +3800 +3000 +6000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 005B +ENCODING 91 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 18 1 -4 +BITMAP +F0 +F0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +F0 +F0 +ENDCHAR +STARTCHAR 005C +ENCODING 92 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 14 0 0 +BITMAP +80 +C0 +40 +40 +60 +20 +20 +20 +30 +10 +10 +18 +08 +08 +ENDCHAR +STARTCHAR 005D +ENCODING 93 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 18 0 -4 +BITMAP +F0 +F0 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +F0 +F0 +ENDCHAR +STARTCHAR 005E +ENCODING 94 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 7 1 7 +BITMAP +10 +38 +28 +6C +44 +C6 +82 +ENDCHAR +STARTCHAR 005F +ENCODING 95 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 2 0 -4 +BITMAP +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0060 +ENCODING 96 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 3 3 1 11 +BITMAP +C0 +60 +20 +ENDCHAR +STARTCHAR 0061 +ENCODING 97 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 0062 +ENCODING 98 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +C000 +C000 +C000 +C000 +DE00 +FF00 +E300 +C180 +C180 +C180 +C180 +E300 +FF00 +DC00 +ENDCHAR +STARTCHAR 0063 +ENCODING 99 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +3C +7F +E3 +C0 +80 +80 +C0 +C3 +7F +3C +ENDCHAR +STARTCHAR 0064 +ENCODING 100 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +01 +01 +01 +01 +39 +7D +C3 +C3 +81 +81 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 0065 +ENCODING 101 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0066 +ENCODING 102 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 14 0 0 +BITMAP +1C +3C +20 +20 +F8 +F8 +20 +20 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR 0067 +ENCODING 103 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +3D +7F +C3 +C3 +81 +81 +C3 +C3 +7F +3D +01 +C3 +FE +7C +ENDCHAR +STARTCHAR 0068 +ENCODING 104 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +C0 +C0 +C0 +C0 +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +ENDCHAR +STARTCHAR 0069 +ENCODING 105 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 14 1 0 +BITMAP +C0 +C0 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 006A +ENCODING 106 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 18 -1 -4 +BITMAP +30 +30 +00 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +F0 +E0 +ENDCHAR +STARTCHAR 006B +ENCODING 107 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +C0 +C0 +C0 +C0 +C7 +CE +DC +F8 +F8 +D8 +CC +C6 +C6 +C3 +ENDCHAR +STARTCHAR 006C +ENCODING 108 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 14 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 006D +ENCODING 109 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 10 1 0 +BITMAP +DC70 +FEF8 +E38C +C30C +C30C +C30C +C30C +C30C +C30C +C30C +ENDCHAR +STARTCHAR 006E +ENCODING 110 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 10 1 0 +BITMAP +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +ENDCHAR +STARTCHAR 006F +ENCODING 111 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 0070 +ENCODING 112 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 -4 +BITMAP +DE00 +FF00 +E300 +C180 +C180 +C180 +C180 +E300 +FF00 +DC00 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 0071 +ENCODING 113 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +39 +7D +C3 +C3 +81 +81 +C3 +C3 +7D +39 +01 +01 +01 +01 +ENDCHAR +STARTCHAR 0072 +ENCODING 114 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 10 1 0 +BITMAP +DC +F8 +E0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0073 +ENCODING 115 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +7C +FE +C6 +E0 +FC +3E +03 +C3 +FE +7C +ENDCHAR +STARTCHAR 0074 +ENCODING 116 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 13 0 0 +BITMAP +20 +20 +20 +F8 +F8 +20 +20 +20 +20 +20 +20 +38 +38 +ENDCHAR +STARTCHAR 0075 +ENCODING 117 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 10 1 0 +BITMAP +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 0076 +ENCODING 118 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 0 0 +BITMAP +C180 +6180 +6100 +2300 +3300 +3200 +1600 +1C00 +1C00 +0C00 +ENDCHAR +STARTCHAR 0077 +ENCODING 119 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 10 0 0 +BITMAP +C308 +4308 +4718 +6798 +6590 +24B0 +3CB0 +3CE0 +18E0 +1860 +ENDCHAR +STARTCHAR 0078 +ENCODING 120 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 0 0 +BITMAP +6180 +6300 +3600 +1E00 +0C00 +1C00 +1E00 +3300 +6300 +E180 +ENDCHAR +STARTCHAR 0079 +ENCODING 121 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 -4 +BITMAP +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 007A +ENCODING 122 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 0 0 +BITMAP +7F80 +7F80 +0300 +0600 +0C00 +1800 +3000 +6000 +FF80 +FF80 +ENDCHAR +STARTCHAR 007B +ENCODING 123 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 18 1 -4 +BITMAP +38 +38 +60 +60 +60 +60 +60 +60 +C0 +C0 +60 +60 +60 +60 +60 +20 +38 +38 +ENDCHAR +STARTCHAR 007C +ENCODING 124 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 1 18 2 -4 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR 007D +ENCODING 125 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 18 0 -4 +BITMAP +E0 +F0 +30 +30 +30 +30 +30 +18 +1C +1C +18 +30 +30 +30 +30 +30 +F0 +E0 +ENDCHAR +STARTCHAR 007E +ENCODING 126 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 4 1 4 +BITMAP +7000 +FC80 +8F80 +0700 +ENDCHAR +STARTCHAR 00A0 +ENCODING 160 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 0 0 0 0 +BITMAP +ENDCHAR +STARTCHAR 00A1 +ENCODING 161 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 14 2 -4 +BITMAP +C0 +C0 +00 +40 +40 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00A2 +ENCODING 162 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 18 1 -4 +BITMAP +02 +02 +02 +06 +3C +7F +E7 +C8 +C8 +C8 +D1 +F3 +7F +3C +20 +20 +20 +40 +ENDCHAR +STARTCHAR 00A3 +ENCODING 163 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +1F00 +3F80 +30C0 +6000 +6000 +2000 +FE00 +FE00 +3000 +3000 +2000 +7C40 +FFC0 +4380 +ENDCHAR +STARTCHAR 00A4 +ENCODING 164 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 8 1 2 +BITMAP +9D +FF +63 +C1 +C1 +63 +FF +9D +ENDCHAR +STARTCHAR 00A5 +ENCODING 165 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +C0C0 +60C0 +6180 +3180 +3300 +1B00 +1E00 +7FC0 +7FC0 +0C00 +7FC0 +7FC0 +0C00 +0C00 +ENDCHAR +STARTCHAR 00A6 +ENCODING 166 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 1 18 2 -4 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +00 +00 +00 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR 00A7 +ENCODING 167 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 -4 +BITMAP +3C00 +7E00 +6300 +6000 +7000 +7C00 +8E00 +8300 +C180 +E180 +3900 +1E00 +0600 +0300 +C300 +6300 +7F00 +3C00 +ENDCHAR +STARTCHAR 00A8 +ENCODING 168 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 2 1 12 +BITMAP +98 +98 +ENDCHAR +STARTCHAR 00A9 +ENCODING 169 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 14 14 0 0 +BITMAP +0FC0 +1860 +2010 +4788 +CC4C +8804 +9804 +9804 +8844 +CCCC +4788 +2010 +1860 +0FC0 +ENDCHAR +STARTCHAR 00AA +ENCODING 170 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 6 7 0 7 +BITMAP +3C +44 +04 +7C +C4 +4C +7C +ENDCHAR +STARTCHAR 00AB +ENCODING 171 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 9 1 1 +BITMAP +13 +32 +26 +64 +CC +64 +26 +32 +13 +ENDCHAR +STARTCHAR 00AC +ENCODING 172 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 6 1 4 +BITMAP +FF80 +FF80 +0180 +0180 +0180 +0180 +ENDCHAR +STARTCHAR 00AD +ENCODING 173 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 2 1 4 +BITMAP +F8 +F8 +ENDCHAR +STARTCHAR 00AE +ENCODING 174 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 14 14 0 0 +BITMAP +0FC0 +1860 +2010 +4F88 +C8CC +88C4 +8F84 +8904 +8884 +C8CC +4848 +2010 +1860 +0FC0 +ENDCHAR +STARTCHAR 00AF +ENCODING 175 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 2 0 15 +BITMAP +FFE0 +FFE0 +ENDCHAR +STARTCHAR 00B0 +ENCODING 176 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 5 5 1 9 +BITMAP +70 +C8 +88 +C8 +70 +ENDCHAR +STARTCHAR 00B1 +ENCODING 177 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 11 1 0 +BITMAP +1800 +1800 +1800 +1800 +FF80 +FF80 +1800 +1800 +1800 +FF80 +FF80 +ENDCHAR +STARTCHAR 00B2 +ENCODING 178 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 7 0 7 +BITMAP +78 +4C +0C +18 +30 +60 +FC +ENDCHAR +STARTCHAR 00B3 +ENCODING 179 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 7 0 7 +BITMAP +78 +4C +0C +18 +0C +CC +78 +ENDCHAR +STARTCHAR 00B4 +ENCODING 180 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 3 3 2 11 +BITMAP +60 +40 +C0 +ENDCHAR +STARTCHAR 00B5 +ENCODING 181 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +C1 +C1 +C1 +C1 +C1 +C1 +C1 +E3 +FF +DD +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00B6 +ENCODING 182 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 17 0 -3 +BITMAP +3FC0 +7FC0 +F980 +F980 +F980 +F980 +7980 +3980 +0980 +0980 +0980 +0980 +0980 +0980 +0980 +0980 +0980 +ENDCHAR +STARTCHAR 00B7 +ENCODING 183 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 2 2 6 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR 00B8 +ENCODING 184 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 4 1 -4 +BITMAP +60 +70 +30 +E0 +ENDCHAR +STARTCHAR 00B9 +ENCODING 185 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 3 7 1 7 +BITMAP +20 +60 +E0 +A0 +20 +20 +20 +ENDCHAR +STARTCHAR 00BA +ENCODING 186 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 7 0 7 +BITMAP +38 +44 +44 +C6 +44 +44 +38 +ENDCHAR +STARTCHAR 00BB +ENCODING 187 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 7 9 2 1 +BITMAP +98 +C8 +4C +66 +36 +66 +4C +C8 +98 +ENDCHAR +STARTCHAR 00BC +ENCODING 188 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 1 0 +BITMAP +2018 +6030 +E020 +A040 +20C0 +2080 +2100 +030C +061C +041C +082C +186C +307E +200C +ENDCHAR +STARTCHAR 00BD +ENCODING 189 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 1 0 +BITMAP +2010 +6030 +E020 +A040 +20C0 +2180 +2100 +023C +0664 +0C04 +080C +1018 +3030 +607E +ENDCHAR +STARTCHAR 00BE +ENCODING 190 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 16 14 0 0 +BITMAP +780C +4C18 +0C10 +1820 +0C60 +CC40 +7880 +0186 +030E +020E +0416 +0C36 +183F +1006 +ENDCHAR +STARTCHAR 00BF +ENCODING 191 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 9 14 1 -4 +BITMAP +0C00 +0C00 +0000 +0C00 +0C00 +0800 +1800 +3000 +6000 +4000 +C180 +6180 +7F00 +1E00 +ENDCHAR +STARTCHAR 00C0 +ENCODING 192 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0600 +0600 +0200 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 00C1 +ENCODING 193 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0300 +0200 +0600 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 00C2 +ENCODING 194 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0600 +0F00 +0980 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 00C3 +ENCODING 195 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0C80 +1F80 +1B80 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 00C4 +ENCODING 196 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 17 0 0 +BITMAP +0980 +0980 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 00C5 +ENCODING 197 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0600 +0900 +0900 +0900 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 00C6 +ENCODING 198 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 18 14 0 0 +BITMAP +03FFC0 +03FFC0 +066000 +066000 +0C6000 +0C6000 +087F80 +187F80 +1FE000 +3FE000 +306000 +606000 +607FC0 +C07FC0 +ENDCHAR +STARTCHAR 00C7 +ENCODING 199 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 -4 +BITMAP +0F80 +3FC0 +70E0 +6070 +C000 +C000 +C000 +C000 +C000 +C030 +6070 +70E0 +3FC0 +0F80 +0400 +0600 +0300 +0E00 +ENDCHAR +STARTCHAR 00C8 +ENCODING 200 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0C00 +0C00 +0600 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 00C9 +ENCODING 201 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0600 +0600 +0C00 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 00CA +ENCODING 202 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0E00 +0A00 +1B00 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 00CB +ENCODING 203 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 17 1 0 +BITMAP +1B00 +1B00 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 00CC +ENCODING 204 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 3 18 1 0 +BITMAP +C0 +40 +60 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 00CD +ENCODING 205 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 18 2 0 +BITMAP +C0 +C0 +80 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00CE +ENCODING 206 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 18 0 0 +BITMAP +70 +58 +D8 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 00CF +ENCODING 207 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 17 0 0 +BITMAP +D8 +D8 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 00D0 +ENCODING 208 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 14 0 0 +BITMAP +7F80 +7FE0 +6070 +6030 +6010 +6018 +FE18 +FE18 +6018 +6030 +6030 +6070 +7FE0 +7F80 +ENDCHAR +STARTCHAR 00D1 +ENCODING 209 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0C80 +1F80 +1300 +0000 +E060 +E060 +F060 +D860 +D860 +CC60 +CC60 +C660 +C360 +C360 +C1E0 +C0E0 +C0E0 +C060 +ENDCHAR +STARTCHAR 00D2 +ENCODING 210 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0C00 +0600 +0200 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 00D3 +ENCODING 211 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0300 +0300 +0600 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 00D4 +ENCODING 212 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0700 +0D00 +0D80 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 00D5 +ENCODING 213 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0EC0 +0F80 +1B80 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 00D6 +ENCODING 214 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 17 1 0 +BITMAP +0D80 +0D80 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 00D7 +ENCODING 215 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 7 7 2 3 +BITMAP +82 +C6 +7C +38 +7C +C6 +82 +ENDCHAR +STARTCHAR 00D8 +ENCODING 216 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 15 1 -1 +BITMAP +0F88 +3FD0 +7060 +6070 +C0D0 +C198 +C318 +C618 +CC18 +D818 +7030 +7070 +7FE0 +DF80 +8000 +ENDCHAR +STARTCHAR 00D9 +ENCODING 217 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0C00 +0400 +0600 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 00DA +ENCODING 218 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0300 +0600 +0400 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 00DB +ENCODING 219 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0600 +0F00 +1900 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 00DC +ENCODING 220 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 17 1 0 +BITMAP +1900 +1900 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 00DD +ENCODING 221 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +0300 +0300 +0600 +0000 +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 00DE +ENCODING 222 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +C000 +C000 +C000 +FF80 +FFC0 +C0E0 +C060 +C060 +C0E0 +FFC0 +FF80 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 00DF +ENCODING 223 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +3C00 +7E00 +6300 +C300 +C200 +C600 +C400 +C600 +C380 +C1C0 +C0C0 +D8C0 +CFC0 +C780 +ENDCHAR +STARTCHAR 00E0 +ENCODING 224 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3800 +1800 +0800 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 00E1 +ENCODING 225 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 00E2 +ENCODING 226 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +1800 +3400 +2600 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 00E3 +ENCODING 227 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3200 +7E00 +4E00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 00E4 +ENCODING 228 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 0 +BITMAP +2600 +2600 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 00E5 +ENCODING 229 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +1800 +2400 +2400 +2400 +1800 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 00E6 +ENCODING 230 +SWIDTH 874 0 +DWIDTH 17 0 +BBX 15 10 1 0 +BITMAP +3E78 +7FFC +C386 +0F06 +7FFE +F3FE +8300 +C786 +FFFC +7878 +ENDCHAR +STARTCHAR 00E7 +ENCODING 231 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 -4 +BITMAP +3C +7F +E3 +C0 +80 +80 +C0 +C3 +7F +3C +10 +18 +0C +38 +ENDCHAR +STARTCHAR 00E8 +ENCODING 232 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3000 +1800 +0800 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 00E9 +ENCODING 233 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 00EA +ENCODING 234 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 00EB +ENCODING 235 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 0 +BITMAP +2600 +2600 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 00EC +ENCODING 236 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 3 14 1 0 +BITMAP +C0 +C0 +60 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 00ED +ENCODING 237 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 3 14 2 0 +BITMAP +60 +C0 +80 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00EE +ENCODING 238 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 14 0 0 +BITMAP +30 +78 +C8 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 00EF +ENCODING 239 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 13 0 0 +BITMAP +C8 +C8 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 00F0 +ENCODING 240 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3200 +1E00 +3C00 +2600 +3B00 +7F00 +C300 +C180 +8180 +8180 +C180 +E300 +7F00 +3C00 +ENDCHAR +STARTCHAR 00F1 +ENCODING 241 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +3B +3E +6E +00 +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +ENDCHAR +STARTCHAR 00F2 +ENCODING 242 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3000 +1800 +0800 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 00F3 +ENCODING 243 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 00F4 +ENCODING 244 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 00F5 +ENCODING 245 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3200 +7E00 +4E00 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 00F6 +ENCODING 246 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 0 +BITMAP +2600 +2600 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 00F7 +ENCODING 247 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 8 1 2 +BITMAP +1800 +1800 +0000 +FF80 +FF80 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 00F8 +ENCODING 248 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 9 12 1 -1 +BITMAP +0080 +1E80 +7F00 +6380 +C680 +C480 +C880 +D180 +7380 +7F00 +5E00 +8000 +ENDCHAR +STARTCHAR 00F9 +ENCODING 249 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +18 +18 +0C +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 00FA +ENCODING 250 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +0C +0C +18 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 00FB +ENCODING 251 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +18 +3C +26 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 00FC +ENCODING 252 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 13 1 0 +BITMAP +26 +26 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 00FD +ENCODING 253 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 18 1 -4 +BITMAP +0C +08 +18 +00 +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 00FE +ENCODING 254 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 -4 +BITMAP +C000 +C000 +C000 +C000 +DE00 +FF00 +E300 +C180 +C180 +C180 +C180 +E300 +FF00 +DC00 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 00FF +ENCODING 255 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 17 1 -4 +BITMAP +64 +64 +00 +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 0100 +ENCODING 256 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 16 0 0 +BITMAP +1F80 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 0101 +ENCODING 257 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +3E00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 0102 +ENCODING 258 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0880 +0980 +0700 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 0103 +ENCODING 259 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +2200 +2200 +1C00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 0104 +ENCODING 260 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 18 0 -4 +BITMAP +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +0010 +0020 +0030 +001C +ENDCHAR +STARTCHAR 0105 +ENCODING 261 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 14 1 -4 +BITMAP +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +0100 +0100 +0100 +01E0 +ENDCHAR +STARTCHAR 0106 +ENCODING 262 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +0300 +0300 +0600 +0000 +0F80 +3FC0 +70E0 +6070 +C000 +C000 +C000 +C000 +C000 +C030 +6070 +70E0 +3FC0 +0F80 +ENDCHAR +STARTCHAR 0107 +ENCODING 263 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +0C +08 +18 +00 +3C +7F +E3 +C0 +80 +80 +C0 +C3 +7F +3C +ENDCHAR +STARTCHAR 0108 +ENCODING 264 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +0600 +0F00 +0980 +0000 +0F80 +3FC0 +70E0 +6070 +C000 +C000 +C000 +C000 +C000 +C030 +6070 +70E0 +3FC0 +0F80 +ENDCHAR +STARTCHAR 0109 +ENCODING 265 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +1C +14 +36 +00 +3C +7F +E3 +C0 +80 +80 +C0 +C3 +7F +3C +ENDCHAR +STARTCHAR 010A +ENCODING 266 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 17 1 0 +BITMAP +0600 +0600 +0000 +0F80 +3FC0 +70E0 +6070 +C000 +C000 +C000 +C000 +C000 +C030 +6070 +70E0 +3FC0 +0F80 +ENDCHAR +STARTCHAR 010B +ENCODING 267 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 13 1 0 +BITMAP +18 +18 +00 +3C +7F +E3 +C0 +80 +80 +C0 +C3 +7F +3C +ENDCHAR +STARTCHAR 010C +ENCODING 268 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +0D80 +0D00 +0700 +0000 +0F80 +3FC0 +70E0 +6070 +C000 +C000 +C000 +C000 +C000 +C030 +6070 +70E0 +3FC0 +0F80 +ENDCHAR +STARTCHAR 010D +ENCODING 269 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +26 +3C +18 +00 +3C +7F +E3 +C0 +80 +80 +C0 +C3 +7F +3C +ENDCHAR +STARTCHAR 010E +ENCODING 270 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +3600 +1400 +1C00 +0000 +FF00 +FFC0 +C0E0 +C060 +C020 +C030 +C030 +C030 +C030 +C060 +C060 +C0E0 +FFC0 +FF00 +ENDCHAR +STARTCHAR 010F +ENCODING 271 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 1 0 +BITMAP +0160 +0160 +0120 +0140 +3D00 +7F00 +C300 +C300 +8100 +8100 +C300 +C300 +7D00 +3900 +ENDCHAR +STARTCHAR 0110 +ENCODING 272 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 14 0 0 +BITMAP +7F80 +7FE0 +6070 +6030 +6010 +6018 +FE18 +FE18 +6018 +6030 +6030 +6070 +7FE0 +7F80 +ENDCHAR +STARTCHAR 0111 +ENCODING 273 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 0 +BITMAP +0100 +1FC0 +1FC0 +0100 +3900 +7D00 +C300 +C300 +8100 +8100 +C300 +C300 +7D00 +3900 +ENDCHAR +STARTCHAR 0112 +ENCODING 274 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 16 1 0 +BITMAP +1F80 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0113 +ENCODING 275 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +7E00 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0114 +ENCODING 276 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +1100 +1100 +0E00 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0115 +ENCODING 277 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +2200 +2200 +1C00 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0116 +ENCODING 278 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 17 1 0 +BITMAP +0600 +0600 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0117 +ENCODING 279 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 0 +BITMAP +1C00 +1C00 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0118 +ENCODING 280 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 -4 +BITMAP +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +0100 +0100 +0100 +01E0 +ENDCHAR +STARTCHAR 0119 +ENCODING 281 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 -4 +BITMAP +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +0800 +0800 +0800 +0F00 +ENDCHAR +STARTCHAR 011A +ENCODING 282 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +1300 +1E00 +0C00 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 011B +ENCODING 283 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3600 +3400 +1C00 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 011C +ENCODING 284 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0300 +0780 +0CC0 +0000 +0F80 +3FE0 +7070 +6030 +C010 +C000 +C000 +C1F8 +C1F8 +C018 +6018 +7038 +3FF0 +0FC0 +ENDCHAR +STARTCHAR 011D +ENCODING 285 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 18 1 -4 +BITMAP +18 +3C +66 +00 +3D +7F +C3 +C3 +81 +81 +C3 +C3 +7F +3D +01 +C3 +FE +7C +ENDCHAR +STARTCHAR 011E +ENCODING 286 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0C40 +0480 +0780 +0000 +0F80 +3FE0 +7070 +6030 +C010 +C000 +C000 +C1F8 +C1F8 +C018 +6018 +7038 +3FF0 +0FC0 +ENDCHAR +STARTCHAR 011F +ENCODING 287 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 18 1 -4 +BITMAP +22 +26 +1C +00 +3D +7F +C3 +C3 +81 +81 +C3 +C3 +7F +3D +01 +C3 +FE +7C +ENDCHAR +STARTCHAR 0120 +ENCODING 288 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 17 1 0 +BITMAP +0300 +0300 +0000 +0F80 +3FE0 +7070 +6030 +C010 +C000 +C000 +C1F8 +C1F8 +C018 +6018 +7038 +3FF0 +0FC0 +ENDCHAR +STARTCHAR 0121 +ENCODING 289 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 17 1 -4 +BITMAP +18 +18 +00 +3D +7F +C3 +C3 +81 +81 +C3 +C3 +7F +3D +01 +C3 +FE +7C +ENDCHAR +STARTCHAR 0122 +ENCODING 290 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 -4 +BITMAP +0F80 +3FE0 +7070 +6030 +C010 +C000 +C000 +C1F8 +C1F8 +C018 +6018 +7038 +3FF0 +0FC0 +0300 +0380 +0180 +0700 +ENDCHAR +STARTCHAR 0123 +ENCODING 291 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 19 1 -4 +BITMAP +08 +10 +18 +18 +00 +3D +7F +C3 +C3 +81 +81 +C3 +C3 +7F +3D +03 +C3 +FE +7C +ENDCHAR +STARTCHAR 0124 +ENCODING 292 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 10 18 2 0 +BITMAP +0C00 +1E00 +1300 +0000 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +FFC0 +FFC0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +ENDCHAR +STARTCHAR 0125 +ENCODING 293 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 18 1 0 +BITMAP +0C +1E +33 +00 +C0 +C0 +C0 +C0 +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +ENDCHAR +STARTCHAR 0126 +ENCODING 294 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 14 0 0 +BITMAP +2030 +FFF8 +FFF8 +2030 +2030 +3FF0 +3FF0 +2030 +2030 +2030 +2030 +2030 +2030 +2030 +ENDCHAR +STARTCHAR 0127 +ENCODING 295 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 0 0 +BITMAP +6000 +FC00 +FC00 +6000 +6F00 +7F80 +7180 +6080 +6080 +6080 +6080 +6080 +6080 +6080 +ENDCHAR +STARTCHAR 0128 +ENCODING 296 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 7 18 -1 0 +BITMAP +76 +7C +DC +00 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 0129 +ENCODING 297 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 14 0 0 +BITMAP +EC +FC +98 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012A +ENCODING 298 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 16 0 0 +BITMAP +FC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012B +ENCODING 299 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 12 0 0 +BITMAP +FC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012C +ENCODING 300 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 18 0 0 +BITMAP +88 +C8 +70 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012D +ENCODING 301 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 14 0 0 +BITMAP +88 +C8 +70 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012E +ENCODING 302 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 18 2 -4 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +80 +80 +80 +F0 +ENDCHAR +STARTCHAR 012F +ENCODING 303 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 18 1 -4 +BITMAP +C0 +C0 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +80 +80 +80 +70 +ENDCHAR +STARTCHAR 0130 +ENCODING 304 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 17 2 0 +BITMAP +C0 +C0 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0131 +ENCODING 305 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 10 2 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0132 +ENCODING 306 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 2 0 +BITMAP +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C860 +CC60 +CFC0 +C780 +ENDCHAR +STARTCHAR 0133 +ENCODING 307 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 6 18 1 -4 +BITMAP +C4 +C4 +00 +00 +C4 +C4 +C4 +C4 +C4 +C4 +C4 +C4 +C4 +C4 +04 +04 +1C +1C +ENDCHAR +STARTCHAR 0134 +ENCODING 308 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 18 1 0 +BITMAP +0700 +0D00 +0D80 +0000 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +8600 +C600 +FC00 +7800 +ENDCHAR +STARTCHAR 0135 +ENCODING 309 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 6 18 -1 -4 +BITMAP +30 +78 +4C +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +F0 +E0 +ENDCHAR +STARTCHAR 0136 +ENCODING 310 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 -4 +BITMAP +C0E0 +C1C0 +C380 +C700 +CE00 +DC00 +FC00 +F600 +E700 +C300 +C180 +C0C0 +C0E0 +C060 +0000 +0700 +0100 +0F00 +ENDCHAR +STARTCHAR 0137 +ENCODING 311 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 18 1 -4 +BITMAP +C0 +C0 +C0 +C0 +C7 +CE +DC +F8 +F8 +D8 +CC +C6 +C6 +C3 +00 +0C +06 +1C +ENDCHAR +STARTCHAR 0138 +ENCODING 312 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +C7 +CE +D8 +F0 +F8 +C8 +CC +C6 +C6 +C3 +ENDCHAR +STARTCHAR 0139 +ENCODING 313 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +1800 +3000 +3000 +0000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 013A +ENCODING 314 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 18 1 0 +BITMAP +60 +C0 +80 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 013B +ENCODING 315 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 -4 +BITMAP +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FF80 +FF80 +0000 +0E00 +0200 +1E00 +ENDCHAR +STARTCHAR 013C +ENCODING 316 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 18 0 -4 +BITMAP +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +00 +70 +30 +E0 +ENDCHAR +STARTCHAR 013D +ENCODING 317 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +C300 +C300 +C200 +C200 +C200 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 013E +ENCODING 318 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 14 1 0 +BITMAP +D8 +D8 +D0 +D0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 013F +ENCODING 319 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +C000 +C000 +C000 +C000 +C000 +C000 +C300 +C300 +C000 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 0140 +ENCODING 320 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 14 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +D8 +D8 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0141 +ENCODING 321 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +6000 +6000 +6000 +6400 +6C00 +7800 +7000 +E000 +E000 +6000 +6000 +6000 +7FC0 +7FC0 +ENDCHAR +STARTCHAR 0142 +ENCODING 322 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 14 0 0 +BITMAP +60 +60 +60 +60 +70 +70 +60 +E0 +E0 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 0143 +ENCODING 323 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0600 +0600 +0400 +0000 +E060 +E060 +F060 +D860 +D860 +CC60 +CC60 +C660 +C360 +C360 +C1E0 +C0E0 +C0E0 +C060 +ENDCHAR +STARTCHAR 0144 +ENCODING 324 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +0C +0C +18 +00 +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +ENDCHAR +STARTCHAR 0145 +ENCODING 325 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 -4 +BITMAP +E060 +E060 +F060 +D860 +D860 +CC60 +CC60 +C660 +C360 +C360 +C1E0 +C0E0 +C0E0 +C060 +0000 +0700 +0180 +0700 +ENDCHAR +STARTCHAR 0146 +ENCODING 326 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +00 +1C +04 +3C +ENDCHAR +STARTCHAR 0147 +ENCODING 327 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +1900 +0F00 +0600 +0000 +E060 +E060 +F060 +D860 +D860 +CC60 +CC60 +C660 +C360 +C360 +C1E0 +C0E0 +C0E0 +C060 +ENDCHAR +STARTCHAR 0148 +ENCODING 328 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +36 +34 +1C +00 +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +ENDCHAR +STARTCHAR 0149 +ENCODING 329 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +C000 +C000 +4000 +8000 +B780 +3FC0 +38C0 +30C0 +30C0 +30C0 +30C0 +30C0 +30C0 +30C0 +ENDCHAR +STARTCHAR 014A +ENCODING 330 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 2 0 +BITMAP +9F00 +BF80 +E1C0 +C0C0 +C060 +8060 +8060 +8060 +8060 +8060 +80C0 +80C0 +8780 +8F00 +ENDCHAR +STARTCHAR 014B +ENCODING 331 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +01 +03 +07 +06 +ENDCHAR +STARTCHAR 014C +ENCODING 332 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 16 1 0 +BITMAP +0F80 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 014D +ENCODING 333 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +7E00 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 014E +ENCODING 334 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0880 +0880 +0700 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 014F +ENCODING 335 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +2200 +2600 +1C00 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 0150 +ENCODING 336 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0CC0 +0D80 +0900 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 0151 +ENCODING 337 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +1B00 +3600 +2600 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 0152 +ENCODING 338 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 17 14 1 0 +BITMAP +1F7F80 +3FFF80 +71E000 +60E000 +C06000 +C06000 +C07F80 +C07F80 +C06000 +C06000 +60E000 +71E000 +3FFF80 +1F7F80 +ENDCHAR +STARTCHAR 0153 +ENCODING 339 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 16 10 1 0 +BITMAP +3C3C +7F7E +E3C3 +C183 +C1FF +C1FF +C180 +E3C3 +7F7E +3C3C +ENDCHAR +STARTCHAR 0154 +ENCODING 340 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +0600 +0C00 +0800 +0000 +FFC0 +FFE0 +C060 +C060 +C060 +C060 +FFE0 +FF80 +C300 +C180 +C0C0 +C060 +C060 +C030 +ENDCHAR +STARTCHAR 0155 +ENCODING 341 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 14 1 0 +BITMAP +30 +30 +60 +00 +DC +F8 +E0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0156 +ENCODING 342 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 -4 +BITMAP +FFC0 +FFE0 +C060 +C060 +C060 +C060 +FFE0 +FF80 +C300 +C180 +C0C0 +C060 +C060 +C030 +0000 +0700 +0180 +0700 +ENDCHAR +STARTCHAR 0157 +ENCODING 343 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 14 1 -4 +BITMAP +DC +F8 +E0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +00 +70 +10 +F0 +ENDCHAR +STARTCHAR 0158 +ENCODING 344 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +3300 +1E00 +0C00 +0000 +FFC0 +FFE0 +C060 +C060 +C060 +C060 +FFE0 +FF80 +C300 +C180 +C0C0 +C060 +C060 +C030 +ENDCHAR +STARTCHAR 0159 +ENCODING 345 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 14 1 0 +BITMAP +D8 +50 +70 +00 +DC +F8 +E0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 015A +ENCODING 346 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0600 +0C00 +0800 +0000 +1F00 +7F80 +60C0 +C0C0 +C000 +7000 +3F00 +07C0 +00C0 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 015B +ENCODING 347 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +0C +18 +10 +00 +7C +FE +C6 +E0 +FC +3E +03 +C3 +FE +7C +ENDCHAR +STARTCHAR 015C +ENCODING 348 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0C00 +1A00 +1300 +0000 +1F00 +7F80 +60C0 +C0C0 +C000 +7000 +3F00 +07C0 +00C0 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 015D +ENCODING 349 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +18 +3C +66 +00 +7C +FE +C6 +E0 +FC +3E +03 +C3 +FE +7C +ENDCHAR +STARTCHAR 015E +ENCODING 350 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 -4 +BITMAP +1F00 +7F80 +60C0 +C0C0 +C000 +7000 +3F00 +07C0 +00C0 +C060 +C060 +60C0 +7FC0 +1F00 +0400 +0E00 +0200 +1C00 +ENDCHAR +STARTCHAR 015F +ENCODING 351 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 -4 +BITMAP +7C +FE +C6 +E0 +FC +3E +03 +C3 +FE +7C +10 +18 +08 +38 +ENDCHAR +STARTCHAR 0160 +ENCODING 352 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +3300 +1E00 +0C00 +0000 +1F00 +7F80 +60C0 +C0C0 +C000 +7000 +3F00 +07C0 +00C0 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 0161 +ENCODING 353 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +6C +2C +38 +00 +7C +FE +C6 +E0 +FC +3E +03 +C3 +FE +7C +ENDCHAR +STARTCHAR 0162 +ENCODING 354 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 19 0 -5 +BITMAP +FFE0 +FFE0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0000 +0600 +0600 +0200 +0400 +ENDCHAR +STARTCHAR 0163 +ENCODING 355 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 18 0 -5 +BITMAP +20 +20 +20 +F8 +F8 +20 +20 +20 +20 +20 +20 +38 +38 +00 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 0164 +ENCODING 356 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 18 0 0 +BITMAP +1900 +0F00 +0600 +0000 +FFE0 +FFE0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0165 +ENCODING 357 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 14 0 0 +BITMAP +06 +26 +22 +22 +F8 +F8 +20 +20 +20 +20 +20 +20 +38 +38 +ENDCHAR +STARTCHAR 0166 +ENCODING 358 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 0 0 +BITMAP +FFE0 +FFE0 +0600 +0600 +0600 +0600 +0600 +3FC0 +3FC0 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0167 +ENCODING 359 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 13 0 0 +BITMAP +20 +60 +60 +F8 +F8 +60 +60 +F8 +F8 +60 +60 +78 +38 +ENDCHAR +STARTCHAR 0168 +ENCODING 360 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0C80 +1F80 +1300 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 0169 +ENCODING 361 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +32 +7E +6E +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 016A +ENCODING 362 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 16 1 0 +BITMAP +1F80 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 016B +ENCODING 363 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 12 1 0 +BITMAP +7E +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 016C +ENCODING 364 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +1180 +0900 +0E00 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 016D +ENCODING 365 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +22 +26 +1C +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 016E +ENCODING 366 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0600 +0A00 +0900 +0A00 +C660 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 016F +ENCODING 367 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 16 1 0 +BITMAP +18 +24 +24 +24 +18 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 0170 +ENCODING 368 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0CC0 +0D80 +1900 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 0171 +ENCODING 369 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +36 +36 +64 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 0172 +ENCODING 370 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 -4 +BITMAP +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +0400 +0400 +0400 +0380 +ENDCHAR +STARTCHAR 0173 +ENCODING 371 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 -4 +BITMAP +C100 +C100 +C100 +C100 +C100 +C100 +C300 +C300 +7F00 +3D00 +0100 +0300 +0300 +01C0 +ENDCHAR +STARTCHAR 0174 +ENCODING 372 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 18 0 0 +BITMAP +00C000 +01E000 +033000 +000000 +C0C0C0 +40C080 +61E180 +61E180 +612180 +233100 +333300 +323300 +321200 +161A00 +161E00 +1C0E00 +1C0C00 +0C0C00 +ENDCHAR +STARTCHAR 0175 +ENCODING 373 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 14 0 0 +BITMAP +0300 +0780 +0CC0 +0000 +C308 +4308 +4718 +6798 +6590 +24B0 +3CB0 +3CE0 +18E0 +1860 +ENDCHAR +STARTCHAR 0176 +ENCODING 374 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +0700 +0500 +0D80 +0000 +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0177 +ENCODING 375 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 18 1 -4 +BITMAP +18 +3C +26 +00 +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 0178 +ENCODING 376 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 17 0 0 +BITMAP +0980 +0980 +0000 +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0179 +ENCODING 377 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 18 0 0 +BITMAP +0600 +0600 +0400 +0000 +7FE0 +7FE0 +00C0 +01C0 +0180 +0300 +0600 +0C00 +1C00 +3800 +3000 +6000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 017A +ENCODING 378 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 0 0 +BITMAP +0600 +0C00 +0800 +0000 +7F80 +7F80 +0300 +0600 +0C00 +1800 +3000 +6000 +FF80 +FF80 +ENDCHAR +STARTCHAR 017B +ENCODING 379 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 17 0 0 +BITMAP +0600 +0600 +0000 +7FE0 +7FE0 +00C0 +01C0 +0180 +0300 +0600 +0C00 +1C00 +3800 +3000 +6000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 017C +ENCODING 380 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 13 0 0 +BITMAP +0C00 +0C00 +0000 +7F80 +7F80 +0300 +0600 +0C00 +1800 +3000 +6000 +FF80 +FF80 +ENDCHAR +STARTCHAR 017D +ENCODING 381 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 18 0 0 +BITMAP +1900 +0F00 +0600 +0000 +7FE0 +7FE0 +00C0 +01C0 +0180 +0300 +0600 +0C00 +1C00 +3800 +3000 +6000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 017E +ENCODING 382 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 0 0 +BITMAP +3300 +1E00 +0C00 +0000 +7F80 +7F80 +0300 +0600 +0C00 +1800 +3000 +6000 +FF80 +FF80 +ENDCHAR +STARTCHAR 017F +ENCODING 383 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 5 14 1 0 +BITMAP +78 +F0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 018F +ENCODING 399 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F80 +3FC0 +70E0 +6030 +6030 +0030 +FFF0 +FFF0 +C010 +C030 +6030 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 0192 +ENCODING 402 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 18 0 -4 +BITMAP +03C0 +03C0 +0200 +0600 +1F80 +1F80 +0600 +0400 +0400 +0C00 +0C00 +0C00 +0800 +0800 +1800 +1800 +7800 +F000 +ENDCHAR +STARTCHAR 01A0 +ENCODING 416 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 1 0 +BITMAP +0F86 +3FE6 +7072 +6034 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 01A1 +ENCODING 417 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 10 1 0 +BITMAP +3C60 +7F60 +C320 +C1C0 +81C0 +8180 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 01AF +ENCODING 431 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 14 1 0 +BITMAP +C064 +C064 +C064 +C064 +C078 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 01B0 +ENCODING 432 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 10 1 0 +BITMAP +C160 +C160 +C120 +C120 +C1C0 +C100 +C300 +C300 +7D00 +3900 +ENDCHAR +STARTCHAR 01CD +ENCODING 461 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0980 +0F00 +0600 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 01CE +ENCODING 462 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3600 +1400 +1C00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 01CF +ENCODING 463 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 18 0 0 +BITMAP +D8 +58 +70 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 01D0 +ENCODING 464 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 5 14 0 0 +BITMAP +98 +F0 +60 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 01D1 +ENCODING 465 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0D80 +0500 +0700 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 01D2 +ENCODING 466 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +2600 +3400 +1800 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 01D3 +ENCODING 467 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +1980 +0F00 +0600 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 01D4 +ENCODING 468 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +36 +34 +1C +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 01D5 +ENCODING 469 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0F00 +0000 +0900 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 01D6 +ENCODING 470 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 15 1 0 +BITMAP +7E +00 +26 +26 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 01D7 +ENCODING 471 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0300 +0600 +0900 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 01D8 +ENCODING 472 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 17 1 0 +BITMAP +0C +0C +18 +00 +26 +26 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 01D9 +ENCODING 473 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0F00 +0600 +0900 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 01DA +ENCODING 474 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 17 1 0 +BITMAP +36 +34 +1C +00 +26 +26 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 01DB +ENCODING 475 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0C00 +0600 +0900 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 01DC +ENCODING 476 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 17 1 0 +BITMAP +30 +18 +08 +00 +26 +26 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 01FA +ENCODING 506 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 20 0 0 +BITMAP +0300 +0300 +0600 +0900 +0900 +0900 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 01FB +ENCODING 507 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 20 1 0 +BITMAP +0600 +0C00 +0800 +0000 +1800 +2400 +2400 +2400 +1800 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 01FC +ENCODING 508 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 18 18 0 0 +BITMAP +006000 +006000 +00C000 +000000 +03FFC0 +03FFC0 +066000 +066000 +0C6000 +0C6000 +087F80 +187F80 +1FE000 +3FE000 +306000 +606000 +607FC0 +C07FC0 +ENDCHAR +STARTCHAR 01FD +ENCODING 509 +SWIDTH 874 0 +DWIDTH 17 0 +BBX 15 14 1 0 +BITMAP +00C0 +0180 +0100 +0000 +3E78 +7FFC +C386 +0F06 +7FFE +F3FE +8300 +C786 +FFFC +7878 +ENDCHAR +STARTCHAR 01FE +ENCODING 510 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 19 1 -1 +BITMAP +0300 +0300 +0200 +0000 +0F88 +3FD0 +7060 +6070 +C0D0 +C198 +C318 +C618 +CC18 +D818 +7030 +7070 +7FE0 +DF80 +8000 +ENDCHAR +STARTCHAR 01FF +ENCODING 511 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 9 15 1 -1 +BITMAP +0600 +0400 +0C00 +0080 +1E80 +7F00 +6380 +C680 +C480 +C880 +D180 +7380 +7F00 +5E00 +8000 +ENDCHAR +STARTCHAR 0259 +ENCODING 601 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3E00 +FF00 +C300 +0180 +FF80 +FF80 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 02C6 +ENCODING 710 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 3 1 11 +BITMAP +60 +F0 +98 +ENDCHAR +STARTCHAR 02C7 +ENCODING 711 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 3 1 11 +BITMAP +D8 +D0 +70 +ENDCHAR +STARTCHAR 02C9 +ENCODING 713 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 1 0 11 +BITMAP +FC +ENDCHAR +STARTCHAR 02D8 +ENCODING 728 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 3 0 11 +BITMAP +C4 +4C +38 +ENDCHAR +STARTCHAR 02D9 +ENCODING 729 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 2 2 11 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR 02DA +ENCODING 730 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 5 1 9 +BITMAP +60 +90 +90 +90 +60 +ENDCHAR +STARTCHAR 02DB +ENCODING 731 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 4 2 -4 +BITMAP +80 +80 +80 +F0 +ENDCHAR +STARTCHAR 02DC +ENCODING 732 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 3 0 11 +BITMAP +64 +FC +9C +ENDCHAR +STARTCHAR 02DD +ENCODING 733 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 3 1 11 +BITMAP +EC +D8 +90 +ENDCHAR +STARTCHAR 0300 +ENCODING 768 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -5 15 +BITMAP +C0 +60 +20 +ENDCHAR +STARTCHAR 0301 +ENCODING 769 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -3 15 +BITMAP +60 +C0 +80 +ENDCHAR +STARTCHAR 0303 +ENCODING 771 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -8 15 +BITMAP +EC +98 +ENDCHAR +STARTCHAR 0309 +ENCODING 777 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -4 15 +BITMAP +E0 +30 +60 +ENDCHAR +STARTCHAR 0323 +ENCODING 803 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -7 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR 037E +ENCODING 894 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 13 2 -3 +BITMAP +C0 +C0 +00 +00 +00 +00 +00 +00 +C0 +C0 +40 +80 +80 +ENDCHAR +STARTCHAR 0384 +ENCODING 900 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 3 3 2 11 +BITMAP +60 +40 +C0 +ENDCHAR +STARTCHAR 0385 +ENCODING 901 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 7 3 0 11 +BITMAP +18 +96 +A6 +ENDCHAR +STARTCHAR 0386 +ENCODING 902 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 14 0 0 +BITMAP +3600 +6700 +4F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 0387 +ENCODING 903 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 2 2 8 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR 0388 +ENCODING 904 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 14 -1 0 +BITMAP +67FE +67FE +C600 +0600 +0600 +0600 +07FC +07FC +0600 +0600 +0600 +0600 +07FE +07FE +ENDCHAR +STARTCHAR 0389 +ENCODING 905 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 -1 0 +BITMAP +6C06 +6C06 +CC06 +0C06 +0C06 +0C06 +0FFE +0FFE +0C06 +0C06 +0C06 +0C06 +0C06 +0C06 +ENDCHAR +STARTCHAR 038A +ENCODING 906 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 6 14 -1 0 +BITMAP +6C +6C +CC +0C +0C +0C +0C +0C +0C +0C +0C +0C +0C +0C +ENDCHAR +STARTCHAR 038C +ENCODING 908 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 14 -1 0 +BITMAP +63E0 +6FF8 +DC18 +180C +300C +3006 +3006 +3006 +3006 +300C +180C +1C18 +0FF8 +03E0 +ENDCHAR +STARTCHAR 038E +ENCODING 910 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 17 14 -1 0 +BITMAP +660180 +630300 +C30600 +018600 +018C00 +00D800 +007800 +007000 +003000 +003000 +003000 +003000 +003000 +003000 +ENDCHAR +STARTCHAR 038F +ENCODING 911 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 14 14 -1 0 +BITMAP +63E0 +6FF0 +DC38 +181C +300C +300C +300C +300C +300C +180C +0818 +0C30 +3E7C +3E7C +ENDCHAR +STARTCHAR 0390 +ENCODING 912 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 6 15 -1 0 +BITMAP +18 +94 +A4 +00 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 0391 +ENCODING 913 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 14 0 0 +BITMAP +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 0392 +ENCODING 914 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FF00 +FF80 +C0C0 +C0C0 +C0C0 +C0C0 +FF80 +FF80 +C0C0 +C060 +C060 +C0C0 +FFC0 +FF80 +ENDCHAR +STARTCHAR 0393 +ENCODING 915 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 2 0 +BITMAP +FF +FF +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR 0394 +ENCODING 916 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 14 0 0 +BITMAP +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3060 +2060 +6060 +6030 +7FF0 +FFF8 +ENDCHAR +STARTCHAR 0395 +ENCODING 917 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0396 +ENCODING 918 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 0 0 +BITMAP +7FE0 +7FE0 +00C0 +01C0 +0180 +0300 +0600 +0C00 +1C00 +3800 +3000 +6000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0397 +ENCODING 919 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 10 14 2 0 +BITMAP +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +FFC0 +FFC0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +ENDCHAR +STARTCHAR 0398 +ENCODING 920 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0F80 +3FE0 +7070 +6030 +C018 +C018 +CF98 +CF98 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 0399 +ENCODING 921 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 14 2 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 039A +ENCODING 922 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +C0E0 +C1C0 +C380 +C700 +CE00 +DC00 +FC00 +F600 +E700 +C300 +C180 +C0C0 +C0E0 +C060 +ENDCHAR +STARTCHAR 039B +ENCODING 923 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 14 0 0 +BITMAP +0600 +0700 +0F00 +0D80 +0980 +1880 +18C0 +10C0 +3040 +3060 +6060 +6030 +4030 +C030 +ENDCHAR +STARTCHAR 039C +ENCODING 924 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 13 14 1 0 +BITMAP +E018 +F038 +F028 +D028 +D868 +D868 +C848 +CCC8 +CCC8 +C488 +C788 +C788 +C308 +C308 +ENDCHAR +STARTCHAR 039D +ENCODING 925 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 1 0 +BITMAP +E060 +E060 +F060 +D860 +D860 +CC60 +CC60 +C660 +C360 +C360 +C1E0 +C0E0 +C0E0 +C060 +ENDCHAR +STARTCHAR 039E +ENCODING 926 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +FFC0 +FFC0 +0000 +0000 +0000 +0000 +7F80 +7F80 +0000 +0000 +0000 +0000 +FFC0 +FFC0 +ENDCHAR +STARTCHAR 039F +ENCODING 927 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 03A0 +ENCODING 928 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 10 14 2 0 +BITMAP +FFC0 +FFC0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +ENDCHAR +STARTCHAR 03A1 +ENCODING 929 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FF80 +FFC0 +C0E0 +C060 +C060 +C060 +C0C0 +FFC0 +FF80 +C000 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 03A3 +ENCODING 931 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +FFC0 +FFC0 +6000 +3000 +1800 +0C00 +0600 +0C00 +1800 +3800 +7000 +6000 +FFC0 +FFC0 +ENDCHAR +STARTCHAR 03A4 +ENCODING 932 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 0 0 +BITMAP +FFE0 +FFE0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 03A5 +ENCODING 933 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 14 0 0 +BITMAP +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 03A6 +ENCODING 934 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0200 +0200 +1FC0 +7FF0 +E238 +C218 +C218 +C218 +C218 +E238 +7FF0 +1FC0 +0200 +0200 +ENDCHAR +STARTCHAR 03A7 +ENCODING 935 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 14 0 0 +BITMAP +6030 +3060 +30C0 +18C0 +0D80 +0F00 +0700 +0700 +0D80 +1980 +18C0 +3060 +6070 +E030 +ENDCHAR +STARTCHAR 03A8 +ENCODING 936 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 14 1 0 +BITMAP +C30C +C30C +C30C +C30C +C30C +C30C +E318 +7338 +3FF0 +1FE0 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 03A9 +ENCODING 937 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F80 +3FC0 +70E0 +6070 +C030 +C030 +C030 +C030 +C030 +4020 +6060 +30C0 +F9F0 +F9F0 +ENDCHAR +STARTCHAR 03AA +ENCODING 938 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 17 0 0 +BITMAP +D8 +D8 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 03AB +ENCODING 939 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 17 0 0 +BITMAP +0980 +0980 +0000 +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 03AC +ENCODING 940 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +3D80 +7F80 +C380 +C300 +C100 +C100 +C300 +C380 +7F80 +3D80 +ENDCHAR +STARTCHAR 03AD +ENCODING 941 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 14 1 0 +BITMAP +18 +18 +10 +00 +78 +7C +C4 +C0 +70 +70 +C0 +C4 +FE +78 +ENDCHAR +STARTCHAR 03AE +ENCODING 942 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 18 1 -4 +BITMAP +0C +0C +08 +00 +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +01 +01 +01 +01 +ENDCHAR +STARTCHAR 03AF +ENCODING 943 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 14 1 0 +BITMAP +60 +40 +C0 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 03B0 +ENCODING 944 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +0C +4B +53 +00 +C3 +C3 +C3 +C3 +C3 +C3 +C3 +E3 +7E +3C +ENDCHAR +STARTCHAR 03B1 +ENCODING 945 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3D80 +7F80 +C380 +C300 +C100 +C100 +C300 +C380 +7F80 +3D80 +ENDCHAR +STARTCHAR 03B2 +ENCODING 946 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 -4 +BITMAP +3E00 +7F00 +6300 +C100 +C300 +DC00 +DF00 +C380 +C180 +C180 +C180 +E380 +FF00 +DE00 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 03B3 +ENCODING 947 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 0 -4 +BITMAP +C180 +6180 +6100 +2300 +3300 +3200 +1600 +1E00 +1C00 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 03B4 +ENCODING 948 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +7F00 +7F00 +3000 +1800 +3E00 +7F00 +E300 +C180 +8180 +8180 +C180 +E300 +7F00 +3C00 +ENDCHAR +STARTCHAR 03B5 +ENCODING 949 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 10 1 0 +BITMAP +78 +7C +C4 +C0 +70 +70 +C0 +C4 +FE +78 +ENDCHAR +STARTCHAR 03B6 +ENCODING 950 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 18 1 -4 +BITMAP +7E +7E +0C +18 +30 +60 +40 +C0 +C0 +80 +80 +C0 +FC +7E +06 +06 +0C +0C +ENDCHAR +STARTCHAR 03B7 +ENCODING 951 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +01 +01 +01 +01 +ENDCHAR +STARTCHAR 03B8 +ENCODING 952 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3C00 +7E00 +6300 +C100 +C180 +C180 +FF80 +FF80 +C180 +C180 +C100 +6300 +7E00 +3C00 +ENDCHAR +STARTCHAR 03B9 +ENCODING 953 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 10 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 03BA +ENCODING 954 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +C7 +CE +D8 +F0 +F0 +D8 +CC +CC +C6 +C3 +ENDCHAR +STARTCHAR 03BB +ENCODING 955 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 0 0 +BITMAP +1000 +1800 +1800 +0800 +0C00 +1C00 +1E00 +1600 +3600 +3300 +6300 +6100 +6180 +C180 +ENDCHAR +STARTCHAR 03BC +ENCODING 956 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +C1 +C1 +C1 +C1 +C1 +C1 +C1 +E3 +FF +DD +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 03BD +ENCODING 957 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 0 0 +BITMAP +C180 +6180 +6100 +2300 +3300 +3200 +1600 +1C00 +1C00 +0C00 +ENDCHAR +STARTCHAR 03BE +ENCODING 958 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 18 1 -4 +BITMAP +3C +7C +C0 +C0 +40 +7C +1C +60 +C0 +C0 +C0 +C0 +7C +3E +06 +06 +0E +0C +ENDCHAR +STARTCHAR 03BF +ENCODING 959 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 03C0 +ENCODING 960 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 10 0 0 +BITMAP +FFF8 +FFF8 +1840 +1840 +1840 +1840 +1840 +1840 +1840 +1840 +ENDCHAR +STARTCHAR 03C1 +ENCODING 961 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 -4 +BITMAP +3E00 +7F00 +6380 +C180 +C180 +C180 +C180 +E380 +FF00 +DE00 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 03C2 +ENCODING 962 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 14 1 -4 +BITMAP +1F +3F +60 +C0 +C0 +80 +C0 +E0 +7C +3E +03 +02 +1E +1C +ENDCHAR +STARTCHAR 03C3 +ENCODING 963 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 10 10 1 0 +BITMAP +3FC0 +7FC0 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 03C4 +ENCODING 964 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 10 0 0 +BITMAP +FE +FE +18 +18 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 03C5 +ENCODING 965 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +C3 +C3 +C3 +C3 +C3 +C3 +C3 +E3 +7E +3C +ENDCHAR +STARTCHAR 03C6 +ENCODING 966 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 1 -4 +BITMAP +3780 +6FC0 +CCC0 +CC60 +8C60 +8C60 +CCC0 +EDC0 +7F80 +3F00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 03C7 +ENCODING 967 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 14 0 -4 +BITMAP +6080 +6180 +3300 +3300 +1E00 +1E00 +0C00 +0C00 +1E00 +1600 +3300 +2100 +6180 +C0C0 +ENDCHAR +STARTCHAR 03C8 +ENCODING 968 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 1 -4 +BITMAP +C620 +C620 +C620 +C620 +C620 +C620 +C620 +C660 +66C0 +3F80 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 03C9 +ENCODING 969 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 10 1 0 +BITMAP +6030 +4010 +C218 +C218 +C218 +C218 +C618 +C538 +7DF0 +38E0 +ENDCHAR +STARTCHAR 03CA +ENCODING 970 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 5 13 0 0 +BITMAP +98 +98 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 03CB +ENCODING 971 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 13 1 0 +BITMAP +36 +36 +00 +C3 +C3 +C3 +C3 +C3 +C3 +C3 +E3 +7E +3C +ENDCHAR +STARTCHAR 03CC +ENCODING 972 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 03CD +ENCODING 973 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +0C +0C +18 +00 +C3 +C3 +C3 +C3 +C3 +C3 +C3 +E3 +7E +3C +ENDCHAR +STARTCHAR 03CE +ENCODING 974 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0180 +0300 +0200 +0000 +6030 +4010 +C218 +C218 +C218 +C218 +C618 +C538 +7DF0 +38E0 +ENDCHAR +STARTCHAR 0401 +ENCODING 1025 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 17 1 0 +BITMAP +1B00 +1B00 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0402 +ENCODING 1026 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 16 14 0 0 +BITMAP +FFE0 +FFE0 +0600 +0600 +0600 +06F8 +07FE +0706 +0603 +0603 +0603 +0646 +067E +063C +ENDCHAR +STARTCHAR 0403 +ENCODING 1027 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 18 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +FF80 +FF80 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 0404 +ENCODING 1028 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F80 +3FC0 +70E0 +6070 +C020 +C000 +FE00 +FE00 +C000 +C000 +6030 +7060 +3FE0 +0F80 +ENDCHAR +STARTCHAR 0405 +ENCODING 1029 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +1F00 +7F80 +60C0 +C0C0 +C000 +7000 +3F00 +07C0 +00C0 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 0406 +ENCODING 1030 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 14 2 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0407 +ENCODING 1031 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 17 0 0 +BITMAP +D8 +D8 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 0408 +ENCODING 1032 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 14 1 0 +BITMAP +06 +06 +06 +06 +06 +06 +06 +06 +06 +06 +86 +C6 +FC +78 +ENDCHAR +STARTCHAR 0409 +ENCODING 1033 +SWIDTH 1028 0 +DWIDTH 20 0 +BBX 19 14 0 0 +BITMAP +3FE000 +3FE000 +306000 +306000 +306000 +306000 +307F80 +307FE0 +306060 +306060 +306060 +B06060 +F07FE0 +607F80 +ENDCHAR +STARTCHAR 040A +ENCODING 1034 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 16 14 2 0 +BITMAP +8300 +8300 +8300 +8300 +8300 +8300 +FFFE +FFFF +8303 +8301 +8301 +8303 +83FF +83FE +ENDCHAR +STARTCHAR 040B +ENCODING 1035 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 0 0 +BITMAP +FFE0 +FFE0 +0600 +0600 +0600 +06F8 +07FC +0706 +0606 +0602 +0602 +0602 +0602 +0602 +ENDCHAR +STARTCHAR 040C +ENCODING 1036 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 18 1 0 +BITMAP +0600 +0C00 +0C00 +0000 +C1C0 +C3C0 +C300 +C600 +C600 +CC00 +F800 +CC00 +C600 +C600 +C300 +C380 +C180 +C1C0 +ENDCHAR +STARTCHAR 040E +ENCODING 1038 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 18 0 0 +BITMAP +0880 +0880 +0700 +0000 +C030 +6020 +6060 +3040 +10C0 +1880 +0980 +0D00 +0700 +0600 +0600 +0600 +3C00 +3800 +ENDCHAR +STARTCHAR 040F +ENCODING 1039 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 -4 +BITMAP +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +FFE0 +FFE0 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0410 +ENCODING 1040 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 14 0 0 +BITMAP +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 0411 +ENCODING 1041 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 10 14 2 0 +BITMAP +FF00 +FF00 +8000 +8000 +8000 +8000 +FF00 +FF80 +81C0 +80C0 +80C0 +81C0 +FF80 +FF00 +ENDCHAR +STARTCHAR 0412 +ENCODING 1042 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FF00 +FF80 +C0C0 +C0C0 +C0C0 +C0C0 +FF80 +FF80 +C0C0 +C060 +C060 +C0C0 +FFC0 +FF80 +ENDCHAR +STARTCHAR 0413 +ENCODING 1043 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 1 0 +BITMAP +FF80 +FF80 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 0414 +ENCODING 1044 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 17 0 -3 +BITMAP +1FE0 +1FE0 +1060 +1060 +1060 +1060 +1060 +3060 +3060 +3060 +2060 +6060 +FFF0 +FFF0 +C010 +C010 +C010 +ENDCHAR +STARTCHAR 0415 +ENCODING 1045 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0416 +ENCODING 1046 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 17 14 0 0 +BITMAP +E0C180 +F0C380 +30C600 +18C600 +18CC00 +0CDC00 +07F000 +0CDC00 +18CC00 +18C600 +30C700 +70C300 +60C380 +E0C180 +ENDCHAR +STARTCHAR 0417 +ENCODING 1047 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 0 +BITMAP +3E00 +7F00 +E380 +C180 +0180 +0380 +0F00 +0F80 +0180 +00C0 +C0C0 +E180 +7F80 +3E00 +ENDCHAR +STARTCHAR 0418 +ENCODING 1048 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 1 0 +BITMAP +C060 +C0E0 +C0E0 +C1A0 +C3A0 +C320 +C620 +CE20 +CC20 +D820 +D820 +F020 +E020 +E020 +ENDCHAR +STARTCHAR 0419 +ENCODING 1049 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +1100 +1900 +0E00 +0000 +C060 +C0E0 +C0E0 +C1A0 +C3A0 +C320 +C620 +CE20 +CC20 +D820 +D820 +F020 +E020 +E020 +ENDCHAR +STARTCHAR 041A +ENCODING 1050 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 0 +BITMAP +C1C0 +C3C0 +C300 +C600 +C600 +CC00 +F800 +CC00 +C600 +C600 +C300 +C380 +C180 +C1C0 +ENDCHAR +STARTCHAR 041B +ENCODING 1051 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 0 0 +BITMAP +3FE0 +3FE0 +3060 +3060 +3060 +3060 +3060 +3060 +3060 +3060 +3060 +B060 +F060 +6060 +ENDCHAR +STARTCHAR 041C +ENCODING 1052 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 13 14 1 0 +BITMAP +E018 +F038 +F028 +D028 +D868 +D868 +C848 +CCC8 +CCC8 +C488 +C788 +C788 +C308 +C308 +ENDCHAR +STARTCHAR 041D +ENCODING 1053 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 10 14 2 0 +BITMAP +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +FFC0 +FFC0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +ENDCHAR +STARTCHAR 041E +ENCODING 1054 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 041F +ENCODING 1055 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 1 0 +BITMAP +FFE0 +FFE0 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +ENDCHAR +STARTCHAR 0420 +ENCODING 1056 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FF80 +FFC0 +C0E0 +C060 +C060 +C060 +C0C0 +FFC0 +FF80 +C000 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 0421 +ENCODING 1057 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F80 +3FC0 +70E0 +6070 +C000 +C000 +C000 +C000 +C000 +C030 +6070 +70E0 +3FC0 +0F80 +ENDCHAR +STARTCHAR 0422 +ENCODING 1058 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 0 0 +BITMAP +FFE0 +FFE0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0423 +ENCODING 1059 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 14 0 0 +BITMAP +C030 +6020 +6060 +3040 +10C0 +1880 +0980 +0D00 +0700 +0600 +0600 +0600 +3C00 +3800 +ENDCHAR +STARTCHAR 0424 +ENCODING 1060 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 14 1 0 +BITMAP +0600 +0600 +1FC0 +7FE0 +E670 +C630 +C618 +C618 +C630 +E670 +7FE0 +1FC0 +0600 +0600 +ENDCHAR +STARTCHAR 0425 +ENCODING 1061 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 14 0 0 +BITMAP +6030 +3060 +30C0 +18C0 +0D80 +0F00 +0700 +0700 +0D80 +1980 +18C0 +3060 +6070 +E030 +ENDCHAR +STARTCHAR 0426 +ENCODING 1062 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 -4 +BITMAP +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +FFF0 +FFF0 +0010 +0010 +0010 +0010 +ENDCHAR +STARTCHAR 0427 +ENCODING 1063 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 10 14 1 0 +BITMAP +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E1C0 +7FC0 +3EC0 +00C0 +00C0 +00C0 +00C0 +ENDCHAR +STARTCHAR 0428 +ENCODING 1064 +SWIDTH 874 0 +DWIDTH 17 0 +BBX 15 14 1 0 +BITMAP +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +FFFE +FFFE +ENDCHAR +STARTCHAR 0429 +ENCODING 1065 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 16 18 1 -4 +BITMAP +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +FFFF +FFFF +0001 +0001 +0001 +0001 +ENDCHAR +STARTCHAR 042A +ENCODING 1066 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 14 14 0 0 +BITMAP +FC00 +FC00 +0C00 +0C00 +0C00 +0C00 +0FF0 +0FFC +0C0C +0C0C +0C0C +0C0C +0FFC +0FF0 +ENDCHAR +STARTCHAR 042B +ENCODING 1067 +SWIDTH 874 0 +DWIDTH 17 0 +BBX 13 14 2 0 +BITMAP +8018 +8018 +8018 +8018 +8018 +8018 +FF18 +FF98 +81D8 +80D8 +80D8 +81D8 +FF98 +FF18 +ENDCHAR +STARTCHAR 042C +ENCODING 1068 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 10 14 2 0 +BITMAP +8000 +8000 +8000 +8000 +8000 +8000 +FF00 +FF80 +81C0 +80C0 +80C0 +8180 +FF80 +FF00 +ENDCHAR +STARTCHAR 042D +ENCODING 1069 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +1F00 +7FC0 +60C0 +C060 +4060 +0030 +07F0 +07F0 +0030 +0020 +C060 +E0E0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 042E +ENCODING 1070 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 16 14 2 0 +BITMAP +80F8 +83FC +870E +8607 +8C03 +8C03 +FC03 +FC03 +8C03 +8C03 +8607 +870E +83FC +80F8 +ENDCHAR +STARTCHAR 042F +ENCODING 1071 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 1 0 +BITMAP +3FE0 +7FE0 +6060 +C060 +C060 +6060 +7FE0 +3FE0 +1C60 +3860 +3060 +6060 +C060 +C060 +ENDCHAR +STARTCHAR 0430 +ENCODING 1072 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 0431 +ENCODING 1073 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3F80 +7F00 +E000 +C000 +9E00 +BF00 +E380 +C180 +C180 +C180 +C180 +6380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0432 +ENCODING 1074 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +FE +FF +C3 +C3 +FE +FF +C3 +C3 +FF +FE +ENDCHAR +STARTCHAR 0433 +ENCODING 1075 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 6 10 1 0 +BITMAP +FC +FC +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0434 +ENCODING 1076 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 13 0 -3 +BITMAP +1F80 +1F80 +3080 +3080 +3080 +3080 +2080 +6080 +FFE0 +FFE0 +8060 +8060 +8060 +ENDCHAR +STARTCHAR 0435 +ENCODING 1077 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0436 +ENCODING 1078 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 10 0 0 +BITMAP +E630 +E670 +3660 +16C0 +0F80 +16C0 +3660 +6620 +6630 +C610 +ENDCHAR +STARTCHAR 0437 +ENCODING 1079 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 10 1 0 +BITMAP +78 +FC +C6 +06 +3C +3C +06 +86 +FE +7C +ENDCHAR +STARTCHAR 0438 +ENCODING 1080 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 10 1 0 +BITMAP +C3 +C3 +C7 +CD +C9 +D9 +D1 +F1 +E1 +C1 +ENDCHAR +STARTCHAR 0439 +ENCODING 1081 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +22 +22 +1C +00 +C3 +C3 +C7 +CD +C9 +D9 +D1 +F1 +E1 +C1 +ENDCHAR +STARTCHAR 043A +ENCODING 1082 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 10 1 0 +BITMAP +C6 +CE +CC +D8 +F0 +D8 +CC +CC +C6 +C6 +ENDCHAR +STARTCHAR 043B +ENCODING 1083 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 10 0 0 +BITMAP +3FC0 +3FC0 +30C0 +30C0 +30C0 +30C0 +30C0 +30C0 +F0C0 +E0C0 +ENDCHAR +STARTCHAR 043C +ENCODING 1084 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 10 1 0 +BITMAP +E0E0 +E0E0 +F1E0 +D1E0 +D160 +DB60 +CA60 +CA60 +CE60 +C460 +ENDCHAR +STARTCHAR 043D +ENCODING 1085 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 10 1 0 +BITMAP +C1 +C1 +C1 +C1 +FF +FF +C1 +C1 +C1 +C1 +ENDCHAR +STARTCHAR 043E +ENCODING 1086 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 043F +ENCODING 1087 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +FF +FF +C3 +C3 +C3 +C3 +C3 +C3 +C3 +C3 +ENDCHAR +STARTCHAR 0440 +ENCODING 1088 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 -4 +BITMAP +DE00 +FF00 +E300 +C180 +C180 +C180 +C180 +E300 +FF00 +DC00 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 0441 +ENCODING 1089 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +3C +7F +E3 +C0 +80 +80 +C0 +C3 +7F +3C +ENDCHAR +STARTCHAR 0442 +ENCODING 1090 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 10 0 0 +BITMAP +FF +FF +08 +08 +08 +08 +08 +08 +08 +08 +ENDCHAR +STARTCHAR 0443 +ENCODING 1091 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 -4 +BITMAP +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 0444 +ENCODING 1092 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 18 1 -4 +BITMAP +0300 +0300 +0300 +0300 +3BF0 +7FF8 +C71C +C30C +830C +830C +C30C +C718 +7FF8 +3BF0 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 0445 +ENCODING 1093 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 0 0 +BITMAP +6180 +6300 +3600 +1E00 +0C00 +1C00 +1E00 +3300 +6300 +E180 +ENDCHAR +STARTCHAR 0446 +ENCODING 1094 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 -4 +BITMAP +C100 +C100 +C100 +C100 +C100 +C100 +C100 +C100 +FF80 +FF80 +0080 +0080 +0080 +0080 +ENDCHAR +STARTCHAR 0447 +ENCODING 1095 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +83 +83 +83 +83 +C3 +FF +7F +03 +03 +03 +ENDCHAR +STARTCHAR 0448 +ENCODING 1096 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 10 1 0 +BITMAP +C218 +C218 +C218 +C218 +C218 +C218 +C218 +C218 +FFF8 +FFF8 +ENDCHAR +STARTCHAR 0449 +ENCODING 1097 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 14 1 -4 +BITMAP +C218 +C218 +C218 +C218 +C218 +C218 +C218 +C218 +FFFC +FFFC +0004 +0004 +0004 +0004 +ENDCHAR +STARTCHAR 044A +ENCODING 1098 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 10 0 0 +BITMAP +F800 +F800 +1800 +1800 +1FC0 +1FE0 +1860 +1860 +1FE0 +1FC0 +ENDCHAR +STARTCHAR 044B +ENCODING 1099 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 10 1 0 +BITMAP +C020 +C020 +C020 +FE20 +FF20 +C320 +C120 +C320 +FF20 +FE20 +ENDCHAR +STARTCHAR 044C +ENCODING 1100 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +C0 +C0 +C0 +FE +FF +C3 +C1 +C3 +FF +FE +ENDCHAR +STARTCHAR 044D +ENCODING 1101 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +7C +FE +C7 +03 +1F +1F +03 +87 +FE +7C +ENDCHAR +STARTCHAR 044E +ENCODING 1102 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 10 1 0 +BITMAP +C3C0 +C7E0 +CE30 +CC10 +FC10 +FC10 +CC10 +CE30 +C7F0 +C3C0 +ENDCHAR +STARTCHAR 044F +ENCODING 1103 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +7F +FF +C3 +C3 +7F +1F +73 +63 +C3 +C3 +ENDCHAR +STARTCHAR 0451 +ENCODING 1105 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 0 +BITMAP +2600 +2600 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0452 +ENCODING 1106 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 0 -4 +BITMAP +6000 +FC00 +FC00 +6000 +6F00 +7F80 +7180 +6080 +6080 +6080 +6080 +6080 +6080 +6080 +0080 +0180 +0380 +0300 +ENDCHAR +STARTCHAR 0453 +ENCODING 1107 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 6 14 1 0 +BITMAP +18 +18 +30 +00 +FC +FC +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0454 +ENCODING 1108 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +3C +7F +C3 +C0 +F8 +F8 +C0 +C3 +7F +3C +ENDCHAR +STARTCHAR 0455 +ENCODING 1109 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +7C +FE +C6 +E0 +FC +3E +03 +C3 +FE +7C +ENDCHAR +STARTCHAR 0456 +ENCODING 1110 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 14 1 0 +BITMAP +C0 +C0 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0457 +ENCODING 1111 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 13 0 0 +BITMAP +C8 +C8 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 0458 +ENCODING 1112 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 18 -1 -4 +BITMAP +30 +30 +00 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +F0 +E0 +ENDCHAR +STARTCHAR 0459 +ENCODING 1113 +SWIDTH 874 0 +DWIDTH 17 0 +BBX 17 10 0 0 +BITMAP +3FC000 +3FC000 +30C000 +30FE00 +30FF00 +30C300 +30C180 +30C300 +F0FF00 +E0FE00 +ENDCHAR +STARTCHAR 045A +ENCODING 1114 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 14 10 1 0 +BITMAP +C200 +C200 +C200 +C200 +FFF0 +FFF8 +C20C +C20C +C3F8 +C3F0 +ENDCHAR +STARTCHAR 045B +ENCODING 1115 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 0 0 +BITMAP +6000 +FC00 +FC00 +6000 +6F00 +7F80 +7180 +6080 +6080 +6080 +6080 +6080 +6080 +6080 +ENDCHAR +STARTCHAR 045C +ENCODING 1116 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 14 1 0 +BITMAP +18 +18 +30 +00 +C6 +CE +CC +D8 +F0 +D8 +CC +CC +C6 +C6 +ENDCHAR +STARTCHAR 045E +ENCODING 1118 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 18 1 -4 +BITMAP +46 +64 +38 +00 +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 045F +ENCODING 1119 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +C1 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +FF +FF +08 +08 +08 +08 +ENDCHAR +STARTCHAR 0490 +ENCODING 1168 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 17 1 0 +BITMAP +03 +03 +03 +FF +FF +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0491 +ENCODING 1169 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 6 14 1 0 +BITMAP +04 +04 +04 +04 +FC +FC +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0492 +ENCODING 1170 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 14 0 0 +BITMAP +7FC0 +7FC0 +6000 +6000 +6000 +6000 +FE00 +FE00 +6000 +6000 +6000 +6000 +6000 +6000 +ENDCHAR +STARTCHAR 0493 +ENCODING 1171 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 10 0 0 +BITMAP +7E +7E +60 +F8 +F8 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 0496 +ENCODING 1174 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 17 18 0 -4 +BITMAP +E0C380 +F0C780 +38C600 +18CE00 +1CCC00 +0FF800 +07F800 +0CDC00 +18CE00 +38C600 +30C700 +70C300 +60C380 +E0C180 +000080 +000080 +000080 +000080 +ENDCHAR +STARTCHAR 0497 +ENCODING 1175 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 13 0 -3 +BITMAP +E630 +E670 +3660 +1FC0 +1FC0 +36E0 +3660 +6630 +6638 +C618 +0018 +0018 +0018 +ENDCHAR +STARTCHAR 049A +ENCODING 1178 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 18 1 -4 +BITMAP +C1C0 +C3C0 +C700 +C600 +CE00 +FC00 +FC00 +CE00 +C600 +C700 +C300 +C380 +C1C0 +C1C0 +00C0 +00C0 +00C0 +00C0 +ENDCHAR +STARTCHAR 049B +ENCODING 1179 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 13 1 -3 +BITMAP +C6 +CE +D8 +F8 +F8 +D8 +CC +CC +C6 +C6 +02 +02 +02 +ENDCHAR +STARTCHAR 049C +ENCODING 1180 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 0 +BITMAP +C1C0 +C3C0 +DF00 +DE00 +DE00 +FC00 +FC00 +DC00 +DE00 +DF00 +DB00 +DB80 +C180 +C1C0 +ENDCHAR +STARTCHAR 049D +ENCODING 1181 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 10 1 0 +BITMAP +C6 +DE +D8 +F8 +F8 +D8 +DC +DC +C6 +C6 +ENDCHAR +STARTCHAR 04A2 +ENCODING 1186 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 2 -4 +BITMAP +80C0 +80C0 +80C0 +80C0 +80C0 +FFC0 +FFC0 +80C0 +80C0 +80C0 +80C0 +80C0 +80E0 +80E0 +0020 +0020 +0020 +0020 +ENDCHAR +STARTCHAR 04A3 +ENCODING 1187 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 -3 +BITMAP +C100 +C100 +C100 +C100 +FF00 +FF00 +C100 +C100 +C180 +C180 +0080 +0080 +0080 +ENDCHAR +STARTCHAR 04AE +ENCODING 1198 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +C0C0 +60C0 +6180 +3180 +3300 +1A00 +0E00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 04AF +ENCODING 1199 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 0 -4 +BITMAP +C180 +6180 +6100 +6300 +3300 +3600 +1600 +1E00 +1C00 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 04B0 +ENCODING 1200 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +C0C0 +60C0 +2180 +3100 +1B00 +1E00 +7FC0 +7FC0 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 04B1 +ENCODING 1201 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 0 -4 +BITMAP +C180 +6180 +6100 +6300 +3300 +3600 +1600 +1E00 +1C00 +0C00 +7F80 +7F80 +0C00 +0C00 +ENDCHAR +STARTCHAR 04B2 +ENCODING 1202 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 -4 +BITMAP +6030 +3060 +38C0 +18C0 +0D80 +0F00 +0700 +0700 +0D80 +1DC0 +18C0 +3060 +6078 +E038 +0018 +0018 +0018 +0018 +ENDCHAR +STARTCHAR 04B3 +ENCODING 1203 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 13 0 -3 +BITMAP +6180 +7300 +3600 +1E00 +0C00 +1E00 +1E00 +3300 +6380 +E180 +0080 +0080 +0080 +ENDCHAR +STARTCHAR 04B8 +ENCODING 1208 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 10 14 1 0 +BITMAP +C0C0 +C0C0 +C0C0 +CCC0 +CCC0 +CCC0 +EDC0 +7FC0 +3EC0 +0CC0 +0CC0 +0CC0 +00C0 +00C0 +ENDCHAR +STARTCHAR 04B9 +ENCODING 1209 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +83 +83 +93 +D3 +FF +7F +13 +13 +03 +03 +ENDCHAR +STARTCHAR 04BA +ENCODING 1210 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +C000 +C000 +C000 +C000 +C000 +DF80 +FFC0 +E0E0 +C060 +C060 +C060 +C060 +C060 +C060 +ENDCHAR +STARTCHAR 04BB +ENCODING 1211 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +C0 +C0 +C0 +C0 +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +ENDCHAR +STARTCHAR 04D8 +ENCODING 1240 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F80 +3FC0 +70E0 +6030 +6030 +0030 +FFF0 +FFF0 +C010 +C030 +6030 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 04D9 +ENCODING 1241 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3E00 +FF00 +C300 +0180 +FF80 +FF80 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 04E8 +ENCODING 1256 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0F80 +3FE0 +7070 +6030 +C018 +C018 +FFF8 +FFF8 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 04E9 +ENCODING 1257 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3E00 +7F00 +C300 +C180 +FF80 +FF80 +8180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 05B0 +ENCODING 1456 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 3 2 -4 +BITMAP +C0 +00 +C0 +ENDCHAR +STARTCHAR 05B1 +ENCODING 1457 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 3 0 -4 +BITMAP +FC +00 +6C +ENDCHAR +STARTCHAR 05B2 +ENCODING 1458 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 3 0 -4 +BITMAP +FC +00 +0C +ENDCHAR +STARTCHAR 05B3 +ENCODING 1459 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 3 0 -4 +BITMAP +FC +60 +0C +ENDCHAR +STARTCHAR 05B4 +ENCODING 1460 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 1 2 -3 +BITMAP +C0 +ENDCHAR +STARTCHAR 05B5 +ENCODING 1461 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 1 1 -3 +BITMAP +D0 +ENDCHAR +STARTCHAR 05B6 +ENCODING 1462 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 3 1 -4 +BITMAP +D0 +00 +60 +ENDCHAR +STARTCHAR 05B7 +ENCODING 1463 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 1 1 -3 +BITMAP +F0 +ENDCHAR +STARTCHAR 05B8 +ENCODING 1464 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 3 1 -4 +BITMAP +F0 +20 +20 +ENDCHAR +STARTCHAR 05B9 +ENCODING 1465 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 1 2 11 +BITMAP +C0 +ENDCHAR +STARTCHAR 05BA +ENCODING 1466 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 1 2 11 +BITMAP +C0 +ENDCHAR +STARTCHAR 05BB +ENCODING 1467 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 3 0 -4 +BITMAP +C0 +30 +04 +ENDCHAR +STARTCHAR 05BC +ENCODING 1468 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 1 2 5 +BITMAP +C0 +ENDCHAR +STARTCHAR 05BD +ENCODING 1469 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 1 3 3 -4 +BITMAP +80 +80 +80 +ENDCHAR +STARTCHAR 05BE +ENCODING 1470 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 2 1 8 +BITMAP +F8 +F8 +ENDCHAR +STARTCHAR 05BF +ENCODING 1471 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 1 1 12 +BITMAP +F0 +ENDCHAR +STARTCHAR 05C0 +ENCODING 1472 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 1 12 2 0 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR 05C1 +ENCODING 1473 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 1 7 12 +BITMAP +C0 +ENDCHAR +STARTCHAR 05C2 +ENCODING 1474 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 1 1 -2 12 +BITMAP +80 +ENDCHAR +STARTCHAR 05C3 +ENCODING 1475 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 10 2 0 +BITMAP +C0 +C0 +00 +00 +00 +00 +00 +00 +C0 +C0 +ENDCHAR +STARTCHAR 05D0 +ENCODING 1488 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +E180 +6100 +3300 +3B00 +7F00 +4E00 +C600 +C600 +C300 +C180 +ENDCHAR +STARTCHAR 05D1 +ENCODING 1489 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 10 0 0 +BITMAP +7C00 +7E00 +0700 +0300 +0100 +0100 +0100 +0100 +FFC0 +FFC0 +ENDCHAR +STARTCHAR 05D2 +ENCODING 1490 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 10 0 0 +BITMAP +78 +7C +0C +0C +0C +1C +3C +64 +66 +C6 +ENDCHAR +STARTCHAR 05D3 +ENCODING 1491 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 0 0 +BITMAP +FF80 +FF80 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 05D4 +ENCODING 1492 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +FE00 +7F00 +0380 +0180 +C180 +C180 +C180 +C180 +C180 +C180 +ENDCHAR +STARTCHAR 05D5 +ENCODING 1493 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 10 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 05D6 +ENCODING 1494 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 6 10 1 0 +BITMAP +FC +FC +30 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 05D7 +ENCODING 1495 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +FE00 +FF00 +C380 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +ENDCHAR +STARTCHAR 05D8 +ENCODING 1496 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +C700 +CF80 +C980 +C180 +C180 +C180 +C180 +6380 +7F00 +1E00 +ENDCHAR +STARTCHAR 05D9 +ENCODING 1497 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 5 1 5 +BITMAP +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 05DA +ENCODING 1498 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 0 -4 +BITMAP +FC +FE +07 +03 +01 +01 +01 +01 +01 +01 +01 +01 +01 +01 +ENDCHAR +STARTCHAR 05DB +ENCODING 1499 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 10 1 0 +BITMAP +F0 +FC +0C +06 +06 +06 +06 +0C +FC +F0 +ENDCHAR +STARTCHAR 05DC +ENCODING 1500 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 14 1 0 +BITMAP +80 +80 +80 +80 +FE +FE +06 +06 +04 +0C +18 +18 +18 +18 +ENDCHAR +STARTCHAR 05DD +ENCODING 1501 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +FE00 +FF00 +C380 +C180 +C180 +C180 +C180 +C180 +FF80 +FF80 +ENDCHAR +STARTCHAR 05DE +ENCODING 1502 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +CE00 +DF00 +7180 +6180 +6180 +6180 +4180 +4180 +CF80 +CF80 +ENDCHAR +STARTCHAR 05DF +ENCODING 1503 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 14 1 -4 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 05E0 +ENCODING 1504 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 4 10 1 0 +BITMAP +E0 +F0 +30 +10 +10 +10 +10 +10 +F0 +F0 +ENDCHAR +STARTCHAR 05E1 +ENCODING 1505 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3E00 +7F00 +E380 +C180 +C180 +C180 +C180 +E380 +7F00 +3E00 +ENDCHAR +STARTCHAR 05E2 +ENCODING 1506 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 11 0 -1 +BITMAP +6180 +2180 +3180 +3180 +3180 +3180 +1300 +1700 +1E00 +FC00 +E000 +ENDCHAR +STARTCHAR 05E3 +ENCODING 1507 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +FC +FF +C3 +C3 +C1 +C1 +71 +01 +01 +01 +01 +01 +01 +01 +ENDCHAR +STARTCHAR 05E4 +ENCODING 1508 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 1 0 +BITMAP +FC00 +FE00 +C700 +C300 +C180 +7180 +0300 +8700 +FE00 +7C00 +ENDCHAR +STARTCHAR 05E5 +ENCODING 1509 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 14 0 -4 +BITMAP +C3 +63 +23 +33 +16 +1C +18 +18 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 05E6 +ENCODING 1510 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 10 0 0 +BITMAP +C3 +63 +33 +33 +1E +0C +04 +06 +7F +7F +ENDCHAR +STARTCHAR 05E7 +ENCODING 1511 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 -4 +BITMAP +FF +FF +01 +01 +43 +43 +46 +44 +44 +44 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 05E8 +ENCODING 1512 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 0 0 +BITMAP +FC +FE +07 +03 +01 +01 +01 +01 +01 +01 +ENDCHAR +STARTCHAR 05E9 +ENCODING 1513 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 10 1 0 +BITMAP +C460 +C460 +C460 +CC60 +CC60 +F860 +40C0 +61C0 +3F80 +1F00 +ENDCHAR +STARTCHAR 05EA +ENCODING 1514 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 10 0 0 +BITMAP +7F80 +7FC0 +18E0 +1860 +1860 +1860 +1860 +1860 +7860 +F060 +ENDCHAR +STARTCHAR 05F0 +ENCODING 1520 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 10 1 0 +BITMAP +C6 +C6 +C6 +C6 +C6 +C6 +C6 +C6 +C6 +C6 +ENDCHAR +STARTCHAR 05F1 +ENCODING 1521 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 10 1 0 +BITMAP +C6 +C6 +C6 +C6 +C6 +06 +06 +06 +06 +06 +ENDCHAR +STARTCHAR 05F2 +ENCODING 1522 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 5 1 5 +BITMAP +C6 +C6 +C6 +C6 +C6 +ENDCHAR +STARTCHAR 05F3 +ENCODING 1523 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 4 1 6 +BITMAP +40 +C0 +C0 +80 +ENDCHAR +STARTCHAR 05F4 +ENCODING 1524 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 6 4 1 6 +BITMAP +4C +C8 +C8 +98 +ENDCHAR +STARTCHAR 060C +ENCODING 1548 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 3 6 2 3 +BITMAP +40 +80 +80 +C0 +E0 +C0 +ENDCHAR +STARTCHAR 061B +ENCODING 1563 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 3 9 1 3 +BITMAP +20 +40 +80 +E0 +60 +60 +00 +60 +60 +ENDCHAR +STARTCHAR 061F +ENCODING 1567 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 11 1 3 +BITMAP +70 +C8 +98 +D8 +C0 +60 +20 +20 +00 +60 +60 +ENDCHAR +STARTCHAR 0621 +ENCODING 1569 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 6 8 1 1 +BITMAP +30 +70 +40 +CC +FC +70 +60 +40 +ENDCHAR +STARTCHAR 0622 +ENCODING 1570 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 14 0 2 +BITMAP +F0 +00 +00 +40 +60 +20 +20 +20 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR 0623 +ENCODING 1571 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 14 1 2 +BITMAP +40 +80 +C0 +80 +00 +00 +80 +C0 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 0624 +ENCODING 1572 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 16 0 -2 +BITMAP +0C +10 +0C +10 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 0625 +ENCODING 1573 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 16 0 -2 +BITMAP +40 +60 +20 +20 +20 +20 +20 +20 +20 +20 +20 +00 +60 +80 +60 +80 +ENDCHAR +STARTCHAR 0626 +ENCODING 1574 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 12 0 -1 +BITMAP +2000 +4000 +6060 +40F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +ENDCHAR +STARTCHAR 0627 +ENCODING 1575 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 11 1 3 +BITMAP +80 +C0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 0628 +ENCODING 1576 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 0629 +ENCODING 1577 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 11 0 3 +BITMAP +10 +D0 +C0 +00 +20 +30 +78 +48 +48 +78 +70 +ENDCHAR +STARTCHAR 062A +ENCODING 1578 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 9 1 3 +BITMAP +0300 +0F00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR 062B +ENCODING 1579 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 10 1 3 +BITMAP +0400 +0700 +0F00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR 062C +ENCODING 1580 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4000 +8600 +8600 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 062D +ENCODING 1581 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4000 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 062E +ENCODING 1582 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 16 0 -4 +BITMAP +0C00 +0400 +0000 +0000 +3F80 +7F80 +0C00 +3000 +4000 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 062F +ENCODING 1583 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 8 1 3 +BITMAP +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR 0630 +ENCODING 1584 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 3 +BITMAP +40 +60 +00 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR 0631 +ENCODING 1585 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 10 1 -2 +BITMAP +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR 0632 +ENCODING 1586 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +04 +04 +00 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR 0633 +ENCODING 1587 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 9 1 -1 +BITMAP +0104 +0182 +0092 +80FE +80FE +8080 +8180 +FF00 +7C00 +ENDCHAR +STARTCHAR 0634 +ENCODING 1588 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 1 -1 +BITMAP +0030 +0038 +0028 +0020 +0000 +0104 +0182 +0092 +80FE +80FE +8080 +8180 +FF00 +7C00 +ENDCHAR +STARTCHAR 0635 +ENCODING 1589 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 9 1 -1 +BITMAP +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810000 +FF0000 +7C0000 +ENDCHAR +STARTCHAR 0636 +ENCODING 1590 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 12 1 -1 +BITMAP +000800 +000800 +000000 +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810000 +FF0000 +7C0000 +ENDCHAR +STARTCHAR 0637 +ENCODING 1591 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1800 +0800 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 0638 +ENCODING 1592 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1880 +0880 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 0639 +ENCODING 1593 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 16 0 -4 +BITMAP +3800 +7C00 +6000 +8000 +8100 +6700 +7C00 +3000 +2000 +4000 +8000 +8000 +C000 +6000 +7F80 +1F00 +ENDCHAR +STARTCHAR 063A +ENCODING 1594 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 20 0 -4 +BITMAP +1000 +1000 +0000 +0000 +3800 +7C00 +6000 +8000 +8100 +6700 +7C00 +3000 +2000 +4000 +8000 +8000 +C000 +6000 +7F80 +1F00 +ENDCHAR +STARTCHAR 0640 +ENCODING 1600 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 5 2 -1 3 +BITMAP +F8 +F8 +ENDCHAR +STARTCHAR 0641 +ENCODING 1601 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 10 0 3 +BITMAP +0018 +0018 +0000 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR 0642 +ENCODING 1602 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 -1 +BITMAP +0100 +0580 +0400 +0000 +0000 +0180 +03C0 +02C0 +83C0 +83C0 +8040 +80C0 +FF80 +7F00 +ENDCHAR +STARTCHAR 0643 +ENCODING 1603 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 12 0 3 +BITMAP +0040 +0060 +0060 +0240 +0420 +0720 +0120 +0120 +9E20 +C020 +7FE0 +7FE0 +ENDCHAR +STARTCHAR 0644 +ENCODING 1604 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 15 1 0 +BITMAP +0200 +0300 +0100 +0100 +0100 +0100 +0100 +0100 +8100 +8080 +8080 +8080 +8300 +FF00 +7E00 +ENDCHAR +STARTCHAR 0645 +ENCODING 1605 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 11 0 -4 +BITMAP +38 +3C +0C +3C +7C +C0 +80 +80 +40 +40 +40 +ENDCHAR +STARTCHAR 0646 +ENCODING 1606 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 12 1 -1 +BITMAP +0800 +0800 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR 0647 +ENCODING 1607 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 7 1 3 +BITMAP +40 +E0 +F0 +90 +90 +F0 +E0 +ENDCHAR +STARTCHAR 0648 +ENCODING 1608 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 11 0 -2 +BITMAP +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 0649 +ENCODING 1609 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 10 0 -1 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +ENDCHAR +STARTCHAR 064A +ENCODING 1610 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 13 0 -4 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +0300 +0B00 +0800 +ENDCHAR +STARTCHAR 064B +ENCODING 1611 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 4 1 12 +BITMAP +60 +80 +60 +80 +ENDCHAR +STARTCHAR 064C +ENCODING 1612 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 3 5 1 12 +BITMAP +20 +60 +A0 +E0 +C0 +ENDCHAR +STARTCHAR 064D +ENCODING 1613 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 4 1 -3 +BITMAP +60 +80 +60 +80 +ENDCHAR +STARTCHAR 064E +ENCODING 1614 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 2 1 12 +BITMAP +60 +80 +ENDCHAR +STARTCHAR 064F +ENCODING 1615 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 5 1 12 +BITMAP +60 +60 +60 +60 +80 +ENDCHAR +STARTCHAR 0650 +ENCODING 1616 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 2 1 0 +BITMAP +60 +80 +ENDCHAR +STARTCHAR 0651 +ENCODING 1617 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 3 1 12 +BITMAP +40 +60 +80 +ENDCHAR +STARTCHAR 0652 +ENCODING 1618 +SWIDTH 154 0 +DWIDTH 3 0 +BBX 2 3 1 12 +BITMAP +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0653 +ENCODING 1619 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 2 0 13 +BITMAP +C0 +70 +ENDCHAR +STARTCHAR 0654 +ENCODING 1620 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 4 1 13 +BITMAP +40 +80 +C0 +80 +ENDCHAR +STARTCHAR 0655 +ENCODING 1621 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 4 1 -3 +BITMAP +40 +80 +C0 +80 +ENDCHAR +STARTCHAR 0660 +ENCODING 1632 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 3 4 4 4 +BITMAP +80 +E0 +C0 +40 +ENDCHAR +STARTCHAR 0661 +ENCODING 1633 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 3 10 3 3 +BITMAP +80 +C0 +C0 +60 +60 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR 0662 +ENCODING 1634 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 5 11 2 3 +BITMAP +80 +C8 +F8 +78 +60 +20 +30 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 0663 +ENCODING 1635 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 4 +BITMAP +CD +7F +76 +20 +20 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 0664 +ENCODING 1636 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 4 11 3 3 +BITMAP +10 +20 +40 +80 +F0 +60 +40 +40 +C0 +F0 +70 +ENDCHAR +STARTCHAR 0665 +ENCODING 1637 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 6 8 2 5 +BITMAP +30 +78 +9C +84 +84 +84 +F8 +F0 +ENDCHAR +STARTCHAR 0666 +ENCODING 1638 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 6 11 2 3 +BITMAP +80 +F0 +F0 +10 +10 +10 +10 +18 +08 +0C +04 +ENDCHAR +STARTCHAR 0667 +ENCODING 1639 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 3 +BITMAP +81 +C1 +C3 +62 +24 +24 +18 +18 +18 +08 +ENDCHAR +STARTCHAR 0668 +ENCODING 1640 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 4 +BITMAP +10 +18 +28 +28 +24 +26 +46 +C3 +81 +81 +ENDCHAR +STARTCHAR 0669 +ENCODING 1641 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 6 11 2 3 +BITMAP +30 +70 +98 +88 +F8 +78 +08 +08 +08 +0C +08 +ENDCHAR +STARTCHAR 066A +ENCODING 1642 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 13 1 2 +BITMAP +63 +62 +06 +04 +0C +08 +18 +10 +30 +20 +60 +46 +C6 +ENDCHAR +STARTCHAR 066B +ENCODING 1643 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 5 2 1 +BITMAP +C0 +C0 +C0 +40 +80 +ENDCHAR +STARTCHAR 066C +ENCODING 1644 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 3 6 2 3 +BITMAP +40 +80 +80 +C0 +E0 +C0 +ENDCHAR +STARTCHAR 066D +ENCODING 1645 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 6 7 2 7 +BITMAP +20 +E8 +50 +FC +70 +E8 +20 +ENDCHAR +STARTCHAR 066E +ENCODING 1646 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 6 1 3 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR 066F +ENCODING 1647 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 9 1 -1 +BITMAP +0180 +03C0 +02C0 +83C0 +83C0 +8040 +80C0 +FF80 +7F00 +ENDCHAR +STARTCHAR 0670 +ENCODING 1648 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 4 0 11 +BITMAP +80 +80 +80 +80 +ENDCHAR +STARTCHAR 0671 +ENCODING 1649 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 15 0 2 +BITMAP +30 +F0 +80 +00 +40 +60 +20 +20 +20 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR 0672 +ENCODING 1650 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 15 0 2 +BITMAP +20 +40 +E0 +00 +40 +60 +20 +20 +20 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR 0673 +ENCODING 1651 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 15 0 -1 +BITMAP +40 +60 +20 +20 +20 +20 +20 +20 +20 +20 +20 +00 +20 +40 +E0 +ENDCHAR +STARTCHAR 0674 +ENCODING 1652 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 4 1 13 +BITMAP +40 +80 +C0 +80 +ENDCHAR +STARTCHAR 0675 +ENCODING 1653 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 12 1 2 +BITMAP +10 +A0 +D0 +60 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 0676 +ENCODING 1654 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 9 16 0 -2 +BITMAP +0080 +0100 +0080 +0100 +0000 +0300 +0700 +0500 +0500 +0700 +0300 +0100 +0100 +0200 +8600 +7C00 +ENDCHAR +STARTCHAR 0677 +ENCODING 1655 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 9 16 0 -2 +BITMAP +0C80 +0D00 +0C80 +0D00 +1000 +0300 +0700 +0500 +0500 +0700 +0300 +0100 +0100 +0200 +8600 +7C00 +ENDCHAR +STARTCHAR 0678 +ENCODING 1656 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 15 0 -1 +BITMAP +0010 +0020 +0010 +0020 +0000 +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +ENDCHAR +STARTCHAR 0679 +ENCODING 1657 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 13 1 3 +BITMAP +0400 +0800 +0400 +0780 +0480 +1F80 +0000 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR 067A +ENCODING 1658 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 3 +BITMAP +0400 +0400 +0600 +0200 +0000 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR 067B +ENCODING 1659 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 -2 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0200 +0200 +0200 +0200 +ENDCHAR +STARTCHAR 067C +ENCODING 1660 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 1 +BITMAP +0300 +0F00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0500 +0600 +ENDCHAR +STARTCHAR 067D +ENCODING 1661 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 3 +BITMAP +0300 +0F00 +0E00 +0200 +0000 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR 067E +ENCODING 1662 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 -2 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0100 +0500 +0700 +0300 +ENDCHAR +STARTCHAR 067F +ENCODING 1663 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 3 +BITMAP +0200 +0A00 +0900 +0D00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR 0680 +ENCODING 1664 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 12 1 -3 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0300 +0D00 +0D00 +0500 +0400 +ENDCHAR +STARTCHAR 0681 +ENCODING 1665 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 0 -4 +BITMAP +0600 +0800 +0600 +0800 +0000 +3F80 +7F80 +0C00 +3000 +4000 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 0682 +ENCODING 1666 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 0 -4 +BITMAP +0C00 +0C00 +0400 +0400 +0000 +0000 +3F80 +7F80 +0C00 +3000 +4000 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 0683 +ENCODING 1667 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4000 +8300 +8B00 +8800 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 0684 +ENCODING 1668 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4000 +8400 +8400 +8600 +4600 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 0685 +ENCODING 1669 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 0 -4 +BITMAP +0800 +0A00 +0A00 +0800 +0000 +0000 +3F80 +7F80 +0C00 +3000 +4000 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 0686 +ENCODING 1670 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4200 +8B00 +8A00 +8200 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 0687 +ENCODING 1671 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4300 +8B00 +8D00 +8500 +4400 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 0688 +ENCODING 1672 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 15 0 3 +BITMAP +20 +20 +20 +2C +34 +FC +00 +10 +18 +0C +04 +04 +04 +7C +7C +ENDCHAR +STARTCHAR 0689 +ENCODING 1673 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 10 1 1 +BITMAP +20 +30 +18 +08 +08 +08 +F8 +F8 +50 +30 +ENDCHAR +STARTCHAR 068A +ENCODING 1674 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 11 1 0 +BITMAP +20 +30 +18 +08 +08 +08 +F8 +F8 +00 +20 +30 +ENDCHAR +STARTCHAR 068B +ENCODING 1675 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 18 0 0 +BITMAP +20 +20 +20 +2C +34 +FC +00 +10 +18 +0C +04 +04 +04 +7C +7C +00 +10 +18 +ENDCHAR +STARTCHAR 068C +ENCODING 1676 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 3 +BITMAP +30 +D0 +C0 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR 068D +ENCODING 1677 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 -1 +BITMAP +20 +30 +18 +08 +08 +08 +F8 +F8 +00 +10 +50 +40 +ENDCHAR +STARTCHAR 068E +ENCODING 1678 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 13 1 3 +BITMAP +40 +50 +50 +40 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR 068F +ENCODING 1679 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 13 1 3 +BITMAP +20 +A0 +A0 +20 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR 0690 +ENCODING 1680 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 14 1 3 +BITMAP +30 +B0 +90 +50 +40 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR 0691 +ENCODING 1681 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 17 1 -2 +BITMAP +08 +10 +08 +0F +09 +3F +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR 0692 +ENCODING 1682 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 13 1 -2 +BITMAP +0A +04 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR 0693 +ENCODING 1683 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 11 1 -3 +BITMAP +02 +03 +01 +01 +01 +01 +01 +03 +8F +7D +03 +ENDCHAR +STARTCHAR 0694 +ENCODING 1684 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 11 1 -3 +BITMAP +02 +03 +01 +01 +01 +01 +01 +03 +8E +79 +01 +ENDCHAR +STARTCHAR 0695 +ENCODING 1685 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 12 1 -4 +BITMAP +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +05 +02 +ENDCHAR +STARTCHAR 0696 +ENCODING 1686 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 11 1 -3 +BITMAP +02 +03 +01 +01 +11 +11 +01 +03 +8E +79 +01 +ENDCHAR +STARTCHAR 0697 +ENCODING 1687 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +06 +1E +18 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR 0698 +ENCODING 1688 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 15 1 -2 +BITMAP +0C +0F +0B +08 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR 0699 +ENCODING 1689 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 16 1 -2 +BITMAP +04 +14 +16 +1A +18 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR 069A +ENCODING 1690 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 12 1 -1 +BITMAP +0020 +0030 +0000 +0104 +0182 +0092 +80FE +80FE +8080 +8188 +FF08 +7C00 +ENDCHAR +STARTCHAR 069B +ENCODING 1691 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 10 1 -2 +BITMAP +0104 +0182 +0092 +80FE +80FE +8080 +8184 +FF14 +7C14 +0004 +ENDCHAR +STARTCHAR 069C +ENCODING 1692 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 15 1 -2 +BITMAP +0060 +0070 +0050 +0040 +0000 +0104 +0182 +0092 +80FE +80FE +8080 +8184 +FF14 +7C14 +0004 +ENDCHAR +STARTCHAR 069D +ENCODING 1693 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 9 1 -1 +BITMAP +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810100 +FF0500 +7C0400 +ENDCHAR +STARTCHAR 069E +ENCODING 1694 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 14 1 -1 +BITMAP +000400 +000500 +000500 +000400 +000000 +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810000 +FF0000 +7C0000 +ENDCHAR +STARTCHAR 069F +ENCODING 1695 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1880 +18E0 +09E0 +0980 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 06A0 +ENCODING 1696 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 21 0 -4 +BITMAP +2000 +2800 +2800 +2000 +0000 +3800 +7C00 +6000 +8000 +8100 +6700 +7C00 +3000 +2000 +4000 +8000 +8000 +C000 +6000 +7F80 +1F00 +ENDCHAR +STARTCHAR 06A1 +ENCODING 1697 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 6 0 3 +BITMAP +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR 06A2 +ENCODING 1698 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 9 0 0 +BITMAP +400C +800E +801A +C00E +7FFE +3FFE +0000 +0004 +0004 +ENDCHAR +STARTCHAR 06A3 +ENCODING 1699 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 12 0 0 +BITMAP +0008 +0008 +0000 +400C +800E +801A +C00E +7FFE +3FFE +0000 +0180 +0080 +ENDCHAR +STARTCHAR 06A4 +ENCODING 1700 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 11 0 3 +BITMAP +0010 +001C +0014 +0010 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR 06A5 +ENCODING 1701 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 11 0 -2 +BITMAP +400C +800E +801A +C00E +7FFE +3FFE +0000 +0002 +000A +000A +0002 +ENDCHAR +STARTCHAR 06A6 +ENCODING 1702 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 12 0 3 +BITMAP +0004 +0014 +0014 +0014 +0010 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR 06A7 +ENCODING 1703 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 13 1 -1 +BITMAP +0300 +0300 +0000 +0000 +0180 +03C0 +02C0 +83C0 +83C0 +8040 +80C0 +FF80 +7F00 +ENDCHAR +STARTCHAR 06A8 +ENCODING 1704 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 -1 +BITMAP +0400 +0700 +0500 +0400 +0000 +0180 +03C0 +02C0 +83C0 +83C0 +8040 +80C0 +FF80 +7F00 +ENDCHAR +STARTCHAR 06A9 +ENCODING 1705 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 11 0 3 +BITMAP +0006 +001E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR 06AA +ENCODING 1706 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 10 0 3 +BITMAP +0080 +0380 +0E00 +1000 +1F00 +8FF8 +80FE +C002 +FFFE +7FFE +ENDCHAR +STARTCHAR 06AB +ENCODING 1707 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 11 0 3 +BITMAP +0006 +0D? +007A +004C +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR 06AC +ENCODING 1708 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 12 0 3 +BITMAP +0640 +0660 @0 +0240 +0420 +0720 +0120 +0120 +9E20 +C020 +7FE0 +7FE0 +ENDCHAR +STARTCHAR 06AD +ENCODING 1709 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 13 0 3 +BITMAP +0C00 +0E40 +0B60 +0860 +0240 +0420 +0720 +0120 +0120 +9E20 +C020 +7FE0 +7FE0 +ENDCHAR +STARTCHAR 06AE +ENCODING 1710 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 17 0 -2 +BITMAP +0040 +0060 +0060 +0240 +0420 +0720 +0120 +0120 +9E20 +C020 +7FE0 +7FE0 +0000 +0300 +0F00 +0E00 +0200 +ENDCHAR +STARTCHAR 06AF +ENCODING 1711 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 14 0 3 +BITMAP +0002 +000E +0038 +0066 +009E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR 06B0 +ENCODING 1712 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 14 0 3 +BITMAP +0002 +000E +0038 +0066 +009E +007A +004C +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR 06B1 +ENCODING 1713 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 14 0 3 +BITMAP +0012 +004E +0038 +0066 +009E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR 06B2 +ENCODING 1714 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 18 0 -1 +BITMAP +0002 +000E +0038 +0066 +009E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +0000 +0040 +0140 +0100 +ENDCHAR +STARTCHAR 06B3 +ENCODING 1715 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 19 0 -2 +BITMAP +0002 +000E +0038 +0066 +009E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +0000 +0080 +0080 +0080 +0080 +ENDCHAR +STARTCHAR 06B4 +ENCODING 1716 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 14 0 3 +BITMAP +0042 +001E +0078 +0066 +009E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE@DCHAR +START 06B5 +ENCODING 1717 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 17 1 0 +BITMAP +0500 +0200 +0000 +0300 +0100 +0100 +0100 +0100 +0100 +0100 +8100 +8080 +8080 +8080 +8300 +FF00 +7E00 +ENDCHAR +STARTCHAR 06B6 +ENCODING 1718 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 17 1 0 +BITMAP +0300 +0300 +0000 +0300 +0100 +0100 +0100 +0100 +0100 +0100 +8100 +8080 +8080 +8080 +8300 +FF00 +7E00 +ENDCHAR +STARTCHAR 06B7 +ENCODING 1719 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 17 1 0 +BITMAP +0600 +0100 +0400 +0300 +0100 +0100 +0100 +0100 +0100 +0100 +8100 +8080 +8080 +8080 +8300 +FF00 +7E00 +ENDCHAR +STARTCHAR 06B8 +ENCODING 1720 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 19 1 -4 +BITMAP +0200 +0300 +0100 +0100 +0100 +0100 +0100 +0100 +8100 +8080 +8080 +8080 +8300 +FF00 +7E00 +0400 +2C00 +3C00 +0C00 +ENDCHAR +STARTCHAR 06B9 +ENCODING 1721 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 15 1 -4 +BITMAP +0800 +0800 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +0000 +0800 +0800 +ENDCHAR +STARTCHAR 06BA +ENCODING 1722 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 8 1 0 +BITMAP +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR 06BB +ENCODING 1723 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 16 1 -1 +BITMAP +1000 +1000 +1000 +1600 +1A00 +3E00 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR 06BC +ENCODING 1724 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 1 -3 +BITMAP +0800 +0800 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +2800 +1800 +ENDCHAR +STARTCHAR 06BD +ENCODING 1725 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 1 -1 +BITMAP +1000 +1400 +3400 +1000 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR 06BE +ENCODING 1726 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 8 -1 3 +BITMAP +08 +1C +1C +26 +27 +19 +FF +E7 +ENDCHAR +STARTCHAR 06BF +ENCODING 1727 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 16 0 -4 +BITMAP +0C00 +0400 +0000 +0000 +3F80 +7F80 +0C00 +3000 +4200 +8B00 +8A00 +8200 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 06C0 +ENCODING 1728 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 12 1 3 +BITMAP +60 +80 +60 +80 +00 +40 +E0 +F0 +90 +90 +F0 +E0 +ENDCHAR +STARTCHAR 06C1 +ENCODING 1729 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 5 0 2 +BITMAP +18 +3C +6E +46 +80 +ENDCHAR +STARTCHAR 06C2 +ENCODING 1730 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 10 0 2 +BITMAP +10 +20 +10 +20 +00 +18 +3C +6E +46 +80 +ENDCHAR +STARTCHAR 06C3 +ENCODING 1731 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 9 0 2 +BITMAP +08 +28 +20 +00 +18 +3C +6E +46 +80 +ENDCHAR +STARTCHAR 06C4 +ENCODING 1732 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 11 0 -2 +BITMAP +03 +07 +05 +05 +07 +03 +01 +0D +16 +8E +7C +ENDCHAR +STARTCHAR 06C5 +ENCODING 1733 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 11 0 -2 +BITMAP +03 +07 +05 +05 +07 +03 +19 +07 +02 +86 +7C +ENDCHAR +STARTCHAR 06C6 +ENCODING 1734 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 14 0 -2 +BITMAP +05 +02 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 06C7 +ENCODING 1735 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 17 0 -2 +BITMAP +03 +03 +03 +03 +04 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 06C8 +ENCODING 1736 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 17 0 -1 +BITMAP +02 +02 +02 +02 +02 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 06C9 +ENCODING 1737 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 14 0 -2 +BITMAP +02 +05 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 06CA +ENCODING 1738 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 15 0 -2 +BITMAP +03 +0F +0C +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 06CB +ENCODING 1739 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 16 0 -2 +BITMAP +04 +07 +0D +0C +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 06CC +ENCODING 1740 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 10 0 -1 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +ENDCHAR +STARTCHAR 06CD +ENCODING 1741 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 13 10 -1 -1 +BITMAP +0030 +0078 +0080 +2100 +E1F0 +40F0 +4010 +60E0 +3FC0 +1F00 +ENDCHAR +STARTCHAR 06CE +ENCODING 1742 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 11 0 -1 +BITMAP +0C00 +0860 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +ENDCHAR +STARTCHAR 06CF +ENCODING 1743 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 14 0 -2 +BITMAP +04 +04 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 06D0 +ENCODING 1744 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 13 0 -4 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +0000 +0400 +0400 +ENDCHAR +STARTCHAR 06D1 +ENCODING 1745 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 13 0 -4 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +0000 +0A00 +0600 +ENDCHAR +STARTCHAR 06D2 +ENCODING 1746 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 14 7 1 0 +BITMAP +0600 +0E00 +3800 +7000 +8000 +FFFC +FFF8 +ENDCHAR +STARTCHAR 06D3 +ENCODING 1747 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 14 10 1 0 +BITMAP +0800 +3000 +1800 +2600 +0E00 +3800 +7000 +8000 +FFFC +FFF8 +ENDCHAR +STARTCHAR 06D4 +ENCODING 1748 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 2 0 3 +BITMAP +F0 +F0 +ENDCHAR +STARTCHAR 06D5 +ENCODING 1749 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 7 1 3 +BITMAP +40 +E0 +F0 +90 +90 +F0 +E0 +ENDCHAR +STARTCHAR 06D6 +ENCODING 1750 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 8 7 -4 10 +BITMAP +20 +20 +20 +23 +7F +80 +FE +ENDCHAR +STARTCHAR 06D7 +ENCODING 1751 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 7 7 -3 10 +BITMAP +28 +30 +38 +24 +7C +80 +FE +ENDCHAR +STARTCHAR 06D8 +ENCODING 1752 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -2 10 +BITMAP +20 +50 +F0 +ENDCHAR +STARTCHAR 06D9 +ENCODING 1753 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 6 -2 10 +BITMAP +90 +D0 +50 +20 +60 +60 +ENDCHAR +STARTCHAR 06DA +ENCODING 1754 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 5 -2 10 +BITMAP +F0 +80 +A0 +80 +F0 +ENDCHAR +STARTCHAR 06DB +ENCODING 1755 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -1 10 +BITMAP +80 +C0 +ENDCHAR +STARTCHAR 06DC +ENCODING 1756 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 8 5 -4 10 +BITMAP +08 +09 +87 +88 +70 +ENDCHAR +STARTCHAR 06DD +ENCODING 1757 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 21 21 0 -4 +BITMAP +00FC00 +0F0380 +13FE80 +1C01C0 +100060 +200020 +400010 +400010 +400008 +400008 +800008 +400008 +400008 +400010 +400010 +200020 +100060 +1C01C0 +13FE80 +0F0380 +00FC00 +ENDCHAR +STARTCHAR 06DE +ENCODING 1758 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 21 0 -4 +BITMAP +002000 +005000 +008800 +1FFF80 +120480 +140280 +180180 +100080 +307040 +5090A0 +909090 +5090A0 +307040 +100080 +180180 +140280 +120480 +1FFF80 +008800 +005000 +002000 +ENDCHAR +STARTCHAR 06DF +ENCODING 1759 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -1 10 +BITMAP +C0 +ENDCHAR +STARTCHAR 06E0 +ENCODING 1760 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -1 10 +BITMAP +C0 +ENDCHAR +STARTCHAR 06E1 +ENCODING 1761 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 3 -3 10 +BITMAP +30 +18 +FC +ENDCHAR +STARTCHAR 06E2 +ENCODING 1762 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 5 -1 10 +BITMAP +40 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR 06E3 +ENCODING 1763 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 8 5 -4 -4 +BITMAP +08 +09 +87 +88 +70 +ENDCHAR +STARTCHAR 06E4 +ENCODING 1764 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -1 10 +BITMAP +C0 +ENDCHAR +STARTCHAR 06E5 +ENCODING 1765 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 4 1 10 +BITMAP +60 +60 +40 +C0 +ENDCHAR +STARTCHAR 06E6 +ENCODING 1766 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 4 0 10 +BITMAP +10 +70 +80 +FE +ENDCHAR +STARTCHAR 06E7 +ENCODING 1767 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 7 4 -4 10 +BITMAP +10 +20 +C0 +FE +ENDCHAR +STARTCHAR 06E8 +ENCODING 1768 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 6 -2 10 +BITMAP +20 +00 +10 +90 +90 +F0 +ENDCHAR +STARTCHAR 06E9 +ENCODING 1769 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 16 1 0 +BITMAP +0800 +1400 +2A00 +5580 +AA40 +D780 +7700 +5300 +5300 +5300 +5300 +5F00 +6300 +9E80 +8080 +FFC0 +ENDCHAR +STARTCHAR 06EA +ENCODING 1770 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -2 -3 +BITMAP +60 +90 +60 +ENDCHAR +STARTCHAR 06EB +ENCODING 1771 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -2 10 +BITMAP +60 +90 +60 +ENDCHAR +STARTCHAR 06EC +ENCODING 1772 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -1 10 +BITMAP +C0 +ENDCHAR +STARTCHAR 06ED +ENCODING 1773 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 5 -1 -4 +BITMAP +40 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR 06F0 +ENCODING 1776 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 3 4 4 4 +BITMAP +80 +E0 +C0 +40 +ENDCHAR +STARTCHAR 06F1 +ENCODING 1777 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 3 10 3 3 +BITMAP +80 +C0 +C0 +60 +60 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR 06F2 +ENCODING 1778 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 5 11 2 3 +BITMAP +80 +C8 +F8 +78 +60 +20 +30 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 06F3 +ENCODING 1779 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 4 +BITMAP +CD +7F +76 +20 +20 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 06F4 +ENCODING 1780 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 10 2 3 +BITMAP +1C +A0 +E2 +FC +78 +60 +20 +20 +20 +20 +ENDCHAR +STARTCHAR 06F5 +ENCODING 1781 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 11 1 3 +BITMAP +10 +18 +1C +1C +26 +42 +42 +42 +CA +FE +7C +ENDCHAR +STARTCHAR 06F6 +ENCODING 1782 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 6 11 2 3 +BITMAP +30 +78 +80 +84 +FC +F8 +30 +20 +40 +40 +40 +ENDCHAR +STARTCHAR 06F7 +ENCODING 1783 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 3 +BITMAP +81 +C1 +C3 +62 +24 +24 +18 +18 +18 +08 +ENDCHAR +STARTCHAR 06F8 +ENCODING 1784 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 4 +BITMAP +10 +18 +28 +28 +24 +26 +46 +C3 +81 +81 +ENDCHAR +STARTCHAR 06F9 +ENCODING 1785 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 6 11 2 3 +BITMAP +30 +70 +98 +88 +F8 +78 +08 +08 +08 +0C +08 +ENDCHAR +STARTCHAR 06FA +ENCODING 1786 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 1 -1 +BITMAP +0060 +0070 +0050 +0040 +0000 +0104 +0182 +0092 +80FE +80FE +8080 +8188 +FF08 +7C00 +ENDCHAR +STARTCHAR 06FB +ENCODING 1787 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 12 1 -1 +BITMAP +000800 +000800 +000000 +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810200 +FF0200 +7C0000 +ENDCHAR +STARTCHAR 06FC +ENCODING 1788 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 20 0 -4 +BITMAP +1000 +1000 +0000 +0000 +3800 +7C00 +6000 +8000 +8100 +6700 +7C00 +3000 +2000 +4000 +8200 +8200 +C000 +6000 +7F80 +1F00 +ENDCHAR +STARTCHAR 06FD +ENCODING 1789 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 6 12 1 -3 +BITMAP +30 +70 +40 +CC +FC +70 +60 +40 +28 +28 +28 +28 +ENDCHAR +STARTCHAR 06FE +ENCODING 1790 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 11 0 -4 +BITMAP +38 +3C +0C +3C +7C +C0 +80 +94 +54 +54 +54 +ENDCHAR +STARTCHAR 1E80 +ENCODING 7808 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 18 0 0 +BITMAP +018000 +00C000 +004000 +000000 +C0C0C0 +40C080 +61E180 +61E180 +612180 +233100 +333300 +323300 +321200 +161A00 +161E00 +1C0E00 +1C0C00 +0C0C00 +ENDCHAR +STARTCHAR 1E81 +ENCODING 7809 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 14 0 0 +BITMAP +0600 +0600 +0200 +0000 +C308 +4308 +4718 +6798 +6590 +24B0 +3CB0 +3CE0 +18E0 +1860 +ENDCHAR +STARTCHAR 1E82 +ENCODING 7810 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 18 0 0 +BITMAP +006000 +004000 +00C000 +000000 +C0C0C0 +40C080 +61E180 +61E180 +612180 +233100 +333300 +323300 +321200 +161A00 +161E00 +1C0E00 +1C0C00 +0C0C00 +ENDCHAR +STARTCHAR 1E83 +ENCODING 7811 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 14 0 0 +BITMAP +0300 +0300 +0200 +0000 +C308 +4308 +4718 +6798 +6590 +24B0 +3CB0 +3CE0 +18E0 +1860 +ENDCHAR +STARTCHAR 1E84 +ENCODING 7812 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 17 0 0 +BITMAP +033000 +033000 +000000 +C0C0C0 +40C080 +61E180 +61E180 +612180 +233100 +333300 +323300 +321200 +161A00 +161E00 +1C0E00 +1C0C00 +0C0C00 +ENDCHAR +STARTCHAR 1E85 +ENCODING 7813 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 13 0 0 +BITMAP +0CC0 +0CC0 +0000 +C308 +4308 +4718 +6798 +6590 +24B0 +3CB0 +3CE0 +18E0 +1860 +ENDCHAR +STARTCHAR 1EA0 +ENCODING 7840 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 17 0 -3 +BITMAP +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EA1 +ENCODING 7841 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 -3 +BITMAP +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1EA2 +ENCODING 7842 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0F00 +0100 +0300 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EA3 +ENCODING 7843 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +1C00 +0600 +0C00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EA4 +ENCODING 7844 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0300 +0200 +0700 +0900 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EA5 +ENCODING 7845 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +1800 +3400 +2600 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EA6 +ENCODING 7846 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0C00 +0600 +0700 +0900 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EA7 +ENCODING 7847 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +3000 +1000 +1800 +0000 +1800 +3400 +2600 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EA8 +ENCODING 7848 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0700 +0300 +0700 +0900 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EA9 +ENCODING 7849 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +3C00 +0400 +0C00 +0000 +1800 +3400 +2600 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EAA +ENCODING 7850 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0C80 +1380 +0700 +0900 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EAB +ENCODING 7851 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 0 +BITMAP +3200 +4E00 +0000 +1800 +3400 +2600 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EAC +ENCODING 7852 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 20 0 -3 +BITMAP +0700 +0900 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EAD +ENCODING 7853 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 -3 +BITMAP +1800 +3400 +2600 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1EAE +ENCODING 7854 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0300 +0200 +0880 +0700 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EAF +ENCODING 7855 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +0C00 +0C00 +1800 +0000 +2200 +2200 +1C00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EB0 +ENCODING 7856 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0C00 +0600 +0880 +0700 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EB1 +ENCODING 7857 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +3000 +1800 +0800 +0000 +2200 +2200 +1C00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EB2 +ENCODING 7858 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0700 +0300 +0880 +0700 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EB3 +ENCODING 7859 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +1C00 +0600 +0C00 +0000 +2200 +2200 +1C00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EB4 +ENCODING 7860 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0E80 +1380 +0880 +0700 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EB5 +ENCODING 7861 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 0 +BITMAP +3B00 +2600 +0000 +2200 +2200 +1C00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EB6 +ENCODING 7862 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 20 0 -3 +BITMAP +0880 +0700 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EB7 +ENCODING 7863 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 -3 +BITMAP +2200 +2200 +1C00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1EB8 +ENCODING 7864 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 17 1 -3 +BITMAP +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EB9 +ENCODING 7865 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 -3 +BITMAP +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1EBA +ENCODING 7866 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0E00 +0300 +0600 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 1EBB +ENCODING 7867 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +1C00 +0600 +0C00 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EBC +ENCODING 7868 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +1C80 +1F80 +1300 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 1EBD +ENCODING 7869 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3A00 +3E00 +6E00 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EBE +ENCODING 7870 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0600 +0400 +0E00 +1B00 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 1EBF +ENCODING 7871 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EC0 +ENCODING 7872 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0800 +0400 +0E00 +1B00 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 1EC1 +ENCODING 7873 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +3000 +1000 +1800 +0000 +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EC2 +ENCODING 7874 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0E00 +0600 +0E00 +1B00 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 1EC3 +ENCODING 7875 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +3C00 +0400 +0C00 +0000 +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EC4 +ENCODING 7876 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +1D00 +2700 +0E00 +1B00 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 1EC5 +ENCODING 7877 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 0 +BITMAP +3200 +4E00 +0000 +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EC6 +ENCODING 7878 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 20 1 -3 +BITMAP +0E00 +1B00 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EC7 +ENCODING 7879 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 -3 +BITMAP +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1EC8 +ENCODING 7880 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 18 1 0 +BITMAP +E0 +30 +70 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 1EC9 +ENCODING 7881 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 14 0 0 +BITMAP +F0 +10 +30 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 1ECA +ENCODING 7882 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 17 2 -3 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +00 +C0 +C0 +ENDCHAR +STARTCHAR 1ECB +ENCODING 7883 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 17 1 -3 +BITMAP +C0 +C0 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +00 +C0 +C0 +ENDCHAR +STARTCHAR 1ECC +ENCODING 7884 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 17 1 -3 +BITMAP +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1ECD +ENCODING 7885 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 -3 +BITMAP +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1ECE +ENCODING 7886 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0700 +0180 +0300 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1ECF +ENCODING 7887 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +1C00 +0600 +0C00 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 1ED0 +ENCODING 7888 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0300 +0200 +0700 +0D80 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1ED1 +ENCODING 7889 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 1ED2 +ENCODING 7890 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0400 +0200 +0700 +0D80 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1ED3 +ENCODING 7891 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +3000 +1000 +1800 +0000 +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 1ED4 +ENCODING 7892 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0700 +0300 +0700 +0D80 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1ED5 +ENCODING 7893 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +3C00 +0400 +0C00 +0000 +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 1ED6 +ENCODING 7894 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0E40 +1380 +0700 +0D80 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1ED7 +ENCODING 7895 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 0 +BITMAP +3200 +4E00 +0000 +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 1ED8 +ENCODING 7896 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 20 1 -3 +BITMAP +0700 +0D80 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1ED9 +ENCODING 7897 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 -3 +BITMAP +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1EDA +ENCODING 7898 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 18 1 0 +BITMAP +0300 +0300 +0600 +0000 +0F86 +3FE6 +7072 +6034 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1EDB +ENCODING 7899 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +3C60 +7F60 +C320 +C1C0 +81C0 +8180 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EDC +ENCODING 7900 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 18 1 0 +BITMAP +0C00 +0600 +0200 +0000 +0F86 +3FE6 +7072 +6034 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1EDD +ENCODING 7901 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 1 0 +BITMAP +3000 +1800 +0800 +0000 +3C60 +7F60 +C320 +C1C0 +81C0 +8180 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EDE +ENCODING 7902 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 18 1 0 +BITMAP +0700 +0180 +0300 +0000 +0F86 +3FE6 +7072 +6034 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1EDF +ENCODING 7903 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 1 0 +BITMAP +1C00 +0600 +0C00 +0000 +3C60 +7F60 +C320 +C1C0 +81C0 +8180 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EE0 +ENCODING 7904 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 18 1 0 +BITMAP +0EC0 +0F80 +1B80 +0000 +0F86 +3FE6 +7072 +6034 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1EE1 +ENCODING 7905 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 1 0 +BITMAP +3200 +7E00 +4E00 +0000 +3C60 +7F60 +C320 +C1C0 +81C0 +8180 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EE2 +ENCODING 7906 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 17 1 -3 +BITMAP +0F86 +3FE6 +7072 +6034 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EE3 +ENCODING 7907 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 13 1 -3 +BITMAP +3C60 +7F60 +C320 +C1C0 +81C0 +8180 +C180 +C300 +7F00 +3E00 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1EE4 +ENCODING 7908 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 17 1 -3 +BITMAP +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EE5 +ENCODING 7909 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 13 1 -3 +BITMAP +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +00 +18 +18 +ENDCHAR +STARTCHAR 1EE6 +ENCODING 7910 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0E00 +0300 +0700 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 1EE7 +ENCODING 7911 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +3C +04 +0C +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 1EE8 +ENCODING 7912 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 18 1 0 +BITMAP +0300 +0600 +0400 +0000 +C064 +C064 +C064 +C064 +C078 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 1EE9 +ENCODING 7913 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +0C00 +0C00 +1800 +0000 +C160 +C160 +C120 +C120 +C1C0 +C100 +C300 +C300 +7D00 +3900 +ENDCHAR +STARTCHAR 1EEA +ENCODING 7914 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 18 1 0 +BITMAP +0C00 +0400 +0600 +0000 +C064 +C064 +C064 +C064 +C078 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 1EEB +ENCODING 7915 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +3000 +1800 +0800 +0000 +C160 +C160 +C120 +C120 +C1C0 +C100 +C300 +C300 +7D00 +3900 +ENDCHAR +STARTCHAR 1EEC +ENCODING 7916 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 18 1 0 +BITMAP +0E00 +0300 +0700 +0000 +C064 +C064 +C064 +C064 +C078 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 1EED +ENCODING 7917 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +3C00 +0400 +0C00 +0000 +C160 +C160 +C120 +C120 +C1C0 +C100 +C300 +C300 +7D00 +3900 +ENDCHAR +STARTCHAR 1EEE +ENCODING 7918 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 18 1 0 +BITMAP +0C80 +1F80 +1300 +0000 +C064 +C064 +C064 +C064 +C078 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 1EEF +ENCODING 7919 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +3200 +7E00 +6E00 +0000 +C160 +C160 +C120 +C120 +C1C0 +C100 +C300 +C300 +7D00 +3900 +ENDCHAR +STARTCHAR 1EF0 +ENCODING 7920 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 17 1 -3 +BITMAP +C064 +C064 +C064 +C064 +C078 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EF1 +ENCODING 7921 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 13 1 -3 +BITMAP +C160 +C160 +C120 +C120 +C1C0 +C100 +C300 +C300 +7D00 +3900 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1EF2 +ENCODING 7922 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +0C00 +0600 +0200 +0000 +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 1EF3 +ENCODING 7923 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 18 1 -4 +BITMAP +30 +10 +18 +00 +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 1EF4 +ENCODING 7924 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 17 0 -3 +BITMAP +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EF5 +ENCODING 7925 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 -4 +BITMAP +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +36 +F6 +E0 +ENDCHAR +STARTCHAR 1EF6 +ENCODING 7926 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +0F00 +0100 +0300 +0000 +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 1EF7 +ENCODING 7927 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 18 1 -4 +BITMAP +38 +04 +1C +00 +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 1EF8 +ENCODING 7928 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +0EC0 +0F80 +1B80 +0000 +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 1EF9 +ENCODING 7929 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 18 1 -4 +BITMAP +32 +7E +4C +00 +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 200C +ENCODING 8204 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 15 0 -3 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR 200D +ENCODING 8205 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 16 -2 -2 +BITMAP +90 +E0 +D0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 200E +ENCODING 8206 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 15 0 -3 +BITMAP +20 +F0 +A0 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR 200F +ENCODING 8207 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 15 -4 -3 +BITMAP +40 +F0 +50 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 2013 +ENCODING 8211 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 2 0 4 +BITMAP +FFE0 +FFE0 +ENDCHAR +STARTCHAR 2014 +ENCODING 8212 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 19 2 0 4 +BITMAP +FFFFE0 +FFFFE0 +ENDCHAR +STARTCHAR 2015 +ENCODING 8213 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 17 2 1 4 +BITMAP +FFFF80 +FFFF80 +ENDCHAR +STARTCHAR 2017 +ENCODING 8215 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 5 0 -6 +BITMAP +FFE0 +FFE0 +0000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 2018 +ENCODING 8216 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 5 1 9 +BITMAP +40 +C0 +80 +C0 +C0 +ENDCHAR +STARTCHAR 2019 +ENCODING 8217 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 5 1 9 +BITMAP +C0 +C0 +40 +40 +80 +ENDCHAR +STARTCHAR 201A +ENCODING 8218 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 5 1 -3 +BITMAP +C0 +C0 +40 +40 +80 +ENDCHAR +STARTCHAR 201B +ENCODING 8219 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 5 1 9 +BITMAP +C0 +C0 +80 +C0 +40 +ENDCHAR +STARTCHAR 201C +ENCODING 8220 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 5 1 9 +BITMAP +50 +90 +90 +D0 +D0 +ENDCHAR +STARTCHAR 201D +ENCODING 8221 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 5 1 9 +BITMAP +D0 +D0 +50 +90 +90 +ENDCHAR +STARTCHAR 201E +ENCODING 8222 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 5 1 -3 +BITMAP +D0 +D0 +50 +90 +90 +ENDCHAR +STARTCHAR 2020 +ENCODING 8224 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 -3 +BITMAP +1800 +1800 +1800 +1800 +FF80 +FF80 +1800 +1800 +1800 +1800 +1800 +1800 +1800 +1800 +1800 +1800 +1800 +ENDCHAR +STARTCHAR 2021 +ENCODING 8225 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 -3 +BITMAP +1800 +1800 +1800 +1800 +FF80 +FF80 +1800 +1800 +1800 +1800 +1800 +FF80 +FF80 +1800 +1800 +1800 +1800 +ENDCHAR +STARTCHAR 2022 +ENCODING 8226 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 5 1 4 +BITMAP +70 +F8 +F8 +F8 +70 +ENDCHAR +STARTCHAR 2026 +ENCODING 8230 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 15 2 2 0 +BITMAP +C106 +C106 +ENDCHAR +STARTCHAR 202A +ENCODING 8234 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 14 0 -3 +BITMAP +F0 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR 202B +ENCODING 8235 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 14 -4 -3 +BITMAP +F0 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 202C +ENCODING 8236 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 16 -2 -3 +BITMAP +F0 +F0 +F0 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 202D +ENCODING 8237 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 17 -2 -3 +BITMAP +F0 +80 +80 +80 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 202E +ENCODING 8238 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 17 -2 -3 +BITMAP +F0 +10 +10 +10 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 2030 +ENCODING 8240 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 19 14 0 0 +BITMAP +78C000 +488000 +CC8000 +CD0000 +CD0000 +4B0000 +7A0000 +02E3C0 +059240 +059660 +0D1660 +099660 +099240 +10E3C0 +ENDCHAR +STARTCHAR 2032 +ENCODING 8242 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 5 1 9 +BITMAP +60 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR 2033 +ENCODING 8243 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 5 1 9 +BITMAP +78 +58 +D8 +D0 +90 +ENDCHAR +STARTCHAR 2039 +ENCODING 8249 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 9 1 1 +BITMAP +30 +20 +60 +40 +C0 +40 +60 +20 +30 +ENDCHAR +STARTCHAR 203A +ENCODING 8250 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 9 1 1 +BITMAP +C0 +40 +60 +20 +30 +20 +60 +40 +C0 +ENDCHAR +STARTCHAR 203C +ENCODING 8252 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 6 14 2 0 +BITMAP +CC +CC +CC +CC +CC +CC +CC +8C +8C +88 +88 +00 +CC +CC +ENDCHAR +STARTCHAR 203E +ENCODING 8254 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 7 2 0 11 +BITMAP +FE +FE +ENDCHAR +STARTCHAR 2044 +ENCODING 8260 +SWIDTH 154 0 +DWIDTH 3 0 +BBX 11 14 -4 0 +BITMAP +0020 +0040 +00C0 +0180 +0100 +0200 +0600 +0400 +0800 +1800 +3000 +2000 +4000 +C000 +ENDCHAR +STARTCHAR 206A +ENCODING 8298 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 17 -2 -3 +BITMAP +F0 +40 +40 +40 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 206B +ENCODING 8299 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 17 -2 -3 +BITMAP +F0 +90 +90 +90 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 206C +ENCODING 8300 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 16 -2 -3 +BITMAP +F0 +60 +60 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 206D +ENCODING 8301 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 16 -2 -3 +BITMAP +40 +60 +60 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 206E +ENCODING 8302 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 17 -2 -3 +BITMAP +40 +60 +90 +60 +60 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 206F +ENCODING 8303 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 17 -2 -3 +BITMAP +C0 +40 +40 +40 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 207F +ENCODING 8319 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 7 1 5 +BITMAP +B0 +F8 +88 +88 +88 +88 +88 +ENDCHAR +STARTCHAR 20A3 +ENCODING 8355 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +3FC0 +3FC0 +2000 +2000 +2000 +2000 +3F80 +3F80 +2000 +2000 +FC00 +FC00 +2000 +2000 +ENDCHAR +STARTCHAR 20A4 +ENCODING 8356 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +1F00 +3F80 +3180 +60C0 +6000 +FE00 +FE00 +3000 +FE00 +FE00 +3000 +7C40 +FFC0 +4380 +ENDCHAR +STARTCHAR 20A7 +ENCODING 8359 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 14 0 0 +BITMAP +FE0000 +FF3000 +C3B000 +C1B000 +C1FFC0 +C3FFF0 +FFB430 +FE3700 +C037E0 +C031F0 +C03030 +C03630 +C03FF0 +C03BE0 +ENDCHAR +STARTCHAR 20AA +ENCODING 8362 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 13 10 1 0 +BITMAP +FF18 +FF98 +C098 +CC98 +CC98 +CC98 +CC98 +CC18 +CFF8 +CFF0 +ENDCHAR +STARTCHAR 20AB +ENCODING 8363 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 11 1 3 +BITMAP +0E +04 +3C +44 +44 +C4 +44 +44 +3C +00 +FE +ENDCHAR +STARTCHAR 20AC +ENCODING 8364 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +0780 +1FC0 +3840 +3000 +6000 +6000 +FF80 +6000 +FF80 +6000 +3000 +3840 +1FC0 +0780 +ENDCHAR +STARTCHAR 2105 +ENCODING 8453 +SWIDTH 874 0 +DWIDTH 17 0 +BBX 15 14 1 0 +BITMAP +7820 +CC60 +8040 +80C0 +8480 +C980 +7900 +033C +0244 +0642 +04C2 +0842 +0844 +103C +ENDCHAR +STARTCHAR 2113 +ENCODING 8467 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 14 1 0 +BITMAP +30 +78 +48 +48 +50 +50 +60 +60 +C0 +C0 +40 +40 +78 +78 +ENDCHAR +STARTCHAR 2116 +ENCODING 8470 +SWIDTH 1028 0 +DWIDTH 20 0 +BBX 19 14 1 0 +BITMAP +E06000 +E06000 +F06000 +F06780 +D86FC0 +CC6C40 +CC6C60 +C66C40 +C76FC0 +C36780 +C1E000 +C1EFC0 +C0EFC0 +C06000 +ENDCHAR +STARTCHAR 2122 +ENCODING 8482 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 15 8 2 6 +BITMAP +FD86 +118E +114E +114E +1156 +1136 +1136 +1136 +ENDCHAR +STARTCHAR 2126 +ENCODING 8486 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0F80 +3FE0 +7060 +6030 +6030 +C030 +C010 +C010 +6030 +6030 +3060 +18C0 +FDF8 +FDF8 +ENDCHAR +STARTCHAR 212E +ENCODING 8494 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 10 1 0 +BITMAP +3E00 +6100 +C180 +C180 +FFC0 +C000 +C000 +C080 +6100 +3E00 +ENDCHAR +STARTCHAR 2153 +ENCODING 8531 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 1 0 +BITMAP +2010 +6030 +E020 +A040 +20C0 +2180 +2100 +023C +0664 +0C04 +0818 +1006 +3066 +603C +ENDCHAR +STARTCHAR 2154 +ENCODING 8532 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 0 0 +BITMAP +7808 +4C18 +0C10 +1820 +3060 +60C0 +FC80 +011E +0332 +0602 +040C +0802 +1822 +301E +ENDCHAR +STARTCHAR 215B +ENCODING 8539 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 14 1 0 +BITMAP +2010 +6030 +A020 +2040 +20C0 +2180 +2100 +0238 +0664 +0? +0838 +1044 +3044 +603C +ENDCHAR +STARTCHAR 215C +ENCODING 8540 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 0 0 +BITMAP +7808 +4C18 +0C10 +1020 +0C60 +CCC0 +7880 +011E +0332 +0632 +041C +0822 +1822 +301E +ENDCHAR +STARTCHAR 215D +ENCODING 8541 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 0 0 +BITMAP +7C08 +4018 +7810 +4C20 +0460 +CCC0 +7880 +011E +0332 +0632 +041C +0822 +1822 +301E +ENDCHAR +STARTCHAR 215E +ENCODING 8542 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 14 1 0 +BITMAP +F810 +1020 +3060 +2040 +6080 +4180 +4300 +0238 +0464 +0C64 +1838 +1044 +2044 +603C +ENDCHAR +STARTCHAR 2190 +ENCODING 8592 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 17 6 1 1 +BITMAP +100000 +200000 +600000 +FFFF80 +600000 +100000 +ENDCHAR +STARTCHAR 2191 +ENCODING 8593 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 16 1 -4 +BITMAP +10 +38 +7C +D2 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 2192 +ENCODING 8594 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 17 6 1 1 +BITMAP +000400 +000200 +000300 +FFFF80 +000200 +000400 +ENDCHAR +STARTCHAR 2193 +ENCODING 8595 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 16 1 -4 +BITMAP +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +90 +56 +3C +18 +10 +ENDCHAR +STARTCHAR 2194 +ENCODING 8596 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 17 7 1 1 +BITMAP +100400 +200200 +600300 +FFFF80 +600300 +100400 +100400 +ENDCHAR +STARTCHAR 2195 +ENCODING 8597 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 18 1 -4 +BITMAP +10 +18 +38 +74 +92 +10 +10 +10 +10 +10 +10 +10 +10 +90 +56 +3C +18 +10 +ENDCHAR +STARTCHAR 21A8 +ENCODING 8616 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 20 1 -6 +BITMAP +10 +18 +38 +74 +92 +10 +10 +10 +10 +10 +10 +10 +10 +90 +56 +3C +18 +10 +00 +FE +ENDCHAR +STARTCHAR 2202 +ENCODING 8706 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +0E +1E +33 +21 +01 +0F +3D +61 +C3 +82 +86 +CC +FC +70 +ENDCHAR +STARTCHAR 2206 +ENCODING 8710 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 12 0 1 +BITMAP +0600 +0600 +0A00 +0B00 +1100 +1180 +2180 +20C0 +20C0 +4040 +4060 +FFE0 +ENDCHAR +STARTCHAR 220F +ENCODING 8719 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 13 18 1 -4 +BITMAP +FFF8 +FFF8 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +ENDCHAR +STARTCHAR 2211 +ENCODING 8721 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 -4 +BITMAP +FFF0 +FFF0 +6000 +3000 +3800 +1800 +0C00 +0600 +0300 +0700 +0600 +0C00 +1800 +3000 +6000 +6000 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 2212 +ENCODING 8722 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 2 1 6 +BITMAP +FF80 +FF80 +ENDCHAR +STARTCHAR 2215 +ENCODING 8725 +SWIDTH 154 0 +DWIDTH 3 0 +BBX 11 14 -4 0 +BITMAP +0020 +0040 +00C0 +0180 +0100 +0200 +0600 +0400 +0800 +1800 +3000 +2000 +4000 +C000 +ENDCHAR +STARTCHAR 2219 +ENCODING 8729 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 2 2 6 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR 221A +ENCODING 8730 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 18 1 -1 +BITMAP +0080 +0080 +0080 +0080 +0080 +0080 +0100 +2100 +E100 +3100 +1900 +1900 +0E00 +0E00 +0600 +0600 +0200 +0200 +ENDCHAR +STARTCHAR 221E +ENCODING 8734 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 6 1 4 +BITMAP +71C0 +7BE0 +CE20 +CE20 +7BE0 +71C0 +ENDCHAR +STARTCHAR 221F +ENCODING 8735 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 12 12 3 0 +BITMAP +8000 +8000 +8000 +8000 +8000 +8000 +8000 +8000 +8000 +8000 +8000 +FFF0 +ENDCHAR +STARTCHAR 2229 +ENCODING 8745 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 1 0 +BITMAP +0F00 +3FC0 +70C0 +6060 +4020 +4020 +C020 +C020 +C020 +C020 +C020 +C020 +C020 +C020 +ENDCHAR +STARTCHAR 222B +ENCODING 8747 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 19 0 -2 +BITMAP +18 +38 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +E0 +C0 +ENDCHAR +STARTCHAR 2248 +ENCODING 8776 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 7 0 3 +BITMAP +7C40 +FFC0 +8780 +0000 +7C40 +FFC0 +8780 +ENDCHAR +STARTCHAR 2260 +ENCODING 8800 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 1 0 +BITMAP +0300 +0200 +0200 +0400 +FF80 +FF80 +0800 +1800 +FF80 +FF80 +2000 +2000 +4000 +4000 +ENDCHAR +STARTCHAR 2261 +ENCODING 8801 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 2 +BITMAP +FF80 +FF80 +0000 +0000 +FF80 +FF80 +0000 +0000 +FF80 +FF80 +ENDCHAR +STARTCHAR 2264 +ENCODING 8804 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +0080 +0780 +1E00 +7000 +C000 +7000 +1E00 +0780 +0080 +0000 +FF80 +FF80 +ENDCHAR +STARTCHAR 2265 +ENCODING 8805 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +8000 +E000 +7800 +0F00 +0180 +0F00 +7800 +E000 +8000 +0000 +FF80 +FF80 +ENDCHAR +STARTCHAR 2302 +ENCODING 8962 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 1 +BITMAP +0C00 +1200 +2100 +4100 +8080 +8080 +8080 +8080 +8080 +FF80 +ENDCHAR +STARTCHAR 2310 +ENCODING 8976 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 6 1 4 +BITMAP +FF80 +FF80 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 2320 +ENCODING 8992 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 4 21 5 -5 +BITMAP +70 +10 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR 2321 +ENCODING 8993 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 4 21 2 -5 +BITMAP +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +D0 +60 +ENDCHAR +STARTCHAR 2500 +ENCODING 9472 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 2 0 5 +BITMAP +FFFC +FFFC +ENDCHAR +STARTCHAR 2502 +ENCODING 9474 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 2 23 4 -6 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 250C +ENCODING 9484 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 13 6 -6 +BITMAP +FF +FF +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 2510 +ENCODING 9488 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 13 0 -6 +BITMAP +FF +FF +03 +03 +03 +03 +03 +03 +03 +03 +03 +03 +03 +ENDCHAR +STARTCHAR 2514 +ENCODING 9492 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 12 6 5 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +FF +FF +ENDCHAR +STARTCHAR 2518 +ENCODING 9496 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 12 0 5 +BITMAP +03 +03 +03 +03 +03 +03 +03 +03 +03 +03 +FF +FF +ENDCHAR +STARTCHAR 251C +ENCODING 9500 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 23 6 -6 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +FF +FF +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 2524 +ENCODING 9508 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 23 0 -6 +BITMAP +03 +03 +03 +03 +03 +03 +03 +03 +03 +03 +FF +FF +03 +03 +03 +03 +03 +03 +03 +03 +03 +03 +03 +ENDCHAR +STARTCHAR 252C +ENCODING 9516 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 13 0 -6 +BITMAP +FFFC +FFFC +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 2534 +ENCODING 9524 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 12 0 5 +BITMAP +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +FFFC +FFFC +ENDCHAR +STARTCHAR 253C +ENCODING 9532 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 23 0 -6 +BITMAP +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +FFFC +FFFC +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 2550 +ENCODING 9552 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 5 0 3 +BITMAP +FFFC +0000 +0000 +FFFC +FFFC +ENDCHAR +STARTCHAR 2551 +ENCODING 9553 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 5 23 4 -6 +BITMAP +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +ENDCHAR +STARTCHAR 2552 +ENCODING 9554 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 14 6 -6 +BITMAP +FF +C0 +C0 +FF +FF +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 2553 +ENCODING 9555 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 10 13 4 -6 +BITMAP +FFC0 +FFC0 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +ENDCHAR +STARTCHAR 2554 +ENCODING 9556 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 10 14 4 -6 +BITMAP +FFC0 +C000 +C000 +CFC0 +CFC0 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +ENDCHAR +STARTCHAR 2555 +ENCODING 9557 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 14 0 -6 +BITMAP +FF +03 +03 +FF +FF +03 +03 +03 +03 +03 +03 +03 +03 +03 +ENDCHAR +STARTCHAR 2556 +ENCODING 9558 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 9 13 0 -6 +BITMAP +FF80 +FF80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +ENDCHAR +STARTCHAR 2557 +ENCODING 9559 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 9 14 0 -6 +BITMAP +FF80 +0080 +0080 +FC80 +FC80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +ENDCHAR +STARTCHAR 2558 +ENCODING 9560 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 14 6 3 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +FF +C0 +C0 +FF +FF +ENDCHAR +STARTCHAR 2559 +ENCODING 9561 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 10 12 4 5 +BITMAP +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +FFC0 +FFC0 +ENDCHAR +STARTCHAR 255A +ENCODING 9562 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 10 14 4 3 +BITMAP +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +CFC0 +C000 +C000 +FFC0 +FFC0 +ENDCHAR +STARTCHAR 255B +ENCODING 9563 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 14 0 3 +BITMAP +03 +03 +03 +03 +03 +03 +03 +03 +03 +FF +03 +03 +FF +FF +ENDCHAR +STARTCHAR 255C +ENCODING 9564 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 9 12 0 5 +BITMAP +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +FF80 +FF80 +ENDCHAR +STARTCHAR 255D +ENCODING 9565 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 9 14 0 3 +BITMAP +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +FC80 +0080 +0080 +FF80 +FF80 +ENDCHAR +STARTCHAR 255E +ENCODING 9566 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 23 6 -6 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +FF +C0 +C0 +FF +FF +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 255F +ENCODING 9567 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 10 23 4 -6 +BITMAP +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +CFC0 +CFC0 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +ENDCHAR +STARTCHAR 2560 +ENCODING 9568 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 10 23 4 -6 +BITMAP +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +CFC0 +C000 +C000 +CFC0 +CFC0 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +ENDCHAR +STARTCHAR 2561 +ENCODING 9569 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 23 0 -6 +BITMAP +03 +03 +03 +03 +03 +03 +03 +03 +03 +FF +03 +03 +FF +FF +03 +03 +03 +03 +03 +03 +03 +03 +03 +ENDCHAR +STARTCHAR 2562 +ENCODING 9570 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 9 23 0 -6 +BITMAP +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +FC80 +FC80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +ENDCHAR +STARTCHAR 2563 +ENCODING 9571 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 9 23 0 -6 +BITMAP +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +FC80 +0080 +0080 +FC80 +FC80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +ENDCHAR +STARTCHAR 2564 +ENCODING 9572 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 14 0 -6 +BITMAP +FFFC +0000 +0000 +FFFC +FFFC +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 2565 +ENCODING 9573 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 13 0 -6 +BITMAP +FFFC +FFFC +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +ENDCHAR +STARTCHAR 2566 +ENCODING 9574 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 14 0 -6 +BITMAP +FFFC +0000 +0000 +FCFC +FCFC +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +ENDCHAR +STARTCHAR 2567 +ENCODING 9575 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 14 0 3 +BITMAP +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +FFFC +0000 +0000 +FFFC +FFFC +ENDCHAR +STARTCHAR 2568 +ENCODING 9576 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 12 0 5 +BITMAP +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +FFFC +FFFC +ENDCHAR +STARTCHAR 2569 +ENCODING 9577 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 14 0 3 +BITMAP +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +FCFC +0000 +0000 +FFFC +FFFC +ENDCHAR +STARTCHAR 256A +ENCODING 9578 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 23 0 -6 +BITMAP +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +FFFC +0300 +0300 +FFFC +FFFC +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 256B +ENCODING 9579 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 23 0 -6 +BITMAP +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +FFFC +FFFC +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +ENDCHAR +STARTCHAR 256C +ENCODING 9580 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 23 0 -6 +BITMAP +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +FCFC +0000 +0000 +FCFC +FCFC +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +ENDCHAR +STARTCHAR 2580 +ENCODING 9600 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 11 0 6 +BITMAP +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +ENDCHAR +STARTCHAR 2584 +ENCODING 9604 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 12 0 -6 +BITMAP +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +ENDCHAR +STARTCHAR 2588 +ENCODING 9608 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 23 0 -6 +BITMAP +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +ENDCHAR +STARTCHAR 258C +ENCODING 9612 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 7 23 0 -6 +BITMAP +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +ENDCHAR +STARTCHAR 2590 +ENCODING 9616 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 7 23 7 -6 +BITMAP +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +ENDCHAR +STARTCHAR 2591 +ENCODING 9617 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 22 1 -5 +BITMAP +8440 +0000 +2118 +0000 +8440 +0000 +0000 +2118 +0000 +8440 +0000 +2118 +0000 +0000 +8440 +0000 +2118 +0000 +8440 +0000 +0000 +2118 +ENDCHAR +STARTCHAR 2592 +ENCODING 9618 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 22 0 -5 +BITMAP +52A4 +0000 +AD58 +0000 +52A4 +0000 +0000 +AD58 +0000 +52A4 +0000 +AD58 +0000 +0000 +52A4 +0000 +AD58 +0000 +52A4 +0000 +0000 +AD58 +ENDCHAR +STARTCHAR 2593 +ENCODING 9619 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 14 23 0 -6 +BITMAP +5AB4 +FFFC +A548 +FFFC +5AB4 +FFFC +FFFC +A548 +FFFC +5AB4 +FFFC +A548 +FFFC +FFFC +5AB4 +FFFC +A548 +FFFC +5AB4 +FFFC +FFFC +A548 +FFFC +ENDCHAR +STARTCHAR 25A0 +ENCODING 9632 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 9 1 0 +BITMAP +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +ENDCHAR +STARTCHAR 25A1 +ENCODING 9633 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 9 1 0 +BITMAP +FF80 +8080 +8080 +8080 +8080 +8080 +8080 +8080 +FF80 +ENDCHAR +STARTCHAR 25AA +ENCODING 9642 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 4 1 4 +BITMAP +F8 +F8 +F8 +F8 +ENDCHAR +STARTCHAR 25AB +ENCODING 9643 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 4 1 4 +BITMAP +88 +88 +88 +F8 +ENDCHAR +STARTCHAR 25AC +ENCODING 9644 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 19 4 0 3 +BITMAP +FFFFE0 +FFFFE0 +FFFFE0 +FFFFE0 +ENDCHAR +STARTCHAR 25B2 +ENCODING 9650 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 13 13 3 0 +BITMAP +0200 +0200 +0700 +0700 +0F80 +0F80 +1FC0 +1FC0 +3FE0 +3FE0 +7FF0 +7FF0 +FFF8 +ENDCHAR +STARTCHAR 25BA +ENCODING 9658 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 13 13 3 0 +BITMAP +8000 +E000 +F800 +FE00 +FF80 +FFE0 +FFF8 +FFE0 +FF80 +FE00 +F800 +E000 +8000 +ENDCHAR +STARTCHAR 25BC +ENCODING 9660 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 13 13 3 0 +BITMAP +FFF8 +7FF0 +7FF0 +3FE0 +3FE0 +1FC0 +1FC0 +0F80 +0F80 +0700 +0700 +0200 +0200 +ENDCHAR +STARTCHAR 25C4 +ENCODING 9668 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 13 13 3 0 +BITMAP +0008 +0038 +00F8 +03F8 +0FF8 +3FF8 +FFF8 +3FF8 +0FF8 +03F8 +00F8 +0038 +0008 +ENDCHAR +STARTCHAR 25CA +ENCODING 9674 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +10 +28 +28 +44 +42 +82 +81 +81 +82 +42 +44 +28 +28 +10 +ENDCHAR +STARTCHAR 25CB +ENCODING 9675 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 8 2 1 +BITMAP +44 +82 +81 +01 +01 +80 +42 +38 +ENDCHAR +STARTCHAR 25CF +ENCODING 9679 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 8 2 1 +BITMAP +7C +FE +FF +FF +FF +FE +7E +38 +ENDCHAR +STARTCHAR 25D8 +ENCODING 9688 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 9 1 0 +BITMAP +FF80 +FF80 +FF80 +E380 +E180 +E380 +FF80 +FF80 +FF80 +ENDCHAR +STARTCHAR 25D9 +ENCODING 9689 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 11 0 0 +BITMAP +FFE0 +FFE0 +E6E0 +DF60 +DFA0 +FFA0 +FFA0 +DFE0 +EF60 +F1E0 +FFE0 +ENDCHAR +STARTCHAR 25E6 +ENCODING 9702 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 5 1 4 +BITMAP +20 +90 +88 +88 +70 +ENDCHAR +STARTCHAR 263A +ENCODING 9786 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 12 12 4 -1 +BITMAP +0E00 +3080 +4040 +8020 +91A0 +9190 +8010 +8000 +9120 +4E20 +20C0 +1F00 +ENDCHAR +STARTCHAR 263B +ENCODING 9787 +SWIDTH 1028 0 +DWIDTH 20 0 +BBX 12 12 4 -1 +BITMAP +0F00 +3FC0 +7FE0 +7FE0 +EF70 +EF70 +FFF0 +FFF0 +7FE0 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 263C +ENCODING 9788 +SWIDTH 874 0 +DWIDTH 17 0 +BBX 17 17 0 -2 +BITMAP +008000 +008000 +208200 +11E400 +0C1800 +080800 +000400 +100400 +F00780 +100400 +000400 +080800 +0C1800 +11E400 +208200 +008000 +008000 +ENDCHAR +STARTCHAR 2640 +ENCODING 9792 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 10 14 2 -4 +BITMAP +1E00 +0080 +0000 +8040 +8040 +8040 +0040 +4000 +2000 +0E00 +0000 +0000 +0000 +7FC0 +ENDCHAR +STARTCHAR 2642 +ENCODING 9794 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 17 1 -2 +BITMAP +0060 +0160 +0440 +0000 +0090 +0010 +0100 +0000 +2300 +4080 +8000 +8040 +8040 +8040 +8000 +4080 +2100 +ENDCHAR +STARTCHAR 2660 +ENCODING 9824 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 1 1 +BITMAP +1800 +3C00 +7E00 +FF00 +FF00 +FF80 +E700 +0000 +1800 +3E00 +ENDCHAR +STARTCHAR 2663 +ENCODING 9827 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 11 1 0 +BITMAP +1E00 +1F00 +1F00 +7EC0 +FFE0 +FFE0 +FFE0 +F3C0 +0400 +0C00 +3F00 +ENDCHAR +STARTCHAR 2665 +ENCODING 9829 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 11 1 0 +BITMAP +F780 +FFC0 +FFC0 +FF80 +7F80 +7F00 +3E00 +1E00 +1C00 +0800 +0800 +ENDCHAR +STARTCHAR 2666 +ENCODING 9830 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 11 1 0 +BITMAP +10 +18 +3C +7E +FE +FF +FE +7C +3C +18 +10 +ENDCHAR +STARTCHAR 266A +ENCODING 9834 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 13 0 0 +BITMAP +0600 +0780 +0380 +0080 +0080 +0000 +0000 +0000 +0000 +7800 +F800 +F800 +7800 +ENDCHAR +STARTCHAR 266B +ENCODING 9835 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 15 1 -1 +BITMAP +0060 +03E0 +0FE0 +0E20 +0820 +0820 +0820 +0820 +0820 +09E0 +0BE0 +FBE0 +F9E0 +F800 +F000 +ENDCHAR +STARTCHAR E801 +ENCODING 59393 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 12 -1 0 +BITMAP +C0 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR E802 +ENCODING 59394 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 0 -4 +BITMAP +FC +FE +07 +03 +01 +01 +01 +31 +01 +31 +01 +01 +01 +01 +ENDCHAR +STARTCHAR E803 +ENCODING 59395 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 0 -4 +BITMAP +FC +FE +07 +03 +01 +01 +01 +79 +11 +11 +01 +01 +01 +01 +ENDCHAR +STARTCHAR E804 +ENCODING 59396 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 10 14 -2 0 +BITMAP +1000 +D000 +1000 +1000 +1FC0 +1FC0 +00C0 +00C0 +0080 +0180 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR E805 +ENCODING 59397 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 10 14 -2 0 +BITMAP +1000 +D000 +1000 +1000 +1FC0 +1FC0 +00C0 +0CC0 +0080 +0180 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR E818 +ENCODING 59416 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 7 1 12 +BITMAP +60 +80 +60 +80 +40 +60 +80 +ENDCHAR +STARTCHAR E83A +ENCODING 59450 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 13 2 -1 3 +BITMAP +FFF8 +FFF8 +ENDCHAR +STARTCHAR F001 +ENCODING 61441 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 0 0 +BITMAP +1D +3D +30 +20 +F9 +F9 +21 +21 +21 +21 +21 +21 +21 +21 +ENDCHAR +STARTCHAR F002 +ENCODING 61442 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 0 0 +BITMAP +1D +3D +31 +21 +F9 +F9 +21 +21 +21 +21 +21 +21 +21 +21 +ENDCHAR +STARTCHAR F004 +ENCODING 61444 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 4 2 -5 +BITMAP +C0 +C0 +40 +80 +ENDCHAR +STARTCHAR F005 +ENCODING 61445 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 3 1 -4 +BITMAP +70 +30 +E0 +ENDCHAR +STARTCHAR F006 +ENCODING 61446 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 2 -4 16 +BITMAP +60 +C0 +ENDCHAR +STARTCHAR F007 +ENCODING 61447 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -7 16 +BITMAP +C0 +80 +ENDCHAR +STARTCHAR F008 +ENCODING 61448 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -3 11 +BITMAP +60 +40 +C0 +ENDCHAR +STARTCHAR F009 +ENCODING 61449 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -6 15 +BITMAP +60 +40 +C0 +ENDCHAR +STARTCHAR F00A +ENCODING 61450 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 21 0 -4 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +80 +00 +00 +00 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR F00B +ENCODING 61451 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 21 -2 -4 +BITMAP +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +F0 +ENDCHAR +STARTCHAR F00C +ENCODING 61452 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 21 0 -4 +BITMAP +80 +C0 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR F00D +ENCODING 61453 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 21 -2 -4 +BITMAP +40 +C0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR F00E +ENCODING 61454 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 21 0 -4 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +C0 +ENDCHAR +STARTCHAR F00F +ENCODING 61455 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -8 11 +BITMAP +C0 +60 +20 +ENDCHAR +STARTCHAR F010 +ENCODING 61456 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 2 -5 16 +BITMAP +F0 +30 +ENDCHAR +STARTCHAR F011 +ENCODING 61457 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 2 -8 16 +BITMAP +E0 +60 +ENDCHAR +STARTCHAR F012 +ENCODING 61458 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -4 11 +BITMAP +E0 +30 +70 +ENDCHAR +STARTCHAR F013 +ENCODING 61459 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -7 15 +BITMAP +E0 +30 +70 +ENDCHAR +STARTCHAR F014 +ENCODING 61460 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -7 11 +BITMAP +E0 +30 +70 +ENDCHAR +STARTCHAR F015 +ENCODING 61461 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 7 2 -10 16 +BITMAP +72 +9C +ENDCHAR +STARTCHAR F016 +ENCODING 61462 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -10 15 +BITMAP +64 +9C +ENDCHAR +STARTCHAR F017 +ENCODING 61463 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -12 15 +BITMAP +64 +9C +ENDCHAR +STARTCHAR F018 +ENCODING 61464 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 7 2 -13 15 +BITMAP +76 +DC +ENDCHAR +STARTCHAR F019 +ENCODING 61465 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -8 11 +BITMAP +EC +98 +ENDCHAR +STARTCHAR F01A +ENCODING 61466 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -10 11 +BITMAP +E4 +98 +ENDCHAR +STARTCHAR F01B +ENCODING 61467 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -11 11 +BITMAP +64 +9C +ENDCHAR +STARTCHAR F01C +ENCODING 61468 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -6 15 +BITMAP +74 +DC +ENDCHAR +STARTCHAR F01D +ENCODING 61469 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -5 11 +BITMAP +E4 +98 +ENDCHAR +STARTCHAR F01E +ENCODING 61470 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -7 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F01F +ENCODING 61471 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -8 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F020 +ENCODING 61472 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -10 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F021 +ENCODING 61473 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -8 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F022 +ENCODING 61474 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 2 -10 -3 +BITMAP +80 +80 +ENDCHAR +STARTCHAR F023 +ENCODING 61475 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -6 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F024 +ENCODING 61476 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -6 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F025 +ENCODING 61477 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -6 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F026 +ENCODING 61478 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -8 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F027 +ENCODING 61479 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -7 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F028 +ENCODING 61480 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -9 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F029 +ENCODING 61481 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -4 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F02A +ENCODING 61482 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -3 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F02B +ENCODING 61483 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -7 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F02C +ENCODING 61484 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -2 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F02D +ENCODING 61485 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -9 16 +BITMAP +E4 +98 +ENDCHAR +STARTCHAR F02E +ENCODING 61486 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -9 15 +BITMAP +E4 +98 +ENDCHAR +STARTCHAR F02F +ENCODING 61487 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -10 16 +BITMAP +E4 +98 +ENDCHAR +STARTCHAR F030 +ENCODING 61488 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -10 15 +BITMAP +EC +98 +ENDCHAR +STARTCHAR F031 +ENCODING 61489 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 10 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR FB01 +ENCODING 64257 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 0 0 +BITMAP +1D +3D +30 +20 +F9 +F9 +21 +21 +21 +21 +21 +21 +21 +21 +ENDCHAR +STARTCHAR FB02 +ENCODING 64258 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 0 0 +BITMAP +1D +3D +31 +21 +F9 +F9 +21 +21 +21 +21 +21 +21 +21 +21 +ENDCHAR +STARTCHAR FB1D +ENCODING 64285 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 8 1 2 +BITMAP +C0 +C0 +C0 +C0 +C0 +00 +00 +40 +ENDCHAR +STARTCHAR FB1E +ENCODING 64286 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -3 12 +BITMAP +CC +78 +ENDCHAR +STARTCHAR FB1F +ENCODING 64287 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 7 1 3 +BITMAP +C6 +C6 +C6 +C6 +C6 +00 +FE +ENDCHAR +STARTCHAR FB20 +ENCODING 64288 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 0 0 +BITMAP +6180 +2180 +3180 +3180 +3180 +3180 +1300 +1B00 +FE00 +FC00 +ENDCHAR +STARTCHAR FB2A +ENCODING 64298 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 13 1 0 +BITMAP +0020 +0000 +0000 +C460 +C460 +C460 +CC60 +CC60 +F860 +40C0 +61C0 +3F80 +1F00 +ENDCHAR +STARTCHAR FB2B +ENCODING 64299 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 13 1 0 +BITMAP +C000 +0000 +0000 +C460 +C460 +C460 +CC60 +CC60 +F860 +40C0 +61C0 +3F80 +1F00 +ENDCHAR +STARTCHAR FB2C +ENCODING 64300 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 13 1 0 +BITMAP +0020 +0000 +0000 +C460 +C460 +C460 +CC60 +CC60 +FB60 +40C0 +61C0 +3F80 +1F00 +ENDCHAR +STARTCHAR FB2D +ENCODING 64301 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 13 1 0 +BITMAP +C000 +0000 +0000 +C460 +C460 +C460 +CC60 +CC60 +FB60 +40C0 +61C0 +3F80 +1F00 +ENDCHAR +STARTCHAR FB2E +ENCODING 64302 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 -3 +BITMAP +E180 +6100 +3300 +3B00 +7F00 +4E00 +C600 +C600 +C300 +C180 +0000 +0000 +3C00 +ENDCHAR +STARTCHAR FB2F +ENCODING 64303 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 15 1 -5 +BITMAP +E180 +6100 +3300 +3B00 +7F00 +4E00 +C600 +C600 +C300 +C180 +0000 +0000 +3C00 +0800 +0800 +ENDCHAR +STARTCHAR FB30 +ENCODING 64304 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +E180 +6100 +3300 +3B00 +7F00 +4E00 +C600 +C600 +DB00 +C180 +ENDCHAR +STARTCHAR FB31 +ENCODING 64305 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 10 0 0 +BITMAP +7C00 +7E00 +0700 +0300 +3100 +0100 +0100 +0100 +FFC0 +FFC0 +ENDCHAR +STARTCHAR FB32 +ENCODING 64306 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 10 0 0 +BITMAP +78 +7C +0C +3C +0C +1C +3C +64 +66 +C6 +ENDCHAR +STARTCHAR FB33 +ENCODING 64307 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 0 0 +BITMAP +FF80 +FF80 +0300 +1B00 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR FB34 +ENCODING 64308 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +FE00 +7F00 +0380 +0180 +C980 +C180 +C180 +C180 +C180 +C180 +ENDCHAR +STARTCHAR FB35 +ENCODING 64309 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 10 0 0 +BITMAP +30 +30 +30 +30 +F0 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR FB36 +ENCODING 64310 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 10 0 0 +BITMAP +3F +3F +0C +D8 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR FB38 +ENCODING 64312 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +C700 +CF80 +C980 +C180 +CD80 +C180 +C180 +6380 +7F00 +1E00 +ENDCHAR +STARTCHAR FB39 +ENCODING 64313 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 5 0 5 +BITMAP +30 +30 +F0 +30 +30 +ENDCHAR +STARTCHAR FB3A +ENCODING 64314 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 0 -4 +BITMAP +FC +FE +07 +03 +11 +01 +01 +01 +01 +01 +01 +01 +01 +01 +ENDCHAR +STARTCHAR FB3B +ENCODING 64315 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 10 1 0 +BITMAP +F0 +FC +0C +06 +66 +06 +06 +0C +FC +F0 +ENDCHAR +STARTCHAR FB3C +ENCODING 64316 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 14 1 0 +BITMAP +80 +80 +80 +80 +FE +FE +06 +26 +04 +0C +18 +18 +18 +18 +ENDCHAR +STARTCHAR FB3E +ENCODING 64318 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +CE00 +DF00 +7180 +6180 +6D80 +6180 +4180 +4180 +CF80 +CF80 +ENDCHAR +STARTCHAR FB40 +ENCODING 64320 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 4 10 1 0 +BITMAP +E0 +F0 +30 +10 +90 +10 +10 +10 +F0 +F0 +ENDCHAR +STARTCHAR FB41 +ENCODING 64321 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3E00 +7F00 +E380 +C180 +C980 +C180 +C180 +E380 +7F00 +3E00 +ENDCHAR +STARTCHAR FB43 +ENCODING 64323 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +FC +FF +C3 +C3 +C1 +CD +61 +01 +01 +01 +01 +01 +01 +01 +ENDCHAR +STARTCHAR FB44 +ENCODING 64324 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 1 0 +BITMAP +FC00 +FE00 +C700 +C300 +C180 +6D80 +0300 +8700 +FE00 +7C00 +ENDCHAR +STARTCHAR FB46 +ENCODING 64326 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 10 0 0 +BITMAP +C3 +63 +33 +33 +7E +0C +04 +06 +7F +7F +ENDCHAR +STARTCHAR FB47 +ENCODING 64327 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 -4 +BITMAP +FF +FF +01 +19 +43 +43 +46 +44 +44 +44 +40 +40 +40 +40 +ENDCHAR +STARTCHAR FB48 +ENCODING 64328 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 0 0 +BITMAP +FC +FE +07 +03 +11 +01 +01 +01 +01 +01 +ENDCHAR +STARTCHAR FB49 +ENCODING 64329 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 10 1 0 +BITMAP +C460 +C460 +C460 +CC60 +CC60 +FB60 +40C0 +61C0 +3F80 +1F00 +ENDCHAR +STARTCHAR FB4A +ENCODING 64330 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 10 0 0 +BITMAP +7F80 +7FC0 +18E0 +1860 +1B60 +1860 +1860 +1860 +7860 +F060 +ENDCHAR +STARTCHAR FB4B +ENCODING 64331 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 13 1 0 +BITMAP +40 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR FB4C +ENCODING 64332 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 13 0 0 +BITMAP +1C00 +0000 +0000 +7C00 +7E00 +0700 +0300 +0100 +0100 +0100 +0100 +FFC0 +FFC0 +ENDCHAR +STARTCHAR FB4D +ENCODING 64333 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 13 1 0 +BITMAP +78 +00 +00 +F0 +FC +0C +06 +06 +06 +06 +0C +FC +F0 +ENDCHAR +STARTCHAR FB4E +ENCODING 64334 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +3C00 +0000 +0000 +FC00 +FE00 +C700 +C300 +C180 +7180 +0300 +8700 +FE00 +7C00 +ENDCHAR +STARTCHAR FB4F +ENCODING 64335 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +8000 +8000 +8000 +8000 +E180 +E180 +3180 +3B00 +7F00 +6E00 +4600 +4700 +C300 +C180 +ENDCHAR +STARTCHAR FB50 +ENCODING 64336 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 15 0 2 +BITMAP +30 +F0 +80 +00 +40 +60 +20 +20 +20 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR FB51 +ENCODING 64337 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 5 14 -1 3 +BITMAP +30 +F0 +00 +00 +60 +20 +20 +20 +20 +20 +20 +20 +18 +18 +ENDCHAR +STARTCHAR FB52 +ENCODING 64338 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 -2 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0200 +0200 +0200 +0200 +ENDCHAR +STARTCHAR FB53 +ENCODING 64339 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 -2 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0200 +0200 +0200 +0200 +ENDCHAR +STARTCHAR FB54 +ENCODING 64340 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 -2 +BITMAP +08 +08 +0C +04 +FC +FC +00 +30 +30 +10 +10 +ENDCHAR +STARTCHAR FB55 +ENCODING 64341 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 -2 +BITMAP +08 +08 +0C +04 +FC +FC +00 +30 +30 +10 +10 +ENDCHAR +STARTCHAR FB56 +ENCODING 64342 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 -2 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0100 +0500 +0700 +0300 +ENDCHAR +STARTCHAR FB57 +ENCODING 64343 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 -2 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0100 +0500 +0700 +0300 +ENDCHAR +STARTCHAR FB58 +ENCODING 64344 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 -2 +BITMAP +08 +08 +0C +04 +FC +FC +00 +08 +28 +38 +18 +ENDCHAR +STARTCHAR FB59 +ENCODING 64345 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 -2 +BITMAP +08 +08 +0C +04 +FC +FC +00 +08 +28 +38 +18 +ENDCHAR +STARTCHAR FB5A +ENCODING 64346 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 12 1 -3 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0300 +0D00 +0D00 +0500 +0400 +ENDCHAR +STARTCHAR FB5B +ENCODING 64347 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 12 1 -3 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0300 +0D00 +0D00 +0500 +0400 +ENDCHAR +STARTCHAR FB5C +ENCODING 64348 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 12 -1 -3 +BITMAP +08 +08 +0C +04 +FC +FC +00 +18 +68 +68 +28 +20 +ENDCHAR +STARTCHAR FB5D +ENCODING 64349 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 12 -1 -3 +BITMAP +08 +08 +0C +04 +FC +FC +00 +18 +68 +68 +28 +20 +ENDCHAR +STARTCHAR FB5E +ENCODING 64350 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 3 +BITMAP +0400 +0400 +0600 +0200 +0000 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FB5F +ENCODING 64351 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 3 +BITMAP +0400 +0400 +0600 +0200 +0000 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FB60 +ENCODING 64352 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +20 +20 +30 +10 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FB61 +ENCODING 64353 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +20 +20 +30 +10 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FB62 +ENCODING 64354 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 3 +BITMAP +0200 +0A00 +0900 +0D00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FB63 +ENCODING 64355 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 3 +BITMAP +0200 +0A00 +0900 +0D00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FB64 +ENCODING 64356 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +10 +50 +48 +68 +60 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FB65 +ENCODING 64357 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +10 +50 +48 +68 +60 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FB66 +ENCODING 64358 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 13 1 3 +BITMAP +0400 +0800 +0400 +0780 +0480 +1F80 +0000 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FB67 +ENCODING 64359 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 13 1 3 +BITMAP +0400 +0800 +0400 +0780 +0480 +1F80 +0000 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FB68 +ENCODING 64360 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 13 -1 3 +BITMAP +20 +20 +20 +2C +34 +7C +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FB69 +ENCODING 64361 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 13 -1 3 +BITMAP +20 +20 +20 +2C +34 +7C +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FB6A +ENCODING 64362 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 11 0 3 +BITMAP +0010 +001C +0014 +0010 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR FB6B +ENCODING 64363 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 11 0 3 +BITMAP +0010 +001C +0014 +0010 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR FB6C +ENCODING 64364 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 12 -1 3 +BITMAP +20 +38 +78 +60 +18 +38 +2C +3C +3C +04 +FC +FC +ENDCHAR +STARTCHAR FB6D +ENCODING 64365 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 12 -1 3 +BITMAP +20 +28 +68 +20 +18 +1C +24 +24 +1C +0C +FC +FC +ENDCHAR +STARTCHAR FB6E +ENCODING 64366 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 12 0 3 +BITMAP +0004 +0014 +0014 +0014 +0010 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR FB6F +ENCODING 64367 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 12 0 3 +BITMAP +0004 +0014 +0014 +0014 +0010 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR FB70 +ENCODING 64368 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 14 -1 3 +BITMAP +10 +50 +48 +68 +60 +00 +18 +38 +2C +3C +3C +04 +FC +FC +ENDCHAR +STARTCHAR FB71 +ENCODING 64369 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 14 -1 3 +BITMAP +10 +50 +48 +68 +60 +00 +18 +1C +24 +24 +1C +0C +FC +FC +ENDCHAR +STARTCHAR FB72 +ENCODING 64370 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4000 +8400 +8400 +8600 +4600 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FB73 +ENCODING 64371 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 12 0 -4 +BITMAP +3F80 +7F80 +0E00 +31C0 +41C0 +8800 +8800 +8C00 +4C00 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FB74 +ENCODING 64372 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 11 -1 -2 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0400 +0400 +0600 +0600 +ENDCHAR +STARTCHAR FB75 +ENCODING 64373 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 11 -1 -2 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0400 +0400 +0600 +0600 +ENDCHAR +STARTCHAR FB76 +ENCODING 64374 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4000 +8300 +8B00 +8800 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FB77 +ENCODING 64375 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 12 0 -4 +BITMAP +3F80 +7F80 +0E00 +31C0 +41C0 +8400 +9400 +9000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FB78 +ENCODING 64376 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 10 -1 -1 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0200 +0A00 +0800 +ENDCHAR +STARTCHAR FB79 +ENCODING 64377 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 10 -1 -1 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0200 +0A00 +0800 +ENDCHAR +STARTCHAR FB7A +ENCODING 64378 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4200 +8B00 +8A00 +8200 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FB7B +ENCODING 64379 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 12 0 -4 +BITMAP +3F80 +7F80 +0E00 +31C0 +41C0 +8400 +9400 +9400 +4400 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FB7C +ENCODING 64380 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 11 -1 -2 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0200 +0A00 +0E00 +0200 +ENDCHAR +STARTCHAR FB7D +ENCODING 64381 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 11 -1 -2 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0200 +0A00 +0E00 +0200 +ENDCHAR +STARTCHAR FB7E +ENCODING 64382 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4300 +8B00 +8D00 +8500 +4400 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FB7F +ENCODING 64383 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 12 0 -4 +BITMAP +3F80 +7F80 +0E00 +31C0 +45C0 +9400 +9600 +9E00 +5800 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FB80 +ENCODING 64384 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 12 -1 -3 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0200 +0A00 +0B00 +0D00 +0C00 +ENDCHAR +STARTCHAR FB81 +ENCODING 64385 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 12 -1 -3 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0200 +0A00 +0B00 +0D00 +0C00 +ENDCHAR +STARTCHAR FB82 +ENCODING 64386 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 -1 +BITMAP +20 +30 +18 +08 +08 +08 +F8 +F8 +00 +10 +50 +40 +ENDCHAR +STARTCHAR FB83 +ENCODING 64387 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 -1 +BITMAP +20 +30 +18 +08 +08 +08 +F8 +F8 +00 +10 +50 +40 +ENDCHAR +STARTCHAR FB84 +ENCODING 64388 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 3 +BITMAP +30 +D0 +C0 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FB85 +ENCODING 64389 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 3 +BITMAP +30 +D0 +C0 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FB86 +ENCODING 64390 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 13 1 3 +BITMAP +40 +50 +50 +40 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FB87 +ENCODING 64391 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 13 1 3 +BITMAP +40 +50 +50 +40 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FB88 +ENCODING 64392 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 15 0 3 +BITMAP +20 +20 +20 +2C +34 +FC +00 +10 +18 +0C +04 +04 +04 +7C +7C +ENDCHAR +STARTCHAR FB89 +ENCODING 64393 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 15 0 3 +BITMAP +20 +20 +20 +2C +34 +FC +00 +10 +18 +0C +04 +04 +04 +7C +7C +ENDCHAR +STARTCHAR FB8A +ENCODING 64394 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 15 1 -2 +BITMAP +0C +0F +0B +08 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR FB8B +ENCODING 64395 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 15 1 -2 +BITMAP +0C +0F +0B +08 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR FB8C +ENCODING 64396 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 17 1 -2 +BITMAP +08 +10 +08 +0F +09 +3F +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR FB8D +ENCODING 64397 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 17 1 -2 +BITMAP +08 +10 +08 +0F +09 +3F +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR FB8E +ENCODING 64398 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 11 0 3 +BITMAP +0006 +001E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR FB8F +ENCODING 64399 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 11 0 3 +BITMAP +000600 +001E00 +007800 +004000 +006000 +007000 +001800 +800C00 +801200 +FFF3C0 +7FE1C0 +ENDCHAR +STARTCHAR FB90 +ENCODING 64400 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 11 -1 3 +BITMAP +03 +0F +3C +20 +30 +38 +0C +02 +01 +FF +FF +ENDCHAR +STARTCHAR FB91 +ENCODING 64401 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 11 -1 3 +BITMAP +0300 +0F00 +3C00 +2000 +3000 +3800 +0C00 +0600 +0900 +F9E0 +F0E0 +ENDCHAR +STARTCHAR FB92 +ENCODING 64402 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 14 0 3 +BITMAP +0002 +000E +0038 +0066 +009E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR FB93 +ENCODING 64403 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 14 0 3 +BITMAP +000200 +000E00 +003800 +006600 +009E00 +007800 +004000 +006000 +007000 +001800 +800C00 +801200 +FFF3C0 +7FE1C0 +ENDCHAR +STARTCHAR FB94 +ENCODING 64404 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 14 -1 3 +BITMAP +01 +07 +1C +33 +4F +3C +20 +30 +38 +0C +02 +01 +FF +FF +ENDCHAR +STARTCHAR FB95 +ENCODING 64405 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 14 -1 3 +BITMAP +0100 +0700 +1C00 +3300 +4F00 +3C00 +2000 +3000 +3800 +0C00 +0600 +0900 +F9E0 +F0E0 +ENDCHAR +STARTCHAR FB96 +ENCODING 64406 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 19 0 -2 +BITMAP +0002 +000E +0038 +0066 +009E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +0000 +0080 +0080 +0080 +0080 +ENDCHAR +STARTCHAR FB97 +ENCODING 64407 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 19 0 -2 +BITMAP +000200 +000E00 +003800 +006600 +009E00 +007800 +004000 +006000 +007000 +001800 +800C00 +801200 +FFF3C0 +7FE1C0 +000000 +020000 +020000 +020000 +020000 +ENDCHAR +STARTCHAR FB98 +ENCODING 64408 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 19 -1 -2 +BITMAP +01 +07 +1C +33 +4F +3C +20 +30 +38 +0C +02 +01 +FF +FF +00 +08 +08 +0C +0C +ENDCHAR +STARTCHAR FB99 +ENCODING 64409 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 19 -1 -2 +BITMAP +0100 +0700 +1C00 +3300 +4F00 +3C00 +2000 +3000 +3800 +0C00 +0600 +0900 +F9E0 +F0E0 +0000 +3000 +3000 +1000 +1000 +ENDCHAR +STARTCHAR FB9A +ENCODING 64410 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 14 0 3 +BITMAP +0012 +004E +0038 +0066 +009E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR FB9B +ENCODING 64411 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 14 0 3 +BITMAP +001200 +004E00 +003800 +006600 +009E00 +007800 +004000 +006000 +007000 +001800 +800C00 +801200 +FFF3C0 +7FE1C0 +ENDCHAR +STARTCHAR FB9C +ENCODING 64412 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 14 -1 3 +BITMAP +09 +27 +1C +33 +4F +3C +20 +30 +38 +0C +02 +01 +FF +FF +ENDCHAR +STARTCHAR FB9D +ENCODING 64413 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 14 -1 3 +BITMAP +0900 +2700 +1C00 +3300 +4F00 +3C00 +2000 +3000 +3800 +0C00 +0600 +0900 +F9E0 +F0E0 +ENDCHAR +STARTCHAR FB9E +ENCODING 64414 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 8 1 0 +BITMAP +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR FB9F +ENCODING 64415 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 8 1 0 +BITMAP +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR FBA0 +ENCODING 64416 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 16 1 -1 +BITMAP +1000 +1000 +1000 +1600 +1A00 +3E00 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR FBA1 +ENCODING 64417 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 16 1 -1 +BITMAP +1000 +1000 +1000 +1600 +1A00 +3E00 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR FBA2 +ENCODING 64418 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 13 -1 3 +BITMAP +20 +20 +20 +2C +34 +7C +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FBA3 +ENCODING 64419 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 13 -1 3 +BITMAP +20 +20 +20 +2C +34 +7C +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FBA4 +ENCODING 64420 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 12 1 3 +BITMAP +60 +80 +60 +80 +00 +40 +E0 +F0 +90 +90 +F0 +E0 +ENDCHAR +STARTCHAR FBA5 +ENCODING 64421 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 13 0 3 +BITMAP +30 +40 +30 +40 +10 +10 +28 +48 +F8 +E8 +08 +06 +06 +ENDCHAR +STARTCHAR FBA6 +ENCODING 64422 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 7 1 3 +BITMAP +40 +E0 +F0 +90 +90 +F0 +E0 +ENDCHAR +STARTCHAR FBA7 +ENCODING 64423 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 5 0 2 +BITMAP +18 +3C +6E +46 +80 +ENDCHAR +STARTCHAR FBA8 +ENCODING 64424 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 -2 +BITMAP +08 +08 +0C +04 +FC +FC +00 +10 +20 +30 +10 +ENDCHAR +STARTCHAR FBA9 +ENCODING 64425 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 7 12 -1 -4 +BITMAP +10 +10 +10 +F6 +DE +18 +10 +00 +08 +10 +08 +08 +ENDCHAR +STARTCHAR FBAA +ENCODING 64426 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 8 -1 3 +BITMAP +08 +1C +1C +26 +27 +19 +FF +E7 +ENDCHAR +STARTCHAR FBAB +ENCODING 64427 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 9 0 4 +BITMAP +10 +10 +28 +48 +F8 +E8 +08 +06 +06 +ENDCHAR +STARTCHAR FBAC +ENCODING 64428 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 8 -1 3 +BITMAP +08 +1C +1C +26 +27 +19 +FF +E7 +ENDCHAR +STARTCHAR FBAD +ENCODING 64429 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 10 -1 -1 +BITMAP +04 +0C +14 +18 +FF +FF +24 +34 +1E +0C +ENDCHAR +STARTCHAR FBAE +ENCODING 64430 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 14 7 1 0 +BITMAP +0600 +0E00 +3800 +7000 +8000 +FFFC +FFF8 +ENDCHAR +STARTCHAR FBAF +ENCODING 64431 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 14 9 1 -4 +BITMAP +00FC +07FC +1F00 +3800 +6000 +8000 +8000 +FFFC +FFF8 +ENDCHAR +STARTCHAR FBB0 +ENCODING 64432 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 14 10 1 0 +BITMAP +0800 +3000 +1800 +2600 +0E00 +3800 +7000 +8000 +FFFC +FFF8 +ENDCHAR +STARTCHAR FBB1 +ENCODING 64433 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 14 14 1 -4 +BITMAP +0020 +0040 +0020 +0040 +0000 +00FC +07FC +1F00 +3800 +6000 +8000 +8000 +FFFC +FFF8 +ENDCHAR +STARTCHAR FBD3 +ENCODING 64467 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 13 0 3 +BITMAP +0C00 +0E40 +0B60 +0860 +0240 +0420 +0720 +0120 +0120 +9E20 +C020 +7FE0 +7FE0 +ENDCHAR +STARTCHAR FBD4 +ENCODING 64468 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 13 0 3 +BITMAP +0C00 +0E40 +0B60 +0860 +0240 +0420 +0720 +0120 +0120 +9E20 +C020 +7FE0 +7FE0 +ENDCHAR +STARTCHAR FBD5 +ENCODING 64469 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 13 -1 3 +BITMAP +30 +0C +23 +0F +3C +20 +30 +38 +0C +02 +01 +FF +FF +ENDCHAR +STARTCHAR FBD6 +ENCODING 64470 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 13 -1 3 +BITMAP +30 +0C +23 +0F +3C +20 +30 +38 +0C +02 +01 +FF +FF +ENDCHAR +STARTCHAR FBD7 +ENCODING 64471 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 17 0 -2 +BITMAP +03 +03 +03 +03 +04 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBD8 +ENCODING 64472 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 17 0 -2 +BITMAP +03 +03 +03 +03 +04 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBD9 +ENCODING 64473 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 14 0 -2 +BITMAP +05 +02 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBDA +ENCODING 64474 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 14 0 -2 +BITMAP +05 +02 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBDB +ENCODING 64475 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 17 0 -1 +BITMAP +02 +02 +02 +02 +02 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBDC +ENCODING 64476 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 17 0 -1 +BITMAP +02 +02 +02 +02 +02 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBDD +ENCODING 64477 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 9 16 0 -2 +BITMAP +0C80 +0D00 +0C80 +0D00 +1000 +0300 +0700 +0500 +0500 +0700 +0300 +0100 +0100 +0200 +8600 +7C00 +ENDCHAR +STARTCHAR FBDE +ENCODING 64478 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 16 0 -2 +BITMAP +04 +07 +0D +0C +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBDF +ENCODING 64479 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 16 0 -2 +BITMAP +04 +07 +0D +0C +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBE0 +ENCODING 64480 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 11 0 -2 +BITMAP +03 +07 +05 +05 +07 +03 +19 +07 +02 +86 +7C +ENDCHAR +STARTCHAR FBE1 +ENCODING 64481 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 11 0 -2 +BITMAP +03 +07 +05 +05 +07 +03 +19 +07 +02 +86 +7C +ENDCHAR +STARTCHAR FBE2 +ENCODING 64482 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 14 0 -2 +BITMAP +02 +05 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBE3 +ENCODING 64483 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 14 0 -2 +BITMAP +02 +05 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBE4 +ENCODING 64484 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 13 0 -4 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +0000 +0400 +0400 +ENDCHAR +STARTCHAR FBE5 +ENCODING 64485 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 9 0 -4 +BITMAP +01E0 +43E0 +8200 +83C0 +C040 +7FC0 +3F00 +0400 +0400 +ENDCHAR +STARTCHAR FBE6 +ENCODING 64486 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 -2 +BITMAP +08 +08 +0C +04 +FC +FC +00 +30 +30 +10 +10 +ENDCHAR +STARTCHAR FBE7 +ENCODING 64487 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 -2 +BITMAP +08 +08 +0C +04 +FC +FC +00 +30 +30 +10 +10 +ENDCHAR +STARTCHAR FBFC +ENCODING 64508 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 10 0 -1 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +ENDCHAR +STARTCHAR FBFD +ENCODING 64509 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 7 0 -2 +BITMAP +01E0 +43E0 +8200 +83C0 +C040 +7FC0 +3F00 +ENDCHAR +STARTCHAR FBFE +ENCODING 64510 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 10 -1 -1 +BITMAP +08 +08 +0C +04 +FC +FC +00 +08 +28 +20 +ENDCHAR +STARTCHAR FBFF +ENCODING 64511 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 10 -1 -1 +BITMAP +08 +08 +0C +04 +FC +FC +00 +08 +28 +20 +ENDCHAR +STARTCHAR FC5E +ENCODING 64606 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 8 0 12 +BITMAP +10 +30 +50 +F0 +40 +20 +30 +40 +ENDCHAR +STARTCHAR FC5F +ENCODING 64607 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 7 1 12 +BITMAP +40 +60 +80 +60 +80 +60 +80 +ENDCHAR +STARTCHAR FC60 +ENCODING 64608 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 5 1 12 +BITMAP +60 +80 +40 +60 +80 +ENDCHAR +STARTCHAR FC61 +ENCODING 64609 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 7 1 12 +BITMAP +60 +60 +60 +80 +40 +60 +80 +ENDCHAR +STARTCHAR FC62 +ENCODING 64610 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 5 1 12 +BITMAP +40 +60 +80 +60 +80 +ENDCHAR +STARTCHAR FD3E +ENCODING 64830 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 19 1 -4 +BITMAP +10 +10 +20 +60 +60 +60 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +40 +60 +60 +20 +10 +10 +ENDCHAR +STARTCHAR FD3F +ENCODING 64831 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 19 1 -4 +BITMAP +80 +80 +40 +60 +60 +20 +30 +30 +30 +30 +30 +30 +30 +20 +60 +60 +40 +80 +80 +ENDCHAR +STARTCHAR FDF2 +ENCODING 65010 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 13 0 3 +BITMAP +0200 +0000 +0080 +0580 +0600 +0100 +0120 +0920 +1920 +2920 +49A0 +FFE0 +E760 +ENDCHAR +STARTCHAR FE80 +ENCODING 65152 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 6 8 1 1 +BITMAP +30 +70 +40 +CC +FC +70 +60 +40 +ENDCHAR +STARTCHAR FE81 +ENCODING 65153 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 14 0 2 +BITMAP +F0 +00 +00 +40 +60 +20 +20 +20 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR FE82 +ENCODING 65154 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 13 0 3 +BITMAP +E0 +00 +00 +C0 +40 +40 +40 +40 +40 +40 +40 +30 +30 +ENDCHAR +STARTCHAR FE83 +ENCODING 65155 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 14 1 2 +BITMAP +40 +80 +C0 +80 +00 +00 +80 +C0 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR FE84 +ENCODING 65156 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 13 0 3 +BITMAP +40 +80 +60 +80 +00 +40 +C0 +40 +40 +40 +40 +70 +30 +ENDCHAR +STARTCHAR FE85 +ENCODING 65157 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 16 0 -2 +BITMAP +0C +10 +0C +10 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FE86 +ENCODING 65158 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 16 0 -2 +BITMAP +0C +10 +0C +10 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FE87 +ENCODING 65159 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 16 0 -2 +BITMAP +40 +60 +20 +20 +20 +20 +20 +20 +20 +20 +20 +00 +60 +80 +60 +80 +ENDCHAR +STARTCHAR FE88 +ENCODING 65160 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 15 0 -1 +BITMAP +C0 +40 +40 +40 +40 +40 +40 +40 +30 +30 +00 +40 +80 +60 +80 +ENDCHAR +STARTCHAR FE89 +ENCODING 65161 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 12 0 -1 +BITMAP +2000 +4000 +6060 +40F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +ENDCHAR +STARTCHAR FE8A +ENCODING 65162 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 13 0 -2 +BITMAP +2000 +4000 +6000 +4000 +0000 +0000 +01E0 +43E0 +8200 +83C0 +C040 +7FC0 +3F00 +ENDCHAR +STARTCHAR FE8B +ENCODING 65163 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +10 +20 +10 +20 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FE8C +ENCODING 65164 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +10 +20 +10 +20 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FE8D +ENCODING 65165 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 11 1 3 +BITMAP +80 +C0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR FE8E +ENCODING 65166 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 10 0 4 +BITMAP +C0 +40 +40 +40 +40 +40 +40 +40 +30 +30 +ENDCHAR +STARTCHAR FE8F +ENCODING 65167 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0600 +0600 +ENDCHAR +STARTCHAR FE90 +ENCODING 65168 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0600 +0600 +ENDCHAR +STARTCHAR FE91 +ENCODING 65169 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 9 -1 0 +BITMAP +08 +08 +0C +04 +FC +FC +00 +10 +10 +ENDCHAR +STARTCHAR FE92 +ENCODING 65170 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 9 -1 0 +BITMAP +08 +08 +0C +04 +FC +FC +00 +10 +10 +ENDCHAR +STARTCHAR FE93 +ENCODING 65171 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 11 0 3 +BITMAP +10 +D0 +C0 +00 +20 +30 +78 +48 +48 +78 +70 +ENDCHAR +STARTCHAR FE94 +ENCODING 65172 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 14 0 3 +BITMAP +10 +50 +40 +00 +00 +10 +10 +28 +48 +F8 +E8 +08 +06 +06 +ENDCHAR +STARTCHAR FE95 +ENCODING 65173 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 9 1 3 +BITMAP +0300 +0F00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FE96 +ENCODING 65174 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 9 1 3 +BITMAP +0300 +0F00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FE97 +ENCODING 65175 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 10 -1 3 +BITMAP +08 +28 +20 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FE98 +ENCODING 65176 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 10 -1 3 +BITMAP +08 +28 +20 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FE99 +ENCODING 65177 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 10 1 3 +BITMAP +0400 +0700 +0F00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FE9A +ENCODING 65178 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 10 1 3 +BITMAP +0400 +0700 +0F00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FE9B +ENCODING 65179 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +20 +28 +28 +20 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FE9C +ENCODING 65180 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +20 +28 +28 +20 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FE9D +ENCODING 65181 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4000 +8600 +8600 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FE9E +ENCODING 65182 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 12 0 -4 +BITMAP +3F80 +7F80 +0E00 +31C0 +41C0 +8000 +8400 +8400 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FE9F +ENCODING 65183 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 9 -1 0 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0400 +0400 +ENDCHAR +STARTCHAR FEA0 +ENCODING 65184 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 9 -1 0 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0400 +0400 +ENDCHAR +STARTCHAR FEA1 +ENCODING 65185 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4000 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FEA2 +ENCODING 65186 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 12 0 -4 +BITMAP +3F80 +7F80 +0E00 +31C0 +41C0 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FEA3 +ENCODING 65187 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 6 -1 3 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +ENDCHAR +STARTCHAR FEA4 +ENCODING 65188 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 6 -1 3 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +ENDCHAR +STARTCHAR FEA5 +ENCODING 65189 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 16 0 -4 +BITMAP +0C00 +0400 +0000 +0000 +3F80 +7F80 +0C00 +3000 +4000 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FEA6 +ENCODING 65190 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 16 0 -4 +BITMAP +0400 +0400 +0000 +0000 +3F80 +7F80 +0E00 +31C0 +41C0 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FEA7 +ENCODING 65191 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 10 -1 3 +BITMAP +0400 +0400 +0000 +0000 +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +ENDCHAR +STARTCHAR FEA8 +ENCODING 65192 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 10 -1 3 +BITMAP +0400 +0400 +0000 +0000 +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +ENDCHAR +STARTCHAR FEA9 +ENCODING 65193 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 8 1 3 +BITMAP +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FEAA +ENCODING 65194 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 8 1 3 +BITMAP +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FEAB +ENCODING 65195 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 3 +BITMAP +40 +60 +00 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FEAC +ENCODING 65196 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 3 +BITMAP +40 +60 +00 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FEAD +ENCODING 65197 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 10 1 -2 +BITMAP +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR FEAE +ENCODING 65198 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 10 1 -2 +BITMAP +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR FEAF +ENCODING 65199 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +04 +04 +00 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR FEB0 +ENCODING 65200 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +04 +04 +00 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR FEB1 +ENCODING 65201 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 9 1 -1 +BITMAP +0104 +0182 +0092 +80FE +80FE +8080 +8180 +FF00 +7C00 +ENDCHAR +STARTCHAR FEB2 +ENCODING 65202 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 9 1 -1 +BITMAP +0104 +0182 +0092 +80FE +80FE +8080 +8180 +FF00 +7C00 +ENDCHAR +STARTCHAR FEB3 +ENCODING 65203 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 5 -1 3 +BITMAP +0020 +10A0 +08A0 +FFE0 +FF60 +ENDCHAR +STARTCHAR FEB4 +ENCODING 65204 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 5 -1 3 +BITMAP +0020 +10A0 +08A0 +FFE0 +FF60 +ENDCHAR +STARTCHAR FEB5 +ENCODING 65205 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 1 -1 +BITMAP +0030 +0038 +0028 +0020 +0000 +0104 +0182 +0092 +80FE +80FE +8080 +8180 +FF00 +7C00 +ENDCHAR +STARTCHAR FEB6 +ENCODING 65206 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 1 -1 +BITMAP +0030 +0038 +0028 +0020 +0000 +0104 +0182 +0092 +80FE +80FE +8080 +8180 +FF00 +7C00 +ENDCHAR +STARTCHAR FEB7 +ENCODING 65207 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 10 -1 3 +BITMAP +0100 +01C0 +0340 +0300 +0000 +0020 +10A0 +08A0 +FFE0 +FF60 +ENDCHAR +STARTCHAR FEB8 +ENCODING 65208 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 10 -1 3 +BITMAP +0100 +01C0 +0340 +0300 +0000 +0020 +10A0 +08A0 +FFE0 +FF60 +ENDCHAR +STARTCHAR FEB9 +ENCODING 65209 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 9 1 -1 +BITMAP +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810000 +FF0000 +7C0000 +ENDCHAR +STARTCHAR FEBA +ENCODING 65210 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 9 1 -1 +BITMAP +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810000 +FF0000 +7C0000 +ENDCHAR +STARTCHAR FEBB +ENCODING 65211 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 17 6 -1 3 +BITMAP +000700 +001F80 +103180 +08C180 +FFFF80 +FFFF80 +ENDCHAR +STARTCHAR FEBC +ENCODING 65212 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 17 6 -1 3 +BITMAP +000700 +001F80 +103180 +08C180 +FFFF80 +FFFF80 +ENDCHAR +STARTCHAR FEBD +ENCODING 65213 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 12 1 -1 +BITMAP +000800 +000800 +000000 +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810000 +FF0000 +7C0000 +ENDCHAR +STARTCHAR FEBE +ENCODING 65214 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 12 1 -1 +BITMAP +000800 +000800 +000000 +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810000 +FF0000 +7C0000 +ENDCHAR +STARTCHAR FEBF +ENCODING 65215 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 17 9 -1 3 +BITMAP +006000 +006000 +000000 +000700 +001F80 +103180 +08C180 +FFFF80 +FFFF80 +ENDCHAR +STARTCHAR FEC0 +ENCODING 65216 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 17 9 -1 3 +BITMAP +006000 +006000 +000000 +000700 +001F80 +103180 +08C180 +FFFF80 +FFFF80 +ENDCHAR +STARTCHAR FEC1 +ENCODING 65217 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1800 +0800 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR FEC2 +ENCODING 65218 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1800 +0800 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR FEC3 +ENCODING 65219 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1800 +0800 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR FEC4 +ENCODING 65220 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1800 +0800 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR FEC5 +ENCODING 65221 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1880 +0880 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR FEC6 +ENCODING 65222 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1880 +0880 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR FEC7 +ENCODING 65223 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1880 +0880 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR FEC8 +ENCODING 65224 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1880 +0880 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR FEC9 +ENCODING 65225 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 16 0 -4 +BITMAP +3800 +7C00 +6000 +8000 +8100 +6700 +7C00 +3000 +2000 +4000 +8000 +8000 +C000 +6000 +7F80 +1F00 +ENDCHAR +STARTCHAR FECA +ENCODING 65226 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 9 13 0 -4 +BITMAP +1C00 +3C00 +1C00 +3C00 +2780 +4380 +4000 +8000 +4000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FECB +ENCODING 65227 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 6 -1 3 +BITMAP +1E00 +3F00 +2040 +3380 +FF00 +FC00 +ENDCHAR +STARTCHAR FECC +ENCODING 65228 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 6 -1 3 +BITMAP +1E +3E +3E +0C +FF +E3 +ENDCHAR +STARTCHAR FECD +ENCODING 65229 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 20 0 -4 +BITMAP +1000 +1000 +0000 +0000 +3800 +7C00 +6000 +8000 +8100 +6700 +7C00 +3000 +2000 +4000 +8000 +8000 +C000 +6000 +7F80 +1F00 +ENDCHAR +STARTCHAR FECE +ENCODING 65230 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 9 17 0 -4 +BITMAP +0800 +0800 +0000 +0000 +1C00 +3C00 +1C00 +3C00 +2780 +4380 +4000 +8000 +4000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FECF +ENCODING 65231 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 9 -1 3 +BITMAP +0C00 +0C00 +0000 +1E00 +3F00 +2040 +3380 +FF00 +FC00 +ENDCHAR +STARTCHAR FED0 +ENCODING 65232 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 10 -1 3 +BITMAP +08 +08 +00 +00 +1E +3E +3E +0C +FF +E3 +ENDCHAR +STARTCHAR FED1 +ENCODING 65233 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 10 0 3 +BITMAP +0018 +0018 +0000 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR FED2 +ENCODING 65234 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 10 0 3 +BITMAP +0018 +0018 +0000 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR FED3 +ENCODING 65235 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +10 +10 +00 +18 +38 +2C +3C +3C +04 +FC +FC +ENDCHAR +STARTCHAR FED4 +ENCODING 65236 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 12 -1 3 +BITMAP +08 +08 +00 +00 +18 +1C +24 +24 +1C +0C +FC +FC +ENDCHAR +STARTCHAR FED5 +ENCODING 65237 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 -1 +BITMAP +0100 +0580 +0400 +0000 +0000 +0180 +03C0 +02C0 +83C0 +83C0 +8040 +80C0 +FF80 +7F00 +ENDCHAR +STARTCHAR FED6 +ENCODING 65238 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 -1 +BITMAP +0100 +0580 +0400 +0000 +0000 +0180 +03C0 +02C0 +83C0 +83C0 +8040 +80C0 +FF80 +7F00 +ENDCHAR +STARTCHAR FED7 +ENCODING 65239 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 12 -1 3 +BITMAP +08 +28 +20 +00 +18 +38 +2C +3C +3C +04 +FC +FC +ENDCHAR +STARTCHAR FED8 +ENCODING 65240 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 13 -1 3 +BITMAP +08 +28 +20 +00 +00 +18 +1C +24 +24 +1C +0C +FC +FC +ENDCHAR +STARTCHAR FED9 +ENCODING 65241 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 12 0 3 +BITMAP +0040 +0060 +0060 +0240 +0420 +0720 +0120 +0120 +9E20 +C020 +7FE0 +7FE0 +ENDCHAR +STARTCHAR FEDA +ENCODING 65242 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 12 0 3 +BITMAP +0040 +0060 +0060 +0240 +0420 +0720 +0120 +0120 +9E20 +C020 +7FE0 +7FE0 +ENDCHAR +STARTCHAR FEDB +ENCODING 65243 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 11 -1 3 +BITMAP +03 +0F +3C +20 +30 +38 +0C +02 +01 +FF +FF +ENDCHAR +STARTCHAR FEDC +ENCODING 65244 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 11 -1 3 +BITMAP +03 +0F +3C +20 +30 +38 +0C +02 +01 +FF +FF +ENDCHAR +STARTCHAR FEDD +ENCODING 65245 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 15 1 0 +BITMAP +0200 +0300 +0100 +0100 +0100 +0100 +0100 +0100 +8100 +8080 +8080 +8080 +8300 +FF00 +7E00 +ENDCHAR +STARTCHAR FEDE +ENCODING 65246 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 15 1 0 +BITMAP +0200 +0300 +0100 +0100 +0100 +0100 +0100 +0100 +8100 +8080 +8080 +8080 +8300 +FF00 +7E00 +ENDCHAR +STARTCHAR FEDF +ENCODING 65247 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 5 12 -1 3 +BITMAP +20 +38 +10 +10 +10 +10 +10 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FEE0 +ENCODING 65248 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 5 12 -1 3 +BITMAP +20 +38 +10 +10 +10 +10 +10 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FEE1 +ENCODING 65249 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 11 0 -4 +BITMAP +38 +3C +0C +3C +7C +C0 +80 +80 +40 +40 +40 +ENDCHAR +STARTCHAR FEE2 +ENCODING 65250 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 11 0 -4 +BITMAP +38 +3C +0C +3C +7C +C0 +80 +80 +40 +40 +40 +ENDCHAR +STARTCHAR FEE3 +ENCODING 65251 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 5 -1 3 +BITMAP +02 +0D +1D +FF +F7 +ENDCHAR +STARTCHAR FEE4 +ENCODING 65252 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 5 -1 3 +BITMAP +02 +0D +1D +FF +F7 +ENDCHAR +STARTCHAR FEE5 +ENCODING 65253 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 12 1 -1 +BITMAP +0800 +0800 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR FEE6 +ENCODING 65254 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 12 1 -1 +BITMAP +0800 +0800 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR FEE7 +ENCODING 65255 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 9 -1 3 +BITMAP +10 +10 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FEE8 +ENCODING 65256 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 9 -1 3 +BITMAP +10 +10 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FEE9 +ENCODING 65257 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 7 1 3 +BITMAP +40 +E0 +F0 +90 +90 +F0 +E0 +ENDCHAR +STARTCHAR FEEA +ENCODING 65258 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 9 0 4 +BITMAP +10 +10 +28 +48 +F8 +E8 +08 +06 +06 +ENDCHAR +STARTCHAR FEEB +ENCODING 65259 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 8 -1 3 +BITMAP +08 +1C +1C +26 +27 +19 +FF +E7 +ENDCHAR +STARTCHAR FEEC +ENCODING 65260 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 10 -1 -1 +BITMAP +04 +0C +14 +18 +FF +FF +24 +34 +1E +0C +ENDCHAR +STARTCHAR FEED +ENCODING 65261 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 11 0 -2 +BITMAP +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FEEE +ENCODING 65262 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 11 0 -2 +BITMAP +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FEEF +ENCODING 65263 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 10 0 -1 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +ENDCHAR +STARTCHAR FEF0 +ENCODING 65264 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 7 0 -2 +BITMAP +01E0 +43E0 +8200 +83C0 +C040 +7FC0 +3F00 +ENDCHAR +STARTCHAR FEF1 +ENCODING 65265 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 13 0 -4 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +0300 +0B00 +0800 +ENDCHAR +STARTCHAR FEF2 +ENCODING 65266 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 9 0 -4 +BITMAP +01E0 +43E0 +8200 +83C0 +C040 +7FC0 +3F00 +0A00 +0A00 +ENDCHAR +STARTCHAR FEF3 +ENCODING 65267 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 10 -1 -1 +BITMAP +08 +08 +0C +04 +FC +FC +00 +08 +28 +20 +ENDCHAR +STARTCHAR FEF4 +ENCODING 65268 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 10 -1 -1 +BITMAP +08 +08 +0C +04 +FC +FC +00 +08 +28 +20 +ENDCHAR +STARTCHAR FEF5 +ENCODING 65269 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 15 1 1 +BITMAP +E000 +0000 +8200 +C380 +E100 +6100 +1100 +0A00 +0A00 +0600 +0400 +0600 +1A00 +1E00 +1C00 +ENDCHAR +STARTCHAR FEF6 +ENCODING 65270 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 13 1 3 +BITMAP +E000 +0000 +C000 +F100 +7900 +0500 +0280 +0080 +0180 +0280 +0680 +3CC0 +F840 +ENDCHAR +STARTCHAR FEF7 +ENCODING 65271 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 15 0 1 +BITMAP +6000 +8000 +6100 +81C0 +0080 +4080 +6080 +3080 +0900 +0500 +0300 +0200 +0500 +0F00 +0E00 +ENDCHAR +STARTCHAR FEF8 +ENCODING 65272 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 13 1 3 +BITMAP +4000 +8000 +C000 +8100 +E100 +7900 +0480 +0280 +0180 +0280 +0680 +3CC0 +F840 +ENDCHAR +STARTCHAR FEF9 +ENCODING 65273 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 18 1 -4 +BITMAP +8200 +C380 +E100 +6100 +1100 +0A00 +0A00 +0600 +0400 +0600 +1A00 +1E00 +1C00 +0000 +1000 +2000 +1800 +2000 +ENDCHAR +STARTCHAR FEFA +ENCODING 65274 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 16 1 -2 +BITMAP +C000 +F100 +7900 +0500 +0280 +0080 +0180 +0280 +0680 +3CC0 +F840 +0000 +2000 +4000 +6000 +4000 +ENDCHAR +STARTCHAR FEFB +ENCODING 65275 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 13 1 1 +BITMAP +8200 +C380 +E100 +6100 +1100 +0A00 +0A00 +0600 +0400 +0600 +1A00 +1E00 +1C00 +ENDCHAR +STARTCHAR FEFC +ENCODING 65276 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 11 1 3 +BITMAP +C000 +F100 +7900 +0500 +0280 +0080 +0180 +0280 +0680 +3CC0 +F840 +ENDCHAR +STARTCHAR FFFC +ENCODING 65532 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 19 14 0 0 +BITMAP +E71CE0 +800020 +800020 +000000 +1EF980 +B3C9A0 +A1F1A0 +A1C9A0 +B3C920 +1EFF00 +000000 +800020 +800020 +E71CE0 +ENDCHAR +ENDFONT diff --git a/Asteroid_Tracker/asteroid.bmp b/Asteroid_Tracker/asteroid.bmp new file mode 100644 index 000000000..db026a29f Binary files /dev/null and b/Asteroid_Tracker/asteroid.bmp differ diff --git a/Asteroid_Tracker/code.py b/Asteroid_Tracker/code.py new file mode 100644 index 000000000..1baccafae --- /dev/null +++ b/Asteroid_Tracker/code.py @@ -0,0 +1,161 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import os +import time +import ssl +import board +import wifi +import socketpool +import microcontroller +import displayio +from adafruit_display_text.bitmap_label import Label +from adafruit_bitmap_font import bitmap_font +import adafruit_imageload +from fourwire import FourWire +import adafruit_requests +from adafruit_gc9a01a import GC9A01A +from adafruit_ticks import ticks_ms, ticks_add, ticks_diff + +cad_url = ("https://ssd-api.jpl.nasa.gov/cad.api?" + "des=2024%20YR4&body=ALL&" + "date-min=2030-01-01&date-max=2060-01-01") +sentry_url = "https://ssd-api.jpl.nasa.gov/sentry.api?des=2024%20YR4" +# connect to wifi +try: + wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD')) +except TypeError: + print("Could not find WiFi info. Check your settings.toml file!") + raise +context = ssl.create_default_context() +with open("/ssd-api-jpl-nasa-gov-chain.pem", "rb") as certfile: + context.load_verify_locations(cadata=certfile.read()) + +pool = socketpool.SocketPool(wifi.radio) +requests = adafruit_requests.Session(pool, context) + +spi = board.SPI() +tft_cs = board.TX +tft_dc = board.RX +tft_reset = None + +displayio.release_displays() + +display_bus = FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_reset) +display = GC9A01A(display_bus, width=240, height=240, auto_refresh=False) + +main_group = displayio.Group() +display.root_group = main_group + +bitmap_bg, palette_bg = adafruit_imageload.load("/earth_bg.bmp", + bitmap=displayio.Bitmap, + palette=displayio.Palette) + +grid_bg = displayio.TileGrid(bitmap_bg, pixel_shader=palette_bg) +main_group.append(grid_bg) + +font = bitmap_font.load_font('/Arial-14.bdf') +name_area = Label(font, text="2024 YR4", color=0xFFFFFF, background_color=0x000000) +name_area.anchored_position = (display.width / 2, 0) +name_area.anchor_point = (0.5, 0.0) + +date_area = Label(font, text="2032-12-22", color=0xFFFFFF, background_color=0x000000) +date_area.anchored_position = (display.width / 2, name_area.height+10) +date_area.anchor_point = (0.5, 0.0) + +moon_area = Label(font, text="Moon: ", color=0xFFFFFF, background_color=0x000000) +moon_area.anchored_position = (display.width / 2, name_area.height+10 + date_area.height+5) +moon_area.anchor_point = (0.5, 0.0) + +earth_area = Label(font, text="Earth: ", color=0xFFFFFF, background_color=0x000000) +earth_area.anchored_position = (display.width / 2, name_area.height+10 + + moon_area.height+5 + + date_area.height + 5) +earth_area.anchor_point = (0.5, 0.0) + +impact_area = Label(font, text="Earth Impact: 0.0000%", color=0xFFFFFF, background_color=0x000000) +impact_area.anchored_position = (display.width / 2, name_area.height+10 + + moon_area.height+5 + + earth_area.height + 5 + + date_area.height + 5) +impact_area.anchor_point = (0.5, 0.0) +main_group.append(impact_area) +main_group.append(earth_area) +main_group.append(moon_area) +main_group.append(date_area) +main_group.append(name_area) + +bit_asteroid, pal_asteroid = adafruit_imageload.load("/asteroid.bmp", + bitmap=displayio.Bitmap, + palette=displayio.Palette) + +asteroid = displayio.TileGrid(bit_asteroid, pixel_shader=pal_asteroid, + x = 25, y=100) +pal_asteroid.make_transparent(0) +main_group.append(asteroid) + +def diagonal_travel(bitmap_object, start_x=-59, start_y=-59, end_x=240, end_y=240, delay=0.01): + # Set initial position + bitmap_object.x = start_x + bitmap_object.y = start_y + + # Calculate total movement distance + distance_x = end_x - start_x + distance_y = end_y - start_y + + # Calculate number of steps (use the larger distance) + steps = max(abs(distance_x), abs(distance_y)) // 1 + + # Calculate step size for each axis to maintain diagonal movement + step_x = distance_x / steps + step_y = distance_y / steps + + # Animate the movement + for i in range(steps + 1): + # Update position + bitmap_object.x = int(start_x + (step_x * i)) + bitmap_object.y = int(start_y + (step_y * i)) + display.refresh() + # Pause to control animation speed + time.sleep(delay) + +def au_to_miles(au): + # 1 AU = 92,955,807 miles + miles_per_au = 92955807 + + return au * miles_per_au + +timer_clock = ticks_ms() +timer = 3600 * 1000 +first_run = True + +while True: + try: + if first_run or ticks_diff(ticks_ms(), timer_clock) >= timer: + sentry_response = requests.get(sentry_url) + sentry_json = sentry_response.json() + impact = sentry_json['summary']['ip'] + sentry_response.close() + overall_ip = float(impact) * 100 + cad_response = requests.get(cad_url) + cad_json = cad_response.json() + earth_distance = au_to_miles(float(cad_json['data'][0][4])) + earth_area.text = f"{cad_json['data'][0][10]}: {int(earth_distance)} mi" + moon_distance = au_to_miles(float(cad_json['data'][1][4])) + moon_area.text = f"{cad_json['data'][1][10]}: {int(moon_distance)} mi" + date = cad_json['data'][0][3] + date = date.split() + date_area.text = f"{date[0]}" + cad_response.close() + impact_area.text = f"Earth Impact: {overall_ip:.4f}%" + display.refresh() + timer_clock = ticks_add(timer_clock, timer) + diagonal_travel(asteroid, start_x=-45, start_y=300, end_x=300, end_y=-45) + time.sleep(0.1) + # pylint: disable=broad-except + except Exception as e: + print("Error:\n", str(e)) + print("Resetting microcontroller in 10 seconds") + time.sleep(10) + microcontroller.reset() diff --git a/Asteroid_Tracker/earth_bg.bmp b/Asteroid_Tracker/earth_bg.bmp new file mode 100644 index 000000000..ab3215bc0 Binary files /dev/null and b/Asteroid_Tracker/earth_bg.bmp differ diff --git a/Asteroid_Tracker/ssd-api-jpl-nasa-gov-chain.pem b/Asteroid_Tracker/ssd-api-jpl-nasa-gov-chain.pem new file mode 100644 index 000000000..8e7e3df1a --- /dev/null +++ b/Asteroid_Tracker/ssd-api-jpl-nasa-gov-chain.pem @@ -0,0 +1,109 @@ +-----BEGIN CERTIFICATE----- +MIIHRjCCBS6gAwIBAgIQV82HcwAIb4tFlHpCQCtGuzANBgkqhkiG9w0BAQsFADBR +MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSgwJgYDVQQD +DB9FbnRydXN0IE9WIFRMUyBJc3N1aW5nIFJTQSBDQSAxMB4XDTI1MDIwNTE0MDkw +MloXDTI2MDMwMzE0MTg1OFoweDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlm +b3JuaWExETAPBgNVBAcMCFBhc2FkZW5hMSIwIAYDVQQKDBlKZXQgUHJvcHVsc2lv +biBMYWJvcmF0b3J5MR0wGwYDVQQDDBRzc2QtYXBpLmpwbC5uYXNhLmdvdjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKXzsG9/H8CQzmmu1vwdM1RYrziS +8dzCuw2fqOJXfvOEB+jbZZGIPDvUXCqug0Gb+Z5MsbAdwxT8RsKRuWl/xgRZWr/Y +mtafmEIf3QeKy3/Hu2uUS1GQjTkfmY/3cj6szXJDF4YAC3lngFVWftmGrXhA1Dmm +WqApxguIf2XPjetKjcX1TMdC5XyQ/lsy/vJTX+S8G9HRk+OhO45kAf8AvVeCWCOa +XQ7jpEVBd610RGgD972XNazhoYtL2QKBm6GrSkx1rW/7aiPU0QLbkCoTJIno1yHn +nlYKVYWn0V1uG2vcuChhebX6WOHp7U6KAcaKVbTvaTxv8whi+t4gjcJRbgECAwEA +AaOCAvEwggLtMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUaA1FyjXC55ob8LOE +3dXafwuJwREwaAYIKwYBBQUHAQEEXDBaMDYGCCsGAQUFBzAChipodHRwOi8vY2Vy +dC5zc2wuY29tL0VudHJ1c3QtT1ZUTFMtSS1SMS5jZXIwIAYIKwYBBQUHMAGGFGh0 +dHA6Ly9vY3Nwcy5zc2wuY29tMB8GA1UdEQQYMBaCFHNzZC1hcGkuanBsLm5hc2Eu +Z292MCMGA1UdIAQcMBowCAYGZ4EMAQICMA4GDCsGAQQBgqkwAQMBAjAdBgNVHSUE +FjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDov +L2NybHMuc3NsLmNvbS9FbnRydXN0LU9WVExTLUktUjEuY3JsMB0GA1UdDgQWBBQ9 +28d7XB5zNhW4Z/FiFGVefv8TpDAOBgNVHQ8BAf8EBAMCBaAwggF/BgorBgEEAdZ5 +AgQCBIIBbwSCAWsBaQB3AJaXZL9VWJet90OHaDcIQnfp8DrV9qTzNm5GpD8PyqnG +AAABlNZ6jp0AAAQDAEgwRgIhAM/xkbmguT7NTj3lc6p/F3Um9y7fDhYjzHhWvyDc +HIaQAiEAmRCNTCoJAOFtiXFseiUANEn16Wr3rW5cAUiAJ3mQPewAdwDLOPcViXyE +oURfW8Hd+8lu8ppZzUcKaQWFsMsUwxRY5wAAAZTWeo6SAAAEAwBIMEYCIQCExfjt +QsfbwEpS8cI3YNcXOAW3fMiAh6vOW2wD88iruwIhALfInWVFlobCtQYXLtXq2iqe +HO083hp/cD0oDIChPD9SAHUAZBHEbKQS7KeJHKICLgC8q08oB9QeNSer6v7VA8l9 +zfAAAAGU1nqOzgAABAMARjBEAiBTSQczvVZCJ41l+JiC9n8fOkuYNf8jQ1uG5rKy +M/g6IwIgK7YZziGBfBHHKYR8e+IyitJktRevFehnGPEwbMNOO1wwDQYJKoZIhvcN +AQELBQADggIBAGCVD/1ROYGTKPhFeDUFiPjW7JKagsmldnWdtYQ7ran5Ozd8Hkju +XaEi/sDed8wHv1Bf8lesHd3dz2KlaefLVBknntOMSC7fxr7cvkHHgJyJbWtrOESF +JTuy13CdbIHZTxSRtVErCqumUC4omAOfffoGEMlcKvLlIK1NtZTibPsmeUVceMjI +1iZ6OeAOQfZHwlHk49r1zN2D41/5NOT6hpg1bP+rwp/ZhRpT0cB0Q+PBF/GeRCJp +fyLWng/yfILPl2EZoo2RJ0FbdM7VhxGK9359CbKpIPDrZAqagTafEvzRoL9afBAo +n/fht0RCmHiz56vmYo4a742Hwr1Hgempgx+UBlTluf7UGEJ3ju9JEgM/wY+Zc9wm +HyBcQjzPFcDMGGJo/cQwPNYOI06LePpvGiWLe/8WvW+MSPk19JEQj4uOf02Yowzj +1LXFvSzTase6AjrjiOPd57rgmwUKju+/ouX5qyOBbB4dKJ1Q7pOvb2wR+yF/2Mro +YJS73WJVK64mk6aletwcL0uy+vZiZlesBWIiERPR915NiDEeEYSXYtmwu0XhiS8b +jxpMbXIEuhRtA3c8WeqKCbuSnQs+8SMaYpHZ3QgwCreBWl25J5J4nPtW3tPgINkG +gKDVZyGsOJE4t/sQs7zoQAf4rX7eY+U4w+6CIE7XAkACI7Mug6kXOJZJ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGVjCCBD6gAwIBAgIQb+Y+3l/BwDr7bXqFvToVbTANBgkqhkiG9w0BAQsFADBO +MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD +DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTI0MDgyMjE3NTMzOFoX +DTI3MDgyMjE3NTMzN1owUTELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw +b3JhdGlvbjEoMCYGA1UEAwwfRW50cnVzdCBPViBUTFMgSXNzdWluZyBSU0EgQ0Eg +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKCL+NvDMIL3efFuNaQc +aYwzFpZQd/B6gkTd0s+Cu5jFu3Iw5qxis7xsRQWf739+ohRm42PYEiH7IjErxQAw ++jbLstW7HP7UaTDoYSN/IZ5mG0wHF/QLlAyXsGz9hNPPE31CN8xfA4JFH8jaQftN +QJJnRgWKFys3LK/U2YWbOkx4M50XHFsEDkAuwkt11vEzveJkglfd2O9srAhMsz21 +YciZed5VQRncdFbY0hh/hbs9n9eRkmg/ItDOmvKbWiljXP7Pigl9mMJWfnqEJaUd +tt4FzpiizghGgTwGytDAUH7GxtiLdf3F/Vs5UhRUdEQEnm5Y1OVdjLb3CZpTc3vw +XViwO/jG7b64Ancehrrpagbj8yVXGk4Vh8Rj4nf99whmGGP+z9+9T5DXaWTF2xt9 +PCbviJaIotT3XO7J2VGZyxnV85us4WVY7/vpCQgUEajsglaFW53UCD3uzuBUR3lW +YDWZvd7wiPg5wWhA6DXL//MKVQ0dvUJ03AI+zxUvYCDyhBPOEx9ojRgF7HOvq+wG +EvX6kV34e5ZLaeR0Wr8iaUq8Wl9oPB0vxuZdJMT4ewNHjLB6IFJY4cszBQBPmxMx +jnRkaDb7B/dlS/I2sjTyxB/n+CwbHbuiwkKqVVQpbYws7cmrkUjLQklqFO1xJrVI +Me3bAHHqOZeMfUYCo5gxrPCLAgMBAAGjggErMIIBJzASBgNVHRMBAf8ECDAGAQH/ +AgEAMB8GA1UdIwQYMBaAFPsuN+7jhHonLs0ZNbEzfP/UREK5MEwGCCsGAQUFBwEB +BEAwPjA8BggrBgEFBQcwAoYwaHR0cDovL2NlcnQuc3NsLmNvbS9TU0xjb20tVExT +LVJvb3QtMjAyMi1SU0EuY2VyMBEGA1UdIAQKMAgwBgYEVR0gADAdBgNVHSUEFjAU +BggrBgEFBQcDAgYIKwYBBQUHAwEwQQYDVR0fBDowODA2oDSgMoYwaHR0cDovL2Ny +bHMuc3NsLmNvbS9TU0xjb20tVExTLVJvb3QtMjAyMi1SU0EuY3JsMB0GA1UdDgQW +BBRoDUXKNcLnmhvws4Td1dp/C4nBETAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcN +AQELBQADggIBABNdeusuCgNkxuATfOU8MHWeX7BYQA77yRx/fdV5rEMOdIRMRH/J +Ar7qQ+RH9SY4tqAwkfsKBNhgqZnjzeYOMmOVRTlOQpKJwMwZbX5M1IvuF45EF5BO +dwRBIMAqSxLzFV4CAS1LUEptuA6SGMC6thY4TdQoHN1YR5A/tFmPj9ASDxlqE7Wc +7ZkeL1R8NAKNbcYGPEUXAy9NMiIwwnTqJqQSQXAquf8rhOiOfqWoghMU1xUQ4VgO +aPPCbHCanTLWLLo6MEcHuVNdYvtTUmxixuTcqU2E+XfzUH0qoOskiwxAXncRaM+H +7diEROecsP9PQFui/ll7QmiEE4goazA72Mvk1IsL7+2gI9BrUgWGxGLOoCcJqvUg +Z/8K6N5UJZKXnjOL+tjQVk8qCcF818vuOtOvSAQUeOjSdb1QjaM18Fc62qyclga8 +FIxqs4UPJg7ozHrCkPBUXb1MlUu0yf0Y9i8R9woh6S0k4TZGZKKKdxmS7QnF4D6M +Rr60DDCwdUKP5dMmqPsWd2qaBxlaS3wacNqjhdt0DbXmEOz18BRiKbRxaZ4sDxn9 +O8XngqHUi9j5bulLTfQSqxDXuMwG0WjkqgkJaCujQ1zIZ7sSIcfGzBevRSy1R32Y +Wp1i1vr3oWsj+Cw9gr8FPEw/pPcW7GWfoJvpiHVQ99u7+vUqjQQ13ieL +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO +MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD +DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX +DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw +b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP +L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY +t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins +S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3 +PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO +L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3 +R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w +dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS ++YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS +d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG +AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f +gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j +BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z +NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt +hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM +QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf +R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ +DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW +P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy +lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq +bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w +AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q +r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji +Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU +98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= +-----END CERTIFICATE----- diff --git a/Azure_Food_Scale/code.py b/Azure_Food_Scale/code.py index 2386afa34..3c6204a5e 100644 --- a/Azure_Food_Scale/code.py +++ b/Azure_Food_Scale/code.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries # SPDX-License-Identifier: MIT +from os import getenv import time import json import board @@ -38,15 +39,20 @@ nau7802.gain = 128 enabled = nau7802.enable(True) -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) print("Connecting to WiFi...") -wifi.radio.connect(secrets["ssid"], secrets["password"]) +wifi.radio.connect(ssid, password) print("Connected to WiFi!") # check system time @@ -65,7 +71,7 @@ esp = None pool = socketpool.SocketPool(wifi.radio) device = IoTCentralDevice( - pool, esp, secrets['id_scope'], secrets['device_id'], secrets['device_primary_key'] + pool, esp, getenv("id_scope"), getenv("device_id"), getenv("device_primary_key") ) display.fill(0) display.print("DIALING*") @@ -191,6 +197,8 @@ def send_to_azure(current_oz, current_grams): values = [] val_offset = 0 avg_values = [] +the_ounces = 0 +the_grams = 0 # initial reading from the scale for w in range(5): diff --git a/Bare_eInk_Guide/212x104_flexible_monochrome_arduino/.uno.test.only b/Bare_eInk_Guide/212x104_flexible_monochrome_arduino/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Bare_eInk_Guide/212x104_flexible_monochrome_arduino/212x104_flexible_monochrome_arduino.ino b/Bare_eInk_Guide/212x104_flexible_monochrome_arduino/212x104_flexible_monochrome_arduino.ino new file mode 100644 index 000000000..0c4f208d6 --- /dev/null +++ b/Bare_eInk_Guide/212x104_flexible_monochrome_arduino/212x104_flexible_monochrome_arduino.ino @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: 2025 Ladyada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/*************************************************** + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_ThinkInk.h" + +#ifdef ARDUINO_ADAFRUIT_FEATHER_RP2040_THINKINK // detects if compiling for + // Feather RP2040 ThinkInk +#define EPD_DC PIN_EPD_DC // ThinkInk 24-pin connector DC +#define EPD_CS PIN_EPD_CS // ThinkInk 24-pin connector CS +#define EPD_BUSY PIN_EPD_BUSY // ThinkInk 24-pin connector Busy +#define SRAM_CS -1 // use onboard RAM +#define EPD_RESET PIN_EPD_RESET // ThinkInk 24-pin connector Reset +#define EPD_SPI &SPI1 // secondary SPI for ThinkInk +#else +#define EPD_DC 10 +#define EPD_CS 9 +#define EPD_BUSY 7 // can set to -1 to not use a pin (will wait a fixed delay) +#define SRAM_CS 6 +#define EPD_RESET 8 // can set to -1 and share with microcontroller Reset! +#define EPD_SPI &SPI // primary SPI +#endif + +// 2.13" 212x104 Flexible Monochrome and IL0373 chipset +ThinkInk_213_Grayscale4_T5 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY, EPD_SPI); + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + Serial.println("Adafruit EPD full update test in mono"); + Serial.println("2.13 Monochrome EPD with IL0373 chipset"); + display.begin(THINKINK_MONO); +} + +void loop() { + Serial.println("Banner demo"); + display.clearBuffer(); + display.setTextSize(3); + display.setCursor((display.width() - 180) / 2, (display.height() - 24) / 2); + display.setTextColor(EPD_BLACK); + display.print("Monochrome"); + display.display(); + + delay(2000); + + Serial.println("B/W rectangle demo"); + display.clearBuffer(); + display.fillRect(display.width() / 2, 0, display.width() / 2, + display.height(), EPD_BLACK); + display.display(); + + delay(2000); + + Serial.println("Text demo"); + // large block of text + display.clearBuffer(); + display.setTextSize(1); + testdrawtext( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " + "adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, " + "fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor " + "neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet " + "ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a " + "tortor imperdiet posuere. ", + EPD_BLACK); + display.display(); + + delay(2000); + + display.clearBuffer(); + for (int16_t i = 0; i < display.width(); i += 4) { + display.drawLine(0, 0, i, display.height() - 1, EPD_BLACK); + } + + for (int16_t i = 0; i < display.height(); i += 4) { + display.drawLine(display.width() - 1, 0, 0, i, EPD_BLACK); + } + display.display(); + + delay(2000); +} + +void testdrawtext(const char *text, uint16_t color) { + display.setCursor(0, 0); + display.setTextColor(color); + display.setTextWrap(true); + display.print(text); +} diff --git a/Bare_eInk_Guide/212x104_flexible_monochrome_circuitpython/code.py b/Bare_eInk_Guide/212x104_flexible_monochrome_circuitpython/code.py new file mode 100644 index 000000000..5800d2b68 --- /dev/null +++ b/Bare_eInk_Guide/212x104_flexible_monochrome_circuitpython/code.py @@ -0,0 +1,57 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft, written for Adafruit Industries +# SPDX-FileCopyrightText: Copyright (c) 2021 Melissa LeBlanc-Williams for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +"""Simple test for 2.13" 212x104 Flexible Monochrome eInk display.""" + +import time + +import board +import busio +import displayio +from fourwire import FourWire + +import adafruit_il0373 + +displayio.release_displays() + +if "EPD_MOSI" in dir(board): # Feather RP2040 ThinkInk + spi = busio.SPI(board.EPD_SCK, MOSI=board.EPD_MOSI, MISO=None) + epd_cs = board.EPD_CS + epd_dc = board.EPD_DC + epd_reset = board.EPD_RESET + epd_busy = board.EPD_BUSY +else: + spi = board.SPI() # Uses SCK and MOSI + epd_cs = board.D9 + epd_dc = board.D10 + epd_reset = board.D8 # Set to None for FeatherWing + epd_busy = board.D7 # Set to None for FeatherWing + +display_bus = FourWire(spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=1000000) +time.sleep(1) + +display = adafruit_il0373.IL0373( + display_bus, width=212, height=104, rotation=90, busy_pin=epd_busy, + black_bits_inverted=False, color_bits_inverted=True, swap_rams=True +) + +g = displayio.Group() + +pic = displayio.OnDiskBitmap("/display-ruler-640x360.bmp") +t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) +g.append(t) + +display.root_group = g + +display.refresh() + +print("refreshed") + +time.sleep(display.time_to_refresh + 5) +print("waited correct time") + +# Keep the display the same +while True: + time.sleep(10) diff --git a/Bare_eInk_Guide/212x104_flexible_monochrome_circuitpython/display-ruler-640x360.bmp b/Bare_eInk_Guide/212x104_flexible_monochrome_circuitpython/display-ruler-640x360.bmp new file mode 100644 index 000000000..a9c776e75 Binary files /dev/null and b/Bare_eInk_Guide/212x104_flexible_monochrome_circuitpython/display-ruler-640x360.bmp differ diff --git a/Bare_eInk_Guide/212x104_flexible_monochrome_python/code.py b/Bare_eInk_Guide/212x104_flexible_monochrome_python/code.py new file mode 100644 index 000000000..ae9d7ebb3 --- /dev/null +++ b/Bare_eInk_Guide/212x104_flexible_monochrome_python/code.py @@ -0,0 +1,97 @@ +# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +ePaper Display Shapes and Text demo using the Pillow Library. +2.13" 212x104 Flexible Monochrome +https://www.adafruit.com/product/4243 +""" + +import board +import busio +import digitalio +from PIL import Image, ImageDraw, ImageFont + +from adafruit_epd.il0373 import Adafruit_IL0373_213_Flex_Mono + +# First define some color constants +WHITE = (0xFF, 0xFF, 0xFF) +BLACK = (0x00, 0x00, 0x00) + +# Next define some constants to allow easy resizing of shapes and colors +BORDER = 20 +FONTSIZE = 24 +BACKGROUND_COLOR = BLACK +FOREGROUND_COLOR = WHITE +TEXT_COLOR = BLACK + +# create the spi device and pins we will need +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) +ecs = digitalio.DigitalInOut(board.CE0) +dc = digitalio.DigitalInOut(board.D22) +srcs = None +rst = digitalio.DigitalInOut(board.D27) +busy = digitalio.DigitalInOut(board.D17) + +# give them all to our driver +display = Adafruit_IL0373_213_Flex_Mono(104, 212, + spi, + cs_pin=ecs, + dc_pin=dc, + sramcs_pin=srcs, + rst_pin=rst, + busy_pin=busy, +) + +display.rotation = 3 +width = display.width +height = display.height +image = Image.new("RGB", (width, height)) + +# clear the buffer +display.fill(WHITE) + +# Get drawing object to draw on image. +draw = ImageDraw.Draw(image) +# empty it +draw.rectangle((0, 0, width, height), fill=WHITE) + +# Draw an outline box +draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE) + +# Draw some shapes. +# First define some constants to allow easy resizing of shapes. +padding = 5 +shape_width = 30 +top = padding +bottom = height - padding +# Move left to right keeping track of the current x position for drawing shapes. +x = padding +# Draw an ellipse. +draw.ellipse((x, top, x + shape_width, bottom), outline=BLACK, fill=WHITE) +x += shape_width + padding +# Draw a rectangle. +draw.rectangle((x, top, x + shape_width, bottom), outline=BLACK, fill=BLACK) +x += shape_width + padding +# Draw a triangle. +draw.polygon( + [(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)], + outline=BLACK, + fill=BLACK, +) +x += shape_width + padding +# Draw an X. +draw.line((x, bottom, x + shape_width, top), fill=BLACK) +draw.line((x, top, x + shape_width, bottom), fill=BLACK) +x += shape_width + padding + +# Load default font. +font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20) + +draw.text((x, top), "Hello", font=font, fill=BLACK) +draw.text((x, top + 20), "World!", font=font, fill=BLACK) + +# Display image. +display.image(image) + +display.display() diff --git a/Bare_eInk_Guide/250x122_monochrome_arduino/.uno.test.only b/Bare_eInk_Guide/250x122_monochrome_arduino/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Bare_eInk_Guide/250x122_monochrome_arduino/250x122_monochrome_arduino.ino b/Bare_eInk_Guide/250x122_monochrome_arduino/250x122_monochrome_arduino.ino new file mode 100644 index 000000000..b87ee1bff --- /dev/null +++ b/Bare_eInk_Guide/250x122_monochrome_arduino/250x122_monochrome_arduino.ino @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: 2025 Ladyada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/*************************************************** + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_ThinkInk.h" + +#ifdef ARDUINO_ADAFRUIT_FEATHER_RP2040_THINKINK // detects if compiling for + // Feather RP2040 ThinkInk +#define EPD_DC PIN_EPD_DC // ThinkInk 24-pin connector DC +#define EPD_CS PIN_EPD_CS // ThinkInk 24-pin connector CS +#define EPD_BUSY PIN_EPD_BUSY // ThinkInk 24-pin connector Busy +#define SRAM_CS -1 // use onboard RAM +#define EPD_RESET PIN_EPD_RESET // ThinkInk 24-pin connector Reset +#define EPD_SPI &SPI1 // secondary SPI for ThinkInk +#else +#define EPD_DC 10 +#define EPD_CS 9 +#define EPD_BUSY 7 // can set to -1 to not use a pin (will wait a fixed delay) +#define SRAM_CS 6 +#define EPD_RESET 8 // can set to -1 and share with microcontroller Reset! +#define EPD_SPI &SPI // primary SPI +#endif + +// 2.13" Monochrome displays with 250x122 pixels and SSD1680Z chipset +ThinkInk_213_Mono_GDEY0213B74 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY, EPD_SPI); + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + Serial.println("Adafruit EPD full update test in mono"); + Serial.println("2.13 Monochrome EPD with SSD1680Z chipset"); + display.begin(THINKINK_MONO); +} + +void loop() { + Serial.println("Banner demo"); + display.clearBuffer(); + display.setTextSize(3); + display.setCursor((display.width() - 180) / 2, (display.height() - 24) / 2); + display.setTextColor(EPD_BLACK); + display.print("Monochrome"); + display.display(); + + delay(2000); + + Serial.println("B/W rectangle demo"); + display.clearBuffer(); + display.fillRect(display.width() / 2, 0, display.width() / 2, + display.height(), EPD_BLACK); + display.display(); + + delay(2000); + + Serial.println("Text demo"); + // large block of text + display.clearBuffer(); + display.setTextSize(1); + testdrawtext( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " + "adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, " + "fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor " + "neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet " + "ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a " + "tortor imperdiet posuere. ", + EPD_BLACK); + display.display(); + + delay(2000); + + display.clearBuffer(); + for (int16_t i = 0; i < display.width(); i += 4) { + display.drawLine(0, 0, i, display.height() - 1, EPD_BLACK); + } + + for (int16_t i = 0; i < display.height(); i += 4) { + display.drawLine(display.width() - 1, 0, 0, i, EPD_BLACK); + } + display.display(); + + delay(2000); +} + +void testdrawtext(const char *text, uint16_t color) { + display.setCursor(0, 0); + display.setTextColor(color); + display.setTextWrap(true); + display.print(text); +} diff --git a/Bare_eInk_Guide/250x122_monochrome_circuitpython/code.py b/Bare_eInk_Guide/250x122_monochrome_circuitpython/code.py new file mode 100644 index 000000000..b49cf01be --- /dev/null +++ b/Bare_eInk_Guide/250x122_monochrome_circuitpython/code.py @@ -0,0 +1,60 @@ +# SPDX-FileCopyrightText: Copyright (c) 2021 Melissa LeBlanc-Williams for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +"""Simple test script for 2.13" 250x122 monochrome display.""" + +import time + +import board +import busio +import displayio +from fourwire import FourWire + +import adafruit_ssd1680 + +displayio.release_displays() + +if "EPD_MOSI" in dir(board): # Feather RP2040 ThinkInk + spi = busio.SPI(board.EPD_SCK, MOSI=board.EPD_MOSI, MISO=None) + epd_cs = board.EPD_CS + epd_dc = board.EPD_DC + epd_reset = board.EPD_RESET + epd_busy = board.EPD_BUSY +else: + spi = board.SPI() # Uses SCK and MOSI + epd_cs = board.D9 + epd_dc = board.D10 + epd_reset = board.D8 # Set to None for FeatherWing + epd_busy = board.D7 # Set to None for FeatherWing + +display_bus = FourWire(spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=1000000) +time.sleep(1) + +display = adafruit_ssd1680.SSD1680( + display_bus, + width=250, + height=122, + busy_pin=epd_busy, + highlight_color=0xFF0000, + rotation=270, + colstart=0, +) + +g = displayio.Group() + +pic = displayio.OnDiskBitmap("/display-ruler-640x360.bmp") +t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) +g.append(t) + +display.root_group = g + +display.refresh() + +print("refreshed") + +time.sleep(display.time_to_refresh + 5) +print("waited correct time") + +while True: + time.sleep(10) diff --git a/Bare_eInk_Guide/250x122_monochrome_circuitpython/display-ruler-640x360.bmp b/Bare_eInk_Guide/250x122_monochrome_circuitpython/display-ruler-640x360.bmp new file mode 100644 index 000000000..a9c776e75 Binary files /dev/null and b/Bare_eInk_Guide/250x122_monochrome_circuitpython/display-ruler-640x360.bmp differ diff --git a/Bare_eInk_Guide/250x122_monochrome_python/code.py b/Bare_eInk_Guide/250x122_monochrome_python/code.py new file mode 100644 index 000000000..b1d5b9adb --- /dev/null +++ b/Bare_eInk_Guide/250x122_monochrome_python/code.py @@ -0,0 +1,100 @@ +# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +ePaper Display Shapes and Text demo using the Pillow Library. +2.13" 250x122 Monochrome +https://www.adafruit.com/product/6383 +""" + +import board +import busio +import digitalio +from PIL import Image, ImageDraw, ImageFont + +from adafruit_epd.ssd1680 import Adafruit_SSD1680 + +# First define some color constants +WHITE = (0xFF, 0xFF, 0xFF) +BLACK = (0x00, 0x00, 0x00) + +# Next define some constants to allow easy resizing of shapes and colors +BORDER = 20 +FONTSIZE = 24 +BACKGROUND_COLOR = BLACK +FOREGROUND_COLOR = WHITE +TEXT_COLOR = BLACK + +# create the spi device and pins we will need +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) +ecs = digitalio.DigitalInOut(board.CE0) +dc = digitalio.DigitalInOut(board.D22) +srcs = None +rst = digitalio.DigitalInOut(board.D27) +busy = digitalio.DigitalInOut(board.D17) + +display = Adafruit_SSD1680(122, + 250, + spi, + cs_pin=ecs, + dc_pin=dc, + sramcs_pin=srcs, + rst_pin=rst, + busy_pin=busy, +) + +display.rotation = 3 +width = display.width +height = display.height +image = Image.new("RGB", (width, height)) + +WHITE = (0xFF, 0xFF, 0xFF) +BLACK = (0x00, 0x00, 0x00) + +# clear the buffer +display.fill(WHITE) + +# Get drawing object to draw on image. +draw = ImageDraw.Draw(image) +# empty it +draw.rectangle((0, 0, width, height), fill=WHITE) + +# Draw an outline box +draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE) + +# Draw some shapes. +# First define some constants to allow easy resizing of shapes. +padding = 5 +shape_width = 30 +top = padding +bottom = height - padding +# Move left to right keeping track of the current x position for drawing shapes. +x = padding +# Draw an ellipse. +draw.ellipse((x, top, x + shape_width, bottom), outline=BLACK, fill=WHITE) +x += shape_width + padding +# Draw a rectangle. +draw.rectangle((x, top, x + shape_width, bottom), outline=BLACK, fill=BLACK) +x += shape_width + padding +# Draw a triangle. +draw.polygon( + [(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)], + outline=BLACK, + fill=BLACK, +) +x += shape_width + padding +# Draw an X. +draw.line((x, bottom, x + shape_width, top), fill=BLACK) +draw.line((x, top, x + shape_width, bottom), fill=BLACK) +x += shape_width + padding + +# Load default font. +font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20) + +draw.text((x, top), "Hello", font=font, fill=BLACK) +draw.text((x, top + 20), "World!", font=font, fill=BLACK) + +# Display image. +display.image(image) + +display.display() diff --git a/Bare_eInk_Guide/296x152_monochrome_arduino/.uno.test.only b/Bare_eInk_Guide/296x152_monochrome_arduino/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Bare_eInk_Guide/296x152_monochrome_arduino/296x152_monochrome_arduino.ino b/Bare_eInk_Guide/296x152_monochrome_arduino/296x152_monochrome_arduino.ino new file mode 100644 index 000000000..914d24b78 --- /dev/null +++ b/Bare_eInk_Guide/296x152_monochrome_arduino/296x152_monochrome_arduino.ino @@ -0,0 +1,100 @@ +// SPDX-FileCopyrightText: 2025 Ladyada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/*************************************************** + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_ThinkInk.h" + +#ifdef ARDUINO_ADAFRUIT_FEATHER_RP2040_THINKINK // detects if compiling for + // Feather RP2040 ThinkInk +#define EPD_DC PIN_EPD_DC // ThinkInk 24-pin connector DC +#define EPD_CS PIN_EPD_CS // ThinkInk 24-pin connector CS +#define EPD_BUSY PIN_EPD_BUSY // ThinkInk 24-pin connector Busy +#define SRAM_CS -1 // use onboard RAM +#define EPD_RESET PIN_EPD_RESET // ThinkInk 24-pin connector Reset +#define EPD_SPI &SPI1 // secondary SPI for ThinkInk +#else +#define EPD_DC 10 +#define EPD_CS 9 +#define EPD_BUSY 7 // can set to -1 to not use a pin (will wait a fixed delay) +#define SRAM_CS 6 +#define EPD_RESET 8 // can set to -1 and share with microcontroller Reset! +#define EPD_SPI &SPI // primary SPI +#endif + +// 2.66" Monochrome display with 296x152 pixels and SSD1680 chipset +ThinkInk_266_Grayscale4_MFGN display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY, + EPD_SPI); + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + Serial.println("Adafruit EPD full update test in mono"); + Serial.println("2.66 Monochrome EPD with SSD1680 chipset"); + display.begin(THINKINK_MONO); +} + +void loop() { + Serial.println("Banner demo"); + display.clearBuffer(); + display.setTextSize(3); + display.setCursor((display.width() - 180) / 2, (display.height() - 24) / 2); + display.setTextColor(EPD_BLACK); + display.print("Monochrome"); + display.display(); + + delay(2000); + + Serial.println("B/W rectangle demo"); + display.clearBuffer(); + display.fillRect(display.width() / 2, 0, display.width() / 2, + display.height(), EPD_BLACK); + display.display(); + + delay(2000); + + Serial.println("Text demo"); + // large block of text + display.clearBuffer(); + display.setTextSize(1); + testdrawtext( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " + "adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, " + "fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor " + "neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet " + "ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a " + "tortor imperdiet posuere. ", + EPD_BLACK); + display.display(); + + delay(2000); + + display.clearBuffer(); + for (int16_t i = 0; i < display.width(); i += 4) { + display.drawLine(0, 0, i, display.height() - 1, EPD_BLACK); + } + + for (int16_t i = 0; i < display.height(); i += 4) { + display.drawLine(display.width() - 1, 0, 0, i, EPD_BLACK); + } + display.display(); + + delay(2000); +} + +void testdrawtext(const char *text, uint16_t color) { + display.setCursor(0, 0); + display.setTextColor(color); + display.setTextWrap(true); + display.print(text); +} diff --git a/Bare_eInk_Guide/296x152_monochrome_circuitpython/code.py b/Bare_eInk_Guide/296x152_monochrome_circuitpython/code.py new file mode 100644 index 000000000..9c3685c1b --- /dev/null +++ b/Bare_eInk_Guide/296x152_monochrome_circuitpython/code.py @@ -0,0 +1,60 @@ +# SPDX-FileCopyrightText: Copyright (c) 2021 Melissa LeBlanc-Williams for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +"""Simple test script for 2.66" 296x152 monochrome display.""" + +import time + +import board +import busio +import displayio +from fourwire import FourWire + +import adafruit_ssd1680 + +displayio.release_displays() + +if "EPD_MOSI" in dir(board): # Feather RP2040 ThinkInk + spi = busio.SPI(board.EPD_SCK, MOSI=board.EPD_MOSI, MISO=None) + epd_cs = board.EPD_CS + epd_dc = board.EPD_DC + epd_reset = board.EPD_RESET + epd_busy = board.EPD_BUSY +else: + spi = board.SPI() # Uses SCK and MOSI + epd_cs = board.D9 + epd_dc = board.D10 + epd_reset = board.D8 # Set to None for FeatherWing + epd_busy = board.D7 # Set to None for FeatherWing + +display_bus = FourWire(spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=1000000) +time.sleep(1) + +display = adafruit_ssd1680.SSD1680( + display_bus, + width=296, + height=152, + busy_pin=epd_busy, + highlight_color=0xFF0000, + rotation=270, + colstart=0, +) + +g = displayio.Group() + +pic = displayio.OnDiskBitmap("/display-ruler-640x360.bmp") +t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) +g.append(t) + +display.root_group = g + +display.refresh() + +print("refreshed") + +time.sleep(display.time_to_refresh + 5) +print("waited correct time") + +while True: + time.sleep(10) diff --git a/Bare_eInk_Guide/296x152_monochrome_circuitpython/display-ruler-640x360.bmp b/Bare_eInk_Guide/296x152_monochrome_circuitpython/display-ruler-640x360.bmp new file mode 100644 index 000000000..a9c776e75 Binary files /dev/null and b/Bare_eInk_Guide/296x152_monochrome_circuitpython/display-ruler-640x360.bmp differ diff --git a/Bare_eInk_Guide/296x152_monochrome_python/code.py b/Bare_eInk_Guide/296x152_monochrome_python/code.py new file mode 100644 index 000000000..e9cad08d3 --- /dev/null +++ b/Bare_eInk_Guide/296x152_monochrome_python/code.py @@ -0,0 +1,100 @@ +# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +ePaper Display Shapes and Text demo using the Pillow Library. +2.13" 250x122 Monochrome +https://www.adafruit.com/product/6383 +""" + +import board +import busio +import digitalio +from PIL import Image, ImageDraw, ImageFont + +from adafruit_epd.ssd1680 import Adafruit_SSD1680 + +# First define some color constants +WHITE = (0xFF, 0xFF, 0xFF) +BLACK = (0x00, 0x00, 0x00) + +# Next define some constants to allow easy resizing of shapes and colors +BORDER = 20 +FONTSIZE = 24 +BACKGROUND_COLOR = BLACK +FOREGROUND_COLOR = WHITE +TEXT_COLOR = BLACK + +# create the spi device and pins we will need +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) +ecs = digitalio.DigitalInOut(board.CE0) +dc = digitalio.DigitalInOut(board.D22) +srcs = None +rst = digitalio.DigitalInOut(board.D27) +busy = digitalio.DigitalInOut(board.D17) + +display = Adafruit_SSD1680(152, + 296, + spi, + cs_pin=ecs, + dc_pin=dc, + sramcs_pin=srcs, + rst_pin=rst, + busy_pin=busy, +) + +display.rotation = 3 +width = display.width +height = display.height +image = Image.new("RGB", (width, height)) + +WHITE = (0xFF, 0xFF, 0xFF) +BLACK = (0x00, 0x00, 0x00) + +# clear the buffer +display.fill(WHITE) + +# Get drawing object to draw on image. +draw = ImageDraw.Draw(image) +# empty it +draw.rectangle((0, 0, width, height), fill=WHITE) + +# Draw an outline box +draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE) + +# Draw some shapes. +# First define some constants to allow easy resizing of shapes. +padding = 5 +shape_width = 30 +top = padding +bottom = height - padding +# Move left to right keeping track of the current x position for drawing shapes. +x = padding +# Draw an ellipse. +draw.ellipse((x, top, x + shape_width, bottom), outline=BLACK, fill=WHITE) +x += shape_width + padding +# Draw a rectangle. +draw.rectangle((x, top, x + shape_width, bottom), outline=BLACK, fill=BLACK) +x += shape_width + padding +# Draw a triangle. +draw.polygon( + [(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)], + outline=BLACK, + fill=BLACK, +) +x += shape_width + padding +# Draw an X. +draw.line((x, bottom, x + shape_width, top), fill=BLACK) +draw.line((x, top, x + shape_width, bottom), fill=BLACK) +x += shape_width + padding + +# Load default font. +font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20) + +draw.text((x, top), "Hello", font=font, fill=BLACK) +draw.text((x, top + 20), "World!", font=font, fill=BLACK) + +# Display image. +display.image(image) + +display.display() diff --git a/Bare_eInk_Guide/296x152_tricolor_arduino/.uno.test.only b/Bare_eInk_Guide/296x152_tricolor_arduino/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Bare_eInk_Guide/296x152_tricolor_arduino/296x152_tricolor_arduino.ino b/Bare_eInk_Guide/296x152_tricolor_arduino/296x152_tricolor_arduino.ino new file mode 100644 index 000000000..fdb0d338e --- /dev/null +++ b/Bare_eInk_Guide/296x152_tricolor_arduino/296x152_tricolor_arduino.ino @@ -0,0 +1,104 @@ +// SPDX-FileCopyrightText: 2025 Ladyada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/*************************************************** + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_ThinkInk.h" + +#ifdef ARDUINO_ADAFRUIT_FEATHER_RP2040_THINKINK // detects if compiling for + // Feather RP2040 ThinkInk +#define EPD_DC PIN_EPD_DC // ThinkInk 24-pin connector DC +#define EPD_CS PIN_EPD_CS // ThinkInk 24-pin connector CS +#define EPD_BUSY PIN_EPD_BUSY // ThinkInk 24-pin connector Busy +#define SRAM_CS -1 // use onboard RAM +#define EPD_RESET PIN_EPD_RESET // ThinkInk 24-pin connector Reset +#define EPD_SPI &SPI1 // secondary SPI for ThinkInk +#else +#define EPD_DC 10 +#define EPD_CS 9 +#define EPD_BUSY 7 // can set to -1 to not use a pin (will wait a fixed delay) +#define SRAM_CS 6 +#define EPD_RESET 8 // can set to -1 and share with microcontroller Reset! +#define EPD_SPI &SPI // primary SPI +#endif + +// 2.66" Tricolor EPD with SSD1680Z chipset +ThinkInk_266_Tricolor_MFGNR display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, + EPD_BUSY, EPD_SPI); + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + Serial.println("Adafruit EPD full update test in red/black/white"); + Serial.println("2.66 Tri-Color EPD with SSD1680Z chipset"); + display.begin(THINKINK_TRICOLOR); +} + +void loop() { + Serial.println("Banner demo"); + display.clearBuffer(); + display.setTextSize(3); + display.setCursor((display.width() - 144) / 2, (display.height() - 24) / 2); + display.setTextColor(EPD_BLACK); + display.print("Tri"); + display.setTextColor(EPD_RED); + display.print("Color"); + display.display(); + + delay(15000); + + Serial.println("Color rectangle demo"); + display.clearBuffer(); + display.fillRect(display.width() / 3, 0, display.width() / 3, + display.height(), EPD_BLACK); + display.fillRect((display.width() * 2) / 3, 0, display.width() / 3, + display.height(), EPD_RED); + display.display(); + + delay(15000); + + Serial.println("Text demo"); + // large block of text + display.clearBuffer(); + display.setTextSize(1); + testdrawtext( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " + "adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, " + "fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor " + "neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet " + "ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a " + "tortor imperdiet posuere. ", + EPD_BLACK); + display.display(); + + delay(15000); + + display.clearBuffer(); + for (int16_t i = 0; i < display.width(); i += 4) { + display.drawLine(0, 0, i, display.height() - 1, EPD_BLACK); + } + + for (int16_t i = 0; i < display.height(); i += 4) { + display.drawLine(display.width() - 1, 0, 0, i, EPD_RED); + } + display.display(); + + delay(15000); +} + +void testdrawtext(const char *text, uint16_t color) { + display.setCursor(0, 0); + display.setTextColor(color); + display.setTextWrap(true); + display.print(text); +} diff --git a/Bare_eInk_Guide/296x152_tricolor_circuitpython/code.py b/Bare_eInk_Guide/296x152_tricolor_circuitpython/code.py new file mode 100644 index 000000000..26d545c8c --- /dev/null +++ b/Bare_eInk_Guide/296x152_tricolor_circuitpython/code.py @@ -0,0 +1,60 @@ +# SPDX-FileCopyrightText: Copyright (c) 2021 Melissa LeBlanc-Williams for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +"""Simple test script for 2.66" 296x152 tri-color display.""" + +import time + +import board +import busio +import displayio +from fourwire import FourWire + +import adafruit_ssd1680 + +displayio.release_displays() + +if "EPD_MOSI" in dir(board): # Feather RP2040 ThinkInk + spi = busio.SPI(board.EPD_SCK, MOSI=board.EPD_MOSI, MISO=None) + epd_cs = board.EPD_CS + epd_dc = board.EPD_DC + epd_reset = board.EPD_RESET + epd_busy = board.EPD_BUSY +else: + spi = board.SPI() # Uses SCK and MOSI + epd_cs = board.D9 + epd_dc = board.D10 + epd_reset = board.D8 # Set to None for FeatherWing + epd_busy = board.D7 # Set to None for FeatherWing + +display_bus = FourWire(spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=1000000) +time.sleep(1) + +display = adafruit_ssd1680.SSD1680( + display_bus, + width=296, + height=152, + busy_pin=epd_busy, + highlight_color=0xFF0000, + rotation=270, + colstart=0, +) + +g = displayio.Group() + +pic = displayio.OnDiskBitmap("/display-ruler-640x360.bmp") +t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) +g.append(t) + +display.root_group = g + +display.refresh() + +print("refreshed") + +time.sleep(display.time_to_refresh + 5) +print("waited correct time") + +while True: + time.sleep(10) diff --git a/Bare_eInk_Guide/296x152_tricolor_circuitpython/display-ruler-640x360.bmp b/Bare_eInk_Guide/296x152_tricolor_circuitpython/display-ruler-640x360.bmp new file mode 100644 index 000000000..a9c776e75 Binary files /dev/null and b/Bare_eInk_Guide/296x152_tricolor_circuitpython/display-ruler-640x360.bmp differ diff --git a/Bare_eInk_Guide/296x152_tricolor_python/code.py b/Bare_eInk_Guide/296x152_tricolor_python/code.py new file mode 100644 index 000000000..31a178db0 --- /dev/null +++ b/Bare_eInk_Guide/296x152_tricolor_python/code.py @@ -0,0 +1,102 @@ +# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +ePaper Display Shapes and Text demo using the Pillow Library. +2.66" 296x152 Tri-Color SSD1680Z Chipset +https://www.adafruit.com/product/6393 +""" + +import board +import busio +import digitalio +from PIL import Image, ImageDraw, ImageFont + +from adafruit_epd.ssd1680 import Adafruit_SSD1680Z + +# First define some color constants +WHITE = (0xFF, 0xFF, 0xFF) +BLACK = (0x00, 0x00, 0x00) +RED = (0xFF, 0x00, 0x00) + +# Next define some constants to allow easy resizing of shapes and colors +BORDER = 20 +FONTSIZE = 24 +BACKGROUND_COLOR = BLACK +FOREGROUND_COLOR = WHITE +TEXT_COLOR = RED + +# create the spi device and pins we will need +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) +ecs = digitalio.DigitalInOut(board.CE0) +dc = digitalio.DigitalInOut(board.D22) +srcs = None +rst = digitalio.DigitalInOut(board.D27) +busy = digitalio.DigitalInOut(board.D17) + +display = Adafruit_SSD1680Z(152, + 296, + spi, + cs_pin=ecs, + dc_pin=dc, + sramcs_pin=srcs, + rst_pin=rst, + busy_pin=busy, +) + +display.rotation = 3 +width = display.width +height = display.height +image = Image.new("RGB", (width, height)) + +WHITE = (0xFF, 0xFF, 0xFF) +RED = (0xFF, 0x00, 0x00) +BLACK = (0x00, 0x00, 0x00) + +# clear the buffer +display.fill(WHITE) + +# Get drawing object to draw on image. +draw = ImageDraw.Draw(image) +# empty it +draw.rectangle((0, 0, width, height), fill=WHITE) + +# Draw an outline box +draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE) + +# Draw some shapes. +# First define some constants to allow easy resizing of shapes. +padding = 5 +shape_width = 30 +top = padding +bottom = height - padding +# Move left to right keeping track of the current x position for drawing shapes. +x = padding +# Draw an ellipse. +draw.ellipse((x, top, x + shape_width, bottom), outline=RED, fill=WHITE) +x += shape_width + padding +# Draw a rectangle. +draw.rectangle((x, top, x + shape_width, bottom), outline=RED, fill=BLACK) +x += shape_width + padding +# Draw a triangle. +draw.polygon( + [(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)], + outline=BLACK, + fill=RED, +) +x += shape_width + padding +# Draw an X. +draw.line((x, bottom, x + shape_width, top), fill=BLACK) +draw.line((x, top, x + shape_width, bottom), fill=RED) +x += shape_width + padding + +# Load default font. +font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20) + +draw.text((x, top), "Hello", font=font, fill=BLACK) +draw.text((x, top + 20), "World!", font=font, fill=BLACK) + +# Display image. +display.image(image) + +display.display() diff --git a/Bare_eInk_Guide/340x180_quadcolor_arduino/.uno.test.only b/Bare_eInk_Guide/340x180_quadcolor_arduino/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Bare_eInk_Guide/340x180_quadcolor_arduino/340x180_quadcolor_arduino.ino b/Bare_eInk_Guide/340x180_quadcolor_arduino/340x180_quadcolor_arduino.ino new file mode 100644 index 000000000..ec8e84815 --- /dev/null +++ b/Bare_eInk_Guide/340x180_quadcolor_arduino/340x180_quadcolor_arduino.ino @@ -0,0 +1,119 @@ +// SPDX-FileCopyrightText: 2025 Ladyada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/*************************************************** + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_ThinkInk.h" + +#ifdef ARDUINO_ADAFRUIT_FEATHER_RP2040_THINKINK // detects if compiling for + // Feather RP2040 ThinkInk +#define EPD_DC PIN_EPD_DC // ThinkInk 24-pin connector DC +#define EPD_CS PIN_EPD_CS // ThinkInk 24-pin connector CS +#define EPD_BUSY PIN_EPD_BUSY // ThinkInk 24-pin connector Busy +#define SRAM_CS -1 // use onboard RAM +#define EPD_RESET PIN_EPD_RESET // ThinkInk 24-pin connector Reset +#define EPD_SPI &SPI1 // secondary SPI for ThinkInk +#else +#define EPD_DC 10 +#define EPD_CS 9 +#define EPD_BUSY 7 // can set to -1 to not use a pin (will wait a fixed delay) +#define SRAM_CS 6 +#define EPD_RESET 8 // can set to -1 and share with microcontroller Reset! +#define EPD_SPI &SPI // primary SPI +#endif + +// 2.13" Quadcolor EPD with JD79661 chipset +//ThinkInk_213_Quadcolor_AJHE5 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY, EPD_SPI); + +// 3.52" Quadcolor EPD with JD79667 chipset +ThinkInk_352_Quadcolor_AJHE5 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY, EPD_SPI); + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + Serial.println("Adafruit EPD full update test in red/yellow/black/white"); + Serial.println("3.52 Quadcolor EPD with JD79667 chipset"); + display.begin(THINKINK_QUADCOLOR); +} + +void loop() { + Serial.println("Banner demo"); + display.clearBuffer(); + display.setTextSize(3); + display.setCursor((display.width() - 144) / 2, (display.height() - 24) / 2); + String text = "QuadColor"; + uint16_t colors[] = {EPD_BLACK, EPD_RED, EPD_YELLOW}; + + for (int i = 0; i < text.length(); i++) { + // Change color for every character (0: BLACK, 1: RED, 2: YELLOW, 3: BLACK, etc.) + display.setTextColor(colors[i % 3]); + display.print(text.charAt(i)); + } + display.display(); + + delay(15000); + + Serial.println("Color quadrant demo"); + display.clearBuffer(); + // Top-left quadrant - EPD_BLACK + display.fillRect(0, 0, display.width() / 2, display.height() / 2, EPD_BLACK); + // Top-right quadrant - EPD_RED + display.fillRect(display.width() / 2, 0, display.width() / 2, display.height() / 2, EPD_RED); + // Bottom-left quadrant - EPD_YELLOW + display.fillRect(0, display.height() / 2, display.width() / 2, display.height() / 2, EPD_YELLOW); + // Bottom-right quadrant - assume you have a 4th color like EPD_WHITE or another color + display.fillRect(display.width() / 2, display.height() / 2, display.width() / 2, display.height() / 2, EPD_WHITE); + + display.display(); + + delay(15000); + + Serial.println("Text demo"); + // large block of text + display.clearBuffer(); + display.setTextSize(1); + testdrawtext( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " + "adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, " + "fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor " + "neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet " + "ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a " + "tortor imperdiet posuere. ", + EPD_BLACK); + display.display(); + + delay(15000); + + display.clearBuffer(); + for (int16_t i = 0; i < display.width(); i += 4) { + display.drawLine(0, 0, i, display.height() - 1, EPD_BLACK); + } + for (int16_t i = 0; i < display.height(); i += 4) { + display.drawLine(display.width() - 1, 0, 0, i, EPD_RED); + } + for (int16_t i = 0; i < display.width(); i += 4) { + display.drawLine(display.width()/2, display.height()-1, i, 0, + EPD_YELLOW); + } + + display.display(); + + delay(15000); +} + +void testdrawtext(const char *text, uint16_t color) { + display.setCursor(0, 0); + display.setTextColor(color); + display.setTextWrap(true); + display.print(text); +} diff --git a/Bare_eInk_Guide/340x180_quadcolor_circuitpython/code.py b/Bare_eInk_Guide/340x180_quadcolor_circuitpython/code.py new file mode 100644 index 000000000..0d3659b37 --- /dev/null +++ b/Bare_eInk_Guide/340x180_quadcolor_circuitpython/code.py @@ -0,0 +1,62 @@ +# SPDX-FileCopyrightText: Copyright (c) 2021 Melissa LeBlanc-Williams for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +"""Simple test for 3.52" 340x180 quad-color eInk display.""" + +import time + +import board +import busio +import displayio +from fourwire import FourWire + +import adafruit_jd79667 + +displayio.release_displays() + +if "EPD_MOSI" in dir(board): # Feather RP2040 ThinkInk + spi = busio.SPI(board.EPD_SCK, MOSI=board.EPD_MOSI, MISO=None) + epd_cs = board.EPD_CS + epd_dc = board.EPD_DC + epd_reset = board.EPD_RESET + epd_busy = board.EPD_BUSY +else: + spi = board.SPI() # Uses SCK and MOSI + epd_cs = board.D9 + epd_dc = board.D10 + epd_reset = board.D8 # Set to None for FeatherWing + epd_busy = board.D7 # Set to None for FeatherWing + +display_bus = FourWire(spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=1000000) +time.sleep(1) + +display = adafruit_jd79667.JD79667( + display_bus, + width=384, + height=184, + busy_pin=epd_busy, + rotation=270, + colstart=0, + highlight_color=0xFFFF00, + highlight_color2=0xFF0000, +) + +g = displayio.Group() + +pic = displayio.OnDiskBitmap("/display-ruler-640x360.bmp") +t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) +g.append(t) + +display.root_group = g + +display.refresh() + +print("refreshed") + +time.sleep(display.time_to_refresh + 5) +print("waited correct time") + +# Keep the display the same +while True: + time.sleep(10) diff --git a/Bare_eInk_Guide/340x180_quadcolor_circuitpython/display-ruler-640x360.bmp b/Bare_eInk_Guide/340x180_quadcolor_circuitpython/display-ruler-640x360.bmp new file mode 100644 index 000000000..a9c776e75 Binary files /dev/null and b/Bare_eInk_Guide/340x180_quadcolor_circuitpython/display-ruler-640x360.bmp differ diff --git a/Bare_eInk_Guide/340x180_quadcolor_python/code.py b/Bare_eInk_Guide/340x180_quadcolor_python/code.py new file mode 100644 index 000000000..56950df61 --- /dev/null +++ b/Bare_eInk_Guide/340x180_quadcolor_python/code.py @@ -0,0 +1,98 @@ +# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +ePaper Display Shapes and Text demo using the Pillow Library. +3.52" Quad Color 384x180 display +https://www.adafruit.com/product/6414 +""" + +import board +import busio +import digitalio +from PIL import Image, ImageDraw, ImageFont + +from adafruit_epd.jd79667 import Adafruit_JD79667 + +# RGB colors +WHITE = (255, 255, 255) +BLACK = (0, 0, 0) +RED = (255, 0, 0) +YELLOW = (255, 255, 0) + +# Create the SPI device and pins +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) +ecs = digitalio.DigitalInOut(board.CE0) +dc = digitalio.DigitalInOut(board.D22) +srcs = None # No SRAM +rst = digitalio.DigitalInOut(board.D27) +busy = digitalio.DigitalInOut(board.D17) + +display = Adafruit_JD79667( + 180, + 384, + spi, + cs_pin=ecs, + dc_pin=dc, + sramcs_pin=srcs, + rst_pin=rst, + busy_pin=busy, +) + +display.rotation = 3 + +# Get display dimensions +width = display.width +height = display.height +image = Image.new("RGB", (width, height)) +# Get drawing object +draw = ImageDraw.Draw(image) + +# Fill background with white +draw.rectangle((0, 0, width, height), fill=WHITE) + +# Draw a border +draw.rectangle((0, 0, width - 1, height - 1), outline=BLACK, fill=WHITE) + +# Draw some shapes to demonstrate all four colors +padding = 10 +shape_width = 30 +top = padding + 10 +bottom = height - padding - 10 + +# Starting x position +x = padding + 10 + +# Draw an ellipse filled with red +draw.ellipse((x, top, x + shape_width, bottom), outline=RED, fill=None) +x += shape_width + padding + +# Draw a rectangle filled with yellow +draw.rectangle((x, top, x + shape_width, bottom), outline=YELLOW, fill=BLACK) +x += shape_width + padding + +# Draw a triangle filled with red +draw.polygon( + [(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)], + outline=BLACK, + fill=YELLOW, +) +x += shape_width + padding + +# Draw an X with red and yellow lines +draw.line((x, bottom, x + shape_width, top), fill=RED) +draw.line((x, top, x + shape_width, bottom), fill=BLACK) +x += shape_width + padding + +# Add some text +font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 28) + +# Draw text in different colors +draw.text((x, top), "Hello", font=font, fill=BLACK) +draw.text((x, top + 28), "World!", font=font, fill=RED) +draw.text((x, top + (28*2)), "Quad", font=font, fill=YELLOW) +draw.text((x, top + (28*3)), "Color!", font=font, fill=BLACK) + +display.image(image) + +display.display() diff --git a/Bare_eInk_Guide/400x300_monochrome_arduino/.uno.test.only b/Bare_eInk_Guide/400x300_monochrome_arduino/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Bare_eInk_Guide/400x300_monochrome_arduino/400x300_monochrome_arduino.ino b/Bare_eInk_Guide/400x300_monochrome_arduino/400x300_monochrome_arduino.ino new file mode 100644 index 000000000..a9e27a78e --- /dev/null +++ b/Bare_eInk_Guide/400x300_monochrome_arduino/400x300_monochrome_arduino.ino @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: 2025 Ladyada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/*************************************************** + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_ThinkInk.h" + +#ifdef ARDUINO_ADAFRUIT_FEATHER_RP2040_THINKINK // detects if compiling for + // Feather RP2040 ThinkInk +#define EPD_DC PIN_EPD_DC // ThinkInk 24-pin connector DC +#define EPD_CS PIN_EPD_CS // ThinkInk 24-pin connector CS +#define EPD_BUSY PIN_EPD_BUSY // ThinkInk 24-pin connector Busy +#define SRAM_CS -1 // use onboard RAM +#define EPD_RESET PIN_EPD_RESET // ThinkInk 24-pin connector Reset +#define EPD_SPI &SPI1 // secondary SPI for ThinkInk +#else +#define EPD_DC 10 +#define EPD_CS 9 +#define EPD_BUSY 7 // can set to -1 to not use a pin (will wait a fixed delay) +#define SRAM_CS 6 +#define EPD_RESET 8 // can set to -1 and share with microcontroller Reset! +#define EPD_SPI &SPI // primary SPI +#endif + +// 4.2" Grayscale/Monochrome displays with 400x300 pixels and SSD1683 chipset +ThinkInk_420_Grayscale4_MFGN display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY, EPD_SPI); + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + Serial.println("Adafruit EPD full update test in mono"); + Serial.println("4.2 Monochrome EPD with SSD1683 chipset"); + display.begin(THINKINK_MONO); +} + +void loop() { + Serial.println("Banner demo"); + display.clearBuffer(); + display.setTextSize(3); + display.setCursor((display.width() - 180) / 2, (display.height() - 24) / 2); + display.setTextColor(EPD_BLACK); + display.print("Monochrome"); + display.display(); + + delay(2000); + + Serial.println("B/W rectangle demo"); + display.clearBuffer(); + display.fillRect(display.width() / 2, 0, display.width() / 2, + display.height(), EPD_BLACK); + display.display(); + + delay(2000); + + Serial.println("Text demo"); + // large block of text + display.clearBuffer(); + display.setTextSize(1); + testdrawtext( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " + "adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, " + "fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor " + "neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet " + "ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a " + "tortor imperdiet posuere. ", + EPD_BLACK); + display.display(); + + delay(2000); + + display.clearBuffer(); + for (int16_t i = 0; i < display.width(); i += 4) { + display.drawLine(0, 0, i, display.height() - 1, EPD_BLACK); + } + + for (int16_t i = 0; i < display.height(); i += 4) { + display.drawLine(display.width() - 1, 0, 0, i, EPD_BLACK); + } + display.display(); + + delay(2000); +} + +void testdrawtext(const char *text, uint16_t color) { + display.setCursor(0, 0); + display.setTextColor(color); + display.setTextWrap(true); + display.print(text); +} diff --git a/Bare_eInk_Guide/400x300_monochrome_python/code.py b/Bare_eInk_Guide/400x300_monochrome_python/code.py new file mode 100644 index 000000000..40e489a93 --- /dev/null +++ b/Bare_eInk_Guide/400x300_monochrome_python/code.py @@ -0,0 +1,97 @@ +# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +ePaper Display Shapes and Text demo using the Pillow Library. +4.2" 300x400 Monochrome +https://www.adafruit.com/product/6381 +""" + +import board +import busio +import digitalio +from PIL import Image, ImageDraw, ImageFont + +from adafruit_epd.ssd1683 import Adafruit_SSD1683 + +# First define some color constants +WHITE = (0xFF, 0xFF, 0xFF) +BLACK = (0xFF, 0x00, 0x00) + +# Next define some constants to allow easy resizing of shapes and colors +BORDER = 20 +FONTSIZE = 24 +BACKGROUND_COLOR = BLACK +FOREGROUND_COLOR = WHITE +TEXT_COLOR = BLACK + +# create the spi device and pins we will need +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) +ecs = digitalio.DigitalInOut(board.CE0) +dc = digitalio.DigitalInOut(board.D22) +srcs = None +rst = digitalio.DigitalInOut(board.D27) +busy = digitalio.DigitalInOut(board.D17) + + +display = Adafruit_SSD1683(400, 300, # 4.2" 300x400 monochrome display + spi, + cs_pin=ecs, + dc_pin=dc, + sramcs_pin=srcs, + rst_pin=rst, + busy_pin=busy, +) + +display.rotation = 0 +width = display.width +height = display.height +image = Image.new("RGB", (width, height)) + +# clear the buffer +display.fill(WHITE) + +# Get drawing object to draw on image. +draw = ImageDraw.Draw(image) +# empty it +draw.rectangle((0, 0, width, height), fill=WHITE) + +# Draw an outline box +draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE) + +# Draw some shapes. +# First define some constants to allow easy resizing of shapes. +padding = 15 +shape_width = 50 +top = padding +bottom = height - padding +# Move left to right keeping track of the current x position for drawing shapes. +x = padding +# Draw an ellipse. +draw.ellipse((x, top, x + shape_width, bottom), outline=BLACK, fill=WHITE) +x += shape_width + padding +# Draw a rectangle. +draw.rectangle((x, top, x + shape_width, bottom), outline=BLACK, fill=BLACK) +x += shape_width + padding +# Draw a triangle. +draw.polygon( + [(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)], + outline=BLACK, + fill=BLACK, +) +x += shape_width + padding +# Draw an X. +draw.line((x, bottom, x + shape_width, top), fill=BLACK) +draw.line((x, top, x + shape_width, bottom), fill=BLACK) +x += shape_width + padding + +# Load default font. +font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 30) + +draw.text((x, top), "Hello", font=font, fill=BLACK) +draw.text((x, top + 30), "World!", font=font, fill=BLACK) + +# Display image. +display.image(image) + +display.display() diff --git a/Bare_eInk_Guide/400x300_tricolor_arduino/.uno.test.only b/Bare_eInk_Guide/400x300_tricolor_arduino/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Bare_eInk_Guide/400x300_tricolor_arduino/400x300_tricolor_arduino.ino b/Bare_eInk_Guide/400x300_tricolor_arduino/400x300_tricolor_arduino.ino new file mode 100644 index 000000000..588ba2256 --- /dev/null +++ b/Bare_eInk_Guide/400x300_tricolor_arduino/400x300_tricolor_arduino.ino @@ -0,0 +1,104 @@ +// SPDX-FileCopyrightText: 2025 Ladyada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/*************************************************** + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_ThinkInk.h" + +#ifdef ARDUINO_ADAFRUIT_FEATHER_RP2040_THINKINK // detects if compiling for + // Feather RP2040 ThinkInk +#define EPD_DC PIN_EPD_DC // ThinkInk 24-pin connector DC +#define EPD_CS PIN_EPD_CS // ThinkInk 24-pin connector CS +#define EPD_BUSY PIN_EPD_BUSY // ThinkInk 24-pin connector Busy +#define SRAM_CS -1 // use onboard RAM +#define EPD_RESET PIN_EPD_RESET // ThinkInk 24-pin connector Reset +#define EPD_SPI &SPI1 // secondary SPI for ThinkInk +#else +#define EPD_DC 10 +#define EPD_CS 9 +#define EPD_BUSY 7 // can set to -1 to not use a pin (will wait a fixed delay) +#define SRAM_CS 6 +#define EPD_RESET 8 // can set to -1 and share with microcontroller Reset! +#define EPD_SPI &SPI // primary SPI +#endif + +// 4.2" Tricolor EPD with SSD1683 chipset +ThinkInk_420_Tricolor_MFGNR display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, + EPD_BUSY, EPD_SPI); + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + Serial.println("Adafruit EPD full update test in red/black/white"); + Serial.println("4.2 Tri-Color EPD with SSD1683 chipset"); + display.begin(THINKINK_TRICOLOR); +} + +void loop() { + Serial.println("Banner demo"); + display.clearBuffer(); + display.setTextSize(3); + display.setCursor((display.width() - 144) / 2, (display.height() - 24) / 2); + display.setTextColor(EPD_BLACK); + display.print("Tri"); + display.setTextColor(EPD_RED); + display.print("Color"); + display.display(); + + delay(15000); + + Serial.println("Color rectangle demo"); + display.clearBuffer(); + display.fillRect(display.width() / 3, 0, display.width() / 3, + display.height(), EPD_BLACK); + display.fillRect((display.width() * 2) / 3, 0, display.width() / 3, + display.height(), EPD_RED); + display.display(); + + delay(15000); + + Serial.println("Text demo"); + // large block of text + display.clearBuffer(); + display.setTextSize(1); + testdrawtext( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " + "adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, " + "fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor " + "neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet " + "ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a " + "tortor imperdiet posuere. ", + EPD_BLACK); + display.display(); + + delay(15000); + + display.clearBuffer(); + for (int16_t i = 0; i < display.width(); i += 4) { + display.drawLine(0, 0, i, display.height() - 1, EPD_BLACK); + } + + for (int16_t i = 0; i < display.height(); i += 4) { + display.drawLine(display.width() - 1, 0, 0, i, EPD_RED); + } + display.display(); + + delay(15000); +} + +void testdrawtext(const char *text, uint16_t color) { + display.setCursor(0, 0); + display.setTextColor(color); + display.setTextWrap(true); + display.print(text); +} diff --git a/Bare_eInk_Guide/400x300_tricolor_python/code.py b/Bare_eInk_Guide/400x300_tricolor_python/code.py new file mode 100644 index 000000000..b19c4a99a --- /dev/null +++ b/Bare_eInk_Guide/400x300_tricolor_python/code.py @@ -0,0 +1,98 @@ +# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +ePaper Display Shapes and Text demo using the Pillow Library. +4.2" 300x400 Tri-Color +https://www.adafruit.com/product/6382 +""" + +import board +import busio +import digitalio +from PIL import Image, ImageDraw, ImageFont + +from adafruit_epd.ssd1683 import Adafruit_SSD1683 + +# First define some color constants +WHITE = (0xFF, 0xFF, 0xFF) +BLACK = (0x00, 0x00, 0x00) +RED = (0xFF, 0x00, 0x00) + +# Next define some constants to allow easy resizing of shapes and colors +BORDER = 20 +FONTSIZE = 24 +BACKGROUND_COLOR = BLACK +FOREGROUND_COLOR = WHITE +TEXT_COLOR = BLACK + +# create the spi device and pins we will need +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) +ecs = digitalio.DigitalInOut(board.CE0) +dc = digitalio.DigitalInOut(board.D22) +srcs = None +rst = digitalio.DigitalInOut(board.D27) +busy = digitalio.DigitalInOut(board.D17) + +# give them all to our driver +display = Adafruit_SSD1683(400, 300, # 4.2" 300x400 Tri-Color display + spi, + cs_pin=ecs, + dc_pin=dc, + sramcs_pin=srcs, + rst_pin=rst, + busy_pin=busy, +) + +display.rotation = 0 +width = display.width +height = display.height +image = Image.new("RGB", (width, height)) + +# clear the buffer +display.fill(WHITE) + +# Get drawing object to draw on image. +draw = ImageDraw.Draw(image) +# empty it +draw.rectangle((0, 0, width, height), fill=WHITE) + +# Draw an outline box +draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE) + +# Draw some shapes. +# First define some constants to allow easy resizing of shapes. +padding = 15 +shape_width = 50 +top = padding +bottom = height - padding +# Move left to right keeping track of the current x position for drawing shapes. +x = padding +# Draw an ellipse. +draw.ellipse((x, top, x + shape_width, bottom), outline=RED, fill=WHITE) +x += shape_width + padding +# Draw a rectangle. +draw.rectangle((x, top, x + shape_width, bottom), outline=RED, fill=BLACK) +x += shape_width + padding +# Draw a triangle. +draw.polygon( + [(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)], + outline=BLACK, + fill=RED, +) +x += shape_width + padding +# Draw an X. +draw.line((x, bottom, x + shape_width, top), fill=BLACK) +draw.line((x, top, x + shape_width, bottom), fill=RED) +x += shape_width + padding + +# Load default font. +font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 30) + +draw.text((x, top), "Hello", font=font, fill=BLACK) +draw.text((x, top + 30), "World!", font=font, fill=BLACK) + +# Display image. +display.image(image) + +display.display() diff --git a/Bare_eInk_Guide/416x240_monochrome_arduino/.uno.test.only b/Bare_eInk_Guide/416x240_monochrome_arduino/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Bare_eInk_Guide/416x240_monochrome_arduino/416x240_monochrome_arduino.ino b/Bare_eInk_Guide/416x240_monochrome_arduino/416x240_monochrome_arduino.ino new file mode 100644 index 000000000..f96545fc7 --- /dev/null +++ b/Bare_eInk_Guide/416x240_monochrome_arduino/416x240_monochrome_arduino.ino @@ -0,0 +1,100 @@ +// SPDX-FileCopyrightText: 2025 Ladyada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/*************************************************** + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_ThinkInk.h" + +#ifdef ARDUINO_ADAFRUIT_FEATHER_RP2040_THINKINK // detects if compiling for + // Feather RP2040 ThinkInk +#define EPD_DC PIN_EPD_DC // ThinkInk 24-pin connector DC +#define EPD_CS PIN_EPD_CS // ThinkInk 24-pin connector CS +#define EPD_BUSY PIN_EPD_BUSY // ThinkInk 24-pin connector Busy +#define SRAM_CS -1 // use onboard RAM +#define EPD_RESET PIN_EPD_RESET // ThinkInk 24-pin connector Reset +#define EPD_SPI &SPI1 // secondary SPI for ThinkInk +#else +#define EPD_DC 10 +#define EPD_CS 9 +#define EPD_BUSY 7 // can set to -1 to not use a pin (will wait a fixed delay) +#define SRAM_CS 6 +#define EPD_RESET 8 // can set to -1 and share with microcontroller Reset! +#define EPD_SPI &SPI // primary SPI +#endif + +// 3.7" Monochrome Display with 420x240 pixels and UC8253 chipset +ThinkInk_370_Mono_BAAMFGN display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, + EPD_BUSY, EPD_SPI); + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + Serial.println("Adafruit EPD full update test in mono"); + Serial.println("3.7 Monochrome EPD with UC8253 chipset"); + display.begin(THINKINK_MONO); +} + +void loop() { + Serial.println("Banner demo"); + display.clearBuffer(); + display.setTextSize(3); + display.setCursor((display.width() - 180) / 2, (display.height() - 24) / 2); + display.setTextColor(EPD_BLACK); + display.print("Monochrome"); + display.display(); + + delay(2000); + + Serial.println("B/W rectangle demo"); + display.clearBuffer(); + display.fillRect(display.width() / 2, 0, display.width() / 2, + display.height(), EPD_BLACK); + display.display(); + + delay(2000); + + Serial.println("Text demo"); + // large block of text + display.clearBuffer(); + display.setTextSize(1); + testdrawtext( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " + "adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, " + "fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor " + "neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet " + "ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a " + "tortor imperdiet posuere. ", + EPD_BLACK); + display.display(); + + delay(2000); + + display.clearBuffer(); + for (int16_t i = 0; i < display.width(); i += 4) { + display.drawLine(0, 0, i, display.height() - 1, EPD_BLACK); + } + + for (int16_t i = 0; i < display.height(); i += 4) { + display.drawLine(display.width() - 1, 0, 0, i, EPD_BLACK); + } + display.display(); + + delay(2000); +} + +void testdrawtext(const char *text, uint16_t color) { + display.setCursor(0, 0); + display.setTextColor(color); + display.setTextWrap(true); + display.print(text); +} diff --git a/Bare_eInk_Guide/416x240_monochrome_circuitpython/code.py b/Bare_eInk_Guide/416x240_monochrome_circuitpython/code.py new file mode 100644 index 000000000..a7bc738c9 --- /dev/null +++ b/Bare_eInk_Guide/416x240_monochrome_circuitpython/code.py @@ -0,0 +1,61 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft, written for Adafruit Industries +# SPDX-FileCopyrightText: Copyright (c) 2021 Melissa LeBlanc-Williams for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense + +"""Simple test script for 3.7" 240x416 monochrome display (ThinkInk_370_Mono_BAAMFGN).""" + +import time + +import board +import busio +import displayio +from fourwire import FourWire + +import adafruit_uc8253 + +displayio.release_displays() + +if "EPD_MOSI" in dir(board): # Feather RP2040 ThinkInk + spi = busio.SPI(board.EPD_SCK, MOSI=board.EPD_MOSI, MISO=None) + epd_cs = board.EPD_CS + epd_dc = board.EPD_DC + epd_reset = board.EPD_RESET + epd_busy = board.EPD_BUSY +else: + spi = board.SPI() # Uses SCK and MOSI + epd_cs = board.D9 + epd_dc = board.D10 + epd_reset = board.D8 # Set to None for FeatherWing + epd_busy = board.D7 # Set to None for FeatherWing + +display_bus = FourWire(spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=1000000) +time.sleep(1) + +display = adafruit_uc8253.UC8253( + display_bus, + width=416, + height=240, + busy_pin=epd_busy, + rotation=270, + vcom_cdi=0x97, +) + +g = displayio.Group() + +pic = displayio.OnDiskBitmap("/display-ruler-1280x720.bmp") +t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) +g.append(t) + +display.root_group = g + +display.refresh() + +print("refreshed") + +time.sleep(display.time_to_refresh + 5) +print("waited correct time") + +# Keep the display the same +while True: + time.sleep(10) diff --git a/Bare_eInk_Guide/416x240_monochrome_circuitpython/display-ruler-1280x720.bmp b/Bare_eInk_Guide/416x240_monochrome_circuitpython/display-ruler-1280x720.bmp new file mode 100644 index 000000000..f73b1c3c2 Binary files /dev/null and b/Bare_eInk_Guide/416x240_monochrome_circuitpython/display-ruler-1280x720.bmp differ diff --git a/Bare_eInk_Guide/416x240_monochrome_python/code.py b/Bare_eInk_Guide/416x240_monochrome_python/code.py new file mode 100644 index 000000000..06cc08bfd --- /dev/null +++ b/Bare_eInk_Guide/416x240_monochrome_python/code.py @@ -0,0 +1,99 @@ +# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +ePaper Display Shapes and Text demo using the Pillow Library. +3.7" Monochrome 416x240 display +https://www.adafruit.com/product/6395 +""" + +import board +import busio +import digitalio +from PIL import Image, ImageDraw, ImageFont + +from adafruit_epd.uc8253 import Adafruit_UC8253_Mono + +# First define some color constants +WHITE = (0xFF, 0xFF, 0xFF) +BLACK = (0x00, 0x00, 0x00) + +# Next define some constants to allow easy resizing of shapes and colors +BORDER = 20 +FONTSIZE = 24 +BACKGROUND_COLOR = BLACK +FOREGROUND_COLOR = WHITE +TEXT_COLOR = BLACK + +# create the spi device and pins we will need +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) +ecs = digitalio.DigitalInOut(board.CE0) +dc = digitalio.DigitalInOut(board.D22) +srcs = None +rst = digitalio.DigitalInOut(board.D27) +busy = digitalio.DigitalInOut(board.D17) + +display = Adafruit_UC8253_Mono(240, 416, + spi, + cs_pin=ecs, + dc_pin=dc, + sramcs_pin=srcs, + rst_pin=rst, + busy_pin=busy +) + +display.set_black_buffer(1, True) +display.set_color_buffer(1, True) +display.rotation = 3 + +width = display.width +height = display.height +image = Image.new("RGB", (width, height)) + +# clear the buffer +display.fill(WHITE) + +# Get drawing object to draw on image. +draw = ImageDraw.Draw(image) +# empty it +draw.rectangle((0, 0, width, height), fill=WHITE) + +# Draw an outline box +draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE) + +# Draw some shapes. +# First define some constants to allow easy resizing of shapes. +padding = 15 +shape_width = 45 +top = padding +bottom = height - padding +# Move left to right keeping track of the current x position for drawing shapes. +x = padding +# Draw an ellipse. +draw.ellipse((x, top, x + shape_width, bottom), outline=BLACK, fill=WHITE) +x += shape_width + padding +# Draw a rectangle. +draw.rectangle((x, top, x + shape_width, bottom), outline=BLACK, fill=BLACK) +x += shape_width + padding +# Draw a triangle. +draw.polygon( + [(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)], + outline=BLACK, + fill=BLACK, +) +x += shape_width + padding +# Draw an X. +draw.line((x, bottom, x + shape_width, top), fill=BLACK) +draw.line((x, top, x + shape_width, bottom), fill=BLACK) +x += shape_width + padding + +# Load default font. +font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 30) + +draw.text((x, top), "Hello", font=font, fill=BLACK) +draw.text((x, top + 30), "World!", font=font, fill=BLACK) + +# Display image. +display.image(image) + +display.display() diff --git a/Bare_eInk_Guide/416x240_tricolor_arduino/.uno.test.only b/Bare_eInk_Guide/416x240_tricolor_arduino/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Bare_eInk_Guide/416x240_tricolor_arduino/416x240_tricolor_arduino.ino b/Bare_eInk_Guide/416x240_tricolor_arduino/416x240_tricolor_arduino.ino new file mode 100644 index 000000000..35e7b2d77 --- /dev/null +++ b/Bare_eInk_Guide/416x240_tricolor_arduino/416x240_tricolor_arduino.ino @@ -0,0 +1,104 @@ +// SPDX-FileCopyrightText: 2025 Ladyada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/*************************************************** + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_ThinkInk.h" + +#ifdef ARDUINO_ADAFRUIT_FEATHER_RP2040_THINKINK // detects if compiling for + // Feather RP2040 ThinkInk +#define EPD_DC PIN_EPD_DC // ThinkInk 24-pin connector DC +#define EPD_CS PIN_EPD_CS // ThinkInk 24-pin connector CS +#define EPD_BUSY PIN_EPD_BUSY // ThinkInk 24-pin connector Busy +#define SRAM_CS -1 // use onboard RAM +#define EPD_RESET PIN_EPD_RESET // ThinkInk 24-pin connector Reset +#define EPD_SPI &SPI1 // secondary SPI for ThinkInk +#else +#define EPD_DC 10 +#define EPD_CS 9 +#define EPD_BUSY 7 // can set to -1 to not use a pin (will wait a fixed delay) +#define SRAM_CS 6 +#define EPD_RESET 8 // can set to -1 and share with microcontroller Reset! +#define EPD_SPI &SPI // primary SPI +#endif + +// 3.7" Tricolor Display with 417x240 pixels and UC8253 chipset +ThinkInk_370_Tricolor_BABMFGNR display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, + EPD_BUSY, EPD_SPI); + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + Serial.println("Adafruit EPD full update test in red/black/white"); + Serial.println("3.7 Tri-Color EPD with UC8253 chipset"); + display.begin(THINKINK_TRICOLOR); +} + +void loop() { + Serial.println("Banner demo"); + display.clearBuffer(); + display.setTextSize(3); + display.setCursor((display.width() - 144) / 2, (display.height() - 24) / 2); + display.setTextColor(EPD_BLACK); + display.print("Tri"); + display.setTextColor(EPD_RED); + display.print("Color"); + display.display(); + + delay(15000); + + Serial.println("Color rectangle demo"); + display.clearBuffer(); + display.fillRect(display.width() / 3, 0, display.width() / 3, + display.height(), EPD_BLACK); + display.fillRect((display.width() * 2) / 3, 0, display.width() / 3, + display.height(), EPD_RED); + display.display(); + + delay(15000); + + Serial.println("Text demo"); + // large block of text + display.clearBuffer(); + display.setTextSize(1); + testdrawtext( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " + "adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, " + "fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor " + "neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet " + "ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a " + "tortor imperdiet posuere. ", + EPD_BLACK); + display.display(); + + delay(15000); + + display.clearBuffer(); + for (int16_t i = 0; i < display.width(); i += 4) { + display.drawLine(0, 0, i, display.height() - 1, EPD_BLACK); + } + + for (int16_t i = 0; i < display.height(); i += 4) { + display.drawLine(display.width() - 1, 0, 0, i, EPD_RED); + } + display.display(); + + delay(15000); +} + +void testdrawtext(const char *text, uint16_t color) { + display.setCursor(0, 0); + display.setTextColor(color); + display.setTextWrap(true); + display.print(text); +} diff --git a/Bare_eInk_Guide/416x240_tricolor_circuitpython/code.py b/Bare_eInk_Guide/416x240_tricolor_circuitpython/code.py new file mode 100644 index 000000000..16e67d5df --- /dev/null +++ b/Bare_eInk_Guide/416x240_tricolor_circuitpython/code.py @@ -0,0 +1,61 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft, written for Adafruit Industries +# SPDX-FileCopyrightText: Copyright (c) 2021 Melissa LeBlanc-Williams for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense + +"""Simple test script for 3.7" 240x416 tricolor display (ThinkInk_370_Tricolor_BABMFGNR).""" + +import time + +import board +import busio +import displayio +from fourwire import FourWire + +import adafruit_uc8253 + +displayio.release_displays() + +if "EPD_MOSI" in dir(board): # Feather RP2040 ThinkInk + spi = busio.SPI(board.EPD_SCK, MOSI=board.EPD_MOSI, MISO=None) + epd_cs = board.EPD_CS + epd_dc = board.EPD_DC + epd_reset = board.EPD_RESET + epd_busy = board.EPD_BUSY +else: + spi = board.SPI() # Uses SCK and MOSI + epd_cs = board.D9 + epd_dc = board.D10 + epd_reset = board.D8 # Set to None for FeatherWing + epd_busy = board.D7 # Set to None for FeatherWing + +display_bus = FourWire(spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=1000000) +time.sleep(1) + +display = adafruit_uc8253.UC8253( + display_bus, width=416, height=240, busy_pin=epd_busy, rotation=270, highlight_color=0xFF0000 +) + +g = displayio.Group() + +pic = displayio.OnDiskBitmap("/display-ruler-1280x720.bmp") +t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) +g.append(t) + +display.root_group = g + +display.refresh() + +print("refreshed") + +time.sleep(display.time_to_refresh + 5) +# Always refresh a little longer. It's not a problem to refresh +# a few seconds more, but it's terrible to refresh too early +# (the display will throw an exception when if the refresh +# is too soon) +print("waited correct time") + + +# Keep the display the same +while True: + time.sleep(10) diff --git a/Bare_eInk_Guide/416x240_tricolor_circuitpython/display-ruler-1280x720.bmp b/Bare_eInk_Guide/416x240_tricolor_circuitpython/display-ruler-1280x720.bmp new file mode 100644 index 000000000..f73b1c3c2 Binary files /dev/null and b/Bare_eInk_Guide/416x240_tricolor_circuitpython/display-ruler-1280x720.bmp differ diff --git a/Bare_eInk_Guide/416x240_tricolor_python/code.py b/Bare_eInk_Guide/416x240_tricolor_python/code.py new file mode 100644 index 000000000..fccc60c62 --- /dev/null +++ b/Bare_eInk_Guide/416x240_tricolor_python/code.py @@ -0,0 +1,102 @@ +# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +ePaper Display Shapes and Text demo using the Pillow Library. +3.7" Tri-Color 416x240 display +https://www.adafruit.com/product/6394 +""" + +import board +import busio +import digitalio +from PIL import Image, ImageDraw, ImageFont + +from adafruit_epd.uc8253 import Adafruit_UC8253_Tricolor + +# First define some color constants +WHITE = (0xFF, 0xFF, 0xFF) +BLACK = (0x00, 0x00, 0x00) +RED = (0xFF, 0x00, 0x00) + +# Next define some constants to allow easy resizing of shapes and colors +BORDER = 20 +FONTSIZE = 24 +BACKGROUND_COLOR = BLACK +FOREGROUND_COLOR = WHITE +TEXT_COLOR = BLACK + +# create the spi device and pins we will need +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) +ecs = digitalio.DigitalInOut(board.CE0) +dc = digitalio.DigitalInOut(board.D22) +srcs = None +rst = digitalio.DigitalInOut(board.D27) +busy = digitalio.DigitalInOut(board.D17) + +display = Adafruit_UC8253_Tricolor(240, 416, + spi, + cs_pin=ecs, + dc_pin=dc, + sramcs_pin=srcs, + rst_pin=rst, + busy_pin=busy +) + +display.rotation = 3 + +width = display.width +height = display.height +image = Image.new("RGB", (width, height)) + +WHITE = (0xFF, 0xFF, 0xFF) +RED = (0xFF, 0x00, 0x00) +BLACK = (0x00, 0x00, 0x00) + +# clear the buffer +display.fill(WHITE) + +# Get drawing object to draw on image. +draw = ImageDraw.Draw(image) +# empty it +draw.rectangle((0, 0, width, height), fill=WHITE) + +# Draw an outline box +draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE) + +# Draw some shapes. +# First define some constants to allow easy resizing of shapes. +padding = 15 +shape_width = 45 +top = padding +bottom = height - padding +# Move left to right keeping track of the current x position for drawing shapes. +x = padding +# Draw an ellipse. +draw.ellipse((x, top, x + shape_width, bottom), outline=RED, fill=WHITE) +x += shape_width + padding +# Draw a rectangle. +draw.rectangle((x, top, x + shape_width, bottom), outline=RED, fill=BLACK) +x += shape_width + padding +# Draw a triangle. +draw.polygon( + [(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)], + outline=BLACK, + fill=RED, +) +x += shape_width + padding +# Draw an X. +draw.line((x, bottom, x + shape_width, top), fill=BLACK) +draw.line((x, top, x + shape_width, bottom), fill=RED) +x += shape_width + padding + +# Load default font. +font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 30) + +draw.text((x, top), "Hello", font=font, fill=BLACK) +draw.text((x, top + 30), "World!", font=font, fill=BLACK) + +# Display image. +display.image(image) + +display.display() diff --git a/Bare_eInk_Guide/648x480_monochrome_arduino/.uno.test.only b/Bare_eInk_Guide/648x480_monochrome_arduino/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Bare_eInk_Guide/648x480_monochrome_arduino/648x480_monochrome_arduino.ino b/Bare_eInk_Guide/648x480_monochrome_arduino/648x480_monochrome_arduino.ino new file mode 100644 index 000000000..1870f4c8a --- /dev/null +++ b/Bare_eInk_Guide/648x480_monochrome_arduino/648x480_monochrome_arduino.ino @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: 2025 Ladyada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/*************************************************** + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_ThinkInk.h" + +#ifdef ARDUINO_ADAFRUIT_FEATHER_RP2040_THINKINK // detects if compiling for + // Feather RP2040 ThinkInk +#define EPD_DC PIN_EPD_DC // ThinkInk 24-pin connector DC +#define EPD_CS PIN_EPD_CS // ThinkInk 24-pin connector CS +#define EPD_BUSY PIN_EPD_BUSY // ThinkInk 24-pin connector Busy +#define SRAM_CS -1 // use onboard RAM +#define EPD_RESET PIN_EPD_RESET // ThinkInk 24-pin connector Reset +#define EPD_SPI &SPI1 // secondary SPI for ThinkInk +#else +#define EPD_DC 10 +#define EPD_CS 9 +#define EPD_BUSY 7 // can set to -1 to not use a pin (will wait a fixed delay) +#define SRAM_CS 6 +#define EPD_RESET 8 // can set to -1 and share with microcontroller Reset! +#define EPD_SPI &SPI // primary SPI +#endif + +// 5.83" Monochrome displays with 648 x 480 pixels and UC8179 chipset +ThinkInk_583_Mono_AAAMFGN display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY, EPD_SPI); + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + Serial.println("Adafruit EPD full update test in mono"); + Serial.println("5.83 Monochrome EPD with UC8179 chipset"); + display.begin(THINKINK_MONO); +} + +void loop() { + Serial.println("Banner demo"); + display.clearBuffer(); + display.setTextSize(3); + display.setCursor((display.width() - 180) / 2, (display.height() - 24) / 2); + display.setTextColor(EPD_BLACK); + display.print("Monochrome"); + display.display(); + + delay(2000); + + Serial.println("B/W rectangle demo"); + display.clearBuffer(); + display.fillRect(display.width() / 2, 0, display.width() / 2, + display.height(), EPD_BLACK); + display.display(); + + delay(2000); + + Serial.println("Text demo"); + // large block of text + display.clearBuffer(); + display.setTextSize(1); + testdrawtext( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " + "adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, " + "fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor " + "neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet " + "ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a " + "tortor imperdiet posuere. ", + EPD_BLACK); + display.display(); + + delay(2000); + + display.clearBuffer(); + for (int16_t i = 0; i < display.width(); i += 4) { + display.drawLine(0, 0, i, display.height() - 1, EPD_BLACK); + } + + for (int16_t i = 0; i < display.height(); i += 4) { + display.drawLine(display.width() - 1, 0, 0, i, EPD_BLACK); + } + display.display(); + + delay(2000); +} + +void testdrawtext(const char *text, uint16_t color) { + display.setCursor(0, 0); + display.setTextColor(color); + display.setTextWrap(true); + display.print(text); +} diff --git a/Bare_eInk_Guide/648x480_monochrome_circuitpython/code.py b/Bare_eInk_Guide/648x480_monochrome_circuitpython/code.py new file mode 100644 index 000000000..827ecb70c --- /dev/null +++ b/Bare_eInk_Guide/648x480_monochrome_circuitpython/code.py @@ -0,0 +1,62 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft, written for Adafruit Industries +# SPDX-FileCopyrightText: Copyright (c) 2021 Melissa LeBlanc-Williams for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense + +"""Simple test script for 5.83" 648x480 monochrome display (ThinkInk_583_Mono_AAAMFGN).""" + +import time + +import board +import busio +import displayio +from fourwire import FourWire + +import adafruit_uc8179 + +displayio.release_displays() + +if "EPD_MOSI" in dir(board): # Feather RP2040 ThinkInk + spi = busio.SPI(board.EPD_SCK, MOSI=board.EPD_MOSI, MISO=None) + epd_cs = board.EPD_CS + epd_dc = board.EPD_DC + epd_reset = board.EPD_RESET + epd_busy = board.EPD_BUSY +else: + spi = board.SPI() # Uses SCK and MOSI + epd_cs = board.D9 + epd_dc = board.D10 + epd_reset = board.D8 # Set to None for FeatherWing + epd_busy = board.D7 # Set to None for FeatherWing + +display_bus = FourWire(spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=1000000) +time.sleep(1) + +display = adafruit_uc8179.UC8179( + display_bus, + width=648, + height=480, + busy_pin=epd_busy, + rotation=180, + black_bits_inverted=True, + colstart=0, +) + +g = displayio.Group() + +pic = displayio.OnDiskBitmap("/display-ruler-1280x720.bmp") +t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) +g.append(t) + +display.root_group = g + +display.refresh() + +print("refreshed") + +time.sleep(display.time_to_refresh + 5) +print("waited correct time") + +# Keep the display the same +while True: + time.sleep(10) diff --git a/Bare_eInk_Guide/648x480_monochrome_circuitpython/display-ruler-1280x720.bmp b/Bare_eInk_Guide/648x480_monochrome_circuitpython/display-ruler-1280x720.bmp new file mode 100644 index 000000000..f73b1c3c2 Binary files /dev/null and b/Bare_eInk_Guide/648x480_monochrome_circuitpython/display-ruler-1280x720.bmp differ diff --git a/Bare_eInk_Guide/648x480_monochrome_python/code.py b/Bare_eInk_Guide/648x480_monochrome_python/code.py new file mode 100644 index 000000000..4767a26a9 --- /dev/null +++ b/Bare_eInk_Guide/648x480_monochrome_python/code.py @@ -0,0 +1,100 @@ +# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +ePaper Display Shapes and Text demo using the Pillow Library. +5.83" mono 648x480 display +https://www.adafruit.com/product/6397 +""" + +import board +import busio +import digitalio +from PIL import Image, ImageDraw, ImageFont + +from adafruit_epd.uc8179 import Adafruit_UC8179 + +# First define some color constants +WHITE = (0xFF, 0xFF, 0xFF) +BLACK = (0xFF, 0x00, 0x00) + +# Next define some constants to allow easy resizing of shapes and colors +BORDER = 20 +FONTSIZE = 24 +BACKGROUND_COLOR = BLACK +FOREGROUND_COLOR = WHITE +TEXT_COLOR = BLACK + +# create the spi device and pins we will need +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) +ecs = digitalio.DigitalInOut(board.CE0) +dc = digitalio.DigitalInOut(board.D22) +srcs = None +rst = digitalio.DigitalInOut(board.D27) +busy = digitalio.DigitalInOut(board.D17) + +# give them all to our driver +display = Adafruit_UC8179(648, 480, + spi, + cs_pin=ecs, + dc_pin=dc, + sramcs_pin=srcs, + rst_pin=rst, + busy_pin=busy, +) + +display.set_black_buffer(1, False) +display.set_color_buffer(1, False) +display.rotation = 0 + +width = display.width +height = display.height +image = Image.new("RGB", (width, height)) + +# clear the buffer +display.fill(WHITE) + +# Get drawing object to draw on image. +draw = ImageDraw.Draw(image) +# empty it +draw.rectangle((0, 0, width, height), fill=WHITE) + +# Draw an outline box +draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE) + +# Draw some shapes. +# First define some constants to allow easy resizing of shapes. +padding = 25 +shape_width = 80 +top = padding +bottom = height - padding +# Move left to right keeping track of the current x position for drawing shapes. +x = padding +# Draw an ellipse. +draw.ellipse((x, top, x + shape_width, bottom), outline=BLACK, fill=WHITE) +x += shape_width + padding +# Draw a rectangle. +draw.rectangle((x, top, x + shape_width, bottom), outline=BLACK, fill=BLACK) +x += shape_width + padding +# Draw a triangle. +draw.polygon( + [(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)], + outline=BLACK, + fill=BLACK, +) +x += shape_width + padding +# Draw an X. +draw.line((x, bottom, x + shape_width, top), fill=BLACK) +draw.line((x, top, x + shape_width, bottom), fill=BLACK) +x += shape_width + padding + +# Load default font. +font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 40) + +draw.text((x, top), "Hello", font=font, fill=BLACK) +draw.text((x, top + 40), "World!", font=font, fill=BLACK) + +# Display image. +display.image(image) + +display.display() diff --git a/Bare_eInk_Guide/800x480_monochrome_arduino/.uno.test.only b/Bare_eInk_Guide/800x480_monochrome_arduino/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Bare_eInk_Guide/800x480_monochrome_arduino/800x480_monochrome_arduino.ino b/Bare_eInk_Guide/800x480_monochrome_arduino/800x480_monochrome_arduino.ino new file mode 100644 index 000000000..755a07f68 --- /dev/null +++ b/Bare_eInk_Guide/800x480_monochrome_arduino/800x480_monochrome_arduino.ino @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: 2025 Ladyada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/*************************************************** + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_ThinkInk.h" + +#ifdef ARDUINO_ADAFRUIT_FEATHER_RP2040_THINKINK // detects if compiling for + // Feather RP2040 ThinkInk +#define EPD_DC PIN_EPD_DC // ThinkInk 24-pin connector DC +#define EPD_CS PIN_EPD_CS // ThinkInk 24-pin connector CS +#define EPD_BUSY PIN_EPD_BUSY // ThinkInk 24-pin connector Busy +#define SRAM_CS -1 // use onboard RAM +#define EPD_RESET PIN_EPD_RESET // ThinkInk 24-pin connector Reset +#define EPD_SPI &SPI1 // secondary SPI for ThinkInk +#else +#define EPD_DC 10 +#define EPD_CS 9 +#define EPD_BUSY 7 // can set to -1 to not use a pin (will wait a fixed delay) +#define SRAM_CS 6 +#define EPD_RESET 8 // can set to -1 and share with microcontroller Reset! +#define EPD_SPI &SPI // primary SPI +#endif + +// 7.5" Monochrome displays with 800 x 480 pixels and UC8179 chipset +ThinkInk_750_Mono_AAAMFGN display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY, EPD_SPI); + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + Serial.println("Adafruit EPD full update test in mono"); + Serial.println("7.5 Monochrome EPD with UC8179 chipset"); + display.begin(THINKINK_MONO); +} + +void loop() { + Serial.println("Banner demo"); + display.clearBuffer(); + display.setTextSize(3); + display.setCursor((display.width() - 180) / 2, (display.height() - 24) / 2); + display.setTextColor(EPD_BLACK); + display.print("Monochrome"); + display.display(); + + delay(2000); + + Serial.println("B/W rectangle demo"); + display.clearBuffer(); + display.fillRect(display.width() / 2, 0, display.width() / 2, + display.height(), EPD_BLACK); + display.display(); + + delay(2000); + + Serial.println("Text demo"); + // large block of text + display.clearBuffer(); + display.setTextSize(1); + testdrawtext( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " + "adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, " + "fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor " + "neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet " + "ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a " + "tortor imperdiet posuere. ", + EPD_BLACK); + display.display(); + + delay(2000); + + display.clearBuffer(); + for (int16_t i = 0; i < display.width(); i += 4) { + display.drawLine(0, 0, i, display.height() - 1, EPD_BLACK); + } + + for (int16_t i = 0; i < display.height(); i += 4) { + display.drawLine(display.width() - 1, 0, 0, i, EPD_BLACK); + } + display.display(); + + delay(2000); +} + +void testdrawtext(const char *text, uint16_t color) { + display.setCursor(0, 0); + display.setTextColor(color); + display.setTextWrap(true); + display.print(text); +} diff --git a/Bare_eInk_Guide/800x480_monochrome_circuitpython/code.py b/Bare_eInk_Guide/800x480_monochrome_circuitpython/code.py new file mode 100644 index 000000000..a55f6af15 --- /dev/null +++ b/Bare_eInk_Guide/800x480_monochrome_circuitpython/code.py @@ -0,0 +1,62 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft, written for Adafruit Industries +# SPDX-FileCopyrightText: Copyright (c) 2021 Melissa LeBlanc-Williams for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense + +"""Simple test script for 7.5" 800x480 monochrome display""" + +import time + +import board +import busio +import displayio +from fourwire import FourWire + +import adafruit_uc8179 + +displayio.release_displays() + +if "EPD_MOSI" in dir(board): # Feather RP2040 ThinkInk + spi = busio.SPI(board.EPD_SCK, MOSI=board.EPD_MOSI, MISO=None) + epd_cs = board.EPD_CS + epd_dc = board.EPD_DC + epd_reset = board.EPD_RESET + epd_busy = board.EPD_BUSY +else: + spi = board.SPI() # Uses SCK and MOSI + epd_cs = board.D9 + epd_dc = board.D10 + epd_reset = board.D8 # Set to None for FeatherWing + epd_busy = board.D7 # Set to None for FeatherWing + +display_bus = FourWire(spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=1000000) +time.sleep(1) + +display = adafruit_uc8179.UC8179( + display_bus, + width=800, + height=480, + busy_pin=epd_busy, + rotation=180, + black_bits_inverted=True, + colstart=0, +) + +g = displayio.Group() + +pic = displayio.OnDiskBitmap("/display-ruler-1280x720.bmp") +t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) +g.append(t) + +display.root_group = g + +display.refresh() + +print("refreshed") + +time.sleep(display.time_to_refresh + 5) +print("waited correct time") + +# Keep the display the same +while True: + time.sleep(10) diff --git a/Bare_eInk_Guide/800x480_monochrome_circuitpython/display-ruler-1280x720.bmp b/Bare_eInk_Guide/800x480_monochrome_circuitpython/display-ruler-1280x720.bmp new file mode 100644 index 000000000..f73b1c3c2 Binary files /dev/null and b/Bare_eInk_Guide/800x480_monochrome_circuitpython/display-ruler-1280x720.bmp differ diff --git a/Bare_eInk_Guide/800x480_monochrome_python/code.py b/Bare_eInk_Guide/800x480_monochrome_python/code.py new file mode 100644 index 000000000..3d44e1cb2 --- /dev/null +++ b/Bare_eInk_Guide/800x480_monochrome_python/code.py @@ -0,0 +1,100 @@ +# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +ePaper Display Shapes and Text demo using the Pillow Library. +7.5" mono 800x480 display +https://www.adafruit.com/product/6396 +""" + +import board +import busio +import digitalio +from PIL import Image, ImageDraw, ImageFont + +from adafruit_epd.uc8179 import Adafruit_UC8179 + +# First define some color constants +WHITE = (0xFF, 0xFF, 0xFF) +BLACK = (0xFF, 0x00, 0x00) + +# Next define some constants to allow easy resizing of shapes and colors +BORDER = 20 +FONTSIZE = 24 +BACKGROUND_COLOR = BLACK +FOREGROUND_COLOR = WHITE +TEXT_COLOR = BLACK + +# create the spi device and pins we will need +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) +ecs = digitalio.DigitalInOut(board.CE0) +dc = digitalio.DigitalInOut(board.D22) +srcs = None +rst = digitalio.DigitalInOut(board.D27) +busy = digitalio.DigitalInOut(board.D17) + +# give them all to our driver +display = Adafruit_UC8179(800, 480, + spi, + cs_pin=ecs, + dc_pin=dc, + sramcs_pin=srcs, + rst_pin=rst, + busy_pin=busy, +) + +display.set_black_buffer(1, False) +display.set_color_buffer(1, False) +display.rotation = 0 + +width = display.width +height = display.height +image = Image.new("RGB", (width, height)) + +# clear the buffer +display.fill(WHITE) + +# Get drawing object to draw on image. +draw = ImageDraw.Draw(image) +# empty it +draw.rectangle((0, 0, width, height), fill=WHITE) + +# Draw an outline box +draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE) + +# Draw some shapes. +# First define some constants to allow easy resizing of shapes. +padding = 25 +shape_width = 100 +top = padding +bottom = height - padding +# Move left to right keeping track of the current x position for drawing shapes. +x = padding +# Draw an ellipse. +draw.ellipse((x, top, x + shape_width, bottom), outline=BLACK, fill=WHITE) +x += shape_width + padding +# Draw a rectangle. +draw.rectangle((x, top, x + shape_width, bottom), outline=BLACK, fill=BLACK) +x += shape_width + padding +# Draw a triangle. +draw.polygon( + [(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)], + outline=BLACK, + fill=BLACK, +) +x += shape_width + padding +# Draw an X. +draw.line((x, bottom, x + shape_width, top), fill=BLACK) +draw.line((x, top, x + shape_width, bottom), fill=BLACK) +x += shape_width + padding + +# Load default font. +font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 50) + +draw.text((x, top), "Hello", font=font, fill=BLACK) +draw.text((x, top + 50), "World!", font=font, fill=BLACK) + +# Display image. +display.image(image) + +display.display() diff --git a/Bare_eInk_Guide/800x480_tricolor_arduino/.uno.test.only b/Bare_eInk_Guide/800x480_tricolor_arduino/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Bare_eInk_Guide/800x480_tricolor_arduino/800x480_tricolor_arduino.ino b/Bare_eInk_Guide/800x480_tricolor_arduino/800x480_tricolor_arduino.ino new file mode 100644 index 000000000..d975b74db --- /dev/null +++ b/Bare_eInk_Guide/800x480_tricolor_arduino/800x480_tricolor_arduino.ino @@ -0,0 +1,103 @@ +// SPDX-FileCopyrightText: 2025 Ladyada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/*************************************************** + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_ThinkInk.h" + +#ifdef ARDUINO_ADAFRUIT_FEATHER_RP2040_THINKINK // detects if compiling for + // Feather RP2040 ThinkInk +#define EPD_DC PIN_EPD_DC // ThinkInk 24-pin connector DC +#define EPD_CS PIN_EPD_CS // ThinkInk 24-pin connector CS +#define EPD_BUSY PIN_EPD_BUSY // ThinkInk 24-pin connector Busy +#define SRAM_CS -1 // use onboard RAM +#define EPD_RESET PIN_EPD_RESET // ThinkInk 24-pin connector Reset +#define EPD_SPI &SPI1 // secondary SPI for ThinkInk +#else +#define EPD_DC 10 +#define EPD_CS 9 +#define EPD_BUSY 7 // can set to -1 to not use a pin (will wait a fixed delay) +#define SRAM_CS 6 +#define EPD_RESET 8 // can set to -1 and share with microcontroller Reset! +#define EPD_SPI &SPI // primary SPI +#endif + +// 7.5" Tricolor displays with 800x480 pixels and UC8179 chipset +ThinkInk_750_Tricolor_AABMFGNR display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY, EPD_SPI); + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + Serial.println("Adafruit EPD full update test in red/black/white"); + Serial.println("7.5 Tri-Color EPD with UC8179 chipset"); + display.begin(THINKINK_TRICOLOR); +} + +void loop() { + Serial.println("Banner demo"); + display.clearBuffer(); + display.setTextSize(3); + display.setCursor((display.width() - 144) / 2, (display.height() - 24) / 2); + display.setTextColor(EPD_BLACK); + display.print("Tri"); + display.setTextColor(EPD_RED); + display.print("Color"); + display.display(); + + delay(15000); + + Serial.println("Color rectangle demo"); + display.clearBuffer(); + display.fillRect(display.width() / 3, 0, display.width() / 3, + display.height(), EPD_BLACK); + display.fillRect((display.width() * 2) / 3, 0, display.width() / 3, + display.height(), EPD_RED); + display.display(); + + delay(15000); + + Serial.println("Text demo"); + // large block of text + display.clearBuffer(); + display.setTextSize(1); + testdrawtext( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " + "adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, " + "fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor " + "neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet " + "ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a " + "tortor imperdiet posuere. ", + EPD_BLACK); + display.display(); + + delay(15000); + + display.clearBuffer(); + for (int16_t i = 0; i < display.width(); i += 4) { + display.drawLine(0, 0, i, display.height() - 1, EPD_BLACK); + } + + for (int16_t i = 0; i < display.height(); i += 4) { + display.drawLine(display.width() - 1, 0, 0, i, EPD_RED); + } + display.display(); + + delay(15000); +} + +void testdrawtext(const char *text, uint16_t color) { + display.setCursor(0, 0); + display.setTextColor(color); + display.setTextWrap(true); + display.print(text); +} diff --git a/Bare_eInk_Guide/800x480_tricolor_circuitpython/code.py b/Bare_eInk_Guide/800x480_tricolor_circuitpython/code.py new file mode 100644 index 000000000..51adc6b74 --- /dev/null +++ b/Bare_eInk_Guide/800x480_tricolor_circuitpython/code.py @@ -0,0 +1,63 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft, written for Adafruit Industries +# SPDX-FileCopyrightText: Copyright (c) 2021 Melissa LeBlanc-Williams for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense + +"""Simple test script for 7.5" 800x480 tricolor display (ThinkInk_750_Tricolor_AABMFGNR).""" + +import time + +import board +import busio +import displayio +from fourwire import FourWire + +import adafruit_uc8179 + +displayio.release_displays() + +if "EPD_MOSI" in dir(board): # Feather RP2040 ThinkInk + spi = busio.SPI(board.EPD_SCK, MOSI=board.EPD_MOSI, MISO=None) + epd_cs = board.EPD_CS + epd_dc = board.EPD_DC + epd_reset = board.EPD_RESET + epd_busy = board.EPD_BUSY +else: + spi = board.SPI() # Uses SCK and MOSI + epd_cs = board.D9 + epd_dc = board.D10 + epd_reset = board.D8 # Set to None for FeatherWing + epd_busy = board.D7 # Set to None for FeatherWing + +display_bus = FourWire(spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=1000000) +time.sleep(1) + +display = adafruit_uc8179.UC8179( + display_bus, + width=800, + height=480, + busy_pin=epd_busy, + rotation=180, + black_bits_inverted=True, + highlight_color=0xFF0000, + colstart=0, +) + +g = displayio.Group() + +pic = displayio.OnDiskBitmap("/display-ruler-1280x720.bmp") +t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) +g.append(t) + +display.root_group = g + +display.refresh() + +print("refreshed") + +time.sleep(display.time_to_refresh + 5) +print("waited correct time") + +# Keep the display the same +while True: + time.sleep(10) diff --git a/Bare_eInk_Guide/800x480_tricolor_circuitpython/display-ruler-1280x720.bmp b/Bare_eInk_Guide/800x480_tricolor_circuitpython/display-ruler-1280x720.bmp new file mode 100644 index 000000000..f73b1c3c2 Binary files /dev/null and b/Bare_eInk_Guide/800x480_tricolor_circuitpython/display-ruler-1280x720.bmp differ diff --git a/Bare_eInk_Guide/800x480_tricolor_python/code.py b/Bare_eInk_Guide/800x480_tricolor_python/code.py new file mode 100644 index 000000000..d00948cb3 --- /dev/null +++ b/Bare_eInk_Guide/800x480_tricolor_python/code.py @@ -0,0 +1,99 @@ +# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +ePaper Display Shapes and Text demo using the Pillow Library. +7.5" Tri-Color 800x480 display +https://www.adafruit.com/product/6415 +""" + +import board +import busio +import digitalio +from PIL import Image, ImageDraw, ImageFont + +from adafruit_epd.uc8179 import Adafruit_UC8179 + +# First define some color constants +WHITE = (0xFF, 0xFF, 0xFF) +BLACK = (0x00, 0x00, 0x00) +RED = (0xFF, 0x00, 0x00) + +# Next define some constants to allow easy resizing of shapes and colors +BORDER = 20 +FONTSIZE = 24 +BACKGROUND_COLOR = BLACK +FOREGROUND_COLOR = WHITE +TEXT_COLOR = BLACK + +# create the spi device and pins we will need +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) +ecs = digitalio.DigitalInOut(board.CE0) +dc = digitalio.DigitalInOut(board.D22) +srcs = None +rst = digitalio.DigitalInOut(board.D27) +busy = digitalio.DigitalInOut(board.D17) + +display = Adafruit_UC8179(800, 480, # 7.5" tricolor 800x480 display + spi, + cs_pin=ecs, + dc_pin=dc, + sramcs_pin=srcs, + rst_pin=rst, + busy_pin=busy, + tri_color = True +) + +display.rotation = 0 + +width = display.width +height = display.height +image = Image.new("RGB", (width, height)) + +# clear the buffer +display.fill(WHITE) + +# Get drawing object to draw on image. +draw = ImageDraw.Draw(image) +# empty it +draw.rectangle((0, 0, width, height), fill=WHITE) + +# Draw an outline box +draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE) + +# Draw some shapes. +# First define some constants to allow easy resizing of shapes. +padding = 25 +shape_width = 100 +top = padding +bottom = height - padding +# Move left to right keeping track of the current x position for drawing shapes. +x = padding +# Draw an ellipse. +draw.ellipse((x, top, x + shape_width, bottom), outline=RED, fill=WHITE) +x += shape_width + padding +# Draw a rectangle. +draw.rectangle((x, top, x + shape_width, bottom), outline=RED, fill=BLACK) +x += shape_width + padding +# Draw a triangle. +draw.polygon( + [(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)], + outline=BLACK, + fill=RED, +) +x += shape_width + padding +# Draw an X. +draw.line((x, bottom, x + shape_width, top), fill=BLACK) +draw.line((x, top, x + shape_width, bottom), fill=RED) +x += shape_width + padding + +# Load default font. +font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 50) + +draw.text((x, top), "Hello", font=font, fill=BLACK) +draw.text((x, top + 50), "World!", font=font, fill=BLACK) + +# Display image. +display.image(image) + +display.display() diff --git a/Bluetooth_Lumon_Speaker/.esp32.test.only b/Bluetooth_Lumon_Speaker/.esp32.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Bluetooth_Lumon_Speaker/Bluetooth_Lumon_Speaker.ino b/Bluetooth_Lumon_Speaker/Bluetooth_Lumon_Speaker.ino new file mode 100644 index 000000000..86a6ee426 --- /dev/null +++ b/Bluetooth_Lumon_Speaker/Bluetooth_Lumon_Speaker.ino @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2020 Phil Schatzmann +// +// SPDX-License-Identifier: GPL-3.0-or-later + +/* + Streaming Music from Bluetooth + + Copyright (C) 2020 Phil Schatzmann + 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 3 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 . +*/ + +// ==> Example which shows how to use the built in ESP32 I2S >= 3.0.0 + +#include "ESP_I2S.h" +#include "BluetoothA2DPSink.h" + +const uint8_t I2S_SCK = 8; /* Audio data bit clock */ +const uint8_t I2S_WS = 7; /* Audio data left and right clock */ +const uint8_t I2S_SDOUT = 14; /* ESP32 audio data output (to speakers) */ +I2SClass i2s; + +BluetoothA2DPSink a2dp_sink(i2s); + +void setup() { + i2s.setPins(I2S_SCK, I2S_WS, I2S_SDOUT); + if (!i2s.begin(I2S_MODE_STD, 44100, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO, I2S_STD_SLOT_BOTH)) { + Serial.println("Failed to initialize I2S!"); + while (1); // do nothing + } + + a2dp_sink.start("Lumon Industries Speaker"); +} + +void loop() { +} diff --git a/Bluetooth_Unified_Keyboard_Bridge/.pico_rp2040.test.only b/Bluetooth_Unified_Keyboard_Bridge/.pico_rp2040.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Bluetooth_Unified_Keyboard_Bridge/.pico_rp2350.test.only b/Bluetooth_Unified_Keyboard_Bridge/.pico_rp2350.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Bluetooth_Unified_Keyboard_Bridge/Bluetooth_Unified_Keyboard_Bridge.ino b/Bluetooth_Unified_Keyboard_Bridge/Bluetooth_Unified_Keyboard_Bridge.ino new file mode 100644 index 000000000..03ba50b89 --- /dev/null +++ b/Bluetooth_Unified_Keyboard_Bridge/Bluetooth_Unified_Keyboard_Bridge.ino @@ -0,0 +1,730 @@ +// SPDX-FileCopyrightText: 2025 John Park for Adafruit Industries +// +// SPDX-License-Identifier: MIT +// +// made with assistance from Claude Sonnet 4 +// +// Unified Bluetooth HID Bridge - BT Classic & BLE +// put keyboard in pairing mode, then press reset or BOOT button +// slow blinks mean scanning +// fast blinks mean keyboard detected, press a keyboard key to connect + +// === CONFIGURATION === +#define DEBUG_MODE false // Set to false to reduce serial output +#define BLINK_MODE true // Set to false for solid LED (no keypress blinks) +#define SCAN_MODE "Both" // Options: "BT_Classic", "BLE", "Both" + +// Include both Bluetooth stacks +extern "C" { +#include "btstack.h" +} +#include +#include +#include +#include + +// Connection state management +typedef enum { + INIT, + SCANNING_CLASSIC, + CLASSIC_CONNECTING, + CLASSIC_CONNECTED, + SCANNING_BLE, + BLE_CONNECTED, + BOTH_FAILED, + DISCONNECTED +} connection_state_t; + +connection_state_t connection_state = INIT; + +// BT Classic components +BluetoothHCI hci; +bd_addr_t target_keyboard_addr; +bool target_keyboard_found = false; +uint16_t hid_control_cid = 0; +uint16_t hid_interrupt_cid = 0; +static btstack_packet_callback_registration_t hci_event_callback_registration; + +// BLE components +BluetoothHIDMaster ble_hid; +HIDKeyStream keystream; + +// Shared state tracking +static uint8_t last_modifiers = 0; +static uint8_t last_keys[6] = {0}; +bool keyPressed[256] = {0}; // Track which keys are currently pressed + +// LED management +unsigned long ledTimer = 0; +bool ledState = false; +unsigned long ledOffTime = 0; +bool ledBlinking = false; +int pairingBlinks = 0; +unsigned long pairingBlinkTimer = 0; + +// Timing management +unsigned long lastScan = 0; +unsigned long stateStartTime = 0; +const unsigned long CLASSIC_SCAN_TIMEOUT = 10000; // 10 seconds +const unsigned long BLE_SCAN_TIMEOUT = 15000; // 15 seconds + +void setup() { + Serial.begin(115200); + delay(3000); + + Serial.println("=== UNIFIED BLUETOOTH HID BRIDGE ==="); + Serial.printf("Scan mode: %s\n", SCAN_MODE); + Serial.println("Put your Bluetooth device in pairing mode now"); + + // Initialize LED + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, LOW); + Serial.println("LED initialized"); + + // Initialize USB HID + Keyboard.begin(); + Mouse.begin(); + Serial.println("USB HID initialized"); + + // Start with LED blinking to show we're alive + ledTimer = millis(); + ledState = true; + digitalWrite(LED_BUILTIN, HIGH); + + Serial.println("Starting Bluetooth stack initialization..."); + + // Choose scan mode based on user setting + if (strcmp(SCAN_MODE, "BT_Classic") == 0) { + Serial.println("BT Classic only mode"); + connection_state = SCANNING_CLASSIC; + stateStartTime = millis(); + initAndScanClassic(); + } else if (strcmp(SCAN_MODE, "BLE") == 0) { + Serial.println("BLE only mode"); + connection_state = SCANNING_BLE; + stateStartTime = millis(); + initAndScanBLE(); + } else { + Serial.println("Both protocols mode - trying Classic first"); + connection_state = SCANNING_CLASSIC; + stateStartTime = millis(); + initAndScanClassic(); + } +} + +void initAndScanClassic() { + Serial.println("\n=== INITIALIZING BT CLASSIC STACK ==="); + + // Initialize HCI for Classic + l2cap_init(); + sm_init(); + gap_set_default_link_policy_settings(LM_LINK_POLICY_ENABLE_SNIFF_MODE | LM_LINK_POLICY_ENABLE_ROLE_SWITCH); + hci_set_master_slave_policy(HCI_ROLE_MASTER); + hci_set_inquiry_mode(INQUIRY_MODE_RSSI_AND_EIR); + + Serial.println("BTStack components initialized"); + + hci.install(); + hci.begin(); + Serial.println("HCI installed and started"); + + // Register BTStack event handler + hci_event_callback_registration.callback = &classic_packet_handler; + hci_add_event_handler(&hci_event_callback_registration); + Serial.println("Event handler registered"); + + // Turn on Bluetooth + hci_power_control(HCI_POWER_ON); + Serial.println("Bluetooth power ON"); + + delay(2000); // Give it time to initialize + + Serial.println("Starting BT Classic device scan..."); + scanForClassicDevices(); +} + +void scanForClassicDevices() { + Serial.println("Scanning for BT Classic devices..."); + + auto devices = hci.scan(BluetoothHCI::any_cod); + + Serial.printf("Classic scan completed. Found %d devices:\n", devices.size()); + + if (devices.size() == 0) { + Serial.println("No Classic devices found. Will try BLE after timeout."); + return; + } + + Serial.println("Address | RSSI | Class | Name"); + Serial.println("------------------|------|----------|------------------"); + + for (auto device : devices) { + uint32_t cod = device.deviceClass(); + uint8_t majorClass = (cod >> 8) & 0x1F; + uint8_t minorClass = (cod >> 2) & 0x3F; + + Serial.printf("%s | %4d | %08lx | %s", + device.addressString(), device.rssi(), cod, device.name()); + + // Look for HID keyboards in Classic scan + if (majorClass == 5 && (minorClass & 0x10)) { // HID Keyboard + Serial.print(" [HID KEYBOARD] *** CONNECTING ***"); + + // We found a Classic keyboard! + const char* addrStr = device.addressString(); + sscanf(addrStr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &target_keyboard_addr[0], &target_keyboard_addr[1], &target_keyboard_addr[2], + &target_keyboard_addr[3], &target_keyboard_addr[4], &target_keyboard_addr[5]); + target_keyboard_found = true; + + Serial.printf("\nFound Classic HID keyboard: %s\n", device.name()); + Serial.printf("Address: %s\n", device.addressString()); + + // Start Classic connection + connection_state = CLASSIC_CONNECTING; + stateStartTime = millis(); + startClassicConnection(); + + Serial.println(); + return; // Exit the loop - we found our keyboard + } else { + // Show device type for debugging + switch (majorClass) { + case 1: Serial.print(" [Computer]"); break; + case 2: Serial.print(" [Phone]"); break; + case 3: Serial.print(" [Network]"); break; + case 4: Serial.print(" [Audio/Video]"); break; + case 5: Serial.print(" [HID Device]"); break; + default: Serial.printf(" [Class:%d]", majorClass); break; + } + } + Serial.println(); + } + + Serial.println("No HID keyboards found in Classic scan."); +} + +void fallbackToBLE() { + Serial.println("\n=== FALLING BACK TO BLE ==="); + connection_state = SCANNING_BLE; + stateStartTime = millis(); + initAndScanBLE(); +} + +void initAndScanBLE() { + Serial.println("Initializing BLE stack..."); + + // Setup the HID key to ASCII conversion + keystream.begin(); + Serial.println("KeyStream initialized"); + + // Setup BLE callbacks + setupBLECallbacks(); + Serial.println("BLE callbacks configured"); + + // Start BLE HID master + ble_hid.begin(true); + Serial.println("BLE HID master started"); + + // Start BLE connection attempt + ble_hid.connectBLE(); + Serial.println("BLE connection initiated - waiting for device..."); + Serial.println("(BLE devices will be detected on first keypress)"); +} + +void setupBLECallbacks() { + // BLE Mouse callbacks + ble_hid.onMouseMove([](void *cbdata, int dx, int dy, int dw) { + (void) cbdata; + if (DEBUG_MODE) { + Serial.printf("BLE Mouse: X:%d Y:%d Wheel:%d\n", dx, dy, dw); + } + Mouse.move(dx, dy); + if (dw != 0) Mouse.move(0, 0, dw); + blinkOnActivity(); + }); + + ble_hid.onMouseButton([](void *cbdata, int butt, bool down) { + (void) cbdata; + if (DEBUG_MODE) { + Serial.printf("BLE Mouse: Button %d %s\n", butt, down ? "DOWN" : "UP"); + } + if (down) { + if (butt == 1) Mouse.press(MOUSE_LEFT); + else if (butt == 2) Mouse.press(MOUSE_RIGHT); + else if (butt == 3) Mouse.press(MOUSE_MIDDLE); + } else { + if (butt == 1) Mouse.release(MOUSE_LEFT); + else if (butt == 2) Mouse.release(MOUSE_RIGHT); + else if (butt == 3) Mouse.release(MOUSE_MIDDLE); + } + blinkOnActivity(); + }); + + // BLE Keyboard callbacks + ble_hid.onKeyDown([](void *cbdata, int key) { + handleBLEKey(key, true); + }, (void *)true); + + ble_hid.onKeyUp([](void *cbdata, int key) { + handleBLEKey(key, false); + }, (void *)false); +} + +void startClassicConnection() { + if (!target_keyboard_found) { + Serial.println("ERROR: No Classic target keyboard found"); + fallbackToBLE(); + return; + } + + Serial.println("=== STARTING CLASSIC HID CONNECTION ==="); + Serial.println("Creating L2CAP Control channel..."); + + // Create control channel first + l2cap_create_channel(&classic_packet_handler, target_keyboard_addr, BLUETOOTH_PSM_HID_CONTROL, + 48, &hid_control_cid); +} + +void handleBLEKey(int key, bool state) { + if (DEBUG_MODE) { + Serial.printf("BLE Keyboard: %02x %s\n", key, state ? "DOWN" : "UP"); + } + + if (key >= 256) return; // Bounds check + + // Check if this is the first BLE key press (connection detection) + if (connection_state == SCANNING_BLE) { + Serial.printf("\n*** BLE KEYBOARD DETECTED ON FIRST KEYPRESS ***\n"); + Serial.printf("=== BLE DEVICE CONNECTED ===\n"); + Serial.printf("Ready to forward BLE input to USB.\n"); + Serial.printf("========================\n"); + + connection_state = BLE_CONNECTED; + celebrationBlinks(8); // 4 blinks for BLE + + // After celebration, LED will go solid (handled in LED patterns) + } + + // Forward the key to USB + forwardBLEKeyToUSB(key, state); + blinkOnActivity(); +} + +void classic_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { + UNUSED(size); + + if (packet_type == HCI_EVENT_PACKET) { + uint8_t event = hci_event_packet_get_type(packet); + + switch (event) { + case BTSTACK_EVENT_STATE: + if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING) { + Serial.println("Classic BTstack ready"); + } + break; + + case L2CAP_EVENT_CHANNEL_OPENED: + { + uint16_t cid = l2cap_event_channel_opened_get_local_cid(packet); + uint16_t psm = l2cap_event_channel_opened_get_psm(packet); + uint8_t status = l2cap_event_channel_opened_get_status(packet); + + if (status) { + Serial.printf("Classic L2CAP connection failed, status 0x%02x\n", status); + handleClassicConnectionError(status); + return; + } + + Serial.printf("Classic L2CAP channel opened: CID=0x%04x, PSM=0x%04x\n", cid, psm); + + if (psm == BLUETOOTH_PSM_HID_CONTROL) { + hid_control_cid = cid; + Serial.println("Classic HID Control channel established"); + Serial.println("Creating L2CAP Interrupt channel..."); + + // Create interrupt channel + l2cap_create_channel(&classic_packet_handler, target_keyboard_addr, BLUETOOTH_PSM_HID_INTERRUPT, + 48, &hid_interrupt_cid); + } else if (psm == BLUETOOTH_PSM_HID_INTERRUPT) { + hid_interrupt_cid = cid; + Serial.println("Classic HID Interrupt channel established"); + Serial.println("*** CLASSIC HID CONNECTION COMPLETE ***"); + connection_state = CLASSIC_CONNECTED; + + celebrationBlinks(6); // 3 blinks for Classic + + // After celebration, LED will go solid (handled in LED patterns) + } + } + break; + + case L2CAP_EVENT_CHANNEL_CLOSED: + { + uint16_t cid = l2cap_event_channel_closed_get_local_cid(packet); + Serial.printf("Classic L2CAP channel closed: CID=0x%04x\n", cid); + + if (cid == hid_control_cid) { + hid_control_cid = 0; + } else if (cid == hid_interrupt_cid) { + hid_interrupt_cid = 0; + } + + if (hid_control_cid == 0 && hid_interrupt_cid == 0) { + Serial.println("Classic HID connection lost."); + connection_state = DISCONNECTED; + target_keyboard_found = false; + } + } + break; + + default: + break; + } + } else if (packet_type == L2CAP_DATA_PACKET) { + // Classic HID input data + if (channel == hid_interrupt_cid) { + if (DEBUG_MODE) { + Serial.printf("Classic HID Input Data (%d bytes): ", size); + for (int i = 0; i < size; i++) { + Serial.printf("%02X ", packet[i]); + } + Serial.println(); + } + + processClassicHIDReport(packet, size); + } + } +} + +void handleClassicConnectionError(uint8_t status) { + Serial.printf("Classic connection failed with status 0x%02x - ", status); + switch (status) { + case 0x04: Serial.println("Page timeout"); break; + case 0x05: Serial.println("Authentication failure"); break; + case 0x08: Serial.println("Connection timeout"); break; + default: Serial.printf("Error code 0x%02x\n", status); break; + } + + Serial.println("Trying BLE fallback..."); + fallbackToBLE(); +} + +void processClassicHIDReport(uint8_t *report, uint16_t length) { + if (length < 10) { + Serial.printf("Invalid Classic HID report length: %d\n", length); + return; + } + + uint8_t modifiers = report[2]; + uint8_t *keys = &report[4]; + + // Forward to USB HID + forwardClassicToUSB(modifiers, keys); + blinkOnActivity(); +} + +// Shared key mapping function +uint8_t hidToUsbKey(uint8_t hidKey) { + switch (hidKey) { + // Letters + case 0x04: return 'a'; case 0x05: return 'b'; case 0x06: return 'c'; case 0x07: return 'd'; + case 0x08: return 'e'; case 0x09: return 'f'; case 0x0A: return 'g'; case 0x0B: return 'h'; + case 0x0C: return 'i'; case 0x0D: return 'j'; case 0x0E: return 'k'; case 0x0F: return 'l'; + case 0x10: return 'm'; case 0x11: return 'n'; case 0x12: return 'o'; case 0x13: return 'p'; + case 0x14: return 'q'; case 0x15: return 'r'; case 0x16: return 's'; case 0x17: return 't'; + case 0x18: return 'u'; case 0x19: return 'v'; case 0x1A: return 'w'; case 0x1B: return 'x'; + case 0x1C: return 'y'; case 0x1D: return 'z'; + + // Numbers + case 0x1E: return '1'; case 0x1F: return '2'; case 0x20: return '3'; case 0x21: return '4'; + case 0x22: return '5'; case 0x23: return '6'; case 0x24: return '7'; case 0x25: return '8'; + case 0x26: return '9'; case 0x27: return '0'; + + // Special keys + case 0x28: return KEY_RETURN; case 0x29: return KEY_ESC; + case 0x2A: return KEY_BACKSPACE; case 0x2B: return KEY_TAB; + case 0x2C: return ' '; case 0x39: return KEY_CAPS_LOCK; + + // Symbols + case 0x2D: return '-'; case 0x2E: return '='; case 0x2F: return '['; case 0x30: return ']'; + case 0x31: return '\\'; case 0x33: return ';'; case 0x34: return '\''; case 0x35: return '`'; + case 0x36: return ','; case 0x37: return '.'; case 0x38: return '/'; + + // Function keys + case 0x3A: return KEY_F1; case 0x3B: return KEY_F2; case 0x3C: return KEY_F3; + case 0x3D: return KEY_F4; case 0x3E: return KEY_F5; case 0x3F: return KEY_F6; + case 0x40: return KEY_F7; case 0x41: return KEY_F8; case 0x42: return KEY_F9; + case 0x43: return KEY_F10; case 0x44: return KEY_F11; case 0x45: return KEY_F12; + + // Arrow keys + case 0x4F: return KEY_RIGHT_ARROW; case 0x50: return KEY_LEFT_ARROW; + case 0x51: return KEY_DOWN_ARROW; case 0x52: return KEY_UP_ARROW; + + // Navigation + case 0x49: return KEY_INSERT; case 0x4A: return KEY_HOME; + case 0x4B: return KEY_PAGE_UP; case 0x4C: return KEY_DELETE; + case 0x4D: return KEY_END; case 0x4E: return KEY_PAGE_DOWN; + + // Modifiers + case 0xE0: return KEY_LEFT_CTRL; case 0xE1: return KEY_LEFT_SHIFT; + case 0xE2: return KEY_LEFT_ALT; case 0xE3: return KEY_LEFT_GUI; + case 0xE4: return KEY_RIGHT_CTRL; case 0xE5: return KEY_RIGHT_SHIFT; + case 0xE6: return KEY_RIGHT_ALT; case 0xE7: return KEY_RIGHT_GUI; + + default: return 0; + } +} + +void forwardClassicToUSB(uint8_t modifiers, uint8_t *keys) { + // Handle modifier changes + uint8_t modifier_changes = modifiers ^ last_modifiers; + + // Process each modifier bit + if (modifier_changes & 0x01) (modifiers & 0x01) ? Keyboard.press(KEY_LEFT_CTRL) : Keyboard.release(KEY_LEFT_CTRL); + if (modifier_changes & 0x02) (modifiers & 0x02) ? Keyboard.press(KEY_LEFT_SHIFT) : Keyboard.release(KEY_LEFT_SHIFT); + if (modifier_changes & 0x04) (modifiers & 0x04) ? Keyboard.press(KEY_LEFT_ALT) : Keyboard.release(KEY_LEFT_ALT); + if (modifier_changes & 0x08) (modifiers & 0x08) ? Keyboard.press(KEY_LEFT_GUI) : Keyboard.release(KEY_LEFT_GUI); + if (modifier_changes & 0x10) (modifiers & 0x10) ? Keyboard.press(KEY_RIGHT_CTRL) : Keyboard.release(KEY_RIGHT_CTRL); + if (modifier_changes & 0x20) (modifiers & 0x20) ? Keyboard.press(KEY_RIGHT_SHIFT) : Keyboard.release(KEY_RIGHT_SHIFT); + if (modifier_changes & 0x40) (modifiers & 0x40) ? Keyboard.press(KEY_RIGHT_ALT) : Keyboard.release(KEY_RIGHT_ALT); + if (modifier_changes & 0x80) (modifiers & 0x80) ? Keyboard.press(KEY_RIGHT_GUI) : Keyboard.release(KEY_RIGHT_GUI); + + // Handle key releases + for (int i = 0; i < 6; i++) { + if (last_keys[i] != 0) { + bool still_pressed = false; + for (int j = 0; j < 6; j++) { + if (keys[j] == last_keys[i]) { + still_pressed = true; + break; + } + } + if (!still_pressed) { + uint8_t usb_key = hidToUsbKey(last_keys[i]); + if (usb_key != 0) Keyboard.release(usb_key); + } + } + } + + // Handle key presses + for (int i = 0; i < 6; i++) { + if (keys[i] != 0) { + bool already_pressed = false; + for (int j = 0; j < 6; j++) { + if (last_keys[j] == keys[i]) { + already_pressed = true; + break; + } + } + if (!already_pressed) { + uint8_t usb_key = hidToUsbKey(keys[i]); + if (usb_key != 0) Keyboard.press(usb_key); + } + } + } + + // Save current state + last_modifiers = modifiers; + memcpy(last_keys, keys, 6); +} + +void forwardBLEKeyToUSB(int key, bool state) { + if (key >= 256) return; + + bool isModifier = (key >= 0xE0 && key <= 0xE7); + + if (isModifier) { + uint8_t usbKey = hidToUsbKey(key); + if (state) Keyboard.press(usbKey); + else Keyboard.release(usbKey); + return; + } + + // Handle regular keys + uint8_t usbKey = hidToUsbKey(key); + if (usbKey != 0) { + if (state && !keyPressed[key]) { + keyPressed[key] = true; + Keyboard.press(usbKey); + } else if (!state && keyPressed[key]) { + keyPressed[key] = false; + Keyboard.release(usbKey); + } + } +} + +void celebrationBlinks(int count) { + pairingBlinks = count; + pairingBlinkTimer = millis(); + digitalWrite(LED_BUILTIN, HIGH); +} + +void blinkOnActivity() { + if (BLINK_MODE && pairingBlinks == 0 && (connection_state == CLASSIC_CONNECTED || connection_state == BLE_CONNECTED)) { + digitalWrite(LED_BUILTIN, LOW); // Turn OFF briefly to show activity + ledBlinking = true; + ledOffTime = millis() + 50; // Stay off for 50ms + } +} + +void loop() { + unsigned long currentTime = millis(); + + // Handle state timeouts + handleStateTimeouts(currentTime); + + // Handle LED patterns + handleLEDPatterns(currentTime); + + // Handle BOOTSEL button + handleBootselButton(); + + delay(10); +} + +void handleStateTimeouts(unsigned long currentTime) { + switch (connection_state) { + case SCANNING_CLASSIC: + if (currentTime - stateStartTime > CLASSIC_SCAN_TIMEOUT) { + if (strcmp(SCAN_MODE, "BT_Classic") == 0) { + Serial.println("Classic scan timeout - BT Classic only mode, retrying..."); + stateStartTime = currentTime; + scanForClassicDevices(); // Retry Classic scan + } else { + Serial.println("Classic scan timeout - falling back to BLE"); + fallbackToBLE(); + } + } + break; + + case SCANNING_BLE: + if (currentTime - stateStartTime > BLE_SCAN_TIMEOUT) { + if (strcmp(SCAN_MODE, "BLE") == 0) { + Serial.println("BLE scan timeout - BLE only mode, retrying..."); + stateStartTime = currentTime; + initAndScanBLE(); // Retry BLE scan + } else { + Serial.println("BLE scan timeout - restarting from Classic"); + connection_state = BOTH_FAILED; + stateStartTime = currentTime; + } + } + break; + + case BOTH_FAILED: + if (currentTime - stateStartTime > 5000) { // Wait 5 seconds before retry + Serial.println("Retrying scan sequence..."); + connection_state = SCANNING_CLASSIC; + stateStartTime = currentTime; + initAndScanClassic(); + } + break; + } +} + +void handleLEDPatterns(unsigned long currentTime) { + // Handle pairing celebration blinks first + if (pairingBlinks > 0) { + if (currentTime - pairingBlinkTimer >= 150) { + pairingBlinks--; + bool state = (pairingBlinks % 2 == 0); + digitalWrite(LED_BUILTIN, state); + pairingBlinkTimer = currentTime; + } + return; + } + + // Handle activity blinks + if (ledBlinking && currentTime >= ledOffTime) { + digitalWrite(LED_BUILTIN, HIGH); // Turn back ON after brief off period + ledBlinking = false; + return; + } + + // Handle state-based LED patterns + switch (connection_state) { + case SCANNING_CLASSIC: + case SCANNING_BLE: + // Slow blink while scanning (1 second cycle) + if (currentTime - ledTimer >= 1000) { + ledState = !ledState; + digitalWrite(LED_BUILTIN, ledState); + ledTimer = currentTime; + } + break; + + case CLASSIC_CONNECTING: + // Fast blink while connecting - tells user to press a key + if (currentTime - ledTimer >= 250) { + ledState = !ledState; + digitalWrite(LED_BUILTIN, ledState); + ledTimer = currentTime; + } + break; + + case CLASSIC_CONNECTED: + case BLE_CONNECTED: + // Solid ON while connected (unless doing activity blinks) + if (!ledBlinking) { + digitalWrite(LED_BUILTIN, HIGH); + } + break; + + case BOTH_FAILED: + case DISCONNECTED: + // Very slow pulse when failed/disconnected (2 second cycle) + if (currentTime - ledTimer >= 2000) { + ledState = !ledState; + digitalWrite(LED_BUILTIN, ledState); + ledTimer = currentTime; + } + break; + } +} + +void handleBootselButton() { + if (BOOTSEL) { + while (BOOTSEL) delay(1); + + Serial.println("\nBOOTSEL pressed - restarting scan sequence"); + + // Clean up current connections + if (connection_state == CLASSIC_CONNECTED) { + if (hid_control_cid) l2cap_disconnect(hid_control_cid); + if (hid_interrupt_cid) l2cap_disconnect(hid_interrupt_cid); + } else if (connection_state == BLE_CONNECTED) { + ble_hid.disconnect(); + ble_hid.clearPairing(); + } + + // Reset all state + Keyboard.releaseAll(); + Mouse.release(MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE); + + for (int i = 0; i < 256; i++) keyPressed[i] = false; + memset(last_keys, 0, 6); + last_modifiers = 0; + + target_keyboard_found = false; + hid_control_cid = 0; + hid_interrupt_cid = 0; + pairingBlinks = 0; + ledBlinking = false; + + // Restart from appropriate scan mode + if (strcmp(SCAN_MODE, "BT_Classic") == 0) { + connection_state = SCANNING_CLASSIC; + Serial.println("Restarting BT Classic scan..."); + initAndScanClassic(); + } else if (strcmp(SCAN_MODE, "BLE") == 0) { + connection_state = SCANNING_BLE; + Serial.println("Restarting BLE scan..."); + initAndScanBLE(); + } else { + connection_state = SCANNING_CLASSIC; + Serial.println("Restarting unified scan..."); + initAndScanClassic(); + } + } +} \ No newline at end of file diff --git a/Buckaroo_Plant_Care_Bot/code.py b/Buckaroo_Plant_Care_Bot/code.py index ca0938346..076119f2b 100644 --- a/Buckaroo_Plant_Care_Bot/code.py +++ b/Buckaroo_Plant_Care_Bot/code.py @@ -22,31 +22,17 @@ clue_display = displayio.Group() # draw the dry plant -dry_plant_file = open("dry.bmp", "rb") -dry_plant_bmp = displayio.OnDiskBitmap(dry_plant_file) -# CircuitPython 6 & 7 compatible +dry_plant_bmp = displayio.OnDiskBitmap("dry.bmp") dry_plant_sprite = displayio.TileGrid( - dry_plant_bmp, - pixel_shader=getattr(dry_plant_bmp, "pixel_shader", displayio.ColorConverter()), + dry_plant_bmp, pixel_shader=dry_plant_bmp.pixel_shader ) -# CircuitPython 7 compatible -# dry_plant_sprite = displayio.TileGrid( -# dry_plant_bmp, pixel_shader=dry_plant_bmp.pixel_shader -# ) clue_display.append(dry_plant_sprite) # draw the happy plant on top (so it can be moved out of the way when needed) -happy_plant_file = open("happy.bmp", "rb") -happy_plant_bmp = displayio.OnDiskBitmap(happy_plant_file) -# CircuitPython 6 & 7 compatible +happy_plant_bmp = displayio.OnDiskBitmap("happy.bmp") happy_plant_sprite = displayio.TileGrid( - happy_plant_bmp, - pixel_shader=getattr(happy_plant_bmp, "pixel_shader", displayio.ColorConverter()), + happy_plant_bmp, pixel_shader=happy_plant_bmp.pixel_shader ) -# CircuitPython 7 compatible -# happy_plant_sprite = displayio.TileGrid( -# happy_plant_bmp, pixel_shader=happy_plant_bmp.pixel_shader -# ) clue_display.append(happy_plant_sprite) # Create text diff --git a/CAN_Bus_BFF/CircuitPython/can_bus_bff_receiver.py b/CAN_Bus_BFF/CircuitPython/can_bus_bff_receiver.py index 1adb9c912..c9300c012 100644 --- a/CAN_Bus_BFF/CircuitPython/can_bus_bff_receiver.py +++ b/CAN_Bus_BFF/CircuitPython/can_bus_bff_receiver.py @@ -5,6 +5,7 @@ import board import terminalio import displayio +import i2cdisplaybus from digitalio import DigitalInOut from adafruit_mcp2515.canio import Message, RemoteTransmissionRequest from adafruit_mcp2515 import MCP2515 as CAN @@ -15,7 +16,7 @@ i2c = board.STEMMA_I2C() # STEMMA OLED setup -display_bus = displayio.I2CDisplay(i2c, device_address=0x3D, reset=None) +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3D, reset=None) display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=64) cs = DigitalInOut(board.A3) diff --git a/CLUE_Altimeter/.circuitpython.skip b/CLUE/CLUE_Altimeter/.circuitpython.skip similarity index 100% rename from CLUE_Altimeter/.circuitpython.skip rename to CLUE/CLUE_Altimeter/.circuitpython.skip diff --git a/CLUE_Altimeter/code.py b/CLUE/CLUE_Altimeter/code.py old mode 100755 new mode 100644 similarity index 100% rename from CLUE_Altimeter/code.py rename to CLUE/CLUE_Altimeter/code.py diff --git a/CLUE_Altimeter/images/network23.bmp b/CLUE/CLUE_Altimeter/images/network23.bmp old mode 100755 new mode 100644 similarity index 100% rename from CLUE_Altimeter/images/network23.bmp rename to CLUE/CLUE_Altimeter/images/network23.bmp diff --git a/CLUE_BBQ/code.py b/CLUE/CLUE_BBQ/code.py similarity index 100% rename from CLUE_BBQ/code.py rename to CLUE/CLUE_BBQ/code.py diff --git a/CLUE_BBQ/font/GothamBlack-25.bdf b/CLUE/CLUE_BBQ/font/GothamBlack-25.bdf old mode 100755 new mode 100644 similarity index 100% rename from CLUE_BBQ/font/GothamBlack-25.bdf rename to CLUE/CLUE_BBQ/font/GothamBlack-25.bdf diff --git a/CLUE_BBQ/font/GothamBlack-50.bdf b/CLUE/CLUE_BBQ/font/GothamBlack-50.bdf old mode 100755 new mode 100644 similarity index 100% rename from CLUE_BBQ/font/GothamBlack-50.bdf rename to CLUE/CLUE_BBQ/font/GothamBlack-50.bdf diff --git a/CLUE_BLE_Morse_Code/code.py b/CLUE/CLUE_BLE_Morse_Code/code.py old mode 100755 new mode 100644 similarity index 100% rename from CLUE_BLE_Morse_Code/code.py rename to CLUE/CLUE_BLE_Morse_Code/code.py diff --git a/CLUE_BLE_Morse_Code/morse_bg.bmp b/CLUE/CLUE_BLE_Morse_Code/morse_bg.bmp old mode 100755 new mode 100644 similarity index 100% rename from CLUE_BLE_Morse_Code/morse_bg.bmp rename to CLUE/CLUE_BLE_Morse_Code/morse_bg.bmp diff --git a/CLUE_Beacon/bg.bmp b/CLUE/CLUE_Beacon/bg.bmp old mode 100755 new mode 100644 similarity index 100% rename from CLUE_Beacon/bg.bmp rename to CLUE/CLUE_Beacon/bg.bmp diff --git a/CLUE_Beacon/cluebeacon.bmp b/CLUE/CLUE_Beacon/cluebeacon.bmp old mode 100755 new mode 100644 similarity index 100% rename from CLUE_Beacon/cluebeacon.bmp rename to CLUE/CLUE_Beacon/cluebeacon.bmp diff --git a/CLUE_Beacon/code.py b/CLUE/CLUE_Beacon/code.py similarity index 100% rename from CLUE_Beacon/code.py rename to CLUE/CLUE_Beacon/code.py diff --git a/CLUE_Cycling_Simple/code.py b/CLUE/CLUE_Cycling_Simple/code.py similarity index 100% rename from CLUE_Cycling_Simple/code.py rename to CLUE/CLUE_Cycling_Simple/code.py diff --git a/CLUE_Dice_Roller/Anton-Regular-104.bdf b/CLUE/CLUE_Dice_Roller/Anton-Regular-104.bdf similarity index 100% rename from CLUE_Dice_Roller/Anton-Regular-104.bdf rename to CLUE/CLUE_Dice_Roller/Anton-Regular-104.bdf diff --git a/CLUE_Dice_Roller/Helvetica-Bold-36.bdf b/CLUE/CLUE_Dice_Roller/Helvetica-Bold-36.bdf similarity index 100% rename from CLUE_Dice_Roller/Helvetica-Bold-36.bdf rename to CLUE/CLUE_Dice_Roller/Helvetica-Bold-36.bdf diff --git a/CLUE_Dice_Roller/code.py b/CLUE/CLUE_Dice_Roller/code.py similarity index 100% rename from CLUE_Dice_Roller/code.py rename to CLUE/CLUE_Dice_Roller/code.py diff --git a/CLUE_Egg_Drop/broken_egg.bmp b/CLUE/CLUE_Egg_Drop/broken_egg.bmp similarity index 100% rename from CLUE_Egg_Drop/broken_egg.bmp rename to CLUE/CLUE_Egg_Drop/broken_egg.bmp diff --git a/CLUE/CLUE_Egg_Drop/code.py b/CLUE/CLUE_Egg_Drop/code.py new file mode 100644 index 000000000..67bf9bfa8 --- /dev/null +++ b/CLUE/CLUE_Egg_Drop/code.py @@ -0,0 +1,99 @@ +# SPDX-FileCopyrightText: 2020 John Park for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import time +import math +import board +from digitalio import DigitalInOut, Direction, Pull +import pwmio +from adafruit_lsm6ds.lsm6ds33 import LSM6DS33 +from adafruit_lsm6ds.lsm6ds3trc import LSM6DS3TRC +from adafruit_lsm6ds import AccelRange, AccelHPF, Rate +from adafruit_display_text import label +import displayio +import terminalio + +button_a = DigitalInOut(board.BUTTON_A) +button_a.direction = Direction.INPUT +button_a.pull = Pull.UP + +splash = displayio.Group() + +# bad egg +BAD_EGG_FILENAME = "broken_egg.bmp" + +begg_bmp = displayio.OnDiskBitmap(BAD_EGG_FILENAME) +begg_sprite = displayio.TileGrid(begg_bmp, pixel_shader=begg_bmp.pixel_shader) + +# good egg +GOOD_EGG_FILENAME = "good_egg.bmp" + +gegg_bmp = displayio.OnDiskBitmap(GOOD_EGG_FILENAME) +gegg_sprite = displayio.TileGrid(gegg_bmp, pixel_shader=gegg_bmp.pixel_shader) + +# draw the bad egg! +splash.append(begg_sprite) +# draw the good egg on top +splash.append(gegg_sprite) + +# Draw a label +text_group = displayio.Group(scale=2, x=10, y=220) +text = "Current & Max Acceleration" +text_area = label.Label(terminalio.FONT, text=text, color=0x0000FF) +text_group.append(text_area) # Subgroup for text scaling +splash.append(text_group) + +# display everything so far +board.DISPLAY.root_group = splash + +# connect to the accelerometer +i2c = board.I2C() # uses board.SCL and board.SDA +# i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller +# connect to the accelerometer +i2c = board.I2C() # uses board.SCL and board.SDA +# i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller +try: + sensor = LSM6DS33(i2c) # older CLUEs +except RuntimeError: + sensor = LSM6DS3TRC(i2c) # newer CLUEs (Jan 2025) +# highest range for impacts! +sensor.accelerometer_range = AccelRange.RANGE_16G +# we'll read at about 1KHz +sensor.accelerometer_rate = Rate.RATE_1_66K_HZ +# Instead of raw accelerometer data, we'll read the *change* in acceleration (shock) +sensor.high_pass_filter = AccelHPF.SLOPE +sensor.high_pass_filter_enabled = True + +# and make a lil buzzer +buzzer = pwmio.PWMOut(board.SPEAKER, variable_frequency=True) +buzzer.frequency = 1000 + +max_slope = 0 +egg_ok = True +while True: + # This isn't the acceleration but the SLOPE (change!) in acceleration + x, y, z = sensor.acceleration + # take the vector length by squaring, adding, taking root + slope_g = math.sqrt(x*x + y*y + z*z) / 9.8 # take vector, convert to g + # we'll track the max delta g + + if max_slope < slope_g: + max_slope = slope_g + print(slope_g) + text_area.text = "Max Slope %0.1fg" % max_slope + if max_slope >= 9 and egg_ok: + gegg_sprite.x = 300 + time.sleep(0.1) + egg_ok = False + buzzer.duty_cycle = 2**15 + time.sleep(2) + buzzer.duty_cycle = 0 + continue + + if button_a.value is False and egg_ok is False: + print("Reset") + time.sleep(0.1) # debounce + max_slope = 0 + gegg_sprite.x = 0 + egg_ok = True diff --git a/CLUE_Egg_Drop/good_egg.bmp b/CLUE/CLUE_Egg_Drop/good_egg.bmp similarity index 100% rename from CLUE_Egg_Drop/good_egg.bmp rename to CLUE/CLUE_Egg_Drop/good_egg.bmp diff --git a/CLUE/CLUE_Hand_Wash_Timer/code.py b/CLUE/CLUE_Hand_Wash_Timer/code.py new file mode 100644 index 000000000..8f1217ffa --- /dev/null +++ b/CLUE/CLUE_Hand_Wash_Timer/code.py @@ -0,0 +1,94 @@ +# SPDX-FileCopyrightText: 2020 John Park for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +Start a 20 second hand washing timer via proximity sensor. +Countdown the seconds with text and beeps. +Display a bitmaps for waiting and washing modes. +""" + +import time +import board +from adafruit_clue import clue +from adafruit_display_text import label +from adafruit_bitmap_font import bitmap_font +import displayio +import pwmio + +clue.display.brightness = 0.8 +clue_display = displayio.Group() + +# draw the background image +WASH_ON_FILENAME = "wash_on.bmp" +wash_on_bmp = displayio.OnDiskBitmap(WASH_ON_FILENAME) +wash_on_sprite = displayio.TileGrid(wash_on_bmp, pixel_shader=wash_on_bmp.pixel_shader) + +clue_display.append(wash_on_sprite) + +# draw the foreground image +WASH_OFF_FILENAME = "wash_off.bmp" + +wash_off_bmp = displayio.OnDiskBitmap(WASH_OFF_FILENAME) +wash_off_sprite = displayio.TileGrid(wash_off_bmp, pixel_shader=wash_off_bmp.pixel_shader) + +clue_display.append(wash_off_sprite) + +# Create text +# first create the group +text_group = displayio.Group() +# Make a label +title_font = bitmap_font.load_font("/font/RacingSansOne-Regular-38.bdf") +title_font.load_glyphs("HandWashTimer".encode('utf-8')) +title_label = label.Label(title_font, text="Hand Wash", color=0x001122) +# Position the label +title_label.x = 10 +title_label.y = 16 +# Append label to group +text_group.append(title_label) + +title2_label = label.Label(title_font, text="Timer", color=0x001122) +# Position the label +title2_label.x = 6 +title2_label.y = 52 +# Append label to group +text_group.append(title2_label) + +timer_font = bitmap_font.load_font("/font/RacingSansOne-Regular-29.bdf") +timer_font.load_glyphs("0123456789ADSWabcdefghijklmnopqrstuvwxyz:!".encode('utf-8')) +timer_label = label.Label(timer_font, text="Wave to start", color=0x4f3ab1) +timer_label.x = 24 +timer_label.y = 100 +text_group.append(timer_label) + +clue_display.append(text_group) +clue.display.root_group = clue_display + +def countdown(seconds): + for i in range(seconds): + buzzer.duty_cycle = 2**15 + timer_label.text = ("Scrub time: {}".format(seconds-i)) + buzzer.duty_cycle = 0 + time.sleep(1) + timer_label.text = ("Done!") + wash_off_sprite.x = 0 + buzzer.duty_cycle = 2**15 + time.sleep(0.3) + buzzer.duty_cycle = 0 + timer_label.x = 24 + timer_label.y = 100 + timer_label.text = ("Wave to start") + +# setup buzzer +buzzer = pwmio.PWMOut(board.SPEAKER, variable_frequency=True) +buzzer.frequency = 1000 + +while True: + # print("Distance: {}".format(clue.proximity)) # use to test the sensor + if clue.proximity > 1: + timer_label.x = 12 + timer_label.y = 226 + timer_label.text = "Scrub Away!" + wash_off_sprite.x = 300 + time.sleep(2) + countdown(20) diff --git a/CLUE_Hand_Wash_Timer/font/RacingSansOne-Regular-29.bdf b/CLUE/CLUE_Hand_Wash_Timer/font/RacingSansOne-Regular-29.bdf old mode 100755 new mode 100644 similarity index 100% rename from CLUE_Hand_Wash_Timer/font/RacingSansOne-Regular-29.bdf rename to CLUE/CLUE_Hand_Wash_Timer/font/RacingSansOne-Regular-29.bdf diff --git a/CLUE_Hand_Wash_Timer/font/RacingSansOne-Regular-38.bdf b/CLUE/CLUE_Hand_Wash_Timer/font/RacingSansOne-Regular-38.bdf old mode 100755 new mode 100644 similarity index 100% rename from CLUE_Hand_Wash_Timer/font/RacingSansOne-Regular-38.bdf rename to CLUE/CLUE_Hand_Wash_Timer/font/RacingSansOne-Regular-38.bdf diff --git a/CLUE_Hand_Wash_Timer/wash_off.bmp b/CLUE/CLUE_Hand_Wash_Timer/wash_off.bmp old mode 100755 new mode 100644 similarity index 100% rename from CLUE_Hand_Wash_Timer/wash_off.bmp rename to CLUE/CLUE_Hand_Wash_Timer/wash_off.bmp diff --git a/CLUE_Hand_Wash_Timer/wash_on.bmp b/CLUE/CLUE_Hand_Wash_Timer/wash_on.bmp old mode 100755 new mode 100644 similarity index 100% rename from CLUE_Hand_Wash_Timer/wash_on.bmp rename to CLUE/CLUE_Hand_Wash_Timer/wash_on.bmp diff --git a/CLUE_Heart_Rate_Trainer/.circuitpython.skip b/CLUE/CLUE_Heart_Rate_Trainer/.circuitpython.skip similarity index 100% rename from CLUE_Heart_Rate_Trainer/.circuitpython.skip rename to CLUE/CLUE_Heart_Rate_Trainer/.circuitpython.skip diff --git a/CLUE_Heart_Rate_Trainer/code.py b/CLUE/CLUE_Heart_Rate_Trainer/code.py similarity index 100% rename from CLUE_Heart_Rate_Trainer/code.py rename to CLUE/CLUE_Heart_Rate_Trainer/code.py diff --git a/CLUE_I_Ching/christopher_done_24.bdf b/CLUE/CLUE_I_Ching/christopher_done_24.bdf similarity index 100% rename from CLUE_I_Ching/christopher_done_24.bdf rename to CLUE/CLUE_I_Ching/christopher_done_24.bdf diff --git a/CLUE_I_Ching/code.py b/CLUE/CLUE_I_Ching/code.py similarity index 100% rename from CLUE_I_Ching/code.py rename to CLUE/CLUE_I_Ching/code.py diff --git a/CLUE_Light_Painter/.circuitpython.skip b/CLUE/CLUE_Light_Painter/.circuitpython.skip similarity index 100% rename from CLUE_Light_Painter/.circuitpython.skip rename to CLUE/CLUE_Light_Painter/.circuitpython.skip diff --git a/CLUE_Light_Painter/bmp2led.py b/CLUE/CLUE_Light_Painter/bmp2led.py old mode 100755 new mode 100644 similarity index 100% rename from CLUE_Light_Painter/bmp2led.py rename to CLUE/CLUE_Light_Painter/bmp2led.py diff --git a/CLUE_Light_Painter/bmps-72px/adabot.bmp b/CLUE/CLUE_Light_Painter/bmps-72px/adabot.bmp similarity index 100% rename from CLUE_Light_Painter/bmps-72px/adabot.bmp rename to CLUE/CLUE_Light_Painter/bmps-72px/adabot.bmp diff --git a/CLUE_Light_Painter/bmps-72px/arrow-blue.bmp b/CLUE/CLUE_Light_Painter/bmps-72px/arrow-blue.bmp similarity index 100% rename from CLUE_Light_Painter/bmps-72px/arrow-blue.bmp rename to CLUE/CLUE_Light_Painter/bmps-72px/arrow-blue.bmp diff --git a/CLUE_Light_Painter/bmps-72px/arrow-red.bmp b/CLUE/CLUE_Light_Painter/bmps-72px/arrow-red.bmp similarity index 100% rename from CLUE_Light_Painter/bmps-72px/arrow-red.bmp rename to CLUE/CLUE_Light_Painter/bmps-72px/arrow-red.bmp diff --git a/CLUE_Light_Painter/bmps-72px/minerva.bmp b/CLUE/CLUE_Light_Painter/bmps-72px/minerva.bmp similarity index 100% rename from CLUE_Light_Painter/bmps-72px/minerva.bmp rename to CLUE/CLUE_Light_Painter/bmps-72px/minerva.bmp diff --git a/CLUE_Light_Painter/bmps-72px/rainbow.bmp b/CLUE/CLUE_Light_Painter/bmps-72px/rainbow.bmp old mode 100755 new mode 100644 similarity index 100% rename from CLUE_Light_Painter/bmps-72px/rainbow.bmp rename to CLUE/CLUE_Light_Painter/bmps-72px/rainbow.bmp diff --git a/CLUE_Light_Painter/bmps-72px/wales.bmp b/CLUE/CLUE_Light_Painter/bmps-72px/wales.bmp old mode 100755 new mode 100644 similarity index 100% rename from CLUE_Light_Painter/bmps-72px/wales.bmp rename to CLUE/CLUE_Light_Painter/bmps-72px/wales.bmp diff --git a/CLUE_Light_Painter/boot.py b/CLUE/CLUE_Light_Painter/boot.py old mode 100755 new mode 100644 similarity index 100% rename from CLUE_Light_Painter/boot.py rename to CLUE/CLUE_Light_Painter/boot.py diff --git a/CLUE_Light_Painter/code.py b/CLUE/CLUE_Light_Painter/code.py old mode 100755 new mode 100644 similarity index 100% rename from CLUE_Light_Painter/code.py rename to CLUE/CLUE_Light_Painter/code.py diff --git a/CLUE_Light_Painter/richbutton.py b/CLUE/CLUE_Light_Painter/richbutton.py old mode 100755 new mode 100644 similarity index 100% rename from CLUE_Light_Painter/richbutton.py rename to CLUE/CLUE_Light_Painter/richbutton.py diff --git a/CLUE_Metal_Detector/code.py b/CLUE/CLUE_Metal_Detector/code.py similarity index 100% rename from CLUE_Metal_Detector/code.py rename to CLUE/CLUE_Metal_Detector/code.py diff --git a/CLUE_Metronome/.circuitpython.skip b/CLUE/CLUE_Metronome/.circuitpython.skip similarity index 100% rename from CLUE_Metronome/.circuitpython.skip rename to CLUE/CLUE_Metronome/.circuitpython.skip diff --git a/CLUE_Metronome/code.py b/CLUE/CLUE_Metronome/code.py similarity index 100% rename from CLUE_Metronome/code.py rename to CLUE/CLUE_Metronome/code.py diff --git a/CLUE_Milk_Checker/.circuitpython.skip b/CLUE/CLUE_Milk_Checker/.circuitpython.skip similarity index 100% rename from CLUE_Milk_Checker/.circuitpython.skip rename to CLUE/CLUE_Milk_Checker/.circuitpython.skip diff --git a/CLUE_Milk_Checker/bmps/milk_bg.bmp b/CLUE/CLUE_Milk_Checker/bmps/milk_bg.bmp similarity index 100% rename from CLUE_Milk_Checker/bmps/milk_bg.bmp rename to CLUE/CLUE_Milk_Checker/bmps/milk_bg.bmp diff --git a/CLUE_Milk_Checker/bmps/mouth_sheet.bmp b/CLUE/CLUE_Milk_Checker/bmps/mouth_sheet.bmp similarity index 100% rename from CLUE_Milk_Checker/bmps/mouth_sheet.bmp rename to CLUE/CLUE_Milk_Checker/bmps/mouth_sheet.bmp diff --git a/CLUE_Milk_Checker/code.py b/CLUE/CLUE_Milk_Checker/code.py similarity index 100% rename from CLUE_Milk_Checker/code.py rename to CLUE/CLUE_Milk_Checker/code.py diff --git a/CLUE_Milk_Checker/fonts/Alphakind_28.bdf b/CLUE/CLUE_Milk_Checker/fonts/Alphakind_28.bdf similarity index 100% rename from CLUE_Milk_Checker/fonts/Alphakind_28.bdf rename to CLUE/CLUE_Milk_Checker/fonts/Alphakind_28.bdf diff --git a/CLUE_Milk_Checker/fonts/F25_Bank_Printer_Bold_12.bdf b/CLUE/CLUE_Milk_Checker/fonts/F25_Bank_Printer_Bold_12.bdf similarity index 100% rename from CLUE_Milk_Checker/fonts/F25_Bank_Printer_Bold_12.bdf rename to CLUE/CLUE_Milk_Checker/fonts/F25_Bank_Printer_Bold_12.bdf diff --git a/CLUE_Purse_Slideshow/Adabot and Mho.bmp b/CLUE/CLUE_Purse_Slideshow/Adabot and Mho.bmp similarity index 100% rename from CLUE_Purse_Slideshow/Adabot and Mho.bmp rename to CLUE/CLUE_Purse_Slideshow/Adabot and Mho.bmp diff --git a/CLUE_Purse_Slideshow/Adafruit rainbow star.bmp b/CLUE/CLUE_Purse_Slideshow/Adafruit rainbow star.bmp similarity index 100% rename from CLUE_Purse_Slideshow/Adafruit rainbow star.bmp rename to CLUE/CLUE_Purse_Slideshow/Adafruit rainbow star.bmp diff --git a/CLUE_Purse_Slideshow/Nested Hearts.bmp b/CLUE/CLUE_Purse_Slideshow/Nested Hearts.bmp similarity index 100% rename from CLUE_Purse_Slideshow/Nested Hearts.bmp rename to CLUE/CLUE_Purse_Slideshow/Nested Hearts.bmp diff --git a/CLUE_Purse_Slideshow/code.py b/CLUE/CLUE_Purse_Slideshow/code.py similarity index 100% rename from CLUE_Purse_Slideshow/code.py rename to CLUE/CLUE_Purse_Slideshow/code.py diff --git a/CLUE_Rock_Paper_Scissors/.circuitpython.skip b/CLUE/CLUE_Rock_Paper_Scissors/.circuitpython.skip similarity index 100% rename from CLUE_Rock_Paper_Scissors/.circuitpython.skip rename to CLUE/CLUE_Rock_Paper_Scissors/.circuitpython.skip diff --git a/CLUE_Rock_Paper_Scissors/advanced/.circuitpython.skip b/CLUE/CLUE_Rock_Paper_Scissors/advanced/.circuitpython.skip similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/.circuitpython.skip rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/.circuitpython.skip diff --git a/CLUE/CLUE_Rock_Paper_Scissors/advanced/code.py b/CLUE/CLUE_Rock_Paper_Scissors/advanced/code.py new file mode 100644 index 000000000..a9bbf2169 --- /dev/null +++ b/CLUE/CLUE_Rock_Paper_Scissors/advanced/code.py @@ -0,0 +1,563 @@ +# SPDX-FileCopyrightText: 2020 Kevin J Walters for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# clue-multi-rpsgame v1.20 +# CircuitPython massively multiplayer rock paper scissors game over Bluetooth LE + +# Tested with CLUE and Circuit Playground Bluefruit Alpha with TFT Gizmo +# using CircuitPython and 5.3.0 + +# copy this file to CLUE/CPB board as code.py + +# MIT License + +# Copyright (c) 2020 Kevin J. Walters + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +import gc +import os +import random + +from micropython import const +import board +import digitalio + +import neopixel +from adafruit_ble import BLERadio + +# These imports works on CLUE, CPB (and CPX on 5.x) +try: + from audioio import AudioOut +except ImportError: + from audiopwmio import PWMAudioOut as AudioOut + +# RPS module files +from rps_advertisements import JoinGameAdvertisement, \ + RpsEncDataAdvertisement, \ + RpsKeyDataAdvertisement, \ + RpsRoundEndAdvertisement +from rps_audio import SampleJukebox +from rps_comms import broadcastAndReceive, addrToText, MIN_AD_INTERVAL +from rps_crypto import bytesPad, strUnpad, generateOTPadKey, \ + enlargeKey, encrypt, decrypt +from rps_display import RPSDisplay, blankScreen + + +# Look for our name in settings.toml file if present +ble_name = os.getenv("rps_name", os.getenv("ble_name")) +if ble_name is None: + print("INFO: No rps_name or ble_name entry found in settings.toml") + +debug = 1 + +def d_print(level, *args, **kwargs): + """A simple conditional print for debugging based on global debug level.""" + if not isinstance(level, int): + print(level, *args, **kwargs) + elif debug >= level: + print(*args, **kwargs) + + +def tftGizmoPresent(): + """Determine if the TFT Gizmo is attached. + The TFT's Gizmo circuitry for backlight features a 10k pull-down resistor. + This attempts to verify the presence of the pull-down to determine + if TFT Gizmo is present. + This is likely to get confused if anything else is connected to pad A3. + Only use this on Circuit Playground Express (CPX) + or Circuit Playground Bluefruit (CPB) boards.""" + present = True + try: + with digitalio.DigitalInOut(board.A3) as backlight_pin: + backlight_pin.pull = digitalio.Pull.UP + present = not backlight_pin.value + except ValueError: + # The Gizmo is already initialised, i.e. showing console output + pass + + return present + + +# Assuming CLUE if it's not a Circuit Playround (Bluefruit) +clue_less = "Circuit Playground" in os.uname().machine + +# Note: difference in pull-up and pull-down +# and logical not use for buttons +if clue_less: + # CPB with TFT Gizmo (240x240) + # from adafruit_circuitplayground import cp # Avoiding to save memory + + # Outputs + if tftGizmoPresent(): + from adafruit_gizmo import tft_gizmo + display = tft_gizmo.TFT_Gizmo() + JG_RX_COL = 0x0000ff + BUTTON_Y_POS = 120 + else: + display = None + JG_RX_COL = 0x000030 # dimmer blue for upward facing CPB NeoPixels + BUTTON_Y_POS = None + + audio_out = AudioOut(board.SPEAKER) + #pixels = cp.pixels + pixels = neopixel.NeoPixel(board.NEOPIXEL, 10) + + # Enable the onboard amplifier for speaker + #cp._speaker_enable.value = True # pylint: disable=protected-access + speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE) + speaker_enable.switch_to_output(value=False) + speaker_enable.value = True + + # Inputs + # buttons reversed if it is used upside-down with Gizmo + _button_a = digitalio.DigitalInOut(board.BUTTON_A) + _button_a.switch_to_input(pull=digitalio.Pull.DOWN) + _button_b = digitalio.DigitalInOut(board.BUTTON_B) + _button_b.switch_to_input(pull=digitalio.Pull.DOWN) + if display is None: + def button_left(): + return _button_a.value + def button_right(): + return _button_b.value + else: + def button_left(): + return _button_b.value + def button_right(): + return _button_a.value + +else: + # CLUE with builtin screen (240x240) + # from adafruit_clue import clue # Avoiding to save memory + + # Outputs + display = board.DISPLAY + audio_out = AudioOut(board.SPEAKER) + #pixels = clue.pixel + pixels = neopixel.NeoPixel(board.NEOPIXEL, 1) + JG_RX_COL = 0x0000ff + BUTTON_Y_POS = 152 + + # Inputs + _button_a = digitalio.DigitalInOut(board.BUTTON_A) + _button_a.switch_to_input(pull=digitalio.Pull.UP) + _button_b = digitalio.DigitalInOut(board.BUTTON_B) + _button_b.switch_to_input(pull=digitalio.Pull.UP) + def button_left(): + return not _button_a.value + def button_right(): + return not _button_b.value + + +blankScreen(display, pixels) + +# Set to True for blue flashing when devices are joining the playing group +JG_FLASH = False + +IMAGE_DIR = "rps/images" +AUDIO_DIR = "rps/audio" + +audio_files = (("searching", "welcome-to", "arena", "ready") + + ("rock", "paper", "scissors") + + ("start-tx", "end-tx", "txing") + + ("rock-scissors", "paper-rock", "scissors-paper") + + ("you-win", "draw", "you-lose", "error") + + ("humiliation", "excellent")) + +gc.collect() +d_print(2, "GC before SJ", gc.mem_free()) +sample = SampleJukebox(audio_out, audio_files, + directory=AUDIO_DIR) +del audio_files # not needed anymore +gc.collect() +d_print(2, "GC after SJ", gc.mem_free()) + +# A lookup table in Dict form for win/lose, each value is a sample name +# Does not need to cater for draw (tie) condition +WAV_VICTORY_NAME = { "rp": "paper-rock", + "pr": "paper-rock", + "ps": "scissors-paper", + "sp": "scissors-paper", + "sr": "rock-scissors", + "rs": "rock-scissors"} + +# This limit is based on displaying names on screen with scale=2 font +MAX_PLAYERS = 8 +# Some code is dependent on these being lower-case +CHOICES = ("rock", "paper", "scissors") + +rps_display = RPSDisplay(display, pixels, + CHOICES, sample, WAV_VICTORY_NAME, + MAX_PLAYERS, BUTTON_Y_POS, + IMAGE_DIR + "/rps-sprites-ind4.bmp", + ble_color=JG_RX_COL) + +# Transmit maximum times in seconds +JG_MSG_TIME_S = 20 +FIRST_MSG_TIME_S = 12 +STD_MSG_TIME_S = 4 +LAST_ACK_TIME_S = 1.5 + + +# Intro screen with audio +rps_display.introductionScreen() + +# Enable the Bluetooth LE radio and set player's name (from settings.toml) +ble = BLERadio() +if ble_name is not None: + ble.name = ble_name + + +game_no = 1 +round_no = 1 +wins = losses = draws = voids = 0 + +# TOTAL_ROUNDS = 5 +TOTAL_ROUNDS = 3 + +CRYPTO_ALGO = "chacha20" +KEY_SIZE = 8 # in bytes +KEY_ENLARGE = 256 // KEY_SIZE // 8 + +# Scoring values +POINTS_WIN = 2 +POINTS_DRAW = 1 + +WIN = const(1) +DRAW = const(2) # AKA tie +LOSE = const(3) +INVALID = const(4) + +def evaluateRound(mine, yours): + """Determine who won the round in this game based on the two strings mine and yours. + Returns WIN, DRAW, LOSE or INVALID for bad input.""" + # Return INVALID if any input is None + try: + mine_lc = mine.lower() + yours_lc = yours.lower() + except AttributeError: + return INVALID + + if mine_lc not in CHOICES or yours_lc not in CHOICES: + return INVALID + + # Both inputs are valid choices if we got this far + # pylint: disable=too-many-boolean-expressions + if mine_lc == yours_lc: + return DRAW + elif (mine_lc == "rock" and yours_lc == "scissors" + or mine_lc == "paper" and yours_lc == "rock" + or mine_lc == "scissors" and yours_lc == "paper"): + return WIN + + return LOSE + + +rps_display.playerListScreen() + +def addPlayer(name, addr_text, address, ad): + # pylint: disable=unused-argument + # address is part of call back + """Add the player name and mac address to players global variable + and the name and rssi (if present) to on-screen list.""" + + rssi = ad.rssi if ad else None + + players.append((name, addr_text)) + rps_display.addPlayer(name, rssi=rssi) + + +# Make a list of all the player's (name, mac address as text) +# where both are strings with this player as first entry +players = [] +my_name = ble.name +rps_display.fadeUpDown("down") +addPlayer(my_name, addrToText(ble.address_bytes), None, None) + + +# These two functions mainly serve to adapt the call back arguments +# to the called functions which do not use them +def jgAdCallbackFlashBLE(_a, _b, _c): + """Used in broadcastAndReceive to flash the NeoPixels + when advertising messages are received.""" + return rps_display.flashBLE() + +def jgEndscanCallback(_a, _b, _c): + """Used in broadcastAndReceive to allow early termination of the scanning + when the left button is pressed. + Button may need to be held down for a second.""" + return button_left() + +# Join Game +gc.collect() +d_print(2, "GC before JG", gc.mem_free()) + +sample.play("searching", loop=True) +rps_display.fadeUpDown("up") +jg_msg = JoinGameAdvertisement(game="RPS") +(_, _, _) = broadcastAndReceive(ble, + jg_msg, + scan_time=JG_MSG_TIME_S, + scan_response_request=True, + ad_cb=(jgAdCallbackFlashBLE + if JG_FLASH + else None), + endscan_cb=jgEndscanCallback, + name_cb=addPlayer) +del _ # To clean-up with GC below +sample.stop() +gc.collect() +d_print(2, "GC after JG", gc.mem_free()) + +# Wait for button release - this stops a long press +# being acted upon in the main loop further down +while button_left(): + pass + +scores = [0] * len(players) +num_other_players = len(players) - 1 + +# Set the advertising interval to the minimum for four or fewer players +# and above that extend value by players multiplied by 7ms +ad_interval = MIN_AD_INTERVAL if len(players) <= 4 else len(players) * 0.007 + +d_print(1, "PLAYERS", players) + +# Sequence numbers - real packets start range between 1-255 inclusive +seq_tx = [1] # The next number to send + +new_round_init = True + +# A nonce by definition must not be reused but here a random key is +# generated per round and this is used once per round so this is ok +static_nonce = bytes(range(12, 0, -1)) + +while True: + if round_no > TOTAL_ROUNDS: + print("Summary: ", + "wins {:d}, losses {:d}," + " draws {:d}, void {:d}\n\n".format(wins, losses, draws, voids)) + + rps_display.showGameResult(players, scores, rounds_tot=TOTAL_ROUNDS) + + # Reset variables for another game + round_no = 1 + wins = losses = draws = voids = 0 + scores = [0] * len(players) + game_no += 1 + + if new_round_init: + rps_display.showGameRound(game_no=game_no, round_no=round_no, rounds_tot=TOTAL_ROUNDS) + # Make a new initial random choice for the player and show it + my_choice_idx = random.randrange(len(CHOICES)) + rps_display.fadeUpDown("down") + rps_display.showChoice(my_choice_idx, + game_no=game_no, round_no=round_no, rounds_tot=TOTAL_ROUNDS, + won_sf=wins, drew_sf=draws, lost_sf=losses) + rps_display.fadeUpDown("up") + new_round_init = False + + if button_left(): + while button_left(): # Wait for button release + pass + my_choice_idx = (my_choice_idx + 1) % len(CHOICES) + rps_display.showChoice(my_choice_idx, + game_no=game_no, round_no=round_no, rounds_tot=TOTAL_ROUNDS, + won_sf=wins, drew_sf=draws, lost_sf=losses) + + if button_right(): + gc.collect() + d_print(2, "GC before comms", gc.mem_free()) + + # This sound cue is really for other players + sample.play("ready") + + my_choice = CHOICES[my_choice_idx] + player_choices = [my_choice] + + # Repeating key four times to make key for ChaCha20 + short_key = generateOTPadKey(KEY_SIZE) + key = enlargeKey(short_key, KEY_ENLARGE) + d_print(3, "KEY", key) + + plain_bytes = bytesPad(my_choice, size=8, pad=0) + cipher_bytes = encrypt(plain_bytes, key, CRYPTO_ALGO, + nonce=static_nonce) + enc_data_msg = RpsEncDataAdvertisement(enc_data=cipher_bytes, + round_no=round_no) + + # Wait for ready sound sample to stop playing + sample.wait() + sample.play("start-tx") + sample.wait() + sample.play("txing", loop=True) + # Players will not be synchronised at this point as they do not + # have to make their choices simultaneously - much longer 12 second + # time to accomodate this + _, enc_data_by_addr, _ = broadcastAndReceive(ble, + enc_data_msg, + RpsEncDataAdvertisement, + RpsKeyDataAdvertisement, + scan_time=FIRST_MSG_TIME_S, + ad_interval=ad_interval, + receive_n=num_other_players, + seq_tx=seq_tx) + + key_data_msg = RpsKeyDataAdvertisement(key_data=short_key, round_no=round_no) + # All of the programs will be loosely synchronised now + _, key_data_by_addr, _ = broadcastAndReceive(ble, + key_data_msg, + RpsEncDataAdvertisement, + RpsKeyDataAdvertisement, + RpsRoundEndAdvertisement, + scan_time=STD_MSG_TIME_S, + ad_interval=ad_interval, + receive_n=num_other_players, + seq_tx=seq_tx, + ads_by_addr=enc_data_by_addr) + del enc_data_by_addr + + # Play end transmit sound while doing next decrypt bit + sample.play("end-tx") + + re_msg = RpsRoundEndAdvertisement(round_no=round_no) + # The round end message is really about acknowledging receipt of + # the key_data_msg by sending a non-critical message with the ack + _, re_by_addr, _ = broadcastAndReceive(ble, + re_msg, + RpsEncDataAdvertisement, + RpsKeyDataAdvertisement, + RpsRoundEndAdvertisement, + scan_time=LAST_ACK_TIME_S, + ad_interval=ad_interval, + receive_n=num_other_players, + seq_tx=seq_tx, + ads_by_addr=key_data_by_addr) + del key_data_by_addr, _ # To allow GC + + # This will have accumulated all the messages for this round + allmsg_by_addr = re_by_addr + del re_by_addr + + # Decrypt results + # If any data is incorrect the opponent_choice is left as None + for p_idx1 in range(1, len(players)): + print("DECRYPT GC", p_idx1, gc.mem_free()) + opponent_name = players[p_idx1][0] + opponent_macaddr = players[p_idx1][1] + opponent_choice = None + opponent_msgs = allmsg_by_addr.get(opponent_macaddr) + if opponent_msgs is None: + opponent_msgs = [] + cipher_ad = cipher_bytes = cipher_round = None + key_ad = key_bytes = key_round = None + # There should be either one or two messges per type + # two occurs when there + for msg_idx in range(len(opponent_msgs)): + if (cipher_ad is None + and isinstance(opponent_msgs[msg_idx][0], + RpsEncDataAdvertisement)): + cipher_ad = opponent_msgs[msg_idx][0] + cipher_bytes = cipher_ad.enc_data + cipher_round = cipher_ad.round_no + elif (key_ad is None + and isinstance(opponent_msgs[msg_idx][0], + RpsKeyDataAdvertisement)): + key_ad = opponent_msgs[msg_idx][0] + key_bytes = key_ad.key_data + key_round = key_ad.round_no + + if cipher_ad and key_ad: + if round_no == cipher_round == key_round: + key = enlargeKey(key_bytes, KEY_ENLARGE) + plain_bytes = decrypt(cipher_bytes, key, CRYPTO_ALGO, + nonce=static_nonce) + opponent_choice = strUnpad(plain_bytes) + else: + print("Received wrong round for {:d} {:d}: {:d} {:d}", + opponent_name, round_no, cipher_round, key_round) + else: + print("Missing packets: RpsEncDataAdvertisement " + "and RpsKeyDataAdvertisement:", cipher_ad, key_ad) + player_choices.append(opponent_choice) + + # Free up some memory by deleting any data that's no longer needed + del allmsg_by_addr + gc.collect() + d_print(2, "GC after comms", gc.mem_free()) + + sample.wait() # Ensure end-tx has completed + + # Chalk up wins and losses - checks this player but also has to + # check other players against each other to calculate all the + # scores for the high score table at the end of game + for p_idx0, (p0_name, _) in enumerate(players[:len(players) - 1]): + for p_idx1, (p1_name, _) in enumerate(players[p_idx0 + 1:], p_idx0 + 1): + # evaluateRound takes text strings for RPS + result = evaluateRound(player_choices[p_idx0], + player_choices[p_idx1]) + + # this_player is used to control incrementing the summary + # for the tally for this local player + this_player = 0 + void = False + if p_idx0 == 0: + this_player = 1 + p0_ch_idx = None + p1_ch_idx = None + try: + p0_ch_idx = CHOICES.index(player_choices[p_idx0]) + p1_ch_idx = CHOICES.index(player_choices[p_idx1]) + except ValueError: + void = True # Ensure this is marked void + print("ERROR", "failed to decode", + player_choices[p_idx0], player_choices[p_idx1]) + + # showPlayerVPlayer takes int index values for RPS + rps_display.showPlayerVPlayer(p0_name, p1_name, p_idx1, + p0_ch_idx, p1_ch_idx, + result == WIN, + result == DRAW, + result == INVALID or void) + + if result == INVALID or void: + voids += this_player + elif result == DRAW: + draws += this_player + scores[p_idx0] += POINTS_DRAW + scores[p_idx1] += POINTS_DRAW + elif result == WIN: + wins += this_player + scores[p_idx0] += POINTS_WIN + else: + losses += this_player + scores[p_idx1] += POINTS_WIN + + d_print(2, + p0_name, player_choices[p_idx0], "vs", + p1_name, player_choices[p_idx1], + "result", result) + + print("Game {:d}, round {:d}, wins {:d}, losses {:d}, draws {:d}, " + "void {:d}".format(game_no, round_no, wins, losses, draws, voids)) + + round_no += 1 + new_round_init = True diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/arena.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/arena.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/arena.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/arena.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/draw.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/draw.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/draw.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/draw.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/end-tx.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/end-tx.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/end-tx.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/end-tx.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/error.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/error.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/error.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/error.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/excellent.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/excellent.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/excellent.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/excellent.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/humiliation.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/humiliation.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/humiliation.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/humiliation.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/paper-rock.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/paper-rock.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/paper-rock.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/paper-rock.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/paper.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/paper.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/paper.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/paper.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/ready.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/ready.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/ready.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/ready.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/rock-scissors.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/rock-scissors.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/rock-scissors.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/rock-scissors.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/rock.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/rock.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/rock.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/rock.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/scissors-paper.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/scissors-paper.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/scissors-paper.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/scissors-paper.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/scissors.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/scissors.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/scissors.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/scissors.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/searching.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/searching.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/searching.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/searching.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/start-tx.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/start-tx.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/start-tx.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/start-tx.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/txing.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/txing.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/txing.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/txing.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/welcome-to.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/welcome-to.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/welcome-to.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/welcome-to.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/you-lose.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/you-lose.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/you-lose.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/you-lose.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/audio/you-win.wav b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/you-win.wav similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/audio/you-win.wav rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/audio/you-win.wav diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps/images/rps-sprites-ind4.bmp b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/images/rps-sprites-ind4.bmp similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps/images/rps-sprites-ind4.bmp rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps/images/rps-sprites-ind4.bmp diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps_advertisements.py b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps_advertisements.py similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps_advertisements.py rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps_advertisements.py diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps_audio.py b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps_audio.py similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps_audio.py rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps_audio.py diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps_comms.py b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps_comms.py similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps_comms.py rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps_comms.py diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps_crypto.py b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps_crypto.py similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps_crypto.py rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps_crypto.py diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps_crypto_chacha.py b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps_crypto_chacha.py similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps_crypto_chacha.py rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps_crypto_chacha.py diff --git a/CLUE_Rock_Paper_Scissors/advanced/rps_display.py b/CLUE/CLUE_Rock_Paper_Scissors/advanced/rps_display.py similarity index 100% rename from CLUE_Rock_Paper_Scissors/advanced/rps_display.py rename to CLUE/CLUE_Rock_Paper_Scissors/advanced/rps_display.py diff --git a/CLUE_Rock_Paper_Scissors/simple/code.py b/CLUE/CLUE_Rock_Paper_Scissors/simple/code.py similarity index 100% rename from CLUE_Rock_Paper_Scissors/simple/code.py rename to CLUE/CLUE_Rock_Paper_Scissors/simple/code.py diff --git a/CLUE_Rock_Paper_Scissors/tests/test_rps_advertisements.py b/CLUE/CLUE_Rock_Paper_Scissors/tests/test_rps_advertisements.py similarity index 100% rename from CLUE_Rock_Paper_Scissors/tests/test_rps_advertisements.py rename to CLUE/CLUE_Rock_Paper_Scissors/tests/test_rps_advertisements.py diff --git a/CLUE_Rock_Paper_Scissors/tests/test_rps_crypto.py b/CLUE/CLUE_Rock_Paper_Scissors/tests/test_rps_crypto.py similarity index 100% rename from CLUE_Rock_Paper_Scissors/tests/test_rps_crypto.py rename to CLUE/CLUE_Rock_Paper_Scissors/tests/test_rps_crypto.py diff --git a/CLUE_Rock_Paper_Scissors/very-simple/code.py b/CLUE/CLUE_Rock_Paper_Scissors/very-simple/code.py similarity index 100% rename from CLUE_Rock_Paper_Scissors/very-simple/code.py rename to CLUE/CLUE_Rock_Paper_Scissors/very-simple/code.py diff --git a/CLUE_Sensor_Plotter/.circuitpython.skip b/CLUE/CLUE_Sensor_Plotter/.circuitpython.skip similarity index 100% rename from CLUE_Sensor_Plotter/.circuitpython.skip rename to CLUE/CLUE_Sensor_Plotter/.circuitpython.skip diff --git a/CLUE_Sensor_Plotter/adafruit-spinning-logo-plot-2chan.wav b/CLUE/CLUE_Sensor_Plotter/adafruit-spinning-logo-plot-2chan.wav similarity index 100% rename from CLUE_Sensor_Plotter/adafruit-spinning-logo-plot-2chan.wav rename to CLUE/CLUE_Sensor_Plotter/adafruit-spinning-logo-plot-2chan.wav diff --git a/CLUE_Sensor_Plotter/code.py b/CLUE/CLUE_Sensor_Plotter/code.py similarity index 100% rename from CLUE_Sensor_Plotter/code.py rename to CLUE/CLUE_Sensor_Plotter/code.py diff --git a/CLUE_Sensor_Plotter/plot_source.py b/CLUE/CLUE_Sensor_Plotter/plot_source.py similarity index 100% rename from CLUE_Sensor_Plotter/plot_source.py rename to CLUE/CLUE_Sensor_Plotter/plot_source.py diff --git a/CLUE_Sensor_Plotter/plotter.py b/CLUE/CLUE_Sensor_Plotter/plotter.py similarity index 100% rename from CLUE_Sensor_Plotter/plotter.py rename to CLUE/CLUE_Sensor_Plotter/plotter.py diff --git a/CLUE_Sensor_Plotter/test_PlotSource.py b/CLUE/CLUE_Sensor_Plotter/test_PlotSource.py similarity index 100% rename from CLUE_Sensor_Plotter/test_PlotSource.py rename to CLUE/CLUE_Sensor_Plotter/test_PlotSource.py diff --git a/CLUE_Sensor_Plotter/test_Plotter.py b/CLUE/CLUE_Sensor_Plotter/test_Plotter.py similarity index 100% rename from CLUE_Sensor_Plotter/test_Plotter.py rename to CLUE/CLUE_Sensor_Plotter/test_Plotter.py diff --git a/CLUE/CLUE_Servo_Barometer/code.py b/CLUE/CLUE_Servo_Barometer/code.py new file mode 100644 index 000000000..1bea67d92 --- /dev/null +++ b/CLUE/CLUE_Servo_Barometer/code.py @@ -0,0 +1,109 @@ +# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries +# SPDX-License-Identifier: MIT + +import time +import board +import simpleio +import adafruit_bmp280 +import pwmio +import displayio +from adafruit_motor import servo +import terminalio +from adafruit_clue import clue +from adafruit_display_text import label + +# pwm setup for servo +pwm = pwmio.PWMOut(board.D0, duty_cycle=2 ** 15, frequency=50) +gauge = servo.Servo(pwm) + +# bmp280 sensor setup +i2c = board.I2C() # uses board.SCL and board.SDA +# i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller +bmp280 = adafruit_bmp280.Adafruit_BMP280_I2C(i2c) + +# change depending on your location's elevation +NOMINAL_PRESSURE = 1005.94 + +PRESSURE_RANGE = 40 # hPa, expected pressure range variance caused by local weather +PRESSURE_LOW_LIM = NOMINAL_PRESSURE - PRESSURE_RANGE +PRESSURE_HIGH_LIM = NOMINAL_PRESSURE + PRESSURE_RANGE + +# board display +# scaling for terminalio font +display = board.DISPLAY +group = displayio.Group(scale=3) + +# text elements +temp_header = "Temperature:" +press_header = "Pressure:" +temp_text = " ºC" +press_text = " hPa" +font = terminalio.FONT +blue = 0x0000FF +red = 0xFF0000 + +# temperature text elements +temp_label = label.Label(font, text=temp_header, color=red, x=5, y=10) +temp_data = label.Label(font, text=temp_text, color=red, x=5, y=25) + +# pressure text elements +press_label = label.Label(font, text=press_header, color=blue, x=5, y=50) +press_data = label.Label(font, text=press_text, color=blue, x=5, y=65) + +# adding text to display group +group.append(temp_label) +group.append(press_label) +group.append(temp_data) +group.append(press_data) + +display.root_group = group + +# function to convert celsius to fahrenheit +def c_to_f(temp): + temp_f = (temp * 9/5) + 32 + return temp_f + +# function to convert hPa to inHg +def hpa_to_inHg(hPa): + inches_mercury = hPa * 0.02953 + return inches_mercury + +# time.monotonic clock +clock = 0 +# units state +metric_units = False + +while True: + # non-blocking 2 second delay + if (clock + 2) < time.monotonic(): + # map servo range to barometric pressure range + servo_value = simpleio.map_range(bmp280.pressure, + PRESSURE_LOW_LIM, PRESSURE_HIGH_LIM, 180, 0) + # set servo to pressure + gauge.angle = servo_value + # print data for debugging + print("\nTemperature: %0.1f C" % bmp280.temperature) + print("Pressure: %0.1f hPa" % bmp280.pressure) + print(servo_value) + # if metric units... + if metric_units: + # update temp & pressure text in celsius and hPa + temp_data.text = "%0.1f ºC" % bmp280.temperature + press_data.text = "%0.1f hPa" % bmp280.pressure + # if imperial units... + else: + # convert celsius to fahrenheit + temp_fahrenheit = c_to_f(bmp280.temperature) + # convert hPa to inHg + pressure_inHg = hpa_to_inHg(bmp280.pressure) + # update temp & pressure text + temp_data.text = "%0.1f ºF" % temp_fahrenheit + press_data.text = "%0.1f inHg" % pressure_inHg + # reset time.monotonic() clock + clock = time.monotonic() + # if a button is pressed, metric_units is True, show metric + if clue.button_a: + metric_units = True + # if b button is pressed, metric_units is False, show imperial units + if clue.button_b: + metric_units = False diff --git a/CLUE_plenbit_demo/code.py b/CLUE/CLUE_plenbit_demo/code.py similarity index 100% rename from CLUE_plenbit_demo/code.py rename to CLUE/CLUE_plenbit_demo/code.py diff --git a/CircuitPython_CLUEbot/code.py b/CLUE/CircuitPython_CLUEbot/code.py old mode 100755 new mode 100644 similarity index 100% rename from CircuitPython_CLUEbot/code.py rename to CLUE/CircuitPython_CLUEbot/code.py diff --git a/CircuitPython_CLUEbot/robot.py b/CLUE/CircuitPython_CLUEbot/robot.py old mode 100755 new mode 100644 similarity index 100% rename from CircuitPython_CLUEbot/robot.py rename to CLUE/CircuitPython_CLUEbot/robot.py diff --git a/CLUE/Clue_Scale/README.md b/CLUE/Clue_Scale/README.md new file mode 100644 index 000000000..78fe0d716 --- /dev/null +++ b/CLUE/Clue_Scale/README.md @@ -0,0 +1,2 @@ +Files for the Adafruit Learning System guide Clue Coffee Scale +https://learn.adafruit.com/clue-coffee-scale/overview diff --git a/Clue_Scale/clue_scale_bkg.bmp b/CLUE/Clue_Scale/clue_scale_bkg.bmp similarity index 100% rename from Clue_Scale/clue_scale_bkg.bmp rename to CLUE/Clue_Scale/clue_scale_bkg.bmp diff --git a/Clue_Scale/clue_scale_calibrator.py b/CLUE/Clue_Scale/clue_scale_calibrator.py similarity index 100% rename from Clue_Scale/clue_scale_calibrator.py rename to CLUE/Clue_Scale/clue_scale_calibrator.py diff --git a/Clue_Scale/code.py b/CLUE/Clue_Scale/code.py similarity index 100% rename from Clue_Scale/code.py rename to CLUE/Clue_Scale/code.py diff --git a/Clue_Scale/fonts/Helvetica-Bold-24.bdf b/CLUE/Clue_Scale/fonts/Helvetica-Bold-24.bdf similarity index 87% rename from Clue_Scale/fonts/Helvetica-Bold-24.bdf rename to CLUE/Clue_Scale/fonts/Helvetica-Bold-24.bdf index ac52ecbdf..037fe8b20 100644 --- a/Clue_Scale/fonts/Helvetica-Bold-24.bdf +++ b/CLUE/Clue_Scale/fonts/Helvetica-Bold-24.bdf @@ -1,5355 +1,5355 @@ -STARTFONT 2.1 -FONT -FontForge-Helvetica-Bold-R-Normal--25-240-75-75-P-138-ISO10646-1 -SIZE 24 75 75 -FONTBOUNDINGBOX 29 29 -4 -5 -COMMENT "Generated by fontforge, http://fontforge.sourceforge.net" -COMMENT "Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype AG and/or its subsidiaries." -STARTPROPERTIES 40 -FOUNDRY "FontForge" -FAMILY_NAME "Helvetica" -WEIGHT_NAME "Bold" -SLANT "R" -SETWIDTH_NAME "Normal" -ADD_STYLE_NAME "" -PIXEL_SIZE 25 -POINT_SIZE 240 -RESOLUTION_X 75 -RESOLUTION_Y 75 -SPACING "P" -AVERAGE_WIDTH 138 -CHARSET_REGISTRY "ISO10646" -CHARSET_ENCODING "1" -FONTNAME_REGISTRY "" -CHARSET_COLLECTIONS "ISO10646-1" -FONT_NAME "Helvetica-Bold" -FACE_NAME "Helvetica Bold" -COPYRIGHT "Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype AG and/or its subsidiaries." -FONT_VERSION "001.007" -FONT_ASCENT 20 -FONT_DESCENT 5 -UNDERLINE_POSITION -2 -UNDERLINE_THICKNESS 2 -X_HEIGHT 13 -CAP_HEIGHT 17 -RAW_ASCENT 800 -RAW_DESCENT 200 -NORM_SPACE 7 -RELATIVE_WEIGHT 70 -RELATIVE_SETWIDTH 50 -SUPERSCRIPT_X 0 -SUPERSCRIPT_Y 12 -SUPERSCRIPT_SIZE 16 -SUBSCRIPT_X 0 -SUBSCRIPT_Y 3 -SUBSCRIPT_SIZE 16 -FIGURE_WIDTH 14 -AVG_LOWERCASE_WIDTH 136 -AVG_UPPERCASE_WIDTH 170 -ENDPROPERTIES -CHARS 229 -STARTCHAR space -ENCODING 32 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 1 1 0 0 -BITMAP -00 -ENDCHAR -STARTCHAR exclam -ENCODING 33 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 4 18 2 0 -BITMAP -F0 -F0 -F0 -F0 -F0 -F0 -F0 -70 -70 -70 -60 -60 -60 -00 -F0 -F0 -F0 -F0 -ENDCHAR -STARTCHAR quotedbl -ENCODING 34 -SWIDTH 474 0 -DWIDTH 12 0 -BBX 7 7 2 11 -BITMAP -E6 -E6 -E6 -E6 -E6 -E6 -E6 -ENDCHAR -STARTCHAR numbersign -ENCODING 35 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 17 1 0 -BITMAP -1CE0 -1CC0 -1CC0 -18C0 -18C0 -FFF0 -FFF0 -19C0 -39C0 -3980 -FFF0 -FFF0 -3180 -3380 -3380 -7380 -7300 -ENDCHAR -STARTCHAR dollar -ENCODING 36 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 22 1 -2 -BITMAP -0600 -0600 -1F80 -3FC0 -7FE0 -F6F0 -E6F0 -E600 -F600 -7E00 -7F80 -3FE0 -07E0 -06F0 -0670 -E670 -F6F0 -FFE0 -7FC0 -1F80 -0600 -0600 -ENDCHAR -STARTCHAR percent -ENCODING 37 -SWIDTH 889 0 -DWIDTH 22 0 -BBX 21 18 1 0 -BITMAP -3C0300 -7F0600 -FF0600 -E38C00 -C38800 -E39800 -FF1000 -7F3000 -3C6000 -0063C0 -00C7E0 -00CFF0 -018C30 -019C38 -030C30 -020FF0 -0607E0 -0403C0 -ENDCHAR -STARTCHAR ampersand -ENCODING 38 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 16 18 1 0 -BITMAP -07C0 -0FE0 -1FE0 -1C70 -1C70 -1CF0 -1FE0 -0FC0 -1F80 -3FCE -7BCE -71FE -F0FC -F078 -78FC -7FFE -3FFE -1F8F -ENDCHAR -STARTCHAR quotesingle -ENCODING 39 -SWIDTH 238 0 -DWIDTH 6 0 -BBX 2 7 2 11 -BITMAP -C0 -C0 -C0 -C0 -C0 -C0 -C0 -ENDCHAR -STARTCHAR parenleft -ENCODING 40 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 7 23 1 -5 -BITMAP -0E -1C -18 -38 -38 -70 -70 -F0 -F0 -F0 -F0 -E0 -F0 -F0 -F0 -F0 -70 -70 -78 -38 -1C -1C -0E -ENDCHAR -STARTCHAR parenright -ENCODING 41 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 6 23 1 -5 -BITMAP -C0 -E0 -70 -70 -38 -38 -3C -1C -1C -1C -1C -1C -1C -1C -1C -1C -3C -38 -38 -70 -70 -E0 -C0 -ENDCHAR -STARTCHAR asterisk -ENCODING 42 -SWIDTH 389 0 -DWIDTH 10 0 -BBX 8 8 1 10 -BITMAP -18 -18 -9B -FF -7C -3C -6E -66 -ENDCHAR -STARTCHAR plus -ENCODING 43 -SWIDTH 584 0 -DWIDTH 15 0 -BBX 13 13 1 0 -BITMAP -0700 -0700 -0700 -0700 -0700 -FFF8 -FFF8 -FFF8 -0700 -0700 -0700 -0700 -0700 -ENDCHAR -STARTCHAR comma -ENCODING 44 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 3 8 2 -4 -BITMAP -E0 -E0 -E0 -E0 -20 -60 -E0 -80 -ENDCHAR -STARTCHAR hyphen -ENCODING 45 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 7 3 1 5 -BITMAP -FE -FE -FE -ENDCHAR -STARTCHAR period -ENCODING 46 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 3 4 2 0 -BITMAP -E0 -E0 -E0 -E0 -ENDCHAR -STARTCHAR slash -ENCODING 47 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 9 18 -1 0 -BITMAP -0380 -0700 -0700 -0700 -0E00 -0E00 -0E00 -1C00 -1C00 -1C00 -1800 -3800 -3800 -3800 -7000 -7000 -7000 -E000 -ENDCHAR -STARTCHAR zero -ENCODING 48 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 18 1 0 -BITMAP -1F80 -3FC0 -7FE0 -70E0 -F0F0 -F0F0 -F0F0 -E0F0 -E0F0 -E0F0 -E0F0 -F0F0 -F0F0 -F0F0 -70E0 -7FE0 -3FC0 -1F80 -ENDCHAR -STARTCHAR one -ENCODING 49 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 7 18 2 0 -BITMAP -06 -0E -1E -FE -FE -0E -0E -0E -0E -0E -0E -0E -0E -0E -0E -0E -0E -0E -ENDCHAR -STARTCHAR two -ENCODING 50 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 18 1 0 -BITMAP -1F00 -3FC0 -7FE0 -F1E0 -E0F0 -E0F0 -00F0 -00E0 -01E0 -03C0 -0F80 -1F00 -3E00 -7800 -F000 -FFF0 -FFF0 -FFF0 -ENDCHAR -STARTCHAR three -ENCODING 51 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 18 1 0 -BITMAP -1F80 -3FC0 -7FE0 -F1E0 -E0E0 -E0E0 -00E0 -07C0 -0F80 -0FE0 -01F0 -00F0 -E0F0 -E0F0 -F0F0 -FFE0 -7FC0 -1F00 -ENDCHAR -STARTCHAR four -ENCODING 52 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 18 1 0 -BITMAP -03C0 -07C0 -07C0 -0FC0 -0DC0 -1DC0 -39C0 -31C0 -71C0 -61C0 -E1C0 -FFF0 -FFF0 -FFF0 -01C0 -01C0 -01C0 -01C0 -ENDCHAR -STARTCHAR five -ENCODING 53 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 18 1 0 -BITMAP -7FE0 -7FE0 -7FE0 -7000 -7000 -7000 -6F80 -7FC0 -FFE0 -F1F0 -00F0 -00F0 -00F0 -E0F0 -F1E0 -FFE0 -7FC0 -1F00 -ENDCHAR -STARTCHAR six -ENCODING 54 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 18 1 0 -BITMAP -0F80 -3FC0 -7FE0 -70E0 -F070 -E000 -E700 -FFC0 -FFE0 -F1F0 -F0F0 -E0F0 -E0F0 -F0F0 -70E0 -7FE0 -3FC0 -1F80 -ENDCHAR -STARTCHAR seven -ENCODING 55 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 18 1 0 -BITMAP -FFF0 -FFF0 -FFF0 -00F0 -01E0 -01C0 -0380 -0780 -0700 -0F00 -0E00 -0E00 -1E00 -1C00 -1C00 -3C00 -3C00 -3C00 -ENDCHAR -STARTCHAR eight -ENCODING 56 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 18 1 0 -BITMAP -1F80 -3FC0 -7FE0 -70E0 -F0E0 -F0E0 -79E0 -3FC0 -3FC0 -7FE0 -F0F0 -F0F0 -E0F0 -F0F0 -F0F0 -7FE0 -7FC0 -1F80 -ENDCHAR -STARTCHAR nine -ENCODING 57 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 18 1 0 -BITMAP -1F00 -3FC0 -7FE0 -F0E0 -E0F0 -E0F0 -E0F0 -F0F0 -F1F0 -7FF0 -7F70 -1E70 -00F0 -F0E0 -F1E0 -7FC0 -3FC0 -1F00 -ENDCHAR -STARTCHAR colon -ENCODING 58 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 4 13 2 0 -BITMAP -F0 -F0 -F0 -F0 -00 -00 -00 -00 -00 -F0 -F0 -F0 -F0 -ENDCHAR -STARTCHAR semicolon -ENCODING 59 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 4 17 2 -4 -BITMAP -F0 -F0 -F0 -F0 -00 -00 -00 -00 -00 -F0 -F0 -F0 -F0 -30 -30 -60 -C0 -ENDCHAR -STARTCHAR less -ENCODING 60 -SWIDTH 584 0 -DWIDTH 15 0 -BBX 13 13 1 0 -BITMAP -0008 -0038 -01F8 -07E0 -1F80 -FE00 -F000 -FC00 -3F00 -0FC0 -01F8 -0078 -0018 -ENDCHAR -STARTCHAR equal -ENCODING 61 -SWIDTH 584 0 -DWIDTH 15 0 -BBX 13 9 1 2 -BITMAP -FFF8 -FFF8 -FFF8 -0000 -0000 -0000 -FFF8 -FFF8 -FFF8 -ENDCHAR -STARTCHAR greater -ENCODING 62 -SWIDTH 584 0 -DWIDTH 15 0 -BBX 13 12 1 0 -BITMAP -E000 -F800 -7F00 -0FC0 -03F0 -00F8 -01F8 -07E0 -3F00 -FC00 -F000 -8000 -ENDCHAR -STARTCHAR question -ENCODING 63 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 12 18 2 0 -BITMAP -1F80 -7FC0 -FFE0 -F1F0 -E0F0 -E0F0 -00F0 -01E0 -03C0 -0780 -0F00 -0E00 -0E00 -0000 -0F00 -0F00 -0F00 -0F00 -ENDCHAR -STARTCHAR at -ENCODING 64 -SWIDTH 975 0 -DWIDTH 24 0 -BBX 18 18 3 0 -BITMAP -01F800 -0FFE00 -1E0700 -380380 -71E7C0 -63FEC0 -E7BCC0 -EE1CC0 -CE1CC0 -CE1CC0 -EE18C0 -EE3980 -67FF00 -77DE00 -380180 -1E0700 -0FFE00 -03F800 -ENDCHAR -STARTCHAR A -ENCODING 65 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 16 18 1 0 -BITMAP -03C0 -07E0 -07E0 -07E0 -0FF0 -0F70 -0E78 -1E78 -1E78 -1C3C -3C3C -3FFC -7FFE -7FFE -781E -F00F -F00F -F00F -ENDCHAR -STARTCHAR B -ENCODING 66 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 15 18 2 0 -BITMAP -FFE0 -FFF8 -FFFC -E03C -E03C -E01C -E03C -FFF8 -FFF8 -FFFC -E03C -E01E -E01E -E01E -E03C -FFFC -FFF8 -FFE0 -ENDCHAR -STARTCHAR C -ENCODING 67 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 16 18 1 0 -BITMAP -07E0 -0FF8 -3FFE -3E3E -780F -780F -F000 -F000 -F000 -F000 -F000 -F000 -780F -780F -7E3E -3FFC -1FF8 -07E0 -ENDCHAR -STARTCHAR D -ENCODING 68 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 15 18 2 0 -BITMAP -FFE0 -FFF8 -FFF8 -F07C -F03C -F01E -F01E -F01E -F01E -F01E -F01E -F01E -F01E -F03C -F07C -FFF8 -FFF0 -FFC0 -ENDCHAR -STARTCHAR E -ENCODING 69 -SWIDTH 667 0 -DWIDTH 17 0 -BBX 14 18 2 0 -BITMAP -FFF8 -FFF8 -FFF8 -F000 -F000 -F000 -F000 -FFF0 -FFF0 -FFF0 -F000 -F000 -F000 -F000 -F000 -FFFC -FFFC -FFFC -ENDCHAR -STARTCHAR F -ENCODING 70 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 13 18 2 0 -BITMAP -FFF8 -FFF8 -FFF8 -F000 -F000 -F000 -F000 -FFF0 -FFF0 -FFF0 -F000 -F000 -F000 -F000 -F000 -F000 -F000 -F000 -ENDCHAR -STARTCHAR G -ENCODING 71 -SWIDTH 778 0 -DWIDTH 19 0 -BBX 17 18 1 0 -BITMAP -03F000 -0FFC00 -3FFE00 -3E1F00 -780F00 -780780 -F00000 -F00000 -F07F80 -F07F80 -F07F80 -F00780 -780780 -7C0F80 -3E1F80 -3FFF80 -0FFB80 -07E380 -ENDCHAR -STARTCHAR H -ENCODING 72 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 14 18 2 0 -BITMAP -F01C -F01C -F01C -F01C -F01C -F01C -F01C -FFFC -FFFC -FFFC -F01C -F01C -F01C -F01C -F01C -F01C -F01C -F01C -ENDCHAR -STARTCHAR I -ENCODING 73 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 3 18 2 0 -BITMAP -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -ENDCHAR -STARTCHAR J -ENCODING 74 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 11 18 1 0 -BITMAP -01E0 -01E0 -01E0 -01E0 -01E0 -01E0 -01E0 -01E0 -01E0 -01E0 -01E0 -E1E0 -E1E0 -E1E0 -F1E0 -FFC0 -7FC0 -3F00 -ENDCHAR -STARTCHAR K -ENCODING 75 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 16 18 2 0 -BITMAP -F03E -F07C -F0F8 -F1F0 -F1E0 -F3C0 -F780 -FF00 -FF80 -FFC0 -FBE0 -F1E0 -F1F0 -F0F8 -F07C -F07C -F03E -F01F -ENDCHAR -STARTCHAR L -ENCODING 76 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 13 18 2 0 -BITMAP -F000 -F000 -F000 -F000 -F000 -F000 -F000 -F000 -F000 -F000 -F000 -F000 -F000 -F000 -F000 -FFF8 -FFF8 -FFF8 -ENDCHAR -STARTCHAR M -ENCODING 77 -SWIDTH 833 0 -DWIDTH 21 0 -BBX 17 18 2 0 -BITMAP -F80F80 -FC1F80 -FC1F80 -FC1B80 -EC1B80 -EC3B80 -EE3B80 -EE3B80 -EE3380 -E63380 -E77380 -E77380 -E76380 -E36380 -E3E380 -E3E380 -E3E380 -E3C380 -ENDCHAR -STARTCHAR N -ENCODING 78 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 14 18 2 0 -BITMAP -F01C -F81C -F81C -FC1C -FC1C -FE1C -EE1C -E71C -E79C -E39C -E3DC -E1DC -E1FC -E0FC -E07C -E07C -E03C -E03C -ENDCHAR -STARTCHAR O -ENCODING 79 -SWIDTH 778 0 -DWIDTH 19 0 -BBX 17 18 1 0 -BITMAP -03F000 -0FFC00 -3FFE00 -3E3F00 -780F80 -780780 -F00780 -F00780 -F00380 -F00380 -F00380 -F00780 -780780 -780F00 -3E1F00 -3FFE00 -0FFC00 -03F000 -ENDCHAR -STARTCHAR P -ENCODING 80 -SWIDTH 667 0 -DWIDTH 17 0 -BBX 14 18 2 0 -BITMAP -FFE0 -FFF0 -FFF8 -F078 -F03C -F03C -F03C -F078 -FFF8 -FFF0 -FFE0 -F000 -F000 -F000 -F000 -F000 -F000 -F000 -ENDCHAR -STARTCHAR Q -ENCODING 81 -SWIDTH 778 0 -DWIDTH 19 0 -BBX 17 19 1 -1 -BITMAP -03F000 -0FFC00 -3FFE00 -3E3F00 -780F80 -780780 -F00780 -F00780 -F00380 -F00380 -F00780 -F03780 -787F80 -783F00 -3E3F00 -3FFF00 -0FFF80 -03F380 -000100 -ENDCHAR -STARTCHAR R -ENCODING 82 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 15 18 2 0 -BITMAP -FFF0 -FFF8 -FFFC -F03C -F01E -F01E -F01C -F03C -FFF8 -FFF0 -FFF8 -F03C -F03C -F03C -F03C -F03C -F03C -F01E -ENDCHAR -STARTCHAR S -ENCODING 83 -SWIDTH 667 0 -DWIDTH 17 0 -BBX 15 18 1 0 -BITMAP -0FC0 -3FF0 -7FF8 -787C -F03C -F01C -F800 -7F80 -7FF0 -1FFC -01FC -003E -F01E -F01E -F83C -7FFC -3FF8 -0FE0 -ENDCHAR -STARTCHAR T -ENCODING 84 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 15 18 0 0 -BITMAP -FFFE -FFFE -FFFE -03C0 -03C0 -03C0 -03C0 -03C0 -03C0 -03C0 -03C0 -03C0 -03C0 -03C0 -03C0 -03C0 -03C0 -03C0 -ENDCHAR -STARTCHAR U -ENCODING 85 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 14 18 2 0 -BITMAP -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F87C -7FF8 -3FF0 -0FC0 -ENDCHAR -STARTCHAR V -ENCODING 86 -SWIDTH 667 0 -DWIDTH 17 0 -BBX 15 18 1 0 -BITMAP -F01E -F01E -F01C -703C -783C -7838 -3878 -3C78 -3C70 -1C70 -1CF0 -1EE0 -0EE0 -0FE0 -0FC0 -07C0 -07C0 -0780 -ENDCHAR -STARTCHAR W -ENCODING 87 -SWIDTH 944 0 -DWIDTH 24 0 -BBX 22 18 1 0 -BITMAP -F0783C -F0783C -F0F83C -F0FC38 -78FC78 -78FC78 -78DC70 -79DC70 -39CEF0 -3DCEF0 -3DCEE0 -1D8EE0 -1F8EE0 -1F87C0 -1F87C0 -0F87C0 -0F07C0 -0F0780 -ENDCHAR -STARTCHAR X -ENCODING 88 -SWIDTH 667 0 -DWIDTH 17 0 -BBX 15 18 1 0 -BITMAP -F03E -783C -7C78 -3C78 -3EF0 -1EE0 -0FE0 -0FC0 -07C0 -07C0 -0FE0 -1FE0 -1EF0 -3CF8 -3C78 -787C -F83C -F03E -ENDCHAR -STARTCHAR Y -ENCODING 89 -SWIDTH 667 0 -DWIDTH 17 0 -BBX 15 18 1 0 -BITMAP -F01E -F83E -783C -7878 -3C78 -3C70 -1EF0 -1EE0 -0FE0 -07C0 -07C0 -0380 -0380 -0380 -0380 -0380 -0380 -0380 -ENDCHAR -STARTCHAR Z -ENCODING 90 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 14 18 1 0 -BITMAP -FFFC -FFFC -FFFC -0078 -00F0 -01F0 -03E0 -07C0 -0780 -0F00 -1F00 -3E00 -7C00 -7800 -F000 -FFFC -FFFC -FFFC -ENDCHAR -STARTCHAR bracketleft -ENCODING 91 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 6 23 2 -5 -BITMAP -FC -FC -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -FC -FC -ENDCHAR -STARTCHAR backslash -ENCODING 92 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 9 18 -1 0 -BITMAP -E000 -7000 -7000 -7000 -3800 -3800 -3800 -1800 -1C00 -1C00 -1C00 -0E00 -0E00 -0E00 -0700 -0700 -0700 -0380 -ENDCHAR -STARTCHAR bracketright -ENCODING 93 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 6 23 1 -5 -BITMAP -FC -FC -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -FC -FC -ENDCHAR -STARTCHAR asciicircum -ENCODING 94 -SWIDTH 584 0 -DWIDTH 15 0 -BBX 11 9 2 9 -BITMAP -0E00 -1E00 -1F00 -3B00 -3B80 -7180 -71C0 -E1C0 -E0E0 -ENDCHAR -STARTCHAR underscore -ENCODING 95 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 14 1 0 -3 -BITMAP -FFFC -ENDCHAR -STARTCHAR grave -ENCODING 96 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 5 4 0 15 -BITMAP -E0 -70 -38 -18 -ENDCHAR -STARTCHAR a -ENCODING 97 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 14 1 0 -BITMAP -1F80 -7FE0 -7FE0 -F0E0 -F0E0 -01E0 -3FE0 -7EE0 -F0E0 -E0E0 -E1E0 -FFE0 -FFF0 -3CF0 -ENDCHAR -STARTCHAR b -ENCODING 98 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 12 18 2 0 -BITMAP -E000 -E000 -E000 -E000 -E780 -EFE0 -FFE0 -F1F0 -E0F0 -E070 -E070 -E070 -E070 -E0F0 -F0F0 -FFE0 -FFE0 -E780 -ENDCHAR -STARTCHAR c -ENCODING 99 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 14 1 0 -BITMAP -0F80 -3FE0 -7FE0 -78F0 -F0F0 -F000 -E000 -E000 -F000 -F0F0 -F0F0 -7FE0 -3FC0 -1F80 -ENDCHAR -STARTCHAR d -ENCODING 100 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 13 18 1 0 -BITMAP -0078 -0078 -0078 -0078 -1F78 -3FF8 -7FF8 -F8F8 -F078 -F078 -E078 -E078 -F078 -F078 -F8F8 -7FF8 -3FF8 -1F78 -ENDCHAR -STARTCHAR e -ENCODING 101 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 14 1 0 -BITMAP -1F80 -3FC0 -7FE0 -F0F0 -E0F0 -E070 -FFF0 -FFF0 -E000 -E000 -F0F0 -7FE0 -3FC0 -1F80 -ENDCHAR -STARTCHAR f -ENCODING 102 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 8 18 0 0 -BITMAP -0F -1F -3F -3C -FF -FF -3F -3C -3C -3C -3C -3C -3C -3C -3C -3C -3C -3C -ENDCHAR -STARTCHAR g -ENCODING 103 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 13 19 1 -5 -BITMAP -1F78 -3FF8 -7FF8 -78F8 -F078 -F078 -F078 -F078 -F078 -F078 -78F8 -7FF8 -3FF8 -1F78 -0078 -F078 -7FF0 -7FE0 -1F80 -ENDCHAR -STARTCHAR h -ENCODING 104 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 12 18 2 0 -BITMAP -E000 -E000 -E000 -E000 -E780 -EFE0 -FFE0 -F1F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -ENDCHAR -STARTCHAR i -ENCODING 105 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 3 18 2 0 -BITMAP -E0 -E0 -E0 -00 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -ENDCHAR -STARTCHAR j -ENCODING 106 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 5 23 0 -5 -BITMAP -38 -38 -38 -00 -38 -38 -38 -38 -38 -38 -38 -38 -38 -38 -38 -38 -38 -38 -38 -38 -F8 -F8 -F0 -ENDCHAR -STARTCHAR k -ENCODING 107 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 18 2 0 -BITMAP -E000 -E000 -E000 -E000 -E1E0 -E3E0 -E3C0 -E780 -EF00 -FE00 -FF00 -FF00 -F780 -E7C0 -E3C0 -E3E0 -E1E0 -E0F0 -ENDCHAR -STARTCHAR l -ENCODING 108 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 3 18 2 0 -BITMAP -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -ENDCHAR -STARTCHAR m -ENCODING 109 -SWIDTH 889 0 -DWIDTH 22 0 -BBX 19 14 2 0 -BITMAP -E78F00 -EFDFC0 -FFFFC0 -F1F3E0 -E1E1E0 -E1E1E0 -E1E1E0 -E1E1E0 -E1E1E0 -E1E1E0 -E1E1E0 -E1E1E0 -E1E1E0 -E1E1E0 -ENDCHAR -STARTCHAR n -ENCODING 110 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 12 14 2 0 -BITMAP -E780 -EFE0 -FFE0 -F1F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -ENDCHAR -STARTCHAR o -ENCODING 111 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 13 14 1 0 -BITMAP -0FC0 -3FE0 -7FF0 -78F8 -F078 -F038 -E038 -E038 -F038 -F078 -7878 -7FF0 -3FE0 -0F80 -ENDCHAR -STARTCHAR p -ENCODING 112 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 12 19 2 -5 -BITMAP -E780 -EFE0 -FFE0 -F1F0 -E0F0 -E070 -E070 -E070 -E070 -E0F0 -F0F0 -FFE0 -FFE0 -E780 -E000 -E000 -E000 -E000 -E000 -ENDCHAR -STARTCHAR q -ENCODING 113 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 13 19 1 -5 -BITMAP -1F78 -3FF8 -7FF8 -78F8 -F078 -F078 -E078 -E078 -F078 -F078 -F8F8 -7FF8 -3FF8 -1F78 -0078 -0078 -0078 -0078 -0078 -ENDCHAR -STARTCHAR r -ENCODING 114 -SWIDTH 389 0 -DWIDTH 10 0 -BBX 7 14 2 0 -BITMAP -E6 -EE -FE -FE -F0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -ENDCHAR -STARTCHAR s -ENCODING 115 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 14 1 0 -BITMAP -1F80 -7FC0 -7FE0 -F0F0 -F000 -FF00 -7FE0 -1FF0 -01F0 -E0F0 -F0F0 -FFE0 -7FE0 -1F80 -ENDCHAR -STARTCHAR t -ENCODING 116 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 8 18 0 0 -BITMAP -3C -3C -3C -3C -FF -FF -3F -3C -3C -3C -3C -3C -3C -3C -3C -3F -3F -1F -ENDCHAR -STARTCHAR u -ENCODING 117 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 12 14 2 0 -BITMAP -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -F1F0 -FFF0 -7FF0 -3CF0 -ENDCHAR -STARTCHAR v -ENCODING 118 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 13 14 0 0 -BITMAP -F038 -7878 -7878 -7870 -3870 -3CF0 -1CE0 -1CE0 -1CE0 -0FC0 -0FC0 -0FC0 -0780 -0780 -ENDCHAR -STARTCHAR w -ENCODING 119 -SWIDTH 778 0 -DWIDTH 19 0 -BBX 19 14 0 0 -BITMAP -F0F0E0 -70F1E0 -70F1E0 -79F1C0 -79B1C0 -39B9C0 -39BB80 -3DBB80 -1F9B80 -1F1B80 -1F1F00 -1F1F00 -0F1F00 -0F0F00 -ENDCHAR -STARTCHAR x -ENCODING 120 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 14 1 0 -BITMAP -F0F0 -F9E0 -79E0 -3FC0 -3FC0 -1F80 -0F00 -0F00 -1F80 -3FC0 -3FC0 -79E0 -F1F0 -F0F0 -ENDCHAR -STARTCHAR y -ENCODING 121 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 13 19 0 -5 -BITMAP -F038 -7878 -7878 -7870 -3870 -3CF0 -3CE0 -1CE0 -1FE0 -0FC0 -0FC0 -0FC0 -0780 -0780 -0780 -0700 -3F00 -3E00 -3C00 -ENDCHAR -STARTCHAR z -ENCODING 122 -SWIDTH 500 0 -DWIDTH 13 0 -BBX 12 14 0 0 -BITMAP -7FF0 -7FF0 -7FF0 -01E0 -03C0 -07C0 -0F80 -0F00 -1E00 -3C00 -7C00 -FFF0 -FFF0 -FFF0 -ENDCHAR -STARTCHAR braceleft -ENCODING 123 -SWIDTH 389 0 -DWIDTH 10 0 -BBX 8 23 1 -5 -BITMAP -0F -1F -1C -1C -1C -1C -1C -1C -1C -38 -F0 -F0 -78 -3C -1C -1C -1C -1C -1C -1C -1C -1F -0F -ENDCHAR -STARTCHAR bar -ENCODING 124 -SWIDTH 280 0 -DWIDTH 7 0 -BBX 3 18 2 0 -BITMAP -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -ENDCHAR -STARTCHAR braceright -ENCODING 125 -SWIDTH 389 0 -DWIDTH 10 0 -BBX 8 23 1 -5 -BITMAP -F0 -F8 -38 -38 -38 -38 -38 -38 -38 -3C -1F -0F -1E -38 -38 -38 -38 -38 -38 -38 -38 -F8 -E0 -ENDCHAR -STARTCHAR asciitilde -ENCODING 126 -SWIDTH 584 0 -DWIDTH 15 0 -BBX 11 4 2 4 -BITMAP -FC60 -FFE0 -CFE0 -8380 -ENDCHAR -STARTCHAR exclamdown -ENCODING 161 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 4 19 2 -5 -BITMAP -F0 -F0 -F0 -F0 -00 -00 -60 -60 -60 -70 -70 -70 -F0 -F0 -F0 -F0 -F0 -F0 -F0 -ENDCHAR -STARTCHAR cent -ENCODING 162 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 19 1 -3 -BITMAP -0080 -0080 -0F80 -3FC0 -7FE0 -7BF0 -F3F0 -F200 -E200 -E600 -F400 -F4F0 -FCF0 -7FE0 -3FC0 -1F80 -1800 -1000 -1000 -ENDCHAR -STARTCHAR sterling -ENCODING 163 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 18 1 0 -BITMAP -1F80 -3FE0 -7FE0 -F0F0 -F070 -F070 -F000 -7800 -FF00 -3F00 -3C00 -1C00 -3800 -3800 -7410 -FFF0 -FFF0 -43E0 -ENDCHAR -STARTCHAR currency -ENCODING 164 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 14 14 0 2 -BITMAP -4000 -E018 -F7BC -7FF8 -3FF0 -3870 -3070 -3030 -3870 -3870 -3FF0 -7FF8 -E21C -4008 -ENDCHAR -STARTCHAR yen -ENCODING 165 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 14 18 0 0 -BITMAP -F03C -7038 -7878 -3870 -3CF0 -1CE0 -1EE0 -0FC0 -FFFC -0780 -0780 -FFFC -07FC -0780 -0780 -0780 -0780 -0780 -ENDCHAR -STARTCHAR brokenbar -ENCODING 166 -SWIDTH 280 0 -DWIDTH 7 0 -BBX 3 18 2 0 -BITMAP -E0 -E0 -E0 -E0 -E0 -E0 -E0 -00 -00 -00 -00 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -ENDCHAR -STARTCHAR section -ENCODING 167 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 23 1 -5 -BITMAP -0F80 -3FC0 -7FE0 -71E0 -70E0 -7800 -7E00 -3F80 -7FE0 -E3F0 -E0F0 -F070 -FC70 -7FE0 -3FC0 -0FC0 -03E0 -00E0 -70E0 -79E0 -7FC0 -3F80 -0E00 -ENDCHAR -STARTCHAR dieresis -ENCODING 168 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 8 3 0 15 -BITMAP -E7 -E7 -E7 -ENDCHAR -STARTCHAR copyright -ENCODING 169 -SWIDTH 737 0 -DWIDTH 18 0 -BBX 19 18 0 0 -BITMAP -03F000 -0FFE00 -3F1F00 -380780 -71F3C0 -E3F9C0 -E71CC0 -E60CE0 -CE00E0 -CE00E0 -E60CE0 -E71CC0 -E3F9C0 -71F3C0 -380780 -3E1F00 -0FFE00 -03F000 -ENDCHAR -STARTCHAR ordfeminine -ENCODING 170 -SWIDTH 370 0 -DWIDTH 9 0 -BBX 7 11 1 7 -BITMAP -7C -FE -C6 -7E -E6 -C6 -FE -F6 -00 -FE -FE -ENDCHAR -STARTCHAR guillemotleft -ENCODING 171 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 10 10 2 2 -BITMAP -1040 -10C0 -71C0 -F380 -C300 -C300 -F380 -71C0 -30C0 -1040 -ENDCHAR -STARTCHAR logicalnot -ENCODING 172 -SWIDTH 584 0 -DWIDTH 15 0 -BBX 13 8 1 3 -BITMAP -FFF8 -FFF8 -FFF8 -0038 -0038 -0038 -0038 -0038 -ENDCHAR -STARTCHAR registered -ENCODING 174 -SWIDTH 737 0 -DWIDTH 18 0 -BBX 19 18 0 0 -BITMAP -03F000 -0FFE00 -1F1F00 -380780 -77E3C0 -E7F9C0 -E718C0 -E718E0 -C7F8E0 -C7E0E0 -E770E0 -E730C0 -E739C0 -771BC0 -380780 -3E1F00 -0FFE00 -03F000 -ENDCHAR -STARTCHAR macron -ENCODING 175 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 8 2 0 15 -BITMAP -FF -FF -ENDCHAR -STARTCHAR degree -ENCODING 176 -SWIDTH 400 0 -DWIDTH 10 0 -BBX 8 7 1 11 -BITMAP -3C -7E -42 -C3 -42 -66 -3C -ENDCHAR -STARTCHAR plusminus -ENCODING 177 -SWIDTH 584 0 -DWIDTH 15 0 -BBX 13 13 1 0 -BITMAP -0700 -0700 -0700 -FFF8 -FFF8 -FFF8 -0700 -0700 -0700 -0000 -FFF8 -FFF8 -FFF8 -ENDCHAR -STARTCHAR twosuperior -ENCODING 178 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 8 11 0 7 -BITMAP -3C -7F -67 -E3 -07 -0F -1E -38 -70 -7F -FF -ENDCHAR -STARTCHAR threesuperior -ENCODING 179 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 8 11 0 7 -BITMAP -3C -7F -E7 -07 -1E -1F -03 -C3 -E7 -7E -3C -ENDCHAR -STARTCHAR acute -ENCODING 180 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 6 4 3 15 -BITMAP -3C -78 -70 -E0 -ENDCHAR -STARTCHAR mu -ENCODING 181 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 12 19 2 -5 -BITMAP -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -F1F0 -FFF0 -FFF0 -FEF0 -E000 -E000 -E000 -E000 -E000 -ENDCHAR -STARTCHAR paragraph -ENCODING 182 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 13 22 0 -4 -BITMAP -1FF8 -7FF8 -FF18 -FF18 -FF18 -FF18 -FF18 -7F18 -1F18 -0718 -0718 -0718 -0718 -0718 -0718 -0718 -0718 -0718 -0718 -0718 -0718 -0718 -ENDCHAR -STARTCHAR periodcentered -ENCODING 183 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 3 4 2 4 -BITMAP -E0 -E0 -E0 -E0 -ENDCHAR -STARTCHAR cedilla -ENCODING 184 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 6 5 0 -5 -BITMAP -30 -38 -0C -0C -FC -ENDCHAR -STARTCHAR onesuperior -ENCODING 185 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 5 11 1 7 -BITMAP -18 -38 -F8 -F8 -38 -38 -38 -38 -38 -38 -38 -ENDCHAR -STARTCHAR ordmasculine -ENCODING 186 -SWIDTH 365 0 -DWIDTH 9 0 -BBX 9 11 0 7 -BITMAP -3E00 -7F00 -E380 -E380 -E180 -E380 -7F00 -3E00 -0000 -7F00 -7F00 -ENDCHAR -STARTCHAR guillemotright -ENCODING 187 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 10 10 2 2 -BITMAP -8400 -C200 -E380 -73C0 -31C0 -31C0 -73C0 -E380 -C200 -8400 -ENDCHAR -STARTCHAR onequarter -ENCODING 188 -SWIDTH 834 0 -DWIDTH 21 0 -BBX 18 18 1 0 -BITMAP -180600 -380C00 -F80C00 -381800 -383000 -383000 -386000 -386380 -38C780 -398580 -398D80 -031980 -031980 -063180 -0C3FC0 -0C3FC0 -180180 -180180 -ENDCHAR -STARTCHAR onehalf -ENCODING 189 -SWIDTH 834 0 -DWIDTH 21 0 -BBX 19 18 1 0 -BITMAP -180600 -380C00 -F80C00 -381800 -383000 -383000 -386000 -386780 -38CFC0 -399CE0 -3998E0 -0300E0 -0301C0 -060380 -0C0700 -0C0E00 -181FE0 -181FE0 -ENDCHAR -STARTCHAR threequarters -ENCODING 190 -SWIDTH 834 0 -DWIDTH 21 0 -BBX 20 18 0 0 -BITMAP -3E0180 -7F0300 -630300 -070600 -1E0400 -1F0C00 -031800 -E318E0 -6331E0 -7F33E0 -3E63E0 -00C6E0 -00C4E0 -018CE0 -018FF0 -030FF0 -0600E0 -0600E0 -ENDCHAR -STARTCHAR questiondown -ENCODING 191 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 13 19 1 -5 -BITMAP -0700 -0700 -0700 -0700 -0000 -0700 -0700 -0700 -0F00 -3E00 -7C00 -7800 -F000 -F078 -F078 -78F0 -7FF0 -3FE0 -0F80 -ENDCHAR -STARTCHAR Agrave -ENCODING 192 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 16 24 1 0 -BITMAP -1E00 -0F00 -0780 -0380 -0000 -0000 -03C0 -07E0 -07E0 -07E0 -0FF0 -0F70 -0E78 -1E78 -1E78 -1C3C -3C3C -3FFC -7FFE -7FFE -781E -F00F -F00F -F00F -ENDCHAR -STARTCHAR Aacute -ENCODING 193 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 16 24 1 0 -BITMAP -0078 -00F0 -00E0 -01C0 -0000 -0000 -03C0 -07E0 -07E0 -07E0 -0FF0 -0F70 -0E78 -1E78 -1E78 -1C3C -3C3C -3FFC -7FFE -7FFE -781E -F00F -F00F -F00F -ENDCHAR -STARTCHAR Acircumflex -ENCODING 194 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 16 24 1 0 -BITMAP -03C0 -03E0 -07E0 -0E70 -0000 -0000 -03C0 -07E0 -07E0 -07E0 -0FF0 -0F70 -0E78 -1E78 -1E78 -1C3C -3C3C -3FFC -7FFE -7FFE -781E -F00F -F00F -F00F -ENDCHAR -STARTCHAR Atilde -ENCODING 195 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 16 23 1 0 -BITMAP -0790 -0FF0 -08E0 -0000 -0000 -03C0 -07E0 -07E0 -07E0 -0FF0 -0F70 -0E78 -1E78 -1E78 -1C3C -3C3C -3FFC -7FFE -7FFE -781E -F00F -F00F -F00F -ENDCHAR -STARTCHAR Adieresis -ENCODING 196 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 16 23 1 0 -BITMAP -0E70 -0E70 -0E70 -0000 -0000 -03C0 -07E0 -07E0 -07E0 -0FF0 -0F70 -0E78 -1E78 -1E78 -1C3C -3C3C -3FFC -7FFE -7FFE -781E -F00F -F00F -F00F -ENDCHAR -STARTCHAR Aring -ENCODING 197 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 16 24 1 0 -BITMAP -01C0 -0360 -0660 -0360 -03C0 -0000 -03C0 -07E0 -07E0 -07E0 -0FF0 -0F70 -0E78 -1E78 -1E78 -1C3C -3C3C -3FFC -7FFE -7FFE -781E -F00F -F00F -F00F -ENDCHAR -STARTCHAR AE -ENCODING 198 -SWIDTH 1000 0 -DWIDTH 25 0 -BBX 24 18 0 0 -BITMAP -03FFFF -03FFFF -03FFFF -079C00 -079C00 -071C00 -0F1C00 -0F1FFE -0E1FFE -1E1FFE -1E1C00 -3FFC00 -3FFC00 -3FFC00 -781C00 -781FFF -781FFF -F01FFF -ENDCHAR -STARTCHAR Ccedilla -ENCODING 199 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 16 23 1 -5 -BITMAP -07E0 -0FF8 -3FFE -3E3E -780F -780F -F000 -F000 -F000 -F000 -F000 -F000 -780F -780F -7E3E -3FFC -1FF8 -07E0 -0300 -03C0 -00C0 -00C0 -07C0 -ENDCHAR -STARTCHAR Egrave -ENCODING 200 -SWIDTH 667 0 -DWIDTH 17 0 -BBX 14 24 2 0 -BITMAP -3C00 -1C00 -0E00 -0600 -0000 -0000 -FFF8 -FFF8 -FFF8 -F000 -F000 -F000 -F000 -FFF0 -FFF0 -FFF0 -F000 -F000 -F000 -F000 -F000 -FFFC -FFFC -FFFC -ENDCHAR -STARTCHAR Eacute -ENCODING 201 -SWIDTH 667 0 -DWIDTH 17 0 -BBX 14 24 2 0 -BITMAP -01E0 -03C0 -0380 -0700 -0000 -0000 -FFF8 -FFF8 -FFF8 -F000 -F000 -F000 -F000 -FFF0 -FFF0 -FFF0 -F000 -F000 -F000 -F000 -F000 -FFFC -FFFC -FFFC -ENDCHAR -STARTCHAR Ecircumflex -ENCODING 202 -SWIDTH 667 0 -DWIDTH 17 0 -BBX 14 24 2 0 -BITMAP -0700 -0F80 -1DC0 -38C0 -0000 -0000 -FFF8 -FFF8 -FFF8 -F000 -F000 -F000 -F000 -FFF0 -FFF0 -FFF0 -F000 -F000 -F000 -F000 -F000 -FFFC -FFFC -FFFC -ENDCHAR -STARTCHAR Edieresis -ENCODING 203 -SWIDTH 667 0 -DWIDTH 17 0 -BBX 14 23 2 0 -BITMAP -39C0 -39C0 -39C0 -0000 -0000 -FFF8 -FFF8 -FFF8 -F000 -F000 -F000 -F000 -FFF0 -FFF0 -FFF0 -F000 -F000 -F000 -F000 -F000 -FFFC -FFFC -FFFC -ENDCHAR -STARTCHAR Igrave -ENCODING 204 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 6 24 -1 0 -BITMAP -F0 -70 -38 -1C -00 -00 -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -ENDCHAR -STARTCHAR Iacute -ENCODING 205 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 6 24 2 0 -BITMAP -3C -38 -70 -E0 -00 -00 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -ENDCHAR -STARTCHAR Icircumflex -ENCODING 206 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 9 24 -1 0 -BITMAP -1C00 -3E00 -7700 -E380 -0000 -0000 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -ENDCHAR -STARTCHAR Idieresis -ENCODING 207 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 8 23 -1 0 -BITMAP -F7 -F7 -F7 -00 -00 -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -ENDCHAR -STARTCHAR Eth -ENCODING 208 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 17 18 0 0 -BITMAP -3FF800 -3FFE00 -3FFE00 -3C1F00 -3C0F00 -3C0780 -3C0780 -FFC780 -FFC780 -FFC780 -3C0780 -3C0780 -3C0780 -3C0F00 -3C1F00 -3FFE00 -3FFC00 -3FF000 -ENDCHAR -STARTCHAR Ntilde -ENCODING 209 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 14 23 2 0 -BITMAP -0F20 -1FE0 -11C0 -0000 -0000 -F01C -F81C -F81C -FC1C -FC1C -FE1C -EE1C -E71C -E79C -E39C -E3DC -E1DC -E1FC -E0FC -E07C -E07C -E03C -E03C -ENDCHAR -STARTCHAR Ograve -ENCODING 210 -SWIDTH 778 0 -DWIDTH 19 0 -BBX 17 23 1 0 -BITMAP -0F0000 -078000 -038000 -01C000 -000000 -03F000 -0FFC00 -3FFE00 -3E3F00 -780F80 -780780 -F00780 -F00780 -F00380 -F00380 -F00380 -F00780 -780780 -780F00 -3E1F00 -3FFE00 -0FFC00 -03F000 -ENDCHAR -STARTCHAR Oacute -ENCODING 211 -SWIDTH 778 0 -DWIDTH 19 0 -BBX 17 23 1 0 -BITMAP -007800 -007000 -00E000 -01C000 -000000 -03F000 -0FFC00 -3FFE00 -3E3F00 -780F80 -780780 -F00780 -F00780 -F00380 -F00380 -F00380 -F00780 -780780 -780F00 -3E1F00 -3FFE00 -0FFC00 -03F000 -ENDCHAR -STARTCHAR Ocircumflex -ENCODING 212 -SWIDTH 778 0 -DWIDTH 19 0 -BBX 17 23 1 0 -BITMAP -01E000 -03E000 -077000 -0E3800 -000000 -03F000 -0FFC00 -3FFE00 -3E3F00 -780F80 -780780 -F00780 -F00780 -F00380 -F00380 -F00380 -F00780 -780780 -780F00 -3E1F00 -3FFE00 -0FFC00 -03F000 -ENDCHAR -STARTCHAR Otilde -ENCODING 213 -SWIDTH 778 0 -DWIDTH 19 0 -BBX 17 23 1 0 -BITMAP -038800 -07F800 -0CF000 -000000 -000000 -03F000 -0FFC00 -3FFE00 -3E3F00 -780F80 -780780 -F00780 -F00780 -F00380 -F00380 -F00380 -F00780 -780780 -780F00 -3E1F00 -3FFE00 -0FFC00 -03F000 -ENDCHAR -STARTCHAR Odieresis -ENCODING 214 -SWIDTH 778 0 -DWIDTH 19 0 -BBX 17 23 1 0 -BITMAP -073800 -073800 -073800 -000000 -000000 -03F000 -0FFC00 -3FFE00 -3E3F00 -780F80 -780780 -F00780 -F00780 -F00380 -F00380 -F00380 -F00780 -780780 -780F00 -3E1F00 -3FFE00 -0FFC00 -03F000 -ENDCHAR -STARTCHAR multiply -ENCODING 215 -SWIDTH 584 0 -DWIDTH 15 0 -BBX 12 12 1 0 -BITMAP -6030 -F070 -78E0 -3DC0 -1F80 -0F00 -0F80 -1FC0 -39E0 -70F0 -E070 -4020 -ENDCHAR -STARTCHAR Oslash -ENCODING 216 -SWIDTH 778 0 -DWIDTH 19 0 -BBX 17 18 1 0 -BITMAP -03F080 -0FFD80 -3FFF00 -3E3F00 -780F80 -781F80 -F03780 -F06780 -F0C380 -F18380 -F30380 -F60780 -7C0780 -780F00 -3E1F00 -7FFE00 -4FFC00 -C3F000 -ENDCHAR -STARTCHAR Ugrave -ENCODING 217 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 14 24 2 0 -BITMAP -3C00 -1E00 -0F00 -0700 -0000 -0000 -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F87C -7FF8 -3FF0 -0FC0 -ENDCHAR -STARTCHAR Uacute -ENCODING 218 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 14 24 2 0 -BITMAP -00F0 -01E0 -01C0 -0380 -0000 -0000 -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F87C -7FF8 -3FF0 -0FC0 -ENDCHAR -STARTCHAR Ucircumflex -ENCODING 219 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 14 24 2 0 -BITMAP -0780 -07C0 -0FC0 -1CE0 -0000 -0000 -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F87C -7FF8 -3FF0 -0FC0 -ENDCHAR -STARTCHAR Udieresis -ENCODING 220 -SWIDTH 722 0 -DWIDTH 18 0 -BBX 14 23 2 0 -BITMAP -1CE0 -1CE0 -1CE0 -0000 -0000 -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F03C -F87C -7FF8 -3FF0 -0FC0 -ENDCHAR -STARTCHAR Yacute -ENCODING 221 -SWIDTH 667 0 -DWIDTH 17 0 -BBX 15 24 1 0 -BITMAP -00F0 -01E0 -01C0 -0380 -0000 -0000 -F01E -F83E -783C -7878 -3C78 -3C70 -1EF0 -1EE0 -0FE0 -07C0 -07C0 -0380 -0380 -0380 -0380 -0380 -0380 -0380 -ENDCHAR -STARTCHAR Thorn -ENCODING 222 -SWIDTH 667 0 -DWIDTH 17 0 -BBX 14 18 2 0 -BITMAP -F000 -F000 -FFE0 -FFF0 -FFF8 -F078 -F03C -F03C -F03C -F038 -F078 -FFF8 -FFF0 -FFC0 -F000 -F000 -F000 -F000 -ENDCHAR -STARTCHAR germandbls -ENCODING 223 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 12 18 2 0 -BITMAP -1F80 -7FC0 -FFE0 -F1E0 -E0E0 -E0E0 -E1E0 -E7C0 -E7E0 -E7F0 -E0F0 -E070 -E070 -E070 -E0F0 -E7F0 -E7E0 -E780 -ENDCHAR -STARTCHAR agrave -ENCODING 224 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 19 1 0 -BITMAP -3800 -1C00 -0E00 -0600 -0000 -1F80 -7FE0 -7FE0 -F0E0 -F0E0 -01E0 -3FE0 -7EE0 -F0E0 -E0E0 -E1E0 -FFE0 -FFF0 -3CF0 -ENDCHAR -STARTCHAR aacute -ENCODING 225 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 19 1 0 -BITMAP -01C0 -0380 -0700 -0600 -0000 -1F80 -7FE0 -7FE0 -F0E0 -F0E0 -01E0 -3FE0 -7EE0 -F0E0 -E0E0 -E1E0 -FFE0 -FFF0 -3CF0 -ENDCHAR -STARTCHAR acircumflex -ENCODING 226 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 19 1 0 -BITMAP -0F00 -1F80 -3980 -31C0 -0000 -1F80 -7FE0 -7FE0 -F0E0 -F0E0 -01E0 -3FE0 -7EE0 -F0E0 -E0E0 -E1E0 -FFE0 -FFF0 -3CF0 -ENDCHAR -STARTCHAR atilde -ENCODING 227 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 18 1 0 -BITMAP -1C40 -3FC0 -2380 -0000 -1F80 -7FE0 -7FE0 -F0E0 -F0E0 -01E0 -3FE0 -7EE0 -F0E0 -E0E0 -E1E0 -FFE0 -FFF0 -3CF0 -ENDCHAR -STARTCHAR adieresis -ENCODING 228 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 18 1 0 -BITMAP -39C0 -39C0 -39C0 -0000 -1F80 -7FE0 -7FE0 -F0E0 -F0E0 -01E0 -3FE0 -7EE0 -F0E0 -E0E0 -E1E0 -FFE0 -FFF0 -3CF0 -ENDCHAR -STARTCHAR aring -ENCODING 229 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 20 1 0 -BITMAP -0700 -0F00 -1980 -1980 -0F00 -0000 -1F80 -7FE0 -7FE0 -F0E0 -F0E0 -01E0 -3FE0 -7EE0 -F0E0 -E0E0 -E1E0 -FFE0 -FFF0 -3CF0 -ENDCHAR -STARTCHAR ae -ENCODING 230 -SWIDTH 889 0 -DWIDTH 22 0 -BBX 20 14 1 0 -BITMAP -1F8F80 -3FFFC0 -7FFFE0 -F0F0F0 -F0F070 -01E070 -3FFFF0 -7FFFF0 -F0E000 -E0F000 -E0F0F0 -FFFFE0 -FFBFE0 -3E1F80 -ENDCHAR -STARTCHAR ccedilla -ENCODING 231 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 19 1 -5 -BITMAP -0F80 -3FE0 -7FE0 -78F0 -F0F0 -F000 -E000 -E000 -F000 -F0F0 -F0F0 -7FE0 -3FC0 -1F80 -0C00 -0F00 -0300 -0300 -1F00 -ENDCHAR -STARTCHAR egrave -ENCODING 232 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 19 1 0 -BITMAP -3800 -1C00 -0E00 -0600 -0000 -1F80 -3FC0 -7FE0 -F0F0 -E0F0 -E070 -FFF0 -FFF0 -E000 -E000 -F0F0 -7FE0 -3FC0 -1F80 -ENDCHAR -STARTCHAR eacute -ENCODING 233 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 19 1 0 -BITMAP -01C0 -0380 -0700 -0600 -0000 -1F80 -3FC0 -7FE0 -F0F0 -E0F0 -E070 -FFF0 -FFF0 -E000 -E000 -F0F0 -7FE0 -3FC0 -1F80 -ENDCHAR -STARTCHAR ecircumflex -ENCODING 234 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 19 1 0 -BITMAP -0F00 -1F80 -3980 -31C0 -0000 -1F80 -3FC0 -7FE0 -F0F0 -E0F0 -E070 -FFF0 -FFF0 -E000 -E000 -F0F0 -7FE0 -3FC0 -1F80 -ENDCHAR -STARTCHAR edieresis -ENCODING 235 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 18 1 0 -BITMAP -39C0 -39C0 -39C0 -0000 -1F80 -3FC0 -7FE0 -F0F0 -E0F0 -E070 -FFF0 -FFF0 -E000 -E000 -F0F0 -7FE0 -3FC0 -1F80 -ENDCHAR -STARTCHAR igrave -ENCODING 236 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 6 20 -1 0 -BITMAP -F0 -70 -38 -1C -00 -00 -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -ENDCHAR -STARTCHAR iacute -ENCODING 237 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 6 20 2 0 -BITMAP -3C -38 -70 -E0 -00 -00 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -ENDCHAR -STARTCHAR icircumflex -ENCODING 238 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 9 20 -1 0 -BITMAP -1C00 -3E00 -7700 -E380 -0000 -0000 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -1C00 -ENDCHAR -STARTCHAR idieresis -ENCODING 239 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 8 18 -1 0 -BITMAP -F7 -F7 -F7 -00 -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -1C -ENDCHAR -STARTCHAR eth -ENCODING 240 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 13 18 1 0 -BITMAP -0660 -0FF0 -07C0 -1FE0 -00F0 -0F70 -3FF8 -7FF8 -F8F8 -F078 -F038 -E038 -F038 -F078 -7878 -7FF0 -3FE0 -0F80 -ENDCHAR -STARTCHAR ntilde -ENCODING 241 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 12 18 2 0 -BITMAP -1CC0 -3FC0 -6780 -0000 -E780 -EFE0 -FFE0 -F1F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -ENDCHAR -STARTCHAR ograve -ENCODING 242 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 13 19 1 0 -BITMAP -3C00 -1E00 -0E00 -0700 -0000 -0FC0 -3FE0 -7FF0 -78F8 -F078 -F038 -E038 -E038 -F038 -F078 -7878 -7FF0 -3FE0 -0F80 -ENDCHAR -STARTCHAR oacute -ENCODING 243 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 13 19 1 0 -BITMAP -01E0 -01C0 -0380 -0700 -0000 -0FC0 -3FE0 -7FF0 -78F8 -F078 -F038 -E038 -E038 -F038 -F078 -7878 -7FF0 -3FE0 -0F80 -ENDCHAR -STARTCHAR ocircumflex -ENCODING 244 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 13 19 1 0 -BITMAP -0780 -0F80 -1DC0 -38E0 -0000 -0FC0 -3FE0 -7FF0 -78F8 -F078 -F038 -E038 -E038 -F038 -F078 -7878 -7FF0 -3FE0 -0F80 -ENDCHAR -STARTCHAR otilde -ENCODING 245 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 13 18 1 0 -BITMAP -0E60 -1FE0 -33C0 -0000 -0FC0 -3FE0 -7FF0 -78F8 -F078 -F038 -E038 -E038 -F038 -F078 -7878 -7FF0 -3FE0 -0F80 -ENDCHAR -STARTCHAR odieresis -ENCODING 246 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 13 18 1 0 -BITMAP -1DE0 -1DE0 -1DE0 -0000 -0FC0 -3FE0 -7FF0 -78F8 -F078 -F038 -E038 -E038 -F038 -F078 -7878 -7FF0 -3FE0 -0F80 -ENDCHAR -STARTCHAR divide -ENCODING 247 -SWIDTH 584 0 -DWIDTH 15 0 -BBX 13 14 1 -1 -BITMAP -0700 -0F80 -0F00 -0700 -0000 -FFF8 -FFF8 -FFF8 -0000 -0000 -0700 -0F80 -0F00 -0700 -ENDCHAR -STARTCHAR oslash -ENCODING 248 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 14 14 1 0 -BITMAP -0F8C -3FF8 -7FF0 -78F8 -F0F8 -F1B8 -E338 -E638 -FC38 -F878 -F878 -7FF0 -7FE0 -8F80 -ENDCHAR -STARTCHAR ugrave -ENCODING 249 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 12 20 2 0 -BITMAP -7800 -3800 -1C00 -0E00 -0000 -0000 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -F1F0 -FFF0 -7FF0 -3CF0 -ENDCHAR -STARTCHAR uacute -ENCODING 250 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 12 20 2 0 -BITMAP -03C0 -0380 -0700 -0E00 -0000 -0000 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -F1F0 -FFF0 -7FF0 -3CF0 -ENDCHAR -STARTCHAR ucircumflex -ENCODING 251 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 12 20 2 0 -BITMAP -0E00 -1F00 -3B80 -31C0 -0000 -0000 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -F1F0 -FFF0 -7FF0 -3CF0 -ENDCHAR -STARTCHAR udieresis -ENCODING 252 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 12 18 2 0 -BITMAP -3BC0 -3BC0 -3BC0 -0000 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -E0F0 -F1F0 -FFF0 -7FF0 -3CF0 -ENDCHAR -STARTCHAR yacute -ENCODING 253 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 13 25 0 -5 -BITMAP -00F0 -01E0 -03C0 -0380 -0000 -0000 -F038 -7878 -7878 -7870 -3870 -3CF0 -3CE0 -1CE0 -1FE0 -0FC0 -0FC0 -0FC0 -0780 -0780 -0780 -0700 -3F00 -3E00 -3C00 -ENDCHAR -STARTCHAR thorn -ENCODING 254 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 12 23 2 -5 -BITMAP -E000 -E000 -E000 -E000 -E780 -EFE0 -FFE0 -F1F0 -E0F0 -E070 -E070 -E070 -E070 -E0F0 -F0F0 -FFE0 -FFE0 -E780 -E000 -E000 -E000 -E000 -E000 -ENDCHAR -STARTCHAR ydieresis -ENCODING 255 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 13 23 0 -5 -BITMAP -1CE0 -1CE0 -1CE0 -0000 -F038 -7878 -7878 -7870 -3870 -3CF0 -3CE0 -1CE0 -1FE0 -0FC0 -0FC0 -0FC0 -0780 -0780 -0780 -0700 -3F00 -3E00 -3C00 -ENDCHAR -STARTCHAR dotlessi -ENCODING 305 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 3 14 2 0 -BITMAP -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -E0 -ENDCHAR -STARTCHAR Lslash -ENCODING 321 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 15 18 0 0 -BITMAP -3C00 -3C00 -3C00 -3C00 -3C80 -3F80 -3F00 -3C00 -7C00 -FC00 -BC00 -3C00 -3C00 -3C00 -3C00 -3FFE -3FFE -3FFE -ENDCHAR -STARTCHAR lslash -ENCODING 322 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 7 18 0 0 -BITMAP -38 -38 -38 -38 -38 -3A -3E -3C -78 -F8 -B8 -38 -38 -38 -38 -38 -38 -38 -ENDCHAR -STARTCHAR OE -ENCODING 338 -SWIDTH 1000 0 -DWIDTH 25 0 -BBX 23 18 1 0 -BITMAP -07DFFE -1FFFFE -3FFFFE -7C3E00 -781E00 -F01E00 -F01E00 -F01FFC -F01FFC -F01FFC -F01E00 -F01E00 -F01E00 -781E00 -7C3E00 -3FFFFE -1FFFFE -07DFFE -ENDCHAR -STARTCHAR oe -ENCODING 339 -SWIDTH 944 0 -DWIDTH 24 0 -BBX 22 14 1 0 -BITMAP -0F87C0 -3FEFF0 -7FFFF8 -78FC78 -F07838 -F0383C -E03FFC -E03FFC -F03800 -F07800 -787C38 -7FFFF8 -3FFFF0 -0F87C0 -ENDCHAR -STARTCHAR Scaron -ENCODING 352 -SWIDTH 667 0 -DWIDTH 17 0 -BBX 15 23 1 0 -BITMAP -1C60 -0EE0 -07C0 -0380 -0000 -0FC0 -3FF0 -7FF8 -787C -F03C -F01C -F800 -7F80 -7FF0 -1FFC -01FC -003E -F01E -F01E -F83C -7FFC -3FF8 -0FE0 -ENDCHAR -STARTCHAR scaron -ENCODING 353 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 19 1 0 -BITMAP -39C0 -1F80 -1F00 -0F00 -0000 -1F80 -7FC0 -7FE0 -F0F0 -F000 -FF00 -7FE0 -1FF0 -01F0 -E0F0 -F0F0 -FFE0 -7FE0 -1F80 -ENDCHAR -STARTCHAR Ydieresis -ENCODING 376 -SWIDTH 667 0 -DWIDTH 17 0 -BBX 15 23 1 0 -BITMAP -1CE0 -1CE0 -1CE0 -0000 -0000 -F01E -F83E -783C -7878 -3C78 -3C70 -1EF0 -1EE0 -0FE0 -07C0 -07C0 -0380 -0380 -0380 -0380 -0380 -0380 -0380 -ENDCHAR -STARTCHAR Zcaron -ENCODING 381 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 14 24 1 0 -BITMAP -38E0 -1DC0 -0F80 -0780 -0000 -0000 -FFFC -FFFC -FFFC -0078 -00F0 -01F0 -03E0 -07C0 -0780 -0F00 -1F00 -3E00 -7C00 -7800 -F000 -FFFC -FFFC -FFFC -ENDCHAR -STARTCHAR zcaron -ENCODING 382 -SWIDTH 500 0 -DWIDTH 13 0 -BBX 12 20 0 0 -BITMAP -38E0 -1DC0 -1F80 -0F00 -0000 -0000 -7FF0 -7FF0 -7FF0 -01E0 -03C0 -07C0 -0F80 -0F00 -1E00 -3C00 -7C00 -FFF0 -FFF0 -FFF0 -ENDCHAR -STARTCHAR florin -ENCODING 402 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 13 23 0 -5 -BITMAP -00F8 -01F8 -03F0 -03C0 -0380 -0380 -0780 -3FF0 -3FF0 -0700 -0700 -0700 -0F00 -0F00 -0F00 -0E00 -0E00 -1E00 -1E00 -1E00 -FC00 -F800 -F000 -ENDCHAR -STARTCHAR circumflex -ENCODING 710 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 8 4 0 15 -BITMAP -3C -3E -76 -E7 -ENDCHAR -STARTCHAR caron -ENCODING 711 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 8 4 0 15 -BITMAP -E3 -67 -7E -3C -ENDCHAR -STARTCHAR breve -ENCODING 728 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 8 4 0 15 -BITMAP -C1 -C3 -7F -3C -ENDCHAR -STARTCHAR dotaccent -ENCODING 729 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 3 3 3 15 -BITMAP -E0 -E0 -E0 -ENDCHAR -STARTCHAR ring -ENCODING 730 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 6 5 1 14 -BITMAP -78 -4C -CC -6C -38 -ENDCHAR -STARTCHAR ogonek -ENCODING 731 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 5 5 2 -5 -BITMAP -70 -E0 -C0 -C0 -F8 -ENDCHAR -STARTCHAR tilde -ENCODING 732 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 9 3 0 15 -BITMAP -7180 -FF00 -CE00 -ENDCHAR -STARTCHAR hungarumlaut -ENCODING 733 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 11 4 1 15 -BITMAP -79E0 -71C0 -E380 -C700 -ENDCHAR -STARTCHAR endash -ENCODING 8211 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 14 3 0 5 -BITMAP -FFFC -FFFC -FFFC -ENDCHAR -STARTCHAR emdash -ENCODING 8212 -SWIDTH 1000 0 -DWIDTH 25 0 -BBX 25 3 0 5 -BITMAP -FFFFFF80 -FFFFFF80 -FFFFFF80 -ENDCHAR -STARTCHAR quoteleft -ENCODING 8216 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 3 7 2 11 -BITMAP -20 -60 -C0 -80 -E0 -E0 -E0 -ENDCHAR -STARTCHAR quoteright -ENCODING 8217 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 3 7 2 11 -BITMAP -E0 -E0 -E0 -20 -60 -C0 -80 -ENDCHAR -STARTCHAR quotesinglbase -ENCODING 8218 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 3 6 2 -3 -BITMAP -E0 -E0 -E0 -20 -60 -C0 -ENDCHAR -STARTCHAR quotedblleft -ENCODING 8220 -SWIDTH 500 0 -DWIDTH 13 0 -BBX 9 7 2 11 -BITMAP -2180 -E300 -8200 -8600 -E780 -E780 -E780 -ENDCHAR -STARTCHAR quotedblright -ENCODING 8221 -SWIDTH 500 0 -DWIDTH 13 0 -BBX 9 7 2 11 -BITMAP -E780 -E780 -E780 -2180 -6180 -C300 -8600 -ENDCHAR -STARTCHAR quotedblbase -ENCODING 8222 -SWIDTH 500 0 -DWIDTH 13 0 -BBX 9 7 2 -4 -BITMAP -E780 -E780 -E780 -6180 -6180 -C300 -0600 -ENDCHAR -STARTCHAR dagger -ENCODING 8224 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 22 1 -4 -BITMAP -0F00 -0F00 -0F00 -0F00 -0F00 -FFF0 -FFF0 -FFF0 -0F00 -0F00 -0F00 -0F00 -0F00 -0F00 -0F00 -0F00 -0F00 -0F00 -0F00 -0F00 -0F00 -0F00 -ENDCHAR -STARTCHAR daggerdbl -ENCODING 8225 -SWIDTH 556 0 -DWIDTH 14 0 -BBX 12 22 1 -4 -BITMAP -0F00 -0F00 -0F00 -0F00 -0F00 -FFF0 -FFF0 -FFF0 -0F00 -0F00 -0F00 -0F00 -0F00 -0F00 -FFF0 -FFF0 -FFF0 -0F00 -0F00 -0F00 -0F00 -0F00 -ENDCHAR -STARTCHAR bullet -ENCODING 8226 -SWIDTH 350 0 -DWIDTH 9 0 -BBX 8 8 0 5 -BITMAP -3C -7F -7F -FF -FF -FF -7F -3E -ENDCHAR -STARTCHAR ellipsis -ENCODING 8230 -SWIDTH 1000 0 -DWIDTH 25 0 -BBX 21 4 2 0 -BITMAP -F07078 -F07078 -F07078 -F07078 -ENDCHAR -STARTCHAR perthousand -ENCODING 8240 -SWIDTH 1000 0 -DWIDTH 25 0 -BBX 25 18 0 0 -BITMAP -3C080000 -7E180000 -FF100000 -E7300000 -E7600000 -FF600000 -7EC00000 -3CC00000 -01800000 -01800000 -033C1E00 -027E3F00 -06FF7F80 -04C77380 -0CE77380 -18FF7F80 -187E3F00 -303C1E00 -ENDCHAR -STARTCHAR guilsinglleft -ENCODING 8249 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 4 10 2 2 -BITMAP -10 -30 -70 -E0 -C0 -C0 -E0 -70 -30 -10 -ENDCHAR -STARTCHAR guilsinglright -ENCODING 8250 -SWIDTH 333 0 -DWIDTH 8 0 -BBX 4 10 2 2 -BITMAP -80 -C0 -E0 -70 -30 -30 -70 -E0 -C0 -80 -ENDCHAR -STARTCHAR fraction -ENCODING 8260 -SWIDTH 167 0 -DWIDTH 4 0 -BBX 12 18 -4 0 -BITMAP -0030 -0030 -0060 -00C0 -00C0 -0180 -0180 -0300 -0600 -0600 -0C00 -0C00 -1800 -3000 -3000 -6000 -6000 -C000 -ENDCHAR -STARTCHAR trademark -ENCODING 8482 -SWIDTH 1000 0 -DWIDTH 25 0 -BBX 23 10 1 8 -BITMAP -FF9E1E -FF9E1E -1C1E3E -1C1F3E -1C1B7E -1C1B6E -1C1BEE -1C19EE -1C19CE -1C19CE -ENDCHAR -STARTCHAR minus -ENCODING 8722 -SWIDTH 584 0 -DWIDTH 15 0 -BBX 13 3 1 5 -BITMAP -FFF8 -FFF8 -FFF8 -ENDCHAR -STARTCHAR fi -ENCODING 64257 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 14 18 0 0 -BITMAP -0F3C -1F3C -3F3C -3C00 -FF3C -FF3C -3F3C -3C3C -3C3C -3C3C -3C3C -3C3C -3C3C -3C3C -3C3C -3C3C -3C3C -3C3C -ENDCHAR -STARTCHAR fl -ENCODING 64258 -SWIDTH 611 0 -DWIDTH 15 0 -BBX 14 18 0 0 -BITMAP -0F3C -1F3C -3F3C -3C3C -FF3C -FF3C -3F3C -3C3C -3C3C -3C3C -3C3C -3C3C -3C3C -3C3C -3C3C -3C3C -3C3C -3C3C -ENDCHAR -STARTCHAR .notdef -ENCODING -1 -SWIDTH 278 0 -DWIDTH 7 0 -BBX 1 1 0 0 -BITMAP -00 -ENDCHAR -ENDFONT +STARTFONT 2.1 +FONT -FontForge-Helvetica-Bold-R-Normal--25-240-75-75-P-138-ISO10646-1 +SIZE 24 75 75 +FONTBOUNDINGBOX 29 29 -4 -5 +COMMENT "Generated by fontforge, http://fontforge.sourceforge.net" +COMMENT "Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype AG and/or its subsidiaries." +STARTPROPERTIES 40 +FOUNDRY "FontForge" +FAMILY_NAME "Helvetica" +WEIGHT_NAME "Bold" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 25 +POINT_SIZE 240 +RESOLUTION_X 75 +RESOLUTION_Y 75 +SPACING "P" +AVERAGE_WIDTH 138 +CHARSET_REGISTRY "ISO10646" +CHARSET_ENCODING "1" +FONTNAME_REGISTRY "" +CHARSET_COLLECTIONS "ISO10646-1" +FONT_NAME "Helvetica-Bold" +FACE_NAME "Helvetica Bold" +COPYRIGHT "Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype AG and/or its subsidiaries." +FONT_VERSION "001.007" +FONT_ASCENT 20 +FONT_DESCENT 5 +UNDERLINE_POSITION -2 +UNDERLINE_THICKNESS 2 +X_HEIGHT 13 +CAP_HEIGHT 17 +RAW_ASCENT 800 +RAW_DESCENT 200 +NORM_SPACE 7 +RELATIVE_WEIGHT 70 +RELATIVE_SETWIDTH 50 +SUPERSCRIPT_X 0 +SUPERSCRIPT_Y 12 +SUPERSCRIPT_SIZE 16 +SUBSCRIPT_X 0 +SUBSCRIPT_Y 3 +SUBSCRIPT_SIZE 16 +FIGURE_WIDTH 14 +AVG_LOWERCASE_WIDTH 136 +AVG_UPPERCASE_WIDTH 170 +ENDPROPERTIES +CHARS 229 +STARTCHAR space +ENCODING 32 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR exclam +ENCODING 33 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 4 18 2 0 +BITMAP +F0 +F0 +F0 +F0 +F0 +F0 +F0 +70 +70 +70 +60 +60 +60 +00 +F0 +F0 +F0 +F0 +ENDCHAR +STARTCHAR quotedbl +ENCODING 34 +SWIDTH 474 0 +DWIDTH 12 0 +BBX 7 7 2 11 +BITMAP +E6 +E6 +E6 +E6 +E6 +E6 +E6 +ENDCHAR +STARTCHAR numbersign +ENCODING 35 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 17 1 0 +BITMAP +1CE0 +1CC0 +1CC0 +18C0 +18C0 +FFF0 +FFF0 +19C0 +39C0 +3980 +FFF0 +FFF0 +3180 +3380 +3380 +7380 +7300 +ENDCHAR +STARTCHAR dollar +ENCODING 36 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 22 1 -2 +BITMAP +0600 +0600 +1F80 +3FC0 +7FE0 +F6F0 +E6F0 +E600 +F600 +7E00 +7F80 +3FE0 +07E0 +06F0 +0670 +E670 +F6F0 +FFE0 +7FC0 +1F80 +0600 +0600 +ENDCHAR +STARTCHAR percent +ENCODING 37 +SWIDTH 889 0 +DWIDTH 22 0 +BBX 21 18 1 0 +BITMAP +3C0300 +7F0600 +FF0600 +E38C00 +C38800 +E39800 +FF1000 +7F3000 +3C6000 +0063C0 +00C7E0 +00CFF0 +018C30 +019C38 +030C30 +020FF0 +0607E0 +0403C0 +ENDCHAR +STARTCHAR ampersand +ENCODING 38 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 18 1 0 +BITMAP +07C0 +0FE0 +1FE0 +1C70 +1C70 +1CF0 +1FE0 +0FC0 +1F80 +3FCE +7BCE +71FE +F0FC +F078 +78FC +7FFE +3FFE +1F8F +ENDCHAR +STARTCHAR quotesingle +ENCODING 39 +SWIDTH 238 0 +DWIDTH 6 0 +BBX 2 7 2 11 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR parenleft +ENCODING 40 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 7 23 1 -5 +BITMAP +0E +1C +18 +38 +38 +70 +70 +F0 +F0 +F0 +F0 +E0 +F0 +F0 +F0 +F0 +70 +70 +78 +38 +1C +1C +0E +ENDCHAR +STARTCHAR parenright +ENCODING 41 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 6 23 1 -5 +BITMAP +C0 +E0 +70 +70 +38 +38 +3C +1C +1C +1C +1C +1C +1C +1C +1C +1C +3C +38 +38 +70 +70 +E0 +C0 +ENDCHAR +STARTCHAR asterisk +ENCODING 42 +SWIDTH 389 0 +DWIDTH 10 0 +BBX 8 8 1 10 +BITMAP +18 +18 +9B +FF +7C +3C +6E +66 +ENDCHAR +STARTCHAR plus +ENCODING 43 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 13 13 1 0 +BITMAP +0700 +0700 +0700 +0700 +0700 +FFF8 +FFF8 +FFF8 +0700 +0700 +0700 +0700 +0700 +ENDCHAR +STARTCHAR comma +ENCODING 44 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 3 8 2 -4 +BITMAP +E0 +E0 +E0 +E0 +20 +60 +E0 +80 +ENDCHAR +STARTCHAR hyphen +ENCODING 45 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 7 3 1 5 +BITMAP +FE +FE +FE +ENDCHAR +STARTCHAR period +ENCODING 46 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 3 4 2 0 +BITMAP +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR slash +ENCODING 47 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 9 18 -1 0 +BITMAP +0380 +0700 +0700 +0700 +0E00 +0E00 +0E00 +1C00 +1C00 +1C00 +1800 +3800 +3800 +3800 +7000 +7000 +7000 +E000 +ENDCHAR +STARTCHAR zero +ENCODING 48 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +1F80 +3FC0 +7FE0 +70E0 +F0F0 +F0F0 +F0F0 +E0F0 +E0F0 +E0F0 +E0F0 +F0F0 +F0F0 +F0F0 +70E0 +7FE0 +3FC0 +1F80 +ENDCHAR +STARTCHAR one +ENCODING 49 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 7 18 2 0 +BITMAP +06 +0E +1E +FE +FE +0E +0E +0E +0E +0E +0E +0E +0E +0E +0E +0E +0E +0E +ENDCHAR +STARTCHAR two +ENCODING 50 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +1F00 +3FC0 +7FE0 +F1E0 +E0F0 +E0F0 +00F0 +00E0 +01E0 +03C0 +0F80 +1F00 +3E00 +7800 +F000 +FFF0 +FFF0 +FFF0 +ENDCHAR +STARTCHAR three +ENCODING 51 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +1F80 +3FC0 +7FE0 +F1E0 +E0E0 +E0E0 +00E0 +07C0 +0F80 +0FE0 +01F0 +00F0 +E0F0 +E0F0 +F0F0 +FFE0 +7FC0 +1F00 +ENDCHAR +STARTCHAR four +ENCODING 52 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +03C0 +07C0 +07C0 +0FC0 +0DC0 +1DC0 +39C0 +31C0 +71C0 +61C0 +E1C0 +FFF0 +FFF0 +FFF0 +01C0 +01C0 +01C0 +01C0 +ENDCHAR +STARTCHAR five +ENCODING 53 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +7FE0 +7FE0 +7FE0 +7000 +7000 +7000 +6F80 +7FC0 +FFE0 +F1F0 +00F0 +00F0 +00F0 +E0F0 +F1E0 +FFE0 +7FC0 +1F00 +ENDCHAR +STARTCHAR six +ENCODING 54 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +0F80 +3FC0 +7FE0 +70E0 +F070 +E000 +E700 +FFC0 +FFE0 +F1F0 +F0F0 +E0F0 +E0F0 +F0F0 +70E0 +7FE0 +3FC0 +1F80 +ENDCHAR +STARTCHAR seven +ENCODING 55 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +FFF0 +FFF0 +FFF0 +00F0 +01E0 +01C0 +0380 +0780 +0700 +0F00 +0E00 +0E00 +1E00 +1C00 +1C00 +3C00 +3C00 +3C00 +ENDCHAR +STARTCHAR eight +ENCODING 56 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +1F80 +3FC0 +7FE0 +70E0 +F0E0 +F0E0 +79E0 +3FC0 +3FC0 +7FE0 +F0F0 +F0F0 +E0F0 +F0F0 +F0F0 +7FE0 +7FC0 +1F80 +ENDCHAR +STARTCHAR nine +ENCODING 57 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +1F00 +3FC0 +7FE0 +F0E0 +E0F0 +E0F0 +E0F0 +F0F0 +F1F0 +7FF0 +7F70 +1E70 +00F0 +F0E0 +F1E0 +7FC0 +3FC0 +1F00 +ENDCHAR +STARTCHAR colon +ENCODING 58 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 4 13 2 0 +BITMAP +F0 +F0 +F0 +F0 +00 +00 +00 +00 +00 +F0 +F0 +F0 +F0 +ENDCHAR +STARTCHAR semicolon +ENCODING 59 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 4 17 2 -4 +BITMAP +F0 +F0 +F0 +F0 +00 +00 +00 +00 +00 +F0 +F0 +F0 +F0 +30 +30 +60 +C0 +ENDCHAR +STARTCHAR less +ENCODING 60 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 13 13 1 0 +BITMAP +0008 +0038 +01F8 +07E0 +1F80 +FE00 +F000 +FC00 +3F00 +0FC0 +01F8 +0078 +0018 +ENDCHAR +STARTCHAR equal +ENCODING 61 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 13 9 1 2 +BITMAP +FFF8 +FFF8 +FFF8 +0000 +0000 +0000 +FFF8 +FFF8 +FFF8 +ENDCHAR +STARTCHAR greater +ENCODING 62 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 13 12 1 0 +BITMAP +E000 +F800 +7F00 +0FC0 +03F0 +00F8 +01F8 +07E0 +3F00 +FC00 +F000 +8000 +ENDCHAR +STARTCHAR question +ENCODING 63 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 18 2 0 +BITMAP +1F80 +7FC0 +FFE0 +F1F0 +E0F0 +E0F0 +00F0 +01E0 +03C0 +0780 +0F00 +0E00 +0E00 +0000 +0F00 +0F00 +0F00 +0F00 +ENDCHAR +STARTCHAR at +ENCODING 64 +SWIDTH 975 0 +DWIDTH 24 0 +BBX 18 18 3 0 +BITMAP +01F800 +0FFE00 +1E0700 +380380 +71E7C0 +63FEC0 +E7BCC0 +EE1CC0 +CE1CC0 +CE1CC0 +EE18C0 +EE3980 +67FF00 +77DE00 +380180 +1E0700 +0FFE00 +03F800 +ENDCHAR +STARTCHAR A +ENCODING 65 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 18 1 0 +BITMAP +03C0 +07E0 +07E0 +07E0 +0FF0 +0F70 +0E78 +1E78 +1E78 +1C3C +3C3C +3FFC +7FFE +7FFE +781E +F00F +F00F +F00F +ENDCHAR +STARTCHAR B +ENCODING 66 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 15 18 2 0 +BITMAP +FFE0 +FFF8 +FFFC +E03C +E03C +E01C +E03C +FFF8 +FFF8 +FFFC +E03C +E01E +E01E +E01E +E03C +FFFC +FFF8 +FFE0 +ENDCHAR +STARTCHAR C +ENCODING 67 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 18 1 0 +BITMAP +07E0 +0FF8 +3FFE +3E3E +780F +780F +F000 +F000 +F000 +F000 +F000 +F000 +780F +780F +7E3E +3FFC +1FF8 +07E0 +ENDCHAR +STARTCHAR D +ENCODING 68 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 15 18 2 0 +BITMAP +FFE0 +FFF8 +FFF8 +F07C +F03C +F01E +F01E +F01E +F01E +F01E +F01E +F01E +F01E +F03C +F07C +FFF8 +FFF0 +FFC0 +ENDCHAR +STARTCHAR E +ENCODING 69 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 14 18 2 0 +BITMAP +FFF8 +FFF8 +FFF8 +F000 +F000 +F000 +F000 +FFF0 +FFF0 +FFF0 +F000 +F000 +F000 +F000 +F000 +FFFC +FFFC +FFFC +ENDCHAR +STARTCHAR F +ENCODING 70 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 13 18 2 0 +BITMAP +FFF8 +FFF8 +FFF8 +F000 +F000 +F000 +F000 +FFF0 +FFF0 +FFF0 +F000 +F000 +F000 +F000 +F000 +F000 +F000 +F000 +ENDCHAR +STARTCHAR G +ENCODING 71 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 18 1 0 +BITMAP +03F000 +0FFC00 +3FFE00 +3E1F00 +780F00 +780780 +F00000 +F00000 +F07F80 +F07F80 +F07F80 +F00780 +780780 +7C0F80 +3E1F80 +3FFF80 +0FFB80 +07E380 +ENDCHAR +STARTCHAR H +ENCODING 72 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 14 18 2 0 +BITMAP +F01C +F01C +F01C +F01C +F01C +F01C +F01C +FFFC +FFFC +FFFC +F01C +F01C +F01C +F01C +F01C +F01C +F01C +F01C +ENDCHAR +STARTCHAR I +ENCODING 73 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 3 18 2 0 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR J +ENCODING 74 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +01E0 +01E0 +01E0 +01E0 +01E0 +01E0 +01E0 +01E0 +01E0 +01E0 +01E0 +E1E0 +E1E0 +E1E0 +F1E0 +FFC0 +7FC0 +3F00 +ENDCHAR +STARTCHAR K +ENCODING 75 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 18 2 0 +BITMAP +F03E +F07C +F0F8 +F1F0 +F1E0 +F3C0 +F780 +FF00 +FF80 +FFC0 +FBE0 +F1E0 +F1F0 +F0F8 +F07C +F07C +F03E +F01F +ENDCHAR +STARTCHAR L +ENCODING 76 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 13 18 2 0 +BITMAP +F000 +F000 +F000 +F000 +F000 +F000 +F000 +F000 +F000 +F000 +F000 +F000 +F000 +F000 +F000 +FFF8 +FFF8 +FFF8 +ENDCHAR +STARTCHAR M +ENCODING 77 +SWIDTH 833 0 +DWIDTH 21 0 +BBX 17 18 2 0 +BITMAP +F80F80 +FC1F80 +FC1F80 +FC1B80 +EC1B80 +EC3B80 +EE3B80 +EE3B80 +EE3380 +E63380 +E77380 +E77380 +E76380 +E36380 +E3E380 +E3E380 +E3E380 +E3C380 +ENDCHAR +STARTCHAR N +ENCODING 78 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 14 18 2 0 +BITMAP +F01C +F81C +F81C +FC1C +FC1C +FE1C +EE1C +E71C +E79C +E39C +E3DC +E1DC +E1FC +E0FC +E07C +E07C +E03C +E03C +ENDCHAR +STARTCHAR O +ENCODING 79 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 18 1 0 +BITMAP +03F000 +0FFC00 +3FFE00 +3E3F00 +780F80 +780780 +F00780 +F00780 +F00380 +F00380 +F00380 +F00780 +780780 +780F00 +3E1F00 +3FFE00 +0FFC00 +03F000 +ENDCHAR +STARTCHAR P +ENCODING 80 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 14 18 2 0 +BITMAP +FFE0 +FFF0 +FFF8 +F078 +F03C +F03C +F03C +F078 +FFF8 +FFF0 +FFE0 +F000 +F000 +F000 +F000 +F000 +F000 +F000 +ENDCHAR +STARTCHAR Q +ENCODING 81 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 19 1 -1 +BITMAP +03F000 +0FFC00 +3FFE00 +3E3F00 +780F80 +780780 +F00780 +F00780 +F00380 +F00380 +F00780 +F03780 +787F80 +783F00 +3E3F00 +3FFF00 +0FFF80 +03F380 +000100 +ENDCHAR +STARTCHAR R +ENCODING 82 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 15 18 2 0 +BITMAP +FFF0 +FFF8 +FFFC +F03C +F01E +F01E +F01C +F03C +FFF8 +FFF0 +FFF8 +F03C +F03C +F03C +F03C +F03C +F03C +F01E +ENDCHAR +STARTCHAR S +ENCODING 83 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 15 18 1 0 +BITMAP +0FC0 +3FF0 +7FF8 +787C +F03C +F01C +F800 +7F80 +7FF0 +1FFC +01FC +003E +F01E +F01E +F83C +7FFC +3FF8 +0FE0 +ENDCHAR +STARTCHAR T +ENCODING 84 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 15 18 0 0 +BITMAP +FFFE +FFFE +FFFE +03C0 +03C0 +03C0 +03C0 +03C0 +03C0 +03C0 +03C0 +03C0 +03C0 +03C0 +03C0 +03C0 +03C0 +03C0 +ENDCHAR +STARTCHAR U +ENCODING 85 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 14 18 2 0 +BITMAP +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F87C +7FF8 +3FF0 +0FC0 +ENDCHAR +STARTCHAR V +ENCODING 86 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 15 18 1 0 +BITMAP +F01E +F01E +F01C +703C +783C +7838 +3878 +3C78 +3C70 +1C70 +1CF0 +1EE0 +0EE0 +0FE0 +0FC0 +07C0 +07C0 +0780 +ENDCHAR +STARTCHAR W +ENCODING 87 +SWIDTH 944 0 +DWIDTH 24 0 +BBX 22 18 1 0 +BITMAP +F0783C +F0783C +F0F83C +F0FC38 +78FC78 +78FC78 +78DC70 +79DC70 +39CEF0 +3DCEF0 +3DCEE0 +1D8EE0 +1F8EE0 +1F87C0 +1F87C0 +0F87C0 +0F07C0 +0F0780 +ENDCHAR +STARTCHAR X +ENCODING 88 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 15 18 1 0 +BITMAP +F03E +783C +7C78 +3C78 +3EF0 +1EE0 +0FE0 +0FC0 +07C0 +07C0 +0FE0 +1FE0 +1EF0 +3CF8 +3C78 +787C +F83C +F03E +ENDCHAR +STARTCHAR Y +ENCODING 89 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 15 18 1 0 +BITMAP +F01E +F83E +783C +7878 +3C78 +3C70 +1EF0 +1EE0 +0FE0 +07C0 +07C0 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +ENDCHAR +STARTCHAR Z +ENCODING 90 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 14 18 1 0 +BITMAP +FFFC +FFFC +FFFC +0078 +00F0 +01F0 +03E0 +07C0 +0780 +0F00 +1F00 +3E00 +7C00 +7800 +F000 +FFFC +FFFC +FFFC +ENDCHAR +STARTCHAR bracketleft +ENCODING 91 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 6 23 2 -5 +BITMAP +FC +FC +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +FC +FC +ENDCHAR +STARTCHAR backslash +ENCODING 92 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 9 18 -1 0 +BITMAP +E000 +7000 +7000 +7000 +3800 +3800 +3800 +1800 +1C00 +1C00 +1C00 +0E00 +0E00 +0E00 +0700 +0700 +0700 +0380 +ENDCHAR +STARTCHAR bracketright +ENCODING 93 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 6 23 1 -5 +BITMAP +FC +FC +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +FC +FC +ENDCHAR +STARTCHAR asciicircum +ENCODING 94 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 11 9 2 9 +BITMAP +0E00 +1E00 +1F00 +3B00 +3B80 +7180 +71C0 +E1C0 +E0E0 +ENDCHAR +STARTCHAR underscore +ENCODING 95 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 14 1 0 -3 +BITMAP +FFFC +ENDCHAR +STARTCHAR grave +ENCODING 96 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 5 4 0 15 +BITMAP +E0 +70 +38 +18 +ENDCHAR +STARTCHAR a +ENCODING 97 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +1F80 +7FE0 +7FE0 +F0E0 +F0E0 +01E0 +3FE0 +7EE0 +F0E0 +E0E0 +E1E0 +FFE0 +FFF0 +3CF0 +ENDCHAR +STARTCHAR b +ENCODING 98 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 18 2 0 +BITMAP +E000 +E000 +E000 +E000 +E780 +EFE0 +FFE0 +F1F0 +E0F0 +E070 +E070 +E070 +E070 +E0F0 +F0F0 +FFE0 +FFE0 +E780 +ENDCHAR +STARTCHAR c +ENCODING 99 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F80 +3FE0 +7FE0 +78F0 +F0F0 +F000 +E000 +E000 +F000 +F0F0 +F0F0 +7FE0 +3FC0 +1F80 +ENDCHAR +STARTCHAR d +ENCODING 100 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0078 +0078 +0078 +0078 +1F78 +3FF8 +7FF8 +F8F8 +F078 +F078 +E078 +E078 +F078 +F078 +F8F8 +7FF8 +3FF8 +1F78 +ENDCHAR +STARTCHAR e +ENCODING 101 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +1F80 +3FC0 +7FE0 +F0F0 +E0F0 +E070 +FFF0 +FFF0 +E000 +E000 +F0F0 +7FE0 +3FC0 +1F80 +ENDCHAR +STARTCHAR f +ENCODING 102 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 8 18 0 0 +BITMAP +0F +1F +3F +3C +FF +FF +3F +3C +3C +3C +3C +3C +3C +3C +3C +3C +3C +3C +ENDCHAR +STARTCHAR g +ENCODING 103 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 13 19 1 -5 +BITMAP +1F78 +3FF8 +7FF8 +78F8 +F078 +F078 +F078 +F078 +F078 +F078 +78F8 +7FF8 +3FF8 +1F78 +0078 +F078 +7FF0 +7FE0 +1F80 +ENDCHAR +STARTCHAR h +ENCODING 104 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 18 2 0 +BITMAP +E000 +E000 +E000 +E000 +E780 +EFE0 +FFE0 +F1F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +ENDCHAR +STARTCHAR i +ENCODING 105 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 3 18 2 0 +BITMAP +E0 +E0 +E0 +00 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR j +ENCODING 106 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 5 23 0 -5 +BITMAP +38 +38 +38 +00 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +F8 +F8 +F0 +ENDCHAR +STARTCHAR k +ENCODING 107 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 2 0 +BITMAP +E000 +E000 +E000 +E000 +E1E0 +E3E0 +E3C0 +E780 +EF00 +FE00 +FF00 +FF00 +F780 +E7C0 +E3C0 +E3E0 +E1E0 +E0F0 +ENDCHAR +STARTCHAR l +ENCODING 108 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 3 18 2 0 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR m +ENCODING 109 +SWIDTH 889 0 +DWIDTH 22 0 +BBX 19 14 2 0 +BITMAP +E78F00 +EFDFC0 +FFFFC0 +F1F3E0 +E1E1E0 +E1E1E0 +E1E1E0 +E1E1E0 +E1E1E0 +E1E1E0 +E1E1E0 +E1E1E0 +E1E1E0 +E1E1E0 +ENDCHAR +STARTCHAR n +ENCODING 110 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 14 2 0 +BITMAP +E780 +EFE0 +FFE0 +F1F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +ENDCHAR +STARTCHAR o +ENCODING 111 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0FC0 +3FE0 +7FF0 +78F8 +F078 +F038 +E038 +E038 +F038 +F078 +7878 +7FF0 +3FE0 +0F80 +ENDCHAR +STARTCHAR p +ENCODING 112 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 19 2 -5 +BITMAP +E780 +EFE0 +FFE0 +F1F0 +E0F0 +E070 +E070 +E070 +E070 +E0F0 +F0F0 +FFE0 +FFE0 +E780 +E000 +E000 +E000 +E000 +E000 +ENDCHAR +STARTCHAR q +ENCODING 113 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 13 19 1 -5 +BITMAP +1F78 +3FF8 +7FF8 +78F8 +F078 +F078 +E078 +E078 +F078 +F078 +F8F8 +7FF8 +3FF8 +1F78 +0078 +0078 +0078 +0078 +0078 +ENDCHAR +STARTCHAR r +ENCODING 114 +SWIDTH 389 0 +DWIDTH 10 0 +BBX 7 14 2 0 +BITMAP +E6 +EE +FE +FE +F0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR s +ENCODING 115 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +1F80 +7FC0 +7FE0 +F0F0 +F000 +FF00 +7FE0 +1FF0 +01F0 +E0F0 +F0F0 +FFE0 +7FE0 +1F80 +ENDCHAR +STARTCHAR t +ENCODING 116 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 8 18 0 0 +BITMAP +3C +3C +3C +3C +FF +FF +3F +3C +3C +3C +3C +3C +3C +3C +3C +3F +3F +1F +ENDCHAR +STARTCHAR u +ENCODING 117 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 14 2 0 +BITMAP +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +F1F0 +FFF0 +7FF0 +3CF0 +ENDCHAR +STARTCHAR v +ENCODING 118 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 13 14 0 0 +BITMAP +F038 +7878 +7878 +7870 +3870 +3CF0 +1CE0 +1CE0 +1CE0 +0FC0 +0FC0 +0FC0 +0780 +0780 +ENDCHAR +STARTCHAR w +ENCODING 119 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 19 14 0 0 +BITMAP +F0F0E0 +70F1E0 +70F1E0 +79F1C0 +79B1C0 +39B9C0 +39BB80 +3DBB80 +1F9B80 +1F1B80 +1F1F00 +1F1F00 +0F1F00 +0F0F00 +ENDCHAR +STARTCHAR x +ENCODING 120 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +F0F0 +F9E0 +79E0 +3FC0 +3FC0 +1F80 +0F00 +0F00 +1F80 +3FC0 +3FC0 +79E0 +F1F0 +F0F0 +ENDCHAR +STARTCHAR y +ENCODING 121 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 13 19 0 -5 +BITMAP +F038 +7878 +7878 +7870 +3870 +3CF0 +3CE0 +1CE0 +1FE0 +0FC0 +0FC0 +0FC0 +0780 +0780 +0780 +0700 +3F00 +3E00 +3C00 +ENDCHAR +STARTCHAR z +ENCODING 122 +SWIDTH 500 0 +DWIDTH 13 0 +BBX 12 14 0 0 +BITMAP +7FF0 +7FF0 +7FF0 +01E0 +03C0 +07C0 +0F80 +0F00 +1E00 +3C00 +7C00 +FFF0 +FFF0 +FFF0 +ENDCHAR +STARTCHAR braceleft +ENCODING 123 +SWIDTH 389 0 +DWIDTH 10 0 +BBX 8 23 1 -5 +BITMAP +0F +1F +1C +1C +1C +1C +1C +1C +1C +38 +F0 +F0 +78 +3C +1C +1C +1C +1C +1C +1C +1C +1F +0F +ENDCHAR +STARTCHAR bar +ENCODING 124 +SWIDTH 280 0 +DWIDTH 7 0 +BBX 3 18 2 0 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR braceright +ENCODING 125 +SWIDTH 389 0 +DWIDTH 10 0 +BBX 8 23 1 -5 +BITMAP +F0 +F8 +38 +38 +38 +38 +38 +38 +38 +3C +1F +0F +1E +38 +38 +38 +38 +38 +38 +38 +38 +F8 +E0 +ENDCHAR +STARTCHAR asciitilde +ENCODING 126 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 11 4 2 4 +BITMAP +FC60 +FFE0 +CFE0 +8380 +ENDCHAR +STARTCHAR exclamdown +ENCODING 161 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 4 19 2 -5 +BITMAP +F0 +F0 +F0 +F0 +00 +00 +60 +60 +60 +70 +70 +70 +F0 +F0 +F0 +F0 +F0 +F0 +F0 +ENDCHAR +STARTCHAR cent +ENCODING 162 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 -3 +BITMAP +0080 +0080 +0F80 +3FC0 +7FE0 +7BF0 +F3F0 +F200 +E200 +E600 +F400 +F4F0 +FCF0 +7FE0 +3FC0 +1F80 +1800 +1000 +1000 +ENDCHAR +STARTCHAR sterling +ENCODING 163 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +1F80 +3FE0 +7FE0 +F0F0 +F070 +F070 +F000 +7800 +FF00 +3F00 +3C00 +1C00 +3800 +3800 +7410 +FFF0 +FFF0 +43E0 +ENDCHAR +STARTCHAR currency +ENCODING 164 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 14 14 0 2 +BITMAP +4000 +E018 +F7BC +7FF8 +3FF0 +3870 +3070 +3030 +3870 +3870 +3FF0 +7FF8 +E21C +4008 +ENDCHAR +STARTCHAR yen +ENCODING 165 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 14 18 0 0 +BITMAP +F03C +7038 +7878 +3870 +3CF0 +1CE0 +1EE0 +0FC0 +FFFC +0780 +0780 +FFFC +07FC +0780 +0780 +0780 +0780 +0780 +ENDCHAR +STARTCHAR brokenbar +ENCODING 166 +SWIDTH 280 0 +DWIDTH 7 0 +BBX 3 18 2 0 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +E0 +00 +00 +00 +00 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR section +ENCODING 167 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 23 1 -5 +BITMAP +0F80 +3FC0 +7FE0 +71E0 +70E0 +7800 +7E00 +3F80 +7FE0 +E3F0 +E0F0 +F070 +FC70 +7FE0 +3FC0 +0FC0 +03E0 +00E0 +70E0 +79E0 +7FC0 +3F80 +0E00 +ENDCHAR +STARTCHAR dieresis +ENCODING 168 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 8 3 0 15 +BITMAP +E7 +E7 +E7 +ENDCHAR +STARTCHAR copyright +ENCODING 169 +SWIDTH 737 0 +DWIDTH 18 0 +BBX 19 18 0 0 +BITMAP +03F000 +0FFE00 +3F1F00 +380780 +71F3C0 +E3F9C0 +E71CC0 +E60CE0 +CE00E0 +CE00E0 +E60CE0 +E71CC0 +E3F9C0 +71F3C0 +380780 +3E1F00 +0FFE00 +03F000 +ENDCHAR +STARTCHAR ordfeminine +ENCODING 170 +SWIDTH 370 0 +DWIDTH 9 0 +BBX 7 11 1 7 +BITMAP +7C +FE +C6 +7E +E6 +C6 +FE +F6 +00 +FE +FE +ENDCHAR +STARTCHAR guillemotleft +ENCODING 171 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 10 10 2 2 +BITMAP +1040 +10C0 +71C0 +F380 +C300 +C300 +F380 +71C0 +30C0 +1040 +ENDCHAR +STARTCHAR logicalnot +ENCODING 172 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 13 8 1 3 +BITMAP +FFF8 +FFF8 +FFF8 +0038 +0038 +0038 +0038 +0038 +ENDCHAR +STARTCHAR registered +ENCODING 174 +SWIDTH 737 0 +DWIDTH 18 0 +BBX 19 18 0 0 +BITMAP +03F000 +0FFE00 +1F1F00 +380780 +77E3C0 +E7F9C0 +E718C0 +E718E0 +C7F8E0 +C7E0E0 +E770E0 +E730C0 +E739C0 +771BC0 +380780 +3E1F00 +0FFE00 +03F000 +ENDCHAR +STARTCHAR macron +ENCODING 175 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 8 2 0 15 +BITMAP +FF +FF +ENDCHAR +STARTCHAR degree +ENCODING 176 +SWIDTH 400 0 +DWIDTH 10 0 +BBX 8 7 1 11 +BITMAP +3C +7E +42 +C3 +42 +66 +3C +ENDCHAR +STARTCHAR plusminus +ENCODING 177 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 13 13 1 0 +BITMAP +0700 +0700 +0700 +FFF8 +FFF8 +FFF8 +0700 +0700 +0700 +0000 +FFF8 +FFF8 +FFF8 +ENDCHAR +STARTCHAR twosuperior +ENCODING 178 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 8 11 0 7 +BITMAP +3C +7F +67 +E3 +07 +0F +1E +38 +70 +7F +FF +ENDCHAR +STARTCHAR threesuperior +ENCODING 179 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 8 11 0 7 +BITMAP +3C +7F +E7 +07 +1E +1F +03 +C3 +E7 +7E +3C +ENDCHAR +STARTCHAR acute +ENCODING 180 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 6 4 3 15 +BITMAP +3C +78 +70 +E0 +ENDCHAR +STARTCHAR mu +ENCODING 181 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 19 2 -5 +BITMAP +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +F1F0 +FFF0 +FFF0 +FEF0 +E000 +E000 +E000 +E000 +E000 +ENDCHAR +STARTCHAR paragraph +ENCODING 182 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 13 22 0 -4 +BITMAP +1FF8 +7FF8 +FF18 +FF18 +FF18 +FF18 +FF18 +7F18 +1F18 +0718 +0718 +0718 +0718 +0718 +0718 +0718 +0718 +0718 +0718 +0718 +0718 +0718 +ENDCHAR +STARTCHAR periodcentered +ENCODING 183 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 3 4 2 4 +BITMAP +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR cedilla +ENCODING 184 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 6 5 0 -5 +BITMAP +30 +38 +0C +0C +FC +ENDCHAR +STARTCHAR onesuperior +ENCODING 185 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 5 11 1 7 +BITMAP +18 +38 +F8 +F8 +38 +38 +38 +38 +38 +38 +38 +ENDCHAR +STARTCHAR ordmasculine +ENCODING 186 +SWIDTH 365 0 +DWIDTH 9 0 +BBX 9 11 0 7 +BITMAP +3E00 +7F00 +E380 +E380 +E180 +E380 +7F00 +3E00 +0000 +7F00 +7F00 +ENDCHAR +STARTCHAR guillemotright +ENCODING 187 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 10 10 2 2 +BITMAP +8400 +C200 +E380 +73C0 +31C0 +31C0 +73C0 +E380 +C200 +8400 +ENDCHAR +STARTCHAR onequarter +ENCODING 188 +SWIDTH 834 0 +DWIDTH 21 0 +BBX 18 18 1 0 +BITMAP +180600 +380C00 +F80C00 +381800 +383000 +383000 +386000 +386380 +38C780 +398580 +398D80 +031980 +031980 +063180 +0C3FC0 +0C3FC0 +180180 +180180 +ENDCHAR +STARTCHAR onehalf +ENCODING 189 +SWIDTH 834 0 +DWIDTH 21 0 +BBX 19 18 1 0 +BITMAP +180600 +380C00 +F80C00 +381800 +383000 +383000 +386000 +386780 +38CFC0 +399CE0 +3998E0 +0300E0 +0301C0 +060380 +0C0700 +0C0E00 +181FE0 +181FE0 +ENDCHAR +STARTCHAR threequarters +ENCODING 190 +SWIDTH 834 0 +DWIDTH 21 0 +BBX 20 18 0 0 +BITMAP +3E0180 +7F0300 +630300 +070600 +1E0400 +1F0C00 +031800 +E318E0 +6331E0 +7F33E0 +3E63E0 +00C6E0 +00C4E0 +018CE0 +018FF0 +030FF0 +0600E0 +0600E0 +ENDCHAR +STARTCHAR questiondown +ENCODING 191 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 13 19 1 -5 +BITMAP +0700 +0700 +0700 +0700 +0000 +0700 +0700 +0700 +0F00 +3E00 +7C00 +7800 +F000 +F078 +F078 +78F0 +7FF0 +3FE0 +0F80 +ENDCHAR +STARTCHAR Agrave +ENCODING 192 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 24 1 0 +BITMAP +1E00 +0F00 +0780 +0380 +0000 +0000 +03C0 +07E0 +07E0 +07E0 +0FF0 +0F70 +0E78 +1E78 +1E78 +1C3C +3C3C +3FFC +7FFE +7FFE +781E +F00F +F00F +F00F +ENDCHAR +STARTCHAR Aacute +ENCODING 193 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 24 1 0 +BITMAP +0078 +00F0 +00E0 +01C0 +0000 +0000 +03C0 +07E0 +07E0 +07E0 +0FF0 +0F70 +0E78 +1E78 +1E78 +1C3C +3C3C +3FFC +7FFE +7FFE +781E +F00F +F00F +F00F +ENDCHAR +STARTCHAR Acircumflex +ENCODING 194 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 24 1 0 +BITMAP +03C0 +03E0 +07E0 +0E70 +0000 +0000 +03C0 +07E0 +07E0 +07E0 +0FF0 +0F70 +0E78 +1E78 +1E78 +1C3C +3C3C +3FFC +7FFE +7FFE +781E +F00F +F00F +F00F +ENDCHAR +STARTCHAR Atilde +ENCODING 195 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 23 1 0 +BITMAP +0790 +0FF0 +08E0 +0000 +0000 +03C0 +07E0 +07E0 +07E0 +0FF0 +0F70 +0E78 +1E78 +1E78 +1C3C +3C3C +3FFC +7FFE +7FFE +781E +F00F +F00F +F00F +ENDCHAR +STARTCHAR Adieresis +ENCODING 196 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 23 1 0 +BITMAP +0E70 +0E70 +0E70 +0000 +0000 +03C0 +07E0 +07E0 +07E0 +0FF0 +0F70 +0E78 +1E78 +1E78 +1C3C +3C3C +3FFC +7FFE +7FFE +781E +F00F +F00F +F00F +ENDCHAR +STARTCHAR Aring +ENCODING 197 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 24 1 0 +BITMAP +01C0 +0360 +0660 +0360 +03C0 +0000 +03C0 +07E0 +07E0 +07E0 +0FF0 +0F70 +0E78 +1E78 +1E78 +1C3C +3C3C +3FFC +7FFE +7FFE +781E +F00F +F00F +F00F +ENDCHAR +STARTCHAR AE +ENCODING 198 +SWIDTH 1000 0 +DWIDTH 25 0 +BBX 24 18 0 0 +BITMAP +03FFFF +03FFFF +03FFFF +079C00 +079C00 +071C00 +0F1C00 +0F1FFE +0E1FFE +1E1FFE +1E1C00 +3FFC00 +3FFC00 +3FFC00 +781C00 +781FFF +781FFF +F01FFF +ENDCHAR +STARTCHAR Ccedilla +ENCODING 199 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 23 1 -5 +BITMAP +07E0 +0FF8 +3FFE +3E3E +780F +780F +F000 +F000 +F000 +F000 +F000 +F000 +780F +780F +7E3E +3FFC +1FF8 +07E0 +0300 +03C0 +00C0 +00C0 +07C0 +ENDCHAR +STARTCHAR Egrave +ENCODING 200 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 14 24 2 0 +BITMAP +3C00 +1C00 +0E00 +0600 +0000 +0000 +FFF8 +FFF8 +FFF8 +F000 +F000 +F000 +F000 +FFF0 +FFF0 +FFF0 +F000 +F000 +F000 +F000 +F000 +FFFC +FFFC +FFFC +ENDCHAR +STARTCHAR Eacute +ENCODING 201 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 14 24 2 0 +BITMAP +01E0 +03C0 +0380 +0700 +0000 +0000 +FFF8 +FFF8 +FFF8 +F000 +F000 +F000 +F000 +FFF0 +FFF0 +FFF0 +F000 +F000 +F000 +F000 +F000 +FFFC +FFFC +FFFC +ENDCHAR +STARTCHAR Ecircumflex +ENCODING 202 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 14 24 2 0 +BITMAP +0700 +0F80 +1DC0 +38C0 +0000 +0000 +FFF8 +FFF8 +FFF8 +F000 +F000 +F000 +F000 +FFF0 +FFF0 +FFF0 +F000 +F000 +F000 +F000 +F000 +FFFC +FFFC +FFFC +ENDCHAR +STARTCHAR Edieresis +ENCODING 203 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 14 23 2 0 +BITMAP +39C0 +39C0 +39C0 +0000 +0000 +FFF8 +FFF8 +FFF8 +F000 +F000 +F000 +F000 +FFF0 +FFF0 +FFF0 +F000 +F000 +F000 +F000 +F000 +FFFC +FFFC +FFFC +ENDCHAR +STARTCHAR Igrave +ENCODING 204 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 6 24 -1 0 +BITMAP +F0 +70 +38 +1C +00 +00 +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +ENDCHAR +STARTCHAR Iacute +ENCODING 205 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 6 24 2 0 +BITMAP +3C +38 +70 +E0 +00 +00 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR Icircumflex +ENCODING 206 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 9 24 -1 0 +BITMAP +1C00 +3E00 +7700 +E380 +0000 +0000 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +ENDCHAR +STARTCHAR Idieresis +ENCODING 207 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 8 23 -1 0 +BITMAP +F7 +F7 +F7 +00 +00 +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +ENDCHAR +STARTCHAR Eth +ENCODING 208 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 17 18 0 0 +BITMAP +3FF800 +3FFE00 +3FFE00 +3C1F00 +3C0F00 +3C0780 +3C0780 +FFC780 +FFC780 +FFC780 +3C0780 +3C0780 +3C0780 +3C0F00 +3C1F00 +3FFE00 +3FFC00 +3FF000 +ENDCHAR +STARTCHAR Ntilde +ENCODING 209 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 14 23 2 0 +BITMAP +0F20 +1FE0 +11C0 +0000 +0000 +F01C +F81C +F81C +FC1C +FC1C +FE1C +EE1C +E71C +E79C +E39C +E3DC +E1DC +E1FC +E0FC +E07C +E07C +E03C +E03C +ENDCHAR +STARTCHAR Ograve +ENCODING 210 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 23 1 0 +BITMAP +0F0000 +078000 +038000 +01C000 +000000 +03F000 +0FFC00 +3FFE00 +3E3F00 +780F80 +780780 +F00780 +F00780 +F00380 +F00380 +F00380 +F00780 +780780 +780F00 +3E1F00 +3FFE00 +0FFC00 +03F000 +ENDCHAR +STARTCHAR Oacute +ENCODING 211 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 23 1 0 +BITMAP +007800 +007000 +00E000 +01C000 +000000 +03F000 +0FFC00 +3FFE00 +3E3F00 +780F80 +780780 +F00780 +F00780 +F00380 +F00380 +F00380 +F00780 +780780 +780F00 +3E1F00 +3FFE00 +0FFC00 +03F000 +ENDCHAR +STARTCHAR Ocircumflex +ENCODING 212 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 23 1 0 +BITMAP +01E000 +03E000 +077000 +0E3800 +000000 +03F000 +0FFC00 +3FFE00 +3E3F00 +780F80 +780780 +F00780 +F00780 +F00380 +F00380 +F00380 +F00780 +780780 +780F00 +3E1F00 +3FFE00 +0FFC00 +03F000 +ENDCHAR +STARTCHAR Otilde +ENCODING 213 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 23 1 0 +BITMAP +038800 +07F800 +0CF000 +000000 +000000 +03F000 +0FFC00 +3FFE00 +3E3F00 +780F80 +780780 +F00780 +F00780 +F00380 +F00380 +F00380 +F00780 +780780 +780F00 +3E1F00 +3FFE00 +0FFC00 +03F000 +ENDCHAR +STARTCHAR Odieresis +ENCODING 214 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 23 1 0 +BITMAP +073800 +073800 +073800 +000000 +000000 +03F000 +0FFC00 +3FFE00 +3E3F00 +780F80 +780780 +F00780 +F00780 +F00380 +F00380 +F00380 +F00780 +780780 +780F00 +3E1F00 +3FFE00 +0FFC00 +03F000 +ENDCHAR +STARTCHAR multiply +ENCODING 215 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 12 12 1 0 +BITMAP +6030 +F070 +78E0 +3DC0 +1F80 +0F00 +0F80 +1FC0 +39E0 +70F0 +E070 +4020 +ENDCHAR +STARTCHAR Oslash +ENCODING 216 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 18 1 0 +BITMAP +03F080 +0FFD80 +3FFF00 +3E3F00 +780F80 +781F80 +F03780 +F06780 +F0C380 +F18380 +F30380 +F60780 +7C0780 +780F00 +3E1F00 +7FFE00 +4FFC00 +C3F000 +ENDCHAR +STARTCHAR Ugrave +ENCODING 217 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 14 24 2 0 +BITMAP +3C00 +1E00 +0F00 +0700 +0000 +0000 +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F87C +7FF8 +3FF0 +0FC0 +ENDCHAR +STARTCHAR Uacute +ENCODING 218 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 14 24 2 0 +BITMAP +00F0 +01E0 +01C0 +0380 +0000 +0000 +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F87C +7FF8 +3FF0 +0FC0 +ENDCHAR +STARTCHAR Ucircumflex +ENCODING 219 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 14 24 2 0 +BITMAP +0780 +07C0 +0FC0 +1CE0 +0000 +0000 +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F87C +7FF8 +3FF0 +0FC0 +ENDCHAR +STARTCHAR Udieresis +ENCODING 220 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 14 23 2 0 +BITMAP +1CE0 +1CE0 +1CE0 +0000 +0000 +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F03C +F87C +7FF8 +3FF0 +0FC0 +ENDCHAR +STARTCHAR Yacute +ENCODING 221 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 15 24 1 0 +BITMAP +00F0 +01E0 +01C0 +0380 +0000 +0000 +F01E +F83E +783C +7878 +3C78 +3C70 +1EF0 +1EE0 +0FE0 +07C0 +07C0 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +ENDCHAR +STARTCHAR Thorn +ENCODING 222 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 14 18 2 0 +BITMAP +F000 +F000 +FFE0 +FFF0 +FFF8 +F078 +F03C +F03C +F03C +F038 +F078 +FFF8 +FFF0 +FFC0 +F000 +F000 +F000 +F000 +ENDCHAR +STARTCHAR germandbls +ENCODING 223 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 18 2 0 +BITMAP +1F80 +7FC0 +FFE0 +F1E0 +E0E0 +E0E0 +E1E0 +E7C0 +E7E0 +E7F0 +E0F0 +E070 +E070 +E070 +E0F0 +E7F0 +E7E0 +E780 +ENDCHAR +STARTCHAR agrave +ENCODING 224 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +3800 +1C00 +0E00 +0600 +0000 +1F80 +7FE0 +7FE0 +F0E0 +F0E0 +01E0 +3FE0 +7EE0 +F0E0 +E0E0 +E1E0 +FFE0 +FFF0 +3CF0 +ENDCHAR +STARTCHAR aacute +ENCODING 225 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +01C0 +0380 +0700 +0600 +0000 +1F80 +7FE0 +7FE0 +F0E0 +F0E0 +01E0 +3FE0 +7EE0 +F0E0 +E0E0 +E1E0 +FFE0 +FFF0 +3CF0 +ENDCHAR +STARTCHAR acircumflex +ENCODING 226 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +0F00 +1F80 +3980 +31C0 +0000 +1F80 +7FE0 +7FE0 +F0E0 +F0E0 +01E0 +3FE0 +7EE0 +F0E0 +E0E0 +E1E0 +FFE0 +FFF0 +3CF0 +ENDCHAR +STARTCHAR atilde +ENCODING 227 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +1C40 +3FC0 +2380 +0000 +1F80 +7FE0 +7FE0 +F0E0 +F0E0 +01E0 +3FE0 +7EE0 +F0E0 +E0E0 +E1E0 +FFE0 +FFF0 +3CF0 +ENDCHAR +STARTCHAR adieresis +ENCODING 228 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +39C0 +39C0 +39C0 +0000 +1F80 +7FE0 +7FE0 +F0E0 +F0E0 +01E0 +3FE0 +7EE0 +F0E0 +E0E0 +E1E0 +FFE0 +FFF0 +3CF0 +ENDCHAR +STARTCHAR aring +ENCODING 229 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 20 1 0 +BITMAP +0700 +0F00 +1980 +1980 +0F00 +0000 +1F80 +7FE0 +7FE0 +F0E0 +F0E0 +01E0 +3FE0 +7EE0 +F0E0 +E0E0 +E1E0 +FFE0 +FFF0 +3CF0 +ENDCHAR +STARTCHAR ae +ENCODING 230 +SWIDTH 889 0 +DWIDTH 22 0 +BBX 20 14 1 0 +BITMAP +1F8F80 +3FFFC0 +7FFFE0 +F0F0F0 +F0F070 +01E070 +3FFFF0 +7FFFF0 +F0E000 +E0F000 +E0F0F0 +FFFFE0 +FFBFE0 +3E1F80 +ENDCHAR +STARTCHAR ccedilla +ENCODING 231 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 -5 +BITMAP +0F80 +3FE0 +7FE0 +78F0 +F0F0 +F000 +E000 +E000 +F000 +F0F0 +F0F0 +7FE0 +3FC0 +1F80 +0C00 +0F00 +0300 +0300 +1F00 +ENDCHAR +STARTCHAR egrave +ENCODING 232 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +3800 +1C00 +0E00 +0600 +0000 +1F80 +3FC0 +7FE0 +F0F0 +E0F0 +E070 +FFF0 +FFF0 +E000 +E000 +F0F0 +7FE0 +3FC0 +1F80 +ENDCHAR +STARTCHAR eacute +ENCODING 233 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +01C0 +0380 +0700 +0600 +0000 +1F80 +3FC0 +7FE0 +F0F0 +E0F0 +E070 +FFF0 +FFF0 +E000 +E000 +F0F0 +7FE0 +3FC0 +1F80 +ENDCHAR +STARTCHAR ecircumflex +ENCODING 234 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +0F00 +1F80 +3980 +31C0 +0000 +1F80 +3FC0 +7FE0 +F0F0 +E0F0 +E070 +FFF0 +FFF0 +E000 +E000 +F0F0 +7FE0 +3FC0 +1F80 +ENDCHAR +STARTCHAR edieresis +ENCODING 235 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +39C0 +39C0 +39C0 +0000 +1F80 +3FC0 +7FE0 +F0F0 +E0F0 +E070 +FFF0 +FFF0 +E000 +E000 +F0F0 +7FE0 +3FC0 +1F80 +ENDCHAR +STARTCHAR igrave +ENCODING 236 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 6 20 -1 0 +BITMAP +F0 +70 +38 +1C +00 +00 +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +ENDCHAR +STARTCHAR iacute +ENCODING 237 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 6 20 2 0 +BITMAP +3C +38 +70 +E0 +00 +00 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR icircumflex +ENCODING 238 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 9 20 -1 0 +BITMAP +1C00 +3E00 +7700 +E380 +0000 +0000 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +ENDCHAR +STARTCHAR idieresis +ENCODING 239 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 8 18 -1 0 +BITMAP +F7 +F7 +F7 +00 +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +ENDCHAR +STARTCHAR eth +ENCODING 240 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0660 +0FF0 +07C0 +1FE0 +00F0 +0F70 +3FF8 +7FF8 +F8F8 +F078 +F038 +E038 +F038 +F078 +7878 +7FF0 +3FE0 +0F80 +ENDCHAR +STARTCHAR ntilde +ENCODING 241 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 18 2 0 +BITMAP +1CC0 +3FC0 +6780 +0000 +E780 +EFE0 +FFE0 +F1F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +ENDCHAR +STARTCHAR ograve +ENCODING 242 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 13 19 1 0 +BITMAP +3C00 +1E00 +0E00 +0700 +0000 +0FC0 +3FE0 +7FF0 +78F8 +F078 +F038 +E038 +E038 +F038 +F078 +7878 +7FF0 +3FE0 +0F80 +ENDCHAR +STARTCHAR oacute +ENCODING 243 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 13 19 1 0 +BITMAP +01E0 +01C0 +0380 +0700 +0000 +0FC0 +3FE0 +7FF0 +78F8 +F078 +F038 +E038 +E038 +F038 +F078 +7878 +7FF0 +3FE0 +0F80 +ENDCHAR +STARTCHAR ocircumflex +ENCODING 244 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 13 19 1 0 +BITMAP +0780 +0F80 +1DC0 +38E0 +0000 +0FC0 +3FE0 +7FF0 +78F8 +F078 +F038 +E038 +E038 +F038 +F078 +7878 +7FF0 +3FE0 +0F80 +ENDCHAR +STARTCHAR otilde +ENCODING 245 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0E60 +1FE0 +33C0 +0000 +0FC0 +3FE0 +7FF0 +78F8 +F078 +F038 +E038 +E038 +F038 +F078 +7878 +7FF0 +3FE0 +0F80 +ENDCHAR +STARTCHAR odieresis +ENCODING 246 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +1DE0 +1DE0 +1DE0 +0000 +0FC0 +3FE0 +7FF0 +78F8 +F078 +F038 +E038 +E038 +F038 +F078 +7878 +7FF0 +3FE0 +0F80 +ENDCHAR +STARTCHAR divide +ENCODING 247 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 13 14 1 -1 +BITMAP +0700 +0F80 +0F00 +0700 +0000 +FFF8 +FFF8 +FFF8 +0000 +0000 +0700 +0F80 +0F00 +0700 +ENDCHAR +STARTCHAR oslash +ENCODING 248 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 14 14 1 0 +BITMAP +0F8C +3FF8 +7FF0 +78F8 +F0F8 +F1B8 +E338 +E638 +FC38 +F878 +F878 +7FF0 +7FE0 +8F80 +ENDCHAR +STARTCHAR ugrave +ENCODING 249 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 20 2 0 +BITMAP +7800 +3800 +1C00 +0E00 +0000 +0000 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +F1F0 +FFF0 +7FF0 +3CF0 +ENDCHAR +STARTCHAR uacute +ENCODING 250 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 20 2 0 +BITMAP +03C0 +0380 +0700 +0E00 +0000 +0000 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +F1F0 +FFF0 +7FF0 +3CF0 +ENDCHAR +STARTCHAR ucircumflex +ENCODING 251 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 20 2 0 +BITMAP +0E00 +1F00 +3B80 +31C0 +0000 +0000 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +F1F0 +FFF0 +7FF0 +3CF0 +ENDCHAR +STARTCHAR udieresis +ENCODING 252 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 18 2 0 +BITMAP +3BC0 +3BC0 +3BC0 +0000 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +E0F0 +F1F0 +FFF0 +7FF0 +3CF0 +ENDCHAR +STARTCHAR yacute +ENCODING 253 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 13 25 0 -5 +BITMAP +00F0 +01E0 +03C0 +0380 +0000 +0000 +F038 +7878 +7878 +7870 +3870 +3CF0 +3CE0 +1CE0 +1FE0 +0FC0 +0FC0 +0FC0 +0780 +0780 +0780 +0700 +3F00 +3E00 +3C00 +ENDCHAR +STARTCHAR thorn +ENCODING 254 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 23 2 -5 +BITMAP +E000 +E000 +E000 +E000 +E780 +EFE0 +FFE0 +F1F0 +E0F0 +E070 +E070 +E070 +E070 +E0F0 +F0F0 +FFE0 +FFE0 +E780 +E000 +E000 +E000 +E000 +E000 +ENDCHAR +STARTCHAR ydieresis +ENCODING 255 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 13 23 0 -5 +BITMAP +1CE0 +1CE0 +1CE0 +0000 +F038 +7878 +7878 +7870 +3870 +3CF0 +3CE0 +1CE0 +1FE0 +0FC0 +0FC0 +0FC0 +0780 +0780 +0780 +0700 +3F00 +3E00 +3C00 +ENDCHAR +STARTCHAR dotlessi +ENCODING 305 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 3 14 2 0 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR +STARTCHAR Lslash +ENCODING 321 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 15 18 0 0 +BITMAP +3C00 +3C00 +3C00 +3C00 +3C80 +3F80 +3F00 +3C00 +7C00 +FC00 +BC00 +3C00 +3C00 +3C00 +3C00 +3FFE +3FFE +3FFE +ENDCHAR +STARTCHAR lslash +ENCODING 322 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 7 18 0 0 +BITMAP +38 +38 +38 +38 +38 +3A +3E +3C +78 +F8 +B8 +38 +38 +38 +38 +38 +38 +38 +ENDCHAR +STARTCHAR OE +ENCODING 338 +SWIDTH 1000 0 +DWIDTH 25 0 +BBX 23 18 1 0 +BITMAP +07DFFE +1FFFFE +3FFFFE +7C3E00 +781E00 +F01E00 +F01E00 +F01FFC +F01FFC +F01FFC +F01E00 +F01E00 +F01E00 +781E00 +7C3E00 +3FFFFE +1FFFFE +07DFFE +ENDCHAR +STARTCHAR oe +ENCODING 339 +SWIDTH 944 0 +DWIDTH 24 0 +BBX 22 14 1 0 +BITMAP +0F87C0 +3FEFF0 +7FFFF8 +78FC78 +F07838 +F0383C +E03FFC +E03FFC +F03800 +F07800 +787C38 +7FFFF8 +3FFFF0 +0F87C0 +ENDCHAR +STARTCHAR Scaron +ENCODING 352 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 15 23 1 0 +BITMAP +1C60 +0EE0 +07C0 +0380 +0000 +0FC0 +3FF0 +7FF8 +787C +F03C +F01C +F800 +7F80 +7FF0 +1FFC +01FC +003E +F01E +F01E +F83C +7FFC +3FF8 +0FE0 +ENDCHAR +STARTCHAR scaron +ENCODING 353 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +39C0 +1F80 +1F00 +0F00 +0000 +1F80 +7FC0 +7FE0 +F0F0 +F000 +FF00 +7FE0 +1FF0 +01F0 +E0F0 +F0F0 +FFE0 +7FE0 +1F80 +ENDCHAR +STARTCHAR Ydieresis +ENCODING 376 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 15 23 1 0 +BITMAP +1CE0 +1CE0 +1CE0 +0000 +0000 +F01E +F83E +783C +7878 +3C78 +3C70 +1EF0 +1EE0 +0FE0 +07C0 +07C0 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +ENDCHAR +STARTCHAR Zcaron +ENCODING 381 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 14 24 1 0 +BITMAP +38E0 +1DC0 +0F80 +0780 +0000 +0000 +FFFC +FFFC +FFFC +0078 +00F0 +01F0 +03E0 +07C0 +0780 +0F00 +1F00 +3E00 +7C00 +7800 +F000 +FFFC +FFFC +FFFC +ENDCHAR +STARTCHAR zcaron +ENCODING 382 +SWIDTH 500 0 +DWIDTH 13 0 +BBX 12 20 0 0 +BITMAP +38E0 +1DC0 +1F80 +0F00 +0000 +0000 +7FF0 +7FF0 +7FF0 +01E0 +03C0 +07C0 +0F80 +0F00 +1E00 +3C00 +7C00 +FFF0 +FFF0 +FFF0 +ENDCHAR +STARTCHAR florin +ENCODING 402 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 13 23 0 -5 +BITMAP +00F8 +01F8 +03F0 +03C0 +0380 +0380 +0780 +3FF0 +3FF0 +0700 +0700 +0700 +0F00 +0F00 +0F00 +0E00 +0E00 +1E00 +1E00 +1E00 +FC00 +F800 +F000 +ENDCHAR +STARTCHAR circumflex +ENCODING 710 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 8 4 0 15 +BITMAP +3C +3E +76 +E7 +ENDCHAR +STARTCHAR caron +ENCODING 711 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 8 4 0 15 +BITMAP +E3 +67 +7E +3C +ENDCHAR +STARTCHAR breve +ENCODING 728 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 8 4 0 15 +BITMAP +C1 +C3 +7F +3C +ENDCHAR +STARTCHAR dotaccent +ENCODING 729 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 3 3 3 15 +BITMAP +E0 +E0 +E0 +ENDCHAR +STARTCHAR ring +ENCODING 730 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 6 5 1 14 +BITMAP +78 +4C +CC +6C +38 +ENDCHAR +STARTCHAR ogonek +ENCODING 731 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 5 5 2 -5 +BITMAP +70 +E0 +C0 +C0 +F8 +ENDCHAR +STARTCHAR tilde +ENCODING 732 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 9 3 0 15 +BITMAP +7180 +FF00 +CE00 +ENDCHAR +STARTCHAR hungarumlaut +ENCODING 733 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 11 4 1 15 +BITMAP +79E0 +71C0 +E380 +C700 +ENDCHAR +STARTCHAR endash +ENCODING 8211 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 14 3 0 5 +BITMAP +FFFC +FFFC +FFFC +ENDCHAR +STARTCHAR emdash +ENCODING 8212 +SWIDTH 1000 0 +DWIDTH 25 0 +BBX 25 3 0 5 +BITMAP +FFFFFF80 +FFFFFF80 +FFFFFF80 +ENDCHAR +STARTCHAR quoteleft +ENCODING 8216 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 3 7 2 11 +BITMAP +20 +60 +C0 +80 +E0 +E0 +E0 +ENDCHAR +STARTCHAR quoteright +ENCODING 8217 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 3 7 2 11 +BITMAP +E0 +E0 +E0 +20 +60 +C0 +80 +ENDCHAR +STARTCHAR quotesinglbase +ENCODING 8218 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 3 6 2 -3 +BITMAP +E0 +E0 +E0 +20 +60 +C0 +ENDCHAR +STARTCHAR quotedblleft +ENCODING 8220 +SWIDTH 500 0 +DWIDTH 13 0 +BBX 9 7 2 11 +BITMAP +2180 +E300 +8200 +8600 +E780 +E780 +E780 +ENDCHAR +STARTCHAR quotedblright +ENCODING 8221 +SWIDTH 500 0 +DWIDTH 13 0 +BBX 9 7 2 11 +BITMAP +E780 +E780 +E780 +2180 +6180 +C300 +8600 +ENDCHAR +STARTCHAR quotedblbase +ENCODING 8222 +SWIDTH 500 0 +DWIDTH 13 0 +BBX 9 7 2 -4 +BITMAP +E780 +E780 +E780 +6180 +6180 +C300 +0600 +ENDCHAR +STARTCHAR dagger +ENCODING 8224 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 22 1 -4 +BITMAP +0F00 +0F00 +0F00 +0F00 +0F00 +FFF0 +FFF0 +FFF0 +0F00 +0F00 +0F00 +0F00 +0F00 +0F00 +0F00 +0F00 +0F00 +0F00 +0F00 +0F00 +0F00 +0F00 +ENDCHAR +STARTCHAR daggerdbl +ENCODING 8225 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 22 1 -4 +BITMAP +0F00 +0F00 +0F00 +0F00 +0F00 +FFF0 +FFF0 +FFF0 +0F00 +0F00 +0F00 +0F00 +0F00 +0F00 +FFF0 +FFF0 +FFF0 +0F00 +0F00 +0F00 +0F00 +0F00 +ENDCHAR +STARTCHAR bullet +ENCODING 8226 +SWIDTH 350 0 +DWIDTH 9 0 +BBX 8 8 0 5 +BITMAP +3C +7F +7F +FF +FF +FF +7F +3E +ENDCHAR +STARTCHAR ellipsis +ENCODING 8230 +SWIDTH 1000 0 +DWIDTH 25 0 +BBX 21 4 2 0 +BITMAP +F07078 +F07078 +F07078 +F07078 +ENDCHAR +STARTCHAR perthousand +ENCODING 8240 +SWIDTH 1000 0 +DWIDTH 25 0 +BBX 25 18 0 0 +BITMAP +3C080000 +7E180000 +FF100000 +E7300000 +E7600000 +FF600000 +7EC00000 +3CC00000 +01800000 +01800000 +033C1E00 +027E3F00 +06FF7F80 +04C77380 +0CE77380 +18FF7F80 +187E3F00 +303C1E00 +ENDCHAR +STARTCHAR guilsinglleft +ENCODING 8249 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 4 10 2 2 +BITMAP +10 +30 +70 +E0 +C0 +C0 +E0 +70 +30 +10 +ENDCHAR +STARTCHAR guilsinglright +ENCODING 8250 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 4 10 2 2 +BITMAP +80 +C0 +E0 +70 +30 +30 +70 +E0 +C0 +80 +ENDCHAR +STARTCHAR fraction +ENCODING 8260 +SWIDTH 167 0 +DWIDTH 4 0 +BBX 12 18 -4 0 +BITMAP +0030 +0030 +0060 +00C0 +00C0 +0180 +0180 +0300 +0600 +0600 +0C00 +0C00 +1800 +3000 +3000 +6000 +6000 +C000 +ENDCHAR +STARTCHAR trademark +ENCODING 8482 +SWIDTH 1000 0 +DWIDTH 25 0 +BBX 23 10 1 8 +BITMAP +FF9E1E +FF9E1E +1C1E3E +1C1F3E +1C1B7E +1C1B6E +1C1BEE +1C19EE +1C19CE +1C19CE +ENDCHAR +STARTCHAR minus +ENCODING 8722 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 13 3 1 5 +BITMAP +FFF8 +FFF8 +FFF8 +ENDCHAR +STARTCHAR fi +ENCODING 64257 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 14 18 0 0 +BITMAP +0F3C +1F3C +3F3C +3C00 +FF3C +FF3C +3F3C +3C3C +3C3C +3C3C +3C3C +3C3C +3C3C +3C3C +3C3C +3C3C +3C3C +3C3C +ENDCHAR +STARTCHAR fl +ENCODING 64258 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 14 18 0 0 +BITMAP +0F3C +1F3C +3F3C +3C3C +FF3C +FF3C +3F3C +3C3C +3C3C +3C3C +3C3C +3C3C +3C3C +3C3C +3C3C +3C3C +3C3C +3C3C +ENDCHAR +STARTCHAR .notdef +ENCODING -1 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +ENDFONT diff --git a/Clue_Scale/fonts/OpenSans-16.bdf b/CLUE/Clue_Scale/fonts/OpenSans-16.bdf similarity index 100% rename from Clue_Scale/fonts/OpenSans-16.bdf rename to CLUE/Clue_Scale/fonts/OpenSans-16.bdf diff --git a/Clue_Scale/fonts/OpenSans-9.bdf b/CLUE/Clue_Scale/fonts/OpenSans-9.bdf similarity index 100% rename from Clue_Scale/fonts/OpenSans-9.bdf rename to CLUE/Clue_Scale/fonts/OpenSans-9.bdf diff --git a/Clue_Shot_Timer/code.py b/CLUE/Clue_Shot_Timer/code.py similarity index 100% rename from Clue_Shot_Timer/code.py rename to CLUE/Clue_Shot_Timer/code.py diff --git a/Clue_Shot_Timer/fonts/Arial-18.pcf b/CLUE/Clue_Shot_Timer/fonts/Arial-18.pcf old mode 100755 new mode 100644 similarity index 100% rename from Clue_Shot_Timer/fonts/Arial-18.pcf rename to CLUE/Clue_Shot_Timer/fonts/Arial-18.pcf diff --git a/Clue_Shot_Timer/fonts/Arial-Bold-24.pcf b/CLUE/Clue_Shot_Timer/fonts/Arial-Bold-24.pcf old mode 100755 new mode 100644 similarity index 100% rename from Clue_Shot_Timer/fonts/Arial-Bold-24.pcf rename to CLUE/Clue_Shot_Timer/fonts/Arial-Bold-24.pcf diff --git a/Clue_Shot_Timer/fonts/Lato-Regular-74.pcf b/CLUE/Clue_Shot_Timer/fonts/Lato-Regular-74.pcf old mode 100755 new mode 100644 similarity index 100% rename from Clue_Shot_Timer/fonts/Lato-Regular-74.pcf rename to CLUE/Clue_Shot_Timer/fonts/Lato-Regular-74.pcf diff --git a/Clue_Shot_Timer/settings.txt b/CLUE/Clue_Shot_Timer/settings.txt similarity index 100% rename from Clue_Shot_Timer/settings.txt rename to CLUE/Clue_Shot_Timer/settings.txt diff --git a/Clue_Step_Counter/clue_bgBMP.bmp b/CLUE/Clue_Step_Counter/clue_bgBMP.bmp similarity index 100% rename from Clue_Step_Counter/clue_bgBMP.bmp rename to CLUE/Clue_Step_Counter/clue_bgBMP.bmp diff --git a/CLUE/Clue_Step_Counter/code.py b/CLUE/Clue_Step_Counter/code.py new file mode 100644 index 000000000..490033ad5 --- /dev/null +++ b/CLUE/Clue_Step_Counter/code.py @@ -0,0 +1,182 @@ +# SPDX-FileCopyrightText: 2020 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import time +import board +import displayio +from adafruit_clue import clue +from simpleio import map_range +from adafruit_bitmap_font import bitmap_font +from adafruit_lsm6ds.lsm6ds33 import LSM6DS33 +from adafruit_lsm6ds.lsm6ds3trc import LSM6DS3TRC +from adafruit_lsm6ds import Rate, AccelRange +from adafruit_progressbar.progressbar import ProgressBar +from adafruit_display_text.label import Label + +# turns off onboard NeoPixel to conserve battery +clue.pixel.brightness = 0.0 + +# accessing the Clue's accelerometer +sensor = LSM6DS33(board.I2C()) +try: + sensor = LSM6DS33(board.I2C()) +except RuntimeError: + sensor = LSM6DS3TRC(board.I2C()) + +# step goal +step_goal = 10000 + +# onboard button states +a_state = False +b_state = False + +# array to adjust screen brightness +bright_level = [0, 0.5, 1] + +countdown = 0 # variable for the step goal progress bar +clock = 0 # variable used to keep track of time for the steps per hour counter +clock_count = 0 # holds the number of hours that the step counter has been running +clock_check = 0 # holds the result of the clock divided by 3600 seconds (1 hour) +last_step = 0 # state used to properly counter steps +mono = time.monotonic() # time.monotonic() device +mode = 1 # state used to track screen brightness +steps_log = 0 # holds total steps to check for steps per hour +steps_remaining = 0 # holds the remaining steps needed to reach the step goal +sph = 0 # holds steps per hour + +# variables to hold file locations for background and fonts +clue_bgBMP = "/clue_bgBMP.bmp" +small_font = "/fonts/Roboto-Medium-16.bdf" +med_font = "/fonts/Roboto-Bold-24.bdf" +big_font = "/fonts/Roboto-Black-48.bdf" + +# glyphs for fonts +glyphs = b'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-,.: ' + +# loading bitmap fonts +small_font = bitmap_font.load_font(small_font) +small_font.load_glyphs(glyphs) +med_font = bitmap_font.load_font(med_font) +med_font.load_glyphs(glyphs) +big_font = bitmap_font.load_font(big_font) +big_font.load_glyphs(glyphs) + +# creating display and default brightness +clue_display = board.DISPLAY +clue_display.brightness = 0.5 + +# graphics group +clueGroup = displayio.Group() + +# loading bitmap background +clue_bg = displayio.OnDiskBitmap(clue_bgBMP) +clue_tilegrid = displayio.TileGrid(clue_bg, pixel_shader=clue_bg.pixel_shader) +clueGroup.append(clue_tilegrid) + +# creating the ProgressBar object +bar_group = displayio.Group() +prog_bar = ProgressBar(1, 1, 239, 25, bar_color=0x652f8f) +bar_group.append(prog_bar) + +clueGroup.append(bar_group) + +# text for step goal +steps_countdown = Label(small_font, text='%d Steps Remaining' % step_goal, color=clue.WHITE) +steps_countdown.x = 55 +steps_countdown.y = 12 + +# text for steps +text_steps = Label(big_font, text="0 ", color=0xe90e8b) +text_steps.x = 45 +text_steps.y = 70 + +# text for steps per hour +text_sph = Label(med_font, text=" -- ", color=0x29abe2) +text_sph.x = 8 +text_sph.y = 195 + +# adding all text to the display group +clueGroup.append(text_sph) +clueGroup.append(steps_countdown) +clueGroup.append(text_steps) + +# sending display group to the display at startup +clue_display.root_group = clueGroup + +# setting up the accelerometer and pedometer +sensor.accelerometer_range = AccelRange.RANGE_2G +sensor.accelerometer_data_rate = Rate.RATE_26_HZ +sensor.gyro_data_rate = Rate.RATE_SHUTDOWN +sensor.pedometer_enable = True + +while True: + + # button debouncing + if not clue.button_a and not a_state: + a_state = True + if not clue.button_b and not b_state: + b_state = True + + # setting up steps to hold step count + steps = sensor.pedometer_steps + + # creating the data for the ProgressBar + countdown = map_range(steps, 0, step_goal, 0.0, 1.0) + + # actual counting of the steps + # if a step is taken: + if abs(steps-last_step) > 1: + step_time = time.monotonic() + # updates last_step + last_step = steps + # updates the display + text_steps.text = '%d' % steps + clock = step_time - mono + + # logging steps per hour + if clock > 3600: + # gets number of hours to add to total + clock_check = clock / 3600 + # logs the step count as of that hour + steps_log = steps + # adds the hours to get a new hours total + clock_count += round(clock_check) + # divides steps by hours to get steps per hour + sph = steps_log / clock_count + # adds the sph to the display + text_sph.text = '%d' % sph + # resets clock to count to the next hour again + clock = 0 + mono = time.monotonic() + + # adjusting countdown to step goal + prog_bar.progress = float(countdown) + + # displaying countdown to step goal + if step_goal - steps > 0: + steps_remaining = step_goal - steps + steps_countdown.text = '%d Steps Remaining' % steps_remaining + else: + steps_countdown.text = 'Steps Goal Met!' + + # adjusting screen brightness, a button decreases brightness + if clue.button_a and a_state: + mode -= 1 + a_state = False + if mode < 0: + mode = 0 + clue_display.brightness = bright_level[mode] + else: + clue_display.brightness = bright_level[mode] + # b button increases brightness + if clue.button_b and b_state: + mode += 1 + b_state = False + if mode > 2: + mode = 2 + clue_display.brightness = bright_level[mode] + else: + clue_display.brightness = bright_level[mode] + + time.sleep(0.001) diff --git a/Clue_Step_Counter/fonts/Roboto-Black-48.bdf b/CLUE/Clue_Step_Counter/fonts/Roboto-Black-48.bdf similarity index 100% rename from Clue_Step_Counter/fonts/Roboto-Black-48.bdf rename to CLUE/Clue_Step_Counter/fonts/Roboto-Black-48.bdf diff --git a/Clue_Step_Counter/fonts/Roboto-Bold-24.bdf b/CLUE/Clue_Step_Counter/fonts/Roboto-Bold-24.bdf similarity index 100% rename from Clue_Step_Counter/fonts/Roboto-Bold-24.bdf rename to CLUE/Clue_Step_Counter/fonts/Roboto-Bold-24.bdf diff --git a/Clue_Step_Counter/fonts/Roboto-Medium-16.bdf b/CLUE/Clue_Step_Counter/fonts/Roboto-Medium-16.bdf similarity index 100% rename from Clue_Step_Counter/fonts/Roboto-Medium-16.bdf rename to CLUE/Clue_Step_Counter/fonts/Roboto-Medium-16.bdf diff --git a/MIDI_CLUE_BLE_Glove/code.py b/CLUE/MIDI_CLUE_BLE_Glove/code.py old mode 100755 new mode 100644 similarity index 100% rename from MIDI_CLUE_BLE_Glove/code.py rename to CLUE/MIDI_CLUE_BLE_Glove/code.py diff --git a/CLUE/README.md b/CLUE/README.md new file mode 100644 index 000000000..b07a10538 --- /dev/null +++ b/CLUE/README.md @@ -0,0 +1,6 @@ +## CLUE Project Subdirectory + +Adafruit Learning System Guides relating to the Adafruit CLUE learning boards should be +placed in this folder (rather than the top level Learning System repo). + +Please support Open Source software from Adafruit by buying Adafruit hardware diff --git a/CLUE_Egg_Drop/code.py b/CLUE_Egg_Drop/code.py deleted file mode 100644 index aa3f7c171..000000000 --- a/CLUE_Egg_Drop/code.py +++ /dev/null @@ -1,110 +0,0 @@ -# SPDX-FileCopyrightText: 2020 John Park for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -import time -import math -import board -from digitalio import DigitalInOut, Direction, Pull -import pwmio -from adafruit_lsm6ds.lsm6ds33 import LSM6DS33 -from adafruit_lsm6ds import AccelRange, AccelHPF, Rate -from adafruit_display_text import label -import displayio -import terminalio - -button_a = DigitalInOut(board.BUTTON_A) -button_a.direction = Direction.INPUT -button_a.pull = Pull.UP - -splash = displayio.Group() - -# bad egg -BAD_EGG_FILENAME = "broken_egg.bmp" - -# CircuitPython 6 & 7 compatible -begg_file = open(BAD_EGG_FILENAME, "rb") -begg_bmp = displayio.OnDiskBitmap(begg_file) -begg_sprite = displayio.TileGrid( - begg_bmp, - pixel_shader=getattr(begg_bmp, 'pixel_shader', displayio.ColorConverter()) -) - -# # CircuitPython 7+ compatible -# begg_bmp = displayio.OnDiskBitmap(BAD_EGG_FILENAME) -# begg_sprite = displayio.TileGrid(begg_bmp, pixel_shader=begg_bmp.pixel_shader) - -# good egg -GOOD_EGG_FILENAME = "good_egg.bmp" - -# CircuitPython 6 & 7 compatible -gegg_file = open(GOOD_EGG_FILENAME, "rb") -gegg_bmp = displayio.OnDiskBitmap(gegg_file) -gegg_sprite = displayio.TileGrid( - gegg_bmp, - pixel_shader=getattr(gegg_bmp, 'pixel_shader', displayio.ColorConverter()) -) - -# # CircuitPython 7+ compatible -# gegg_bmp = displayio.OnDiskBitmap(GOOD_EGG_FILENAME) -# gegg_sprite = displayio.TileGrid(gegg_bmp, pixel_shader=gegg_bmp.pixel_shader) - -# draw the bad egg! -splash.append(begg_sprite) -# draw the good egg on top -splash.append(gegg_sprite) - -# Draw a label -text_group = displayio.Group(scale=2, x=10, y=220) -text = "Current & Max Acceleration" -text_area = label.Label(terminalio.FONT, text=text, color=0x0000FF) -text_group.append(text_area) # Subgroup for text scaling -splash.append(text_group) - -# display everything so far -board.DISPLAY.root_group = splash - -# connect to the accelerometer -i2c = board.I2C() # uses board.SCL and board.SDA -# i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller -sensor = LSM6DS33(i2c) -# highest range for impacts! -sensor.accelerometer_range = AccelRange.RANGE_16G -# we'll read at about 1KHz -sensor.accelerometer_rate = Rate.RATE_1_66K_HZ -# Instead of raw accelerometer data, we'll read the *change* in acceleration (shock) -sensor.high_pass_filter = AccelHPF.SLOPE -sensor.high_pass_filter_enabled = True - -# and make a lil buzzer -buzzer = pwmio.PWMOut(board.SPEAKER, variable_frequency=True) -buzzer.frequency = 1000 - -max_slope = 0 -egg_ok = True -while True: - # This isn't the acceleration but the SLOPE (change!) in acceleration - x, y, z = sensor.acceleration - # take the vector length by squaring, adding, taking root - slope_g = math.sqrt(x*x + y*y + z*z) / 9.8 # take vector, convert to g - # we'll track the max delta g - - if max_slope < slope_g: - max_slope = slope_g - print(slope_g) - text_area.text = "Max Slope %0.1fg" % max_slope - if max_slope >= 9 and egg_ok: - gegg_sprite.x = 300 - time.sleep(0.1) - egg_ok = False - buzzer.duty_cycle = 2**15 - time.sleep(2) - buzzer.duty_cycle = 0 - continue - - if button_a.value is False and egg_ok is False: - print("Reset") - time.sleep(0.1) # debounce - max_slope = 0 - gegg_sprite.x = 0 - egg_ok = True diff --git a/CLUE_Hand_Wash_Timer/code.py b/CLUE_Hand_Wash_Timer/code.py deleted file mode 100644 index 55644829d..000000000 --- a/CLUE_Hand_Wash_Timer/code.py +++ /dev/null @@ -1,114 +0,0 @@ -# SPDX-FileCopyrightText: 2020 John Park for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -""" -Start a 20 second hand washing timer via proximity sensor. -Countdown the seconds with text and beeps. -Display a bitmaps for waiting and washing modes. -""" - -import time -import board -from adafruit_clue import clue -from adafruit_display_text import label -from adafruit_bitmap_font import bitmap_font -import displayio -import pwmio - -clue.display.brightness = 0.8 -clue_display = displayio.Group() - -# draw the background image -WASH_ON_FILENAME = "wash_on.bmp" - -# CircuitPython 6 & 7 compatible -wash_on_file = open(WASH_ON_FILENAME, "rb") -wash_on_bmp = displayio.OnDiskBitmap(wash_on_file) -wash_on_sprite = displayio.TileGrid( - wash_on_bmp, - pixel_shader=getattr(wash_on_bmp, 'pixel_shader', displayio.ColorConverter()) -) - -# # CircuitPython 7+ compatible -# wash_on_bmp = displayio.OnDiskBitmap(WASH_ON_FILENAME) -# wash_on_sprite = displayio.TileGrid(wash_on_bmp, pixel_shader=wash_on_bmp.pixel_shader) - -clue_display.append(wash_on_sprite) - -# draw the foreground image -WASH_OFF_FILENAME = "wash_off.bmp" - -# CircuitPython 6 & 7 compatible -wash_off_file = open(WASH_OFF_FILENAME, "rb") -wash_off_bmp = displayio.OnDiskBitmap(wash_off_file) -wash_off_sprite = displayio.TileGrid( - wash_off_bmp, - pixel_shader=getattr(wash_off_bmp, 'pixel_shader', displayio.ColorConverter()) -) - -# # CircuitPython 7+ compatible -# wash_off_bmp = displayio.OnDiskBitmap(WASH_OFF_FILENAME) -# wash_off_sprite = displayio.TileGrid(wash_off_bmp, pixel_shader=wash_off_bmp.pixel_shader) - -clue_display.append(wash_off_sprite) - - -# Create text -# first create the group -text_group = displayio.Group() -# Make a label -title_font = bitmap_font.load_font("/font/RacingSansOne-Regular-38.bdf") -title_font.load_glyphs("HandWashTimer".encode('utf-8')) -title_label = label.Label(title_font, text="Hand Wash", color=0x001122) -# Position the label -title_label.x = 10 -title_label.y = 16 -# Append label to group -text_group.append(title_label) - -title2_label = label.Label(title_font, text="Timer", color=0x001122) -# Position the label -title2_label.x = 6 -title2_label.y = 52 -# Append label to group -text_group.append(title2_label) - -timer_font = bitmap_font.load_font("/font/RacingSansOne-Regular-29.bdf") -timer_font.load_glyphs("0123456789ADSWabcdefghijklmnopqrstuvwxyz:!".encode('utf-8')) -timer_label = label.Label(timer_font, text="Wave to start", color=0x4f3ab1) -timer_label.x = 24 -timer_label.y = 100 -text_group.append(timer_label) - -clue_display.append(text_group) -clue.display.root_group = clue_display - -def countdown(seconds): - for i in range(seconds): - buzzer.duty_cycle = 2**15 - timer_label.text = ("Scrub time: {}".format(seconds-i)) - buzzer.duty_cycle = 0 - time.sleep(1) - timer_label.text = ("Done!") - wash_off_sprite.x = 0 - buzzer.duty_cycle = 2**15 - time.sleep(0.3) - buzzer.duty_cycle = 0 - timer_label.x = 24 - timer_label.y = 100 - timer_label.text = ("Wave to start") - -# setup buzzer -buzzer = pwmio.PWMOut(board.SPEAKER, variable_frequency=True) -buzzer.frequency = 1000 - -while True: - # print("Distance: {}".format(clue.proximity)) # use to test the sensor - if clue.proximity > 1: - timer_label.x = 12 - timer_label.y = 226 - timer_label.text = "Scrub Away!" - wash_off_sprite.x = 300 - time.sleep(2) - countdown(20) diff --git a/CLUE_Rock_Paper_Scissors/advanced/code.py b/CLUE_Rock_Paper_Scissors/advanced/code.py deleted file mode 100644 index 9da01840d..000000000 --- a/CLUE_Rock_Paper_Scissors/advanced/code.py +++ /dev/null @@ -1,571 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Kevin J Walters for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -# clue-multi-rpsgame v1.20 -# CircuitPython massively multiplayer rock paper scissors game over Bluetooth LE - -# Tested with CLUE and Circuit Playground Bluefruit Alpha with TFT Gizmo -# using CircuitPython and 5.3.0 - -# copy this file to CLUE/CPB board as code.py - -# MIT License - -# Copyright (c) 2020 Kevin J. Walters - -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. - -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - - -import gc -import os -import random - -from micropython import const -import board -import digitalio - -import neopixel -from adafruit_ble import BLERadio - -# These imports works on CLUE, CPB (and CPX on 5.x) -try: - from audioio import AudioOut -except ImportError: - from audiopwmio import PWMAudioOut as AudioOut - -# RPS module files -from rps_advertisements import JoinGameAdvertisement, \ - RpsEncDataAdvertisement, \ - RpsKeyDataAdvertisement, \ - RpsRoundEndAdvertisement -from rps_audio import SampleJukebox -from rps_comms import broadcastAndReceive, addrToText, MIN_AD_INTERVAL -from rps_crypto import bytesPad, strUnpad, generateOTPadKey, \ - enlargeKey, encrypt, decrypt -from rps_display import RPSDisplay, blankScreen - - -# Look for our name in secrets.py file if present -ble_name = None -try: - from secrets import secrets - ble_name = secrets.get("rps_name") - if ble_name is None: - ble_name = secrets.get("ble_name") - if ble_name is None: - print("INFO: No rps_name or ble_name entry found in secrets dict") -except ImportError: - pass # File is optional, reaching here is not a program error - - -debug = 1 - -def d_print(level, *args, **kwargs): - """A simple conditional print for debugging based on global debug level.""" - if not isinstance(level, int): - print(level, *args, **kwargs) - elif debug >= level: - print(*args, **kwargs) - - -def tftGizmoPresent(): - """Determine if the TFT Gizmo is attached. - The TFT's Gizmo circuitry for backlight features a 10k pull-down resistor. - This attempts to verify the presence of the pull-down to determine - if TFT Gizmo is present. - This is likely to get confused if anything else is connected to pad A3. - Only use this on Circuit Playground Express (CPX) - or Circuit Playground Bluefruit (CPB) boards.""" - present = True - try: - with digitalio.DigitalInOut(board.A3) as backlight_pin: - backlight_pin.pull = digitalio.Pull.UP - present = not backlight_pin.value - except ValueError: - # The Gizmo is already initialised, i.e. showing console output - pass - - return present - - -# Assuming CLUE if it's not a Circuit Playround (Bluefruit) -clue_less = "Circuit Playground" in os.uname().machine - -# Note: difference in pull-up and pull-down -# and logical not use for buttons -if clue_less: - # CPB with TFT Gizmo (240x240) - # from adafruit_circuitplayground import cp # Avoiding to save memory - - # Outputs - if tftGizmoPresent(): - from adafruit_gizmo import tft_gizmo - display = tft_gizmo.TFT_Gizmo() - JG_RX_COL = 0x0000ff - BUTTON_Y_POS = 120 - else: - display = None - JG_RX_COL = 0x000030 # dimmer blue for upward facing CPB NeoPixels - BUTTON_Y_POS = None - - audio_out = AudioOut(board.SPEAKER) - #pixels = cp.pixels - pixels = neopixel.NeoPixel(board.NEOPIXEL, 10) - - # Enable the onboard amplifier for speaker - #cp._speaker_enable.value = True # pylint: disable=protected-access - speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE) - speaker_enable.switch_to_output(value=False) - speaker_enable.value = True - - # Inputs - # buttons reversed if it is used upside-down with Gizmo - _button_a = digitalio.DigitalInOut(board.BUTTON_A) - _button_a.switch_to_input(pull=digitalio.Pull.DOWN) - _button_b = digitalio.DigitalInOut(board.BUTTON_B) - _button_b.switch_to_input(pull=digitalio.Pull.DOWN) - if display is None: - def button_left(): - return _button_a.value - def button_right(): - return _button_b.value - else: - def button_left(): - return _button_b.value - def button_right(): - return _button_a.value - -else: - # CLUE with builtin screen (240x240) - # from adafruit_clue import clue # Avoiding to save memory - - # Outputs - display = board.DISPLAY - audio_out = AudioOut(board.SPEAKER) - #pixels = clue.pixel - pixels = neopixel.NeoPixel(board.NEOPIXEL, 1) - JG_RX_COL = 0x0000ff - BUTTON_Y_POS = 152 - - # Inputs - _button_a = digitalio.DigitalInOut(board.BUTTON_A) - _button_a.switch_to_input(pull=digitalio.Pull.UP) - _button_b = digitalio.DigitalInOut(board.BUTTON_B) - _button_b.switch_to_input(pull=digitalio.Pull.UP) - def button_left(): - return not _button_a.value - def button_right(): - return not _button_b.value - - -blankScreen(display, pixels) - -# Set to True for blue flashing when devices are joining the playing group -JG_FLASH = False - -IMAGE_DIR = "rps/images" -AUDIO_DIR = "rps/audio" - -audio_files = (("searching", "welcome-to", "arena", "ready") - + ("rock", "paper", "scissors") - + ("start-tx", "end-tx", "txing") - + ("rock-scissors", "paper-rock", "scissors-paper") - + ("you-win", "draw", "you-lose", "error") - + ("humiliation", "excellent")) - -gc.collect() -d_print(2, "GC before SJ", gc.mem_free()) -sample = SampleJukebox(audio_out, audio_files, - directory=AUDIO_DIR) -del audio_files # not needed anymore -gc.collect() -d_print(2, "GC after SJ", gc.mem_free()) - -# A lookup table in Dict form for win/lose, each value is a sample name -# Does not need to cater for draw (tie) condition -WAV_VICTORY_NAME = { "rp": "paper-rock", - "pr": "paper-rock", - "ps": "scissors-paper", - "sp": "scissors-paper", - "sr": "rock-scissors", - "rs": "rock-scissors"} - -# This limit is based on displaying names on screen with scale=2 font -MAX_PLAYERS = 8 -# Some code is dependent on these being lower-case -CHOICES = ("rock", "paper", "scissors") - -rps_display = RPSDisplay(display, pixels, - CHOICES, sample, WAV_VICTORY_NAME, - MAX_PLAYERS, BUTTON_Y_POS, - IMAGE_DIR + "/rps-sprites-ind4.bmp", - ble_color=JG_RX_COL) - -# Transmit maximum times in seconds -JG_MSG_TIME_S = 20 -FIRST_MSG_TIME_S = 12 -STD_MSG_TIME_S = 4 -LAST_ACK_TIME_S = 1.5 - - -# Intro screen with audio -rps_display.introductionScreen() - -# Enable the Bluetooth LE radio and set player's name (from secrets.py) -ble = BLERadio() -if ble_name is not None: - ble.name = ble_name - - -game_no = 1 -round_no = 1 -wins = losses = draws = voids = 0 - -# TOTAL_ROUNDS = 5 -TOTAL_ROUNDS = 3 - -CRYPTO_ALGO = "chacha20" -KEY_SIZE = 8 # in bytes -KEY_ENLARGE = 256 // KEY_SIZE // 8 - -# Scoring values -POINTS_WIN = 2 -POINTS_DRAW = 1 - -WIN = const(1) -DRAW = const(2) # AKA tie -LOSE = const(3) -INVALID = const(4) - -def evaluateRound(mine, yours): - """Determine who won the round in this game based on the two strings mine and yours. - Returns WIN, DRAW, LOSE or INVALID for bad input.""" - # Return INVALID if any input is None - try: - mine_lc = mine.lower() - yours_lc = yours.lower() - except AttributeError: - return INVALID - - if mine_lc not in CHOICES or yours_lc not in CHOICES: - return INVALID - - # Both inputs are valid choices if we got this far - # pylint: disable=too-many-boolean-expressions - if mine_lc == yours_lc: - return DRAW - elif (mine_lc == "rock" and yours_lc == "scissors" - or mine_lc == "paper" and yours_lc == "rock" - or mine_lc == "scissors" and yours_lc == "paper"): - return WIN - - return LOSE - - -rps_display.playerListScreen() - -def addPlayer(name, addr_text, address, ad): - # pylint: disable=unused-argument - # address is part of call back - """Add the player name and mac address to players global variable - and the name and rssi (if present) to on-screen list.""" - - rssi = ad.rssi if ad else None - - players.append((name, addr_text)) - rps_display.addPlayer(name, rssi=rssi) - - -# Make a list of all the player's (name, mac address as text) -# where both are strings with this player as first entry -players = [] -my_name = ble.name -rps_display.fadeUpDown("down") -addPlayer(my_name, addrToText(ble.address_bytes), None, None) - - -# These two functions mainly serve to adapt the call back arguments -# to the called functions which do not use them -def jgAdCallbackFlashBLE(_a, _b, _c): - """Used in broadcastAndReceive to flash the NeoPixels - when advertising messages are received.""" - return rps_display.flashBLE() - -def jgEndscanCallback(_a, _b, _c): - """Used in broadcastAndReceive to allow early termination of the scanning - when the left button is pressed. - Button may need to be held down for a second.""" - return button_left() - -# Join Game -gc.collect() -d_print(2, "GC before JG", gc.mem_free()) - -sample.play("searching", loop=True) -rps_display.fadeUpDown("up") -jg_msg = JoinGameAdvertisement(game="RPS") -(_, _, _) = broadcastAndReceive(ble, - jg_msg, - scan_time=JG_MSG_TIME_S, - scan_response_request=True, - ad_cb=(jgAdCallbackFlashBLE - if JG_FLASH - else None), - endscan_cb=jgEndscanCallback, - name_cb=addPlayer) -del _ # To clean-up with GC below -sample.stop() -gc.collect() -d_print(2, "GC after JG", gc.mem_free()) - -# Wait for button release - this stops a long press -# being acted upon in the main loop further down -while button_left(): - pass - -scores = [0] * len(players) -num_other_players = len(players) - 1 - -# Set the advertising interval to the minimum for four or fewer players -# and above that extend value by players multiplied by 7ms -ad_interval = MIN_AD_INTERVAL if len(players) <= 4 else len(players) * 0.007 - -d_print(1, "PLAYERS", players) - -# Sequence numbers - real packets start range between 1-255 inclusive -seq_tx = [1] # The next number to send - -new_round_init = True - -# A nonce by definition must not be reused but here a random key is -# generated per round and this is used once per round so this is ok -static_nonce = bytes(range(12, 0, -1)) - -while True: - if round_no > TOTAL_ROUNDS: - print("Summary: ", - "wins {:d}, losses {:d}," - " draws {:d}, void {:d}\n\n".format(wins, losses, draws, voids)) - - rps_display.showGameResult(players, scores, rounds_tot=TOTAL_ROUNDS) - - # Reset variables for another game - round_no = 1 - wins = losses = draws = voids = 0 - scores = [0] * len(players) - game_no += 1 - - if new_round_init: - rps_display.showGameRound(game_no=game_no, round_no=round_no, rounds_tot=TOTAL_ROUNDS) - # Make a new initial random choice for the player and show it - my_choice_idx = random.randrange(len(CHOICES)) - rps_display.fadeUpDown("down") - rps_display.showChoice(my_choice_idx, - game_no=game_no, round_no=round_no, rounds_tot=TOTAL_ROUNDS, - won_sf=wins, drew_sf=draws, lost_sf=losses) - rps_display.fadeUpDown("up") - new_round_init = False - - if button_left(): - while button_left(): # Wait for button release - pass - my_choice_idx = (my_choice_idx + 1) % len(CHOICES) - rps_display.showChoice(my_choice_idx, - game_no=game_no, round_no=round_no, rounds_tot=TOTAL_ROUNDS, - won_sf=wins, drew_sf=draws, lost_sf=losses) - - if button_right(): - gc.collect() - d_print(2, "GC before comms", gc.mem_free()) - - # This sound cue is really for other players - sample.play("ready") - - my_choice = CHOICES[my_choice_idx] - player_choices = [my_choice] - - # Repeating key four times to make key for ChaCha20 - short_key = generateOTPadKey(KEY_SIZE) - key = enlargeKey(short_key, KEY_ENLARGE) - d_print(3, "KEY", key) - - plain_bytes = bytesPad(my_choice, size=8, pad=0) - cipher_bytes = encrypt(plain_bytes, key, CRYPTO_ALGO, - nonce=static_nonce) - enc_data_msg = RpsEncDataAdvertisement(enc_data=cipher_bytes, - round_no=round_no) - - # Wait for ready sound sample to stop playing - sample.wait() - sample.play("start-tx") - sample.wait() - sample.play("txing", loop=True) - # Players will not be synchronised at this point as they do not - # have to make their choices simultaneously - much longer 12 second - # time to accomodate this - _, enc_data_by_addr, _ = broadcastAndReceive(ble, - enc_data_msg, - RpsEncDataAdvertisement, - RpsKeyDataAdvertisement, - scan_time=FIRST_MSG_TIME_S, - ad_interval=ad_interval, - receive_n=num_other_players, - seq_tx=seq_tx) - - key_data_msg = RpsKeyDataAdvertisement(key_data=short_key, round_no=round_no) - # All of the programs will be loosely synchronised now - _, key_data_by_addr, _ = broadcastAndReceive(ble, - key_data_msg, - RpsEncDataAdvertisement, - RpsKeyDataAdvertisement, - RpsRoundEndAdvertisement, - scan_time=STD_MSG_TIME_S, - ad_interval=ad_interval, - receive_n=num_other_players, - seq_tx=seq_tx, - ads_by_addr=enc_data_by_addr) - del enc_data_by_addr - - # Play end transmit sound while doing next decrypt bit - sample.play("end-tx") - - re_msg = RpsRoundEndAdvertisement(round_no=round_no) - # The round end message is really about acknowledging receipt of - # the key_data_msg by sending a non-critical message with the ack - _, re_by_addr, _ = broadcastAndReceive(ble, - re_msg, - RpsEncDataAdvertisement, - RpsKeyDataAdvertisement, - RpsRoundEndAdvertisement, - scan_time=LAST_ACK_TIME_S, - ad_interval=ad_interval, - receive_n=num_other_players, - seq_tx=seq_tx, - ads_by_addr=key_data_by_addr) - del key_data_by_addr, _ # To allow GC - - # This will have accumulated all the messages for this round - allmsg_by_addr = re_by_addr - del re_by_addr - - # Decrypt results - # If any data is incorrect the opponent_choice is left as None - for p_idx1 in range(1, len(players)): - print("DECRYPT GC", p_idx1, gc.mem_free()) - opponent_name = players[p_idx1][0] - opponent_macaddr = players[p_idx1][1] - opponent_choice = None - opponent_msgs = allmsg_by_addr.get(opponent_macaddr) - if opponent_msgs is None: - opponent_msgs = [] - cipher_ad = cipher_bytes = cipher_round = None - key_ad = key_bytes = key_round = None - # There should be either one or two messges per type - # two occurs when there - for msg_idx in range(len(opponent_msgs)): - if (cipher_ad is None - and isinstance(opponent_msgs[msg_idx][0], - RpsEncDataAdvertisement)): - cipher_ad = opponent_msgs[msg_idx][0] - cipher_bytes = cipher_ad.enc_data - cipher_round = cipher_ad.round_no - elif (key_ad is None - and isinstance(opponent_msgs[msg_idx][0], - RpsKeyDataAdvertisement)): - key_ad = opponent_msgs[msg_idx][0] - key_bytes = key_ad.key_data - key_round = key_ad.round_no - - if cipher_ad and key_ad: - if round_no == cipher_round == key_round: - key = enlargeKey(key_bytes, KEY_ENLARGE) - plain_bytes = decrypt(cipher_bytes, key, CRYPTO_ALGO, - nonce=static_nonce) - opponent_choice = strUnpad(plain_bytes) - else: - print("Received wrong round for {:d} {:d}: {:d} {:d}", - opponent_name, round_no, cipher_round, key_round) - else: - print("Missing packets: RpsEncDataAdvertisement " - "and RpsKeyDataAdvertisement:", cipher_ad, key_ad) - player_choices.append(opponent_choice) - - # Free up some memory by deleting any data that's no longer needed - del allmsg_by_addr - gc.collect() - d_print(2, "GC after comms", gc.mem_free()) - - sample.wait() # Ensure end-tx has completed - - # Chalk up wins and losses - checks this player but also has to - # check other players against each other to calculate all the - # scores for the high score table at the end of game - for p_idx0, (p0_name, _) in enumerate(players[:len(players) - 1]): - for p_idx1, (p1_name, _) in enumerate(players[p_idx0 + 1:], p_idx0 + 1): - # evaluateRound takes text strings for RPS - result = evaluateRound(player_choices[p_idx0], - player_choices[p_idx1]) - - # this_player is used to control incrementing the summary - # for the tally for this local player - this_player = 0 - void = False - if p_idx0 == 0: - this_player = 1 - p0_ch_idx = None - p1_ch_idx = None - try: - p0_ch_idx = CHOICES.index(player_choices[p_idx0]) - p1_ch_idx = CHOICES.index(player_choices[p_idx1]) - except ValueError: - void = True # Ensure this is marked void - print("ERROR", "failed to decode", - player_choices[p_idx0], player_choices[p_idx1]) - - # showPlayerVPlayer takes int index values for RPS - rps_display.showPlayerVPlayer(p0_name, p1_name, p_idx1, - p0_ch_idx, p1_ch_idx, - result == WIN, - result == DRAW, - result == INVALID or void) - - if result == INVALID or void: - voids += this_player - elif result == DRAW: - draws += this_player - scores[p_idx0] += POINTS_DRAW - scores[p_idx1] += POINTS_DRAW - elif result == WIN: - wins += this_player - scores[p_idx0] += POINTS_WIN - else: - losses += this_player - scores[p_idx1] += POINTS_WIN - - d_print(2, - p0_name, player_choices[p_idx0], "vs", - p1_name, player_choices[p_idx1], - "result", result) - - print("Game {:d}, round {:d}, wins {:d}, losses {:d}, draws {:d}, " - "void {:d}".format(game_no, round_no, wins, losses, draws, voids)) - - round_no += 1 - new_round_init = True diff --git a/CLUE_Servo_Barometer/code.py b/CLUE_Servo_Barometer/code.py deleted file mode 100644 index f616f6ccf..000000000 --- a/CLUE_Servo_Barometer/code.py +++ /dev/null @@ -1,109 +0,0 @@ -# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries -# SPDX-License-Identifier: MIT - -import time -import board -import simpleio -import adafruit_bmp280 -import pwmio -import displayio -from adafruit_motor import servo -import terminalio -from adafruit_clue import clue -from adafruit_display_text import label - -# pwm setup for servo -pwm = pwmio.PWMOut(board.D0, duty_cycle=2 ** 15, frequency=50) -gauge = servo.Servo(pwm) - -# bmp280 sensor setup -i2c = board.I2C() # uses board.SCL and board.SDA -# i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller -bmp280 = adafruit_bmp280.Adafruit_BMP280_I2C(i2c) - -# change depending on your location's elevation -NOMINAL_PRESSURE = 1005.94 - -PRESSURE_RANGE = 40 # hPa, expected pressure range variance caused by local weather -PRESSURE_LOW_LIM = NOMINAL_PRESSURE - PRESSURE_RANGE -PRESSURE_HIGH_LIM = NOMINAL_PRESSURE + PRESSURE_RANGE - -# board display -# scaling for terminalio font -display = board.DISPLAY -group = displayio.Group(scale=3) - -# text elements -temp_header = "Temperature:" -press_header = "Pressure:" -temp_text = " ºC" -press_text = " hPa" -font = terminalio.FONT -blue = 0x0000FF -red = 0xFF0000 - -# temperature text elements -temp_label = label.Label(font, text=temp_header, color=red, x=5, y=10) -temp_data = label.Label(font, text=temp_text, color=red, x=5, y=25) - -# pressure text elements -press_label = label.Label(font, text=press_header, color=blue, x=5, y=50) -press_data = label.Label(font, text=press_text, color=blue, x=5, y=65) - -# adding text to display group -group.append(temp_label) -group.append(press_label) -group.append(temp_data) -group.append(press_data) - -display.root_group = group - -# function to convert celcius to fahrenheit -def c_to_f(temp): - temp_f = (temp * 9/5) + 32 - return temp_f - -# function to convert hPa to inHg -def hpa_to_inHg(hPa): - inches_mercury = hPa * 0.02953 - return inches_mercury - -# time.monotonic clock -clock = 0 -# units state -metric_units = False - -while True: - # non-blocking 2 second delay - if (clock + 2) < time.monotonic(): - # map servo range to barometric pressure range - servo_value = simpleio.map_range(bmp280.pressure, - PRESSURE_LOW_LIM, PRESSURE_HIGH_LIM, 180, 0) - # set servo to pressure - gauge.angle = servo_value - # print data for debugging - print("\nTemperature: %0.1f C" % bmp280.temperature) - print("Pressure: %0.1f hPa" % bmp280.pressure) - print(servo_value) - # if metric units... - if metric_units: - # update temp & pressure text in celcius and hPa - temp_data.text = "%0.1f ºC" % bmp280.temperature - press_data.text = "%0.1f hPa" % bmp280.pressure - # if imperial units... - else: - # convert celcius to fahrenheit - temp_fahrenheit = c_to_f(bmp280.temperature) - # convert hPa to inHg - pressure_inHg = hpa_to_inHg(bmp280.pressure) - # update temp & pressure text - temp_data.text = "%0.1f ºF" % temp_fahrenheit - press_data.text = "%0.1f inHg" % pressure_inHg - # reset time.monotonic() clock - clock = time.monotonic() - # if a button is pressed, metric_units is True, show metric - if clue.button_a: - metric_units = True - # if b button is pressed, metric_units is False, show imperial units - if clue.button_b: - metric_units = False diff --git a/CPB_AMS_Gizmo_BLE/code.py b/CPB_AMS_Gizmo_BLE/code.py index cd8788f57..330cb170e 100755 --- a/CPB_AMS_Gizmo_BLE/code.py +++ b/CPB_AMS_Gizmo_BLE/code.py @@ -33,15 +33,8 @@ radio.start_advertising(a) def wrap_in_tilegrid(filename:str): - # CircuitPython 6 & 7 compatible - odb = displayio.OnDiskBitmap(open(filename, "rb")) - return displayio.TileGrid( - odb, pixel_shader=getattr(odb, 'pixel_shader', displayio.ColorConverter()) - ) - - # # CircuitPython 7+ compatible - # odb = displayio.OnDiskBitmap(filename) - # return displayio.TileGrid(odb, pixel_shader=odb.pixel_shader) + odb = displayio.OnDiskBitmap(filename) + return displayio.TileGrid(odb, pixel_shader=odb.pixel_shader) def make_background(width, height, color): color_bitmap = displayio.Bitmap(width, height, 1) diff --git a/CPB_ANCS/code.py b/CPB_ANCS/code.py index 6c93b87a9..f00f360dd 100644 --- a/CPB_ANCS/code.py +++ b/CPB_ANCS/code.py @@ -93,15 +93,8 @@ def check_timeout(self): advertisement.solicited_services.append(AppleNotificationCenterService) def wrap_in_tilegrid(filename:str): - # CircuitPython 6 & 7 compatible - odb = displayio.OnDiskBitmap(open(filename, "rb")) - return displayio.TileGrid( - odb, pixel_shader=getattr(odb, 'pixel_shader', displayio.ColorConverter()) - ) - - # # CircuitPython 7+ compatible - # odb = displayio.OnDiskBitmap(filename) - # return displayio.TileGrid(odb, pixel_shader=odb.pixel_shader) + odb = displayio.OnDiskBitmap(filename) + return displayio.TileGrid(odb, pixel_shader=odb.pixel_shader) display = tft_gizmo.TFT_Gizmo() group = displayio.Group() diff --git a/Cartoon_Character_Clock/song_1.mp3 b/Cartoon_Character_Clock/song_1.mp3 new file mode 100644 index 000000000..e046ba007 Binary files /dev/null and b/Cartoon_Character_Clock/song_1.mp3 differ diff --git a/Cartoon_Character_Clock/song_2.mp3 b/Cartoon_Character_Clock/song_2.mp3 new file mode 100644 index 000000000..e7d70e82b Binary files /dev/null and b/Cartoon_Character_Clock/song_2.mp3 differ diff --git a/Cheekmate/CircuitPython/code.py b/Cheekmate/CircuitPython/code.py index 2f3078432..cd1a88cd4 100755 --- a/Cheekmate/CircuitPython/code.py +++ b/Cheekmate/CircuitPython/code.py @@ -6,10 +6,9 @@ CHEEKMATE: secret message receiver using WiFi, Adafruit IO and a haptic buzzer. Periodically polls an Adafruit IO dashboard, converting new messages to Morse code. - -secrets.py file must be present and contain WiFi & Adafruit IO credentials. """ +from os import getenv import gc import time import ssl @@ -23,11 +22,20 @@ import wifi from adafruit_io.adafruit_io import IO_HTTP -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) # CONFIGURABLE GLOBALS ----------------------------------------------------- @@ -154,10 +162,10 @@ def play(string): # WIFI CONNECT ------------------------------------------------------------- try: - print("Connecting to {}...".format(secrets["ssid"]), end="") - wifi.radio.connect(secrets["ssid"], secrets["password"]) + print(f"Connecting to {ssid}...") + wifi.radio.connect(ssid, password) print("OK") - print("IP:", wifi.radio.ipv4_address) + print(f"IP: {wifi.radio.ipv4_address}") pool = socketpool.SocketPool(wifi.radio) requests = adafruit_requests.Session(pool, ssl.create_default_context()) @@ -169,8 +177,6 @@ def play(string): # ADAFRUIT IO INITIALIZATION ----------------------------------------------- -aio_username = secrets["aio_username"] -aio_key = secrets["aio_key"] io = IO_HTTP(aio_username, aio_key, requests) # SUCCESSFUL STARTUP, PROCEED INTO MAIN LOOP ------------------------------- diff --git a/CircuitPython_ESP32_Camera/esp32-kaluga-onionskin-gif/code.py b/CircuitPython_ESP32_Camera/esp32-kaluga-onionskin-gif/code.py index 31423f6e8..4db78ec64 100644 --- a/CircuitPython_ESP32_Camera/esp32-kaluga-onionskin-gif/code.py +++ b/CircuitPython_ESP32_Camera/esp32-kaluga-onionskin-gif/code.py @@ -52,7 +52,9 @@ import board import busio import bitmaptools +import fourwire import displayio +import busdisplay import sdcardio import storage import gifio @@ -68,7 +70,7 @@ def record_pressed(): displayio.release_displays() spi = busio.SPI(MOSI=board.LCD_MOSI, clock=board.LCD_CLK) -display_bus = displayio.FourWire( +display_bus = fourwire.FourWire( spi, command=board.LCD_D_C, chip_select=board.LCD_CS, @@ -101,7 +103,7 @@ def record_pressed(): b"\x29\x80\x78" # Display on then delay 0x78 (120ms) ) -display = displayio.Display(display_bus, _INIT_SEQUENCE, width=320, height=240) +display = busdisplay.BusDisplay(display_bus, _INIT_SEQUENCE, width=320, height=240) sd_spi = busio.SPI(clock=board.IO18, MOSI=board.IO14, MISO=board.IO17) sd_cs = board.IO12 @@ -193,7 +195,7 @@ def take_stop_motion_gif(n_frames=10, replay_frame_time=.3): writer.add_frame(frame, replay_frame_time) for i in range(1, n_frames): print(f"{i}/{n_frames}") - old_frame.blit(0, 0, frame, x1=0, y1=0, x2=cam.width, y2=cam.height) + bitmaptools.blit(old_frame, frame, 0, 0, x1=0, y1=0, x2=cam.width, y2=cam.height) frame = wait_record_pressed_update_display(False, cam) writer.add_frame(frame, replay_frame_time) print("done") diff --git a/CircuitPython_Flying_Toasters/code.py b/CircuitPython_Flying_Toasters/code.py index aa8fa3696..5e5b7ac9b 100644 --- a/CircuitPython_Flying_Toasters/code.py +++ b/CircuitPython_Flying_Toasters/code.py @@ -21,6 +21,7 @@ from random import seed, randint import board import displayio +import fourwire from adafruit_st7789 import ST7789 import adafruit_imageload @@ -63,7 +64,7 @@ def make_display(): spi.configure(baudrate=24000000) # Configure SPI for 24MHz spi.unlock() displayio.release_displays() - display_bus = displayio.FourWire(spi, command=board.D7, chip_select=board.D10, reset=board.D9) + display_bus = fourwire.FourWire(spi, command=board.D7, chip_select=board.D10, reset=board.D9) return ST7789(display_bus, width=240, height=240, rowstart=80, auto_refresh=True) diff --git a/CircuitPython_GetSuperpower_PicoW_OpenAI/code.py b/CircuitPython_GetSuperpower_PicoW_OpenAI/code.py index 3768736c3..704adcf8f 100644 --- a/CircuitPython_GetSuperpower_PicoW_OpenAI/code.py +++ b/CircuitPython_GetSuperpower_PicoW_OpenAI/code.py @@ -7,6 +7,7 @@ import board import displayio +import i2cdisplaybus import digitalio import keypad import socketpool @@ -75,7 +76,7 @@ # STEMMA I2C on picowbell i2c = board.STEMMA_I2C() -display_bus = displayio.I2CDisplay(i2c, device_address=0x3D, reset=oled_reset) +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3D, reset=oled_reset) WIDTH = 128 HEIGHT = 64 diff --git a/CircuitPython_JEplayer_mp3/code.py b/CircuitPython_JEplayer_mp3/code.py index d4d57c64c..67992e192 100644 --- a/CircuitPython_JEplayer_mp3/code.py +++ b/CircuitPython_JEplayer_mp3/code.py @@ -38,7 +38,7 @@ import adafruit_bitmap_font.bitmap_font import adafruit_display_text.label -from adafruit_progressbar import ProgressBar +from adafruit_progressbar.horizontalprogressbar import HorizontalProgressBar import sdcardio import analogjoy import audioio @@ -75,9 +75,12 @@ class PlaybackDisplay: def __init__(self): self.group = displayio.Group() self.glyph_width, self.glyph_height = font.get_bounding_box()[:2] - self.pbar = ProgressBar(0, 0, board.DISPLAY.width, - self.glyph_height*2, bar_color=0x0000ff, - outline_color=0x333333, stroke=1) + self.pbar = HorizontalProgressBar((0, 0), + (board.DISPLAY.width, self.glyph_height*2), + min_value = 0.0, max_value = 1.0, + bar_color=0x0000ff, + outline_color=0x333333, + fill_color=0x000000) self.iconbar = icons.IconBar() self.iconbar.group.y = 1000 for i in range(5, 8): @@ -115,11 +118,11 @@ def text(self, text): @property def progress(self): """The fraction of progress through the current track""" - return self.pbar.progress + return self.pbar.value @progress.setter def progress(self, frac): - self.pbar.progress = frac + self.pbar.value = frac def set_bitmap(self, candidates): """Find and use a background from among candidates, or else the fallback bitmap""" @@ -127,32 +130,16 @@ def set_bitmap(self, candidates): if i == self._bitmap_filename: return # Already loaded - # CircuitPython 6 & 7 compatible try: - bitmap_file = open(i, 'rb') + bitmap = displayio.OnDiskBitmap(i) except OSError: continue - bitmap = displayio.OnDiskBitmap(bitmap_file) self._bitmap_filename = i # Create a TileGrid to hold the bitmap self.tile_grid = displayio.TileGrid( - bitmap, - pixel_shader=getattr( - bitmap, "pixel_shader", displayio.ColorConverter() - ), + bitmap, pixel_shader=bitmap.pixel_shader ) - # # CircuitPython 7+ compatible - # try: - # bitmap = displayio.OnDiskBitmap(i) - # except OSError: - # continue - # self._bitmap_filename = i - # # Create a TileGrid to hold the bitmap - # self.tile_grid = displayio.TileGrid( - # bitmap, pixel_shader=bitmap.pixel_shader - # ) - # Add the TileGrid to the Group if len(self.group) == 0: self.group.append(self.tile_grid) diff --git a/CircuitPython_JEplayer_mp3/rsrc/background.bmp b/CircuitPython_JEplayer_mp3/rsrc/background.bmp index 8922329a4..f0e9b0cce 100644 Binary files a/CircuitPython_JEplayer_mp3/rsrc/background.bmp and b/CircuitPython_JEplayer_mp3/rsrc/background.bmp differ diff --git a/CircuitPython_KeyPad_Calculator/code/code.py b/CircuitPython_KeyPad_Calculator/code/code.py index 1b6d58b8d..67fce4c12 100644 --- a/CircuitPython_KeyPad_Calculator/code/code.py +++ b/CircuitPython_KeyPad_Calculator/code/code.py @@ -4,6 +4,7 @@ import board import displayio +import i2cdisplaybus import keypad import adafruit_displayio_sh1107 from adafruit_hid.keyboard import Keyboard @@ -57,7 +58,7 @@ def lookup(layer, key_number): # Use for I2C i2c = board.I2C() # uses board.SCL and board.SDA # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller -display_bus = displayio.I2CDisplay(i2c, device_address=0x3C) +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3C) # SH1107 is vertically oriented 64x128 WIDTH = 128 diff --git a/CircuitPython_Knob_Sketcher/feather_sketcher/code.py b/CircuitPython_Knob_Sketcher/feather_sketcher/code.py index 789e1331b..ee1d1567e 100755 --- a/CircuitPython_Knob_Sketcher/feather_sketcher/code.py +++ b/CircuitPython_Knob_Sketcher/feather_sketcher/code.py @@ -9,6 +9,7 @@ import time import board import displayio +import fourwire import digitalio import analogio import adafruit_ili9341 @@ -55,7 +56,7 @@ tft_cs = board.D9 tft_dc = board.D10 tft_rst = board.D6 -display_bus = displayio.FourWire( +display_bus = fourwire.FourWire( spi, command=tft_dc, chip_select=tft_cs, reset=tft_rst ) display = adafruit_ili9341.ILI9341(display_bus, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT) diff --git a/CircuitPython_LED_Sand_Hourglass/hourglass/code.py b/CircuitPython_LED_Sand_Hourglass/hourglass/code.py index 908fd7be9..57f235326 100755 --- a/CircuitPython_LED_Sand_Hourglass/hourglass/code.py +++ b/CircuitPython_LED_Sand_Hourglass/hourglass/code.py @@ -4,7 +4,6 @@ import time import board -import adafruit_lsm6ds.lsm6ds33 from adafruit_ht16k33 import matrix import matrixsand @@ -14,8 +13,13 @@ i2c = board.I2C() # uses board.SCL and board.SDA # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller -# the accelo -accelo = adafruit_lsm6ds.lsm6ds33.LSM6DS33(i2c) +# check for LSM6DS33 or LSM6DS3TR-C (Adafruit Feather Sense) +try: + from adafruit_lsm6ds.lsm6ds33 import LSM6DS33 as LSM6DS # pylint: disable=unused-import + accelo = LSM6DS(i2c) +except RuntimeError: + from adafruit_lsm6ds.lsm6ds3 import LSM6DS3 as LSM6DS # pylint: disable=unused-import + accelo = LSM6DS(i2c) # the matrices m1 = matrix.Matrix8x8(i2c, 0x70) diff --git a/CircuitPython_LED_Sand_Hourglass/single_matrix/code.py b/CircuitPython_LED_Sand_Hourglass/single_matrix/code.py index b3c64fc80..62055dcc6 100755 --- a/CircuitPython_LED_Sand_Hourglass/single_matrix/code.py +++ b/CircuitPython_LED_Sand_Hourglass/single_matrix/code.py @@ -4,7 +4,6 @@ import time import board -import adafruit_lsm6ds.lsm6ds33 from adafruit_ht16k33 import matrix import matrixsand @@ -14,8 +13,13 @@ i2c = board.I2C() # uses board.SCL and board.SDA # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller -# the accelo -accelo = adafruit_lsm6ds.lsm6ds33.LSM6DS33(i2c) +# check for LSM6DS33 or LSM6DS3TR-C (Adafruit Feather Sense) +try: + from adafruit_lsm6ds.lsm6ds33 import LSM6DS33 as LSM6DS # pylint: disable=unused-import + accelo = LSM6DS(i2c) +except RuntimeError: + from adafruit_lsm6ds.lsm6ds3 import LSM6DS3 as LSM6DS # pylint: disable=unused-import + accelo = LSM6DS(i2c) # the matrix matrix = matrix.Matrix8x8(i2c, 0x70) diff --git a/CircuitPython_Logger/.circuitpython.skip b/CircuitPython_Logger/.circuitpython.skip deleted file mode 100644 index 42c98ade8..000000000 --- a/CircuitPython_Logger/.circuitpython.skip +++ /dev/null @@ -1,4 +0,0 @@ -CircuitPython_Logger/ble_handler.py 16: Bad option value 'missing-super-argument' (bad-option-value) -CircuitPython_Logger/uart_handler.py 16: Bad option value 'missing-super-argument' (bad-option-value) -CircuitPython_Logger/file_handler.py 15: Bad option value 'missing-super-argument' (bad-option-value) -CircuitPython_Logger/aio_handler.py 15: Bad option value 'missing-super-argument' (bad-option-value) diff --git a/CircuitPython_Logger/aio_handler/code.py b/CircuitPython_Logger/aio_handler/code.py deleted file mode 100644 index 704f5660d..000000000 --- a/CircuitPython_Logger/aio_handler/code.py +++ /dev/null @@ -1,49 +0,0 @@ -# SPDX-FileCopyrightText: 2018 Dave Astels for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -""" -Adafruit IO based message handler for CircuitPython logging. - -Adafruit invests time and resources providing this open source code. -Please support Adafruit and open source hardware by purchasing -products from Adafruit! - -Written by Dave Astels for Adafruit Industries -Copyright (c) 2018 Adafruit Industries -Licensed under the MIT license. - -All text above must be included in any redistribution. -""" - -from adafruit_portalbase import PortalBase - -# Example: -# -# from aio_handler import AIOHandler -# import adafruit_logging as logging -# l = logging.getLogger('aio') -# # Pass in the device object based on portal_base -# # (Funhouse, PyPortal, MagTag, etc) as the 2nd parameter -# l.addHandler(AIOHandler('test', portal_device)) -# l.level = logging.ERROR -# l.error("test") - -from adafruit_logging import Handler - -class AIOHandler(Handler): - - def __init__(self, name, portal_device): - """Create an instance.""" - self._log_feed_name=f"{name}-logging" - if not issubclass(type(portal_device), PortalBase): - raise TypeError("portal_device must be a PortalBase or subclass of PortalBase") - self._portal_device = portal_device - - - def emit(self, record): - """Generate the message and write it to the AIO Feed. - - :param record: The record (message object) to be logged - """ - self._portal_device.push_to_io(self._log_feed_name, self.format(record)) diff --git a/CircuitPython_Logger/aio_test/aio_handler.py b/CircuitPython_Logger/aio_test/aio_handler.py new file mode 100644 index 000000000..936f38821 --- /dev/null +++ b/CircuitPython_Logger/aio_test/aio_handler.py @@ -0,0 +1,40 @@ +# SPDX-FileCopyrightText: 2018 Dave Astels for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +Adafruit IO based message handler for CircuitPython logging. + +Adafruit invests time and resources providing this open source code. +Please support Adafruit and open source hardware by purchasing +products from Adafruit! + +Written by Dave Astels for Adafruit Industries +Copyright (c) 2018 Adafruit Industries +Licensed under the MIT license. + +All text above must be included in any redistribution. +""" + +from adafruit_portalbase import PortalBase +from adafruit_logging import Handler, NOTSET + + +class AIOHandler(Handler): + + def __init__(self, name, portal_device, level: int = NOTSET): + """Create an instance.""" + super().__init__(level) + self._log_feed_name = f"{name}-logging" + if not issubclass(type(portal_device), PortalBase): + raise TypeError( + "portal_device must be a PortalBase or subclass of PortalBase" + ) + self._portal_device = portal_device + + def emit(self, record): + """Generate the message and write it to the AIO Feed. + + :param record: The record (message object) to be logged + """ + self._portal_device.push_to_io(self._log_feed_name, self.format(record)) diff --git a/CircuitPython_Logger/aio_test/code.py b/CircuitPython_Logger/aio_test/code.py index faa78fa7c..fb3f38535 100644 --- a/CircuitPython_Logger/aio_test/code.py +++ b/CircuitPython_Logger/aio_test/code.py @@ -8,27 +8,26 @@ from aio_handler import AIOHandler import adafruit_logging as logging -device=PyPortal() +device = PyPortal() -l = logging.getLogger('aio') -l.addHandler(AIOHandler('test', device)) +l = logging.getLogger("aio") +l.addHandler(AIOHandler("test", device)) -def go(): - while True: - t = random.randint(1, 5) - if t == 1: - print('debug') - l.debug("debug message: %d", random.randint(0, 1000)) - elif t == 2: - print('info') - l.info("info message: %d", random.randint(0, 1000)) - elif t == 3: - print('warning') - l.warning("warning message: %d", random.randint(0, 1000)) - elif t == 4: - print('error') - l.error("error message: %d", random.randint(0, 1000)) - elif t == 5: - print('critical') - l.critical("critical message: %d", random.randint(0, 1000)) - time.sleep(5.0 + (random.random() * 5.0)) +while True: + t = random.randint(1, 5) + if t == 1: + print("debug") + l.debug("debug message: %d", random.randint(0, 1000)) + elif t == 2: + print("info") + l.info("info message: %d", random.randint(0, 1000)) + elif t == 3: + print("warning") + l.warning("warning message: %d", random.randint(0, 1000)) + elif t == 4: + print("error") + l.error("error message: %d", random.randint(0, 1000)) + elif t == 5: + print("critical") + l.critical("critical message: %d", random.randint(0, 1000)) + time.sleep(5.0 + (random.random() * 5.0)) diff --git a/CircuitPython_Logger/ble_handler/code.py b/CircuitPython_Logger/ble_handler/code.py deleted file mode 100644 index 9650bc05b..000000000 --- a/CircuitPython_Logger/ble_handler/code.py +++ /dev/null @@ -1,50 +0,0 @@ -# SPDX-FileCopyrightText: 2019 Dave Astels for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -""" -BLE based message handler for CircuitPython logging. - -Adafruit invests time and resources providing this open source code. -Please support Adafruit and open source hardware by purchasing -products from Adafruit! - -Written by Dave Astels for Adafruit Industries -Copyright (c) 2018 Adafruit Industries -Licensed under the MIT license. - -All text above must be included in any redistribution. -""" - - -from adafruit_logging import Handler -from adafruit_ble.uart import UARTServer - -class BLEHandler(Handler): - """Send logging output to the BLE uart port.""" - - def __init__(self): - """Create an instance. - - :param uart: the busio.UART instance to which to write messages - """ - self._advertising_now = False - self._uart = UARTServer() - self._uart.start_advertising() - - def format(self, record): - """Generate a string to log. - - :param record: The record (message object) to be logged - """ - return super().format(record) + '\r\n' - - def emit(self, record): - """Generate the message and write it to the UART. - - :param record: The record (message object) to be logged - """ - while not self._uart.connected: - pass - data = bytes(self.format(record), 'utf-8') - self._uart.write(data) diff --git a/CircuitPython_Logger/ble_test/ble_handler.py b/CircuitPython_Logger/ble_test/ble_handler.py new file mode 100644 index 000000000..3e8aa7510 --- /dev/null +++ b/CircuitPython_Logger/ble_test/ble_handler.py @@ -0,0 +1,55 @@ +# SPDX-FileCopyrightText: 2019 Dave Astels for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +BLE based message handler for CircuitPython logging. + +Adafruit invests time and resources providing this open source code. +Please support Adafruit and open source hardware by purchasing +products from Adafruit! + +Written by Dave Astels for Adafruit Industries +Copyright (c) 2018 Adafruit Industries +Licensed under the MIT license. + +All text above must be included in any redistribution. +""" + + +from adafruit_logging import Handler, NOTSET + +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from adafruit_ble.services.nordic import UARTService + + +class BLEHandler(Handler): + """Send logging output to the BLE uart port.""" + + def __init__(self, level: int = NOTSET): + """Create an instance. + + :param uart: the busio.UART instance to which to write messages + """ + super().__init__(level) + self._advertising_now = False + ble = BLERadio() + self._uart = UARTService() + self._advertisement = ProvideServicesAdvertisement(self._uart) + ble.start_advertising(self._advertisement) + + def format(self, record): + """Generate a string to log. + + :param record: The record (message object) to be logged + """ + return super().format(record) + "\r\n" + + def emit(self, record): + """Generate the message and write it to the UART. + + :param record: The record (message object) to be logged + """ + data = bytes(self.format(record), "utf-8") + self._uart.write(data) diff --git a/CircuitPython_Logger/ble_test/code.py b/CircuitPython_Logger/ble_test/code.py index 0b0938064..77d11eb7a 100644 --- a/CircuitPython_Logger/ble_test/code.py +++ b/CircuitPython_Logger/ble_test/code.py @@ -7,26 +7,25 @@ from ble_handler import BLEHandler import adafruit_logging as logging -l = logging.getLogger('ble') +l = logging.getLogger("ble") l.addHandler(BLEHandler()) -def go(): - while True: - t = random.randint(1, 5) - if t == 1: - print('debug') - l.debug("%d", random.randint(0, 1000)) - elif t == 2: - print('info') - l.info("%d", random.randint(0, 1000)) - elif t == 3: - print('warning') - l.warning("%d", random.randint(0, 1000)) - elif t == 4: - print('error') - l.error("%d", random.randint(0, 1000)) - elif t == 5: - print('critical') - l.critical(" %d", random.randint(0, 1000)) - time.sleep(5.0 + (random.random() * 5.0)) +while True: + t = random.randint(1, 5) + if t == 1: + print("debug") + l.debug("%d", random.randint(0, 1000)) + elif t == 2: + print("info") + l.info("%d", random.randint(0, 1000)) + elif t == 3: + print("warning") + l.warning("%d", random.randint(0, 1000)) + elif t == 4: + print("error") + l.error("%d", random.randint(0, 1000)) + elif t == 5: + print("critical") + l.critical(" %d", random.randint(0, 1000)) + time.sleep(5.0 + (random.random() * 5.0)) diff --git a/CircuitPython_Logger/file_test/code.py b/CircuitPython_Logger/file_test/code.py index 2ec9ce59a..14e8f7fb6 100644 --- a/CircuitPython_Logger/file_test/code.py +++ b/CircuitPython_Logger/file_test/code.py @@ -21,25 +21,24 @@ vfs = storage.VfsFat(sdcard) storage.mount(vfs, "/sd") -l = logging.getLogger('file') -l.addHandler(logging.FileHandler('/sd/test.txt')) +l = logging.getLogger("file") +l.addHandler(logging.FileHandler("/sd/test.txt")) -def go(): - while True: - t = random.randint(1, 5) - if t == 1: - print('debug') - l.debug("debug message: %d", random.randint(0, 1000)) - elif t == 2: - print('info') - l.info("info message: %d", random.randint(0, 1000)) - elif t == 3: - print('warning') - l.warning("warning message: %d", random.randint(0, 1000)) - elif t == 4: - print('error') - l.error("error message: %d", random.randint(0, 1000)) - elif t == 5: - print('critical') - l.critical("critical message: %d", random.randint(0, 1000)) - time.sleep(5.0 + (random.random() * 5.0)) +while True: + t = random.randint(1, 5) + if t == 1: + print("debug") + l.debug("debug message: %d", random.randint(0, 1000)) + elif t == 2: + print("info") + l.info("info message: %d", random.randint(0, 1000)) + elif t == 3: + print("warning") + l.warning("warning message: %d", random.randint(0, 1000)) + elif t == 4: + print("error") + l.error("error message: %d", random.randint(0, 1000)) + elif t == 5: + print("critical") + l.critical("critical message: %d", random.randint(0, 1000)) + time.sleep(5.0 + (random.random() * 5.0)) diff --git a/CircuitPython_Logger/uart_handler/code.py b/CircuitPython_Logger/uart_handler/code.py index 39b515ce9..b4932f45b 100644 --- a/CircuitPython_Logger/uart_handler/code.py +++ b/CircuitPython_Logger/uart_handler/code.py @@ -1,57 +1,13 @@ # SPDX-FileCopyrightText: 2018 Dave Astels for Adafruit Industries # # SPDX-License-Identifier: MIT - -""" -UART based message handler for CircuitPython logging. - -Adafruit invests time and resources providing this open source code. -Please support Adafruit and open source hardware by purchasing -products from Adafruit! - -Written by Dave Astels for Adafruit Industries -Copyright (c) 2018 Adafruit Industries -Licensed under the MIT license. - -All text above must be included in any redistribution. -""" - - -# Example: -# -# import board -# import busio -# from uart_handler import UartHandler -# import adafruit_logging as logging -# -# uart = busio.UART(board.TX, board.RX, baudrate=115200) -# logger = logging.getLogger('uart') -# logger.addHandler(UartHandler(uart)) -# logger.level = logging.INFO -# logger.info('testing') - -from adafruit_logging import Handler - -class UartHandler(Handler): - """Send logging output to a serial port.""" - - def __init__(self, uart): - """Create an instance. - - :param uart: the busio.UART instance to which to write messages - """ - self._uart = uart - - def format(self, record): - """Generate a string to log. - - :param record: The record (message object) to be logged - """ - return super().format(record) + '\r\n' - - def emit(self, record): - """Generate the message and write it to the UART. - - :param record: The record (message object) to be logged - """ - self._uart.write(bytes(self.format(record), 'utf-8')) +import board +import busio +from uart_handler import UartHandler +import adafruit_logging as logging + +uart = busio.UART(board.TX, board.RX, baudrate=115200) +logger = logging.getLogger("test") +logger.addHandler(UartHandler(uart)) +logger.setLevel(logging.INFO) +logger.info("testing") diff --git a/CircuitPython_Logger/uart_handler/uart_handler.py b/CircuitPython_Logger/uart_handler/uart_handler.py new file mode 100644 index 000000000..9d743a009 --- /dev/null +++ b/CircuitPython_Logger/uart_handler/uart_handler.py @@ -0,0 +1,46 @@ +# SPDX-FileCopyrightText: 2018 Dave Astels for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +UART based message handler for CircuitPython logging. + +Adafruit invests time and resources providing this open source code. +Please support Adafruit and open source hardware by purchasing +products from Adafruit! + +Written by Dave Astels for Adafruit Industries +Copyright (c) 2018 Adafruit Industries +Licensed under the MIT license. + +All text above must be included in any redistribution. +""" + + +from adafruit_logging import Handler, NOTSET + + +class UartHandler(Handler): + """Send logging output to a serial port.""" + + def __init__(self, uart, level: int = NOTSET): + """Create an instance. + + :param uart: the busio.UART instance to which to write messages + """ + super().__init__(level) + self._uart = uart + + def format(self, record): + """Generate a string to log. + + :param record: The record (message object) to be logged + """ + return super().format(record) + "\r\n" + + def emit(self, record): + """Generate the message and write it to the UART. + + :param record: The record (message object) to be logged + """ + self._uart.write(bytes(self.format(record), "utf-8")) diff --git a/CircuitPython_OLED_Watch/code.py b/CircuitPython_OLED_Watch/code.py index 247c8845c..7b9a4a7da 100755 --- a/CircuitPython_OLED_Watch/code.py +++ b/CircuitPython_OLED_Watch/code.py @@ -4,6 +4,7 @@ import board import displayio +import i2cdisplaybus import adafruit_displayio_ssd1306 import terminalio import adafruit_ds3231 @@ -17,7 +18,7 @@ i2c = board.I2C() # uses board.SCL and board.SDA # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller -display_bus = displayio.I2CDisplay(i2c, device_address=0x3c) +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3c) oled = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32) rtc = adafruit_ds3231.DS3231(i2c) diff --git a/CircuitPython_RGBMatrix/fruit/code.py b/CircuitPython_RGBMatrix/fruit/code.py index f63b72bd5..49df8a223 100644 --- a/CircuitPython_RGBMatrix/fruit/code.py +++ b/CircuitPython_RGBMatrix/fruit/code.py @@ -25,14 +25,8 @@ filename = "emoji.bmp" -# CircuitPython 6 & 7 compatible -bitmap_file = open(filename, 'rb') -bitmap = displayio.OnDiskBitmap(bitmap_file) -pixel_shader = getattr(bitmap, 'pixel_shader', displayio.ColorConverter()) - -# # CircuitPython 7+ compatible -# bitmap = displayio.OnDiskBitmap(filename) -# pixel_shader = bitmap.pixel_shader +bitmap = displayio.OnDiskBitmap(filename) +pixel_shader = bitmap.pixel_shader # Each wheel can be in one of three states: STOPPED, RUNNING, BRAKING = range(3) diff --git a/CircuitPython_RGBMatrix/tiled/code.py b/CircuitPython_RGBMatrix/tiled/code.py index 7c63d0343..7273d34af 100755 --- a/CircuitPython_RGBMatrix/tiled/code.py +++ b/CircuitPython_RGBMatrix/tiled/code.py @@ -46,24 +46,14 @@ # Load BMP image, create Group and TileGrid to hold it FILENAME = "wales.bmp" -# CircuitPython 6 & 7 compatible -BITMAP = displayio.OnDiskBitmap(open(FILENAME, "rb")) +BITMAP = displayio.OnDiskBitmap(FILENAME) TILEGRID = displayio.TileGrid( BITMAP, - pixel_shader=getattr(BITMAP, 'pixel_shader', displayio.ColorConverter()), + pixel_shader=BITMAP.pixel_shader, tile_width=BITMAP.width, tile_height=BITMAP.height ) -# # CircuitPython 7+ compatible -# BITMAP = displayio.OnDiskBitmap(FILENAME) -# TILEGRID = displayio.TileGrid( -# BITMAP, -# pixel_shader=BITMAP.pixel_shader, -# tile_width=BITMAP.width, -# tile_height=BITMAP.height -# ) - GROUP = displayio.Group() GROUP.append(TILEGRID) DISPLAY.root_group = GROUP diff --git a/CircuitPython_Scrolling_Clouds/code.py b/CircuitPython_Scrolling_Clouds/code.py index b3e3d67c2..adf36b942 100644 --- a/CircuitPython_Scrolling_Clouds/code.py +++ b/CircuitPython_Scrolling_Clouds/code.py @@ -21,6 +21,7 @@ from random import seed, randint import board import displayio +import fourwire from adafruit_st7789 import ST7789 import adafruit_imageload @@ -54,7 +55,7 @@ def make_display(): spi.unlock() displayio.release_displays() - display_bus = displayio.FourWire(spi, command=board.D7, chip_select=board.D10, reset=board.D9) + display_bus = fourwire.FourWire(spi, command=board.D7, chip_select=board.D10, reset=board.D9) return ST7789(display_bus, width=240, height=240, rowstart=80, auto_refresh=True) diff --git a/CircuitPython_Sip_and_Puff/puff_detector.py b/CircuitPython_Sip_and_Puff/puff_detector.py index 855c64983..145a5f312 100644 --- a/CircuitPython_Sip_and_Puff/puff_detector.py +++ b/CircuitPython_Sip_and_Puff/puff_detector.py @@ -10,6 +10,7 @@ from adafruit_display_text import label from displayio import Group import displayio +import i2cdisplaybus import adafruit_displayio_ssd1306 import adafruit_lps35hw @@ -94,7 +95,7 @@ def _init_stuff(self): displayio.release_displays() i2c = board.I2C() - display_bus = displayio.I2CDisplay(i2c, device_address=0x3D) + display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3D) self.display = adafruit_displayio_ssd1306.SSD1306( display_bus, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT ) diff --git a/CircuitPython_TVBGone/gemma_main.py b/CircuitPython_TVBGone/gemma_main.py new file mode 100644 index 000000000..097485c5c --- /dev/null +++ b/CircuitPython_TVBGone/gemma_main.py @@ -0,0 +1,62 @@ +# SPDX-FileCopyrightText: 2019 Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# Gemma M0 version of TVBgone +# This will NOT work with CircuitPython 7 and later +# as PulseOut is no longer available on Gemma M0 +# Here for educational/research purposes only + +import array +import time + +import adafruit_dotstar +import board +import pulseio +from digitalio import DigitalInOut, Direction + +# pylint: disable=eval-used + +pixel = adafruit_dotstar.DotStar( + board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2) +pixel.fill((0, 0, 0)) + +# Button to see output debug +led = DigitalInOut(board.D13) +led.direction = Direction.OUTPUT + +pwm = pulseio.PWMOut(board.A2, frequency=38000, + duty_cycle=2 ** 15, variable_frequency=True) +pulse = pulseio.PulseOut(pwm) + +time.sleep(0.5) # Give a half second before starting + +# gooooo! +f = open("/codes.txt", "r") +for line in f: + code = eval(line) + print(code) + pwm.frequency = code['freq'] + led.value = True + # If this is a repeating code, extract details + try: + repeat = code['repeat'] + delay = code['repeat_delay'] + except KeyError: # by default, repeat once only! + repeat = 1 + delay = 0 + # The table holds the on/off pairs + table = code['table'] + pulses = [] # store the pulses here + # Read through each indexed element + for i in code['index']: + pulses += table[i] # and add to the list of pulses + pulses.pop() # remove one final 'low' pulse + + for i in range(repeat): + pulse.send(array.array('H', pulses)) + time.sleep(delay) + led.value = False + time.sleep(code['delay']) + +f.close() diff --git a/CircuitPython_USB_VID_PID_Reporter/code.py b/CircuitPython_USB_VID_PID_Reporter/code.py new file mode 100644 index 000000000..7348b892f --- /dev/null +++ b/CircuitPython_USB_VID_PID_Reporter/code.py @@ -0,0 +1,110 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +CircuitPython USB VID/PID Reporter +Feather RP2040 USB Host with OLED FeatherWing + +""" + +import usb.core +import keypad +import board +import displayio +import terminalio + +from adafruit_display_text import label +from i2cdisplaybus import I2CDisplayBus + +import adafruit_displayio_sh1107 + +displayio.release_displays() + +# init display +i2c = board.I2C() +display_bus = I2CDisplayBus(i2c, device_address=0x3C) +display = adafruit_displayio_sh1107.SH1107(display_bus, width=128, height=64) + +# text groups +main = displayio.Group() +extra_info = displayio.Group() +groups = [main, extra_info] +display.root_group = main + +# text objects for title, VID and PID +title_text = label.Label(terminalio.FONT, text="USB VID/PID Reporter", color=0xFFFFFF, x=5, y=15) +main.append(title_text) +vid_text = label.Label(terminalio.FONT, text="VID:", color=0xFFFFFF, x=5, y=35) +main.append(vid_text) +pid_text = label.Label(terminalio.FONT, text="PID:", color=0xFFFFFF, x=5, y=50) +main.append(pid_text) + +# text objects for manufacturer and product info +# added to secondary group +man_header = label.Label(terminalio.FONT, text="Manufacturer:", color=0xFFFFFF, x=5, y=10) +extra_info.append(man_header) +man_text = label.Label(terminalio.FONT, text=" ", color=0xFFFFFF, x=5, y=25) +extra_info.append(man_text) +prod_header = label.Label(terminalio.FONT, text="Product:", color=0xFFFFFF, x=5, y=40) +extra_info.append(prod_header) +prod_text = label.Label(terminalio.FONT, text=" ", color=0xFFFFFF, x=5, y=55) +extra_info.append(prod_text) + +# init A, B and C buttons on FeatherWing as keypad keys +keys = keypad.Keys((board.D5,board.D6,board.D9,), value_when_pressed=False, pull=True) + +# variables +last_pid = 0x0000 # store last PID +last_vid = 0x0000 # store last VID +usb_dev = False # is there a USB device? +first_run = True # first run through loop +group_index = 0 # display group index +while True: + event = keys.events.get() + if event: + # if any button is pressed, toggle graphics group + if event.pressed: + group_index = (group_index + 1) % 2 + display.root_group = groups[group_index] + # find connected devices + devices = list(usb.core.find(find_all=True)) + # if no device, reset states and text objects + if not devices and usb_dev or first_run: + print("no device") + pid_text.text = "PID:" + vid_text.text = "VID:" + man_text.text = " " + prod_text.text = " " + usb_dev = False + first_run = False + else: + if not usb_dev: + first_run = False + for device in devices: + try: + # if its the same device, don't scan again + if (last_pid == hex(device.idProduct) and + last_vid == hex(device.idVendor) and usb_dev): + break + # new device! + usb_dev = True + # get PID, VID, manufacturer and product + # update text elements + print("pid", hex(device.idProduct)) + last_pid = hex(device.idProduct) + pid_text.text = f"PID: {last_pid}" + print("vid", hex(device.idVendor)) + last_vid = hex(device.idVendor) + vid_text.text = f"VID: {last_vid}" + print("man", device.manufacturer) + # only update manufacturer and product if info is known + if device.manufacturer is not None: + man_text.text = device.manufacturer + print("product", device.product) + if device.product is not None: + prod_text.text = device.product + print() + # if there's any error reading info from a USB device, continue + except usb.core.USBError: + print("got an error, continuing..") + continue diff --git a/CircuitPython_WeatherCloud/code.py b/CircuitPython_WeatherCloud/code.py index f86ee2333..ed046e914 100644 --- a/CircuitPython_WeatherCloud/code.py +++ b/CircuitPython_WeatherCloud/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import random import audioio @@ -24,21 +25,25 @@ wave = audiocore.WaveFile(wave_file) audio = audioio.AudioOut(board.A0) +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Use cityname, country code where countrycode is ISO3166 format. # E.g. "New York, US" or "London, GB" -LOCATION = secrets['timezone'] +LOCATION = getenv('timezone') # Set up where we'll be fetching data from -DATA_SOURCE = "http://api.openweathermap.org/data/2.5/weather?q="+secrets['timezone'] -DATA_SOURCE += "&appid="+secrets['openweather_token'] +DATA_SOURCE = "http://api.openweathermap.org/data/2.5/weather?q="+LOCATION +DATA_SOURCE += "&appid="+getenv('openweather_token') # If you are using a board with pre-defined ESP32 Pins: esp32_cs = DigitalInOut(board.ESP_CS) @@ -47,8 +52,8 @@ spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) -status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) # Uncomment for Most Boards -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) # Uncomment for Most Boards +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) pixels = neopixel.NeoPixel(board.D2, 150, brightness=1.0, auto_write=False) pixels.fill(0x050505) pixels.show() @@ -132,22 +137,17 @@ print(weather_type) # See https://openweathermap.org/weather-conditions # default to no rain or thunder raining = snowing = thundering = has_sound = False + wave_filename = None if weather_type == 'Sunny': palette = sunny_palette - wave_file = open("sound/Clear.wav", "rb") - wave = audiocore.WaveFile(wave_file) - has_sound = True + wave_filename = "sound/Clear.wav" if weather_type == 'Clouds': palette = cloudy_palette - wave_file = open("sound/Clouds.wav", "rb") - wave = audiocore.WaveFile(wave_file) - has_sound = True + wave_filename = "sound/Clouds.wav" if weather_type == 'Rain': palette = cloudy_palette - wave_file = open("sound/Rain.wav", "rb") - wave = audiocore.WaveFile(wave_file) + wave_filename = "sound/Rain.wav" raining = True - has_sound = True if weather_type == 'Thunderstorm': palette = thunder_palette raining = thundering = True @@ -156,9 +156,11 @@ next_bolt_time = time.monotonic() + random.randint(1, 5) if weather_type == 'Snow': palette = cloudy_palette - wave_file = open("sound/Snow.wav", "rb") - wave = audiocore.WaveFile(wave_file) + wave_filename = "sound/Snow.wav" snowing = True + if wave_filename: + wave_file = open(wave_filename, "rb") + wave = audiocore.WaveFile(wave_file) has_sound = True weather_refresh = time.monotonic() except RuntimeError as e: @@ -204,11 +206,13 @@ # pick next thunderbolt time now Thunder = random.randint(0, 2) if Thunder == 0: - wave_file = open("sound/Thunderstorm0.wav", "rb") + wave_filename = "sound/Thunderstorm0.wav" elif Thunder == 1: - wave_file = open("sound/Thunderstorm1.wav", "rb") + wave_filename = "sound/Thunderstorm1.wav" elif Thunder == 2: - wave_file = open("sound/Thunderstorm2.wav", "rb") - wave = audiocore.WaveFile(wave_file) - audio.play(wave) + wave_filename = "sound/Thunderstorm2.wav" + if wave_filename: + wave_file = open(wave_filename, "rb") + wave = audiocore.WaveFile(wave_file) + audio.play(wave) next_bolt_time = time.monotonic() + random.randint(5, 15) # between 5 and 15 s diff --git a/CircuitPython_WeatherCloud/secrets.py b/CircuitPython_WeatherCloud/secrets.py deleted file mode 100644 index 63bdfe3c2..000000000 --- a/CircuitPython_WeatherCloud/secrets.py +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -# This file is where you keep secret settings, passwords, and tokens! -# If you put them in the code you risk committing that info or sharing it - -secrets = { - 'ssid' : 'my_ssid', - 'password' : 'my_pass', - 'timezone' : "America/New_York", # http://worldtimeapi.org/timezones - 'openweather_token' : 'putYourOpenWeatherTokenHere', - } diff --git a/CircuitPython_WeatherCloud/settings.toml b/CircuitPython_WeatherCloud/settings.toml new file mode 100644 index 000000000..d751ea31a --- /dev/null +++ b/CircuitPython_WeatherCloud/settings.toml @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# This file is where you keep private settings, passwords, and tokens! +# If you put them in the code you risk committing that info or sharing it + + +CIRCUITPY_WIFI_SSID="your-wifi-ssid" +CIRCUITPY_WIFI_PASSWORD="your-wifi-password" +timezone="America/New_York" # http://worldtimeapi.org/timezones +openweather_token="putYourOpenWeatherTokenHere" diff --git a/CircuitPython_displayio/displayio_display_driver/code.py b/CircuitPython_displayio/displayio_display_driver/code.py index ca8026e49..8db5bd99e 100644 --- a/CircuitPython_displayio/displayio_display_driver/code.py +++ b/CircuitPython_displayio/displayio_display_driver/code.py @@ -4,6 +4,7 @@ import board import displayio +import fourwire import adafruit_ili9341 # Release any previously configured displays @@ -17,7 +18,7 @@ tft_dc = board.D9 # Setup the display bus -display_bus = displayio.FourWire(spi_bus, command=tft_dc, chip_select=tft_cs) +display_bus = fourwire.FourWire(spi_bus, command=tft_dc, chip_select=tft_cs) # Setup the Display display = adafruit_ili9341.ILI9341(display_bus, width=320, height=240) diff --git a/CircuitPython_displayio/displayio_display_manual/code.py b/CircuitPython_displayio/displayio_display_manual/code.py index 60ba96c38..439692743 100644 --- a/CircuitPython_displayio/displayio_display_manual/code.py +++ b/CircuitPython_displayio/displayio_display_manual/code.py @@ -4,6 +4,8 @@ import board import displayio +import busdisplay +import fourwire # Release any previously configured displays displayio.release_displays() @@ -16,7 +18,7 @@ tft_dc = board.D9 # Setup the display bus -display_bus = displayio.FourWire(spi_bus, command=tft_dc, chip_select=tft_cs) +display_bus = fourwire.FourWire(spi_bus, command=tft_dc, chip_select=tft_cs) # Setup the initialization sequence # stolen from adafruit_ili9341.py @@ -47,7 +49,7 @@ ) # Setup the Display -display = displayio.Display(display_bus, INIT_SEQUENCE, width=320, height=240) +display = busdisplay.BusDisplay(display_bus, INIT_SEQUENCE, width=320, height=240) # # DONE - now you can use the display however you want diff --git a/CircuitPython_displayio/displayio_parallelbus/code.py b/CircuitPython_displayio/displayio_parallelbus/code.py index b8ea15e40..092c564e6 100644 --- a/CircuitPython_displayio/displayio_parallelbus/code.py +++ b/CircuitPython_displayio/displayio_parallelbus/code.py @@ -4,13 +4,15 @@ import board import displayio +import busdisplay +import paralleldisplaybus # Release any previously configured displays displayio.release_displays() # Setup the display bus # Tested with a Metro M4 Express -display_bus = displayio.ParallelBus(data0=board.D13, +display_bus = paralleldisplaybus.ParallelBus(data0=board.D13, command=board.D6, chip_select=board.D7, write=board.D5, @@ -45,7 +47,7 @@ ) # Setup the Display -display = displayio.Display(display_bus, INIT_SEQUENCE, width=320, height=240) +display = busdisplay.BusDisplay(display_bus, INIT_SEQUENCE, width=320, height=240) # # DONE - now you can use the display however you want diff --git a/CircuitPython_qrio/adafruit_io/code.py b/CircuitPython_qrio/adafruit_io/code.py index 9c0d4ab0f..0012af8f0 100644 --- a/CircuitPython_qrio/adafruit_io/code.py +++ b/CircuitPython_qrio/adafruit_io/code.py @@ -4,17 +4,18 @@ """ This demo is designed for the Kaluga development kit version 1.3 with the -ILI9341 display. Your secrets.py must be populated with your wifi credentials +ILI9341 display. Your settings.toml must be populated with your wifi credentials and your Adafruit IO credentials. """ +from os import getenv import ssl -from secrets import secrets from ulab import numpy as np from terminalio import FONT import board import busio import displayio +import fourwire import qrio import socketpool import wifi @@ -24,13 +25,28 @@ from adafruit_io.adafruit_io import IO_MQTT import adafruit_minimqtt.adafruit_minimqtt as MQTT +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + # To change the name of the feed on adafruit_io, just modify this string: feed_name = "qrstring" print("Initializing display") displayio.release_displays() spi = busio.SPI(MOSI=board.LCD_MOSI, clock=board.LCD_CLK) -display_bus = displayio.FourWire( +display_bus = fourwire.FourWire( spi, command=board.LCD_D_C, chip_select=board.LCD_CS, reset=board.LCD_RST ) display = ILI9341(display_bus, width=320, height=240, rotation=90) @@ -52,14 +68,14 @@ cam.colorspace = adafruit_ov2640.OV2640_COLOR_YUV print("Connecting to WIFI") -wifi.radio.connect(secrets["ssid"], secrets["password"]) +wifi.radio.connect(ssid, password) pool = socketpool.SocketPool(wifi.radio) print("Connecting to Adafruit IO") mqtt_client = MQTT.MQTT( broker="io.adafruit.com", - username=secrets["aio_username"], - password=secrets["aio_key"], + username=aio_username, + password=aio_key, socket_pool=pool, ssl_context=ssl.create_default_context(), ) diff --git a/CircuitPython_qrio/repl/code.py b/CircuitPython_qrio/repl/code.py index 62814d4a4..23cf5dbba 100644 --- a/CircuitPython_qrio/repl/code.py +++ b/CircuitPython_qrio/repl/code.py @@ -12,6 +12,7 @@ import board import busio import displayio +import fourwire import qrio import adafruit_ov2640 from adafruit_display_text.bitmap_label import Label @@ -20,7 +21,7 @@ print("Initializing display") displayio.release_displays() spi = busio.SPI(MOSI=board.LCD_MOSI, clock=board.LCD_CLK) -display_bus = displayio.FourWire( +display_bus = fourwire.FourWire( spi, command=board.LCD_D_C, chip_select=board.LCD_CS, reset=board.LCD_RST ) display = ILI9341(display_bus, width=320, height=240, rotation=90) diff --git a/CircuitPython_qrio/usb_hid/code.py b/CircuitPython_qrio/usb_hid/code.py index b08cc8780..cf8288eac 100644 --- a/CircuitPython_qrio/usb_hid/code.py +++ b/CircuitPython_qrio/usb_hid/code.py @@ -4,8 +4,7 @@ """ This demo is designed for the Kaluga development kit version 1.3 with the -ILI9341 display. Your secrets.py must be populated with your wifi credentials -and your Adafruit IO credentials. +ILI9341 display. """ from ulab import numpy as np @@ -13,6 +12,7 @@ import board import busio import displayio +import fourwire import qrio import adafruit_ov2640 from adafruit_display_text.bitmap_label import Label @@ -24,7 +24,7 @@ print("Initializing display") displayio.release_displays() spi = busio.SPI(MOSI=board.LCD_MOSI, clock=board.LCD_CLK) -display_bus = displayio.FourWire( +display_bus = fourwire.FourWire( spi, command=board.LCD_D_C, chip_select=board.LCD_CS, reset=board.LCD_RST ) display = ILI9341(display_bus, width=320, height=240, rotation=90) diff --git a/CircuitPython_sdcardio_sdioio/show_bitmaps/code.py b/CircuitPython_sdcardio_sdioio/show_bitmaps/code.py index 75c7d4eb5..9a6f58812 100644 --- a/CircuitPython_sdcardio_sdioio/show_bitmaps/code.py +++ b/CircuitPython_sdcardio_sdioio/show_bitmaps/code.py @@ -21,17 +21,8 @@ for filename in bmpfiles: print("showing", filename) - # CircuitPython 6 & 7 compatible - bitmap_file = open(filename, "rb") - bitmap = displayio.OnDiskBitmap(bitmap_file) - tile_grid = displayio.TileGrid( - bitmap, - pixel_shader=getattr(bitmap, 'pixel_shader', displayio.ColorConverter()) - ) - - # # CircuitPython 7+ compatible - # bitmap = displayio.OnDiskBitmap(filename) - # tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader) + bitmap = displayio.OnDiskBitmap(filename) + tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader) group = displayio.Group() group.append(tile_grid) diff --git a/CircuitStonks/code.py b/CircuitStonks/code.py index 9120bb98f..527ab97ef 100644 --- a/CircuitStonks/code.py +++ b/CircuitStonks/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import board from digitalio import DigitalInOut @@ -14,12 +15,17 @@ minitft = minitft_featherwing.MiniTFTFeatherWing() -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # If you are using a board with pre-defined ESP32 Pins: esp32_cs = DigitalInOut(board.D13) @@ -27,11 +33,11 @@ esp32_reset = DigitalInOut(board.D12) spi = board.SPI() esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password) # Symbol "INX" for S&P500, "DJIA" for Dow DATA_SOURCE = "https://www.alphavantage.co/query?function=GLOBAL_QUOTE&apikey=" -DATA_SOURCE += secrets['alphavantage_key'] +DATA_SOURCE += getenv('alphavantage_key') symbols = ["DJIA", "INX", "AAPL", "TSLA", "MSFT"] # Set text, font, and color diff --git a/CircuitStonks/secrets.py b/CircuitStonks/secrets.py deleted file mode 100644 index ab38afa01..000000000 --- a/CircuitStonks/secrets.py +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries -# -# SPDX-License-Identifier: MIT - - -secrets = { - 'ssid' : 'myssid', - 'password' : 'mypassword', - 'timezone' : "America/New_York", # http://worldtimeapi.org/timezones - 'alphavantage_key' : 'GRABAFREEKEYONLINE' - } diff --git a/CircuitStonks/settings.toml b/CircuitStonks/settings.toml new file mode 100644 index 000000000..7ab57aeb4 --- /dev/null +++ b/CircuitStonks/settings.toml @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# This file is where you keep private settings, passwords, and tokens! +# If you put them in the code you risk committing that info or sharing it + +CIRCUITPY_WIFI_SSID="your-wifi-ssid" +CIRCUITPY_WIFI_PASSWORD="your-wifi-password" +timezone="America/New_York" # http://worldtimeapi.org/timezones +alphavantage_key="GRABAFREEKEYONLINE" diff --git a/Circuit_Playground_O_Phonor/notes_tft/code.py b/Circuit_Playground_O_Phonor/notes_tft/code.py index cbfc308d0..b0114e1d9 100755 --- a/Circuit_Playground_O_Phonor/notes_tft/code.py +++ b/Circuit_Playground_O_Phonor/notes_tft/code.py @@ -8,6 +8,7 @@ import busio import audiobusio import displayio +import fourwire from adafruit_st7789 import ST7789 from adafruit_bitmap_font import bitmap_font from adafruit_display_text import label @@ -46,7 +47,7 @@ tft_dc = board.TX tft_backlight = board.A3 -display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs) +display_bus = fourwire.FourWire(spi, command=tft_dc, chip_select=tft_cs) display = ST7789(display_bus, width=240, height=240, rowstart=80, backlight_pin=tft_backlight, rotation=180) diff --git a/Clue_Scale/README.md b/Clue_Scale/README.md deleted file mode 100644 index e635f01bf..000000000 --- a/Clue_Scale/README.md +++ /dev/null @@ -1,2 +0,0 @@ -Files for the ADafruit Learning System guide Clue Coffee Scale -https://learn.adafruit.com/clue-coffee-scale/overview diff --git a/Clue_Step_Counter/code.py b/Clue_Step_Counter/code.py deleted file mode 100644 index 598f4f797..000000000 --- a/Clue_Step_Counter/code.py +++ /dev/null @@ -1,185 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Liz Clark for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -import time -import board -import displayio -from adafruit_clue import clue -from simpleio import map_range -from adafruit_bitmap_font import bitmap_font -from adafruit_lsm6ds.lsm6ds33 import LSM6DS33 -from adafruit_lsm6ds import Rate, AccelRange -from adafruit_progressbar.progressbar import ProgressBar -from adafruit_display_text.label import Label - -# turns off onboard NeoPixel to conserve battery -clue.pixel.brightness = (0.0) - -# accessing the Clue's accelerometer -sensor = LSM6DS33(board.I2C()) - -# step goal -step_goal = 10000 - -# onboard button states -a_state = False -b_state = False - -# array to adjust screen brightness -bright_level = [0, 0.5, 1] - -countdown = 0 # variable for the step goal progress bar -clock = 0 # variable used to keep track of time for the steps per hour counter -clock_count = 0 # holds the number of hours that the step counter has been running -clock_check = 0 # holds the result of the clock divided by 3600 seconds (1 hour) -last_step = 0 # state used to properly counter steps -mono = time.monotonic() # time.monotonic() device -mode = 1 # state used to track screen brightness -steps_log = 0 # holds total steps to check for steps per hour -steps_remaining = 0 # holds the remaining steps needed to reach the step goal -sph = 0 # holds steps per hour - -# variables to hold file locations for background and fonts -clue_bgBMP = "/clue_bgBMP.bmp" -small_font = "/fonts/Roboto-Medium-16.bdf" -med_font = "/fonts/Roboto-Bold-24.bdf" -big_font = "/fonts/Roboto-Black-48.bdf" - -# glyphs for fonts -glyphs = b'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-,.: ' - -# loading bitmap fonts -small_font = bitmap_font.load_font(small_font) -small_font.load_glyphs(glyphs) -med_font = bitmap_font.load_font(med_font) -med_font.load_glyphs(glyphs) -big_font = bitmap_font.load_font(big_font) -big_font.load_glyphs(glyphs) - -# creating display and default brightness -clue_display = board.DISPLAY -clue_display.brightness = 0.5 - -# graphics group -clueGroup = displayio.Group() - -# loading bitmap background -# CircuitPython 6 & 7 compatible -clue_bg = displayio.OnDiskBitmap(open(clue_bgBMP, "rb")) -clue_tilegrid = displayio.TileGrid( - clue_bg, pixel_shader=getattr(clue_bg, 'pixel_shader', displayio.ColorConverter()) -) -clueGroup.append(clue_tilegrid) - -# # CircuitPython 7+ compatible -# clue_bg = displayio.OnDiskBitmap(clue_bgBMP) -# clue_tilegrid = displayio.TileGrid(clue_bg, pixel_shader=clue_bg.pixel_shader) -# clueGroup.append(clue_tilegrid) - -# creating the ProgressBar object -bar_group = displayio.Group() -prog_bar = ProgressBar(1, 1, 239, 25, bar_color=0x652f8f) -bar_group.append(prog_bar) - -clueGroup.append(bar_group) - -# text for step goal -steps_countdown = Label(small_font, text='%d Steps Remaining' % step_goal, color=clue.WHITE) -steps_countdown.x = 55 -steps_countdown.y = 12 - -# text for steps -text_steps = Label(big_font, text="0 ", color=0xe90e8b) -text_steps.x = 45 -text_steps.y = 70 - -# text for steps per hour -text_sph = Label(med_font, text=" -- ", color=0x29abe2) -text_sph.x = 8 -text_sph.y = 195 - -# adding all text to the display group -clueGroup.append(text_sph) -clueGroup.append(steps_countdown) -clueGroup.append(text_steps) - -# sending display group to the display at startup -clue_display.root_group = clueGroup - -# setting up the accelerometer and pedometer -sensor.accelerometer_range = AccelRange.RANGE_2G -sensor.accelerometer_data_rate = Rate.RATE_26_HZ -sensor.gyro_data_rate = Rate.RATE_SHUTDOWN -sensor.pedometer_enable = True - -while True: - - # button debouncing - if not clue.button_a and not a_state: - a_state = True - if not clue.button_b and not b_state: - b_state = True - - # setting up steps to hold step count - steps = sensor.pedometer_steps - - # creating the data for the ProgressBar - countdown = map_range(steps, 0, step_goal, 0.0, 1.0) - - # actual counting of the steps - # if a step is taken: - if abs(steps-last_step) > 1: - step_time = time.monotonic() - # updates last_step - last_step = steps - # updates the display - text_steps.text = '%d' % steps - clock = step_time - mono - - # logging steps per hour - if clock > 3600: - # gets number of hours to add to total - clock_check = clock / 3600 - # logs the step count as of that hour - steps_log = steps - # adds the hours to get a new hours total - clock_count += round(clock_check) - # divides steps by hours to get steps per hour - sph = steps_log / clock_count - # adds the sph to the display - text_sph.text = '%d' % sph - # resets clock to count to the next hour again - clock = 0 - mono = time.monotonic() - - # adjusting countdown to step goal - prog_bar.progress = float(countdown) - - # displaying countdown to step goal - if step_goal - steps > 0: - steps_remaining = step_goal - steps - steps_countdown.text = '%d Steps Remaining' % steps_remaining - else: - steps_countdown.text = 'Steps Goal Met!' - - # adjusting screen brightness, a button decreases brightness - if clue.button_a and a_state: - mode -= 1 - a_state = False - if mode < 0: - mode = 0 - clue_display.brightness = bright_level[mode] - else: - clue_display.brightness = bright_level[mode] - # b button increases brightness - if clue.button_b and b_state: - mode += 1 - b_state = False - if mode > 2: - mode = 2 - clue_display.brightness = bright_level[mode] - else: - clue_display.brightness = bright_level[mode] - - time.sleep(0.001) diff --git a/Computer_Space/.feather_m4_express.test.only b/Computer_Space/.feather_m4_express.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Computer_Space/Computer_Space.ino b/Computer_Space/Computer_Space.ino new file mode 100644 index 000000000..6218dd724 --- /dev/null +++ b/Computer_Space/Computer_Space.ino @@ -0,0 +1,1120 @@ +// SPDX-FileCopyrightText: 2025 John Park and Claude +// +// SPDX-License-Identifier: MIT +// Computer Space simulation for Arduino + +// For Adafruit Feather M4 with OLED display + +#include +#include +#include +#include + +// Display setup +#define OLED_CS 5 +#define OLED_DC 6 +#define OLED_RESET 9 +Adafruit_SSD1305 display(128, 64, &SPI, OLED_DC, OLED_RESET, OLED_CS, 7000000UL); + +// Game constants +#define GAME_WIDTH 85 // Game area width - for 4:3 aspect ratio +#define GAME_HEIGHT 64 // Game area height +#define SCREEN_WIDTH 128 // Physical display width +#define SCREEN_HEIGHT 64 // Physical display height +#define GAME_X_OFFSET ((SCREEN_WIDTH - GAME_WIDTH) / 2) // Center the game area +#define GAME_Y_OFFSET 0 +#define WHITE 1 +#define BLACK 0 + +// Score positions - all inside game area +#define SCORE_Y_TOP 18 // Player score +#define SCORE_Y_MIDDLE 32 // Saucer score +#define SCORE_Y_BOTTOM 46 // Timer + +// Score fonts are 3x5 pixels +#define DIGIT_WIDTH 3 +#define DIGIT_HEIGHT 5 +#define DIGIT_SPACING 5 // Total width including spacing + +// Scores +int player_score = 0; // Starting scores at 0 as requested +int saucer_score = 0; +unsigned long game_timer = 0; // Starting from 00 and counting up to 99 +const unsigned long GAME_DURATION = 99000; // 99 seconds + +// Number of stars (similar to PDP-1 Spacewar!) +#define NUM_STARS 40 + +// Ship and saucer states +#define ALIVE 0 +#define EXPLODING 1 +#define RESPAWNING 2 +#define EXPLOSION_FRAMES 12 // Number of frames for explosion animation + +// Screen flash effect +bool screen_flash = false; +int flash_frames = 0; +#define FLASH_DURATION 3 // How long to flash the screen + +// Game objects +// Ship +float ship_x, ship_y; +float ship_vx, ship_vy; +float ship_rotation = 0; +float target_rotation = 0; +const float ship_thrust = 0.13; // 33% slower than original 0.2 +bool ship_thrusting = false; +int ship_state = ALIVE; +int ship_explosion_frame = 0; +unsigned long ship_respawn_time = 0; + +// Saucers (moving in formation) +float saucer1_x, saucer1_y; +float saucer2_x, saucer2_y; +float saucer_vertical_distance; // Distance between saucers (maintained) +unsigned long direction_change_time = 0; +int saucer1_state = ALIVE; +int saucer2_state = ALIVE; +int saucer1_explosion_frame = 0; +int saucer2_explosion_frame = 0; +unsigned long saucer1_respawn_time = 0; +unsigned long saucer2_respawn_time = 0; + +// Diagonal movement table +const int8_t MOVEMENT_TABLE[][2] = { + { 1, 0}, // Right + {-1, 0}, // Left + { 0, -1}, // Up + { 0, 1}, // Down + { 1, 1}, // Down-Right + {-1, -1}, // Up-Left + {-1, 1}, // Down-Left + { 1, -1} // Up-Right +}; +uint8_t current_movement = 0; + +// Bullets +bool player_bullet_active = false; +float player_bullet_x, player_bullet_y; +float player_bullet_vx, player_bullet_vy; +unsigned long player_bullet_expire = 0; +float player_bullet_tracking_factor = 0.08; // How much the bullet tracks ship rotation + +bool saucer1_bullet_active = false; +float saucer1_bullet_x, saucer1_bullet_y; +float saucer1_bullet_vx, saucer1_bullet_vy; +unsigned long saucer1_bullet_expire = 0; + +bool saucer2_bullet_active = false; +float saucer2_bullet_x, saucer2_bullet_y; +float saucer2_bullet_vx, saucer2_bullet_vy; +unsigned long saucer2_bullet_expire = 0; + +// Shooting cooldowns +unsigned long player_fire_cooldown = 0; +unsigned long saucer_fire_cooldown = 0; +const unsigned long PLAYER_COOLDOWN = 700; // milliseconds +const unsigned long SAUCER_COOLDOWN = 1500; // milliseconds +const unsigned long BULLET_LIFETIME = 2000; // 2 seconds as requested +const float BULLET_SPEED = 42.0; // Much faster than ship movement + +// Respawn timing +const unsigned long RESPAWN_DELAY = 2000; // 2 seconds + +// Game timing +unsigned long last_time = 0; +unsigned long auto_rotation_time = 0; +unsigned long auto_thrust_time = 0; +unsigned long game_start_time = 0; +unsigned long timer_update_time = 0; + +// Star coordinates +uint8_t stars[NUM_STARS][2]; + +// Background counter for star flicker (PDP-1 style) +uint8_t bg_counter = 0; + +// Digit patterns for 0-9 (3x5 pixels, 1 for pixel on, 0 for pixel off) +const uint8_t DIGITS[10][DIGIT_HEIGHT][DIGIT_WIDTH] = { + // 0 + { + {1, 1, 1}, + {1, 0, 1}, + {1, 0, 1}, + {1, 0, 1}, + {1, 1, 1} + }, + // 1 + { + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0}, + {0, 1, 0} + }, + // 2 + { + {1, 1, 1}, + {0, 0, 1}, + {1, 1, 1}, + {1, 0, 0}, + {1, 1, 1} + }, + // 3 + { + {1, 1, 1}, + {0, 0, 1}, + {1, 1, 1}, + {0, 0, 1}, + {1, 1, 1} + }, + // 4 + { + {1, 0, 1}, + {1, 0, 1}, + {1, 1, 1}, + {0, 0, 1}, + {0, 0, 1} + }, + // 5 + { + {1, 1, 1}, + {1, 0, 0}, + {1, 1, 1}, + {0, 0, 1}, + {1, 1, 1} + }, + // 6 + { + {1, 1, 1}, + {1, 0, 0}, + {1, 1, 1}, + {1, 0, 1}, + {1, 1, 1} + }, + // 7 + { + {1, 1, 1}, + {0, 0, 1}, + {0, 0, 1}, + {0, 0, 1}, + {0, 0, 1} + }, + // 8 + { + {1, 1, 1}, + {1, 0, 1}, + {1, 1, 1}, + {1, 0, 1}, + {1, 1, 1} + }, + // 9 + { + {1, 1, 1}, + {1, 0, 1}, + {1, 1, 1}, + {0, 0, 1}, + {1, 1, 1} + } +}; + +// Explosion pattern data - expanding circle animation +const uint8_t EXPLOSION_RADIUS[] = {1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1}; +const uint8_t EXPLOSION_POINTS = 8; // Points to draw in the circle + +// Function prototypes +void drawDigit(int digit, int x, int y); +void drawScore(int score, int x, int y); +void drawScores(); +void clearScoreArea(); +void drawStars(); +void clearShip(); +void clearSaucer(float x, float y); +bool checkCollision(float x1, float y1, float x2, float y2, float radius); +bool isAimedAtSaucer(float ship_x, float ship_y, float ship_rotation, float saucer_x, float saucer_y, float tolerance = 0.6); +void drawShip(float x, float y, float rotation); +void drawSaucer(float x, float y); +void updateSaucerBullet(bool &active, float &x, float &y, float &vx, float &vy, unsigned long &expire, float dt, unsigned long current_time); +float normalizeAngle(float angle); +float getAngleDifference(float a1, float a2); +float getAngleToTarget(float x1, float y1, float x2, float y2); +void updateSaucers(float dt, unsigned long current_time); +void updateTimer(); +void drawExplosion(float x, float y, int frame); +void respawnShip(); +void respawnSaucer(int saucer_num); +void triggerScreenFlash(); + +void setup() { + Serial.begin(9600); + + // Initialize display + if (!display.begin()) { + Serial.println("SSD1305 allocation failed"); + while (1); + } + + // Show intro text + display.clearDisplay(); + display.setTextSize(1); + display.setTextColor(WHITE); + display.setCursor(10, 10); + display.println("Computer Space"); + display.setCursor(32, 30); + display.println("PDP-1 Style"); + display.setCursor(32, 50); + display.println("Demo Mode"); + display.display(); + delay(2000); + + display.clearDisplay(); + + // Initialize stars (PDP-1 style - fewer stars) + randomSeed(analogRead(0)); + for (int i = 0; i < NUM_STARS; i++) { + stars[i][0] = GAME_X_OFFSET + random(0, GAME_WIDTH); + stars[i][1] = GAME_Y_OFFSET + random(0, GAME_HEIGHT); + } + + // Initialize game objects + respawnShip(); + + // Initialize saucers in formation (one above the other) + respawnSaucer(1); + respawnSaucer(2); + saucer_vertical_distance = saucer2_y - saucer1_y; + + direction_change_time = millis() + random(2000, 5000); + game_start_time = millis(); + timer_update_time = millis(); + + // Draw the stars and initial score display + drawStars(); + drawScores(); + display.display(); + + last_time = millis(); +} + +void loop() { + unsigned long current_time = millis(); + float dt = (current_time - last_time) / 1000.0; // Convert to seconds + last_time = current_time; + + // Cap dt to prevent large jumps + if (dt > 0.1) dt = 0.1; + + // Update timer + updateTimer(); + + // Handle screen flash effect + if (screen_flash) { + // Flash the entire screen white + if (flash_frames == 0) { + display.fillRect(GAME_X_OFFSET, GAME_Y_OFFSET, GAME_WIDTH, GAME_HEIGHT, WHITE); + display.display(); + delay(50); // Short delay to make flash visible + } + + flash_frames++; + if (flash_frames >= FLASH_DURATION) { + screen_flash = false; + flash_frames = 0; + // Clear screen after flash + display.fillRect(GAME_X_OFFSET, GAME_Y_OFFSET, GAME_WIDTH, GAME_HEIGHT, BLACK); + } + } + + // Clear previous objects + clearShip(); + clearSaucer(saucer1_x, saucer1_y); + clearSaucer(saucer2_x, saucer2_y); + + if (player_bullet_active) { + display.drawPixel(player_bullet_x, player_bullet_y, BLACK); + } + if (saucer1_bullet_active) { + display.drawPixel(saucer1_bullet_x, saucer1_bullet_y, BLACK); + } + if (saucer2_bullet_active) { + display.drawPixel(saucer2_bullet_x, saucer2_bullet_y, BLACK); + } + + // Process ship based on its state + if (ship_state == ALIVE) { + // Simulate AI decisions for the player ship (PDP-1 style) + if (current_time > auto_rotation_time) { + // Choose a target to aim at (50% chance for each saucer if they're alive) + if (saucer1_state == ALIVE && saucer2_state == ALIVE) { + if (random(100) > 50) { + target_rotation = getAngleToTarget(ship_x, ship_y, saucer1_x, saucer1_y); + } else { + target_rotation = getAngleToTarget(ship_x, ship_y, saucer2_x, saucer2_y); + } + } else if (saucer1_state == ALIVE) { + target_rotation = getAngleToTarget(ship_x, ship_y, saucer1_x, saucer1_y); + } else if (saucer2_state == ALIVE) { + target_rotation = getAngleToTarget(ship_x, ship_y, saucer2_x, saucer2_y); + } else { + // Both saucers exploding/respawning, just pick a random direction + target_rotation = random(0, 628) / 100.0; // Random angle between 0 and 2*PI + } + + // Add some randomness to make it less precise (PDP-1 style) + target_rotation += random(-30, 30) * 0.01; + target_rotation = normalizeAngle(target_rotation); + + auto_rotation_time = current_time + random(1000, 3000); + } + + if (current_time > auto_thrust_time) { + // Thrusting decision based on aim + float angle_diff = abs(getAngleDifference(ship_rotation, target_rotation)); + if (angle_diff < 0.2) { + // If aimed correctly, thrust for a while + ship_thrusting = true; + auto_thrust_time = current_time + random(300, 800); + } else { + // If not aimed correctly, don't thrust + ship_thrusting = false; + auto_thrust_time = current_time + random(100, 300); + } + } + + // Update ship rotation with smoother movement (PDP-1 style) + float angle_diff = getAngleDifference(ship_rotation, target_rotation); + if (abs(angle_diff) > 0.05) { + // Rotate at a maximum of 0.05 radians per frame for smoother movement + ship_rotation += (angle_diff > 0 ? 1 : -1) * min(abs(angle_diff), 0.05f); + ship_rotation = normalizeAngle(ship_rotation); + } + + // Apply thrust to ship ONLY in the direction it's pointing + if (ship_thrusting) { + // Since the rocket points up (negative y) when rotation=0, + // we need to adjust the thrust direction by 90 degrees + ship_vx += cos(ship_rotation - PI/2) * ship_thrust; + ship_vy += sin(ship_rotation - PI/2) * ship_thrust; + } + + // Update position based on velocity (inertia - PDP-1 style physics) + ship_x += ship_vx * dt; + ship_y += ship_vy * dt; + + // Apply very slight drag (just to prevent perpetual motion) + ship_vx *= 0.995; + ship_vy *= 0.995; + + // Wrap ship around game area + if (ship_x < GAME_X_OFFSET) { + ship_x = GAME_X_OFFSET + GAME_WIDTH - 1; + } else if (ship_x >= GAME_X_OFFSET + GAME_WIDTH) { + ship_x = GAME_X_OFFSET; + } + + if (ship_y < GAME_Y_OFFSET) { + ship_y = GAME_Y_OFFSET + GAME_HEIGHT - 1; + } else if (ship_y >= GAME_Y_OFFSET + GAME_HEIGHT) { + ship_y = GAME_Y_OFFSET; + } + + // Check for collision with saucers + if (saucer1_state == ALIVE && checkCollision(ship_x, ship_y, saucer1_x, saucer1_y, 8)) { + // Collided with saucer 1 + ship_state = EXPLODING; + ship_explosion_frame = 0; + saucer1_state = EXPLODING; + saucer1_explosion_frame = 0; + + // Increment saucer score + saucer_score++; + if (saucer_score > 9) saucer_score = 9; // Cap at 9 + + // Trigger screen flash + triggerScreenFlash(); + } + else if (saucer2_state == ALIVE && checkCollision(ship_x, ship_y, saucer2_x, saucer2_y, 8)) { + // Collided with saucer 2 + ship_state = EXPLODING; + ship_explosion_frame = 0; + saucer2_state = EXPLODING; + saucer2_explosion_frame = 0; + + // Increment saucer score + saucer_score++; + if (saucer_score > 9) saucer_score = 9; // Cap at 9 + + // Trigger screen flash + triggerScreenFlash(); + } + + // Player shooting - only when aimed at a saucer + if (!player_bullet_active && current_time > player_fire_cooldown && random(100) > 90) { + // Check if aimed at any saucer + bool can_fire = false; + + if (saucer1_state == ALIVE && isAimedAtSaucer(ship_x, ship_y, ship_rotation, saucer1_x, saucer1_y)) { + can_fire = true; + } else if (saucer2_state == ALIVE && isAimedAtSaucer(ship_x, ship_y, ship_rotation, saucer2_x, saucer2_y)) { + can_fire = true; + } + + if (can_fire) { + player_bullet_active = true; + player_bullet_x = ship_x + cos(ship_rotation - PI/2) * 6; + player_bullet_y = ship_y + sin(ship_rotation - PI/2) * 6; + player_bullet_vx = cos(ship_rotation - PI/2) * BULLET_SPEED; + player_bullet_vy = sin(ship_rotation - PI/2) * BULLET_SPEED; + player_bullet_expire = current_time + BULLET_LIFETIME; + player_fire_cooldown = current_time + PLAYER_COOLDOWN; + } + } + } + else if (ship_state == EXPLODING) { + // Ship is exploding, update animation + ship_explosion_frame++; + if (ship_explosion_frame >= EXPLOSION_FRAMES) { + ship_state = RESPAWNING; + ship_respawn_time = current_time + RESPAWN_DELAY; + } + } + else if (ship_state == RESPAWNING) { + // Check if it's time to respawn + if (current_time > ship_respawn_time) { + respawnShip(); + } + } + + // Update saucers based on state + if (saucer1_state == ALIVE && saucer2_state == ALIVE) { + // Update saucers (in formation, PDP-1 style) + updateSaucers(dt, current_time); + } + else if (saucer1_state == EXPLODING) { + // Saucer 1 is exploding, update animation + saucer1_explosion_frame++; + if (saucer1_explosion_frame >= EXPLOSION_FRAMES) { + saucer1_state = RESPAWNING; + saucer1_respawn_time = current_time + RESPAWN_DELAY; + } + } + else if (saucer1_state == RESPAWNING) { + // Check if it's time to respawn saucer 1 + if (current_time > saucer1_respawn_time) { + respawnSaucer(1); + + // If saucer 2 is also active, update the formation distance + if (saucer2_state == ALIVE) { + saucer_vertical_distance = saucer2_y - saucer1_y; + } + } + } + + if (saucer2_state == EXPLODING) { + // Saucer 2 is exploding, update animation + saucer2_explosion_frame++; + if (saucer2_explosion_frame >= EXPLOSION_FRAMES) { + saucer2_state = RESPAWNING; + saucer2_respawn_time = current_time + RESPAWN_DELAY; + } + } + else if (saucer2_state == RESPAWNING) { + // Check if it's time to respawn saucer 2 + if (current_time > saucer2_respawn_time) { + respawnSaucer(2); + + // If saucer 1 is also active, update the formation distance + if (saucer1_state == ALIVE) { + saucer_vertical_distance = saucer2_y - saucer1_y; + } + } + } + + // Update player bullet with tracking behavior + if (player_bullet_active) { + // If ship is alive, update bullet direction to track ship's rotation + if (ship_state == ALIVE) { + // Calculate the target velocity based on current ship rotation + float target_vx = cos(ship_rotation - PI/2) * BULLET_SPEED; + float target_vy = sin(ship_rotation - PI/2) * BULLET_SPEED; + + // Gradually adjust bullet velocity to track the ship's rotation + player_bullet_vx += (target_vx - player_bullet_vx) * player_bullet_tracking_factor; + player_bullet_vy += (target_vy - player_bullet_vy) * player_bullet_tracking_factor; + + // Normalize velocity to maintain constant speed + float speed = sqrt(player_bullet_vx * player_bullet_vx + player_bullet_vy * player_bullet_vy); + if (speed > 0) { + player_bullet_vx = (player_bullet_vx / speed) * BULLET_SPEED; + player_bullet_vy = (player_bullet_vy / speed) * BULLET_SPEED; + } + } + + // Update position + player_bullet_x += player_bullet_vx * dt; + player_bullet_y += player_bullet_vy * dt; + + // Wrap bullet within game area + if (player_bullet_x < GAME_X_OFFSET) { + player_bullet_x = GAME_X_OFFSET + GAME_WIDTH - 1; + } else if (player_bullet_x >= GAME_X_OFFSET + GAME_WIDTH) { + player_bullet_x = GAME_X_OFFSET; + } + + if (player_bullet_y < GAME_Y_OFFSET) { + player_bullet_y = GAME_Y_OFFSET + GAME_HEIGHT - 1; + } else if (player_bullet_y >= GAME_Y_OFFSET + GAME_HEIGHT) { + player_bullet_y = GAME_Y_OFFSET; + } + + // Check collisions with saucers + if (saucer1_state == ALIVE && checkCollision(player_bullet_x, player_bullet_y, saucer1_x, saucer1_y, 4)) { + player_bullet_active = false; + saucer1_state = EXPLODING; + saucer1_explosion_frame = 0; + + // Increment player score + player_score++; + if (player_score > 9) player_score = 9; // Cap at 9 + + // Trigger screen flash + triggerScreenFlash(); + } + else if (saucer2_state == ALIVE && checkCollision(player_bullet_x, player_bullet_y, saucer2_x, saucer2_y, 4)) { + player_bullet_active = false; + saucer2_state = EXPLODING; + saucer2_explosion_frame = 0; + + // Increment player score + player_score++; + if (player_score > 9) player_score = 9; // Cap at 9 + + // Trigger screen flash + triggerScreenFlash(); + } + + // Bullet lifetime + if (current_time > player_bullet_expire) { + player_bullet_active = false; + } + } + + // Update saucer bullets + if (saucer1_state == ALIVE) { + updateSaucerBullet(saucer1_bullet_active, saucer1_bullet_x, saucer1_bullet_y, + saucer1_bullet_vx, saucer1_bullet_vy, saucer1_bullet_expire, dt, current_time); + } + + if (saucer2_state == ALIVE) { + updateSaucerBullet(saucer2_bullet_active, saucer2_bullet_x, saucer2_bullet_y, + saucer2_bullet_vx, saucer2_bullet_vy, saucer2_bullet_expire, dt, current_time); + } + + // Saucer shooting (PDP-1 style random timing) + if (!saucer1_bullet_active && !saucer2_bullet_active && current_time > saucer_fire_cooldown) { + if (random(100) > 50 && saucer1_state == ALIVE && ship_state == ALIVE) { + // Saucer 1 shoots + saucer1_bullet_active = true; + saucer1_bullet_x = saucer1_x; + saucer1_bullet_y = saucer1_y; + + // Aim towards player with some randomness (PDP-1 style accuracy) + float angle = atan2(ship_y - saucer1_y, ship_x - saucer1_x) + + (random(-50, 50) / 100.0); + saucer1_bullet_vx = cos(angle) * BULLET_SPEED * 0.7; + saucer1_bullet_vy = sin(angle) * BULLET_SPEED * 0.7; + saucer1_bullet_expire = current_time + BULLET_LIFETIME; + } else if (saucer2_state == ALIVE && ship_state == ALIVE) { + // Saucer 2 shoots + saucer2_bullet_active = true; + saucer2_bullet_x = saucer2_x; + saucer2_bullet_y = saucer2_y; + + // Aim towards player with some randomness + float angle = atan2(ship_y - saucer2_y, ship_x - saucer2_x) + + (random(-50, 50) / 100.0); + saucer2_bullet_vx = cos(angle) * BULLET_SPEED * 0.7; + saucer2_bullet_vy = sin(angle) * BULLET_SPEED * 0.7; + saucer2_bullet_expire = current_time + BULLET_LIFETIME; + } + saucer_fire_cooldown = current_time + SAUCER_COOLDOWN; + } + + // Update background counter for star flicker effect (PDP-1 style) + bg_counter++; + + // Draw stars only on certain frames (PDP-1 style) + if (bg_counter % 2 == 0) { + drawStars(); + } + + // Only draw game objects if not in a screen flash + if (!screen_flash) { + // Draw game objects based on their state + if (ship_state == ALIVE) { + drawShip(ship_x, ship_y, ship_rotation); + } else if (ship_state == EXPLODING) { + drawExplosion(ship_x, ship_y, ship_explosion_frame); + } + + if (saucer1_state == ALIVE) { + drawSaucer(saucer1_x, saucer1_y); + } else if (saucer1_state == EXPLODING) { + drawExplosion(saucer1_x, saucer1_y, saucer1_explosion_frame); + } + + if (saucer2_state == ALIVE) { + drawSaucer(saucer2_x, saucer2_y); + } else if (saucer2_state == EXPLODING) { + drawExplosion(saucer2_x, saucer2_y, saucer2_explosion_frame); + } + + // Draw bullets + if (player_bullet_active) { + display.drawPixel(player_bullet_x, player_bullet_y, WHITE); + } + if (saucer1_bullet_active) { + display.drawPixel(saucer1_bullet_x, saucer1_bullet_y, WHITE); + } + if (saucer2_bullet_active) { + display.drawPixel(saucer2_bullet_x, saucer2_bullet_y, WHITE); + } + + // Clear score area and draw scores + clearScoreArea(); + drawScores(); + } + + // Update display + display.display(); + + // Small delay for performance + delay(20); // ~50 FPS - Similar to PDP-1 refresh rate +} + +// Trigger a white screen flash effect +void triggerScreenFlash() { + screen_flash = true; + flash_frames = 0; +} + +// Draw a PDP-1 style explosion animation +void drawExplosion(float x, float y, int frame) { + int radius = EXPLOSION_RADIUS[frame]; + + // Draw expanding circle with points + for (int i = 0; i < EXPLOSION_POINTS; i++) { + float angle = i * (2.0 * PI / EXPLOSION_POINTS); + int px = x + radius * cos(angle); + int py = y + radius * sin(angle); + + // Only draw if within game area + if (px >= GAME_X_OFFSET && px < GAME_X_OFFSET + GAME_WIDTH && + py >= GAME_Y_OFFSET && py < GAME_Y_OFFSET + GAME_HEIGHT) { + display.drawPixel(px, py, WHITE); + } + + // Add some randomly placed debris particles + if (frame > 2 && frame < 10) { + float debris_angle = angle + random(-30, 30) * 0.01; + float debris_dist = random(1, radius + 2); + int dx = x + debris_dist * cos(debris_angle); + int dy = y + debris_dist * sin(debris_angle); + + if (dx >= GAME_X_OFFSET && dx < GAME_X_OFFSET + GAME_WIDTH && + dy >= GAME_Y_OFFSET && dy < GAME_Y_OFFSET + GAME_HEIGHT) { + display.drawPixel(dx, dy, WHITE); + } + } + } +} + +// Respawn ship at a random position +void respawnShip() { + ship_x = GAME_X_OFFSET + random(GAME_WIDTH/4, 3*GAME_WIDTH/4); + ship_y = GAME_Y_OFFSET + random(GAME_HEIGHT/4, 3*GAME_HEIGHT/4); + ship_vx = ship_vy = 0; + ship_state = ALIVE; +} + +// Respawn saucer at a new position +void respawnSaucer(int saucer_num) { + if (saucer_num == 1) { + saucer1_x = GAME_X_OFFSET + random(10, GAME_WIDTH - 10); + saucer1_y = GAME_Y_OFFSET + random(10, GAME_HEIGHT/2 - 10); + saucer1_state = ALIVE; + } else { + saucer2_x = GAME_X_OFFSET + random(10, GAME_WIDTH - 10); + saucer2_y = GAME_Y_OFFSET + random(GAME_HEIGHT/2 + 10, GAME_HEIGHT - 10); + saucer2_state = ALIVE; + } +} + +// Draw a single digit using our custom font +void drawDigit(int digit, int x, int y) { + if (digit < 0 || digit > 9) return; // Only support 0-9 + + // Draw the digit pixel by pixel + for (int row = 0; row < DIGIT_HEIGHT; row++) { + for (int col = 0; col < DIGIT_WIDTH; col++) { + if (DIGITS[digit][row][col] == 1) { + display.drawPixel(x + col, y + row, WHITE); + } + } + } +} + +// Draw a score with multiple digits +void drawScore(int score, int x, int y) { + // Handle single and double digit scores + if (score < 10) { + // Single digit - add leading zero for timer + if (y == SCORE_Y_BOTTOM) { + // This is the timer, draw leading zero + drawDigit(0, x - DIGIT_SPACING, y); + drawDigit(score, x, y); + } else { + // Single digit score + drawDigit(score, x, y); + } + } else if (score < 100) { + // Double digits + int tens = score / 10; + int ones = score % 10; + drawDigit(tens, x - DIGIT_SPACING, y); + drawDigit(ones, x, y); + } +} + +// Update game timer - always counts up from 00 to 99 +void updateTimer() { + unsigned long current_time = millis(); + + // Update timer only once per second + if (current_time - timer_update_time >= 1000) { + timer_update_time = current_time; + + // Always increment timer + game_timer++; + if (game_timer >= 100) { + game_timer = 0; // Reset to 00 when reaching 100 + } + } +} + +// Clear the score area more thoroughly +void clearScoreArea() { + // Define score display areas + for (int i = 0; i < 3; i++) { + int y_pos; + switch (i) { + case 0: y_pos = SCORE_Y_TOP; break; + case 1: y_pos = SCORE_Y_MIDDLE; break; + case 2: y_pos = SCORE_Y_BOTTOM; break; + } + + // Clear area for double-digit score (including spacing) + for (int y = y_pos; y < y_pos + DIGIT_HEIGHT; y++) { + for (int x = GAME_X_OFFSET + GAME_WIDTH - 12; x < GAME_X_OFFSET + GAME_WIDTH; x++) { + display.drawPixel(x, y, BLACK); + } + } + } +} + +// Draw scores with custom font, positioned at edge of game area +void drawScores() { + // Position scores a few pixels from the right edge of game area + int score_x = GAME_X_OFFSET + GAME_WIDTH - 5; + + // Player score at top position + drawScore(player_score, score_x, SCORE_Y_TOP); + + // Saucer score at middle position + drawScore(saucer_score, score_x, SCORE_Y_MIDDLE); + + // Timer at bottom position (always show as 2 digits) + drawScore(game_timer, score_x, SCORE_Y_BOTTOM); +} + +// Update saucers using the PDP-1 style zig-zag formation movement +void updateSaucers(float dt, unsigned long current_time) { + // Check if it's time to change direction + if (current_time > direction_change_time) { + // Select a new movement pattern from the table + current_movement = random(0, 8); // 8 possible movement directions + + // Set next direction change time + direction_change_time = current_time + random(1500, 3000); + } + + // Apply current movement pattern + float speed_factor = 25.0 * dt; + float dx = MOVEMENT_TABLE[current_movement][0] * speed_factor; + float dy = MOVEMENT_TABLE[current_movement][1] * speed_factor; + + // Update saucer positions, maintaining their formation + saucer1_x += dx; + saucer1_y += dy; + + // Always keep saucer2 at the same position relative to saucer1 + saucer2_x = saucer1_x; + saucer2_y = saucer1_y + saucer_vertical_distance; + + // Wrap saucers around the game area + if (saucer1_x < GAME_X_OFFSET) { + saucer1_x = GAME_X_OFFSET + GAME_WIDTH - 1; + saucer2_x = saucer1_x; + } else if (saucer1_x >= GAME_X_OFFSET + GAME_WIDTH) { + saucer1_x = GAME_X_OFFSET; + saucer2_x = saucer1_x; + } + + if (saucer1_y < GAME_Y_OFFSET) { + saucer1_y = GAME_Y_OFFSET + GAME_HEIGHT - 1; + saucer2_y = saucer1_y + saucer_vertical_distance; + } else if (saucer1_y >= GAME_Y_OFFSET + GAME_HEIGHT) { + saucer1_y = GAME_Y_OFFSET; + saucer2_y = saucer1_y + saucer_vertical_distance; + } + + // Also wrap saucer2 if it goes off screen + if (saucer2_y >= GAME_Y_OFFSET + GAME_HEIGHT) { + saucer2_y = GAME_Y_OFFSET + (saucer2_y - (GAME_Y_OFFSET + GAME_HEIGHT)); + saucer1_y = saucer2_y - saucer_vertical_distance; + } else if (saucer2_y < GAME_Y_OFFSET) { + saucer2_y = GAME_Y_OFFSET + GAME_HEIGHT - (GAME_Y_OFFSET - saucer2_y); + saucer1_y = saucer2_y - saucer_vertical_distance; + } +} + +// Normalize angle to [0, 2π] +float normalizeAngle(float angle) { + while (angle < 0) angle += 2 * PI; + while (angle >= 2 * PI) angle -= 2 * PI; + return angle; +} + +// Get the shortest angle difference between two angles +float getAngleDifference(float a1, float a2) { + float diff = normalizeAngle(a2 - a1); + if (diff > PI) diff -= 2 * PI; + return diff; +} + +// Get angle from point 1 to point 2 +float getAngleToTarget(float x1, float y1, float x2, float y2) { + return atan2(y2 - y1, x2 - x1); +} + +// Helper function to update saucer bullets +void updateSaucerBullet(bool &active, float &x, float &y, float &vx, float &vy, + unsigned long &expire, float dt, unsigned long current_time) { + if (active) { + x += vx * dt; + y += vy * dt; + + // Wrap bullet within game area + if (x < GAME_X_OFFSET) { + x = GAME_X_OFFSET + GAME_WIDTH - 1; + } else if (x >= GAME_X_OFFSET + GAME_WIDTH) { + x = GAME_X_OFFSET; + } + + if (y < GAME_Y_OFFSET) { + y = GAME_Y_OFFSET + GAME_HEIGHT - 1; + } else if (y >= GAME_Y_OFFSET + GAME_HEIGHT) { + y = GAME_Y_OFFSET; + } + + // Check collision with player + if (ship_state == ALIVE && checkCollision(x, y, ship_x, ship_y, 4)) { + active = false; + ship_state = EXPLODING; + ship_explosion_frame = 0; + + // Increment saucer score + saucer_score++; + if (saucer_score > 9) saucer_score = 9; // Cap at 9 + + // Trigger screen flash + triggerScreenFlash(); + } + + // Bullet lifetime + if (current_time > expire) { + active = false; + } + } +} + +// Draw stars +void drawStars() { + for (int i = 0; i < NUM_STARS; i++) { + // Only draw stars within the game area + if (stars[i][0] >= GAME_X_OFFSET && stars[i][0] < GAME_X_OFFSET + GAME_WIDTH && + stars[i][1] >= GAME_Y_OFFSET && stars[i][1] < GAME_Y_OFFSET + GAME_HEIGHT) { + display.drawPixel(stars[i][0], stars[i][1], WHITE); + } + } +} + +// Improved collision detection using distance formula +bool checkCollision(float x1, float y1, float x2, float y2, float radius) { + return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) < radius; +} + +// Check if ship is aimed at a saucer +bool isAimedAtSaucer(float ship_x, float ship_y, float ship_rotation, + float saucer_x, float saucer_y, float tolerance) { + // Calculate angle to saucer + float angle_to_saucer = atan2(saucer_y - ship_y, saucer_x - ship_x); + + // Calculate the difference between angles + float angle_diff = getAngleDifference(ship_rotation - PI/2, angle_to_saucer); + + // Check if angle difference is within tolerance + return abs(angle_diff) < tolerance; +} + +// Draw player ship as a dot pattern (PDP-1 style) +void drawShip(float x, float y, float rotation) { + int orig_x = (int)x; + int orig_y = (int)y; + + // Define the rocket shape points in its local coordinate system (PDP-1 style) + const int NUM_SHIP_POINTS = 15; + const int8_t points[][2] = { + {0, -6}, // Top point + {-2, -4}, {2, -4}, // Upper row + {-3, -2}, {3, -2}, // Mid-upper row + {-3, 0}, {3, 0}, // Middle row + {-2, 1}, {2, 1}, // Mid-lower row + {-4, 2}, {0, 2}, {4, 2}, // Lower body row + {-3, 4}, {3, 4} // Bottom fins + }; + + // Draw each point after rotation (PDP-1 style) + for (int i = 0; i < NUM_SHIP_POINTS; i++) { + // Rotate point + float rx = points[i][0] * cos(rotation) - points[i][1] * sin(rotation); + float ry = points[i][0] * sin(rotation) + points[i][1] * cos(rotation); + + // Calculate pixel position + int px = orig_x + (int)rx; + int py = orig_y + (int)ry; + + // Only draw if within game area + if (px >= GAME_X_OFFSET && px < GAME_X_OFFSET + GAME_WIDTH && + py >= GAME_Y_OFFSET && py < GAME_Y_OFFSET + GAME_HEIGHT) { + display.drawPixel(px, py, WHITE); + } + } + + // Add exhaust flame if thrusting - pointing from bottom of rocket + if (ship_thrusting) { + // Calculate bottom center position of the rocket + float bottom_x = 0 * cos(rotation) - 4 * sin(rotation); + float bottom_y = 0 * sin(rotation) + 4 * cos(rotation); + + // Add flame a bit below the bottom center + float flame_x = bottom_x + 2 * sin(rotation); // Perpendicular to rotation + float flame_y = bottom_y - 2 * cos(rotation); // Perpendicular to rotation + + int px = orig_x + (int)flame_x; + int py = orig_y + (int)flame_y; + + // Only draw if within game area + if (px >= GAME_X_OFFSET && px < GAME_X_OFFSET + GAME_WIDTH && + py >= GAME_Y_OFFSET && py < GAME_Y_OFFSET + GAME_HEIGHT) { + display.drawPixel(px, py, WHITE); + } + } +} + +// Helper to clear ship (draws in black) +void clearShip() { + // We'll use a larger area to ensure we cover the ship in any rotation + for (int dy = -8; dy <= 8; dy++) { + for (int dx = -8; dx <= 8; dx++) { + int x = ship_x + dx; + int y = ship_y + dy; + + // Only clear points within the game area + if (x >= GAME_X_OFFSET && x < GAME_X_OFFSET + GAME_WIDTH && + y >= GAME_Y_OFFSET && y < GAME_Y_OFFSET + GAME_HEIGHT) { + // Don't erase stars + bool is_star = false; + for (int i = 0; i < NUM_STARS; i++) { + if (stars[i][0] == x && stars[i][1] == y) { + is_star = true; + break; + } + } + if (!is_star) { + display.drawPixel(x, y, BLACK); + } + } + } + } +} + +// Draw saucer as a dot pattern (PDP-1 style) +void drawSaucer(float x, float y) { + int orig_x = (int)x; + int orig_y = (int)y; + + // Define saucer points (PDP-1 style dot pattern) + const int NUM_SAUCER_POINTS = 18; + const int8_t points[][2] = { + // Top dome + {-1, -2}, {1, -2}, + // Mid-top row + {-4, -1}, {-3, -1}, {3, -1}, {4, -1}, + // Middle row (widest) + {-5, 0}, {-2, 0}, {-1, 0}, {1, 0}, {2, 0}, {5, 0}, + // Mid-bottom row + {-4, 1}, {-3, 1}, {3, 1}, {4, 1}, + // Bottom + {-1, 2}, {1, 2} + }; + + // Draw each point + for (int i = 0; i < NUM_SAUCER_POINTS; i++) { + int px = orig_x + points[i][0]; + int py = orig_y + points[i][1]; + + // Only draw if within game area + if (px >= GAME_X_OFFSET && px < GAME_X_OFFSET + GAME_WIDTH && + py >= GAME_Y_OFFSET && py < GAME_Y_OFFSET + GAME_HEIGHT) { + display.drawPixel(px, py, WHITE); + } + } +} + +// Helper to clear saucer +void clearSaucer(float x, float y) { + // Clear a rectangle around the saucer + for (int dy = -6; dy <= 6; dy++) { + for (int dx = -6; dx <= 6; dx++) { + int px = x + dx; + int py = y + dy; + + // Only clear points within the game area + if (px >= GAME_X_OFFSET && px < GAME_X_OFFSET + GAME_WIDTH && + py >= GAME_Y_OFFSET && py < GAME_Y_OFFSET + GAME_HEIGHT) { + // Don't erase stars + bool is_star = false; + for (int i = 0; i < NUM_STARS; i++) { + if (stars[i][0] == px && stars[i][1] == py) { + is_star = true; + break; + } + } + if (!is_star) { + display.drawPixel(px, py, BLACK); + } + } + } + } +} \ No newline at end of file diff --git a/BLE_Crickit_Light_Switch/code.py b/Crickits/BLE_Crickit_Light_Switch/code.py similarity index 100% rename from BLE_Crickit_Light_Switch/code.py rename to Crickits/BLE_Crickit_Light_Switch/code.py diff --git a/Crickits/Crickit_Animatronic_Doorbell/README.md b/Crickits/Crickit_Animatronic_Doorbell/README.md new file mode 100644 index 000000000..b74c11245 --- /dev/null +++ b/Crickits/Crickit_Animatronic_Doorbell/README.md @@ -0,0 +1,3 @@ +## Crickit_Animatronic_Doorbell + +Code for https://learn.adafruit.com/hacking-holiday-animatronics/code-the-animatronic-eyeball-doorbell diff --git a/Crickit_Animatronic_Doorbell/code.py b/Crickits/Crickit_Animatronic_Doorbell/code.py similarity index 100% rename from Crickit_Animatronic_Doorbell/code.py rename to Crickits/Crickit_Animatronic_Doorbell/code.py diff --git a/Crickit_Animatronic_Doorbell/phrase_01.mp3 b/Crickits/Crickit_Animatronic_Doorbell/phrase_01.mp3 similarity index 100% rename from Crickit_Animatronic_Doorbell/phrase_01.mp3 rename to Crickits/Crickit_Animatronic_Doorbell/phrase_01.mp3 diff --git a/Crickit_Animatronic_Doorbell/phrase_02.mp3 b/Crickits/Crickit_Animatronic_Doorbell/phrase_02.mp3 similarity index 100% rename from Crickit_Animatronic_Doorbell/phrase_02.mp3 rename to Crickits/Crickit_Animatronic_Doorbell/phrase_02.mp3 diff --git a/Crickit_Animatronic_Doorbell/phrase_03.mp3 b/Crickits/Crickit_Animatronic_Doorbell/phrase_03.mp3 similarity index 100% rename from Crickit_Animatronic_Doorbell/phrase_03.mp3 rename to Crickits/Crickit_Animatronic_Doorbell/phrase_03.mp3 diff --git a/Crickit_Animatronic_Doorbell/ring.mp3 b/Crickits/Crickit_Animatronic_Doorbell/ring.mp3 similarity index 100% rename from Crickit_Animatronic_Doorbell/ring.mp3 rename to Crickits/Crickit_Animatronic_Doorbell/ring.mp3 diff --git a/Crickits/Crickit_CPX_Marionette/README.md b/Crickits/Crickit_CPX_Marionette/README.md new file mode 100644 index 000000000..1bdbae6ac --- /dev/null +++ b/Crickits/Crickit_CPX_Marionette/README.md @@ -0,0 +1 @@ +## Code for the guide https://learn.adafruit.com/universal-marionette-with-crickit diff --git a/Crickit_CPX_Marionette/code.py b/Crickits/Crickit_CPX_Marionette/code.py similarity index 100% rename from Crickit_CPX_Marionette/code.py rename to Crickits/Crickit_CPX_Marionette/code.py diff --git a/Crickit_Exhibit/code.py b/Crickits/Crickit_Exhibit/code.py similarity index 100% rename from Crickit_Exhibit/code.py rename to Crickits/Crickit_Exhibit/code.py diff --git a/Crickits/Crickit_FlippyBot/.feather_m0_express.test.only b/Crickits/Crickit_FlippyBot/.feather_m0_express.test.only new file mode 100644 index 000000000..8d1c8b69c --- /dev/null +++ b/Crickits/Crickit_FlippyBot/.feather_m0_express.test.only @@ -0,0 +1 @@ + diff --git a/Crickit_FlippyBot/BluefruitConfig.h b/Crickits/Crickit_FlippyBot/BluefruitConfig.h similarity index 100% rename from Crickit_FlippyBot/BluefruitConfig.h rename to Crickits/Crickit_FlippyBot/BluefruitConfig.h diff --git a/Crickit_FlippyBot/Crickit_FlippyBot.ino b/Crickits/Crickit_FlippyBot/Crickit_FlippyBot.ino similarity index 100% rename from Crickit_FlippyBot/Crickit_FlippyBot.ino rename to Crickits/Crickit_FlippyBot/Crickit_FlippyBot.ino diff --git a/Crickit_FlippyBot/STL_Files/Battery_Tray.stl b/Crickits/Crickit_FlippyBot/STL_Files/Battery_Tray.stl similarity index 100% rename from Crickit_FlippyBot/STL_Files/Battery_Tray.stl rename to Crickits/Crickit_FlippyBot/STL_Files/Battery_Tray.stl diff --git a/Crickit_FlippyBot/STL_Files/Body_1.stl b/Crickits/Crickit_FlippyBot/STL_Files/Body_1.stl similarity index 100% rename from Crickit_FlippyBot/STL_Files/Body_1.stl rename to Crickits/Crickit_FlippyBot/STL_Files/Body_1.stl diff --git a/Crickit_FlippyBot/STL_Files/Body_2.stl b/Crickits/Crickit_FlippyBot/STL_Files/Body_2.stl similarity index 100% rename from Crickit_FlippyBot/STL_Files/Body_2.stl rename to Crickits/Crickit_FlippyBot/STL_Files/Body_2.stl diff --git a/Crickit_FlippyBot/STL_Files/Crickit_Tray.stl b/Crickits/Crickit_FlippyBot/STL_Files/Crickit_Tray.stl similarity index 100% rename from Crickit_FlippyBot/STL_Files/Crickit_Tray.stl rename to Crickits/Crickit_FlippyBot/STL_Files/Crickit_Tray.stl diff --git a/Crickit_FlippyBot/STL_Files/Joint_Cap.stl b/Crickits/Crickit_FlippyBot/STL_Files/Joint_Cap.stl similarity index 100% rename from Crickit_FlippyBot/STL_Files/Joint_Cap.stl rename to Crickits/Crickit_FlippyBot/STL_Files/Joint_Cap.stl diff --git a/Crickit_FlippyBot/STL_Files/Leg.stl b/Crickits/Crickit_FlippyBot/STL_Files/Leg.stl similarity index 100% rename from Crickit_FlippyBot/STL_Files/Leg.stl rename to Crickits/Crickit_FlippyBot/STL_Files/Leg.stl diff --git a/Crickit_FlippyBot/STL_Files/Motor_Arm.stl b/Crickits/Crickit_FlippyBot/STL_Files/Motor_Arm.stl similarity index 100% rename from Crickit_FlippyBot/STL_Files/Motor_Arm.stl rename to Crickits/Crickit_FlippyBot/STL_Files/Motor_Arm.stl diff --git a/Crickit_FlippyBot/STL_Files/Plain_Arm.stl b/Crickits/Crickit_FlippyBot/STL_Files/Plain_Arm.stl similarity index 100% rename from Crickit_FlippyBot/STL_Files/Plain_Arm.stl rename to Crickits/Crickit_FlippyBot/STL_Files/Plain_Arm.stl diff --git a/Crickits/Crickit_FlippyBot/STL_Files/README.md b/Crickits/Crickit_FlippyBot/STL_Files/README.md new file mode 100644 index 000000000..d3ad4435d --- /dev/null +++ b/Crickits/Crickit_FlippyBot/STL_Files/README.md @@ -0,0 +1 @@ +STL 3D model files for https://learn.adafruit.com/crickit-flippy-robot diff --git a/Crickit_FlippyBot/packetParser.cpp b/Crickits/Crickit_FlippyBot/packetParser.cpp similarity index 100% rename from Crickit_FlippyBot/packetParser.cpp rename to Crickits/Crickit_FlippyBot/packetParser.cpp diff --git a/Crickit_Hello_World/circuitplayground-helloworld.uf2 b/Crickits/Crickit_Hello_World/circuitplayground-helloworld.uf2 similarity index 100% rename from Crickit_Hello_World/circuitplayground-helloworld.uf2 rename to Crickits/Crickit_Hello_World/circuitplayground-helloworld.uf2 diff --git a/Crickit_Hello_World/code.py b/Crickits/Crickit_Hello_World/code.py similarity index 100% rename from Crickit_Hello_World/code.py rename to Crickits/Crickit_Hello_World/code.py diff --git a/Crickit_Hello_World/hello.wav b/Crickits/Crickit_Hello_World/hello.wav similarity index 100% rename from Crickit_Hello_World/hello.wav rename to Crickits/Crickit_Hello_World/hello.wav diff --git a/Crickit_MicroBit_Robot/README.md b/Crickits/Crickit_MicroBit_Robot/README.md similarity index 100% rename from Crickit_MicroBit_Robot/README.md rename to Crickits/Crickit_MicroBit_Robot/README.md diff --git a/Crickit_MicroBit_Robot/Wiring.fzz b/Crickits/Crickit_MicroBit_Robot/Wiring.fzz similarity index 100% rename from Crickit_MicroBit_Robot/Wiring.fzz rename to Crickits/Crickit_MicroBit_Robot/Wiring.fzz diff --git a/Crickit_MicroBit_Robot/Wiring_bb.png b/Crickits/Crickit_MicroBit_Robot/Wiring_bb.png similarity index 100% rename from Crickit_MicroBit_Robot/Wiring_bb.png rename to Crickits/Crickit_MicroBit_Robot/Wiring_bb.png diff --git a/Crickits/Crickit_MicroBit_Robot/microbit-Basic-Movement-Robot.hex b/Crickits/Crickit_MicroBit_Robot/microbit-Basic-Movement-Robot.hex new file mode 100644 index 000000000..32092580e --- /dev/null +++ b/Crickits/Crickit_MicroBit_Robot/microbit-Basic-Movement-Robot.hex @@ -0,0 +1,14412 @@ +:020000040000FA +:10000000C0070000D1060000D1000000B1060000CA +:1000100000000000000000000000000000000000E0 +:100020000000000000000000000000005107000078 +:100030000000000000000000DB000000E500000000 +:10004000EF000000F9000000030100000D010000B6 +:1000500017010000210100002B0100003501000004 +:100060003F01000049010000530100005D01000054 +:1000700067010000710100007B01000085010000A4 +:100080008F01000099010000A3010000AD010000F4 +:10009000B7010000C1010000CB010000D501000044 +:1000A000DF010000E9010000F3010000FD01000094 +:1000B00007020000110200001B02000025020000E0 +:1000C0001FB5C046C04600F0EFFA04B00FB41FBD24 +:1000D00008205A49096809580847382057490968CB +:1000E000095808473C2055490968095808474020E5 +:1000F0005249096809580847442050490968095875 +:10010000084748204D490968095808474C204B4981 +:10011000096809580847502048490968095808479C +:100120005420464909680958084758204349096836 +:10013000095808475C204149096809580847602068 +:100140003E4909680958084764203C49096809582C +:100150000847682039490968095808476C20374919 +:100160000968095808477020344909680958084740 +:100170007420324909680958084778202F490968CE +:10018000095808477C202D490968095808478020EC +:100190002A490968095808478420284909680958E4 +:1001A0000847882025490968095808478C202349B1 +:1001B00009680958084790202049096809580847E4 +:1001C00094201E4909680958084798201B49096866 +:1001D000095808479C201949096809580847A02070 +:1001E0001649096809580847A4201449096809589C +:1001F0000847A8201149096809580847AC200F4949 +:10020000096809580847B0200C4909680958084787 +:10021000B4200A49096809580847B82007490968FD +:1002200009580847BC2005490968095808470000D3 +:1002300003480449024A034B7047000000000020B5 +:10024000C0070000C00700000122D84B5A6000BF61 +:10025000D74A1268002AFBD0016000BFD44A126856 +:10026000002AFBD00022D14B5A6000BFD04A12684E +:10027000002AFBD07047F0B505460E46174600240D +:1002800006E0A200B158A2005019FFF7DDFF641C80 +:10029000BC42F6D30020F0BD0120C043C549086030 +:1002A000401048607047014601229204086890425D +:1002B00001D9102070470020FCE7F0B505460C4638 +:1002C0001646002706E028462168FFF7BDFF2D1DD2 +:1002D000241D7F1CB742F6D3F0BD70B505460C4611 +:1002E0002E460BE0304600F075F9FF2C01D80024B3 +:1002F00001E0FF3C013C012080023618002CF1D1C6 +:1003000070BD0146012292044868904201D909203B +:100310007047A9484069401C01D10F20F8E7002030 +:10032000F6E7FEB504462068030000F037FA05043E +:100330002B4249598B00201DFFF7E3FF0546002D96 +:1003400001D02846FEBDFFF7A7FF0120C00200F044 +:1003500041F9042221469948FFF78DFF002801D07A +:100360000320EFE708222146944800F06DF90028A9 +:1003700006D1002192480068FFF766FF00F00CF9F3 +:100380000320DFE7A768E6686068019031463846D9 +:10039000FFF7A3FF324638460199FFF78EFFB20000 +:1003A0003846019900F050F9002800D1CAE703202F +:1003B000C8E700F0E3F9834800688349086041E03A +:1003C00060680190E668A0680090B200009901980A +:1003D00000F03AF90746002F00D1B3E70E20B1E74D +:1003E000201DFFF760FF0546002D01D02846A9E734 +:1003F0006068002807D1FFF74FFF0320800200F05C +:10040000E9F800F0C9F8FFF747FF0120C00200F04B +:10041000E1F8042221466948FFF72DFF002801D0AA +:1004200003208FE708222146644800F00DF90028D8 +:1004300006D1002162480068FFF706FF00F0ACF823 +:1004400003207FE700BF00207CE770B505460C461F +:10045000182D04D12068FFF764FF206002E001201E +:10046000206000BF00BF70BDF0B589B05248406940 +:1004700003905248806881000398081802900398FE +:10048000000B01900121090302984018401E000B47 +:1004900000900124002520462946019A00F0C4F866 +:1004A0000022401E91410791069001260027304608 +:1004B0003946009A00F0B8F80022401E914105919B +:1004C0000490049BDB43059AD2430698184307998E +:1004D00011430791069037490698086007984860CD +:1004E00009B0F0BD70B53448446934488568466841 +:1004F000AA003146204600F0A7F8002801D00020CD +:1005000070BD0120FCE72D484068002801D0012083 +:1005100000E000200546FFF7E5FF002807D0FFF7C1 +:10052000BBFE0320800200F055F800F035F8FFF71D +:100530009BFF002D0ED020484669204884684768FC +:1005400021463046FFF7C9FE224639463046FFF7BE +:10055000B4FE00BF00F020F810B5184844681A48EF +:100560000460204600F0DCF810BD15480068006803 +:10057000401C01D100BFFEE710480068002802D0EF +:10058000042806D101E0FFF7BEFFFFF7E5FF00BF3B +:10059000FEE700BF00BFFEE7BFF34F8F0B480C49DB +:1005A000C860BFF34F8F00BFFEE7000000E50140C9 +:1005B00000E40140000600400010001000080000A8 +:1005C000B8070000BC070000000000200400FA0586 +:1005D00000ED00E010B50146104B1A6808460223F2 +:1005E0000F4C636000BF0F4B1B68002BFBD0531CEC +:1005F00004D0904202D20A4B186101E0084B986087 +:1006000000BF084B1B68002BFBD00023044C636029 +:1006100000BF044B1B68002BFBD010BD0010001066 +:1006200000E5014000E4014010B5202A04DB01464A +:10063000203A9140002010BD914020239C1A03468F +:10064000E3401943904010BD034610B50B439B0790 +:100650000FD1042A0DD308C810C9121FA342F8D025 +:1006600018BA21BA884201D9012010BD0020C04328 +:1006700010BD002A03D0D30703D0521C07E000208E +:1006800010BD03780C78401C491C1B1B07D1037854 +:100690000C78401C491C1B1B01D1921EF1D118463D +:1006A00010BD70477047704710B500F007F810BDD7 +:1006B000014B1B68DB6818470000002019481A49E5 +:1006C0007047FFF7FBFFFFF7FBFC00BD20BFFDE716 +:1006D0001649174C24688C420BD1164B1B68994263 +:1006E0000CD1154B154A1360186810498842EDD09B +:1006F0000AE0134880F30888124B18470F4A13602A +:1007000018680A498842E1D080F308880E49884277 +:1007100004DD0E48026802210A4302605B68184744 +:100720000346DFE7C0070000C0070000FFFFFFFF30 +:10073000000C000014100010001000000000002049 +:10074000000400206B05000000200020240500406C +:100750000D48704502D1EFF3098101E0EFF3088104 +:10076000886902380078182802D1C046074A104725 +:10077000074A12682C3212681047000000B5054B7A +:10078000054A9B58984700BDFDFFFFFF4B04000042 +:1007900000000020001000000400000030B4744687 +:1007A000641E2578641CAB4204D3635D5B00E318D0 +:1007B00030BC18471D46F8E7000C00000010000090 +:1010000000150020CD64010025220000336401009A +:1010100000000000000000000000000000000000D0 +:101020000000000000000000000000003D6501001D +:101030000000000000000000252200002522000022 +:10104000A9650100AF6501002522000025220000EE +:101050002522000025220000252200002522000074 +:10106000B56501002522000025220000BB650100B6 +:1010700025220000C1650100C7650100CD650100A2 +:101080002522000025220000252200002522000044 +:101090002522000025220000252200002522000034 +:1010A000D3650100D965010025220000252200003A +:1010B0002522000025220000252200002522000014 +:1010C00000F002F815F0E3F90CA030C80838241835 +:1010D0002D18A246671EAB4654465D46AC4201D170 +:1010E00015F0D5F97E460F3E0FCCB64601263342A9 +:1010F00000D0FB1AA246AB4633431847B456010052 +:10110000E4560100103A02D378C878C1FAD85207E1 +:1011100001D330C830C101D504680C6070470000AD +:101120000023002400250026103A01D378C1FBD803 +:10113000520700D330C100D50B6070471FB5C046C1 +:10114000C04615F063F904B00FB41FBDF0B44046BB +:10115000494652465B460FB402A0013001B506482D +:10116000004700BF01BC86460FBC804689469246B8 +:101170009B46F0BC70470000C11000008269024924 +:101180008161024810447047911100000100000085 +:1011900001B41EB400B50BF0E6FF01B40198864619 +:1011A00001BC01B01EBD0000401E00BF00BF00BF5B +:1011B00000BF00BF00BF00BF00BF00BF00BF00BF37 +:1011C00000BFF1D17047000070B505460C461646C9 +:1011D00002E00FCC0FC5103E102EFAD2082E02D31B +:1011E00003CC03C5083E042E07D301CC01C5361F2E +:1011F00003E021782970641C6D1C761EF9D270BD45 +:101200008307FF22DB0E9A408907090E99400028C8 +:101210000BDA0007000F0838830828489B001818CD +:10122000C36993430B43C3617047830824489B0001 +:101230001B181868904308431860704710B504469F +:1012400000210120FFF7DCFF00211820FFF7D8FF65 +:1012500000210B20FFF7D4FF02211920FFF7D0FF58 +:1012600002210D20FFF7CCFF02210E20FFF7C8FF5F +:1012700002210F20FFF7C4FF0221C81FFFF7C0FFA4 +:1012800003211620FFF7BCFF03211520FFF7B8FF4D +:10129000204600F019F8002010BD6421018070473D +:1012A00010B500F020F810BD0648704710B500F0EA +:1012B00022F810BD704770477047000000ED00E055 +:1012C00000E400E003F9004370B505462D4C07200B +:1012D0002070A01CFFF7E1FF5920A080294620467E +:1012E00000F099FB70BD10B500F09EFB2549002071 +:1012F000891E087010BDF8B5224E0446B61E30781F +:1013000001270D46002807D0204660380B2808D852 +:10131000204600F03DFF2BE0602CF9D01A48086011 +:10132000F8BD20466C38032803D8204600F071FF32 +:101330001EE0204670381F2803D8204600F045F9EB +:1013400016E0204690380F2803D8204600F0E8F831 +:101350000EE02046A0380F2803D8204600F074F88D +:1013600006E02046B0380F2804D8204600F0CAF91D +:10137000286000E02F60602CD2D128680028CFD1EF +:101380003770F8BD1A000020013000000120244908 +:10139000C003086023490020087007202249C005C7 +:1013A0008860704770B51F4D04462878A04207D06A +:1013B000002C05D0002803D01CA14D2015F033F8D7 +:1013C0002878A0420ED000211D4A17482C70002C0E +:1013D00019D01C4B012C06D0022C0BD013A1682075 +:1013E00015F021F870BD11600221116053610321D5 +:1013F000090605E011600321116053610121C9054F +:101400008160416070BD116011600721C905816074 +:1014100070BD10B505A1712015F005F810BD0000D4 +:1014200080E100E02000002000F501407372635C61 +:1014300068616C5F63636D5F6161722E63000000C1 +:1014400000F500404001002010B5A038030015F061 +:10145000DBF80B070E172028313A414B525C650030 +:101460004B6808788A68194603F0E6F910BD888849 +:101470008A6883B20888194680B203F0ECF910BD7F +:1014800008884C68CB688A6880B2214603F0E7F987 +:1014900010BD08884B688A6880B2194603F0FBF9D2 +:1014A00010BD88888A6883B20888194680B203F024 +:1014B00007FA10BD88888A6883B20888194680B206 +:1014C00003F041FA10BD08884A6880B2114603F063 +:1014D00080FA10BD088982B2888883B208881946CC +:1014E00080B203F081FA10BD08884A6880B21146C4 +:1014F00003F09EFA10BD08894C6882B20888CB6858 +:1015000080B2214603F018FB10BD08884C68CB68F8 +:101510008A6880B2214603F02AFC10BD012010BD6C +:1015200010B59038030015F06FF809060F161D244A +:101530002C363F464E0088888A6883B20888194650 +:1015400080B204F031F910BD08884A6880B21146B3 +:1015500004F065F910BD08884A6880B2114604F0AD +:101560006AF910BD08884A6880B2114604F070F923 +:1015700010BD08884B688A6880B2194604F07BF970 +:1015800010BD088982B2888883B20888194680B263 +:1015900004F07AF910BD08894B6882B208881946B0 +:1015A00080B204F090F910BD08884A6880B21146F4 +:1015B00004F09BF910BD888882B20888114680B279 +:1015C00004F0EFF910BD012010BD10B57038030014 +:1015D00015F01AF81B0F15192125282F363B40440A +:1015E000484C53585F688D707980888D8D8D8D8FB4 +:1015F00096004A680878114608F0FDFD10BD08689D +:1016000008F04AFE10BD0C790B7B8A6808682146F9 +:1016100008F053FE10BD086808F011FF10BD08F077 +:1016200065FB10BD08884A6880B2114609F043F88E +:1016300010BD0A790888114680B209F0D3F810BDB0 +:10164000087840B209F0DCF810BD088880B209F0D3 +:10165000F0F810BD086809F0FEF810BD086801F048 +:10166000D2FB10BD086801F0FCFB10BD088982B2F6 +:1016700009C9194609F007F910BD05C9114609F055 +:1016800051F910BD08884A6880B211460AF0A6F9DF +:1016900010BD0C790888CB688A6880B221460AF0B0 +:1016A000C5FA10BD0B7908888A6880B219460AF01D +:1016B0006DFC10BD08884C68CB688A6880B22146F2 +:1016C0000AF0D5FC10BD08884A6880B211460AF0BD +:1016D00018FD10BD0B7908880A7A80B2194609F006 +:1016E00044F910BD088880B209F044F910BD062005 +:1016F00010BD08884A6880B2114609F042F910BD51 +:10170000012010BD10B5B02805D0B12808D0B228EE +:101710000BD0012010BD088880B20BF0FBF810BD83 +:10172000088880B20BF015F910BD08884B688A68EC +:1017300080B219460BF01EF910BD000010B5030071 +:1017400014F062FF0A0609060C0C0F0F06060612BB +:1017500008F0F4FA10BD0AF0C5FE10BD01F03EFA23 +:1017600010BD06F09FFA10BDFAA1FE4814F05BFE12 +:1017700010BD3EB5FC49054603C900900191FF200C +:10178000C33069460881F94A092310460A212838DE +:101790000BF0BFFD0024F6480BF0D9FD641CE4B249 +:1017A0000A2CF8D3F14801231A4602A990300BF015 +:1017B000A0F9002804D0FF20E6A13D3014F033FE4C +:1017C000686800F024FC00211E22084604F06CF931 +:1017D00008F0C3FC02222421E64801F07DFBE54825 +:1017E00001222C214C3001F077FBE2490B20B0396B +:1017F00001F0FEF9002804D0FF20D6A1513014F0EA +:1018000012FE0AF03EFE02F097F96B460022082114 +:10181000D9A008F07DFB002804D0FF20CDA15730CF +:1018200014F001FE284602F0E7FC002804D0FF2057 +:10183000C8A1593014F0F7FDF3218900D14814F004 +:10184000D3FCD04801214171022181710721C1716E +:101850003EBD10B5CB4CA0780A2804D3FF20BDA113 +:10186000903014F0E0FD20786021484300190021F9 +:101870000173417BF722C908C900C91C1140EF223E +:10188000114041730121E1700C3010BD70B50E465E +:1018900000211C4619801546030014F0B5FE0723ED +:1018A000050B1711231D23002246294630460AF056 +:1018B00037FE70BD22462946304608F095F870BDC7 +:1018C00022462946304601F0E2FF70BD22462946F5 +:1018D000304603F0EAFD70BD22462946304600F04E +:1018E00010FC70BDFF209BA1EF3014F09CFD032085 +:1018F00070BD70B5A34CE078002818D02078602126 +:1019000048430019407B00254007400F0119087922 +:10191000401E08712078401CC0B220700A2800D1F7 +:101920002570A078401CA0700BF097FEE57070BD8C +:101930009448C079002800D08BE7704770B5914D6E +:10194000A86800280CD0FFF7F3FF002862D06022BF +:10195000A968FFF739FCFFF7CCFF0020A860EFE78C +:101960006879002856D0FFF774FF044681484C3050 +:1019700001F0C2FA6060002804D17A4875A14A30AB +:1019800014F051FD606801F01AFB00280DD02046CC +:1019900007F00BFF6078010703D5C008C000401CAA +:1019A0002BE0744861684C302DE0724861684C301F +:1019B00001F0ABFA00F05AFB00282BD1FFF749FFEA +:1019C00004466C4801F098FA6060002804D1332086 +:1019D00060A1000114F027FD606801F0F4FA00280E +:1019E00014D060680088608020460AF0CCFD6078E2 +:1019F000010706D5C008C000801C6070FFF779FFA2 +:101A00009EE75C48616801F080FA99E7594861688F +:101A100001F07BFA70BD10B55B4CE160A0605B48E3 +:101A200000F032FC607010BD57490020087070470C +:101A300070B5574E0546706A94B00C46401C04D1F0 +:101A4000B06AC0430004000C0BD0306AC007C00F5E +:101A50002870706A14F0DBFBB06A2071000A6071B4 +:101A600014E02B206946087009A9684601F07BFA4A +:101A7000002804D03B4837A17E3814F0D4FC012064 +:101A8000287006220AA9204614F04FFB2878002867 +:101A900003D06079C0210843607114B070BDF0B507 +:101AA0003B4C0646206895B00D4637460837401C2B +:101AB00008D16068401C05D1A068401C02D1E068D4 +:101AC000401C11D02068314614F0A1FB6068311D24 +:101AD00014F09DFBA068394614F099FBE06831468C +:101AE0000C3114F094FB25E02B206946087009A9FD +:101AF000684601F038FA002804D01A4815A1553874 +:101B000014F091FC08220AA9304614F00EFB2B2099 +:101B10006946087009A9684601F025FA002804D032 +:101B200010480CA14E3814F07EFC08220AA9384651 +:101B300014F0FBFA20692E460836401C08D1606973 +:101B4000401C05D1A069401C02D1E069401C33D083 +:101B500020691FE07372635C686F73745F636F72F8 +:101B6000652E6300C3020000F866010094010020A6 +:101B70003D170000640800206E524635313832327D +:101B800000000000E8030020240000203D190000B0 +:101B900080000010294614F03AFB6069291D14F0FA +:101BA00036FBA069314614F032FBE06929460C315E +:101BB00014F02DFB15B0F0BD2B246846047009A964 +:101BC00001F0D1F9002803D0F649F74814F02BFCB6 +:101BD000082209AF28460AA914F0A7FA684604703B +:101BE00009A901F0C0F9002804D0EF48ED49C01D53 +:101BF00014F019FC0822391D304614F096FAD9E782 +:101C000070B5EA4C0546A068002804D0E648E549CE +:101C1000563014F008FCA56070BD10B50146E448CC +:101C200001F073F9E1498879401CC0B2887101283C +:101C300003D1E048407800F04BFB10BD70B504467E +:101C4000DD4816460D46814204D1D748D549CB30F0 +:101C500014F0E9FB012E05D0D348D249DA3014F054 +:101C6000E2FB70BD6620207000202072A58101205B +:101C7000A07370BD70B515460C460646FFF758FEBA +:101C800000280CD066210170468001210172216874 +:101C90000161A18881820573FFF72BFE70BD1321BE +:101CA000304608F09FFD70BDC2494968884201D2A4 +:101CB00010207047072101700020704770B5BD4C9F +:101CC00005462078002694B0002801D00820E4E6DC +:101CD000BA4A6260954201D21020DEE668680028A8 +:101CE00009D00921D82804D3C31C9B089B00834238 +:101CF00005D00846D1E60720000268600EE0012109 +:101D000009074B6B896B4B43AD49511A0122591A94 +:101D1000D202891A814201D20421EAE700F050FF81 +:101D20006178A06806F052F8E068401E07280BD8DA +:101D3000302269460A708870684607F007F9002863 +:101D400002D009A806F07CFA2846FFF712FD012010 +:101D500020703046A1E6F8B5044696480F46406824 +:101D6000814208D3002C01D0844204D3E01C8008B7 +:101D70008000A04201D01020F8BD8C488178002955 +:101D800011D0398800914178602251430D18287B89 +:101D90000C350007000F3B4600222946FFF776FD71 +:101DA000060004D015E0002038800520F8BD002C86 +:101DB00013D039880098814201D90C260DE028788B +:101DC0003B460007000F22462946FFF75FFD06004D +:101DD00005D00C2E01D0002038803046F8BD734C61 +:101DE0006078401CC0B260700A2801D10020607089 +:101DF000A078401EA07068784107490F01290ED0D5 +:101E0000022906D003291AD066496E4814F00BFB4C +:101E1000E3E7C006E1D46868FFF7FFFEDDE764484A +:101E200069684C3001F071F86079401CC0B2607193 +:101E30000128D2D15F48407800F04AFACDE7E07936 +:101E4000401CE071C9E7604A10B5904209D3594A75 +:101E50000124A4045268A04201D3904201D39142CC +:101E600001D2102010BD00F0FCFE10BD564B10B585 +:101E7000994209D34F4B0124A4045B68A14201D3CA +:101E8000994201D39A4201D2102010BD022803D0FA +:101E9000102801D0092010BD00F009FF0028FAD059 +:101EA000052010BD484B10B598420DD3414B01247D +:101EB000A4045B68A04201D3984205D3994203D39E +:101EC000002A03D09A4201D2102010BD00F015FF65 +:101ED0000028FAD0072010BD10B50446354894B04C +:101EE0004068844202D2102014B010BD0F2008A90F +:101EF000087369460BA801F036F80028F4D168464B +:101F0000007A207068464089608068468089A08099 +:101F10000020E9E710B500290BD0264A526891420B +:101F200002D30B68934201D2102010BD8A88002A88 +:101F300002D001F05AFE10BD092010BD10B5224A92 +:101F400094B091420ED31B4A01239B0452689942DC +:101F500001D3914206D3441E1E2C41D8994203D38B +:101F6000914201D21020BFE7012837D10878002420 +:101F7000C007C00F002803D003206946887001E025 +:101F80006846847038206946087009A9684600F0E0 +:101F9000EAFF002804D041200CA1C00014F043FA4D +:101FA0002046A1E7541B000093020000E803002034 +:101FB0006408002024000020FFFF0000001900201A +:101FC000000000200A040000008001007372635CBE +:101FD000686F73745F636F72652E6300072083E719 +:101FE0000246203A1F2AF9D807F0F9FF7CE710B51E +:101FF0005F4A5268914201D2102010BD0246203A39 +:102000001F2A02D808F065F810BD072010BD70B572 +:102010000546584C0020207020464619544846601A +:10202000E01C80088000A04204D0FF2052491330F9 +:1020300014F0F9F901200007C06AC0430006000E41 +:1020400003D14E480068401C03D04D484D49301A1A +:10205000C862A8B20122214604F039F9002804D050 +:10206000FF204549233014F0DEF970BDF0B595B07E +:102070003B2008A9087369460BA800F074FF0028EC +:1020800004D0FF203C496B3014F0CDF93E4E0024C3 +:102090006D4630E02F19B87DC10706D0400704D443 +:1020A00060004019C0880AF08DFB3848807900280C +:1020B0001FD0B87D80071CD560004019C088002261 +:1020C00006210AF09CFB002813D03C2108A80173CC +:1020D00060004019C1886846C18569460BA800F0B8 +:1020E00042FF06000BD0FF2023497F3014F09BF9FC +:1020F00005E0641CE4B268460079A042CAD83046C4 +:1021000058E5F7B505460078002700090C463E461D +:10211000062804D0FF201849A83014F084F9287A42 +:1021200000280ED0012814D0FF201349C93014F024 +:102130007AF90298002C068001D027806680002062 +:10214000FEBD02270926002C0ED0A889A080A87BFE +:1021500008E003271426002C06D02869E060A88A2E +:102160002082287B2072E4E702980680E7E70000DF +:102170002400002000190020CC1F000000100010D7 +:10218000000000200005004004300000E8030020AB +:1021900010B56038030014F037FA0A060A0F131856 +:1021A0001F252930353A0868FFF788FD10BD05C99D +:1021B0001146FFF7D0FD10BD0868FFF775FD10BD93 +:1021C00005C91146FFF73FFE10BD4B6808788A68C5 +:1021D0001946FFF74BFE10BD8A6809C91946FFF77B +:1021E00061FE10BD0868FFF777FE10BD08884A68D9 +:1021F00080B21146FFF78EFE10BD05C91146FFF7EC +:102200009DFE10BD05C91146FFF7F1FE10BD01206E +:1022100010BD0120704700000E4A12680C498A4226 +:102220000AD118470B4A1268094B9A4204D101B5EA +:102230000AF090FF03BC8E46074909680958084711 +:1022400006480749054A064B704700000000000099 +:10225000BEBAFECA7800002004000020001500204D +:102260000015002001203F49400608603E490860F3 +:102270003E490A68FF231B029A4383121A430A60ED +:10228000384980390860704710B502460420384943 +:1022900004E0C3005B181B79002B0AD00346401EE4 +:1022A000C0B2002BF5D133A1432014F0BCF8FF20BD +:1022B00010BDC300CA50002259184A718A71012208 +:1022C0000A7110BD2A4A0021C000801801717047B0 +:1022D00010B50446042803D326A1522014F0A3F815 +:1022E0002348E1000C182079012803D021A15320B4 +:1022F00014F099F86079A179401CC0B2814200D0F5 +:1023000060710120174940068031086010BD70B52A +:10231000164804250068164E0004800F1B4C022846 +:102320001AD014A1692014F07EF815E02078C100BD +:1023300088190279012A07D1427983799A4203D018 +:1023400042798271705880472078401CC0B220705A +:10235000042801D30020207028466D1EEDB200280D +:10236000E4D170BD80E100E080E200E018E400E02C +:10237000E00800207372635C736F635F7369676E5C +:10238000616C6C696E672E630000000034000020F1 +:1023900010B5EFF31080C407E40F72B6D24841784D +:1023A000491C41704078012801D10BF07BF9002CC9 +:1023B00000D162B610BD70B5CB4CE07800280AD1D0 +:1023C0000125E570FFF7E4FF0BF074F9002804D055 +:1023D00000200BF047F9002070BDC44865714560CE +:1023E000F9E770B5EFF31080C507ED0F72B6BE4C7C +:1023F0006078002803D1BEA18F2014F014F8607813 +:10240000401E60706078002801D10BF04FF9002D5C +:1024100000D162B670BD10B5B348C178002904D0B0 +:1024200000214171C170FFF7DCFF002010BD10B525 +:1024300004460BF03FF9AC49C978084000D00120B0 +:102440002060002010BDF8B50246A74C0026A671FA +:102450000820042101251027130014F0D5F80D08D9 +:102460000A0C0E101214161E262123252800257191 +:1024700022E0022001E021711EE020711CE02771A2 +:102480001AE02020F9E7012616E0FFF781FF0BF0A4 +:1024900011F90028FBD002260EE02171A5710BE096 +:1024A0002771FBE7202000E040202071F6E7FF20A5 +:1024B0008FA1763013F0B7FF0BF008F9002809D090 +:1024C0000BF00AF9B04205D130460BF008F90028AC +:1024D000FAD02CE001208007C560894900224A60BB +:1024E000884A9661814B02225A608560864802695B +:1024F000D243D206D517026910231A4302610F4650 +:102500006D1C00E020BF78680028FBD030460BF03F +:10251000E6F80028FAD0002D04D17B48026910218A +:102520008A43026171490220886000207860A079A6 +:1025300000280CD00BF0BEF805460BF01BF8734AD0 +:10254000002D02D0A260E06001E0E260A060002EF9 +:1025500001D100F0A5F8F8BD10B504460BF0B0F8B5 +:10256000002805D060490120C8704A78521C4A7082 +:102570002046FFF768FF10BDF8B5614DA86800263A +:10258000012802D1AE600BF06DF86868012800D117 +:102590006E6028680127544C012812D12E606079A2 +:1025A000002803D000200BF05DF866712078002829 +:1025B00007D00BF07FF8002803D0012080070761C7 +:1025C000A770286901282AD12E6100F05FF8012048 +:1025D00080074761A079002815D00BF06BF80090B8 +:1025E0000AF0C8FF0099002901D0E16800E0A16865 +:1025F000411A022901DA8A1C11DC0099002901D054 +:10260000E06000E0A060FFF7C3FE0BF053F8002885 +:1026100004D0012080070761A77000E02770E868F8 +:10262000012812D100F032F800F030F800F02EF856 +:10263000A078002804D1FF202DA1033013F0F3FE71 +:10264000EE60A6702670FFF7CCFEF8BD10B5264CE4 +:10265000E078002801D10BF029F80120810788617A +:1026600000F014F8A07800280BD0254CE068002872 +:1026700003D10BF034F80028F8D10020E06000F01E +:1026800005F800201949C043886010BD08B55020E6 +:10269000694608806A461088411E1180FAD208BD3A +:1026A000F8B5124819278760154900200860C860EE +:1026B0000BF000F8BE0701240B4D002802D0346156 +:1026C000AC7000E02C70FFF763FE084847600D49CE +:1026D00028798863FFF7DAFFB461FFF7D7FF08496D +:1026E000002008617461F8BD38000020000300403C +:1026F0007372635C736F635F636C6F636B2E6300F5 +:10270000000100400005004000ED00E0FFFFFF7FFA +:102710008107C90E002808DA0007000F0838800872 +:102720002E4A80008018C06904E080082C4A80008E +:1027300080180068C8400006800F704710B50D2053 +:10274000FFF7E6FFC4B20420C043FFF7E1FFC0B2C9 +:10275000844203D023A11A2013F065FE26490120EC +:10276000486010BD0121254A48031060244B002217 +:102770001A60244A5160244A1060244A11601F499B +:1027800080390860704701211C4A480310601F4AC5 +:1027900051601B4A002111601B490860704710B549 +:1027A00017490868012804D00EA1572013F03BFEFA +:1027B00010BD114880680022C0B20A600AF020FCF7 +:1027C00010BD10B50E4801680029FCD0FFF7E7FFE7 +:1027D00001200D494003086010BD000000ED00E03D +:1027E00000E400E07372635C736F635F68616C5F49 +:1027F000726E672E6300000000D5004080E100E0AB +:1028000000D1004000D3004080E200E000D0004052 +:1028100030B40121BC48C9020160CD1005604A03F3 +:102820000260BA4803681B021B0A036004680023A5 +:10283000240A24020460B6480468240A24020460BE +:10284000B448012444608460B34C23606360A36097 +:10285000B24B19601D601A60B14B19601A600121FA +:10286000016030BC704710B40121A748CA02026061 +:102870000B0203600C060460A64841608160A94811 +:1028800041680029FCD1A4490020086048608860A4 +:10289000A24802600360046010BC704701219F4899 +:1028A000C9020160C91001607047002805D00128E5 +:1028B00005D0022805D19C4870479C4870479C4829 +:1028C000704710B59BA18B2013F0ADFD002010BD0B +:1028D00070B500219E4C9F4D9F4A8F4B002808D019 +:1028E00001281DD0022822D092A1B32013F09BFD15 +:1028F00070BD01200004A060A86011601960974BB2 +:10290000C2039A60964A90607F4A00121060954810 +:10291000016086480160944801609448017070BD70 +:1029200001204004A060A8605160596070BD012082 +:102930008004A060A8609160996070BDF8B594466D +:10294000834A8B4F834D00240126002808D001289C +:1029500032D0022840D077A1E82013F064FDF8BD02 +:10296000891E0902090A0120000490603C64686025 +:102970006C4A1164012B1DD000217C4A7D4B5170A3 +:102980006146DC63DE637C4B5C6002249C60042453 +:102990001C61744B3D31196073490E605F4B8915A2 +:1029A00019606F4B58605E4801606C49C005486013 +:1029B0001670F8BD0121E0E70120704E4004704F11 +:1029C000012B04D13464506068603964F8BD9060B4 +:1029D000346468603964F8BD01206A4E80046A4F2F +:1029E000012BF4D1EEE74F484068704770B54A4D6F +:1029F00028680026564C012806D1A068C00303D5DC +:102A000001200004A0602E606868012809D1A06838 +:102A1000800306D501204004A0606E6001200BF009 +:102A200041FEA868012809D1A068400306D501200D +:102A30008004A060AE6002200BF034FE70BD10B5C3 +:102A40004A490878002818D00120444AC0079060FD +:102A5000434AC00B90602C4A00121060414A00208B +:102A60001060324A1060404A106008704A78002AAC +:102A700002D048700BF016FE10BD0320FAE70120CB +:102A8000424900060860704701202449000608609A +:102A9000704701203D4940050860704701201F49EB +:102AA00040050860704733490020C86388151B49FA +:102AB00008607047410A364AC005C00D5043801C6B +:102AC0005143400A0818704710B4324C430B63431B +:102AD0001B0C5C020C602E4C6343C31A2E485C0234 +:102AE00058432B4B400D4343E31A0124DB032404DA +:102AF0001B191B1613700A681018086010BC704769 +:102B000010B50BF0A2FE10BD80E100E008E400E08B +:102B100018E400E000B0004040B1004080E200E076 +:102B200000E100E000B5004048B1004040810040B5 +:102B300044B100407372635C72656D5F68616C5F85 +:102B40006576656E745F74696D65722E6300000052 +:102B500000B3004040B3004040B5004000F50140E4 +:102B60000083004040850040008200404800002073 +:102B700000B10040C08F00400085004004B100401B +:102B800004B5004008B1004008B5004000E200E094 +:102B9000093D0000378600006F0C010010B50BF0F6 +:102BA00040FE10BD00200449C8630120012181407E +:102BB000024A116000BF7047C01F004080E200E081 +:102BC00010B50CF097FA0AF059F9FEF7DFFB12F096 +:102BD00063FA0CF0F5FF0CF081FF10BD70B50C46E8 +:102BE000054603F0D5FA214628460EF026F870BDBA +:102BF00070B50D46040012D0002D10D021012846DA +:102C000013F0F0FA10225449284613F08EFA524875 +:102C100001210838018044804560002070BD0120FA +:102C200070BD70B54C4E00240546083E11E0716839 +:102C300020014018817BAA7B914209D1C17BEA7BAC +:102C4000914205D10C22294613F042FA002806D001 +:102C5000641C30888442EADB0020C04370BD2046FB +:102C600070BD70B50D4606000AD0002D08D03A4C54 +:102C7000083C20886188401C884203D9042070BD2C +:102C8000102070BD3046FFF7CCFF002801DB401C50 +:102C90000AE020886168000140181022314613F0D4 +:102CA00044FA2088401C20802870002070BD70B538 +:102CB00014460D001FD0002C1DD00021A170022849 +:102CC00002D0102817D108E068782978000208435C +:102CD00011D00121A17010800BE02846FFF7A1FF61 +:102CE000002808DB401CA070687B297B0002084399 +:102CF0002080002070BD012070BD70B505461446CF +:102D00000E000AD000203070A878012807D004D91E +:102D1000114908390A8890420BD9012070BD002C56 +:102D200004D0287820702888000A5070022008708B +:102D300010E0002C0CD049680001411810222046F8 +:102D4000103913F0F2F9287820732888000A60738C +:102D500010203070002070BD540000205A4910B57A +:102D6000884207D301218904884205D3574909685D +:102D7000884201D2102010BD0146012006F0E4FA7D +:102D800010BD30B5044693B000200D4607901421C5 +:102D90000BA813F029FA1C21684613F025FA6A469D +:102DA000112010770020507710780221084310700E +:102DB00007A80C90012008AA907245486A46108521 +:102DC0000AA80B902088108460885084A088908482 +:102DD000E088D084907FF9210840801C40084000A2 +:102DE000907708209086108708A80F9010AA0BA94A +:102DF000684600F083FF002803D110A800882880CF +:102E0000002013B030BD3EB5044608206946088056 +:102E10002D48844207D301208004844205D32B48E7 +:102E20000068844201D210203EBD2146012006F0F8 +:102E30008BFA0028F8D12088694688806088C8808D +:102E4000A0880881E088488107F05FF801AB6A46F6 +:102E5000002101F0E1FB694609880829E4D003203C +:102E60003EBD1FB504460020029008206946088137 +:102E700015480391844207D301208004844206D37D +:102E800012480068844202D2102004B010BD07F03E +:102E90003CF8014602AA0F4801F055FD0028F4D184 +:102EA00069460989082901D00320EEE769460988A7 +:102EB000218069464988618069468988A180694680 +:102EC000C988E180E1E700000080010028000020BF +:102ED000042A0000FFFF000010B5031D036000205E +:102EE000521E04E05C181C60401C2346C0B2904295 +:102EF000F8DB0020186010BD01460A680020002A97 +:102F000002D0104612680A60704702680A600160C9 +:102F10007047000000B51E2823D00BDC0C281CD005 +:102F20001FDC030013F070FB090F1D111D1D171787 +:102F300013151D00302814DD3A38030013F064FB2C +:102F4000030F11091100002000BD214800BD04201D +:102F500000BD0D2000BD0F2000BD082000BD1120C8 +:102F600000BD032000BD10B50C4605F0EFFF0028A2 +:102F70001ED0204605F064F9002816D022780E2ACB +:102F80000DD00F2A0BD0022A09D0032A07D0102A0D +:102F900009D010A17C2013F046FA002010BDA078C3 +:102FA000FFF7B8FF10BD112010BD0AA18220F2E783 +:102FB00008A18820EFE710B504F083FF10BD10B51D +:102FC00005F03EF910BD10B504F0D9FF10BD0000AA +:102FD000023000007372635C686F73745F686369CA +:102FE0002E63000070477047704770477047704706 +:102FF00070477047704770477047704770470000D0 +:1030000010FFFFFFDBE5B151008001006400FFFF0E +:1030100003B40148019001BD09000020002803D03D +:103020008178012939D101E0102070470188FE4ADA +:10303000881A914233D01BDCFC4A881A91422ED068 +:103040000BDC00292BD00320C002081A27D001284E +:1030500025D001210903401A07E001281FD00228CA +:103060001DD0FF281BD0FF380138002815D116E0ED +:10307000FF220132811A904211D008DC01280ED0C3 +:1030800002280CD0FE280AD0FF2806D107E001292B +:1030900005D0022903D0032901D0002070470F205A +:1030A000704700B50B2826D009DC030013F0ACFAFA +:1030B0000B1D2125251B25292325271F1B00112832 +:1030C0001BD008DC0C2816D00D281CD00F2814D0DB +:1030D000102808D10FE0822809D084280FD0852835 +:1030E0000FD0872811D0032000BD002000BD05208F +:1030F00000BDCF4800BD072000BD0F2000BD04204B +:1031000000BD062000BD0C2000BD0D20800200BDCA +:1031100070B500290BD0CB1FFA3B81241E46CDB2DF +:10312000112B1BD2012805D0022806D009E000206F +:1031300010701DE0FF20043001E0FF2003308142C9 +:1031400018D0330013F060FA111613131613161665 +:103150001316161613131313161316000846FF380A +:1031600081381F2803D9FF39FE39022902D815708A +:10317000002070BD1470072070BD00B5030013F06F +:1031800043FA060406040C080A0C002000BD1120B6 +:1031900000BD072000BD082000BD032000BD007851 +:1031A0000207120F04D0012A05D0022A0AD10EE02C +:1031B000000907D108E00009012805D0022803D042 +:1031C000032801D0072070470870002070470620B0 +:1031D0007047002807D0012807D0022807D003280D +:1031E00007D007207047002004E0112002E02120D2 +:1031F00000E0312008700020704738B50C4605000B +:103200004FD06946FFF7CBFF002822D12088032149 +:1032100089028843694609788907090D0843208097 +:103220006946681CFFF7BBFF002812D121880320E4 +:1032300000038143684600788007800C01432180A9 +:10324000A8784007820F2020012A03D0022A03D049 +:10325000072038BD814300E00143218088B2010589 +:10326000890F08D0012189038843A9780907C90F6C +:1032700089030843208080B28104890F0AD0A9788D +:103280004004C906C90F400CC903084320808004CC +:10329000800F02D12088400403D5208840210843B4 +:1032A0002080002038BD70B50446002008801546F7 +:1032B0006068FFF7A2FF002815D12189A08981420B +:1032C00010D861688978C90708D00121490288426D +:1032D00008D8491C12F0A3FF298009E0FF21FF3123 +:1032E000884201D90C2070BDFF30FF3003302880A8 +:1032F000002070BD10B5137804785B08E4075B000C +:10330000E40F23431370FD2423400478A407E40F43 +:10331000640023431370FB24234004786407E40F04 +:10332000A40023431370F724234004782407E40FF8 +:10333000E40023431370EF2423400478E406E40FF1 +:10334000240123431370DF2423400478A406E40FF0 +:103350006401234313700078BF244006C00F23404C +:10336000800103431370002906D00878C10701D1FA +:10337000800701D5012000E00020C0015906490E58 +:103380000843107010BD30B50A8803239B020488DF +:103390009A4323059D0F02D1A3049C0F01D09B0FDC +:1033A00000E001239B021A4303230A801B039A4374 +:1033B00003889804840F02D11805830F01D0800F71 +:1033C00000E00120000302430A8030BDF3B593B052 +:1033D0000D000FD0139800280FD01221284612F0AC +:1033E00001FF03AAFF21012003F0E7F8002426468D +:1033F00037467AE0102015B0F0BD0720FBE768469D +:10340000807D01280BD16846818A0520C002081AF8 +:1034100010D0012810D0022812D0032812D0042C7A +:1034200014D0052C15D113E002290000012800005A +:1034300003300000012400E002246846468A08E0C8 +:10344000032406E068460424478A02E0052400E0DD +:1034500006246846418A1398814246D12C74002E76 +:1034600041D00DAA0EA905200292019100901023CF +:103470000022FF21304603F041F9002823D168469D +:10348000808E2A46C0B20EA9FFF711FC00281AD17F +:10349000AE81002F27D00DA9052008AE0291009023 +:1034A000132300220196FF21384603F027F9002854 +:1034B00009D16846808EF11CC01EC0B22A1DFFF7DC +:1034C000F6FB002801D0032095E708A88178427810 +:1034D00008021043E881062C05D16846807DA87259 +:1034E0006846808A2881002085E703A803F06EF8EB +:1034F000002884D0FFF7D5FD7DE7002805D0F94AE4 +:10350000012903D0022903D003207047518800E02D +:103510009188814201D1002070470720704770B523 +:103520000C4605461C21204612F05CFE002020803F +:10353000002D08D0012D04D0EBA1F04812F073FF4C +:1035400070BD062000E00520A07070BD70B592B07F +:103550001546064601206A461071107453740846D9 +:1035600008300395029048889082FEF7E1F9040044 +:1035700019D06580172069468883203600940AABED +:103580007178023307AA01A80DF05FF9064660784A +:10359000000701D5FEF7ADF9002E0AD03046FFF73F +:1035A000ECFD12B070BD1321284607F01BF9032073 +:1035B000F7E708A800906846838B0422012128467B +:1035C00008F035FEEDE770B506468AB000200D46DE +:1035D00007900590069003A90490052402460291E5 +:1035E0000190102300942946304603F087F8002804 +:1035F0000DD108A804A9009102900194684683891E +:1036000000222946304602F095FE002801D0FFF73F +:1036100048FD0AB070BD10B50DF01DFB10BDF0B532 +:1036200089B000260546059600780C460827030059 +:1036300012F0EAFF0CFD070C3A0B77779EC2FCD81C +:10364000E8FD68680A38FEF7E8FA0DE1A88800236B +:1036500080B201220321009009F08CFA0290002C24 +:1036600004D0A648A0A16E3012F0DDFE029800281A +:1036700004D1A2489CA16F3012F0D5FE02980099A7 +:1036800008300CF017FDFEF753F9040007D06078FE +:103690003843607000986080FEF72BF9E6E0132154 +:1036A000009807F09FF8EFE0002C04D1BD208EA118 +:1036B000800012F0B8FE608800230122032109F087 +:1036C00059FA0090002804D18C4887A1883012F064 +:1036D000AAFE0099002008802A7994461EE0C300C3 +:1036E0005B199B6807936B469B8B1A0708D5DA0614 +:1036F00006D56046C20050194038C08F088006E0E9 +:103700005B0409D50871C2005019C08848806078F0 +:10371000384360700226A7E0401CC0B28445DED862 +:10372000A2E0E888694608800090002C04D1734824 +:103730006DA1983012F077FE2878062814D10098F1 +:10374000C00B11D0608800230122032109F012FA76 +:10375000060004D1694864A1A23012F064FE002082 +:103760003071A88870803BE06078384360707BE0FF +:10377000002C04D161485CA1B43012F054FE608882 +:1037800000230122032109F0F5F90090002804D15B +:103790005A4855A1B73012F046FE009808300DF097 +:1037A000ACFA0121484002D1E888C00B5CD00098F7 +:1037B00061880226C180D7E7002C04D14F484AA176 +:1037C000D03012F030FE608800230122032109F07E +:1037D000D1F9002804D1494843A1D33012F023FE87 +:1037E0000226C1E7002C04D144483FA1DC3012F08E +:1037F0001AFE0226618801222046FEF71FFA0120E8 +:103800000590B1E7A889002380B20122032100902E +:1038100009F0B0F90746002C04D0384832A1EE3048 +:1038200012F001FE002F07D12FA101E00FE016E0FA +:103830003248EF3012F0F7FD686802902889694637 +:103840008881012202A90098FEF714FA0CE0002CEE +:103850008AD16D2024A1C00012F0E5FD84E727483D +:1038600021A1FE3012F0DFFD002C0DD060780007A2 +:103870000AD50598002807D18420207020465822B8 +:1038800029460830FDF7A0FC304609B0F0BDF7B579 +:103890000C460546007A224688B00A320292921CF3 +:1038A00004920027811E16323E4601920B0012F050 +:1038B000ABFE08F605F548488DD1F4F5688800237D +:1038C0000122032109F056F90190002803D106A135 +:1038D0000B4812F0A8FD01980088002812D052274A +:1038E000072601E1000900207372635C676174744C +:1038F000735F636F72652E63000000006F0200004B +:103900008603000051271E26002C7DD06888A080E9 +:103910000120A071019802990079C0004019C08966 +:10392000FFF754FD002870D101980079C0004019BC +:10393000C089208101980079C0004019408AA08385 +:10394000F2E0698A0091062820D1E889C00B1DD0D9 +:1039500008462230512786B2002CD6D0A889049977 +:10396000FFF734FD002873D16888A0800220A07181 +:10397000A88920810120A072288AE08300982084F1 +:103980006969009A019812F0D0FBCDE0084620301A +:10399000502786B2002CB8D0A8890299FFF716FDEF +:1039A000002855D16888A080A889E080287A062858 +:1039B0000AD002202072288AA0830098E083204643 +:1039C00069692030009ADEE70120F3E76888002368 +:1039D0000122032109F0CEF80690688A009006982B +:1039E000002803D1FD49FE4812F01DFD069808305D +:1039F0000DF083F90121484002D1E889C00B26D09F +:103A00000098223086B201E073E021E05127002CBB +:103A100079D06888A080A8890499FFF7D7FC00288E +:103A200016D10220A071A88920810420A072288AC2 +:103A3000E083009820846969009A019812F075FB70 +:103A40000699002008710698A98941806CE003203E +:103A50000BB0F0BD688805F0D2FB019068880023A8 +:103A60000122032109F086F800900198002804D172 +:103A7000DB48DA492C3012F0D6FC0098002804D13B +:103A8000D748D6492D3012F0CEFC0098D549C088D1 +:103A9000884205D05127222604E01EE03FE035E0B1 +:103AA00050272026002C2ED06888A080502F07D0C9 +:103AB0000220A0712146287B0831FFF730FD33E05A +:103AC000287BA11DFFF72BFD6A8800230099019830 +:103AD000FFF73CFD0028BBD126E0C349A889C9886F +:103AE000814207D154270626002C0CD06888A0807C +:103AF0001AE008E053270826002C04D06888A0802C +:103B0000A889E08010E00A98068013E05527072670 +:103B1000002CF8D0A889A0800020A07104E08D209E +:103B2000AE49C00012F07FFC0A98002C068001D03C +:103B30002780668000208BE7AB4900200870704723 +:103B400030B585B00C4601F0E0F90546FF2804D1F8 +:103B5000A348A249953012F066FC00202080207115 +:103B60006080401EE0802046294608300CF096FA1E +:103B70006A462946012002F020FD102412E0684622 +:103B8000808800070ED56846C0882946FFF71BFDD0 +:103B900068468188FF2321438180C0882946019A95 +:103BA00002F036FE684602F011FD0028E7D005B0AD +:103BB00030BD0A46014610B5104608300CF082FAB6 +:103BC00010BD70B5002305461A46032108F0D2FF48 +:103BD000040004D182488149B73012F024FC204609 +:103BE000294608300CF066FA70BDF0B591B00C466D +:103BF000074605F004FB050005D02878222804D2EA +:103C0000082011B0F0BD7948FBE700231A460321D4 +:103C1000384608F0AFFF0646002C02D0A0880028E6 +:103C20000CD00120694608710220087400204874F5 +:103C3000002C05D0A0880883206802E00920E0E776 +:103C4000088305903046083003970290FDF770FE18 +:103C5000040018D0678017206946888320350094B7 +:103C60000AAB6978023307AA01A80CF0EEFD0546FD +:103C70006078000701D5FDF73CFE002D09D02846ED +:103C8000FFF77BFABDE71321384606F0ABFD0320B2 +:103C9000B7E708A800906846838B042201213846C4 +:103CA00008F0C5FA0021C943F180AAE7FFB585B045 +:103CB0000E9E7788384605F0A2FA054600231A467C +:103CC0000321384608F056FF0446002D03D143492E +:103CD000474812F0A8FB002C04D145483F49401C3E +:103CE00012F0A1FB0834089869460394C1C105A8E5 +:103CF0000DC8203569780CF017FAC6E5F0B5044612 +:103D0000002099B00D4601460D9010A881811646FD +:103D100001818180344A68469180018510A8018024 +:103D200068460187818581841078012808D002289F +:103D300006D0032804D0042802D0082019B0F0BD12 +:103D40002C4A944273D32C4F0121890438688C4249 +:103D500001D3844278D3274A954275D3012189043F +:103D60008D4201D385426FD36168002913D0214A67 +:103D7000914269D301229204914201D3814263D3DB +:103D800060892189884203D801225202914201D9D7 +:103D90000C20D3E70D9016AA0EA92846FFF783FA48 +:103DA0000028CBD1686880784007800F02280AD1AC +:103DB0006846008F8004800F05D02869002802D053 +:103DC0003968884240D30AA92069FFF716FA00280B +:103DD000B4D1206900281CD060780FE0E8380000DA +:103DE000EE030000FFFF0000000900200230000089 +:103DF0000C050000008001002800002080076846B4 +:103E0000008D03D58004800F68D002E08004800F0D +:103E100064D16846008D810618D58004800F6068E3 +:103E200006D0002812D0396888420DD302E00BE09A +:103E300000280BD0FE49884206D30121890488421C +:103E400004D33968884201D2102077E709A9606954 +:103E5000FFF7D3F900289CD16069002808D0684694 +:103E6000808C0105890F012938D18004800F35D05D +:103E70000BA9A069FFF7C1F900288AD16846808C98 +:103E800080062BD46846808D810627D4A16900293D +:103E900006D00105890F012920D18004800F1DD093 +:103EA000E068002804D00078002817D01C2815D21C +:103EB00004AA611C2046FFF71DFA0121890210A8FF +:103EC0000180012768468773DA49818104AA033299 +:103ED00017A92868FEF711FF002801D007202DE759 +:103EE00010A8007F15A9C01CC2B200200C9201903E +:103EF000FF32009003460291FF3203A8033210996B +:103F000002F0B3FA002826D110A9888A0F902A89D6 +:103F10002969C94801910092029010A90A8B6B8906 +:103F200028680E9902F0A1FA01007DD1C24800254F +:103F3000001F818868464174090A8174052104A81C +:103F40006A4623C210A82A46FF21808A0C9B02F0F1 +:103F5000F1F9002802D0FFF7A4F8EFE66846007CEC +:103F60000322C1090020920290430122920280188C +:103F70001490002928D0014610A801806846292104 +:103F8000877309028181058608A8007C0023410807 +:103F900060784900C007C00F014308A80174FD20E4 +:103FA00001406078A54A8007C00F4000014308A87F +:103FB00001740CA9022001910090029503A81099A8 +:103FC00002F053FA01002FD16068002828D0206940 +:103FD00000280DD10AA90EA8FFF7D5F9607880074F +:103FE00006D46946088D032109038843694608857C +:103FF000904968468773FE31818190492089891EE6 +:1040000012F00DF962680D9811AB019200900293C5 +:104010000A46002303A80A9902F027FA010003D1F7 +:104020002078C10603D400E086E080062AD56846E1 +:104030000586606900280DD109A90EA8FFF7A3F92C +:104040006846818C03208002814301208002091888 +:10405000684681846946888CC821084369468884FB +:1040600074488F73FF30888112AA0CA90220029233 +:10407000019100900023714A03A8099902F0F5F913 +:10408000010059D12078C00729D068460586A0696B +:1040900000280DD10BA90EA8FFF775F96846818D90 +:1040A000032080028143012080020918684681852F +:1040B0006846818D40200143684681858773604949 +:1040C000818113AA0CA90220029201910090002381 +:1040D0005A4A03A80B9902F0C8F901002CD1E068F4 +:1040E00000282DD010A8149901805549684687737F +:1040F000491C8181E16808A80A78027449784174F2 +:10410000E0684122418868464186E06800230179E1 +:1041100008A80175E068D200C18808A84175090A9D +:1041200081750CA8072101900091029503A81099B0 +:1041300002F09BF9010003D00F9800F0EAFEFDE5C4 +:104140003D480321001F0170002E0AD08088308076 +:1041500010A88088708010A80089B08010A880897D +:10416000F0800020EAE530B501248BB015460B46FF +:10417000012802D002281CD104E06846052184737E +:10418000C90203E02B4968468473891E8181002B94 +:1041900012D003210020890288430121890240189E +:1041A0006946888405AA04A91846FEF7A6FD0028DA +:1041B00004D007200BB030BD1020FBE76A46127C0C +:1041C0001D480092801E05A9FF3201910290FF3226 +:1041D000002303A80332099902F047F9002802D00E +:1041E000FEF75FFFE6E71448001F002D01D041886D +:1041F000298004700020DDE770B592B004460126E6 +:1042000008A886700F496846018410AA08A930469C +:10421000FFF7A9FF00284DD12078074DC0070024E3 +:104220002D1F002848D01C21684611F0DDFF0BE04F +:1042300000800100032800000409002003020000A0 +:10424000032900000118000068460178202001437E +:104250006846017008A88670F9496846018411947F +:104260000794817FF92001406846891C81770020EE +:1042700001466846017700200146684641770421DF +:104280008185C485018607A80A9011A80D9008A809 +:1042900009900EAA09A96846FFF730FD002809D148 +:1042A0006846008FE8806846808F2881401C6881BE +:1042B0002C70002012B070BDEC802C8110A80088FA +:1042C000F4E7F7B5DF4900260A789EB0012A04D04A +:1042D000022A02D0082021B0F0BD4A88824201D0D3 +:1042E0000620F8E71F98824201D10720F3E7012258 +:1042F00010A98A75D4488882002003239B020146B6 +:1043000099439302CB1810A90B8669468A81CF4A3C +:10431000CA8118A9887110A9888419A904916946CD +:10432000CA820690FF20087503A802F072F90024E3 +:104330002546274608AA052103A802F06DF90028A2 +:1043400010D082286FD1002C6FD0002D6DD010A816 +:104350008480C5800021017418A8807B11AC0128DD +:1043600065D06DE008A88079002F21D0012857D1B1 +:104370006846818CB44881421CD113AA0DA905203E +:104380006B4607C36846408C10230022FF2102F0D1 +:10439000B5F9002868D110A88089042801D0062822 +:1043A0004CD16846818E1F98814239D10F2092E707 +:1043B000012835D16846808C0521C902884202D087 +:1043C000491C88422CD19F4841886846408C8142D4 +:1043D00001D1012700E00027002C01D0002D10D0D2 +:1043E0001F9988421CD113AB0DAA05216E460EC63B +:1043F000044610230022FF2102F080F9002833D167 +:1044000001E035460CE010A88089022801D0102870 +:1044100014D1C0B21BAA0DA9FEF749FC00280DD18A +:104420006846468C86E71FE0FFE7052053E714A99E +:104430001BA8221DFEF761FC002801D003204AE7DB +:1044400010A8007C0023001DC2B210A8027420989E +:1044500002900194009215A81C9902F006F8002819 +:1044600002D1784902220A70FEF71BFE33E710B52D +:104470000B46401E86B084B203AA00211846FEF700 +:1044800039FF04AA052103A802920191009001239B +:104490000022FF21204601F04DFF04466846008AB5 +:1044A000012804D06D206A49000111F0BCFF2046AC +:1044B000FEF7F7FD06B010BDF0B5624F0446387840 +:1044C00087B00E46032804D0042802D0082007B085 +:1044D000F0BD04AA03A92046FEF7E5FE0500F6D1CB +:1044E000606880784007800F02280DD16846808977 +:1044F0008004800F08D02069002805D0554909683C +:10450000884201D21020E2E7208905AA6B46216982 +:1045100007C369460A8A63892068039901F0A5FFE9 +:10452000002802D0FEF7BDFDD1E7002E02D068467C +:10453000808A3080042038702846C8E738B50C00DF +:10454000054609D000236A46FF2102F039F9002808 +:1045500004D0FEF7A6FD38BD102038BD69462046C0 +:10456000FEF74BFE0028F8D1A078FF21C307DB0F30 +:104570002846009A02F04CF9EBE73EB50C0009D052 +:1045800002AB6A46FF2102F01BF9002804D0FEF7B7 +:1045900088FD3EBD10203EBD0321204611F022FEC5 +:1045A0006846008801A90005800FFEF712FE00286A +:1045B0000BD16846007920706846008801A9800404 +:1045C000800FFEF706FE002801D003203EBD68469E +:1045D00000796070A278EF20024068460088C10B25 +:1045E00009010A43F7210A404104C90FC9000A43DF +:1045F000A270F9210A40800601D5022000E00120C6 +:10460000400069460243097A50084000C907C90FB3 +:104610000843A07000203EBD7FB5144605220192DC +:1046200003AD029500930A462388FF2101F082FE24 +:10463000694689892180FEF734FD04B070BD000011 +:10464000052A00000009002002280000FFFF0000EA +:10465000E838000028000020F3B5002799B068462C +:104660000C4607873D4600291ED0E068002806D08A +:10467000A068002818D001886A4611870780199819 +:1046800004F0BDFD002812D0007822287ED31998AE +:1046900000F03BFC002300901A460321199808F013 +:1046A00069FA060009D104E010201BB0F0BDFD48F6 +:1046B000FBE7FD49FD4811F0B6FEA078012803D0C4 +:1046C000022801D00720F0E72088002808D0401EEB +:1046D00080B203AA009901F070FF002859D11DE0B3 +:1046E000F048401CE1E76946498A228891420BD292 +:1046F0006846807D0025012810D16846808AEC49F3 +:1047000088420BD1012509E0914203D1002D2AD026 +:104710006D1C01E0022D0BD0032D04D203A801F083 +:1047200055FF0028DFD082281BD0002831D11DE0A2 +:104730006946897D0129F1D16946DD4B8A8A5B1E74 +:10474000D11A9A420FD005DCDA48101A0BD0012892 +:10475000E4D108E0012906D0FF390129DED1032583 +:10476000E1E7022D15D10D2080029EE7E0680028C8 +:1047700016D00EA9052202910192009069460B8F76 +:10478000A2882088FF2101F0D5FD00E01EE000286E +:1047900002D0FEF786FC88E76846A168008F088093 +:1047A0006846008AC00601D5C3487EE707980028FE +:1047B00003D06846008B022801D0032075E70798D4 +:1047C000A1780078012903D0800710D408206CE775 +:1047D000C007FBD000220721199808F010F8002824 +:1047E00002D00725022004E0AE48801C5DE70225C8 +:1047F000032008A908702188684681851998083621 +:104800000A90099617216846818712AB02330FAAD6 +:10481000052108A800970CF018F8002802D0FEF730 +:10482000ACFC42E710A800906846838F042229461A +:10483000199807F0FCFC38E770B5064615460C469B +:104840000846FEF7EBFB002804D12A4621463046F5 +:10485000FFF789FCF2E610B5FFF733FD10BD70B528 +:104860001E4614460D0014D0002C12D06168002999 +:104870000FD00121FEF741FE002809D12068FEF784 +:10488000CDFB002804D1324621462846FFF736FAF0 +:10489000D4E61020D2E670B515460C000ED00221E9 +:1048A000FEF72BFE002808D12068FEF7B7FB002892 +:1048B00003D129462046FFF7FFFDBFE61020BDE6E5 +:1048C000F8B506467D480D46016814468A4231D344 +:1048D0006068002808D07A4A90422BD301229204C3 +:1048E000904201D3884225D37648864204D0304690 +:1048F00004F085FC00280CD0304600F006FB06468C +:10490000284600F0BFFA002804D16068002802D0D1 +:1049100012E06448F8BD00236A463146284601F09B +:104920004FFF002802D0FEF7BCFBF8BD68460088A8 +:10493000800601D41020F8BD6188224628466368AD +:10494000FFF76AFEF8BDF7B55C4E0746306886B0E3 +:104950001446824202D2102009B0F0BD384600F061 +:10496000D4FA05465748874201D0FF2D08D00023CE +:1049700004AA2946079801F023FF002826D101E068 +:104980004848E9E76846008AC00601D54A48E3E797 +:1049900003A9002002910527019000976288494BE6 +:1049A0002946079801F0AAFE00280FD161683268F5 +:1049B000914208D30191029000972388628829468A +:1049C000079801F09BFE694689892180FEF769FB03 +:1049D000C2E7002907D03C4B0A881B899A4202D8BB +:1049E0003048401C704737E610B586B004236C464B +:1049F000A382354BDC88002C07D01B898B4201D267 +:104A0000914204D92748401C54E5062052E56B46E4 +:104A100019825A820021009101911C800221997013 +:104A200005A9029104A903916946FFF715FE41E526 +:104A3000F3B50C4685B0812069460873002C1BD065 +:104A4000059804F0DCFB070018D03878222869D3D9 +:104A5000059800F05AFA049000220121059807F009 +:104A6000CEFE00280CD000231A460321059808F03A +:104A700081F805000AD105E0102028E5094826E55F +:104A8000112024E50849114811F0CDFC28460830D2 +:104A90000BF032FB06462078012819D0022838D0C6 +:104AA000072014E502300000E8380000E1080000AB +:104AB0000328000000280000013400002800002026 +:104AC00000800100FFFF000000090020840A0000B0 +:104AD000A18803AAFEF71CFB0028CED1B00721D580 +:104AE0006846007B00281FD1A079C0071CD0E06871 +:104AF000002205216B4607C36389228968880499CF +:104B000001F018FC6946087300280DD0FEF7C9FAB9 +:104B1000DDE4A18803AAFEF7FBFA0028ADD134201A +:104B2000064201D10820D2E46846037B2946384674 +:104B3000059AFEF70BFDCAE4FFB597B0002001907F +:104B40001F4615460C460E46179804F058FB0028E1 +:104B500004D00078222803D20820A6E5F448A4E572 +:104B6000B80801D00720A0E5032F00D1002717982F +:104B700000F0CBF90890002C1BD0022D77D3ED4824 +:104B8000006884427CD361190091012902D0491E3A +:104B9000814275D3AD1EAAB22146E74810F036F81F +:104BA00000991E394A7F0B7F11021943884267D151 +:104BB000ADB2E248B90702D50189491C00E00121E4 +:104BC00089B20091F90701D0078900E0DA4F03AA02 +:104BD0000899009801F0F1FC0DE0F078B17800023E +:104BE000084310284CD80199091D401880B2019043 +:104BF000A84245D82618002E60D07078317800027F +:104C0000084300998842E8D358E06946098A0A07B0 +:104C100054D5002C3FD0019AA618121D92B20992C9 +:104C2000F278B37812021A439446102A28D8099AC7 +:104C30006244AA4224D87278337812021A4390420E +:104C40001ED1C8061ED509980AAA052120186B4650 +:104C500007C3707831780002084363460022089940 +:104C600001F068FB002803D0FEF71BFA1DE507E002 +:104C7000F078B178000208436946098D884201D076 +:104C80000B2012E5F078B17800020843099940182A +:104C900080B2019006E0C90604D50899FEF793FC9E +:104CA0000028E3D16946088A1021884369460882B2 +:104CB000488AFF23049A089901F0AAFD03A801F08D +:104CC00085FC002803D16846408AB8429DD900235C +:104CD0001A460321179807F04DFF040003D19849A5 +:104CE000984811F0A0FB20880028BFD0012108A817 +:104CF00001700173002646732188684601862046AC +:104D00000830099017980A90FCF712FE05001BD096 +:104D10001798688017206946888010AB023301AA73 +:104D2000052108A800950BF090FD0746687800075C +:104D300004D584488249223011F075FB002F09D038 +:104D40003846FEF71AFAB0E41321179805F04AFD29 +:104D50000320AAE40EA8009068468388042201215B +:104D6000179807F064FA00288BD126809DE4F0B5EF +:104D700000248DB01F4615460E46002A04D0B908FF +:104D800004D007200DB0F0BD1020FBE7032F00D1A9 +:104D9000002700F0BAF80390FF2804D06749B8074D +:104DA00003D5488902E06248ECE70120FA0702D007 +:104DB0004989491E00E0604906AA8FB2039901F0B3 +:104DC000FCFB38E06946898B090734D504AB052123 +:104DD0000022029300910192574B039901F08EFC3F +:104DE000002821D1002E21D06A46128A2988A218D3 +:104DF0003019121D914234D36946CA8B0270120ACF +:104E000042700A8A8270120AC27004A90522001D2B +:104E10000092029101906946C88B0B8A0022039987 +:104E200001F06CFC002801D00320ABE76846008A43 +:104E30002018001D84B206A801F0C8FB002804D089 +:104E4000822806D0FEF72DF99CE76846C08BB84251 +:104E5000B8D9002C07D0002E10D02988A01C814280 +:104E600003D20C208EE705208CE7224631463248DB +:104E70000FF0CCFE31190870000A4870A41C2C8079 +:104E800000207FE700B585B06946FEF79FFA00284D +:104E90000AD16846007C030011F0B6FB08052F2FED +:104EA0002F2F08080531032005B000BD6846807823 +:104EB000012807D1684600880321C902401A1CD086 +:104EC00001281AD068468079012806D16846808872 +:104ED00015214902401A05280FD96846807A012811 +:104EE00011D16846018929200002081A05D002283C +:104EF00003D0032801D0042805D10F20D4E712A144 +:104F0000164811F090FA0020CEE710B507F028FE01 +:104F100010BD10B50C4601F023FB002803D00AA1F8 +:104F20000F4811F080FA2046FEF7BBF810BD0000D4 +:104F30000230000028000020FFFF000000090020D0 +:104F4000E83800003F0B00007372635C67617474A3 +:104F5000735F636F72652E63000000002202000021 +:104F6000BB060000F8B500780C46164610340E3625 +:104F7000069F022809D0032836D005287ED0FF20BE +:104F8000F6A1E53011F04FFAF8BDCD890A2068434B +:104F90000E30188031203880002AF5D0087B9581AA +:104FA000801FC7B21AE020886168308048780A788C +:104FB00000021043F080C8788A78000210433081E4 +:104FC000B21C3846091DFDF772FE002F01D00028E3 +:104FD00002D000203071708008340A3628466D1ED9 +:104FE000ADB20028DFD1F8BDCD890A2068430E306C +:104FF000188032203880002AF5D0087B9581401F28 +:10500000C7B243E0616822880878F2803279C3072A +:1050100052085200DB0F1A43FD231A408307DB0FAF +:105020005B001A43FB231A404307DB0F9B001A4324 +:10503000F7231A400307DB0FDB001A43EF231A4064 +:10504000C306DB0F1B011A43DF231A408306DB0F65 +:105050005B011A43BF231A404306DB0F9B011A432F +:105060003271C00970718A784B7810021843308110 +:1050700032463846C91CFDF71AFE00E00CE0002855 +:1050800002D00020B070308008340A3628466D1EE9 +:10509000ADB20028B6D1F8BD087BCD89801E86B29E +:1050A0003046083068431030188034203880002A99 +:1050B000F1D0174695811037E800D681C0190090CD +:1050C0000DE020883880009878603246616800984A +:1050D00011F02BF800980834801908370090284602 +:1050E0006D1EADB20028ECD1F8BDFFB581B00A9DB0 +:1050F0001E460C46002A05D0607AFF300130D08071 +:10510000E089108101980E270078030011F07CFAE5 +:105110000B7E0719293541536C7878787E00009210 +:10512000087B082805D0032803D091A1954811F0E9 +:105130007AF9378030200FE000990020888105B08F +:10514000F0BD0092087B042804D08E4888A114305A +:1051500011F069F937803120288000980028EBD1C0 +:10516000EDE70092087B042804D0932080A1800002 +:1051700011F059F937803220EEE70092087B0228BF +:1051800004D080487AA13A3011F04DF937803320AD +:10519000E2E7087B1746042804D07A4874A14C3013 +:1051A00011F041F91020308034202880002FC6D023 +:1051B0000020B88116E0207B1746052806D0062877 +:1051C00004D070486AA1603011F02DF912203080AF +:1051D00035202880002FB2D0E089B88100203882A5 +:1051E00001984088F881AAE70092087B072804D03C +:1051F00064485FA1713011F016F937803620ABE7B3 +:1052000033460095019800F00EFC98E72F2053A13B +:10521000000111F008F992E770B50C46054603F05D +:10522000EEFF002804D00078222803D2082070BDA9 +:10523000554870BD00231A460421284607F09AFC01 +:105240002060002801D0002070BD032070BDFFB594 +:105250008BB00D4607461720694608850E98032631 +:105260001446002805D10EA93846FFF7D5FF0028BF +:1052700034D1002D0BD000220321384607F0BFFAAD +:10528000002834D00E980078002830D108E020782B +:10529000092819D00F2823D030A13C4811F0C3F8B9 +:1052A0000E98A760801D03AA606002320AA92046FA +:1052B00000F00FFC002827D0030011F0A5F9071A11 +:1052C000182323211C1E23000726002231463846BE +:1052D00007F095FA0028E3D12B48801C0FB0F0BDF1 +:1052E00000220321384607F08AFA0028D8D111207D +:1052F000F4E70020F2E70820F0E72348401CEDE740 +:105300000720EBE70320E9E701A800906846038D3A +:1053100004223146384606F08AFF0028DED1002DEF +:10532000DCD00E990D70D9E730B587B01D460C461C +:10533000002A11D0042369460B7013888B81528890 +:10534000CA81A2788A7422880A8200236A46294682 +:10535000FFF77DFF07B030BD1020FBE77372635C81 +:1053600067617474635F636F72652E630000000091 +:105370007372635C67617474635F636F72652E63DD +:105380000000000025020000023000004F03000072 +:10539000F3B581B001980C4600780826030011F09F +:1053A00033F9125F47471B134B0A0A0A0A0A0A0A13 +:1053B0000A0A0A0A0A5F002C02D1F849F84808E0F4 +:1053C0006078304360703CE0002CF9D1F448F34938 +:1053D000083011F028F8F3E70198002380880122B3 +:1053E00087B20421384607F0C5FB0546002C04D0DF +:1053F0007520EA49C00011F016F8002D04D1E848E4 +:10540000E649143011F00FF83946A81D00F058FB9A +:10541000FCF78EFA040006D0607830436070678035 +:10542000FCF767FA0FE01321384605F0DBF915E0C9 +:10543000DB48DA49283002E0D948D8492D3010F04D +:10544000F2FF002C0AD06078000707D59320207067 +:105450002046582208300199FBF7B6FE0020FEBD19 +:10546000CF48CE493130EAE710B500210170801DE8 +:1054700000F023FB10BD0A4610B50146901D00F058 +:1054800027FB10BD70B5002305461A46042107F01E +:1054900071FB040004D1F920C049800010F0C3FF63 +:1054A0002946A01D00F00CFB70BDF7B5054684B081 +:1054B0000C4600206946088188806F8803460122D7 +:1054C0000421384607F056FB060004D1FD20B349FD +:1054D000800010F0A8FF002C03D0A7800020E080FF +:1054E0002081297A20461230C91E142700900B0013 +:1054F00011F08AF80FFEFDFC3809A95E657A2FB21B +:10550000C9E99191FC003078012804D0A3497020AA +:10551000143110F088FFA9896A46C8000E309080C7 +:1055200030201081002C13D0A18100200DE0C1009B +:10553000327909190A747288CA8182005319DA898A +:105540004A821A8A401C8A8280B2A1898142EED89E +:10555000F1E002A8009001AB22462946304600F057 +:105560002BFAE8E03078042804D08C49BD201431AF +:1055700010F059FFA8890622014650436A460E30B2 +:10558000908033201081002CE2D0A18100200BE01C +:10559000062141434F190919FA89CA81BA7C8A74D4 +:1055A0003A8A401C0A8280B2A1898142F0D8C2E0C6 +:1055B000307806280BD079491431D72005E03078AF +:1055C000062804D07549EB20143110F02CFFE8892F +:1055D00069461230888035200881002CB8D0A9890E +:1055E000A1817188E18126E03078072804D06B49D9 +:1055F000FF20143110F017FFA8896A4601460E30CB +:10560000908036201081002CA2D0A1812046AA894A +:105610000E30296954E0E8896946123080B2382298 +:1056200088800A81002C7ED0A989A181287A10283F +:1056300007D00221A173E9892182EA8929690098AA +:105640003EE00121F6E702A8009001AB2246294680 +:105650003046FFF787FC6EE03078082805D04F49C8 +:10566000FF201431EE3010F0DEFE684637218780CF +:105670000181002C5FD0A989A18100206082208255 +:105680000120A07357E03078092805D04349FF2056 +:105690001431FF3010F0C7FE288A69461430888024 +:1056A00037200881002C46D00421A173A989A1814B +:1056B000E9892182298A618220462A8A143069690F +:1056C00010F033FD37E030780A2804D033493548EC +:1056D000143110F0A8FE6846372187800181002C24 +:1056E00029D00521A1730020A08102E01EE003E083 +:1056F0000CE0208260821EE002A8009001AB2246EE +:1057000029463046FFF7F1FC15E00CE00D20694614 +:10571000392288800A81002C05D00120E0800020F9 +:105720002081207307E00699088019E01C481B4976 +:10573000A43010F078FE6846069980880880002C16 +:105740000ED0684600892080684680886080287A6C +:10575000032805D0102803D0112801D00020307074 +:10576000002007B0F0BDF7B5568815460F46002358 +:1057700082B01A460421304607F0FCF9040004D137 +:1057800007480649C43010F04EFEA41D33462A4691 +:1057900039460094029800F022FBD0E45C530000EC +:1057A0009503000013020000F7B58CB00D461446B7 +:1057B00007A90C98FFF730FD002812D1B64E01273B +:1057C000002C0FD00321684601701021818208A8A7 +:1057D00002460690204605A9FDF78FFA00280BD057 +:1057E00007207BE50821684601708581C681052177 +:1057F0008774C90201820BE00798A17801712188A2 +:105800004180684605218774C90201828581C6816D +:1058100002460121079B0C98FFF719FD5EE508B5CC +:1058200001236A4693709D4B13800A460223694602 +:10583000FFF77AFD08BD08B501236A469370974BC0 +:105840005B1C13800A4603236946FFF76DFD08BD04 +:1058500000B587B000290CD002236A4613700B886C +:1058600093814988D18100230421FFF7F0FC07B020 +:1058700000BD1020FBE710B5002903D00523FFF77A +:1058800053FD10BD072010BD70B588B00D461446FD +:10589000064607A9FFF7C0FC00280DD1002C0DD04B +:1058A0000621684601708581C481079B02465C80A1 +:1058B00006213046FFF7CBFC08B070BD05216846D5 +:1058C00001708581F1E710B588B000290BD007245D +:1058D0006B461C709A81049100236A462146FFF7AB +:1058E000B6FC08B010BD1020FBE770B500241722ED +:1058F00088B0002914D00D782B0010F085FE062307 +:10590000050519041B231522D21E93B2CA88002A4A +:1059100002D08E68002E03D09A4203D90C20CBE728 +:105920001020C9E7042D05D08A88002A0AD101E099 +:105930000620C1E7012D11D0022D05D0042D18D06D +:10594000052D23D00720B7E709236A4613704B883B +:105950009381CB88D381896804911DE00C236A462A +:1059600013704B889381CB88D38189680824049174 +:1059700012E00D236A4613704B8893818B88D38184 +:10598000CB88138289680924059105E00E236A46B5 +:105990001370497811730A2400232146FFF757FC3E +:1059A0008AE700B587B00F236A4613709181002300 +:1059B0001946FFF74CFC5AE7FEB50078089D1C46D7 +:1059C00016460F46012803D03549912010F02BFDD3 +:1059D000F889C0000E30208030202880387B001FDE +:1059E000C0B20190002E1DD0F889B081002516E0CC +:1059F000E8008419C0190090224641690E320198CE +:105A0000FDF755F9002802D000202074E0810098AD +:105A10006D1C008A60820098ADB2408AA082B08975 +:105A2000A842E5D8FEBD70B514461425049A1D8021 +:105A300037231380002C0ED0CA89A28100226282F3 +:105A40000078082808D0092810D00A2819D014494D +:105A5000144810F0E8FC70BD087B0C2804D01148F5 +:105A60000F490C3810F0DFFC012008E0087B0D28FE +:105A700004D00C480A49083810F0D5FC0420A07363 +:105A800070BD087B0E2804D006480549001F10F0A1 +:105A9000CAFC0520F3E70000FFFF00000228000019 +:105AA00070530000BB02000010B5FE4B5860197225 +:105AB0001A80C90010F098FB10BD002101807047CA +:105AC00010B50022D2430280032007F0F8FC10BD7D +:105AD0007047F0B50E460446017801208840F2492F +:105AE00099B008400090616815460888EF4A9042D6 +:105AF00006D0009A002A06D0EB4A521E104202D06D +:105B0000012019B0F0BD009A10430880002D12D07A +:105B1000002028702178EA1C0027681C01920B00E5 +:105B200010F072FD10F30E16233A59616F3CB4B0B9 +:105B30008AB8F2F1F0F320780B28EBD00420E0E7EC +:105B400002212970A1890170090A4170032097E0A0 +:105B500004212970A1890170090A41700198E18925 +:105B60000170090A417005208AE006212970A18987 +:105B70000170090A41700199E2890A70120A4A709B +:105B8000218A0171090A4171A28AE81DA16910F0F8 +:105B9000CCFAA08AC01D73E0082129702178082959 +:105BA00001D110212970A1890170090A4170019861 +:105BB000E1890170090A41700520308020466A1D84 +:105BC00002A91030FDF799F800287DD16946308888 +:105BD000097A401854E00A212970A1890170090A44 +:105BE000417003200BE00C212970A1890170090A82 +:105BF00041700198E1890170090A417005203080E7 +:105C00009CE0A08984464000401C81B230888842D4 +:105C10005AD3052958D30E202870002008E02369A4 +:105C200042009B5A521953701B0A401C937080B259 +:105C30006045F4D33180B9E09A48417A002973D0A5 +:105C4000491E4172217B4068C9004518A98828680F +:105C5000082240180838216910F067FA02216846C6 +:105C600001710021417128680390A988684601816B +:105C7000002101A8FFF78CFB0020A880002E00D097 +:105C8000308093E0297880221143297029784022BE +:105C90001143297029788909890112312970A18954 +:105CA0000170090A4170E289E81C216910F03DFA8F +:105CB000E089C01C3080287841063FD5C00975D0E6 +:105CC00001216846017200E02CE000214172318818 +:105CD000091D81810495E189019808180590001D2E +:105CE00006907048017A68460177002102A8FFF704 +:105CF0004FFB074630880C303080022F06D0002F33 +:105D000054D065E03DE033E01CE05EE06548694664 +:105D1000097F4268CB00D218037A994202D2918857 +:105D2000002902D0042753E02FE0417A491C417238 +:105D30001560308890800020308049E06168A0893B +:105D4000888033E029788909890116312970A18971 +:105D50000170090A41700198E1890170090A4170D6 +:105D6000228A681D616910F0E0F9208A401D46E72B +:105D700028788009800118302870207B6870022004 +:105D80007EE760680188090401D4052720E0C08807 +:105D9000A189884201D006271AE01E202870012020 +:105DA0003080606801884904490C0180009800280F +:105DB0000ED03C4800220088A1688300032007F031 +:105DC000D9FA61682078887007E0002030800327C6 +:105DD0006068009902888A430280384691E6FFB5E0 +:105DE0009FB0289D0E46002805D0172803D82A8882 +:105DF0002E4B9A4202D1072023B0F0BD32785306D1 +:105E000001D4D20901D00820F6E700226B461A71AE +:105E10005A7114463278431E1D939BB2189303ABFC +:105E20001A939706CB1CBF0E1B93821E711C3B005E +:105E300010F0EAFB209011EE66EE74EEB0EED4EEB8 +:105E4000EDEEECEEEBEEEAEEE9EEEEEEE8EEE7EE8E +:105E5000E6EEE5EE90EE05287CD10421684601715E +:105E6000A9780172F078B278010211436846418145 +:105E70003179417170788006800E0C282ED009DCB3 +:105E8000801E030010F0C0FB0919661C6621662401 +:105E90006627660012282AD00ADC0E2821D0102896 +:105EA000DAD121E00C090020FF710000FFFF0000A3 +:105EB00016281FD01828CFD11FE02878800701E0CE +:105EC00028784007002845DA45E128780007F9E7F7 +:105ED0002878C006F6E728788006F3E72878400699 +:105EE000F0E728780006EDE72888C005EAE728886B +:105EF000C004E7E728888004E4E728884004E1E755 +:105F00002A78920726D50328A6D105206A46107163 +:105F1000487809780002084310811CE12978490774 +:105F2000F0D5062816D3717890B2012902D0022943 +:105F300092D101E0022100E01021189106216A4669 +:105F400011710021118102AF189AB11C0237921C05 +:105F50001B921AE0B3E04A780B7812021A433A8097 +:105F6000801E891C1790BA1C1A911898FCF79FFE86 +:105F70001A991898189A091817986B46801A1A894E +:105F800080B2521C1A811B9ABF1D8242E3D900289D +:105F900086D1E0E028780007B4D51D98694682B222 +:105FA0000720087100200881701C0A3111E0437835 +:105FB00007781B023B430B80C37887781B023B4367 +:105FC0004B806F463B89121F5B1C001D92B23B81C8 +:105FD000091D042AEBD2002A71D1BCE02978C90638 +:105FE0006DD502286BD308206946087100204881CE +:105FF00070780872844692B2B01C1A9919E089E050 +:1060000090E07EE067E05BE030E025E019E013E03F +:10601000BCE0437807781B023B430B80831C4B603A +:106020006346D21A6F467B8960445B1C92B27B81C7 +:1060300008319445EDD9CEE7287880063FD509226E +:1060400003E0287840063AD50A2268460271AA88F9 +:106050000281189A428107E0287800062FD50B208C +:106060006A46107118981081039174E02988C90557 +:1060700025D5022823D30C206946087100204881C9 +:1060800070780872844692B2B01C1A9914E0437872 +:1060900007781B023B430B80C37887781B023B4386 +:1060A0004B80031D4B606346D21A6F467B89604468 +:1060B0005B1C92B27B8108319445E8D98BE763E0A1 +:1060C0002988C90460D501285ED10D216846017177 +:1060D000A98801813FE02988890455D5052853D333 +:1060E0000E2269460A71AA880A811B99401F4A78C4 +:1060F000097812020A4369464A818881701D04901A +:1061000029E0298849043FD501283DD10F2069465F +:10611000087120E02A88120436D44A780B781202DB +:106120001A43EA8003282FD332789206920E1B2A54 +:1061300026D011226B461A712A880123DB031A43E9 +:106140002A804A78097812020A4369460A81C01EE9 +:1061500048811B98039030788006800E1B2809D058 +:106160001D2807D00320229907F0A9F92888C00B21 +:10617000C003288001A82199FFF70AF920463BE6D1 +:1061800010226B461A71DCE70724F7E70824F5E7CD +:1061900000B597B0032806D16A461070019100211E +:1061A0006846FFF7F5F817B000BD000010B58B7812 +:1061B000002B11D082789A4207D10B88002B0BD08C +:1061C00003E08B79091D002B08D08B789A42F8D117 +:1061D00003880C88A342F4D1002010BD812010BD9B +:1061E000052826D0002A02D0012A0DD102E0098814 +:1061F000090501E009888904890F07D0012918D011 +:10620000022909D003290ED081207047002A01D02D +:10621000032070470220704703280AD0042808D0C2 +:10622000002804D007E0042803D0022803D005206A +:106230007047002070470F20704770B513880546DF +:1062400014460B8018061DD5FE481022807AA842FD +:1062500003D813430B80002070BDA06893430078DF +:10626000E840C007C00E03430B802078A178800768 +:10627000800D0843F4490FF0D2FFA0686943081865 +:10628000401C70BD906870BD37B569468B8813801F +:1062900019061BD5EB4C0125A47A9168844209D8D4 +:1062A000FE280FD1D80602D5A5406D1E00E00025BE +:1062B0000D7007E085400C78DB06DB0FAC438340B4 +:1062C0001C430C7010881021884310803EBDF8B527 +:1062D0000746C81C80080E468000B04201D08620C8 +:1062E000F8BD082A01D90E20F8BDD64D00202E6039 +:1062F000AF802881AA723446E88016E0E988491CFC +:10630000E980810610D48007A178800D0843CE492A +:106310000FF085FF206800F0BAFA2989401880B292 +:106320002881381A8019A0600C3420884107E5D4F0 +:106330000020F8BDFFB589B09F041646139DBF0C21 +:106340000193099800F095FA04000AD0207800061D +:1063500009D5BC48817A0A98814204D887200DB0BB +:10636000F0BD0120FBE7224669460A98FFF765FF6A +:106370000690002069460872052D14D0012221469E +:106380002846FFF72DFF0028E9D1207840060AD5DE +:10639000022168460172099981810188C1810682C2 +:1063A0004782129805900198000404D500273E46C4 +:1063B0000125079709E02078A1788007800D084320 +:1063C000A14907900FF02BFF0D46019840040AD514 +:1063D0000798A84207D12088E1788005800F000245 +:1063E0000843B04201D3AE4201D90720B7E7B8193C +:1063F00080B20190A84201D90D20B0E76846007A2A +:10640000002804D002A8FDF706F90028A7D10798B4 +:10641000A8420BD1208803210902884301998905EC +:10642000890F0902084320800198E0701498002821 +:1064300000D007801298002815D006983A46801997 +:1064400012990FF072FE224669460A98FFF7F5FE90 +:1064500069460888102188436946088022460099C9 +:106460000A98FFF711FF002079E7FFB5754D0C2260 +:10647000E8882968504383B00C180D9F724905982D +:106480000FF0CDFE0091049800F001FA29682A89E6 +:106490008E46611A0C310918944651188AB2A9889F +:1064A000914202D8842007B0F0BD6A46168A3206AF +:1064B00003D5B20601D58520F5E7EA88521C92B2D1 +:1064C000EA800E9B002B00D01A80B20601D5A7608F +:1064D00006E0604480B22881091A70460818A0605E +:1064E0002246FE200499FFF7CFFE0598A070009881 +:1064F000E07020880599800889058000890F08438D +:1065000003210902884300998905890F090208437C +:1065100004210843208003988078A07103980088A4 +:10652000A08000202073310601D5AC7A00E0012460 +:10653000B10600D5002700260EE0052100200191BC +:1065400002900097E88831460C9B069AFFF7F2FE0E +:106550000028A8D1761CF6B2A642EED30020A2E70E +:10656000F1B5009800F085F9060002D00025009CE6 +:1065700014E00120F8BD204600F07BF907460078C2 +:1065800031498007820DB87810430FF048FE386813 +:1065900000F07DF94019641C85B2A4B22948C18875 +:1065A000601E8142E7DC00992648491EC1800189AE +:1065B000491B018100203070F8BD002804D0401E26 +:1065C00010809170002070470120704710B504467C +:1065D00001881C48C288914201D3822010BD006806 +:1065E0000C22514342189079A07290882081108823 +:1065F000D1788005800F00020843A081A078211D7A +:10660000FFF71BFE20612088401C2080E0800020D6 +:1066100010BD012101827047F7B50546002084B006 +:10662000C043108068681746817868468170686842 +:1066300001886846018000218171288A2C88A04247 +:1066400005D303E0180900200102000004462C8253 +:1066500035E0288A401C2882301D6968FFF7A6FDB6 +:1066600000282AD139889248814201D1601E3880A1 +:106670006888A04228D33088F1788005800F000216 +:10668000084302906946301DFFF790FD002814D1A1 +:106690006989874881421BD0002231460598FFF75F +:1066A0009FFD002809D16A890298824205D1E968D4 +:1066B000B0680FF00DFD00280AD0641CA4B220467B +:1066C00000F0D7F80600C4D1641E2C828220EAE6CE +:1066D0007C80B079B871B088B8803078B1788007A4 +:1066E000800D084378810298B8813946287A32466D +:1066F0000831FFF7A2FD38610020D4E6FFB585B070 +:106700001C460F46059800F0B4F8050009D028781B +:10671000000608D56748807AB84204D8872009B0B7 +:10672000F0BD0120FBE707982A468605B60D6946AD +:106730003846FFF782FD07460E98052816D000223E +:106740002946FFF74DFD0028E9D1287840060DD5F0 +:106750000121684601710599018101884181868185 +:10676000C48101A8FCF757FF0028D8D12888AA784F +:106770008107890D11438005800FEA7800021043DC +:10678000079A964207D04C4A914204D3611E814237 +:1067900001DD0B20C3E7864201D90720BFE7801B3C +:1067A00082B2A24200D922461098002800D002806E +:1067B0000F98002802D0B9190FF0B7FC0020AEE7FF +:1067C000F8B51D4617460E4600F053F8040008D0F1 +:1067D0002078000607D53748807AB04203D8872052 +:1067E000F8BD0120F8BD224639463046FFF725FDA9 +:1067F000002D0BD02078A1788007800D08432E490A +:10680000884201D2012000E0002028700020F8BD5D +:10681000F8B51E4617460D4600F02BF8040008D0C8 +:106820002078000607D52348807AA84203D887201D +:10683000F8BD0120F8BD224639462846FFF724FD61 +:10684000FF2E14D02588A178A807800D08431A4987 +:106850000FF0E5FC002E03D1FF31FF31033189B287 +:10686000A170A80880008905890F084320800020B6 +:10687000F8BD1049CA88824207D3002805D00C22EF +:10688000096850430C38081870470020704703B55A +:106890000846694609888A0607D4090604D50549C9 +:1068A000897A4143491C88B20CBD00200CBD000010 +:1068B000FFFF00001809002001020000F8B507786A +:1068C0000D460446012F19D0072F02D00C2F19D1E5 +:1068D00014E0A068216906780B2E0BD0052006F085 +:1068E000EEFD052E0ED0782300220520216906F04A +:1068F00041FD07E0782300220620F8E70520216902 +:1069000006F0DDFD002D0ED000202870294620461F +:1069100004F0AEF9FE482978C05D884201D1032019 +:10692000F8BD0220F8BD0021204604F0A1F90020A6 +:10693000F8BD70B50E460C462036317901208AB07C +:106940001546002909D0012905D12978042902D149 +:106950000520107000200AB070BD6068019005A885 +:1069600002900D21C01C0FF03DFC032205A8A16878 +:106970000FF0DBFB01203071062069460870206AA9 +:10698000049029466846FFF799FFE4E770B50C4686 +:10699000154620310A790120062686B0002A2CD01F +:1069A000012A28D12978042925D169681022A068F4 +:1069B00001F0B4F96868C07B000606D5D44AA06827 +:1069C0001023103A014601F09EF91022A168E068F8 +:1069D00001F0A4F9A068C07B000606D5CC4AE068A7 +:1069E0001023103A014601F08EF92E70A0686860FD +:1069F000E068A860002006B070BD60680190C448DF +:106A0000203802900120087168460670206A0490C0 +:106A100029466846FFF752FFEDE7027B032A06D0BE +:106A2000002224235A540B78092B02D003E00420BF +:106A300070470A76CA61027B9300521C0273C150F0 +:106A400003207047F0B50E4615460C462036024628 +:106A500031790120072393B000290CD0012924D0DB +:106A600002292ED0032904D12978042901D12B70C1 +:106A7000002013B0F0BD01203071606800280DD0F7 +:106A8000A1690B7060684860206988606069C860AF +:106A9000206A08621046FFF7C0FFEAE70620287068 +:106AA000206968606069A86009E029780629E0D15A +:106AB0000220307104202870954820386860032037 +:106AC000D7E729780429D4D1A08910280AD9103809 +:106AD00080B2A081A1681023091805A86A6801F096 +:106AE00012F923E010282FD0C2B21020801AA1681A +:106AF0000DAF1190C0190FF018FB11980006000E91 +:106B000006D0401EC1B28020785438460FF06AFB90 +:106B1000626910230DA909A801F0F5F8102309A94D +:106B200005A86A6801F0EFF80320307160680190F1 +:106B300005A80290062069460870206A049029463C +:106B40006846FFF7BBFE94E710232269A168E2E7DD +:106B5000F0B50E460C4620363179012006278FB05D +:106B6000154600290BD0012932D0022905D12978F8 +:106B7000042902D10820107000200FB0F0BD217D43 +:106B800008A8CA07D20F02718807C10F08A80171AF +:106B90006846027041700722801CE1680FF0C5FA58 +:106BA00002A80722013021690FF0BFFA6068059042 +:106BB0000AA8069010236A46A16801F0A4F80120F3 +:106BC000307168460774206A0890294604A820E0BE +:106BD00029780429D1D1062205A8E1690FF0A5FA88 +:106BE00006A806220230A1690FF09FFA0020089043 +:106BF0006068019009A80290102305AA696801F055 +:106C000082F80220307168460770206A0490294695 +:106C10006846FFF753FEB0E770B50D460C462035C9 +:106C2000297901208CB01646002909D0012905D107 +:106C30003178042902D10920107000200CB070BDF9 +:106C40006068019006A802900822E1680FF06DFAD2 +:106C5000082208A8A1680FF068FA01202871062010 +:106C600069460870206A049031466846FFF726FEA0 +:106C7000E4E770B50D460C462035297901208CB02B +:106C80001646002908D00129D8D131780429D5D158 +:106C90000A2010700020D1E76068019006A80290D9 +:106CA0000822A1680FF041FA002008900990012005 +:106CB0002871062069460870206A049031466846AB +:106CC000FFF7FCFDBAE730B50B4620331C790120F5 +:106CD0008BB0002C09D0012C05D11178042902D1E8 +:106CE0000B20107000200BB030BD4868019005A843 +:106CF00002908C6868462578057564784475CC6880 +:106D0000257885756478C47500200690079001E0A9 +:106D10002867010008900120187106236846037057 +:106D2000086A049011466846FFF7C8FDDBE770B5B6 +:106D30000C462034034625790120002D0AD0012D70 +:106D400014D0022D05D111780A2902D10C2010701F +:106D5000002070BD01202071C868052202704A68B9 +:106D60004260F84A8260921CC2600BE015780B2DDD +:106D7000EFD102202071C868042404705268426078 +:106D80008A688260096A016201461846FFF745FE7B +:106D900070BD30B5011D02463132947803258379E8 +:106DA000ED432C4323408371DB070DD04B7954799D +:106DB00023404B710B79127913400B718278C9789B +:106DC0008A4200D9817030BD00224A710A71F5E70C +:106DD000F7B50C4686B00020694626460870203676 +:106DE000317901271E2015461F2977D24B007B449D +:106DF0009B885B009F441E0017023E0256026902F8 +:106E000088029A02D102F5022E03590371037F030F +:106E1000AE03C303CC03F7031A0464049A04AB045F +:106E2000DF04FE0410052A0565059B05C6058305DC +:106E300087058B056069002802D0007813287DD073 +:106E4000A0680590002849D0012168460170206A99 +:106E500004900321684601710A214171E0690290A2 +:106E600020790028EFD0059909780029E7D00C296E +:106E700064D20B000FF0C8FB0CFD1A4B90B5E8FC78 +:106E8000FBFAF9F807FD022828D16069002802D032 +:106E90000078082852D1022168460170206A0490C7 +:106EA00005984178684601710021B9E20620216AFF +:106EB00006F005FB20790728E6D1606900F050FF55 +:106EC00002280CD0606900F04BFF042807D06069ED +:106ED0000028B8D000780128D6D103E01BE2616910 +:106EE0000120087005980079C11F0A2901D30A20E2 +:106EF00050E06169072288706069059930300FF0B1 +:106F000014F90120307161690320087034E007280A +:106F1000BAD16069002896D001780929B4D10599C1 +:106F2000C978890707D1059949790029DFD10599E1 +:106F300089790029DBD105994A7900E04EE20146C2 +:106F400020314B7D9A43D2D1059A8B7D92799A4319 +:106F5000CDD1059A1279D31F0A2BC8D20979914253 +:106F600036D80722C01C05990FF0DFF801203071D8 +:106F700061690A200870032069460870206A04903D +:106F80006069313001906069001D029060691C30B9 +:106F90000390A1E22076F2E311288DD1606900F020 +:106FA000DFFE042804D0606900F0DAFE0B2893D1DC +:106FB0006069059910223730491C0FF0B6F86069F6 +:106FC000017804297CD12421095C8278914201D97D +:106FD0000620DFE70521017003203071684601704B +:106FE000E2E3112894D1606900F0BAFE062804D0CB +:106FF000606900F0B5FE0C288AD1E068002813D043 +:107000002069002810D060690178062910D00D2170 +:1070100001706069059910225730491C0FF085F8FE +:107020006069573009218CE100206946087072E1DF +:10703000072101706069059910224730491C0FF043 +:1070400074F860694730EDE70228F0D1606900F01C +:1070500087FE0028EBD0606900F082FE0128E6D0B0 +:10706000606900F07DFE05E0B1E08DE06CE02AE0B3 +:107070000AE0D6E00828DAD00521684601710598B3 +:1070800041786846417146E11128D0D160690028F5 +:10709000CDD001780E29CAD1C16A4078022810D01B +:1070A0000020142250431430085805991022491C1E +:1070B0000FF03BF80520216A00F040FE0F205EE053 +:1070C000F1E10120EDE70B28B1D160690028AED0D5 +:1070D00001780F29ABD1C16A4078022826D0002060 +:1070E000142250430C300958059842780A70807871 +:1070F00048706069C16A4078022819D000201422C3 +:1071000050431030085805990822C91C0FF00DF89B +:107110000520216A00F012FE60694178022909D039 +:1071200000220832825C5208520073E00120D7E747 +:107130000120E4E70122F4E7012100E00021083109 +:107140004254BCE30267010011289CD16069002809 +:1071500099D00178102996D1C16A4078022811D0BF +:107160000020142250431830085805991022491C59 +:107170000EF0DBFF0520216A00F0E0FD11206169BF +:107180000870B4E30120ECE7082884D16069002886 +:107190009DD00178112997D10599C06A497801706D +:1071A00060690599C06A0622401C891C0EF0BDFF6B +:1071B0000520216A00F0C2FD60694178022904D0EF +:1071C00000220832825CFD2323E00122F9E7112826 +:1071D000BBD160690028BBD001781229B5D1C16A42 +:1071E0004078022819D00020142250431C3008583F +:1071F00005991022491C0EF098FF0520216A00F025 +:107200009DFD60694178022909D000220832825C24 +:10721000FB231A40022991D18EE70120E4E70122E5 +:10722000F4E70720B6E6287801288ED160696968FE +:1072300014221C30F9F7C8FF6069017F002901D0D2 +:107240002176ACE30178032901D0032037E002273F +:10725000C77081794907490F8171017A4907490F40 +:107260000172417A4907490F41726069FFF791FD48 +:10727000377196E228780F28E3D107206946087015 +:10728000216A049191680291694608716169072237 +:10729000C91C02980EF049FF6169042008700020A3 +:1072A0003071BBE028780328CBD1606901780529CB +:1072B000696807D0082247300EF037FF042030718C +:1072C00005206FE208225730F6E728780328B8D166 +:1072D000606901780529696811D008224F300EF0E5 +:1072E00024FF052030716069006A00280AD002205E +:1072F0002870002028716069006AA860F9E00822FF +:107300005F30ECE704204DE22878022899D12879F3 +:10731000002801D0207642E36069A96801626069B3 +:10732000002901D1F949016206200BE228780F28D3 +:1073300087D1A868E0616069017805292BD04730C2 +:1073400007213171E16802220A706269126A4A609B +:10735000886060693030C8606069C01C086162691B +:10736000087D926A400812784000D207D20F10437D +:1073700008756269926A521C8A61FD221040626936 +:10738000D26A1278D207920F104308756069C06AFA +:10739000401CC86153E25730D2E728780828BAD198 +:1073A0006069017805291AD00B2101700720694610 +:1073B0000870206A0490E069029011200871029818 +:1073C0000321017051681022401C0EF0AEFE002116 +:1073D0006846FFF773FA00203071E06187E206210A +:1073E000E3E728780F2896D1072069460870206ABD +:1073F0000490A8680290112008710298042101707D +:1074000061690A78072A0ED0002232710C220A70B4 +:1074100061691022401C47310EF087FE002168464A +:10742000FFF74CFA63E21022401C57310EF07DFE4C +:1074300000216846FFF742FA0A203071E168032014 +:1074400008706069006A48606069573088606069E8 +:107450004730F3E128780828A1D1606969681022D3 +:1074600037300EF035FE002801D0042092E5606927 +:107470000078072817D00A203071E16803200870CF +:107480006069006A486060695730886060694730A9 +:10749000C860206A08620698FFF7BFFA074660696D +:1074A000FFF777FC6BE208207AE1287809289AD167 +:1074B0000B20307161696868897810224018511A70 +:1074C0000EF090FE082069460870206A04906868F3 +:1074D000019060698078087268E129780D29BBD134 +:1074E00061698979C90703D00C20307109203EE019 +:1074F0003071032770E228780E28ADD1606914221C +:10750000291D1C30F9F760FE6069018DC06A417267 +:10751000090A817260698178C06AC1716169CA6A49 +:10752000081D117AC909C9011172437962691943A9 +:107530008378D26A9B079B0F012B00D00023007930 +:107540009B01C00003431943117260694078012810 +:1075500076D0B4E160694178022901D0012100E0D0 +:1075600000210831405CC00707D00E20EAE06946E0 +:107570000870206A1146049019E11320B8E72878B2 +:107580000F2894D1A868E0610F2030710520EEE744 +:10759000287803288BD16069C16A4078022801D01D +:1075A000012000E000201422504310300858082227 +:1075B00069680EF0BAFD10203071E168062022697A +:1075C00008706069406A48606069C36A4078022850 +:1075D00001D0012000E00020142778431030185813 +:1075E000CA6088602BE128780C2886D16069C26A5D +:1075F0004078022801D0012000E0002014214843F7 +:107600000C30105802230932696800F07CFB11200D +:107610003071E168052008706069006A486060693F +:10762000C06A093088603948001F07E128780B28B4 +:10763000A7D161694878CA6A022802D0012001E016 +:1076400059E1002014235843143010588A7869688F +:107650000EF06BFD60694178C26A022901D00121F8 +:1076600000E00021142359431431525881785018F6 +:107670001022511A0EF0B6FD072069460870206AE4 +:107680000490E069029011200871029806210170AF +:107690006169CA6A4978022901D0012100E000210C +:1076A00014235943143151581022401C0EF03DFD53 +:1076B00000216846FFF702F90020E06112206FE028 +:1076C00028780F2891D1072168460170206A04901C +:1076D000906802900B2268460271029801706169FD +:1076E000CA6A4978022901D0012100E0002114234F +:1076F00059430C3151580A78427049788170616958 +:10770000CA6A4978022903D0012102E00867010012 +:10771000002114235943103151580822C01C0EF087 +:1077200004FD00216846FFF7C9F826E76069417843 +:10773000022901D0012100E000210831405C8007CE +:1077400003D5142030710A2011E71620D0E62878DE +:107750000F287AD1A868E061072069460870206A7E +:107760000490E069029011200871029808210170CC +:107770006169CA6A4978022902D0012101E011E158 +:10778000002114235943183151581022401C0EF087 +:10779000CCFC00216846FFF791F80020E06115203D +:1077A00030710A2069460870206A049029466846AC +:1077B000FFF784F82BE028780F2846D10720694688 +:1077C0000870206A0490906802900820087102985E +:1077D0000921017061690622C969097841706169EE +:1077E000801CC969491C0EF0A0FC00216846FFF707 +:1077F00065F8AAE760694178022901D0012200E01A +:1078000000220832805C400703D51720C8E70746EE +:10781000B5E0012953D070E028780F2815D1A86869 +:10782000E06118203071E168052008706069006A25 +:1078300048606069C06A09308860F848C860206A9A +:1078400008620698FFF7E9F8E1E76FE028780B286F +:107850006CD16069C16A4078022801D0012000E043 +:107860000020142250431C300858102269680EF082 +:107870005CFC072069460870206A0490E069029069 +:107880001120087102980A2101706169CA6A497859 +:10789000022901D0012100E00021142359431C31A9 +:1078A00051581022401C0EF040FC00216846FFF7A2 +:1078B00005F80020E0616069407801281DD1192099 +:1078C00016E660694278022A09D000210831411881 +:1078D000097800290DD0CA0703D00E2106E0012146 +:1078E000F4E7890701D5102100E01221017000277B +:1078F00072E0012A01D00D20FAE51C20F8E51D20D8 +:1079000030710B2033E62978102948D1F0E5606901 +:107910000178012943D0082941D00021317100F0BC +:1079200019FA0C2069460870206A049037E028781C +:107930000F2805D01020107003271B2030714BE05A +:10794000072168460170206A0490A868029002210D +:1079500068460171029805210170217E4170002165 +:107960006846FEF7ABFF0B2168460170206A049061 +:1079700029466846FEF7A2FF07461B203071012FFB +:107980000DD029E0012168460170206A049004218D +:1079900068460171217E41710020207612E0207E30 +:1079A00000280FD06169132008701A2030710A2056 +:1079B00069460870206A049029466846FEF77EFFF3 +:1079C000074609E06069002801D01421017068466B +:1079D0000078002800D021E5384609B0F0BDF7B5A1 +:1079E0000F4620373879012686B00C46002804D08F +:1079F000012828D002281CD197E02079012804D042 +:107A0000022811D0032814D10AE0A0684078012888 +:107A10000ED10620216A05F02CFD00287FD10CE054 +:107A2000A1681320087008E0A0684178022901D0FD +:107A3000052674E00078082871D1012038710A20E9 +:107A40006946087033E0089800780F2867D107214D +:107A500068460170206A049008988568029522792A +:107A60000220012A04D0022A29D0032A57D10FE08C +:107A70000646684606710B202870207B00214007CF +:107A8000400F68706846FEF719FFA068067045E071 +:107A900006466846067105202870207B6870002124 +:107AA0006846FEF70BFF3E710B2168460170206AA5 +:107AB000049068460899FEF701FF06462FE06846E5 +:107AC000017101202870207C6870607CC007C00FA5 +:107AD000A870A07C4007400FE870E17C2971C007C6 +:107AE0001FD0207D4007400F6871607D4007400F28 +:107AF000A87100216846FEF7E1FEA068072229462A +:107B000030300EF012FBE068017AA068203001717D +:107B1000A16828798870A16809200870002630467D +:107B20005BE70020A8716871E3E7A1681420087082 +:107B3000012168460170206A0490042168460171A1 +:107B4000217B41710021FEF7B9FEE7E7F0B585B072 +:107B50000F4605460124287B800040198038C66FF7 +:107B60003078411E0A290AD22C498000323140184F +:107B70008038C36F3A463146284698470446002C61 +:107B800001D0012C11D1287B401E0006000E287365 +:107B900001D00324DFE70D2069460870306A0490A5 +:107BA000002101966846FEF789FE032CD3D02046BB +:107BB00005B0F0BD70B515460A4604462946104684 +:107BC000FFF7C4FF0646002C0FD0207814280CD1F4 +:107BD000207E002806D000202870204629460C3040 +:107BE000FFF7B4FF204600F0B5F8304670BD70478F +:107BF00010B5012903D0022901D0052010BD417024 +:107C000000F0A8F8002010BD002809D0027E002A4C +:107C100006D00A4601460C31CCE700000667010099 +:107C20000120704730B5044687B00D46062005F0A8 +:107C300046FC2946052005F042FC2078142805D092 +:107C40000020694608702046FFF7DEFF07B030BD10 +:107C50007FB50E4600216A4611730178092903D0C9 +:107C60000A2903D0002407E0446900E08468002C5E +:107C700002D0217E002912D0154601462846FEF783 +:107C8000CCFE032809D1324629462046FFF792FF51 +:107C90006946097B002900D0042004B070BD254648 +:107CA0000C35EAE700B50023012285B005280CD089 +:107CB000062808D1684602700491022101714371BF +:107CC0000021FEF7FBFD05B000BD6846027004917F +:107CD0000271F4E710B590B00C4605216A461170A8 +:107CE000019022480290001D03900AA96846FFF700 +:107CF000AFFF002805D1102220460B990EF015FA8F +:107D0000002010B010BD30B505E05B1EDBB2CC5CCE +:107D1000D55C6C40C454002BF7D130BD10B50024A5 +:107D200009E00B78521E5B00234303700B78401C64 +:107D3000DC09D2B2491C002AF3D110BD70B50C4643 +:107D4000054605F0BCFB782300222146284605F0B5 +:107D500011FB70BD4178012900D0082101707047E6 +:107D6000002801D0007870470820704700670100A4 +:107D700038B50446002069460870204609F053FDD6 +:107D8000002803D1FBA1A3200EF04DFB204609F0F3 +:107D900099FC002803D1F7A1A8200EF044FB684607 +:107DA000007838BD70B5F84D002428462C77203077 +:107DB0008471C47101F09AF928464038047020306B +:107DC0008473847484772C75AC7170BD10B50C46C7 +:107DD000EE4982888A8042884A8000780870084686 +:107DE0000E38847009F050FC08F0FDFFFFF7DAFF51 +:107DF00020460BF013F8E449A8310846813809F011 +:107E0000ADFEE2480CF021FBE0480A3808F0FEFF26 +:107E1000002803D0D7A1C5200EF005FB01F066F9BC +:107E200010BD7CB50E461D46144601A909F008F8A0 +:107E3000002807D10AF091FB022803D1D248007D27 +:107E4000002801D001207CBD01988030807C09F0A1 +:107E50004DFC00280CD0684609F052FC0028F2D0F6 +:107E6000002C03D009F011FCA04206D200207CBDFA +:107E7000C0A1C7480EF0D7FAF8E7009809F0D8F883 +:107E80003146009809F0DBF8E2B22946009809F083 +:107E9000F0F909F045FC002804D1BD48B5A11E3019 +:107EA0000EF0C1FAB94C00250E3C6068A030417953 +:107EB000002902D045710BF0D8F860688030458306 +:107EC000C0E730B40179002904D0012907D030BCC3 +:107ED00000207047831D42880488022103E0428805 +:107EE0000488831D0121204630BC9AE7F8B51D4661 +:107EF00014460E4607460AF030FB022803D0A2487B +:107F0000007D002823D0A1480E3841684988398077 +:107F100040688030807C09F069FD002804D153203E +:107F200094A1C0000EF07FFA684609F069FD0028B0 +:107F30000DD0009809F0BAF83070022808D0012856 +:107F400006D093488BA167300EF06DFA0020F8BD83 +:107F50002946009809F0A4F92080002804D1552072 +:107F600084A1C0000EF05FFA09F05DFD002804D185 +:107F7000874880A160300EF056FA0120F8BD38B570 +:107F80000446831D821C6946FFF7B0FF00280DD010 +:107F90000020607168460078012808D0022806D0C9 +:107FA000FF2074A101300EF03EFA012038BD20718F +:107FB000FBE7F8B50AF0D1FA744D734C0E3D022878 +:107FC00002D0207D00287DD0207F0026102818D1E7 +:107FD000A079002803D067A16E480EF024FA6868E3 +:107FE00001464030827F92070BD526724988618115 +:107FF000C17F2173018CE181408C20820120A0711E +:108000002677614F203FB87C00285ED168686946BA +:108010008030807C09F007FC002805D0694668782C +:1080200009784018687004E05A4852A119300EF0DF +:10803000FAF9207D00283AD06868418852484038D3 +:10804000806D4088814204D00F204AA1C0010EF00B +:10805000EAF968688030807C09F0C8FC002804D107 +:108060004C4844A124300EF0DEF909F0EEFC002863 +:108070001DD068688030807CFFF77AFE69784018F0 +:10808000687041484038806D4030417A01290DD1F7 +:108090002670696849886180807A20710120B877EC +:1080A000207F102801D0282800D1267726756978EE +:1080B00000290AD06868428833484038C286018760 +:1080C000012000E001E0B8746E700AF029FA00287F +:1080D00005D1207D002802D0A878FAF7F9F8F8BD7C +:1080E000F8B50446FFF765FF274D0026203DA87E22 +:1080F000002808D0667010202070E87EA070287FCD +:10810000E070AE769AE0204F403F3878002808D0E3 +:108110002C22B91C20460EF008F80E2020703E706C +:108120008CE0A87B184F002815D0387F102808D085 +:10813000282806D0002804D0FF200EA1C2300EF05F +:1081400072F90120E070E87BA070287C60700F203D +:108150002070AE7372E00121204609F099FC0028DE +:108160001AD0387D002857D10021204609F090FC14 +:10817000F8BD00007372635C6C6C5F6374726C2E8C +:1081800073302E630000000094090020720000206C +:108190004F02000062070000A97CF8480090F848F0 +:1081A000002910D0017805290DD2491C0170667094 +:1081B0000D202070012028750622A01C00990DF0CA +:1081C000B4FFAE743AE0EE480670B879002812D0D9 +:1081D000387F002804D00120EA4940020EF023F93C +:1081E00066700120E54920700A221431A01C0DF0B0 +:1081F0009CFFBE7122E020460CF083F800281DD1C0 +:10820000A87C002802D0DE480178CEE7A87F0028AD +:1082100002D0387D002801D00020A9E7387F00284F +:1082200003D0D849D8480EF0FEF866700A202070B6 +:1082300006223946A01C0DF078FFAE77012097E7A3 +:108240004EE710B5CD4C343C2178002904D01321E1 +:108250000E2000F052FF10BDC9490088091D08F02A +:10826000EFFD002801D0022007E0C5484068014624 +:1082700020318A79012A02D00C20207105E00022E9 +:108280002271097E21724088E080012060711321F3 +:10829000E1700E21A170207010BDB84810B53438BF +:1082A0000178002904D024210E2000F026FF10BD03 +:1082B000012101702422C2700C220271417110BD93 +:1082C00070B5AE4C0546343C2078002804D03E21E1 +:1082D0000E2000F012FF70BD0AF03FF9002808D10F +:1082E0000AF03EF9002804D1A4480C30007F002891 +:1082F00001D00C2003E0287809F033FD0020207124 +:10830000012060713E21E170207070BD9B4810B566 +:1083100034380178002904D03C210E2000F0EDFE15 +:1083200010BD00210171012141713C22C270017018 +:1083300010BDF8B5914C343C2078002804D03B2186 +:108340000E2000F0DAFE13E70020A0710AF005F914 +:108350008A4E01250C36022802D0307D002840D0FC +:10836000874F694678688030807C09F073FA00286E +:1083700003D1844985480EF056F8307D002806D098 +:10838000A06D4030407A002801D0012600E0002690 +:1083900078688030807C09F029FB002804D17B4874 +:1083A000784908300EF03FF809F04FFB684031463D +:1083B000014316D07968FD2249882181217E400041 +:1083C000490849003143114001432176684600784D +:1083D000002802D00420014301E0FB200140217667 +:1083E000A5710020207165713B20E0702570BFE60B +:1083F00010B5624C343C2078002804D00E21084689 +:1084000000F07BFE10BD5E4906220831A01D0DF074 +:108410008CFE00202071012060710E21E17020701F +:1084200010BD70B5554C0546343C2078002804D06A +:1084300038210E2000F061FE70BD50480C30007FE6 +:10844000002807D00C202071012060713821E170D4 +:10845000207070BD287809F072FC28780CF05BF968 +:108460000020F0E770B5454D0446343D28780028DB +:1084700004D037210E2000F040FE70BD3F480C3084 +:10848000007F002801D00C200AE03D4E2188706852 +:108490004088884203D10AF060F8022807D0022001 +:1084A0002871012068713721E970287070BD7168EA +:1084B0007F2020310876487600208876A2788A715D +:1084C000E278CA7122790A72EAE710B52B4C343C83 +:1084D0002078002804D039210E2000F00EFE10BDB7 +:1084E0000AF03BF8032808D00AF03AF8032804D031 +:1084F00022480C30007F002801D00C2003E01F49E7 +:1085000000202C31C8712071012060713921E17087 +:10851000207010BD70B5194C0646343C20780028F8 +:1085200004D03A210E2000F0E8FD70BD0AF015F8E5 +:10853000032808D00AF014F8032804D00F480C30A0 +:10854000007F002801D00C2011E00C4D2C35E8797B +:1085500008280BD20001001910223146683000F0C3 +:10856000D6FDE879401CE871002000E0072020716A +:10857000012060713A21E170207070BD88090020EF +:108580006400002074810000210200001708000030 +:10859000F8B5FA4E04463078002804D03D210E206C +:1085A00000F0ABFDE4E5F5484030007F002801D045 +:1085B0000C2034E0F24D218868684088884203D15D +:1085C00009F0CBFF022801D0022028E06F68648800 +:1085D000FD883A896800B988401C844218D3E9486C +:1085E00041431046E84A50430DF019FE401EFF215A +:1085F00080B2F531884200D90846844200D2204634 +:10860000691C401C0DF00BFE6D1C6843401E85B2BA +:10861000E620C05D002800D1BD84F58000203071C7 +:10862000012070713D21F1703070A1E5F8B5D34C97 +:1086300005462078002804D035210E2000F05DFD8D +:1086400096E5CE484030007F002801D00C2016E08F +:10865000A878002801D0012804D1A888FF21F5318D +:10866000884201D912200AE0C54F298878684088DD +:10867000884203D109F071FF022807D0022020713F +:10868000012060713521E170207071E57968002664 +:108690000846C0310E70AA884A800122A0300271BB +:1086A000AA78012A00D000220A704079002801D05F +:1086B0000AF0DBFC2671E3E770B5B04C0546207884 +:1086C000002804D030210E2000F017FD55E709F0F6 +:1086D00044FF002804D1A9484030007F002801D081 +:1086E0000C2003E028780AF0E0FB00202071012034 +:1086F00060713021E17020703FE770B59F4C0546F6 +:108700002078002804D033210E2000F0F6FC34E756 +:1087100009F023FF002804D198484030007F00284A +:1087200001D00C2018E02978002911D00A290FD097 +:1087300014290DD01E290BD0282909D0322907D0A1 +:108740004B2905D0642903D0FF2901D0122003E072 +:1087500028460AF023FC002020710120607133219B +:10876000E170207009E770B5844C06462078251D1D +:10877000002804D032210E2000F0BFFCFDE6314677 +:10878000002009F0AEFA2870002805D17C480622A6 +:10879000314608300DF0C9FC012060713221E170D2 +:1087A0002070EAE670B5754C2178002904D031219B +:1087B0000E2000F0A2FCE0E600214156012504292C +:1087C00012D0002910D0081D0ED0001D0CD0001DA5 +:1087D0000AD0001D08D0001D06D00A3004D00A308F +:1087E00002D01220207103E0084606F079FD657181 +:1087F0003120E0702570C0E6FEB5604C0746207859 +:10880000002804D025210E2000F077FCFEBD38881A +:10881000694608F015FB594D01460020083500292E +:1088200004D002212171286028710FE00098009E79 +:108830000A30019060360020B07105222846019967 +:108840000DF073FCB0790028F5D13888E0800E2057 +:10885000A0702520E070012060712070FEBD10B571 +:10886000464C2078002804D005210E2000F045FC5D +:1088700010BD0020207108F008FFE08008F0D1FF53 +:108880002072012060710521E170207010BDF1B5EA +:108890003A4C2034A07B002804D010210F2000F097 +:1088A0002CFC65E4354D4035A8790C2610270028AE +:1088B00016D1287F002813D109F04FFE022824D1B9 +:1088C0002F4800994068098842888A421DD1014694 +:1088D000C0310A7A002A05D04030807F80070DD44D +:1088E000E6730EE05E22125C920707D406220A723B +:1088F000A0304079002801D00AF0B7FB2F77002084 +:10890000E07327740120A07332E40220F8E710B569 +:108910001A480178002904D00F210E2000F0EDFB49 +:1089200010BD00210171FF2181710021C943018126 +:1089300013490E310A7882728A8882814988C181FE +:10894000012141710E2282700F22C270017010BD90 +:1089500010B50A4C2078002804D02B210E2000F0FE +:10896000CCFB10BD0821A01D04F024FB00202071C9 +:10897000012060712B21E170207010BD540900208E +:1089800064000020C40900001027000070B5FA4DF3 +:1089900004462878002804D02A210E2000F0ADFBE0 +:1089A000EBE5F54810222146303800F0B0FBF248E4 +:1089B0001022A118203800F0AAFBEF4830380CF044 +:1089C000BCFBED49102210392C46A81D00F09FFB7E +:1089D000002020710E20A0702A20E070012060711C +:1089E0002070CAE5F8B50546E348E34C40300090F6 +:1089F000007F0C2628272034002801D0E6733EE0B3 +:108A0000A07B002804D028210F2000F076FB04E48E +:108A1000A87805280DD013280BD0142809D01528C4 +:108A200007D01A2805D0292803D03D2801D03B289B +:108A300003D12888D149884201D912201EE009F0CB +:108A40008CFD0228DAD1CE482A88406841889142BC +:108A500013D10146C0310A79002ACFD1AA784A71D0 +:108A600001220A710099A0300F770021E17340794B +:108A7000002804D00AF0F9FA01E00220E07327741C +:108A80000120A0735FE4F8B5BB4F064638783D1D62 +:108A9000002804D017210E2000F02FFB53E43146AC +:108AA000012009F01EF901242870002807D1B248DE +:108AB00006226030314605460DF037FBAC717C7103 +:108AC0001720F8703C703EE470B5AB4C0646207839 +:108AD000002804D00B210E2000F00FFB4DE509F01B +:108AE0003CFD032808D009F03BFD032804D0A24830 +:108AF0004030007F002801D00C2016E03378002B96 +:108B000003D0012B01D012200FE09B4DE035297AD4 +:108B1000082909D22846721C0C3006F097FB287AE7 +:108B2000401C2872002000E00720207101206071A5 +:108B30000B21E170207020E510B58F4C20780028C3 +:108B400004D00A210E2000F0D8FA16E709F005FD3E +:108B5000032808D009F004FD032804D086484030DB +:108B6000007F002801D00C2002E000F0BFFA0020B6 +:108B70002071012060710A21E1702070FDE610B5BE +:108B80000AF032F9002803D07E497F480DF04BFCF3 +:108B900008F04BFD0BF051FC002804D01720794958 +:108BA00040010DF040FC08F0ACFF002804D0B920D3 +:108BB000744980000DF037FC00F098FAFFF7F2F8E6 +:108BC0006D4800210171012141710222C2700170C2 +:108BD000D3E610B5684C2178002904D020210E205E +:108BE00000F08BFAC9E601781F290ED8411C0CD081 +:108BF000002121710278411C104609F08FF80120F4 +:108C000060712021E1702070B7E612202071F6E734 +:108C1000F8B5594C2178002904D01B210E2000F012 +:108C20006CFABFE401216171534E0C212171403671 +:108C3000317F00296FD10078514F0025012804D0E1 +:108C400000284AD01220207165E009F086FC002837 +:108C500003D109F085FC002804D009F07EFC02282D +:108C600022D058E008F08FFF002854D0307D002833 +:108C700051D1786801224580032108F0B4FB78685F +:108C800009F05AF97868923008F001FD002803D104 +:108C90003C493E480DF0C7FB0AF00BF9002839D0DB +:108CA00085203849C00015E009F05AFC002832D16F +:108CB000707F00282FD001282DD004282BD008F059 +:108CC00062FF002827D00AF0F4F8002822D02F48AD +:108CD0002C4918300DF0A7FB1CE009F03EFC0328DE +:108CE00004D009F03DFC03280FD014E000200AF066 +:108CF00005F800280FD12571307D00280BD1786848 +:108D00008030807CFFF734F805E0002009F0F6FFA2 +:108D1000002800D125711B20E0700120207041E463 +:108D200010B5154C2178002904D01A210E2000F02E +:108D3000E4F922E601781F290ED8411C0CD000214D +:108D400021710278411C104608F0FDFF012060717E +:108D50001A21E170207010E612202071F6E770B53C +:108D6000054E044630780C25002811D018210E201D +:108D700000F0C3F9AAE4000054090020FF0E00002F +:108D80006400002074810000D3020000240400006D +:108D900009F0E3FB03285AD009F0E2FB032856D080 +:108DA000E14A107F002852D16079002801D00128C3 +:108DB0002DD1A079002801D0012828D1A07B00283E +:108DC00005D0012803D0022801D003281FD1607BE1 +:108DD00000281CD0C0081AD161880120800381427C +:108DE00002D82388834203D9207901280FD119E0C2 +:108DF0002079002806D0012814D0022805D00328A5 +:108E000005D102E020290BD30CE0A02B0AD2207957 +:108E1000042805D12088202802D36188884201D9FE +:108E2000122514E0207950776079002802D00128BB +:108E300003D00CE0BD4A002105E0BB4A2032907906 +:108E4000002804D00121204608F0CEFE054601206E +:108E5000357170711821F170307037E470B5B24C13 +:108E60000546403C2078002804D02E210E2000F03A +:108E700044F92BE409F071FB0C22022815D1AA4811 +:108E8000007F002811D1A9482B88083841684888FC +:108E900083421AD10846C030037A002B05D1203115 +:108EA000C97E0F2903D0102901D0227103E00521CA +:108EB0000172002020710E20A0702E20E070288802 +:108EC000E08001206071207016E40220F2E770B5A6 +:108ED000954C0546403C2078002804D02D210E20DA +:108EE00000F00BF908E409F038FB0C21022814D13A +:108EF0008D48007F002810D18C4E2A88083E70686B +:108F000043889A4220D1C822125C002A05D13B2214 +:108F1000125C0F2A03D0102A01D021710AE010221E +:108F2000A91CD6300DF001F970680421C03001721F +:108F3000002020710E20A0702D20E0702888E08095 +:108F40000120607120700DE40220F2E710B5017875 +:108F50000B000DF059FB3F9E9E399E9E599E9E9E92 +:108F60009E3C3F9E9E8752559E9E999E9E9E432963 +:108F70009E2D319E9E9E9E359E9E9E955C9E9E47FA +:108F80009E4B4F9E21259E6C6064689E709E7F83E1 +:108F90007C788A8D74919E00801CFFF798FF76E0A4 +:108FA000801CFFF75BFF72E0801CFFF7D8FE6EE0CD +:108FB000801CFFF7B5FE6AE0801CFFF729FE66E023 +:108FC000801CFFF706FE62E0FFF7D9FD5FE0FFF7C8 +:108FD000B3FD5CE0801CFFF777FD58E0801CFFF7D5 +:108FE00052FD54E0801CFFF7FDFC50E0801CFFF7B1 +:108FF000CDFC4CE0FFF7ACFC49E0FFF788FC46E015 +:10900000801CFFF744FC42E0FFF729FC3FE0801C96 +:10901000FFF7F2FB3BE0801CFFF7C4FB37E0801C4E +:10902000FFF7A1FB33E0801CFFF767FB2FE0801CFC +:10903000FFF742FB2BE0801CFFF7F8FA27E0801CCB +:10904000FFF7A6FA23E0801CFFF764FA1FE0FFF7A2 +:109050003CFA1CE0801CFFF705FA18E0801CFFF7C3 +:10906000E0F914E0FFF7C4F911E0FFF762F90EE050 +:10907000801CFFF74BF90AE0801CFFF721F906E09E +:10908000801CFFF70AF902E0801CFFF7DAF80120E4 +:1090900073E4002071E470B52349244C054640393F +:1090A000083C0A460126403260682B000DF0ACFAFD +:1090B00005171A1A04171A000122002108F093F963 +:1090C000616800220846C0310A724A7209F067FFDF +:1090D000002803D016A11B480DF0A5F960E4167511 +:1090E00088655DE4174812A13330F5E70E4900208A +:1090F000C031C8612039087270470B4A203A937E0C +:10910000002B03D1D076117701209076704730B5CF +:10911000134606E0CC18203CE47FD51A44555B1E6C +:10912000DBB2002BF6D130BD940900206C0000208A +:109130007372635C6C6C5F6374726C2E73302E633D +:10914000000000005108000070B5FD4D040008D07B +:10915000012C10D0022C07D0032C05D0F9A17020CF +:1091600007E0F8A1672004E02878012803D0F5A1E2 +:109170006D200DF058F92C7070BD70B5F04D04469F +:1091800010280AD0112C16D028468178122C07D02E +:10919000132C0AD0EBA19F200BE0EAA1942008E059 +:1091A000112908D0E7A1992003E0112903D0E5A1F6 +:1091B0009C200DF038F9AC7070BD10B5E04894B04B +:1091C000007B002819D0172069460870DC4900A8E8 +:1091D00006220D3102300CF0A8FF09A96846F9F704 +:1091E000C2FE0446112805D0002C03D0D5A1BB2017 +:1091F0000DF019F9204614B010BD3220E4E710B587 +:1092000001220023114603F0B5FC10BDFFB595B057 +:109210001D460E460746FFF7F2FF04000AD02078ED +:10922000222804D3A07F8006C00FA84204D10820C2 +:1092300019B0F0BDC748FBE7372168460170478089 +:10924000002D05D00121017146711799817102E04D +:1092500000206946087109A96846F9F784FEA07FD5 +:10926000DF21084069010843A0770020E0E770B5DE +:109270000446084620380D4603000DF0C5F90A06DD +:109280000A11232C334249505761FF20ADA1083009 +:1092900052E02078202851D1FF20AAA10B304BE0CA +:1092A000A7480178032949D08078132846D0207830 +:1092B000242843D0252841D023283FD0FF20A1A136 +:1092C0000E3039E02078222838D0232836D8FF20E5 +:1092D0009CA1153030E0207822282FD0FF2099A1C2 +:1092E000193029E02078222828D0242826D02628C2 +:1092F00024D0272822D0292820D0FF2091A11C305B +:109300001AE02078252819D0FF208EA1233013E001 +:109310002078252812D0FF208AA126300CE0207862 +:1093200025280BD0FF2087A1293005E020782828A8 +:1093300004D0FF2083A12C300DF075F8257070BD8E +:10934000FF2080A12F30F7E730B5834C0B88834A8C +:10935000022801D0934204D09D1FA54225D20228A5 +:1093600002D04D88954203D04D88AD1FA5421CD236 +:109370004C88A34219D88B88FF25F435AB4214D80A +:10938000022802D0C888904205D0C888724D0A3899 +:109390002D1FA84209D2C888904208D0944206D016 +:1093A0005B1C63438000834201DB072030BD00204B +:1093B00030BDF0B56A49884245D36A4A0125AD04FB +:1093C0001368A84201D398423DD30279002A06D0FF +:1093D000082A02D8067B082E05D90720F0BD047B99 +:1093E000002CFAD0F6E7002A06D004688C422AD373 +:1093F000AC4201D39C4226D3002E06D084688C4216 +:1094000021D3AC4201D39C421DD300240CE005685B +:10941000A700ED598D4216D30127BF04BD4201D3E9 +:109420009D4210D3641CE4B2A242F0D80022012570 +:10943000AD040CE084689700E4598C4203D3AC423D +:1094400003D39C4201D21020F0BD521CD2B29642EE +:10945000F0D80020F0BDFFB50022099B002802D003 +:10946000994205DC58E0002902D1002004B0F0BD8B +:109470000920FBE7845C002C12D087187D78112D21 +:1094800043D010DC2B000DF0BFF80A401726262C25 +:109490002C2E2E363640835C002B30D1521CD2B29B +:1094A0008A42F8DBE1E71C2D2FDA123D2B000DF08C +:1094B000ABF8042C2C121A2C022CD9D1BB78039CAB +:1094C000072B237001D25B0701D40A20CEE7029B51 +:1094D00001241B7816E0E343DB0708E0012C08D0E9 +:1094E00013E00620C2E70F2523072D075B19002B89 +:1094F000F4D03046BAE7029B1B789C0701D50B20BD +:10950000B4E702242343029C2370835C521C9A1804 +:10951000D2B28A4202DDABE7192676028A42A9DB83 +:10952000A3E710B504780B46002C1FD001210E4A8A +:10953000012C1ED0022C22D0032C2AD125E00000C1 +:10954000740A00207372635C6761705F636F726599 +:109550002E630000023000007B0C0000FFFF0000C3 +:109560000080010028000020023200000021197054 +:1095700011E019708179890903290AD10BE019706A +:1095800081798909012904D105E019708179890956 +:1095900001D0104610BD411C0622581C0CF0C5FD20 +:1095A000002010BD08B51346002806D0FEA00068B4 +:1095B000009048796A468009105C18700622581C91 +:1095C0000CF0B3FD08BD30B50C46097895B02229E2 +:1095D00002D2082015B030BD282369460B704880A0 +:1095E000132A03D03B2A01D00720F3E708460A716B +:1095F00009A9F9F7B8FC050003D121212046FFF79E +:1096000036FE2846E6E700B595B0232369460B7081 +:109610004880108888805088C880D0884881908889 +:10962000088100208881C88109A96846F9F79BFC58 +:1096300015B000BD70B50C00064610D0FFF7DFFD79 +:10964000050003D1D949DA480CF0EDFEA68028893F +:10965000E0802889208168896081A889A08170BD07 +:1096600070B50E46050003D00021092003F027FF46 +:109670000120D04C022E207324D0032E04D0CC48DD +:10968000CA491E300CF0CFFECA4806210D3003F047 +:1096900091FCA07C8006800EA074FFF78EFDA08B4D +:1096A00000280ED0002D0CD08300012200210920BB +:1096B00003F060FE092804D0BD48BC4928300CF0F6 +:1096C000B2FE70BDBB480321103003F073FCA07CD8 +:1096D00040218006800E0843A074B6480C3002F08A +:1096E00015F9DAE77FB501A9012003F0C3FA0028D4 +:1096F00004D0AF48AD4967300CF095FEAE4E01A8DE +:1097000003F0C6FA050002D0052D4CD048E0029CBB +:10971000A07F01072CD520462230009068462346C2 +:10972000628E80882146343301F07BFA0546A07FA3 +:10973000F7210840A077002D05D0B5422FD09C48D6 +:109740009A49783029E0E17F480889074000C90F2D +:1097500008432021095D4007400FC9000843E07716 +:10976000207828281CD129212046FFF780FD17E00A +:109770004007C4D568462246808821460E32FFF74E +:1097800042FF0546A07FFB210840A077002D07D0AF +:10979000B54204D08648854992300CF044FE00253D +:1097A000284604B070BD0020FBE7F8B5040004D1E2 +:1097B000ED207E4980000CF036FE7220207060683B +:1097C00008250178091F0B000CF01EFF11F90A3D56 +:1097D0005FF83D0EF8F83E3D3D3D3DF986F93D0010 +:1097E00073487249AA3074E087883846FFF707FD4E +:1097F000060004D16E486D49B2300CF014FE60785A +:109800000421284360706B4CA07F0843A07721217E +:109810003046FFF72CFDB07F8007800F012801D173 +:10982000801EA080384602F057FE3846FBF72AFE1D +:109830003846FAF7C6F93946022003F040FEB07FF9 +:10984000EF210840B077F8BD86883046FFF7D7FC97 +:10985000002804D156485549D0300CF0E4FD60682A +:109860008078012804D052485049D2300CF0DBFDFA +:1098700060688179304602F04EFF0028E3D06178BD +:10988000294361706168C880F8BD87883846FFF752 +:10989000B6FC060004D146484449E3300CF0C3FD51 +:1098A00060783946284360706068C088308160689D +:1098B0000089708160684089B081022003F0FFFD5B +:1098C0000020B075FFF70EFF0028DDD001203749DA +:1098D00080020CF0A8FDF8BD80783C2815D0002748 +:1098E000022815D00026002804D031482F49F8302E +:1098F0000CF099FD0021084603F0E1FD002107204E +:1099000003F0DDFD002E05D046E001270026F1E73B +:109910000126EAE76078284360702648817F294362 +:109920008177002F38D160688688304601F055F87D +:109930000546807F6168800889798000012900D010 +:1099400002210843A87760680622C08A28816068DF +:10995000008B68816068408BA8816068C079E87579 +:1099600061682846183008310CF0DFFB6068062279 +:10997000807B68706168A81C0F310CF0D6FBA87F53 +:109980008107890F304602F090FDA87F8007800F85 +:10999000012801D10748868006480178032913D0A1 +:1099A0008078132814D00BE00302FF0144950000D7 +:1099B00013030000740A0020023000000CE00FE0E6 +:1099C000FF20FCA1453084E70120FFF7BDFBF8BD77 +:1099D0001120FFF7D2FBF8BD204601F02AFCF8BDAC +:1099E000607828436070F8BDF7B505460078002719 +:1099F00000090C463E4601287ED00022F14902288B +:109A00007BD0072804D00A2878D0EAA1EE482DE1BF +:109A1000686803780D2B31D006DC042B6FD0072B40 +:109A200036D00A2B6AD106E0122B38D0132B40D047 +:109A3000142BF7D1B2E011270726002C72D08088B2 +:109A4000A0806968FB238979A171E04905468A7F76 +:109A50001A408A77032103F0C5F80421284603F051 +:109A6000C1F80021284603F0BDF80221284603F082 +:109A7000B9F80121284603F0B5F8F9E001270926D5 +:109A8000002CDBD08088A080686880792072EFE0AD +:109A900012270E2680882146FFF7CCFDE8E01A2722 +:109AA0000726002CCAD04088A08068680079A07181 +:109AB000DEE081783C2936D010271E26002CBDD050 +:109AC0008088A0806868C08A20836868C08AE08235 +:109AD0006868008B60836868408BA0836968207D1C +:109AE000497F4008C9074000C90F084320756968CD +:109AF000C007C00F497F03E05FE08AE0ADE01CE0F3 +:109B000049084900084320756968A21DC8790831D1 +:109B1000FFF748FD69682246887B0D320F31FFF759 +:109B200041FD05E074E019270726002C70D0A271D2 +:109B3000A648F722817F11407DE01B272E26002CAE +:109B400066D0A1806968A21D0879491DFFF72AFD2A +:109B500068682030C07A60736868C0780428A07B89 +:109B600019D040084000A073F921084069681F22FD +:109B7000C9788907490F0843A07369684007C97A03 +:109B8000400FC9000843A073696820460F300C31AC +:109B90000CF0CBFA6CE001210843E4E71E270E2607 +:109BA000002C6DD0A1806868E21D407AA0716968C0 +:109BB0008878C91CFFF7F6FC5AE0287A012805D0FE +:109BC000022815D080487BA132384FE01D270E2691 +:109BD000002C55D06888A080A889E080E889208181 +:109BE000288A6081688AA0817848DF22817FA2E785 +:109BF00012270E266888FFF71DFD002C40D06878DC +:109C00004007400F032833D17048FD22817F92E73F +:109C100036E0287A03000CF0F7FC06041010202030 +:109C2000202619270726002C2AD0A1806748A27178 +:109C3000817F4908490081771AE019270726002CFF +:109C40001ED0A180287A012805D00320A0715F488A +:109C5000EF22817F6FE70220F8E721462846029A2B +:109C600001F04BFCFEBD532052A100010CF0DBFBC8 +:109C70000298002C068001D0278066800020FEBD5F +:109C800002980680FAE710B5504894B080781328FF +:109C900002D0082014B010BD22206946087009A91E +:109CA0006846F9F760F904460021072003F007FC35 +:109CB0002046EFE700B5454895B08078122801D0DE +:109CC0000820B5E41E216846017000218170C17032 +:109CD00009A9F9F748F90028F3D10021072003F07A +:109CE000EEFB1120FFF749FA0020A1E400B5374848 +:109CF00095B00078022801D0032818D11B2108A8AC +:109D000001730021817369460BA8F9F72CF900282B +:109D100004D1684640781B2801D0032088E4002144 +:109D2000084603F0CCFB68468078002801D0082064 +:109D30007EE40120FFF708FA002079E4F8B5234C0F +:109D400003000CF061FC0A068017808080804B3590 +:109D50006E80FFF7CBFF00282AD1F7F7E9FD002836 +:109D600026D02221017000210172F7F7C2FDA07FE9 +:109D7000012152E08EB23046FFF741FA050004D1CE +:109D800011480CA12E300CF04EFB287821280FD062 +:109D9000F7F7CEFD00281BD01221017002270772B1 +:109DA00046800020A875F7F7A4FDA07F3843A07770 +:109DB000F8BD00007372635C6761705F636F72650A +:109DC0002E630000FFFF000036050000740A00202B +:109DD000132229463046FFF7F6FBE9E7A578122D56 +:109DE00006D0132D07D0FA49FA480CF01CFBDFE728 +:109DF000FFF760FF01E0FFF746FF0028D8D1F7F733 +:109E000097FD0028D4D022210170122D07D0022105 +:109E10000172F7F76EFDA07F10210843C7E701210B +:109E2000F6E7A07C810901290BD0800904D0E9481C +:109E3000E74922300CF0F7FA03210020FFF710FC6D +:109E4000B6E70221F9E7E348E1492930CDE7F7B564 +:109E500014460D0004D1DF48DD4931300CF0E3FA3F +:109E600028780827012807D002281FD0D948D849C8 +:109E700062300CF0D8FAFEBD0098FFF7C0F906007A +:109E800004D1D448D24938300CF0CDFA0220B07554 +:109E90001030207060783843607007CD083407C4F4 +:109EA000CD482022817F11438177FEBD0098FFF7C6 +:109EB000A6F9060004D1C748C54946300CF0B3FAEC +:109EC000A988C648814208D1EA88824205D1132276 +:109ED00031460098FFF777FBFEBD814202D1E8884A +:109EE000002809D01220207060783843607007CDB8 +:109EF000083407C4002006E07823002202200099DD +:109F000003F038FA0120B075FEBDB34840897047B0 +:109F1000FFB591B01498F8F721FF00285DD1012416 +:109F2000684603218471C9028180002201A920466C +:109F3000FAF719F9002850D16846152184714902B1 +:109F4000818000261C2102A800960CF04DF901200A +:109F50000146684610310170002001466846417094 +:109F60008178F9273940891C21438170017A0225C3 +:109F70002943017212998186C6861F2101870C90A0 +:109F800011980F9001A80B9009AA0BA902A8F9F744 +:109F9000B5FE002821D168468F4E808CF08068463F +:109FA00084718F498180807809AA3840801C4108DB +:109FB0004900684681708586058713A80F900BA914 +:109FC00002A8F9F79BFE002807D16846808C3081F3 +:109FD00031460A311498F8F7D4FE15B0F0BD30B50B +:109FE0000C46804995B08C4241D37F4901229204AE +:109FF0000968944201D38C4239D3203800220125CC +:10A0000003000CF001FB06042F494D535C64002152 +:10A01000082003F02EFA002802D0112015B030BD20 +:10A0200024206946087000A80522A11C02300CF00B +:10A030007CF809A96846F8F796FF050002D0082DBC +:10A040000ED031E0082300221146184603F092F9A1 +:10A05000082829D05F485E49D6300CF0E4F923E0A7 +:10A060000620DBE76068002803D0884201D2102078 +:10A07000D4E73D2168460170218841806188818054 +:10A0800009A9F8F770FF05000ED1606800280BD011 +:10A090006946098D018007E0206801F079FC02E043 +:10A0A000204600F0D8FC05462846B7E73E2007E0EA +:10A0B000857000E0827009A9F8F755FFF3E73420B6 +:10A0C000694608702078C0076846F3D0F0E707209B +:10A0D000A4E730B50C46444995B009688C4201D2DA +:10A0E00010209BE7203803000CF08EFA0504212194 +:10A0F000232132002088FFF782F8002804D000785E +:10A10000222803D2082089E7384887E725216846B6 +:10A1100001702188418009A9F8F725FF050015D1B4 +:10A120000AA905220231A01C0BF0FFFF0EE0062554 +:10A130000CE02068002805D0884201D2102505E0F7 +:10A1400001F01BFC24480025808BA080284665E791 +:10A15000072063E720481330704710B520211E48C0 +:10A160000CF040F80120FEF7EFFF1120FFF705F893 +:10A1700000211948C943818000218176E1218900AD +:10A18000818301460C300D310446F7F751FC12482B +:10A190000722214613300BF0C8FFFFF70EF8002806 +:10A1A00003D00B4912480CF03EF900F0D5FF10BD6A +:10A1B00010B504463C210CF015F8A07F8008800003 +:10A1C000A077202020700020A0752034607010BD82 +:10A1D000B49D00008C050000740A0020FFFF000001 +:10A1E000012A000000800100280000200230000049 +:10A1F000FB0600007047FEB50546FF480C4681424D +:10A2000007D301208004844205D3FC4800688442BF +:10A2100001D21020FEBD002D02D0012D32D126E04A +:10A22000F74908220F4668460BF07FFF3946204663 +:10A23000FFF777F90028EDD1FEF7BFFF060006D043 +:10A240000722694638460BF070FF3046FEBD207885 +:10A25000002801D0012805D1E94807223946C01D50 +:10A260000BF063FF0021092003F029F90FE00978C2 +:10A27000002907D0012905D0022905D0032903D0E0 +:10A28000E048FEBD0720FEBD0120FFF7E9F9DC48EC +:10A290000C3885760020FEBD10B5D8490968884283 +:10A2A00001D2102093E7D64902460C390B7B0D31C1 +:10A2B0001846FFF777F9002089E7FFB599B0054602 +:10A2C000002069460871087208A9087408751446C8 +:10A2D000CA480122C849920400681E46002D05D0D4 +:10A2E0008D420BD3954201D3854207D3002C08D071 +:10A2F0008C4203D3944204D3844202D210201DB076 +:10A30000F0BD2846204318D01F270CAB01AA0097A8 +:10A3100028461A99FFF79FF80028F0D10DAB02AA42 +:10A32000314620460097FFF796F80028E7D16846A7 +:10A33000007AC10703D00A20E1E70720DFE78007A2 +:10A3400005D568460079800701D50B20D7E703AF14 +:10A35000002D0FD01A20694608731A988873294671 +:10A36000F81C1A9A0BF0E1FE0EA903A8F8F7FBFD02 +:10A370000028C4D1002C0ED02021684601738673BA +:10A3800032462146F81C0BF0D0FE0EA903A8F8F7C0 +:10A39000EAFD0028B3D19A4908A8007C0C3948701E +:10A3A0000020ACE770B504460A2020700D46204618 +:10A3B000F8F7D9FD002805D139202070294620461C +:10A3C000F8F7D1FD70BDF7B500260C4605460B2702 +:10A3D0001AE02968B00009580978002903D001293A +:10A3E00001D00720FEBDA170296806220958E01C93 +:10A3F000491C0BF09AFE277020460299F8F7B3FD2E +:10A400000028EFD1761CF6B22879B042E1D80026B8 +:10A410003A270FE0A868B10041581022A01C0BF0A9 +:10A4200084FE277020460299F8F79DFD0028D9D1B7 +:10A43000761CF6B2287BB042ECD80020FEBDF0B509 +:10A44000044671A003C897B06B4B00271591149078 +:10A450009C4211D369480125AD040268AC4201D386 +:10A46000944209D32078012809D16168994203D325 +:10A47000A94204D3914202D2102017B0F0BD604926 +:10A480000C390A78012A0CD18A88614B9A4203D090 +:10A49000002806D0012804D08A7F13079B0F06D11D +:10A4A00001E00820E9E7D30701D1910701D5112088 +:10A4B000E3E7218A574B0A46203A9A4207D30128FC +:10A4C00075D1002973D1628A002A70D111E0022867 +:10A4D00001D0032801D1A02969D3012809D0484A15 +:10A4E0000C3A5278D20704D0628A002A5FD0B42A8C +:10A4F0005DD8002806D0012808D0022804D00328FF +:10A5000055D117E0002518E0022516E0002902D1F8 +:10A51000608A00280CD004256068007800280CD0E0 +:10A52000012809D0022807D0032805D03548A4E720 +:10A530000125F1E7032500E00127207A002806D055 +:10A54000012806D0022806D003287CD105E0002689 +:10A5500004E0012602E0022600E00326002D01D0DF +:10A56000022D14D1002E12D0E068FEF722FF002841 +:10A5700083D123480C384078800702D02148401E00 +:10A580007BE7022D03D1022E5DD0032E5BD0182174 +:10A5900068460170218A4180218A8180857118482E +:10A5A0000C38007B002803D001286FD104E04AE07A +:10A5B00000216846C17102E001206946C871684601 +:10A5C000077221780930012937D006210BF00AFEE5 +:10A5D00069460E74207D8207C107D20F4007C90F5C +:10A5E0005200C00F11438000014314A8405C69462B +:10A5F000C873002827D00FE0008001002800002049 +:10A60000800A002002320000070605040302010050 +:10A61000FFFF0000E13F000009A96846F8F7A3FC2E +:10A62000002884D109A96846FFF7BCFE0028A7D1FD +:10A63000002D0AD0022D08D010E061680622491CC6 +:10A640000BF073FDC4E7072017E7002E06D009AA18 +:10A650006946E068FFF7B7FE002891D11B206946E4 +:10A6600008700120887009A96846F8F77CFC00286A +:10A6700086D108A840791B2819D12B000BF0C4FF04 +:10A680000504040707040A00032001E00FE002208C +:10A69000FEF75AFD012D0CD0608A002809D0002257 +:10A6A00083001146104602F065FE002801D0032009 +:10A6B000E3E60020E1E6F3B5032687B00D46002966 +:10A6C0000AD0FA4885426FD301208004854203D323 +:10A6D000F7480068854267D30798FEF790FD0400AD +:10A6E00005D02078222804D2082009B0F0BDF14816 +:10A6F000FBE7A07F8707BF0F002D05D0294638460E +:10A70000FEF722FE0600F0D139460027EA4801296B +:10A7100007D0022931D0E949E9480BF084FE3046E0 +:10A72000E3E7A27D2946012A02D0827F920701D564 +:10A730001120DAE700291BD108216A46049711820B +:10A740000592418904AADF48FAF7FDF80028CCD128 +:10A750006846008A082801D00320C6E768460188B9 +:10A7600001814188418181888181C188C18102A99B +:10A77000079801F061FF0646D1E7A17D022916D1B5 +:10A78000807F800613D4002D04D0A07F40070CD416 +:10A79000002100E00121079801F08FFF0600BED1E3 +:10A7A000A775002DBBD004E01AE01126B7E7002DF5 +:10A7B00016D02A4621460798FEF725FF064611289F +:10A7C000ADD1A07F4007AAD42046082229460E30EA +:10A7D0000BF0ABFCA07F04210843A07700269EE786 +:10A7E000102082E770B50C460546FEF708FD010013 +:10A7F00004D022462846FEF7E6FE70BDAD4870BD87 +:10A8000000B50146143195B0192901D2810707D04E +:10A8100001461E3104D00A3102D0072015B000BD18 +:10A82000312269460A70887009A96846F8F79BFBCF +:10A83000F4E701B582B00220694608809E4802AB69 +:10A8400000896A460021F9F7E7FE6946098802296E +:10A8500000D003200EBD1CB50021009102216A46E4 +:10A860001180934901900968884201D210201CBDD3 +:10A87000914801899348FAF766F8694609880229E0 +:10A88000F5D003201CBDF0B50E46884985B01746AB +:10A8900005468E4207D386480122920400689642FC +:10A8A00004D3864202D2102005B0F0BD1F2F01D97B +:10A8B0000C20F9E7804C8D4226D3954201D3854286 +:10A8C00022D3E08803A9F9F758FE0028ECD12878B4 +:10A8D00069464873E08803A9F9F730FE0028E3D100 +:10A8E0006946009008780221084369460870497B50 +:10A8F000090703D00821084369460870E0886946C3 +:10A90000F9F7B5FD0028CFD169468F80E08833463E +:10A9100001AA0021F9F780FE69468988B942C3D0AF +:10A920000320C1E71CB50C4600210091019122884B +:10A9300069460A805E4901900968002801D0884272 +:10A9400001D38C4201D210201CBD002801D0002A66 +:10A9500009D059486A46C1885A48F9F7F4FF694650 +:10A96000098821801CBD0C201CBD10B50123FEF7F9 +:10A970004DFC2CE4002310B51A461946FEF746FCA0 +:10A9800025E430B505464A4895B000680C4681423A +:10A9900002D2102015B030BD2846FEF730FC00284A +:10A9A00007D00178222902D3807F800603D40820B3 +:10A9B000F0E74048EEE7132168460170458009A999 +:10A9C000F8F7D1FA0028E5D108AA0A2151567F29C3 +:10A9D00001D02170DEE70520DCE7F8B5012304464D +:10A9E0001A46194602F0C6F8074601231A46022104 +:10A9F000204602F0BFF8064601231A4604212046ED +:10AA000002F0B8F8054601231A460321204602F059 +:10AA1000B1F80446002F03D128492B480BF003FD61 +:10AA2000002E04D1AD20254980000BF0FCFC002D48 +:10AA300004D125482149801C0BF0F5FC002C04D1E1 +:10AA400021481E49C01C0BF0EEFC22213846FEF7BF +:10AA50000EFC3846F8BD10B50446006800280CD03E +:10AA60001249884207D301218904884205D310493D +:10AA70000968884201D2102014E400F071FFA08818 +:10AA80000D4CA083A07E01280DD10021092002F0E9 +:10AA9000F0FC002800D00120A17C8909012915D0F3 +:10AAA0000321FEF7DDFD002006E400000080010028 +:10AAB0002800002002300000740A0020B49D00002D +:10AAC000C6090000FFFF0000B30200000221E8E712 +:10AAD00030B5F74B9A4207D301239B049A4205D322 +:10AAE000F44B1B689A4201D2102030BD1578EB065A +:10AAF0005B0F042B07D85478072C04D39378102BC2 +:10AB000001D8A34201D2072030BDD3785B0702D41D +:10AB100013795B0701D5062030BDC37FAC075B0806 +:10AB20005B00E40F2343C3770878EF2318401378C2 +:10AB30009B06DB0F1B0118430870F12318401378A4 +:10AB4000DB065B0F5B001843087050780873002029 +:10AB500030BD30B500240C70C378DB07DB0F0B7001 +:10AB6000C578AD07ED0F6D002B430B70C5786D07F1 +:10AB7000ED0FAD002B430B7014700179C907C90F9D +:10AB8000117003799B07DB0F5B001943117000798B +:10AB90004007C00F80000143117030BD70B51446EE +:10ABA0000D460646F6F7C4FE002809D0A221017022 +:10ABB000142221460830F6F707FBF6F79AFE70BD1F +:10ABC000132229463046FEF7FEFC70BD70B51446D0 +:10ABD0000E460546F6F7ACFE002809D0222101708A +:10ABE00045802178017261784172F6F782FE70BD6E +:10ABF000132231462846FEF7E6FC70BD10B5AE4C78 +:10AC0000207C00280CD1204621461038FDF762F840 +:10AC1000002803D0A9A1F2200BF005FC012020742C +:10AC200010BD70B594B015460C462C226946189E8E +:10AC30000A704880002B17D00822194601A80BF093 +:10AC400074FA68468581102231460E300BF06DFA99 +:10AC500009A96846F8F787F9002803D1A17F1022D7 +:10AC60001143A17714B070BD002001900290E8E775 +:10AC7000F0B50646008A97B080B20D460190FEF707 +:10AC8000BEFA04468C48317848380746E8370990C0 +:10AC90000B000BF0B9FC0EFCFB48085F8798B8D995 +:10ACA000FAF9F8F7F6FC002301221946019801F0A1 +:10ACB00061FF050004D1FF2080A130300BF0B3FB11 +:10ACC000002C04D1FF207DA131300BF0ACFB387E8D +:10ACD000C00904D078486030C06DA86112E02B2014 +:10ACE000694608720BA902A8F8F73DF9002804D0BC +:10ACF000FF2072A13C300BF096FB74490C980BF0CE +:10AD00008EFAA9617068A862B068E862A07F8007C7 +:10AD1000800F012820780DD0252804D0FF2067A1BE +:10AD20004D300BF080FB324621460198FFF736FF8D +:10AD300017B0F0BD2528F6D0222806D0242804D04C +:10AD4000FF205EA146300BF06EFB25212046FEF76A +:10AD50008EFAE8E7002301221946019801F00AFF64 +:10AD6000060004D1FF2055A158300BF05CFB002CED +:10AD700004D1FF2051A159300BF055FB2078252834 +:10AD800004D03078012108433070D1E702202870C8 +:10AD9000B068A860B068002802D000202871C7E71A +:10ADA0000120FBE72B2069460870434968464C396F +:10ADB000F8F7D9F8002804D0FF2040A178300BF034 +:10ADC00032FB03201BE02A206946087000A81022ED +:10ADD000023071680BF0A9F904A810220230B168A2 +:10ADE0000BF0A3F9344968464C39F8F7BCF8002851 +:10ADF00004D0FF2031A189300BF015FB042028700E +:10AE00000998686094E7B068002804D1FF202BA15E +:10AE100095300BF008FBE07F400704D5FF2027A109 +:10AE200096300BF000FBB06806220A3800903379A8 +:10AE30000421019801F0FBF90028A6D0FF201FA1F2 +:10AE40009B300BF0F0FA73E7002C04D1FF201BA11C +:10AE5000A3300BF0E8FA2046223010220546716834 +:10AE60000BF063F928212046FEF701FAA07F800746 +:10AE7000800F022814D100231A462146009501981C +:10AE800006E04BE1BAE0B0E095E03FE071E05FE161 +:10AE9000FFF7C7FE11281BD029212046FEF7E7F94E +:10AEA000E07F317A4007400FC9000843E0773FE771 +:10AEB0000080010028000020400B00207372635CBA +:10AEC0006761705F7365632E6300000040420F008E +:10AED000A07F000704D5FF20FD49B0300BF0A3FA96 +:10AEE000A07F08210843A0770020608620463430E8 +:10AEF0000BF078F9E07FFD220146C9071040890F69 +:10AF00000843E077307A2034207011E700230122D3 +:10AF10001946019801F02EFE040004D1FF20EC49EF +:10AF2000CD300BF080FA2B2069460872E94902A85F +:10AF3000F8F719F8002804D0FF20E549D2300BF0CB +:10AF400072FAE4488188204621300176090A417668 +:10AF50000E2129702146FC316960017E2974407EF2 +:10AF60006874DC482C30A860103030346C61E860C4 +:10AF7000DEE6002C04D1FF20D549E6300BF053FA71 +:10AF80002078212893D93079012802D0022808D1CD +:10AF900003E0E07F04210843E077387E0121084385 +:10AFA0003876324621460198FFF7F8FD23212046E6 +:10AFB000FEF75DF9BCE601220421019801F01FFCB7 +:10AFC0000028A2D0002301221946019801F0D2FDE9 +:10AFD000040003D1BE49C0480BF025FA0F202870A9 +:10AFE000172028716E34AC60A2E60421019801F0AC +:10AFF00056FC002889D11020287099E600230122F0 +:10B000001946019801F0B6FD050004D18720B0492A +:10B0100080000BF008FA2E462036307E41064DD5D2 +:10B02000A17F8F07BF0FC00713D029468031486F1B +:10B0300000280ED0027CF37DD207D20F5B001A43AA +:10B040000274486F5108E27F4900D207D20F1143C2 +:10B050000174307E000713D52A468032116F002913 +:10B060000ED0087CF37DC007C00F5B001843087446 +:10B07000116FE27F40084000D207D20F10430874DE +:10B08000307E80070BD5F8204259002A07D0012FC7 +:10B0900005D02946307C31311032FEF783FA307EFC +:10B0A000C0060BD5F8204259002A07D0012F05D140 +:10B0B0002946307C31311032FEF774FA0523684698 +:10B0C0000370357E4570834822216038019A0170F3 +:10B0D0004178C908C900C91C417042800372457299 +:10B0E000F6F78EFD2078252809D021280BD07A4844 +:10B0F00077495B300BF097F92078222803D9222179 +:10B100002046FEF7B4F80021019801F06BFD0028FD +:10B1100000D10DE670486E49633092E674686D4D5B +:10B1200020786035092802D00A28F2D10BE0E168C6 +:10B13000002902D02846F7F7E8FE2169002902D04D +:10B140002846F7F7E2FE21462846F7F7DEFEEFE550 +:10B1500061485F49883074E65E4810B504222821B2 +:10B160006030F7F7B9FE5B480024EC30017E4906F9 +:10B17000490E01764038C465FCF739FD55493C312C +:10B1800008461038F6F78BFC52484C30047410BD5A +:10B1900070B50D46FEF733F8040004D14E484C4913 +:10B1A000A7300BF040F9FF21053128460BF01CF8C1 +:10B1B000A07F8007800F01280CD00221284688300C +:10B1C000FCF716FD002804D043484149AC300BF091 +:10B1D0002AF970BD0121F1E70A46014610B5104673 +:10B1E0008830FCF71FFD10BD70B5054611200C46D8 +:10B1F0000870002161702121495D002908D00329D0 +:10B200000ED0042910D034483149C6300BF00BF968 +:10B2100020780009012802D9E87FC008607070BD5D +:10B220000007000F203002E00007000F30302070D0 +:10B23000EEE7F0B504464068082601789BB008297F +:10B240000DD00B2903D00C294BD1012181716068ED +:10B2500087883846FDF7D3FF05004CD147E0478883 +:10B260003846FDF7CCFF050004D1172018494001EE +:10B270000BF0D9F82878212833D0282833D16068FA +:10B2800002210C3000F050FF00282CD0606808210B +:10B29000001D00F049FF002825D02D2168460170CF +:10B2A000478029461022223101A80AF03EFF0FA94B +:10B2B0006846F7F758FE002804D007480449EF30E5 +:10B2C0000BF0B1F8A87F10210843A877292105E0E9 +:10B2D000BCAE0000F40A0020030200002846FDF77F +:10B2E000C6FF1BB0F0BD607830436070F9E7FE49DF +:10B2F000FE480BF098F8A87FEF210840A87729783E +:10B3000021290FD061688A79002A02D08978002922 +:10B3100012D08007800F022849D0F448F249343017 +:10B320000BF081F8FEF7DEF90028DAD0EF48EE499D +:10B330003F300BF078F8D4E7607830436070E87FF6 +:10B34000C00701D0042100E00321212041552878C5 +:10B3500029280BD03946062002F0B1F82878242895 +:10B36000E0D122212846FDF782FFDBE700230122FE +:10B370001946384601F0FEFB040004D1C920DA4921 +:10B3800080000BF050F825212846FDF770FF0D20B6 +:10B3900008A90871204609A98830FCF735FC022865 +:10B3A000C0D00028BED0D148CF491D30B8E7607862 +:10B3B00030436070B6E7F7B58AB015460646FDF72C +:10B3C0001EFF002841D0017822293ED323293CD0FA +:10B3D000C17F490739D4807F8007800F01280DD0B5 +:10B3E000002301220021304601F0C4FB0746C0487B +:10B3F0000290F7F781FD040007D101E00123F0E797 +:10B40000BA48B94959300BF00EF8002F1FD08837D1 +:10B4100067610298F7F770FD07460298F7F76CFD31 +:10B4200009212170266225710B99E760A1602061D6 +:10B4300003A92046FCF70CFC022806D0002804D003 +:10B44000AA48A94975300AF0EEFF0DB0F0BD002002 +:10B4500007466061E4E730B5002387B00546012266 +:10B46000194601F087FB04462846FDF7C8FE007820 +:10B4700022281BD9002C04D19C489B4981300AF01A +:10B48000D2FF0F21684601701721017120466E30EE +:10B49000029069461A30FCF7B7FB022806D0002854 +:10B4A00004D0E520904980000AF0BDFF07B030BD10 +:10B4B00030B5002387B005460122194601F05AFB3A +:10B4C00004462846FDF79BFE00782228EED9002C82 +:10B4D00004D18648844993300AF0A5FF10206946BC +:10B4E000087020468830FCF78FFB0028DED0E9206A +:10B4F0007D4980000AF097FFD8E7F7B50546007848 +:10B500000027000982B00C463E4602287ED007285C +:10B5100002D00A284AD14AE068680178082907D091 +:10B520000B2930D00C292ED070486F49D33060E100 +:10B5300014271A26002C6AD04088A080FDF75FFEF1 +:10B540000090002804D169486749AF300AF06BFFCA +:10B5500000980099C07DA21D1831FEF723F8686895 +:10B5600008228089E081696820461030091D0AF0B0 +:10B57000DCFD207E01210843F92108402076009857 +:10B580004021807F47E018270826002CD3D08088F0 +:10B59000A080FDF734FE050004D1F7205249800059 +:10B5A0000AF041FFA11D2846FFF71EFE23E1002CF3 +:10B5B00001D0288BA080287A01287DD0022804D0D1 +:10B5C00003282FD048494B4813E11C270726002C9D +:10B5D000B1D0A088FDF713FE0090002804D1FD2013 +:10B5E000414980000AF01FFF287B8007800F012857 +:10B5F000A07914D040084000A071FD210840297BAB +:10B600004907C90F49000843A07101E0E3E0DFE00A +:10B6100000988021807F084300998877EBE0012122 +:10B620000843E9E713270B26002C84D0A088FDF7F8 +:10B63000E6FD00900023A0880122194601F09AFA45 +:10B6400005460098002804D12A48274960380AF0A6 +:10B65000EAFE002D04D181202349C0000AF0E3FE58 +:10B660000098807F8007800F012859D0E86A817890 +:10B670008907890F0129A17954D049084900A1718E +:10B680008278FD255207D20F294052001143A17143 +:10B69000E322114002785207D20E1143A171DF223A +:10B6A00011404278D207920E1143A1710021E1713D +:10B6B000C1782172427900E037E00179607AD307DE +:10B6C00040084000DB0F18439307DB0F28405B0066 +:10B6D00018435207FB23D20F1840920010436072A8 +:10B6E000A07A4008400007E0BCAE00000E03000056 +:10B6F000540B002067040000CA07D20F10438A07CA +:10B70000D20F2840520049071043C90F1840890042 +:10B710000843A0720098007823286CD92621AFE056 +:10B72000A86AA4E701221143A9E7297BFE48022960 +:10B7300010D017270C26002C4AD0012911D003293C +:10B740001ED004291FD005291DD0F849F8480AF059 +:10B750006AFE23E019270726002C4CD00121A17195 +:10B7600005E00121A171E17989088900E171017E7B +:10B77000CA094906D201890E49000A4302760DE042 +:10B780000220A07106E0687B0007000F8030A071E6 +:10B79000052918D0E07980088000E071A088FDF7C5 +:10B7A0002EFD05460078212825D0232804D0E04826 +:10B7B000DE490C300AF037FEA088002101F012FAB1 +:10B7C000222128465DE0E07980088000401CE4E703 +:10B7D0000498068015E0002C01D06888A080287AA3 +:10B7E000032828D004280FD005284DD0D048CF49B1 +:10B7F00064300AF018FE0498002C068001D02780DF +:10B800006680002005B0F0BD15270C26002CDFD087 +:10B810000023A0880122194601F0ACF9050004D1EB +:10B82000C348C2492A300AF0FEFD0622A11DA869BC +:10B8300009F0DCF9DFE716270726002CC8D0A0881E +:10B84000FDF7DDFC00900023A0880122194601F0DD +:10B8500091F905460098002801D0002D04D1B44884 +:10B86000B24938300AF0DFFD2878C00601D5022041 +:10B8700000E00120A071009800782328BBD927217F +:10B880000098FDF7F4FCB6E717270C26002C9FD094 +:10B89000A088FDF7B4FC00906D7A002804D1A4487C +:10B8A000A2494B300AF0BFFD0621A01D0AF09AFC08 +:10B8B0000020A071207A032108432072FB21084058 +:10B8C0000099C97FC907490F08432072680692D5BD +:10B8D000E07904210843E071A07AE90740084000BC +:10B8E000C90F0843E17A2A0749084900D20F1143DA +:10B8F000FD22AB07DB0F10405B001843A072E80687 +:10B90000C00F114040000143E17274E710B50446D6 +:10B91000807990B08009012804D04D20834900012E +:10B920000AF081FDFFF76AF90120694608707E4838 +:10B930000AA9A0380190201D0290601C0B90684657 +:10B94000FCF786F9002804D07948784987300AF056 +:10B950006AFD0322601C0B990AF0E7FB10B010BDD2 +:10B9600010B5714CA03C002805D00146102220469D +:10B970000AF0DBFB0120207410BD10B50446FFF770 +:10B980003DF969491022A03920460AF0CEFB10BDCE +:10B9900070B50025644C00281CD06649884207D346 +:10B9A00001218904884205D363490968884201D28C +:10B9B00010250DE0062109F003F9411C07D05A4972 +:10B9C0004039C865207E80210843207600E00725A5 +:10B9D000284670BD207E4006400EF6E7F3B50020F5 +:10B9E00089B00D46029000290AD0524885421CD3E6 +:10B9F00001208004854203D34F480068854214D358 +:10BA00000998FDF7FCFB060003D03078222815D1F9 +:10BA100002E04A480BB0F0BD002D08D1B07FC1094B +:10BA200003D08007800F022801D01020F2E7B07FFA +:10BA3000C10601D4000703D5002D01D00820E9E795 +:10BA40003948007EC00712D1F07F400701D50D2094 +:10BA5000E0E7002201231146099801F08BF8070066 +:10BA600005D0B07F8007800F022802D00BE01120A4 +:10BA7000D0E7002D07D02A4639463046FFF728F890 +:10BA800002900028C6D128488C38F7F735FA040010 +:10BA900003D126492A480AF0C6FC0A2020700998DA +:10BAA000206238468830A060B07FFB218007800F7D +:10BAB000012829D0002D4CD002202071381DE060D3 +:10BAC00038780007400F20743878C006C00F6074C3 +:10BAD000A07C2A788008D2078000D20F1043A0747F +:10BAE0000840F17F01AAC907490F0843A074A8784C +:10BAF000E07469462846FFF72CF8684600792075FF +:10BB000068460078607528E001202071207B2A7843 +:10BB10008008D2078000D20F104320730840297894 +:10BB20008907C90F89000DE0E00B0020BCAE0000C2 +:10BB300053040000008001002800002002300000B3 +:10BB4000630500000843207324213046FDF78FFB76 +:10BB50000BE0032020710520207325213046FDF7DE +:10BB600086FBB07F4006400EB07703A92046FCF765 +:10BB70006FF8022805D0002803D0FD49FD480AF0DF +:10BB800052FC029846E7FFB581B00A9D06461C4666 +:10BB90001746142128460AF027FB0B980021016064 +:10BBA000F8070ED0F44920680968884239D312306A +:10BBB00028602068143068602068A8600B982168AD +:10BBC0000160B80726D56068002803D0EA490968F3 +:10BBD000884226D3029900290AD0FC3600280ED0CC +:10BBE00031461030FDF79DFC00281BD1606810E045 +:10BBF000002816D0E86080366068B0670AE0FEF77B +:10BC0000A9FA0146072230460AF08FFAFEF7F6FF3E +:10BC1000DA48E860780707D5D749A06809688842FC +:10BC200001D21020EEE528610020EBE5FFB5D44AF3 +:10BC30000E4607CA97B002AB07C3002700970197CB +:10BC40001798FDF7DCFA050005D02878262804D0DF +:10BC500008201BB0F0BDCB48FBE700231A4619466D +:10BC6000179800F087FF040004D1C248C049803013 +:10BC70000AF0D9FBA87F8007800F1690012814D006 +:10BC8000022824D0BB48BA4999300AF0CCFB0121E4 +:10BC90000022852E31D01EDC002E26D0812E26D00B +:10BCA000822E26D0832E1ED125E0002EEFD12146F4 +:10BCB0002846199AFEF70CFF0028CAD119988078F7 +:10BCC000009019980078C007C00F0190DFE719981D +:10BCD000002808D1DBE7862E11D0882E11D0892EBE +:10BCE00011D08A2E11D00720B3E710460EE0084687 +:10BCF0000CE002200AE0032008E0052006E0062010 +:10BD000004E0082002E0092000E00A20002222715D +:10BD100001216A461176211D0791002801D020716A +:10BD2000FAE0169801280CD0A66AE06A02220121E6 +:10BD300010900020A0602846173002291AD0012157 +:10BD400019E0E66AA06A1090032030702078FB2387 +:10BD5000C006C00F7070B07801221840009BF370CD +:10BD60008008019B800018430221B0700020707190 +:10BD70003071DEE70021890009190861681C022A78 +:10BD800001D0012100E00021890009190861B07883 +:10BD90008007800F01285ED1109880788007800F7F +:10BDA000012858D110980079844610984079009065 +:10BDB000169801281DD0317908A801747179017590 +:10BDC00008A8027C6046024008A8007D009908404F +:10BDD000139010433FD06C491A98884207D3012131 +:10BDE0008904884215D364490968884211D2102019 +:10BDF0002FE70CAA0DA91998FEF7ABFE08A8007C46 +:10BE000061460840307108A8007D009908407071B3 +:10BE1000D6E720463C3021460090F031169801913B +:10BE2000022834D000211A9B20460C33FFF7ABFECA +:10BE30000028DDD12046503021460090F43116987C +:10BE40000191012825D0002120461A9B139AFFF763 +:10BE50009AFE0028CCD110988078400702D4E87F61 +:10BE6000C0072BD0169902A8012914D0109909787F +:10BE70004900405A21780907490F4900C8408707FF +:10BE8000BF0F2AD0012F14D0022F0FD113E00121B0 +:10BE9000C9E70121D8E721780907490F4900405A2D +:10BEA000109909784900C8408707BF0F032F04D0B5 +:10BEB00004E0022711E001270FE00227169801286D +:10BEC0000BD1B078FB210840E97FC907490F08432F +:10BED000B07020780007400F3070207810224008A2 +:10BEE000400020701099D2434978C907C90E114308 +:10BEF00008402070C00623D4022F21D0012F21D06A +:10BF00000020A061E0612062606220461830A060DD +:10BF1000E87F40084000E877204606A98830FBF714 +:10BF200073FE002806D0022804D06F2010490001BB +:10BF30000AF079FA25212846FDF799F9002088E6CC +:10BF4000032008E020460D211B300AF04BF9204663 +:10BF50001830A060042069460875E87F0121084375 +:10BF6000E87705AA29461798FEF730FED4E70000C7 +:10BF7000BCAE00008E05000028000020400B002011 +:10BF8000606701000230000000800100F0B587B05A +:10BF900015460E0004460DD06A48854207D301209D +:10BFA0008004854206D368480068854202D210208A +:10BFB00007B0F0BD2046FDF722F9070004D038781D +:10BFC000272803D00820F3E76048F1E700231A464A +:10BFD0001946204600F0CEFD040003D15C495D48BF +:10BFE0000AF021FA0020002E05D0022E08D0012EE2 +:10BFF00011D00720DCE701216A461171A06018E02A +:10C00000234618336946A360087110222946184652 +:10C010000AF08BF80DE021461831A16069460871DD +:10C02000A061E061206260620621284608F0C8FD38 +:10C03000A0612078C10714D0400840002070022081 +:10C04000694608702046183002907030FBF7DCFD1E +:10C05000022806D0002804D03E483D4923300AF08B +:10C06000E2F925213846FDF702F90020A0E770B576 +:10C0700094B00D460646002B02D0072014B070BDC8 +:10C08000FDF7BDF8040007D02078222802D3A07F56 +:10C09000400603D40820F1E72C48EFE7002D19D023 +:10C0A0002D216846017046801022294601A80AF019 +:10C0B0003CF8E07F297C4008C9074000C90F0843CD +:10C0C000E077297C40078906400FC90EC900084364 +:10C0D000E07703E02E2168460170468009A9684692 +:10C0E000F6F741FF694609782D2905D1002803D1CB +:10C0F000A17F10221143A177A17FBF221140A17718 +:10C10000BCE710B50C46FDF77AF8002805D00E49BB +:10C1100009688C4203D2102010BD0C4810BD214686 +:10C12000FFF762F8002010BD05E00278401C002AED +:10C1300001D0002070470A46491E89B2002AF4D176 +:10C14000012070470080010028000020023000001C +:10C15000BCAE00000F07000030B50346072903D02E +:10C160000820DA781C7916E00720FAE707290BD0B7 +:10C170005500ED186D79072D01D0401EC0B2521C3C +:10C18000D2B20F2A07D105E05500ED186D79072DC1 +:10C19000F3D0F4E700222546641EE4B2002DE5D179 +:10C1A00030BDFFB581B00C461646114620460A9FA9 +:10C1B0000B9DFFF7D1FF00280AD020790F2803D369 +:10C1C000FEA1A0200AF02FF9A078C00907D019E03D +:10C1D000072E02D0112005B0F0BDFD48FBE7019805 +:10C1E0002880381D6880002068712871EF800498CD +:10C1F00028812846F6F7DFFE002803D1EFA1AD2005 +:10C200000AF011F9E07821794018491CC0B2217177 +:10C210000F2801D30F38C0B2400000194671817950 +:10C22000F12249084900114081710020D3E7FFB590 +:10C2300083B01C4616460F4600231A4602210C9D69 +:10C24000039800F097FC010008D033463A46019568 +:10C2500000940398FFF7A5FF07B0F0BDDC48801EEF +:10C26000FAE7F0B5054616460F4650888DB0002314 +:10C270000122022100F07EFC040003D1CFA1DF20C7 +:10C280000AF0D1F8002069460871A078400603D171 +:10C29000CAA1E3200AF0C7F8042F5ED32A78D0079A +:10C2A000C017401C06D161786B78994255D121782E +:10C2B000090752D00121142A46DA012A42D0122A53 +:10C2C00002D0132A40D128E00C2F3DD1A27852068B +:10C2D000520E012A38D0207800090001401C20703D +:10C2E000687860706846017168792A7901021143A3 +:10C2F00068460181E879AA790102114368464181C3 +:10C30000687A2A7A0102114368468181E87AAA7A1A +:10C31000010211436846C1811AE0062F14D120782A +:10C320000009000120707188012001F0C8F8022185 +:10C3300068460171C91E018168792A790102114399 +:10C3400068461FE0062F0AD06A461279002A1BD0E1 +:10C350007088324601A9FDF77AFD0DB0F0BD207856 +:10C360000009000120707188012001F0A8F8022165 +:10C370006846017168792A79010211436846018192 +:10C380000021C9434181E3E70028E6D0748868466C +:10C3900081766978C176022181830021C18304A856 +:10C3A00005220090062311462046FFF740FF002893 +:10C3B000D3D088A1D6200AF036F8CEE7F7B58CB0F6 +:10C3C00015460C990D98F9F7CEF9C0B2082851D14D +:10C3D000002069468885688800230122022100F038 +:10C3E000C9FB040004D1FF2074A163300AF01BF8DC +:10C3F00001230021E07822790BE046003619767996 +:10C400009E4201D1491CC9B2401CC0B20F2800D1C4 +:10C4100000201646521ED2B2002EEED1002902D1C3 +:10C4200017206946888504AB02330BAA00950C9946 +:10C430000D98F7F73BFC0006000E07D002281BD032 +:10C44000032817D0FF205DA1893011E06846808D58 +:10C4500000280FD002A901910090688804230122CE +:10C460002146FFF79EFE002804D0FF2053A176301E +:10C4700009F0D9FF0FB0F0BD68781021084368704B +:10C48000F8E70020584902464300401CCA520828D9 +:10C49000FAD3704700218170017809090901017000 +:10C4A00000214170C1700171704770B50D460023C5 +:10C4B0000122022100F05EFB040004D1FF203FA115 +:10C4C000CF3009F0B0FFA0786906C009C001490E5D +:10C4D0000843A07070BD704710B50146012000F000 +:10C4E000EEFF10BD3EB58DB2002301220221284689 +:10C4F00000F040FB040004D1FF2030A1E43009F03B +:10C5000092FF20786946000900012070022008701F +:10C5100036488880C88000222846FDF798FC3EBD3A +:10C52000F7B505460078002700090C463E4601286D +:10C5300004D0FF2021A1F33009F075FF287A0328E9 +:10C540000CD041201DA1C00009F06DFF0298002C05 +:10C55000068001D0278066800020FEBDEA89702712 +:10C5600010460A3086B2002C0AD06888A080A889BC +:10C570002081E28020460A30296909F0D6FDE5E7EE +:10C5800002980680E8E7F8B543680246D9799C79B5 +:10C59000090221435C7A1E7A25025C88981D354386 +:10C5A000241FA14238D11B79022B35D1042D34D060 +:10C5B000052D3DD0062D34D0402D19E07372635CFB +:10C5C0006C326361705F636F72652E630000000000 +:10C5D000043000007372635C6C326361705F636F80 +:10C5E00072652E6300000000000C0020FFFF0000B9 +:10C5F00012D3061D0F461446284600F0E9F9082814 +:10C600000AD01120207003202072A581E7812661C5 +:10C610006078082108436070F8BD001DFFF7CEFE6A +:10C62000F8BD031D50880A461946FEF7C4FEF8BD42 +:10C63000001DFFF716FEF8BD70B50D4600238CB047 +:10C6400006461A46022100F095FA040031D02078FF +:10C650000007000F01282ED01220694688746078E8 +:10C660000523801CC874082088822888C8826888AE +:10C670000883A8884883E888888302A90C20019150 +:10C6800000901A4621463046FFF78BFD00280ED158 +:10C69000F02300223146012000F06CFE20780009D2 +:10C6A0000001401C20706078801C607000200CB07D +:10C6B00070BDCD48FBE71120F9E770B50D460023AA +:10C6C0008CB006461A46022100F054FA040006D047 +:10C6D00020780007000F012803D00820E7E7C248B0 +:10C6E000E5E71321684681746178C1740221818273 +:10C6F000C58202A906200523019100901A46214611 +:10C700003046FFF74EFD0028D1D120780009000106 +:10C7100020700020CBE7F3B581B00D460023012245 +:10C720000221019800F026FA00260446002803D1D1 +:10C73000AE49AF4809F077FE2079A8423BD2AC4819 +:10C74000AA49401C09F06FFE35E0E07841000F195E +:10C75000401C7979C0B20091E0700F2801D100200F +:10C76000E0702079401E2071B879C00708D0009889 +:10C770000199042815D09D498220183109F053FEF3 +:10C78000B8790007410F08D0400F019904280CD058 +:10C7900096498F20183109F046FE009807280AD1E3 +:10C7A00007E00846FEF784FEEAE70846FEF753FE78 +:10C7B000F3E7761CF6B228466D1EEDB20028C4D110 +:10C7C0003046FEBD10B500230122022100F0D2F94F +:10C7D000040004D1B5208549800009F024FEE078EA +:10C7E00021794018C0B2E0700F2801D30F38E070F3 +:10C7F00000202071A07880210843A07010BDF8B5FA +:10C8000017460D4600231A46022100F0B3F9040032 +:10C8100005D0002D0CD0002F07D0062006E0072DF4 +:10C8200001D00820F8BD0720F8BD0820A84204D890 +:10C830006F486E49423009F0F6FD29462046FFF761 +:10C840008BFC0646002F28D0002E26D1E0782179D7 +:10C850001CE0420012195379072B03D093791B0770 +:10C860005B0F04D0401CC0B20F280CD00CE040007D +:10C8700000198079F12318406B071B0F1843907142 +:10C8800000290AD104E00020491EC9B20029E0D1E4 +:10C89000574856495A3009F0C6FD3046F8BDF8B53C +:10C8A0000D4600231A46022100F064F9040004D169 +:10C8B0004F484E49683009F0B6FD681E052804D37C +:10C8C0004B484A49693009F0AEFD0F21E2782079E2 +:10C8D000002310E0560036197779AF4206D1B179BE +:10C8E00049084900B1715B1CDBB21146521CD2B23F +:10C8F0000F2A00D100220646401EC0B2002EE9D108 +:10C900000F2905D248000019817901221143817154 +:10C910001846F8BD10B50446402801D2072010BDC6 +:10C9200000F056F8082802D03120000210BD002186 +:10C93000304802E0491C082903D24A00825A002AE2 +:10C94000F8D1082903D049004452002010BD04202A +:10C9500010BD10B5402801D2072010BD00F038F8F6 +:10C96000082805D00021234A40001152084610BD76 +:10C97000052010BDF0B58BB016460C00074607D059 +:10C98000002E05D06188402904D207200BB0F0BDED +:10C990001020FBE72088002801D0172801D90C209F +:10C9A000F4E7084600F014F808280FD0258803A8FB +:10C9B0002A463146023009F0B8FB01A8009062888F +:10C9C0002B4607213846FFF732FCDFE70520DDE77D +:10C9D00001460020074A02E0401C082803D2430019 +:10C9E000D35A8B42F8D1704702300000BCC500001A +:10C9F000AD020000000C0020F8B50546E54C079E8E +:10CA0000069821706270A370E6702071681C42085D +:10CA10005200E14B0021880000198446C261605C2D +:10CA200040008218002D0AD0002005E0664647002D +:10CA3000F669401CF353C0B2665C8642F6D8491CC6 +:10CA4000C9B20529E7D30026D21C9708B000BF0061 +:10CA500000198760304600F042F9A15D761C48431A +:10CA6000C219F6B2052EEFD3501B80B2F8BDF0B557 +:10CA70000546C84F8C460020FF247E5DA9009646DF +:10CA80000346CF190CE0F9695A008A5AC2498A4212 +:10CA900004D1401CC0B2FF2C00D11C465B1CDBB291 +:10CAA0009E42F0D86146002909D100280BD0002D04 +:10CAB00007D0B84949788E4203D2401EC0B2002840 +:10CAC00001D071460C70F0BD70B5B24C8D000023E2 +:10CAD0002D19615C09E0EC695E00A45B844202D11F +:10CAE0001370012070BD5B1CDBB29942F3D80020AB +:10CAF00070BDFEB51C4617460D46060008D0002D39 +:10CB000006D0F01C80088000B04203D01020FEBD8B +:10CB10000E20FEBD002F03D0002C01D0A74201D96A +:10CB20000720FEBD0094234622463946002001948A +:10CB3000FFF762FF2988814207D0814201D2042198 +:10CB400000E0092128800846FEBD009423462246C5 +:10CB5000394630460194FFF74FFF28800020FEBD84 +:10CB600010B5044600F0C5F8002801D0E0B210BDB1 +:10CB7000FF2010BDFFB50546874881B01E460C4614 +:10CB8000854204D0052C02D20398022802D300204B +:10CB900005B0F0BD002769460F7028466A46214659 +:10CBA000FFF792FF00280ED068460178204600F07B +:10CBB000A8F8002EECD00028EAD1284600F099F819 +:10CBC000002809D103E03846002EF6D1E0E7FF2027 +:10CBD00072A15C3009F027FC21462846039A00F038 +:10CBE0009CF8D5E7F8B505460C4600206A4E694624 +:10CBF0006E4F0870B5423BD0052C01D30720F8BD1D +:10CC00000A4621462846FFF75FFF002830D06846D5 +:10CC10000178204600F075F8230009F0F5FC0504C2 +:10CC2000090C11161B0001462846FEF7D5FA15E03F +:10CC3000FDF7E0FA12E001462846FFF74CFC0DE054 +:10CC400001462846F6F7B5FF08E001462846F8F702 +:10CC500012FC03E056A17B2009F0E5FB4D4A684633 +:10CC6000A10000788918C96940000E520020F8BD63 +:10CC70003846F8BD524A1268914201D210207047DE +:10CC8000052801D3072070470872002048727047BA +:10CC9000F8B504464A480068844201D21020F8BD25 +:10CCA000207A3C4A83009B18617A3B4D125C11E06C +:10CCB000DE694F00F65BAE420AD04A1C6272DA6946 +:10CCC0004B00D25A228000F01CF860600020F8BDB2 +:10CCD000491CC9B28A42EBD861720520F8BD0EB575 +:10CCE000384B40000ECB0091029301926946085ADE +:10CCF0000EBD28494978814201D9012070470020A2 +:10CD0000704770B50C460546FFF7E9FF214AA900B8 +:10CD1000891889686043401870BDF8B50C4606460E +:10CD200000206946134608706A4619462046FFF7F8 +:10CD30009EFE002500282BD0164A6846A1000078E8 +:10CD40008918C96940000E52684601782046FFF7ED +:10CD5000D8FF0546230009F057FC0504090C0F1401 +:10CD6000170029463046FEF713FA11E0FDF720FAC6 +:10CD70000EE0FFF78FFB0BE029463046F6F7E0FEAA +:10CD800006E0F8F771FB03E009A1622009F04BFB14 +:10CD90002846F8BD100C0020FFFF00007372635C92 +:10CDA000686F73745F636D2E6300000002300000D3 +:10CDB0007372635C686F73745F636D2E6300000051 +:10CDC000280000206C67010010B5014620220948A8 +:10CDD00009F0ABF907490020C877084610BD06499D +:10CDE000012048610548064A0168914201D10021AD +:10CDF00001607047400C00200005004078000020D2 +:10CE0000BEBAFECA8107C90E002808DA0007000F63 +:10CE100008388008C24A80008018C06904E0800891 +:10CE2000C04A800080180068C8400006800F704724 +:10CE3000BD4948788978884201D3401A02E021220E +:10CE4000511A0818C0B27047B74923314878897819 +:10CE5000884201D3401A02E02122511A0818C0B2B8 +:10CE60007047B149463148788978884201D3401AE1 +:10CE700002E02122511A0818C0B27047A94910B522 +:10CE80000C310868FF22120290430122D2031043A2 +:10CE90000860A54900202331487088702339487004 +:10CEA0008870463148708870A04808F0C8F89F48DC +:10CEB000401C08F0C4F8F5F741FC00F028F910BD5B +:10CEC00020207047B4E770B50C4605460026FFF7F2 +:10CED000AFFF9549A04214D30A46203A00232046CA +:10CEE000641EE4B200280BD08878105C2870887823 +:10CEF0006D1C401CC0B288702128F0D18B70EEE709 +:10CF0000012600F004F9304670BD202070479BE7F1 +:10CF100070B50C4605460026FFF796FF824923317F +:10CF2000A04214D30A46203A00232046641EE4B2ED +:10CF300000280BD08878105C287088786D1C401C05 +:10CF4000C0B288702128F0D18B70EEE7012600F086 +:10CF5000DEF8304670BD202101700020704710B50A +:10CF60000446FFF77EFF2070002010BD70B50C4610 +:10CF70000546FFF776FF6C494631A04215D30A46B5 +:10CF8000203A00232046641EE4B200280BD08878A3 +:10CF9000105C287088786D1C401CC0B288702128F5 +:10CFA000F0D18B70EEE7002400E0614C00F0AFF8A8 +:10CFB000204670BD70B50C460546212904D9FF20D6 +:10CFC0005CA1473009F02FFA55484068103840B24C +:10CFD000FFF718FFC6B20D20FFF714FFC0B286425C +:10CFE00007D2FF2053A14D3009F01DFA01E0F5F7FB +:10CFF000E8FB21462846FFF766FF0028F7D070BD02 +:10D00000F8B507464948484C401E474E007825462B +:10D0100046362335002806D1A9786878212200F009 +:10D020006BF800280ED0A1786078212200F064F817 +:10D03000002814D0B1787078212200F05DF8002823 +:10D0400028D033E038496878C91C0F546878401CF0 +:10D05000C0B26870212829D10020687026E03249CA +:10D06000607820390F546078401CC0B2607021286D +:10D0700001D1002060702D4F7F1E3878002815D018 +:10D08000A1786078212200F037F800280ED0002027 +:10D0900038700BE02449707826310F547078401CAA +:10D0A000C0B27070212801D100207070A978687812 +:10D0B000212200F021F800281DD0A17860782122DB +:10D0C00000F01AF8002816D0B1787078212200F00C +:10D0D00013F800280FD0F5F756FB144807F0B7FFF8 +:10D0E00001214903884203D016A1C12009F09BF910 +:10D0F0000E4807F0C4FFF8BD401C884205D090429E +:10D1000001D1002901D0002070470120704710B5DF +:10D11000064807F09CFF002801D1F5F723FB10BD5E +:10D1200000ED00E000E400E0800C00207D00002025 +:10D13000072000007372635C736F635F72616E64DB +:10D140002E6300007372635C736F635F72616E6461 +:10D150002E6300000C4908784A78401CC0B2904207 +:10D1600000D008707047094A074820BF40BF20BF61 +:10D170004178037843701368002B02D103788B4207 +:10D18000F3D00020704700007F00002000E200E0A4 +:10D19000FEB5F34C07466068FF213E0181552178BA +:10D1A000FF2913D00901083141583246491E08327F +:10D1B00009020192090A805800F0C8F9002802D03B +:10D1C0002478254615E06168207888552770FEBDD3 +:10D1D000E34842680198115828010090083010581F +:10D1E00000F0B4F9002806D1DD482C4641680098CB +:10D1F0000D5CFF2DECD1DA4821014068855547547C +:10D20000FEBD70B5D64A04460020157A53680AE080 +:10D210000201561C9E5DA64203D10C329A588A42E6 +:10D2200004D0401CC0B28542F2D8FF2070BDF8B5D2 +:10D23000CB4F3E7801F013FE0146FF2E68D034013B +:10D24000254678680835405900F080F9022802D94F +:10D25000786840595AE0C2494868025D0A70A11CCA +:10D26000425C002A0CD0521E425441590122D20580 +:10D2700089180902090A41513046FFF789FF30E059 +:10D28000631CC25C0092221D94468258002A10D072 +:10D2900001239B029A420FD99205920D43595703DD +:10D2A000DB191B021B0A43516346C3589A1A920AA0 +:10D2B00009E0FF21C1540AE0435952039A181202AF +:10D2C000120A4251002242543046FFF761FFA4483F +:10D2D0000C344168C26800980959800012580098BF +:10D2E00090479F4C2078FF2812D001F0B8FD0146EE +:10D2F0002078626800010830105800F027F90128F2 +:10D3000096D92078616800010830085801F09AFD2C +:10D31000F8BDF8B51C4615460E460746FF2B03D34D +:10D3200090A1D32009F07FF88D48FF21C7604560A8 +:10D3300004720674017000224270104604E002017B +:10D34000521C401CA954C0B2A042F8D3F8BD70B51D +:10D35000834C06466578207C854203D381A1E62074 +:10D3600009F061F8E068A90046506078401C6070E0 +:10D37000284670BDFFB581B01D46FF2401F06FFD4A +:10D38000774F064679780198814203D875A1F42039 +:10D3900009F049F872480021037A406810E00A0158 +:10D3A0009446521C825CFF2A24D0019FBA4205D1C8 +:10D3B00062460C328758029A97421DD0491CC9B266 +:10D3C0008B42ECD8FF2C17D021014B1C019AC25480 +:10D3D0000B33029AC250039B614F0022012B0ED0E7 +:10D3E0000B1DC25001239B029D4216D9AA05920D26 +:10D3F00008D008E00C46E1E7FF2005B0F0BD0B1DAA +:10D40000C550EFE71A4653039B190E461B02083618 +:10D410001B0AAA1A8351920A09E0002D00D10125A6 +:10D420006B039B191D022D0A0B460833C550891C3E +:10D4300042543D463E782046FFF7AAFE2878B04287 +:10D4400015D001F00CFD014628786A68000108300B +:10D45000105800F07BF8012807D928786968000186 +:10D460000830085801F0EEFC01E0FFF7E0FE0198FB +:10D47000C3E770B50C46054601F0F1FC06462146AF +:10D480002846FFF7BEFEFF2817D0354D0401204681 +:10D49000696808300858314600F058F8012109033E +:10D4A00040186968A41C095D400B002901D089025D +:10D4B0000818002800D1012070BD002070BDF3B510 +:10D4C00081B00F460198FFF79CFEFF282AD0244D1B +:10D4D0002E7869683246344604E0844205D02646F8 +:10D4E0002301CC5CFF2CF8D11CE0FF2C1AD0A64203 +:10D4F0001FD11001085C2870FF2818D001F0AFFC84 +:10D500002A780146120168680832805800F01EF837 +:10D51000012809D92878696800010830085801F005 +:10D5200091FC06E00020FEBDFFF781FE01E001F066 +:10D5300091FC39460198FFF79CFF22016968FF239F +:10D54000541C0B558A5C3301CA54FEBD401A0002BC +:10D550000121000AC905884200D900207047000057 +:10D56000CC0C00207372635C736F635F74696D65CC +:10D57000722E6300F0B500241C4A01211C4B0803E5 +:10D58000546018601B4B1C601B4C20601B480469D6 +:10D59000E443E406E617046910252C430461184CA3 +:10D5A0006160184D2960761C00E020BF1F68002FC5 +:10D5B000FBD0002E03D107691026B743076190689E +:10D5C0008005906801D5104A10436960A160002170 +:10D5D00019600121084A09031160F0BD10B5044625 +:10D5E000FFF7C8FF2060002010BD000000C500400C +:10D5F00080E100E000C1004080E200E000ED00E0DA +:10D6000000C3004000C0004000FCFFFF70B51F4990 +:10D610000A68002A17D000231D4601244A68521CBC +:10D620004A60092A00D34D600E792246B2400E6846 +:10D6300016420AD072B60B6893430B6062B6496813 +:10D640000160002070BD052070BD5B1C092BE5D377 +:10D650000FA1362008F0E7FEF5E70120104980050C +:10D6600008607047EFF31081CA07D20F72B601212C +:10D6700081400648036819430160002A00D162B660 +:10D68000EBE7024800210160416070478400002000 +:10D690007372635C736F635F6576742E6300000062 +:10D6A00000E200E001208107086070470120810747 +:10D6B000486070471048C068C00700D0012070471C +:10D6C0000D488068C00700D0012070470A484069B3 +:10D6D000C00700D0012070470748C069704706495D +:10D6E0008A69D20306D589698907890F814201D1E8 +:10D6F000012070470020704700040040F8B5F84C46 +:10D70000207BE17A88421CD00126F64D0027E07A82 +:10D71000215C14200A4642435019037C052B11D08A +:10D72000037C062B1CD0037C072B28D0437C012BC9 +:10D7300033D0EDA1EF4808F076FE207BE17A8842F5 +:10D74000E5D1F8BD0674E07A0A2807D0E07A401CDB +:10D75000E072491CC8B2AA5802210CE00020F7E789 +:10D760000674E07A0A2808D0E07A401CE072491C6E +:10D77000C8B2AA5803219047DFE70020F6E70674F5 +:10D78000E07A0A2807D0E07A401CE072491CC8B24F +:10D79000AA580821EFE70020F7E74774E07A0A2843 +:10D7A00007D0E07A401CE072491CC8B2AA58072191 +:10D7B000E1E70020F7E770B50024CF4E0620707235 +:10D7C000CE4825464477047738300473C472CC4879 +:10D7D00007F035FCCB480575F572CB49601E8860B3 +:10D7E0007571B570F57035717570C848643905701C +:10D7F00045701420604340180574641CE4B2052C85 +:10D80000F7D30120F5F764F80020F5F761F801205F +:10D81000B071F4F727FDBE48F4F736FDBD4C20701B +:10D82000BD48F4F731FD6070F4F7F2FF70BD10B53C +:10D83000F5F719F8B74C2078F4F744FD6078F4F761 +:10D8400041FDAD4C207A002803D0F4F7CAFD00203A +:10D85000207210BD70B5A84CA079002804D0A2A1F8 +:10D86000AE4808F0E0FD70BDE07A002803D19EA12B +:10D87000AB4808F0D8FD0126A6710025E572607A54 +:10D88000042114225043974A801801749E488168ED +:10D89000491C04D0691E81600120F5F719F80020A9 +:10D8A000F5F716F8F4F7FAFF07F00AFDF5F7FBF8BD +:10D8B0009C480560056001209B49C0030860F5F79E +:10D8C00071F992480078022804D0032804D1E07846 +:10D8D000002801D0A67000E0A570F5F7D0F870BD63 +:10D8E000034680490520142242435218203A127FF1 +:10D8F000002A04D0401E0006000EF4D17047142206 +:10D90000424351180A46803AD366012220390A77E9 +:10D910007047012805D0032805D1002903D1002034 +:10D9200070470029FBD010B4734C00236370774A12 +:10D93000002890700CD002280AD007291AD20800BB +:10D9400078440079001887441505070D0F1113005E +:10D95000D37003E01B2000E03A20D07001206070FB +:10D9600010BC70475820F8E77720F6E79620F4E7D8 +:10D97000B520F2E710BC0020704710B5634840782E +:10D98000F5F798F880B210BD411E1422504310B52F +:10D99000544A8418203C042902D8207F002803D14F +:10D9A00051A1624808F03FFD207F012804D0B32038 +:10D9B0004DA1800008F037FD0020207710BD70B524 +:10D9C0004E4C607F217F884201D1012500E0002577 +:10D9D000F5F709F8F5F76EF8617F227F914201D1E2 +:10D9E000012100E00021A942EBD170BDF7B5074647 +:10D9F000481E84468EB0C0B2142205905043394A66 +:10DA000085180495287C2D1D07282AD1344C002622 +:10DA1000E07A227B824221D0235C059A934201D195 +:10DA2000012601E0002E04D00A2811D0421CA25C7D +:10DA300022540A280ED0401C227BC0B28242EBD175 +:10DA4000002E0BD0207B002806D0207B401E04E057 +:10DA50000022ECE70020EFE70A202073049A01205F +:10DA600010746046244C042813D8142041431D48E8 +:10DA700008182038007F00280BD00498007C01286B +:10DA80000BD00498007C012803D01098807A0128DC +:10DA900007D015A1264808F0C6FC1098807A012806 +:10DAA0006FD104980F4B007C022845D00C4C207B92 +:10DAB0000A2872D0207BE17A401C884203D10AA157 +:10DAC0001C4808F0B0FC049901204874217B05989B +:10DAD0006054207B0A2864D0207B401C20731CE10A +:10DAE000D80D0020E80D00207372635C72656D2E06 +:10DAF00063000000CF0500006C0E0020A00D002088 +:10DB0000780E0020C00D00204C0E00208E0000205A +:10DB10002FD200008C000020FDD600007D02000006 +:10DB20005E02000000F5004080E200E0CB02000051 +:10DB30001503000022030000607A059A0146904216 +:10DB400006D0014614267043C018807C9042F8D15C +:10DB5000627A824208D1617A14225143C918897CC1 +:10DB600061720121A17207E014224243D2181426E7 +:10DB70007143927CC9188A74142206215043C0183C +:10DB800081741098007A062819D201007944097925 +:10DB900049188F440812100E0C0AE07A00288ED023 +:10DBA00091E700209AE700200FE0B4200DE07320F9 +:10DBB0000BE0322009E00A2007E0062005E0FF2004 +:10DBC000FDA1E03008F02FFC0020029010980168C1 +:10DBD0000298081A28601099097A002912D00221A7 +:10DBE000401A0102090A296010980268406810185A +:10DBF0000002000A68601098807A0228109803D00A +:10DC0000007B74E00421EBE7007A002813D00222A5 +:10DC1000029810188446109842686046083016181A +:10DC2000E848029A4078904202D9E278002A04D06B +:10DC30003046083005E00422EAE7029A801A80198B +:10DC40000830627A062A1CD0627A14235A43DE4BCB +:10DC5000D2185268914214D0DC4B0793617A142297 +:10DC60005143D94A89184A688968D21BC91B1202D4 +:10DC70000902120A090A90423AD89A4238D89942BF +:10DC800036D83818801B0002000A286010996044BA +:10DC9000CF4AC9680002000A9446421A01239B0534 +:10DCA00007929A4201D2104614E00A1A09929A4247 +:10DCB00001D207980EE0079A6346624503D9591AC4 +:10DCC0000818401C06E0099A624506D9181A40183F +:10DCD000401C4042002860DC03E0B7A1BD4808F0CA +:10DCE000A2FB286880190002000A686000202872E0 +:10DCF0006868082608300002000A68601098407AB8 +:10DD0000A8721098007A687203280ED200280CD0EE +:10DD1000FFF7D0FC002803D007E0002011B0F0BDD1 +:10DD200002983A210E1A32200290A6480178012961 +:10DD300001D0032909D141780298814205D9E078C0 +:10DD4000002802D10298081A861928689F4AC01B29 +:10DD5000844601026868090AC01B03021B0A029379 +:10DD60008E421AD81346914217D80299994214D874 +:10DD7000617A062915D0667A6146062203920092DE +:10DD80001422914B7243D2189368DB1B8B4216D836 +:10DD90000396967C062EF3D177E0059801F055F9AD +:10DDA000BBE70499022205980A74627A062A00D019 +:10DDB000627A8A7460720120A07211B0F0BD062EE2 +:10DDC00063D000223146944614227F4B4A43D21836 +:10DDD0005368DB1B834229D2917BAB7A99421FD8CF +:10DDE00004980521059C01747B4D287B0A2811D0DD +:10DDF000287BE97A401C884203D16FA1774808F05C +:10DE000012FB287B2C54287B0A2807D0287B401C37 +:10DE1000287382E7E87A0028EFD0F2E70020F7E7DE +:10DE200001218C46917C0629CED102E06046002873 +:10DE30002AD03546009114202A46424362480621E2 +:10DE4000171839741038007B0A28634816D0017BF4 +:10DE5000C07A491C814203D157A1614808F0E3FA16 +:10DE60005D48017B4554017B0A290BD0017B491C8D +:10DE70000173BD7C0098A842DDD106E0C07A00287D +:10DE8000EAD0EDE70021F3E70096049902204E4D19 +:10DE90000874607AB04207D1049900988874059894 +:10DEA00060720120A07221E00398062E0FD0062890 +:10DEB00003D141A14B4808F0B6FA0398142250430D +:10DEC0004019059981740499009888740EE0062819 +:10DED00003D139A1444808F0A6FA0398142250430C +:10DEE000401905998174049906208874012011B0A5 +:10DEF000F0BD70B50D463D4A441900210B46101A7D +:10DF00008B4103D22CA13A4808F08DFA394885425A +:10DF100003DD29A1384808F086FA3848854203DA3B +:10DF200025A1374808F07FFA3648844205DA002CEC +:10DF300001DB204670BD334800E03348201870BD37 +:10DF4000401E70B5C0B2142148431F494418607B7D +:10DF5000062813D201007944097949188F44020C2C +:10DF60000A080604002068E0B42010E073200EE0E8 +:10DF700032200CE00A200AE0062008E0FF200EA173 +:10DF8000E03008F050FA617B0020002955D00221D2 +:10DF90004018616840180002000AF4F78BFD0C2558 +:10DFA0006557124A441900210B46101A8B412FD293 +:10DFB00001A10F482AE000007372635C72656D2E48 +:10DFC000630000008E000020E80D0020FFFF3F00EE +:10DFD000FFFFFF000E070000D80D00200702000021 +:10DFE000C5030000DD030000E3030000FF7F841E83 +:10DFF000F50300000020A107F603000000E05EF832 +:10E00000F70300000080841E00807BE108F00BFA1B +:10E01000FB48854203DDFB49FB4808F004FAFB4856 +:10E02000854203DAF749FA4808F0FDF9F9488442D5 +:10E0300007DA002C03DB204670BD0421A8E7F54871 +:10E0400000E0F548201870BDF0B5064683B0F348EF +:10E050000190457A029534687068001B0702F04809 +:10E060003F0A001B0090062D2DD014202946414365 +:10E07000EC480122081884464168E9489205864622 +:10E08000081B904210D3631A93420DD30246704688 +:10E09000724503D900984018401C05E073450ED91D +:10E0A000411A0819401C404200280CDA60460295CB +:10E0B000857C0198C0790028D5D003B0F0BDD14946 +:10E0C000D94808F0B0F90298854226D01421484377 +:10E0D000D4490123401802908068D1499B058C46A1 +:10E0E000011B8646994210D3221A9A420DD36346E9 +:10E0F000614503D900997144491C06E019466245FF +:10E100002DD9091A0819401C4142002905DD029841 +:10E11000B17A807B814200D37446062D15D0C14967 +:10E120001420454368184268121B1202120ABA42B0 +:10E130000BD2B37A827B934200D38468857C0198AA +:10E14000C0790028B9D1062DEAD13068A042B4D0F8 +:10E15000E0190002000A3460706003B0F0BDA94904 +:10E16000B14808F060F9D8E7F0B5B049044648680E +:10E1700085B0C005C00D1CD0103840B200280CDAA4 +:10E180000207120F083A920892005118C9698007D5 +:10E19000C00EC1400806800F09E08108A44A89002A +:10E1A000891809688007C00EC1400806800F002842 +:10E1B00008D000272078002806D0012804D00020AD +:10E1C00005B0F0BD0127F5E72079062813D201003C +:10E1D0007944097949188F44020C0A080604002082 +:10E1E00018E0B42010E073200EE032200CE00A208A +:10E1F0000AE0062008E0FF208249E03008F013F929 +:10E2000021790020002905D002214618834D002FD6 +:10E2100002D003E00421F8E70020E871694602AA71 +:10E22000A068F4F751FC694608228A56E06801A903 +:10E2300080180122C01C1F2801DA019209E003AAFC +:10E24000F4F742FC6846007B002802D00198401C8D +:10E25000019000990198401808300002000A0190CE +:10E26000881B0002000A0090607969468872009855 +:10E270000390F4F7B8FB009A019B121A181A6D4923 +:10E2800012020002120A000A8A4216D8884214D8E2 +:10E290006846FFF7D9FE00990398814205D0881996 +:10E2A0000002000AF4F706FCA0600120E9790029C9 +:10E2B00086D0002FB0D005B0F0BD0020F6E7F3B552 +:10E2C0008FB05D480C460B9006F0C1FE5B4A0F997B +:10E2D000524F56185A4D203E00280BD05948007D09 +:10E2E000002803D058A15B4808F09DF82078012849 +:10E2F0007ED060E1687F0A280CD0687F297F401CAF +:10E30000884203D150A1544808F08DF820780128A4 +:10E3100004D00CE0287F0028F4D0F7E7F07F002835 +:10E3200003D049A14D4808F07EF80120F077697FBD +:10E330000F9814224A4E51438919087420780228F4 +:10E3400022D0687F14214843861920793072607981 +:10E35000707232460C323146A068F4F7B5FB0C20DF +:10E3600030560F2804DD1F3830733068401C306091 +:10E370000C217156301DE26801905018C01C1F28F6 +:10E3800070DA01200199FDE028494868C005C00DF8 +:10E3900021D0103840B200280CDA0207120F083AD8 +:10E3A000920892005118C9698007C00EC140080642 +:10E3B000800F09E081081E4A8900891809688007D2 +:10E3C000C00EC1400806800F002804D105201EA100 +:10E3D000000208F028F8687F1421484386190021BC +:10E3E000E0686A460691117006A9F4F76DFB00E03B +:10E3F000D7E06A46002010560F2834DD012033E0B4 +:10E400000020A107B8DF0000F603000000E05EF87E +:10E41000F70300000080841E00807BE16C0E00206A +:10E42000FFFFFF00E80D00200E07000000ED00E0F8 +:10E4300000E400E0FFFF3F00780E00209200002083 +:10E44000A00D0020C00D00207372635C72656D2EFC +:10E450006300000011050000EF040000F404000058 +:10E46000E00C002082E0002006994018079002206E +:10E47000B0722079307260797072A068311DC01C52 +:10E4800006911F2801DA012009E0F4F71DFB684618 +:10E490000078002804D0069806990068401C08609F +:10E4A000307A062813D201007944097949188F443B +:10E4B000020C0A08060400200FE0B4200DE07320CF +:10E4C0000BE0322009E00A2007E0062005E0FF20EB +:10E4D000FD49E03007F0A7FF00202179002943D053 +:10E4E00002214018069071680830081807990890B2 +:10E4F00009180698081A0C900020F871F4F773FABE +:10E5000004463060079820180002000AF060787A0C +:10E51000062825D0797A14204143EC480818406831 +:10E520000899029040180002000A0390707A694628 +:10E53000887402A8FFF788FD0299039A091B121B31 +:10E5400009021202E24B090A120A0C98994207D8F2 +:10E55000824205D80299069808180002000A306025 +:10E56000F8790028C8D110E00421BAE704AA01997B +:10E57000F4F7AAFA6846007C002804D001980199B3 +:10E580000068401C08602078B072687F0A2806D0B6 +:10E59000687F401C68770B9806F071FD47E000200B +:10E5A000F8E7F07F002804D0A320CAA1C00007F03C +:10E5B0003AFF0120F077CA490F98087420780228A2 +:10E5C00003D1C4A1C74807F02EFFC54E2079307291 +:10E5D0006079707232460C323146A068F4F774FAF2 +:10E5E0000C2030560F2804DD1F3830733068401C73 +:10E5F00030600C22B256301DE16801908818C01CB2 +:10E600001F2802DA012001990BE003AA0199F4F70F +:10E610005BFA6846007B002804D0019801990068E5 +:10E62000401C08602078B072AD4901200875687FF1 +:10E63000297F884224D07C7A062C23D0F4F7D3F9A2 +:10E6400014214C43A14961180A7C042A18D00A7C81 +:10E65000032A15D04B6889681B1A081A1B0200028E +:10E660009B4A1B0A000A082B0AD31146934207D87B +:10E67000884205D8687F297F884201D0F4F7FFF9E6 +:10E6800011B0F0BD687F297F8842F7D111B0F0BD8D +:10E6900010B50020F4F709F910BD10B50120F4F70A +:10E6A00004F910BDF1B5009802281ED08E4C607A96 +:10E6B000062803D187A18D4807F0B5FE0026A67174 +:10E6C0000125E572607A03211422804F5043C0195E +:10E6D0000174F4F7D9F9009800280BD0012829D04B +:10E6E000032879D07BA1824844E082480078F3F780 +:10E6F000EFFDF8BD8048007F002803D075A17F485A +:10E7000007F091FE65717C4D00202E60F4F7E0F873 +:10E71000A968481C04D0012300221846F4F70EF91A +:10E72000607A617A401CC0B2142251437A580121A8 +:10E730009047F8BD0120F4F7CBF8607900280DD0A0 +:10E740006D488068401C09D0607A617A401CC0B274 +:10E75000142251437A5806219047F8BD6648007F3D +:10E7600001280AD0022812D0032822D0042834D04D +:10E7700058A1634807F057FEF8BD2079002803D060 +:10E780002671F4F786F9E5705B480677F8BD207AC4 +:10E79000002802D1F3F7FCFD2572607A617A401CF3 +:10E7A000C0B2142251437A5800219047524806774C +:10E7B000F8BD514F0123397B78680022411A184671 +:10E7C000F4F7BCF82079002803D02671F4F761F93A +:10E7D000E57002203877F8BD19E0474E217870685F +:10E7E0000123411A00221846F4F7A8F8207A0028DD +:10E7F00002D1F3F7CDFD2572607A617A401CC0B278 +:10E80000142251437A58002190473577F8BD607A39 +:10E81000617A401CC0B2142251437A5805219047B6 +:10E82000F8BD10B5304C607A062803D129A13548CF +:10E8300007F0F9FD607A617A401CC0B2142251439E +:10E84000224A52580421904710BDF0B583B00620EB +:10E850000290F4F7C8F8244C0090617A2A4801909D +:10E86000062920D0617A1420414318480918097CF0 +:10E87000042918D0617A142251430818007C032817 +:10E880007BD0019900980B6849681B1A081A1B0273 +:10E8900000020F4A1B0A000A082B6ED3114693424E +:10E8A0006BD8884269D814488068401C03D009A1FD +:10E8B000164807F0B8FD00206071607A06282CD158 +:10E8C0006078002829D023E0B8DF0000E80D0020A0 +:10E8D000FFFF3F007372635C72656D2E6300000082 +:10E8E000C00D00201E0500006C0E00204F0500002A +:10E8F000A20500008C0000204C0E00205B050000EB +:10E9000096050000A90500005C0E0020E50500004A +:10E91000FE48C178417081780170607A062815D070 +:10E92000607A1421FA4A48438018007C04280DD1EB +:10E93000607A0290607A0121142358438018017490 +:10E94000607A58438018807C6072A172F14D687FB4 +:10E95000297FF14F884233D0F04E287F142148435D +:10E960008019007CC05D0128287F07D048438019AA +:10E97000007CC05D02282FD044E0FDE11421484313 +:10E980008019807A01280AD0287F0221142250435E +:10E990008019007CC155287F0A2808D009E0287F0B +:10E9A0000021142250438019007CC1552AE0002028 +:10E9B00001E0287F401C2877687F297F8842CCD1DE +:10E9C000D74D287D00284CD0287CC15D012928D056 +:10E9D000C05D022830D03AE0287F142148438019D6 +:10E9E000807A012803D0CFA1D14807F01CFD297FF0 +:10E9F00000201422514389198872297F51438919B3 +:10EA0000097CC855287F142148438219287F484330 +:10EA10008019017C0098FEF7E9FF287F0A28C8D1F9 +:10EA2000C5E7A97A012904D00221C1550020287523 +:10EA30000DE00021C1550AE0A87A012803D0B9A150 +:10EA4000BC4807F0F0FC0020A872297CC855287D3E +:10EA5000002806D0297CB24A0098FEF7C7FF0020A4 +:10EA60002875029806281ED014214843A84940184A +:10EA7000017C012917D107210174AF4D287B0A2899 +:10EA80003CD0287BE97A401C884203D1A5A1AB4841 +:10EA900007F0C9FC297B02986854287B0A2831D0EA +:10EAA000287B401C2873607A06287DD0A07A002835 +:10EAB0007BD00020A072617A1420414394480E1844 +:10EAC0009F49B56873680A46F6687C32CB679660E2 +:10EAD00055609C4D697E002916D00226617A142269 +:10EAE0008B4851430818407B06281BD2010079440B +:10EAF000097949188F440A1412100E0CE87A00287C +:10EB0000C4D0C7E70020CDE70426E7E700210FE0E7 +:10EB1000B4210DE073210BE0322109E00A2107E066 +:10EB2000062105E0FF208849E03007F07CFC002149 +:10EB30002973687E022801D0012810D12869009A23 +:10EB40004018821A1202120A3A2A08D932380321CE +:10EB500000026976000A28613220287308E0322911 +:10EB600006D2207A00280AD1F3F712FC012005E032 +:10EB7000207A002803D0F3F734FC00202072634988 +:10EB80000822487820700978012901D0032906D18C +:10EB900001212171297B884201D9421A0832A378C8 +:10EBA000002B00D0921C01E08DE09BE02179002930 +:10EBB00001D1002B5DD09446644A00990092019ADD +:10EBC000176852687F1A511A3F0209023F0A090A60 +:10EBD000BC451BD85D4A974218D8009A914215D877 +:10EBE000297B884223D92B69421A9A1A1202120AE7 +:10EBF000101880190002000A2A616860002914D0E8 +:10EC0000032028770006000E3ED14CE00020207142 +:10EC1000A070297B002925D028694018801900029E +:10EC2000000A6860022028772EE00120E9E781428F +:10EC30000BD92A69511889190902090A6960002843 +:10EC400001D00420DDE70220DBE7002B03D135A152 +:10EC50003F4807F0E8FB286980190002000A686055 +:10EC6000002004E0296989190902090A69602877E6 +:10EC700019E0287B00280FD02969081880190002A4 +:10EC8000000A686002202877286901238119002280 +:10EC90001846F3F753FE09E0286980190002000ABC +:10ECA0006860002028770120F3F712FE607A1421B3 +:10ECB000484317490C2240188256012300206968F6 +:10ECC000F3F73CFE0EE00120F3F702FE0020F3F71D +:10ECD000FFFDF3F7E3FD207A002803D0F3F781FB73 +:10ECE00000202072A078002804D0F3F7D2FE002084 +:10ECF000E070A0706078002804D00448C1784170AA +:10ED000081780170207900282BD023E08E0000202C +:10ED1000E80D0020A00D002091000020E00C002054 +:10ED2000C00D00207372635C72656D2E630000007D +:10ED30000706000023060000D80D0020350600005D +:10ED4000E00D00204C0E0020B8DF0000FFFF3F0068 +:10ED5000870600000020CF49E0700978002900D123 +:10ED60002071CD48017BC07A814203D0CB484078E6 +:10ED7000F3F7AEFA0120E07103B0F0BDF0B5C84C76 +:10ED80000746607A83B0062803D1C6A1C84807F0B9 +:10ED90004AFB607A1421C74E48438019007C03283F +:10EDA00003D0C0A1C44807F03EFBC44DA868401C76 +:10EDB00003D0BCA1C24807F036FB607A1421484357 +:10EDC00081190C20085600216A4600911171C01962 +:10EDD00001AA6946F3F778FE6A46042010560F2808 +:10EDE00001DD012000E0002000994018696840180A +:10EDF0000102090AA9606079002804D001230022D9 +:10EE00001846F3F79BFD03B0F0BD70B5AE4CAD4AAC +:10EE10000B1AA34214D3451AA54211D3934203D926 +:10EE2000101A43185B1C0BE0954204D9511A0818BC +:10EE3000401C434204E0A549A54807F0F4FA00232A +:10EE4000184670BD10B50146012300220220F3F7D9 +:10EE500075FD10BD10B50220F3F73AFD10BD10B5D9 +:10EE6000F3F7C1FD10BDF0B58D4D0446E87A83B0CF +:10EE7000002803D18BA1974807F0D5FA642C4DD315 +:10EE8000954900200246091B824147D39348417FA0 +:10EE9000007F814242D19248007D00283ED1687AAD +:10EEA0001421844F4843854EC519306801AA0019C2 +:10EEB0006946F3F709FE694604200856002802DD7A +:10EEC0000098401C0090A96800986B680A18D21A34 +:10EED0001202844B120A9A4220D8AA7C062A08D031 +:10EEE00014235A43D2195268511A0902090A81425D +:10EEF00014D3B068401C05D00120F3F7E9FC0020D2 +:10EF0000C043B060306800193060A86800994018AC +:10EF10000002000A7061012003B0F0BD002003B0C0 +:10EF2000F0BDF8B50646401EC5B2142061496843DD +:10EF30004418207C002803D15AA16B4807F073FACB +:10EF40006648017F407F81420CD0684A14234B43BE +:10EF50009B181B7CB3420CD00A290CD0491CC9B2A7 +:10EF60008142F3D15E48017D002964D0007CB0422B +:10EF700061D10020F8BD0021F1E7217C052905D0F1 +:10EF8000217C062902D0217C072928D10121217466 +:10EF9000C17A0023027B8A4221D00246565CAE42EF +:10EFA00001D1012301E0002B04D00A2911D04E1C0D +:10EFB000965D56540A290ED0491C167BC9B28E4262 +:10EFC000ECD1002B0BD0117B002906D0117B491E00 +:10EFD00004E00026ECE70021EFE70A211173617CD1 +:10EFE00000292AD06774C17A0023027B8A4224D088 +:10EFF000425CAA4201D1012301E0002B04D00A297E +:10F0000012D04A1C825C42540A290FD0491C027B50 +:10F01000C9B28A42ECD1002B0FD0027B0146002AF4 +:10F0200006D00A7B521E04E00022EBE70021EEE747 +:10F030000A220A7301E018480027217C01299CD18B +:10F04000617C002999D10120F8BD70B505461420D6 +:10F05000184A05216843801801740F4C207B0A2848 +:10F0600011D0207BE17A401C884203D11749204807 +:10F0700007F0D9F9207B2554207B0A2807D0207B74 +:10F08000401C207370BDE07A0028EFD0F2E700202A +:10F09000F7E700008E000020D80D00208C00002033 +:10F0A0006C0E00207372635C72656D2E630000004D +:10F0B000EA060000E80D0020EB0600004C0E0020E0 +:10F0C000EC060000FF7F841E0020A107B8DF0000CF +:10F0D0000E0700002D070000FF1FA107A00D002054 +:10F0E000C00D0020FFFF3F006A070000E00C002079 +:10F0F0000702000070B5FF4D00246C702C70AC61ED +:10F1000000F0CEFC284620304470C473AC6214304A +:10F110002C6305F094FF002804D0FF20F6A14E30A8 +:10F1200007F081F92C7770BD0B23DB4310B5C21AB1 +:10F13000F54998421FD008DC1C3222D00A2A20D080 +:10F14000142A1CD0182A08D117E0083011D004283E +:10F150000DD0082809D00C2805D0FF20E6A1753075 +:10F1600007F061F910BD04200CE000200AE0FC204B +:10F1700008E0F82006E0F42004E0F02002E0EC20B3 +:10F1800000E0D820C86010BD70B50125DF49022617 +:10F190000E60DF490022CA63CD63DE49C96A0907F0 +:10F1A0000ED4DC494031CB6ADB4A53620B6B93626D +:10F1B0004B6BD3628B6B1363C96BD30519435163DC +:10F1C000D14C002826D0012828D0FF20CAA1A13088 +:10F1D00007F029F9D148A063FF200430606325635C +:10F1E00003202061C849962040314860C1491C2055 +:10F1F0000856FFF799FFCB49C9488860C948CA49F2 +:10F2000080304160C9490160C9480660C949102081 +:10F21000486070BDC8486061C84803E0C848606184 +:10F22000C648801FA061D5E770B50C46B14D0146B8 +:10F230000622A81C06F079FF2C7270BDAD48203064 +:10F2400040787047AB4A517010707047F8B504466B +:10F250000D465079117900020843690009190884A4 +:10F260001F461646501C06F0C1FF317800020843C5 +:10F27000A90060502846083001268640002F0ED095 +:10F28000012F04D0FF209CA1E83007F0CCF8206BC0 +:10F29000304301460120A84001432163F8BD206BA3 +:10F2A000B043F6E770B50D460446082904D9FF209F +:10F2B00091A1F93007F0B7F80022A24809E09100C7 +:10F2C000635809180B6053001B191B8C0B62521CEE +:10F2D000D2B2AA42F3D3206B9A494031086070BD84 +:10F2E00010B50446FFF720FF8248047710BD81481F +:10F2F0002030007B704710B5834CC178616206F006 +:10F3000075FF0002E06110BD252808D0262808D02E +:10F31000272808D041000A2807D8091D06E0022145 +:10F3200005E01A2103E0502101E0891DC9B2764AA7 +:10F33000916075494031486170476E4988617047F6 +:10F3400070B5002818D002226A4C784B0320A272B4 +:10F35000F0331860734D72486860002001262075F4 +:10F3600000290BD0012910D002291BD0952062A1C1 +:10F37000800007F058F870BD0122E5E77248012AC5 +:10F3800001D0466070BD066070BD5A48012A006B0E +:10F3900005D00121490508432063696070BD012142 +:10F3A0000905F8E7A069002803D153A1674807F0D1 +:10F3B0003AF8A169A06A40186549886059486549CA +:10F3C0008030816060491031C1600120216BC00331 +:10F3D00001432163686047482030C67370BD08B59B +:10F3E0000C20694608705148002110380161564AC6 +:10F3F000012111610BE000BF00BF00BF00BF00BFD3 +:10F4000000BF00BF00BF6A461178491E11706946EF +:10F410000978002902D001690029ECD068460078FB +:10F42000002804D1494834A1203006F0FCFF08BD73 +:10F43000F8B53E4CF034206886083E48B600416876 +:10F44000C906CD0F10218160002727603549344857 +:10F450008860FFF7C4FF35481038076100F020FBD3 +:10F460002660002D02D0334910204860F8BD10B549 +:10F4700006F0BCFE00022449000AC86310BD2349FF +:10F48000022008602A49086070472049022080391C +:10F4900008607047304908707047164810B534301E +:10F4A00005F0D5FD002804D0284813A15A3006F0F5 +:10F4B000BAFF10BD0F4810B5343005F0E0FD10BDA7 +:10F4C00011494860704770B50A4D0446A86AA042C9 +:10F4D00004D31E4808A16B3006F0A5FF0120287355 +:10F4E0001C49002008392C6148601948446000F02C +:10F4F000DEFA70BD7C0E00207372635C68616C5F25 +:10F500007263732E630000000015004080E100E08C +:10F51000C01F004080000010001700405B06000084 +:10F520000040000400F50140408000401011004000 +:10F5300080E200E000130040060102002500030203 +:10F5400005010300001600400010004047020000C3 +:10F5500040850040488100409700002010B5FF48DA +:10F5600002210173C6210161FD4A00215160806AB8 +:10F57000FC49C630486000F09AFA10BD0121FA48F3 +:10F5800089058160F548026B8A430021026301739B +:10F590007047F64801214160C160F1490020486090 +:10F5A000F0494860ED4988627047F149402008629F +:10F5B000F0490A6802430A607047EE480168402239 +:10F5C00091430160EA49002008627047E9480168F8 +:10F5D000102291430160E849012088617047E749A2 +:10F5E0000020C861E34801681022114301607047A0 +:10F5F000E249CA69012A01D000207047DC4A9268BA +:10F600005206520E524202700020C861012070471B +:10F6100070B5D248D24D017B002902D0696801291A +:10F6200009D00024D5490A69012A06D00023807A2E +:10F63000012804D006E00124F4E74023F7E7CA6874 +:10F64000012A04D000221A43012802D004E020221B +:10F65000F9E74B68012B05D000231343C84A022861 +:10F6600002D007E01023F8E71668012E02D1CE6819 +:10F67000012E04D000261E43022802D007E00826EF +:10F68000F9E71268002A02D1CA68012A04D00022D0 +:10F690003243022802D005E00422F9E7002C01D011 +:10F6A000022300E000231343022807D14868012801 +:10F6B00004D16868012801D0012600E00026B14885 +:10F6C0001E4302681206120E02D04A69012A00D0B7 +:10F6D0000022A24C2034227300680006000E02D0E3 +:10F6E0008869012800D000206073A148006A0028C2 +:10F6F00003D000F0A8FA012800D00020A07300F089 +:10F70000C7F9002068603046F3E670B50C00054686 +:10F7100003D19D499D4806F086FEE00706D0012CE6 +:10F7200004D06D209849C00006F07DFE002D0ED05B +:10F7300002218A4801294172C4728E4809D00229E7 +:10F740000AD0924890491A3006F06DFED1E60121A8 +:10F75000EFE70168042201E001680822114301601B +:10F76000C7E670B57D4C0022E37A990701D54107C1 +:10F7700014D47A49DD062031002D05DA4D7B002DA9 +:10F7800002D08D7B002D09D01D0702D50D78002DEC +:10F7900004D15B0703D54978002900D10122637A9F +:10F7A0007449002B06D00225284010430CD0FFF7E7 +:10F7B0003FFE9EE66C4A76489060086880088000AC +:10F7C000086000F06DF994E6012B07D0022B0ED0F3 +:10F7D0006E486D496B3006F026FE8AE60868042202 +:10F7E0009043086000F05CF90120A07281E608688F +:10F7F00008229043086000F053F9A57279E6574952 +:10F8000008757047F8B5554F544D2037FA7B564C64 +:10F810000021286B002A31D00122D203A26090433C +:10F820002A46544D10632E685A4A102090600020DA +:10F8300028601014A060FFF7D2FD00F029F92E60B7 +:10F84000281460605349102048604448817A4A482F +:10F8500001290DD002290ED04C484FA1801F06F07F +:10F86000E2FD0020F8733D48007D022874D0F8BD09 +:10F8700001210160F5E701214160F2E73A4A906019 +:10F880000E462963FFF7C4FE044636482E754168CC +:10F8900069620068A862AA7A022A0AD16A78002AF4 +:10F8A00007D0334B403B5B681B7813402A789A4360 +:10F8B00008D03E70E20708D0084603F04AFD012157 +:10F8C000A86A09E001223A70F4E7A10601D50221F5 +:10F8D00002E0A10702D5002103F04BFD2448403887 +:10F8E00041680622A81C093106F0F2FB002809D164 +:10F8F0001F48297A403840680078C009814201D108 +:10F90000012000E0002078702046FFF72AFF2648FB +:10F91000007800280DD001284AD002285BD00328A7 +:10F9200078D01DA1214806F07EFDA87A022870D06B +:10F93000A3E0A00701D502F0EDFB200702D50120CE +:10F9400002F020FC600702D5002002F01BFCA0069C +:10F95000EBD502F07CFBE8E793E000007C0E002092 +:10F96000408100404085004000F50140008000409B +:10F9700040150040001200400010004000110040FF +:10F980000014004040160040F8F40000630300003B +:10F9900000400004001300407372635C68616C5F98 +:10F9A0007263732E6300000097000020E6040000DD +:10F9B000A00701D504F0BBFF200702D5012004F009 +:10F9C00021FF600702D5002004F01CFFA006ACD583 +:10F9D00004F0A4FEA9E7A007BF27002802DA3C40F4 +:10F9E000F3F702FB200703D53C400120F3F7FBFAB5 +:10F9F000600703D53C400020F3F7F5FAA00602D5D6 +:10FA00003C40F3F7EFFA60068FD5F3F7EEFA8CE798 +:10FA100000E012E0A00701D5F3F7EAFA200702D5CB +:10FA20000120F3F7E4FA600702D50020F3F7DFFACC +:10FA3000A00690D5F3F7DAFA77E7287B00281CD0E8 +:10FA40001F494E6002281FD0012803D01D491E48BF +:10FA500006F0E9FCA96A2869884204D81A481949BD +:10FA6000401C06F0E0FC2969184841600120296B20 +:10FA700080050143296316494860287D012800D08C +:10FA8000F5E6F3F7C5FAF8BD2969A86A4118EBE76E +:10FA900010480021C160016141604161816170478E +:10FAA0000D480021417281720121C17270470A48DC +:10FAB0000121026B89050A430263054841607047D2 +:10FAC0004081004098F90000FB04000040850040A0 +:10FAD00000F50140001100407C0E00202E4800215E +:10FAE00001704170704770B5064614460D460120FE +:10FAF000F1F758FC28490120284B08709E60DC6013 +:10FB00001D6170BDF8B504460120F1F74BFC224998 +:10FB10000120087021494C60214900264E600321D4 +:10FB2000204D0906A960204F002C0AD0012C03D0DB +:10FB30001EA1412006F077FC3E60032000066860AD +:10FB4000F8BD386001200006F9E710B512480178C9 +:10FB500000290ED00321134A0906916010494A6812 +:10FB60000021002A03D0154A1268427000E041705B +:10FB700001700020F1F716FC10BD0748017800293C +:10FB800007D007484068002802D00C480068C0B27F +:10FB900070474078704700009800002000F5004052 +:10FBA00000F1004000F5014000F200407372635C18 +:10FBB00068616C5F63636D2E6300000000F40040B9 +:10FBC0003A4800210170417010218170704770B572 +:10FBD000064614460D460220F1F7E4FB01203349A6 +:10FBE000334A0870E41E14619660556070BD10B50C +:10FBF0000220F1F7D7FB2D49012008702D48002184 +:10FC000001604160816001202B49C005486010BD42 +:10FC100010B5264C2078002811D001202649C005B7 +:10FC2000886000F034F80021002804D001206070C2 +:10FC30002248006801E061701020A070217000204F +:10FC4000F1F7B0FB10BD10B51848017800290BD0B2 +:10FC500018480068002805D000F019F8002800D0E6 +:10FC6000012010BD022010BD407810BD10B50F4816 +:10FC70000178002909D000F00AF8002803D00F48C5 +:10FC80000068C0B210BD102010BD807810BD0948BA +:10FC90000168002905D04168002902D08068002849 +:10FCA00001D0002070470120704700009A0000201A +:10FCB00000F5004000F1004000F5014000F4004074 +:10FCC000FFB593B0044600201D9E049015981C9D1E +:10FCD0001027082806D0E06901F014F8002809D0A0 +:10FCE0003770CCE028880921384328801F980227E4 +:10FCF000017016E0E169012088710521E269C902FD +:10FD00009180E1698872E169F9480881E169002020 +:10FD10008873288820210843288011211F980427F0 +:10FD200001701F980225801C0390307810900A20E3 +:10FD30003070204618301190F6F76BFC00206FE011 +:10FD40001598102809D1022D07D06846828A049997 +:10FD50000398401A8270110AC1706846C08A1699C9 +:10FD6000884203D9E349097A149106E0884204D114 +:10FD70001099002901D0317021E003990870000A20 +:10FD800048701E980088401BC01B83B2FF20C01B18 +:10FD9000984200D203460398149AC0190CA9009205 +:10FDA000019002912020015D6846C08A0022F6F78A +:10FDB000A5FC3070002806D0C0B2832862D0684607 +:10FDC000C08A208345E00F98002805D0C948006804 +:10FDD00000790A2830D33CE06846008EC119C9B2C8 +:10FDE0000491022D0FD01F99049A4978914203D1B2 +:10FDF0006A46128C824209D0BE480491006801789C +:10FE0000032909D027E008461F994870B9480068BF +:10FE10000178042906D008E000790A281BD20120C5 +:10FE20000F9009E06946C98A8180039904980818EF +:10FE300003900498281885B205AA14991198F6F72A +:10FE4000EBFB002805D11E980088401BB84200DB60 +:10FE500076E7022D0ED01598102807D1049A039941 +:10FE60006846808A891A8870000AC8701E980580C2 +:10FE7000002030709F4800680078032802D00020DE +:10FE800017B0F0BD0220FBE7F8B50446406B002632 +:10FE9000134600282BD0491F8DB2618F2A460832A5 +:10FEA000278F8A18BA4221D89A7840185F781102B1 +:10FEB00039430170090A41701A79DF781102394318 +:10FEC0008170090AC1700571290A41712A46591DBC +:10FED000801D06F02AF9608FAD1D401980B2608741 +:10FEE000626B002110180170417000E00926304655 +:10FEF000F8BD30B50B88048F9C4212D9446BE018D2 +:10FF00004478057824022C430BD0447905792402E7 +:10FF10002C436404640CA41D1B190B80106000208A +:10FF200030BD822030BDF7B588B000256846058217 +:10FF300005275DE00398417802780E021643417967 +:10FF4000027908021043000452D40A980123068063 +:10FF500005A802905B02002200970195304609999E +:10FF6000F6F7CCFB04004AD16846018A0183039866 +:10FF70004179027909021143437802781C02144343 +:10FF8000B4421ED10A041CD44B0401215B0C89032A +:10FF900000950B4301970295C17880780A020243CD +:10FFA00020460999F6F7C6F9040011D1039948795A +:10FFB0000A79000210430122D20310430871000A9B +:10FFC000487103AA06A90898FFF793FF0400CED052 +:10FFD0000399009501970295487809780002084333 +:10FFE00069468B8A00220999F6F7A4F9822C06D17A +:10FFF00003AA04A90898FFF77CFF04009AD068467A +:020000040001F9 +:10000000058209E003984179027909021143490404 +:10001000490C0171090A417103AA04A90898FFF764 +:1000200068FF0028EED0822C02D020460BB0F0BD35 +:100030000020FBE730B50446406B002597B0002850 +:100040000DD00B2268460270228F0281606B0391F3 +:10005000019000216846F3F7E2FA6846057065638F +:100060006587258717B030BDF8B50F460546696B23 +:100070000020069E144600290FD0012B0DD13246D8 +:1000800039462846FFF74FFF002806D1002C04D040 +:1000900032463946284600F044FEF8BD0022028070 +:1000A000C262831D0263C3614263428702872030BC +:1000B0000170704710B50022D24302800420FDF782 +:1000C000FEF910BD10B596B00446FFF7B3FF208EC1 +:1000D000002808D0012069460870E06A01900021DC +:1000E0006846F3F79CFA0020E062206316B010BD6A +:1000F00001280000B40E00200146098800200A07EC +:1001000000D501200A06120F01D002221043CA05B1 +:1001100001D5042210438A0501D510221043490558 +:1001200001D5202108437047FFB5A9B00600329DD4 +:10013000359C2B981F46229016D0007841060FD48C +:100140008106890E1E2909D021884A05520E0BD13D +:100150003A88172A08D3FE4A914205D0C10906D031 +:100160008006800E122802D003202DB0F0BD20465C +:100170002C302690F7492A980872002018AA03907C +:1001800010726A46107404AA0A60339A4A6020AA60 +:10019000908090812298007801908106681C1C90C4 +:1001A000701F1D902B98890EC21C2492224620326B +:1001B0001B92083A401C02920B0006F025FA1FFD24 +:1001C000FD11FD1FFD8EFDFCFDFBFDFAFDF9FDFCA3 +:1001D000FDF8FDFDFDF7FDF6FDFDFDFDFDF5FD0066 +:1001E000032E76D102E018A9087219E303202870C3 +:1001F0001C9917220A7000224A70CFE2052EF0D116 +:100200004178027808021043208320A98880249A2C +:100210005178127809021143618300287ED0884208 +:100220007CD800202072E080401E60840298F6F79F +:10023000F0F905202870A81C0190022000901BAA4C +:100240002A990298F6F7E8F9002868D118A8807C66 +:10025000012803D002206870102002E0012068709D +:1002600002202490002225A91CA8F2F746FD0028B0 +:100270002BD120A8007D2499814226D13A8800996B +:10028000801C511A814220DB10A8C18D0198017099 +:10029000090A417001991CA8891C01910099019AD1 +:1002A000891C009125A9F2F728FD20A8007D01995D +:1002B0001BAA091801910099081880B200902A9988 +:1002C0000298F6F7A9F90028CCD00098022826D089 +:1002D00064E272E018A9087261E2072E6DD34178DA +:1002E0000346027808021043208320A98880249ABC +:1002F0005178127809021143618300280ED0884298 +:100300000CD8012020725879197900020843E08046 +:1003100000202073E06900F0F5FC01E098E0A9E01E +:1003200000280ED1E169012088710521E269C90226 +:100330009180E1698872E16987480881E16900205C +:100340008873F01F60842298C01D60620298F6F7DF +:1003500060F907202870681C00900120019000209F +:1003600010A9C8852FE00198012814D0E069807990 +:10037000012830D000981E38417F007F09020143D8 +:1003800000980170090A41700098801C0090019843 +:10039000801C80B2019010A8C18D00980170090ADC +:1003A00041700098801C09E00AE296E13BE1DFE041 +:1003B00004E29BE077E036E016E2AFE000900198BF +:1003C000801C80B201901BAA2A990298F6F724F9A2 +:1003D000002803D007E010A8818DD1E73988019863 +:1003E000081A0428BFDA0198012843D0E06980790F +:1003F000012804D010A8818D5548814206D110A84B +:10040000818D00980170090A417009E000981E383A +:10041000417F027F0802009910430870000A48706B +:100420000198801CBAE1072E01D0152E76D14178B3 +:10043000027808021043208320A98880249A5178EA +:100440001278090211436183002801D0884201D942 +:1004500001203FE7012020720020E0802073052E5C +:100460000AD01D982299E269C0B2491DF2F71FFC1B +:10047000002801D00A202DE70020C04360841AA87C +:10048000019023A9229802970395009100780023F8 +:100490008206920E20462A99FFF712FC0390208BC9 +:1004A00020A988807BE1032EC0D1402220A98A8127 +:1004B0004178027808021043208320A988802A9975 +:1004C0001EAB1C9A02930192009139880022491EAA +:1004D0008BB21B990978F6F711F918A90872002850 +:1004E00033D10B20287010A8008F3FE0052E9DD13E +:1004F000802220A98A814178027808021043208353 +:10050000249984464A78097812020A43628420A911 +:1005100088801248824202D30720DBE6AFE03F200A +:100520008002024362842A981FAB1C9902930191B6 +:1005300000903888401E83B21B9801786046F6F719 +:10054000DDF818A9087200280CD08328AAD107E08A +:10055000FFFF0000B40E002001280000010200008F +:100560000220B8E00D20287010A8808F401C15E1F3 +:1005700001990C22C9095143C91CB14204D90198FF +:1005800040067CD5002009E1427803781002184328 +:1005900020AA9080844622980078400609D505203C +:1005A0006A46107422980078C00905D000201074A3 +:1005B0001DE106206A46107424981F902A9A009024 +:1005C0000023701A029383B21E9001921B9800229E +:1005D00001786046F5F7AEFE18A908720022694658 +:1005E0000A74832801D102200390229800784006E3 +:1005F0000DD52088C00506D520A9208B8988884282 +:1006000001D100206062002018A90872C6E0FF2115 +:10061000013120A88181808820831E9860841F98E2 +:1006200060621320B8E0052E29D3417802780802D1 +:10063000104320A98880218F002902D0FE4A9142D0 +:1006400006D10A216A4611740121C943218702E0BB +:1006500007216A46117422992A9A491D0192009134 +:1006600001221D990023D203029311438BB22499D6 +:100670004A78097812020A431B99097800E0C9E018 +:10068000F5F758FE18A90872002269460A7401227B +:10069000520220A98A81832808D0002809D0218FFE +:1006A000E54881427ED10020208778E08888208339 +:1006B0004DE7606B002808D031462046229AFFF7AC +:1006C000E3FB18A90872002869D12B463A46304648 +:1006D000229900F056FB039061E02298022E4078A8 +:1006E00001907DD1002801D0012879D108206946E8 +:1006F00008740198087521A800901B9800220178C1 +:100700002046019BFFF7B0FC6946002248758A75B8 +:10071000002802D10198012809D0208F002806D096 +:10072000002008740120800220A988810EE004A81E +:100730003399F2F774FF0390002069460874012092 +:10074000800220A988810398022807D0BB4800684E +:100750008079002805D018A908722BE00198208321 +:100760001DE00398002803D0812018A9087240E0FA +:1007700021A800901B98012201782046019BFFF7D9 +:1007800073FC18A9087220463499FFF753FC18A986 +:10079000087A002803D11920287001203880684683 +:1007A000007C00E03CE0002804D004A83399F2F774 +:1007B00036FF0390039800282ED01AE0062012E599 +:1007C0002078000713D5012E11D109216846017444 +:1007D000A188818204203499FCF771FE082100E091 +:1007E00005E020A88181CDE60198400612D50320BE +:1007F000039020A9208889890843208020A988891E +:100800004005400E04D026992B98086026988680D3 +:100810000398AAE40420E6E418A8007A00280ED081 +:100820000120287022980078687020A88088A8701D +:10083000000AE87018A8007A28710520388020A9DD +:100840002088898988432080E2E7FFB50746A1B068 +:1008500000201C903A7801209040794A7C68104032 +:1008600010AA1087744B22885B1C9A4203D0002880 +:1008700004D0100702D5012025B0F0BD249E002031 +:10088000307023980025028810A8028518A80575E5 +:100890006A4B68461972057404A8186020462C300B +:1008A0001B902A985860249E94463878721C052123 +:1008B000039201282DD0022808D003287DD130785A +:1008C000800980011D303070B889A08038780228F6 +:1008D00004D13078800980011B303070F01C1FAAD1 +:1008E00001900292009110A8008D0022C01E83B2D8 +:1008F0002020015DB889F5F701FF0028DED10398BB +:10090000B9890170090A417010A9888FC01C088537 +:1009100028E1787B18AA10753A7B012A02D0022AB6 +:10092000CCD1FCE022887F231B011A4010AB1A8730 +:10093000802A4AD006DC102A10D0202A0ED0402A65 +:100940000AD124E0FF3A013A65D0FF3A013A79D062 +:10095000FF3AFF3A022A76D00525A2E02078C006A9 +:1009600001D5082000E010201C9004206A46107475 +:10097000002090821AA81DAA1EAB03960192029035 +:1009800000933B8A20461C9AFFF79AF984E0228B59 +:100990003B8A9646934268D10A221C92002839D19C +:1009A000039801906046401E1FAA83B20292202045 +:1009B0000091015D0022704600E0BAE0F5F79EFE6E +:1009C000014618A801750B201AE0228B3B8A964637 +:1009D00093424AD10C221C92002862D103980190C4 +:1009E00060461FAA401E0292009183B22020015D42 +:1009F000628C7046F5F782FE014618A801750D203D +:100A0000307010A8818F491C01850421684601744B +:100A1000218B818245E0238B3A8A9C469A4224D1DD +:100A200012221C9200283CD1606A002813D00022B8 +:100A30006B4607C3638C07E0FEFF0000B40E002086 +:100A400009F800000DE04BE02020015D6046F5F75D +:100A500071FC18A9087513203070012010A90885B1 +:100A60001FE0398A228B914201D00425B6E016217D +:100A70001C91002815D11B98818802682046FFF739 +:100A800003FA18A9087500280BD11B983346016892 +:100A900080881AAA00F075F9054602281BD0042D9B +:100AA00019D01B988088002811D06846007C002847 +:100AB00004D004A82A99F2F7B2FD05460120694640 +:100AC00008741B981B990068059000208880002DF1 +:100AD00048D0052D2ED06846007C032878D07DE0D4 +:100AE00018211C91002806D0388A20832046B96836 +:100AF000FFF7A0FAD5E72046183000902020015DCE +:100B0000237E01222046FFF7AFFA18A908750028B6 +:100B1000ECD119203070012010A90885E6E7208863 +:100B200001214902084010A90887FF38FF38022830 +:100B300006D0052510A92088098F884320804DE024 +:100B4000208F9849884290D116201C90386900283F +:100B500005D06063B88A20870020608702E000200B +:100B6000C043208710A8008F7F21090102468A43D5 +:100B70000DD0782300220420B968FCF7FBFB3878FD +:100B8000A07010A92088098F0843208002E02188E6 +:100B9000814321806846007C002805D08248416856 +:100BA00004A8F2F73CFD054618A8007D002815D0E2 +:100BB0001C98707001203070208BB070000AF070AB +:100BC00018A8007D3071052110A8018506E0FFE717 +:100BD0007548416804A8F2F722FD05467248017A7B +:100BE00020884005400E22D11B98808800281ED006 +:100BF000239A0026138810AA1385249A2A9B6F46ED +:100C00004CC71B9A039412681AABFFF78DFA05467E +:100C100002280CD00120694608741B982A990068A4 +:100C2000059004A8F2F7FBFC05461B98868010A8E7 +:100C3000018D2398018028461EE600B597B0042850 +:100C400007D102206A461070019100216846F2F730 +:100C5000E6FC17B000BD10B5534C037800222168A4 +:100C6000012B02D0022B42D126E00B78002B01D0C1 +:100C7000042B03D10A712268032111702168838833 +:100C80000A79D200921D8B5221680A79D20008326B +:100C90008918C2880A80216803890A79D2000A3239 +:100CA0008B52428920680179C9000C314252216877 +:100CB0000879401C08711EE00A7482888A802168C5 +:100CC000C288CA80226801891181226841895181C4 +:100CD000C1682068C1606168F2F7A1FC0146022882 +:100CE00007D02068007C002802D1002903D0812091 +:100CF00010BD832010BD002010BD406B002800D027 +:100D0000012070478178012909D100880521C90295 +:100D1000884202D0491C884201D10020704705203A +:100D20007047F7B586B00024684615460F468481A3 +:100D300005261AE0049841780278090211432980B7 +:100D4000811D019602940091417902790B021343AF +:100D5000C178827809020A43417800780902084381 +:100D60003946F5F7E7FA002806D104AA03A9069840 +:100D7000FFF7BFF80028DDD0822800D1002009B09D +:100D8000F0BD10B51488844201D2052010BD17248F +:100D90001C701080421E581C491C05F0C6F900202A +:100DA00010BD0000FEFF0000B40E002010B540484A +:100DB00004F04DF9002801D00C2010BDFF211131A5 +:100DC0003C4805F011FA3B4901200870002048809A +:100DD000E03188718874887520310871344804F0D6 +:100DE0004EF9002010BD10B5314804F028F9002854 +:100DF00003D031A1312005F016FBFFF7D7FF002803 +:100E000003D02DA1382005F00EFB10BD10B504460F +:100E1000274804F01CF9002801D00C2010BD2549FA +:100E20000878002807D0002008702148216004F0CD +:100E300026F9002010BD1E4804F021F91F2010BD26 +:100E400070B505460C461A4804F001F9002801D097 +:100E50000C2070BD174A5088A84202D11078002893 +:100E600004D0134804F00BF9122070BD1048226022 +:100E700004F005F9002070BD10B504460C4804F0DC +:100E8000E6F8002801D00C2010BD0A48017800299E +:100E900007D00020C0432080054804F0F0F812205D +:100EA00010BD40882080024804F0E9F8002010BD01 +:100EB0009D000020C00E00207372635C6C6C5F6448 +:100EC000622E630010B5282105F08CF910BD70B5B5 +:100ED000054600780A0700090001120F1043287028 +:100EE0000B0005F091FB07050705070509050B0039 +:100EF000062408E00C2406E0222404E00024F2A1E9 +:100F0000572005F090FA68788009800120436870C6 +:100F100070BD00780007000F704710B50622C01C96 +:100F200005F003F910BD10B50622093005F0FDF8F3 +:100F300010BD0278BF23C9071A40490E0A43027048 +:100F4000704702785206520EC9010A430270704778 +:100F500070B515460E4604461F2A03D9DAA1A8200B +:100F600005F061FA20462A463146093005F0DDF8E1 +:100F70006078AD1D80098001A906890E0843607064 +:100F800070BD70B515460E4604461F2A03D9CEA182 +:100F9000CC2005F048FA20462A463146093005F0B3 +:100FA000C4F86078AD1D80098001A906890E084348 +:100FB000607070BD70B501780907090F03292ED044 +:100FC000052931D1411C827E0C46437E1102194312 +:100FD000037FC27D1D02037EC67E1B021343827DFA +:100FE000407835438006800E22281DD106291BD368 +:100FF0001920C001814217D8FF26F436B54213D814 +:10100000002A11D0082A0FD88A420DD28B420BD861 +:10101000617F227F09021143814207D904E04078B1 +:101020008006800E0C2801D0002070BD012070BD0C +:1010300000210A464254491C2229FBDB704710B5A7 +:1010400002788B07920892009B0F1A430270427835 +:10105000520952014270012908D0022906D0032901 +:1010600005D0FF2098A1EE3005F0DDF910BD01217B +:101070000A43427010BD10B502788B0792089200A7 +:101080009B0F1A43027042785209520142700129A3 +:1010900007D0022905D0032904D08BA18E4805F082 +:1010A000C2F910BD01210A43427010BD00788007CB +:1010B000800F70470278EF23C9071A40C90E0A4310 +:1010C0000270704770B50546C1700B0005F09CFAC0 +:1010D0000E080A0C0E1012120C14141212160C1810 +:1010E0000C2413E0082411E002240FE017240DE083 +:1010F0000D240BE0012409E0092407E0062405E0A3 +:101100007548002470A1A03005F08DF96878400979 +:1011100040012043687070BDC0787047017AC27981 +:10112000080210437047817A427A080210437047E0 +:10113000017BC27A08021043704781794279080224 +:101140001043704700797047817B427B080210434F +:10115000704770B5017AC37909021943431C857A37 +:101160001C46467A2B023343657926792C02344398 +:10117000C21C5A4E00798D1FB54214D8FF25F43594 +:10118000AB4210D800280ED008280CD888420AD2CA +:101190008C4208D8507A117A00020843B11D884267 +:1011A00001D8012070BD002070BD0B4610B5011D97 +:1011B0000522184604F0B9FF10BD817A427A080270 +:1011C0001043704701717047007970470B4610B5A6 +:1011D000011D0822184604F0A8FF10BD027B0A700A +:1011E000407B487070470B46014610B508220E310F +:1011F000184604F09AFF10BD0B46014610B50422B4 +:101200001631184604F091FF10BD10B50822001DDC +:1012100004F08BFF10BD10B504220C3004F085FFE4 +:1012200010BD017170474171090A81717047C17128 +:10123000090A017270470079704781794279080282 +:1012400010437047017AC279080210437047017158 +:101250007047017170470B4610B5011D08221846F2 +:1012600004F063FF10BD10B50822001D04F05DFFFF +:1012700010BD70B515460E4604461B2A03D912A1AF +:10128000174805F0D0F82A463146E01C04F04DFF1F +:101290006078E90640094001C90E0843607070BDDE +:1012A00070B5054640780E46C406E40E1B2C04D9E2 +:1012B0000B4805A10C3005F0B6F82246E91C304673 +:1012C00004F033FF204670BD7372635C756C5F7011 +:1012D00064752E6300000000070200007A0C000015 +:1012E000F7030000C1074008C207C90FD20F511809 +:1012F0004008C207D20F51184008C207D20F511838 +:101300004008C207D20F51184208D007C00F40183A +:101310005208D107C90F0918500840187047002219 +:1013200002808271C271C2720273427382738270D0 +:10133000C270027142714276828303464284203336 +:101340009A7102859A72C2750276C2730274DA7259 +:101350001A739A7319750284FF21603081709A752F +:10136000704770B504460020A083208C1E46484379 +:101370001546114604F061FF2084F000294604F070 +:101380004EFF401C80B20146192269439202E0835D +:10139000914201DD401EE0837D202946000204F0D9 +:1013A0003EFF401CA08470BD70B50546087B0E460C +:1013B000C006C00E08730020A87504463019007AD4 +:1013C000FFF790FF29194874A97D641C0818E4B23E +:1013D000A875052CF2D3C0B2252803D979A18A209B +:1013E00005F021F870BDF8B5044630302646274692 +:1013F0002546C036A03780350090032909D0002942 +:101400001AD0012924D0022902D1A11CFFF7CCFF58 +:10141000F8BD1146FFF783FF002028836883A88367 +:10142000E883288468847871E88538732621085514 +:10143000A08430703071F8BD0020E885B871A188B3 +:1014400023890A460098FFF78CFFA11C0098DDE76E +:101450000020E885B38A328AA1880098FFF781FFCF +:10146000F8BD70B5867D0D460446002E01D0252EB0 +:1014700001D9122070BD002A18D0287EE17D50438A +:101480000818252104F0CBFE0846E1754207520FEB +:10149000C908504B69189A5C097A8A4368D031466A +:1014A00004F0BDFE491CCAB2002007E0002070BD58 +:1014B000002803D02118097C511ACAB22118497C8E +:1014C00091423AD32918097AC943CB07DB17D21ABC +:1014D000521E1206120E35D08B07DB17D21A521E7F +:1014E0001206120E30D04B07DB17D21A521E12060C +:1014F000120E2CD00B07DB17D21A521E1206120E38 +:1015000028D0CB06DB17D21A521E1206120E24D098 +:101510008B06DB17D21A521E1206120E20D04B0673 +:10152000DB17D21A521E1206120E1CD00906C9175A +:10153000511A491E0A06120E18D0401C0528B7DBA6 +:101540001F2070BDC00013E0C000401C10E0C000B0 +:10155000801C0DE0C000C01C0AE0C000001D07E0B8 +:10156000C000401D04E0C000801D01E0C000C01D9F +:1015700020769BE738B505460C466846FEF738F8F6 +:1015800000281ED0694600200856207209216156A5 +:101590000022411A00D5494220356B798B420FDC7D +:1015A000FF2B0DD0A17A491CC9B2A172AB79994227 +:1015B00002D8617A7F2903D160720020A0720122D3 +:1015C000104638BD7372635C6C6C5F7574696C2E09 +:1015D000630000007667010010B5040004D0FF200E +:1015E000FAA1AB3004F01FFFFB4821464143FB4802 +:1015F000FF230918FF330022581C5A544254C81DB7 +:10160000FF30FA3002704270F448001FC378A342E2 +:1016100002D18270FF23C370EF48EF4BC01E081841 +:101620009B1EC91802700A7010BD70B5EB480026E9 +:10163000001F8670FF24C47035462846FFF7CCFF94 +:101640006D1C2D062D0EF8D00020E4490B229201CE +:10165000E14B43435B189B181E74401C0006000EB0 +:10166000F6D0DF48FFF7E4FC0021DD48FFF722FD5C +:101670000121DB48FFF7E3FCDA4804704470847012 +:10168000C4700471447170BDCFE71B20704730B542 +:101690000021D24A0B239B01CF4C4C43A418E418E1 +:1016A000247C002C05D0491C0906090EF4D000202A +:1016B00030BDC94C01254C43A218D21815740170D5 +:1016C000284630BD10B5044600F0D0F900280CD0F3 +:1016D0002046FFF781FFC0490B224C43BF49002041 +:1016E0006118920189180874012010BD10B50446D4 +:1016F00000F0BCF9002802D0BA484471012010BDA6 +:10170000034610B5B748B44940794843B349421835 +:101710001046FF30E130C17F807F04F0D5FF10BD5F +:1017200010B5B048AC4940790F224843AB49401846 +:10173000A949D239095CFF30FF3004F09FFF10BD8A +:1017400010B5044600F092F9002802D0A5480471B3 +:10175000012010BD034610B5A2489F4900794843B7 +:101760009E4942181046FF30E130C17F807F04F06F +:1017700098FF10BD70B59B4C97492079974D484311 +:101780004019C11DFF31F931FF30E130807F0F2258 +:1017900004F064FF002813D020798F494843401992 +:1017A000FF30FF3002300178491C01700178407829 +:1017B000814204D1884885A1773804F034FE0120A5 +:1017C00070BD884884490079484384494018FF30F7 +:1017D000E130C17F807F814201D10120704700202C +:1017E000704770B57F487C49007948437B49401871 +:1017F000FF30E130867FC57F0F242946304604F054 +:1018000026FF002801D0204670BD70066906400EF4 +:10181000490E884201D3401A01E0081A201AC0B2CA +:1018200070BD0F20704770B50C46054600F01EF9DC +:1018300000280ED0002020706748454367482818CC +:10184000FF30FF300230017842788A1A22704170EE +:10185000012070BD70B50C46054600F007F9002860 +:101860000BD05D4845435D482818FF30FF300230FB +:1018700001784078081A2070012070BD5849016035 +:10188000704710B5044600F0F1F8002802D0554822 +:101890000470012010BD5149091FCA78FF2A02D0E7 +:1018A0000021016007E08A784C492439012A02D0DE +:1018B000016001207047002070474848801E017871 +:1018C000012908D001210170464801784348001FD2 +:1018D000C170012070470020704710B5044600F029 +:1018E000C5F8002802D03F484470012010BD3B4994 +:1018F0003C4B091FCA785B789A4206D18A78203916 +:10190000002A02D001600120704700207047334850 +:10191000344A001FC1785278914209D1FF21C17029 +:10192000801C0178002903D000210170012070473C +:101930000020704729482B4A001FC17852789142F5 +:1019400004D18078002801D0002070470120704722 +:1019500010B5044600F08AF8002802D02148C4706F +:10196000012010BD034610B51E481B49C0784843EE +:101970001A494018C21DFF320B21FC328901401860 +:10198000C17B807B04F0A0FE10BD10B51548124944 +:10199000C0784843114940180B2189014118C97B7F +:1019A0000D4AD21E8018062204F068FE10BD0D48B4 +:1019B0000949C0784843094941180B20800108189B +:1019C000C17B807B81420FD1012070477372635CC1 +:1019D000646D5F712E630000D1020000F40F0020DF +:1019E000C51200209E0000200020EEE710B504463E +:1019F00000F03CF8002802D021488470012010BD7E +:101A0000034610B51E481F49807848431E494018B8 +:101A1000C21DFF320B21FC3289014018C17B807B43 +:101A200004F03FFE10BD10B51548164980780B2212 +:101A300048431549920140181249891E41188018DF +:101A4000807B062204F00AFE10BD0D480D49807807 +:101A500048430D4941180B2080010818C17B807B49 +:101A6000814201D10120B0E70020AEE7002805D176 +:101A70000648007C002801D00120A6E70020A4E74A +:101A80009E000020D1020000F40F0020B4120020BC +:101A9000F8B5FF4E0446B079002500280AD0002989 +:101AA0002DD1657010202070F079A070307AE07030 +:101AB000B57124E0F64F203F387A012804D0707ABF +:101AC000012810D00020F8BD002918D1657013201E +:101AD000EF4920701C221639A01C04F026FB0120BF +:101AE000A0713D720BE0002909D165701420E8490E +:101AF000207008220A31A01C04F017FB7572012027 +:101B0000F8BDF8B5E3480178002902D00C2630462C +:101B1000F8BD0026DE4D3446403D2E756E75EE75DF +:101B20002E76AE75294620396E730F464E734037B8 +:101B30007E717F218170687E002804D0FDF73DFD15 +:101B4000FEF766F86C763C72D14884711430FFF76A +:101B5000B9F9CF483C30FFF7B5F9D8E710B5CD4B10 +:101B600000221A70CA4B203B1A711A46603A11665D +:101B7000D065FFF7C6FF002804D0FF20C6A187303C +:101B800004F051FC10BDC2484038007D7047C04988 +:101B900010B54039C87B897B42078307D20FDB0F22 +:101BA000D218C007C00F101840000B0004F02CFD25 +:101BB000050B060B04080F00BB4906E0BB4810BD2F +:101BC000B949083101E0B8490839085A10BDFF2069 +:101BD000B1A1A73004F027FC002010BDAC48B449E7 +:101BE0004038008A48437047F8B5A94C0646407B08 +:101BF000403CE07337791346A773012F26D0308815 +:101C00002082A348B27B203882710546603D29704E +:101C100006221946681C04F088FAB0796873062217 +:101C2000F11DE81D04F081FA607B0126002800D038 +:101C3000667597486038407B002800D0A6753B0049 +:101C400004F0E2FC0506082549084B000020D7E710 +:101C500000211DE08E4801211430FFF738F98C482F +:101C6000E91D1430FFF75FF9687B002807D00128D1 +:101C700007D0FF2088A1EE3004F0D5FB0CE0002156 +:101C800000E0012182481430FFF75BF904E00621EF +:101C90007F481430FFF71BF90020E07520767C4860 +:101CA000691C1430FFF739F9794829781430FFF7A7 +:101CB00040F9774804213C30FFF709F97448691C62 +:101CC0003C30FFF72AF9724829783C30FFF731F9A8 +:101CD00026750020F8BD0221DAE7FF206EA1F8305A +:101CE000CAE770B56A4C0125403C0346257620467C +:101CF0002030007A002801D03A2070BD64480022CC +:101D0000803806789E4206D1E2750622401C04F017 +:101D10000CFAE57500E02276002070BD70B504462F +:101D20005B4D0020403DA87528462246323804F01D +:101D3000FCF92846203844730120A87570BD544929 +:101D400020390871704710B5514C0022403C627533 +:101D5000607302462046123804F0E7F901206075EE +:101D600010BD4B49203948717047F8B500F0A4FB0D +:101D7000474C0025403C607E002804D0FDF71DFC48 +:101D8000FDF746FF6576434F3D70FDF793FBA07B63 +:101D9000012804D00021084601F0A6FAF8BD002170 +:101DA000022001F0A1FA3A4C203C207A002809D008 +:101DB000374881790029F1D11321C17105720121C0 +:101DC0008171F8BD78780028FBD0314E0622803E24 +:101DD000707BE0733078A0753046F11D703004F0F0 +:101DE000A4F930460622711C773004F09EF93C209D +:101DF000A072012020727D70F8BD10B5244C403CCB +:101E0000E17BA07CCA0701D0C2070BD08A070FD59F +:101E100082070DD42620FDF777FAA07C0221084323 +:101E2000A07410BD2520FDF76FFAA07C0121F6E714 +:101E30004907F6D54007F4D42720FDF765FAA07CC2 +:101E40000421ECE770B5134E3078002872D1104CA5 +:101E5000403C207D00286DD0FDF71FFB0025A574B8 +:101E6000E57475702846FDF715FB0020FDF78CF929 +:101E70000D480D38FDF73FFA0B481038FDF7F7FA1B +:101E8000FDF76CFBFFF7B9FFFDF7FFFA012111E049 +:101E900068130020A40000207372635C6C6C5F61A7 +:101EA00064762E63000000008E6701009A8913009B +:101EB000710200000020FDF743FA0F210520FDF715 +:101EC000C1F92646403E3178701CFDF7ADF9A07B84 +:101ED00001280CD004280AD0607D002807D02146B4 +:101EE00012390846627B6630FFF732F86575A07DCF +:101EF000002807D0FE480146427B12399C30FFF78C +:101F000040F8A575306E0178002903D00178001DD6 +:101F1000FDF7C8F9F06D0178002906D0F44A401C9D +:101F2000C732FDF754FE01206076FDF7C3FA0020AA +:101F300070BDFFE70C20FBE7EE494860704770B5C5 +:101F4000050001D0FFF759FFE94C2034E07C002860 +:101F50000AD0A07B012804D19920E749C00004F0F1 +:101F600062FAFFF702FFE3E7002D0DD00221002007 +:101F7000FDF7E6F9DE4840300079032801D001285A +:101F800002D10220FDF73BFCE07D002600280DD0A9 +:101F9000D74D203D2846691C9430FEF7BEFF2846E9 +:101FA000691CBC30FEF7B9FFE6752676D048743060 +:101FB000FDF786FAA07B030004F026FB0504040469 +:101FC0000D04090001210846FDF79FFB03E0CA4903 +:101FD000CA4804F028FAE17BA07C81430120002953 +:101FE00003D1A17B012903D0E074C24908709FE7A7 +:101FF000A674FAE710B5FDF750FABE48007800283D +:1020000018D1BB482030007D002813D00020FFF7F6 +:1020100096FFB74840300079002809D001280FD03A +:10202000022805D003280BD0B349B54804F0FBF9CA +:10203000002010BD00F040FAFDF73CFA0C2010BD66 +:10204000F0F7E6FFF4E7AB49012048707047F8B5B8 +:10205000002400F0E0FF002824D0FF202D30FDF701 +:102060006CF9A44D2878A24F403701281DD00228D2 +:1020700001D0032834D0A2489F496B3004F0D3F933 +:10208000287800280DD0387900280AD0012808D0F7 +:10209000022838D0032836D099489749803004F078 +:1020A000C2F9F8BDFFF761FEF8BD914E2036B07B56 +:1020B000032815D0707E002803D0FDF798FDFDF7AA +:1020C00074FA8B48C430FDF7FBF9B07B012812D0BD +:1020D000042810D0B879012806D0032804D004E0E1 +:1020E0000120FFF72CFFCBE7102421460E200143EF +:1020F0000020FDF70AFB7879012801D1FDF76FFA7E +:1021000002202870BCE728780228CDD10120FDF7F5 +:1021100076FBF8BD70B5764840304079012801D192 +:1021200000F0D4F9724C2034607E002803D0FDF713 +:1021300044FAFDF76DFD00F06EFF00280CD06D4DE8 +:102140002878022804D06E486B49A33004F06BF95C +:10215000A07B012803D006E0FFF707FEE8E6992000 +:102160008000FDF7EAF80120FFF7E9FE2878002853 +:10217000F4D028780128F1D039205F49000104F01B +:1021800052F9D5E6F0B5074689B000200690FDF774 +:10219000AEF800900020019056480078022804D044 +:1021A00057485549F03004F03EF9514D40356879B3 +:1021B000012801D100F08AF94D48C430FEF7A9FE8C +:1021C0004B4E04462036002F70D03046A430FEF728 +:1021D000F1FE0028F8D0FDF731F80028F4D0707E29 +:1021E00000280AD005277F1EFFB2FDF72CFD02282C +:1021F0000FD0012800D0002001903D492046C43175 +:102200000C46643C030004F0FFF906A4A4A40CA44B +:1022100056A4002FE7D177203AA1C00004F003F9BB +:10222000E9E7B07B012841D004283FD0019A00980B +:10223000104304D1A879002801D0022836D168794A +:1022400001281DD1607A00281AD101206072087817 +:1022500006224006C00FA0722548C91C6B3003F04F +:1022600064FF244C224FA07871377F2804D1A92025 +:1022700024A1C00004F0D7F8A07838707F20A070A7 +:102280001B489C30FDF71CF91A480321017028797E +:10229000002860D001280AD002285CD0032806D08C +:1022A000164818A1E03804F0BEF854E051E00120CF +:1022B000FDF7A5FA4FE00E480F462038C978C079DF +:1022C000814230D10A4839792038027A91422AD1A4 +:1022D0007979427A914226D1B979827A914222D192 +:1022E000F979C27A91421ED1397A027B914211E08A +:1022F00008130020A4000020981E0100F60400002E +:10230000DE0200007372635C6C6C5F6164762E6346 +:102310000000000007D13978407B4906C90F81428F +:1023200001D1012100E00021B07B012801D0042867 +:1023300001D100290AD100280BD101990098084346 +:1023400004D1A879002801D0012802D1307E0028CC +:102350001FD001200690707E002803D0FDF72DF9D4 +:10236000FDF756FC0698002802D00120FFF7E7FD94 +:102370005D48017800290AD00178012907D000784A +:10238000032804D095205949C00004F04CF809B046 +:10239000F0BD55480422406855490F3003F0C5FE92 +:1023A000387806224006C10F4F4840680177F91C73 +:1023B0001D3003F0BAFE4C484D4940680322091D08 +:1023C000133003F0B2FE4848494A4068B97D817530 +:1023D0000F3A117ED37D09021943018311468B7E8A +:1023E0004F7E1B023B438380137FD77E1A023A4302 +:1023F000C2808A7F4B7F1102194301813C4905222B +:1024000010310A3003F091FE3948374A1130017912 +:102410005768C906C90EB97600794009F876287A56 +:10242000002809D0A07900283AD11320E0710020BB +:1024300020720120A07133E00020A8727888B08556 +:10244000387FE8732A48394606221D31833803F065 +:102450006CFE27490622F3390878A87508467730BC +:10246000491C03F062FEB888F087F888208038891C +:102470006080F87E20710198002860790BD00121DE +:1024800008436071FDF7F2FB61794000C907C90F8D +:102490000143617102E04008400060710120287230 +:1024A000114C0020207000F007F8FDF703F8012020 +:1024B000616800F019FF4EE710B5FDF76AF8FDF707 +:1024C0005DF8FCF7B5FFFCF7DAFF10BD064810B564 +:1024D000801CFDF78DF8002802D103497F20887009 +:1024E000FDF774F810BD0000A400002004230100D3 +:1024F000DB1300208107C90E002808DA0007000F4F +:1025000008388008F74A80008018C06904E0800815 +:10251000F54A800080180068C8400006800F7047A8 +:1025200010B500F03BFF10BD70B5F04C0546626879 +:10253000002908D0002A04D0FF20EDA10C3003F0C0 +:1025400072FF656070BD002A04D1FF20E8A112303F +:1025500003F069FF0020606070BDE948C07E7047ED +:10256000E7482830C07E704738B5E04C20680168E5 +:102570004978012925D001216846FAF7C9FC684647 +:102580000078E049000203F04AFE2068426AC06811 +:1025900012685118FBF7ADFC2168C860D84A206862 +:1025A00028320321904218D0028B002A15D0012234 +:1025B0004272017200210171021D017F00F0FBFED9 +:1025C00038BD7D21C068C900FBF793FC2168C86055 +:1025D000FFF7DDFA21680861E0E7028B521C0283F5 +:1025E0004172E6E7FFB5C64E85B0706A346805688B +:1025F00060680190306A0390298E0798401A80B273 +:1026000002900898002804D02746383720464830E2 +:1026100002E0371D2846A830009003203871059845 +:10262000002820D001287DD002285ED003287AD04F +:10263000AFA1B54803F0F7FE0898002807D0387915 +:10264000032804D0B048AAA1093003F0ECFEA16A27 +:102650007069FBF74EFCB860616A206A88427DD9D8 +:10266000009801601FE1306A002804D1A648A0A1AB +:102670007A3803F0D8FEA449288B373948434018EC +:10268000069900F0A6FEA0619F49A8883739484303 +:10269000069900F09EFEE061316A9B48891CA162A8 +:1026A0002A8B37384243A069974B121AE63BD2185F +:1026B0005118A162944BAA7D373B5A4340008018C1 +:1026C000FF30193020626062306A081AED21FF384D +:1026D000C90015388842AFD28C49884204D28A4852 +:1026E00083A15D3803F09FFEB6E0874A288B373A16 +:1026F000E16850430818069900F06BFEA06182491A +:10270000A88837394843069900F063FEE061306AD3 +:10271000002804D17C4876A1553803F084FEAE2011 +:10272000405B01E02CE05AE00028288B784AE16801 +:102730001DD050430818A169401AA0622169A06801 +:10274000734A4843A1694018A97D4000514340188D +:10275000FF3017302062A888504300E0A1E0E16913 +:10276000411A6F20C000081A6062A06A34E050432A +:102770000818A169401A3168D63849684018DCE762 +:10278000284680300190C08D002802D0306A002891 +:1027900004D15F4856A1401F03F045FEA8885C495C +:1027A000E3694843C01AA06201999C46CA8D216919 +:1027B000A368521A4B43A169591863465343C91879 +:1027C000AA7D534B49005A438918FF3117312162C2 +:1027D0006F21C900411A6162316A401A35E00898D8 +:1027E000002803D03420005D002878D1A88848490B +:1027F0004843E169401A02994843A0622846803064 +:102800000490C08D0028019829D0002804D03E48AB +:1028100037A1163803F007FE04983D4AC18D02988F +:102820000818E16948434000FF3017302062A8884B +:102830005043411A6F20C000081A606200F0AEFDDC +:1028400000281CD0A16A0398081AED21FF38C9009E +:102850005538884200D3EFE601203871ECE60028B5 +:1028600002D00398002804D1294821A11A3003F08E +:10287000DAFD0198A16AD6380818A062CCE7FBF708 +:102880009EF8726901461046FCF7BFFAA16A081A61 +:10289000ED21FF38C90050388842DCD2012009B050 +:1028A000F0BD0099086000981A4900688035081842 +:1028B000F860298B0798081A00B2002804DD0598F3 +:1028C000022801D0032000E00120787108983870B8 +:1028D0000898002820D03420005D00281CD0022059 +:1028E000DDE7000000ED00E000E400E0B4000020BF +:1028F0007372635C6C6C5F6C6D2E73302E630000C2 +:10290000F413002010270000190500002902000020 +:10291000E20400004B1700000898012148402034D1 +:102920006075317F3A46304600F045FD0020B6E73D +:1029300010B5FE4900280A68516A096807D0126874 +:102940008988FB4BD2695943891A03F068FC10BD92 +:10295000F8B5F64F38680468416A26460D68203697 +:10296000717D00290AD0618E2A8E914206D1407A6B +:10297000012803D1EF49F04803F055FDFBF71FF89C +:10298000014638684069FCF740FAFFF7D1FF2A8E0C +:10299000618E1318994202DB491C618602E0401CDB +:1029A00010186086B07D002806D19C21608E495B9E +:1029B000884201D1401C6086DC480168088B0328EE +:1029C00002D2401C088302E0618E982041532846C1 +:1029D00040300646C1898089081A298E401E401859 +:1029E00087B218E0D148EB7E00685B00406A00794E +:1029F0004100D248415AC05A401881B2207D00237C +:102A0000FFF7F0FD00280FD001280ED0CA48C949B1 +:102A10003A3003F008FD628EB81A00B20028E1DAFD +:102A20000820B07200F010FEF8BD608E401C608679 +:102A3000F1E770B5BD4D002168680162C27E1300E8 +:102A400003F0E2FD045656034A56426A14680268CF +:102A500011700268516000682030407D002808D164 +:102A6000FAF7ADFF69680968096CFCF7CEF9002830 +:102A700018DC6868228E0168498E914206D1214691 +:102A800080318B8B9A1ACA83238605E0891A9E228D +:102A900011530168498E21860268C1681164C168BA +:102AA000416111E068680168098E228E8B1A224606 +:102AB0008032D3830168098E218601680B6CC36064 +:102AC0000B6C4361886C9062204601F0D8FC0028B2 +:102AD0000DD098499A4808E0C1684161FFF7B2F902 +:102AE000002804D096489349801D03F09CFC70BDDB +:102AF000934890490D30F8E710B58C4A0B001268E6 +:102B000003F082FD0906090F1F0C2E2E082B2E0044 +:102B1000FFF78FFF10BD00F068FC10BDFCF772FEE0 +:102B200010BDD07E022806D0D07E032806D0FF201C +:102B30008049A3300EE0FFF70BFF10BDFFF714FD37 +:102B400010BDD07E0228F6D0D07E0328F6D0FF201C +:102B50007849AE3003F067FCF0E7FAF715FF10BDD7 +:102B6000FF207449BC3003F05EFC10BDF3B581B0AA +:102B70000E4601276D4D734C0B0003F045FD090611 +:102B80002F39392F40403939400001216D48FFF776 +:102B9000CBFC31460198FFF7AFFFE07E022826D13B +:102BA00068680568406A0668FAF7E7FEB188604A17 +:102BB0005143EA69891AD639E962B72802D26248D4 +:102BC000081803E0081A6049B7314018E8625F4806 +:102BD000E96A814200D80846E86205E00198FFF7FB +:102BE0008BFFE07E022802D1206820300775FEBDF1 +:102BF0002C600198FFF780FF00202860FEBDFF20B9 +:102C00004C495C3003F00FFCFEBD70B50C46064627 +:102C10000B0003F0F9FC09060D10100D1A1A101024 +:102C20001A00484801212830FFF77EFC2146304633 +:102C3000FFF762FF70BD43483C4D283028603046A6 +:102C4000FFF75AFF0020286070BDFF20394982300D +:102C500003F0E9FB70BDF0B5344C0020216885B06D +:102C600003258D76CA7E0746032A03D0C97E002934 +:102C700029D029E0087F002803D12E49344803F0E9 +:102C8000D2FB2068067F684605714571FAF797FE0A +:102C90000290FF20F53003900121684601706946DB +:102CA0003046FBF70CFB00E020BF2068007FFCF7FC +:102CB00038F90028F8D02068007FFAF765FE206810 +:102CC000077700F072FB012021688F7605B0F0BD18 +:102CD00016490A68907600E020BF0A68D07E002876 +:102CE00003D0D07E937E9842F6D0D07E002803D0C9 +:102CF00000200021917670470120FAE770B5114954 +:102D00000024CA7E094D032A03D02831CA7E032A33 +:102D10002ED12960002827D0012821D00C48054950 +:102D2000973003F080FB0020296813E0B4000020F6 +:102D3000E2040000F0280100F70500009E67010092 +:102D4000A1030000F4130020C4F8FFFF38120000B4 +:102D500072020000086048622860002C08D070BD34 +:102D60000320FFF7B5FF01E0FFF775FF0446DAE740 +:102D70000C2070BDF8B5F94F04461F25E67E3300E0 +:102D800003F042FC042920031B20F548844204D0B0 +:102D9000FF20F449FC3003F046FB02203C60FFF7C3 +:102DA00097FF002805D03968002008604862386025 +:102DB00011E00C25002038600AE00120FFF79EFF9B +:102DC000054603E0E749E84803F02DFB002D02D05B +:102DD000E07EB042D2D1E07E002804D0E248E14952 +:102DE000801D03F020FBF8BD10B5DD48FFF7C2FFE2 +:102DF000DB482830FFF7BEFFD94900205031087565 +:102E0000D649C91F4870D64948610A4628325061E0 +:102E100088769076D1494860086010BD70B5044648 +:102E20000120FFF767FBC5B20B20FFF763FBC0B2C1 +:102E3000854204D0FF20CB49C63003F0F4FA0120CC +:102E4000FFF758FBC5B21820FFF754FBC0B285420C +:102E500004D0FF20C349C73003F0E5FA0420C04383 +:102E6000FFF748FBC5B21920FFF744FBC0B285420B +:102E700004D0FF20BB49C83003F0D5FAB748B849A1 +:102E8000083804700020C87688760A462832D07642 +:102E90009076B24B012408331C711860486250626E +:102EA00008601060FFF7A0FF70BDAC4908310871E1 +:102EB0007047FEB5AA49CA7E08462830A74C002AAA +:102EC00002D1C27E002A03D0C97E022903D005E0C8 +:102ED000A648216006E0C17E002901D00C20FEBD7D +:102EE0002060A348FAF7FCFC216808779B4920681A +:102EF000C91F0160C91C4162007F002804D1AD20B8 +:102F00009849800003F08FFAFAF737FD9949884213 +:102F100000D20846FF30C83086B220680325C57647 +:102F2000FEF735FE21680861FEF758FE00270028ED +:102F300027D0FEF753FE21684A6A10600968012015 +:102F4000087001466846F9F7E3FF684600788A4949 +:102F5000000203F064F90191FAF731FD019971184B +:102F6000FAF7C7FF2168C8602068057245720771CB +:102F7000021D017F00F01FFA2068078300202760F0 +:102F8000FEBDFAF71CFD3146FAF7B3FF2168C860B1 +:102F900008680770096801204870E5E77047F8B5D0 +:102FA0006F4EF17E002904D131462831C97E0029B7 +:102FB00001D00C20F8BD0221F176694C674F5034E6 +:102FC0000837776234600025386025753979C07E0E +:102FD0004A006A4940008A5A085A2B46101881B2A2 +:102FE0002A462846FFF7FEFA002804D0CF205D4984 +:102FF000800003F018FA25610120A5602075658620 +:1030000025865748703085753968088E401E0886B9 +:1030100035830020F8BD10B5504801244068817EFA +:1030200003290CD001684978002906D0006A544968 +:10303000884202D90024FFF706F8204610BD00247C +:10304000FBE74648406802681178491C1170016A24 +:103050000068C26A914204D8007D012801D0012095 +:1030600070470020704700207047F8B53B4C3C4843 +:103070002060416A00680D68002634210E54A621A4 +:10308000495D00294BD1007D032848D1FAF797FC10 +:10309000014620684069FBF7B8FE00283FDDFFF7D6 +:1030A00047FC298E401C4118206802681186006880 +:1030B000018E9C22525B511A09B200292FDD012199 +:1030C0002030817528464030C1898089081A298EB0 +:1030D000401E401887B21BE0496A09794A00274917 +:1030E0008B5A028E007D9446EA7E5200895AC91896 +:1030F00089B201236246FFF775FA00280FD0012834 +:103100000FD002280BD01B481649193803F08BF951 +:1031100021680868028EBA1A12B2002ADCDA266028 +:10312000F8BD20680068018E491C0186F0E7F8B5FB +:103130000A4D00266A680128516A0C6853D1087943 +:103140000E4940000B5A1068077D032F1AD0027DEC +:10315000022A24D0007D012834D044E0B4000020AD +:10316000F4130020F0280100070200006D2B01007D +:103170000B2C0100F6050000102700009E670100DF +:10318000D98213000661106886609C20025BE07E95 +:103190004000085AC01881B2002303201BE02246D9 +:1031A0008032D78D0761E07E928B4000085AC018AC +:1031B00081B200230220FFF715FA6A680121126824 +:1031C00011750AE09C20025BE07E4000085AC0189E +:1031D00081B200230120FFF705FA002803D09C49A3 +:1031E0009C4803F020F9FAF735FB9B480078EFF78D +:1031F0006FF8686806830268218E51860068203067 +:103200008675F8BD38B5944C0021083460680D46C9 +:1032100000684278002A01D045701FE0007800283D +:1032200009D001216846F9F773FE684600788B499A +:10323000000202F0F4FF6068426AC0681268511828 +:10324000FAF757FE01466068C160057103214172BB +:10325000021D017F00F0AFF860680583FAF7FAFA03 +:103260007D480078EFF734F838BD7B4A10B5014649 +:10327000083250680B0003F0C7F9060D1504081753 +:103280000C31012100F0D1F807E00021106800F0B6 +:10329000CCF810BD0120FFF74AFF00210846FFF7D8 +:1032A00043F910BD032116E0416A02680968D36939 +:1032B00093608A886A4B5A430368DA600A46C032D0 +:1032C000D3890B83137B8B75138A8B80538ACB80B6 +:1032D000928A0A8102210068017510BD5D485C492F +:1032E000913003F0A0F810BD70B500280BD05A4CF7 +:1032F000083401280ED002281ED056485449B43054 +:1033000003F091F870BDFFF77DFF00210846FFF73D +:103310000BF970BD6068002501684D7000F045F83C +:103320000320F5F7B8FEFAF795FA4B486560007888 +:10333000EEF7CEFF656070BDFFF764FF606800F0D8 +:1033400034F800210846FFF7EFF80420F5F7A3FE54 +:1033500070BD414908314968CA7E022A08D10A680D +:103360001378002B04D150600968CA6A1018C8622B +:103370007047394A10B50832526800290CD001292B +:1033800007D0022907D033483149D93003F04BF830 +:1033900010BD801E00E0401F106210BD2E48083096 +:1033A0004068002800D0012070470021C176817656 +:1033B00001604162704710B50B46C17E847EA14218 +:1033C00004D011461846FAF77AFF10BDFFF7EDFF5B +:1033D00010BD024610B50020002905D00846504314 +:1033E000204902F01CFF401C10BD1B4810B50830DE +:1033F0004068C07E030003F007F9041515030B15A0 +:1034000001F05EF900280CD00F2017A1800106E022 +:10341000FEF7F0FD002804D0F12013A1800003F096 +:1034200002F810BD10A11448F9E710B504460029B0 +:1034300003D00020FFF77BFE03E007480078EEF79B +:1034400047FF2046FFF7B1FF0020F5F724FE10BD2F +:10345000F028010092060000AC00002010270000B8 +:10346000E204000040420F007372635C6C6C5F6C9E +:103470006D2E73302E630000CB030000F8B5FEF70D +:10348000B0F90446FEF756FAF84E0546706920304A +:10349000407D002809D0012827D002282AD00328FF +:1034A00032D0FF20F2A19A3037E0F0481830FEF712 +:1034B0001EFA002801D003200FE0EC481830FEF778 +:1034C00049F9002804D070695B21095C002908D003 +:1034D000E6481830FEF7D2F90120716920314875AD +:1034E0001DE002212030417519E0E0481830FEF758 +:1034F000C5F914E0DD481830FEF72CF900280ED18C +:10350000FF20DBA18C3008E0D8481830FEF7EFF937 +:10351000002804D1FF20D6A1943002F084FFB069C6 +:10352000F72201781140017072692032937DDB0728 +:103530001B0F1943FB2319400170D37DDB075B0F81 +:1035400019430170577DEF23022F04D0012F07D0BC +:10355000032F07D00CE0012C06D8002D04D007E083 +:103560006D1E2C43002C03D019401023194300E09A +:1035700019400170D17F002916D0517D012913D047 +:10358000BF48FBF79DFFBE480021283001767269D5 +:10359000916ED26E42610161B949B269FCF7A3FA3A +:1035A0000020FCF7AFFA03E0FBF78AFFFCF7CDFA47 +:1035B000B0690078C00606D4F0690078C00602D46D +:1035C000F079002806D0B079002803D101210846FF +:1035D000FCF79BF8032030703079002803D1FBF70B +:1035E000BDFF01203071F8BD70B5A0481C30FEF75A +:1035F000B9F901259D4C002802D00020607002E03E +:1036000065709F48E061606940300078002802D012 +:103610006078002805D0E069FBF752FFFCF795FAC7 +:1036200070BD9748FBF74CFF9548283005766269D6 +:10363000116F526F42610161914AE169FCF753FADF +:103640000120FCF75FFA70BD10B588490023486976 +:1036500002462030C3768377012049239854A03254 +:103660009279002A03D008700021022001E0002195 +:103670000320FFF7FAFD10BD70B57C4C6079C206DF +:103680002046406901468031002A01DA002202E02A +:10369000CA8DCB8BD218CA850246C0321379002B53 +:1036A00005D0034640331D8AC98B69181982617A97 +:1036B000002903D03D2001F051F94AE003462033B0 +:1036C000D97E042945D0217A002913D0480701D496 +:1036D000C80601D51E2030E0080701D53D202CE0AA +:1036E000C80705D1880703D461A1664802F09BFE94 +:1036F0002A2022E04030817D002905D0418A4D1CDE +:103700004582858AA9420FD2517A062902D0117AC0 +:10371000062905D1018B4A1C0283828A914203D279 +:10372000028AC1898A4201D3222006E09A7F8089D9 +:10373000002A0AD088420FD3082001F00FF96069EF +:103740002030C07E042804D006E0062804D33E20A2 +:10375000F3E7FFF779FF70BD0120207000210846D4 +:10376000FFF783FD70BD10B5404840690146203128 +:103770008A7F002A29D0012A27D0022A06D0032ACC +:1037800004D03BA1404802F04EFE10BDC97E032983 +:103790000FD0082919D001464031CA898989511AA8 +:1037A000891E89B2032900D303218030828B5118EE +:1037B00009E0014640318A89032A06D3028EC9896D +:1037C00080305118491C018310BD8030818BFAE78D +:1037D00000B5030002F018FF0604070B0F121217C2 +:1037E00000290ED00FE0891E02290AD90BE0891F9B +:1037F000012906D907E0082903D004E00B390C2978 +:1038000001D8012000BD002000BDFEB505461748C7 +:103810001830FEF740F8002804D11B4814A1D13815 +:1038200002F001FE114CA069FDF702FC0321A06922 +:10383000FDF721FCA069EF220178114001702946B3 +:10384000FDF740FC002601272B0002F0DDFE0E5C98 +:103850005C085C2C6060255C4C5C603C375C60699B +:103860006521095C002911D0062111E0C400002067 +:103870007372635C6C6C5F736C6176652E630000C1 +:1038800090140020430200005C080000C030417921 +:10389000A069FDF797FC3AE060698030417CA0693F +:1038A000FDF7D7FC33E06169A069B831FDF7ADFCE5 +:1038B0006169A0698C31FDF7AEFC28E00621A069A2 +:1038C000FDF7C5FC23E020690178A069FDF7A9FC9C +:1038D00020698188A069FDF7A6FC20694188A0695C +:1038E000FDF7A5FC13E00096019660696030007951 +:1038F000002803D069460878384308706946A069F3 +:10390000FDF7B1FC03E0F949F94802F08CFDFDF741 +:10391000D4FF002804D1F648F449801D02F083FD4D +:103920000C2D06D0072D03D0606940304682877584 +:10393000FEBD606940300683FEBDF0B5ED4CC82089 +:1039400061698DB0405C04280AD0052835D15C201F +:10395000405C00282AD0012060314871022026E016 +:1039600010226846D63101F030F86169102204A8AF +:10397000B03101F02AF8684601F0DFFB08AE8DCEC9 +:10398000616984250E4678360DC66F5000250D6797 +:103990004D67012540267554D74D88318DC5284681 +:1039A0000822093002F0C1FB052000E00D20FFF7DE +:1039B0002CFF61690020C03108720DB0F0BDF8B570 +:1039C000CC481830FDF767FF002848D0C94C207A52 +:1039D000002844D16069C421095C002500290ED06B +:1039E0002030C17E0120FFF7F3FE002807D1606977 +:1039F0002030C17E0420FFF7EBFE002806D060696E +:103A0000C921095C0126062907D00DE06069502113 +:103A10000D526030457102204EE02030C17E0420FE +:103A2000FFF7D6FE002813D0616908462030C27E19 +:103A3000921E130002F0E8FD166262621D6262626D +:103A400060621F6262622843626262626262466210 +:103A500060695E21095CC90702D0C0304572F8BDBB +:103A60000C20FFF7D2FE60694030817F31438177BF +:103A7000F8BD072020E0FDF79AFF0028F8D0606924 +:103A8000403005700B2017E0F9F741FA0C28EFD30E +:103A900060690821B830F9F73BFA002806D0606960 +:103AA00004218C30F9F734FA002804D1C72093A1FF +:103AB000C00002F0B8FC0420FFF7A7FEF8BDFFF736 +:103AC0003CFFF8BD00228A66CA66C6770A4678318E +:103AD000C8C9894878322838D26842632830C8C0BB +:103AE00008220D30091D02F020FB0620FFF78DFE95 +:103AF000606940308575F8BD0920DDE700F036FFCC +:103B0000F8BD70B57B4C3B216069095C08292FD159 +:103B10000146028EC0314B89521C9A4228D1227A2A +:103B2000002A25D10A8A83889A4207D14B8AC58800 +:103B3000AB4203D18B8A0589AB4209D043884B85C0 +:103B40008A854A8ACA858A8A0A860122E6210A5417 +:103B500001221146FDF747FC00210420FFF785FBF9 +:103B600060690021C92211542030C1760321817778 +:103B700070BD70B55F4C60692030C07E172803D0DF +:103B80005EA1624802F04FFC616900220B4640339F +:103B9000DA7608469A75E030867D0B240125002EE2 +:103BA00006D0837C002B14D1C4740275857410E098 +:103BB0001E7F002E07D01A774C88FA235C520276BB +:103BC0000C23837505E04E88FA235E520276057752 +:103BD00084752031CA7670BD70B5464CA0798007D7 +:103BE00036D5207A002833D160692030C17E01208B +:103BF000FFF7EEFD00282BD1A0690126C078002533 +:103C0000030002F001FD0E8585088537465F0A85B1 +:103C1000168526625285032152E060692030C07EFD +:103C2000052804D0394835A1333802F0FCFB60691F +:103C30000CE060692030C07E092804D033482FA1F1 +:103C40002D3802F0F0FB606956210D542030C57606 +:103C500070BD60692030C07E0B2804D02B4827A19E +:103C6000263802F0E0FB60695B210E540C21203005 +:103C7000C17670BD60692030C07E0F2804D0234813 +:103C80001EA11F3802F0CFFB60695B210E5410218A +:103C9000EDE760692030C07E102804D01B4817A1D2 +:103CA000183802F0C0FB12210AE060692030C07EA3 +:103CB000102804D0154811A1123802F0B4FB1421C9 +:103CC0006069D4E7FFF755FF70BD60690146C030F9 +:103CD000027A062A04D14031897F890700D505720E +:103CE000417A0629F0D1457270BD0000703801009C +:103CF000CD070000C4000020B81400207372635C7C +:103D00006C6C5F736C6176652E6300004C0500007F +:103D1000FD49FE4802F087FBE6E710B5FC4C606900 +:103D20002030C17E0020FFF753FD002803D1207A08 +:103D3000012108432072207A002808D1E069FDF7AC +:103D4000EBF961699122505405202031C87610BDED +:103D500010B5EF4C60690146C0314A7A002A06D09E +:103D6000097A062903D0217A012211432172217A8E +:103D7000002928D14030807F800715D4E069FDF705 +:103D80005AFA61694031C877E069FDF756FA61690E +:103D900040310884E069FDF755FA6169022240313B +:103DA0004884887F10438877606900220146C031CB +:103DB0000B7A062B00D10A724030837FDB0702D1D9 +:103DC00006234B72028310BDF8B5D14C60692030D8 +:103DD000C17E0020FFF7FCFC0125002807D16069A7 +:103DE0004030007F002802D1207A28432072207AB8 +:103DF000002830D160690026014640304682857532 +:103E0000B031E069FDF7EFF96169E0698831FDF7EC +:103E1000F3F960690146E030827D0827002A06D068 +:103E2000817C002913D1C774067585740FE04A8818 +:103E3000F8204252FA31E069FDF7C8F96169E0699A +:103E4000FF310331FDF7CAF96069E03087756069B9 +:103E50000F212030C176F8BD10B5AD4C606920301F +:103E6000C17E0020FFF7B4FC002803D1207A012195 +:103E700008432072207A002812D1E069FDF769F921 +:103E800000280ED0E069FDF75FF96169CA2250523F +:103E9000098E00F0D6FD002806D0282000F05EFD37 +:103EA00010BDFFF73AFF10BDE069FDF74BF96169FE +:103EB000C0310873E069FDF740F96169C031C8811C +:103EC000E069FDF72BF96169C0310882E069FDF70F +:103ED0002AF96169C0314882E069FDF729F9616911 +:103EE000D422505208202031C87610BDF8B5884C35 +:103EF000A079C00776D0207A002873D1606920307D +:103F0000C17E0120FFF764FC002863D1E069002531 +:103F1000C178022701260B0002F076FB0D1613086C +:103F2000415A5A445C575A192F545A00FDF74CF91C +:103F30006169C62250543B20475440314D828E75F2 +:103F400048E000F093FD45E0FFF786FF42E060693E +:103F50002030C17E0020FFF73BFC002802D1207AF0 +:103F600030432072207A002834D160690146403104 +:103F70004D828E750B2120300FE0606901462030A4 +:103F8000C27E0C2A02D0227A3A432272227A002A76 +:103F900020D1C57740310E770D21C1761AE0FFF7A9 +:103FA00013FF17E0606901462030C27E122A02D05A +:103FB000227A3A432272227A002A0BD140318D753F +:103FC0001721EAE7FFF7C4FE04E000F00DFD01E071 +:103FD000FFF7A3FE62690023106F516F401C594127 +:103FE00051671067F8BDF8B5494C05466069203047 +:103FF0008079012801D1FBF7E9FA012D14D160691C +:104000004021095C002903D12030C07F002801D065 +:10401000FBF79BFDFBF7BDFAFBF7B0FAFBF708FADD +:10402000FBF72DFAFBF746FA60790225C107012656 +:10403000002901D180070ED560692030817F0029D9 +:1040400002D0032902D006E0867700E085770021C0 +:104050000120FFF70AF960692030817F012903D12F +:104060006179090700D58577607A002803D100F0CF +:1040700027FDFFF7A4FC207900250028606902D005 +:104080008030058403E08030018C491C0184607914 +:10409000C00705D06069AC210D544030858104E033 +:1040A000616940318889401C8881E079002806D008 +:1040B0006169A031087B022806D8401C087360693A +:1040C000A030007B022806D9606901468030058453 +:1040D0004584A0310D7360692030C17E0020FFF758 +:1040E00077FB002804D160692030C07E072855D1B5 +:1040F00060690146C0310A7A062A4FD0497A0629FA +:104100004CD03E21095C05E0FC3C0100BA050000F2 +:10411000C4000020022941D1A030007B00283DD1FD +:10412000FDF74FFB002839D0FDF704FC002835D0FF +:1041300061690A468032508B01282FD90846A03089 +:10414000844646716038C7898389B81E834201DB83 +:10415000012002E0F81A401E80B2138CA789BB42EE +:1041600001D3012302E0FB1A5B1C9BB2984200D9E9 +:104170001846012801D163465D71C0310B78002BD0 +:1041800010D0528C49888A4201D3012102E0891A59 +:10419000491C89B2884205D9084603E061690120BB +:1041A000A0314D7161690A8E803110188883FFF744 +:1041B000DAFAFFF761FAFEF756FF002809D06069C6 +:1041C0000146FF3001300279002A02D14988C180BE +:1041D00006716069A0308571F8BD70B5F84C6069F2 +:1041E0002030407D00283ED0022810D1FDF7C2FAD1 +:1041F000002804D17120F349000102F014F962692A +:104200000023916ED06E491C58419166D06660695A +:10421000002520304575017D012904D10575A1795E +:1042200010221143A171C17C012915D1C574A07957 +:1042300008210843A071FDF76AFB002804D1E5209E +:10424000E049C00002F0EFF860690023816EC26EA1 +:10425000491C5A41C266816660692030817D01290E +:1042600002D0012181753FE585753DE570B5D44CDF +:104270000026E169012508788207920F0420012AAF +:1042800015D0022A13D0032A03D0217A01432172C8 +:104290002AE560780028FBD1606920308574A17917 +:1042A0002943A17122E0C6751EE5C5751CE5497854 +:1042B000CA0624D06278002AEAD1C906C90E1B2991 +:1042C00018D8617901436171FDF75FFB002804D1C3 +:1042D0003B20BC49400102F0A6F860690023016F51 +:1042E000426F491C5A41426701672030C17D012954 +:1042F000DBD1D8E7207A102108432072F4E460690A +:10430000F3E77CB504460020C0436946888001A8D5 +:10431000FCF7B2FD00287AD169468888FCF790FD49 +:10432000002803D0A749A84802F07DF8009801466C +:10433000E030827C0025002A08D0657010212170B1 +:10434000C17CA170017DE170857472E082799C4E20 +:10435000002A13D065700720207008E07169E620FC +:104360008D8445540A22A01CE83101F0DEFE00983D +:10437000E03080790028F1D1A5705AE0827D002AD2 +:1043800038D0827D130002F03FF90D2F2F2F2F2FF1 +:104390002F2F2F112F2F24082F0065700C21217033 +:1043A000017EA17071694988A18010E065700820C4 +:1043B00020707069082240886080201DFA3101F069 +:1043C000B4FEFF2100980331095AA181E0308575C0 +:1043D0002FE065700B212170017EA1707169498801 +:1043E000A180017FA171F2E7774876495D3002F044 +:1043F0001AF81EE0C81DF9300279002A08D01122EF +:1044000065702270811C89886180057111E012E05D +:10441000027A002A0FD012226570FF312270033118 +:1044200004E005720A8962804A89A280027A002A21 +:10443000F7D101207CBD00207CBD614800780128B7 +:1044400001D00C2070470020704770B55C4C0546C9 +:104450002078002804D05C485A49933001F0E3FFEB +:1044600000202561A07201202070FFF7E6FF0028E0 +:1044700004D0554853499E3001F0D5FF34E4F8B5D7 +:104480004F4F3978012901D00C20F8BD0126A62113 +:1044900078610E548030807CFDF752F900282FD0CF +:1044A00078698030807CFDF753FA002828D078693D +:1044B0008030807CFDF7E5F9002821D078698030D4 +:1044C000807CFDF70AFA00281AD0FAF7E6FF78692F +:1044D00000258030408B002827D039481830FDF760 +:1044E000DAF9002821D07869C421095C00291CD0A0 +:1044F0002030C17E0120FFF76BF9002802D014E0C4 +:104500001220F8BD78692030C17E0420FFF760F9E1 +:1045100000280AD1786950210D526030457102207F +:10452000FFF773F97869A03045717869E621095C75 +:10453000002903D1818CC288914200D8C188B981F9 +:1045400001468031CA8B521E93B20A8CD21892B2A5 +:104550000A8494460246A0321479002C02D04D847D +:10456000157102E04C8CE4184C8404464034A78951 +:10457000FF18A7814C8B012C01D8641C4C83002BA5 +:1045800000D015732030C07E0D4C04281ED0507909 +:1045900000281DD0A1898C451AD2FDF712F90028F8 +:1045A00016D060690146C0310A78002A10D08030E8 +:1045B000408C498888420BD3A570E6700AE0000061 +:1045C000C4000020FC3C010081080000A67001E04E +:1045D000A570E5706069A5210D543B21095C062991 +:1045E00001D0072918D1CA21028E095A511A09B2DD +:1045F000002911DB01460522CC310A3001F095FD7E +:10460000012202216069FCF7EEFE6069C9210D54A8 +:104610003B210D546030867160699E210A5A811CCD +:104620003030FCF71EFFA07800283DD16069C02122 +:10463000095C002901D0803045840120FAF7A4FDEF +:1046400060691330FAF713FF60690F30FAF753FE11 +:104650000120FAF71FFF61694020405C002803D168 +:104660003F20405C00280DD00A467831C8C9F9487F +:104670007832D26842632830C8C008220D30091D44 +:1046800001F053FDFAF701FF01210846FAF758FE41 +:1046900060698030806AFAF716FFFEF7A5FF60694F +:1046A0004030007AFAF730FE6571E571A571257228 +:1046B0006572257102202070FAF7FCFE0020F8BD1B +:1046C00010B5E54C2078022801D00C2010BDA07850 +:1046D000002803D00020FFF786FC17E0FAF7DDFE84 +:1046E00000F033F9606920308079012801D1FAF7B0 +:1046F00076FFA07A002809D0012807D0022807D029 +:10470000032805D0D549D64801F08DFE002010BD04 +:10471000EEF77EFCFAE7D0498872704710B5CE4CB0 +:104720002078032804D0CE48CC49293001F07BFE04 +:10473000606901212030827C002A06D00022827428 +:104740000175A27904231A43A271A2691378DB438D +:104750009B0707D1C37C002B04D1C174A07902212F +:104760000843A0711078C00606D4E0690078C0063E +:1047700002D4E07900280CD06078002809D1A07913 +:10478000002806D1FEF75DFC002802D0207A002820 +:1047900003D00120FFF727FC03E0FEF725FF00F020 +:1047A000D4F8207801280DD0A07A00280AD001285A +:1047B00008D0022807D0032805D0A948A7496830A7 +:1047C00001F031FE10BD0120FBF719F810BD10B546 +:1047D000A14C606920308079012812D1FAF7F6FEE9 +:1047E0006169881C3031FCF7C5FE002809D060697A +:1047F000C21D4388F93253812030007E107301209E +:10480000107210BD70B5944C05462078042804D071 +:1048100093489249803001F006FE617910200143EF +:104820006171002D50D0FBF7A8F96178012508438C +:10483000002811D160694021095C00290CD0E16990 +:104840004A78D20608D0097820300907C07DC90F00 +:10485000814201D165724EE0E078002809D0E0691C +:104860004178C90605D10078C00602D4FFF7AFFF32 +:1048700041E0FFF7ACFFE06900784007C10F6069D5 +:104880002030807D814205D0FFF7A7FC60790821A8 +:1048900008436071E06900780007C10F606920304B +:1048A000C07D814201D1FFF7E1FC6079284360714E +:1048B0000020E071A079000704D560692030C07E37 +:1048C000032818D0207A14E0022001436171E079B6 +:1048D000401CC0B2E07101280DD8606940300078FA +:1048E00000280CD05B484078C106C90E052906D2C5 +:1048F000C006002803D00120FFF775FB01E0FEF79A +:10490000BDFD207801280DD0A07A00280AD001280A +:1049100009D0022806D0032805D051484F49E2307B +:1049200001F081FD9FE40120FAF769FF9BE410B5D7 +:1049300049480078042804D049484849EA3001F041 +:1049400072FD0120FFF74FFB10BD10B501210020C3 +:10495000FAF7DBFE40490420087010BD3E494A22A8 +:104960004969505404202031C876704710B53A4C3C +:10497000C8206169405C00281CD0062806D0203180 +:10498000C97E0020FEF724FF002813D0606901468D +:10499000C0310A7A130001F037FE070D0D0D0D0D21 +:1049A0000D050D004030807FC20704D0C043800752 +:1049B00000D1087210BD0C20FEF727FF60690122AC +:1049C0004030817F1143817710BD10B5002A0AD095 +:1049D000002306E0D41A6418203CE47FC4545B1C16 +:1049E000DBB29342F6D310BD7CB51B4C606920301E +:1049F000C17E0020FEF7ECFE0125002802D1207ABE +:104A000028432072207A00281AD16946E069FCF711 +:104A100022FC684600780022C107C90F6846017071 +:104A20006069002902D06030057101E060300271D8 +:104A30006069014640304282857509202031C87680 +:104A40007CBD401A074900B2884201DC00280BDC1B +:104A50000120704790140020C4000020FC3C01009D +:104A6000F4090000FE7F00000020F2E710B5534C6F +:104A700060692030C17E0020FEF7AAFE0028207A5F +:104A800010D000280DD1E069FCF797FB6169CA22BC +:104A90005052098EFFF7D5FF002807D02820FFF7D6 +:104AA0005DFF10BD01210843207210BD6169E069FE +:104AB000CC31FCF77AFB606906212030C17610BD4D +:104AC00010B500F04EF83D4C607940070BD5606999 +:104AD0002030C17E0520FEF77BFE002803D0207A1F +:104AE000082108432072FFF701FA00F018F8FFF7D9 +:104AF00073F8A079C0060FD5207A00280CD1606920 +:104B00002030C17E0B0001F07FFD07070707070774 +:104B1000070507000721C176FEF7F3FF10BD10B5AA +:104B200026488179490715D5017A002912D14069B3 +:104B30003B21095C891E0B0001F066FD07050C0C8A +:104B40000C0D0C0F0C00002256210A54C030807945 +:104B5000FFF704FF10BD012100E00221C0304172C7 +:104B600010BD10B515488179090720D5017A0029B3 +:104B70001DD1406902462032D47EA41E230001F0DC +:104B800043FD13160B1616161616161616161616BF +:104B90001616161616171600562211546030407954 +:104BA000002801D0062000E01620FFF7D7FE10BD38 +:104BB0004030C1768175D17610BD0000C400002060 +:104BC00030B50346002002460DE09C5C2546303D92 +:104BD0000A2D02D30020C04330BD0A256843303877 +:104BE0002018521CD2B28A42EFD330BD70B50D46A8 +:104BF000144608E00A2101F012FB2A193031203A4C +:104C0000641ED177E4B2002CF4D170BD10B500233E +:104C100010E0040A00020443A0B2CC5C4440200629 +:104C2000000F60400407240C44402006C00C604084 +:104C30005B1C9BB29342ECD310BD000010B572B662 +:104C400000F0DCF800280BD0ECF72AFBF8F7EFFDBA +:104C500000F0A5FD6E490020C86288626D490860B9 +:104C600062B6002010BDF3B5002501200007C06A20 +:104C700081B0C0430006000E04D167480068401CA4 +:104C800000D1012572B600F0B9F8002802D062B652 +:104C90000820FEBDECF75AFAECF706FB5F4B604EBE +:104CA00000211A68CA40D2071FD00246CA40D20764 +:104CB00018D14AB2002A07DA1407240F083CA408C6 +:104CC000A400A419E46904E09408564FA400E41970 +:104CD00024689207D20ED4402206920F012A04D0F3 +:104CE000032A02D062B65048FEBD491C2029D8D301 +:104CF0000198030001F088FC14212323232323239C +:104D000023230B0D0F11131F1517191B1D2E002424 +:104D100016E0012414E0022412E0032410E004242D +:104D20000EE008240CE009240AE00A2408E00B2421 +:104D300006E00C2404E0052402E0072400E0062439 +:104D4000F06901210002000AC9070843F061002D43 +:104D500004D009E062B601200003FEBD2C4D3348AB +:104D6000E862ECF7A1FAA8622A49314808603149A3 +:104D700002980860ECF798FA214600F0F7FCF8F783 +:104D80001AFD00F0FDFE00F073FD0198ECF756FAF5 +:104D9000040062B603D0FFF751FF2046FEBD00209D +:104DA000FEBD10B5044600F029F8002800D001200F +:104DB0002070002010BD204908600020704710B509 +:104DC0000C46102808D011280BD012280CD013281C +:104DD0000ED00120086010BD03CC083CFFF743FF54 +:104DE0000AE0FFF72BFF07E02068FFF7DAFF03E098 +:104DF0001149206808600020206010BD05480C495A +:104E00000068884201D101207047002070470000EF +:104E100000050040780000200010001000E100E0D4 +:104E200000ED00E000E400E00110000000190000C7 +:104E3000BEBAFECAE40000200400002010B52038ED +:104E40000C46030001F0E0FB33A6AAAEB2B8BCC02A +:104E5000C5E0DBE41B1F23272C31373C41474D5075 +:104E600054585C606D71656974787C8084888C901E +:104E700094989C9FA2CACFE9F0F3D3D7F80020689A +:104E800000F0DDF8D6E0206800F0E1F8D2E020681C +:104E900000F0F5F8CEE0207840B200F0D7FAC9E093 +:104EA000207840B200F0F5FAC4E02078616840B2A2 +:104EB00000F008FBBEE0207840B200F018FBB9E03B +:104EC000207840B200F023FBB4E02078217940B292 +:104ED00000F02EFBAEE02078616840B200F058FB95 +:104EE000A8E000F064FBA5E0206800F068FBA1E00A +:104EF000207800F07DFB9DE02068F8F72CF899E021 +:104F00002068F8F72CF895E021792068F8F72EF85A +:104F100090E0206800F0E6F98CE0206800F0E7F906 +:104F200088E0207800F0E7F984E000F0F1F981E012 +:104F3000207800F0F3F97DE0207800F005FA79E0C0 +:104F4000206800F01EFA75E0206800F020FA71E099 +:104F5000206800F022FA6DE0206800F023FA69E092 +:104F6000206800F025FA65E0206800F027FA61E08B +:104F7000206800F028FA5DE00846ECF7FFF859E0F9 +:104F8000EDF719FA56E0EDF746FA53E02068EDF731 +:104F90004EFA4FE0206800F0E1F84BE0206800F0A6 +:104FA000E9F847E0206800F0F0F843E02078A268D4 +:104FB000616800F0F5F83DE0207800F006F939E08E +:104FC000207800F017F935E02078616800F027F9C3 +:104FD00030E02078616800F03AF92BE02179207800 +:104FE00000F016FC26E0206800F06BF822E0206854 +:104FF000F8F70CFB1EE02068F8F7F0FA1AE007CC8F +:105000000C3C00F0FFFC15E0206800F052FD11E0C0 +:1050100003CC083C00F07DFD0CE0206800F06EFF42 +:1050200008E009E003E0FFE700F080FF02E020680D +:1050300000F0B8FF206010BD0120086010BD002105 +:105040000170084670470146002008707047EFF372 +:105050001081C907C90F72B60278012A01D0012256 +:1050600000E0002201230370002900D162B6002A6B +:1050700001D000207047012040037047E7E7EFF3BD +:105080001081C907C90F72B600220270002900D131 +:1050900062B600207047F2E710B52848FFF7CFFF4F +:1050A000002803D026A11D2001F0BDF92348401C93 +:1050B000FFF7C5FF002803D021A1212001F0B3F99B +:1050C00010BDF1B5224D6F6801261C48FFF7BFFFE8 +:1050D0001A4C002803D10026601CFFF7D0FF1D4AA0 +:1050E0001D490120506000BF00BF00BF00BF00BFCE +:1050F00000230B604B60009B6B60106000BF00BF23 +:1051000000BF00BF00BF0868002802D1486800281F +:10511000F9D048680028E4D1002E04D06F60601CEC +:10512000FFF795FF07E0601CFFF791FF0028D3D140 +:105130000248FFF7A4FF0020F8BDC2E7E800002006 +:105140007372635C736F635F6563622E630000005C +:1051500000E5004000E0004000E100405A495B4BA0 +:105160000A685B499A42096801D18904890C016087 +:10517000002070475449554B0A6855499A4201D15D +:105180008004800C4860002070474F494F4B0A68EC +:105190004F499A4201D18004800C886000207047FA +:1051A00030B5494B494D1C684A4BAC4202D01028DF +:1051B00002D203E00E2801D3184630BDC300444894 +:1051C000181801614261002030BD3F493F4B0A6819 +:1051D0004049491C9A4202D0042802D203E0022826 +:1051E00001D3084670473C4A0121C0008018016085 +:1051F000002070473449354B0A683649491C9A42A9 +:1052000002D0042802D203E0022801D308467047E6 +:10521000314A0121C000801841600020704770B5FC +:10522000294A2C4B14682D4E284D82005B1C921984 +:10523000AC4203D0042803D2116006E0022801D357 +:10524000184670BD8804800C1060002070BD70B5D9 +:105250001D4A204B1468214E1C4D82005B1C921984 +:10526000AC4203D0042803D2106806E0022801D320 +:10527000184670BD10688004800C0860002070BD66 +:1052800010B5134A164890600E200021C3009B18E9 +:1052900019615961401C1028F8D300200F4A05E01D +:1052A000022803D383009B18196005E083009B1834 +:1052B0001C68A404A40C1C60401C0428F0D310BD7E +:1052C000034907488860704778000020BEBAFECACC +:1052D00000F501400820000000F0014000F8014006 +:1052E00000C0FFFF47490968016000207047454939 +:1052F0000860002070470121434A002803D001289C +:1053000003D042487047916300E0D16300207047AA +:105310003F49012008603D48801C704704223D4BF6 +:105320003B49002805D05A600869012210430861F2 +:1053300008E008694008400008619A60324900208E +:10534000C03188600020704731490622002808D00B +:10535000012809D002280DD003280FD02B48401C6B +:1053600070470869904302E008699043801C086117 +:105370000020704708699043001DF8E70869104352 +:10538000F5E723494A6A02434A62002070472049F0 +:105390004A6A82434A62002070471D49496A016097 +:1053A000002070471A49CA690243CA610020704749 +:1053B0001749CA698243CA61002070471449C96904 +:1053C0000160002070471249024600204031002A47 +:1053D00003D0012A01D0072070478A6370470D4926 +:1053E0000420886008490020C03188600A480168AC +:1053F0008022090A0902114301600849012008605E +:1054000070470000000400404000004004200000FD +:10541000000500400003004000E400E000E100E07F +:105420008107C90E002808DA0007000F0838800835 +:10543000814A80008018C06904E080087F4A8000AB +:1054400080180068C8400006800F704710B50446F9 +:1054500000F0DBF8002813D02046FFF7E1FFC0B2D0 +:1054600000F0E1F800280DD07549E2060B78D20E65 +:1054700001209040002B08D04A681043486006E0A5 +:10548000704810BD6F48401C10BD6F490860002077 +:1054900010BD10B5044600F0B8F800280BD06849DC +:1054A000E2060B78D20E01209040002B05D04A680E +:1054B00082434A6004E0634810BD6349803108605C +:1054C000002010BD70B50D46044600F09EF800287F +:1054D0000BD05E480068E206D20E012191400840E0 +:1054E00000D001202860002070BD564870BD10B566 +:1054F000044600F08AF8002807D0E106C90E012012 +:10550000884052490860002010BD4E4810BD10B5BB +:10551000044600F07AF8002808D0E106C90E012000 +:1055200088404A4980310860002010BD454810BDC0 +:1055300070B50D46044600F068F8002819D02846DA +:1055400000F071F8002816D0A007C10EFF228A4093 +:10555000A807000E8840002C10DA2107090F08392F +:105560008B0835499B005B18D96991430143D96188 +:105570000CE0344870BD3348401C70BDA3082F496F +:105580009B005B181968914301431960002070BDAE +:1055900070B50C46054600F038F8002805D02846BE +:1055A000FFF73EFF2070002070BD264870BDBFF39E +:1055B0004F8F21492648C860BFF34F8FFEE770B573 +:1055C0001F4C05462178012000290ED1207072B6AB +:1055D00000F0F4F81C4E803631688143616000F0C1 +:1055E000EDF8C043306062B600202870002070BD26 +:1055F00013490A78002A06D0002804D1124A4868C4 +:105600001060002008700020704710B50446202864 +:1056100007DA00F0D3F80121A140084201D10120AE +:1056200010BD002010BD012803D0032801D00020A8 +:10563000704701207047000000ED00E000E400E04A +:10564000EC0000200120000000E100E000E200E0AA +:105650000400FA05F8B50446800700250126002855 +:1056600004DA5848C563C66302208443E00404D5C5 +:105670005548C563C66380148443600003D553480E +:10568000456080058443E00504D55148C563C66381 +:1056900080158443A00404D54E48C563C6634014F6 +:1056A000844360042704C00FF90F884203D04AA145 +:1056B000612000F0B8FEB80F0AD04C49CD634C48C9 +:1056C000C563C563CE63C663C6630320800384439A +:1056D00020050AD5474FFD632F20EBF765FDFE63DC +:1056E0002F20EBF761FDF8148443FFF7C9FD424812 +:1056F000044203D038A18D2000F095FEF8BDF0B52E +:1057000000210A46FF230446CC40E4072AD04CB2CD +:10571000E606F60E0125B540384E3560384E356048 +:10572000002C11DA25072D0F083DAE08354DB600C7 +:105730007719FD69A407E60E1C46B440A54314463C +:10574000B4402543FD610DE0A6082F4DB600761943 +:105750003568A407E70E1C46BC40A5431446BC4070 +:1057600025433560491C2029CDD3F0BD70B5274CA9 +:105770000D462060FFF76EFF2068FFF7C0FF284648 +:10578000ECF7EAFEFFF788FCF7F778FBFFF778FD08 +:10579000FFF725FEECF766FD00F06AF870BD10B566 +:1057A0001A4C2068FFF756FF2068FFF7A8FFFFF7A5 +:1057B00067FDECF74BFF0020206010BD1348006828 +:1057C00070470000C01F0040C0CF004000E501400E +:1057D000C08F0040C0DF00407372635C736F635F13 +:1057E000636F6E6669672E6300000000C0EF0040C3 +:1057F000C0FF0040C0BF0040FEFF0FFC80E100E0A2 +:1058000080E200E000ED00E000E400E0F4000020B1 +:1058100070B5002402460D4620462146002A1ED0BF +:10582000012A04D0022A04D0032A1ED103E0012059 +:1058300002E0022013E003202B0000F0E5FE071633 +:105840000507090B0D0F1600012108E0022106E0F3 +:10585000032104E0042102E0052100E00621F8F71D +:1058600058F8002801D0204670BD0724FBE700004F +:10587000B348002101708170704770B5B14D0123AC +:105880006B60B14B1C68002CFCD0002407E00E6854 +:1058900006601E68002EFCD0001D091D641C944289 +:1058A000F5D30020686018680028FCD070BD70B582 +:1058B000A34C0E466178884203D0A4A16F2000F06B +:1058C000B2FD0325330000F09FFE09520624245246 +:1058D0005252524952002078022803D09BA17320D3 +:1058E00000F0A1FD2570A078022802D0012804D084 +:1058F00008E0A06800F0D2FB04E02046083007C8AA +:10590000FFF7BBFF0020A070F7F7A4FF0420207072 +:1059100070BDF8F754F801466068F9F776FA064664 +:105920002078022803D089A1872000F07CFD8B4AD3 +:105930008B498C48964205D86269032A02D2521CD0 +:10594000626102E0864207D84D71801BC8608449BD +:105950006078F8F7B4FC70BD032003E0A07800285D +:10596000FAD10220F7F77EFE00F0E1F870BD77A1D2 +:10597000B12000F058FD70BD70B50546F8F71FF86E +:105980006F4C60602078012803D070A1B82000F02F +:105990004AFD73490220087000220A718D600422BA +:1059A0004A71704ACA6020706078F8F788FC70BD50 +:1059B00010B5634CA078002802D12078002801D0CF +:1059C000112010BD6848F7F78BFF607060780028E1 +:1059D00004D0012020700020606110BD032010BDA4 +:1059E00010B50124020B64040121604BA04202D2D5 +:1059F0009140186802E0203A58689140084000D071 +:105A0000012010BDF8B50E46910005464F19144609 +:105A10003F1F009100F053FB009980028919091F74 +:105A2000B14201D2012200E00022002C03D0FF216C +:105A300001318C4201D90920F8BD4D498D4219D35D +:105A4000AF4217D3854205D2874203D2284630435E +:105A5000800701D01020F8BD8E420BD3002A09D157 +:105A60002846FFF7BDFF002804D13846FFF7B8FFEE +:105A7000002801D00F20F8BD3E483F490068884209 +:105A800005D0224631462846FFF7F7FE0FE0FFF724 +:105A90008FFF0028EFD12A480121C660856004618C +:105AA00081702046302148431830FFF765FF002001 +:105AB000F8BD10B504462E48800A84420BD300F08E +:105AC000FEFAA04201D8102010BDA0020446FFF744 +:105AD00087FF002801D00F2010BD26482649006806 +:105AE000884203D0204600F0D9FA0AE0FFF760FFB1 +:105AF0000028F1D112480221846081701F48FFF70D +:105B00003BFF002010BD1A48010B01208840401EB9 +:105B1000704700B50B460246FFF7F5FF104201D073 +:105B20000F2000BD114802604360002000BD10B589 +:105B3000034C6078F7F728FF00202070A07010BD9C +:105B4000F800002000E5014000E401407372635C4E +:105B5000736F635F666C6173682E6300307500005D +:105B6000E0140020D0FB0100AF5801000006004007 +:105B70000080010078000020BEBAFECA3A5600003C +:105B8000F74805218170002101704170C17081606A +:105B9000704710B5F3490A78022A07D0CA6810186E +:105BA000C860C8689638F9F7E9F810BD8A68101817 +:105BB00088608868F6E70378EB49EC4A002B02D04E +:105BC000012B10D014E00379002B01D0012B0FD151 +:105BD0004379002B01D0012B0AD18368643B8B42AF +:105BE00006D2C06810E00379002B03D0012B01D04E +:105BF000002070474379002B01D0012BF8D1C368F6 +:105C0000643B8B42F4D280689042F1D80120704707 +:105C1000F8B504460226F8F740FD0068002803D0D6 +:105C2000D3A1BD2000F0FFFB0127CD4D002C08D0F3 +:105C30002078002817D0012805D0022811D0032889 +:105C400013D02F710DE06068C82808D3F9F70BF95D +:105C5000002804D06068FFF79CFF012603E00026BF +:105C600001E000F0F9F93046F8BD28780028F8D1B5 +:105C70006068FFF7A0FF0028E3D060680078002884 +:105C800026D0A878042803D0B9A1F72000F0CBFBD8 +:105C9000B44F0020387060680079012800D00020DF +:105CA000387160684079002837D0042078716068C6 +:105CB0008168E868F8F71DF9B8606068C0689630D8 +:105CC000F8600320A870A749E878F8F7F8FAC8E761 +:105CD000A4480221017061680979012919D00021C5 +:105CE000017161684979002915D004214171616809 +:105CF0008968963181606168C968C160C068984CE4 +:105D000014346060F7F75BFE20606F700220A870AB +:105D1000A7E70321E4E70321E8E70320C6E7F8B596 +:105D20008F4C0D46E178884204D0FF2090A11930B5 +:105D300000F079FB28468A4F00250126143703001E +:105D400000F062FC090612375A7C8D97C4A0C4008B +:105D5000A078032807D0A078022804D0FF2084A1CF +:105D60001D3000F060FBF8BDA078032807D0A078B4 +:105D7000022804D0FF207EA1213000F054FB042033 +:105D8000A07025712078002810D1FFF702FFE0787D +:105D9000F8F7D6F8E0607D49886A7D4A02402261C2 +:105DA0007B4AD24310408862002050E000F054F952 +:105DB000F8BDA078032807D0A078022804D0FF20DF +:105DC0006BA1423000F02FFB2078002802D000F0B9 +:105DD0004FF9F8BDA07803281FD104202AE0091A42 +:105DE0006048C1600146E078F8F769FAF8BD042020 +:105DF000F7F738FCA570F8BDA078032807D0A07885 +:105E0000022804D0FF205AA1633000F00CFB207858 +:105E10000028DCD1A07803280BD0F7F7D0FD01468D +:105E20003868F8F7F2FF0028E1DB79688142DEDBB1 +:105E3000D5E70520F7F716FCA670F8BDA078042872 +:105E400004D0FF204AA1843000F0EDFA0220A168BE +:105E50008847FFF7DDFEFF260546BD3642E0A07805 +:105E6000042804D0FF2042A1893000F0DCFA012090 +:105E7000EDE7A078042899D0FF203DA18E3000F0F6 +:105E8000D2FA93E7A07804280AD06078002802D0DC +:105E9000A078022804D0FF2035A1933000F0C3FA87 +:105EA0002078002893D12079002804D00620F7F725 +:105EB000D9FB2571C0E76078002805D02949E07832 +:105EC000F8F7FDF96570F8BD0720B3E7FF2028A1BA +:105ED000AE3046E7002D0AD0012D06D024A1304671 +:105EE00000F0A1FA022DF5D1F8BD042000E0032056 +:105EF000A1688847FFF78CFE0546F3E770B50500FB +:105F000005D0174CA078052803D0112070BD1020B3 +:105F100070BD2048F7F7E4FCE070E078002803D07B +:105F2000A5600020A07070BD032070BD10B50C48A6 +:105F30000178002901D0112010BD817805292BD0CE +:105F4000817801292AD08178002927D00121017088 +:105F50008178012922D0807800281FD020E000001D +:105F600010010020F01400203D860100FF1FA10752 +:105F70007372635C736F635F726164696F5F74698E +:105F80006D65736C6F742E630000000000050040A7 +:105F9000028100001F5D01000F2010BD00F068F8B5 +:105FA000002010BDF8B5394E0446B078002801D065 +:105FB00001280DD1002C0DD02046FFF7FCFD002854 +:105FC0000AD02078324D002808D0B078012823D09C +:105FD0000F20F8BD1020F8BD0720F8BD02272F7054 +:105FE0002079012814D0002028716079002811D070 +:105FF00004206871A0689630A860E068E860E868EE +:10600000224C14346060F7F7DAFC2060B77019E0B6 +:106010000320E9E70320ECE700202870207901281D +:1060200016D0002028716079002813D004206871F0 +:10603000A168F068F7F75DFFA860E0689630E86057 +:106040000320B0701249F078F8F739F90020F8BD54 +:106050000320E7E70320EAE710B50E48816A0E4AFD +:1060600011400A4A126911438162F7F7F3FB10BD30 +:1060700010B5064CE078F7F787FC0820F7F7F2FA3E +:106080000520A07000202070607010BD100100205D +:10609000F014002000050040FD7EFFFF0A4A0221A7 +:1060A00051600A490B68002BFCD0906008680028FA +:1060B000FCD00020506008680028FCD07047012008 +:1060C000000740697047000000E5014000E401401E +:1060D000034610B50B439B070FD1042A0DD308C804 +:1060E00010C9121FA342F8D018BA21BA884201D9A8 +:1060F000012010BD0020C04310BD002A03D0D307EB +:1061000003D0521C07E0002010BD03780C78401C1F +:10611000491C1B1B07D103780C78401C491C1B1B16 +:1061200001D1921EF1D1184610BDF8B5042A2CD326 +:10613000830712D00B78491C0370401C521E830742 +:106140000BD00B78491C0370401C521E830704D0EF +:106150000B78491C0370401C521E8B079B0F05D007 +:10616000C91ADF002023DE1B08C90AE0EBF72CF870 +:10617000F8BD1D4608C9FD401C46B4402C4310C064 +:10618000121F042AF5D2F308C91A521EF0D40B7854 +:10619000491C0370401C521EEAD40B78491C037042 +:1061A000401C012AE4D409780170F8BD01E004C064 +:1061B000091F0429FBD28B0701D50280801CC90767 +:1061C00000D00270704700290BD0C30702D00270C4 +:1061D000401C491E022904D3830702D50280801C7B +:1061E000891EE3E70022EEE70022DFE70378C278AA +:1061F0001946437812061B0219438378C0781B04A2 +:10620000194311430902090A000608437047020AAC +:1062100008704A70020C8A70020ECA707047002221 +:1062200003098B4273D3030A8B4258D3030B8B426F +:106230003CD3030C8B4221D312E003460B437FD4A3 +:10624000002243088B4274D303098B425FD3030AB5 +:106250008B4244D3030B8B4228D3030C8B420DD3C8 +:10626000FF22090212BA030C8B4202D31212090256 +:1062700065D0030B8B4219D300E0090AC30B8B4294 +:1062800001D3CB03C01A5241830B8B4201D38B0342 +:10629000C01A5241430B8B4201D34B03C01A5241E7 +:1062A000030B8B4201D30B03C01A5241C30A8B422A +:1062B00001D3CB02C01A5241830A8B4201D38B0215 +:1062C000C01A5241430A8B4201D34B02C01A5241B9 +:1062D000030A8B4201D30B02C01A5241CDD2C3092B +:1062E0008B4201D3CB01C01A524183098B4201D3A7 +:1062F0008B01C01A524143098B4201D34B01C01A92 +:10630000524103098B4201D30B01C01A5241C30809 +:106310008B4201D3CB00C01A524183088B4201D378 +:106320008B00C01A524143088B4201D34B00C01A64 +:106330005241411A00D201465241104670475DE079 +:10634000CA0F00D04942031000D3404253400022FC +:106350009C4603098B422DD3030A8B4212D3FC22A5 +:10636000890112BA030A8B420CD3890192118B4224 +:1063700008D3890192118B4204D389013AD092113A +:1063800000E08909C3098B4201D3CB01C01A5241F5 +:1063900083098B4201D38B01C01A524143098B42BE +:1063A00001D34B01C01A524103098B4201D30B01A7 +:1063B000C01A5241C3088B4201D3CB00C01A5241CC +:1063C00083088B4201D38B00C01A5241D9D24308B3 +:1063D0008B4201D34B00C01A5241411A00D20146F0 +:1063E000634652415B10104601D34042002B00D55A +:1063F0004942704763465B1000D3404201B500201C +:10640000C046C04602BD70477047704710B500F0E7 +:106410003BF810BD012308CB134B1860134B1960D8 +:10642000134B1A607047134A134B13607246053AB8 +:10643000F0E7114A0F4B1B689A420ED10D4B00201A +:10644000186001980D4B04B598470CBC9E46024657 +:10645000029800990A4B1B68184706980599094B42 +:106460001B68DB6818470000340100203801002059 +:106470003C0100202C010020EFBEADDEC9CD0000A4 +:10648000E4000020040000201D481E497047FFF76B +:10649000FBFFEAF753FE00BD01200007C06AC0B24F +:1064A000FF2804D1184819490968884202D01848C1 +:1064B00018490160184819490968884203D1184AE7 +:1064C00013605B68184700BD20BFFDE71248134901 +:1064D000096888420ED1134B18680B498842F3D0E3 +:1064E00080F308881049884204DD104802680221C0 +:1064F0000A4302600E4880470E4880470E48004716 +:106500000015002000150020FFFFFFFF0010001005 +:106510002C050040080000000010000000000020D2 +:10652000040000200080010000200020240500401D +:10653000DFCD000099640100156401001348704527 +:1065400002D1EFF3098101E0EFF308818869023895 +:106550000078102814DB202810DB2B280BDB0C4ADA +:1065600012680C4B9A4203D1602804DB0A4A104798 +:10657000022008607047094A10470000084A104787 +:10658000084A12682C32126810470000FDFFFFFF16 +:1065900078000020BEBAFECAAD1200003D4E0100D8 +:1065A000BF4D0100040000200D4B0E4908470E4B63 +:1065B0000C4908470D4B0B4908470D4B0949084743 +:1065C0000C4B084908470C4B064908470B4B05493B +:1065D00008470B4B034908470A4B0249084700008C +:1065E00079250000192200009D2B00003F2A0000A1 +:1065F000ED2900009F270000B912000013140000CD +:10660000012B00000F23000030B47446641E25786F +:10661000641CAB4200D21D46635D5B00E31830BCD6 +:10662000184703B5684600784006400E401C884273 +:1066300005D269460878401CC0B208700CBD684697 +:106640000078000601D500200CBD80200CBD414023 +:10665000802901D0002070470120704737B50878A5 +:106660000C4669460978884206D020781146FFF723 +:10667000D8FF207001203EBD00203EBD37B5044646 +:106680000078154669460979FFF7E1FF002801D037 +:1066900000203EBD20782946FFF7C3FF207001206F +:1066A0003EBD0FB568460179007881420AD0684640 +:1066B000007922214006400E4843801818600120CE +:1066C00004B000BD0020FBE77FB5684601791C4699 +:1066D00015460078FFF7BBFF002802D0002004B069 +:1066E00070BD6846007822214006400E484340199C +:1066F00020600120F3E70000FFFFFFFF0000FFFF25 +:106700000100030000000100000000000000000084 +:1067100000000000000000008700000000000000F2 +:10672000000000000000000000000001020304005F +:106730000D0E0F100000000033690000516B0000C7 +:10674000196C0000736C0000C76C00002F6D000016 +:106750008D690000456A0000D16D0000DF790000FE +:10676000100110013A0200001A02000004013C006E +:10677000230044000E0001020408102040805555FB +:1067800055D6BE898E0000007006120DB4130000AD +:1067900014035A06A00900006004F208840DF401F5 +:1067A000FA00960064004B0032001E001400000046 +:1067B000E067010008000020100000000411000044 +:1067C000F0670100180000202801000004110000FB +:1067D0001869010040010020C013000020110000D2 +:1067E0000249022208681042FCD0704700E200E033 +:1067F0000000000000000000000000000000000099 +:106800000000000000000000000000000000000088 +:106810000000000000000000000000000000000078 +:10682000000000000100010054000020FB349B5FC9 +:106830008000008000100000000000000000000048 +:106840000000000000000000000000000000000048 +:106850000000000001000000000000000000000037 +:106860000000000000000000000000000000000028 +:106870000000000000000000000000000000000018 +:106880000000000000000000000000000000000008 +:1068900000000000000000000000000000000000F8 +:1068A00000000000000000000000000000000000E8 +:1068B00000000000000000000000000000000000D8 +:1068C00000000000000000000000000000000000C8 +:1068D00000000000000000000000000000000000B8 +:1068E00000000000000000000000000000000000A8 +:1068F0000000000000000000000000000000000098 +:106900000000000000000000196401000000000009 +:0869100000000000000000007F +:1080000000400020CD3C0200093D02000B3D020073 +:108010000000000000000000000000000000000060 +:108020000000000000000000000000000D3D020004 +:1080300000000000000000000F3D0200113D0200A2 +:10804000133D020089D80100BD3F0200133D02002C +:10805000133D020000000000C9400200133D020071 +:10806000133D0200653D020045440200133D02003D +:10807000133D0200133D0200133D0200133D0200B8 +:10808000133D0200133D0200133D0200133D0200A8 +:10809000133D0200F136020085380200133D020054 +:1080A000133D0200133D020000000000000000002C +:1080B00000000000000000000000000000000000C0 +:1080C000054B0648033310B51B1A062B03D9044B86 +:1080D000002B00D0984710BDC0200020C0200020F9 +:1080E000000000000648074910B5091A8910CB0F97 +:1080F0005918491003D0044B002B00D0984710BDED +:10810000C0200020C02000200000000010B5074C57 +:108110002378002B09D1FFF7D3FF054B002B02D0AA +:10812000044800E000BF0123237010BDD8200020C8 +:1081300000000000B8450300094B10B5002B03D028 +:108140000849094800E000BF08480368002B02D135 +:10815000FFF7C8FF10BD064B002BF9D09847F7E793 +:1081600000000000DC200020B8450300C0200020F3 +:1081700000000000164B002B00D1144B9D464022FE +:1081800092029A1A924600218B460F461348144ACF +:10819000121A1AF0FDFA0F4B002B00D098470E4B25 +:1081A000002B00D098470020002104000D000D484E +:1081B000002802D00C4800E000BF14F081FD200030 +:1081C00029001AF07CF814F065FDC0460000080094 +:1081D000004000200000000000000000C02000203F +:1081E00010290020000000000000000010B504006D +:1081F000034B41600360080017F002F8200010BD37 +:10820000282E030070B50500082001F051FE041E61 +:1082100005D0044B45600360280016F0F1FF2000F4 +:1082200070BDC046282E03001FB50C00416803A88E +:1082300003F0B4F9002362420193009303A90348B9 +:1082400004F07AFC03A816F052FE1FBD1C22002089 +:1082500030B585B00C00416803A8150003F09EF905 +:1082600000236242009303A90195044804F064FCD2 +:1082700003A816F03CFE05B030BDC0461C2200200D +:1082800030B585B00D00416802A8140003F086F9EE +:1082900002A903A816F038FE00230193FF3B220039 +:1082A00003A9009305482B0004F002FD03A816F073 +:1082B0001EFE02A816F01BFE05B030BD1C220020D9 +:1082C00010B50AB2FF2301B2014803F07FF910BDD7 +:1082D00090220020F8B5FF2304000D00161E9E42D8 +:1082E0000CDC00239A4209DDFF339A4206D0094F85 +:1082F000380017F035FD012807D133002AB2DBB270 +:1083000021B2054803F062F9F8BD0121380017F0E9 +:1083100009FDF2E71C2200209022002010B50AB2CD +:10832000002301B2014803F051F910BD9022002052 +:1083300010B50AB201B2034803F05EF9C317181A68 +:10834000C00F10BD9022002010B5024817F00AFDA2 +:1083500010BDC0461C22002010B50100014804F0E9 +:10836000D5FC10BD1C22002010B5024804F02CFBE7 +:1083700010BDC0461C22002010B5C1B2014817F044 +:10838000D1FC10BD1C22002010B5024817F0E8FCFB +:1083900010BDC0461C220020030010B50448002B6D +:1083A00002D017F023FD01E017F025FD10BDC046F7 +:1083B0001C22002037B50C4901A817F026FD01A8A2 +:1083C00003F0FCF8050001A816F091FD082001F06B +:1083D0006FFD041E02D02900FFF708FF280016F0E9 +:1083E00019FF20003EBDC0461C220020F8B5040045 +:1083F0000E00082809D1E425134F6D007859036851 +:10840000DB699847022819DD03E00300093B012BD3 +:1084100006D93200102321001B2002F025F8F8BDF8 +:10842000E425094F6D0078590368DB6998470528F2 +:10843000EFDC7859082103689B6903E0042178592F +:1084400003689B699847E4E72C210020E423064A4F +:108450005B0010B50400D05816F0DBFF001B434250 +:108460005841C0B210BDC0462C210020030010B5F9 +:108470000948012B02D0022B03D1084816F0D7FF80 +:1084800005E000201A2B05D1054817F0E9FF431E2F +:108490009841C0B210BDC04694220020BC220020EA +:1084A000E4220020F7B5E422214B5200985816F040 +:1084B00081FF0FF07DFCE4221D4B52000400985810 +:1084C0000D0016F07EFF0FF073FCE422184B5200F3 +:1084D000060098580F0016F07BFF0FF069FC220091 +:1084E000009001912B00200029000EF03DFE32008B +:1084F0003B0004000D00300039000EF035FE020094 +:108500000B00200029000DF0DFFE009A019B0D00FA +:108510000400190010000EF027FE02000B002000DE +:1085200029000DF0D1FE11F031F90FF00BFCFEBD6A +:108530002C210020030010B50020032B1BD81800AD +:108540000CF0ECFC02091017E4230B4A5B00D05836 +:1085500016F030FF0FE0E423074A5B00D05816F016 +:1085600030FF08E0E423044A5B00D05816F030FFE7 +:1085700001E0FFF797FF10BD2C21002010B5024845 +:1085800017F04FFC10BDC0461C220020E62310B59A +:10859000024A5B00D05803F071FE10BD2C21002070 +:1085A00010B5024818F07EF910BDC0460C2300201B +:1085B00010B5002808D001280DD1E423074A5B003C +:1085C000D05803F0C1FB07E0E423044A5B00D05815 +:1085D00003F0A4FB00E0002010BDC0462C210020C9 +:1085E00070B5E624134D64000600285916F08CFF80 +:1085F000002802D1285903F043FD0020032E17D88C +:1086000030000CF08BFC02060A0E285916F0EFFF22 +:108610000AE0285916F0F2FF06E0285916F0F5FF97 +:1086200002E0285916F0A6FFFA2189000CF00AFD95 +:1086300070BDC0462C210020E62310B5024A5B0025 +:10864000D05803F01DFD10BD2C210020E423044A66 +:108650005B0010B50100D05802689269904710BDC8 +:108660002C21002013B50423C25E811D684602F050 +:1086700037FF02236A4601A8084905F051FD019819 +:108680000223C15E043014F0ABFF040001A816F011 +:1086900071FB684616F06EFB200016BD30210020ED +:1086A00013B50E4C200017F0FDFF021E05D101008E +:1086B0000B4814F095FF04000EE00023210001A8F0 +:1086C00018F033F801980223C15E043014F088FFDB +:1086D000040001A816F04EFB200016BD302100203A +:1086E0006442030037B50D000423C25E811D01A85A +:1086F00002F0F6FE094C01A90022200005F042FB21 +:1087000001A816F037FB2A0010230121202001F0D8 +:10871000ABFE0021200005F081FC37BD3021002098 +:1087200007B500280DD00423C25E811D01A802F008 +:10873000D7FE022201A9034817F0EEFF01A816F0A8 +:1087400019FB07BD3021002010B5002806D001001C +:10875000426808310223024805F0F0FB10BDC04614 +:108760003021002070B5051E00DC402529000020C6 +:1087700000F0CEF8060008364268310004000223FB +:10878000054805F06DFC0100854203D0300000F083 +:10879000BFF80400200070BD302100200C4B10B544 +:1087A0000C00984206D00B4B984207D119230B704E +:1087B000183B0AE018230B70173B06E000F0DEFEC2 +:1087C000031E02D0837B23700123180010BDC04616 +:1087D000E9030000EA030000F0B585B002AB9E1D7E +:1087E0000F0031000192FFF7D9FF0C4C002807D091 +:1087F00002ABDD1D29003800FFF7D0FF002805D1AE +:108800000199200005F03EFA05B0F0BD00220021DC +:10881000AA567156200005F087FDF1E730210020AF +:1088200010B5064C19221821200005F07DFDE1212C +:108830002000490205F026FA10BDC0463021002074 +:1088400010B50100014805F053FD10BD3021002096 +:1088500010B50100014805F0D1FA10BD302100200B +:1088600010B5034B0A000100186814F0AAFE10BDF1 +:10887000F4200020F7B50700134E009135680192EF +:10888000002D0BD06B68BB4203D1AB68009A9342BA +:1088900001D02D68F4E7019BEB6014E0102019F083 +:1088A00022FF04001022290019F072FF2000336813 +:1088B0000C302360009B0121A360019B6760E36093 +:1088C00001F0CAFB3460F7BDF420002070B506004B +:1088D0000D1E02DA19F09CFF05000B48002D12D086 +:1088E000E81D01F0E5FA041E01D0084B0360A580E5 +:1088F000002E04D0A01D2A00310019F02BFF002308 +:1089000020006519AB7170BDDC2E0300702F0300D1 +:1089100070B506000D1E0B4813DD0800083001F08D +:10892000C7FA041E01D0084B0360200065600830C0 +:108930002A00311E02D019F00DFF01E019F028FFC6 +:10894000200070BDA02E0300AC2E0300014B186068 +:108950007047C04604200020F7B5050001260F49E6 +:108960000B6801912C000020DF0FBC4661469F0977 +:108970004F405F4019095A084F409B087B405340C5 +:10898000DB0713431A004000324010436408EBD168 +:108990008542E7D3019A1360FEBDC0460420002043 +:1089A00000487047DC2E0300F7B504000D000028D6 +:1089B0000AD0154B002922D008009C4223D0124B2C +:1089C00020009D4204D11EE0104C0029F7D1250063 +:1089D000A688AF880020F119FFF778FF030006335F +:1089E0000090A11D32001800019319F0B3FE019B05 +:1089F000A91D98193A0019F0ADFE009803E0034D47 +:108A000028009C42E4D1FEBDDC2E0300582E03005A +:108A1000F0B5040085B002912378202B01D10134F8 +:108A2000FAE72B3B5A425341E41823782D2B03D10C +:108A300001340022394B01E00022394B00920193AE +:108A40002378302B04D1202263781343782B03D072 +:108A50000025002600272BE010220299200014F0A8 +:108A600035FA0FF0A5F9009A019B4DE01A00303A53 +:108A70000392092A20D800222A4B300039000EF038 +:108A800073FB06000F0003980FF092F932003B00D1 +:108A90000DF01AFC06000F00002D08D00098019977 +:108AA0000022204B0DF03CFF009001910125013484 +:108AB0002378002BDAD10EE0002D01D12E2BF5D03A +:108AC00020229343452B06D02378202B01D101345B +:108AD000FAE7002B1ED1009801993B0032000EF0FE +:108AE00043FB237806000F00002B10D00A220299C6 +:108AF000601C14F0EBF90B49020000200CF026FC7E +:108B000002000B00300039000EF02EFB04E0029B47 +:108B10001C6001E00020044905B0F0BD0000F0BF7A +:108B20000000F03F000024400000F87F70B50B000B +:108B300004000D48002A15DDA588002903DA6B180A +:108B4000D943C9170B40E91A8A4203DB06480029BA +:108B500001DC07E0110000209D4201D90634E01835 +:108B6000FFF7B4FE70BDC046DC2E030070B50A00EE +:108B700005000C000600002902D10120002D4CD078 +:108B8000630026495B0D59181D2908D91E2931D1CA +:108B9000002E2FD1224B9A422CD122483DE014299D +:108BA0000EDC002E26D120481B182000984021D131 +:108BB0008020E302000618431F23591AC84010E022 +:108BC0001A481B182800984014D18020E3020006A0 +:108BD00018431F235B1AD8403423591A2B00CB406B +:108BE00018430123002A02DA4042984000E0400086 +:108BF000184312D123002A00280021000FF082F828 +:108C000003000E20002B08D1023801F051F9002892 +:108C100001D0074B03604560846070BD01FCFFFF1D +:108C20000000D0C1010000800DFCFFFFEDFBFFFF45 +:108C3000002F0300F0B5851D85B0060003A92800AC +:108C4000FFF7E6FE0400B088039B28180F0083425C +:108C50003AD10022002320000CF0F0FA002835D190 +:108C600001236A46D37101227E00760852421A4BD4 +:108C7000200031000FF046F800280AD10122164BDF +:108C80005242200031000CF0F3FA002801D16B466B +:108C9000D871802300225B032000310001250FF0F2 +:108CA00031F8002809D1802300225B032000310025 +:108CB0000CF0CAFA002800D1051C01235D406B4668 +:108CC000DB79EDB2AB4201D30024044F2000390020 +:108CD000FFF74CFF05B0F0BDFFFFEF7F0000F87F0E +:108CE00010B514F0FBFC041E05480E2C07D0E3075A +:108CF00002D4044801F0B4FA601014F075FC10BD01 +:108D0000DC2E030071030000064B10B5984203D817 +:108D100001234000184303E00FF08CF8FFF726FF13 +:108D200010BDC046FFFFFF3FF0B5002385B0140023 +:108D3000002206000D000CF087FA002805D02D2334 +:108D4000237080231B06ED1801340022002330001D +:108D500029000CF073FA002802D0302323707BE046 +:108D60003000290010F018FC0EF0ECFF3C4A070020 +:108D70003C4B300029000CF085FA00281AD03A4A02 +:108D80003A4B300029000CF05FFA002812D0002F77 +:108D900020DD3A00002036490CF0D8FA0B00020022 +:108DA000290030000DF0BCFD7B1C06000D00019376 +:108DB000012712E03A0000202D490CF0C7FA0B0001 +:108DC0000200290030000DF0ABFD012306000D006C +:108DD000019302E001231F00019300230293290065 +:108DE00030000EF0AFFF03003033237003900EF01D +:108DF000DFFF02000B00300029000EF02FFC1C4B9F +:108E000000220EF0B1F9019B0600013B0D00019319 +:108E1000002B01D0013402E02E2363700234039B47 +:108E2000029A1343DAD0130001330293102BD6DDDC +:108E3000019B002BD3DC013C2378302BFBD02E3B55 +:108E40005A425341E41A012F06D06523A11C6370D6 +:108E5000380001F001FD01E00023637005B0F0BDB2 +:108E60008DEDB5A0F7C6B03E50EFE2D6E41A4B4404 +:108E700000002440012070B54042FFF76DFD040062 +:108E80000D48FFF769FD060020000EF0D3FF002219 +:108E90000A4B0EF069F9040030000D000EF0CAFF15 +:108EA000074A084B0DF03CFD02000B002000290092 +:108EB0000DF00AFA70BDC046FFFFFF000000F03D54 +:108EC0000000E0DFFFFF6F43024B1B68588CC000BF +:108ED0007047C04608210020134B70B51B68060080 +:108EE0005A6A0D00002399005458B44203D101334B +:108EF0009B009B5816E0002C01D00233F3E714F0DE +:108F00004AFC2B0000280DD023009A00825896427C +:108F100003D101339B001B5804E0002A01D0023327 +:108F2000F3E72B00180070BD0821002070B5050084 +:108F30000C00160000290CDB8388994209DAA40092 +:108F40002C19E368002B09D00B21064815F015FCFD +:108F500004E00A21034815F010FCF0E72800E66061 +:108F600070BDC04686030000031E03D0024A904233 +:108F700000D1002318007047DC2E03001C4BF7B50E +:108F80001B680600DA6A131D0193136852685D1EA0 +:108F9000904215D3174A9B18019A9B009B58984200 +:108FA0000ED8002358194008019982005258964261 +:108FB0001CD003D9431C9D42F4D216E0451EFAE7AB +:108FC00000277C196408019AA3003100985814F016 +:108FD00015FB002801D1200008E0002803DA671CF7 +:108FE000AF42EED901E0651EFAE70020FEBDC046A3 +:108FF00008210020FFFFFF3F044B10B51B68013123 +:10900000DB6A8900C95814F0E7FB10BD0821002075 +:10901000044B10B51B680131DB6A8900C95814F094 +:10902000EAFB10BD08210020014B18687047C046BC +:109030000421002010B5040014F0BBFA002808D069 +:10904000201E1CD0012302201C4218D10E2C09D155 +:1090500015E00122236804209343DA78F92A0ED11F +:1090600098780CE01800422C09D018000A2C06D081 +:109070000420062C03D0024801F0F2F8042010BDB1 +:109080002103000010B5041E0E2C19D0002817D0A3 +:1090900014F08FFA002805D0200000F017F80EF029 +:1090A00087FE0FE02000FFF7C5FF022802D16068AD +:1090B000A16807E0032803D12000FFF7BBFDE2E72A +:1090C0000020014910BDC0460000F87FF7B501241B +:1090D000204201D020415CE0830703D58011431E6C +:1090E000984156E0002801D1002052E0FFF7CAFF66 +:1090F0006B46060001224D006D080F00DC715242E4 +:10910000244B300029000EF0FDFD00280AD1012279 +:10911000204B5242300029000CF0AAF8002801D15F +:109120006B46D871802300225B03300029000124A4 +:109130000EF0E8FD002809D1802300225B033000F7 +:1091400029000CF081F8002800D1041C01235C40A8 +:109150006B46DB79E4B2A342C6D2300039000FF08F +:1091600097FE00220C4B10F027F900220023040088 +:109170000D000CF069F8002807D02000290000221B +:10918000054B0DF0A1F804000D00200029000CF0A3 +:109190003BF9FEBDFFFFEF7F0000F04110B5FFF788 +:1091A00071FF0022034B0DF08FF80FF0A9FAFFF7C3 +:1091B000DDFC10BD0000E03F70B5040014F0F9F9CB +:1091C00000280BD00A2C29D0002C27D00E2C25D01B +:1091D000062C23D0601E441EA04120E02000FFF793 +:1091E00029FF032803D10E4B9C4215D116E002281B +:1091F00012D12000FFF746FF02000B0004000D0013 +:109200000EF080FD002809D1002200232000290053 +:109210000CF014F8002801D1012000E0002070BDFE +:10922000DC2E030070B590B00400FFF703FF0300CD +:109230002000032B55D0022B40D1E30704D560104A +:10924000694601F009FB33E00E2C01D1264848E0C5 +:109250002000FFF717FF01224E0076080D00524252 +:10926000224B310004000EF04DFD002813D10122E5 +:109270001E4B5242200031000BF0F0FF00280AD1B3 +:1092800000230022200029000BF0DEFF031E1848F7 +:1092900027D1184825E022002B00200029000EF0DD +:1092A00031FD0028D2D16A4620002900FFF73CFD9D +:1092B000012168464942FFF709FB12E00E48052BE1 +:1092C0000FD00E48002C0CD00D480A2C09D00648AF +:1092D0000E2C06D00B48422C03D00B48062C00D095 +:1092E0000A4810B070BDC046A02F0300FFFFEF7FFB +:1092F000642E0300F02E0300CC2F0300402F030048 +:10930000E42E0300742E0300582E0300302F0300B8 +:1093100010B50400FFF78EFE042812D1200014F0CF +:1093200048F9002810D1012322689A431300DB8AF0 +:10933000928A1B041343054A934205D020009847A4 +:1093400002E02000FFF76EFF10BDC0461193010040 +:1093500010B5FFF76FFE05280ED80BF0DFFD1203E6 +:109360000507090B08480DE008480BE0084809E02C +:10937000084807E0084805E0084800F071FF0020B1 +:1093800000E0074810BDC046BC2F0300602F03005B +:10939000AC2F0300502F0300902E03002203000087 +:1093A000802E030010B5062805D0FFF743FEF523F5 +:1093B0009B00C01800E0024800F052FF10BDC046FC +:1093C000DD03000070B50400436800205900FFF77A +:1093D0007DFA0F262200094D6168131B0132994264 +:1093E0000ADDD1795B000911695CC3189971D179E3 +:1093F0003140695CD971EFE770BDC046043E03009F +:1094000070B50E4C200004F087FA051E03D02B2007 +:1094100001F09CFA0FE00A4E3378002B0BD100F0DC +:1094200063FAC1B2200004F063FA0621200004F0C0 +:10943000D3F901233370280070BDC0467824002082 +:109440003628002030B587B004000D00FFF7D8FFA4 +:10945000031E0ED1AAB2A1B202A815F025FD082262 +:1094600004A9684619F076F9029A039B024817F09E +:10947000C7F807B030BDC0469824002037B5FFF7C5 +:10948000BFFF002802D00021080014E00B4901A80A +:1094900004F054FB0A4C01A9200015F07EFE01A83F +:1094A00015F03AFE200015F09BFE0500200015F097 +:1094B0009AFE01002800FFF72BFA3EBD9024002001 +:1094C000F820002010B50400FFF79AFF002807D10C +:1094D000002C05D0210062680831024804F04EFBE0 +:1094E00010BDC0469024002037B5FFF789FF011E4C +:1094F00001D0002010E001A815F040FE074C01A9A2 +:10950000200015F059FE050001A815F005FE002DFC +:10951000EFD1200015F06AFE3EBDC046F8200020C5 +:1095200010B50400FFF76CFF002803D1E1B2024838 +:1095300004F0DEF910BDC0467824002010B5040008 +:10954000FFF75EFF002803D12100024804F044F930 +:1095500010BDC0467824002010B5054C200015F041 +:1095600004FE044A0449200019F0B6F810BDC046B4 +:10957000F82000200020002019F10200C31F002065 +:10958000122B02D8014A9B0098587047E02F030025 +:10959000014B98687047C046C020002010B50C00F1 +:1095A000FFF7ECFF002805D0FA22034BD200210080 +:1095B00004F048F810BDC046DC05000010B5FFF708 +:1095C000DDFF014B186010BD0021002070B5154C67 +:1095D000060023680D00002B02D10720FFF7EEFFE5 +:1095E000002E04DC0021206803F09AFF0CE08021AB +:1095F0002068890003F094FF31000B480BF022FD36 +:109600000100206804F04AF8002D09DD280001F06F +:1096100009FD0021206803F083FF052018F048FFB2 +:1096200070BDC0460021002040420F00F7B5040085 +:1096300008000E00170014F049FF02000500009713 +:10964000330008326100024803F06AFB2800FEBDC7 +:10965000E4210020130007B50A00400000934B6886 +:1096600008320100014803F06BFB0EBDE42100202D +:1096700037B5094C2368002B0CD11C2019F033F8A6 +:10968000012305005B4200931622183315210AF0CE +:1096900099FA256020683EBDFC200020F0B5164CEC +:1096A0000700206885B00D001600002804D003686C +:1096B0009B689847002323603800FFF75FFF837B98 +:1096C00028000393FFF75AFF857B3000FFF756FF12 +:1096D000867B1C2019F007F8694607000120097BEA +:1096E0004042009073B26AB249B238000AF06AFA96 +:1096F000276005B0F0BDC046FC200020024B4000B2 +:109700001B6818187047C04608210020030010B5D8 +:109710000420002B11D058003F2B0EDD074A934246 +:1097200005DC0520032158430BF08CFC05E0581C98 +:10973000034BFF30984200D9024810BDFF010000E2 +:10974000FEFF0000FFFF0000012370B50A6805005E +:109750009A4313890E00042B02D00D4800F080FDBF +:109760003000002D12D0A8000C3000F0A1FB041E28 +:1097700001D0084B03602000B368AAB2A580A360A3 +:1097800092000C30002119F003F8200070BDC04693 +:10979000850300005C3003000B4B026970B50500C7 +:1097A0009A4203D0E220800000F05AFD288800F0A1 +:1097B0007FFB041E00D005602A88201D043A00218A +:1097C00018F0E6FF200070BDE3E502001C4BF7B582 +:1097D00005000E1E9E4232D8C488A14223D9200023 +:1097E000FFF794FF071EB74200DA3700B80001F018 +:1097F0003DFDA30000900193002C03D01A002968BE +:1098000018F0A8FF0099019B8C463A1B634418008E +:109810009200002118F0BCFF286801F05DFD009B5C +:10982000EF802B600AE08288914207D22B68521A9F +:10983000880092001818002118F0AAFFAE80F7BD2A +:10984000FFFF0000084B70B505000C0016009942A0 +:1098500008D88388994202D30131FFF7B7FF2B68FC +:10986000A400E65070BDC046FEFF0000C38870B57E +:1098700005000C0016008B4206D8084B99420BD805 +:10988000013189B214F0CEFE2A68A3009E50AB8845 +:109890009C4201D30134AC8070BDC046FEFF000085 +:1098A000034B036000234360038143817047C0463C +:1098B0002C300300024B0360002343607047C04616 +:1098C0008C300300044B0360002343600381438119 +:1098D000C360038243827047BC300300014B1B68A6 +:1098E0001869704708210020014B1B689869704770 +:1098F00008210020014B1B68188C704708210020AC +:10990000F8B50268164B06009A4200D0FEE743689D +:10991000144D188C2B60800014F0B6FF04002B68E7 +:10992000114F1A8C00219200386018F031FF276027 +:109930002C680E4B22689A4203D1B36822699A427E +:1099400000D0FEE700F0D4FC2B6820001C6B002345 +:1099500040301A001900A04715F01CF8F8BDC046A9 +:10996000104200000821002004210020708E3B924C +:1099700010B50248FFF7C4FF10BDC04640290300E0 +:1099800070B506000C2000F093FA041E05D00D4BB4 +:1099900003600023436003814381300014F001FE23 +:1099A000094B98420BD13589002D08D0201D290084 +:1099B00014F064FEAA007168606818F0CBFE200005 +:1099C00070BDC0462C300300BC300300014B5888EA +:1099D0007047C046C0200020014B98687047C046C1 +:1099E000C0200020074B1B68002B09D01A0008324A +:1099F0008242F8D8596852189042F4D2012000E00F +:109A00001800704714210020032370B50468050076 +:109A10009C43A30F002C03D10C4800F021FC04E070 +:109A2000002B02D02503AD0B03E02800E369984723 +:109A30000500002D04D0064B9D4205D9002C03DB08 +:109A4000D420800000F00CFC280070BD5103000001 +:109A5000CA080000104A70B59188060001391068E4 +:109A60008B00C3180D0010006A1C0FD01C00043BB3 +:109A70005A68B24208D18D4202D114F0C5FD09E006 +:109A800014F0C2FD206005E0013DEDE7D22080002A +:109A900000F0E6FB70BDC0460C210020802010B510 +:109AA000400001F0E3FBF82343600F4B83600F4B52 +:109AB0001A68C260020008321A6000230C4A8361EF +:109AC0001368002B01D0984205D20360106007E0B4 +:109AD000904203D313001A68002AF9D1026018607B +:109AE000044B4630186010BDF8000080282100208B +:109AF000142100201C21002010B5041F2368DB075F +:109B000002D5084800F0ACFB2000FFF76BFF0028EF +:109B100002D1044800F0A4FB012322681343236010 +:109B200010BDC0464F03000010B5040014F065FEE0 +:109B3000002816D123680B4A134212D1DB78F92B87 +:109B40000FD12000FFF74EFF002802D1064800F099 +:109B500087FB01232268210013432360034814F08C +:109B600057FE10BD030000404F03000020210020DD +:109B7000F8B506000F000025BD421FD0AB00F45819 +:109B8000200014F03AFE002816D123680C4A134234 +:109B900012D1DB78F92B0FD12000FFF723FF00282B +:109BA00002D1084800F05CFB012322682100134326 +:109BB0002360054814F02CFE0135DDE7F8BDC046F2 +:109BC000030000404F0300002021002010B50400D6 +:109BD00014F013FE002827D12368144A134223D11E +:109BE000DB78F92B20D12000FFF7FCFE002802D102 +:109BF0000F4800F035FB012223681A43226003223C +:109C000093439B69002B01D0200098470324094807 +:109C10008388002B08D014F0F7FC0368A3439B69EA +:109C2000002BF4D09847F2E710BDC0460300004077 +:109C30004F0300002021002070B5050001F016FB45 +:109C4000083D04004560AB0703D0D220800000F03F +:109C500007FB80222000636812061A43A2600D4AA7 +:109C6000083011681060E1600B490A68002A01D0D1 +:109C7000944205D222600C6007E08C4203D30A00B4 +:109C800011680029F9D121601460044A9B08C318A7 +:109C9000136070BD28210020142100201C21002009 +:109CA000F0B56F4C87B0237806009B0703D5D22010 +:109CB000800000F0D5FA0222237801251343237097 +:109CC0000024684B1A689F880192A7420ED9019A16 +:109CD000A300D058284205D00300AB4358881A8807 +:109CE00000041043FFF772FF0134EEE7300000F08C +:109CF00029FB5D4E3368002B11D05C4B1B685C8DDB +:109D0000FFF7F8FD33680026051BA4001C19B542B7 +:109D100005D0B300E058FFF759FF0136F7E70024FC +:109D2000534B1D68534B1E78A64205D9A300E85833 +:109D3000FFF74CFF0134F7E700231F004E4A019361 +:109D400013604E4A02931668002E61D03400736887 +:109D500008349B089A00A2180492FF18049BA3429F +:109D600054D901222368134203D11A0F2500062A71 +:109D70001BD10122934323602000FFF745FE85009D +:109D800065192C00EAE7012213421CD11A0F062A9A +:109D900019D08022D20513420BD02800FFF734FEE1 +:109DA000049B80002D18AB420DD92B68002BEADAFA +:109DB000F3E7DB78F92B02D0314800F051FA2800A4 +:109DC00014F012FCE9E72B1B9B100393039A019BF1 +:109DD00094466344019393001A00FF2120000593E9 +:109DE00018F0D6FC8023059A1B0613432360039BBF +:109DF000012BC6DD00236360029B002B02D11E4BAA +:109E00001C6001E0029B5C600294BAE736689BE745 +:109E10001C490B68002B13D0019B9C08164B1A6839 +:109E20003300002A0CD010680003800B1B189C42E2 +:109E300004D21B1B9B00D3180B6001E05268F0E7B3 +:109E40000A21019ABB0092004A43934201D3FFF7D3 +:109E500025FE0221024A13788B43137007B0F0BD30 +:109E6000372800200C210020042100200821002098 +:109E7000182100203828002028210020142100204B +:109E8000490300001C21002070B5041F2368050051 +:109E90005B0F032B02D0054800F0E2F98023226813 +:109EA0001B0613432800236070BDC0464903000011 +:109EB000F0B5C31C9B1085B00293404B984202DD65 +:109EC000162000F0CDF93E4B3E4E5B68DB0569D1B4 +:109ED0003378DB0766D4012233781343337000F004 +:109EE00023FA002805D04368002B02D1364800F041 +:109EF000B7F900270022354B01921D680393002D0E +:109F00003FD0002F03D1324B1B689D423BD8280025 +:109F100014F073FC002802D02E4800F0A1F92C6840 +:109F2000002C02DB2C4800F09BF9029B2403A40BBD +:109F3000E41A6B6822D40BD08020029AA100920010 +:109F40000006AA1801431160012C01D053601300D0 +:109F5000019A002A01D0536001E0039A13600022A5 +:109F60002A60934222D05B6893421FD01B0D93421C +:109F70001CD1D420800000F073F917E001951D007A +:109F8000BDE7002F03D10020FFF78AFE08E0012F74 +:109F900002D1FFF783FD03E0D320800000F060F9D9 +:109FA0000137A7E70D4800F05BF994E7012228008C +:109FB00033789343337005B0F0BDC04628230000CA +:109FC00000ED00E0372800204E030000282100208B +:109FD0001C210020510300004B03000092030000ED +:109FE000184B70B55B6806000D00DB0502D0164803 +:109FF00000F036F900F098F9144B04001D60144B82 +:10A00000751BAD101D701D0000280AD00C2014F027 +:10A010003BFC63680360A3684360E3688360E060BF +:10A020000AE0102014F030FC0A4B04001B680360A7 +:10A030000023C36000F080F90023A6602B7020008D +:10A04000636070BD00ED00E0920300001821002065 +:10A05000382800200421002070B50C1E0ED00129E4 +:10A0600007DD013C0AD3051D0121FFF7F5FF28009C +:10A07000F7E701210143024814F0CAFB70BDC04656 +:10A080000C21002010B5040014F0B7FB002803D108 +:10A090002100024814F0BCFB10BDC0460C2100207A +:10A0A0000023044A13609380D380034A1360938093 +:10A0B000D38070470C210020202100201FB50C0008 +:10A0C000010003A801F06AFA002203A9009213001C +:10A0D0000194034802F030FD03A814F008FF1FBDEF +:10A0E0001C22002037B50C1E00DC0124124D002874 +:10A0F00002D08288002A07D1280015F081FE0520B1 +:10A10000604300F08FFF15E0012A0DD0811D12B2CF +:10A1100001A801F0E5F9220001A9280002F068FD7C +:10A1200001A814F027FE05E005228179624328008A +:10A1300002F0E0FC37BDC0461C22002010B50248EA +:10A1400014F0F9FE10BDC046902200201FB50C008F +:10A15000010003A801F022FA0023220001930093DA +:10A1600003A90533034802F0A3FD03A814F0BFFEC2 +:10A170001FBDC0461C2200201FB5010002A801F02F +:10A180000DFA02A903A814F0BFFE002203A9019250 +:10A1900000921300054802F0CFFC03A814F0A7FEBC +:10A1A00002A814F0A4FE05B000BDC0461C22002089 +:10A1B000034B10B51B681C6B00231A00A04710BD91 +:10A1C00008210020044B10B51B681C6B00231A00EB +:10A1D0001900A04710BDC046082100207FB505002A +:10A1E00000902D0C0191029284B2102269460F4812 +:10A1F000039318F0AFFA29002000FEF731FB0600A8 +:10A20000280013F051FA0500002E03D00100F06879 +:10A21000FFF7CEFF00212000FEF722FB002803D02D +:10A220002900C068FFF7C4FF7FBDC046C0200020E2 +:10A2300010B50A00010003480223043003F07EFE3B +:10A2400010BDC0462C21002010B50400034B036054 +:10A25000403014F08FFD200010BDC046F4300300E4 +:10A2600010B50400034818F018F9200000F06EFB48 +:10A2700010BDC046E093040010B500F045FC09484D +:10A2800000F018FCFEF762FB012000F0DDFF064B3A +:10A29000984206D9012000F0D7FF044BC018FFF701 +:10A2A000CBFC10BDFFFFFF7F0404000000FCFFFF9C +:10A2B00010B5041E06D0FFF7E5FE034A210003484F +:10A2C00014F053FC10BDC046A9EB02006FE9020078 +:10A2D00010B5041E06D0FFF7D5FE034A210003483F +:10A2E00014F043FC10BDC04663E90200C5A10100A3 +:10A2F00010B5044800F09EF9042000F021FBFFF7A0 +:10A30000BBFF10BD2C210020054B10B51C68FEF7CB +:10A31000DBFD044BE4182018800A800210BDC04603 +:10A3200008210020FF030000024B1B68181E00D00C +:10A33000D86D7047B0240020014B1B68D86570476A +:10A34000B0240020F0B5264B87B01A680393002A8A +:10A3500005D1012000F08AFF059005983BE0002020 +:10A3600000F034FC0090800000F080FF019000F0CD +:10A370002DFC009B834203D0CB208000FFF770FFB1 +:10A380000027009B9F4225DA019ABB00D458E36D59 +:10A390001E1D002B04D10137F3E7B668002EFAD05A +:10A3A000039B35681A68944203D0636CE16B5B1AB7 +:10A3B000ED1873680293944205D0E26B636C9B1AAC +:10A3C000029AD3180293029B9D42E6D201CDFFF779 +:10A3D000FDFBF8E7019800F07FFF07B0F0BDC04635 +:10A3E000B024002010B5064C200000F06BF8054AA0 +:10A3F0000549200018F070F9044814F04AFD10BD1A +:10A400002C2100200020002011A40100C0200020E9 +:10A41000CA23144A9B0010B5C2501C330400C01854 +:10A4200014F0A8FCD0239B00E01814F0A3FC20003B +:10A430009130FF3001F09EFC20006930FF3001F0C8 +:10A4400099FC2000F03002F0A3F92000D03002F097 +:10A4500095FE2000643009F02DFB201DFFF7F4FE6F +:10A46000200010BD90350300F0B585B005000E004A +:10A4700017000393FEF7F4F9002818D1283018F0DC +:10A4800032F96B4604009B89A9B20093B2B20B4B20 +:10A4900014F00FFC0A482100D03002F0F7FD00282C +:10A4A00005D0200014F01CFC200018F02EF93A0012 +:10A4B00031002800FEF7DEF905B0F0BDDDA1010096 +:10A4C0002C2100201423F0B5040093B0192200932E +:10A4D0001821043003F0E0FB23002500260064333C +:10A4E0001800B43513211093B83609F0EFFA28009C +:10A4F00016F080F900221E21300015F0A6FC200085 +:10A50000D03002F05BFE2300F033474A06211800EA +:10A51000119302F061F920000027012369301A002D +:10A5200000971121FF3001F0A1FC2000913000972D +:10A53000012302221A21FF3001F098FC2000B930DB +:10A54000022201211A23FF3002F0F8FE300001F050 +:10A55000F5F9E4235B00E050300001F0E3FCE62372 +:10A560005B00E0500100E42220005200D130119B3A +:10A57000A2580095FF3002F03FF82000E13029009A +:10A580001C22FF3004F092F8192320000F93013BA6 +:10A590000E93013B0D93013B0C93013B0B93013B4D +:10A5A0000A93013B0993013B0893013B0793013B4D +:10A5B0000693013B0593013B0493013B0393013B4D +:10A5C0000293013B0193F930013B082200930721DC +:10A5D000013BFF3015F05AFCCA239B00E01829000C +:10A5E00005F024F9D3239B00E0181D2103F0D2F8D5 +:10A5F000DD239B00E75010982770032117F06CFDB6 +:10A6000023002200200009499C33A0321C60116005 +:10A610005760074A80305A610221012209F006FE84 +:10A62000200013B0F0BDC046FC300300B9E90200C1 +:10A63000A5E902000123F0B5057891B007001D409F +:10A6400000D0DFE00300D0331800049300F0AAFB31 +:10A6500000F05AFA282018F046F80400103014F0E0 +:10A6600018FC694B65802380182018F03CF8060020 +:10A67000664B80C603901022290030000E930F9580 +:10A6800018F086F808220EA9300018F063F8604B25 +:10A69000039AE56053611223A260A380256265627C +:10A6A0002100049802F0F2FC002805D0200014F0EC +:10A6B00017FB200018F029F801223B785549134375 +:10A6C0003B703B00B4331800059316F099F85249DB +:10A6D0000390059816F094F800260690642000F088 +:10A6E000A1FC340035003B006933FF3318000793A9 +:10A6F00014F09DFE002803D1039B002B0DD109E02F +:10A7000038009130FF3014F092FE0028F4D0182D5C +:10A7100003DDF1E7069B002B70D03800653021B2D5 +:10A72000FF2332B2FF3000F051FF322000F07AFCFC +:10A73000631CDCB20135052C02D10024731CDEB28F +:10A74000039B192D02D0002B02D1CCE7002B03D0A4 +:10A750003049059803F03EFF039817F0D6FF06989E +:10A7600017F0D3FF2D492E4800F040FDDD239B005C +:10A77000FB580893002B38D100F0AEF801000AA86E +:10A7800000F09EFE14F09DF9089014F09AF96B46C3 +:10A790000990198C0CA814F009FB099B0DA8190C41 +:10A7A00014F004FB0DAA0CA90BA814F04FFB0DA884 +:10A7B00014F0E0FA0CA814F0DDFACA20012380009E +:10A7C0000BAA0AA900933818049B05F083F80BA87C +:10A7D00014F0D0FA0AA814F0CDFACC239B00FB5851 +:10A7E0000893DD23089A9B00FA50CA2339009B0086 +:10A7F000079AF031F81805F067FA74E70749094835 +:10A8000000F0F4FC11B0F0BDFD0300002DEA0200E1 +:10A81000EDE902004B3E0300563E030000200020FD +:10A82000001C00200800002010B5041E0DD017F0F9 +:10A83000EFFF230001382018834208D21A780178EC +:10A840000138197042700133F6E7024800E0002039 +:10A8500010BDC04617FCFFFFF0B585B001900C1E7F +:10A8600028D00027C217161A56407D1C6319029380 +:10A870003000013B0A2103930AF0CAFCCB17C91828 +:10A880005940039B3031197030000A210AF0DAFB7D +:10A89000061E01D02F00E8E7019B002B03DA2D23D1 +:10A8A000029ABD1C1370002620006655FFF7BCFFFE +:10A8B000300000E0014805B0F0BDC04617FCFFFFC6 +:10A8C000BFF34F8F024A034BDA60BFF34F8FFEE7AF +:10A8D0000400FA0500ED00E0F0B58DB005AF1922D7 +:10A8E0001549380017F036FF0022144B05245A7121 +:10A8F00080225205566E0122250001940292039394 +:10A90000019930000AF09AFB080002990AF010FB46 +:10A91000019B03996B430193029B361A6B4302938D +:10A92000631E2C1B6C433C19225C1C1ECA54E7D1CD +:10A9300008000DB0F0BDC046663E03003928002077 +:10A94000014B18607047C046A4240020F0B595B0B4 +:10A950001822002106000EA817F01AFF13210EA8D6 +:10A9600017F017FD03210EA817F0BEFD01224A4B78 +:10A9700000921B68002B01D0DBB200930123474AF1 +:10A98000002109A809F0D4FE454B9E4200D90026BB +:10A9900072B6444B1022002105A81D6817F0F8FE7E +:10A9A000414B64213000059305240AF04BFB6043C2 +:10A9B0005030281806900A2130000AF043FB0A2183 +:10A9C0000AF026FC614350316918079130000A21D2 +:10A9D0000AF01EFC4C43210050316C18802608946C +:10A9E0000024B601009B002B3CD004AD0027032CB3 +:10A9F00002D180260024B6016B682C4A02936300C2 +:10AA00000133D318002201921021581E0078014111 +:10AA1000039119788C4660460299095C03980142BB +:10AA200004D0012090400199014301910132063385 +:10AA3000092AE9D1019B2A68D9431D4B0901194014 +:10AA4000029B934203D1312F01DC002100E031430E +:10AA500009A817F0A2FDFA23139A0F99DB001068DA +:10AA6000014201D1FFF72CFF013B002BF7D1FA2364 +:10AA7000013401377600E4B25B009F42B7D1043560 +:10AA800008ABAB42B2D1044B1B68002BAAD0009B91 +:10AA9000013BDBB20093A5E7A4240020F0FF0000F7 +:10AAA000E703000008200020B53E03007F3E0300BE +:10AAB000F01F0000F7B500281FDD0126104C421ED4 +:10AAC0002368019415000020DF0FBC4664469F09EF +:10AAD00067405F401C09590867409B087B404B401A +:10AAE000DB070B4319004000314008436D08EBD1F0 +:10AAF0008242E7D3019A136000E00248FEBDC046DF +:10AB0000A824002017FCFFFFF8B50023144C236095 +:10AB100013F0C9FF2500002808D00421200013F0FD +:10AB2000BEFF00281BD00F4B236018E00122A12795 +:10AB300004210D4B0D4E1A602368FF000B4A706014 +:10AB4000944662465268084C002AFAD0E2591B0229 +:10AB5000013913430029F1D12B6001236360F8BD53 +:10AB6000A8240020ED5EBC0B00D00040FCD00040CB +:10AB7000F0B585B01F000AAB1B88060002911500D6 +:10AB80000393002F1AD0282017F0ADFD6B46040068 +:10AB90001989039BAAB200933B0014F08AF833682A +:10ABA00021005B6830009847002808D0200014F08E +:10ABB00097F8200017F0A9FD024800E0024805B010 +:10ABC000F0BDC04616FCFFFF17FCFFFF1FB50023BA +:10ABD0000190039372B60E4B03A91A6801A813F0F3 +:10ABE0007CFF0C4B03A91A6801A813F076FF0A4BEF +:10ABF00003A91A6801A813F070FF62B6019B002B2D +:10AC000002D0064A12681A60039B581C05B000BDAA +:10AC1000D8240020D0240020CC240020E0240020D0 +:10AC20000B4B70B51C68002C11D0656D00F004FC56 +:10AC3000A36C002903D1834201D92C00F3E7200043 +:10AC400013F07CFF0349200013F065FFF5E770BDAA +:10AC5000D0240020D8240020F0B5040093B007933E +:10AC6000230C0293294B04901C68294B05911E6804 +:10AC7000069285B20027002E46D0002C30D0636D9E +:10AC800024480393A36C9AB21B0C99B2854216D147 +:10AC90002148824213D1002B04D0029B994201D05B +:10ACA000039CEAE7002F01D00127F9E7200013F009 +:10ACB00045FF1A49200013F02EFF0137F0E7002A64 +:10ACC00001D09542ECD1002B02D0029B9942E7D1F2 +:10ACD000200013F033FF1149200013F01CFFDFE7C1 +:10ACE0000F4BEB18012B0FD91023029A0093290068 +:10ACF0000C4B08A813F0DDFF336808A99B683000EF +:10AD0000984708A813F0ECFF13B0F0BDCC24002046 +:10AD1000DC240020FE030000FF030000D8240020F4 +:10AD200002FCFFFF59AC010010B572B60B4B1C685A +:10AD3000002C03D0200013F001FF08E062B6602071 +:10AD400017F0D1FC60220021040017F021FD002340 +:10AD5000034A2000E364E263E36510BDAC240020F5 +:10AD600000400020094B10B51C68E36CDB070AD5D6 +:10AD7000FFF7DAFF064B1860002804D0E36DC365C7 +:10AD80000023E3650400200010BDC046B02400206D +:10AD9000D4240020024B1878012318407047C04685 +:10ADA0003F280020F7B50600FFF7F4FF051E33D15A +:10ADB0001A4C2660FFF7B8FF194B1A49186013F0B8 +:10ADC000AAFEFFF7B1FF184B1860184B4363184BEE +:10ADD0008363206800280ED0C027164E2A00330057 +:10ADE00015490097FFF7C4FE009733002A00134966 +:10ADF0002068FFF7BDFE0C2017F075FC0023838050 +:10AE000083710F4B03600F4B836000F02DFB01211A +:10AE10000D4A13780B431370F7BDC046DC240020A5 +:10AE2000B0240020D8240020E0240020FC3F002093 +:10AE3000D1EB020059AC0100FF030000FE0300004B +:10AE40001C31030021AC01003F280020F7B50600AB +:10AE50000D0017000193002801D1002015E0002902 +:10AE6000FBD0FFF761FF041EF7D0084B019A436344 +:10AE7000066045608760064B002A00D0054B200025 +:10AE8000A363054913F047FE2000FEBDFC3F0020F0 +:10AE90009BEB0200B9EB0200D8240020F8B50500B6 +:10AEA000EFF30884C36B006C1C1B6B6C1B1A9C4279 +:10AEB00010D91F23084F20343E689C433D60002872 +:10AEC00001D000F009FA200000F0D0F92864201821 +:10AED00068643E60F8BDC046B0240020024B18688C +:10AEE000434258417047C046D8240020002310B583 +:10AEF00004499C006258002A01D00133F9E76050F0 +:10AF0000100010BDB4240020002310B5044A99009D +:10AF10008C58844201D00133F9E70020885010BDDD +:10AF2000B424002010B50024074BE058002802D0BC +:10AF300003685B6898470434182CF5D1034B1B68F1 +:10AF4000002B00D120BF10BDB4240020D824002045 +:10AF5000F8B5FFF71FFF002856D02C4E3468350097 +:10AF6000E36CDA0718D502273B43E364284B1D68DE +:10AF70000423EA6C28001343EB64636BEB63FFF775 +:10AF80008DFF2800696C05F020FD3068C36C3B42E2 +:10AF90003AD005F054FD37E01E4F1F4E3A68002AA4 +:10AFA00001D1326808E0216DB94205D1616D0029F7 +:10AFB00000D11100296000E02A602A6831688A42C5 +:10AFC00008D11B0706D52C60FFF7ACFF3B68002BB0 +:10AFD000FAD02B6029688C4216D03368994204D18C +:10AFE0000E4B4B630E4B8B6305E09C4203D100225A +:10AFF0004B6C100006E02000FFF750FF200029688E +:10B00000626C4B6C05F0A0FCF8BDC046B02400207B +:10B01000D4240020D8240020E0240020FC3F00207D +:10B02000D1EB020070B50500FFF7B4FE002803D194 +:10B03000280017F03DFA0FE0FFF794FE040000F03F +:10B04000FBF92818A064200013F078FD03492000C4 +:10B0500013F061FDFFF77CFF70BDC046D0240020D7 +:10B06000F7B51A4D06002B680F00002B03D0FFF731 +:10B0700091FE002801D1164827E0FFF773FE154B1B +:10B08000041E1B689C4208D0200013F057FD124993 +:10B09000200013F040FDFFF75BFF3B043343A36444 +:10B0A000200013F04BFD20000C4913F034FD0C4B35 +:10B0B0000020F318012B08D9C02300933A00094B54 +:10B0C00031002868FFF754FD0020FEBDDC2400207D +:10B0D00016FCFFFFB0240020D8240020CC24002040 +:10B0E00002FCFFFF59AC010070B5FFF753FE0028CA +:10B0F0001FD0104D286813F021FD00220E4E346839 +:10B10000002C10D0636D002B0AD1032A08DDA26D3C +:10B11000206C536500F0E0F8200000F0DDF802E05C +:10B1200001321C00ECE73100286813F0F4FCFFF753 +:10B130000FFF70BDB0240020AC240020F7B507003D +:10B140000D00002830D0FFF725FE00282ED0194E24 +:10B150003068C36C5B0703D1C36D0193002B06D02D +:10B16000154A2900380013F000FD00241FE00224D6 +:10B1700005F04DFC3268D36C1C4003D003218B4397 +:10B18000D364F2E701210B43D3642800B847336846 +:10B190000120DA6CDC6511008143D964530706D5C0 +:10B1A000280013F001FD02E0044C00E0044C2000F4 +:10B1B000FEBDC046B0240020A9EB020017FCFFFF33 +:10B1C00016FCFFFF020010B5014B12CB12C210BDDE +:10B1D000E4240020034A044B12681A607E225A605D +:10B1E0007047C04608200020E424002070B5124EAD +:10B1F00005003278022A1AD081421AD90C1A072C7B +:10B2000017D9080003232843034012D172B60B4814 +:10B21000D2001550821851608022A40812061443EF +:10B220002C6032780132327062B6180002E00448B5 +:10B2300000E0044870BDC04640280020EC240020F7 +:10B2400013FCFFFF17FCFFFF064B1A780023824216 +:10B2500005D9054AC00013185B6880581B1A1800EE +:10B260007047C04640280020EC24002070B5051E21 +:10B2700024D0134A134E13781400002B0CD112491A +:10B2800012483370FFF7B2FF114B984202D11E20D3 +:10B29000FFF75CFB01232370002433789C4209DA1A +:10B2A0000C49E300C918280013F098FC002805D1C8 +:10B2B0000134F2E71420FFF749FB002070BDC046BF +:10B2C00041280020402800200038002010290020BC +:10B2D00017FCFFFFEC24002070B500281FD0104B96 +:10B2E00010491C780023A34216DADA005558A84208 +:10B2F00010D98A18526890420CD2041F2368002B80 +:10B3000002DC1E20FFF722FB802322681B0613436A +:10B31000236004E00133E6E71E20FFF717FB70BD52 +:10B3200040280020EC24002070B5051E15DD0C4BD4 +:10B330000C4E1A681C00002A02D0306816F02EFF4E +:10B34000FA21256000243068074B89008361C462BC +:10B35000694316F02BFF200000E0044870BDC04692 +:10B360002C250020FC24002015B4010017FCFFFF51 +:10B37000F8B5114F06003D68002D0AD1302017F0B6 +:10B38000B2F9040008F0C6FB0C4BA5612360E5622E +:10B390003C600B4D2B68002B09D1102017F0A3F94E +:10B3A000040016F07BFE20002C6016F051FE3000E9 +:10B3B000FFF7BAFFF8BDC046FC2400204039030067 +:10B3C00028250020014B18687047C0462C25002016 +:10B3D00070B50D4C2368002B03D00C4B1B68002B61 +:10B3E00002D10620FFF7C4FF206816F048FE0200D5 +:10B3F0000749C3170D684E685219734120680A60E7 +:10B400004B6016F042FE70BD28250020FC24002071 +:10B41000D020002010B5FFF7DBFF0024054BE058DB +:10B42000002802D003681B6898470434282CF5D103 +:10B4300010BDC0460025002010B5FFF7C9FFFA2255 +:10B44000034B920018685968002309F05FFF10BD94 +:10B45000D020002010B5FFF7BBFF024B18685968D9 +:10B4600010BDC046D02000200B4B10B51B68040057 +:10B47000002B03D0094B1B68002B02D10620FFF7DD +:10B4800077FF0023064A99008858002801D001332D +:10B49000F9E78C5010BDC04628250020FC24002070 +:10B4A00000250020002310B5044A99008C588442DE +:10B4B00001D00133F9E70020885010BD002500209D +:10B4C00010B50400002902D00B78002B02D1034BE9 +:10B4D000236001E013F055FC200010BD2C31030067 +:10B4E000F8B505000E00140000290AD00B78002BD7 +:10B4F00007D0002A05D0080097B217F089F98742D3 +:10B5000002D90B4B2B6010E0601DFFF7AFFE2860E7 +:10B5100013F06FFE2868220047803100043017F0D6 +:10B5200019F92B681C19002323712800F8BDC046A7 +:10B530002C310300014B03607047C0462C310300DF +:10B5400010B50548054C206013F05AFE044A054921 +:10B55000200017F0C1F810BD2C3103003025002069 +:10B560000020002075ED0200084B73B51C68050033 +:10B57000002C0AD00100266808310822684617F01E +:10B58000E9F80CCD31682000884773BD34250020D0 +:10B59000014B03607047C0463431030010B504000E +:10B5A000002902D1044B036003E00160080013F09E +:10B5B00027FE200010BDC046343103000300024ABC +:10B5C00000681A607047C0463431030030B5046823 +:10B5D0006088814206DAA588AA4203DA002901DBE5 +:10B5E000002A01DA034804E042436018801883719E +:10B5F000002030BD17FCFFFF10B50068438899425A +:10B6000006DA8488A24203DA002901DB002A01DA83 +:10B61000034803E05A4343189B18987910BDC0466D +:10B6200017FCFFFFF0B5070085B00E001D000029D4 +:10B6300021DD002A1FDD002B1DD0046863880393E1 +:10B640008B4200DD0391A3880293934200DD0292B6 +:10B65000002306340193019B029A93420DDA2900DC +:10B660002000039A17F076F83B68AD195B88E41860 +:10B67000019B0133EEE7024800E0002005B0F0BD79 +:10B6800017FCFFFFF8B504000D0016001F0000298D +:10B6900001DB002A02DA0D4B236016E0100048435C +:10B6A0000630FFF7E3FD206013F0A3FD23685D8003 +:10B6B0009E80002F06D03B00320029002000FFF7BB +:10B6C000B1FF02E0200013F036FCF8BD3431030076 +:10B6D000F7B505000C1E05D000200F0006000190F4 +:10B6E000010015E0224B03603FE0302252429446B5 +:10B6F0009C446246092A14D90A2B0DD1019B3618A5 +:10B7000001330193B14200DA310000200600013715 +:10B710003B78002BE9D106E00028F8D00136002064 +:10B72000F5E70120F3E76A46928809B212B22800D1 +:10B73000FFF7A8FF2B680A26991D01235B4220789A +:10B74000002812D00200303A092A06D8DA43D2176C +:10B75000134073431B18303B05E0002B03DB0B70D9 +:10B76000012301315B420134E9E72800FEBDC046F8 +:10B7700034310300F0B5040087B004A815001E00A2 +:10B780000F00FFF71FFD23685A88954208DA9B884F +:10B79000B34205DD1F2F03D9059B00939F4201DDB6 +:10B7A00018482DE0052300217B430093049B01935F +:10B7B000009B019ACB18A03BD35C00220293731824 +:10B7C0009C465319276803937888834202DABB8822 +:10B7D0009C4507DB0132052AF3D101310529E7D168 +:10B7E00000200DE0634658435319FB1810271741FA +:10B7F0001B1802980740781E87417F429F71E9E736 +:10B8000007B0F0BD17FCFFFFF7B5036806009C1DED +:10B810005B880D005A1A0192002918DD0027994211 +:10B8200002DB13F088FB14E033689B889F4210DA38 +:10B830006119019A200016F08DFF019B2900E01884 +:10B8400013F05CFB336801375B88E418ECE70248CF +:10B8500000E00020FEBDC04617FCFFFF10B5054804 +:10B86000054C206013F0CCFC044A0549200016F07A +:10B8700033FF10BD343103003825002000200020A4 +:10B88000EFEE020010B5054C0121200013F076FC0C +:10B89000034A0449200016F01FFF10BD3C2500207C +:10B8A0000020002019F102000388074A10B501208A +:10B8B000934208D0834202D00020DB0703D41E202D +:10B8C000FFF744F8002010BDFFFF0000004870475C +:10B8D00016FCFFFF10B53220FFF738F8004810BD06 +:10B8E00016FCFFFF8280142210B5134C028108342D +:10B8F000020000230460416204000221303283719F +:10B900008172C360036143618361C3610362363442 +:10B9100013705370227843868A43F1310A4083863C +:10B920002270020040321370021DD3870133438717 +:10B930008387C38710BDC04654310300F0B5544F10 +:10B9400097B03B6806000593002B00D094E006AC4E +:10B950000B331C222121200001F028FD0EAD0B230A +:10B960001D2222210AA801F021FD0B231B222321E5 +:10B97000280001F01BFD082016F0B5FE0122059BF2 +:10B980001100049015F0BEFA3A21300014F0DEFFE9 +:10B9900000281CD0A38812ADAB80A3795C20AB71CA +:10B9A0003C4B1293A3681493237B2B73637B6B73C1 +:10B9B000A37BAB7316F097FE0423019336330093F9 +:10B9C0002A00049B3100040003F00AFA53E03221FC +:10B9D000300014F0E9FF00281CD0A38812ADAB8022 +:10B9E000A3795C20AB712B4B1293A3681493237B38 +:10B9F0002B73637B6B73A37BAB7316F074FE042312 +:10BA000001932E3300932A00049B3100040003F0BD +:10BA10008BFB30E03C21300014F081FF002822D065 +:10BA2000AB8812ACA380AB79A420A371194B1293FD +:10BA3000AB6814932B7B23736B7B6373AB7BA37318 +:10BA400016F051FE052305000293013B01933833A4 +:10BA500000932200049B310003F0E0F80E4B3D60A0 +:10BA600044351D6008E0442016F03DFE0422049990 +:10BA70000400FFF737FF3C60074B054C18680028AF +:10BA800002D0216813F053FD206817B0F0BDC04606 +:10BA9000402500204431030044250020F0B56049D2 +:10BAA000C56885B08D4206DA030036331A78022362 +:10BAB00013400BD117E0C82200235200954212DD3B +:10BAC000030036331A78002392070CD401230600B2 +:10BAD0001F00363632785408A7433C0002279C40AA +:10BAE000BA432243327004698C4205DA02003632CE +:10BAF0001278520709D415E0C8225200944211DD91 +:10BB000002003632127852070CD406000122363673 +:10BB100033789F08BA439700042293431A00012305 +:10BB20003A433270426901920200019E40328E42D5 +:10BB300005DA01003631097809070AD415E0C82171 +:10BB4000019E49008E4210DD010036310978090757 +:10BB50000BD40600012136363378DF08B9430827B5 +:10BB6000C900BB430B43337001E0002B18D013789E +:10BB7000032B15D80133DBB21370012B03D1002145 +:10BB8000031DD9870CE0042B0AD1020001213632B3 +:10BB9000137804300B4313700023C3870B333CE04E +:10BBA00013780293002B1BD006000127011DCB8FB9 +:10BBB000363601339BB2CB8703963678BC46374086 +:10BBC00008D01D2B0CD963469E43039B1E70002397 +:10BBD000CB8704E0092B03D9029BCF87013B13706D +:10BBE00013F050FB0F4A0723904216D90E49043B2D +:10BBF0008D4212DBC8220133920095420DDC023BDC +:10BC00008C420ADB013B944207DC019804338842F2 +:10BC100003DB0133904200DC0023180005B0F0BDC7 +:10BC200070FEFFFFFF700200E0FCFFFFF0B50400B4 +:10BC300089B0C0680CF0BCF80090019120690CF04C +:10BC4000B7F80690079160690CF0B2F80200029014 +:10BC5000802000060B180391009801990DF052FA0C +:10BC60000CF074F9E0620CF01DF906000F000DF005 +:10BC70001FF804900591300039000CF0F7FC049A8D +:10BC8000059B06000F00009801990BF06DFA320039 +:10BC9000009001913B00029803990BF065FA0200B5 +:10BCA0000B00009801990BF0D9FC02000B000698DC +:10BCB00007990DF027FA0CF049F90022051C002322 +:10BCC0000298039909F0D4FA002801D1A56219E07D +:10BCD0000021281C09F006FB0D4E002801D10D4F54 +:10BCE00000E00D4F281C0CF0DDF802000B003000C6 +:10BCF00039000BF0B3FC32003B000AF0E5FA0CF01F +:10BD000025F9A0620222A3791343A37109B0F0BD03 +:10BD1000EA2E4454FB21F9BFFB21F93F10B513F083 +:10BD20005EFB064909F08EFF0CF0BCF8044A054B97 +:10BD30000AF0F6FD0CF006F810BDC0460000B44352 +:10BD4000EA2E4454FB21194010B513F055FB064967 +:10BD500009F078FF0CF0A6F8044A054B0AF0E0FD64 +:10BD60000BF0F0FF10BDC0460000B443EA2E44546F +:10BD7000FB21194010B50400034B08330360FFF7A3 +:10BD800091FB200010BDC0468831030070B5C36927 +:10BD9000C2681B688AB00400451D1A4250D0EB7F70 +:10BDA000002B01D0013BEB77EB7F082B0DD9012253 +:10BDB000A379134209D11343A371A188130006A8E4 +:10BDC00013F072F8FFF738FB2062EB7F012B26D8C7 +:10BDD0000123A2791A4222D00025A188A57102224E +:10BDE00002A813F061F8A31DDE7F012E17D1FFF723 +:10BDF00023FB2B00226A801A994100900191019B3C +:10BE0000A188AB4203D1174B009A9A4202D9012371 +:10BE1000042201E03300032206A813F045F80323AF +:10BE2000A2791340012B1AD1FFF706FB0023226AE7 +:10BE3000801A9941994208D10B4B984205D80EE0DF +:10BE4000EB7F0B2BB0D80133ADE70222A379A18899 +:10BE50001343A3710332012306A813F025F80AB097 +:10BE600070BDC046E7030000DB050000F0B5070029 +:10BE700000250E0085B002930AAB1B7808370393A8 +:10BE8000104B0400083303600192858085712900FE +:10BE90001822380016F07CFC039A3100380016F0A6 +:10BEA0007DFA6B466A469B88127AA380A31DE671D1 +:10BEB000DA77631D25622000DD77FFF7D5FA2000D1 +:10BEC00005B0F0BD883103000048704716FCFFFF45 +:10BED00010B53320FEF73AFD004810BD16FCFFFFF9 +:10BEE000002310B50400838083710D48216408305D +:10BEF00020608020C000A061E0612062E36020003B +:10BF0000236163616362A362E36223636363A36388 +:10BF1000E3636364110013F0D0FA200010BDC04643 +:10BF2000A0310300F0B5534F97B03B68060005936E +:10BF3000002B00D094E00B331C22212106A80AAC70 +:10BF400001F034FA0EAD0B231D222221200001F056 +:10BF50002DFA0B231B222321280001F027FA0820A9 +:10BF600016F0C1FB0122059B1100049014F0CAFFDA +:10BF70001D21300014F001FD00281CD0A38812AD53 +:10BF8000AB80A3796020AB713B4B1293A3681493F1 +:10BF9000237B2B73637B6B73A37BAB7316F0A3FBC9 +:10BFA00005230193183300932A00049B31000400F9 +:10BFB00002F0EAFF53E03C21300014F00CFD0028B1 +:10BFC0001CD0A38812ADAB80A3796020AB712A4B43 +:10BFD0001293A3681493237B2B73637B6B73A37BF4 +:10BFE000AB7316F080FB05230193373300932A00CF +:10BFF000049B3100040003F039F930E03C213000AB +:10C0000014F08DFC002822D0AB8812ACA380AB7951 +:10C01000A420A371184B1293AB6814932B7B23734A +:10C020006B7B6373AB7BA37316F05DFB052305008D +:10C030000293013B0193383300932200049B3100AB +:10C0400002F0ECFD0D4B1D6044353D6008E04820DA +:10C0500016F049FB052204990400FFF741FF3C60FC +:10C06000064B1A68034B002A01D019684A64186805 +:10C0700017B0F0BD442500204431030040250020C6 +:10C080007FB50426040080793040051E18D123684E +:10C090002000DB699847200013F03AFAA3790322C5 +:10C0A0003343A371A1880123684612F0FDFEA379F2 +:10C0B00028001A00B243A2719B0702D4024800E094 +:10C0C000024804B070BDC04614FCFFFF15FCFFFF22 +:10C0D000F0B504008BB0406C13F08EF9061C606C58 +:10C0E00013F07DF902222100051C07A813F021FAA4 +:10C0F00008980AF063F8041C09980AF05FF80090A9 +:10C10000301C0BF0CFFE06000F000CF0D1FD0BF041 +:10C110001DFF3900019030000CF0A8FA0BF016FF5B +:10C120000290281C0BF0BEFE06000F000CF0C0FDB4 +:10C130000BF00CFF3900039030000CF097FA06006A +:10C140000F000098019909F07DFD0299051C201C43 +:10C1500009F078FD011C281C09F088FE0BF0A2FEF6 +:10C160000490059107980AF029F83900051C300061 +:10C170000BF0ECFE011C281C09F064FD0399051C62 +:10C18000201C09F05FFD019909F05CFD011C281CD1 +:10C1900009F018FA0399041C009809F053FD02995C +:10C1A00009F050FD011C201C09F00CFA0BF07AFE7E +:10C1B000049A059B0CF0A6FF00220E4B0AF0D4FF58 +:10C1C0000D4A0E4B0AF0ACFB0BF0C0FE011C0C48F4 +:10C1D00009F04CFE0021041C09F070F8002804D07E +:10C1E000201C084909F0EEF9041C201C09F0C4FFCA +:10C1F0000BB0F0BD00807640EA2E4454FB2119407C +:10C200000000B4420000B44330B585B00122010003 +:10C2100001A813F08EF9029809F0D0FF0BF042FE4E +:10C2200004000D00019809F0C9FF0BF03BFE22004D +:10C230002B000CF067FF00220C4B0AF095FF0C4A14 +:10C240000C4B0AF06DFB0BF081FE0021041C09F081 +:10C2500035F8002804D0201C074909F0B3F9041C64 +:10C26000201C09F089FF05B030BDC0460080664043 +:10C27000EA2E4454FB2109400000B44310B58379F1 +:10C2800004005A070DD49B0701D4FFF7F9FE636C35 +:10C290002000002B02D0FFF71BFF03E0FFF7B4FFE5 +:10C2A00000E0014810BDC04615FCFFFF82B0F0B5AC +:10C2B0000400EBB064207193709216F0F9F8052237 +:10C2C0000EA8110012F040FE98490FA8FFF700FADF +:10C2D000002396251A001FA86D001A50C1180C33B0 +:10C2E0004A608A60AB42F8D11922002111A816F0E9 +:10C2F0004FFAA06813F036FD00260990FF21A068D0 +:10C3000000F004FD8A4FA06800F05EFB07960896D7 +:10C31000874A3BB2934202D0864A934212DAA0681F +:10C3200013F06EFDA568844918A8FFF7C9F87822B4 +:10C3300018A9280000F032FC18A812F01BFD7C4F51 +:10C34000002606E0002F01D00F2E02D1A06800F0D9 +:10C350003BFB0322089B606801331A40089213F0EC +:10C3600029F80500606813F02CF80022734B069240 +:10C370009D4210DB013206922A00C8320BDB0422F8 +:10C380000692AA229200954205DC03220692C82D4D +:10C3900001DC013A069200220492984210DB01234C +:10C3A00004930300C8330BDB04230493AA239B00EC +:10C3B000984205DC03230493C82801DC013B049365 +:10C3C0000EA812F0B8FD002511ABEB5C012B08D1D3 +:10C3D0005B496B00CA185278C95C0EA8FF23FFF7AF +:10C3E000F5F80135192DEFD16B4610229A5E6B4698 +:10C3F0000EA81821595E089BFFF7E8F83BB2002B06 +:10C4000001DB0F2E07D90023A068009374301A00B7 +:10C410000EA912F0A6FD00230593059B484A5B0078 +:10C42000995C0698814227D1D3185B78049A93428D +:10C4300022D12C2206AB9B18059A9B5C012B1BD0AA +:10C440000C23079A216853431D0000220AA813F009 +:10C4500070F81FAA2B0094460AAA634423CA23C378 +:10C460002C2206AB05999B182B3A5A54079B013393 +:10C47000DBB20793731CDEB2059B01330593192BC6 +:10C48000CBD1642016F014F83B00643B9FB2079BAD +:10C49000182B00D83CE71A001FA918A813F0B6FA09 +:10C4A0006A461BAB23CB23C21B6813601899199AE9 +:10C4B0001A9B206813F012F8E568002D0CD0214972 +:10C4C00010A8FEF7FDFF1C2318AA10A9280014F0DD +:10C4D000CAF910A812F04EFCA06813F091FC0FA945 +:10C4E00010A8A56812F010FD0022174B009210A9A9 +:10C4F00001932800130000F0D1FA10A812F0F7FC05 +:10C50000FA20800015F0D4FFA06813F079FC099997 +:10C51000A06800F0FBFB0FA812F0E9FC0EA812F0D7 +:10C52000E6FC6BB0F0BC08BC02B01847C740030083 +:10C530008C3C0000D18AFFFF0C41030058FDFFFF37 +:10C540009540030021410300DC050000F0B587B0F1 +:10C5500001930EAB1B88060003930D9B0D00009307 +:10C56000019B02920C9F002B3DD0002F02D1009B1B +:10C57000DB0738D5282016F0B6F80400103012F08A +:10C5800088FC6B461B8918202580638016F0ABF869 +:10C59000049707000500009B10220593019B0021D2 +:10C5A00008C7380016F0F4F8082204A9380016F07D +:10C5B000D1F80E4B02226B6100230399E3602362E2 +:10C5C000636233680A43A560A2805B682100300083 +:10C5D0009847002808D0200012F082FB200016F0B7 +:10C5E00094F8034800E0034807B0F0BD19F60200D4 +:10C5F00016FCFFFF17FCFFFF70B58CB08360109B2B +:10C6000001604260C36004001849180014F0F8F893 +:10C61000051E14D001001C22103105A816F09AF84E +:10C620006A4608AB43CB43C21B6813602068059978 +:10C63000069A079B12F052FF280016F066F80C4B82 +:10C64000186800280ED00B4A05AB0592002206920E +:10C65000C03202926A4622CB22C223000322052165 +:10C66000FFF774FF20000CB070BDC04621410300ED +:10C6700034250020ADC20100F0B5040085B0637A16 +:10C680009C46002B03D1200013F0DDF969E0A37A6A +:10C69000266F01931023019AF35600259B1801225F +:10C6A0009A402900F36802920393039B9D4231DA7A +:10C6B000B368019A6B439B1872695B00E77AD318E1 +:10C6C0001A785878E379012F04D15F1E3F1A1000C1 +:10C6D0003A000EE0022F05D15F1EBA1A277A013FF9 +:10C6E000381A06E0032F04D1277A013FBF1A02004F +:10C6F00038005B004343606F8218D3189B79634511 +:10C7000000DD6346627B1A4202D00123AB4019432D +:10C710000135CAE71123C943F356606C9940236978 +:10C720001940029B194315F038FFA37B072B18D83B +:10C73000627B581C520062730B499A00A073022B53 +:10C7400003D8885815F0A9FE99E7084B2000236309 +:10C7500000236363064B8958E4622364143015F0A8 +:10C7600025FD05B0F0BDC046E431030079C60100E7 +:10C7700033FA020010B50400044B036015F00EFDFF +:10C78000200007F0DDF9200010BDC046403903004D +:10C7900010B504000E4B08330360FEF783FE200043 +:10C7A000743012F0A4FB2000603012F0A0FB2000D7 +:10C7B000583012F0DFFA2000503012F0DBFA20007F +:10C7C000044B14306361FFF7D5FF200010BDC04655 +:10C7D000CC3103002C390300F8B500250400324B9E +:10C7E0008580083303608571143016000F0007F050 +:10C7F00091F920002D4BE562636125645030FEF70E +:10C8000099FE20005830FEF795FE20006030FEF7BC +:10C81000BFFE20000423F25E33682667590009B288 +:10C82000743012F091FB3378226FE3717368012644 +:10C8300023721023E572A572A7802561D3569168F3 +:10C8400059188B4204DA3000984001330543F8E769 +:10C8500011230120D356D16859188B4206DA020001 +:10C860009A402669013332432261F6E7142015F01D +:10C870003AFF226900212A430123060007F058FFEE +:10C88000FF2262722200002301254832666465732C +:10C89000A373237320001370A366FEF7E5FDA3794D +:10C8A00020002B43A371F8BDCC3103002C390300C9 +:10C8B000F0B5437A85B00400002B03D1200013F0BB +:10C8C000C2F866E00122837A11009C461023066FAD +:10C8D0000025F35603926344994001912900F368BF +:10C8E0000293029B9D422CDAB36872696B436344E6 +:10C8F0005B00E77AD3181A785878E379012F04D1CE +:10C900005F1E3F1A10003A000EE0022F05D15F1E95 +:10C91000BA1A277A013F381A06E0032F04D1277A82 +:10C92000013FBF1A020038005B004343606F82186A +:10C93000D3189B79002B02D0039BAB4019430135E0 +:10C94000CFE71123C943F356606C9940236919401E +:10C95000019B194315F021FE667AB31EDBB2FC2B56 +:10C9600014D8FEF72FFD0C4B0500236300230B4862 +:10C9700063630B4BFF21E4622364704308F062FBA6 +:10C98000290041432000143015F010FC637A012B7C +:10C9900094D905B0F0BDC04647FA0200B6030000C6 +:10C9A00033FA02001FB5012381881A00684612F08D +:10C9B0007BFA012303491A00684612F075FA05B0A4 +:10C9C00000BDC046FE0300001FB5030048331A78BF +:10C9D0000400002A0DD000221A70012381881A0059 +:10C9E000684612F061FA012304491A00684612F001 +:10C9F0005BFA2000743012F09EFA1FBDFF030000A6 +:10CA000010B548300378002B06D00378012B03D0F3 +:10CA10000121024812F0B8F810BDC046FF03000023 +:10CA200010B501210400062012F0AEF8064B984222 +:10CA300009D1230048331A78002A04D01B78012B2F +:10CA400001D020BFF5E710BD16FCFFFF70B5050053 +:10CA5000141E09DB060048363378002B06D03378E5 +:10CA6000012B03D00B4813E00B4811E000232800F2 +:10CA70001A007430FEF77EFE0020844207D02B009F +:10CA80004A331C8007234C352880337000E0200097 +:10CA900070BDC04612FCFFFF17FCFFFF73B5079C7B +:10CAA0000500002C09DB060048363078002806D047 +:10CAB0003078012803D00D4816E00D4814E00698A0 +:10CAC0001BB2C0B20090280012B2743012F049FAC2 +:10CAD0000020844207D02B004A331C8007234C35AA +:10CAE0002880337000E0200076BDC04612FCFFFFB6 +:10CAF00017FCFFFFF8B505000F00161E13DBFFF74C +:10CB00007FFF2B0048331C78E4B2002C0DD132009B +:10CB100039002800FFF79AFF301E07D02800FFF7E2 +:10CB20007FFF200002E0024800E00248F8BDC04656 +:10CB300017FCFFFF11FCFFFFF0B587B00D9E05004D +:10CB40000F0002920393002E1EDBFFF759FF2B000C +:10CB500048331C78E4B2002C18D1390005A812F033 +:10CB6000D3F90C9B029A009305A9039B0196280018 +:10CB7000FFF794FF05A812F0BAF9301E07D028007D +:10CB8000FFF74EFF200002E0024800E0024807B035 +:10CB9000F0BDC04617FCFFFF11FCFFFFF8B5040015 +:10CBA000171E09DD060048363378002B06D033788F +:10CBB000012B03D00C4816E00C4814E02200E37966 +:10CBC0005632013B137023000025200054331D8092 +:10CBD000503012F02CF923004A331F800223280022 +:10CBE0004C3425803370F8BD12FCFFFF17FCFFFFAB +:10CBF000F7B505000F00161E18DDFFF701FF2B002B +:10CC000048331878C4B2002C12D1390001A812F0B0 +:10CC100006F9320001A92800FFF7C0FF01A812F0B1 +:10CC2000A9F82800FFF7FCFE200002E0014800E020 +:10CC30000148FEBD17FCFFFF11FCFFFFF8B5040023 +:10CC4000161E09DD070048373A78002A06D03A78E0 +:10CC5000012A03D0144826E0144824E05D42069BD4 +:10CC6000FF3301D16B1D00E0069B22009BB26432B2 +:10CC700013802300200066331D70603012F04CF9E1 +:10CC8000220000236C3213709D4200D0B3B2220008 +:10CC90004A321380079B00205A1E9341013E4C34B8 +:10CCA000053326803B70F8BD12FCFFFF17FCFFFF29 +:10CCB000F0B587B005000F00161E03931DDDFFF7CA +:10CCC0009FFE2B0048331C78E4B2002C17D13900AA +:10CCD00005A812F019F90D9B320001930C9B05A9D0 +:10CCE00000932800039BFFF7A9FF05A812F0FFF8A7 +:10CCF0002800FFF795FE200002E0024800E002480D +:10CD000007B0F0BD17FCFFFF11FCFFFFFF2902D8A1 +:10CD10004172002000E001487047C04617FCFFFF49 +:10CD200013B5040004A800780090200015F0A9FABB +:10CD3000002801D1207500E0004816BD0EFCFFFF61 +:10CD400013B5040004A800780090200015F081FAC3 +:10CD5000002801D1207500E0004816BD0EFCFFFF41 +:10CD60007FB50D0011000F226A4404001E1E1170D1 +:10CD700015D0089B002B12DD012329000093FFF73B +:10CD8000DFFF002801D007480AE00090089B32002E +:10CD900029002000FFF7C4FF002801D0F3E7024874 +:10CDA00004B070BD0EFCFFFF17FCFFFF30B50400A0 +:10CDB00087B0057B006C08F023F8A02200210E4B01 +:10CDC000AD00D200285199500C4A14319950636C2F +:10CDD0006846597C237BC91849B213F00BF9039BB1 +:10CDE000019A03211A60207B0130C0B208F026F9B5 +:10CDF000217307B030BDC04600700040040500003C +:10CE000082B070B50400002588B00C920D93636C5D +:10CE10009A6895420ADA197C02A8491949B213F0B6 +:10CE2000E9F8069B039A01351A60F0E75D7C237BE5 +:10CE300002A8ED186DB2290013F0DCF8039A059BE7 +:10CE400001921A600021182202A815F0A1FC02A884 +:10CE50000022290015F0A2FA206C002801D015F05C +:10CE600054FC082015F03FFC2900060007F0A0FF45 +:10CE7000094B2000E3620023FA212363074B266459 +:10CE8000A462E3631030090115F090F908B070BC9A +:10CE900008BC02B01847C046ADCD0100A1FF02009A +:10CEA000F0B504000E00150085B000930CAB1B8894 +:10CEB0001030019311F0EDFF26806580182015F0E9 +:10CEC00012FC070002AE33003D000AAA03CA03C3E6 +:10CED000009B102208C50021280015F059FC3100E4 +:10CEE0000822280015F036FC064B02227B61200048 +:10CEF00000230199A7600A43E360A2802362636272 +:10CF000005B0F0BDB5FF020070B505000400103596 +:10CF10000E00302286B00021280015F039FC2800D0 +:10CF200006F0F8FD0023194A66642261184AA362DC +:10CF30001668E363237323606360A3609E421FD07F +:10CF4000144A28200492059315F0CDFBC023050058 +:10CF50006A46029304AB03CB03C2230006210222DC +:10CF60002800FFF79DFF336829005B683000984771 +:10CF7000002805D0280011F0B3FE280015F0C5FBED +:10CF800000232000236406B070BDC0462C39030086 +:10CF90003425002001CE010030B5134B91B01D683F +:10CFA0000400002D17D0114B6A460493002305930B +:10CFB0001033029304AB03CB03C2230002220621E9 +:10CFC00006A8FFF76DFF2B6806A99B682800984705 +:10CFD00006A811F085FE2000054B10302361FFF7F5 +:10CFE000C9FB200011B030BD3425002001CE010066 +:10CFF0002C390300F7B507000D1E27D000230226A9 +:10D0000004690193002C1DD0AA88A38853403342A1 +:10D0100016D1324203D1AB88334207D010E0A96861 +:10D02000A06813F054FF002804D1F4E7A368AA68AD +:10D03000934205D12B88002B0AD022889A4207D030 +:10D04000646ADFE7019B2000002B1ADC0D4818E022 +:10D050006B88002B02D062889A42F1D1EB68E268BB +:10D06000934201D0002BEBD17B68002B01D0200034 +:10D070009847A388044A1343A380019B013301937B +:10D08000DEE7FEBD17FCFFFF0080FFFFF0B50600E6 +:10D0900085B00D1E5CD001270469002C1DD0022133 +:10D0A000AA8800230A4202D0A3885B083B4022687A +:10D0B00029688A4257D1002B0AD0A968A06813F0CA +:10D0C00006FF00284FD0EB68E26893424BD141E065 +:10D0D000A368AA68934246D1F5E731692A880F0010 +:10D0E0000B1E0CD1356101232149684611F0DCFE8D +:10D0F00020003AE0586A1F00002812D00300188868 +:10D100009042F7D318003B000488944209D1478825 +:10D110006C88A74205D8446A0300002C01D0200087 +:10D12000F2E799420AD10888824204D306D14C889A +:10D130006888844202D96962356102E0596A69628D +:10D140005D6201230A49684611F0AEFE00200CE042 +:10D1500008480AE0A3881AB2002A02DA5B045B0CD2 +:10D16000A380054801E0646A97E705B0F0BDC046BA +:10D17000FD03000017FCFFFF16FCFFFF064B10B578 +:10D180001A00040008322C33026083600830FDF777 +:10D19000BBFE200010BDC0460432030008B4024BA1 +:10D1A0009C46083808BC60477DD1010008B4024B9A +:10D1B0009C46083808BC60475B0003000C4A00230B +:10D1C00011002C32083110B5436083818373826073 +:10D1D000036143618361C383016004000830FDF78C +:10D1E00085FE044B1A68002A00D11C60200010BD87 +:10D1F0000432030034250020F7B50E000125046930 +:10D200000192002C37D0238832889A4201D0002B1B +:10D2100026D1638872889A4201D0002B20D1FDF775 +:10D22000B9FD0123002806D0A288BF331340C03BBC +:10D230005A425341DBB2019A934210D1A7883BB2C4 +:10D24000002B0CDB10223100A01815F083FA4023CC +:10D250001F4207D1FDF79EFD002803D006E0002500 +:10D26000646ACEE7200012F001FFF9E721000348CD +:10D27000FDF764FFF4E72800FEBDC0466D00030023 +:10D2800008B4024B9C46083808BC6047F70103000D +:10D29000F0B587B001930EAB1B88060003930D9B7E +:10D2A0000D000093019B02920C9F002B3DD0002F9C +:10D2B00002D1009BDB0738D5282015F014FA0400B2 +:10D2C000103011F0E6FD6B461B8918202580638025 +:10D2D00015F009FA049707000500009B102205933A +:10D2E000019B002108C7380015F052FA082204A952 +:10D2F000380015F02FFA0E4B02226B6100230399C0 +:10D30000E3602362636233680A43A560A2805B68BE +:10D31000210030009847002808D0200011F0E0FCE0 +:10D32000200015F0F2F9034800E0034807B0F0BD13 +:10D330002302030016FCFFFF17FCFFFFF0B50400FB +:10D34000160000258380164A164B857102602181E4 +:10D3500046810573186889B08C46A8421DD0124AD0 +:10D3600005950492C02202926A4604AB82CB82C227 +:10D37000614623002A00FFF78BFF0B4A094B0692F8 +:10D38000C022186802926A4606AB079582CB82C219 +:10D3900023002A003100FFF77BFF200009B0F0BD19 +:10D3A00048320300342500204D03030030B500242B +:10D3B00003730123034D847105608180827343737D +:10D3C000846030BD4431030070B583790400DB070D +:10D3D00002D5806815F099F9A3799B0702D5A0685A +:10D3E00015F093F9A3795B0707D5A0230021144A10 +:10D3F000DB00D150A06815F088F9A3791B0708D588 +:10D40000A568002D05D0280013F0D8FD280015F0E0 +:10D410007CF9A379DB0605D5A068002802D0036853 +:10D42000DB6898476023A2791A4205D0A0680028DB +:10D4300002D003685B6898470023A360A37170BDA6 +:10D4400000700040F7B50222037B04000F00134276 +:10D4500025D0012925D88579154016D1FFF7B4FFCD +:10D46000182015F040F9A37B18222900060001932B +:10D4700015F08EF96B4604213000595614F0A0FFC8 +:10D480000222A379A6601343A371A3685A68002FF0 +:10D4900003D0DB681A60002004E01B69FAE7024849 +:10D4A00000E00248FEBDC04616FCFFFF17FCFFFF70 +:10D4B000F7B50127037B04003B422CD0612385791B +:10D4C0001D4018D1FFF780FF182015F00CF9A37B41 +:10D4D00018220093637B29000600019315F058F988 +:10D4E0006B460021019A5956300014F057FFA3797A +:10D4F000A6603B43A3716023A2791A4203D0A068BF +:10D5000014F0E3FD08E0A268536950681B681840F6 +:10D51000431E984100E00148FEBDC04616FCFFFFD7 +:10D5200070B5037B04000D001B0713D50B4B99420C +:10D5300012D812F0A6FF0300002083420DD128006C +:10D5400008F03CFE064908F0B3F9011CA06803F09E +:10D550009FFA02E0034800E0034870BDFF030000AB +:10D5600000C07F4416FCFFFF17FCFFFF70B50425C9 +:10D57000037B04002B4214D083792B420DD1FFF79B +:10D5800023FF082015F0AFF80E210600615607F0C2 +:10D590000FFCA379A6602B43A371A06807F030FCB1 +:10D5A00000E0014870BDC04616FCFFFFF7B501273B +:10D5B000037B04003B4219D0102385791D4011D113 +:10D5C000FFF702FF282015F08EF80E21A2883B00FD +:10D5D000615600950600FEF749FC1022A379A6606B +:10D5E0001343A371A06811F022FF00E00048FEBDC4 +:10D5F00016FCFFFF70B5037B05000E001B0713D55B +:10D60000002913DB12F03DFF041E11D1A86803F0BE +:10D6100053FA0949884202D0A86803F053FA31004E +:10D62000A86806F043FF04E0044C02E0044C00E06C +:10D630000024200070BDC046204E000016FCFFFFF5 +:10D6400017FCFFFFF8B51400027B070012071CD57A +:10D6500000291CDB002C1ADD002B18DDB42900DDAD +:10D66000B421FA26B600714365100800B4215D1B91 +:10D6700007F0E8FC754360433100281807F0E2FC2E +:10D6800001003800FFF7B6FF02E0024800E0024860 +:10D69000F8BDC04616FCFFFF17FCFFFF10B58379ED +:10D6A0001B0703D5806803F00DFA00E0004810BDA9 +:10D6B00016FCFFFF10B50124837941731C4004D090 +:10D6C000806814F011FF002007E06022134203D0AD +:10D6D000806814F001FDF6E7004810BD16FCFFFF5E +:10D6E000F8B56023867904000D001E4025D1FFF7B0 +:10D6F0006BFE582014F0F7FF0E210700615601F071 +:10D700004BF83800A760617B14F0E6FC0122A068AA +:10D71000104B114F436204628662476311001C3054 +:10D7200006F084FDA0680D4B8463C3630664C76480 +:10D7300001221C30022106F079FD6022A379934377 +:10D74000403A012D02D0022D01D140221343002086 +:10D75000A371F8BD050503006F040300290503004C +:10D7600010B50300032911D8080007F0D7FB0B02FE +:10D7700002061800FFF7B4FF02E01800FFF716FFDB +:10D78000002004E0180012F0E1FEF9E7004810BDA7 +:10D7900017FCFFFF70B5040000250D4B0E00083389 +:10D7A0008580857103602100183012F006FF20008B +:10D7B0002100203012F043FF064BA680A571E571D1 +:10D7C0002572E5602561656120001C6070BDC04662 +:10D7D0005832030048250020072906D8044B054A83 +:10D7E0005956054B0020D15000E004487047C04610 +:10D7F000B3420300001000400C05000017FCFFFFBF +:10D800008379DB0702D5C160002000E00048704743 +:10D8100016FCFFFF8379DB0701D5C06800E00148F3 +:10D820007047C04616FCFFFF70B545690400002D27 +:10D8300021D0037A032B20D8FFF7ECFFA8622C201D +:10D8400014F051FF2C220021050014F0A1FF002349 +:10D85000626953622369002B01D1226105E0596A94 +:10D86000002901D00B00FAE75A62237A656101337F +:10D870002372002002E0024800E0024870BDC0466A +:10D8800017FCFFFF13FCFFFF154B70B55A68154DD1 +:10D89000002A03D000225A600132AA601B69114E8F +:10D8A000002B1CD000210E4B0F4C19618023DB0094 +:10D8B000F358012B0ED1A923DB00F158206849420F +:10D8C000FFF79EFF2068FFF7AFFF23685A69074BF9 +:10D8D000F25002E02068FFF793FF0123AB6070BDB8 +:10D8E000FC10004000100040482500200405000006 +:10D8F00070B505000C0011F0D6F8002804D1034BD8 +:10D90000034AEC71D45000E0024870BD24050000C9 +:10D910000010004016FCFFFFF8B5837905000020D9 +:10D92000DB076FD411F0BFF8002868D16E69002EB4 +:10D9300008D12C3014F0D7FE04002C22310014F052 +:10D9400027FF6C616B69002B5BD000222E4B0121FD +:10D950005A608022D20511605A68002AFCD0062243 +:10D960002A4B2B4C9A562B4B0026E2500722043BA5 +:10D97000E2500833E650284A284B2800E250E97963 +:10D98000FFF7B6FF01220821254B2648E650043355 +:10D99000E250254B254FE1500433E0500223244848 +:10D9A000235024482750244F043827501827234851 +:10D9B00027506F6922482750C120800021502149FB +:10D9C0008538FF380B500B6080218900635871380F +:10D9D000FF38034363501C4B5E6062605A68002A44 +:10D9E000FCD000240126184B28001C61084B9E60C7 +:10D9F000FDF77CFAAB7920003343AB7102E01348AA +:10DA000000E01348F8BDC046FC000040B3420300EC +:10DA1000001000400C050000746962751C050000D0 +:10DA20002C0500002000040214050000FFFF000088 +:10DA3000340500003C0500002110010054050000E1 +:10DA40000405000000E100E0FC10004016FCFFFFB0 +:10DA500013FCFFFF03000069002809D00221054ADA +:10DA6000D167426A1A611A7A013A1A72024B196036 +:10DA70007047C04604E100E000E100E070B504003A +:10DA80000D0011F010F8002845D1002D45D02B785D +:10DA9000232B42D802220121214BDA67214B224A53 +:10DAA000586111615A692049002AFBD01F4A1D485C +:10DAB0008D50002545600120086011005A68002A39 +:10DAC000FCD00020174A1061174A01309060186995 +:10DAD000154A0028FBD06069505000201149486168 +:10DAE000012111615A69002AFCD000210D4A5160C0 +:10DAF0000D4A013151605A68002AFCD000200122F1 +:10DB0000C021084B49001861074B9A60084B9218D6 +:10DB10005A501A6002E0074800E0074870BDC0464E +:10DB200004E100E0FC10004000100040040500008B +:10DB300000E100E016FCFFFF17FCFFFF37B54C6863 +:10DB40000500002C03D10C4911F0EDFA12E0636AD4 +:10DB500001A84B602278211D033AA36A11F017FB3C +:10DB6000200014F0D2FD01A9280011F0DCFA01A870 +:10DB700011F0D2FA28003EBD3C25002030B505004A +:10DB80008DB0002911D0232A0FD801ACD31C00205E +:10DB900023700123A07002A86370E37014F0DAFD13 +:10DBA00021002868FFF76AFF00E001480DB030BD92 +:10DBB00017FCFFFFF0B585B0040014F031FB204BDB +:10DBC0001B785B073AD50025236CC6B20227DF5FBE +:10DBD000BD420EDA200029B2403011F04DF98642E4 +:10DBE00005D1012320211A00684611F05DF90135A5 +:10DBF000EEE7250023004E3528884C331978013094 +:10DC000007F006FB230050331B8889B28B420FD0EC +:10DC10002B88A26CD654636C2980002B0EDB2A88DB +:10DC200093420BD101235B4263640222023301E081 +:10DC3000012303222021684611F036F905B0F0BD1A +:10DC4000422800200121024A13780B4313707047C9 +:10DC5000422800200221024A13780B4313707047B8 +:10DC6000422800200121024A13788B431370704729 +:10DC7000422800200221024A13788B431370704718 +:10DC80004228002010B5002903DB024B196014F074 +:10DC9000B3FA10BD4C25002070B504001E0004AB83 +:10DCA0001D7805F085FF20000E4B40302360FDF706 +:10DCB00041FC230001364C33013522001E701D73D8 +:10DCC0000023E1214E32A364636513805380938166 +:10DCD000D381013B200063644902FFF7D3FF20009A +:10DCE00070BDC046F430030070B50500141E012C51 +:10DCF00010D003004E331888023B4018197807F003 +:10DD000087FA69640025022C05D12100202010F03B +:10DD10003BFF00E0014D280070BDC04617FCFFFF2F +:10DD200070B5050004000A005035002907D1030032 +:10DD30004E331B882A889A4212D111481FE00129CC +:10DD400006D101002A884E310B889A42FCD007E0A8 +:10DD5000022905D103004E331B88298899420AD035 +:10DD6000A36C28884C341E5C2178013007F050FAEF +:10DD70003000298003E00121FFF7B6FFF0E770BD16 +:10DD80000CFCFFFF70B5151E012D0AD0403011F0BC +:10DD90004EF80024022D05D10121202010F0F4FEC0 +:10DDA00000E0014C200070BD17FCFFFFF8B5114DDD +:10DDB00004002B781B0705D5012112F0A7FC606D2C +:10DDC000FDF78AFA082723002E785833BE432E70B9 +:10DDD0001878FDF74BFA6065002808D02300002072 +:10DDE0005A335C343E4318802E70208000E0024895 +:10DDF000F8BDC0464228002013FCFFFF70B50B4B56 +:10DE000005001B780C009B070ED4FFF723FF2B00A7 +:10DE1000013458331C702800FFF7C8FF04002800A5 +:10DE2000FFF728FF200000E0014870BD42280020D5 +:10DE30000DFCFFFFF0B5060007005C365A3733884B +:10DE40003A8885B004009A421ED0104B1B781B07FD +:10DE50001AD53388426DD15C14F0E6F9230030887E +:10DE600058331978013007F0D3F93B888DB2AB42B3 +:10DE700009D1074901230222684611F015F8012152 +:10DE8000200012F043FC358005B0F0BD4228002090 +:10DE9000FF03000073B50D0006A9040009780430E3 +:10DEA000002A01D1DE070DD5002D0BD00C34260041 +:10DEB00018244C433419A360044B626025606361ED +:10DEC000012200E0002206F0ABF873BD69060300F2 +:10DED000F0B507000400002589B003910492059372 +:10DEE0005A37049B9D4213DA23003E885833197831 +:10DEF000701C07F08DF923005C331B8889B29942AE +:10DF000006D0039B626D5B5D013593553980E8E770 +:10DF1000059B012B03D002210648FDF7A1F8012340 +:10DF200020000093044A00232100FFF7B3FF2800DC +:10DF300009B0F0BDFF03000035DE0100F7B5194C54 +:10DF40001F0023780500019116009B0725D4002AA5 +:10DF500025DD002923D0FFF77DFE23781B0701D59F +:10DF6000002407E02800FFF721FF0028F8D017E081 +:10DF7000A6420DDD019B321B191928003B00FFF75B +:10DF8000A7FF39002418280012F0B0FB002FEFD1B2 +:10DF90002800FFF76FFE200002E0034800E003487E +:10DFA000FEBDC046422800200DFCFFFF17FCFFFF0E +:10DFB000F0B5174E87B0337805005B0705D5002113 +:10DFC00012F0A4FBA86CFDF787F904273378BB4354 +:10DFD00003936B461B7B33702B004C331878FDF793 +:10DFE00045F9A864002810D02B0000244E331C8073 +:10DFF0005C80039B28001F433770064A009423006F +:10E000002900FFF747FF200000E0034807B0F0BDFC +:10E0100042280020B5DB010013FCFFFF70B50E4C59 +:10E02000050023780E00DB0714D4FFF70BFE2378DE +:10E030005B0709D531002800FFF772FE04002800B5 +:10E04000FFF710FE200006E02800FFF7B1FF0028D0 +:10E05000F0D000E0014870BD422800200DFCFFFF19 +:10E06000F7B52C4C0193237805000F001600DB0751 +:10E070004DD4FFF7E7FD23785B0703D5019B1C1EFA +:10E080000AD011E02800FFF793FF0028F6D03FE008 +:10E09000B44237DA3855013400212800FFF740FE3A +:10E0A0001D4B9842F4D12DE0019B012B0AD13C007D +:10E0B000E31BB3421BDA01212800FFF731FE207079 +:10E0C0000134F5E7019B0024022B1BD1280012F03C +:10E0D000ECFA864207DD280012F0E7FA019A311ABD +:10E0E0002800FFF701FE3C00E31B9E4203DCF443E3 +:10E0F000E417344006E002212800FFF711FE2070EB +:10E100000134F1E72800FFF7ADFD200000E00348EF +:10E11000FEBDC046422800200CFCFFFF0DFCFFFFA7 +:10E12000F0B58BB002AF7B60704BB8601B780C0011 +:10E130001500DA072CD45B0708D40800FFF738FF76 +:10E14000011E03D0B86810F031FECAE02000FFF7CE +:10E1500079FD230050331B88FB603B6101235B4248 +:10E160007B6126004E3633883A699A4203D07B6938 +:10E17000013300D197E07B68012B21D07B68022B13 +:10E180002FD07B69002B50DA2000FFF76BFDB868B9 +:10E19000FDF7D0F9A5E0138839699942FBD0002634 +:10E1A000A36C5B5C7B602B6802229B5E9E420DDB56 +:10E1B000230038694C331978013007F029F83961A8 +:10E1C0007B690133DDD122004E32E4E731B2280011 +:10E1D00010F052FE7B68834201D13B697B610136BE +:10E1E000E1E77B690133CCD11C232900F81810F03A +:10E1F00016FE1C237A68F9182000FFF7C3FD1C23C4 +:10E20000F81810F0B7FD3388013B7B611C23F81828 +:10E21000FDF790F91C232000F918403010F007FE9C +:10E220001C23F81810F0A6FDABE76B46FA687B607C +:10E230007B699D1A934205DA23004C331D787B6974 +:10E24000AD1AED182B0069460833DB08DB00CB1A4A +:10E250009D4602AE6A1C0021300014F099FA23009A +:10E260004C333B611A78BB8A20000193FB68009312 +:10E27000A16C330012F002FA230050337B6118883E +:10E280003B6901301978401906F0C2FF7B69200014 +:10E290001980FFF7E7FC2AB23100B868FDF720F9D2 +:10E2A0007B689D461DE00026A36C3A699B5C3B6041 +:10E2B0002B6802229B5E9E420ADA31B2280010F0DF +:10E2C000DBFD3B68834201D13B697B610136EFE7AF +:10E2D000230038694C331978013006F099FF396111 +:10E2E0003FE7BD46B86809B0F0BDC04642280020EF +:10E2F00070B50B4B05001B780C00DB070ED4FFF745 +:10E30000A1FC2B0001344C331C702800FFF750FE99 +:10E3100004002800FFF7A6FC200000E0014870BDC3 +:10E32000422800200DFCFFFF70B5224B86B01B7801 +:10E3300004000D0016009B0701D01F4837E0FFF7CF +:10E3400089FC2000FFF77EFC200012F0BEF90028B7 +:10E3500003DD0121200012F0D9F90021200012F084 +:10E36000D5F929000025201D320005F0BBFD200055 +:10E370000095124A2B002100FFF78CFD200012F0BF +:10E38000A4F9A84207DD01230D4A009321002B00C8 +:10E390002000FFF77FFD0B4B20001968FFF772FC90 +:10E3A0002000FFF75FFC2000FFF764FC002006B0B0 +:10E3B00070BDC046422800200DFCFFFFB5DB010008 +:10E3C00035DE01004C250020F7B580277F053D692B +:10E3D0007C690822113C6C4306002100684614F059 +:10E3E000B9F9104B009A9A4219D000930023019377 +:10E3F000796930001339694312F0BDF9019A009927 +:10E40000300012F0D0F92100300012F0B4F979692F +:10E41000AB08133969432200300012F0B6F90198B5 +:10E42000FEBDC046FECA0000F0B50D00ABB00D92B7 +:10E4300000213022060012A80B9314F0A9F928003D +:10E4400014F0E6F9431C0C93102B00DDB6E00B9B97 +:10E45000202B00D9B2E02900300012F0D1F9071EBC +:10E4600029D129000C9A12A814F074F90D990B9A6D +:10E4700016A814F06FF980235B051F695A693000F4 +:10E48000113A7A435D690D92FFF79EFF0D9B302292 +:10E490000833002104001EA80F9314F079F9290015 +:10E4A00013397943300012F066F90F9B0B93002368 +:10E4B0000C930E9335E010300B9A0D9914F03BF944 +:10E4C0000400380014F021F9002C7AD0C9E70B9928 +:10E4D00030221EA814F03EF912A91EA814F08EF9DD +:10E4E000002822D13849300022001091119412F0F6 +:10E4F0005AF96A460B9B099315AB23CB23C223CB56 +:10E5000023C223CB23C23000149B1299139A12F01A +:10E5100058F901230E930B9B30330B930C9B013363 +:10E520000C930C9BA342D2DB10E06A460B9B099331 +:10E5300021AB23CB23C223CB23C223CB23C2300066 +:10E540001E991F9A209B12F03CF9E4E7E543302125 +:10E55000ED1725404D430F9B5D190E9B002B1BD1E2 +:10E56000B81E06F0E5FC84422AD017490134300079 +:10E5700022001091119412F016F96A46099515AB14 +:10E5800023CB23C223CB23C223CB23C23000129937 +:10E59000139A149B12F015F90D99300012F0EBF854 +:10E5A00080235B0559690C23634313390233794394 +:10E5B0000D9A300012F0E9F8002402E0034C00E06C +:10E5C000034C20002BB0F0BDFECA000017FCFFFF7B +:10E5D00013FCFFFF8023F0B55B051A6995B002922A +:10E5E0005A6905910299113A51435C69029B133CA7 +:10E5F000050003915C43FFF7E7FE061E4ED000279F +:10E60000039B302208330021083408A8019314F03A +:10E61000BFF82100280012F0AEF80497B74220DAC4 +:10E620000199302208A814F095F8059908A814F06B +:10E63000E5F8002809D11B49721E280006910792AF +:10E6400012F0B1F80123049306E022000C23019993 +:10E65000280012F09AF83034019B013730330193CF +:10E66000DCE7049B002B05D10E493200280012F094 +:10E670009AF813E00399280012F07DF880235B05D7 +:10E6800059690C23029A13394A4373431100280035 +:10E690000233039A12F079F8002000E0024815B026 +:10E6A000F0BDC046FECA00000CFCFFFF70B50400C0 +:10E6B000A280FA22002308000C4992000831216050 +:10E6C000A3716061E260A3606382094912F098F867 +:10E6D000051E09D00100200010310222123014F072 +:10E6E00039F8280014F011F8200070BD70320300D2 +:10E6F0002C41030030B50225837987B004002B42FA +:10E7000004D1FCF7F3FBA3792B43A371200012F093 +:10E71000BBF800282DD06B46DD1C280012F0ABF8AA +:10E720002B78002B03D001A812F0A3F80FE00122F0 +:10E73000114B1A60114A5368002BFCD000220F4B7A +:10E740005A600F4B01321B6801930B4B5A60032236 +:10E75000019BD9170A40D3189B102382FCF76CFE4B +:10E76000E368A18818180123A0601A0002A810F01D +:10E770009BFB002007B030BD00C00040FCC0004043 +:10E7800008C5004010B50400024B036005F092F983 +:10E79000200010BD9032030010B5040005F096F97A +:10E7A000034B00222360002320002265636510BD17 +:10E7B00090320300022802D10122014B1A707047E7 +:10E7C0004328002070B5064C05002378002B04D1A7 +:10E7D000044802F03BFE01232370280070BDC046B0 +:10E7E00044280020B5E7010070B50C0010F05BF97B +:10E7F000002811D0164B0022A50A1C001A70280010 +:10E8000012F06FF8002803D00A2013F051FEF6E74B +:10E810002378002BFCD019E0022180250D4B0E4AF5 +:10E82000ED00995080205959C0000029FAD0A1214B +:10E83000084DC9006C5019580029FCD0002005492A +:10E8400088508021C9005A58002AFCD070BDC046AB +:10E850004328002000E0014004050000F8B50C004A +:10E8600015001E0010F01FF9002812D0194B0022CD +:10E870001F001A7032002900200012F030F8002822 +:10E8800003D00A2013F014FEF4E73B78002BFCD0F1 +:10E890001EE00121104A114B944699508021C90075 +:10E8A0005A58002AFCD080270022FF008021C9008E +:10E8B000964207DD910068586050D9590029FCD074 +:10E8C0000132F3E7002260461A505A58002AFCD061 +:10E8D000F8BDC046432800200405000000E00140C8 +:10E8E000F0B589B00E9D06000F000592002D05D1F0 +:10E8F000802252055569314AAD18AD02AC05A40D10 +:10E9000057D1BA0A92020192BA05920D0292D21818 +:10E91000049205993A00300011F0E5FF00280AD171 +:10E92000FF2403223900049BA400043393432140B5 +:10E930000393019D14E0002D3BD029003000FFF728 +:10E9400053FF8023019A5B0029003000FFF786FF08 +:10E9500001993000FFF748FF80232100DB0003937B +:10E9600000230793039B8B4225DD0322029B0A4071 +:10E97000D200994207DB049B994204DA059B029876 +:10E980001B1A5B5C00E06B5C93400327079A4C1CEE +:10E9900013430793274001D02100E3E7019B89102F +:10E9A0008900591807AA01233000FFF757FF07977E +:10E9B000F2E7034800E0002009B0F0BDEDFF3F00A2 +:10E9C00017FCFFFF08B4024B9C46443808BC604764 +:10E9D00003090300F8B5FA230189DB000400594359 +:10E9E000324812F08AFAFA21890006F0A1FA304F73 +:10E9F0002081A17A380012F080FA23002600250039 +:10EA000022894C33A072A0361A808C3531780023CD +:10EA10002A22286811F021FA002801D0254844E074 +:10EA200031781F235B22286811F017FA0028F5D1EE +:10EA3000317820235C22286811F00FFA0028EDD1EC +:10EA4000317801232C22286811F007FA0028E5D13B +:10EA5000317801232D22286811F0FFF90028DDD13B +:10EA6000317801232E22286811F0F7F90028D5D13A +:10EA7000A17A380012F03CFA3178C3B20E2228682D +:10EA800011F0EBF90028C9D1FA2321899B005943E1 +:10EA9000064812F02DFA01231843C3B231782A2216 +:10EAA000286811F0DAF90028B8D1F8BD583303000E +:10EAB000D83203000EFCFFFF08B4024B9C464438DA +:10EAC00008BC6047D5E90100074B10B51A000400E7 +:10EAD00008323C3302604364443010F0BCFC200038 +:10EAE00010F0C9FB200010BDF832030008B4024B3F +:10EAF0009C46443808BC6047C9EA010008B4024B90 +:10EB00009C46443808BC60470D090300F0B5042555 +:10EB100083798BB004002B4204D1FCF7E7F9A37989 +:10EB20002B43A37120009030FEF7C2FC061E66D175 +:10EB30002300A033197820000C2307AD00938C30FC +:10EB40002B0001220068FEF70BF9002801D02E4EA1 +:10EB500056E00A2304AA9B182A785A706A781A7019 +:10EB60000022995EAA785A70EA781A7000201A5E1C +:10EB70000392287958706879187000201F5EA87970 +:10EB80005870E87918700022985E0490287A5870BE +:10EB9000687A18700022985E0590A87A5870E87A12 +:10EBA00018701F2000229B5E039A9C46A37A524253 +:10EBB0005A435943D5177B430540AA185211A26105 +:10EBC000DF17CA1702403840C3185B112362642361 +:10EBD0005118059A5B4253434911A3676423E161CD +:10EBE0006146049A20005A434B43E267221DD367D3 +:10EBF00010F0B2FB2000443010F034FC00E000269E +:10EC000030000BB0F0BDC0460EFCFFFF08B4024B55 +:10EC10009C46443808BC60470DEB0100F7B51E0068 +:10EC2000040008AB1B881500019309AB00911A88FA +:10EC300031000AAB1F88FCF755FE20003A00310076 +:10EC40004430FDF74DF9134B20001A003C33636448 +:10EC5000230008322260009A8C331A60AB8890300F +:10EC60008380AB796A4683710B4B92880360AB68F3 +:10EC7000032183602B7B03736B7B4373AB7B8373B9 +:10EC80002300A0331A80FEF715FD2000FFF7A2FE37 +:10EC90002000FEBDF832030044310300F8B5FA2627 +:10ECA0000189B60004007143264812F026F93100AC +:10ECB00006F03EF9244F2081A17A380012F01DF9A8 +:10ECC0002500A0725835297800232A22606C11F0A3 +:10ECD000C4F8002801D01D4832E0297810232B22E7 +:10ECE000606C11F0BAF80028F5D1297801232D22A3 +:10ECF000606C11F0B2F80028EDD1297801232E22A2 +:10ED0000606C11F0AAF80028E5D1A17A380012F061 +:10ED1000EFF82978C3B20E22606C11F09EF800283B +:10ED2000D9D121890748714312F0E2F80123184331 +:10ED3000C3B229782A22606C11F08FF80028CAD15A +:10ED4000F8BDC046F4330300A03303000EFCFFFF00 +:10ED500010B50400034B0833036010F08CFA200058 +:10ED600010BDC046C03303007FB50425837904007D +:10ED70002B4204D1FCF7BAF8A3792B43A3712000EE +:10ED80004830FEF795FB051E24D12300583319782F +:10ED9000062302AE009301223300606CFDF7E0FF12 +:10EDA000002801D00D4D16E0042302200022A17A94 +:10EDB000F3563056B2564B43C0004A43404241439B +:10EDC000DB0023622368D200A161E2619B6A20001C +:10EDD000984700E00025280004B070BD0EFCFFFF3E +:10EDE000F8B50400150006AA168807AA0F001288B5 +:10EDF0001900FCF777FD0F4B67640833236023008D +:10EE0000AA8848339A80AA7920009A710A4AA26493 +:10EE1000AA6822652A7B1A736A7B5A73AA7B9A7343 +:10EE20000023A371230058331E80FFF737FF200013 +:10EE3000F8BDC046C03303004431030010B50400E0 +:10EE4000034B0833036010F006FB200010BDC046E2 +:10EE5000FC33030070B50825837986B004002B428B +:10EE600004D1FCF743F8A3792B43A37120004C3065 +:10EE7000FEF71EFB002830D023005C3319780623F0 +:10EE800004AE009301223300A06CFDF769FF051E5C +:10EE900001D0134821E00E2332786B445A70727807 +:10EEA00020001A700022995E64224A43A263B2785D +:10EEB0005A70F2781A700022995E642252425143CD +:10EEC0006163317959707179197000215B5E5A4321 +:10EED0002368E2631B6A9847280006B070BDC046ED +:10EEE0000EFCFFFFF0B507005C3787B004003978EF +:10EEF00000231022806C10F0B0FF0326002807D0FA +:10EF00001F483AE02B78334211D06420FCF78AF88E +:10EF10000F2502ABED180123397808220093A06C6D +:10EF20002B00FDF71DFF164B9842EBD1E8E7FA25C1 +:10EF30002189144EAD006943300011F0DEFF290035 +:10EF400005F0F6FF20813978A0231122A06C10F083 +:10EF500084FF0028D4D1A36C218903936943300036 +:10EF60003F7811F0C5FF01231843C3B210223900C6 +:10EF7000039810F072FF0028C2D107B0F0BDC04660 +:10EF80000EFCFFFF80340300F8B50400150006AA4C +:10EF9000168807AA0F0012881900FCF7A1FF0D4B75 +:10EFA000A764083323602300AA884C339A80AA7987 +:10EFB00020009A71084AE264AA6862652A7B1A7383 +:10EFC0006A7B5A73AA7B1E829A73FFF78BFF20001D +:10EFD000F8BDC046FC33030044310300F7B5FA2501 +:10EFE0000189204FAD0004006943380011F085FF0E +:10EFF000290005F09DFFA17A20811B4811F07DFFBB +:10F000002600636CA07200932189583633786943D7 +:10F010003800019311F06CFF07231843C3B220227C +:10F020000199009810F019FF002801D00F4818E04E +:10F03000317810232222606C10F00FFF0028F5D1E8 +:10F04000A17A0948656C377811F052FF80235B4242 +:10F050001843C3B223223900280010F0FEFE002816 +:10F06000E4D1FEBD2C350300043503000EFCFFFF88 +:10F0700010B50400034B0833036010F0FCF82000C7 +:10F0800010BDC04688340300F0B50425837985B0EF +:10F0900004002B4204D1FBF729FFA3792B43A37172 +:10F0A00020004830FEF704FA002838D023005833F7 +:10F0B0001978062302AE0093A8223300606CFDF796 +:10F0C0004FFE051E01D0174829E01F210023F25EE4 +:10F0D000D3170B409A18521193B20222B75E3380B5 +:10F0E000FA170A40D7197F11BAB20427F05F1BB292 +:10F0F000C71739400818401181B2A07A5B424343D8 +:10F10000728012B2B180524209B242434843E36175 +:10F1100023682062A2619B6A20009847280005B0FE +:10F12000F0BDC0460EFCFFFFF8B50400150006AAAE +:10F13000168807AA0F0012881900FCF7D3FB0F4BA3 +:10F140006764083323602300AA8848339A80AA7929 +:10F1500020009A710A4AA264AA6822652A7B1A735F +:10F160006A7B5A73AA7B9A730023A37123005833D6 +:10F170001E80FFF733FF2000F8BDC046883403002F +:10F1800044310300F7B5FA2504000189134EAD00A0 +:10F190006943300011F0B1FE290005F0C9FE2700D7 +:10F1A000A36C208100935C373B7881B269433000C7 +:10F1B000019311F09DFE6022C3B20199009810F0F6 +:10F1C0004CFE002801D0064807E03978012362226E +:10F1D000A06C10F042FE0028F5D1FEBD8035030082 +:10F1E0000EFCFFFF10B50400034B0833036010F062 +:10F1F00032F9200010BDC046343503007FB5082524 +:10F20000837904002B4204D1FBF770FEA3792B43D2 +:10F21000A37120004C30FEF74BF9002822D02300C8 +:10F220005C331978062302AE0093E8223300A06C09 +:10F23000FDF796FD051E01D00B4813E00223F25E98 +:10F2400096235B425A4362630021725E200053435F +:10F25000A3630423F25E96235343E36323681B6A8C +:10F260009847280004B070BD0EFCFFFFF8B50400FD +:10F27000150006AA168807AA0F0012881900FCF7C5 +:10F280002FFE0D4BA764083323602300AA884C335C +:10F290009A80AA7920009A71084AE264AA68626595 +:10F2A0002A7B1A736A7B5A73AA7B1E829A73FFF7B2 +:10F2B00069FF2000F8BDC046343503004431030027 +:10F2C00010B50400054B083303601C300FF052FDED +:10F2D000200018300FF04EFD200010BD88350300CF +:10F2E000FF23F0B52B4C8DB0237000230500694639 +:10F2F0000088009303F028FC002802D16B469B781D +:10F300002370254E3368DB68002B06D10023288844 +:10F310001A00190011F06AFB3AE02378032BF5D8A4 +:10F320001E4901A8FCF7CCF8336801A9DE6804A8DF +:10F330000FF075FD04A9300011F08FFA060004A843 +:10F340000FF018FD371E1ED031002022103104A806 +:10F3500013F000FA300013F0D8F9217804ABC9009B +:10F360005918082202A813F0F5F928880123082269 +:10F3700002A911F03BFB0127002804D12888084A84 +:10F380000C2111F031FB01A80FF0F4FC002FBDD0CF +:10F390000DB0F0BD9020002050250020B7410300A3 +:10F3A000FFFF0000F0B5837991B004005B071BD527 +:10F3B000FCF742F800232269801A9941994203D14F +:10F3C000F423FF3398420FD9A068002808D0364BA9 +:10F3D0001D8801F04FFC036815221B6A290098471D +:10F3E0000422A3799343A371A3799B075AD52F4D88 +:10F3F0002B68DB68002B51D02D4B1A780193032A20 +:10F400004CD8294B2B491B8804A80093FCF758F8CB +:10F410002B6804A9DE6808A80FF001FD08A93000D8 +:10F4200011F01BFA070008A80FF0A4FC02AB9E1D08 +:10F4300008233200338006A9073B009811F0D8FA60 +:10F44000002F08D039002022103108A813F082F9CB +:10F45000380013F05AF9019B32881B7806A9DE00A8 +:10F4600008AB9E19300013F066F9002813D008226B +:10F4700006A9300013F06EF92B6804A9DD6805A811 +:10F480000FF0CDFC202308AA05A9280011F0EBF904 +:10F4900005A80FF06FFC04A80FF06CFC0222A37902 +:10F4A0009343A37111B0F0BDE82700205025002040 +:10F4B00090200020B7410300F7B504000025019219 +:10F4C000C77FAF4254D966197078884202D1152996 +:10F4D00027D804E0605D2D180135EDB2F1E7012277 +:10F4E0008A40264802421CD0D91901201F2943DC3A +:10F4F000E1193718B94210D80021C8B2834205D9A2 +:10F50000019A7018575C01318770F6E7625D9A18AE +:10F510006255E27F9B18E37728E00878C8540139E8 +:10F52000E8E7655D013DEDB2AB4209D10021C8B20B +:10F5300083421BD9019A7018545C01318470F6E73C +:10F54000FF187F1B01201F2F16DC0227A81C7F42FB +:10F5500036187F1BE07F2218964203D23078F05590 +:10F560000136F7E7451B023DE57701E0002003E0A7 +:10F57000019A200011F086FAFEBDC046FC00200072 +:10F58000F0B585B001930AAB1E880BAB1B78451C08 +:10F5900002930EAB1B78040003930B7817000370E3 +:10F5A0004B8A102243820131280013F0D3F86B46B6 +:10F5B0009B88268363836B461B7B002623776B46E1 +:10F5C00001221B7A6761E683EB77A31CDA770C9B39 +:10F5D0000C256362230020000D9A28331A705E7098 +:10F5E0009E702A0031002C3013F0D2F82000074B17 +:10F5F000E663A3632A003100403013F0C9F820000D +:10F60000034B2665E36405B0F0BDC046070A03005E +:10F61000F909030070B50D0001F02CFB040003682C +:10F62000002D02D15B69984708E09B6898478542A6 +:10F6300004D2236820009B6898470500FA208000C8 +:10F640006843024905F074FCE08070BD710200005F +:10F65000F0B507001600A1B002C704006B4918A856 +:10F660001D0011F041FA331E03D0300013F0D0F822 +:10F6700083B201220492002203920292023201928A +:10F680000093320018A93800FFF77AFF2300604981 +:10F69000583318A8079311F027FA2B1E03D028001F +:10F6A00013F0B6F883B20122049200220392029270 +:10F6B0000232019200932A0018A90798FFF760FF11 +:10F6C00023005449AC3318A8089311F00DFA269B77 +:10F6D000002B03D0180013F09BF883B20122049290 +:10F6E000002203920292023201920093269A18A9F4 +:10F6F0000898FFF745FF631CFF33474918A8099393 +:10F7000011F0F2F9279B002B03D0180013F080F8BA +:10F7100083B2012204920022601C03920292023200 +:10F7200001920093279A18A9FF30FFF729FF2300C1 +:10F730005533FF33394918A8099311F0D5F9289B9F +:10F74000002B03D0180013F063F883B20122049257 +:10F75000002203920292023201920093289A18A981 +:10F760000998FFF70DFF2300A933FF332C4918A890 +:10F770000A9311F0B9F9299B002B03D0180013F05C +:10F7800047F883B201220492002218AD039202923C +:10F79000023201920093299A29000A98FFF7F0FE9D +:10F7A000204B1B780B93002B2DD1079B12971393A3 +:10F7B000089B0DAF1493631CFF331593099B1A49E3 +:10F7C00016930A9B3800179311F08EF91D214920DA +:10F7D0003B7810222B707B8A12AE6B8206ABC91865 +:10F7E000C01812F0B7FF06232B756B469B8D20685F +:10F7F000AB83AE6101F04EFA036829001B6898479D +:10F800000122084B1A70200021B0F0BD292A000007 +:10F81000242A0000252A0000272A0000262A0000AA +:10F82000282A0000452800200A18000070B500258D +:10F8300004000B4B8580083385710360C16018306C +:10F84000FBF778FE20001C30FBF774FE0123621CDE +:10F85000D377044AA560656120001460A37170BD70 +:10F860008835030050250020FA2130B585B0050009 +:10F8700001230222890068460FF016FB074C20681E +:10F88000002809D011F07AF92988054B22681980DF +:10F89000022193790B43937105B030BD50250020B0 +:10F8A000E827002010B50C1E072C0BD8806801F04B +:10F8B000E1F9054B195703685B6C9847002802D0A3 +:10F8C000024800E0024810BDB342030016FCFFFFEF +:10F8D00017FCFFFFF0B5A54C0D00A54404000493F0 +:10F8E0009AAB1B78A24909A805930792FBF7E8FD9C +:10F8F000200029001C300FF09AFAC020800001F08F +:10F900009BFD082012F0EFFE0700002101F07AF9BC +:10F9100015AD0021A7600C220EA812F039FF2B00B4 +:10F920000EAA43CA43C3934B2900EB60002338005F +:10F930002B6111F04CFBA06801F09CF90C22002116 +:10F940000690280012F024FF142012F0CCFE8A4BFF +:10F950002A0015930300C2CAC2C3884B069EC36027 +:10F960000023A43603613368002B00D003613060AC +:10F97000A06801F08FF90C2200210600280012F087 +:10F9800007FF142012F0AFFE7D4B1593030086CDC8 +:10F9900086C37C4BC36000230361336B002B00D014 +:10F9A00003613063A06801F065F915AD0C220021F8 +:10F9B0000600280012F0ECFE142012F094FE724BA8 +:10F9C00098361593030086CD86C3704BC360002321 +:10F9D00003613368002B00D003613060012004AB69 +:10F9E0001B7C04AA034308A9137411F003F8A06850 +:10F9F00001F060F9036866495B6A9847A06801F006 +:10FA000059F9036863499B699847A06801F052F966 +:10FA10000022036800921D6805990323A847059BEF +:10FA2000002B0AD0200011F0B2F8032805DDA068F1 +:10FA300001F040F90368DB6898470EA811F019F847 +:10FA40002F2004ABC01811F014F8362004ABC018F6 +:10FA500011F00FF83D20042504ABC01811F009F88F +:10FA60000EAB0A93A06804AB5D7701F023F903683D +:10FA70000AA91B699847A06801F0FCF803680AA965 +:10FA80005B6D9847A06801F0F5F803680021DB6D15 +:10FA90009847A06801F0EEF8036802219B6D984733 +:10FAA00006212000FFF7FEFE182012F01CFEA168C0 +:10FAB00000F062FA542012F016FE049AA16800F0D9 +:10FAC00053FD354B354A1B68A1680393344B15A889 +:10FAD0001B680CAE0293334B00271B680193079BF6 +:10FAE0001B685B190093304B12681B68FFF7B0FD71 +:10FAF000302012F0F8FD049AA16800F0FBFAA0682B +:10FB000001F0B8F8036831009B6A98470823A068A1 +:10FB10003380DB187380B78001F0ACF803683100E4 +:10FB2000DB6A98472900A06810F0EAFF099A0921CA +:10FB30009378A068521910F0F6FFA06801F09AF8C7 +:10FB400032210771A068FFF765FD04AB1B7FBB4244 +:10FB500004D0A06801F08EF810F0BCFF09A80FF0E7 +:10FB600009F995239B009D44F0BDC046ACFDFFFF05 +:10FB7000C3410300150A030069F80100230A0300CA +:10FB8000E1F20100310A03005F0A03003F0A0300AB +:10FB9000ADFB0100E1FB01005825002054250020A9 +:10FBA000102000205C2500200C20002013B5062228 +:10FBB0006846FBF795FC094B1C68002C0AD0694687 +:10FBC00001A80FF02CF9200001A911F001F801A8FB +:10FBD0000FF0D0F868460FF0CDF813BD5025002087 +:10FBE000002373B501AE0C0031000500019302F053 +:10FBF000ABFF002802D1B278064B1A70064B18688A +:10FC0000002806D061426141044BC9B21D8010F04A +:10FC1000E7FF73BD9020002050250020E82700203A +:10FC200030B5284CA9B06A220D000DA8210012F0B1 +:10FC300091FD0DA903A8FBF7B1FC03A906A80FF0DD +:10FC400063F901230193013BFF3B00930533FF332D +:10FC5000642206A92800FDF72BF806A80FF047F943 +:10FC6000210019226A3106A812F074FD0522002431 +:10FC7000110006AB04A80FF06EF904A905A80FF057 +:10FC800043F9019400942300220005A92800FCF701 +:10FC900053FF05A80FF02BF921002800FDF736F8D7 +:10FCA00005340520FBF7BEF9FF2CF5D1FA208000C2 +:10FCB000FBF7B8F904A80FF01AF903A80FF017F929 +:10FCC00029B030BD34410300F0B5954B95B0059295 +:10FCD0001A68082304000291D16C06A80B43D36470 +:10FCE0009049FBF7EDFB904907A8FBF7E9FB2200E1 +:10FCF00000250DAE30001C3206A90FF0A7F807AAA8 +:10FD0000310008A80FF0A2F830000FF033F8631CA0 +:10FD1000DD77A06800F0AEFF03680BAF5B69984722 +:10FD2000300010F0A6FE2B2004ABC01810F0A1FE8E +:10FD3000322004ABC01810F09CFE392004ABC01870 +:10FD400010F097FE0B960426A0687E713D7100F0BE +:10FD500091FF036839005B6D9847A06800F08AFF47 +:10FD6000036829009B6D9847A06810F0F6FE0621F5 +:10FD7000A06810F0C5FE089A09219378A06892192E +:10FD800010F0D1FEA06800F075FFC8210571A068D1 +:10FD9000FFF740FCA06800F06DFFFF270581A06819 +:10FDA00000F068FF10F096FE0298FCF70DFE2000B0 +:10FDB000FBF79CF802992000FFF732FF0299200020 +:10FDC00010F021FF039504966369DB0735D5574989 +:10FDD00009A8FBF77DFC09A90AA80FF095F80022F5 +:10FDE0000AA91300019200920298FCF7A5FE0AA846 +:10FDF0000FF07DF8039B002B01D1043F00E0043796 +:10FE0000282F03DD0023FE2F06DC06E002980FF00A +:10FE1000F7FF0123002F00DC039305980FF007FB89 +:10FE2000002806D0012362699A431300049A134301 +:10FE3000636109A80FF05BF800256369049A134217 +:10FE40002AD0FF210298FCF761FF0025A369022256 +:10FE50009B5E9D421BDA200029B218300FF00CF88F +:10FE60000023010002981A007430FBF783FCC820BD +:10FE70008000FBF7D7F802980FF0C2FFC820FBF70D +:10FE8000D1F802226369134201D10135DEE7FA207D +:10FE90008000FBF7C7F8002502226369134233D0C4 +:10FEA00008261E401AD0224909A8FBF711FC09A90F +:10FEB0000AA80FF029F800220AA901920092130063 +:10FEC0000298FCF739FE0AA80FF011F81948FBF761 +:10FED000A9F809A80FF00BF8174D15E0174909A864 +:10FEE000FBF7F6FB09A90AA80FF00EF83300320061 +:10FEF0000AA9019600960298FCF71EFE0AA80EF0C9 +:10FF0000F6FF09A80EF0F3FF6420FBF78BF80C4B0B +:10FF100001359D4200DC57E70EF0D7FD54E7C0469F +:10FF2000B0240020D1410300E1410300E34103007C +:10FF300028420300983A00008C0A00006542030042 +:10FF40008B0A000073B50B4E05003100C06810F03D +:10FF500057FC041E0AD16B46DA1D107004233100D1 +:10FF6000E868FEF761FA200012F0CFFB0EF0ADFD5D +:10FF700073BDC0464B3E0300F0B505000024574B4F +:10FF8000A9B0083303600391A96021000BAB1A19D3 +:10FF900001345170102CFAD1012251481A701A1BE9 +:10FFA000013C015D5174002CF9D19A7B597B1202FE +:10FFB0000A43290045270C31029125211B7813AEF5 +:10FFC000337002ABFF18C91872823800102212F089 +:10FFD000C1FB029B02AA7361012333833377093388 +:10FFE000FB771DAB1C706D239B181C706E232100CA +:10FFF0009B1874830C22F4831EA81C70746212F088 +:020000040002F8 +:10000000C7FB384B0C22B3632100F46323A812F022 +:10001000BFFB354B0222F364462302A95B18DA7753 +:10002000220034652C73059606AF3B1901345A70D3 +:10003000102CFAD101232D493B703B1B013C0A5D7A +:100040005A74002CF9D111212520BB7B7A7B1B022D +:100050000BAE13433A78738202ABC9183270C018E2 +:10006000102212F077FB01230398337505ABB361BF +:10007000B48300F00FFE036831001B68984713AB90 +:10008000DB8BA868AB8200F005FE03680094A98AA8 +:10009000029ADE680123B047A86800F0FBFD0290D9 +:1000A000142012F020FB06000C22210012F070FB3D +:1000B000300001233461082220C0390007930694E0 +:1000C00012F048FB0A4BF360029B9B69002B00D0A7 +:1000D00033612800029B9E6129B0F0BDA03503006A +:1000E000CB420300070A0300F9090300BB420300E7 +:1000F0006F0C0300F0B500260400764BDDB008332A +:1001000003608160C260868086713200724947A8B0 +:1001100010F04DFE230014330893122301250193A0 +:100120000E3B04950093089A330047A90396029664 +:100130001DA8FFF725FA3200684947A810F037FEDE +:100140000C2322000193083B15AF10320495009355 +:1001500047A933000396029632A8FFF711FA32003E +:100160005F49380010F023FE23001C330993082355 +:100170000193043B390004950093099A33000396D8 +:10018000029647A8FFF7FCF932005649380010F0F4 +:100190000EFE542012F0A7FA2300183307931223FF +:1001A00001930E3B390004950093079A33000396A0 +:1001B00002960690FFF7E4F9069B0822A3624A4BD9 +:1001C0000AA90A93069B0B961800DC62303012F0E5 +:1001D000C1FA069A454B268293631300668229333F +:1001E0001D7023690422E3610999079812F0B2FA9D +:1001F00004220799089812F0ADFA6622022304A996 +:100200005218D377BA225218D37787225200521845 +:10021000D377069A3649D218D3771DAB0C9332ABFD +:100220000D9347AB0E93069B3200A68510A80F9343 +:1002300010F0BDFD30223121452004AB9B181B7806 +:1002400012323B7004AB9B181B88323A7B8204ABA2 +:10025000C918C01812F07EFA04230CADA0683B75D3 +:10026000BD61BE8300F016FD036839001B68984726 +:10027000822204AB9B181B885432238404AB9B1846 +:100280001B885432A38404AB9B181B88A06863842A +:1002900000F000FD0700142012F025FA05000C22E2 +:1002A000310012F075FA2800124B2E61082210C09E +:1002B00010A91093119612F04DFA0F4BEB60BB6929 +:1002C000B34200D02B61BD612000FAF70FFE200081 +:1002D0005DB0F0BDAC350300EB4203001B430300EF +:1002E0000B430300DB420300810D0300ED0C030010 +:1002F000FB42030065030200170D0300F0B5040084 +:100300000E00150085B000930CAB1B8810300193D4 +:100310000EF0BFFD26806580182012F0E4F907007A +:1003200002AE33003D000AAA03CA03C3009B102299 +:1003300008C50021280012F02BFA310008222800FD +:1003400012F008FA064B02227B612000002301997B +:10035000A7600A43E360A2802362636205B0F0BD38 +:10036000410D0300F0B50B898DB00593CB680500F6 +:1003700004934B88828C9A420ED1049C059B049A6C +:100380001B1BD318032B39DD62882188012308A8A1 +:100390000EF08AFD0434F1E7428C9A422ED1049C7F +:1003A000059B049A1B1BD318032B27DD23882820C9 +:1003B00006936388EF680793114B08930023099312 +:1003C00012F091F9C0236A460600029308AB03CBF2 +:1003D00003C22B000699079A3000FFF78FFF3B6896 +:1003E00031005B6838009847002805D030000EF0D7 +:1003F00077FC300012F089F90434D1E70DB0F0BD7C +:10040000010E030070B5040090B0806810F0F3FC9A +:100410000223010019401AD1A38D002B17D00D4BD8 +:100420006A4604931023E568A1850591029304AB05 +:1004300041CB41C20A00230006A8FFF75FFF2B68EB +:1004400006A99B682800984706A80EF049FC10B042 +:1004500070BDC046010E030082B0F0B587B0040045 +:1004600003A80D930C92FEF7ADF90CAB5D88022D3D +:1004700034D0FF2D62D0012D64D104A810F0BAF958 +:10048000334904A810F0BCF905AE071E06D12B00B5 +:1004900032002F4904A83570FDF7C6FF380012F06E +:1004A00034F9256DAB0503D1290003A8FEF79CF9AB +:1004B00022001023290003A80C32FEF7CFF90222F4 +:1004C0002449300012F046F9206800F0E3FB03688D +:1004D000218932005C690223A04733E02200256DA8 +:1004E000102329000C3203A8FEF7B8F980235B0122 +:1004F000EC1880256D056B69174A9B189B029C427E +:1005000012D2164B22689A420CD1154B62689A425D +:1005100008D1002305AA13702100009303A801331A +:10052000FEF7DEF90834E6E705A810F063F908499C +:1005300005A8FEF74FF80EF0C8FA03E0094B18685B +:10054000FFF700FD07B0F0BC08BC02B01847C0467A +:10055000563E03002B430300EDFF3F00EF40110424 +:10056000BBA22FB850250020F0B5002504000300E1 +:10057000216042602A00A9B04C338572C5721D709B +:1005800002AB00910565DD700BAF7B1901355A7028 +:10059000102DFAD1012365493B707B1B013D4A5D5B +:1005A0005A74002DF9D12521BB7B7A7B1B0213AE37 +:1005B0001343738202ABC91845233A7802A81B186B +:1005C00032701800102212F0C5F8012202AB03337A +:1005D0006421736114237283327702AA5218137054 +:1005E00033831DAB1D706D2302AA9B181D706E23F3 +:1005F00029009B18F5830C221EA81D70756212F04D +:10060000C7F84B4B0C22B3632900F56323A812F003 +:10061000BFF8484B02A9F364462302225B18290065 +:10062000DA773565039606AB5A1901355170102DEE +:10063000FAD1012240481A705A1B013D415D5174A4 +:10064000002DF9D19A7B597B12020A4325201121F2 +:100650001B787A823B7002AB1022C918C01812F0C6 +:1006600079F8012300983B7503ABBB61BD8300F0B3 +:1006700011FB036839001B689847F38B20682381BE +:1006800000F008FB0700142012F02DF806000C22E1 +:10069000290012F07DF83000284B3561082210C087 +:1006A00004A90493059512F055F8254BF360BB6936 +:1006B000002B00D03361BE6163682820019312F0E3 +:1006C00012F8050010300EF0E4FB002624236E80A3 +:1006D0002B80182012F007F807001A4B10C7009063 +:1006E0001022310038000693079612F051F80822C4 +:1006F00006A9380012F02EF8134B009AEE605361F1 +:100700001223AB80019BAA601B682E626E625B683D +:10071000290001989847B04205D028000EF0E0FA71 +:10072000280011F0F2FF200029B0F0BD2F43030094 +:10073000070A0300F90903003F43030015080200FC +:100740003B0E030059040200650E03007FB5CB7811 +:10075000827A04000D00934226D006D2D31A0721D4 +:100760000022DD0F9942554104E09B1A0125F82B28 +:1007700000DC0025EDB2002D49D102222449684653 +:10078000891811F0E7FF206800F084FA03682189D6 +:100790005E696A460223B047E37A0433DBB2E37250 +:1007A000A3724C34257032E00600013383722300BB +:1007B0004C3630780C33000118180431102211F037 +:1007C000C9FF3378012B16D0002B0DD0032B1CD181 +:1007D000012324211A0068460EF066FB00233370C3 +:1007E000E37A0433E37212E06B78AA781B021343B6 +:1007F000236501230AE06B781A06AB781B041343C8 +:10080000226D13432365022300E0013333707FBD63 +:100810002B430300F0B54A88038997B007009A423A +:1008200000D08DE00B89002B00D189E0CD682C78B9 +:10083000022C00D17EE008D8002C0BD0012C00D077 +:100840007EE02900FFF782FF7AE0EE2C52D0FF2CE9 +:1008500068D075E006A800F089F9142101AE347063 +:100860006B7806AA73706B780E204B43D3189B6885 +:1008700068441B0EB3706B784B43D3189B681B0CFA +:10088000F3706B784B43D3189B681B0A33716B78FA +:100890004B43D3189B6873716B784B43D318DB6859 +:1008A0001B0EB3716B784B43D318DB681B0CF371D1 +:1008B0006B784B43D318DB681B0A33726B784B435E +:1008C000D318DB6873726B785943511810310822C2 +:1008D00011F040FF386800F0DDF9036839895D697F +:1008E00032001223A8473B004C33BC72FC721C70D0 +:1008F0003C6525E006AD03220021280011F048FFE9 +:1009000001236B700F4B2C70186810F0ADF9A870B4 +:10091000386800F0BFF9036839895C692A0003234D +:10092000A0470DE06B78002B04D0012B08D10EF00E +:10093000CCF805E001232200242106A80EF0B4FA29 +:1009400017B0F0BD50250020002815D00060416090 +:100950008260C360046145618661C7614446046288 +:100960004C464462544684625C46C46264460463F6 +:100970006E46466374468463002A06D0C46B043C0A +:10098000043A25681560B442F9D18C6BA6464E6BCB +:10099000B546002B06D0CC6B043C043B1D6825609B +:1009A000B442F9D10C6BA446CC6AA3468C6AA24629 +:1009B0004C6AA1460C6AA046CF698E694D690C69E4 +:1009C000CB688A6808684968704700604160826047 +:1009D000C360046145618661C761444604624C4658 +:1009E0004462544684625C46C462644604636E4654 +:1009F000466374468463C46B043C043925680D6007 +:100A0000B442F9D1C76986694569046970470060D5 +:100A100041608260C360046145618661C76144468C +:100A200004624C464462544684625C46C462644636 +:100A300004636C4644637446846304697047846B42 +:100A4000A646446BA546046BA446C46AA346846AC2 +:100A5000A246446AA146046AA046C76986694569F8 +:100A60000469C36882680068416870470CC8074819 +:100A700010B51B18DB00D3181800934205D31C686F +:100A80008C4202D31800083BF7E710BDFFFFFF1FA1 +:100A900070B50D1C06000021281C04F00FFC041E7C +:100AA00006D13000291C03F0BDFD7560200000E078 +:100AB000004870BD17FCFFFF014B18687047C04627 +:100AC0001420002070B504000D0003F0BFFD616824 +:100AD0002000FFF7DDFF024B00201D6070BDC04607 +:100AE00014200020F8B51B4C0500A3059B0D03D076 +:100AF0008022D200A418E41A80235B05164A5B69A1 +:100B000016499B181648174A174E9B029C421FD243 +:100B10002768974218D167688F4215D1A768874226 +:100B200012D1E768B7420FD1280021000822103106 +:100B3000243011F00FFE280021003830183108222F +:100B400011F008FE2C6303E08027FF00E419DDE7C5 +:100B5000F8BDC046C4450300EDFF3F00C615A841DF +:100B6000C49866C9708E3B9275EE5197F8B5002314 +:100B7000070004000370061D403700253000357063 +:100B80007560B5600C3008222900143611F000FEA3 +:100B9000BE42F2D12278032A09D01423C021534344 +:100BA0004902E31801329D60D96022701D712178DD +:100BB000124B03290AD01422C0204A434002A21833 +:100BC00001319060D3602170012111718022D20027 +:100BD00099189B0522789B0DC91A032A09D0142362 +:100BE0005343E318996006490132D960227002220A +:100BF0001A712000FFF776FF2000F8BDC4450300FE +:100C0000FFBB0300002370B50400016043609942FC +:100C10000AD1064D2B68002B02D110F00AFC286087 +:100C200023689B00EB586360200070BD6C2500209A +:100C300070B500280DD10C4C2668002E07D1083065 +:100C400011F051FD05003100FFF7DCFF2560206841 +:100C500008E00122054906480B68134002D10260F2 +:100C600043600A6070BDC0466025002070250020EA +:100C700064250020436810B50400002B02D104480D +:100C800011F05EFB606803681B69984710BDC046A1 +:100C90004F430300436810B50400002B02D1044801 +:100CA00011F04EFB606803689B69984710BDC04611 +:100CB0004F430300436810B50400002B02D10448E1 +:100CC00011F03EFB606803685B6A984710BDC04640 +:100CD0004F43030000487047FFFF0000F0B597B096 +:100CE0000593036807AD1B680491039311002B0063 +:100CF000060091C991C30024D36821000C220CA8DE +:100D0000EB602C6111F044FD21000B4B10940F930C +:100D100011AB1C701A1901345170102CFAD1002239 +:100D20005A820193059B2A00009304990CAB300072 +:100D3000039CA04717B0F0BD1B110300FC3070B539 +:100D4000046C0500002C0DD1242011F0CCFC064BC6 +:100D500044608361054B8460C46004614461C46184 +:100D600003602864286C70BD983603008037030048 +:100D7000FC3070B5C56B0600002D16D1342011F083 +:100D8000B2FC04003422290011F002FD084BA560DA +:100D90006360084B65612361074B2562E361074B84 +:100DA000E562A362064BF4632360F06B70BDC0463E +:100DB000C8360300B836030028370300383703006D +:100DC000483703007FB503791548002B26D0154D11 +:100DD000154C2B782000002B20D102AE300010F0F3 +:100DE00079F9002814D17388592B11D13378B2883E +:100DF000D91F012902D800920C4A01E000920C4A46 +:100E0000202120000BF09EFF01232B70200005E025 +:100E100020220849200011F002FDF7E704B070BD60 +:100E20007243030046280020472800208C4303001B +:100E3000A9430300CE43030010B50400024B08C0D1 +:100E400010F0DAF9200010BD3837030010B50400A7 +:100E5000024B08C010F0D0F9200010BDD8360300B6 +:100E600010B50400024B08C010F0C6F9200010BDF8 +:100E7000C836030010B50400024B08C010F0BCF9DE +:100E8000200010BDB836030010B50400024B08C0A6 +:100E900010F0B2F9200010BDA836030010B5040010 +:100EA000024B08C010F0A8F9200010BDE83603007E +:100EB00010B50400024B08C010F09EF9200010BDD0 +:100EC0009836030010B50400024B08C010F094F9E6 +:100ED000200010BDEC35030010B50400024B08C023 +:100EE00010F08AF9200010BDDC35030010B50400B5 +:100EF000024B08C010F080F9200010BDCC35030073 +:100F000010B50400024B08C010F076F9200010BDA7 +:100F1000FC35030010B50400024B08C010F06CF95A +:100F2000200010BD28370300FC3070B5046C0500AC +:100F3000002C0DD1242011F0D6FB064B44608361B8 +:100F4000054B8460C46004614461C461036028642B +:100F5000286C70BD9836030080370300104B10B525 +:100F6000083303600F4B0400C36080230E4A5B000C +:100F7000C250C018FBF7FEFB20000C4BB830E360FA +:100F8000FFF7BEFF2000AC30FFF79CFF2000A03031 +:100F9000FFF7A2FF20006C30FFF7A8FF200010BD74 +:100FA000AC370300F43703002C3903000C36030080 +:100FB000F0B50500040087B0AC356B68AB60AE6877 +:100FC000002E08D0F368210030009847AB68002B52 +:100FD000F3D01B69F2E72000B03010F00DF92200C9 +:100FE000FC235832117820000B40137023005C332F +:100FF0001E700A3010F014FA2000343010F010FA8D +:101000002000643010F0F8F82000983010F0F4F868 +:10101000200001ADA43010F0EFF831000C222800C0 +:1010200011F0B6FB23002A006C3383CA83C3094B3B +:10103000E667A3670C223100280011F0A9FB23000A +:10104000803307CD07C33000034A90341A6026600E +:1010500007B0F0BDFF100300F1100300454AF0B5E2 +:101060000600C260A022444B16360833036001001C +:10107000002342820400320085B003718360037450 +:10108000838235311370013200259142FAD18027D5 +:1010900080222000D201BF001100F57737842B0099 +:1010A0000095383000F020FF2300210040330393E7 +:1010B0001A002B005F311370013200258A42FAD1E9 +:1010C000039B2200DD77230060331F80FC23643202 +:1010D000117820000B401370230068331D70274BDC +:1010E0002900E36625670C22783011F051FB2300BC +:1010F000270088331D60224B0837FB67843729009F +:101100000C22380011F044FB1E4B1F4AFB602300E9 +:10111000A0333D611A601D4A5D60DA601C4A1D61A2 +:101120009A61DD61300010F07BF9039810F078F9D6 +:10113000184B601CE3602300C4331D705D709D700C +:10114000FF3002F0E7FC8C235B00E55023001933ED +:10115000FF335D618023104A5B00E25023000122CF +:101160002000FE3352425A86023B9D63DD631D64BC +:1011700005B0F0BD0C360300AC370300CC350300DE +:10118000FF100300F1100300DC350300EC35030011 +:10119000FC350300F43703002C39030070B5074C0D +:1011A0002368002B07D1A020400011F09CFA050015 +:1011B000FFF754FF2560206870BDC04674250020ED +:1011C00070B50C220D000021040011F0E1FA00239B +:1011D0002361024B25602000E36070BD0D11030008 +:1011E00070B500250400264B05710360254B457141 +:1011F0008360254BC5604361244B85610362244BAA +:101200004562C362234B05638363C5632900443091 +:10121000FFF7D6FF200029005830FFF7D1FF20004C +:1012200029006C30FFF7CCFF1B4B2200236023000A +:10123000F832803320C39342FCD126001D00E936EA +:10124000FF36280008220021083511F0A1FAAE422D +:10125000F7D18E22330000209200A11801C3002292 +:101260009942FBD18E239B00E2540C490C4B611830 +:10127000E3181A8002339942FBD1200070BDC046AA +:10128000F8360300A8360300B8360300C83603005A +:10129000D8360300E83603008038030062020000FD +:1012A0003A02000010B5040002F01CF8034B1B6862 +:1012B000002B01D02000984710BDC04678250020A3 +:1012C000F0B58DB0050001F07FFA0020FFF766FF52 +:1012D000036807001B6998473B6804009B69380056 +:1012E00098473B6806005B6A3800984703002888E7 +:1012F00010380B2800D997E003F010FE063D9696B3 +:10130000965A969696619673AF882000390010F031 +:10131000A9FA22006B7B583201931378A87919003F +:101320000223194306AB11701F80012306AA937094 +:10133000D07013006A461279E91D9A722B000622BA +:10134000163307A80B9311F005FA29000B2006AB02 +:1013500006220E31C01811F0FDF994346368A360C1 +:10136000A068002860D0C36806A99847A368002B2E +:10137000F4D01B69F3E720002E49AF8810F072FA11 +:101380002200022058321378A9798343137006ABE8 +:101390001F809970A0346368A360A068002843D0C0 +:1013A000C36806A99847A368002BF4D01B69F3E72C +:1013B0005B69A91D002B37D0A888984734E0636E7D +:1013C000AF79002B30D0A366A06E00282CD0C36864 +:1013D00039009847A36E002B01D1636EF3E71B69B8 +:1013E000F1E70122AB7BE91D1A4001925A07920FE7 +:1013F000DB08029206A806226F7B049311F0AAF97B +:101400006A46127906ABDA716A46127A9F711A72CD +:101410006A46127C20005A722B000F3309938C34D9 +:101420008030236806A998472900300010F00DFB92 +:101430000DB0F0BDFFFF00000723D72802D9024BF3 +:1014400018600023180070477C250020014B1860AD +:101450007047C046782500201FB5A3238022DB00FB +:10146000D205D3580820DB0700D405301E4B482294 +:101470001E4902F0C3F900280AD080B2002807D123 +:10148000BFF34F8F1A4A1B4BDA60BFF34F8FFEE753 +:1014900002AC08220021200011F07AF90123237008 +:1014A000154B20001B68636010F03BF8002801D04A +:1014B000072017E0684610F032F80028F8D1694696 +:1014C00010F02BF80028F3D10C4802F0C7F980B2D5 +:1014D000002807D10A4802F0CBF980B2002801D1D8 +:1014E00000F080FC04B010BD291503008025002009 +:1014F0000400FA0500ED00E07C250020C112020086 +:10150000A512020080B2002807D1BFF34F8F034A13 +:10151000034BDA60BFF34F8FFEE770470400FA0514 +:1015200000ED00E070B500200C00FFF737FE036807 +:101530005B6A98472378142B17D002D8132B05D059 +:101540003FE0152B18D0222B35D03AE064680122F9 +:10155000A37819005D0811402A404568DB065B0F3F +:10156000002D2ED02088A8472BE08368002B28D0A0 +:101570006268917810881CE06468A27813091207E9 +:10158000120F012A02D0022A08D00DE0013BDBB283 +:101590000021022B09D80C4AD15C06E00421012B62 +:1015A00003D00131022B00D00021C368002B08D0EA +:1015B0002088984705E00369002B02D062681088F4 +:1015C0009847002070BDC046D6430300014B1878F1 +:1015D0007047C04668280020F0B51E002F4B87B02A +:1015E000009201931A78002305000C009A4252D110 +:1015F00001F0AAFE002801D00B234CE0002E0ED0F3 +:1016000003A9222003960FF097FF002807D0062396 +:10161000082840D011384342434104333BE00023C3 +:1016200002AA1000137000F093FE011EE4D10126FF +:101630001B4F35403A783440B2432A4363000225B9 +:1016400014000720009AAC4302401C431C23AA400C +:101650009C4314433C7003AC0C22200011F098F81A +:101660000920104B3900039302AB0522C0182571E5 +:1016700011F070F821000C4800F0D6FE002807D0C9 +:101680000723042807D0013B082804D0053302E0D3 +:10169000019B1E700300180007B0F0BD68280020F1 +:1016A00091200020251502006728002010B507486A +:1016B00000F084FF0023984206D00733042803D0AB +:1016C000013B082800D00533180010BD6728002012 +:1016D000002373B501930F4B01AD1B780E00290059 +:1016E0002B7001F031FA041E04D0042305280FD01A +:1016F00007330DE03100280000F0D0FE2300002861 +:1017000006D00723042803D0013B082800D0053366 +:10171000180076BD6728002073B5104C0E00050038 +:1017200005222100684611F015F8012E06D0022E80 +:1017300011D1012223781343B34303E0022223781B +:10174000B34393436946280023700FF0F3FE031E52 +:1017500002D00B2300E00223180076BD9120002068 +:10176000094B10B51A7801000923002A09D007484F +:1017700000F0CCFE0023984203D003330E2800D0A3 +:101780000333180010BDC0466828002067280020D9 +:10179000024B0B60092313607047C046D943030016 +:1017A00010B504000020FFF7F9FC03681B69984797 +:1017B0000300F3331C7086235B00C050030000213C +:1017C000044AFC335A61044A99615A62F43010F0B9 +:1017D000EDFC10BD2717030039170300012110B5D8 +:1017E000044A080001F094FF031E00D00B231800E8 +:1017F00010BDC046A1170200F0B593B001900020C3 +:101800000C00FFF7CBFC03685B6A9847FFF7DEFE2E +:1018100006AB00280DD000221A7105AA06920822F4 +:1018200018001A730AAA9A60FFF79AFF002802D0DC +:1018300052E01871187300231F0023732371019B5A +:10184000BA331B78BB4246D907237B43019AD2188F +:10185000BB321278022A31D1002506AE337BAB426F +:1018600036D907207843AB000293019BAA001818D1 +:10187000089BBB3099580FF061FE00281BD0B3685D +:10188000AA009A58237BA1689B005A50237B0133FE +:101890002373337B5A1E954208D01049B2685B18F7 +:1018A0009B009B5803930399029BD15006AA137B7C +:1018B000013B13730CE00135EDB2CEE701992279BB +:1018C000CB182168BB339200535023790133237125 +:1018D0007B1CDFB2B3E7002013B0F0BDFFFFFF3F7A +:1018E000F0B59DB01F006B4605001A70581C06220B +:1018F000229E02AC10F02EFF002F07D03B882380E1 +:101900007B886380BB88A380FB8806E0322323802A +:10191000DB186380F533A780FF33E3800CAB04A9A9 +:10192000049314AB8B602F000023B9370B710B733A +:101930003B78002B17D101203B78022708A90340F0 +:101940005A000B78BB4304AF4F601343002E10D0F6 +:10195000B2798343024013430B7033880B81738841 +:101960004B81B38811E02800FFF746FF0028E2D042 +:1019700029E02A00323212788343024013430B706D +:10198000AB8D0B81EB8D4B812B8E220068468B81BA +:101990000FF002FE03000020834214D00630082B13 +:1019A00011D005D80130042B0DD0834208D109E0B5 +:1019B0000520112B07D0054A934203D0102B01D0EC +:1019C0000B2000E004201DB0F0BDC0460232000034 +:1019D000F0B50A7804009BB00D000220012A42D025 +:1019E0004B88032A04D1A03B10009BB21F4A03E09E +:1019F0000320203B1E4A9BB2934234D8AA881D4B39 +:101A000003209A422FD80AAB009312AB02936A4686 +:101A10000023260013711373B8363378002B05D0DA +:101A200069462000FFF7E8FE00281CD104AF182209 +:101A30000021380010F0ACFE2B7838003B70337872 +:101A40003B726B46FB606B883B82AB887B820FF0FE +:101A50008DFD02000320002A05D101211000583419 +:101A600023780B4323701BB0F0BDC046603F0000DD +:101A7000E03F0000FF3F000013B504680093A46836 +:101A800013000A000149A04716BDC046FFFF000031 +:101A900037B506AC257804680195009324691300D6 +:101AA0000A000149A0473EBDFFFF0000F0B589B024 +:101AB000019307000FAB0D0016000021082202A8B9 +:101AC0001C7810F065FE0EAB1B8802AA1380019BE8 +:101AD0000393002C06D0310028000FF0CBFE002825 +:101AE00041D154E03B007A79F833A2423DD9083322 +:101AF000190008390988B14208D130222034A400E5 +:101B0000E3590133DB7F134202D12EE00134ECE7CD +:101B100002220020DB06DB0F04ACD31AA370019B6A +:101B20002680E3600EABA3601A4BA0809D4207D1D4 +:101B3000FFF734FB03681B6998470FF096FE05001A +:101B4000210028000FF09AFE80B200281FD0112833 +:101B50001CD013D8082817D002AA310028000FF093 +:101B600089FE002812D0032011E002AA31002800CB +:101B70000FF080FE0028F6D1063008E0064B9842B0 +:101B800004D0064B9842E7D1062000E0052009B0BA +:101B9000F0BDC046FFFF000003300000013400002C +:101BA000F0B5050097B008002E240B9100F046F91F +:101BB00004ABE4181090220010A901200FF058FE89 +:101BC000002801D00320D4E023880B9A0A90938345 +:101BD0000B9B0A9A1B7D934250D96B791D2B01D91F +:101BE0000720C6E00B9B9B690C930A9B0C9A9B00F9 +:101BF0009C586369002B46D1638B002B43D1631C37 +:101C0000DB7F022B3FD134E06979A31C1F31C9006F +:101C10006918621CDB7FD27F089121002A31097884 +:101C20000020079121002931097806910D9905912D +:101C30000C990491217F0391218B0291618B019179 +:101C40006169009110A910F041F80028BAD16B79B0 +:101C500007001A00203292001F335451DB005B5BF7 +:101C6000E3836B7901336B71230028331B78BB420C +:101C700037D80A980130C3B20A93A9E72B7900201C +:101C800001332B7175E0200000F0D8F80026109089 +:101C90000D960C96230028331B78B342B4D9626AA0 +:101CA000B3009F58342204AB9B1800221A70002303 +:101CB000002111AAD21801335170102BF8D14622FD +:101CC00004AB9B182C4A11A938001A800FF059FE5A +:101CD000002803D07B690C937B8B0D93731CDEB2C1 +:101CE000D8E78E239B00EB5C132B00D978E7626A60 +:101CF000BB009E580023180011A90B70CA180133AD +:101D00005070102BFAD11C4B30004B820FF039FE73 +:101D10000C9000282AD1300000F090F88E2292001A +:101D2000AA5C738B1D32FF325200AA180232029253 +:101D3000327F10900192328B10A9009272690C9838 +:101D400010F0A0F8002800D03CE78E238E219B00E5 +:101D5000EA5C8900531CDBB26B541D337A32FF33CB +:101D600092005B005651EB185B88F383781CC7B276 +:101D70007AE717B0F0BDC0460129000070B5050034 +:101D80000FF07CFB041E1CD128007822210080303B +:101D900010F0FEFC2800E93050222100FF3010F046 +:101DA000F7FC280008222100F83010F0F1FC064B67 +:101DB0002822E818210010F0EBFC8E239B00EC5445 +:101DC00000E00624200070BD3A0200000B68002BE2 +:101DD00001D1036002E0024B0360002343607047BF +:101DE000271503001FB502AC08220021200010F0C7 +:101DF000CFFC282323806933FF336380E380803B5B +:101E000001A8FF3B05220C4903700FF040FF80B290 +:101E100000280FD1802080000FF035FF80B200280D +:101E200008D120000FF031FF80B2002802D10FF05E +:101E300028FF80B204B010BDE2430300F0B5438A2E +:101E400087B00293037804000126002B3ED0244B78 +:101E500024491A680393112301929C460022851994 +:101E6000019B934214D0674600235743CF19981E15 +:101E7000012803D9FE5CE85C864207D10133102BB0 +:101E8000F5D111235A4389180E7C1FE00132E7E790 +:101E900028000FF004FF237807000600002B01D173 +:101EA00012342500019B042B10D011245C430D4BF0 +:101EB00010221C192900200010F04CFC0023A370F4 +:101EC000E370019B039A01332774136005AB9E7086 +:101ED0005888029B00040343180007B0F0BDC046B9 +:101EE000C825002069280020F7B5FA26B6007143FE +:101EF000009308AB1B7804000800154917000193F4 +:101F000003F016F885B2300025807843104903F0BD +:101F10000FF86B461B8880B2A3806B461B796080EC +:101F2000A371032D01D80423238080232288DB01A1 +:101F30009A4200D92380032801D804226280628853 +:101F40009A4202D98023DB0163802000FEBDC04697 +:101F500071020000F0B58BB004AB9C1D0E230C2267 +:101F60000390019123804B7806A95343234AD31849 +:101F70001889220003230FF0C2FF00283AD1182746 +:101F8000019B1F4D5B7826885F4300933B0008331D +:101F9000EB18320006A91800029310F0CCFB2C00BD +:101FA00000280DD10C22009B5343144AD318997A70 +:101FB000022319401ED1E819182210F0E9FB19E09C +:101FC000E81943680F4F002B00D10F4F182503224B +:101FD000009B06A96B43E250E3185E603200029852 +:101FE00010F0B8FB019B2A00597803986943382305 +:101FF0006118B84700200BB0F0BDC046EA270020AA +:102000009026002059350200E1340200F0B585B079 +:1020100004000E0002AA8178214801F03BFA002852 +:102020003CD10C2361781F4A4B43D3189B7A019211 +:102030001D4F5B0605D4022E03D01C4F012E00D08D +:102040001B4F1C25A1781B4B69432A00591802A875 +:102050000023B847002813D1022E1FD00C234021A3 +:10206000627802A85343019AD3189A7A8A439A72E3 +:102070006178114B69432A0059182B00B84701E0D9 +:10208000022E0BD00C232278210053430B4A02A8C6 +:10209000D3189B7A0A4A9B009B58984705B0F0BD1D +:1020A000B8260020EA27002059350200E13402005A +:1020B000031F0300CC25002074260020A826002042 +:1020C000B8380300F7B518220190437826485A43E0 +:1020D00081184C68254F002C0FD00C2159437918DA +:1020E000897A4DB2002D07DA490605D41500083566 +:1020F000A6B24519145802E00024260025000C223F +:102100005343FB1818893200230029000FF0F5FE15 +:102110000B2816D10C22019B29005B785343FB1836 +:102120001889320001230FF0E8FE0C21019B104AB0 +:102130005B784B43FF1838890FF0DDFE002806D18D +:1021400011E0002800D00B48012C0CD1EDE7022251 +:10215000094BC318934305D0082803D0112801D098 +:10216000002000E00348FEBD90260020EA27002062 +:10217000FFFF000041800000FECFFFFFF8B5070021 +:102180004878182403006343084D0E00E818220025 +:102190003823390001F01CFA002806D173785C431B +:1021A0002C196368013300D16060F8BD90260020CF +:1021B00070B51C2444430D4E050030190622341915 +:1021C0000021113010F0E4FA10220021200010F05C +:1021D000DFFAFF232374A376013BFF3B2383023303 +:1021E000AB40034A11689943116070BDCC250020B3 +:1021F000B426002037B581B205006A46074801F0D1 +:1022000049F9041E08D15421684601F02DFA041E34 +:1022100002D12800FFF7CCFF20003EBDB8260020E9 +:10222000F0B51D00434B93B01B6801900F001600E2 +:10223000002B7CD0189B542B79D8FF22002403ABB1 +:102240005A709A70DA701C7002AB1C74189B0B9554 +:102250000A93A1B204AA384801F01CF9002809D158 +:10226000082204A9019810F066FA002802D103ABF5 +:102270009C7002E00134062CEBD103ACA178FF295D +:1022800055D0032F0AD1189A06AB542A01D1343AFB +:1022900000E040221A701A7803213AE0274BEB1A2B +:1022A000A72B10D8264B002E04D101228A40186893 +:1022B00010423CD001228A401968914320221960C3 +:1022C00006AB1A7020E01F4BEB1A1B2B09D82022FB +:1022D00006AB1A70002363700CAB0B9318230A93A0 +:1022E00012E019482D1A172D21D8302302AA137491 +:1022F000002363700133E370144B997A0223194071 +:1023000002D1182210F044FA06AB022F0CD10121A1 +:102310001A780A431A7009AB0793064B32001B6800 +:1023200006A92000984702E01A780221F1E713B0CD +:10233000F0BDC046A8260020B8260020CC250020ED +:10234000B42600207426002090260020EA270020D2 +:10235000F0B5040085B0002852D000252A4B2B4848 +:102360001D605D729D7201238372023B072229006A +:102370000381C37210F00CFA18222900244810F0CF +:1023800007FA28000135FFF713FF062DF9D1542372 +:102390006A46204F9380204B39006846D5800093D1 +:1023A00001F014F800282CD101231C4D24782B7047 +:1023B000002C1BD11C27A1B202AA164801F06AF812 +:1023C000061E0CD13B00634315481C22C01802A90D +:1023D000330001F0FDF8002804D02E7011E0002336 +:1023E0002B700EE00134062CE5D10AE06B466A46FC +:1023F0009B88D1883800594389B201F035F900E053 +:10240000084805B0F0BDC046A8260020EA270020F5 +:1024100090260020B826002021220200AD280020AE +:10242000CC2500200E800000F8B5174B06001B7865 +:102430000F00002B22D0002822D0002920D00B68CA +:10244000002B1DD0114D2C68002C1BD1280005310C +:1024500008C0052210F07EF93B790220AB720123FF +:1024600004212A7A9A4302438A432A72EA7913435F +:1024700003438B43EB712000347004E0044802E016 +:10248000044800E00448F8BDAD280020A82600203C +:10249000088000000E80000004800000154B1B78AF +:1024A000002B22D000281ED000291CD00378002B3E +:1024B0001BD1114B1B68002B17D04278002A16D174 +:1024C0000E4B9B7A012B12D02420184003D00123FD +:1024D00010000B700CE05BB2002B02DA02230B70D1 +:1024E00006E0087004E0064802E0064800E00648FE +:1024F0007047C046AD280020A8260020EA2700200B +:102500000E8000000880000010800000254BF0B510 +:102510001B78002B26D0002822D0002920D00B6861 +:10252000002B1DD08B68002B1AD00378002B19D1FB +:102530001D4A1268002A15D01C0018001B4A1032D0 +:102540001B4DEF7A9F420FD1AF7A02252F420BD05D +:1025500001331C32062BF3D108710C7300201FE0ED +:1025600014481DE014481BE00F7BBC420CD203252D +:10257000977A2F40022F07D1133DAC46944466460C +:102580008D68A7007E5101340F79B842E0D2022550 +:10259000977A2F42DCD10D6887007A510130D7E756 +:1025A000F0BDC046AD280020A8260020CC25002084 +:1025B000EA2700200E80000008800000104B70B554 +:1025C0001B78002B1AD0002816D00478002C15D1C7 +:1025D0000C4B1B68002B11D020001C252B006343E3 +:1025E000094AD3189B7EFF2B02D02000FFF702FE82 +:1025F0000134062CF2D102E0044800E0044870BD2A +:10260000AD280020A8260020CC2500200E80000048 +:10261000088000000048704791800000194A0300BC +:10262000127810B50800002A28D0002B24D00029E9 +:1026300022D01C78002C21D1134A1268002A1DD008 +:102640009978FF290AD15978FF2919D00C235943C9 +:102650000E4B59188B7A9B0712D508E01C2359435F +:102660000B4B591802238C7E1C4009D110310722D4 +:1026700010F070F8200004E0064802E0064800E090 +:10268000064810BDAD280020A8260020EA2700201B +:10269000CC2500200E80000008800000058000008E +:1026A000F0B5244B8BB01B7806000C00002B3CD0FF +:1026B000002838D0002936D00278002A35D11E4BA8 +:1026C0001B68002B31D08378052B30D81C256B4339 +:1026D0001A49CB189B7EFF2B29D0E260837803AF89 +:1026E0006B43CB182361164B6261A2606360276065 +:1026F000817801AA134800F0CDFE002818D12B00E4 +:102700002A0001A9380000F063FF002810D1E06022 +:10271000B37860615D43094BA0605D19084B25618A +:102720006360276004E0084802E0084800E00848C9 +:102730000BB0F0BDAD280020A8260020CC2500203D +:10274000AE280020B82600200E800000088000007F +:102750001080000013B5040081786A460B4800F031 +:1027600099FE002810D11C226078094B504369461D +:102770001818130000F02CFF064B074A9B7A210023 +:102780009B009B586846984713BDC046B82600205A +:1027900074260020A8260020C838030070B5050064 +:1027A00000241C263300634306492800C9180FF093 +:1027B0002CFC002804D10134062CF3D1FF3000E0BA +:1027C000200070BDCC250020FF23F0B5BD4A8FB09E +:1027D000127805000393002A00D1AEE1BA4A1168CD +:1027E0000192002900D1A8E104AF7B70BB70FB709F +:1027F000031D06932A23002602AA938203883E70B3 +:10280000B24C102B0AD0A67AB2075ED58288B049A6 +:102810008A4207D02189914257D103E0A37ADB078E +:1028200005D48AE1E27ABA7000227A704DE0112371 +:1028300002AA13737E708388063523810223072240 +:10284000A372290020000FF085FF2800FFF7A6FFE4 +:102850000390FF282DD11C2070439E4B1030181878 +:10286000072229000FF067FF002801D1039620E01E +:102870000136062EEFD102E0EB7903423DD1002272 +:10288000019B05AC1B682100380098472378122B68 +:1028900000D052E18D48837A012B00D14DE1012314 +:1028A0008372023B0381C372072200210FF070FF85 +:1028B00043E10821A27A039B0A43DBB2E372A272CE +:1028C0003800BB70FFF746FFD9E7172B46D101222E +:1028D00004201424019B01995B7A864393434B7235 +:1028E0007A4B05A90C709E72AC791900002CC3D0EC +:1028F000D87AFFF77FFCAA79C2E7BB78FF2BBED05E +:1029000008200643E87A8E72800706D51C205843BB +:10291000704C2018847E94438476CA7AFF2AAED005 +:102920001C2208786B4C5A4302280AD0A4182000B5 +:10293000072210300FF00EFF0222A37E9343A376EE +:1029400007E00121A318644A528A1A839A7E8A43B7 +:102950009A7601213800FFF759FB90E7172B00D931 +:10296000A0E0132B59D102AA137304231E43A672AD +:10297000A81DFFF713FF0390FF2802D0C0B2B87064 +:10298000E072E37AFF2B21D10026E33B180070436D +:10299000504A1018827EFF2A13D12378022B07D0C9 +:1029A000FD23F83A8376210010300FF0D3FE01E0CA +:1029B000FE23837603AB1E70039BDBB2BB70E37216 +:1029C00011E00136062EE1D1444C0DE016234448B7 +:1029D00002AA137300210E2208300FF0D9FE402204 +:1029E000A37A1343A37200240021384B0B91DA7AA7 +:1029F0001C235343374A0D91D3180C93364B09913E +:102A00000893019B0A911A1DA88808AB0FF06FFA72 +:102A1000002800D091E0220032E7142B26D1E37A7F +:102A2000FF2B18D11C2200239446E98962465A43A1 +:102A300028488218128B8A420AD10822039316432F +:102A4000DBB2E372A6723800BB70FFF783FE02E0D0 +:102A50000133062BEAD1E37A1F49FF2B00D1002175 +:102A6000A88800231B4A0FF044FA66E0112B64D1BA +:102A7000022332009A431300A272320707D55BB2D9 +:102A8000002B0BDA00213800FFF7C0FA06E0B87817 +:102A9000FF2803D0FFF78CFBFF23BB701023A3722A +:102AA000023302E01C2B03D1132302AA1373E6E6C0 +:102AB000522B19D1019B0B4A9B7A38009B009B58E3 +:102AC00098473AE0AD280020A8260020EA270020F9 +:102AD000FFFF0000CC25002074260020438000006A +:102AE00090260020A8380300182B26D1AB79112B93 +:102AF00014D1330712D512480E22002108300FF0EE +:102B000047FE162302AA137302224A331E43019B77 +:102B1000A6725B7A1343019A5372B0E680235B423C +:102B20001E4302AA95331373019BA6729B7A054A32 +:102B30009B009B5838009847A1E60FB0F0BDC046F7 +:102B400090260020A838030030B5002912D00A785A +:102B5000002A11D10A4B1B68002B0DD0FF23094C12 +:102B60008B702589FA3B854207D14A70E37A8B70D6 +:102B7000130002E0044B00E0044B180030BDC046D7 +:102B8000A8260020EA2700200E8000000880000010 +:102B900010B5064B586980235B05421C04D01969A7 +:102BA00089B202F0C5F900E0586910BD00100010AC +:102BB000034B10B51B78034A9B009B58984710BDE8 +:102BC000C5280020D83803000B0037B50C240200BC +:102BD00018009D6809786C43044D08302D680095F5 +:102BE000034D1B696459A04737BDC0460827002024 +:102BF000F4260020802252051169142210B50E48D7 +:102C000089B203785343C3181A69501EDA881B89A6 +:102C10008018C01802F08CF9084B02001B680120D4 +:102C20009A4207D800209A4204D1054B1B685842AB +:102C30005841C0B210BDC046C0260020EC2600207E +:102C4000F0260020082310B5034A1168994311604B +:102C5000FFF7AEFF10BDC04600270020094A10B59F +:102C6000136819070AD4990702D501210B43136091 +:102C70000222054B1A70FFF79BFF01E0FFF7E2FF0E +:102C800010BDC04600270020C5280020064B10B507 +:102C90001B681B0705D40122044B1A70FFF788FF3D +:102CA00001E0FFF7CFFF10BD00270020C52800205E +:102CB00010B5002814D0112805D10823094A11683D +:102CC0000B4313600CE01423074A11785943511841 +:102CD0000431FFF779FF0422044B1A7000F092F8D8 +:102CE00010BDC04600270020C0260020C6280020B6 +:102CF000F8B514238025124A6D051478114E5C43F3 +:102D00002B691419E2889BB2278920699A420ED94F +:102D10002B6961699BB2D31A2A69381892B2C91813 +:102D2000C01892080FF00BF92B699BB205E09208CE +:102D3000381861690FF003F9E3883360F8BDC046C5 +:102D4000C02600201427002070B58025094B6D0592 +:102D50002A691C68631E94B25C43FFF719FF2B6954 +:102D6000411E9BB25943044B20001A680FF0E7F84C +:102D700070BDC046EC26002010270020142270B53C +:102D800080260E4976050B785343CB181A89DC88C8 +:102D90001B69A4183169E418200089B202F04EF9C9 +:102DA0000D00FFF7F5FE3369411E9BB25943044BFA +:102DB00049191A6820000FF0C2F870BDC026002023 +:102DC000F026002010B5FFF7E3FE8022074C5205E5 +:102DD00013691169126924689BB292B289B20138F1 +:102DE0009208614358430FF0AAF810BDEC2600206A +:102DF00010B5034B18680FF0A0F8FFF759FF10BD8E +:102E0000EC260020F0B52B4B85B0187803284ED85F +:102E100002F084F8020E114B0023274A1360274A60 +:102E20001360274B5B78002B41D000F0F9F83EE0AF +:102E3000FFF75EFF3BE0234C802723687F0501936B +:102E40000123019A9A431423226002921C4A396991 +:102E5000157889B25D4355192B691800039302F068 +:102E600067F8194B039A18603969EB880600501E01 +:102E7000181889B202F05CF8864203D10223029A44 +:102E8000134303E00323019A9A43130023600F4B7B +:102E90001A680F4B002A03D121680232114200D078 +:102EA00000221A70FFF784FE01E0FFF7A1FF05B0D2 +:102EB000F0BDC046C62800200C27002014270020A3 +:102EC000C026002000270020EC260020102700202C +:102ED000C52800201422F0B580254B494B480B78BB +:102EE00085B05343CB18DF68083A7A4382181489B7 +:102EF0005089526860436D05821829691C890192C6 +:102F0000DA881E6913199B19009300230292404A24 +:102F100089B21360300002F091F83D4B2A00039310 +:102F200000290BD12B6902999BB2994208D0019BD1 +:102F300000998B424FD1002C59D101E0022F08D1CA +:102F40001169300089B201F0F3FF324B186003239E +:102F50003BE02969301989B202F070F82E4B8908DC +:102F60001960009A019B296993422DD089B200987B +:102F700002F064F8002927D080246B46640521699B +:102F8000988889B21F8801F0D3FF26690500B1B285 +:102F9000380001F0CDFFADB280B2854208D16B465A +:102FA0006A469B8812889B1A039A9B0813600BE061 +:102FB00023692169380089B29CB202F03FF889B2D6 +:102FC000641A039BA4081C600223144A1370FFF7C1 +:102FD00019FF05B0F0BD022FB2D02969301989B2AE +:102FE00002F02CF80C4B890819602969BEE7022F02 +:102FF000A6D02969301989B202F020F8064B890859 +:1030000019602B69E0E7C046C0260020F4260020A6 +:10301000F0260020EC26002010270020C6280020E3 +:10302000142210B50A490B785343CB18D988094AA2 +:103030001B791160032B08D0042B06D0012B06D17D +:10304000054A1370FFF7DEFE01E0FFF743FF10BDF6 +:10305000C026002008270020C6280020F7B5124D02 +:1030600001936E7808AC27880424022E1AD02C789D +:10307000A419012C00DD023C14235C432C1962616D +:10308000220020710C3209C909C26B469B88278136 +:10309000E3800024054B01361B786E70A34201D1FA +:1030A000FFF7BEFF2000FEBDC0260020C62800207E +:1030B00070B51424114D002029786143691804313A +:1030C000FFF782FD23000022012029784B43EB18F3 +:1030D0001A71DA80D8601A615A611A816B780918FE +:1030E000013B6B70CBB2022B01D02B7000E02A7039 +:1030F000034B1A70FFF786FE70BDC046C026002045 +:10310000C6280020142210B507490B785343CB186A +:103110001B79042B02D0FFF7CBFF04E00122034B05 +:103120001A70FFF76FFE10BDC0260020C6280020D1 +:10313000F8B508241D4F3D682C4022D180235B0543 +:1031400019691B4B1E68002E1ED01422194889B223 +:1031500003785343C3181A69501EDA881B898018F4 +:10316000C01801F0E5FE144B1B6898420CD1134BBC +:103170001C6001231D43124B3D601C70FFF718FDBE +:1031800013E0FFF75FFD10E0FFF734FD002804D0E7 +:1031900000220A4B1A60023202E0002E03D0032202 +:1031A000074B1A70EAE7FFF7ADFFF8BD00270020D4 +:1031B000F0260020C0260020EC260020102700204A +:1031C000C5280020054B10B51B681B0702D4FFF76C +:1031D00099FF01E0FFF736FD10BDC0460027002033 +:1031E00070B5154D2C68230723D4144A1368013396 +:1031F0001360134B04221B68002B04D1FFF7FAFC69 +:10320000002802D002220F4B0CE00F4B1B68002B52 +:103210000CD0012122000B4B0A4002D10C432C6040 +:1032200000E003221A70FFF7C3FC04E0FFF76AFF17 +:1032300001E0FFF707FD70BD00270020EC2600200D +:1032400010270020C5280020F02600201E4B10B5B6 +:103250001B78022B30D0032B19D0012B32D108213F +:103260001A4A13680B4222D1142319490A785A4387 +:10327000184B8A181968D3885B1A9BB2D380002B2D +:1032800002D1FFF715FF1DE0FFF732FD1AE008211C +:103290000E4A13680B420AD10F4A136801331360B8 +:1032A000FFF7A8FC002804D1FFF72CFF0AE08B43AE +:1032B0001360FFF7A7FD05E0084B094A1B789B0048 +:1032C0009B58984710BDC046C62800200027002004 +:1032D000C026002014270020EC260020C52800204E +:1032E000EC38030070B5144C042522781300AB436E +:1032F00021D002281DD003281DD1104B1B681B07AD +:1033000017D40F490B6801330B60032B04D0022A3A +:103310000CD1FFF74DFC0EE014230A4A0D20117862 +:10332000594351180431FFF74FFC2570FFF76AFD30 +:1033300001E0FFF78BFF70BDC628002000270020AA +:103340000C270020C026002010B501220024164BB7 +:103350001C705C701C71DC80DA601C615C611C811B +:103360001C765C831A625C629C629C830F4B1C809F +:10337000FFF70EFC802304225B051B6902389BB219 +:1033800058430B4B18600B4B20001C600A4B1C6011 +:103390001C815C81094B1C70094B1C60094B1C6033 +:1033A000094B1A6010BDC046C0260020F627002039 +:1033B00004270020EC260020F4260020C628002048 +:1033C0000C2700201427002000270020F7B5042236 +:1033D0002C4B04001B680E000820134251D006300D +:1033E000002C4ED000294CD02368002B49D08027D8 +:1033F0007F053A69A38892B2934201D9072040E041 +:103400000F2BFBD9E288002AF8D01F4953430D68DF +:103410005B190093FFF7BCFB3B6901389BB2584333 +:10342000194B0193009B8342E8D8A3889C469B07D5 +:10343000E4D1164B04201F88012F22D00C237B439C +:10344000134A2068D1189850634680203760756011 +:103450004D600B81E288400503694A810169046976 +:10346000604650439BB2C018013889B201F0EAFDB2 +:10347000A4B2604345190020019B01371D60034B36 +:103480001F80FEBD0027002004270020F627002013 +:10349000F4260020104B30B51C680823640719D5AA +:1034A0000633002816D0002A14D00368002B10D150 +:1034B0000A4D2C68002C0CD02C89406861430918F7 +:1034C0006889444368682418A14202D2136051609D +:1034D00000E00723180030BD00270020F42600205C +:1034E000F0B504001A4885B0056808206D072DD591 +:1034F000063000292AD0002C28D025680738002D56 +:1035000024D1144D2E68002E20D0666803962E8993 +:103510006F896D687743BC46039F6544AF4215D2FF +:10352000002A13D0964211D3D518AE420EDB0325E4 +:10353000093029420AD12B4208D12F4206D10093EB +:103540000F3813000A002100FFF788FD05B0F0BD19 +:1035500000270020F4260020F0B504001A4885B0AA +:10356000056808206D072DD5063000292AD0002CCB +:1035700028D025680738002D24D1144D2E68002E40 +:1035800020D0666803962E896F896D687743BC46A4 +:10359000039F6544AF4215D2002A13D0964211D33F +:1035A000D518AE420EDB0325093029420AD12B4241 +:1035B00008D12F4206D100930C3813000A002100D5 +:1035C000FFF74CFD05B0F0BD00270020F4260020D9 +:1035D000F0B51700224A85B0126802900E009C4692 +:1035E0000824530739D50634002936D0002834D0B2 +:1035F0000C68002C2ED11B4D2A68002A2AD04A685C +:10360000688929896B684843C018824222D2002FFA +:1036100020D0B9421ED36346F81881421ADB032139 +:10362000029B0B4218D163460B4215D11140039106 +:1036300012D16244110002983A000FF08BF80C236B +:103640003268009753430221ED58039A029B3000E1 +:10365000A84702E0072400E01024200005B0F0BDD8 +:1036600000270020F4260020F0B51F4B85B01B6812 +:1036700005000E0008245B0733D50634002830D03F +:103680000368073C002B2CD1184B1A68002A28D05D +:103690001A894768029258685B8953431B18039341 +:1036A0009F421ED20934BB071BD1381A110001F00A +:1036B000C5FC093C002914D10299300001F0BEFC80 +:1036C00089B200290DD1002E0BD0039AF3199A422A +:1036D00007D300223300009229000320FFF7BEFC2D +:1036E0000400200005B0F0BD00270020F4260020D3 +:1036F0000120054A10B513785840044B10701B6820 +:10370000002B00D0984710BDC728002018270020A4 +:103710000C4B70B5050015200C001A600EF029FC4A +:1037200000280ED1290015300EF025FC002808D104 +:1037300015300EF01CFC002803D1210003300EF0E0 +:103740001CFC70BD18270020F0B5274B85B01B78F6 +:10375000002B47D0254D264E2B6834685A425341E2 +:10376000DBB2009363425C41E4B2009B002B37D193 +:1037700003A80EF006FC05280AD0002804D0002279 +:103780001100FDF7BFFE05E003982B68984701E0A4 +:1037900001230093002C1FD1164B03A91B88012481 +:1037A0000B80154B1B68180001930EF0F0FB071EF1 +:1037B000052F0BD0002805D000221100FDF7A2FE36 +:1037C000002403E00198336898473C00009B002BDD +:1037D000CED0002CC9D005E0009B002BC8D001E062 +:1037E000002CD9D005B0F0BDC8280020202700202B +:1037F00024270020F82700201C27002070B5040093 +:103800000720002913D08D0711D10948016009490B +:1038100020000A80084A094913600EF0B4FB002812 +:1038200005D10122064B16301A700EF0A8FB70BDB0 +:103830001C270020F827002028270020931F0300C2 +:10384000C828002010B50EF0A0FB03005A1E9341BB +:10385000014ADBB2137010BDC82800200E230028D7 +:1038600002D0024B18600023180070472427002064 +:103870000E23002802D0024B186000231800704766 +:1038800020270020074B10B51B68002B07D0984756 +:10389000002806D000221100FDF734FE01E0FFF7FA +:1038A00053FF10BD28270020F0B50E788FB0002EF2 +:1038B00000D097E0514C02AB9A1D210008230588E7 +:1038C00013803431073B28000EF069FB4C4B1B681A +:1038D0009847B1200EF065FB002803D0320031007C +:1038E000FDF710FE0EF05FFB002803D00022110050 +:1038F000FDF708FE434E70690EF057FB0196002855 +:1039000003D000221100FDF7FDFD00233E4E2800EC +:1039100031000493FFF718F9051E4CD108A93A4865 +:10392000FEF7BEFE071E33D10C9D072229002000A2 +:1039300010310EF00FFF29001022E01D0EF00AFFDB +:103940002000089D1122290018300EF003FF2000EE +:1039500029002A3012310A220EF0FCFE20000EF05F +:1039600026FB002803D03A003900FDF7CBFD0123E8 +:10397000002404930333069305A904AB224807935C +:103980000594FEF747FEA04215D02200210010E06A +:1039900021003000FEF742FE002803D02A00290053 +:1039A000FDF7B0FD20000EF002FB002803D000223E +:1039B0001100FDF7A7FD8021C022144BC90352005E +:1039C0009950196801200023114C02009A401142BD +:1039D00000D0E2670133202BF7D1019B586900F03A +:1039E0004BF809E00322012100F014F8002803D06D +:1039F00000221100FDF786FD0FB0F0BDFA27002070 +:103A00001820002000100010C928002000E100E06C +:103A100004E100E0F0B5060087B00E20002E22D0B1 +:103A20003788124B06389F421DD0114B1B78002B54 +:103A300019D0104D102369706846032102ACC18073 +:103A4000AA7000211A0020002B700EF0A1FE338A0C +:103A5000210023800123A3706B4638000633A36046 +:103A6000E5600EF0F3FA07B0F0BDC046FFFF0000BE +:103A7000CD280020CE280020F0B50300186880F380 +:103A800008885868FF2464B2EFF30585002D01D142 +:103A9000A6460047251C061C21273FBAF0B4002487 +:103AA000002500260027F0B4F92040B20047C046A8 +:103AB000F0BDC04610B50400034B083303601C3052 +:103AC00000F0ACFB200010BD0039030070B505000C +:103AD00004000E4B0E00083308C5280018220021F0 +:103AE0000EF056FE002320003100E3612362636381 +:103AF000A363E364064A23001C3000F05FFB280048 +:103B000031000EF046FC200070BDC04600390300B5 +:103B100003210300084B10B5083303600023436002 +:103B20008360C360040000F0C5F8044920610EF012 +:103B30004CFC200010BDC0461039030019210300C1 +:103B400010B50400034B083303600EF0F2FA2000B6 +:103B500010BDC0461039030010B50400044B0360CB +:103B60000EF01CFB2000FFF7EBFF200010BDC0464D +:103B7000403903000C4B70B5036000234360836041 +:103B8000C360036243628363962304009B01051DA7 +:103B9000C363280000F0A6F928002200034900F0C2 +:103BA00033FA200070BDC04654390300C921030018 +:103BB00010B50400FFF7DEFF014B2000236010BDAD +:103BC00064390300F7B50027040008A8C7570E485A +:103BD000002508302060082020610C48261D656003 +:103BE000A56025736561A0610097300000F04EFF6D +:103BF0002B0030006269216900F0CEFE3000A1691F +:103C000000F002FF2000FEBD6C39030040420F00AF +:103C100070B5094D04002B6883420BD0061D426924 +:103C200001690023300000F0B7FEA169300000F008 +:103C3000EBFE2C6070BDC0462C27002042610022A4 +:103C400010B5034B01611A60FFF7E2FF10BDC046DB +:103C50002C270020002210B5024B81611A60FFF76B +:103C6000D7FF10BD2C27002070B504000D001600F2 +:103C7000002110220EF08CFD054B3200236129003B +:103C8000200000F0E1FD034B20001C6070BDC04629 +:103C9000A08601003027002070B5054D04002B6878 +:103CA000834203D0016900F089FD2C6070BDC046DD +:103CB00030270020004870479439030010B50248AF +:103CC0000EF08CFB10BDC046943903000848026812 +:103CD00003210A4302600749074A084B9B1A03DD88 +:103CE000043BC858D050FBDC0548804705480047D6 +:103CF00024050040C445030000200020C02000200F +:103D0000614E020075810100FEE7FEE7FEE7FEE777 +:103D1000FEE7FEE701230E4A10B5936480230D49A8 +:103D20009B00CB670C491400086D0C4A002804D096 +:103D30000020086511680131116009490B60A92351 +:103D4000DB001068E358010C9BB20004184310BD5F +:103D50000090004004E100E0FC900040402700207B +:103D600000E100E0F8B50F4C636C002B0FD000278A +:103D70000D4E67643378BB4209D00C4B1D68FFF7CA +:103D8000C9FF2D1ABD4202DC3770FFF797FF236D84 +:103D9000002B06D0064A1368013313600022014B42 +:103DA0001A65F8BDFC900040D62800203C27002072 +:103DB000402700201B4970B50C78002C30D1012021 +:103DC000194B1A4A586054608024E40520605068FA +:103DD0000028FCD000220124042515481A500C307C +:103DE000DC601D5008381A501248C2251A50C122F2 +:103DF00080209200000398508020400298500E4886 +:103E0000AD0046590D4A3240C02636023243425177 +:103E10008022893D9200FF3D425102601C600C707F +:103E200070BDC046D528002000900040FC00004036 +:103E3000040500004C05000000E100E0FF00FFFF6A +:103E4000044B10B51B78002B01D1FFF7B3FFFFF730 +:103E500061FF10BDD5280020104B70B51B78040001 +:103E6000002B01D1FFF7A6FF0D4D0E4E2B78002B36 +:103E700002D033689C4210D0FFF74CFF201A0A286A +:103E800003DCFFF747FF0A30040001232B70A8234F +:103E9000054A3460DB00A4B2D45070BDD5280020A0 +:103EA000D62800203C27002000900040012310B5B8 +:103EB0000A4ADC00A4588C4207DD013BDB00D31822 +:103EC0005A680168064BCA5007E00133112BF0D144 +:103ED00080210268024B4905D15010BD9C39030076 +:103EE00024050000F8B50F000121254BB9400360FF +:103EF000A023244CDB0516001A5905000A43802133 +:103F00001A511A5909060A430121B1401A511A5986 +:103F10008A4396211A511A598901520052081A519E +:103F2000FFF7C4FF002204202B6817495A506C3950 +:103F300058500121996019601900FC31CA60134979 +:103F40005A506A6014391F325A5011495F5009188B +:103F50005A501E517B1C03D0032138000EF0D7FAB3 +:103F6000731C03D0032130000EF0D1FA0122094B5B +:103F700029001A60084807320EF0ECFBF8BDC04675 +:103F800000200040140500006C0500001C05000026 +:103F90000C0500004427002004290020962310B5BA +:103FA000DB00994202DDFFF781FF04E09E210268F9 +:103FB000014BC902D15010BD24050000C1230E4A97 +:103FC0009B00D15810B5090603D50C49096A002990 +:103FD00008D1D3585B070DD5084B0021DB68002BB7 +:103FE00001D107E00121064B1868002802D0054BDB +:103FF0001B68984710BDC04600200040FC200040D0 +:10400000482700204C270020034B196043680349D0 +:104010009B005A507047C0464C270020482700207C +:1040200000681F4B70B5C3185C4263415B00002AF7 +:104030001BD0002903D0012905D1802100E00421F3 +:10404000C122920081505CB2FF23C025E600B3403C +:104050001449AD004A599A431000C0220123B240CE +:10406000A34002434A510B6018E0002908D00129FF +:1040700014D1C2228024920084508258920806E013 +:10408000C22204219200815082580339D2099143FF +:1040900004D001229A401300034AD36770BDC04682 +:1040A00000E0FFBF00E100E004E100E003681A0067 +:1040B000FC32106A0128FCD100201062014AC9B20A +:1040C000995070471C050000F7B5A223A022DB0021 +:1040D000D205D358BE220193314B52009958002982 +:1040E0005DD0C12189005958002958DA0024E02503 +:1040F000C0269C50ED00B6022A4BA700F8580028B5 +:104100004AD0294BE35C002B30D0019B0121E340D6 +:104110000B4212D02300A022C133FF339B00D205F3 +:104120009B589B039B0F032B07D0204B1B68E3403E +:104130000B4202D01E4B1B6817E0019B0122E3409B +:10414000134213D12300A021C133FF339B00C905C3 +:104150005B589B039B0F032B08D1164B1B68E34056 +:10416000134203D00221124B1B689847A023DB05A2 +:10417000FB185A5932420FD059590F4A0A405A5126 +:10418000019AE240D20702D55A59324303E0802116 +:104190005A5989020A435A5101341F2CACD1F7BD38 +:1041A0000060004054270020D7280020D02700209E +:1041B00050270020D4270020FFFFFCFF30B504006B +:1041C00008004D1C1CD00F482160BE240260002056 +:1041D0000D4A640010510D4C8D002B5101240C4BE5 +:1041E0005C54C121802389001B065350094A0A4BA5 +:1041F00054582340C02424042343535040231360C5 +:1042000030BDC046502700200060004054270020E9 +:10421000D728002000E100E0FFFF00FF0021036835 +:10422000014A9B00995070475427002070B5A02484 +:10423000E0250068E40583001B19ED005E59204C61 +:1042400034405C511F4D0124002A0ED0A14204D1FC +:1042500081402A681143296015E0022913D1844066 +:10426000194A11680C4314600DE0012904D1814002 +:104270002A688A432A6006E0022904D18440124950 +:104280000A68A2430A602A680121C2400A4204D196 +:104290000D4A1268C2400A4211D0A222A021D200C7 +:1042A000C9058958F132C140FF32C90702D5995872 +:1042B000C02001E08020995880020143995070BDD0 +:1042C000FFFFFCFFD0270020D427002000220B4B4B +:1042D0009A5682420AD001229A56824208D002227D +:1042E0009A56FF23824207D1022002E0002000E01C +:1042F0000120034B1870C3B258B2704797200020BA +:10430000F62800200022134B30B59A56824209D07D +:1043100001229A56824207D002229A5602218242F4 +:1043200017D102E0002100E001210A0045320A4CC9 +:104330000A48FF3292001450012215004800441C24 +:10434000A5408240A120064C2A43C0002250FF22F3 +:104350005A5430BD97200020031F02000060004027 +:1043600000F001400022F8B5124F0600BA563B009B +:10437000114D013209D00122BA56013207D0022272 +:10438000BA560220013207D102E0002000E00120ED +:104390001E542870C0B20BE028780321013000F0D1 +:1043A00037FF0C0078562970FFF7ACFF3E55E0B29E +:1043B00040B2F8BD97200020F6280020012370B5F8 +:1043C0001E000200A0258640C132FF32ED0592009A +:1043D0005351134A0002AE50A226124A4C00104319 +:1043E000114A89008D18F600E4B2A851C046C046B3 +:1043F000C0460E48E20012180D482B6015500D48BB +:10440000091891510C490D48555004395050190064 +:10441000E2189140A3400A4A0B4304498B5070BDF7 +:104420000C050000030013000060004000F0014094 +:104430001405000040A100401C0500004CA10040F4 +:1044400004050000A820012110B5124A124B14885F +:10445000C00059601C50548810481C509088A922F4 +:10446000D200985080220820920098508020093273 +:104470000003FF3298500A4A1078A222D2009850C6 +:10448000084A1088084A985000221960FC331A65BF +:1044900010BDC0468A20002000A000404405000056 +:1044A00096200020882000204C05000070B50125D2 +:1044B00045570E002800FFF709FF0400431C0ED1EA +:1044C0002800FFF74FFF030051331D49FF331D4AFA +:1044D0009B0004009950C1B22800FFF76FFF64B23F +:1044E000194BA200D6503200184B64001B78043BD5 +:1044F000DA40174BE252002E03D0164B1B689E4247 +:104500000ED32800FFF7FEFE0123A022AB40D20508 +:10451000002E02D0A121C90000E00F4953500EE047 +:1045200072B600210D4A074B11658021C122090393 +:10453000920099500A49053AFF3A995062B670BD07 +:10454000FFFF000000A00040D82700209620002098 +:104550008A2000201C2000200C050000FCA0004048 +:1045600008080000F8B5254B06001A780D00002A4F +:1045700028D10121224B234859601A501950224852 +:10458000C2271A5004301A50204ABF001078A222C5 +:10459000D200985080220820920098501C4A10881F +:1045A0001C4A98501C48C259944664461B4A2240F3 +:1045B0008024E4032243C2518022D20002601960A9 +:1045C0000E4B19702800FFF781FE0400431C0ED12A +:1045D0002800FFF7C7FE030051331149FF33084A93 +:1045E0009B0004009950C1B22800FFF7E7FE7570E8 +:1045F000347030000021FFF759FFF8BDF728002084 +:1046000000A00040FC0F00000405000096200020E0 +:10461000882000204C05000000E100E0FFFF00FFC3 +:10462000FFFF0000084B70B50D1C0400186801F076 +:104630000DFE291C01F006FB01F09EFD010020008B +:10464000FFF734FF70BDC0461C200020F0B5254B9D +:1046500085B01F680D001A008F4240D080210423CE +:104660004902A9420ED3092B39DC15602A001E49E4 +:1046700003AE0B70043BDA401C4B00241A80FF236E +:10468000337007E0132B2AD049000133E9E70134E6 +:10469000032C24D0164B6200D25A164B9A42F6D005 +:1046A000154BA200E35C7370144BD05801F0CEFDA3 +:1046B0000090280001F082FD0190380001F0C6FD55 +:1046C000011C019801F0F4F8011C009801F0BAFAFD +:1046D00000F082FE01003000FFF7E8FED7E705B0EA +:1046E000F0BDC0461C20002096200020882000201D +:1046F0008A200020FFFF000097200020D8270020FC +:1047000001704B1C0AD001238B404360044BC360F3 +:10471000044B0361044B4361044B83607047C04604 +:10472000080500500C0500501005005014050050FD +:104730000261064A10B54260054A01738260054A6B +:10474000190002600DF005FF10BDC04604050050C1 +:1047500010050050000700500368074A9950074AA7 +:10476000FC33196A002904D1013A002AF9D1012049 +:1047700001E00020186270471C050000A1860100BE +:1047800010B50368002A03D08022022092009850BE +:1047900001221C001A62084AFC34E068002804D197 +:1047A000013A002AF9D1012005E00020A322E060AF +:1047B000D2009B580B7010BDA186010010B50B4CA8 +:1047C00002680B4BA14204DC0A498160CC214904F8 +:1047D0000AE0094CA14203DC08498160802102E023 +:1047E00007498160CD21C904D15010BD8FD003008D +:1047F00024050000A08601007F1A060090D0030067 +:10480000801A060070B504001000A025C026C13033 +:10481000FF30F600ED05800046510800C130FF3042 +:1048200080004651A1252068ED004251054A815083 +:1048300019002000FFF7C2FFA02305212268DB003A +:10484000D15070BD0C050000F8B50E001500040035 +:1048500000F074FA2648F2B203780100DBB2012BB3 +:1048600006D14778974203D18778E8B2874211D0C2 +:104870002048EFB20378012B05D14378934202D14F +:104880008078B84211D00878002806D101230B7037 +:104890004A708F706373184B15E0164B1978002916 +:1048A00007D1013119705A709F7002236373134B43 +:1048B00009E013480DF044FD0023FC2223606571DC +:1048C00026719362FFDE19000022FC3123606571BE +:1048D00026718A62A021C9005A500A4920005A5004 +:1048E00001325A502A003100074BFFF78BFFF8BD09 +:1048F000F8280020FC280020003000400040004044 +:10490000E8430300FC0F0000A086010003680022BA +:104910001900FC3110B58A62A021C9005A5006491D +:104920005A5001325A50052204218256415683685A +:10493000FFF768FF10BDC046FC0F000003680021B0 +:104940001A00FC3210B5916001315961074B916832 +:10495000002904D1013B002BF9D1012004E00024FF +:104960000473FFF7D3FF200010BDC046A1860100ED +:10497000036810B51900FC318A6A0020012A08D1A9 +:10498000044C1C5988625A610238A40701D40120E2 +:10499000404210BDC404000070B51D00A0230400F7 +:1049A0001600DB00002D03D000224068C25001E059 +:1049B0000268D550082902D010480DF0C1FC032E22 +:1049C0000AD8300000F0AAFA0B020406022307E01E +:1049D000042305E0062303E009480DF0B1FC0023A1 +:1049E000A0220848D200002D03D061680B5002239A +:1049F00002E021680B5001238B5070BDF943030086 +:104A00001244030054050000036810B55A1C2ED050 +:104A1000A0220020164CD20098501000154AA14246 +:104A200002DC802189041FE0134CA14202DC8021BA +:104A3000C90419E0114CA14202DC8021090513E0F0 +:104A40000F4CA14202DC802149050DE00D4CA14232 +:104A500002DC8021890507E00B4CA14202DC8021A9 +:104A6000C90501E080210906995001221A5010BDA4 +:104A70008FD00300240500001FA107003F420F0054 +:104A80007F841E00FF083D00FF117A00F7B50093F8 +:104A900008AB1B7805005BB20F00160001930133D1 +:104AA00029D1624B1A78022A10D15978FAB2914270 +:104AB0000CD19978F2B2914208D1DA786B461B7822 +:104AC0009A4203D101235A4C03723BE0594A1378AE +:104AD000DBB2022B0FD15078F9B288420BD190781B +:104AE000F1B2884207D1D1786A461278914202D158 +:104AF0002B72514C26E04F4B1A78002A0BD1023210 +:104B0000F9B21A705970F1B29970694609782A722F +:104B1000D970494C13E0454B1A78002A0CD1023267 +:104B20001A70FAB25A70F2B29A706A461278404C11 +:104B3000DA7001232B7202E040480DF001FC019B6A +:104B400001332ED10123002201205B426B6039002A +:104B50003B4B2C60E250E050A023C131FF31DB051C +:104B60008900C850374967500099C131FF31890029 +:104B7000C850A1210098C90060503100C131FF31F7 +:104B80008900CA50A223DB00E650FC342800E26012 +:104B900013000821FFF700FF2B492800FFF734FF1F +:104BA00042E0012300225B422B60254B6C60E25007 +:104BB0000123234938006350A021C130FF30C905CB +:104BC000800042503000C130FF30800042500098D9 +:104BD000C130FF30800042500198C130FF3080006A +:104BE0004250A221C9006750164900986650043906 +:104BF00060501649019860502100FC318A60CA62F9 +:104C0000A721C90063501031635011481149605009 +:104C10001149124860508021042089006050F93900 +:104C2000FF392800FFF7B8FEF7BDC046F82800207E +:104C300000300040FC2800200040004023440300D6 +:104C4000FC0F00000C05000040420F00140500009E +:104C5000012900204405000034050000002900203F +:104C600003681A00FC32D0680028FCD105481950AE +:104C7000D1680129FCD10021D160A322D20098582B +:104C80007047C0461C050000A023F0B5284FDB008C +:104C9000FA5885B001920022A024FA50E023254A58 +:104CA000E405DB00E658E2507833E1580125029133 +:104CB000E250A1238022DB00D205E2500420E5501F +:104CC0000DF0E7FCA222D200A35803979B0F2B42C2 +:104CD00005D0A35813242B4202D0012018E013243E +:104CE000A0250127ED05013C002C10D0124B04201B +:104CF000EF500DF0CEFCA123DB00EF5004200DF0AF +:104D0000C8FCA223DB00EB585B00ECD5E5E72000F4 +:104D1000A023E0220299DB05D2009E507832995000 +:104D2000A023039A0199DB00D15005B0F0BDC04625 +:104D3000004000400D0600000C050000A023E0210B +:104D4000134ADB05C90010B55A5078315A50114B3F +:104D500000221900FC31CA600A62A1211E20C9008C +:104D60005A500D4A0D4C9850CC200D4A4004985092 +:104D7000A2200C4AC00014500B4C0C4814500120C7 +:104D80005050A0220521D2009950FFF77DFF10BDA1 +:104D90000C060000004000400C05000038410040B7 +:104DA0002405000000F001401C40004014050000F4 +:104DB00070B50E000F4C05002100300000F040F8E7 +:104DC000210028600023CB565A1C05D09E4201D1F9 +:104DD0008B6802E00C31F5E70023A0210120064A90 +:104DE000C9002B7150506A211B020B4303495350D9 +:104DF00070BDC046243A0300007000400405000066 +:104E00000C4B0D4A10B50D499C5821409950017921 +:104E10009C5809022143995080200122C0001A6049 +:104E200019581142FCD1A123024ADB00D05880B2AC +:104E300010BDC0460070004004050000FF00FFFFE9 +:104E400010B50400431C07D00DF03AFC0400431CCD +:104E500002D102480DF074FA200010BD5644030040 +:104E6000234A10B513781100012B19D1214B1B686F +:104E70001B0715D1204BE0241A68F02310001840BE +:104E800022420BD11D4A12681A4209D11C4A1D4BFD +:104E90001A6080221C4B12021A6001E03028F1D007 +:104EA0000B68DBB2012B0DD1124A1268120709D12F +:104EB000F021114A12680A40402A03D10F4A1268B1 +:104EC0000A420DD08022A3230021D205DB00D1505D +:104ED0000E4B9960013191609A68002AFCD005E080 +:104EE000C1228021D200C9058B50EBE710BDC0461E +:104EF000E00F00F0E40F00F0E80F00F0EC0F00F01E +:104F0000DFFF07C004050040186C0040FC000040B3 +:104F1000014B18687047C046E427002002B4714670 +:104F200049084900095C49008E4402BC7047C046EC +:104F3000002243088B4274D303098B425FD3030AD8 +:104F40008B4244D3030B8B4228D3030C8B420DD3EB +:104F5000FF22090212BA030C8B4202D31212090279 +:104F600065D0030B8B4219D300E0090AC30B8B42B7 +:104F700001D3CB03C01A5241830B8B4201D38B0365 +:104F8000C01A5241430B8B4201D34B03C01A52410A +:104F9000030B8B4201D30B03C01A5241C30A8B424D +:104FA00001D3CB02C01A5241830A8B4201D38B0238 +:104FB000C01A5241430A8B4201D34B02C01A5241DC +:104FC000030A8B4201D30B02C01A5241CDD2C3094E +:104FD0008B4201D3CB01C01A524183098B4201D3CA +:104FE0008B01C01A524143098B4201D34B01C01AB5 +:104FF000524103098B4201D30B01C01A5241C3082D +:105000008B4201D3CB00C01A524183088B4201D39B +:105010008B00C01A524143088B4201D34B00C01A87 +:105020005241411A00D20146524110467047FFE7F3 +:1050300001B5002000F0F0F802BDC0460029F7D00D +:1050400076E7704703460B437FD4002243088B4228 +:1050500074D303098B425FD3030A8B4244D3030BFF +:105060008B4228D3030C8B420DD3FF22090212BAC4 +:10507000030C8B4202D31212090265D0030B8B4240 +:1050800019D300E0090AC30B8B4201D3CB03C01A2A +:105090005241830B8B4201D38B03C01A5241430B05 +:1050A0008B4201D34B03C01A5241030B8B4201D3F5 +:1050B0000B03C01A5241C30A8B4201D3CB02C01A60 +:1050C0005241830A8B4201D38B02C01A5241430AD8 +:1050D0008B4201D34B02C01A5241030A8B4201D3C7 +:1050E0000B02C01A5241CDD2C3098B4201D3CB016E +:1050F000C01A524183098B4201D38B01C01A52411D +:1051000043098B4201D34B01C01A524103098B4220 +:1051100001D30B01C01A5241C3088B4201D3CB000B +:10512000C01A524183088B4201D38B00C01A5241EE +:1051300043088B4201D34B00C01A5241411A00D29E +:1051400001465241104670475DE0CA0F00D0494207 +:10515000031000D34042534000229C4603098B4277 +:105160002DD3030A8B4212D3FC22890112BA030AFF +:105170008B420CD3890192118B4208D38901921181 +:105180008B4204D389013AD0921100E08909C30906 +:105190008B4201D3CB01C01A524183098B4201D308 +:1051A0008B01C01A524143098B4201D34B01C01AF3 +:1051B000524103098B4201D30B01C01A5241C3086B +:1051C0008B4201D3CB00C01A524183088B4201D3DA +:1051D0008B00C01A5241D9D243088B4201D34B00F5 +:1051E000C01A5241411A00D20146634652415B1037 +:1051F000104601D34042002B00D549427047634618 +:105200005B1000D3404201B5002000F005F802BD5C +:105210000029F8D016E770477047C0468446101C36 +:1052200062468C46191C634600E0C0461FB501F07B +:1052300031FF002801D40021C8421FBD10B501F084 +:1052400085FE4042013010BD10B501F023FF00285B +:1052500001DB002010BD012010BDC04610B501F0DB +:1052600019FF002801DD002010BD012010BDC0463F +:1052700010B501F0ABFE002801DC002010BD0120BC +:1052800010BDC04610B501F0A1FE002801DA0020D3 +:1052900010BD012010BDC0468446081C6146FFE7D2 +:1052A0001FB500F08BFC002801D40021C8421FBDAF +:1052B00010B500F017FC4042013010BD10B500F0F1 +:1052C0007DFC002801DB002010BD012010BDC04680 +:1052D00010B500F073FC002801DD002010BD012096 +:1052E00010BDC04610B500F025FC002801DC0020F0 +:1052F00010BD012010BDC04610B500F01BFC0028F9 +:1053000001DA002010BD012010BDC046002B11D1D4 +:10531000002A0FD1002900D1002802D00021C94362 +:10532000081C07B4024802A14018029003BDC04601 +:10533000E9FEFFFF03B4684601B5029800F082F869 +:10534000019B9E4602B00CBC7047C0461300F0B5EE +:1053500045464E4657469146D2179B185340E0B4F7 +:1053600004000D009846DB0730D506000F0001232E +:105370009A4643465B08984618D022002B0020002E +:10538000290001F0F1FE5346424604000D0013428D +:10539000EFD00B0002003900300001F0E5FE43467B +:1053A0005B0806000F009846002BE6D14B46300004 +:1053B0003900002B05DA32003B000020054901F0DE +:1053C000AFFA1CBC90469946A246F0BD0026014F9C +:1053D000CDE7C0460000F03F9E2110B5C905041C72 +:1053E000FFF78AFF002803D1201C00F0C5FE10BD86 +:1053F0009E21201CC90500F039FD00F0BDFE802370 +:105400001B069C466044F2E770B500220C4B04007A +:105410000D00FFF737FF002804D12000290002F01B +:1054200091FC70BD064B00222000290002F016F905 +:1054300002F088FC80231B069C466044F1E7C046CE +:105440000000E041F0B54D46564644465F46F0B494 +:10545000924683B004000D0099468B422FD82CD081 +:105460004946504602F01CFE29000600200002F0CA +:1054700017FE331A9846203B9B4600D574E05346EE +:105480005A4693401F005346424693401E00AF4287 +:1054900029D826D05B46A41BBD41002B00DA79E059 +:1054A000002200230092019301235A469340019366 +:1054B000012342469340009319E08242D0D9002252 +:1054C0000023009201930C9B002B01D01C605D60B7 +:1054D0000098019903B03CBC90469946A246AB4661 +:1054E000F0BDA342D6D90022002300920193434687 +:1054F000002BE8D0FB0772081A4346467B080EE0F3 +:10550000AB4201D1A2420CD8A41A9D41012024191A +:105510006D410021013E24184D41002E06D0AB42C2 +:10552000EED9013E24196D41002EF8D15B4600985A +:10553000019900196941002B22DB2B005A46D34008 +:105540002A004446E2401C005B461500002B2CDB81 +:1055500026009E40330026004746BE403200801A97 +:10556000994100900191AEE7424620239B1A524692 +:10557000DA40414613004A468A4017001F4382E73B +:10558000424620239B1A2A0046469A402300F340B5 +:105590001343D5E74246202300219B1A00220091A5 +:1055A00001920122DA40019282E74246202326003E +:1055B0009B1ADE402F00B446974066463B003343BB +:1055C000C9E7C046F8B54A02430244004E00C50F81 +:1055D000240E28009B09360EC90F92098D4259D01E +:1055E000A01B002800DC8DE0002E1AD1002A00D07C +:1055F00079E05A0704D00F221A40042A00D004335D +:105600005A0138D50134FF2C00D189E028009B01D4 +:105610005B0AE4B25B02E4055B0A2343C00718435C +:10562000F8BDFF2CE5D08021C9040A431B2800DD0A +:1056300089E016002021C640081A8240511E8A4186 +:1056400032439B1A5A0114D59B019E09300002F087 +:1056500009FD05388640844265DC041B33002020A8 +:105660000134E340041BA640721E964100243343DC +:10567000BFE75A07BFD1DF082800FF2C2FD1002F2A +:1056800000D187E08022D20313003B435B025B0A18 +:10569000FF24BFE7A11B002949DD002E29D0FF2CE4 +:1056A000A7D08026F60432431B2900DD8DE01700C9 +:1056B0002026CF40711A8A40511E8A413A439B18D6 +:1056C0005A01D6D50134FF2C64D0012276491A4004 +:1056D0005B080B4013438CE7031ECAD100207B02FA +:1056E0005B0AE4B296E701380028AAD0FF2C9DD1CE +:1056F0007FE7002A00D17CE701390029DFD0FF2CA9 +:10570000D2D176E7002820D1601CC0B2012853DD39 +:1057100080279E1AFF0437402FD0D61A0D0095E738 +:105720002800002376E7614B241A334061E7002903 +:105730004DD1611CCEB2012E2FDDFF292AD09B183E +:105740005B080C0055E701227BE7002C1BD1002BE6 +:105750005BD0C04300280CD0FF2E7ED01B2800DD7C +:1057600092E01D002024C540201A8340581E83412A +:105770002B43D31A34000D0064E7002E00D065E7F8 +:1057800000200024ABE7FF2E67D08024E4044042D1 +:105790002343E3E7FF2400233CE7002C61D1002BE7 +:1057A0007ED0002A00D124E79B185A0100D460E77C +:1057B0003E4A0C0013401CE7002C1ED1002B2FD1B9 +:1057C000002A66D013000D0013E7012277E7002CB2 +:1057D0001FD1002B5AD0C94300290BD0FF2E50D027 +:1057E0001B295FDC1F002024CF40611A8B40591E0B +:1057F0008B413B439B18340062E7002B1CD1002AED +:105800004AD013000D00FF24F3E6130034000D000E +:10581000EFE6FF2E35D08024E40449422343DFE73E +:10582000002A00D1E5E68027981AFF04074000D13E +:1058300052E7D31A0D00DCE6FF24002A00D1D8E697 +:105840008020DB08C003034204D0D208024201D109 +:1058500013000D00DB00FF24CBE61300FF240D0036 +:10586000C7E6002B0DD0FF24002A00D1C1E680211D +:10587000DB08C9030B42EDD0D2080A42EAD113007B +:10588000E8E71300FF24B4E6012372E713003400B5 +:10589000AFE60027002022E780270020FF03F1E683 +:1058A0001300A6E60123A5E7FFFFFF7DFFFFFFFB37 +:1058B000F0B5564644465F464D46F0B444024600B5 +:1058C000C70F83B08846650A360EBA463DD0FF2E14 +:1058D00022D00023EC00802599469B46ED04254309 +:1058E0007F3E43465C025800DB0F640A000E984678 +:1058F00036D0FF2830D080230021E400DB041C4395 +:105900007F38301A0190484642460843724E800064 +:1059100030587A4013008746002D44D10823994619 +:10592000063B9B46DDE70122FF2000241A4064026B +:10593000C305640AD2071C431443200003B03CBCD7 +:1059400090469946A246AB46F0BD002D20D10423D7 +:105950009946033B9B46C4E7002C17D1022102E085 +:10596000002C0AD10121321A01924A4643460A43C9 +:105970005A48920082587B409746200002F072FB02 +:10598000431F76309C4040420021BAE70321B8E72C +:10599000280002F067FB431F9D40002376304642FB +:1059A00099469B469DE70C239946093B9B4698E701 +:1059B00080240022E403FF20B9E70024C2468B467E +:1059C0005A465346022AAED0032A7DD0012A31D14D +:1059D000012200201A400024A9E70122101A1B28E6 +:1059E00056DD1A4000200024A1E78023DB031D427E +:1059F0004BD18023DB032B435C02640A3A00FF2077 +:105A000095E76D016001854230D2019A0024013A88 +:105A100001921B220127290064006D00002901DB8F +:105A2000A84201D82D1A3C43013A002AF3D16A1E3C +:105A300095412C4301987F300028CEDD620704D0C9 +:105A40000F222240042A00D00434220103D5244A24 +:105A5000019814408030FE2800DD64E70122A40193 +:105A6000640AC0B21A4062E72C00A9E72D1A1A2274 +:105A70000124CFE76B02BCD500248023DB031C4349 +:105A80006402640A4246FF2051E71C42B3D1F4E7A6 +:105A900021002022C140101A8440621E94410C4310 +:105AA000620704D00F222240042A00D0043462018D +:105AB00004D5012201201A40002438E70122A40164 +:105AC000640A1A40002032E78023DB031C4364028F +:105AD000640A5246FF202AE7783A0300B83A0300E6 +:105AE000FFFFFFF7430270B542004C005D0AC30F91 +:105AF0004802120E460A240EC90FFF2A0FD0FF2CAF +:105B000011D00120A24200D070BDB542FCD18B4221 +:105B10000DD0002AF8D12800431E9841F4E7012057 +:105B2000002DF1D1EBE70120002EEDD1E9E70020B7 +:105B3000EAE7C0464302F0B542005D0AC30F4802DF +:105B4000440A4800120E000EC90FFF2A1FD0FF287A +:105B500022D0002A09D16E426E4100280FD1002CBC +:105B60000DD10020002D09D005E0002801D1002C26 +:105B700001D08B4213D0584201231843F0BD002EB0 +:105B8000F7D048424141012049420843F6E7002D41 +:105B9000DDD002204042F1E7002CDAD0F9E7824262 +:105BA000E9DC04DBA542E6D80020A542E6D2584253 +:105BB000434101205B421843E0E7C0464302F0B591 +:105BC00042004C005E0AC30F4802120E450A240E22 +:105BD000C90FFF2A17D0FF2C19D0002A0BD1704211 +:105BE0007041002C17D0002807D0484241410120C5 +:105BF00049420843F0BD002C13D08B4214D05842C8 +:105C000001231843F6E70220002EF3D1E3E7022038 +:105C1000002DEFD1E1E7002DE5D10020002EE9D0E5 +:105C2000EDE7002DE9D1EAE7A242E8DC04DBAE4271 +:105C3000E5D80020AE42DDD25842434101205B420C +:105C40001843D7E7F0B557464E4645464300E0B403 +:105C500046028846760A1F0EC40F002F47D0FF2F3A +:105C600025D0002380259A469946F600ED042E4360 +:105C70007F3F434642465D02D20F5B006D0A1B0E1A +:105C8000904640D0FF2B39D080220020ED00D20476 +:105C900015437F3BFB1842465746591C62408C46D1 +:105CA00007430F2F5CD86F49BF00C9598F46002E9C +:105CB00045D108239A46063B9946DAE74246022830 +:105CC0002DD0032800D1C3E0012800D0A2E0002598 +:105CD00000260240D4B27602ED05760A2E43E40790 +:105CE000264330001CBC90469946A246F0BD002ECB +:105CF0001AD104239A46033B9946BAE72A00511E5B +:105D00008A41901CC6E70120002DC3D0280002F074 +:105D1000A9F9431F76309D4043420020BAE7012491 +:105D2000FF2514400026D6E7300002F09BF9431F00 +:105D30009E400023763047429A46994699E70C23C5 +:105D40009A46093B994694E780260024F603FF25EE +:105D5000C1E735004846B2E7350022004846AEE7C5 +:105D60002904090C0800370C3604360C2C0C794336 +:105D7000704367437443060C64183619B14203D963 +:105D800080214902884647440004000C3104091868 +:105D90008D01681E8541890E2943350CED19AD0131 +:105DA0000D43290104D5012369081D4063460D43B5 +:105DB00019007F31002925DD680704D00F20284015 +:105DC000042800D00435280103D5274980330D402D +:105DD0001900FE29A3DC0124AD016E0A1440CDB2E6 +:105DE00079E78020C003064207D0054205D1284349 +:105DF0004602760A4446FF256DE706437602760A98 +:105E0000FF2568E70124611A1B2905DD14400025E0 +:105E1000002660E76346CBE72E002023CE40591AC8 +:105E20008D406B1E9D412E43730704D00F233340DA +:105E3000042B00D00436730104D50124012514403D +:105E4000002648E70124B601760A1440002542E7FF +:105E500080260124F6032E437602760A1440FF259D +:105E600039E7C046F83A0300FFFFFFF7F8B54A02EA +:105E70004E0043024400240EC50F9B09360EC90F85 +:105E80009209FF2E00D183E001204140A01BA942CE +:105E90005CD0002800DC95E0002E1CD1002A00D048 +:105EA00081E05A0704D00F221A40042A00D004339C +:105EB0005A013BD50134FF2C00D191E001209B0118 +:105EC0005B0AE4B205405B02E4055B0AED0723438D +:105ED0002B431800F8BDFF2CE3D08021C9040A43EE +:105EE0001B2800DD90E016002021C640081A8240E1 +:105EF000511E8A4132439B1A5A0115D59B019E09B6 +:105F0000300002F0AFF80538864084426CDC041B98 +:105F1000330020200134E340041BA640721E96414A +:105F200000243343BDE70D005A07BCD1DF0801232D +:105F30001D40FF2C33D1002F00D190E08022D203EE +:105F400013003B435B025B0AFF24BCE700284FDDE4 +:105F5000002E2ED0FF2CA4D08025ED042A431B2830 +:105F600000DD97E016002025C640281A8240501E0A +:105F7000824132439B185A01D5D50134FF2C6DD094 +:105F800001227B481A405B08034013430D0088E759 +:105F9000002A00D07AE777E7031EC5D100257B02EF +:105FA0005B0AE4B28FE701380028A4D0FF2C97D118 +:105FB00077E7002A00D174E701380028DAD0FF2CF7 +:105FC000CDD16EE7002821D1601CC0B2012858DD78 +:105FD00080279E1AFF0437402FD0D61A0D008FE776 +:105FE00001231D4000236EE7624B241A334058E71B +:105FF000002851D1601CC6B2012E33DDFF282DD000 +:106000009B185B0804004CE7012274E7002C1AD0AF +:10601000FF2E1FD08024E404404223431B2800DDD0 +:1060200096E01D002024C540201A8340581E83415D +:106030002B43D31A34000D005EE7002E00D05FE73B +:1060400000250024ABE7002B44D0C0430028F0D04B +:10605000FF2EE3D11300FF240D0022E70D00FF24E3 +:10606000002330E7002C5DD1002B7DD0002A00D129 +:1060700017E79B185A0100D456E73E4A0400134024 +:106080000FE7002C1ED1002B2FD1002A65D0130062 +:106090000D0006E701226DE7002C1FD1002B59D01F +:1060A000C04300280BD0FF2E4FD01B285EDC1D0004 +:1060B0002024C540201A8340581E83412B439B183F +:1060C000340058E7002B1CD1002A49D013000D00E2 +:1060D000FF24E6E6130034000D00E2E6FF2E34D084 +:1060E0008024E40440422343DFE7002A00D1D8E6BD +:1060F0008027981AFF04074000D14DE7D31A0D00FE +:10610000CFE6FF24002A00D1CBE68020DB08C003C5 +:10611000034204D0D208024201D113000D00DB007B +:10612000FF24BEE6002B10D0FF24002A00D1B8E6E1 +:106130008020DB08C003034203D0D208024200D112 +:106140001300DB000D00FF24ABE61300FF24A8E6DC +:1061500001236EE713003400A3E6002700251EE7A5 +:1061600080270025FF03E9E613009AE60123A6E74E +:10617000FFFFFF7DFFFFFFFB4302590A4300C20FF1 +:106180001B0E00207E2B0EDD9D2B0DDC80200004DD +:106190000143952B0BDC9620C31AD9400B005842C3 +:1061A000002A00D118007047034BD018FBE7963B3C +:1061B00099400B00F3E7C046FFFFFF7F70B5002852 +:1061C00030D0C317C5185D40C40F280001F04AFF46 +:1061D0009E231B1A962B0DDC9622D21A95406A023A +:1061E000520AD8B25202C005520AE40702432243BF +:1061F000100070BD992B19DC9922D21A9540124AD1 +:106200002A40690704D00F210D40042D00D004322C +:10621000510103D50C4B1A409F231B1A9201520ABD +:10622000D8B2DFE7002400200022DBE705222E00A1 +:10623000121AB921D6402A00C91A8A40551EAA410D +:1062400035001543DBE7C046FFFFFFFB70B5041EBA +:1062500028D001F007FF9E231B1A962B0ADC9622FA +:10626000D21A94406202520AD8B25202520AC005AF +:10627000104370BD992B18DC9922D21A9440114A10 +:106280002240610704D00F210C40042C00D00432BE +:10629000510103D50B4B1A409F231B1A9201520A3E +:1062A000D8B2E2E700200022DFE705222500121A1B +:1062B000B921D5402200C91A8A40541EA2412C009F +:1062C0001443DCE7FFFFFFFBF8B556465F464D463B +:1062D0004446F0B40F00FD0FAA4609037C002E00CF +:1062E0005F00450F490A7F0D2943C5001803BC46CE +:1062F000400A570F640DDB0F3843D2009A4500D196 +:10630000AAE06646A61B002E00DCFFE06346002BD9 +:1063100039D10300134300D0D9E06B0709D00F2314 +:106320002B40042B05D02B1DAB42AD416D424919CA +:106330001D000B0200D482E0CA4B01349C4200D104 +:10634000FEE00A005646C84BED081A4050076405A7 +:1063500052020543120B640D002112030B0D1B05A5 +:106360006405120B1A436308C04CF60714401C4323 +:10637000640064083443280021003CBC90469946E0 +:10638000A246AB46F8BDB74B9C42C6D080231B0447 +:106390001843382E00DDEBE01F2E00DD1EE1202328 +:1063A0009B1B9C4603006746BB409846130047462C +:1063B000F3403B436746BA40571EBA4113430200BD +:1063C000F240EB1A9D42B6411D008A1A7642911B9B +:1063D0000B0231D54A02560A002E00D1B4E030003B +:1063E00001F040FE0300083B1F2B00DDB5E020223A +:1063F0002900D21AD1409E400A009D4032439C425F +:1064000000DDB1E01C1B631C1F2B00DDD5E020214B +:1064100014002800C91A8C40D8408D400443DA404B +:10642000681E854111002543002476E7414631432B +:1064300000D134E2310045466B0700D06FE7564685 +:106440004807ED08C9080543864B9C4235D00A032E +:106450006405120B640D7FE76346E31A9B46002B2D +:1064600000DC8BE06746002F3CD07E4FBC4200D161 +:1064700053E780273F0438435B46382B00DCF7E0C6 +:106480000243501E82410020D2B253194218AB423F +:1064900089411D00494289180B02CDD5714B013449 +:1064A0009C4200D13DE101206F4A6B080A40284020 +:1064B0001843D507054351082FE72B000B4300D1A4 +:1064C000CBE180231B030B431A03120B44E7013E6D +:1064D000002E6DD1AE1AB5429B41091A5B42C91A12 +:1064E000350075E70700174300D116E701235B422B +:1064F0009C46E3445B46002B00D0E0E0AA18AA4289 +:106500009B4109185B4259181500C5E7002E75D14B +:10651000661C7605760D012E00DCF3E0AE1AB0465F +:106520004545BF410E1A7F42F61B370200D48FE06B +:10653000551BAA42B641411A76428E1B9A464BE73A +:1065400056460022002507E7280001F08BFD203089 +:106550000300083B1F2B00DC49E72A002838824053 +:1065600000259C4200DC4DE73F49E41A1140D4E687 +:106570000243501E8241D3B2002222E7002B00D0FA +:10658000F3E0631C9C465B055B0D012B00DC9FE088 +:10659000344B9C4500D1C3E0AA180918AA42804197 +:1065A00040424118CD075208154349086446B4E6F5 +:1065B0002C4B9C4200D0ECE6AFE611001F3CE140C2 +:1065C0000C00202B00D17FE04021CB1A9A401543CC +:1065D0006A1E95410021254300242DE73300070062 +:1065E000203BDF403B00202E70D04027BE1BB04038 +:1065F0000243501E824113430022E2E6002C4FD09A +:10660000184CA44500D1ABE08024240476422143F9 +:10661000382E00DDDFE01F2E00DD43E12027BC1B0C +:10662000A1460C004F46BC40A0462C004746F44013 +:106630003C434F46BD406F1EBD41F1402C43151BEE +:10664000AA429241411A5242891A64469A46BFE6CA +:1066500041464546314300D0BEE6002600240025D1 +:10666000F2E6C046FF070000FFFF7FFFFFFF0F803D +:106670001F2B59DC2027FF1ABC46070063469F40AA +:106680005B46B9461700DF40B8464F4643461F43B6 +:1066900063469A40531E9A415B463A43D840F4E61B +:1066A0000C002C435CD0F643002E55D1551BAA425A +:1066B000A441411A6442091B9A46644688E6964FF3 +:1066C000BC4200D0D8E628E6002280E700208FE711 +:1066D0000B002B43002C00D0C2E0002B00D101E1C5 +:1066E0000300134300D118E6AB18AB42B6410918BA +:1066F000764271180A0200D409E1884A1D0011404F +:1067000064460AE6002C5BD10E002E4300D08AE0DE +:106710000100114300D1C2E0010015009A46FCE5DA +:106720006446002100258FE620235B429C46DC4422 +:1067300063460700DF405B46BC46202B00D1ACE03F +:1067400040235F46DB1B98400243501E8241634654 +:1067500013431A00002098E66F4CA44500D057E779 +:106760000100150064469A46D7E5002C39D10C008B +:106770002C436ED0DB43002B1AD0674CA44568D065 +:10678000382B00DDA4E01F2B00DDAEE020240F003D +:10679000E41AA740B9462F00DF40B846A3464F464B +:1067A000444627435C46A5406C1EA541D9403D4365 +:1067B000AD1895429B4109185B42591864466BE637 +:1067C0000C002C4315D1010011437BD001001500B2 +:1067D0009A46514CA1E50D43691E8D410021ECB252 +:1067E0002DE74D4CA44534D0802424045B42214342 +:1067F000C6E7040014434ED0ED084C072C43802517 +:10680000C9082D03294208D0C6082E4205D1D20856 +:10681000410711430C009A463100620FC900E500A0 +:1068200011433D4C79E50600164300D175E5AE1ADB +:10683000B0464545BF410E1A7F42F61B370200D4D1 +:10684000F4E5551BAA42B641411A7642891B9A4685 +:1068500063E50100150064465FE5002200257BE545 +:10686000002B3BD00300134315D0ED084B072B43FF +:106870008025C9082D03294207D0C4082C4204D121 +:1068800041070B002100D2081343C9005A0F1143DE +:10689000DD00214C41E5204C3FE5002054E7002677 +:1068A0000025D1E534000F00203CE7403C00202EBD +:1068B0002BD04027BE1BB1400D43691E8D410021E6 +:1068C0002C43BCE6802100260903134C0025BBE5C0 +:1068D0000D43691E8D410021EDB269E701001500ED +:1068E0000D4C1AE50100150017E51C000F00203CB7 +:1068F000E7403C00202B0CD04027FB1A99400D4369 +:10690000691E8D410021254352E70021D4E71D0077 +:1069100092E50021F3E7C046FF070000FFFF7FFF7D +:10692000F0B556464D4644465F46F0B41D000E0392 +:106930004C00CB0F87B0070092468146360B640DA2 +:1069400098466AD06D4B9C4235D08022430F12048A +:106950001343F6001E43C3009946694B00279C462B +:106960000023644402932B0368001B0BED0F514678 +:106970009B46400D009500D178E0604B98426CD06A +:106980005B46DA004B0F802109040B4313439B46FF +:106990005346D9005A4B9C46002360444246201A75 +:1069A0006A40924601901F430F2F00D9B0E055482E +:1069B000BF00C0598746374300D088E0002399467E +:1069C0000233082700260293CDE74346B3464946E3 +:1069D0000093029B009A9246022B00D0BFE1002157 +:1069E00053460122002689461A40444B00213603B3 +:1069F0000C0D2405360B2643434C1B0526401E4335 +:106A00007600D207760816434846310007B03CBCF2 +:106A100090469946A246AB46F0BD330003434FD0A3 +:106A2000002E00D1BCE1300001F01CFB03000B3B49 +:106A30001C2B00DDADE11D220100D31A08393A00FC +:106A40008F408E40DA40B9461643304B00279C46B3 +:106A5000002360444442029385E753465A46134359 +:106A60002CD1002300219B46023397E70B4320D013 +:106A70005B46002B00D19EE1584601F0F3FA03007B +:106A80000B3B1C2B00DD8FE102005946083A914078 +:106A90008B461D21CB1A5146D9400B0059460B435A +:106AA00051469B469140194B9C466044404200230E +:106AB00074E7002300219B4601336FE703236DE752 +:106AC0000023994601330427002602934BE7032352 +:106AD0000C27029347E70122D51A382D00DCB0E1DC +:106AE00053461A4000210023002689467EE70023F2 +:106AF0008026994600223603004B77E7FF07000007 +:106B000001FCFFFF383B0300FFFF0F80F303000091 +:106B10005E4500D972E100D16DE1019B4D46013B1C +:106B200001930023340002935B461E020B0E1E43AA +:106B30000B020393330C994633041B0C4946200087 +:106B40000093FEF7F5F9009B3700434306004946E2 +:106B500020009846FEF772FA2C0C09040C43A0455D +:106B600009D9E419731EA74200D95CE1A04500D8F9 +:106B700059E1023EE4194346E41A49462000FEF773 +:106B8000D7F90300009A80465343494620009B46AC +:106B9000FEF754FA2A040904120C0A4393450DD94E +:106BA0004346D219013B974200D93AE1934500D8B8 +:106BB00037E102235B429C46D219E0445B46D21A7D +:106BC0004346360433439B460399180C0B0C1D00B7 +:106BD000059309045B46090C0C001B041B0C444381 +:106BE000049159436B4368431B190D0CEB189C42ED +:106BF00003D980246402A44660441C0C09041B04CD +:106C0000090C20185D18824200D2DEE000D1D7E0E6 +:106C1000161A029B9C465D1BAC459B415B42F61AD3 +:106C2000B74200D106E149463000FEF781F9009BEA +:106C300004004343494630009846FEF7FFF92E0C06 +:106C400009040E43B04509D9F619631EB74200D9AD +:106C5000F3E0B04500D8F0E0023CF6194346F31AE1 +:106C6000494618000293FEF763F9009B0600434370 +:106C7000494602989846FEF7E1F92D0409042D0CC7 +:106C80000D43A84509D9ED19731EAF4200D9D6E0CE +:106C9000A84500D8D3E0023EED1924042100434664 +:106CA0003143049E059A3000ED1A0B040C0C1B0CAA +:106CB00058436643534354439A19030C9B189E420E +:106CC00003D980225202944664441A0C00041B0427 +:106CD000000C14191B18A54250D34DD001231943A1 +:106CE000964A019B94466344002B00DCF3E64A0776 +:106CF00009D00F220A40042A05D00A1D8A42894180 +:106D000049428B4411005A46D20108D55A468C4B51 +:106D10001A4093468022D2009446019B6344894ADC +:106D2000934200DD5BE65A46C90850070843560205 +:106D3000514601225B058146360B5B0D0A4055E644 +:106D400080231B031E4211D05A461A420ED15E46C2 +:106D50001E433603360B2A0089467B4B46E6032B3F +:106D600000D1E1E0012BBBD11A40BBE61E43360344 +:106D7000360B4246744B39E6002BB1D07D194A1EC2 +:106D8000AF4252D91100A542A8D1039A9A42A5D187 +:106D9000A6E703003E00283B9E400023994654E6A8 +:106DA00001F060F9203041E603005246283B9A404A +:106DB0000021934677E6504601F054F920305EE614 +:106DC000029B0026AB4200D323E7039E0299B44600 +:106DD00061448846B045B6415B467642F619B21822 +:106DE000013B0291974213D290424FD800D18EE0DE +:106DF000161A9B460DE7894500D28EE674084B466D +:106E0000F60735005B081D434B46DB0702938BE614 +:106E10009742EDD10399029CA142E5D93E1A9B46C7 +:106E2000F7E69846CAE61E00A5E6AC423ED874D006 +:106E3000110053E70121494252E71C000EE71E00F2 +:106E40002BE71F2D3CDC20230A0058465B1B984093 +:106E5000EA4099400243481E81415E461143EE409C +:106E60004B0709D00F230B40042B05D00B00191D35 +:106E700099429B415B42F61833023CD553460122AE +:106E800000211A40002601238946AFE502235B4218 +:106E90009C46039CE344A446029B63449846A04559 +:106EA000B6417642F6190293B218B1E603988A1EEB +:106EB00041008142B6417642F619AD19039161E76E +:106EC0001F225242D31A5A46DA401300202D29D0ED +:106ED00040225846551BA8400143481E81410720C7 +:106EE0000B4318400026002809D00F2200261A4024 +:106EF0001900042ABBD10B0070077602360BDB08A1 +:106F000003439946012253461A4000236EE5029935 +:106F10008D42BBD89B4600267BE603989842C5D39A +:106F2000110032E70020D7E780265B4636031E4378 +:106F30003603360B009A8946034B57E5FF030000E2 +:106F4000FFFFFFFEFE070000FF070000F0B55F46F1 +:106F500056464D464446F0B41F035C00DB0F9A468C +:106F6000194B0E034D00C90F8046360B6D0D8B4635 +:106F700091463F0B640D9D4219D0134B9C421BD090 +:106F80000123A54206D018003CBC90469946A24673 +:106F9000AB46F0BDBE42F6D1C845F4D1D34510D0C2 +:106FA000002DF0D1304303005A1E9341EBE731002E +:106FB00001230143E7D1E0E73A430123002AE2D16C +:106FC000DEE70023DFE7C046FF070000F0B55F46BD +:106FD000444656464D46F0B41F033C0B2C4F0E035F +:106FE0004D00A3465C008446360B6D0DC90F9046DC +:106FF000640DDB0FBD422BD0254FBC422ED0002D9F +:107000000ED130430700814678427841002C17D1D9 +:107010005F463A4314D14B460020002B0AD006E0CD +:10702000002C02D15846024301D099421AD00123C4 +:10703000484218433CBC90469946A246AB46F0BD38 +:107040000028F2D058425841012240421043F1E753 +:1070500037000743D0D002204042EBE75F4617439A +:10706000CDD0F8E7A542E2DC05DB5E45DFD808D0ED +:1070700000205E45DED24842484101234042184389 +:10708000D8E7C445D3D80020C445F4D3D2E7C046DE +:10709000FF070000F0B55F464D4644465646F0B443 +:1070A0001C03240BA4462F4C0F034D005E00C90F98 +:1070B00080463F0B6D0D8B469146760DDB0FA5424A +:1070C00020D0284CA64222D0002D12D13843444271 +:1070D0004441002E20D0002C0DD05C42634101249D +:1070E0005B421C4320003CBC90469946A246AB46FE +:1070F000F0BD002E17D05B4519D05B465C420123E2 +:107100001C43EFE7390002240143EBD1D9E7614684 +:1071100002241143E6D1D7E761460A43DBD10024BC +:107120000028DFD0E9E761460A43E4D1E5E7B5424C +:1071300003DD01225C421443D4E7B542CDDB674551 +:10714000DBD809D000246745CCD259464C42614176 +:10715000012449420C43C5E7C845CED80024C845A0 +:10716000F3D3BFE7FF070000F0B55F4656464D4634 +:107170004446F0B40D0399464E002B0B87B0070030 +:10718000924680469B46760DCC0F002E69D06D4B03 +:107190009E4235D05B468022DD001204430F13432C +:1071A0002B439B46C3009846674B00279C46002311 +:1071B000664401934A4615035000D20F53462D0BE7 +:1071C000400D914600D176E05E4A90426CD080221C +:1071D0005B0F120413435C4AED0094461D43534673 +:1071E0000022DB00604449463618701C6140029062 +:1071F00017430F2F00D9AFE05448BF00C759BF460F +:107200005B461F4300D088E000239B46984602332C +:1072100008270193CEE74946022A6AD0032A00D103 +:1072200009E2012A00D0BBE1114000220023002521 +:107230009046CCB200212D030A0D12052D0B1543EB +:10724000434A1B0515401D436D00E4076D082543A7 +:107250004046290007B03CBC90469946A246AB4642 +:10726000F0BD034352D05B46002B00D18AE1584663 +:1072700000F0F8FE03000B3B1C2B00DD7BE11D2220 +:10728000D31A3A0001005D46DA4008398D401300F8 +:107290008F402B439B46B8462E4B00279C4600232D +:1072A00060444642019385E752462A432CD100258B +:1072B0000023022297E752462A4321D0002D00D115 +:1072C00054E1280000F0CEFE03000B3B1C2B00DD38 +:1072D00046E11D21CB1A51460200D9405346083AD7 +:1072E000954093400D431B4A94466044404200221F +:1072F00079E7012400220C40124B0025904699E7C3 +:107300000025002301226EE703226CE700239B4641 +:1073100098460133042701934CE703230C2701937C +:1073200048E700238025984600242D03054B81E77C +:107330005D464346019A6FE75D4643462100019A48 +:107340006AE7C046FF07000001FCFFFF783B03002F +:10735000FFFF0F80F30300004246120C91461A0C07 +:107360009446424617044A461B041B0C5A43604687 +:1073700090464A4642431000039262461C003F0C6E +:107380007A437C4342440192220C9246019A524431 +:10739000904506D98246802040028046C24450462D +:1073A0000390100C049048462404240C1204121973 +:1073B00005922A0C2D042D0C68432C008246484669 +:1073C0007C4350438146200C8046574357444744F2 +:1073D000BA4503D9802040028046C144380C3F049E +:1073E000B84648442404240C01900498A044404426 +:1073F00004905846000C814658460404200C8246EE +:10740000070048465F434C4643436046604364463A +:10741000834650464443380C8446E4186444A342EF +:1074200003D980235B029C46E34448463F04230C77 +:107430003F0C2404E419574668436F4384464D4685 +:10744000504655434243380C814662444A445B44AB +:10745000944503D9802040028446654403983F0444 +:10746000834604983F0C8446E344C3458041404230 +:107470008246100484460198674484466744A344C6 +:10748000BC46A345A4419946D44464428742BF41C7 +:10749000D4458041E144A04699459B417F4240420A +:1074A000C8440743120CBA18A045A4415F423B00F0 +:1074B00064422343D71843467D19DB0D6D021D43FB +:1074C0005B465A02059B1A43531E9A415B46DB0DED +:1074D0001A4343465B021343EA0107D501225C08C5 +:1074E00013402343EA07029E13436D08574AB2181C +:1074F000002A4BDD580709D00F201840042805D07A +:10750000181D98429B415B42ED180300E80104D529 +:107510004F4A15408022D200B2184E48824200DD08 +:10752000E7E60124DB08680718436D02530580462F +:107530002D0B5B0D0C407DE6802259461203114253 +:1075400008D0154206D115432D0398462D0B4C4605 +:10755000414B6FE65D4615432D032D0B3E4B69E60F +:1075600003005546283B9D400023BCE6504600F0F2 +:1075700079FD2030A8E60300283B9F400023BB464E +:10758000984689E600F06EFD203073E60124A61AC5 +:10759000382E07DD00220C4000230025904649E6E6 +:1075A000029EA3E71F2E20DC20222C001800921B35 +:1075B000F040944093400443581E83411C43F540DF +:1075C000630709D00F232340042B05D023001C1D83 +:1075D0009C4292415242AD182B021FD50124002239 +:1075E0000C4001230025904624E61F202C00404239 +:1075F000821AD440202E1CD04022961BB5402B432B +:10760000581E83410720234318400025002809D035 +:107610000F2200251A401C00042AD8D12300680735 +:107620006D022D0B0124DB08034398460C40002318 +:1076300000E60025E3E780220124120315432D0311 +:1076400098462D0B0C40044BF4E5C046FF030000A8 +:10765000FFFFFFFEFE070000FF070000F0B55746E2 +:107660004E464546E0B40E001100F20F9246C500AA +:10767000420F180337037400400A4E0F7F0A30434D +:10768000CF4E17435A00640D520DDB0FC900B242B2 +:1076900000D1E5E001267340A61AB446534500D157 +:1076A000AFE0002E00DC0DE1002A3AD103000B43CD +:1076B00000D0E4E06B0709D00F232B40042B05D04A +:1076C0002B1DAB42AD416D427F191D003B0200D422 +:1076D00088E0BB4B01349C4200D110E13A00B94B29 +:1076E00051461A4001235007ED0852026405054334 +:1076F000120B640D0B400021280012030D0D120B1C +:1077000064052D0515436208AF4CDB072C4014437C +:10771000640064081C4321001CBC90469946A246A4 +:10772000F0BDA74B9C42C5D080231B041843634681 +:10773000382B00DDFDE01F2B00DD30E16246202309 +:107740009B1A02009A40664690460A009940F24011 +:1077500046464B1E99413243114363460200DA40CC +:10776000691A8D429B410D00BA1A5B42D71A3B023F +:1077700035D57A02530A98464346002B00D1C4E01F +:10778000404600F06FFC0300083B1F2B00DDC5E006 +:1077900020222900D21A4746D1409F400A009D402E +:1077A0003A439C4200DDC0E01C1B631C1F2B00DD24 +:1077B000E4E0202114002800C91AD8408C408D40F4 +:1077C0000443DA40681E854117002543002471E711 +:1077D000424663461A4300D14CE2674645466B0772 +:1077E00000D069E7012351467807ED08FA080B40FD +:1077F000054373498C4238D012036405120B640DA3 +:1078000079E7002E00DC9AE0002A47D06C4A9442C7 +:1078100000D14FE78022120410436246382A00DC70 +:1078200008E10143481E81410022C9B24919D21919 +:10783000A942BF410D007F42BF183A0200D442E185 +:107840005F4A0134944200D14EE101205D4A69084B +:107850003A4028400843D507054357089A4629E788 +:1078600006000E4300D017E714E72900114300D1AA +:10787000F9E1802109030A431203120B3BE70123BC +:107880005B429846C4446346002B72D1691A8D420C +:107890009B413F1A5B42FF1A0D0068E702000A4352 +:1078A00000D107E7012252429046C4446246002AB2 +:1078B00000D0E6E06918A942B6413F187642F719B0 +:1078C0000D00BAE7002E00D080E0621C5205520D78 +:1078D000012A00DCF9E06A1A91464D45B6413A1A90 +:1078E0007642921B9046120200D499E04D1BA942A9 +:1078F0008941C71B49427A1A90469A463CE752464C +:107900000123002513400022F5E6280000F0AAFB21 +:1079100020300300083B1F2B00DC39E72A00283801 +:10792000824000259C4200DC3EE7264FE41A1740C7 +:10793000C0E60143481E81410022C9B210E7002E73 +:1079400000D0F1E0621C94465205520D012A00DC81 +:10795000A0E01B4A944500D1C5E06918A9429241B4 +:107960003F185242D2194908D5070D4357086446BB +:10797000A0E6134B9C4200D0D9E69BE611001F3CC9 +:10798000E1400C00202B00D180E04021CB1A9A402E +:1079900015436A1E95410027254300241FE76346CF +:1079A0000200203BDA406346202B71D0402366461C +:1079B0009B1B98400143481E814111430022CFE6A2 +:1079C000FF070000FFFF7FFFFFFF0F80002C48D064 +:1079D000CA4CA24200D1A2E07442A14680242404F1 +:1079E00027434C46382C00DDDBE01F2C00DD44E152 +:1079F0004E462024A41B3E00A640A246B0464C465C +:107A00002E00E640B4464646644626435446A5400A +:107A10006C1EA54134002C434D46EF400D1B28E061 +:107A20004A4643464D461A4300D0A5E600230024AB +:107A30000025DEE61F2A5ADC66462022921B06003D +:107A400096409146B04662460E00D64042461643E6 +:107A50004A4691404A1E9141020060463143C2406D +:107A6000E4E63C002C435AD0F443A146002C52D10A +:107A70004D1BA9428941C71B49427F1A14009A46EF +:107A800075E69E4A944200D0C7E613E600227FE7DF +:107A900000208FE7002C00D0C8E03B002B4300D132 +:107AA0000FE103000B4300D104E66918A9429B4192 +:107AB0003F185B42DF193B0200D41AE1904B0D00E6 +:107AC0001F406446F6E59A4689E63A002A43002CB0 +:107AD0005CD1002A75D102000A4300D1CAE0070038 +:107AE0000D009A46E6E564460022002581E66246DE +:107AF0000600203AD6406246B046202A00D1B7E0C0 +:107B000040226646921B904001434246481E8141F6 +:107B1000114300228AE6794CA24200D061E70700B7 +:107B20000D0014009A46C5E5002C41D13C002C43C1 +:107B300078D0F443A146002C20D0704CA24271D0E2 +:107B40004C46382C00DDB2E01F2C00DDBCE02026C6 +:107B5000341BA2463C005646B4404E46A0462C007C +:107B6000F440A446444666463443A4465446A540E1 +:107B700064466E1EB54125434C46E7406D188D4264 +:107B800089413F184942CF19140056E6002A2FD1E7 +:107B900002000A4300D184E007000D009A46574CCA +:107BA00088E53D436F1EBD41ECB200270D1B60E729 +:107BB000524CA24236D0744280263604A146374346 +:107BC000BEE702000A4300D174E56A1A90464545B3 +:107BD000B6413A1A7642921B9446120200D4F7E557 +:107BE0004D1BA9428941C71B49427F1A9A4661E54C +:107BF00002000A433AD0ED087C072C438025FA089E +:107C00002D032A4208D0C7082F4205D145072C0072 +:107C10003A009A46C9080C43670FD200E5001743A3 +:107C2000364C47E507000D00140043E53A002A43AF +:107C300043D002000A4319D0ED087C072C4380256D +:107C4000FA082D032A4207D0C6082E4204D147075E +:107C50003C003200C9080C43D700620FE50017430F +:107C60009A46264C26E50022002544E5234C21E5D2 +:107C7000002049E700230025BBE54C463E00203CA0 +:107C8000E6404C46B446202C31D040244E46A61B3C +:107C9000B7403D436C1EA54164462C4300270D1B95 +:107CA000E7E6802200231203144C0025A1E53D43A2 +:107CB0006F1EBD410027EDB260E707000D000F4CBD +:107CC000F8E407000D00F5E44E463C00203EF44089 +:107CD000A0464C46202C0ED040244E46A41BA74064 +:107CE0003D436F1EBD4144460027254346E700271C +:107CF000CFE70D0073E50027F2E7C046FF0700005D +:107D0000FFFF7FFF70B50E4E0C031D0349005B00A3 +:107D1000240B490D2D0B5B0DB14204D00849002006 +:107D20008B4208D070BD04430120002CFAD10449D5 +:107D300000208B42F6D115432800451EA841F1E7EB +:107D4000FF0700000B0330B5134D1A0B4B005B0D02 +:107D5000C90F0024AB4211DD104CA34210DC80247B +:107D6000640322430E4CE41A1F2C0CDD0D48C31A89 +:107D7000DA4013005C42002900D11C00200030BD15 +:107D8000094BCC18FAE7E040084CA44663449A40FB +:107D900013000343EEE7C046FE0300001D0400008D +:107DA0003304000013040000FFFFFF7FEDFBFFFF23 +:107DB00070B5002830D0C317C4185C40C50F200030 +:107DC00000F050F9174B184A1B1AD21A1F2A18DD57 +:107DD000164AD21A9440002224035B05240B5B0D43 +:107DE0000021100024030A0D1205240B1443104A2D +:107DF0001B0514401C436400ED0764082C4321005C +:107E000070BD210091400A000B21081AC4405B0597 +:107E10002403240B5B0DE3E700250023002400224C +:107E2000DEE7C0461E040000330400001304000017 +:107E3000FFFF0F8070B5051E28D000F013F9154B19 +:107E4000154A1B1AD21A1F2A16DD2C00134A0025C8 +:107E5000D21A94405A052403240B520D0021240306 +:107E60000B0D240B1B0523430D4C1205234013431C +:107E70005B002800590870BD0B212C00081AC44073 +:107E8000954024035A05240B520DE7E700220024F5 +:107E9000E4E7C0461E0400003304000013040000A1 +:107EA000FFFF0F804200120E511C4302C9B270B591 +:107EB0005D0AC40F012915DDE02189008C466D079C +:107EC0001B0B6244002128000D0D2D052B431C4D7A +:107ED00052052B40520813435B00E4075B08234321 +:107EE000190070BD002A15D1002D1FD0280000F008 +:107EF000B9F80A281DDC0B232A001B1ADA401300EC +:107F00000200153295400F4A1B03121A52051B0B33 +:107F1000520DD7E7002D06D080221B0B120313430E +:107F20006D07094ACEE7084A0023CBE70022002369 +:107F3000C8E703000B3B9D402B000025E3E7C0464C +:107F4000FFFF0F8089030000FF0700004B0070B5A2 +:107F50005E0D0C03751C640A420F6D052243C90FA8 +:107F6000C4006D0D012D2ADD3B4BF318FE2B1ADCEE +:107F7000002B42DD8001451EA841D2001043620F54 +:107F80000243500704D00F201040042800D00432D0 +:107F90008020C004104021D00133FF2B03D0920178 +:107FA000520ADBB201E0FF2300225202520ADB0533 +:107FB00013435B00C9075B080B43180070BD002E1C +:107FC00007D01443EFD08020D20080040243FF2367 +:107FD000D7E722430023002A03D00522D208FF2B33 +:107FE00003D05202520ADBB2DFE7002A32D08020EF +:107FF000C00302435202520AD7E71800173014DBBD +:108000008020000402431E20C01A1F280FDC250018 +:10801000124BF3189D406E1EB5419A402B0013433E +:108020002200C2401A430023ABE70023D5E7022514 +:108030006D42EB1A1500DD40202809D0084BF318DB +:108040009A401443621E9441220000232A4398E779 +:108050000022F6E70022A8E780FCFFFF82FCFFFF7A +:10806000A2FCFFFF1C2101231B04984201D3000C3A +:1080700010391B0A984201D3000A08391B0998429B +:1080800001D30009043902A2105C40187047C046B1 +:1080900004030202010101010000000000000000D1 +:1080A00010B5002903D1FFF7DDFF203002E0081CE6 +:1080B000FFF7D8FF10BDC046F0B54746494A4B0010 +:1080C00080B406000F0088465B0893424BDC464AAA +:1080D00093420FDC454A464BFEF7F6F8454B00222B +:1080E000FDF7C6F83B00002854D03000190004BC4E +:1080F0009046F0BD404A93423CDC8022D205934238 +:1081000048DD00F0F9FA320004000D003B003000B9 +:108110003900FFF729F80022364BFEF7D5F803F0B7 +:10812000EBF902000B0020002900FEF7CDF8020059 +:108130000B0000202F49FEF7F3FB220006000F0082 +:108140002B0020002900FEF7BFF802000B003000D2 +:108150003900FEF7B9F802F063FC43460600002B35 +:1081600014DD0B00C1E70B000200FEF7ADF80600BE +:108170000B00BAE700F0C0FA02F052FC1F4B204A95 +:10818000FEF7A2F843460600002BEADC80231B061C +:10819000CB18AAE732003B0030003900FEF7E4FFBD +:1081A00004000D003000390000F0A6FA002206009D +:1081B0000F00104B20002900FEF786F803F09CF911 +:1081C00000220C4BFEF780F802000B002000290073 +:1081D000FEF7A6FB32003B00FEF776F800F028FB26 +:1081E000BBE7C046FFFFEF7FFFFF2F3E9C75008877 +:1081F0003CE4377E0000F03F0000B041422EE63FF5 +:10820000EF39FAFEF8B556464D4644465F46A54B53 +:10821000F0B44E00804689468A4676089E420CDDC0 +:10822000A14B9E4200DDA0E000D19BE05346002B15 +:1082300000DCE3E09D4B9E4A9FE09E4B9E4200DDAA +:10824000B1E09D4B9E4200DC9FE001235B429B46D8 +:1082500042464B4640464946FEF786FF02000B0069 +:1082600006000F00FEF780FF04000D00934A944BB8 +:10827000FEF77AFF934A944BFEF726F822002B0074 +:10828000FEF772FF914A924BFEF71EF822002B0078 +:10829000FEF76AFF8F4A904BFEF716F822002B007C +:1082A000FEF762FF8D4A8E4BFEF70EF822002B0080 +:1082B000FEF75AFF8B4A8C4BFEF706F832003B0064 +:1082C000FEF752FF894A8A4B06000F002000290062 +:1082D000FEF74AFF874A884BFFF7C0F922002B00C0 +:1082E000FEF742FF854A864BFFF7B8F922002B00C4 +:1082F000FEF73AFF834A844BFFF7B0F922002B00C8 +:10830000FEF732FF814A824BFFF7A8F922002B00CB +:10831000FEF72AFF0B0059460200013100D170E040 +:1083200059463000CC003900FDF7CEFF42464B469F +:10833000FEF71AFF774D784B2D191C1922686368D8 +:10834000FFF78CF942464B46FFF788F902000B0015 +:1083500028686968FFF782F953460A00002B48DB5A +:1083600003000AE0002800D160E742464B46404641 +:108370004946FDF7A9FF03000A00180011003CBCA4 +:1083800090469946A246AB46F8BD644A644BFDF759 +:108390009BFF0022634BFCF76BFF002800D154E7E2 +:1083A00043464A46E9E700F0A7F95F4B04000D0099 +:1083B0009E4237DC5D4B9E425DDC02000B00FDF708 +:1083C00083FF0022574BFFF749F9802306000F0077 +:1083D0000022DB0520002900FDF776FF0B000200DC +:1083E00039003000FEF79CFA0023804689469B4600 +:1083F0002EE78022120603008A18BEE72B4B4C4A58 +:10840000BBE730003900FDF75FFF42464B46FEF701 +:10841000ABFE02000B0040464946FFF71FF9030080 +:108420000A00AAE7434B9E421ADC0022424BFFF7A8 +:1084300015F9002206000F003F4B20002900FEF72F +:1084400093FE0022374BFDF73FFF0B00020039007F +:108450003000FEF765FA0223804689469B46F7E620 +:108460000B00020035490020FEF75AFA032380462C +:1084700089469B46ECE600222A4BFFF7EFF80022E4 +:1084800006000F00274B20002900FDF71DFF0B0001 +:10849000020039003000FEF743FA01238046894686 +:1084A0009B46D5E6FFFF0F440000F07F182D445493 +:1084B000FB21F93FFFFFDB3FFFFF1F3E11DA22E305 +:1084C0003AAD903FEB0D76244B7BA93F513DD0A0B8 +:1084D000660DB13F6E204CC5CD45B73FFF8300927E +:1084E0002449C23F0D5555555555D53F2F6C6A2C23 +:1084F00044B4A2BF9AFDDE522DDEAD3F6D9A74AF3B +:10850000F2B0B33F711623FEC671BC3FC4EB98991D +:108510009999C93F882D0300682D03009C75008838 +:108520003CE4377E0000F03FFFFFF23FFFFFE53FF6 +:10853000FB21F9BFFF7F03400000F83F0000F0BFC0 +:10854000444AF8B5564692464B005B0D9A44444661 +:108550005F464D465246F0B4884605000C000E00BA +:108560000700132A27DC002A59DB52463A4B1341F5 +:1085700099460B004A461340034316D0374A384BFE +:10858000FDF7A2FE00220023FCF772FE00280AD0AD +:10859000002C04DD802352465B0313419844464679 +:1085A0004B4600279E43380031003CBC904699461C +:1085B000A246AB46F8BD5246332A08DD8023DB00D5 +:1085C0009A45F2D102000B00FDF77EFEEDE7254A49 +:1085D0009446012263445242DA4093460242E4D078 +:1085E0001E4A1F4BFDF770FE00220023FCF740FEE1 +:1085F0000028D8D0002C0CDD5346142B26D0342371 +:10860000524601279B1A9F407F19AF429B415B4214 +:1086100098445B4646469F4338003100C5E70F4A01 +:108620000F4BFDF751FE00220023FCF721FE00282E +:10863000B9D0002C06DB2C4300270026002CB2D03A +:10864000094EB0E7802600273606ACE7133B9C4670 +:10865000E044DEE701FCFFFFFFFF0F009C75008890 +:108660003CE4377EEDFBFFFF0000F03F30B5204AD1 +:108670004B0087B05B0893421CDD1E4A934205DD28 +:1086800002000B00FEF7EAFF07B030BD02AA02F0BD +:108690005DFC03231840049A059B012818D002288A +:1086A0000DD000281ED0029803990124009403F0F5 +:1086B0007FFDE9E70022002303F014F8E4E70298C5 +:1086C000039903F00FF880231B069C466144DBE707 +:1086D00000900298039903F06BFD80231B069C46D3 +:1086E0006144D1E70298039902F0FCFFCCE7C04651 +:1086F000FB21E93FFFFFEF7F49004B08190070475E +:10870000454AF8B5564692464B005B0D9A444D4695 +:108710005F4644465246F0B4894605000C000E0000 +:108720000700132A22DC002A47DB52463B4B134149 +:1087300098460B0042461340034311D0384A394B48 +:10874000FDF7C2FD00220023FCF792FD002805D0B2 +:10875000002C41DB4E46434600279E433800310043 +:108760003CBC90469946A246AB46F8BD5246332AD9 +:1087700008DD8023DB009A45F2D102000B00FDF7F3 +:10878000A3FDEDE7284A9446012263445242DA40B1 +:1087900093460242E4D0224A224BFDF795FD002287 +:1087A0000023FCF765FD0028D8D0002C1ADB5B46BF +:1087B0004E469F4338003100D2E7194A194BFDF766 +:1087C00083FD00220023FCF753FD0028C6D0002CB7 +:1087D00016DB00270026C1E7802352465B031341C6 +:1087E0009944B7E75346142B12D03423524601273D +:1087F0009B1A9F407F19AF429B415B429944D6E749 +:108800006400640825430027002DA7D0074EA5E784 +:10881000133B9C46E144CAE701FCFFFFFFFF0F004A +:108820009C7500883CE4377EEDFBFFFF0000F0BF45 +:10883000F0B54F464646C0B4CA4A8BB004000D009E +:108840000B1E934212DCC84A4E00760896421BDD8E +:108850000022C64BFCF7F2FC002800D181E0002288 +:1088600000230020C249FEF75BF808E0C14A9142AC +:1088700036DD22002B0020002900FDF725FD0BB07E +:108880000CBC90469946F0BDBB4A964274DDBB4A8B +:1088900094466344934200D98FE00022B84B2000F5 +:1088A0002900FDF711FDB74A0B15914699444B4637 +:1088B00080460F000E00002B00DCD7E122002B00C9 +:1088C000FEF7CCFE02000B000020AD49FEF7C6FE0D +:1088D00042463B00FEF724F84446029003910BE029 +:1088E000A94A9342D9DDA74A1E0091461B15994417 +:1088F000002200230292039333031B0B9846A34BE1 +:10890000984500DDEDE042469D4B20001A431100E2 +:1089100000229B4BFEF7A2FE04000D0000229C4BA0 +:1089200006000F00FEF720FC22002B00FEF71CFCC7 +:108930000B00020004920593009201934346002B22 +:1089400049D10022002320002900FCF777FC0028F1 +:1089500000D1D5E04B46002B00D06BE10020002178 +:108960008DE722002B0020002900FEF777FE020091 +:108970000B00FDF7D5FF82E70022864BFDF7A4FC34 +:1089800000220023FCF774FC002805D0824B200055 +:1089900029009E4200DC72E722002B002000290003 +:1089A000FEF7E2FB00227A4BFEF7DEFB02000B0033 +:1089B00020002900FEF752FE61E70022744BFEF70B +:1089C000D3FB2B002200FEF7CFFB002326002F0055 +:1089D00099460090019180230022DB053000390088 +:1089E000FDF772FC02000B0030003900FDF798FF24 +:1089F00002000B0004900591FEF7B6FB04000D0089 +:108A0000664A674BFEF7B0FB664A674BFDF75CFCB6 +:108A100022002B00FEF7A8FB644A654BFDF754FCCF +:108A200022002B00FEF7A0FB624A634BFDF74CFCD3 +:108A300022002B00FEF798FB604A614BFDF744FCD7 +:108A400022002B00FEF790FB5E4A5F4BFDF73CFCDB +:108A500022002B00FEF788FB5C4A5D4BFDF734FCDF +:108A60002B002200FEF780FB4B4604000D00002B7C +:108A700062D04846FFF79CF9564A574B069007913B +:108A8000FEF772FB009A019B0890099120002900D3 +:108A9000FDF71AFC049A059BFEF766FB4F4A04009B +:108AA0000D00069807994E4BFEF75EFB029A039B5A +:108AB000FDF70AFC02000B0020002900FDF704FC72 +:108AC00002000B0000980199FEF7C8FD32003B0040 +:108AD000FEF7C4FD02000B0008980999FEF7BEFDE1 +:108AE000CDE6012342469C46294BE1441A438023AC +:108AF000110042465B039B1A9B102000984607E733 +:108B0000384A334B20002900FEF72EFB02000B00F1 +:108B100000201B49FEF7A2FD049A059BFEF724FBEB +:108B20004B4606000F00002B5ED102000B00200018 +:108B30002900FEF793FDA2E6009A019BFDF7C4FB16 +:108B4000049A059BFEF710FB02000B0000980199A8 +:108B5000FEF784FD02000B0030003900FEF77EFDB9 +:108B60008DE6C0467982DA3FFFFFEF3F0000F0BF9D +:108B7000000050C3FFFFEF7FFFFF1F3E3C412D4031 +:108B80000000F03F01FCFFFFFFFF3F439DA00600F8 +:108B90000000E03F00005043FFFF8F3C44523EDFA7 +:108BA00012F1C23F9FC678D0099AC33FDE03CB962D +:108BB0006446C73FAF788E1DC571CC3F5993229450 +:108BC0002449D23F04FA97999999D93F935555551D +:108BD0005555E53F0000E0FE422EE63F763C7935F4 +:108BE000EF39EA3D555555554846FFF7E1F8254A16 +:108BF000254B00900191FEF7B7FA244A04900591A5 +:108C000000980199224BFEF7AFFA029A039BFDF7F9 +:108C10005BFB02000B0030003900FEF71FFD220055 +:108C20002B00FEF71BFD02000B0004980599FEF7D0 +:108C300015FD24E64846FFF7BBF8144A144B040020 +:108C40000D00FEF791FA029A039BFDF73DFB0D4ADA +:108C500006000F000C4B20002900FEF785FA0200E9 +:108C60000B0030003900FDF72FFB08E60022094B0E +:108C7000FEF7F4FC02000B0020002900FEF7EEFCDA +:108C800026E6C0460000E0FE422EE63F763C7935FF +:108C9000EF39EA3D0000F03F10B500F0F1FB024A69 +:108CA000024BFDF73DFE10BDEF39FAFE422EE63FC6 +:108CB00030B5214A4B0087B05B0893421EDD1F4A46 +:108CC000934205DD02000B00FEF7C8FC07B030BD83 +:108CD00002AA02F03BF903231840049A059B0128DD +:108CE0001ED0022811D000281FD00298039902F04C +:108CF000F9FC80231B069C466144E7E70023002221 +:108D00000093002303F054FAE0E70124029803994A +:108D1000009403F04DFA80231B069C466144D5E77E +:108D20000298039902F0DEFCD0E70124029803992F +:108D3000009403F03DFAC9E7FB21E93FFFFFEF7F15 +:108D400030B5134A4B0087B05B08934218DD114AD7 +:108D5000934205DD02000B00FEF780FC07B030BD3A +:108D600002AA02F0F3F8049A059B02214000084091 +:108D70000139081A00900298039903F0C9FAEDE747 +:108D8000012300220093002303F0C2FAE6E7C04665 +:108D9000FB21E93FFFFFEF7F384AF8B54B000500A4 +:108DA0000C000E005B0893420EDD02000B00002059 +:108DB0003349002C36DBFDF7B3FD314B0022FDF7C4 +:108DC00083FA03001800F8BD2E4A934209DD002003 +:108DD0002B490300002EF5DA8022120694466144E6 +:108DE000F0E7294A934225DD284A93422CDDFFF71C +:108DF00083FC02000B00FDF767FA03F04FFC8023B1 +:108E00000022DB05FDF760FA0B0080210200C90596 +:108E10000020FDF785FD02000B0000201849FEF739 +:108E20001DFCD6E7FDF77CFD154B0022FEF716FC76 +:108E30000300C7E70022124BFDF746FA23002A0081 +:108E4000FEF792F90300BDE7FFF756FCC0230022AE +:108E50001B06FEF789F903F021FC80231B06CF18BF +:108E600080230022DB050400FDF72EFA02000B0030 +:108E700020003900FDF754FDABE7C046FFFFEF7F50 +:108E80000000F03FFFFF3540FFFF7F3CFFFFEF3F5B +:108E90004B00134A5B0D9A1870B5132A0ADCCB0FEE +:108EA000DB07002A19DB0F48002410418143200012 +:108EB000194370BD332A08DD8023DB009A42F8D1C4 +:108EC00002000B00FDF700FAF3E7074A944601227F +:108ED00063445242DA409043EBE700201900E8E790 +:108EE00001FCFFFFFFFF0F00EDFBFFFFF0B5474662 +:108EF00080B48CB004000D0000F0A4FC244B0600EC +:108F000098461B780F005BB2013305D02000290082 +:108F100003F006FE002805D1300039000CB004BC77 +:108F20009046F0BD20002900FFF7E6FB0022194B18 +:108F3000FCF79EF90028EFD001230293164B174847 +:108F400003930023069407950A930494059503F070 +:108F500017FE43461B78089009915BB2022B0BD099 +:108F600002A803F00BFE002806D00A9B0193002BF9 +:108F700007D1089E099FCFE703F086FE21230360F7 +:108F8000F3E703F081FE0A9B01930360F1E7C0461B +:108F90009A2000200000F03FB83B0300E83B0300AC +:108FA000F0B5474680B48CB004000D0000F040FEE0 +:108FB000244B060098461B780F005BB201330DD09E +:108FC0002000290003F0ACFD002807D000221E4B32 +:108FD00020002900FCF738F9002805D130003900BD +:108FE0000CB004BC9046F0BD01230293174B002245 +:108FF000039300230A930023100019000694079599 +:1090000004940595FDF78CFC43461B780890099164 +:109010005BB2022B0BD002A803F0B0FD002806D0F3 +:109020000A9B0193002B07D1089E099FD6E703F006 +:109030002BFE21230360F3E703F026FE0A9B019336 +:109040000360F1E79A2000200000F03FC03B0300DE +:10905000F0B5474680B48CB004000D0000F070FEFF +:10906000244B060098461B780F005BB2013305D0F5 +:109070002000290003F054FD002805D130003900FC +:109080000CB004BC9046F0BD20002900FFF734FB73 +:109090000022194BFCF7ECF80028EFD001230293D3 +:1090A000164B174803930023069407950A930494DC +:1090B000059503F065FD43461B78089009915BB266 +:1090C000022B0BD002A803F059FD002806D00A9B02 +:1090D0000193002B07D1089E099FCFE703F0D4FD31 +:1090E00021230360F3E703F0CFFD0A9B01930360A4 +:1090F000F1E7C0469A2000200000F03FC83B030083 +:10910000E83B030010B501F001F810BDF0B547468B +:1091100080B48CB004000D0001F0B4F8314B0600AF +:1091200098461B780F005BB2013305D02000290060 +:1091300003F0F6FC002805D1300039000CB004BC67 +:109140009046F0BD20002900FFF7D6FA0022264BFA +:1091500000900191FCF796F80028EDD00098019955 +:109160000022214BFCF784F802AE00282BD001230B +:1091700002931E4B00227360002333620023100011 +:10918000190034617561B460F560FDF7C9FB4346B1 +:109190001B78B061F1615BB2022B0AD0300003F0A2 +:1091A000EDFC002805D0336A002B07D1F769B669BA +:1091B000C2E703F069FD21230360F4E703F064FDD7 +:1091C000336A0360F2E702230293084B3062736054 +:1091D00034617561B460F56000220023200029002D +:1091E000D3E7C0469A2000200000F03FD03B0300A8 +:1091F000F0B5474680B48CB004000D0001F0CAF809 +:10920000264B060098461B780F005BB2013305D051 +:109210002000290003F084FC002805D1300039002B +:109220000CB004BC9046F0BD20002900FFF764FAA2 +:109230001B4A1C4BFCF71CF80028EFD003230293B9 +:10924000194B06940795039300230A9343461B7812 +:1092500004940595002B10D1E022144B12060892BD +:10926000099302A803F08AFC00280CD00A9B019302 +:10927000002B0DD1089E099FD0E700200C490890D3 +:109280000991022BEDD103F0FFFC22230360EDE7EF +:1092900003F0FAFC0A9B01930360EBE79A2000209D +:1092A0007DF8B98FCE338640D83B0300FFFFEF47F0 +:1092B0000000F07FF0B546464F46C0B48BB00400C6 +:1092C0000D0001F011F9344B060098461B780F0091 +:1092D0005BB2013338D02000290003F017FC0028CE +:1092E00032D02E4A2E4B20002900FBF7C1FF8146C9 +:1092F000002830D12B4A2C4B20002900FBF7A4FF7B +:10930000002821D004230093284B002201934B46D0 +:10931000089300230692079343461B786E465BB280 +:109320000494059502940395022B2FD0300003F08E +:1093300025FC00282AD0336A002B03D003F0A4FCBC +:10934000336A0360F769B669300039000BB00CBCB2 +:1093500090469946F0BD03230093144B6E4601934B +:109360000023089343461B780494059502940395C3 +:10937000002B05D1E0220E4B120606920793D5E78B +:1093800000200C4906900791022BCFD103F07CFC02 +:1093900022230360CFE7C0469A200020EF39FAFE6F +:1093A000422E864051302DD5104987C0E03B030046 +:1093B000FFFFEF470000F07FF0B5474680B48CB068 +:1093C0001D0006000F00140001F000FA2A4B009067 +:1093D000019198461B785BB2013305D0200029002B +:1093E00003F09EFB002805D1009801990CB004BC45 +:1093F0009046F0BD3000390003F092FB0028F3D016 +:109400000022002320002900FBF718FF0028EBD0E2 +:1094100001230293194B06940795039300230A93A3 +:1094200043461C7804960597002C16D00022002392 +:1094300010001900FDF774FA08900991022C0ED162 +:1094400003F022FC212303600A9B0093002B0CD124 +:10945000089B099C00930194C6E70896099702A807 +:1094600003F08CFB0028EFD1EAE703F00DFC0A9B28 +:1094700000930360ECE7C0469A200020E43B030021 +:10948000F0B5474680B48CB004000D0001F0C8FA76 +:109490000F00002106003B4B3200595698463B0016 +:1094A000013111D02000290003F03AFB32003B00CB +:1094B000002809D00022002320002900FBF7D8FE55 +:1094C00032003B00002805D0100019000CB004BC8D +:1094D0009046F0BD2C4B0A90039343461E780494AB +:1094E000059506940795002E18D1E022274B120609 +:1094F000089209932000002200232900FBF79EFE1A +:1095000000282BD00223029302A803F037FB002887 +:109510001DD103F0B9FB2223036018E000221C4B8D +:10952000200008920993290000220023FBF786FE01 +:1095300000281BD101230293022E11D103F0A4FBBA +:1095400021230360134803F01BFB089009910A9B39 +:109550000193002B0FD1089A099BB5E701230293D1 +:1095600002A803F00BFB0028ECD1E7E702230293EB +:10957000022ECED0C8E703F087FB0A9B019303605D +:10958000E9E7C0469A200020EC3B0300FFFFEFC74D +:109590000000F0FFE83B0300F0B5474680B48CB014 +:1095A00004000D0001F03EFC394B060098461B7884 +:1095B0000F005BB201330DD02000290003F0B0FA98 +:1095C000002807D00022002320002900FBF746FED8 +:1095D000002805D1300039000CB004BC9046F0BD25 +:1095E0002C4B04940595039300230A9343461E785D +:1095F00006940795002E18D1E022274B12060892F8 +:1096000009932000002200232900FBF717FE002801 +:109610002BD00223029302A803F0B0FA00281DD138 +:1096200003F032FB2223036018E000221B4B2000D2 +:1096300008920993290000220023FBF7FFFD002870 +:109640001BD101230293022E11D103F01DFB212314 +:109650000360134803F094FA089009910A9B019360 +:10966000002B0FD1089E099FB4E70123029302A8A3 +:1096700003F084FA0028ECD1E7E702230293022EDC +:10968000CED0C8E703F000FB0A9B01930360E9E733 +:109690009A200020F03B0300FFFFEFC70000F0FF1F +:1096A000E83B0300F0B546464F46C0B48DB0060017 +:1096B0000F0001F051FE2F4B040098461B780D005F +:1096C0005BB2013307D003F021FA81464B462000FC +:1096D0002900002B04D00DB00CBC90469946F0BD7B +:1096E0003900300003F012FA290003002000002B9B +:1096F000F1D003230293204B0696079703934B4622 +:109700000A9343461C7804960597002200233000F4 +:109710003900002C14D1FBF7ABFDE0221206002823 +:1097200023D0164B0892099302A803F027FA0028C9 +:1097300010D00A9B0193002B11D108980999CAE710 +:10974000FBF796FD0022002811D00D4B08920993DB +:10975000022CE9D103F098FA22230360E9E703F031 +:1097600093FA0A9B01930360E7E7064BDAE7064B9F +:10977000ECE7C0469A200020F83B0300FFFFEF47CC +:109780000000F07FFFFFEFC70000F0FFF0B5474695 +:1097900080B48CB004000D0001F0AEFE274B060033 +:1097A00098461B780F005BB201330DD020002900D2 +:1097B00003F0B6F9002807D000220023200029007A +:1097C000FBF742FD002805D1300039000CB004BC85 +:1097D0009046F0BD01230293194B0694079503931D +:1097E00000230A934346049405951C78002C0FD15E +:1097F000002300240893099402A803F0BFF900286D +:1098000010D00A9B0193002B11D1089E099FDBE722 +:109810000022002310001900FDF782F8089009913A +:10982000022CE9D103F030FA21230360E9E703F0C9 +:109830002BFA0A9B01930360E7E7C0469A200020B9 +:10984000003C0300F0B5DB4A4B0085B007000E007A +:109850005B0893420CDDD84A94466344034300D02E +:10986000ACE0002900DC25E10020002105B0F0BDBE +:10987000D24A934200DC9BE0002900DA1DE102009D +:109880000B000020CE49FDF7E9FE0022CD4BFDF78D +:109890006BFC04000D0001F02FFECB4A0F0000907E +:1098A0000191CA4B20002900FDF75EFCC84AC94B54 +:1098B000FCF70AFD22002B00FDF756FCC64AC74BF9 +:1098C000FDF7CCFE22002B00FDF74EFCC44AC54B31 +:1098D000FCF7FAFC22002B00FDF746FCC24AC34B02 +:1098E000FDF7BCFE22002B00FDF73EFCC04AC14B39 +:1098F000FCF7EAFC22002B00FDF736FCBE4A029082 +:109900000391BE4B20002900FDF72EFCBC4ABD4B45 +:10991000FDF7A4FE22002B00FDF726FCBA4ABB4B44 +:10992000FCF7D2FC22002B00FDF71EFCB84AB94B15 +:10993000FDF794FE22002B00FDF716FC0022A04B41 +:10994000FCF7C2FC02000B0002980399FCF7E8FF49 +:10995000009A019BFDF708FC00260290039132005B +:109960003B0030003900FDF7FFFB02000B00200038 +:109970002900FDF773FE320004000D0000980199E4 +:109980003B00FCF7A1FC02000B0020002900FCF7C3 +:10999000C7FF02000B0002980399FCF795FC320008 +:1099A0003B00FCF791FC02000B00FCF78DFC5DE72F +:1099B000994A93420BDC9948994957E702000B00FA +:1099C000FDF74CFE02000B00FCF7AAFF4EE7020079 +:1099D0000B00FDF7C9FB04000D007B4A7B4BFDF734 +:1099E000C3FB7B4A7B4BFCF76FFC22002B00FDF78F +:1099F000BBFB794A794BFDF731FE22002B00FDF7C6 +:109A0000B3FB774A774BFCF75FFC22002B00FDF796 +:109A1000ABFB754A754BFDF721FE22002B00FDF7CD +:109A2000A3FB734A734BFCF74FFC22002B00FDF79E +:109A30009BFB714A00900191704B20002900FDF7BB +:109A400093FB6F4A6F4BFDF709FE22002B00FDF7D9 +:109A50008BFB6D4A6D4BFCF737FC22002B00FDF7AA +:109A600083FB6B4A6B4BFDF7F9FD22002B00FDF7E2 +:109A70007BFB0022524BFCF727FC02000B000098F6 +:109A80000199FCF74DFF3A003300FDF76DFB020032 +:109A90000B0064486449FDF7E1FD02000B0038004B +:109AA0003100FDF7DBFD02000B005C485C49FDF76F +:109AB000D5FDDBE659485D49D8E60022404BFCF76E +:109AC00003FC00223F4BFDF74FFB04000D003E4A14 +:109AD0003E4BFDF749FB3E4A3E4BFCF7F5FB2200AF +:109AE0002B00FDF741FB3C4A3C4BFDF7B7FD220044 +:109AF0002B00FDF739FB3A4A3A4BFCF7E5FB220015 +:109B00002B00FDF731FB384A384BFDF7A7FD22004B +:109B10002B00FDF729FB364A364BFCF7D5FB22001C +:109B20002B00FDF721FB009001912000290001F09E +:109B3000E3FC314A06000F00304B20002900FDF7FE +:109B400013FB2F4A2F4BFDF789FD22002B00FDF759 +:109B50000BFB2D4A2D4BFCF7B7FB22002B00FDF72A +:109B600003FB2B4A2B4BFDF779FD22002B00FDF761 +:109B7000FBFA0022124BFCF7A7FB02000B00009837 +:109B80000199FCF7CDFE32003B00FDF7EDFA254AC6 +:109B9000254BFDF763FD32003B00FCF795FB02000F +:109BA0000B00FCF791FB02000B001C481F49FDF75E +:109BB00055FD5BE6FFFFEF3F000010C0FFFFDF3FFA +:109BC0000000F03F0000E03F09F7FD0DE13D023FDE +:109BD00088B20175E0EF493F3B8F68B52882A43F0A +:109BE0005544880E55C1C93F7D6FEB0312D6D43F53 +:109BF000555555555555C53F82922EB1C5B8B33F01 +:109C000059018D1B6C06E63FC88A599CE52A004025 +:109C10004B2D8A1C273A03400000603C182D445409 +:109C2000FB21F93F075C143326A6913CFB21094038 +:109C3000F0B53C4A83B005000C1E944236DD3A4A2A +:109C4000914208DD394A91423CDD02000B00FCF7ED +:109C50003BFB03B0F0BD364A8A1802432FD0802266 +:109C6000D205914235DC0022324BFDF7F7FC0200B1 +:109C70000B0004000D00FCF727FB220006000F007C +:109C80002B0020002900FDF76FFA02000B003000C6 +:109C90003900FCF719FB01F02FFC02000B0020003B +:109CA0002900FCF711FBFEF7C3FDD2E702000B0011 +:109CB000FDF7D4FC02000B00FCF732FEC9E70020E0 +:109CC0000021C6E700F0ACFE1B4A1C4BFCF7FCFA77 +:109CD000BFE702000B00FDF747FA0022154BFDF726 +:109CE000BDFC01F009FC2A0006000F00230028003B +:109CF0002100FCF7E9FA3200009001913B002800B6 +:109D00002100FCF7E1FA02000B0000200949FCF7F2 +:109D100007FE02000B0000980199FDF79FFC00F080 +:109D20007FFE96E7FFFFEF3FFFFFAF41FFFFEF7FB3 +:109D3000000010C00000F03FEF39FAFE422EE63F6F +:109D4000F0B557464E464B005B089A46C0B4CD4B23 +:109D500087B006000F0089469A4512DDCA4B53446E +:109D6000034322D002000B00FDF778FC0B00020039 +:109D7000FCF7D6FD0300180007B00CBC91469A46CC +:109D8000F0BDC24B9A4524DCC14B9A4500DD0CE185 +:109D9000C04AC14BFCF798FA0022C04BFBF768FAA7 +:109DA000002816D033003900E5E7BD4ABD4BFDF76A +:109DB000DBF9BD4A04000D00BC4B30003900FDF753 +:109DC000D3F90B00020029002000FCF77DFA030004 +:109DD000D1E730003900FEF78FFC02000B000020B5 +:109DE000AE49FDF73BFC0022B14BFDF7BDF9040085 +:109DF0000D00B04AB04BFDF7B7F9B04AB04BFCF7D5 +:109E000063FA22002B00FDF7AFF9AE4AAE4BFDF727 +:109E100025FC22002B00FDF7A7F9AC4AAC4BFCF760 +:109E200053FA22002B00FDF79FF9AA4AAA4BFDF72F +:109E300015FC22002B00FDF797F9A84AA84BFCF768 +:109E400043FA22002B00FDF78FF9A64A02900391F6 +:109E5000A54B20002900FDF787F9A44AA44BFDF784 +:109E6000FDFB22002B00FDF77FF9A24AA24BFCF775 +:109E70002BFA22002B00FDF777F9A04AA04BFDF743 +:109E8000EDFB22002B00FDF76FF9844B0022FCF75D +:109E90001BFA049005912000290001F02DFB994B3D +:109EA00006000F009A4563DC0B000298039900221C +:109EB00000920193049A059BFCF732FD3200029058 +:109EC00003913B0030003900FCF7FEF902000B0063 +:109ED00002980399FDF748F90290039100980199BF +:109EE00002000B00FDF740F902000B0020002900E2 +:109EF000FDF7B4FB009A019B04000D00300039000F +:109F0000FCF7E2F902000B0020002900FCF708FD35 +:109F100002000B00FCF7D8F902000B00624863490D +:109F2000FDF79CFB02000B0002980399FDF796FBDE +:109F300004000D000098019902000B00FCF7C4F921 +:109F400002000B0056487049FDF788FB02000B0029 +:109F500020002900FDF782FB02000B0050486A49EF +:109F6000FDF77CFB4B46002B00DC84E0030002E79E +:109F7000049A059B02980399FCF7D2FC32003B003F +:109F8000FDF7F2F832003B00FCF79EF902000B00EF +:109F9000FCF79AF9444A454BFDF760FB02000B00C1 +:109FA0003F484049FDF75AFBDCE702000B00FDF794 +:109FB000DBF804000D003F4A3F4BFDF7D5F83F4A60 +:109FC0003F4BFCF781F922002B00FDF7CDF83D4A0D +:109FD0003D4BFDF743FB22002B00FDF7C5F83B4A44 +:109FE0003B4BFCF771F922002B00FDF7BDF8394A15 +:109FF000394BFDF733FB22002B00FDF7B5F8374A4C +:10A00000374BFCF761F922002B00FDF7ADF8354A1C +:10A0100000900191344B20002900FDF7A5F8334A48 +:10A02000334BFDF71BFB22002B00FDF79DF8314A57 +:10A03000314BFCF749F922002B00FDF795F82F4A28 +:10A040002F4BFDF70BFB22002B00FDF78DF80022B4 +:10A05000124BFCF739F902000B0000980199FCF74C +:10A060005FFC32003B00FDF77FF83B003200FCF75D +:10A070002BF903007FE68022120694460300614418 +:10A0800079E6C046FFFFEF3F000010C0FFFFDF3F53 +:10A09000FFFF3F3E9C7500883CE4377E0000F03FA8 +:10A0A000182D4454FB21F93F075C143326A6913C3C +:10A0B0000000E03F09F7FD0DE13D023F88B2017568 +:10A0C000E0EF493F3B8F68B52882A43F5544880E96 +:10A0D00055C1C93F7D6FEB0312D6D43F5555555539 +:10A0E0005555C53F82922EB1C5B8B33F59018D1B5E +:10A0F0006C06E63FC88A599CE52A00404B2D8A1C15 +:10A10000273A03403233EF3FFB21E93FF8B5150012 +:10A110004F4646465A001C006B42C0B42B434B4F7F +:10A120005208DB0F88461343BB423AD84B005B080A +:10A1300099464E4643420343DB0F3343BB4230D87C +:10A14000434BE3182B4343D00226A3171E40CB0FEB +:10A150001E434B4603432ED013002B4332D0BA424A +:10A1600041D0B9452ED04B469A1A12153C2A32DC02 +:10A17000002C55DB2A002300FCF7D2FBFEF7BCFACB +:10A18000FEF740F8012E46D0022E39D0002E0ED018 +:10A19000304A314BFDF762FA304A314BFDF75EFA37 +:10A1A00005E002000B0028002100FCF78DF80CBC34 +:10A1B00090469946F8BD022E10D0032EF7D12748BD +:10A1C0002849F4E743462548002B0ADB2649EEE7F9 +:10A1D000FEF718F8EBE721482349D3E71F48204949 +:10A1E000E5E72249E3E791451FD0022EF6D0032E82 +:10A1F000E5D000200021012ED9D180210906D6E723 +:10A20000144A154BFDF72AFA02000B0013481449B3 +:10A21000FDF724FACBE7802424060B191900C6E7C2 +:10A220003C32A7DA00200021ACE7022E06D0032E34 +:10A2300009D00A48012E04D00D49B8E70D480E494F +:10A24000B5E70E49B3E70B480D49B0E70000F07FD2 +:10A25000000010C0075C143326A6A13C182D4454FE +:10A26000FB210940FB2109C0FB21F93FFB21F9BF7C +:10A27000FB21E93FD221337F7CD90240FB21E9BF9A +:10A280007CD902C0F0B5474680B443424E00034338 +:10A290003A4A7608DB0F82B004000D0007008846BA +:10A2A0003343934214D8964242D0354B9E4219DC38 +:10A2B000344A354BFCF708F800220023FAF7D8FFA0 +:10A2C000290000283AD0380002B004BC9046F0BD06 +:10A2D00002000B00FDF7C2F902000B00FCF720FBA7 +:10A2E0000700F0E7294B351E9D4228DD33000200B0 +:10A2F0003100FBF7E9FF220006000F002B000020D1 +:10A300001E49FDF7ABF902000B0030003900FCF7E5 +:10A3100007FBFEF78DFA1E4B0022FCF725FF434694 +:10A320000700002BCFDA80231B069C466144CAE756 +:10A3300000220023FCF7F4FA0700C4E735002200EE +:10A340002B0020002900FBF7BFFF22002B00060096 +:10A350000F00FCF709FF2200009001912B00002064 +:10A360000649FDF77BF902000B0000980199FCF704 +:10A37000D7FA32003B00FBF7A7FFCAE70000F03F27 +:10A38000FFFF2F3E9C7500883CE4377EFFFFDF3FD8 +:10A390000000E03FF0B54B005E08474B83B09E42A3 +:10A3A00018DC464B9E421FDD454B9E425EDD454B11 +:10A3B0009E4200DC75E0444B9E4242DD434B9E4290 +:10A3C0003CD0434A434B10001900FCF7CDFE04007B +:10A3D0000D0005E002000B00FCF7C6FE04000D00B6 +:10A3E0002000290003B0F0BDFEF786F902F056F90F +:10A3F000394B002200900191FBF766FF374B0400B8 +:10A400000D009E42ECDD009A019B10001900FCF744 +:10A41000ABFE22002B0006000F0020002900FBF7F6 +:10A4200053FF02000B0030003900FCF779FA0022DC +:10A43000294BFBF749FF04000D00D1E7284B984258 +:10A44000BFD8FEF759F90022264BFCF78DFE00F02D +:10A450004BF804000D000022224BFCF785FE220081 +:10A460002B00FCF781FE04000D00B9E7FEF744F96C +:10A4700000F03AF800221B4B04000D00FCF774FEBC +:10A4800022002B0006000F0000201649FCF748FAB6 +:10A4900002000B0030003900FBF716FF04000D002E +:10A4A0009EE7FEF729F900F01FF800220D4BFCF79C +:10A4B0005BFE04000D0093E7FFFFEF7F422ED63FC7 +:10A4C000FFFF3540412E8640CD338640CE33864057 +:10A4D0009C7500883CE4377E0000F03FFFFF7F3C26 +:10A4E0007DF8B98F0000E03FF0B5574680B44B00CF +:10A4F0000E00CC0F954984B007005B088B420ED943 +:10A5000093498B4200D884E03203120B024300D0FF +:10A51000F7E03100002C78D00020002175E08D4A52 +:10A52000934200D9B6E08C4A934200D8CAE0002397 +:10A530009A463A00330038003100FCF715FE04005B +:10A540000D00864A864BFCF70FFE864A864BFDF7C8 +:10A5500085F822002B00FCF707FE844A844BFBF7AA +:10A56000B3FE22002B00FCF7FFFD824A824BFDF771 +:10A5700075F822002B00FCF7F7FD804A804BFBF7B3 +:10A58000A3FE22002B00FCF7EFFD02000B003800B9 +:10A590003100FDF763F8534604000D000200002B64 +:10A5A00000D1B4E00B0038003100FCF7DDFD0F00F6 +:10A5B0008021060022002B000020C905FDF74EF87F +:10A5C00002000B0030003900FCF7AAF902000B0072 +:10A5D00002980399FDF742F8009A019BFDF73EF8B7 +:10A5E0000B00020067490020FDF738F8664B9A45DA +:10A5F00000DB7AE0FA24A40054442405631819000F +:10A60000B82300225B04FCF7AFFD04B004BC924603 +:10A61000F0BD5E4A5E4B3100FAF72AFE002869D190 +:10A620005C4A5D4B38003100FAF70EFE002800D07E +:10A6300072E75A4BE4001C19594A5A4B3800310052 +:10A64000FCF792FD22686368FBF73EFEFDF77AFB9C +:10A650008246FDF7ADFB544A544B04000D00FCF755 +:10A6600083FD02000B0038003100FCF7F7FF504A71 +:10A67000009001914F4B20002900FCF775FD0290DE +:10A680000391029A039B00980199FCF7E7FF0700EA +:10A690000E004EE7484A9342CBD8484BE5005B1981 +:10A6A0001A685B683100FCF7D9FF454B00900191B7 +:10A6B0005D192A686B680292039301231B1B1B1B05 +:10A6C0009A46DEE73F4A404B3100FBF7FDFD002292 +:10A6D0002C4BFAF7CDFD002800D128E70022294BAA +:10A6E00038003100FBF7F0FD8FE75446240563186E +:10A6F00019008AE7334A344B10001900FCF734FD87 +:10A7000083E7020033003100FBF7DEFD7DE70B003D +:10A7100038003100FCF728FD8023009001910022D1 +:10A72000DB0520002900FCF799FF02000B000098D0 +:10A730000199FCF7F5F83A003300FCF78FFF0200AF +:10A740000B0000200F49FCF789FF5EE7412E864091 +:10A75000FFFFEF7F422ED63FFFFF2F3ED0A4BE72F9 +:10A760006937663EF16BD2C541BDBB3E2CDE25AFDD +:10A770006A56113F93BDBE166CC1663F3E55555596 +:10A780005555C53F0000F03F03FCFFFFEF39FAFECF +:10A79000422E864051302DD5104987C0A82D030088 +:10A7A000FE822B654715F73F0000E0FE422EE63F94 +:10A7B000763C7935EF39EA3DB1A2F03FC82D030070 +:10A7C000B82D03009C7500883CE4377EF8B55646EA +:10A7D00044465F464D4698465B005B08F0B41E0059 +:10A7E0008246040015001700164326D0CE0FF60748 +:10A7F000B3464E40B146804EB1451EDC564216432C +:10A80000F60F1E43B4467D4EB44516D8994504DC78 +:10A8100084461ADB904218D35FD0794989451BDC06 +:10A820004946002900D0AAE056467649002E18DD98 +:10A8300001397600002EFBDC13E04346FCF794FC64 +:10A8400002000B00FCF76CF8844660463CBC904666 +:10A850009946A246AB46F8BD6B4E4946B44609152B +:10A860006144674EB3420ADC002B00D09EE0654E87 +:10A87000002D07DD013E6D00002DFBDC02E0624E85 +:10A880001D15AE19614DA94267DB484605038020BE +:10A890002D0B400305435D4886424FDB4346802233 +:10A8A0001B031B0B52031343881BEA1A00281DD0FD +:10A8B000BC4289414942521A09D41100E41B214388 +:10A8C0000BD0E50F5200551964000138EDE7E10F98 +:10A8D0006A00551864000138E7E75B46DE0F4C4B11 +:10A8E000F6009E19336871689C46AEE7BC429B41F6 +:10A8F0005B42D21A6CD4E41B13002343EDD0404BCF +:10A9000018009A4206DCE10F53005A186400013E19 +:10A910008242F8DD3D498E424FDA891B142959DC09 +:10A92000202023001400401ACB4084401C43130015 +:10A930000B415A461A431100A44686E7801B844601 +:10A940001F282DDC20273F1A1000F8400700604622 +:10A95000834082403B431700A6E76C1AA4461F2C95 +:10A9600018DC20252D1B0400EC404D46A246644611 +:10A97000A540544625436446A04004008BE7494661 +:10A98000CE022249002E00DC6BE701397600002E52 +:10A99000FBDC66E71F4C641AA040002405007AE740 +:10A9A0001C4B00279B1B9A4013007DE7174EDD02CE +:10A9B000013E6D00002DFBDC64E7174BA446D31865 +:10A9C0005A461343154AB5182D052B4319003CE789 +:10A9D0002A0091E71F2908DC23002020CB40411AE0 +:10A9E0008A4014001C435B46A3E70A4B9B1B1A4199 +:10A9F0005B4614009DE7C046FFFFEF7F0000F07F3D +:10AA0000FFFF0F00EDFBFFFF01FCFFFF02FCFFFF5C +:10AA1000D82D0300E2FBFFFF0000F0FFFF03000062 +:10AA2000F0B557464E464546E0B4DA4A88B00B1EAC +:10AA3000934255DC4A005208024300D1EFE000295E +:10AA400000DA79E1D44B0022FCF78EFB3625D34C9B +:10AA50000B006D42A34247DC1A151B031B0B9846E3 +:10AA6000CF4C8023A446CF4C5B0344442340CE4CC0 +:10AA7000624452195C4045461B1599462543CA4B12 +:10AA8000290091440022FCF7E9FD434602331B03F1 +:10AA900006000F001B0B0022022B2FDC0023FAF70D +:10AAA000CDFB002800D1C1E04B46002B00D14CE18A +:10AAB0004846FDF77DF9BD4ABD4B04000D00FCF78B +:10AAC00053FBBC4A06000F00BB4B20002900FCF7DB +:10AAD0004BFB02000B0030003900FBF7F5FB07E0F1 +:10AAE000AE4C0025A342B7DD02000B00FBF7ECFBE8 +:10AAF00008B01CBC90469946A246F0BD8023DB05F9 +:10AB0000FBF7E2FB02000B0030003900FBF708FF07 +:10AB1000040048460D00FDF74BF922000290039116 +:10AB20002B002000290004940595FCF71DFB040070 +:10AB30000D00A24B020043449A460B00009401957D +:10AB4000FCF712FB04000D009D4A9E4BFCF70CFB2A +:10AB50009D4A9E4BFBF7B8FB22002B00FCF704FB41 +:10AB60009B4A9C4BFBF7B0FB22002B00FCF7FCFA46 +:10AB7000994A9A4BFBF7A8FB009A019BFCF7F4FA61 +:10AB8000974A00900191974B20002900FCF7ECFABE +:10AB9000954A964BFBF798FB22002B00FCF7E4FA52 +:10ABA000934A944BFBF790FB22002B00FCF7DCFA56 +:10ABB0000B00020000980199FBF786FB0D0041464F +:10ABC0008D4B04005B1A51460B43002B54DD0022D1 +:10ABD0008A4B30003900FCF7C7FA32003B00FCF723 +:10ABE000C3FA4B460A00010000910192002B72D17A +:10ABF0001300290002002000FBF766FB049A059B66 +:10AC0000FCF7B2FA02000B0000980199FCF726FD50 +:10AC100002000B0030003900FCF720FD68E700223D +:10AC2000002300207649FBF77BFE61E7754A764BEF +:10AC300030003900FCF798FA02000B0000206F4941 +:10AC4000FCF70CFD320004000D003B003000390021 +:10AC5000FCF78AFA0B00020029002000FCF784FAB6 +:10AC60004B4604000D00002B72D102000B00300097 +:10AC70003900FCF7F3FC3BE74B46002B00D1C5E065 +:10AC800002980399494A4A4BFCF76EFA2200009059 +:10AC900001912B0030003900FCF7E0FC049A059B81 +:10ACA000FCF762FA434A04000D0002980399424BF4 +:10ACB000FCF75AFA02000B0020002900FCF7CEFC3A +:10ACC00032003B00FCF7CAFC02000B00009801991F +:10ACD000FCF7C4FC0CE7354A354B02980399FCF7A6 +:10ACE00043FA009A019B0690079120002900FBF788 +:10ACF000EBFA049A059BFCF737FA2E4A04000D0084 +:10AD0000029803992C4BFCF72FFA02000B0020004D +:10AD10002900FBF7D9FA02000B0000980199FCF713 +:10AD20009DFC32003B00FCF799FC02000B000698EA +:10AD30000799FCF793FCDBE602000B00FCF78EFCA6 +:10AD400000220023FBF7ECFDD2E600200021CFE635 +:10AD50004846FDF72DF8154A154B00900191FCF778 +:10AD600003FA144A0290039100980199124BFCF7E0 +:10AD7000FBF902000B0020002900FCF76FFC3200F9 +:10AD80003B00FCF76BFC02000B0002980399FCF7F8 +:10AD900065FCADE6FFFF0F0000005043FFFFEF7FB3 +:10ADA00001FCFFFF645F09000000F03F0000E0FECF +:10ADB000422EE63F763C7935EF39EA3D86EBF9FFE6 +:10ADC00044523EDF12F1C23FDE03CB966446C73FDA +:10ADD000599322942449D23F935555555555E53FF3 +:10ADE0009FC678D0099AC33FAF788E1DC571CC3FFE +:10ADF00004FA97999999D93F51B806000000E03FAD +:10AE0000000050C3555555555555D53F22002B00D0 +:10AE100030003900FCF722FC049A059BFCF7A4F9EA +:10AE2000F6E6C046F0B54F464646C0B43B4A83B04E +:10AE300004000D000B1E93421CDC4A005208024322 +:10AE40005BD0002960DB0022354BFCF78DF9362200 +:10AE50000D000B003349040052428B420EDD2200EC +:10AE60002B0020002900FBF72FFA03B00CBC904602 +:10AE70009946F0BD2B4900228B42F0DC2A49181577 +:10AE80008C4660448218D10F89461B034A441B0B31 +:10AE900010009846FCF78CFF4A46244B06009B1A8C +:10AEA00042461B051A430F0020001100FFF7B8FDB2 +:10AEB0001F4A04000D001F4B30003900FCF754F905 +:10AEC0001D4A009001911D4B20002900FCF74CF910 +:10AED00002000B0000980199FBF7F6F9184A0400EC +:10AEE0000D00184B30003900FCF73EF902000B0052 +:10AEF00020002900FBF7E8F9B7E700220023002033 +:10AF00001149FBF70DFDB0E702000B00FCF7A6FBB3 +:10AF100000220023FBF704FDA7E7C046FFFF0F0058 +:10AF200000005043FFFFEF7F01FCFFFFFF03000025 +:10AF3000362BF111F3FE593D0EE526157BCBDB3F99 +:10AF400000609F501344D33F000050C3F0B54E46FD +:10AF500057464546E0B4DC4B4E0090B0170089469A +:10AF600076089E4200DC81E0D84B9E4220DCD84A25 +:10AF7000002900DC89E1D74BFCF770FBD54B0400BE +:10AF80000D009E4200D18AE0D34AD44BFCF766FB09 +:10AF900002000B0020003A607B602900FCF75EFB9A +:10AFA000CD4ACE4BFCF75AFBB860F960012066E051 +:10AFB000CB4B9E4200DC8DE0CA4B9E4265DCCA4909 +:10AFC00032158A46924453461B05F51A290004009F +:10AFD000FCF7B8FEFCF7ECFE02000B002000290095 +:10AFE0000A920B93FCF73AFB0022C04BFCF7BCF82B +:10AFF00002900391FCF7A6FEFCF7DAFE04000D00B8 +:10B0000002000B00029803990C940D95FCF726FBA7 +:10B010000022B64BFCF7A8F8002200230E900F91F7 +:10B02000FAF70CF9002800D14CE10023002220009F +:10B030002900FAF703F90222431E9841131AAC4A79 +:10B040003900019202220AA80092524600F064FCE4 +:10B050004B46002B13DA8022120694467B6840424E +:10B0600063447B60FB686344FB6008E002000B0004 +:10B070003A607B60002200230020BA60FB6010B0C1 +:10B080001CBC90469946A246F0BD02000B00FCF79E +:10B09000E5FAB860F960386079600020EFE7D32204 +:10B0A0008E4B5205FCF7DAFA924A934B04000D00DE +:10B0B000FCF7D4FA02000B0020003A607B60290004 +:10B0C000FCF7CCFA8B4A8C4BFCF7C8FAB860F960F5 +:10B0D0000120D4E7FDF710FB884A894B04000D00DE +:10B0E000FCF742F80022874BFBF7EEF8FCF72AFE4C +:10B0F0008046FCF75DFE764A764B06900791FCF79A +:10B1000033F802000B0020002900FCF7A7FA734B6C +:10B1100002900391069807996F4AFCF725F8434679 +:10B1200004000D00049405951F2B30DC013B764A8A +:10B130009B009B589E422AD002000B000298039964 +:10B14000FCF78CFA02000B0005000C003A607B60F3 +:10B15000029803992A002300FCF780FA049A059BC1 +:10B16000FCF77CFA06000B003200BA60FB604B462D +:10B170004046002B00DB82E780231B069C4664448C +:10B1800061443D607C60BE60F960404277E7049AAC +:10B19000059B02980399FCF761FA0B0002003A60E4 +:10B1A0007B604B0036155B0D05000C00F31A102B6D +:10B1B000CEDD06980799D322484B5205FBF7D4FF02 +:10B1C00004000D0002000B0002980399FCF746FAF8 +:10B1D00002000B000298039908920993FCF73EFACB +:10B1E00022002B00FCF73AFA04000D00069807999C +:10B1F000404A414BFBF7B8FF22002B00FCF72EFA28 +:10B2000002000B000490059108980999FCF726FAB2 +:10B2100002000B003A607B604B005B0DF61A0500E4 +:10B22000089A099B0C0002920393312E90DD069838 +:10B230000799B822304B9205FBF796FF04000D00EA +:10B2400002000B0002980399FCF708FA0A000100BB +:10B25000130002910392020008980999FCF7FEF985 +:10B2600022002B00FCF7FAF904000D00069807995C +:10B27000264A274BFBF778FF22002B00FCF7EEF95C +:10B2800002000B000492059358E7124BFBF71CF8E1 +:10B29000104B04000D009E423CD00F4A0F4BFBF7B1 +:10B2A00013F802000B0020003A607B602900FCF7D5 +:10B2B000D5F9094A094BFBF707F8B860F960012096 +:10B2C0004042DCE60323BAE6FB21E93F7BD902409A +:10B2D00000004054FB21F93F3163621A61B4D03D54 +:10B2E000FB213941FFFFEF7FEAFBFFFF00007041C8 +:10B2F000883C03007370032E8A19A33B83C8C96D71 +:10B30000305FE43F0000E03F083C0300C1492025D6 +:10B310009A837B39D3220D4B5205FAF7D5FF0C4A9D +:10B320000C4B04000D00FAF7CFFF02000B002000C9 +:10B330003A607B602900FCF791F9054A054BFAF762 +:10B34000C3FFB860F9600120404298E661B4D03D87 +:10B350007370032E8A19A33BF0B54B005C08594B60 +:10B3600085B007000E009C421DDC002930DB002266 +:10B37000554B00920193554B9C4219DC544B9C4217 +:10B3800000DD73E0534A544B38003100FAF79CFF5C +:10B39000524B0022F9F76CFF310003003800002BFC +:10B3A0001BD005B0F0BD02000B00FAF78DFFF8E7E7 +:10B3B0004B4B9C4278DD4B4B9C4240DD4A4B9C42C0 +:10B3C0003AD0444A444B38003100FBF7CDFEE8E761 +:10B3D0000022464B00920193CDE738003100FDF783 +:10B3E0008BF901F05BF906000F0032003B003000E2 +:10B3F0003900FAF769FF320004000D003B0030000D +:10B400003900FBF7B1FE002202900391334B30006C +:10B410003900FAF759FF02000B0002980399FBF775 +:10B420007FFA02000B0020002900FCF717F9009AB0 +:10B43000019BFBF799FEB4E72D4B9F42C1D8380022 +:10B440003100FDF759F900221F4BFBF78DFEFFF786 +:10B450004BF806000F0002000B0000980199FBF763 +:10B4600083FE32003B00FBF77FFE9AE73800310095 +:10B47000FDF742F901F012F91E4B06000F009C4245 +:10B48000B3DD0022154BFAF71FFF02000B0030005E +:10B490003900FBF745FA32003B00FAF715FF009A36 +:10B4A000019BFBF761FE7CE738003100FDF724F9D2 +:10B4B000FFF71AF802000B0000980199FBF754FE01 +:10B4C0006FE7C046FFFFEF7F0000E03FFFFF354022 +:10B4D000FFFF2F3E3374AC3C1F7BAC7F0000F03F7E +:10B4E000412E8640CD338640CE3386400000E0BFFB +:10B4F0007DF8B98FFFFFEF3FF0B556464D46444605 +:10B500005F46754BF0B40A000D00190083B00600C9 +:10B5100004002940994200D1BAE0002D00DC94E0FB +:10B520002D1500D1A3E06D4B12039C468023120B16 +:10B530005B0365441A43EB0700D581E06B10984626 +:10B54000E30F9B189B188022162100260027640019 +:10B550009203B818984202DC87181B1AB618E00F3D +:10B560005B0001391B18640052080029F1D1002248 +:10B5700001929446802212062020914609E09F42C3 +:10B5800041D0E10FC9180138CB18640052080028D7 +:10B590001ED0614651189F42F1DA8D18AC46CD0F8E +:10B5A000ED07BA464D4539D0DB1B8C42BF417F4287 +:10B5B000DB1B641A019901388B469344594601916B +:10B5C000E10FC9185746CB18640052080028E0D193 +:10B5D00023432BD1019B5B08414972108C46624486 +:10B5E000F10702D5802109060B43414609058D1854 +:10B5F0001E002F003000390003B03CBC9046994635 +:10B60000A246AB46F0BDA1420ED88D18AC46CD0F78 +:10B61000ED074D4548D09A460023CAE76546002D00 +:10B62000C2DB7D1CAA46BFE73B00AAE7019B0133B2 +:10B630003ED0019A01239446134063445B08CBE754 +:10B64000E30F52009A18640078E76B005B0803432D +:10B650002F00002BCED00025002A31D1E20A153D63 +:10B660006405002AFAD080235B031A4223D180208C +:10B670000023400300E00B005200591C0242FAD0A4 +:10B680002020401AED1A2300C3408C401A434AE799 +:10B6900002002B002900FBF767FD32002B00FAF7B0 +:10B6A00013FE06000F00A5E76546002DB3DBB8E7E3 +:10B6B0000136002390E7012320205B420021E1E7CF +:10B6C0003B0002003900FBF7C9FF02000B00FBF74B +:10B6D00027F906000F008DE70000F07F01FCFFFF57 +:10B6E0000000E03FF0B54F464646C0B487B0009238 +:10B6F0000193754B4F00814688467F089F4263DC6B +:10B70000FCF720FB002800D1DAE04A4643464846D1 +:10B710004146FBF729FD04000D006C4A6C4BFBF71A +:10B7200023FD6C4A6C4BFAF7CFFD22002B00FBF790 +:10B730001BFD6A4A6A4BFBF791FF22002B00FBF7C7 +:10B7400013FD684A684BFAF7BFFD22002B00FBF798 +:10B750000BFD664A664BFBF781FF22002B00FBF7CF +:10B7600003FD644A644BFAF7AFFD22002B00FBF7A0 +:10B77000FBFC029003910022604B20002900FBF7A4 +:10B78000F3FC029A039B06000F0020002900FBF740 +:10B79000EBFC009A019B04000D0048464146FBF774 +:10B7A000E3FC02000B0020002900FBF757FF02001A +:10B7B0000B0030003900FBF751FF02000B000020A6 +:10B7C0004F49FBF74BFF70E002000B00FBF7CCFC8E +:10B7D00004000D003D4A3E4BFBF7C6FC3D4A3E4B84 +:10B7E000FAF772FD22002B00FBF7BEFC3B4A3C4BF4 +:10B7F000FBF734FF22002B00FBF7B6FC394A3A4B2B +:10B80000FAF762FD22002B00FBF7AEFC374A384BFB +:10B81000FBF724FF22002B00FBF7A6FC354A364B32 +:10B82000FAF752FD2B002200FBF79EFC354B0290ED +:10B8300003919F429FDD344B00229F423ADC334903 +:10B8400000207B182E4916001F00FBF707FF04900D +:10B8500005910022294B20002900FBF785FC3200CE +:10B860003B00FBF7FBFE029A039B06000F00200043 +:10B870002900FBF779FC009A019B04000D00484663 +:10B880004146FBF771FC02000B0020002900FBF78A +:10B89000E5FE02000B0030003900FBF7DFFE02007E +:10B8A0000B0004980599FBF7D9FE07B00CBC904635 +:10B8B0009946F0BD164B002604920593154FC8E734 +:10B8C00000200F49F1E7C046FFFF3F3ED43888BE55 +:10B8D000E9FAA8BDC4B1B4BD9EEE213EAD529C8034 +:10B8E0004F7E923E9015CB19A001FA3E7751C116BA +:10B8F0006CC1563F4C5555555555A53F0000E03F8E +:10B900000000F03F3233D33F0000E93F0000E0FF8A +:10B910000000E73F0000D23FF0B556464D46444692 +:10B920005F46F0B48E4CA544099119001400A89A02 +:10B930000B938C4B9200D2580B000290013BE01EFF +:10B9400018211D00160008920093F9F77BFBC343F2 +:10B950000200DB171A401300110001330E929A0007 +:10B960009B1ADB001B1906934C1B761918D4A99B54 +:10B97000A5009C46361926AF6544013607E02868C5 +:10B98000FCF716FA013403C70435B44208D0002C82 +:10B99000F5DA00200021013403C70435B442F6D1A2 +:10B9A000089B002B01DA00F0F9FB76AB19008B46FF +:10B9B00026AA9146089A0A930132D2009344029A29 +:10B9C0009A469046009BDB00994408339844009BBC +:10B9D000002B00DAB5E14C4600260027029D2268C4 +:10B9E000636803CDFBF7C0FB02000B003000390099 +:10B9F000FAF76AFC083C06000F004545EFD15346B4 +:10BA0000C0C39A4608239C46E144DA45DFD1089931 +:10BA1000554A0B00944663449B0012A884461A00C2 +:10BA20000298624483460D920B9A0433D200634419 +:10BA300093440F930591059A0A98D30019000C932B +:10BA40008C46030063441E685F68002A34DD12AB35 +:10BA500099461300454A804694466344DB00984467 +:10BA600074AB9A460022424B30003900FBF77CFB56 +:10BA7000FCF768F9FCF79CF900223E4B04000D002E +:10BA8000FBF772FB02000B0030003900FBF7E6FD0C +:10BA9000FCF758F94B4601C39946434620001A6803 +:10BAA0005B682900FAF710FC08235B429C46E044DF +:10BAB00006000F00D045D5D1069B30001A00390092 +:10BAC000994601F063F8FF2300229B0504000D0056 +:10BAD000FBF74AFBFCF714FE0022274BFBF744FB65 +:10BAE00002000B0020002900FBF7B8FD04000D0048 +:10BAF000FCF728F98046FCF75BF902000B002000F8 +:10BB00002900FBF7ABFD4C4606000F00002C00DCC3 +:10BB1000F8E0059B18205A1E920012AB9B58001BA0 +:10BB200019000141884481405B1A12A98B501722E9 +:10BB3000121B13410793079B002B4BDD01239C46EF +:10BB4000059BE044002B00DCF2E280251096119763 +:10BB500012AB0021002409486D04059F19E0C0467E +:10BB600084FDFFFF903D0300FEFFFF3FFFFFFF1F2F +:10BB70000000703E0000704100002040FFFFFF0009 +:10BB8000002A02D0AA1A1A600134013104338F420C +:10BB900009DD1A68002CF3D0821A01311A600124E1 +:10BBA00004338F42F5DC109E119F069B002B0EDDA7 +:10BBB000012B00D1B1E0022B09D1059B12A95A1E1D +:10BBC000920012AB9B5810939B029B0A8B50079BD1 +:10BBD000022B7ED00023002230003900F9F72EFB23 +:10BBE000059B002800D16BE208995A1E914210DC97 +:10BBF000BF490F988C4612A963448C4600219B00D4 +:10BC000063441C68043B21438342FAD1002900D0DD +:10BC1000B5E0089B12AA013B9B00D358002B00D033 +:10BC200084E201220D9B043B596801320029FAD0BD +:10BC300005990B008C46013362440792934242DC23 +:10BC40000E9A9446A99A634492460B9A9B00944696 +:10BC500026AA90469A44059B0A9A6344DB009844BE +:10BC60000C9B94469946079BE144DB006344059393 +:10BC700053461868FCF79CF8434618605960009BCF +:10BC8000002B23DB444600260027029D22686368C0 +:10BC900003CDFBF769FA02000B0030003900FAF718 +:10BCA00013FB083C06000F005D45EFD14B469E603C +:10BCB000DF6004239C460433E2449C46059BE14438 +:10BCC000E0449945D4D1079B0593B4E600260027AC +:10BCD000ECE732003B0000208649FBF7BFFC060082 +:10BCE0000F00002C00D175E7069A0020814900F072 +:10BCF0004DFF02000B0030003900FBF7AFFC0600DF +:10BD00000F0067E7069B002B12D1059B12AA013B8F +:10BD10009B00D558EB1507930DE7059B12A95A1EFA +:10BD2000920012AB9B5810935B025B0A8B504EE75C +:10BD30000022714BF9F7A6FA00280ED100230793D1 +:10BD400048E7534600260027C0C39A4608239C466E +:10BD5000E144DA4500D03AE659E601239C46013336 +:10BD60000793059BE044002B00DDEEE632003B002C +:10BD700000206049FBF772FC06000F002AE74346EB +:10BD80000B93069B12A8183B190006939300C35807 +:10BD90000092002B0FD156481300844612A863442A +:10BDA00084469B006344043B5868013A18390028D4 +:10BDB000F9D000920691069A00204E4900F0E6FE66 +:10BDC000009B04000D00002B00DAB3E112AA944698 +:10BDD0009F00DB0067449C460A9A059362449346A1 +:10BDE00016003868FBF7E4FF22002B00FBF7BCF9D4 +:10BDF000424B30607160002220002900FBF7B4F94B +:10BE0000083E74AB04000D00043FB342E9D10023A7 +:10BE10009A464EAB0293089B99464B460026002754 +:10BE2000002B21DB8020364B5D469846C005354906 +:10BE300000260027002408E008239C460835E0443B +:10BE4000A24511DB4346186859682A686B68FBF7FE +:10BE50008BF902000B0030003900FAF735FA013493 +:10BE600006000F00A145E7DA029A53469446DB002C +:10BE700063441E605F6001239C46093BE2449C468C +:10BE800074ABE3449B45C8D1029B9946A89B022B07 +:10BE900000DD82E0002B37DC1DD1059B00254B44E3 +:10BEA0001E0000243268736828002100FAF70CFA9B +:10BEB000009B05000C00083E5A1E0092F2D2079B20 +:10BEC000002B03D080231B069C4664442A002300D9 +:10BED00009990A604B6007200B9B18409F239B0029 +:10BEE0009D443CBC90469946A246AB46F0BDC04638 +:10BEF000FFFFFF3F0000F03F0000E03F0000703E0A +:10BF0000E82D0300FB21F93F059B00204B441E0058 +:10BF100000214CAF32687368083EFAF7D5F9BE428B +:10BF2000F8D1079B002B24D08023099A1B06CB183D +:10BF3000106053600B0002004E984F99FBF78EFB88 +:10BF4000009B002B0BDD012450AD0CCDFAF7BCF9A2 +:10BF5000009B0134A342F8DA079B002B03D0802317 +:10BF60001B069C4661440B00020009998A60CB6065 +:10BF7000B1E702000B00099C226063600B00020025 +:10BF80004E984F99FBF76AFB009B002BDBDC0B0004 +:10BF9000020009998A60CB609DE7A89B032B9AD188 +:10BFA000009B002B00DCE3E07E4A059B94464B445B +:10BFB0001E685F68009B63449A46DB004B449846CA +:10BFC0004CAB9B4643465C681B681800210032005E +:10BFD0003B0002900391FAF777F904000D0002008C +:10BFE0000B0002980399FBF739FB3B003200FAF78C +:10BFF0006BF943469860D9601C605D6008235B4222 +:10C000009C46E04426002F00C345DBD1009B012B5A +:10C0100000DCADE0059BC8464B441E685F68534694 +:10C02000DB009B46D844434630005C681B683900FF +:10C03000009301941A002300FAF746F904000D005A +:10C0400002000B0000980199FBF708FB3B0032004F +:10C05000FAF73AF943469860D9601C605D6008239E +:10C060005B429C46E04426002F00C145DBD15D4683 +:10C070000027002408354D4450AE2A686B6838000C +:10C080002100FAF721F9083D07000C00AE42F4D177 +:10C09000079B002B71D08021099A4E9B09061360E3 +:10C0A0004B468C465B686444634453604B469B68D4 +:10C0B000176193604B46DB6854616344D3600AE7C1 +:10C0C000994643460B93069B30005A42390000F0D4 +:10C0D0005DFD0022344B04000D00F9F7D3F8002871 +:10C0E00032D0324B002220002900FBF73DF8FBF74D +:10C0F00029FE4A4606009700FBF75AFE00222A4B0B +:10C10000FBF732F802000B0020002900FBF7A6FA2B +:10C11000FBF718FE12AAD0514A46069B013218338B +:10C1200000920693930012AAD65044E601227FE5BE +:10C1300000243AE5A89B022B14DC002B0FDC00D076 +:10C14000C9E600250024BAE64B46200029009E00DF +:10C15000FBF7F8FD12AB98514B4600932BE60020FD +:10C160000021DEE64EAB9946A89B032B00D0B2E639 +:10C17000079B00270024002B8DD14E9A4F9B0999D5 +:10C180000A604B604B469A68DB68009201938A60B4 +:10C19000CB603A0023000A614B619CE676AB0A93C0 +:10C1A00035E4C046FFFFFF1F000070410000703EF5 +:10C1B000F0B54F464646C0B487B000920193464A58 +:10C1C0004B00814688465B08934205DCFBF7BAFDCD +:10C1D0004146031E484666D04A46434648464146C5 +:10C1E000FAF7C2FF04000D0002000B00484641466A +:10C1F000FAF7BAFF394A3A4B06000F00200029002F +:10C20000FAF7B2FF374A384BFBF728FA22002B0027 +:10C21000FAF7AAFF354A364BFAF756F822002B00F8 +:10C22000FAF7A2FF334A344BFBF718FA22002B002F +:10C23000FAF79AFF314B324AFAF746F80E9B029012 +:10C240000391002B34D00098019900222D4BFAF76E +:10C250008BFF029A039B0490059130003900FAF796 +:10C2600083FF02000B0004980599FBF7F7F9220001 +:10C270002B00FAF779FF009A019BFBF7EFF9224AAE +:10C2800004000D00214B30003900FAF76DFF020069 +:10C290000B0020002900FAF717F802000B004846AF +:10C2A0004146FBF7DBF907B00CBC90469946F0BD60 +:10C2B00002000B0020002900FAF756FF124A134B28 +:10C2C000FBF7CCF932003B00FAF74EFF4A464346F3 +:10C2D000F9F7FAFFE7E7C046FFFF3F3E7CD5CF5AAC +:10C2E0003AD9E53DEB9C2B8AE6E55A3E7DFEB157F7 +:10C2F000E31DC73ED561C119A0012A3F1111813F3D +:10C30000A6F810110000E03F495555555555C53F59 +:10C31000F0B55F4656464D464446F0B489B00093AA +:10C320004B005B089A46BB4B8146884602928B467F +:10C330009A4516DCFBF706FD00282FD14B465246E6 +:10C340001A43129B0133134300D148E1129B012B86 +:10C3500000D15BE14A4643460020AF49FAF7E0FAD4 +:10C36000F8E0AE4B9A4519DD002900DA42E14A4671 +:10C370004346AB48AB49FBF771F904000D00029A44 +:10C38000009BA948A949FBF769F92B002200F9F79E +:10C390009BFF002381468846029300934A4643460A +:10C3A00048464146FAF7E0FE02000B0006000F0087 +:10C3B000FAF7DAFE320004000D003B004846414621 +:10C3C000FAF7D2FE9A4A049005919A4B2000290070 +:10C3D000FAF7CAFE984A994BF9F776FF22002B002C +:10C3E000FAF7C2FE964A974BF9F76EFF22002B0030 +:10C3F000FAF7BAFE944A954BF9F766FF22002B0034 +:10C40000FAF7B2FE924A934BF9F75EFF22002B0037 +:10C41000FAF7AAFE904A914BF9F756FF32003B001B +:10C42000FAF7A2FE8E4A069007918E4B2000290053 +:10C43000FAF79AFE8C4A8D4BF9F746FF22002B0043 +:10C44000FAF792FE8A4A8B4BF9F73EFF22002B0047 +:10C45000FAF78AFE884A894BF9F736FF22002B004B +:10C46000FAF782FE864A874BF9F72EFF22002B004F +:10C47000FAF77AFE844A854BF9F726FF02000B0093 +:10C4800006980799F9F720FF049A059BFAF76CFEC6 +:10C49000029D009C2A002300F9F716FF32003B00A2 +:10C4A000FAF762FE02000B0028002100F9F70CFFEA +:10C4B00004000D0004980599754A764BFAF754FE6E +:10C4C00022002B00F9F700FF0B000200414648460E +:10C4D00000920193F9F7F8FE504B04000D009A45C5 +:10C4E0003FDC129B012B35D00F0002000B00002017 +:10C4F0004949FAF715FA00260D00029003914A46C1 +:10C50000434630003900FBF7A9F8002402000B0075 +:10C5100000980199FBF7A2F822002B00FAF724FEFD +:10C520002200009001912B0030003900FAF71CFE28 +:10C530000022594BF9F7C8FE02000B000098019940 +:10C54000F9F7C2FE029A039BFAF70EFE22002B00B7 +:10C55000F9F7BAFE09B03CBC90469946A246AB46F4 +:10C56000F0BD1298FBF724FC220006000F002B0000 +:10C5700020002900FAF7F8FD3200029003913B00F9 +:10C5800020002900F9F7A0FE02000B000298039991 +:10C59000FAF7C6F9009A019BFBF760F802000B005E +:10C5A00048464146FBF75AF802000B00F9F78CFEAB +:10C5B00002000B0030003900FBF750F85B46040026 +:10C5C000981702231840013B181A0D00FBF7F0FBE7 +:10C5D00002000B0020002900FAF7C6FDBAE7484622 +:10C5E0004146FCF789F802000B0000202A49FAF7BF +:10C5F00097F9AFE78022802112069446009B090636 +:10C6000041446344814688460093B0E6484641462B +:10C61000A0E7C046FFFF2F3E0000F0BF2794E53F94 +:10C62000182D4454FB21E93F075C143326A6813CB6 +:10C63000D47ABF74702AFB3EE9A7F0320FB8123FDC +:10C6400068108D1AF726303F1583E0FEC8DB573F90 +:10C6500093846EE9E326823FFE41B31BBAA1AB3F50 +:10C66000735360DBCB75F3BEA69237A0887E143F70 +:10C670000165F2F2D844433F280356C9226D6D3F4D +:10C6800037D60684F464963F7AFE10111111C13F2B +:10C69000635555555555D53F0000F03FF0B54E4612 +:10C6A00045465746E0B4DF4ACC0F4B0084B0814684 +:10C6B0008846E4075B0893424FD9DB4A934200D98E +:10C6C000F9E0002C00D17AE1D84AD94B48464146DE +:10C6D000F9F7FAFD00220023F8F7B6FD002800D094 +:10C6E000F4E0D44AD44B48464146FAF73DFD0200F7 +:10C6F0000B000020D149F9F7E7FDFBF723FB824649 +:10C70000FBF756FBCE4ACF4B06000F00FAF72CFD85 +:10C7100002000B0048464146FAF7A0FFCA4A04004F +:10C720000D0030003900C94BFAF71EFD06000F005E +:10C7300032003B0020002900FAF790FF02000B00B6 +:10C740008146884620002900FAF788FF32003B0026 +:10C75000FAF784FF0290039109E0BD4A934200D9A1 +:10C76000DBE000229246BB4A934200D805E100225A +:10C77000B94B48464146FAF7F7FC04000D000200A9 +:10C780000B0048464146FAF7EFFC06000F00B34A9B +:10C79000B34BFAF7E9FCB34AB34BF9F795FD320016 +:10C7A0003B00FAF7E1FCB14AB14BFAF757FF320010 +:10C7B0003B00FAF7D9FCAF4AAF4BF9F785FD3200E1 +:10C7C0003B00FAF7D1FCAD4AAD4BFAF747FF320018 +:10C7D0003B00FAF7C9FC0022AA4BF9F775FD00905F +:10C7E000019102000B0020002900FAF7BDFC0200B5 +:10C7F0000B000020A449FAF731FF02000B000400EF +:10C800000D0000980199FAF729FF2200009001918C +:10C810002B0048464146FAF7A7FC02000B00002017 +:10C820009A49FAF71BFF02000B0000980199FAF7EA +:10C8300077F83B003200FAF797FC5346002B48D0BC +:10C84000029C039D22002B00FAF708FF4A4643464C +:10C85000FAF78AFC22002B00FAF700FF3B003200B7 +:10C86000FAF7FCFE534604000D00013300D1B1E09D +:10C870005346012B00D187E053460133392B5ED854 +:10C880005346132B00DCB4E081490022C91A0B0582 +:10C8900020002900F9F718FD02000B004846414628 +:10C8A000FAF7DCFE774B0022F9F70EFD53461B0525 +:10C8B0005D1829001DE0774A934220D90903090B2E +:10C8C000014300D013E14146002C12D000207249F0 +:10C8D0000FE002000B0048464146FAF745FC3200E3 +:10C8E0003B00FAF7BBFE02000B0048464146FAF750 +:10C8F000B5FE04B01CBC90469946A246F0BD674AFE +:10C90000674BF8F7B5FC002800D1DAE6654A664BBC +:10C9100010001900FAF728FCEBE7644A934200D9AB +:10C92000CAE0474A474B002C1ED0F9F7CDFC012343 +:10C930005B4204000D009A46434E5D4FF8E64A46BE +:10C940004346FAF78BFE02000B0000204D49FAF730 +:10C9500085FE544602002005431819001000494B7B +:10C960000022FAF77BFEC4E7FAF778FE0123040001 +:10C970000D009A46344E354FDAE64A4A4A4BF9F7EB +:10C98000A3FC02000B00ACE700224A4B484641469C +:10C99000F8F75AFC002800D19AE000222E4B4846B6 +:10C9A0004146F9F791FC02000B0020002900FAF73C +:10C9B00055FEC02300221B06FAF7D6FB99E71D4A55 +:10C9C0001D4B48464146FAF7CFFB02000B00002002 +:10C9D000214990E602000B0048464146FAF73EFE28 +:10C9E00000221D4BFAF7C0FB00221B4BFAF736FE64 +:10C9F0007FE7802352469B031341224A0026D71A21 +:10CA00004A464346FAF72AFE02000B00300039007E +:10CA1000FAF724FE544602002005431819001000BE +:10CA200067E7C04679684340412E864059F3F8C213 +:10CA30001F6EA501FE822B654715F73F0000E0BF82 +:10CA40000000E0FE422EE63F763C7935EF39EA3DC4 +:10CA5000422ED63FFFFF8F3C0000E03F2DC3096E02 +:10CA6000B7FD8ABE3952E686CACFD03EB7DBAA9E52 +:10CA700019CE143F8555FE19A0015A3FF41011112B +:10CA80001111A13F0000F03F0000084000001840D5 +:10CA9000FF030000FFFFEF7F0000F0BFEF39FAFE59 +:10CAA000422E86409C7500883CE4377EB1A2F03F60 +:10CAB000EF39EABD0000D0BF104A114BFAF754FB22 +:10CAC00002000B000020002C00D013E60D4912E6F6 +:10CAD00022002B0048464146FAF7C0FD02000B0039 +:10CAE000F9F7F2FB0022084BF9F7EEFB01E7020031 +:10CAF00043464146F9F7E8FBFBE6C046FE822B655C +:10CB00004715F73F0000E03F0000F03F034B4800AF +:10CB10009C4640086044C00F7047C046000010802B +:10CB20000A000300024330B50220002A00D130BDC4 +:10CB300080221206914216D00C4A0D4C8A1804200D +:10CB4000A242F4D90B4A8A18A242F0D90A4A4900F3 +:10CB5000490803209142EAD9064A00209142E6D1D1 +:10CB600058425841E3E7002BE1D0EFE70000F0FF27 +:10CB7000FFFFDF7F0000F07FFFFF0F000020704706 +:10CB8000002001497047C0460000F87F4B0070B597 +:10CB90005B0D14000A00002B1AD14B005B08034305 +:10CBA00015D00022224BFAF7DFFA224B0A009C42F2 +:10CBB00022DB4B005B0D363B1F4DE318AB4220DC04 +:10CBC000002B0DDD1D4C1B0522401A43110070BDCA +:10CBD0001B4DAB42F0D102000B00F9F775FBF6E7F5 +:10CBE0001D00353518DA174B02009C420ADC0B0099 +:10CBF0001548164900F032F8134A144BFAF7B4FA04 +:10CC0000E5E702000B001248124900F027F8104A2D +:10CC1000104BFAF7A9FADAE7084C363322401B0525 +:10CC20001343190000220C4BFAF79EFACFE7C046D7 +:10CC300000005043B03CFFFFFE070000FFFF0F80E5 +:10CC4000FF07000050C3000059F3F8C21F6EA50192 +:10CC50009C7500883CE4377E0000903C30B54A006B +:10CC6000DB0FDB0752081A43110030BD70B5054CCD +:10CC700005001300201E04D00A000220290000E055 +:10CC800000BF70BD00000000014B18687047C0462F +:10CC900080200020084B10B50400002B02D000219A +:10CCA00000E000BF054B1868836A002B00D098474E +:10CCB000200005F00CFBC04600000000003E030011 +:10CCC0000E4B70B500251E000D4CE41AA410A542B1 +:10CCD00004D0AB00F35898470135F8E705F020FE83 +:10CCE000084B00251E00084CE41AA410A54204D0ED +:10CCF000AB00F35898470135F8E770BD9C20002041 +:10CD00009C2000209C200020BC20002010B5034B5C +:10CD10000100186805F044FD10BDC04680200020C9 +:10CD2000002370B5064C050008001100236000F0D8 +:10CD300063FB431C03D12368002B00D02B6070BD24 +:10CD40000C2900200CB430B5164B9DB00C1E1D688C +:10CD500004DA8B2301202B6040421DE0822302A9CC +:10CD60009B008B810023029008619C4200D0631ECF +:10CD70008B604B6101235B42CB81209A21AB280061 +:10CD8000019300F011F9431C01DA8B232B60002C76 +:10CD900002D00023029A13701DB030BC08BC02B050 +:10CDA0001847C04680200020F0B51E00454B87B0D4 +:10CDB0001B680192029308220B00059003911C78D6 +:10CDC00002995D1C09194878104001D02B00F6E744 +:10CDD0002D2C04D19D1C5C780123009304E000906D +:10CDE0002B2C01D15C789D1C002E02D0102E0AD174 +:10CDF00062E0302C5ED120222B789343582B54D103 +:10CE000010266C780235009F31007B1E9F412E4B0F +:10CE1000FF183800F8F712F9380004913100F8F7DC +:10CE200087F800230322070094461800029A12197B +:10CE300051780422114201D0303C07E06246114093 +:10CE400017D03722012900D02032A41AA64210DDC3 +:10CE50005A1C0BD0B84207D802D1049B9C4203DC79 +:10CE600070430123201801E001235B422C78013537 +:10CE7000DCE75A1C0BD10098059A431E9841124BCF +:10CE8000C01822231360019B002B0AD117E0009ADF +:10CE9000002A00D04042019A002A10D0039A002BA9 +:10CEA00000D06A1E019B1A6009E03024002EAAD12E +:10CEB0000826A8E70A26A6E7302C9CD0A3E707B0EF +:10CEC000F0BDC04684200020FFFFFF7F10B5130097 +:10CED0000A00010002480068FFF766FF10BDC04667 +:10CEE00080200020F0B58E6885B007000C0003920A +:10CEF00001939E4243D890238A89DB001A423ED098 +:10CF000003250969236801985B1A029363695D43ED +:10CF1000EB0F5D19029B6D1001331B18AB4200D95A +:10CF20001D00530510D52900380001F0B2FE061E81 +:10CF300014D0029A216905F00DFCA289194B134007 +:10CF400080221343A38112E02A00380001F0ABFED7 +:10CF5000061E0CD12169380001F0A0FE0C234022EE +:10CF600001203B60A38940421343A38117E0029B49 +:10CF70002661F61826606561019EED1AA560019B89 +:10CF8000B34200D21E0032000399206805F0EBFB8B +:10CF90000020A3689B1BA36023689E19266005B030 +:10CFA000F0BDC0467FFBFFFFF0B59FB00290059338 +:10CFB0008B890F0016001B0610D50B69002B0DD1B5 +:10CFC000402101F066FE38603861002804D10C234E +:10CFD000029A01381360D8E040237B61002306AD3C +:10CFE0006B6120336B761033AB7634002378002BE3 +:10CFF00003D1A31B049312D003E0252BF9D00134F5 +:10D00000F4E7A31B320039000298FFF76BFF431CC3 +:10D0100000D1B4E06A69049B944663446B61237851 +:10D02000002B00D1ABE00122002352426A6002A92A +:10D030005432521801342B60EB60AB601370AB6557 +:10D04000534E21780522300005F06AFB002807D0F6 +:10D050000123801B83402A68013413432B60EFE7D0 +:10D060002B68DA0604D55322202102A81218117069 +:10D070001A0704D553222B2102A812181170227806 +:10D080002A2A03D0099B00200A210EE0059A111DCF +:10D0900012680591002A01DB099204E05242EA601D +:10D0A000022213432B6001340BE02278303A092A24 +:10D0B00004D84B4301349B180120F6E7002800D028 +:10D0C000099323782E2B1ED163782A2B0AD1059B36 +:10D0D00002341A1D1B680592002B01DA01235B4202 +:10D0E000079310E000230A201A0001346B602178B6 +:10D0F0003039092904D84243013452180123F6E794 +:10D10000002B00D00792234E21780322300005F037 +:10D1100007FB002806D04023801B83402A68013487 +:10D1200013432B60217806221B48661C297605F0E4 +:10D13000F7FA002812D0194B002B06D10722059BC5 +:10D14000073393430833059314E005AB00933A008B +:10D15000134B2900029800E000BF07E005AB0093E5 +:10D160003A000F4B2900029800F01CF80390039B33 +:10D17000013304D06B69039A9B186B6135E7BB8957 +:10D180000B985B0601D5012040421FB0F0BDC046A0 +:10D19000954503009B4503009F45030000000000E8 +:10D1A000E5CE0200F0B58BB006920A004332079339 +:10D1B000059004920A7E0C00109B6E2A00D1ABE011 +:10D1C00011D8632A22D009D8002A00D1B5E0582A04 +:10D1D00000D0C5E045310A70814A4FE0642A1DD075 +:10D1E000692A1BD0BCE0732A00D1AAE009D86F2AB3 +:10D1F00029D0702A00D0B3E0202209680A432260B7 +:10D2000037E0752A1FD0782A33D0A9E00E001A68BB +:10D210004236111D196013683370A4E021681A6842 +:10D22000080606D4490604D5111D19600023D55EF1 +:10D2300002E0111D19601568002D3BDA2D23049AB8 +:10D240006D42137036E021681A68080606D4490654 +:10D2500004D51568111D1960ADB202E0111D1960E9 +:10D2600015685F4B227E039308276F2A1DD00A277B +:10D270001BE022007821453211705A4A1968039246 +:10D28000081D226818600D68100602D4500600D5EB +:10D29000ADB2D30702D520231A4322601027002DF8 +:10D2A00003D1202322689A432260230000224333C3 +:10D2B0001A7002E00A274A4B03936368A360002BAD +:10D2C00009DB0422216891432160002D05D1049ED1 +:10D2D000002B11D07BE0002D79D0049E280039006E +:10D2E000F7F7ACFE039B013E5B5C2800337039000E +:10D2F000F7F71EFE051EF1D1082F09D12368DB07C1 +:10D3000006D563682269934202DC3023013E337004 +:10D31000049B9B1B23612BE009681A68080607D44D +:10D32000490605D5111D19601368A28A1A8004E008 +:10D33000111D1960136862691A600023049E23613D +:10D3400016E01A68111D1960166800216268300025 +:10D3500005F0E6F9002801D0801B6060636803E0F7 +:10D36000260042363270012323610023049A137091 +:10D37000079B09AA00932100069B059805F062FA15 +:10D38000431C02D10120404227E023693200069964 +:10D390000598079DA847431CF4D0236800259B07E8 +:10D3A0000FD4099BE068984217DA180015E02200B4 +:10D3B0000123193206990598079EB047431CE1D016 +:10D3C0000135E368099A9B1A9D42F0DBE9E72600E4 +:10D3D000039B42361B7833708EE70BB0F0BDC0461E +:10D3E000A6450300043E030058220120014B4042A1 +:10D3F0001A6070470C29002058220120014B40423E +:10D400001A6070470C29002070470220704710B541 +:10D41000406801F0FFFE10BD704713B5040040687E +:10D4200001F0EAFE002811D061686846EEF7B6F810 +:10D43000694601A801F063FE01A8EEF7BFF860603D +:10D4400001A801F054FD684601F051FD13BD10B56F +:10D45000EAF7D8FE10BD052310B55943EAF7E4FEFC +:10D4600010BD13B50400FFF7D8FF616801A8EEF7FF +:10D4700095F801A801F05FFD01A801F038FD13BD8A +:10D48000F7B5070015001E000C00FFF7C6FF79680E +:10D4900001A8EEF783F8F3B22AB221B201A8EEF7A1 +:10D4A00095F801A801F023FDF7BD37B515000C0074 +:10D4B000416801A8EEF772F82AB221B201A8EEF78E +:10D4C0009BF8040001A801F012FDE043C0172040C2 +:10D4D0003EBD43685888704743689888704710B5C8 +:10D4E0005C1EA3415B42DBB2FFF7CAFF10BD10B563 +:10D4F000FFF7DBFFC317181AC00F10BD052310B5C7 +:10D500005943EAF7A5FE10BD10B50A001023032108 +:10D51000ECF7AAFF10BD70B504000D00ECF72EF873 +:10D52000002807D0F0F742F810232A00032120003A +:10D53000ECF79AFF70BD70B504000D00ECF71EF813 +:10D54000002807D0F0F732F810232A00022120002B +:10D55000ECF78AFF70BD10B5ECF710F8031E04D08D +:10D56000F0F724F8431E9841C3B2180010BD10B55F +:10D57000EDF762FF10BD10B5EDF76CFF10BD704701 +:10D5800080880A3080107047704706307047808866 +:10D5900070478288030000208A4201D3063358185E +:10D5A00070470320704740680B30800870478088C0 +:10D5B00070470123820702D143425841C3B2180089 +:10D5C000704700280BD043688B4201D0002B04D158 +:10D5D0008368934203D0002B01D00068F1E77047C5 +:10D5E00010B5EBF773F910BD07B5002201AB1A8037 +:10D5F000012118701800EBF769F90EBD030030B572 +:10D6000000208B4214D08D1D9A888988981D9142E4 +:10D6100000D911000022835CAC5CA34204D0A34279 +:10D620009B410120184303E001328A42F3D90020D4 +:10D6300030BD80887047F7B5002821D000291FD061 +:10D6400087888E88002A1BDB9219974218D3851D84 +:10D650002C008B1D01938B7900933B1BEB18B3427D +:10D660000ED32378009A934208D13200019920000A +:10D6700005F061F8002801D1601B03E00134ECE7FC +:10D6800001204042FEBD10B5FFF7D5FF0130431E1B +:10D69000984110BD43425841C0B2704710B5FAF7E7 +:10D6A00001FCEBF763FA10BD430010B55A1090422D +:10D6B00002D10120184303E0FAF77AFBEBF756FAA0 +:10D6C00010BD030010B50E20002906DB9A88914298 +:10D6D00003DA59188879FFF7E7FF10BD10B50E235C +:10D6E000002802D0FFF7EDFF0300180010BD422311 +:10D6F000002800D1383B180070470023062806D0C8 +:10D700000333422803D0023B0A2800D0030018004C +:10D71000704710B5EBF7AEFBEBF728FA10BD4843A6 +:10D72000704710B5F7F78EFC10BD10B50C20ECF764 +:10D73000BFFB041E01D0ECF7B3F8200010BD008938 +:10D74000704710B5043000F099FF10BD10B50A0005 +:10D7500004308188ECF78AF810BD10B5043000F071 +:10D7600098FF10BD02890023914202D243688900CC +:10D77000CB581800704710B50430ECF777F810BD9F +:10D7800010B5043000F093FF10BD10B5043000F068 +:10D79000ACFF10BD70470020704740687047416083 +:10D7A000704710B50820ECF783FB041E01D0ECF79E +:10D7B00081F8200010BD10B5ECF752FD10BD431EDE +:10D7C0009841704710B51420ECF772FB041E01D08D +:10D7D000ECF778F8200010BD10B5040000F0A6FFAB +:10D7E0000023984205DB228A904202D2E36880003F +:10D7F000C358180010BDF8B504000F00160025002E +:10D8000000F094FF0C35011E05DA2189201D3A0035 +:10D81000ECF72CF8218A32002800ECF727F8F8BD45 +:10D82000704710B5EBF752FC10BD70B50D00EBF76B +:10D830004DFC04002800EBF749FC84402000FFF772 +:10D8400033FF70BD70B50D00EBF740FC04002800FD +:10D85000EBF73CFC04412000FFF726FF70BD70B5DC +:10D860000D00EBF733FC04002800EBF72FFC6040C1 +:10D87000FFF71AFF70BD70B50D00EBF727FC040031 +:10D880002800EBF723FC2043FFF70EFF70BD10B517 +:10D89000EBF71CFCC043FFF707FF10BD70B50D0090 +:10D8A000EBF714FC04002800EBF710FC2040FFF716 +:10D8B000FBFE70BD70B50D00EBF708FC04002800FE +:10D8C000EBF704FCC4402000EBF71EFA70BD10B566 +:10D8D000EBF7D8FBFAF73AFB10BDD0B50C0001000E +:10D8E00021430023890720D1032A05D12100FFF716 +:10D8F00085FE4342434117E0022A12D1EBF7C2FBF7 +:10D90000060020000F00EBF7BDFB02000B0030000B +:10D9100039000124F7F792FC002800D1041CE3B27F +:10D9200003E0031B58424341DBB21800D0BD70B581 +:10D930000E00EBF7A7FB040030000D00EBF7A2FB95 +:10D9400002000B0020002900F8F7BEFCEBF70EF9EF +:10D9500070BD70B50E00EBF795FB040030000D00B4 +:10D96000EBF790FB02000B0020002900F9F776FE90 +:10D97000EBF7FCF870BD0B000340D0B50C00DB07E3 +:10D980000DD5C3130133012B09D8CB130133012B60 +:10D9900005D84C1040106043FFF786FE0EE0EBF711 +:10D9A00071FB060020000F00EBF76CFB02000B0080 +:10D9B00030003900F9F7D8FBEBF7D8F8D0BD70B5D7 +:10D9C0000E00EBF75FFB040030000D00EBF75AFB95 +:10D9D00002000B0020002900F8F7A2FFEBF7C6F8C1 +:10D9E00070BDF8B501230C00184211D019420FD0B8 +:10D9F0004B100DD0EBF76AFB05002000EBF766FB40 +:10DA000001002800F7F704FC0800FFF74DFE0EE0C8 +:10DA1000EBF738FB060020000F00EBF733FB0200AA +:10DA20000B0030003900FBF7C7FCEBF79FF8F8BD9F +:10DA300070B50E00EBF726FB040030000D00EBF78D +:10DA400045FB290002002000F7F780FCEBF78EF879 +:10DA500070BD0123F7B50E00184201D0194236D12E +:10DA6000EBF710FB040030000D00EBF70BFB06009A +:10DA70000F0002000B0020002900F7F7F9FB002837 +:10DA800005D022002B0034003D0016001F0032009C +:10DA90003B0020002900F7F7D1FB002802D020002E +:10DAA000290011E0EBF7E6F92200009001912B002C +:10DAB00030003900F9F7D2FD009A019BF9F754FBC9 +:10DAC00022002B00F8F700FCEBF750F811E04410AF +:10DAD0004910A14209DB201E884203D0081BEAF747 +:10DAE0003BFF2018FFF7E0FD03E023000C001900C6 +:10DAF000F1E7FEBD10B5EBF7C5FAFBF7C1FCEBF79C +:10DB000035F810BD10B5EBF7BDFAFBF745FDEBF7A7 +:10DB10002DF810BD10B5EBF7B5FAFAF7F1FDEBF7FC +:10DB200025F810BD10B5EBF7ADFAFAF709FDEBF7E4 +:10DB30001DF810BD10B5EBF7A5FAFBF7A9F9EBF747 +:10DB400015F810BD70B504000D000E2801D100209D +:10DB500016E00E29FBD0012318008C4210D00B4098 +:10DB60001C42F4D12000EBF765FA06002800EBF721 +:10DB700061FA8642EBD1320029002000FFF7ADFEAA +:10DB800070BD10B5FFF7DEFF4223002800D1383BFF +:10DB9000180010BD10B5FFF7D5FF4223002800D0B4 +:10DBA000383B180010BDF7B504000D000E2801D158 +:10DBB000002051E00E29FBD0FFF79FFD0600280052 +:10DBC000FFF79BFD01230190019A1800964243D074 +:10DBD0002B401C42ECD12000EBF72CFA0090070000 +:10DBE0002800EBF727FA0300032F01D1022803D006 +:10DBF000032815D1022F29D12000EBF743FA0600A4 +:10DC000028000F00EBF73EFA02000B00300039004D +:10DC10000124F7F713FB002800D1041CE0B21BE03D +:10DC2000012F09D0012801D0019500E00223009ABC +:10DC300026009342BCD103E0012809D102230093BE +:10DC4000009A01993000FFF748FE05E0012FEBD163 +:10DC5000022234000092E7E7FEBD10B5FFF7A3FFF4 +:10DC600010BD10B5FFF79FFF4223002800D1383BBD +:10DC7000180010BD10B5FFF796FF4223002800D012 +:10DC8000383B180010BDF8B50F0000244668058920 +:10DC9000AC420AD2A3003900F058FFF784FF0028F5 +:10DCA00001D0200003E00134F2E701204042F8BD3A +:10DCB00010B500220400FFF7E6FF010000208142BA +:10DCC00003DB201D00F0F3FC012010BD10B5012383 +:10DCD000422805D000230A2802D0EBF76DFA030092 +:10DCE000180010BDF8B504000E000E2801D1022066 +:10DCF0002FE00E29FBD0EBF79DF905003000EBF784 +:10DD000099F9032D06D1032804D131002000FFF733 +:10DD100075FC33E00020B44230D02000EBF7B2F9BC +:10DD2000040030000D00EBF7ADF9220006000F00F3 +:10DD30002B0020002900F9F7E5FF0028D7D1320099 +:10DD40003B0030003900F9F7DDFF002803D0CEE7B3 +:10DD50000120404212E032003B0020002900F7F78A +:10DD600073FA0028F4D13B00320020002900F7F7B5 +:10DD70007FFA431E9841012340421840F8BD10B578 +:10DD800001230C001C40044004D0884200DB002327 +:10DD9000D8B206E0FFF7A6FF030020009A1C00D0CF +:10DDA000D80F10BD0B00034010B5DB0703D5884228 +:10DDB00005DC422008E0FFF795FF831C01D10A2013 +:10DDC00002E00028FBDCF4E710BD0B00034010B5B7 +:10DDD000DB0703D5884205DA422008E0FFF782FF1F +:10DDE000831C01D10A2002E00028FBDAF4E710BD11 +:10DDF0000B00034010B5DB0703D5884205DB42204A +:10DE000004E0FFF76FFF0028F9DA0A2010BD0B00CD +:10DE1000034010B5DB0703D5884205DD422004E04E +:10DE2000FFF760FF0028F9DC0A2010BDE42010B5E0 +:10DE30008000ECF715FA10BD70B50E00EBF722F973 +:10DE4000040030000D00EBF71DF902000B0020006C +:10DE50002900FBF757F9EAF789FE70BD10B5EBF71B +:10DE600011F9FAF76DFFEAF781FE10BD10B5EBF777 +:10DE700009F9FAF71DFFEAF779FE10BD10B5EBF7C7 +:10DE800001F9FAF7F3FBEAF771FE10BD10B5EBF7F5 +:10DE9000F9F8FAF7B7F9EAF769FE10BD10B5EBF734 +:10DEA000F1F8FBF7D5F8EAF761FE10BD10B5EBF716 +:10DEB000E9F8FBF71BF8EAF759FE10BD10B5EBF7D0 +:10DEC000E1F8FBF763FCEAF751FE10BD10B5029CC8 +:10DED00094421FDB002B09D00B0080185C1A94427F +:10DEE0001BDA1C78013804700133F7E7042A06D1E5 +:10DEF000032303400BD10A68026018000EE0022AD7 +:10DF000005D10123034002D10A88028005E004F014 +:10DF100021FC02E00120404200E0002010BD10B5CD +:10DF2000040008000299914205DA002104F030FC57 +:10DF30000120404220E0002B09D00300A418191A48 +:10DF4000914218DA013C217819700133F7E7042A6D +:10DF500005D1032323400BD12268026006E0022A88 +:10DF600006D10123234003D122880280180003E058 +:10DF7000210004F0EFFB002010BD08307047031EA5 +:10DF800007D00023994204DB4268914201DA41182C +:10DF90000B7A18007047002806D0002904DB43687C +:10DFA000994201DA41180A72704710B5FFF7E7FF8E +:10DFB00010BD10B5FFF7EFFF10BD70B50C001600D7 +:10DFC000002B1CDB00291ADB41688C4217DC5268ED +:10DFD000091BD21A8A4200DD0A00002A0FDB350035 +:10DFE0000835864204D1E918281904F0BCFB04E086 +:10DFF00008300019E91804F0ADFB002001E0012011 +:10E00000404270BD4068704710B5002A0EDB44687E +:10E01000A2420BDC002B00DA2300A41A9C4200DD94 +:10E020001C0008308018220004F0B2FB10BD4368C9 +:10E0300010B51C1E8C4200DD0C00002A00DA1A000C +:10E04000191B914200DD110008300019EAF760FC4D +:10E0500010BD70B50D00002B01DA43689B1A002A31 +:10E060002EDB44689918A1422ADC8A4228DC002B66 +:10E0700026D0690024D059428D4201DDAB4206DC36 +:10E080000022012311005B42FFF7BEFF18E00830B9 +:10E090008618002D09DA6C425A193100301904F043 +:10E0A00062FB22000021300008E05C1B7119220095 +:10E0B000300004F058FB2A000021301904F068FBFE +:10E0C00070BD030010B508305968FFF789FA10BD1C +:10E0D00070B50400160008001D1E01DA63689D1A61 +:10E0E000002E2BDB6268AB19934227DC9E4225DCB5 +:10E0F000002D23D0430021D0002801DA2B02C018C4 +:10E100002900F7F785F8002900DA491922000832BA +:10E11000921951180B0055199A420FD014781E7895 +:10E120000132501E0670581C1C70854202D1080036 +:10E130000300F1E79142FBD10100F9E770BD012333 +:10E1400007B55B4200930023FFF737FF07BD10B50B +:10E1500001000020EAF7DCFB10BD10B58188063015 +:10E16000EAF7D6FB10BD30B50400501E85B00D0097 +:10E170000F2869D8F6F7D2FE080C14141C25252E9A +:10E180002E37203B404F475C1800FFF74AFB03E067 +:10E190001800FFF746FBC0B2002D55DD207053E09C +:10E1A0001800FFF73EFB02A908800023009518E045 +:10E1B0001800FFF736FB02E01800EAF787FF02902D +:10E1C0001EE01800FFF72DFB012302A908701A00BA +:10E1D000009536E01800FFF724FB012302A9088010 +:10E1E000009502222DE01800FFF71BFB02E018004B +:10E1F000EAF76CFF02900AE01800FFF768FB029054 +:10E200000095002305E01800FFF761FB0290012351 +:10E210000095042214E01800EAF734FF02900391FD +:10E22000072D11DD082202A9200004F093FA0BE06B +:10E230001800EAF727FF01230822029003910095B6 +:10E2400002A92000FFF742FE05B030BD10B50C005A +:10E25000002A06DB41680830891A80182200FFF77F +:10E2600082FF10BD30B5013A050085B000200F2AAD +:10E2700068D8100002AC0091F6F750FE080B151795 +:10E28000191D2629323A1B424C584E5A00230122AE +:10E2900013E00023012221002800FFF740FE207830 +:10E2A000FFF702FA4EE0002312E0002319E00023FA +:10E2B0001FE0002325E001231A0021002800FFF7BA +:10E2C0002EFE00202056EBE701231A00E3E701238E +:10E2D000022221002800FFF722FE0023E05EDFE794 +:10E2E0000123022221002800FFF719FE2088D7E72A +:10E2F0000123042221002800FFF711FE0298CFE736 +:10E300000123042221002800FFF709FE0298EAF702 +:10E31000FBFC17E0002300E0012304222100280079 +:10E32000FFF7FDFD0298FFF7B9F90BE0002300E0CD +:10E330000123210008222800FFF7F1FD029803992C +:10E34000EAF714FC05B030BD10B5002A03DA00204E +:10E35000FFF7AAF907E0436808309B1A80180A0003 +:10E360001900FFF77FFF10BD10B50400EBF748F868 +:10E37000002807D11023220001211D30ECF774F88A +:10E38000EBF77CF810BD10B5EBF7F8F810BD10B541 +:10E39000EBF7F4F8002801D0EFF78AF810BD10B5BC +:10E3A0000C00EBF7EBF8002802D02100EFF74AF859 +:10E3B00010BD10B5EBF7E2F8002801D0EFF7D6F862 +:10E3C00010BD10B50C00EBF7D9F8002802D02100E1 +:10E3D000EFF7A6F810BD10B50C00EBF7CFF800284A +:10E3E00002D02100EFF75AF910BD70B504000D00FE +:10E3F0001600EBF7C3F8002808D00221EFF7B0F9B8 +:10E400001023320029002000ECF72EF870BDF0B583 +:10E4100085B00C001500EBF7B1F8061E01D1002005 +:10E4200030E0EDF717F800900191043C6742674136 +:10E43000EC173000EFF73CF8B8420BD0EDF70AF8D4 +:10E44000009A019B801A9941A142E8D8F1D18542F6 +:10E45000EFD2E4E7ECF7FEFF03903000EFF728F887 +:10E46000B8420BD1ECF7F6FF009A019B801A994154 +:10E47000A142D4D8F1D18542EFD2D0E7ECF7EAFF40 +:10E48000039BC01A05B0F0BD10B50C00EBF776F891 +:10E49000002802D02100EFF7ADF810BD10B501241F +:10E4A000002903D00234012900D00024EBF766F8DC +:10E4B000002802D02100EFF7FDF810BD10B50C00C8 +:10E4C000EBF75CF82100EFF74BF910BD10B5010038 +:10E4D0000020EAF71DFA10BD10B50400EBF7C8F8EC +:10E4E000036821001B68984710BD10B50400EBF7C6 +:10E4F000BFF82100F5F7AEFB10BD70B50D000400AC +:10E50000EBF7B6F82A002100F5F798FB70BD10B5BF +:10E51000EBF72EFA002010BD704770477047704728 +:10E52000704710B5EAF7AEFDFAF7B6FBEAF71EFB47 +:10E5300010BD10B5EAF7A6FDFAF7BCFEEAF716FB28 +:10E5400010BD10B5EAF79EFDFAF726FCEAF70EFBC0 +:10E5500010BD10B5EAF796FDFBF7A4F8EAF706FB45 +:10E5600010BD10B5EAF78EFDFAF742FEEAF7FEFAA3 +:10E5700010BD10B5EAF786FDFAF7C8FDEAF7F6FA1E +:10E5800010BD10B5EAF77EFDF9F796FDEAF7EEFA51 +:10E5900010BD10B5EAF776FDFAF702FDEAF7E6FAE4 +:10E5A00010BD0323020003400020834208D18242B1 +:10E5B00006D0106801229043C278F92A00D01800D2 +:10E5C00070470023438103814360704700234381E8 +:10E5D0000381436043820382C36070477047704782 +:10E5E00070477047704770470123026810B59A431F +:10E5F00013005B8A128A1B041343984710BD10B5A1 +:10E60000FFF7F2FF10BD704783880200181E08D084 +:10E61000013B9BB2938012689B00D31800221868BC +:10E620001A607047F8B5C688050030000F00EBF798 +:10E630006DF8041C80B2B84200D23C1CA4B2A642C1 +:10E6400014D2A00000F013F9EA880600002A03D0D3 +:10E650009200296804F07EF8E8880021221A8000E0 +:10E660009200301804F094F82E60EC80F8BDC38856 +:10E6700010B58B4201D8FFF7D5FF10BDC38870B528 +:10E6800004000D008B4202D28188FFF7F0FFA580C5 +:10E6900070BD83880200181E08D0013B9BB2938096 +:10E6A00012689B00D318002218681A607047F8B5EA +:10E6B0008388040000208B4216D927688E00B81981 +:10E6C0004A1C0568934206D9013B5A1A311D920033 +:10E6D000791804F048F800212800A3882268013B3B +:10E6E0009BB2A3809B009950F8BDF8B50D008188BE +:10E6F00004001600A94214D9013189B2FFF7B7FF0F +:10E70000A288681C23688000071F521BD91918189B +:10E71000920004F028F82368DE51A3880133A38017 +:10E7200002E02900EBF7A2F8F8BD7047F7B50689BB +:10E7300047680020B04205D28300FB588B421AD0B4 +:10E740000130F7E700248B1D8D880193B4420CD271 +:10E75000A300F9588B889D420AD106312A000198FE +:10E7600003F0E9FF002803D104E00120404202E069 +:10E770000134EBE72000FEBD704710B5EBF770FDEC +:10E7800010BD10B5FFF70DFF002804D00089063832 +:10E7900043425841C0B210BD10B5EBF799FD10BD12 +:10E7A00010B500F092F910BD10B503F076FE10BD63 +:10E7B0001FB5D3B28AB281B2684600F075FB05B0CE +:10E7C00000BD10B5002B00D11033EBF74DFE10BD8E +:10E7D00010B5ECF781F801214942FEF701FF10BDA9 +:10E7E00010B500F06EF910BD704710B5002803D0C9 +:10E7F0008188063000F0D2F810BD0123820705D1D0 +:10E80000002803D0000F43425841C3B2180070479C +:10E8100010B50A008188EBF715F810BD01220368D6 +:10E82000934318888010704770B504680500002C69 +:10E8300006D02000EBF760F9A9882000EBF798F9E3 +:10E8400070BD10B5002811D0C468002C09D0236811 +:10E85000436063688360A368C3602000EBF714FB28 +:10E8600004E0EBF711FB2000EBF766FD10BD03237E +:10E870000330984310B5041D2000EBF719FB8023EB +:10E88000DB051C4310C010BD10B5031E08D0FFF7F8 +:10E89000EEFF8023021F11689B050B4313600300EA +:10E8A000180010BD10B50400FFF7A7FF002802D123 +:10E8B0002000EBF7CFF810BD10B50430FFF7B4FF20 +:10E8C00010BD10B581880C30EBF752F910BD10B5B2 +:10E8D0004068EBF729F910BD10B504000430FFF7CC +:10E8E000A3FF20000C30FFF79FFF10BD012210B5E1 +:10E8F00008C89343198804398908EBF739F910BD22 +:10E9000003207047808880000F3080087047022005 +:10E9100070470520704710B5EBF7CAFC10BD10B565 +:10E92000ECF780FB10BD7047704770477047704729 +:10E93000704710B5040003F0E8FE200010BD10B5CC +:10E94000040003F0E2FE200010BD10B5040003F047 +:10E95000DCFE200010BD10B5040003F0D6FE200040 +:10E9600010BD10B5FFF79EFFECF7BEFB10BD10B554 +:10E9700004002000EBF726FC1420ECF753FBF8E72B +:10E9800010B50400EBF760FC200003F0BEFE200091 +:10E9900010BD704710B5ECF7A7FB10BD10B5EBF735 +:10E9A00047FC10BD10B518C96210E10701D58158A8 +:10E9B000CB588018984710BD70B5DD24A400050021 +:10E9C0000059002804D002F019FB836D9B0702D484 +:10E9D00000F07BF870BD2859F2F74CF90368132159 +:10E9E0005B6A9847642003F063FDF1E782B030B5BD +:10E9F00085B008920500082202A8099303F0AAFE38 +:10EA0000039B029C5810DB0701D52B581C592D186D +:10EA10000AA90822684603F09DFE089A099B28006F +:10EA2000A04705B030BC08BC02B0184782B01FB583 +:10EA3000040006920793120C1A2A14D00AD8042A4A +:10EA400023D0052A27D1E6235B00C15801A800F096 +:10EA500083FD20E01B2A18D01C2A1CD1E130FF3096 +:10EA6000EFF748FE17E06930FF30002100F0DCFCD2 +:10EA700020009130FF30002100F0D6FC2000B9309A +:10EA8000FF30012101F0EAFC05E0E4235B00E158DE +:10EA900001A800F081FC1FBC08BC02B018473ADF97 +:10EAA000704712DF704713B56B46DC1D0023200052 +:10EAB0002370FFF7F6FF2078013843425841C0B277 +:10EAC00016BD80235B05586E704710B5EBF7F8FE56 +:10EAD00010B58368984710BD704770B506000D00EB +:10EAE000141E11D0936D002B02D01E20EBF72EFFC9 +:10EAF0002B683268002A02D0111D31601460646DE9 +:10EB00000133002CF5D12B6070BD10B5040003F06B +:10EB1000FCFD200010BD72B601650B68002B03D10F +:10EB200043658365086007E05A6D002A01D0130031 +:10EB3000FAE758658365426562B67047036D002B3E +:10EB400012D072B6826D436D002A01D0536501E088 +:10EB5000026D1360436D002B01D0826D9A65002316 +:10EB600043658365036562B6704770B504000E00A7 +:10EB70001500ECF70FF9002805D001233200290019 +:10EB80002000ECF763F970BD10B5ECF769FA041ECC +:10EB900001D1ECF7DDF9200010BD10B50C00804765 +:10EBA000A047ECF7A1FA10BD10B5ECF7F3F8002878 +:10EBB00001D0ECF799FA10BD70B5140003001000F5 +:10EBC0000D0098472000A8472000FFF7EDFF70BD1B +:10EBD00010B5ECF7A7F9ECF7BBF9FAE70300F0B5CD +:10EBE0008208980702D1181E01D137E00132541C67 +:10EBF00072B6802621C93606A84217D20368002BB8 +:10EC000011DA5B005B08990041180F68002F08DAE1 +:10EC1000A94206D231007F007F08DB191943016049 +:10EC2000F1E7A34205D29B00C018E5E762B60020D9 +:10EC300014E00232934203D992008218954204D81C +:10EC400003685B005B08036006E080211B1B09066C +:10EC5000043A0B431360046062B60430F0BD70B533 +:10EC6000040008000E00ECF701FB0500002C0ED09C +:10EC700000280CD0231F1A689200B24200DD320037 +:10EC80002100280003F066FD2000ECF725FB28009A +:10EC900070BD10B50800ECF7E9FA10BD10B508001A +:10ECA000ECF71AFB10BD10B508001100FFF7D7FFF5 +:10ECB00010BDF7B51D0008AB1B880400103016000E +:10ECC0000F00019300F0E5F86A4600239288278040 +:10ECD0006680A5602000E360A28063622362FEBDBF +:10ECE00010B5838804009B0702D5806803F00DFDF2 +:10ECF000200010BD82B030B5046A87B00B930500C8 +:10ED00000A920123002C14D110220AA902A803F0B0 +:10ED100021FD182003F0E7FC0400082204A968463E +:10ED200003F018FD029A039B200000F0CDF82C623E +:10ED30001BE02269002A02D001331400F9E7092BF5 +:10ED400013DC10220AA902A803F004FD182003F026 +:10ED5000CAFC0500082204A9684603F0FBFC029ADD +:10ED6000039B280000F0B0F8256107B030BC08BC58 +:10ED700002B0184710B50400006800F04BFA2000FC +:10ED800010BD70B5060008000D0003F041FD040041 +:10ED90000530ECF76BFA306000F02BFA3068290090 +:10EDA0004480621C043003F0D5FC70BD1FB5040024 +:10EDB000080001A9EBF750FD200001A9FFF7E1FFD2 +:10EDC000200004B010BDF8B50B68170002241C5FCA +:10EDD0001368050002229B5E0E00E418601DECF72C +:10EDE00045FA286000F005FA28683168448002235B +:10EDF000CA5E0430043103F0ADFC2B683968181D7D +:10EE0000336802229B5EC0180223CA5E043103F0FD +:10EE1000A1FC2B6828001C1900232371F8BD10B534 +:10EE200004000868206000F0EBF9200010BD70B508 +:10EE30000B68040000680D00984205D000F0EAF964 +:10EE40002868206000F0DCF9200070BD70B5136800 +:10EE500004005D880868002D01D1206004E040882E +:10EE6000002804D11800236000F0CAF902E0200055 +:10EE7000FFF7A9FF200070BD0023994207DB02685D +:10EE80000223D05E0023884201DD51180B7918005F +:10EE90007047002310B5038043800400ECF7DAFAD2 +:10EEA000A060E160200010BD70B5018042800400C8 +:10EEB0001D00ECF7CFFAA060E160002D02D0200029 +:10EEC000ECF752FB200070BD82B010B50400039334 +:10EED0000292FFF7DEFF102202A9200003F03AFCA5 +:10EEE00000232000236110BC08BC02B0184710B5F5 +:10EEF0000400006800F08EF9200010BD10B50A0073 +:10EF0000002103F045FC10BD10B504000868206026 +:10EF100000F076F9200010BD70B50B6804000068A1 +:10EF20000D00984205D000F075F92868206000F0C7 +:10EF300067F9200070BD10B50068418883880630ED +:10EF40005943FFF7DBFF10BD10B504000023ECF7B9 +:10EF500099FB200010BD10B50400ECF793FB2000D6 +:10EF600010BDF0B587B004910CA909780700059190 +:10EF7000016800200391498801918A4277DA039958 +:10EF800089888B4273DA049C2468A4466488151926 +:10EF9000029485426BDD6446A4881E19864266DDB4 +:10EFA000002A03DA00952800019D03E00198029DE4 +:10EFB000801A0090A84200DD0095002B03DA8E42F3 +:10EFC00005DD0E0003E0CE1AA64200DD26006046F5 +:10EFD0000024D117554206302940A34202DA029C90 +:10EFE00064425C43641804190398111C0630002A1B +:10EFF00000DA0021002509B2AB4201DD019D5D432D +:10F00000059B69184518002B27D000221000B2423A +:10F010002DDA002300998B4206DAE15C002901D049 +:10F02000E95401300133F5E7049B01321B68019379 +:10F030005B88E4183B685B88ED18E8E7210028004E +:10F04000009A03F087FB049B1B6802935B88E4181B +:10F050003B685B88ED18019B01330193019BB34230 +:10F06000ECDBF043009BC01730404343180007B06F +:10F07000F0BDF0B587B000AF09687B613B6BB8604D +:10F080003961D418786B7B6949881B188C4201DA86 +:10F09000002C00DC0C0038698688B34202DA002BB1 +:10F0A00000DD1E003300684663430733DB08DB00E6 +:10F0B000C31A9D4678697B6041433B6989180633D2 +:10F0C0005D186B46FB607B699E420EDD29002200C5 +:10F0D000F86803F03FFB3B695B88ED18FB689B1900 +:10F0E000FB607B6901337B61EDE7B86832B221B226 +:10F0F0007B68ECF7C7FABD46B86807B0F0BD10B53D +:10F100000400096804200A5E8B1D0220095E2000AD +:10F11000ECF7B8FA200010BD10B50400006800F04C +:10F1200079F8200010BD10B504000868206000F0D8 +:10F1300067F8200010BDF8B5D443E4171440070069 +:10F1400020000C301E000D00ECF790F8386000F045 +:10F1500050F83B681C7238684660002D04D00930B6 +:10F160002200290003F0F6FAF8BD002310B50400D0 +:10F170001A001900FFF7DFFF200010BD002310B5B3 +:10F1800004000A001900FFF7D6FF200010BD10B5DB +:10F190000400FFF7D0FF200010BD70B50B6804001D +:10F1A00000680D00984205D000F034F8286820600F +:10F1B00000F026F8200070BD0368096810B5012032 +:10F1C0008B420CD01C7A0A7A0020A24207D1093364 +:10F1D0001800093103F0AFFA43425841C0B210BDE4 +:10F1E0000068093070470368187A704703685868E8 +:10F1F000704703230380704710B5ECF755FB10BD33 +:10F2000010B50400ECF750FB002802D1238802332C +:10F21000238010BD10B50400ECF746FB002809D18F +:10F220002388023B9BB2012B01D0238002E0200007 +:10F23000ECF752F810BD036870B5040001811B6A39 +:10F240009847236805005B692000984720812800C3 +:10F2500070BD00897047036870B5040081721B6A35 +:10F26000984723680500DB6920009847A0722800B2 +:10F2700070BD807A7047704710B5040003F045FAFE +:10F28000200010BD0C300EC80800524348435B43B9 +:10F290008018C01870477FB50400FFF7F3FF250002 +:10F2A0009023060031351B0498422AD9638F002B26 +:10F2B00007D1013308221B216846FFF7F5FD012322 +:10F2C000638790239B049E4219D9A38F002B07D1FB +:10F2D000013309221B216846FFF7E6FD0123A387BE +:10F2E0008023DB049E420AD9E38F002B07D1013330 +:10F2F0000A221B216846FFF7D7FD0123E38700237D +:10F300002B702B78042B02D801332B7003E00023E1 +:10F31000E387A38763872000ECF7C0FB021E0B2A5C +:10F3200013D02300A18E3033814204D11A78042AED +:10F3300004D8013201E00022A0861A70A28E618EEC +:10F34000914208D01B78042B05D9628601231B212A +:10F350006846FFF7A9FD7FBD30B50400036A8BB096 +:10F36000009302AD416A8269C369280001F00DFE75 +:10F3700023000C3307CD07C30222A3792000934357 +:10F38000A371FFF788FF0123A1881A0006A8FFF7E1 +:10F390008BFD00200BB030BD70B50C0005000B6874 +:10F3A00008005B6A984721002B000C3115C915C372 +:10F3B000280070BD10B5040003685B6A9847E068D8 +:10F3C00010BD10B5040003685B6A9847206910BD42 +:10F3D00010B5040003685B6A9847606910BD10B5FA +:10F3E000040003685B6A9847A3799B0702D4200056 +:10F3F000ECF71CFCA06A10BD10B5040003685B6A42 +:10F400009847A3799B0702D42000ECF70FFCE06A31 +:10F4100010BD408E704710B50400ECF7ABFC200027 +:10F4200003F073F9200010BD0630C1777047012347 +:10F43000807918407047036870B5040001811B692A +:10F440009847236805009B69200098472081280081 +:10F4500070BD00897047704710B5040003F055F97E +:10F46000200010BD30B50400436BC26801699A1AD0 +:10F4700083698BB05A43836B92125B1AC1694263F2 +:10F480004B439B128363C16B406902AD091A206A2A +:10F4900041438912E16300912800216C01F075FD60 +:10F4A0002300283307CD07C30123A1881A0006A82B +:10F4B000FFF7FAFC00200BB030BD002310B58371BC +:10F4C000643303810368040081801B69984702222A +:10F4D000A3799343013A1343A37110BD84B030B5AF +:10F4E000069303000491059204AC0C3326CC26C38A +:10F4F00026CC26C322681A600222837913438371C3 +:10F5000030BC08BC04B0184702238079184070470B +:10F5100080220023D2008261C26102620222C360A3 +:10F52000036143614362837993438371704741640C +:10F53000704773B50C00050016000B680800DB6906 +:10F540009847E36B280001960093626BA36B216CD4 +:10F5500001F0DCFC280076BD70B50C0005000B68DE +:10F560000800DB69984721002B00283115C915C315 +:10F57000280070BDF0B587B0010003A8FFF7ECFFCD +:10F580000398F8F715FC040004980D00F8F710FC38 +:10F59000060005980F00F8F70BFC2200009001917F +:10F5A0002B0020002900F7F7DFFD320004000D00DA +:10F5B0003B0030003900F7F7D7FD02000B002000B8 +:10F5C0002900F6F781FE009A019B04000D0010004F +:10F5D0001900F7F7C9FD02000B0020002900F6F71B +:10F5E00073FEFAF7D3F8F8F7ADFB07B0F0BD10B52E +:10F5F00004000368DB699847A06A10BD10B50400D9 +:10F600000368DB699847E06A10BD10B50400036821 +:10F61000DB699847206B10BD82B030B585B0089289 +:10F620000500082202A8099303F094F8039B029CAA +:10F630005810DB0701D52B581C592D180AA9082290 +:10F64000684603F087F8089A099B2800A04705B090 +:10F6500030BC08BC02B01847F8B50A6803680E0051 +:10F660000700981AF6F7AAFD72687B68051C981ABD +:10F67000F6F7A4FDBB68041CB068181AF6F79EFDE7 +:10F68000291C061C281CF6F7DDFA211C051C201C71 +:10F69000F6F7D8FA011C281CF5F794FF311C041C5E +:10F6A000301CF6F7CFFA011C201CF5F78BFFF8BDD4 +:10F6B000F0B585B0019002910392FFF7CDFF0127CD +:10F6C000041C061C039B9F4217DA0C217943029B02 +:10F6D00001985918FFF7C0FF051C011C201CF5F705 +:10F6E00001FE002800D02C1C291C301CF5F7E6FD7B +:10F6F000002800D02E1C0137E4E7211C301CF6F74F +:10F70000B5FB05B0F0BDF0B58BB009938023DB00ED +:10F710000025C36003614361002304000C270791A7 +:10F72000089205604560856085610293119B9D424A +:10F7300018DA39006943109B07A85918FFF78CFFA6 +:10F74000F8F7B0FBFAF722F8F8F7FCFAF6F736FD0F +:10F75000061C011C0298F5F7B1FD002800D00296A6 +:10F760000135E3E700260023109D059301960096DE +:10F77000371C059B119A93425EDA290007A8FFF710 +:10F780006BFFF8F78FFBFAF701F8F8F7DFFB011CC6 +:10F7900003900298F6F78CF8FE218905F6F766FBD0 +:10F7A0000490381CF6F7E8FC07000498F6F7E4FC30 +:10F7B000874200DA07003800F6F700FD2B68079A49 +:10F7C000071C981AF6F7FAFC0399F6F771F840004F +:10F7D00004994008F6F736FA011C0098F5F7F2FE96 +:10F7E000089B00900693069A6B68981AF6F7E6FC59 +:10F7F0000399F6F75DF8400004994008F6F722FAFD +:10F80000011C0198F5F7DEFEAB68019009980C35F4 +:10F81000181AF6F7D3FC0399F6F74AF84000049952 +:10F820004008F6F70FFA011C301CF5F7CBFE059BDC +:10F83000061C013305939CE70099081CF6F702FAB1 +:10F840000199051C081CF6F7FDF9011C281CF5F7A9 +:10F85000B9FE311C051C301CF6F7F4F9011C281CFC +:10F86000F5F7B0FEF8F71EFBF9F790FFF8F76EFB1F +:10F87000051C011C0098F6F71BF8391CF6F7E2F995 +:10F88000FE218905F5F79EFE8921C905F6F7DAF90B +:10F89000F6F772FC291CE0600198F6F709F8391CAC +:10F8A000F6F7D0F9FE218905F5F78CFE8921C90507 +:10F8B000F6F7C8F9F6F760FC291C2061301CF5F753 +:10F8C000F7FF391CF6F7BEF9FE218905F5F77AFE38 +:10F8D0008921C905F6F7B6F9F6F74EFC079B60617A +:10F8E0002360089B029800936360099BA360F6F76E +:10F8F00043FCA06120000BB0F0BDF0B50025040072 +:10F9000017000B002E0028002A0091B00791BA4280 +:10F9100008DA1968013240185968761899680C336A +:10F920006D18F4E73900F5F78DFB390020603000E1 +:10F93000F5F788FB390060602800F5F783FB3A0093 +:10F94000A06007992000FFF7B3FE00260DAB0890DA +:10F95000069605960393C8235B420493C8235B4233 +:10F960000293C8235B4201932200039B23CA23C353 +:10F970002268049B9446039A6344136062681D00E6 +:10F980009446029B039A63445360A2680993944689 +:10F99000019B039A6344936007993A0003980A9382 +:10F9A000FFF786FE0B90011C0898F5F79BFC0028DA +:10F9B00005D0099B0A9E06930B9B05950893019B16 +:10F9C000C83301931A00C8235B009A42CCD1029B32 +:10F9D000C83302939342C4D1049B029AC833049360 +:10F9E0009342BBD1059B2268934206D16368069A75 +:10F9F000934202D1A368B34205D0059BA660236061 +:10FA0000069B6360A7E7200011B0F0BD70B504004D +:10FA10000D00160086B003A8FFF76FFF20000196C7 +:10FA200000950399049A059BFFF76DFE200006B030 +:10FA300070BD10B518C96210E10701D58158CB58C7 +:10FA40008018984710BD10B50021406C02F0A5FD4C +:10FA500010BD10B50400ECF79BFE200002F055FE2F +:10FA6000200010BD10B50400ECF784FE200002F069 +:10FA70004CFE200010BD70B5050004007435012156 +:10FA80002800EBF7C1FE2200563213780133DBB2B7 +:10FA90001370E17901318B4225D1002326001370C8 +:10FAA000226D54360221525E33882021934205DABA +:10FAB000200019B25030FFF7DFF90100E27900238E +:10FAC0002800EBF757FE226D33880221525E9342E5 +:10FAD00007DD2300002248331A702000ECF762FF94 +:10FAE00001E00133338070BD70B505000600826D02 +:10FAF0005C350221525E2B8804007436202193422B +:10FB000004DA19B25830FFF7B7F9010000233000CA +:10FB10001A00EBF72FFEA26D2B880221525E934252 +:10FB200007DD2300002248331A702000ECF73AFF6B +:10FB300001E001332B8070BD73B504000600250081 +:10FB4000743630006435FFF7F6F90023EA5E2100D1 +:10FB50000023603100933000FFF703FA002804D13E +:10FB600023006C331B78002B04D1230066331B78F1 +:10FB7000002B07D12300002248331A702000ECF735 +:10FB800011FF06E02A885BB29B182B8001236C349E +:10FB9000237073BDF0B50600002105000400663631 +:10FBA000006E7156408864350023EA5E4B1D1B1AB7 +:10FBB000200085B06C3003909A4202DC0378002B61 +:10FBC00024D127007437002A04DD494209B23800E5 +:10FBD000EBF71AFE0023EA5E210000236031009358 +:10FBE0003800FFF7BEF90023F356002B05D12200A1 +:10FBF000483213702000ECF7D5FE0123039A1370EE +:10FC000000222B88B256D3182B800DE025004835F2 +:10FC10002B78062B03D120007430FFF78CF90023DA +:10FC200020002B70ECF7BEFE05B0F0BD70B50500EE +:10FC300048352B780400002B33D0EBF7C3FB2300AF +:10FC40004C331A881018220080B218804A32128869 +:10FC5000824226D800221A802B78022B02D1200063 +:10FC6000FFF709FF2B78032B02D12000FFF73CFFA1 +:10FC70002B78042B02D12000FFF75EFF2B78052B99 +:10FC80000BD02B78062B08D02B78072B09D100231B +:10FC900020002B70ECF786FE03E02000FFF77AFFD0 +:10FCA000F2E770BD1FB5036F827A9B6804000133D1 +:10FCB0009A4207D18188012302226846FFF7F4F8AF +:10FCC000002306E0ECF7F4FD2000FFF7AFFFA37A76 +:10FCD0000133A3721FBD10B583790400DB0720D563 +:10FCE000027B022A02D1FFF7DDFF1AE0837A016F5F +:10FCF0000133DBB2837289688B4201D100238372A6 +:10FD0000002A02D12000ECF7D3FD237B012B05D183 +:10FD1000637300232000A373ECF7AEFC2000FFF711 +:10FD200085FF10BD70B504000D1E022D06D1EBF746 +:10FD300049FB052802D00520EBF7F6FA237B022BBE +:10FD40000CD1022D0AD0A66E002E05D03000EDF7A2 +:10FD500023F9300002F0D9FC0023A366257370BD9F +:10FD6000007B7047407A7047F0B5837987B0040014 +:10FD70000D00DB0702D5002902D035E0002933D081 +:10FD8000102100220127206F41568368CB188B4237 +:10FD900004DD3E008E4001313243F8E7112100239B +:10FDA00001274156C0680818884204DD3E008E4095 +:10FDB00001313343F8E71A43002D08D00123002115 +:10FDC00001A8F4F7B5FC0122A37913430BE02B0043 +:10FDD000290001A8F4F7ACFC290001A802F0A7FB58 +:10FDE0000122A3799343A37107B0F0BD10B501219F +:10FDF000FFF7BAFF10BD10B50021FFF7B5FF10BD2A +:10FE000010B57430FFF797F810BD052313B50193B3 +:10FE100000930023040074311A00FFF72AF9200030 +:10FE200016BD70B5037B0400022B0AD00221FFF738 +:10FE300079FF482002F057FC0500216FEDF764F8C8 +:10FE4000A566A06E00F0E3F870BD10B50400F3F7EE +:10FE50000BFF00232000237510BD1FB503AC63709A +:10FE600000232270009322000233ECF769FF04B0F4 +:10FE700010BD1FB50F2401236C4400932300ECF741 +:10FE80006FFF002800D1207804B010BD70B50400C9 +:10FE900016001D0003220F23EDF788FA2000310021 +:10FEA0000F2302221030EDF781FA200029000F23E2 +:10FEB00001222030EDF77AFA200004990F23042262 +:10FEC0003030EDF773FA200005990F2305224030FA +:10FED000EDF76CFA200006990B2311225030EDF754 +:10FEE00065FA200007990B230C226030EDF75EFACB +:10FEF0000B2320001A0008997030EDF757FA200004 +:10FF000009990B2312228030EDF750FA20000A994C +:10FF10000B230A229030EDF749FA20000B990F23AA +:10FF20000622A030EDF742FA20000C990B231A228A +:10FF3000B030EDF73BFA20000D990B231422C030AE +:10FF4000EDF734FA20000E990B231722D030EDF78D +:10FF50002DFA20000F990B231622E030EDF726FA38 +:10FF6000200010990B231522F030EDF71FFA601CCA +:10FF700011990B231022FF30EDF718FA20001130F1 +:10FF800012990B230022FF30EDF710FA20002130E8 +:10FF90000B231E221399FF30EDF708FA200070BDE5 +:10FFA00010B518C96210E10701D58158CB588018E7 +:10FFB000984710BD82B030B585B008920500082280 +:10FFC00002A8099302F0C6FB039B029C5810DB07B2 +:10FFD00001D52B581C592D180AA90822684602F091 +:10FFE000B9FB089A099B2800A04705B030BC08BCA3 +:10FFF00002B0184770B504000D001822002102F06D +:020000040003F7 +:10000000C7FB2900200002F0DBF9200070BD036867 +:10001000426803219A18836810B5D018F5F712F8D2 +:10002000A92352215B00FF311A00884204DC083A00 +:10003000FF3A904200DD0200FF2008219B1A58433E +:10004000FF31F4F7FFFF10BD0069002904DD00282F +:1000500002D00139406AF8E7704710B50400EDF7A7 +:100060008DF8200002F051FB200010BDF7B5838809 +:1000700004005A070FD59A0648D4DA060BD50100BA +:1000800008221831684602F065FB22696369200086 +:10009000FEF730FE3AE00422022601271343A38034 +:1000A000A38833420BD0210008221831684602F0A1 +:1000B00051FB22696369A06800F0F4FE10E03B4246 +:1000C00008D0E368206900936169A269E369A568C3 +:1000D000A84705E020696169A269E369A568A847A6 +:1000E0001022A38813420ED0256A002D0BD02900C0 +:1000F000A01802F02FFB2B692800236202F005FBF9 +:10010000EAF726FFCCE704229343A380F7BD030060 +:1001100072B64069002807D002695A61002A00D1EE +:100120009A61DA8B013ADA8362B67047F7B5002537 +:1001300007002E000469002C1BD0A288636A11B24C +:10014000002914DA04210A4211D1002E01D13B61A9 +:1001500000E07362636A20000193FEF7C1FD200096 +:1001600002F0D3FA340001352600019CE3E7019345 +:10017000FAE72800FEBD70B5012286B004000D002C +:100180008669EDF739F8002827D1E38B092B24D8AD +:100190002900102202A802F0DDFA182002F0A3FACA +:1001A000050004A90822684602F0D4FA029A039BCB +:1001B0002800FEF789FE72B6002E03D163696561DF +:1001C0002B6102E033692B6135612B69002B00D173 +:1001D000A561E38B0133E38362B606B070BD82B0E4 +:1001E00010B502A902920393FFF7C5FF002010BCCF +:1001F00008BC02B0184770B50500FFF797FF28004C +:10020000FFF785FF041E0BD0010000222800ECF749 +:10021000F3FF200002F079FAEAF760FE0028EED141 +:1002200070BD82B030B585B008920500082202A8E2 +:10023000099302F08FFA039B029C5810DB0701D54B +:100240002B581C592D180AA90822684602F082FA78 +:10025000089A099B2800A04705B030BC08BC02B032 +:100260001847028903008A4202D18079012305E000 +:10027000428900208A4202D19879022318407047AF +:10028000028903008A4202D18079042305E0428971 +:1002900000208A4202D198790823184070470289C9 +:1002A00003008A4202D18079102305E042890020B0 +:1002B0008A4202D19879202318407047038910B5EB +:1002C0008B4207D183790124002A01D0234300E027 +:1002D000A343837143898B4207D183790221002A8A +:1002E00001D00B4300E08B43837110BD038910B52F +:1002F0008B4207D183790424002A01D0234300E0F4 +:10030000A343837143898B4207D183790821002A53 +:1003100001D00B4300E08B43837110BD038910B5FE +:100320008B4207D183791024002A01D0234300E0B7 +:10033000A343837143898B4207D183792021002A0B +:1003400001D00B4300E08B43837110BD82B0F0B548 +:1003500089B00E920F93078995B20400BD4200D177 +:1003600047890EAB5E88022E23D0052E0FD0012EBA +:100370006FD1290020003200FFF7A0FF39002000D4 +:10038000FFF76FFF002864D0A18833000CE029003C +:1003900020000122FFF7AAFF39002000FFF770FFBD +:1003A000002856D00123A188320004A8FEF77CFD66 +:1003B0004FE039002000FFF754FF002815D032002D +:1003C000A18801236846FEF76FFD29002000FFF792 +:1003D00057FFA68800282DD039002000FFF750FFD6 +:1003E000002827D00123042226E029002000FFF75F +:1003F00056FF00280ED1267B012E0BD129002000AC +:10040000FFF73EFF002821D033000422290004A872 +:10041000FEF74AFD290020000022FFF74FFF2900C8 +:1004200020000022FFF762FF002229002000FFF7D2 +:1004300075FF0EE001230322310004A8FEF734FD0E +:10044000012239002000FFF769FFE3E733000322B0 +:10045000DCE709B0F0BC08BC02B018470173704774 +:10046000032380791840033843425841704710B540 +:1004700018C96210E10701D58158CB5880189847F8 +:1004800010BD70B5837904001B0706D5806800F0A5 +:100490009BFD0E23E35683420FD02000ECF794FF20 +:1004A000082002F020F90E216156050000F080FDC1 +:1004B0000822A379A5601343A371002070BDD0B5B5 +:1004C000040086B08AB20023818802A8FEF7ECFC03 +:1004D000049E059FA06800F0FFF903000B430AD0BB +:1004E000049A059B00920193121A8B4102A8049270 +:1004F0000593EBF739F832003B00A06800F0E9F90A +:1005000006B0D0BD1FB5837904005B0602D5052176 +:10051000FFF7D5FFA3799B0605D5A1880123022209 +:100520006846FEF7C1FC1FBD1FB5837904005B065A +:1005300002D50421FFF7C3FFA3799B0605D5A18847 +:10054000012303226846FEF7AFFC1FBD702310B5E0 +:1005500082791A4201D0ECF737FF002010BD7047B6 +:1005600010B5040002F0D1F8200010BD30B5040031 +:1005700085B02569002D1ED0EA78012A06D0022A0E +:1005800009D12000203000F05EF80AE02000183089 +:1005900000F017F805E092B201231E216846FEF72D +:1005A00083FC23699D42E4D12000EDF753FA280033 +:1005B00002F0ABF8DDE705B030BD00230160436019 +:1005C00070471FB504000068EDF744FA0023626825 +:1005D00043629A4201D160600BE0516A002902D067 +:1005E00001330A00F9E7032B02DD02F08EF806E082 +:1005F000506201231D211A006846FEF755FC1FBDFD +:1006000082B070B58CB0119303781092002B11D189 +:10061000132201A90A708B70123A02334A70CB7010 +:1006200010AC02AB64CC64C31A002368136040684A +:10063000EDF724FA0CB070BC08BC02B018470023D8 +:1006400041600370704770B504004068EDF702FA2E +:100650000123050023700430EAF786FF00232800F9 +:10066000237002F052F870BD10B518C96210E1078E +:1006700001D58158CB588018984710BDF8B50E00A9 +:100680001C00150006AA108807AA1788B84208D0CF +:10069000335C290023700130F4F7BAFD013488B2CD +:1006A000F4E7F8BD4C300078704703000200503387 +:1006B0004E321B8811888B4204D91188023A107877 +:1006C000401800E01088C01A7047020003005C3236 +:1006D0005A3311881B88994205D91188043A107839 +:1006E000C318581A01E01088181A704710B5040092 +:1006F000012905D12000FFF7E8FF0028FADC04E01B +:10070000022902D10020EAF78DFC10BD10B504309B +:100710000022F3F785FC10BD10B509681300022410 +:100720000A5F0431EDF70AFC10BDF7B5150000AF04 +:100730007B602B000E0069460833DB08DB00CB1A18 +:100740009D46013200210400684602F021F87B68D2 +:100750002A0069463000EDF783FC002803DC200006 +:10076000EAF7E8FE04E002B269462000EAF7B8FEC4 +:10077000BD462000FEBD13B50C0001A8EEF722F81F +:10078000210001A8EEF730F813BD73B50D00140079 +:100790001E0001A8EEF716F833002A00210001A878 +:1007A000EEF75CF873BD07B5019280220091520507 +:1007B000136952696946133A5A430223FFF7E5FF6A +:1007C00007BD84B010B504928022039105935205B1 +:1007D000116953695269113B133A4A4359430F9BBC +:1007E0005B1AD21803A90C23FFF7CFFF10BC08BC7B +:1007F00004B0184710B50400EDF7E6FD200010BD69 +:100800008023F7B55B051A695D690191113D554378 +:10081000EDF7DAFD061E1FD0302001F064FF302214 +:1008200000210400002701F0B3FF0835B7420DDABC +:1008300029003022200001F08DFF2100019801F0F5 +:10084000DDFF002802D030350137EFE72000B74246 +:1008500002D101F05AFF0020FEBD10B50968043135 +:10086000FFF7CEFF10BD10B509680431EDF7DCFDD0 +:1008700010BD52DF704712DF7047704710B504009B +:1008800001F043FF200010BD10B50400EAF7D4FDCD +:100890000022A46801238A4202D1844200D91300B5 +:1008A000180010BD10B50400EDF724FF1022A35E60 +:1008B0001222A05E181A10BD10B5EDF71BFF10BD77 +:1008C00010B50400EDF75EFF200001F01EFF2000D0 +:1008D00010BD026543657047416D006D704729DFAB +:1008E000704728DF7047002030B51C1A002C06DD49 +:1008F000155C0C5C0130AC43F7D0012000E0002017 +:1009000030BD10B503685B6A984710BD10B5040090 +:10091000EEF7DAF8200001F0F8FE200010BD10B567 +:10092000C9B20D22FFF7A5FAC7384342584110BD9E +:1009300010B503685B6A984710BD10B50400EEF768 +:1009400007FA200001F0E1FE200010BD10B5C9B289 +:100950000D22FFF78EFA5A384342584110BD10B5A8 +:100960000368DB69984710BD10B50400EEF766FA1E +:10097000200001F0CAFE200010BD10B5C9B2072248 +:10098000FFF777FAC4384342584110BD10B50368E9 +:100990005B6A984710BD10B50400EEF769FB2000B4 +:1009A00001F0B3FE200010BD10B5C9B20F22FFF751 +:1009B00060FA33384342584110BD10B50368DB6913 +:1009C000984710BD10B50400EEF70CFC200001F0B4 +:1009D0009CFE200010BD10B5C9B24F22FFF749FAA6 +:1009E00040384342584110BDA7DF7047A9DF704728 +:1009F000AADF704768DF704710B50368002B01D08D +:100A00000800984710BD10B50368002B01D00800FE +:100A1000984710BD10B50368002B01D00800984717 +:100A200010BD10B50368002B01D00800984710BD19 +:100A300010B50368002B01D00800984710BD10B511 +:100A40000368002B01D00800984710BD10B50400C2 +:100A5000EEF736FC200001F058FE200010BD1FB557 +:100A60000123FA211A0089006846FEF71DFA05B035 +:100A700000BD0022431C0270C11D1A7001338B425D +:100A8000FBD1704770B51D000E001100C27F04003D +:100A9000931C5B1901201F2B12DC2B18A354E37F3E +:100AA0002A001B18DBB2E377E654E07F0130C0B2C6 +:100AB000E077201801F04EFE0020E37FED18E57787 +:100AC00070BD0200010010B5036834320A319B6F1B +:100AD000984710BD10B50400FFF7F3FF2368211DF0 +:100AE000DB6F2000984710BD10B500220400027093 +:100AF000431C11341A700133A342FBD1418210BD53 +:100B000037B50D00F0F7B6F86B46DA1D0123040087 +:100B100019000A301570EEF7CFFC002802D1200032 +:100B2000FFF7CFFF3EBDF8B50D0016001F00F0F730 +:100B3000A1F80400092D03D1036831005B6B9847CD +:100B400020003B00320029000A30EEF7B5FC0028F7 +:100B500002D12000FFF7B5FFF8BD70B5F0F78AF8B5 +:100B600005000A3504001F220021280001F010FEB4 +:100B700000232000EB77FFF7A4FF70BD806810B55D +:100B8000002803D0F0F776F8FFF7A4FF10BD70B58A +:100B90008AB003AD06002800FFF76BFF13206844FE +:100BA000FFF767FF1A206844FFF763FF21206844BE +:100BB000FFF75FFF042301ACB06863710195F0F7A4 +:100BC00079F8036821001B699847A0790AB070BDC5 +:100BD00010B504001830FEF72AF90123636110BD37 +:100BE000022370B5436104000D00EAF725FC206183 +:100BF000002D07D008236269134304226361A3799F +:100C00001343A37170BD8023F0B55B0585B0080068 +:100C10005F6E0291FFF7F4F8012304240525019388 +:100C200029003800F4F70AFA08000199F4F780F96E +:100C30000523052200265D43019B039053433F1A81 +:100C40000193039B01339E420ADA042302989A1B04 +:100C500012B221B2FB337430EAF7B8FC0136F0E788 +:100C6000013CDDD205B0F0BD0130C07F704737B523 +:100C700004680D00002C0ED0011D0822684601F00A +:100C800069FD019A009B5010D20701D52258D35814 +:100C900020182900984737BD10B54A88838A90B03C +:100CA0000C009A4219D10B89002B16D0CB681B7807 +:100CB000012B12D18068EFF7DDFF036815215B6A15 +:100CC0009847FA20800001F0F3FB238804A80380F2 +:100CD000002301A90B70F2F7E7FD10B010BD7047BB +:100CE00010B5040001F011FD200010BD37B50468F7 +:100CF0000D00002C0ED0011D0822684601F02AFDCF +:100D0000019A009B5010D20701D52258D3582018C1 +:100D10002900984737BD37B504680D00002C0ED068 +:100D2000011D0822684601F015FD019A009B501034 +:100D3000D20701D52258D35820182900984737BD2B +:100D400082B030B585B008920500082202A8099348 +:100D500001F000FD039B029C5810DB0701D52B58C6 +:100D60001C592D180AA90822684601F0F3FC089ABC +:100D7000099B2800A04705B030BC08BC02B018474A +:100D800013B5836A4A88DB8B04009A420ED1838DA7 +:100D9000013383858068EFF77DFFA36A2200D98B3A +:100DA0000023046800931832E468A04713BD70B5AF +:100DB0000400013025000300002611351E700133A8 +:100DC0009D42FBD10023638201332370002A08D1A6 +:100DD0000B001033994207D0013B1A7802700130A2 +:100DE000F8E7102201F0BFFCA37B627B1B021343D8 +:100DF0002000638270BD10B500F000F9806D10BD59 +:100E000082B010B50400806803930292FFF7F3FFED +:100E100083070ED502AB1A88A068A2825B88E382A2 +:100E2000EFF738FF22000368218C14325C69042339 +:100E3000A04710BC08BC02B0184737B504680D00C5 +:100E4000002C0ED0011D0822684601F083FC019A97 +:100E5000009B5010D20701D52258D35820182900E2 +:100E6000984737BD82B030B585B00892050008229A +:100E700002A8099301F06EFC039B029C5810DB074B +:100E800001D52B581C592D180AA90822684601F0D3 +:100E900061FC089A099B2800A04705B030BC08BC3B +:100EA00002B0184782B073B50400061D069208A967 +:100EB00008226846079301F04DFC65693100069AE7 +:100EC000079B2068A84773BC08BC02B0184702689B +:100ED00010B594460A680023944507D104310430C4 +:100EE000102201F028FC43424341DBB2180010BD40 +:100EF00010B5EFF7BBFD406810BD10B5EFF7B6FDBC +:100F0000006810BD017042704360704782B0F0B558 +:100F100005920200069308AB1B7805ACE0CCE0C25A +:100F2000002B2ED04A78002A05D0069A5242426001 +:100F3000079A524282604A68022A08D0032A0DD0DA +:100F4000012A10D1026841685242016004E002683F +:100F50005242026042685242426004E042680168C4 +:100F6000524202604160012B04D0022B09D1436838 +:100F70005B4202E0426803680260436083685B4250 +:100F80008360F0BC08BC02B0184782B037B50400DB +:100F9000180007930B7806920193089B00930300B7 +:100FA0002000FFF7B3FF20003EBC08BC02B018478A +:100FB00010B50400F3F7D6FA200010BD10B50400F8 +:100FC00001F08CFA200010BD407840B2704702005A +:100FD0000B00F0B5126889B0019203AA15001E003B +:100FE0004068016809688C4692CE92C5DB68019919 +:100FF000D36000231361E04709B0F0BD10B5EFF7EF +:1010000039FE10BD02207047022070470020704753 +:10101000002070470220704702207047022070476E +:10102000022070470220704702207047022070475C +:10103000022070470220704702207047022070474C +:101040000220704702207047002313607047002081 +:10105000704702207047022070470220704702202C +:101060007047022070470020704700207047002022 +:1010700070470220704702207047416070478160CE +:101080007047C1607047016170474161704702203D +:1010900070470220704702207047022070470220EC +:1010A00070470220704702207047022070470020DE +:1010B0007047022070470220704700207047704739 +:1010C00002207047022070477047022070470020BE +:1010D0007047704766DF704748DF70470079704798 +:1010E0000C3070470C30704710B5FFF7F5FF10BD9E +:1010F00010B50368002B01D00800984710BD10B54B +:101100000368002B01D00800984710BD10B5036894 +:10111000002B01D00800984710BD10B50368002BC4 +:1011200001D00800984710BD0823F0B597B002AA77 +:10113000137106AA029202AA137310000EAB049355 +:101140000C00F0F70DFB0023061E9E4202D0237117 +:10115000A37136E00500072702AB1B7BA37102AB2E +:101160001B79AB4213D96379AB4201D8257128E0D2 +:101170003800684323681818029B0193019AAB005A +:1011800099580135072201F0E5FAEDB2E7E725713C +:101190000727002502AB21791B7B6918AB420FD9C9 +:1011A000637999420CDA794323685918049B0193B7 +:1011B000019AAB009858013500F0C4F9EDB2E9E7A7 +:1011C0002171300017B0F0BD10B5F0F76FFA10BD07 +:1011D00010B508001100F0F79FFA10BD10B5080017 +:1011E0001100F0F775FA10BD10B5080011001A00D3 +:1011F000029BF0F7F1F910BD70B5040000680028FB +:1012000004D0056901F081FA2800F8E7206070BD7C +:1012100010B50400EFF710FE200001F076FA200070 +:1012200010BD10B50400EFF711FE200001F06DFABB +:10123000200010BD10B50400EFF712FE200001F0F1 +:1012400064FA200010BD10B50400EFF713FE200073 +:1012500001F05BFA200010BD10B50400EFF714FE9A +:10126000200001F052FA200010BD10B50400EFF785 +:1012700015FE200001F049FA200010BD10B5040051 +:10128000EFF716FE200001F040FA200010BD70B507 +:101290000400E3692362256A002D08D0EB68210071 +:1012A00028009847236A002BF3D01B69F2E720003F +:1012B0001C30FFF7A1FF28006560A560E56025618F +:1012C000656170BD10B5FFF7E2FF002800D0062071 +:1012D00010BD10B50400EFF7F5FD200001F015FA80 +:1012E000200010BD10B50400EFF7F6FD200001F05E +:1012F0000CFA200010BD10B50400EFF7F7FD200038 +:1013000001F003FA200010BD10B50400EFF7F8FD5E +:10131000200001F0FAF9200010BD10B50400EFF72D +:10132000F9FD200001F0F1F9200010BD70B50400B6 +:10133000E36A2363256B002D08D0EB6821002800A9 +:101340009847236B002BF3D01B69F2E720002C3069 +:10135000FFF752FF20000830FFF74EFF2000143047 +:10136000FFF74AFF20002030FFF746FF280070BD3E +:1013700070B5037904000920002B20D0F2F762FA3F +:1013800003000520002B1AD12500FC35A86B00288E +:1013900003D1286C002806D10AE003685B6A9847ED +:1013A0000028F6D00BE003689B6A9847002806D116 +:1013B00020000C3000F043FA002800D1207170BDED +:1013C000F7B5037907000E001400002B08D008229F +:1013D0000021684601F0DCF90A256B461D710CE01E +:1013E000F0F73AF805000C20002D0FD10123082258 +:1013F0003B712900684601F0CBF93000EFF718FC8B +:10140000E36800906946200098472800FEBD10B5AB +:101410000400EFF7A3FD200001F077F9200010BDD4 +:1014200010B51F220021040001F0B2F90023E37778 +:1014300010BD10B50020EFF7B1FE10BDFC30836B7E +:1014400070B50400002B07D19920800001F04BF902 +:101450000500EFF7C5FEA563A06B70BDFC30836B84 +:1014600070B50400002B07D19920800001F03BF9F2 +:101470000500EFF7B5FEA563A06B70BDF0B50400E5 +:1014800087B0E36B2364266C002E08D0F36821003C +:1014900030009847236C002BF3D01B69F2E7200043 +:1014A0003C30FFF7A9FE2000267166710C30FFF773 +:1014B000A3FE20001830FFF79FFE20002430FFF726 +:1014C0009BFE200001AD3030FFF796FE3100280072 +:1014D000EFF776FE23002A00443383CA83C3EB6808 +:1014E0003100236566652800EFF76AFE23002A00B5 +:1014F000583383CA83C3EB6831006366A66628004D +:10150000EFF75EFE23002A006C3383CA83C33000EA +:10151000EB68E667A36707B0F0BD70DF704771DF67 +:10152000704760DF7047704710B5F2F70DF9002083 +:1015300010BD70477EDF704768DF704710B500F060 +:1015400064FD10BD022310B50B708C330B713F3B53 +:101550004B712D338B714A1C043100F02DFD10BDF1 +:1015600070DF704771DF704772DF704773DF70475D +:1015700074DF704775DF704776DF704777DF70473D +:1015800078DF704779DF70477ADF70477BDF70471D +:101590007CDF70477DDF704788DF7047142070471D +:1015A00064207047A0208001704710B50400FFF749 +:1015B000DFFF0323002806D12300012158331A78C6 +:1015C0008A431A700300180010BD03000800FC21B4 +:1015D000583310B51C78214019703B218A4200D045 +:1015E0002839FFF7C9FF03005A1E934103205B42CD +:1015F000184010BD030010B5FE330A00D98C0368F3 +:101600001B6A984710BD10B50800FFF7BFFF030025 +:101610005A1E934103205B42184010BD10B50800CC +:10162000FFF7B2FF03005A1E934103205B421840AC +:1016300010BD080010B51100FFF79CFF031E00D07D +:101640000323180010BD13B50C001100012C06D89F +:101650006B460622581C01F07DF8002005E0A31E11 +:10166000012B01D9032007E001206B4669461C705D +:10167000FFF776FF0028F5D116BD37B568460D0097 +:101680001400FFF76FFF032300280DD1002D02D0B7 +:101690006B461B782B70231E06D06B460622591C06 +:1016A000200001F057F8002318003EBD080010B5D7 +:1016B0001100FFF76FFF031E00D00323180010BDB9 +:1016C00010B50800FFF75CFF031E00D003231800CD +:1016D00010BD10B50800FFF755FF031E00D003230F +:1016E000180010BD10B50800FFF748FF002398420E +:1016F00003D00533112800D0023B180010BD08208C +:101700007047B830017000207047B9300170002078 +:10171000704702207047B83000787047B9300078C1 +:101720007047002070470200030010B5F3321178B3 +:101730006C309B6F984710BD10B518C96210E10757 +:1017400001D58158CB588018984710BD112337B563 +:10175000080001AC23700D0001F05AF8290082B294 +:101760002000FFF715FF031E00D0032318003EBD25 +:10177000F8B506000D00002407273300BA331B78A4 +:10178000A3420ED96B79A3420BD9390061432B6870 +:10179000072258187118BB31013400F0DBFFE4B2A6 +:1017A000EBE72C710020F8BD10B50C00C97F0120BB +:1017B0001F290ED8002901D103200AE0D37F200081 +:1017C000FFF7D2FE0028F7D1208CFFF7D9FE0028C2 +:1017D000F2D110BDF8B503680700DB6C0D000C7981 +:1017E00098470323844228D8002307212879DAB2B6 +:1017F000904208D90A005A432C680133125D032A2B +:10180000F5D1042319E03E000024BA3634702B7958 +:10181000A34211D9072319003078614358432B683C +:1018200038185918BB30072200F094FF3378013480 +:1018300001333370E4B2EAE700231800F8BD10B5B5 +:101840000400EFF7B5FB00280AD123000122FE3384 +:101850005242DA84BA34463B18705870207000E067 +:10186000062010BDFE30C1847047FE30C08C70472A +:10187000A0DF7047A4DF7047A5DF7047A6DF704781 +:10188000A8DF7047F7B50D00160000210822684652 +:101890001F00089C00F07CFF6A4623883100280066 +:1018A00013800197FFF7E8FF0323002803D16B465D +:1018B0001B88238003001800FEBD70B586B015009C +:1018C0006A4600200E00941DD380EFF767FC036882 +:1018D0001B699847FFF7C9FF012302A98B700023FA +:1018E0000E808B80CD608C60FFF7C8FF83B2181E1E +:1018F00000D0052006B070BDF8B5040000200D0032 +:101900001600EFF74BFC03681B6998472368DF69F3 +:10191000FFF7ABFF330001002A002000B847F8BDF5 +:10192000F0B5D48B02001E000023457985B0F83253 +:101930009D4223D908321700083F3F88A74210D1A3 +:101940001F33DB00C3180E249A8802236C442380C3 +:10195000036803AD00949F682B00B847021E02D0B5 +:101960000DE00133E4E723880620022B07D12B8802 +:1019700010009B0703D00123337000E0042005B062 +:10198000F0BD10B50278002A09D10C781300002CA4 +:1019900013D1438A488A1B1A584243410CE0002362 +:1019A000012A0AD10A78012A07D1013101300F3208 +:1019B00000F0C1FE43424341DBB2180010BD70B5D8 +:1019C00004000D006368A360A068002807D0C36806 +:1019D00029009847A368002BF4D01B69F3E770BD7A +:1019E00010B5C368984710BD30B5150087B00429FD +:1019F0000ED0052917D0032925D144300100040059 +:101A000004A8F0F7E3F9049B002B18D1059B14E020 +:101A10005830010004006846F0F7D8F9009B002B0D +:101A20000DD1019B09E06C300100040002A8F0F721 +:101A3000CDF9029B002B02D1039BDB0703D52900C4 +:101A40002000FFF7CDFF07B030BDF0B50B888FB099 +:101A500005000C00502B0ED004D8012B25D0182BDC +:101A600032D00CE1522B2FD03FD3532B00D006E1C4 +:101A7000CE88052146E002000023CE884179FC3261 +:101A800099423ED90832100008380088B0420AD185 +:101A9000302120339B005A59531CDB7F0B4200D06E +:101AA000D2E02E392EE00133EAE70C7AEB682B61A5 +:101AB0002869002800D1E2E0C368210098472B691B +:101AC000002BF3D01B69F2E7A3880AAE33802B6B9F +:101AD0006B63686B002800D1D1E0C3683100984780 +:101AE0006B6B002BF3D01B69F2E78B79012B05D0D0 +:101AF000022B00D0C3E00E89072103E00E890621E6 +:101B000000E002212B0000206A79F8330090009851 +:101B1000824200D8B3E00833180008380088B04289 +:101B200014D1062958D0072913D03200022900D039 +:101B300096E0A3880AA90B804E80237A0B71A38BB1 +:101B4000CB80E38B20340B81CC6040E000980130E7 +:101B5000DCE71022002102A800F01AFEA38802AAE6 +:101B600013805680E38B06AF9380238C0021D380B3 +:101B700023001022223338000193049300F008FE62 +:101B800002233B70009B20339B005B591A002A32D2 +:101B900011780022914206D0180002A9DB6C403077 +:101BA000984702AB9A89A0883900BA80FFF768FE8F +:101BB000BB88002B63D1A3880AA90B804E80A37A2F +:101BC0000B71E38BCB80238C0B81019BCB602800B6 +:101BD0001430FFF7F4FE52E006AF10220021380067 +:101BE00000F0D6FDA3887E803B80A38B0AAE102236 +:101BF00000213000BB8000F0CBFD01233370009B3F +:101C000020339B005B591A0029321178002291423F +:101C100005D0180039002C309B6B9847BA89B280E8 +:101C2000BB89002B0BD1BA68002A08D00121B379F7 +:101C30000B43B371BB883381FB88F2607381A0884A +:101C40003100FFF71DFE1AE0A11CC97F0134E07FBF +:101C500009020843990607D50321840704D5D28BCE +:101C60002800FFF7C1FE0AE00421DB06F7D50123B7 +:101C7000010019400B00594259410331EFE70FB001 +:101C8000F0BD77DF704778DF70477ADF70477CDF21 +:101C90007047A2DF7047A3DF704763DF704710B55E +:101CA00086B06B46DC1D00232370C15C02AA9954E8 +:101CB0000133102BF9D121001000FFF7EEFF0023B4 +:101CC000984200D12378180006B010BDF0B5160078 +:101CD000302497B000931CAB04CB01901B88029179 +:101CE00003931EAB1B88344004931FAB1B780593F2 +:101CF00021AB1F8822AB1B78069323AB1B7807937D +:101D0000002C33D00322002108A800F041FD01255A +:101D1000022308AA937010212A0008A80A4302701F +:101D2000009A0D33501E08AA52789A43042818D8F6 +:101D3000F3F7F4F80305070C1100012107E0012176 +:101D40000AE001210A431340302208E002210A433D +:101D50001340102203E002210A43134020221343C0 +:101D600002E02A4313400B4308AA53700FAD1C2214 +:101D70000021280000F00CFD621E944108AB644273 +:101D800023402E706B61002F05D0209B002B02D0CA +:101D90006B602F816F8109AC03220021200000F0CD +:101DA000F7FC0120069B079A03400240DB0011016B +:101DB000DBB20B431A00059B0340180002231343B8 +:101DC0000343A37032231E421FD0009B581E0428D9 +:101DD0001BD80F2223789343F3F7A0F80305070CD1 +:101DE0001100012107E001210AE001210B4313400A +:101DF000302208E002210B431340102203E00221AD +:101E00000B4313402022134323700C231E421FD088 +:101E10000098013804281BD80F2263789343F3F706 +:101E20007DF80305070C1100012107E001210AE0FC +:101E300001210B431340302208E002210B431340E1 +:101E4000102203E002210B4313402022134363704E +:101E50000AAD14220021280000F09AFC029B2A00FF +:101E60000A936B469B890FA92B816B461B8A0198AD +:101E7000AB811C9B6C602B61249BFFF70AFF80B237 +:101E800017B0F0BDF0B589B000930EAB1B8805000C +:101E90000F001600019303220FAB002102A81C784B +:101EA00000F076FC012302221C40144302AA947025 +:101EB0001900102202A81143020003AC01705170F6 +:101EC00020001422002100F063FC02AB63606B462B +:101ED0001B88109A23816B469B882100280003975A +:101EE000A3812661FFF7D7FE80B209B0F0BD7FDF86 +:101EF000704782DF7047A7DF7047A9DF7047AADF0E +:101F0000704700207047002070470020704710B5D0 +:101F1000F0F720F810BD10B5F0F7D4F810BD10B5EB +:101F2000F0F72CF910BD002070470020704700200A +:101F300070470020704729DF704728DF704710B5D1 +:101F4000FFF7F9FFF0F7B4FE10BD10B5F0F720FE73 +:101F500080225205136911699BB20138584389B236 +:101F6000F2F7E6FFFFF7E9FFF0F7A2FE10BD2EDF64 +:101F7000704732DF704733DF70474CDF70472EDF2A +:101F8000704751DF704710DF704711DF704761DF26 +:101F9000704710B508001100FFF7CBFA10BDAADF9B +:101FA000704744DF704711DF704713DF704700DF71 +:101FB000704770474DDF704730B500230D001400A7 +:101FC0008DB06946C21AD27B5A540133102BF8D116 +:101FD00000210D2204A800F0DBFB6A462B7868463E +:101FE000D3776B789377AB785377FFF7E3FF2F23A3 +:101FF0006B441B7823702E236B441B7863702D2356 +:102000006B441B78A3700DB030BD30B5037804006D +:1020100085B00D000020022B16D1611C032201A8FF +:1020200000F098FB211D032203A800F093FB02AAF5 +:1020300003A92800FFF7C0FF032202A901A800F0AE +:102040007AFB43425841C0B205B030BDA6DF7047AD +:10205000036810B50400002B05D1C06800F018FA21 +:1020600001236060236010BD10B5040000680028E3 +:1020700004D0E06800F00CFA6368C01A10BD10B517 +:102080008468FFF7F1FF201810BD10B50400C06888 +:1020900000F0FEF900236060A36010BD002310B5BE +:1020A0000360436083600400F1F704FEE0602000F9 +:1020B000FFF7EBFF200010BD10B50400F1F7FAFCAC +:1020C000200000F022FB200010BD836980681B689F +:1020D0001840431E9841704710B5043000F004FAD0 +:1020E00010BD436910B50100002B04D10368002B1B +:1020F00006D0984704E00068002801D004319847D2 +:1021000010BD10B5012903D0022904D1383000E0F8 +:102110002030FFF7E6FF10BD10B503689B689847B5 +:1021200010BD10B50A000300011D006900F078F928 +:1021300010BD10B5011D006900F08EF910BDC36A15 +:1021400010B50100002B04D18369002B06D09847FD +:1021500004E08069002801D01C31984710BD10B5FB +:102160000400F1F7F9FC200000F0CFFA200010BDC8 +:1021700010B50400436842699918FFF7D2FFE36A7B +:10218000002B04D1A369002B07D0984705E0A06974 +:10219000002802D021001C31984710BD10B5040062 +:1021A000FFF7C7FF0023A361E36210BD70B50D0008 +:1021B0000400FFF7BEFF6561206900F069F9291886 +:1021C0002000FFF7AEFF70BD18234A1C5A43821847 +:1021D000926810B55943002A05D14118CB68002BED +:1021E00009D0984707E04318DB68002B03D041185B +:1021F00010311800904710BD70B50D000400043078 +:10220000F1F7CCFEE56370BD10B5043000F059F96C +:1022100010BD10B50C000430F1F748FF200010BDD0 +:1022200010B5FFF7F1FF10BD10B5FFF7F2FF10BDBD +:10223000704710B5040000F068FA200010BD70B5BA +:102240000D000400F1F7E4FC2900201DF2F708FD61 +:1022500070BDF0B585B01C000AAB060003911700F5 +:102260001D78F1F719FD01235D40009523003A0028 +:102270000399300000F0DCF9201A441EA04105B09B +:10228000F0BDF0B585B01C000AAB06000391170045 +:102290001D78F1F701FD01235D40009523003A0010 +:1022A0000399300000F081F9201A441EA04105B0C6 +:1022B000F0BD10B50120FAF7EDFC7047704710B57E +:1022C000FFF7FCFFFFF7F9FFFCF721F910BD10B590 +:1022D000002801D000F001F8FEE700B59BB0032113 +:1022E00002A800F06DF8022108A800F069F80121A9 +:1022F0000EA800F065F8102114A800F061F8059B05 +:10230000039A96201A60099A0C9B1A600F9A129BE6 +:102310001A60159A179B01921A6000F0C9F8069B83 +:10232000039A96201A60099A0B9B1A600F9A119BC8 +:1023300001921A60159A189B1A6000F0B9F8DEE74E +:102340000FB4012010B5FAF7A5FC70B50D0004001C +:102350001600F2F7D5F96B1C07D00021200000F021 +:10236000C9F83100200000F0BFF870BD70B54368B7 +:1023700004000D00002A01D0C26800E00269136069 +:102380002000012100F0B6F82900200000F0ACF890 +:1023900070BD10B50322FFF7D8FF10BD10B5FFF7D1 +:1023A000D4FF10BD70B50D0004001600F2F7A8F9B7 +:1023B0006B1C04D0320000212000FFF7D7FF70BD56 +:1023C00010B50022FFF7EEFF10BD70B504000D0040 +:1023D00003681B68984763681D6070BD036870B52B +:1023E000DB680400984763685A682368002A02D1B2 +:1023F0009B68984713E05B681568984763682D1AD7 +:102400005A68002D07DC916859601B68002BEAD0E0 +:1024100050689847E7E7236810681B69984770BDC4 +:1024200070B50D0072B64B60002346680A60746890 +:10243000002C05D02168511A02D42300A468F7E7C4 +:10244000002B05D1036875601B691000984700E0F8 +:102450009D60AC6062B670BD10B572B642685368DC +:102460008B420CD19B6853600268002B02D19368A9 +:1024700098470BE012691868904707E01300002B9B +:1024800004D09A689142F9D18A689A6062B610BD08 +:1024900010B503685B68984710BD70B50400F1F78C +:1024A000CFFC0500F1F7CCFC401BA042FAD370BD75 +:1024B000FA2310B59B005843FFF7EFFF10BD70479C +:1024C000704703681A00FC32D1680129FCD1002151 +:1024D000D160A322D2009858C0B2704710B540789E +:1024E00040B2F1F70FFF10BD10B5007840B200F018 +:1024F0000EF810BD002901D0012907D10023A02228 +:10250000C356D205C133FF339B0099507047A023B7 +:102510008000DB05C018E02310B50C24DB00C25896 +:102520008900A243C250C2581143C15010BDF8B532 +:1025300005000E00002401273B00A3402A691A422F +:1025400003D060B23100FFF7E2FF01341F2CF3D15A +:10255000F8BD30B5002903D001291DD1002311E0B9 +:1025600001220C0013008B4005691D4203D0056851 +:102570008B00EB181C6001311F29F3D10CE00133F3 +:102580001F2B09D00A009A4004691442F7D004684E +:102590009A00A2181160F2E730BD42680069136822 +:1025A00059400140594011607047F7B50192B1227E +:1025B0001F0003684910D200995080210122890030 +:1025C0005A50190000240600FC31CC601A607D1EB0 +:1025D000019BAC4213DA191900223000F2F7D0F84F +:1025E00000280AD03000F2F7C3F907003000F2F7F4 +:1025F0008DF93D1E1ADB250018E00134E7E7591973 +:1026000001223000F2F7BCF8002803D03000F2F7C6 +:102610007DF90BE0089B3D00002B07D03368FC33AD +:102620009A68002AFCD000223D009A602800FEBD76 +:10263000F8B51700B1221D000368D2004910995067 +:102640008022002492009C50012206009A60AC4235 +:1026500011DA395D3000F2F77FF8002809D0300038 +:10266000F2F754F93000F2F783F9031E0FDB230071 +:102670000DE00134EBE7069B002B04D03000F2F7AD +:102680005DF9002801D12B0001E001235B42180015 +:10269000F8BD82B00190C046C046C046C046C046A4 +:1026A000C046C046C046C046C046C046C046C046FA +:1026B000C046019B013B0193002BECD102B0704757 +:1026C0000023CB565A1C05D0834201D1486802E052 +:1026D0000C31F5E7180070470B0010B50100180029 +:1026E000FAF7C4FA10BD10B5041E00D10134200061 +:1026F000E8F7BCFD002807D1F2F70AFC002801D159 +:1027000000F007F88047F2E710BD10B5E8F7E4FDE8 +:1027100010BD10B50620FAF7F9FA0120FFF7D7FD32 +:10272000C9B28218904204D003788B4202D00130A3 +:10273000F8E70020704730B50024A24208D0035DBE +:10274000651C0C5DA34201D0181B02E02C00F4E7CD +:10275000002030BD002310B59A4203D0CC5CC45495 +:102760000133F9E710BD10B5884202D98B189842A1 +:1027700001D3002305E09B1A013A08D3995C8154E8 +:10278000FAE7934203D0CC5CC4540133F9E710BD9F +:1027900003008218934202D019700133FAE77047A0 +:1027A00070B504000D1E1F2D04D9162303600120EF +:1027B00040421EE0426C002A04D08B00D2181368FD +:1027C000002B08D1200000F015F82A00010020009D +:1027D000FAF7A6FA0DE00020012B0AD0591C03D10C +:1027E00017332360013004E0002428001460984768 +:1027F000200070BD10B5FAF7F7FD10BD02780B7818 +:10280000002A03D0013001319A42F7D0D01A704724 +:102810000023C25C0133002AFBD1581E704703001D +:1028200030B5002A0DD00C7801335D1E013A2C70B2 +:102830000131002CF5D19A189A4202D01C70013354 +:10284000FAE730BDF7B5170001938A680B6900906D +:102850000C00934200DA130022003B6043321278EE +:10286000002A01D001333B6023689B0602D53B68F8 +:1028700002333B60062523681D401ED023004333EE +:102880001B785A1E9341226892061CD53020E1180D +:102890004331087021005A1C45310978A21843328F +:1028A000023311700FE022000123193201990098C0 +:1028B000089EB047431C0ED00135E3683A689B1A66 +:1028C0009D42F0DBDAE72200019943320098089D2F +:1028D000A847431C02D10120404220E00623206883 +:1028E000E1683A6803400025042B03D18D1AEB43BD +:1028F000DB171D40A3682269934201DD9B1AED1886 +:102900000027BD420AD0220001231A320199009803 +:10291000089EB047431CDED00137F2E70020FEBD21 +:10292000F8B5C046F8BC08BC9E467047F8B5C0462E +:10293000F8BC08BC9E467047000000000000000084 +:1029400010420000004803003F2F7C185C30B53E69 +:10295000FFE5020083E702008199010009A301005D +:1029600093E9020049970100DD980100E998010010 +:10297000C98E0100F59801009997010079E70200DE +:1029800011930100D98E010023D80200CD900100DF +:1029900085900100CFD802006D8B01009DD602000A +:1029A000A9D60200098D0100EFD60200A7DB0200C4 +:1029B00045DB0200A59301002DDE020019E50200AF +:1029C0001BE50200702F0300AC2E0300002F030054 +:1029D0005C300300E3E5020007E60200EDE80200D8 +:1029E0001DE8020021E502001DE502001FE50200CE +:1029F00025920100B9910100CDDC0200FDD5020055 +:102A00002BD702003FD7020043D702004DD7020068 +:102A10005BD7020065D7020077D7020081D702009A +:102A20008BD7020087DC0200B1DC0200A189010023 +:102A3000E9D50200DDD60200E18C0100A989010080 +:102A400033D60200358C01002D8B010037D60200F1 +:102A500087D6020095D602005BDC02002FD9020067 +:102A600053D9020077D90200BFD90200E3D902008E +:102A70002BD80200B5D8020045D802005FD802006A +:102A800077D802008FD802009DD802007FDD0200B7 +:102A9000A5DD0200CBDD0200F1DD02000FDE020049 +:102AA00063DC020075DC020083DB020095DB0200C0 +:102AB00031DA020013D7020053DA0200F5DA02001D +:102AC00005DB020015DB020025DB020035DB02001E +:102AD0009D9101001FD7020023D70200FD9601003F +:102AE000C98E010095D70200D98E01009BD7020044 +:102AF0009FD70200A3D702002D8F0100B7D7020095 +:102B0000698F0100BFD70200C5D70200D9D70200E4 +:102B10007D8F0100F98F0100F7D7020011900100AD +:102B20002990010021D80200359001005193010045 +:102B300043E80200E19F0100C9620200495202001D +:102B4000715202005D760200216902006971020083 +:102B500009A30100058201004FD40200298201006F +:102B60005182010057D402008182010063D4020027 +:102B700081D40200ABD40200D3D40200D9D4020025 +:102B8000DFD40200EFD40200FDD40200BDA001009A +:102B9000E5A001003DA101004DA1010079A10100C6 +:102BA00017E902001FE9020009D50200ED830100C8 +:102BB0004D84010017D5020037D502006D84010055 +:102BC00057D50200358501007D8501008D85010006 +:102BD000A1850100B1850100E18501006FD50200EA +:102BE00077D50200398601004D86010099E7020081 +:102BF000A1E70200A9E70200B1E70200C3E7020073 +:102C0000CD990100D9990100D1E70200E1E7020066 +:102C1000E9E70200EBE70200C1820100D582010072 +:102C20001D830100318301004983010059830100A4 +:102C30006983010079830100898301009983010080 +:102C4000B583010087E302008FE302009FE30200E7 +:102C5000B3E30200C3E30200D7E30200EBE30200A8 +:102C6000919501000FE402009D95010089E40200A6 +:102C7000BD950100CD9501009DE40200BDE4020078 +:102C8000CDE402002D96010055960100D9E4020022 +:102C9000EBE40200FBE402009D9601006586010062 +:102CA000A1860100E5860100218701004987010016 +:102CB00065870100D9870100218801004188010052 +:102CC000518801007BDF02007FDF020097DF0200F6 +:102CD000ABDF0200B3DF02004DE2020049E3020075 +:102CE00005E0020009E002002FE0020053E00200CC +:102CF000C3E00200C5930100D1E002003FE1020001 +:102D00004FE102005BE1020023E5020033E502002F +:102D100043E5020053E5020063E5020073E50200AB +:102D200083E5020093E5020039DE02005DDE020069 +:102D30006DDE02007DDE02008DDE02009DDE0200FF +:102D4000ADDE0200BDDE0200459401007D9401006D +:102D5000C594010069E30200E99401002195010096 +:102D60003D95010000000000E2652F227F2B7A3C98 +:102D7000075C143326A6813CBDCBF07A8807703CF3 +:102D8000075C143326A6913C4FBB610567ACDD3F61 +:102D9000182D4454FB21E93F9BF681D20B73EF3F82 +:102DA000182D4454FB21F93F000000000000E03FD3 +:102DB000000000000000E0BF763C7935EF39EA3DC5 +:102DC000763C7935EF39EABD0000E0FE422EE63F61 +:102DD0000000E0FE422EE6BF000000000000000000 +:102DE000000000000000008000000040FB21F93FCF +:102DF000000000002D44743E000000809846F83C1E +:102E00000000006051CC783B00000080831BF0394B +:102E10000000004020257A38000000802282E3363E +:102E2000000000001DF36935080004F900000000EF +:102E300009000000000000000FD4020019D40200B5 +:102E400009D402000BD402000000000000000000C2 +:102E50000000000000000000702F030004006E75E9 +:102E60006C6C0000702F030009002D496E66696EBE +:102E700069747900702F0300040074727565000096 +:102E8000702F03000900756E646566696E656400E5 +:102E9000702F0300080066756E6374696F6E000022 +:102EA000AC2E03000000000000000000080004F940 +:102EB0000000000003000000000000007FD50200B9 +:102EC0001193010000000000A7D5020000000000DF +:102ED000000000000000000000000000702F030050 +:102EE00000000000702F0300050066616C73650030 +:102EF000702F03000800496E66696E6974790000DE +:102F00000C0002F9000000000200000000000000B8 +:102F10007FD502001193010000000000A3D502003C +:102F200000000000000000000000000000000000A1 +:102F3000702F030008005B4F626A6563745D0000D8 +:102F4000702F03000900756E646566696E65640024 +:102F5000702F030006006F626A6563740000000052 +:102F6000702F030006006E756D6265720000000030 +:102F7000080003F90000000001000000000000004C +:102F80007FD502001193010089D5020081D502008E +:102F90008BD50200AFD502008FD5020093D5020079 +:102FA000702F030003004E614E0000004050585443 +:102FB000403A737472696E6700000000702F03005E +:102FC0000700626F6F6C65616E000000702F030078 +:102FD0000A005B46756E6374696F6E5D00000000E9 +:102FE00024230020342300204423002054230020E5 +:102FF00064230020742300208423002094230020D5 +:10300000A4230020B4230020C4230020D4230020C4 +:10301000E4230020F42300200424002014240020B2 +:103020002424002034240020442400200C0004F92F +:10303000000000000600000000000000C3E50200E0 +:103040002BE70200B9E8020001E9020000000000DD +:103050000000000000000000000000000C0004F967 +:10306000000000000400000000000000DFE5020096 +:10307000E1E50200C3E8020005E9020000000000EB +:10308000000000000000000000000000080004F93B +:10309000000000000700000000000000E7E502005B +:1030A000E5E50200CFE802000FE9020000000000A1 +:1030B000000000000000000000000000140004F9FF +:1030C000000000000800000000000000CDE5020044 +:1030D000DDE50200D9E8020013E90200000000006B +:1030E00000000000000000000000000000000000E0 +:1030F0000000000049A2010081E902000500000073 +:103100000500000003000000090000000D0400009D +:10311000153E03000000000000000000D1EA02009C +:103120002BE90200D9EA02000BEB0200FFFF0000CE +:1031300000000000FFFF010001000000000000008F +:103140000000000029E902002BE9020031E9020039 +:1031500033E90200000000000000000029E902003D +:103160002BE9020077F2020079F2020037F2020046 +:1031700053F2020057F2020073F20200CDB80100D0 +:10318000D5B8010059F30200000000000000000063 +:103190008DBD01002BE9020075BD010017F402008E +:1031A000000000000000000029E902002BE90200F5 +:1031B00057F4020059F40200C9BE010037F40200BE +:1031C00053F40200D1BE010065F4020000000000CB +:1031D00000000000D7FC02002BE9020091C70100AB +:1031E00053FA020001000000170000004600000032 +:1031F000A30000005F010000D6020000C40500002B +:10320000A00B00000000000000000000DF01030030 +:103210008DD00100F5CF0100490003007DD10100F0 +:103220005B000300F7010300F8FFFFFF0000000050 +:1032300029E9020081D201009DD10100ADD1010038 +:10324000000000000000000029E902002BE9020054 +:103250002FE902003FE9020000000000000000002A +:1032600029E902006D0503005F0503006105030005 +:10327000000000000000000029E90200B908030076 +:103280007B0803007D080300000000000000000030 +:1032900085E70100C1080300C40900000000000028 +:1032A0008813000008000000102700001000000034 +:1032B000204E0000180000008038010020000000AF +:1032C000007102002800000000E20400300000004D +:1032D0000088130038000000E03203000300000003 +:1032E00002000000000000000400000001000000D7 +:1032F00008000000020000000000000000000000C4 +:1033000029E9020003090300C9EA01000D090300CD +:1033100037F2020053F2020057F2020073F2020089 +:10332000D5E901000DEB010059F30200BCFFFFFFDE +:103330000000000029E90200C5E90100EDEA0100F2 +:10334000FDEA0100B9EA010037F4020053F402007B +:103350000DEC010065F40200983203000800000043 +:10336000E204000000000000C409000008000000A2 +:103370008813000010000000102700001800000053 +:10338000204E0000200000008038010028000000CE +:10339000007102003000000000C409003800000085 +:1033A000A83303000300000002000000000000003A +:1033B00004000000010000000800000002000000FE +:1033C000000000000000000029E9020031090300AC +:1033D00051ED01003B09030037F2020053F20200F5 +:1033E00057F2020073F202009DEC010069ED01004A +:1033F00059F30200603303000800000000000000E1 +:103400000000000029E902005F0903003DEE010011 +:1034100069090300E5EE010037F4020053F40200ED +:1034200055EE010065F40200D430000000000000F9 +:10343000A86100002000000050C300004000000010 +:10344000A086010060000000400D03008000000025 +:10345000801A06008800000000350C009000000073 +:10346000006A1800B000000000D43000D000000056 +:1034700000A86100F00000000050C300F800000048 +:10348000283403000B0000000000000000000000D2 +:1034900029E902008D09030071F00100970903007A +:1034A00037F2020053F2020057F2020073F20200F8 +:1034B000DDEF010089F0010059F30200690200000C +:1034C00080000000E802000090000000C409000035 +:1034D000700000008813000060000000102700004A +:1034E00050000000204E000040000000409C000002 +:1034F00030000000A08601002000000040420F00C4 +:10350000100000000C350300040000000200000061 +:10351000000000000400000010000000080000008F +:10352000200000001000000030000000BC34030048 +:1035300009000000000000000000000029E902006E +:10354000BB090300E5F10100C509030085F1010095 +:1035500037F4020053F40200FDF1010065F40200AB +:10356000102700000C000000204E000008000000A2 +:1035700050C3000004000000A0860100000000000D +:10358000603503000400000000000000000000009F +:1035900029E90200A5F30100C1F201004D0A030070 +:1035A0000000000000000000990C03000000000073 +:1035B0000000000029E9020005040200DF0C0300FE +:1035C000E10C03000000000000000000ED0E02000E +:1035D000F71203000000000000000000D90E0200F6 +:1035E000E51203000000000000000000C50E02000C +:1035F000D31203000000000000000000010F0200D1 +:103600000913030000000000000000000510030083 +:10361000091003000D10030011100300D50C020067 +:1036200015100300191003001D10030021100300E2 +:1036300025100300291003002D1003003110030092 +:1036400035100300391003003D1003004110030042 +:1036500045100300491003004F10030053100300EE +:10366000571003005B1003005F100300631003009A +:10367000671003006B1003006F100300731003004A +:1036800077100300B3220300B3220300B10F02003E +:103690000000000000000000B10E02007D120300D7 +:1036A0000000000000000000890E02005912030013 +:1036B0000000000000000000750E02004712030029 +:1036C0000000000000000000610E0200351203003F +:1036D00000000000000000004D0E02002312030055 +:1036E00000000000000000009D0E02006B120300AD +:1036F00000000000000000008F1003009310030082 +:10370000971003009B1003009F100300A3100300F9 +:10371000A7100300AB100300AF1003007D140300DB +:103720000000000000000000150F02001B13030042 +:103730000000000000000000390E0200111203001A +:103740000000000000000000B3100300DD0C0200C8 +:10375000B7100300BB100300BF100300C11003002B +:10376000C5100300C9100300CB100300CF100300E5 +:10377000D31003002D130300000000000000000020 +:10378000E9110300DD110300D1110300C911030089 +:10379000291103007B1003007F1003008310030036 +:1037A000871003008B100300C51203000000000007 +:1037B00000000000C1130300DD10030071130300BB +:1037C000C50D0200E1100300E51003005D140300C5 +:1037D0003D140300710D0200290F02003D0D02008F +:1037E000E91003005D0F02000F1403000000000049 +:1037F00000000000471603007B1603009D15030020 +:10380000A1150300A5150300AB1503001910030053 +:10381000E1180200CB150300F5150300071603009D +:103820001D160300331603004D170300AD160300E9 +:10383000C1160300D3160300E5160300911702001A +:10384000FF16030071170300D517030003170300C9 +:103850000B17030013170300171703001D170300AE +:103860002317030073100300DD170200A9170300DC +:10387000D11902003F180300000000000000000002 +:10388000A11B0200791A020085180300911A020098 +:10389000AD1A0200BB180300F91803002119030038 +:1038A000AF1003007D1D0200331F0300C52002007E +:1038B0000B1F0300171F03002B1F0300551F0200DF +:1038C0002F1F03000F1F0300271F03007D2102008D +:1038D000071F03001F1F03004B1F0300C52D02001D +:1038E000F12D02007D2D0200492D02008D2C0200D9 +:1038F0005D2C0200E1310200C531020031310200CD +:103900000000000000000000B53A0200B9200300EA +:1039100000000000000000000000000000000000A7 +:10392000B32203000000000000000000593B020029 +:103930005F2103003F2103000000000000000000A1 +:1039400075C7010065FA0200712103000000000044 +:103950000000000027E9020057E902000000000013 +:10396000000000002DE902004BE902000000000009 +:10397000000000003F220300312203003322030035 +:10398000B53D0200413E0200BF240300C1240300F4 +:10399000593E02008039030034270020B0040000A3 +:1039A00000F004006009000000D00900C01200000F +:1039B00000B01300802500000050270040380000B0 +:1039C00000003B00004B000000A04E008070000093 +:1039D00000F07500127A00000000800000960000E0 +:1039E00000509D0000E1000000F0EB00002C010001 +:1039F00000903A0100C2010000E0D70100840300FA +:103A000000B0AF0390D003000000000400080700DE +:103A100000705F0700100E00A4DFBE0E40420F00D2 +:103A200000000010010000000070004004000000D1 +:103A300002000000007000400800000003000000C9 +:103A40000070004010000000040000000070004002 +:103A50002000000005000000007000404000000051 +:103A6000060000000070004080000000FF00000021 +:103A7000FFFFFFFF00000000025A0200265902006B +:103A8000E4590200BC590200E4590200B059020096 +:103A9000E4590200BC5902002659020026590200CE +:103AA000B0590200BC590200685A0200685A02006C +:103AB000685A0200EA5902002659020026590200FB +:103AC000D0590200BA590200D0590200B059020080 +:103AD000D0590200BA5902002659020026590200A4 +:103AE000B0590200BA590200685A0200685A02002E +:103AF000685A0200745A0200605D0200BE5C020057 +:103B0000BE5C0200BC5C0200525D0200525D02001D +:103B1000485D0200BC5C0200525D0200485D02008C +:103B2000525D0200BC5C0200585D0200585D02005C +:103B3000585D0200E25D0200106B0200DE690200C7 +:103B4000E46A0200D4690200E46A0200EE6A02003C +:103B5000E46A0200D4690200DE690200DE69020044 +:103B6000EE6A0200D4690200CA690200CA69020052 +:103B7000CA690200406D0200587302001872020008 +:103B800018720200167202003073020030730200D5 +:103B900022730200167202003073020022730200C8 +:103BA000307302001672020038730200387302008C +:103BB000387302003875020061636F730000000003 +:103BC00061636F73680000006173696E000000003C +:103BD0006174616E68000000636F7368000000002C +:103BE00065787000666D6F64000000006C6F6700A0 +:103BF0006C6F67313000000073696E680000000070 +:103C00007371727400000000FB21F93FFB21094031 +:103C10007CD91240FB2119407A6A1F407CD922408E +:103C2000BBFD2540FB2129403A462C407A6A2F40B3 +:103C30005C4731407CD932409C6B3440BBFD354001 +:103C4000DB8F3740FB2139401BB43A403A463C40B9 +:103C50005AD83D407A6A3F404C7E40405C474140E4 +:103C60006C1042407CD942408CA243409C6B444043 +:103C7000AC344540BBFD4540CBC64640DB8F47409A +:103C8000EB584840FB21494083F9A200444E6E00A6 +:103C9000FC291500D1572700DD34F50062DBC00098 +:103CA0003C999500419043006351FE00BBDEAB00A0 +:103CB000B761C5003A6E2400D24D42004906E000CB +:103CC00009EA2E001C92D100EB1DFE0029B11C0058 +:103CD000E83EA700F535820044BB2E009CE9840035 +:103CE000B4267000417E5F00D691390053833900BD +:103CF0009CF439008B5F840028F9BD00F81F3B005D +:103D0000DEFF97000F980500112FEF000A5A8B0075 +:103D10006D1F6D00CF7E360009CB2700464FB700E0 +:103D20009E663F002DEA5F00BA277500E5EBC700ED +:103D30003D7BF100F739070092528A00FB6BEA00E5 +:103D40001FB15F00085D8D00300356007BFC46000C +:103D5000F0AB6B0020BCCF0036F49A00E3A91D0045 +:103D60005E619100081BE60085996500A0145F0064 +:103D70008D40680080D8FF0027734D000606310093 +:103D8000CA561500C9A873007BE260006B8CC000A6 +:103D90000200000003000000040000000600000014 +:103DA0000000000000000000000000000000000013 +:103DB0000000000000000000000000000000000003 +:103DC00000000000000000000000000000000000F3 +:103DD00000000000000000000000000000000000E3 +:103DE00000000000000000000000000000000000D3 +:103DF00000000000000000000000000000000000C3 +:103E00002020002030313233343536373839616282 +:103E100063646566000000040202040200000204FC +:103E20000404000202000404030100000103030370 +:103E30000001010203030402010103010403010064 +:103E400003000004010102000003025265626F6F6B +:103E5000744D6F646500666C617368496E636F6D65 +:103E6000706C657465007A76677074756F696561EA +:103E70007A76677074756F6965617A7667707400B9 +:103E80000004020204020000020404040002020012 +:103E90000404030100000103030300010102030302 +:103EA00004020101030104030100030000040101F5 +:103EB00002000003021B1B000E110000000000089E +:103EC000080800080A4A4000000A5FEA5FEA0ED9C3 +:103ED0002ED36E19324489330C924C924D0808004F +:103EE000000004880808040804848488000A448ABE +:103EF0004000048EC480000000048800000EC00052 +:103F0000000000080001224488100C9252524C0418 +:103F10008C84848E1C824C901E1EC244924C06CA15 +:103F2000525FE21FF01EC13E02448ED12E1FE244BA +:103F300088100ED12ED12E0ED12EC4880008000874 +:103F40000000048004880244880482000EC00EC071 +:103F500008048244880ED126C0040ED135B36C0CFF +:103F6000925ED2521C925C925C0ED010100E1C928B +:103F700052525C1ED01C901E1ED01C90100ED013EE +:103F8000712E12525ED2521C8808081C1FE2425247 +:103F90004C1254981492101010101E113B75B13130 +:103FA000113935B3710C9252524C1C925C90100C2A +:103FB00092524C861C925C92510ED00C825C1FE493 +:103FC000848484125252524C1131312A44113135B9 +:103FD000BB7112524C9252112A4484841EC4881020 +:103FE0001E0EC808080E10080482410EC242424E3E +:103FF000048A400000000000001F08048000000048 +:104000000ED2524F10101C925C000ED0100E0242C5 +:104010004ED24E0C925C900E06C81C88080ED24EF2 +:10402000C24C10101C9252080008080802400242BC +:104030004C10149814920808080806001B75B1313A +:10404000001C925252000C92524C001C925C900048 +:104050000ED24EC2000ED010100006C804980808F8 +:104060000EC807001252524F0011312A440011317C +:1040700035BB00124C8C9200112A4498001EC48853 +:104080001E06C48C8486080808080818080C8818BE +:1040900000000C8360000001000200030004000027 +:1040A00001010102010301040100020102020203F5 +:1040B00002040200030103020303030403000401DA +:1040C00004020403040404302C3235352C302C3225 +:1040D00035352C300A302C3235352C302C323535F4 +:1040E0002C300A302C302C302C302C300A32353524 +:1040F0002C302C302C302C3235350A302C323535E2 +:104100002C3235352C3235352C300A0054494C547C +:1041100020544F2046494C4C2053435245454E2095 +:1041200000636F6D7061737343616C0074656D70D3 +:1041300043616C00FFFF14000500FFFFFFFFFFFF5E +:10414000FFFFFFFFFFFF00FFFFFF000000FFFFFF7B +:10415000FFFFFFFFFF00FFFFFF000000FF00000068 +:104160000000FFFF00FFFFFF000000FF0000000055 +:10417000000000000000FFFFFFFFFFFFFF00FFFF48 +:10418000FF000000FF0000000000FFFFFFFFFFFF37 +:10419000FFFFFFFFFFFF00FFFFFF000000FF000029 +:1041A000FFFF00FF00FF00FF00FFFFFF00FF00FF19 +:1041B00000FF0000FFFF00626C6553797341747467 +:1041C000727300424243206D6963726F3A62697490 +:1041D00000424243206D6963726F3A626974205BEA +:1041E000005D00302C302C3235352C302C300A302C +:1041F0002C3235352C302C302C300A3235352C32DF +:1042000035352C3235352C3235352C3235350A30B2 +:104210002C3235352C302C302C300A302C302C32CE +:1042200035352C302C300A00302C302C302C302CF2 +:10423000300A302C302C302C302C3235350A302CD2 +:10424000302C302C3235352C300A3235352C302C90 +:104250003235352C302C300A302C3235352C302C80 +:10426000302C300A003235352C302C302C302C32AA +:1042700035350A302C3235352C302C3235352C3052 +:104280000A302C302C3235352C302C300A302C3280 +:1042900035352C302C3235352C300A3235352C3032 +:1042A0002C302C302C3235350A00322E312E312D67 +:1042B0002D6700E2ECF0F4F8FC0004E95D93B02512 +:1042C0001D470AA062FA1922DFA9A8E95D93B1256A +:1042D0001D470AA062FA1922DFA9A8E95DB84C259A +:1042E0001D470AA062FA1922DFA9A8E95D97752582 +:1042F0001D470AA062FA1922DFA9A8E95D93AF253C +:104300001D470AA062FA1922DFA9A8E95D23C42586 +:104310001D470AA062FA1922DFA9A8E95D54042505 +:104320001D470AA062FA1922DFA9A801FF01AAE924 +:104330007D3B10251D470AA062FA1922DFA9A8E9D2 +:104340007DD91D251D470AA062FA1922DFA9A8629E +:1043500061642068616E646C6520746F20756E64A2 +:1043600065726C79696E67207472616E73706F72BA +:104370007400494E495449414C495A4154494F4EA1 +:104380005F494E434F4D504C455445004E6F72644B +:10439000696320424C45342E31207665723A25758A +:1043A0002066773A25303478004E6F726469632056 +:1043B000287370656320756E6B6E6F776E2920763B +:1043C00065723A25752066773A2530347800756E27 +:1043D0006B6E6F776E00010203D8E2ECF0F4F8FC2C +:1043E00000046E52463578004E6F20617661696C2C +:1043F00061626C6520493243004F6E6C79203862EF +:104400006974732053504920737570706F727465AE +:10441000640053504920666F726D6174206572723A +:104420006F72004E6F20617661696C61626C65200D +:1044300053504900636F756C64206E6F742070690F +:104440006E6F75740070696E6D6170206D69732D8B +:104450006D617463680070696E6D6170206E6F7459 +:1044600020666F756E6420666F7220706572697069 +:10447000686572616C0070696E6D6170206E6F743A +:1044800020666F756E6420666F722066756E637449 +:10449000696F6E0000202020202020202020282866 +:1044A00028282820202020202020202020202020F4 +:1044B0002020202020881010101010101010101034 +:1044C0001010101010040404040404040404041064 +:1044D00010101010101041414141414101010101F2 +:1044E00001010101010101010101010101010101BC +:1044F00010101010101042424242424202020202C8 +:10450000020202020202020202020202020202028B +:10451000101010102000000000000000000000003B +:10452000000000000000000000000000000000008B +:10453000000000000000000000000000000000007B +:10454000000000000000000000000000000000006B +:10455000000000000000000000000000000000005B +:10456000000000000000000000000000000000004B +:10457000000000000000000000000000000000003B +:10458000000000000000000000000000000000002B +:104590000000000000232D302B2000686C4C0065CB +:1045A000666745464700303132333435363738395F +:1045B000414243444546000000000000B83BFE7FF6 +:1045C0000100000000000000A10D0C00BA3E030035 +:1045D000C3410300AA420300204E0000B31F0300A2 +:1045E000204E000000000000A03D0300C03D03007D +:1045F000E03D03000000000000000000000000009B +:1046000000000000F743030000000000000000006D +:10461000000000000000000000000000000000009A +:10462000000000000000000000000000000000008A +:10463000000000000000000000000000000000007A +:10464000000000002020002094440300204EFFFFC3 +:1046500000000000FF0F1010070004FF0000010021 +:104660003981010059950100A1A00100E5A30100D5 +:10467000D5B1010041B501005DB8010085B8010068 +:104680000D8101000000000000000000000000009B +:10469000000000000000000000000000000000001A +:1046A000000000000000000000000000000000000A +:1046B00000000000000000000000000000000000FA +:1046C00000000000000000000000000000000000EA +:1046D00000000000000000000000000000000000DA +:1046E00000000000000000000000000000000000CA +:1046F00000000000000000000000000000000000BA +:1047000000000000000000000000000000000000A9 +:104710000000000000000000000000000000000099 +:104720000000000000000000000000000000000089 +:104730000000000000000000000000000000000079 +:104740000000000000000000000000000000000069 +:104750000000000000000000000000000000000059 +:104760000000000000000000000000000000000049 +:104770000000000000000000000000000000000039 +:104780000000000000000000000000000000000029 +:104790000000000000000000000000000000000019 +:1047A0000000000000000000000000000000000009 +:1047B00000000000000000000000000000000000F9 +:1047C00000000000000000000000000000000000E9 +:1047D00000000000000000000000000000000000D9 +:1047E00000000000000000000000000000000000C9 +:1047F00000000000000000000000000000000000B9 +:10480000708E3B92C615A841C49866C975EE519743 +:104810003F2F7C185C30B53E715064D68A7A839203 +:104820001F004E03A060030000000100346003007D +:1048300081560300686203000000000000000000D1 +:104840005C300300000000004D48030000B501206B +:104850003768786003203768B86005203768F860EB +:10486000DF486F467760E4F797FF01B46F467760E3 +:10487000F8F75BFF01B42D216F467760F8F766FF0C +:1048800000982F216F467760F8F760FF00980320AB +:1048900001B4029801B400F0E3FE03B001BC376834 +:1048A0003861CF486F467760E4F776FF01B46F4612 +:1048B0007760F8F73AFF01B425216F467760F8F783 +:1048C00045FF009827216F467760F8F73FFF009873 +:1048D000052001B4029801B400F0C2FE03B001BC8F +:1048E00037687861BF486F467760E4F755FF01B4D9 +:1048F000052001B4032001B4029801B400F0A2FE27 +:1049000003B001BC3768B861B6486F467760E4F71A +:1049100043FF01B4072001B4052001B4029801B49B +:1049200000F090FE03B001BC3768F861AD486F46F7 +:104930007760E4F731FF01B4512001B4072001B4DE +:10494000029801B400F07EFE03B001BC3768386203 +:10495000A4486F467760E4F71FFF01B4532001B409 +:10496000092001B4029801B400F06CFE03B001BC50 +:10497000376878629B486F467760E4F70DFF01B4B3 +:10498000172001B40B2001B4029801B400F05AFEC4 +:1049900003B001BC3768B86292486F467760E4F7AD +:1049A000FBFE01B4152001B40D2001B4029801B43E +:1049B00000F048FE03B001BC3768F86289486F46D2 +:1049C0007760E4F7E9FE01B4132001B40F2001B4CD +:1049D000029801B400F036FE03B001BC37683863BA +:1049E00080486F467760E4F7D7FE01B4112001B428 +:1049F000112001B4029801B400F024FE03B001BC00 +:104A00003768786378486F467760E4F7C5FE01B48D +:104A1000232001B4032001B4029801B400F004FE85 +:104A200003B001BC3768B8636F486F467760E4F73E +:104A3000B3FE01B4212001B4052001B4029801B4F1 +:104A400000F0F2FD03B001BC3768F86366486F46BA +:104A50007760E4F7A1FE01B41F2001B4072001B480 +:104A6000029801B400F0E0FD03B001BC376838647F +:104A70005D486F467760E4F78FFE01B41D2001B4F6 +:104A8000092001B4029801B400F0CEFD03B001BCCE +:104A90003768786455486F467760E4F77DFE01B467 +:104AA000012001B4032001B4029801B400F0AEFD6E +:104AB00003B001BC3768B8644C486F467760E4F7D0 +:104AC0006BFE01B4032001B4052001B4029801B4C7 +:104AD00000F09CFD03B001BC3768F86443486F46A2 +:104AE0007760E4F759FE01B4052001B4072001B452 +:104AF000029801B400F08AFD03B001BC3768386544 +:104B00003A486F467760E4F747FE01B4072001B4E6 +:104B1000092001B4029801B400F078FD03B001BC93 +:104B20003768786532486F467760E4F735FE01B440 +:104B30001B2001B4032001B4029801B400F058FD19 +:104B400003B001BC3768B86529486F467760E4F761 +:104B500023FE01B4192001B4052001B4029801B468 +:104B600000F046FD03B001BC3768F86520486F4689 +:104B70007760E4F711FE01B4572001B4072001B4B7 +:104B8000029801B400F034FD03B001BC3768386608 +:104B900017486F467760E4F7FFFD01B4552001B474 +:104BA000092001B4029801B400F022FD03B001BC59 +:104BB00037687866012040423768B8660120404275 +:104BC0003768F8660B486F467760E4F7E5FD3768AD +:104BD00038676F467760F8F7A8FD01B405210BE050 +:104BE0003C5D0300A05D0300E85D0300305E030050 +:104BF000785E0300C05E03006F467760F8F7A6FD9D +:104C0000009807216F467760F8F7A0FD00985121C2 +:104C10006F467760F8F79AFD009853216F467760EA +:104C2000F8F794FD009817216F467760F8F78EFD2E +:104C3000009815216F467760F8F788FD00981321DA +:104C40006F467760F8F782FD009811216F46776014 +:104C5000F8F77CFD3768386F02BC00F05AFE4160FF +:104C60003768386F212100F054FE81606F4677600D +:104C7000F8F75BFD01B41D216F467760F8F766FD1C +:104C800000981F216F467760F8F760FD009821219A +:104C90006F467760F8F75AFD009823216F467760DA +:104CA000F8F754FD009825216F467760F8F74EFD20 +:104CB000009827216F467760F8F748FD00982D216E +:104CC0006F467760F8F742FD00982F216F467760B6 +:104CD000F8F73CFD009855216F467760F8F736FDF0 +:104CE000009857216F467760F8F730FD009819213A +:104CF0006F467760F8F72AFD00981B216F467760B2 +:104D0000F8F724FD3768386F02BC00F002FEC1607E +:104D10006F467760F8F709FD01B401216F467760AF +:104D2000F8F714FD009803216F467760F8F70EFD41 +:104D3000009805216F467760F8F708FD0098072175 +:104D40006F467760F8F702FD3768386F02BC00F0F5 +:104D5000E0FD016101203768786751203768786786 +:104D6000D548192109016F467760E5F7A7F90F20AB +:104D70000002A13001B400F025FC01B003200002C4 +:104D8000E93001B400F0FCFB01B007200002D13093 +:104D900001B400F017FC01B00B200002B93001B4DF +:104DA00000F0C4FB01B02920376878672720000293 +:104DB000113001B400F002F801B000BD00B5376851 +:104DC000786F01B4012149426F467760F8F7D3FD4F +:104DD00001B003463768786F01B408B400F018F8E2 +:104DE00002B0019801B400F0A1FD6F467760F9F7B9 +:104DF00096FD01B000F002F800BD000000B50120F2 +:104E000001B4012001B400F003F802B000BD0000BD +:104E100000B5019801B43768386901B400F013F89F +:104E200002B0029801B43768786901B400F00BF859 +:104E300002B000BD022C0BDA00B500F07FFD00F0DF +:104E400007F802B000BD7746009800F080FDBE462E +:104E500000B5002001B401B400F03AFB00900498C2 +:104E600001B4C92001B4C720404201B400F00AFBDC +:104E700003B00490049801B48E48C9216F4677604E +:104E8000F8F79DFD01B4019800996F467760F8F737 +:104E900072FD02B0012100F07FFE01B400F0E4FADF +:104EA00001B001900498012100F0BBFE24D00098CD +:104EB00001B40498806801B4012100F03BFC01B00A +:104EC00001B406BC012001B402B404B400F0F5F949 +:104ED00003B0009801B40498806801B4032100F085 +:104EE00029FC01B001B406BC019801B402B404B4B9 +:104EF00000F0E3F903B023E0009801B4049880685F +:104F000001B4012100F016FC01B001B406BC019807 +:104F100001B402B404B400F0D0F903B0009801B4B5 +:104F20000498806801B4032100F004FC01B001B4CE +:104F300006BC012001B402B404B400F0BEF903B011 +:104F400002B000BD7746009800F00EFDBE4600B5E9 +:104F500001980299C16059486F467760E4F71CFCDC +:104F600001B4049801B4019801B400F093F902B0BF +:104F7000029802BC4160019804998160019801B4D3 +:104F800000F010F801B000BD012C0BDA00B500F004 +:104F9000F8FC00F007F801B000BD7746009800F07B +:104FA000E3FCBE4600B501200002FF3001B4FF2043 +:104FB00001B4012001B4049801B400F023F804B056 +:104FC00003200002E93001B400F002F801B000BD96 +:104FD00000B5019801B400F0A9FC6F467760F9F7BD +:104FE0009EFC01B000BD0000042C0BDA00B500F0FF +:104FF000CCFC00F007F804B000BD7746009800F044 +:10500000B3FCBE4600B56F467760F8F78EFB01B47F +:1050100001B4069801B4019800996F467760F8F7DB +:1050200095FB02B0029801B4049801B4069801B44B +:10503000039801B400F00EF801B00021039101B40F +:105040001EBC02B404B408B410B400F063F805B098 +:1050500000BD000000B5002001B401B4039801B404 +:1050600000F0B3FC6F467760F8F769FB01B000F021 +:10507000B8FD01B400F05AFC6F467760F9F726FAE4 +:1050800001B0009001200190019801B4049801B48E +:1050900000F09BFC6F467760F8F751FB01B000F021 +:1050A000A0FD01B40198009900F0A7FD02B007D15E +:1050B0001FE00000FFFF0100A4600300C85F0300C1 +:1050C000009801B4029801B4059801B4049801B4A1 +:1050D0000198009900F02EFB02B001B400F07AFCB8 +:1050E00000F04BFB03B00198032100F028FD019074 +:1050F000CAE7009802B000BD042C0BDA00B500F03E +:1051000044FC00F007F804B000BD7746009800F0BA +:105110002BFCBE4600B5002001B401B401B46F46BB +:105120007760F8F702FB01B401B4079801B4019865 +:1051300000996F467760F8F709FB02B0079801B451 +:10514000009901986F467760F8F700FB01B000986E +:10515000FFF780FF01B00090079801B400F052FC07 +:105160006F467760F8F74EFF01B000F03AFD014658 +:10517000052000F0E4FC01B400F0D8FB6F46776036 +:10518000F9F7A4F901B00190019801B4019801B4B4 +:1051900000F03DFC00216F467760F8F7D0FF02B0C9 +:1051A000019801B4089801B400F031FC02216F4667 +:1051B0007760F8F7C4FF02B0049880686F467760A4 +:1051C000F8F784FD002805D00498806801B400F049 +:1051D00028FC01B00498406801B400F050F801B018 +:1051E00002900A2001B4029801B4049801B400F0BE +:1051F00022F803B0029801B400F00DF801B003B03A +:1052000000BD0000012C0BDA00B500F0BAFB00F085 +:1052100007F801B000BD7746009800F01FFCBE46BD +:1052200000B500BD032C0BDA00B500F024FC00F043 +:1052300007F803B000BD7746009800F00FFCBE46AB +:1052400000B50198406801B4039801B405986F4611 +:105250007760F8F73BFD01B400F01BFC6F46776008 +:10526000E4F7F8F903B000F0BCFC00BD012C0BDA48 +:1052700000B500F086FB00F007F801B000BD7746EE +:10528000009800F0EBFBBE4600B501980A21816052 +:10529000019800BD7746009800F0E0FBBE4600B5DF +:1052A00001980299416000BD032C0BDA00B500F0B3 +:1052B000E2FB00F007F803B000BD7746009800F06D +:1052C00053FBBE4600B5002001B401B40A20009093 +:1052D00003206F467760F9F7F9F801900398C068EA +:1052E00000F017FB8068212100F0D7FC56D003980E +:1052F000C06800F00EFBC06801B4059801B400F06E +:10530000D7FB00226F467760F8F7BDFC02B000F0D3 +:1053100068FC012100F0ADFC3FD0422000906F46B8 +:105320007760F8F702FA01B401B40598C06800F09C +:10533000F0FAC06801B4079801B400F0B9FB00228C +:105340006F467760F8F79FFC02B000F04AFC01B4AA +:10535000019800996F467760F8F7F8F902B006985F +:1053600001B411216F467760F8F76CFA01B001B40F +:10537000009901986F467760F8F7E8F901B0069850 +:1053800001B4009901986F467760F8F7DFF901B032 +:105390000098FFF75FFE01B0019045E00398C068F8 +:1053A00000F0B7FAC06801B4059801B400F080FBC2 +:1053B00000226F467760F8F766FC02B000F011FC3F +:1053C000012100F056FC2FD0422000906F467760FC +:1053D000F8F7ABF901B401B40598C06800F099FA88 +:1053E000C06801B4079801B400F062FB00226F4668 +:1053F0007760F8F748FC02B000F0F3FB01B40198C5 +:1054000000996F467760F8F7A1F902B0069801B4E9 +:10541000009901986F467760F8F798F901B0009805 +:10542000FFF718FE01B0019000980A2100F049FC36 +:1054300004D0AB4801B400F00FF801B0019801B4FA +:10544000032001B4112001B4069801B4FFF762FEF5 +:1054500004B002B000BD000000B56C206F4677605C +:10546000F8F7A9F900BD000000B50198012100F08E +:10547000C4FB04D00120019900F071FB00E0019809 +:1054800000BD000000B5029801B4049801B403986F +:1054900001B400F009F802B001B406BC02B404B4CF +:1054A00000F00CF802B000BD00B50198029900F0C0 +:1054B000E0FB01D0019800E0029800BD00B5019822 +:1054C000029900F0C2FB01D0019800E0029800BDF3 +:1054D00000B53768B86F6F467760F8F7F7FB6F462F +:1054E0007760F8F7D7F86F467760F8F700F96F46FE +:1054F0007760F8F7EBFB002814D07A486F467760A6 +:10550000E4F74AF901B4002001B4932001B43768EC +:10551000386F01B4039801B4FFF714FD04B001BC67 +:105520003768B8673768B86F00BD000000B53768E6 +:10553000786F01B4012149426F467760F8F71BFA92 +:1055400001B001B43768786F01B4012149426F4658 +:105550007760F8F710FA01B001B406BC02B404B4E5 +:10556000FFF756FC02B0019801B400F0DFF96F4676 +:105570007760F9F7D4F901B0FFF740FC00BD0000F7 +:1055800000B53768786F01B43768786F01B40121CE +:1055900049426F467760F8F7EEF901B001B406BCF6 +:1055A00002B404B4FFF734FC02B0019801B400F077 +:1055B000BDF96F467760F9F7B2F901B0FFF71EFC4D +:1055C00000BD000000B53768786F01B43768786FA8 +:1055D00001B4FFF71DFC02B0019801B400F0A6F978 +:1055E0006F467760F9F79BF901B0FFF707FC00BD44 +:1055F0007746009800F062FABE4600B5019802991D +:10560000416001980399816000BD000077460098D1 +:1056100000F061FABE4600B5019802994160019818 +:105620000399816000BD00007746009800F060FAA1 +:10563000BE4600B5019802994160019803998160C6 +:1056400000BD00007746009800F05FFABE4600B546 +:1056500001980299416001980399816000BD0000A2 +:105660007746009800F073F9BE4600B5019802999C +:10567000416001980399816001980A21C16000BDD1 +:10568000F0B50C4615461E46074600F04BFA684634 +:10569000F0B46946E4F7A4FC06463D46A868032436 +:1056A0008047074604B03046F9F7CBF83846F0BDDE +:1056B00082070ED100280CD003681A89012A00D174 +:1056C00070471F6A002F04D001B50124B84700902D +:1056D00000E001B56F467760E3F7A4FD02BD00006E +:1056E000506203001C5F030084071FD100281DD0F7 +:1056F00003681C89032C19D1491007D34468A142BF +:1057000016D24418207A400001307047490005B590 +:1057100008466F467760F8F784F8014605BC6F4687 +:105720007760F8F71FF84000013000BDE3F73AFE5C +:105730000120704784071CD100281AD003681C89F7 +:10574000062C16D1491006D30489A14213D2890030 +:10575000446860587047490005B508466F46776051 +:10576000F8F75FF8014605BC6F467760F7F7FAFF78 +:1057700000BDE3F717FE0020704784071BD1002807 +:1057800019D003681C89032C15D1491005D344682E +:10579000A14212D2441822727047490005B508464A +:1057A0006F467760F8F73DF8014605BC6F467760B5 +:1057B000F7F7E1FF00BDE3F7F5FD00B5F6E7840775 +:1057C0001CD100281AD003681C89062C16D1491058 +:1057D00006D30489A14213D28900446862507047FD +:1057E000490005B508466F467760F8F71AF8014694 +:1057F00005BC6F467760F7F7BEFF00BDE3F7D2FD4B +:1058000000B5F6E7840737D1002835D003681C8936 +:10581000082C05D100B56F467760F7F7DDFF00BDB6 +:105820001C4601B50846E3F7A9FB0146009823464C +:1058300000F002F801B000BDDA6817001CD04F4339 +:10584000D7407F005B68DB191A88D75A8F420BD08C +:1058500002331A88D75A8F4206D002331A88D75A91 +:105860008F4201D0002070479B185A68D70701D09B +:1058700001241047805870476F467760E3F792FD28 +:105880006F467760F8F7D2FA84073AD1002838D00B +:1058900003681C89082C05D100B56F467760F7F7BF +:1058A000AAFF00BD1C4605B50846E3F767FB0146A5 +:1058B0000098234600F002F802B000BDDA68170035 +:1058C0001FD04F43D7407F005B68DB191A88D75A37 +:1058D0008F4209D002331A88D75A8F4204D002333C +:1058E0001A88D75A8F4210D19B185A68D70705D00B +:1058F0001F898F4209D1DA6802241047019B835027 +:1059000070476F467760E3F74DFD6F467760F8F7B5 +:105910008DFA820706D1002804D003681A89152A57 +:1059200000D170476F467760E3F73CFD00B5019802 +:10593000401002D2400000F04AF900BD00200021D2 +:1059400001B4012C01DB0298029101B47047820777 +:1059500006D1002804D003681A89102A00D17047A4 +:105960006F467760E3F71EFD820706D1002804D05A +:1059700003681A89162A00D170476F467760E3F7EB +:1059800011FD0020002101B470470020002101B466 +:10599000032C01DB0498049101B4022C01DB049870 +:1059A000049101B4012C01DB0498049101B4704707 +:1059B000820706D1002804D003681A89062A00D17C +:1059C00070476F467760E3F7EDFC00B50198FFF78D +:1059D000EFFF00BD00B50198401002D2400000F07A +:1059E000F6F802460398029900BD820706D1002806 +:1059F00004D003681A89032A00D170476F46776084 +:105A0000E3F7D0FC00B50198FFF7EFFF00BD00B54C +:105A10000298FFF7EAFF01B40298FFF7E6FF02469B +:105A200001BD820716D1002814D003681A89042A00 +:105A300010D100248188002901D18168084782B0F3 +:105A40000095714601910546AF68B847019C009DDD +:105A500002B020476F467760E3F7A4FC820706D1C7 +:105A6000002804D003681A89172A00D170476F46AE +:105A70007760E3F797FC0020002101B4022C01DBE2 +:105A80000398039101B4012C01DB0398039101B445 +:105A9000704700B50398401002D2400000F097F81C +:105AA00001B40398FFF7A1FF014601BC019A00BDB4 +:105AB00000B50298FFF77CFF019900BD820706D16F +:105AC000002804D003681A89142A00D170476F4651 +:105AD0007760E3F767FC820706D1002804D00368EB +:105AE0001A89132A00D170476F467760E3F75AFC92 +:105AF000820706D1002804D003681A89122A00D12F +:105B000070476F467760E3F74DFC820706D10028A7 +:105B100004D003681A89112A00D170476F46776054 +:105B2000E3F740FC820706D1002804D003681A89F5 +:105B3000042A00D170476F467760E3F733FCC20751 +:105B400006D0CA0704D04A1E821801D61000F047BA +:105B500003B56F467760F7F7EAFE02B000BDC207F3 +:105B600006D0CA0704D04A1E821A01D61000F04798 +:105B700003B56F467760F7F7ECFE02B000BDC207D1 +:105B800003D0CA0701D00840F04703B56F467760DD +:105B9000F7F784FE02B000BDC20703D0CA0701D0E8 +:105BA0000843F04703B56F467760F7F764FE02B02D +:105BB00000BDC20704D0CA0702D04840401CF047CD +:105BC00003B56F467760F7F74AFE02B000BD40109C +:105BD00000D3F047400000B56F467760F7F721FE2D +:105BE00000BD42005110884201D1501CF04700B561 +:105BF0006F467760F7F758FD00BDC20707D0CA07A8 +:105C000005D0401A01DB002070470120704703B522 +:105C10006F467760F8F7D9F8F8F758F8002802B01F +:105C200000BDC20707D0CA0705D0401A01DC00201A +:105C300070470120704703B56F467760F8F7E7F8C3 +:105C4000F8F744F8002802B000BDC20707D0CA0721 +:105C500005D0401A01DD002070470120704703B5D0 +:105C60006F467760F8F79EF8F8F730F8002802B032 +:105C700000BDC20707D0CA0705D0401A01DA0020CC +:105C800070470120704703B56F467760F8F7B0F8AA +:105C9000F8F71CF8002802B000BDC20707D0CA07F9 +:105CA00005D0401A01D0002070470120704703B58D +:105CB0006F467760F7F7D5FFF8F708F8002802B0CD +:105CC00000BDC20707D0CA0705D0401A01D0002086 +:105CD00070470120704703B56F467760F7F751FFB3 +:105CE000F7F7F4FF002802B000BDC20707D0CA07CB +:105CF00005D0401A01D1002070470120704703B53C +:105D00006F467760F7F7B6FFF7F7E0FF002802B0BD +:105D100000BDC20707D0CA0705D0401A01D1002034 +:105D200070470120704703B56F467760F7F732FF81 +:105D3000F7F7CCFF002802B000BD0000100004F906 +:105D4000605D0300100000001D21C633E3E5020082 +:105D500007E60200EDE802001DE802000000000076 +:105D6000300016001400220010000E0014000A007B +:105D70000800060004000200060004000400000001 +:105D8000090008000800000007000C000C000000DB +:105D900014000000354E0300000000000000000069 +:105DA0000C0004F9C45D0300110000001F49A0416C +:105DB000E3E5020007E60200EDE802001DE802004C +:105DC0000000000014000A000800060004000200A1 +:105DD000060004000400000008000800080000009D +:105DE00000000000000000000C0004F90C5E03003D +:105DF000120000001F49A041E3E5020007E602008F +:105E0000EDE802001DE802000000000014000A0096 +:105E10000800060004000200060004000400000060 +:105E2000080008000800000000000000000000005A +:105E30000C0004F9545E0300130000001F49A04148 +:105E4000E3E5020007E60200EDE802001DE80200BB +:105E50000000000014000A00080006000400020010 +:105E6000060004000400000008000800080000000C +:105E700000000000000000000C0004F99C5E03001C +:105E8000140000001F49A041E3E5020007E60200FC +:105E9000EDE802001DE802000000000014000A0006 +:105EA00008000600040002000600040004000000D0 +:105EB00008000800080000000000000000000000CA +:105EC000140004F9E45E0300150000001EE7536AA5 +:105ED000E3E5020007E60200EDE802001DE802002B +:105EE0000000000028001E000C000A001000060040 +:105EF000040002000C00040004000000130008006D +:105F00000800000012000C000C0000001600100039 +:105F1000100000000000000000000000200004F954 +:105F2000405F0300160000001C258B65E3E50200BE +:105F300007E60200EDE802001DE802000000000094 +:105F40002800760064004A0020001E003400520041 +:105F5000600036001400220040000E000C00120009 +:105F60000800060004000200100004000400000005 +:105F70000A0008000800000011000C000C000000DE +:105F800001001000100000000400140014000000C4 +:105F9000030018001800000002001C001C00000094 +:105FA00015000000894F03000D000000A9520300F6 +:105FB00018000000E94F030017000000F95003002B +:105FC00000000000000000000C0004F9EC5F03007A +:105FD000170000001D8B1247E3E5020007E60200F0 +:105FE000EDE802001DE80200000000001800360085 +:105FF00014001A0020000E000C0022000800060009 +:10600000040002000B00040004000000050008006A +:106010000800000017000000255203000E000000D9 +:106020006D5203000F000000055203000000000045 +:106030000000000019000000C4600300CC600300F1 +:10604000D8600300F06003000461030014610300E2 +:106050002461030030610300406103004C610300D0 +:10606000586103006C6103007C61030090610300D0 +:10607000A4610300B0610300BC610300D0610300B0 +:10608000E4610300F4610300046203001062030092 +:106090002462030034620300406203000000000039 +:1060A00000000000FFFF05000500FFFF00FFFFFFED +:1060B000FF00FFFF0000000000FF000000FF00FFE6 +:1060C000FFFF0000702F030000000000702F03008E +:1060D0000500494E50555400702F03000E00494EE4 +:1060E0005055545F50554C4C444F574E00000000E3 +:1060F000702F03000C00494E5055545F50554C4CC6 +:1061000055500000702F030006004F555450555451 +:1061100000000000702F030009005F686173457282 +:10612000726F7200702F030003005F69640000004B +:10613000702F030009005F696E76657274656400F4 +:10614000702F030004005F70696E0000702F030061 +:1061500005005F70696E7300702F03000B005F779E +:10616000616974466F7250696E000000702F030001 +:10617000070061646472657373000000702F030090 +:106180000A00616E616C6F6750696E7300000000F9 +:10619000702F03000B00616E616C6F67577269743A +:1061A00065000000702F03000500626567696E00DE +:1061B000702F03000300656E64000000702F030061 +:1061C0000A006932635F64657669636500000000F8 +:1061D000702F03000A0070696E4D617070696E6700 +:1061E00000000000702F0300070070776D50696E8B +:1061F00073000000702F0300080070776D5769640A +:1062000074680000702F0300030072756E000000B8 +:10621000702F03000D00736F6674776172655265AD +:1062200073657400702F03000900746F7563685004 +:10623000696E7300702F0300050077726974650042 +:10624000702F030006007772697465380000000043 +:10625000702F03000F00496E76616C6964205057FF +:106260004D2070696E00000000000000000000007A +:10C00000903C002061DC030073DC030075DC03005E +:10C010000000000000000000000000000000000020 +:10C0200000000000000000000000000069C10300E3 +:10C03000000000000000000079DC03007BDC03004E +:10C040007DDC03007DDC03007DDC03007DDC030080 +:10C050007DDC0300000000007DDC03007DDC0300CC +:10C060007DDC03007DDC03007DDC03007DDC030060 +:10C070007DDC03007DDC03007DDC03007DDC030050 +:10C080007DDC0300B3D703007DDC03007DDC03000F +:10C09000C9D703007DDC0300A9F303007DDC0300A6 +:10C0A0007DDC03007DDC03000000000000000000D8 +:10C0B0000000000000000000000000000000000080 +:10C0C00000F002F800F040F80CA030C8083824183E +:10C0D0002D18A246671EAB4654465D46AC4201D1C0 +:10C0E00000F032F87E460F3E0FCCB64601263342B2 +:10C0F00000D0FB1AA246AB46334318476C3600000B +:10C100008C360000103A02D378C878C1FAD85207AA +:10C1100001D330C830C101D504680C6070470000FD +:10C120000023002400250026103A01D378C1FBD853 +:10C13000520700D330C100D50B6070471FB5C04611 +:10C14000C0461FBD10B510BD03F091FA1146FFF7B0 +:10C15000F5FF00F0D3F803F0A9FA03B4FFF7F2FFFC +:10C1600003BC03F0ADFA00000648704502D1EFF3BE +:10C17000098101E0EFF30881886902380078024AFA +:10C1800010470000FDFFFFFF95D40300401E00BFD5 +:10C1900000BF00BF00BF00BF00BF00BF00BF00BFA7 +:10C1A00000BF00BF00BFF1D170470000401E00BFBC +:10C1B00000BF00BF00BF00BF00BF00BF00BF00BF87 +:10C1C00000BF00BF00BFF1D170470000401E00BF9C +:10C1D00000BF00BF00BF00BF00BF00BF00BF00BF67 +:10C1E00000BF00BF00BFF1D170470000056885F3B4 +:10C1F000088846680A4AEFF305839A42304602D11E +:10C20000084CA6463047074C064D0646064FF0B48C +:10C21000034C034D024E024FF0B4044800470000A7 +:10C2200000000000FFFFFFFF00000021F9FFFFFFFB +:10C2300070B505460C46164602E00FCC0FC5103E01 +:10C24000102EFAD2082E02D303CC03C5083E042ECA +:10C2500007D301CC01C5361F03E021782970641C87 +:10C260006D1C761EF9D270BD0A4610B501466648AF +:10C2700003F012F810BD10B502F026FC10BD10B589 +:10C28000624C86B01ECC03946C460EC4002807D0C6 +:10C29000684618DF002803D00022114602F0FCFF98 +:10C2A0000F20800313DF002803D00022114602F084 +:10C2B000F3FF574B48225749092003F051F8002853 +:10C2C00003D00022114602F0E7FF00200490059001 +:10C2D00001206946087404A860DF002803D000220A +:10C2E000114602F0D9FF4C4803F056F8002803D05D +:10C2F0000022114602F0D0FF06B010BD08B5474835 +:10C30000C169B12943D0002445480F214069890300 +:10C31000884204D000221146104602F0BDFF0120E1 +:10C320000007006901218902884204D000221146D9 +:10C33000104602F0B1FF3B4800903B4B0522032121 +:10C34000002001F068FA002803D00022114602F014 +:10C35000A3FF00F015FC00F058FC012500281AD0BE +:10C3600000F062FC002803D00022114602F094FF86 +:10C3700020466840FFF783FF00F038F800F07AFCB1 +:10C3800000280ED00022114602F086FF09E00124A9 +:10C390000021C161B8E720466840FFF770FF00F058 +:10C3A00025F803252D03002C04D1A86800F03EFBDE +:10C3B000002807D100F0F5FB002803D00022114629 +:10C3C00002F06AFFA86800F031FB002806D000F0F8 +:10C3D0001CFC002802D1A86800F0EFFBBFF34F8FD0 +:10C3E00013491248C860BFF34F8FFEE7094A10B5E2 +:10C3F00048321421082002F0B9FE002803D00022A0 +:10C40000114602F049FF10BDEFBEADDEE8F60300B5 +:10C41000C7F203002C2B002077C203000005004068 +:10C42000001000104BDC0300EC2800200400FA058B +:10C4300000ED00E070B5FF4C1E46A06815460229CD +:10C4400002D0042916D108E0052813D1A369002BD6 +:10C4500010D03246294604200BE002280AD1F648C3 +:10C46000406880470320A060A369002B02D03246B9 +:10C4700029469847280003D00022114602F00CFFFD +:10C4800070BD4CB5EB4E0120307005200195009435 +:10C4900000F006FB4CBD10B5E64C2078002801D01A +:10C4A000082010BD206901F0A2FA002803D0002264 +:10C4B000114602F0F1FE0F2100228904206901F0EB +:10C4C00059FA040003D00022114602F0E5FE20468E +:10C4D00010BDD84910B5D7481C3141610221816097 +:10C4E000C1681C3002F007FD002803D0002211466D +:10C4F00002F0D2FE10BD00B589B01822CF4902A8C3 +:10C50000FFF796FE069807990090019102A80FC8C0 +:10C5100000F0C6FA09B000BD00B5C64987B0498829 +:10C520006A4611810321090389680691C2490120E5 +:10C5300050394A6803928A680492C9680591069A3C +:10C540000091019202A90EC900F0AAFA002007B0DA +:10C5500000BD10B588B0182102A802F0C5FF002464 +:10C56000B4480294408869468881B3480799503896 +:10C57000C06806900191009003A90EC9204600F002 +:10C580008FFA204608B010BD00B5AA4987B0498887 +:10C590006A461181A849032050394A6803928A6883 +:10C5A0000492C9680591069A0091019202A90EC9E8 +:10C5B00000F076FA0020CAE73EB5A04A6B46183272 +:10C5C00007CA07C39B4D00246C7029466C801C3140 +:10C5D000684602F044FC002801D0AC603EBD032058 +:10C5E0009449000380681C3148609248944A0021B5 +:10C5F000103001F063F9002803D00022114602F048 +:10C600004BFE0F2100228904286901F0B3F90028AC +:10C6100003D00022114602F03FFE01206C60A860AA +:10C6200000203EBD83498861704770B542688248EA +:10C630001468536891685038D26804604360C260DF +:10C6400081600078440701D5840705D19C0703D198 +:10C650008C0701D1940701D0062070BD5B189A1891 +:10C66000744D0F239B02EA60994207D80321090306 +:10C6700089687723DB02591A914201D20C2070BDE0 +:10C680006D4C7049216070496160C10701D06F48ED +:10C6900004E0800701D56E4800E06E48A060A868FD +:10C6A000012802D00826304670BDFFF7F4FE0600D0 +:10C6B000FAD12168E8688847F5E770B5050004D02D +:10C6C000287A800703D0102070BD0E2070BD594C11 +:10C6D000A068032805D0042801D0052803D008202D +:10C6E00070BD0520A0606868E168860060688019F8 +:10C6F000884204D90020C04360600C2070BDFFF761 +:10C70000CAFE0028FAD1A96832466368606902F05F +:10C71000C2FB0028F2D1616889196160E268914228 +:10C72000ECD0092070BD10B5424C0820616800298A +:10C7300000D010BDA1680429FBD13F486178403882 +:10C7400002F010FC002802D00021617010BD05210C +:10C75000A16010BDF8B5374C0746A068032804D087 +:10C76000042804D008252846F8BD0420A06060688D +:10C77000002801D00820F8BDFFF78DFE0500FAD192 +:10C780007868860060788119402901D90920F8BDB0 +:10C79000294AB968403A1018324602F046FE6078DD +:10C7A00080196070DFE710B5224CA068052813D10E +:10C7B000E168606888420FD10620A060FFF76BFE39 +:10C7C000002808D16069E168406802F005FC002893 +:10C7D00001D10721A16010BD082010BD10B515487A +:10C7E0008168072901D0082010BD006901F0FFF819 +:10C7F000002803D00022114602F04EFD0E4880684A +:10C80000804710BD1CB506200195009400F048F942 +:10C810001CBDF8B51C4617460D46064600F0CEF87E +:10C8200000282AD00120000385421AD9291B301B79 +:10C83000234611E000280020142D0020F8F6030004 +:10C8400083C40300D3C40300F7C4030019C5030065 +:10C8500089C5030053C503001A46FFF7DAFF002815 +:10C860000BD13A462946304600F0B3F8002804D1EF +:10C870003A462946304600F0A1F8F8BDF0B589B037 +:10C88000684600F00BFA049800282AD00121090319 +:10C89000079A4018904226D9501A45081046049A23 +:10C8A0000C468718024668001618001908900320E5 +:10C8B00000038068049988420DD261190846042259 +:10C8C00000F087F800280CD121460422084600F029 +:10C8D00080F8002805D1BA1B2B4630460899FFF78F +:10C8E00098FF09B0F0BD049A079800F072F8F8E7D5 +:10C8F00000B58DB004A800F0D1F9099800280DD03A +:10C90000089800280CD008990B9840180190002135 +:10C910000998009180080290684618DF0DB000BDAC +:10C92000032000038068F1E700B58DB004A800F093 +:10C93000B5F909980028F1D0089800280ED0089978 +:10C940000B984018032100910F2102908903099848 +:10C95000019180080390684618DFDFE70320000399 +:10C960008068EFE730B591B0684600F097F9049819 +:10C97000002814D001210903079A4018904214D9C5 +:10C98000501A43081046049A5C0082180019611876 +:10C9900003242403A468049DAC4202D20E2011B0EB +:10C9A00030BD121AFFF735FFF9E703200CAB07C3C0 +:10C9B000049880080F900CA818DFF0E71FB5032338 +:10C9C00001909008039000930291684618DF04B02C +:10C9D00010BD1FB5012301909008039000930291B0 +:10C9E000684618DFF3E7000010B5BB480368012B69 +:10C9F00002D1022900D10160100003D000221146AB +:10CA000002F04AFC10BD10B5B34C48DF002803D03B +:10CA10000022114602F040FC02F0FCFB20680228D4 +:10CA200003D0032801D00428EFD110BD38B5006829 +:10CA3000401C19D00024684600F058F9009801689D +:10CA4000012910D1818800290AD0C1680320000380 +:10CA50008068002202F0CEFA00998988814201D1D3 +:10CA6000012400E00024204638BD10B504469A4851 +:10CA70002021001D02F0B9F9002803D00022114640 +:10CA800002F00AFC9448002320222146001D02F0F7 +:10CA90001BF9002803D00022114602F0FDFB10BD57 +:10CAA0000FB4F8B5684600F021F96846818B069D01 +:10CAB0000122894CFF238948002D13D0012D17D066 +:10CAC000032D2BD00021022D37D02A46052D46D02C +:10CAD000042D4ED0062A01D104202060F8BC08BCE9 +:10CAE00004B0184781800A9983600260C16010E039 +:10CAF0008180099D089949190A9D4919C160A5219C +:10CB000083600160089901610999856141610B9910 +:10CB1000C16122607148FFF7A8FFDFE700990B6849 +:10CB200003608B888380C968C160AA2181600899ED +:10CB30000161099941610A990BE0009D2E68A52EBB +:10CB400009D00660AE888680ED68C56001618360AB +:10CB500041618161DDE781800360C160F6E700F03B +:10CB600085F9002803D00022114602F095FB03202E +:10CB7000B3E781800360C160009989688160C9E77B +:10CB80000EB557480090202001900120029002F03D +:10CB900001F8002804D150496846091D02F023F825 +:10CBA0000EBD10B5FFF708FD002805D100F02FFBE2 +:10CBB0000446FFF728FF204610BD70B511DF00289E +:10CBC00003D00022114602F067FB464900200B68A3 +:10CBD000444C012180340A4682401A4204D0C506E2 +:10CBE000ED0E0A46AA402260401C2028F3D30324FD +:10CBF0002403A06813DF002803D00022114602F0AE +:10CC00004BFBA06802F0F2F970BD08B5684600F071 +:10CC10006DF800980168A52904D08068AA2801D081 +:10CC2000002008BD012008BD10B5FFF79BFE0028BD +:10CC300003D1FFF779FE00281BD0642001F0F2FD3C +:10CC4000FFF71CFE002803D00022114602F024FB4F +:10CC5000FFF788FE002803D00022114602F01CFBDB +:10CC6000FFF746FE040003D00022114602F014FB39 +:10CC7000204610BD00B589B018221B4902A8FFF755 +:10CC8000D7FA069807990090019102A80FC8FFF7FC +:10CC900007FFFFF7B8FE002009B000BD10B50E4930 +:10CCA00088B0044600232022091D684602F04FF890 +:10CCB0000098206068468088A0800398E060029811 +:10CCC000A06004982061059860610698A0610798AB +:10CCD000E06108B010BD000024280020202D0020B5 +:10CCE000E9C9030000E100E01CF70300014901600D +:10CCF0007047000000FC030008280CD004DC00286A +:10CD000007D006280FD108E00B280AD00C280AD13A +:10CD100005E001207047022070470320704704207F +:10CD20007047042901D0062070470520704770B570 +:10CD300015460A46032823D0042820D1FE4C00299A +:10CD400006D0E088FD49884219D0132176DF10E033 +:10CD5000284602F0A3F9002803D00022114602F071 +:10CD60009BFAE069A8420AD101220321F44801F0AC +:10CD700003F8002803D00022114602F08DFA70BD9E +:10CD800001211046FFF7B8FF02460121EEE7F0B59A +:10CD9000054608790E4685B081070CD0032211465E +:10CDA000284600F0E9FF002803D00022114602F0D7 +:10CDB00073FA05B0F0BDE0490090183102F047F970 +:10CDC000010011D1DC4CB168009AA06902F02DFB82 +:10CDD000009802F097F9010006D120466946183004 +:10CDE00002F09CF9010003D0284600F0AFFAE0E71A +:10CDF00004200190009880080290A069039001A887 +:10CE0000FFF75BFC07000BD0092F10D0A06902F0E0 +:10CE100045F9010002D0284600F098FA3946E3E7C8 +:10CE20003079616940186061A069E061C1E73079DB +:10CE300061694118616160780028BAD06089401E3C +:10CE40000004000C6081B4D1284601F0E9F8002804 +:10CE500003D00022114602F01FFA20896081A8E762 +:10CE600010B50022114602F017FA10BD10B5B24CF1 +:10CE700001202070E088B149884208D0132176DF74 +:10CE8000002810D00022114602F006FA0BE0A0782C +:10CE9000002808D074DF002803D00022114602F0D9 +:10CEA000FBF90020A07001F034FC002803D0002220 +:10CEB000114602F0F1F9002010BD70B50D6804466E +:10CEC00001209D4A2B0002F002FC0A2B304306137E +:10CED00020575C466012FFF766FC0421FFF70CFF49 +:10CEE000024604212EE00022114602F0D5F970BD61 +:10CEF000FFF7BCFF002803D00022114602F0CCF956 +:10CF0000FFF76CFC002808D170BDFFF7AFFF0028C9 +:10CF100003D00022114602F0BFF9FFF773FC70BD89 +:10CF2000106188680078107170BD022010618868F7 +:10CF300000780128F8D1FFF7F6FB0221FFF7DCFEAD +:10CF400002460221204600F017FF0028CBD170BD19 +:10CF50000320106170BD12692046012A06D0022A02 +:10CF600007D0032AF6D1FFF712FF70BD00F001FAD7 +:10CF700070BD00F03BFA70BD507088881081508100 +:10CF800070BD00205070108170BD2046516901F0C5 +:10CF900010F8DAE710B5044669488EB08179684622 +:10CFA000817068490180342101A802F09DFA0220B5 +:10CFB000019000216846417284720121018205902E +:10CFC000002101A801F03FFA002803D000221146F9 +:10CFD00002F062F90EB010BDF0B5574C8BB0A078DE +:10CFE00000283AD156481821183802F07DFA204618 +:10CFF000534CC078183C00250126002837D027461E +:10D00000483700950195029510226946F81D039551 +:10D0100002F0DEF9002822D0F81D08900997684632 +:10D02000067509A804906846067708A806900420AB +:10D03000FFF7B0FF25700220207204A8E0602820CE +:10D0400020823F486582183873DF002803D0002211 +:10D05000114602F021F9384886700BB0F0BD05206A +:10D06000FFF798FF2670676025722582E9E70620A2 +:10D07000FFF790FF257065602572E0E770B52E4CD4 +:10D0800001880022E588A6B017290AD01EDC1129E4 +:10D090003FD008DC022977D0102902D18088E080B7 +:10D0A000A27026B070BD264C30342646183613299F +:10D0B00051D01429F5D1C289638D00219A4200D143 +:10D0C000314600238088E21D82DF1BE0512970D0A9 +:10D0D0000EDC18296CD01929E3D180790028E0D121 +:10D0E000A270E068401EE0604FD0FFF775FFD8E700 +:10D0F000522976D05529D4D180790028D1D1132155 +:10D10000284676DF0028CCD00022114602F0C4F871 +:10D11000C7E78020694688803220E060012301AAA9 +:10D1200006A92846AADF002803D00022114602F0F3 +:10D13000B3F82078002807E030280020FFFF000027 +:10D14000582D00203015000001D1FFF745FF0020C9 +:10D15000C043E080A5E70722C14910A802F065F9A5 +:10D160001022E11D0CA802F060F91C22314612A821 +:10D1700002F05BF90CA80A9012A8099006ABB94A14 +:10D18000852128467FDFBDE70DE01822B64906A8B5 +:10D19000FFF74EF80A980B990090019106A80FC866 +:10D1A000FFF77EFC7DE70021284667DFAAE700E065 +:10D1B00017E0817900299AD0807A042803D00628C4 +:10D1C00001D0052893D1022909D0012069460872AF +:10D1D000FF208330888102A92846A8DF92E7022039 +:10D1E000F4E700F08DF88DE710B5044601F0C2FABF +:10D1F0009B482146303800F09AFE2046FFF73EFF5C +:10D2000010BD10B50022114602F046F810BD30B531 +:10D21000944D87B00024203D2C7094482C6102F07E +:10D22000B3F800286AD19248FFF7FCF901F000FF3B +:10D23000002863D18A4800F059F9002801D1012063 +:10D24000E87011206946087207228AA102A87CDFD3 +:10D25000002803D00022114602F01EF800940C2191 +:10D2600068460194018018214180FF21848091311A +:10D27000C1807ADF002803D00022114602F00CF8AA +:10D2800004206946009408807C4801907C48029004 +:10D290007348303800F00BFE002803D000221146FE +:10D2A00001F0FAFF1C21684602F01EF97548019052 +:10D2B0000120800302900094032168460173C48119 +:10D2C0000474714806900594684601F0FEF9002840 +:10D2D00003D00022114601F0DFFF6249E122087805 +:10D2E0004008400010400C30DF221040087007203A +:10D2F000487010208870FFF76FFE002007B030BD27 +:10D3000070B5584C614D203CE088A84201D10820FE +:10D3100070BDE178002914D051490123082234312D +:10D32000A9DF0028F4D12A460C21E088A7DF58495C +:10D33000884204D0082802D0891C8842E8D1002005 +:10D3400070BD00231A461946A9DF70BD10B50A4604 +:10D35000044603211046FFF7CFFC02460321204676 +:10D3600000F00AFD002803D00022114601F094FFCE +:10D3700010BD30B5054687B00020009001900290A6 +:10D38000039038486A46203800791070364A0C3AC3 +:10D3900010689268049068460692059008790C28F7 +:10D3A00006D003221BE00022114601F075FFA5E71D +:10D3B0008C68204600F049F80190201D00F045F8E7 +:10D3C00002902046083000F040F8039004A8FFF7D0 +:10D3D0002CF9002892D00121FFF78EFC0246012192 +:10D3E000284600F0C9FC0028DDD187E7FEB50446D9 +:10D3F000087982070ED08207920F04239B1A00221D +:10D40000154604E08E683554401CC0B2521C9A4246 +:10D41000F8D308710120009088680290087980088C +:10D4200001906846FFF796F900280DD00221FFF71A +:10D4300063FC02460221204600F09EFC002803D037 +:10D440000022114601F028FFFEBD10B5044602F08F +:10D450004DF80002E178000A0906084310BD0000FB +:10D46000882D00205028002040F70300E9D1030058 +:10D470002FCD03004466755461726700BBCE030074 +:10D4800003D20300CD0C000061CE0300FFFF0000BB +:10D490000230000010B50C46002802D001200860C0 +:10D4A00010BD2168002911D01C48421A814212D0B7 +:10D4B0003C2A0DD23C303C3101220B7803701346DC +:10D4C000491E401E521C3C2BF7D904E00E200BE0F5 +:10D4D0003C2201F0AAFF00223C21104801F08AFD05 +:10D4E0000E49891E08800020206010BD70B50546D9 +:10D4F00000223C21094801F07DFD084CA41E218832 +:10D50000884201D00B2070BD3C220449284601F01E +:10D510008CFF2088401C2080002070BD823F0020AE +:10D520008307FF22DB0E9A408907090E99400028E5 +:10D530000BDA0007000F08388308FA489B001B1815 +:10D54000D86990430843D86170478308F6489B0028 +:10D550001B181868904308431860704770B5012481 +:10D56000F24960040860F24940108860F04940398F +:10D570008860F04D6C602F20FEF708FEAC60EE4D29 +:10D5800000242F206C61FEF701FE2C7170BDF0B5F8 +:10D59000E94F2821BC6841430D1939694A1C09D05B +:10D5A00028224A431619AB68B268934204D8D21AAB +:10D5B000B26069623861F0BD0A4602E00A46796AE3 +:10D5C0009B1B4E1C0BD028264E433719BE689E422B +:10D5D000F4D328264E433619B768FF1AB760AB60FC +:10D5E000696228214A4311194862F0BD70B5D24CD6 +:10D5F0002269A5681346114606E0814207D00A4613 +:10D60000282671434919496A4E1CF6D170BD002E77 +:10D61000FCD08A420CD1282043435819406A20612B +:10D62000401C05D1C34B01209860002363616071E9 +:10D63000282041434819282381685A43406A5219D7 +:10D640005062421CE2D0282250434019826851188F +:10D65000816070BDF8B5B84C2569681C35D0B748F5 +:10D66000002640686169401A07023F0A19E0282035 +:10D670004543A0682A189068B84214D8A3693F1A95 +:10D680008619556A002B09D0116AD069984700287D +:10D6900007D00022114601F0FFFD02E0D169106AB7 +:10D6A0008847681CE3D1A178E078814206D1401C0C +:10D6B000C0B2E070022801D10020E0709E4900064F +:10D6C000800D1C310E5000F0BAF9F8BDF8B50446D3 +:10D6D000994800270169009146785CE09648F1007E +:10D6E000C2688D1851E0601C07D0934A28209268C8 +:10D6F000604321468018446A24E028781821414379 +:10D700006A68401CC0B252182870A978884200D1BB +:10D710002F70894B516828209B684843C0181368B4 +:10D72000012B34D1037E002B31D19368C360D368C1 +:10D73000036113694361526902627F4A5279002A88 +:10D7400000D0C7607C4BC2685B6996469C46D31A82 +:10D750001A027B4B120A9A4202D20369D21808E0DD +:10D76000724663469A1A12020369120A934202D958 +:10D770009A1A826000E08760C76001220761027622 +:10D78000921E42620846FFF702FF601CABD1287868 +:10D7900069788842A7D13046761EF6B200289DD11E +:10D7A000654801690098814201D00120F8BD002040 +:10D7B000F8BD64490020086048608860C86061491D +:10D7C00040390860486045E7FEB50020C0435A4D27 +:10D7D00002906869019068462E6900F035F90746A5 +:10D7E00000F04FF90446002F08D002AA01990098D2 +:10D7F00000F08FF90298FFF769FF06E00298FFF743 +:10D8000065FF002801D1002C02D0304600F0AAF9B3 +:10D8100000206871FEBDFFB59807002481B01E4648 +:10D8200015460F4600280BD1002E09D0FFF796FEB3 +:10D8300041490A9888610F70324600208E6008E0E6 +:10D84000072005B0F0BD28234343D4509B181C7615 +:10D85000401CB842F7DB28204743BB19032048701F +:10D860000F461846CB6019461830002218232E4662 +:10D870005E43D3005B181C705C709D70586030185C +:10D88000521C032AF5DB0020C0433861BC70FC70D9 +:10D8900001242D482405046003211420FFF740FED5 +:10D8A000224880380460254C0198A0600321112093 +:10D8B000FFF736FE606878610020C2E770B51E4C45 +:10D8C000A568002D06D0002A06D0002804D0002329 +:10D8D000247809E0082070BD072070BD28265E432B +:10D8E000AE59002E04D05B1CA342F7DB042070BDB0 +:10D8F000282401265C432E516419E26161600360B3 +:10D90000002070BD07494868C005C00D2CD01038F4 +:10D910001CD50207120F083A920892005118C969E3 +:10D9200019E0000000ED00E000E400E080E100E02C +:10D93000401301400010014058280020001501400C +:10D94000FFFF7F004011014080E200E08108B14A02 +:10D950008900891809688007C00EC1400806800F39 +:10D96000012803D0032803D002207047002070470D +:10D9700001207047FEB50446A748174682680D4649 +:10D98000002A0CD001788C4201D2052D01D207204B +:10D99000FEBD2146282359435358012B01D00820AE +:10D9A000FEBD8818406801281DD00026FFF7AAFF99 +:10D9B000C00099490190C9684018694600F018F9FB +:10D9C000002812D001214460016094494968083060 +:10D9D000E2C091490198C96841180098487000F068 +:10D9E0002EF80020FEBD2E46E0E70420FEBDF8B56F +:10D9F000894D0446A868002809D029788C4201D3B3 +:10DA00000720F8BD282161434058012801D0082093 +:10DA1000F8BDFFF777FFC600E8686946301800F0E8 +:10DA2000E7F8002809D0022112C0E86831180098F0 +:10DA3000487000F004F80020F8BD0420F8BD012073 +:10DA4000774900050860704710B5734900238A784C +:10DA5000CC78A24212D0521CD2B28A70022A00D1D3 +:10DA60008B708A786C4B92001C339A58026048691C +:10DA700010180002000A4861012010BD0360002058 +:10DA800010BDF8B5644801690091457833E06248FB +:10DA9000E900C0680E1834782AE0182060437168E5 +:10DAA000641C0818B178E4B2A14200D100240168D6 +:10DAB000022902D003291BD113E0574A40682821CC +:10DAC000926841438F18397E002911D0FFF78EFDEF +:10DAD000002038760CE028277843C0180276406A88 +:10DAE00003E04D4900228B680869471CF3D10861A7 +:10DAF0007078A042D1D128466D1EEDB20028C6D163 +:10DB0000454801690098814201D00120F8BD0020FC +:10DB1000F8BDF7B5404C0025A76823691EE0282111 +:10DB20005943C9198E68864202D9301A886017E0B5 +:10DB3000801B751900268E600E764E699C464B6AD6 +:10DB4000B646002E0AD0019E76193602360ACE60FD +:10DB500076460E6116684E6261461160591CDED130 +:10DB60002361FEBDF8B52C4801694A1C3DD028222E +:10DB70005143826889188E6828494C684769007942 +:10DB8000E11B0D022D0AED1C002815D10120254AAC +:10DB900000045060234A403A5060214940008031DF +:10DBA0000860214908602149012008602F20FEF704 +:10DBB000EDFA194901200871B54200D23546E8193D +:10DBC00000021649000A4031086014494968001BE8 +:10DBD000091B0902090A0002C91C000A814203D973 +:10DBE00001200F4940040860F8BDFFF7B7FCF8BDFD +:10DBF00042788378521C934200D1002203789342EA +:10DC000001D1002070470A604168407818225043D3 +:10DC10000818704700E400E0582800200015014073 +:10DC200000E200E04013014000E100E0001001408C +:10DC300010B50446082904D000221146104601F010 +:10DC40002BFB21686068884710BD1CB501910090CE +:10DC5000024A0821684601F09DFA1CBD31DC030030 +:10DC60000A48026803210A430260094880470948BC +:10DC70000047FEE7FEE7FEE7FEE7FEE7FEE70000FF +:10DC800005480649064A074B704700002405004036 +:10DC9000A9DC0300C1C0030090300020903C0020AC +:10DCA0009034002090340020F8B500F035F82B4E69 +:10DCB000002804D02A4870602A49F01388612A4855 +:10DCC0000124018CC9B201290DD1818C09070AD127 +:10DCD000018D0906090F042905D1808D0006000F6A +:10DCE00001D1224884600027B461214D6F60A805EE +:10DCF0008460686800280ED1C820FEF757FA1D48D6 +:10DD00007F1C8742F5D30020B0610120800784602A +:10DD100068680028FCD0F8BD1348018CC9B20129FD +:10DD200017D1818C090714D1018D09060A0F03D17F +:10DD3000828D1206120F0ED0090F012903D1828D98 +:10DD40001206120F07D0032903D1808D0006000FA1 +:10DD500001D00020704701207047000000050040FE +:10DD6000DFFF07C0006C0040C00F00F0000600405D +:10DD7000000100408813000030B585B0002822D093 +:10DD80000388FE4CA34220D0FD4B1B78002B1CD0F7 +:10DD9000FB4B10255B1C1D705970002401259A70E7 +:10DDA000032269460A820094019402940394028A31 +:10DDB0000A808D708C8004A90291039300886946C3 +:10DDC000A6DF05B030BD0E20FBE70820F9E7F0B56F +:10DDD0008BB004460227684607730026099687849D +:10DDE000C68408A80A900D46A18A208809AAA5DF42 +:10DDF000002804D0E16A00291AD0884718E0684654 +:10DE0000008CC007C00F13D068460682208803A983 +:10DE1000A8DF002813D1A97E28461B3001220B0061 +:10DE200001F055FC09430F1B202224263E28430005 +:10DE3000FF20FE3069460882208803A9A8DF0BB0C6 +:10DE4000F0BD00960AE0062219E069460A710290C8 +:10DE500022E0204690470020F1E700922B8B022B16 +:10DE6000F3D2F0E700971DE003201AE0042018E049 +:10DE7000052016E0298B032905D20322082120461C +:10DE8000FFF77AFFDBE74178027808021043694622 +:10DE9000888003D006200090A26ADAE70720FAE71C +:10DEA000092000906946A26AD3E70322E7E730B56C +:10DEB00085B00D46040038D0002D36D068680028A3 +:10DEC00033D00020C043AF4B20800FCB049301AB75 +:10DED00007C3AD4869460880891C01A863DF002894 +:10DEE00022D1221D69460120A0DF00281CD16846EE +:10DEF0008078A071204600F0CEF8002814D120468A +:10DF000000F055F900280FD12946204600F002F90B +:10DF1000002809D16868A062A868002800D0E062E3 +:10DF200097490120087000204BE70E2049E73EB5D5 +:10DF3000002828D0002926D0826A002A23D00A8807 +:10DF4000102A21D0112A30D0502A1FD0512A1AD19C +:10DF500004460846891D0A78022A14D14A88238A71 +:10DF60009A4210D1807A04280DD006280BD00528BB +:10DF700009D0891C2046FFF72AFF002803D0E16A58 +:10DF8000002900D088473EBD898810E0CA880389EF +:10DF90009A42F8D1082200928A7F6B461A7120318A +:10DFA0000291826A694690473EBD0021C9430180C3 +:10DFB0003EBDF0B585B00A4605002DD028886F49D2 +:10DFC00088422BD06E480078002827D06C4C102057 +:10DFD000641C2070072060700127A7700321684629 +:10DFE00001820026E11C104600F04CF8014668460C +:10DFF000008A0918684601820096019602960396E7 +:10E00000298A01808770868004A80394029028885A +:10E010006946A6DF05B0F0BD0E20FBE70820F9E752 +:10E02000F0B585B00A46050028D0288853498842B3 +:10E0300026D053480078002822D0514C1120641C6F +:10E0400020700127684607820026611C104600F0F8 +:10E0500019F801466846008A091868460182009648 +:10E06000019602960396298A01808770868004A80B +:10E070000394029028886946A6DFCBE70E20C9E703 +:10E080000820C7E70870020A4A70020C8A70000E66 +:10E09000C8700420704730B58FB005461C21684613 +:10E0A00001F022FA6946087804210843694608709D +:10E0B000002401940394049405940694A87908A973 +:10E0C000887031486946801C0884601C00070794EA +:10E0D000000F0C77103048778A7FF9200240921C9D +:10E0E000E7200240012002438A77142109A801F0A9 +:10E0F000FBF908A8099007A80A9069468C851420A6 +:10E10000CC8508860D942B46A888083309AAA2DF7F +:10E110000FB030BDF0B58FB00F4605461C216846E4 +:10E1200001F0E2F9684601780226314301700024CB +:10E1300001940394049405940694A97908A8817025 +:10E1400011496846091D0184601C0107090F10313F +:10E150006846079401770020014668464177817F31 +:10E16000F9200140891CE720014001200143684655 +:10E170008177142109A801F0B7F907E0FFFF00003B +:10E180008028002058F703003015000008A80990E7 +:10E1900007A80A9068468685C48506860D972B4693 +:10E1A000A888203309AA6946A2DF0FB0F0BD30B5B8 +:10E1B0008FB005461C21684601F096F9694608783B +:10E1C0000821084310221043694608700024019476 +:10E1D0000394049405940694A87908A988701448B7 +:10E1E00069460884601C00070794000F0C77103004 +:10E1F0004877887FF9210840801CF72108401043A8 +:10E200000121084369468877142109A801F06CF9B7 +:10E2100008A8099007A80A9069468C851720CC8524 +:10E2200008860D942B46A888103309AAA2DF6FE751 +:10E2300031150000FFB583B0074600200C9C8646D0 +:10E24000267805463AE07868A90041180A886846A9 +:10E2500082804988C1800022694601A865DF0028C4 +:10E2600010D1684601780598814226D17046002871 +:10E2700001D0002200E002222078891841181F29CD +:10E2800002D90C2007B0F0BD7146002908D1401C0E +:10E29000C0B2411C069B049A21701A540120864684 +:10E2A000217806980A18694601A865DF0028E9D197 +:10E2B000694620780978401820706D1C3888A8427B +:10E2C000C1DC7046002804D020780699801B401ECF +:10E2D00088550020D6E7F8B51546069C1E46074629 +:10E2E00002220094FFF7A6FF002806D13346102231 +:10E2F000294638460094FFF79DFFF8BDF7B582B078 +:10E3000000260546167000681446002805D02846E9 +:10E31000039900F0CAF8060008D1687900281ED0D9 +:10E320002078039F001D1F2802D90C2005B0F0BDE6 +:10E33000684679DF0028F9D121780322481C207033 +:10E340007A5421781922481C20707A542078C119F7 +:10E350006846008800F0A4F8217840182070A87959 +:10E360000223002810D02078039A411C21701354F6 +:10E3700020780399471C012227700A542078AA7933 +:10E38000471C039927700A54A868002815D000215B +:10E39000415620788C460246C01C03991F28C4D8D9 +:10E3A000501C20708B5422780A23501C20708B54F0 +:10E3B00020786246431C23700A54A889002809D09B +:10E3C00028460094062202210C30039BFFF783FFAE +:10E3D0000600ABD1A88A002809D02846009407225D +:10E3E00003211430039BFFF776FF06009ED1A88B14 +:10E3F000002809D028460094152214211C30039BC4 +:10E40000FFF769FF060091D1686A002805D022460F +:10E41000039900F07FF8060088D1A86A002805D08B +:10E420002246039900F0B5F8060084D13020405D03 +:10E43000002806D022462846039900F0DCF80600A2 +:10E44000C7D1304672E770B50C4692B000216A46DB +:10E45000117007251171002809D0817949070CD561 +:10E4600002A9FFF74BFF002808D102AE00E000260A +:10E47000002C0ED0A079002802D0284612B070BD22 +:10E4800001AA0AA92046FFF739FF0028F6D10AAAF7 +:10E4900000E00022684603790178304672DFEDE73C +:10E4A0000870000A487002207047F8B514780746D3 +:10E4B000A01C15460E461F2803D83879801C1F283B +:10E4C00001D90C20F8BD1D20001B80B2694686468C +:10E4D00008803019801C7DDF0028F3D138680228BD +:10E4E00005D168460088704501D8092107E03879D0 +:10E4F0000821002801D0704501D968460088421CD7 +:10E500003255641CE2B2B1542978801C0818287076 +:10E510000020F8BDF8B50D4611780646881D144652 +:10E520001F2801D90C20F8BD33880720062BFAD309 +:10E530001927FF01BB4202D94D4A9342F3D1728899 +:10E54000062AF0D3BA4202D9494FBA42EBD1484F1A +:10E55000BB4203D0BA4201D09342E4D8481C052202 +:10E5600020706A5420781222411C21702A5420788D +:10E5700041193088FFF794FF21784018C0B220700D +:10E5800041197088FFF78CFF217840182070002017 +:10E59000F8BD70B5054600790E46801C1446C0B221 +:10E5A0001178821C8A181F2A01D90C2070BD0A46D6 +:10E5B000491C401C2170B0542078FF22411C21705E +:10E5C0003254207881192888FFF76AFF2178401893 +:10E5D000C0B22070AA88002A09D0A968002908D0F2 +:10E5E000801900F022FF207829794018207000203F +:10E5F00070BD072070BDF7B582B002981446C06A9E +:10E600000F46002832D0029800252030009028E0E4 +:10E610000298C16A0C2068430E18217830794A1C90 +:10E62000C01C2270785421781622481C20707A541D +:10E630002078C1193088FFF733FF21784018C0B225 +:10E640002070B288002A09D0B16800290ED0C01904 +:10E6500000F0EBFE20783179401820706D1C009896 +:10E66000EDB2007CA842D3D800205FE607205DE62B +:10E67000FFFF000038B56749674A488890420FD0CD +:10E680004A78664C521CD2B24A70237B934208D31C +:10E69000083175DF002803D0A169002900D0884720 +:10E6A00038BD00254D70217C002907D03B2176DF45 +:10E6B000002803D0A169002900D08847616900299A +:10E6C000EED068460095884738BD70B505460146CE +:10E6D0001C225248FDF7ACFD4E4C002626702968DE +:10E6E000002907D00822A01800F09FFE204608301D +:10E6F0007ADF02E0474808307BDF002808D1401E5F +:10E70000608044486670464A0021001DFFF7D6F835 +:10E7100070BD10B53F484068FFF769F910BDF8B506 +:10E720003C48103000F069F800263A4D3B4C002878 +:10E7300006D06169002919D001200090684614E0D4 +:10E740002878002804D0616900290FD00096F5E7E9 +:10E75000687800280CD0A16800226868FFF70AF9E1 +:10E76000002803D0A169002900D088472E70F8BD89 +:10E770006168F1E7F8B5294C02880027254DE68944 +:10E78000102A18D029464968112A21D0122A2DD0E2 +:10E79000502A0FD1801D0288B2420BD1028B022A6F +:10E7A00008D1C27E837E10021843C007C00F13D069 +:10E7B000FFF7B5FFF8BD818869800146154808223A +:10E7C0001631103000F031FE6F70002EF0D0F8BD21 +:10E7D0000020C04368806F700846FFF708F90028E2 +:10E7E000F5D0A1690029F2D08847F8BD811D0948FC +:10E7F0000822103000F019FEDAE741880548083099 +:10E800000288914204D34088814201D80120704798 +:10E810000020704788280020FFFF0000C42D002042 +:10E8200075E6030031B5054C04E0401E009020461B +:10E83000FDF7CCFC00980028F7D138BDE7030000B5 +:10E8400018225043FE4A0021801801718160416105 +:10E85000012281610261C1607047FFB581B0F94C4E +:10E86000049B039A054626691A4303200092002E52 +:10E8700003D1002A0ED0012222612769039A0126C2 +:10E88000360792003B0000F022FF072707162940B9 +:10E89000526127000222EFE77069326992B2504359 +:10E8A000326933691204920C9BB2594329DF002864 +:10E8B00012D102210FE0084628DF00280CD103996D +:10E8C000002901D0032106E00499002916D12978F6 +:10E8D000042946D017E0216105B0F0BD70693269A6 +:10E8E00092B25043326993B24B4301461846039AA1 +:10E8F00029DF0028F0D10499002901D00421EAE79A +:10E900002978042920D00521E5E773693069366943 +:10E9100080B2434368681B189B18B6B24E43301848 +:10E9200080181946049A29DF0028E9D0D4E7306915 +:10E9300080B24843696880188A08696929DF00281D +:10E94000CAD1009900290CD00621C4E77069316949 +:10E9500089B24843316989B200F0D9FD28DF002827 +:10E96000BAD10721B7E7F8B5B54918230A780F20BF +:10E970005A435418241DB34922782669CF68022AC5 +:10E980001BD001252D07042A2AD0052A5BD128692E +:10E9900081B2304600F0BBFD0146A36828699A1990 +:10E9A00080B24843101A82086068181886192869CE +:10E9B0004B1C80B25843801B34E0B8026268616926 +:10E9C000121A0918A3683018181801239B029A42DA +:10E9D00002D2920829DF31E0FF22013229DF2DE047 +:10E9E000E268974914205043F4314018001D0BC8C9 +:10E9F000B04203D160685943814218D0022A16D030 +:10EA0000286981B2304600F082FD0146286980B253 +:10EA10004843301A820828694B1C80B25843636807 +:10EA20009B19C01A83082046FFF717FF06E02869E4 +:10EA300081B2304600F06BFDC01928DF002802D1FA +:10EA40007F4901228A70F8BDF8B57D4C069E657835 +:10EA50000A2D1DD027787D19EDB20A2D01D30A3D6C +:10EA6000EDB218277D432D192871AA6103C9EE6004 +:10EA7000AB6069612861A1780020002904D1FFF70B +:10EA800072FF112800D100206178491C6170F8BD27 +:10EA90000420F8BD38B50246694818230178594367 +:10EAA000081803690179022B0AD014246343644CCB +:10EAB000F434E4588368009383691030A04738BD6C +:10EAC000604B14331C68F5E7F8B55D4B9978012964 +:10EAD00014D100255B499D700A69082A05D00228D7 +:10EAE0000FD003280AD10D2006E0022807D00D70B0 +:10EAF00000F025FA002801D0FFF7CCFFF8BD0D612A +:10EB0000F6E74F48182403784E496343CC68181839 +:10EB1000641C001DCC600378022B05D14668A1025D +:10EB2000B14201D3012700E00027052B01D1072ABC +:10EB300003D00021042B02D003E00121FAE7072AC9 +:10EB400003D00026042B02D007E00126FAE7406834 +:10EB5000A302834201D3002A1AD00020314301438B +:10EB60003943C5D0374E28463561FFF793FF344C03 +:10EB70002078FFF765FEF5606078401E60702078B1 +:10EB8000401CC0B220700A28B2D30A382070AFE708 +:10EB90000120E3E770B500252A4C2948E56025618E +:10EBA0000570457085702E463046FFF749FE761C8D +:10EBB0000A2EF9D3012212076560516928461269AD +:10EBC000491E92B25143E560A1601D49F4310D60C8 +:10EBD0008D600D61CD601B4914310D60888001216D +:10EBE0002170206170BDF8B5164A044610780E46B3 +:10EBF000002830D0002C30D0002E2ED020680028E5 +:10EC00002BD0012000076768016989B28F4228D89C +:10EC1000102F26D3A168002923D095687943436932 +:10EC20004A19006980B243439A421AD8012000076A +:10EC3000006980B2814212D901200007006903E017 +:10EC4000E02D0020A028002080B2394600F05FFCB3 +:10EC5000002906D103E00820F8BD0E20F8BDB80752 +:10EC600001D00720F8BDBD49486801281CD00F46D7 +:10EC70001421BB4A21C641438E1875602368535046 +:10EC80006168B160A168F160A268616800235143C6 +:10EC9000012212075B1C14699BB2A4B28C4205D2FC +:10ECA0001469A4B2091B02E00420F8BD0021146914 +:10ECB000A4B265191469A4B28C42EBD9BD60401CA2 +:10ECC000336178600020F8BDF8B50446A3481E46BD +:10ECD000007815460F46002807D0002F07D0002CDB +:10ECE00005D02068002817D103E00820F8BD0E20C9 +:10ECF000F8BD9B48016800290ED0C2688168406851 +:10ED00004A4310186268904206D9002D04D0A942E7 +:10ED100002D3A819884201D90720F8BD384600F06F +:10ED200008F9002811D0304600F003F900280CD073 +:10ED3000606800F0FEF8002807D02B463A462146CE +:10ED400002200096FFF780FEF8BD1020F8BDFFB549 +:10ED5000824881B000781F4616460D46002808D02C +:10ED6000002D08D00198002805D02868002817D168 +:10ED700003E00820B0E50E20AEE5794C20680028BD +:10ED80000ED0E168A0686268414389186A689142C0 +:10ED900006D9002E04D0B04202D3F119814201D924 +:10EDA000072099E5019800F0C4F800281BD03846E8 +:10EDB00000F0BFF8002816D0686800F0BAF8002804 +:10EDC00011D068683246C119019800F02EFB0096F8 +:10EDD0002868142148432458002203212846019B17 +:10EDE000A047002078E5102076E5F8B505465B4899 +:10EDF0000F460078002805D0002D05D0286800288F +:10EE000021D103E00820F8BD0E20F8BD544C0026A7 +:10EE10002068002817D0A168E0684843616841185D +:10EE2000686881420FD900F084F800280DD0296865 +:10EE300014225143091968684A688968801A00F0E9 +:10EE400066FB002903D00720F8BD1020F8BD3B4623 +:10EE50000022294604200096FFF7F6FDF8BD3F4A40 +:10EE60001278002A0DD000280DD000290BD002689E +:10EE7000002A08D0394A14321368002B05D0042028 +:10EE80007047082070470E20704702230B6000680F +:10EE9000106000207047F8B5044630481E460078E0 +:10EEA00017460D46002807D0002D07D0002C05D0AE +:10EEB000206802281BD103E00820F8BD0E20F8BD11 +:10EEC000264814300068002811D0084600F031F8B8 +:10EED00000280ED0304600F02CF8002809D03B4620 +:10EEE0002A46214602200096FFF7AEFDF8BD072016 +:10EEF000F8BD1020F8BD08B5184A1278002A05D0D0 +:10EF0000002805D00268022A11D103E0082008BDBC +:10EF10000E2008BD114A14321268002A07D00B4691 +:10EF20000022014604200092FFF78EFD08BD072055 +:10EF300008BD800701D000207047012070470849B4 +:10EF400010B5F43949780020002906D0FFF70BFDF1 +:10EF5000002802D0112800D1002010BDA0280020D8 +:10EF6000D42E002070B500250C290ED3044643187A +:10EF7000008941000919581A0A38C2B21748022AF2 +:10EF8000027002D30A318B4201D2092070BD1448AD +:10EF900000F04BFA134914480A88824202D02388B1 +:10EFA000934217D14988814202D06088884211D1AA +:10EFB0000D4A0323521E20891B03A8420AD9690067 +:10EFC00009194989914203D09E896D1CB142F4D13F +:10EFD000002070BD0B2070BD00207047BC280020B1 +:10EFE000E82E002080100010FFFF000010B5FDF794 +:10EFF000FDF810BD10B50446002A02D0108800228A +:10F0000010E00A48FBE7030A00020343A05C5840F3 +:10F0100003061B0F43401803584083B21806C00C68 +:10F020005840521C8A42EED310BD0000FFFF000082 +:10F030004B48002101704C484A4A02608160C1601F +:10F04000016108224161426081610846704710B544 +:10F0500000291DD000220A60434A5368002B1BD0B0 +:10F06000202817D85B1E5360D0682423401CD06032 +:10F07000106914684343E3180B60012383409169CE +:10F08000401C19434007400F91611061002010BDE2 +:10F090000E2010BD0C2010BD042010BDF0B5324A6A +:10F0A0000646916800292BD057691020791A490724 +:10F0B000490F14680B4624254D436519B54206D106 +:10F0C000012495698C4065400020956104E0491C4D +:10F0D0004907490F8F42EED1491C4E07760F9569BB +:10F0E00001210C469C402B4623420AD19368002BF9 +:10F0F00007D05B1E936053685B1C53603346F0E798 +:10F100000420F0BD184A2423117C1268491E4907C7 +:10F11000490F5943203150500020704770B50028E6 +:10F120001AD0002918D0104AD368002B16D05B1EC5 +:10F13000D360936824265B1C9360536915681C4652 +:10F140007343EE1820330660E858641C08606007BB +:10F15000400F5061002070BD0E2070BD042070BDB6 +:10F16000BD280020F42E00201430002030B5CB0044 +:10F1700008339DB293070024002B01D0072030BD37 +:10F180003B4B9A605219DA605C701C705880998011 +:10F19000002030BDF7B5364C0E466088814237D826 +:10F1A000344F00F069F822786078A188884201DA4B +:10F1B000401C00E00020C0B2904202D100F062F892 +:10F1C00024E065786078884201DA401C00E0002085 +:10F1D000607000F057F8BD4218D0A068EF000299A7 +:10F1E000C151009900290CD0002E0AD06088324607 +:10F1F0004543E068281800F018F9A06838188680A0 +:10F2000002E00021381881800020FEBD0420FEBDF0 +:10F210000920FEBD0EB504E068468188029A009878 +:10F22000904702AA01A9684600F003F80028F3D02D +:10F230000EBD70B50E4B05241D785E78AE4215D01C +:10F240001D781C789E88B44201DA641C00E000241A +:10F250001C705C88DE686C43A41904609B68E8003D +:10F26000C418A4880C80185800241060204670BD73 +:10F27000C4280020FFFF000072B606480168491C40 +:10F280000160704703490868401E086000D162B6FB +:10F2900070470000D4280020BFF34F8F0349024875 +:10F2A000C860BFF34F8FFEE70400FA0500ED00E0F1 +:10F2B00010B5002904D0002211461046FFF7ECFFDC +:10F2C00000F010F810BD10B50021024A0846FFF703 +:10F2D00061FF10BDB1F2030010B508461146FCF7FE +:10F2E000C3FF10BDF8B5384C2078002837D020690E +:10F2F000002807D00026E068002805D00025002E51 +:10F3000004D013E00126F6E70125F8E7684651DF4F +:10F31000052806D0002806D000221146FFF7BCFFC2 +:10F3200004E0012602E0216900988847002D12D1EF +:10F33000608869460880A06861DF052806D000283B +:10F3400006D000221146FFF7A7FF04E0012502E0E6 +:10F35000E168A0688847002ED8D0002DCFD0F8BD36 +:10F3600070B5002901D08C0701D0072070BD164C64 +:10F370000125A16062801549636010DF0028F5D186 +:10F38000257016202EDF70BD002803D00E49C860FE +:10F39000002070470E207047002803D00A490861FA +:10F3A000002070470E20704710B5074840680028BD +:10F3B00007D08047002803D000221146FFF76CFFDA +:10F3C00010BDFFF78FFF10BDD8280020D9F2030031 +:10F3D000034610B50B439B070FD1042A0DD308C871 +:10F3E00010C9121FA342F8D018BA21BA884201D915 +:10F3F000012010BD0020C04310BD002A03D0D30758 +:10F4000003D0521C07E0002010BD03780C78401C8C +:10F41000491C1B1B07D103780C78401C491C1B1B83 +:10F4200001D1921EF1D1184610BDF8B5042A2CD393 +:10F43000830712D00B78491C0370401C521E8307AF +:10F440000BD00B78491C0370401C521E830704D05C +:10F450000B78491C0370401C521E8B079B0F05D074 +:10F46000C91ADF002023DE1B08C90AE0FCF7E0FE12 +:10F47000F8BD1D4608C9FD401C46B4402C4310C0D1 +:10F48000121F042AF5D2F308C91A521EF0D40B78C1 +:10F49000491C0370401C521EEAD40B78491C0370AF +:10F4A000401C521EE4D409780170F8BD01E004C08C +:10F4B000091F0429FBD28B0701D50280801CC907D4 +:10F4C00000D00270704700290BD0C30702D0027031 +:10F4D000401C491E022904D3830702D50280801CE8 +:10F4E000891EE3E70022EEE70022DFE70378C27817 +:10F4F0001946437812061B0219438378C0781B040F +:10F50000194311430902090A000608437047002203 +:10F5100003098B422CD3030A8B4211D300239C4650 +:10F520004EE003460B433CD4002243088B4231D3C8 +:10F5300003098B421CD3030A8B4201D394463FE05C +:10F54000C3098B4201D3CB01C01A524183098B42BC +:10F5500001D38B01C01A524143098B4201D34B01A5 +:10F56000C01A524103098B4201D30B01C01A524108 +:10F57000C3088B4201D3CB00C01A524183088B428F +:10F5800001D38B00C01A524143088B4201D34B0078 +:10F59000C01A5241411A00D20146524110467047EA +:10F5A0005DE0CA0F00D04942031000D340425340EF +:10F5B00000229C4603098B422DD3030A8B4212D3AF +:10F5C000FC22890112BA030A8B420CD389019211E1 +:10F5D0008B4208D3890192118B4204D389013AD01E +:10F5E000921100E08909C3098B4201D3CB01C01AF3 +:10F5F000524183098B4201D38B01C01A5241430906 +:10F600008B4201D34B01C01A524103098B4201D3F3 +:10F610000B01C01A5241C3088B4201D3CB00C01A60 +:10F62000524183088B4201D38B00C01A5241D9D278 +:10F6300043088B4201D34B00C01A5241411A00D2F9 +:10F640000146634652415B10104601D34042002BF5 +:10F6500000D54942704763465B1000D3404201B574 +:10F660000020C046C04602BD7047704770477546CF +:10F6700000F022F8AE46050069465346C008C000B7 +:10F68000854618B020B5FEF7FBFA60BC0027490894 +:10F69000B6460026C0C5C0C5C0C5C0C5C0C5C0C52A +:10F6A000C0C5C0C5403D49008D4670470446C046B0 +:10F6B000C0462046FCF751FD00487047303000201E +:10F6C00001491820ABBEFEE726000200704730B4A7 +:10F6D0007446641E2578641CAB4200D21D46635DEF +:10F6E0005B00E31830BC1847020000000000000077 +:10F6F0000000000000000000040000000000000006 +:10F7000000000000000000000000000000000000F9 +:10F7100035C40300000000000000000002000000EB +:10F7200000000000000000000000000000000000D9 +:10F7300000000000030000000000000000000000C6 +:10F7400005000000000000000000000000000000B4 +:10F75000000000000000000023D1BCEA5F78231500 +:10F76000DEEF12120000000088F7030000280020DE +:10F77000EC00000004C1030074F80300EC28002032 +:10F78000A413000020C103000000000000000000DE +:10F790000000000000000000000000000000000069 +:10F7A0000000000000000000000000000000000059 +:10F7B0000000000000000000000000000000FFFF4B +:10F7C0000000000032000000000000000000000007 +:10F7D0000000000000000000000000000000000029 +:10F7E0000000000000000000000000000000000019 +:10F7F0000000000000000000000000000000000009 +:10F80000000000000024F4000000000000000000E0 +:10F8100000000000000000000000000000000000E8 +:10F8200000000000000000000000000000000000D8 +:10F8300000000000000000000000000000000000C8 +:10F8400000000000000000000000000000000000B8 +:10F8500000000000000000000000000000000000A8 +:10F860000000000000000000000000000000000098 +:04F870000000000094 +:10FC00000100000000000000FE00000000000000F5 +:10FC100000000000000000000000000000000000E4 +:020000041000EA +:0410140000C0030015 +:040000050003C0C173 +:00000001FF + +:020000042000DA +:1000000041140E2FB82FA2BBA4006E070000000001 +:100010007B22636F6D7072657373696F6E223A2213 +:100020004C5A4D41222C2268656164657253697A8D +:1000300065223A3330312C227465787453697A65BD +:10004000223A31363734372C226E616D65223A22DE +:100050004261736963204D6F76656D656E742052E1 +:100060006F626F74222C226555524C223A226874BA +:100070007470733A2F2F6D616B65636F64652E6DBD +:100080006963726F6269742E6F72672F222C22650A +:10009000564552223A22322E302E36222C227078A9 +:1000A00074546172676574223A226D6963726F627B +:1000B0006974227D5D00008000984200000000000D +:1000C00000003D8889C65436C3174FE4DC305FBE5C +:1000D0000EC45C44B9309A9808F4833848796DAE00 +:1000E000FDCEE2E20A3A3E8CADB403FC27ABCC93E2 +:1000F00014FFCC2521E07B808B918851D45C3307A1 +:1001000011930240FD1F32BA86A0FC41BDBA417670 +:10011000D7544F1ECCD277411322E26D54FBE4ED4D +:1001200083DDBB53692E555CF1559D1A2E00BA0430 +:100130004EA2FC70BFB60E6053B595180854076800 +:1001400058C7D7A886CF3E54506ED14A8F02B520EB +:10015000E31878D98FBAADA645120E409612DDF796 +:10016000C092FB38C6B2BE3D8E8AD6D74259937E26 +:100170005810EFC60C641C0C39EA540C9D7E0B4CD5 +:1001800043C067CDE9B06D523D2C996C74B38A526F +:100190008671B95881A6725D4F9DED27BD645815D3 +:1001A000189BBAB99BD8133E668733B41C2A5E638A +:1001B000D797CE241B224A763D5FA57287C4CFE82D +:1001C000FB541AD5A0084472FD1174A63288C048A9 +:1001D000B55F5B38BB078236CD2467A2F945695EFF +:1001E000BCAE6974BA28623BBFCFFBE2A19B5DD96C +:1001F000EFA5D683249D1439C4BD67B41AD9722DD6 +:100200002698EF2BE01DEFE42C4DF525004790E2FA +:100210003D70DE1FCDFC43DE9D6AE158B2DCC38C2D +:100220008B3AE8B8D917D0F27DCF10FDDEF2C47555 +:10023000566A39B72128CE940A3A51E39937099B77 +:10024000A6B4300B2842B75A232C8981F3A0AE21E3 +:10025000CAD3BD5A24C61501E8FF0751BD4D5B5CEA +:10026000A3CC2F69658829BD6125D29693B4F3523A +:10027000CBDCD2E342CF20CF5B3DB24AD3386D38DE +:100280004404267AB76DAD60C18D460D4C3796B7E4 +:10029000B655724EE705CED0F3CC726C2859225376 +:1002A000A67BE50C1BD6BBC43DDC29B59ED985D108 +:1002B0005194CD595625BAC54401731FC36CEB3612 +:1002C00007F71E81D87FFDB06D7D3761ABE7BC3E7F +:1002D00038C79CA63C402B2A00BBE598176BAFE8BB +:1002E0009421C5E919536B5F546F010B0BDE319DEF +:1002F000B7DC55775B90B9C018DA50FC4D7EDDD085 +:10030000D36F64C461E78D1BE9F1A0265AFE7CCD52 +:10031000BB288CCE69B618B0E0F34F0F5D5FA873B1 +:10032000603E6D1C238B9F50918A3157732EC305FD +:100330002A95346296BD8AC0778CDDE243FA21C6E5 +:100340007F09FA877549406D4C467928C1E40F2131 +:10035000C5ECBA77CCB513302B142A4CF40667974A +:1003600053CB03974BD2AFF19E08C95F7D5908D696 +:10037000C494A0693E1F1612943323F2D5F24200B2 +:10038000D42E96DD827C079542603A863768A6B9FE +:10039000E2DF33223F1B960EB21E470B7BCD165E6B +:1003A0006618BA929FED9D5CF5E6F99A197CFB27D9 +:1003B000B3B9885AC9478A6DF4286F7D54982DB215 +:1003C000809AE9DB23AF90BD6D2DE6E87E93320A7B +:1003D000073CAE140A25CD048336423AAE1EEFF038 +:1003E0009F8A99CB2C390E128F10F658DE8E0BCACD +:1003F000AEB487166C04F8EC3DA1C4F26587A18CFD +:10040000594A41A92B4C4EBF5601EBC9C226A4C77D +:1004100052A5B2D8C760C9DFB8E062974BD5AF3FED +:10042000335380D53FF99A072502D753490BC68E1F +:100430006CD115E34E6C10499CA0251FEEF6642A82 +:10044000D645A8A1975D25F74DB72D4D5F2AAC473E +:10045000D8F257A39232F6984CE6B868CD70DBB567 +:10046000D5F0DA444B6E69CB5AB3963CA0858F9F8A +:100470008B62A7F29EC6985C0E5B04D32C52ABDE57 +:100480008DF88BCC59DA4BDFA4A2375AADE5C67E86 +:10049000DF956760FB54884D7B0D3A472C611B97B5 +:1004A00071685FD99B2A1BF7F11AF85D25AB08E547 +:1004B000C52A5EC33DCEA10DFC92476549B679B50C +:1004C0001C322E758C9F0677446C20B72E636D41CD +:1004D0003179A9CA2BD54FFA6B4581943448D71C82 +:1004E00026402B18F26890CA5CC0146CF5EBB9CCAE +:1004F0007911FA6ED8E7ACDD68928AA563F455F3FA +:10050000647258D2674890AE094D61A1E1E64D355D +:100510005F38CD507D22208505D66D14C095B92C4D +:100520002B2E692606C5A6AE72B2C8AB8D53192212 +:100530001D79C0759567E86D1A70FA12F458A21A01 +:100540008F41A7A7A8EFF63C1B2A522FC052543B5D +:1005500063EBD909BA2AC5981315CA6DE97F813AA8 +:1005600095F5199297F2F93BDFB1C90A66876E5586 +:10057000702770A9406B8CD2872839375B9209604D +:1005800067FA43B805A19881166A09A4FAC27E9257 +:100590005FA91C3B82106E1075A0C430C8726E60DB +:1005A0009B5FD5B0D9B77745B99B6FFDBF1D8B5207 +:1005B000344DD36A61BE8BBB70FD1D99EA1551C6DF +:1005C0007BFBBCE6179581546B31EED3E4346EAE01 +:1005D0001465C644E21E78FBB6E11733568D8CEDE8 +:1005E0009B8F843B89018BA249D3833DB60CF1C418 +:1005F00016E59CFD7DC725F039DCCD595F6BF0CF4A +:10060000950161BE292DA4C5515F4FA6381C3B2B17 +:100610002F6B254494B80998B405C02D17C26DA25C +:10062000CA1A0F91ED87D7E06E07184CC8BAF111BE +:10063000638786E0DDC9031125682D32EB943D0107 +:10064000485FF9B27E90B70AD047B6BDF9FBFF54B8 +:10065000E365D060C27FD40FAF031101443A092F84 +:10066000DF2D6368512B2383399B3479D59BA59467 +:1006700026D5C6C3157C64E17E28901F59408FD7CC +:10068000A927A456D5644B7EB4A8AF16EEF0610E30 +:100690001A8F286220C7FCD14F0D16F8FC96079DD3 +:1006A00014CB3524878D2212B47E86164E1F412E20 +:1006B00001776119D855E60A38DC7B0642F6A72394 +:1006C000127FE50751B407440CAE3A70123CCF7A62 +:1006D0005F5168257D5E5E1D9A669C96F45F3D2D98 +:1006E000B8466604CF07511F82FF53586F834EAB45 +:1006F0000CE214E20D08E087D739AD31FE2F13BBB1 +:100700006C7690F95EBFFFF5BFD7306F6B9B1FF61D +:10071000EAEE560123404F2B652AF75D27664A29EA +:100720002FCAFF29B6B415B272AAB48F30F05A1589 +:100730000E74AB8046F9EED16EADF8243E399109C6 +:100740008FDD7D3FCF8468212FD92B53765CCD7C04 +:100750005E60199DB90C28C4DCFC94840BC221B2E4 +:10076000DFF7EB941FCC48F694694B673B8D9B46B3 +:1007700084C11861DDA4F9A5FBBE3A2DD12B33B09D +:10078000DBB50893643728EA5CD1B8BD30911937DE +:100790005AE9B7FC0736433D0B1D1BA458A0ED5684 +:1007A0000E505BFAFFB9B1A67CD67E5D494417C1F5 +:1007B000CCE9F9EC9B9C7602E571F27A52E55106A0 +:1007C00010E78AEB6786BB52E7A3221E9309ADB000 +:1007D000A44C7EC29DC57C992D319D647D33CAFC9D +:1007E000BA27928F5680F6437481368997516A2BC7 +:1007F0002B75CDC98B8C1D8633271805477DF8E1F5 +:10080000C0E566E7BB2A4C40D78B2F9AF2954DB6D0 +:1008100098ED7E5FD4E0D15302C0F46B53BDFA3E35 +:1008200072F0000000000000000000000000000066 diff --git a/Crickits/Crickit_MicroBit_Robot/microbit-Obstacle-Avoiding-Robot.hex b/Crickits/Crickit_MicroBit_Robot/microbit-Obstacle-Avoiding-Robot.hex new file mode 100644 index 000000000..cc7960130 --- /dev/null +++ b/Crickits/Crickit_MicroBit_Robot/microbit-Obstacle-Avoiding-Robot.hex @@ -0,0 +1,14451 @@ +:020000040000FA +:10000000C0070000D1060000D1000000B1060000CA +:1000100000000000000000000000000000000000E0 +:100020000000000000000000000000005107000078 +:100030000000000000000000DB000000E500000000 +:10004000EF000000F9000000030100000D010000B6 +:1000500017010000210100002B0100003501000004 +:100060003F01000049010000530100005D01000054 +:1000700067010000710100007B01000085010000A4 +:100080008F01000099010000A3010000AD010000F4 +:10009000B7010000C1010000CB010000D501000044 +:1000A000DF010000E9010000F3010000FD01000094 +:1000B00007020000110200001B02000025020000E0 +:1000C0001FB5C046C04600F0EFFA04B00FB41FBD24 +:1000D00008205A49096809580847382057490968CB +:1000E000095808473C2055490968095808474020E5 +:1000F0005249096809580847442050490968095875 +:10010000084748204D490968095808474C204B4981 +:10011000096809580847502048490968095808479C +:100120005420464909680958084758204349096836 +:10013000095808475C204149096809580847602068 +:100140003E4909680958084764203C49096809582C +:100150000847682039490968095808476C20374919 +:100160000968095808477020344909680958084740 +:100170007420324909680958084778202F490968CE +:10018000095808477C202D490968095808478020EC +:100190002A490968095808478420284909680958E4 +:1001A0000847882025490968095808478C202349B1 +:1001B00009680958084790202049096809580847E4 +:1001C00094201E4909680958084798201B49096866 +:1001D000095808479C201949096809580847A02070 +:1001E0001649096809580847A4201449096809589C +:1001F0000847A8201149096809580847AC200F4949 +:10020000096809580847B0200C4909680958084787 +:10021000B4200A49096809580847B82007490968FD +:1002200009580847BC2005490968095808470000D3 +:1002300003480449024A034B7047000000000020B5 +:10024000C0070000C00700000122D84B5A6000BF61 +:10025000D74A1268002AFBD0016000BFD44A126856 +:10026000002AFBD00022D14B5A6000BFD04A12684E +:10027000002AFBD07047F0B505460E46174600240D +:1002800006E0A200B158A2005019FFF7DDFF641C80 +:10029000BC42F6D30020F0BD0120C043C549086030 +:1002A000401048607047014601229204086890425D +:1002B00001D9102070470020FCE7F0B505460C4638 +:1002C0001646002706E028462168FFF7BDFF2D1DD2 +:1002D000241D7F1CB742F6D3F0BD70B505460C4611 +:1002E0002E460BE0304600F075F9FF2C01D80024B3 +:1002F00001E0FF3C013C012080023618002CF1D1C6 +:1003000070BD0146012292044868904201D909203B +:100310007047A9484069401C01D10F20F8E7002030 +:10032000F6E7FEB504462068030000F037FA05043E +:100330002B4249598B00201DFFF7E3FF0546002D96 +:1003400001D02846FEBDFFF7A7FF0120C00200F044 +:1003500041F9042221469948FFF78DFF002801D07A +:100360000320EFE708222146944800F06DF90028A9 +:1003700006D1002192480068FFF766FF00F00CF9F3 +:100380000320DFE7A768E6686068019031463846D9 +:10039000FFF7A3FF324638460199FFF78EFFB20000 +:1003A0003846019900F050F9002800D1CAE703202F +:1003B000C8E700F0E3F9834800688349086041E03A +:1003C00060680190E668A0680090B200009901980A +:1003D00000F03AF90746002F00D1B3E70E20B1E74D +:1003E000201DFFF760FF0546002D01D02846A9E734 +:1003F0006068002807D1FFF74FFF0320800200F05C +:10040000E9F800F0C9F8FFF747FF0120C00200F04B +:10041000E1F8042221466948FFF72DFF002801D0AA +:1004200003208FE708222146644800F00DF90028D8 +:1004300006D1002162480068FFF706FF00F0ACF823 +:1004400003207FE700BF00207CE770B505460C461F +:10045000182D04D12068FFF764FF206002E001201E +:10046000206000BF00BF70BDF0B589B05248406940 +:1004700003905248806881000398081802900398FE +:10048000000B01900121090302984018401E000B47 +:1004900000900124002520462946019A00F0C4F866 +:1004A0000022401E91410791069001260027304608 +:1004B0003946009A00F0B8F80022401E914105919B +:1004C0000490049BDB43059AD2430698184307998E +:1004D00011430791069037490698086007984860CD +:1004E00009B0F0BD70B53448446934488568466841 +:1004F000AA003146204600F0A7F8002801D00020CD +:1005000070BD0120FCE72D484068002801D0012083 +:1005100000E000200546FFF7E5FF002807D0FFF7C1 +:10052000BBFE0320800200F055F800F035F8FFF71D +:100530009BFF002D0ED020484669204884684768FC +:1005400021463046FFF7C9FE224639463046FFF7BE +:10055000B4FE00BF00F020F810B5184844681A48EF +:100560000460204600F0DCF810BD15480068006803 +:10057000401C01D100BFFEE710480068002802D0EF +:10058000042806D101E0FFF7BEFFFFF7E5FF00BF3B +:10059000FEE700BF00BFFEE7BFF34F8F0B480C49DB +:1005A000C860BFF34F8F00BFFEE7000000E50140C9 +:1005B00000E40140000600400010001000080000A8 +:1005C000B8070000BC070000000000200400FA0586 +:1005D00000ED00E010B50146104B1A6808460223F2 +:1005E0000F4C636000BF0F4B1B68002BFBD0531CEC +:1005F00004D0904202D20A4B186101E0084B986087 +:1006000000BF084B1B68002BFBD00023044C636029 +:1006100000BF044B1B68002BFBD010BD0010001066 +:1006200000E5014000E4014010B5202A04DB01464A +:10063000203A9140002010BD914020239C1A03468F +:10064000E3401943904010BD034610B50B439B0790 +:100650000FD1042A0DD308C810C9121FA342F8D025 +:1006600018BA21BA884201D9012010BD0020C04328 +:1006700010BD002A03D0D30703D0521C07E000208E +:1006800010BD03780C78401C491C1B1B07D1037854 +:100690000C78401C491C1B1B01D1921EF1D118463D +:1006A00010BD70477047704710B500F007F810BDD7 +:1006B000014B1B68DB6818470000002019481A49E5 +:1006C0007047FFF7FBFFFFF7FBFC00BD20BFFDE716 +:1006D0001649174C24688C420BD1164B1B68994263 +:1006E0000CD1154B154A1360186810498842EDD09B +:1006F0000AE0134880F30888124B18470F4A13602A +:1007000018680A498842E1D080F308880E49884277 +:1007100004DD0E48026802210A4302605B68184744 +:100720000346DFE7C0070000C0070000FFFFFFFF30 +:10073000000C000014100010001000000000002049 +:10074000000400206B05000000200020240500406C +:100750000D48704502D1EFF3098101E0EFF3088104 +:10076000886902380078182802D1C046074A104725 +:10077000074A12682C3212681047000000B5054B7A +:10078000054A9B58984700BDFDFFFFFF4B04000042 +:1007900000000020001000000400000030B4744687 +:1007A000641E2578641CAB4204D3635D5B00E318D0 +:1007B00030BC18471D46F8E7000C00000010000090 +:1010000000150020CD64010025220000336401009A +:1010100000000000000000000000000000000000D0 +:101020000000000000000000000000003D6501001D +:101030000000000000000000252200002522000022 +:10104000A9650100AF6501002522000025220000EE +:101050002522000025220000252200002522000074 +:10106000B56501002522000025220000BB650100B6 +:1010700025220000C1650100C7650100CD650100A2 +:101080002522000025220000252200002522000044 +:101090002522000025220000252200002522000034 +:1010A000D3650100D965010025220000252200003A +:1010B0002522000025220000252200002522000014 +:1010C00000F002F815F0E3F90CA030C80838241835 +:1010D0002D18A246671EAB4654465D46AC4201D170 +:1010E00015F0D5F97E460F3E0FCCB64601263342A9 +:1010F00000D0FB1AA246AB4633431847B456010052 +:10110000E4560100103A02D378C878C1FAD85207E1 +:1011100001D330C830C101D504680C6070470000AD +:101120000023002400250026103A01D378C1FBD803 +:10113000520700D330C100D50B6070471FB5C046C1 +:10114000C04615F063F904B00FB41FBDF0B44046BB +:10115000494652465B460FB402A0013001B506482D +:10116000004700BF01BC86460FBC804689469246B8 +:101170009B46F0BC70470000C11000008269024924 +:101180008161024810447047911100000100000085 +:1011900001B41EB400B50BF0E6FF01B40198864619 +:1011A00001BC01B01EBD0000401E00BF00BF00BF5B +:1011B00000BF00BF00BF00BF00BF00BF00BF00BF37 +:1011C00000BFF1D17047000070B505460C461646C9 +:1011D00002E00FCC0FC5103E102EFAD2082E02D31B +:1011E00003CC03C5083E042E07D301CC01C5361F2E +:1011F00003E021782970641C6D1C761EF9D270BD45 +:101200008307FF22DB0E9A408907090E99400028C8 +:101210000BDA0007000F0838830828489B001818CD +:10122000C36993430B43C3617047830824489B0001 +:101230001B181868904308431860704710B504469F +:1012400000210120FFF7DCFF00211820FFF7D8FF65 +:1012500000210B20FFF7D4FF02211920FFF7D0FF58 +:1012600002210D20FFF7CCFF02210E20FFF7C8FF5F +:1012700002210F20FFF7C4FF0221C81FFFF7C0FFA4 +:1012800003211620FFF7BCFF03211520FFF7B8FF4D +:10129000204600F019F8002010BD6421018070473D +:1012A00010B500F020F810BD0648704710B500F0EA +:1012B00022F810BD704770477047000000ED00E055 +:1012C00000E400E003F9004370B505462D4C07200B +:1012D0002070A01CFFF7E1FF5920A080294620467E +:1012E00000F099FB70BD10B500F09EFB2549002071 +:1012F000891E087010BDF8B5224E0446B61E30781F +:1013000001270D46002807D0204660380B2808D852 +:10131000204600F03DFF2BE0602CF9D01A48086011 +:10132000F8BD20466C38032803D8204600F071FF32 +:101330001EE0204670381F2803D8204600F045F9EB +:1013400016E0204690380F2803D8204600F0E8F831 +:101350000EE02046A0380F2803D8204600F074F88D +:1013600006E02046B0380F2804D8204600F0CAF91D +:10137000286000E02F60602CD2D128680028CFD1EF +:101380003770F8BD1A000020013000000120244908 +:10139000C003086023490020087007202249C005C7 +:1013A0008860704770B51F4D04462878A04207D06A +:1013B000002C05D0002803D01CA14D2015F033F8D7 +:1013C0002878A0420ED000211D4A17482C70002C0E +:1013D00019D01C4B012C06D0022C0BD013A1682075 +:1013E00015F021F870BD11600221116053610321D5 +:1013F000090605E011600321116053610121C9054F +:101400008160416070BD116011600721C905816074 +:1014100070BD10B505A1712015F005F810BD0000D4 +:1014200080E100E02000002000F501407372635C61 +:1014300068616C5F63636D5F6161722E63000000C1 +:1014400000F500404001002010B5A038030015F061 +:10145000DBF80B070E172028313A414B525C650030 +:101460004B6808788A68194603F0E6F910BD888849 +:101470008A6883B20888194680B203F0ECF910BD7F +:1014800008884C68CB688A6880B2214603F0E7F987 +:1014900010BD08884B688A6880B2194603F0FBF9D2 +:1014A00010BD88888A6883B20888194680B203F024 +:1014B00007FA10BD88888A6883B20888194680B206 +:1014C00003F041FA10BD08884A6880B2114603F063 +:1014D00080FA10BD088982B2888883B208881946CC +:1014E00080B203F081FA10BD08884A6880B21146C4 +:1014F00003F09EFA10BD08894C6882B20888CB6858 +:1015000080B2214603F018FB10BD08884C68CB68F8 +:101510008A6880B2214603F02AFC10BD012010BD6C +:1015200010B59038030015F06FF809060F161D244A +:101530002C363F464E0088888A6883B20888194650 +:1015400080B204F031F910BD08884A6880B21146B3 +:1015500004F065F910BD08884A6880B2114604F0AD +:101560006AF910BD08884A6880B2114604F070F923 +:1015700010BD08884B688A6880B2194604F07BF970 +:1015800010BD088982B2888883B20888194680B263 +:1015900004F07AF910BD08894B6882B208881946B0 +:1015A00080B204F090F910BD08884A6880B21146F4 +:1015B00004F09BF910BD888882B20888114680B279 +:1015C00004F0EFF910BD012010BD10B57038030014 +:1015D00015F01AF81B0F15192125282F363B40440A +:1015E000484C53585F688D707980888D8D8D8D8FB4 +:1015F00096004A680878114608F0FDFD10BD08689D +:1016000008F04AFE10BD0C790B7B8A6808682146F9 +:1016100008F053FE10BD086808F011FF10BD08F077 +:1016200065FB10BD08884A6880B2114609F043F88E +:1016300010BD0A790888114680B209F0D3F810BDB0 +:10164000087840B209F0DCF810BD088880B209F0D3 +:10165000F0F810BD086809F0FEF810BD086801F048 +:10166000D2FB10BD086801F0FCFB10BD088982B2F6 +:1016700009C9194609F007F910BD05C9114609F055 +:1016800051F910BD08884A6880B211460AF0A6F9DF +:1016900010BD0C790888CB688A6880B221460AF0B0 +:1016A000C5FA10BD0B7908888A6880B219460AF01D +:1016B0006DFC10BD08884C68CB688A6880B22146F2 +:1016C0000AF0D5FC10BD08884A6880B211460AF0BD +:1016D00018FD10BD0B7908880A7A80B2194609F006 +:1016E00044F910BD088880B209F044F910BD062005 +:1016F00010BD08884A6880B2114609F042F910BD51 +:10170000012010BD10B5B02805D0B12808D0B228EE +:101710000BD0012010BD088880B20BF0FBF810BD83 +:10172000088880B20BF015F910BD08884B688A68EC +:1017300080B219460BF01EF910BD000010B5030071 +:1017400014F062FF0A0609060C0C0F0F06060612BB +:1017500008F0F4FA10BD0AF0C5FE10BD01F03EFA23 +:1017600010BD06F09FFA10BDFAA1FE4814F05BFE12 +:1017700010BD3EB5FC49054603C900900191FF200C +:10178000C33069460881F94A092310460A212838DE +:101790000BF0BFFD0024F6480BF0D9FD641CE4B249 +:1017A0000A2CF8D3F14801231A4602A990300BF015 +:1017B000A0F9002804D0FF20E6A13D3014F033FE4C +:1017C000686800F024FC00211E22084604F06CF931 +:1017D00008F0C3FC02222421E64801F07DFBE54825 +:1017E00001222C214C3001F077FBE2490B20B0396B +:1017F00001F0FEF9002804D0FF20D6A1513014F0EA +:1018000012FE0AF03EFE02F097F96B460022082114 +:10181000D9A008F07DFB002804D0FF20CDA15730CF +:1018200014F001FE284602F0E7FC002804D0FF2057 +:10183000C8A1593014F0F7FDF3218900D14814F004 +:10184000D3FCD04801214171022181710721C1716E +:101850003EBD10B5CB4CA0780A2804D3FF20BDA113 +:10186000903014F0E0FD20786021484300190021F9 +:101870000173417BF722C908C900C91C1140EF223E +:10188000114041730121E1700C3010BD70B50E465E +:1018900000211C4619801546030014F0B5FE0723ED +:1018A000050B1711231D23002246294630460AF056 +:1018B00037FE70BD22462946304608F095F870BDC7 +:1018C00022462946304601F0E2FF70BD22462946F5 +:1018D000304603F0EAFD70BD22462946304600F04E +:1018E00010FC70BDFF209BA1EF3014F09CFD032085 +:1018F00070BD70B5A34CE078002818D02078602126 +:1019000048430019407B00254007400F0119087922 +:10191000401E08712078401CC0B220700A2800D1F7 +:101920002570A078401CA0700BF097FEE57070BD8C +:101930009448C079002800D08BE7704770B5914D6E +:10194000A86800280CD0FFF7F3FF002862D06022BF +:10195000A968FFF739FCFFF7CCFF0020A860EFE78C +:101960006879002856D0FFF774FF044681484C3050 +:1019700001F0C2FA6060002804D17A4875A14A30AB +:1019800014F051FD606801F01AFB00280DD02046CC +:1019900007F00BFF6078010703D5C008C000401CAA +:1019A0002BE0744861684C302DE0724861684C301F +:1019B00001F0ABFA00F05AFB00282BD1FFF749FFEA +:1019C00004466C4801F098FA6060002804D1332086 +:1019D00060A1000114F027FD606801F0F4FA00280E +:1019E00014D060680088608020460AF0CCFD6078E2 +:1019F000010706D5C008C000801C6070FFF779FFA2 +:101A00009EE75C48616801F080FA99E7594861688F +:101A100001F07BFA70BD10B55B4CE160A0605B48E3 +:101A200000F032FC607010BD57490020087070470C +:101A300070B5574E0546706A94B00C46401C04D1F0 +:101A4000B06AC0430004000C0BD0306AC007C00F5E +:101A50002870706A14F0DBFBB06A2071000A6071B4 +:101A600014E02B206946087009A9684601F07BFA4A +:101A7000002804D03B4837A17E3814F0D4FC012064 +:101A8000287006220AA9204614F04FFB2878002867 +:101A900003D06079C0210843607114B070BDF0B507 +:101AA0003B4C0646206895B00D4637460837401C2B +:101AB00008D16068401C05D1A068401C02D1E068D4 +:101AC000401C11D02068314614F0A1FB6068311D24 +:101AD00014F09DFBA068394614F099FBE06831468C +:101AE0000C3114F094FB25E02B206946087009A9FD +:101AF000684601F038FA002804D01A4815A1553874 +:101B000014F091FC08220AA9304614F00EFB2B2099 +:101B10006946087009A9684601F025FA002804D032 +:101B200010480CA14E3814F07EFC08220AA9384651 +:101B300014F0FBFA20692E460836401C08D1606973 +:101B4000401C05D1A069401C02D1E069401C33D083 +:101B500020691FE07372635C686F73745F636F72F8 +:101B6000652E6300C3020000F866010094010020A6 +:101B70003D170000640800206E524635313832327D +:101B800000000000E8030020240000203D190000B0 +:101B900080000010294614F03AFB6069291D14F0FA +:101BA00036FBA069314614F032FBE06929460C315E +:101BB00014F02DFB15B0F0BD2B246846047009A964 +:101BC00001F0D1F9002803D0F649F74814F02BFCB6 +:101BD000082209AF28460AA914F0A7FA684604703B +:101BE00009A901F0C0F9002804D0EF48ED49C01D53 +:101BF00014F019FC0822391D304614F096FAD9E782 +:101C000070B5EA4C0546A068002804D0E648E549CE +:101C1000563014F008FCA56070BD10B50146E448CC +:101C200001F073F9E1498879401CC0B2887101283C +:101C300003D1E048407800F04BFB10BD70B504467E +:101C4000DD4816460D46814204D1D748D549CB30F0 +:101C500014F0E9FB012E05D0D348D249DA3014F054 +:101C6000E2FB70BD6620207000202072A58101205B +:101C7000A07370BD70B515460C460646FFF758FEBA +:101C800000280CD066210170468001210172216874 +:101C90000161A18881820573FFF72BFE70BD1321BE +:101CA000304608F09FFD70BDC2494968884201D2A4 +:101CB00010207047072101700020704770B5BD4C9F +:101CC00005462078002694B0002801D00820E4E6DC +:101CD000BA4A6260954201D21020DEE668680028A8 +:101CE00009D00921D82804D3C31C9B089B00834238 +:101CF00005D00846D1E60720000268600EE0012109 +:101D000009074B6B896B4B43AD49511A0122591A94 +:101D1000D202891A814201D20421EAE700F050FF81 +:101D20006178A06806F052F8E068401E07280BD8DA +:101D3000302269460A708870684607F007F9002863 +:101D400002D009A806F07CFA2846FFF712FD012010 +:101D500020703046A1E6F8B5044696480F46406824 +:101D6000814208D3002C01D0844204D3E01C8008B7 +:101D70008000A04201D01020F8BD8C488178002955 +:101D800011D0398800914178602251430D18287B89 +:101D90000C350007000F3B4600222946FFF776FD71 +:101DA000060004D015E0002038800520F8BD002C86 +:101DB00013D039880098814201D90C260DE028788B +:101DC0003B460007000F22462946FFF75FFD06004D +:101DD00005D00C2E01D0002038803046F8BD734C61 +:101DE0006078401CC0B260700A2801D10020607089 +:101DF000A078401EA07068784107490F01290ED0D5 +:101E0000022906D003291AD066496E4814F00BFB4C +:101E1000E3E7C006E1D46868FFF7FFFEDDE764484A +:101E200069684C3001F071F86079401CC0B2607193 +:101E30000128D2D15F48407800F04AFACDE7E07936 +:101E4000401CE071C9E7604A10B5904209D3594A75 +:101E50000124A4045268A04201D3904201D39142CC +:101E600001D2102010BD00F0FCFE10BD564B10B585 +:101E7000994209D34F4B0124A4045B68A14201D3CA +:101E8000994201D39A4201D2102010BD022803D0FA +:101E9000102801D0092010BD00F009FF0028FAD059 +:101EA000052010BD484B10B598420DD3414B01247D +:101EB000A4045B68A04201D3984205D3994203D39E +:101EC000002A03D09A4201D2102010BD00F015FF65 +:101ED0000028FAD0072010BD10B50446354894B04C +:101EE0004068844202D2102014B010BD0F2008A90F +:101EF000087369460BA801F036F80028F4D168464B +:101F0000007A207068464089608068468089A08099 +:101F10000020E9E710B500290BD0264A526891420B +:101F200002D30B68934201D2102010BD8A88002A88 +:101F300002D001F05AFE10BD092010BD10B5224A92 +:101F400094B091420ED31B4A01239B0452689942DC +:101F500001D3914206D3441E1E2C41D8994203D38B +:101F6000914201D21020BFE7012837D10878002420 +:101F7000C007C00F002803D003206946887001E025 +:101F80006846847038206946087009A9684600F0E0 +:101F9000EAFF002804D041200CA1C00014F043FA4D +:101FA0002046A1E7541B000093020000E803002034 +:101FB0006408002024000020FFFF0000001900201A +:101FC000000000200A040000008001007372635CBE +:101FD000686F73745F636F72652E6300072083E719 +:101FE0000246203A1F2AF9D807F0F9FF7CE710B51E +:101FF0005F4A5268914201D2102010BD0246203A39 +:102000001F2A02D808F065F810BD072010BD70B572 +:102010000546584C0020207020464619544846601A +:10202000E01C80088000A04204D0FF2052491330F9 +:1020300014F0F9F901200007C06AC0430006000E41 +:1020400003D14E480068401C03D04D484D49301A1A +:10205000C862A8B20122214604F039F9002804D050 +:10206000FF204549233014F0DEF970BDF0B595B07E +:102070003B2008A9087369460BA800F074FF0028EC +:1020800004D0FF203C496B3014F0CDF93E4E0024C3 +:102090006D4630E02F19B87DC10706D0400704D443 +:1020A00060004019C0880AF08DFB3848807900280C +:1020B0001FD0B87D80071CD560004019C088002261 +:1020C00006210AF09CFB002813D03C2108A80173CC +:1020D00060004019C1886846C18569460BA800F0B8 +:1020E00042FF06000BD0FF2023497F3014F09BF9FC +:1020F00005E0641CE4B268460079A042CAD83046C4 +:1021000058E5F7B505460078002700090C463E461D +:10211000062804D0FF201849A83014F084F9287A42 +:1021200000280ED0012814D0FF201349C93014F024 +:102130007AF90298002C068001D027806680002062 +:10214000FEBD02270926002C0ED0A889A080A87BFE +:1021500008E003271426002C06D02869E060A88A2E +:102160002082287B2072E4E702980680E7E70000DF +:102170002400002000190020CC1F000000100010D7 +:10218000000000200005004004300000E8030020AB +:1021900010B56038030014F037FA0A060A0F131856 +:1021A0001F252930353A0868FFF788FD10BD05C99D +:1021B0001146FFF7D0FD10BD0868FFF775FD10BD93 +:1021C00005C91146FFF73FFE10BD4B6808788A68C5 +:1021D0001946FFF74BFE10BD8A6809C91946FFF77B +:1021E00061FE10BD0868FFF777FE10BD08884A68D9 +:1021F00080B21146FFF78EFE10BD05C91146FFF7EC +:102200009DFE10BD05C91146FFF7F1FE10BD01206E +:1022100010BD0120704700000E4A12680C498A4226 +:102220000AD118470B4A1268094B9A4204D101B5EA +:102230000AF090FF03BC8E46074909680958084711 +:1022400006480749054A064B704700000000000099 +:10225000BEBAFECA7800002004000020001500204D +:102260000015002001203F49400608603E490860F3 +:102270003E490A68FF231B029A4383121A430A60ED +:10228000384980390860704710B502460420384943 +:1022900004E0C3005B181B79002B0AD00346401EE4 +:1022A000C0B2002BF5D133A1432014F0BCF8FF20BD +:1022B00010BDC300CA50002259184A718A71012208 +:1022C0000A7110BD2A4A0021C000801801717047B0 +:1022D00010B50446042803D326A1522014F0A3F815 +:1022E0002348E1000C182079012803D021A15320B4 +:1022F00014F099F86079A179401CC0B2814200D0F5 +:1023000060710120174940068031086010BD70B52A +:10231000164804250068164E0004800F1B4C022846 +:102320001AD014A1692014F07EF815E02078C100BD +:1023300088190279012A07D1427983799A4203D018 +:1023400042798271705880472078401CC0B220705A +:10235000042801D30020207028466D1EEDB200280D +:10236000E4D170BD80E100E080E200E018E400E02C +:10237000E00800207372635C736F635F7369676E5C +:10238000616C6C696E672E630000000034000020F1 +:1023900010B5EFF31080C407E40F72B6D24841784D +:1023A000491C41704078012801D10BF07BF9002CC9 +:1023B00000D162B610BD70B5CB4CE07800280AD1D0 +:1023C0000125E570FFF7E4FF0BF074F9002804D055 +:1023D00000200BF047F9002070BDC44865714560CE +:1023E000F9E770B5EFF31080C507ED0F72B6BE4C7C +:1023F0006078002803D1BEA18F2014F014F8607813 +:10240000401E60706078002801D10BF04FF9002D5C +:1024100000D162B670BD10B5B348C178002904D0B0 +:1024200000214171C170FFF7DCFF002010BD10B525 +:1024300004460BF03FF9AC49C978084000D00120B0 +:102440002060002010BDF8B50246A74C0026A671FA +:102450000820042101251027130014F0D5F80D08D9 +:102460000A0C0E101214161E262123252800257191 +:1024700022E0022001E021711EE020711CE02771A2 +:102480001AE02020F9E7012616E0FFF781FF0BF0A4 +:1024900011F90028FBD002260EE02171A5710BE096 +:1024A0002771FBE7202000E040202071F6E7FF20A5 +:1024B0008FA1763013F0B7FF0BF008F9002809D090 +:1024C0000BF00AF9B04205D130460BF008F90028AC +:1024D000FAD02CE001208007C560894900224A60BB +:1024E000884A9661814B02225A608560864802695B +:1024F000D243D206D517026910231A4302610F4650 +:102500006D1C00E020BF78680028FBD030460BF03F +:10251000E6F80028FAD0002D04D17B48026910218A +:102520008A43026171490220886000207860A079A6 +:1025300000280CD00BF0BEF805460BF01BF8734AD0 +:10254000002D02D0A260E06001E0E260A060002EF9 +:1025500001D100F0A5F8F8BD10B504460BF0B0F8B5 +:10256000002805D060490120C8704A78521C4A7082 +:102570002046FFF768FF10BDF8B5614DA86800263A +:10258000012802D1AE600BF06DF86868012800D117 +:102590006E6028680127544C012812D12E606079A2 +:1025A000002803D000200BF05DF866712078002829 +:1025B00007D00BF07FF8002803D0012080070761C7 +:1025C000A770286901282AD12E6100F05FF8012048 +:1025D00080074761A079002815D00BF06BF80090B8 +:1025E0000AF0C8FF0099002901D0E16800E0A16865 +:1025F000411A022901DA8A1C11DC0099002901D054 +:10260000E06000E0A060FFF7C3FE0BF053F8002885 +:1026100004D0012080070761A77000E02770E868F8 +:10262000012812D100F032F800F030F800F02EF856 +:10263000A078002804D1FF202DA1033013F0F3FE71 +:10264000EE60A6702670FFF7CCFEF8BD10B5264CE4 +:10265000E078002801D10BF029F80120810788617A +:1026600000F014F8A07800280BD0254CE068002872 +:1026700003D10BF034F80028F8D10020E06000F01E +:1026800005F800201949C043886010BD08B55020E6 +:10269000694608806A461088411E1180FAD208BD3A +:1026A000F8B5124819278760154900200860C860EE +:1026B0000BF000F8BE0701240B4D002802D0346156 +:1026C000AC7000E02C70FFF763FE084847600D49CE +:1026D00028798863FFF7DAFFB461FFF7D7FF08496D +:1026E000002008617461F8BD38000020000300403C +:1026F0007372635C736F635F636C6F636B2E6300F5 +:10270000000100400005004000ED00E0FFFFFF7FFA +:102710008107C90E002808DA0007000F0838800872 +:102720002E4A80008018C06904E080082C4A80008E +:1027300080180068C8400006800F704710B50D2053 +:10274000FFF7E6FFC4B20420C043FFF7E1FFC0B2C9 +:10275000844203D023A11A2013F065FE26490120EC +:10276000486010BD0121254A48031060244B002217 +:102770001A60244A5160244A1060244A11601F499B +:1027800080390860704701211C4A480310601F4AC5 +:1027900051601B4A002111601B490860704710B549 +:1027A00017490868012804D00EA1572013F03BFEFA +:1027B00010BD114880680022C0B20A600AF020FCF7 +:1027C00010BD10B50E4801680029FCD0FFF7E7FFE7 +:1027D00001200D494003086010BD000000ED00E03D +:1027E00000E400E07372635C736F635F68616C5F49 +:1027F000726E672E6300000000D5004080E100E0AB +:1028000000D1004000D3004080E200E000D0004052 +:1028100030B40121BC48C9020160CD1005604A03F3 +:102820000260BA4803681B021B0A036004680023A5 +:10283000240A24020460B6480468240A24020460BE +:10284000B448012444608460B34C23606360A36097 +:10285000B24B19601D601A60B14B19601A600121FA +:10286000016030BC704710B40121A748CA02026061 +:102870000B0203600C060460A64841608160A94811 +:1028800041680029FCD1A4490020086048608860A4 +:10289000A24802600360046010BC704701219F4899 +:1028A000C9020160C91001607047002805D00128E5 +:1028B00005D0022805D19C4870479C4870479C4829 +:1028C000704710B59BA18B2013F0ADFD002010BD0B +:1028D00070B500219E4C9F4D9F4A8F4B002808D019 +:1028E00001281DD0022822D092A1B32013F09BFD15 +:1028F00070BD01200004A060A86011601960974BB2 +:10290000C2039A60964A90607F4A00121060954810 +:10291000016086480160944801609448017070BD70 +:1029200001204004A060A8605160596070BD012082 +:102930008004A060A8609160996070BDF8B594466D +:10294000834A8B4F834D00240126002808D001289C +:1029500032D0022840D077A1E82013F064FDF8BD02 +:10296000891E0902090A0120000490603C64686025 +:102970006C4A1164012B1DD000217C4A7D4B5170A3 +:102980006146DC63DE637C4B5C6002249C60042453 +:102990001C61744B3D31196073490E605F4B8915A2 +:1029A00019606F4B58605E4801606C49C005486013 +:1029B0001670F8BD0121E0E70120704E4004704F11 +:1029C000012B04D13464506068603964F8BD9060B4 +:1029D000346468603964F8BD01206A4E80046A4F2F +:1029E000012BF4D1EEE74F484068704770B54A4D6F +:1029F00028680026564C012806D1A068C00303D5DC +:102A000001200004A0602E606868012809D1A06838 +:102A1000800306D501204004A0606E6001200BF009 +:102A200041FEA868012809D1A068400306D501200D +:102A30008004A060AE6002200BF034FE70BD10B5C3 +:102A40004A490878002818D00120444AC0079060FD +:102A5000434AC00B90602C4A00121060414A00208B +:102A60001060324A1060404A106008704A78002AAC +:102A700002D048700BF016FE10BD0320FAE70120CB +:102A8000424900060860704701202449000608609A +:102A9000704701203D4940050860704701201F49EB +:102AA00040050860704733490020C86388151B49FA +:102AB00008607047410A364AC005C00D5043801C6B +:102AC0005143400A0818704710B4324C430B63431B +:102AD0001B0C5C020C602E4C6343C31A2E485C0234 +:102AE00058432B4B400D4343E31A0124DB032404DA +:102AF0001B191B1613700A681018086010BC704769 +:102B000010B50BF0A2FE10BD80E100E008E400E08B +:102B100018E400E000B0004040B1004080E200E076 +:102B200000E100E000B5004048B1004040810040B5 +:102B300044B100407372635C72656D5F68616C5F85 +:102B40006576656E745F74696D65722E6300000052 +:102B500000B3004040B3004040B5004000F50140E4 +:102B60000083004040850040008200404800002073 +:102B700000B10040C08F00400085004004B100401B +:102B800004B5004008B1004008B5004000E200E094 +:102B9000093D0000378600006F0C010010B50BF0F6 +:102BA00040FE10BD00200449C8630120012181407E +:102BB000024A116000BF7047C01F004080E200E081 +:102BC00010B50CF097FA0AF059F9FEF7DFFB12F096 +:102BD00063FA0CF0F5FF0CF081FF10BD70B50C46E8 +:102BE000054603F0D5FA214628460EF026F870BDBA +:102BF00070B50D46040012D0002D10D021012846DA +:102C000013F0F0FA10225449284613F08EFA524875 +:102C100001210838018044804560002070BD0120FA +:102C200070BD70B54C4E00240546083E11E0716839 +:102C300020014018817BAA7B914209D1C17BEA7BAC +:102C4000914205D10C22294613F042FA002806D001 +:102C5000641C30888442EADB0020C04370BD2046FB +:102C600070BD70B50D4606000AD0002D08D03A4C54 +:102C7000083C20886188401C884203D9042070BD2C +:102C8000102070BD3046FFF7CCFF002801DB401C50 +:102C90000AE020886168000140181022314613F0D4 +:102CA00044FA2088401C20802870002070BD70B538 +:102CB00014460D001FD0002C1DD00021A170022849 +:102CC00002D0102817D108E068782978000208435C +:102CD00011D00121A17010800BE02846FFF7A1FF61 +:102CE000002808DB401CA070687B297B0002084399 +:102CF0002080002070BD012070BD70B505461446CF +:102D00000E000AD000203070A878012807D004D91E +:102D1000114908390A8890420BD9012070BD002C56 +:102D200004D0287820702888000A5070022008708B +:102D300010E0002C0CD049680001411810222046F8 +:102D4000103913F0F2F9287820732888000A60738C +:102D500010203070002070BD540000205A4910B57A +:102D6000884207D301218904884205D3574909685D +:102D7000884201D2102010BD0146012006F0E4FA7D +:102D800010BD30B5044693B000200D4607901421C5 +:102D90000BA813F029FA1C21684613F025FA6A469D +:102DA000112010770020507710780221084310700E +:102DB00007A80C90012008AA907245486A46108521 +:102DC0000AA80B902088108460885084A088908482 +:102DD000E088D084907FF9210840801C40084000A2 +:102DE000907708209086108708A80F9010AA0BA94A +:102DF000684600F083FF002803D110A800882880CF +:102E0000002013B030BD3EB5044608206946088056 +:102E10002D48844207D301208004844205D32B48E7 +:102E20000068844201D210203EBD2146012006F0F8 +:102E30008BFA0028F8D12088694688806088C8808D +:102E4000A0880881E088488107F05FF801AB6A46F6 +:102E5000002101F0E1FB694609880829E4D003203C +:102E60003EBD1FB504460020029008206946088137 +:102E700015480391844207D301208004844206D37D +:102E800012480068844202D2102004B010BD07F03E +:102E90003CF8014602AA0F4801F055FD0028F4D184 +:102EA00069460989082901D00320EEE769460988A7 +:102EB000218069464988618069468988A180694680 +:102EC000C988E180E1E700000080010028000020BF +:102ED000042A0000FFFF000010B5031D036000205E +:102EE000521E04E05C181C60401C2346C0B2904295 +:102EF000F8DB0020186010BD01460A680020002A97 +:102F000002D0104612680A60704702680A600160C9 +:102F10007047000000B51E2823D00BDC0C281CD005 +:102F20001FDC030013F070FB090F1D111D1D171787 +:102F300013151D00302814DD3A38030013F064FB2C +:102F4000030F11091100002000BD214800BD04201D +:102F500000BD0D2000BD0F2000BD082000BD1120C8 +:102F600000BD032000BD10B50C4605F0EFFF0028A2 +:102F70001ED0204605F064F9002816D022780E2ACB +:102F80000DD00F2A0BD0022A09D0032A07D0102A0D +:102F900009D010A17C2013F046FA002010BDA078C3 +:102FA000FFF7B8FF10BD112010BD0AA18220F2E783 +:102FB00008A18820EFE710B504F083FF10BD10B51D +:102FC00005F03EF910BD10B504F0D9FF10BD0000AA +:102FD000023000007372635C686F73745F686369CA +:102FE0002E63000070477047704770477047704706 +:102FF00070477047704770477047704770470000D0 +:1030000010FFFFFFDBE5B151008001006400FFFF0E +:1030100003B40148019001BD09000020002803D03D +:103020008178012939D101E0102070470188FE4ADA +:10303000881A914233D01BDCFC4A881A91422ED068 +:103040000BDC00292BD00320C002081A27D001284E +:1030500025D001210903401A07E001281FD00228CA +:103060001DD0FF281BD0FF380138002815D116E0ED +:10307000FF220132811A904211D008DC01280ED0C3 +:1030800002280CD0FE280AD0FF2806D107E001292B +:1030900005D0022903D0032901D0002070470F205A +:1030A000704700B50B2826D009DC030013F0ACFAFA +:1030B0000B1D2125251B25292325271F1B00112832 +:1030C0001BD008DC0C2816D00D281CD00F2814D0DB +:1030D000102808D10FE0822809D084280FD0852835 +:1030E0000FD0872811D0032000BD002000BD05208F +:1030F00000BDCF4800BD072000BD0F2000BD04204B +:1031000000BD062000BD0C2000BD0D20800200BDCA +:1031100070B500290BD0CB1FFA3B81241E46CDB2DF +:10312000112B1BD2012805D0022806D009E000206F +:1031300010701DE0FF20043001E0FF2003308142C9 +:1031400018D0330013F060FA111613131613161665 +:103150001316161613131313161316000846FF380A +:1031600081381F2803D9FF39FE39022902D815708A +:10317000002070BD1470072070BD00B5030013F06F +:1031800043FA060406040C080A0C002000BD1120B6 +:1031900000BD072000BD082000BD032000BD007851 +:1031A0000207120F04D0012A05D0022A0AD10EE02C +:1031B000000907D108E00009012805D0022803D042 +:1031C000032801D0072070470870002070470620B0 +:1031D0007047002807D0012807D0022807D003280D +:1031E00007D007207047002004E0112002E02120D2 +:1031F00000E0312008700020704738B50C4605000B +:103200004FD06946FFF7CBFF002822D12088032149 +:1032100089028843694609788907090D0843208097 +:103220006946681CFFF7BBFF002812D121880320E4 +:1032300000038143684600788007800C01432180A9 +:10324000A8784007820F2020012A03D0022A03D049 +:10325000072038BD814300E00143218088B2010589 +:10326000890F08D0012189038843A9780907C90F6C +:1032700089030843208080B28104890F0AD0A9788D +:103280004004C906C90F400CC903084320808004CC +:10329000800F02D12088400403D5208840210843B4 +:1032A0002080002038BD70B50446002008801546F7 +:1032B0006068FFF7A2FF002815D12189A08981420B +:1032C00010D861688978C90708D00121490288426D +:1032D00008D8491C12F0A3FF298009E0FF21FF3123 +:1032E000884201D90C2070BDFF30FF3003302880A8 +:1032F000002070BD10B5137804785B08E4075B000C +:10330000E40F23431370FD2423400478A407E40F43 +:10331000640023431370FB24234004786407E40F04 +:10332000A40023431370F724234004782407E40FF8 +:10333000E40023431370EF2423400478E406E40FF1 +:10334000240123431370DF2423400478A406E40FF0 +:103350006401234313700078BF244006C00F23404C +:10336000800103431370002906D00878C10701D1FA +:10337000800701D5012000E00020C0015906490E58 +:103380000843107010BD30B50A8803239B020488DF +:103390009A4323059D0F02D1A3049C0F01D09B0FDC +:1033A00000E001239B021A4303230A801B039A4374 +:1033B00003889804840F02D11805830F01D0800F71 +:1033C00000E00120000302430A8030BDF3B593B052 +:1033D0000D000FD0139800280FD01221284612F0AC +:1033E00001FF03AAFF21012003F0E7F8002426468D +:1033F00037467AE0102015B0F0BD0720FBE768469D +:10340000807D01280BD16846818A0520C002081AF8 +:1034100010D0012810D0022812D0032812D0042C7A +:1034200014D0052C15D113E002290000012800005A +:1034300003300000012400E002246846468A08E0C8 +:10344000032406E068460424478A02E0052400E0DD +:1034500006246846418A1398814246D12C74002E76 +:1034600041D00DAA0EA905200292019100901023CF +:103470000022FF21304603F041F9002823D168469D +:10348000808E2A46C0B20EA9FFF711FC00281AD17F +:10349000AE81002F27D00DA9052008AE0291009023 +:1034A000132300220196FF21384603F027F9002854 +:1034B00009D16846808EF11CC01EC0B22A1DFFF7DC +:1034C000F6FB002801D0032095E708A88178427810 +:1034D00008021043E881062C05D16846807DA87259 +:1034E0006846808A2881002085E703A803F06EF8EB +:1034F000002884D0FFF7D5FD7DE7002805D0F94AE4 +:10350000012903D0022903D003207047518800E02D +:103510009188814201D1002070470720704770B523 +:103520000C4605461C21204612F05CFE002020803F +:10353000002D08D0012D04D0EBA1F04812F073FF4C +:1035400070BD062000E00520A07070BD70B592B07F +:103550001546064601206A461071107453740846D9 +:1035600008300395029048889082FEF7E1F9040044 +:1035700019D06580172069468883203600940AABED +:103580007178023307AA01A80DF05FF9064660784A +:10359000000701D5FEF7ADF9002E0AD03046FFF73F +:1035A000ECFD12B070BD1321284607F01BF9032073 +:1035B000F7E708A800906846838B0422012128467B +:1035C00008F035FEEDE770B506468AB000200D46DE +:1035D00007900590069003A90490052402460291E5 +:1035E0000190102300942946304603F087F8002804 +:1035F0000DD108A804A9009102900194684683891E +:1036000000222946304602F095FE002801D0FFF73F +:1036100048FD0AB070BD10B50DF01DFB10BDF0B532 +:1036200089B000260546059600780C460827030059 +:1036300012F0EAFF0CFD070C3A0B77779EC2FCD81C +:10364000E8FD68680A38FEF7E8FA0DE1A88800236B +:1036500080B201220321009009F08CFA0290002C24 +:1036600004D0A648A0A16E3012F0DDFE029800281A +:1036700004D1A2489CA16F3012F0D5FE02980099A7 +:1036800008300CF017FDFEF753F9040007D06078FE +:103690003843607000986080FEF72BF9E6E0132154 +:1036A000009807F09FF8EFE0002C04D1BD208EA118 +:1036B000800012F0B8FE608800230122032109F087 +:1036C00059FA0090002804D18C4887A1883012F064 +:1036D000AAFE0099002008802A7994461EE0C300C3 +:1036E0005B199B6807936B469B8B1A0708D5DA0614 +:1036F00006D56046C20050194038C08F088006E0E9 +:103700005B0409D50871C2005019C08848806078F0 +:10371000384360700226A7E0401CC0B28445DED862 +:10372000A2E0E888694608800090002C04D1734824 +:103730006DA1983012F077FE2878062814D10098F1 +:10374000C00B11D0608800230122032109F012FA76 +:10375000060004D1694864A1A23012F064FE002082 +:103760003071A88870803BE06078384360707BE0FF +:10377000002C04D161485CA1B43012F054FE608882 +:1037800000230122032109F0F5F90090002804D15B +:103790005A4855A1B73012F046FE009808300DF097 +:1037A000ACFA0121484002D1E888C00B5CD00098F7 +:1037B00061880226C180D7E7002C04D14F484AA176 +:1037C000D03012F030FE608800230122032109F07E +:1037D000D1F9002804D1494843A1D33012F023FE87 +:1037E0000226C1E7002C04D144483FA1DC3012F08E +:1037F0001AFE0226618801222046FEF71FFA0120E8 +:103800000590B1E7A889002380B20122032100902E +:1038100009F0B0F90746002C04D0384832A1EE3048 +:1038200012F001FE002F07D12FA101E00FE016E0FA +:103830003248EF3012F0F7FD686802902889694637 +:103840008881012202A90098FEF714FA0CE0002CEE +:103850008AD16D2024A1C00012F0E5FD84E727483D +:1038600021A1FE3012F0DFFD002C0DD060780007A2 +:103870000AD50598002807D18420207020465822B8 +:1038800029460830FDF7A0FC304609B0F0BDF7B579 +:103890000C460546007A224688B00A320292921CF3 +:1038A00004920027811E16323E4601920B0012F050 +:1038B000ABFE08F605F548488DD1F4F5688800237D +:1038C0000122032109F056F90190002803D106A135 +:1038D0000B4812F0A8FD01980088002812D052274A +:1038E000072601E1000900207372635C676174744C +:1038F000735F636F72652E63000000006F0200004B +:103900008603000051271E26002C7DD06888A080E9 +:103910000120A071019802990079C0004019C08966 +:10392000FFF754FD002870D101980079C0004019BC +:10393000C089208101980079C0004019408AA08385 +:10394000F2E0698A0091062820D1E889C00B1DD0D9 +:1039500008462230512786B2002CD6D0A889049977 +:10396000FFF734FD002873D16888A0800220A07181 +:10397000A88920810120A072288AE08300982084F1 +:103980006969009A019812F0D0FBCDE0084620301A +:10399000502786B2002CB8D0A8890299FFF716FDEF +:1039A000002855D16888A080A889E080287A062858 +:1039B0000AD002202072288AA0830098E083204643 +:1039C00069692030009ADEE70120F3E76888002368 +:1039D0000122032109F0CEF80690688A009006982B +:1039E000002803D1FD49FE4812F01DFD069808305D +:1039F0000DF083F90121484002D1E889C00B26D09F +:103A00000098223086B201E073E021E05127002CBB +:103A100079D06888A080A8890499FFF7D7FC00288E +:103A200016D10220A071A88920810420A072288AC2 +:103A3000E083009820846969009A019812F075FB70 +:103A40000699002008710698A98941806CE003203E +:103A50000BB0F0BD688805F0D2FB019068880023A8 +:103A60000122032109F086F800900198002804D172 +:103A7000DB48DA492C3012F0D6FC0098002804D13B +:103A8000D748D6492D3012F0CEFC0098D549C088D1 +:103A9000884205D05127222604E01EE03FE035E0B1 +:103AA00050272026002C2ED06888A080502F07D0C9 +:103AB0000220A0712146287B0831FFF730FD33E05A +:103AC000287BA11DFFF72BFD6A8800230099019830 +:103AD000FFF73CFD0028BBD126E0C349A889C9886F +:103AE000814207D154270626002C0CD06888A0807C +:103AF0001AE008E053270826002C04D06888A0802C +:103B0000A889E08010E00A98068013E05527072670 +:103B1000002CF8D0A889A0800020A07104E08D209E +:103B2000AE49C00012F07FFC0A98002C068001D03C +:103B30002780668000208BE7AB4900200870704723 +:103B400030B585B00C4601F0E0F90546FF2804D1F8 +:103B5000A348A249953012F066FC00202080207115 +:103B60006080401EE0802046294608300CF096FA1E +:103B70006A462946012002F020FD102412E0684622 +:103B8000808800070ED56846C0882946FFF71BFDD0 +:103B900068468188FF2321438180C0882946019A95 +:103BA00002F036FE684602F011FD0028E7D005B0AD +:103BB00030BD0A46014610B5104608300CF082FAB6 +:103BC00010BD70B5002305461A46032108F0D2FF48 +:103BD000040004D182488149B73012F024FC204609 +:103BE000294608300CF066FA70BDF0B591B00C466D +:103BF000074605F004FB050005D02878222804D2EA +:103C0000082011B0F0BD7948FBE700231A460321D4 +:103C1000384608F0AFFF0646002C02D0A0880028E6 +:103C20000CD00120694608710220087400204874F5 +:103C3000002C05D0A0880883206802E00920E0E776 +:103C4000088305903046083003970290FDF770FE18 +:103C5000040018D0678017206946888320350094B7 +:103C60000AAB6978023307AA01A80CF0EEFD0546FD +:103C70006078000701D5FDF73CFE002D09D02846ED +:103C8000FFF77BFABDE71321384606F0ABFD0320B2 +:103C9000B7E708A800906846838B042201213846C4 +:103CA00008F0C5FA0021C943F180AAE7FFB585B045 +:103CB0000E9E7788384605F0A2FA054600231A467C +:103CC0000321384608F056FF0446002D03D143492E +:103CD000474812F0A8FB002C04D145483F49401C3E +:103CE00012F0A1FB0834089869460394C1C105A8E5 +:103CF0000DC8203569780CF017FAC6E5F0B5044612 +:103D0000002099B00D4601460D9010A881811646FD +:103D100001818180344A68469180018510A8018024 +:103D200068460187818581841078012808D002289F +:103D300006D0032804D0042802D0082019B0F0BD12 +:103D40002C4A944273D32C4F0121890438688C4249 +:103D500001D3844278D3274A954275D3012189043F +:103D60008D4201D385426FD36168002913D0214A67 +:103D7000914269D301229204914201D3814263D3DB +:103D800060892189884203D801225202914201D9D7 +:103D90000C20D3E70D9016AA0EA92846FFF783FA48 +:103DA0000028CBD1686880784007800F02280AD1AC +:103DB0006846008F8004800F05D02869002802D053 +:103DC0003968884240D30AA92069FFF716FA00280B +:103DD000B4D1206900281CD060780FE0E8380000DA +:103DE000EE030000FFFF0000000900200230000089 +:103DF0000C050000008001002800002080076846B4 +:103E0000008D03D58004800F68D002E08004800F0D +:103E100064D16846008D810618D58004800F6068E3 +:103E200006D0002812D0396888420DD302E00BE09A +:103E300000280BD0FE49884206D30121890488421C +:103E400004D33968884201D2102077E709A9606954 +:103E5000FFF7D3F900289CD16069002808D0684694 +:103E6000808C0105890F012938D18004800F35D05D +:103E70000BA9A069FFF7C1F900288AD16846808C98 +:103E800080062BD46846808D810627D4A16900293D +:103E900006D00105890F012920D18004800F1DD093 +:103EA000E068002804D00078002817D01C2815D21C +:103EB00004AA611C2046FFF71DFA0121890210A8FF +:103EC0000180012768468773DA49818104AA033299 +:103ED00017A92868FEF711FF002801D007202DE759 +:103EE00010A8007F15A9C01CC2B200200C9201903E +:103EF000FF32009003460291FF3203A8033210996B +:103F000002F0B3FA002826D110A9888A0F902A89D6 +:103F10002969C94801910092029010A90A8B6B8906 +:103F200028680E9902F0A1FA01007DD1C24800254F +:103F3000001F818868464174090A8174052104A81C +:103F40006A4623C210A82A46FF21808A0C9B02F0F1 +:103F5000F1F9002802D0FFF7A4F8EFE66846007CEC +:103F60000322C1090020920290430122920280188C +:103F70001490002928D0014610A801806846292104 +:103F8000877309028181058608A8007C0023410807 +:103F900060784900C007C00F014308A80174FD20E4 +:103FA00001406078A54A8007C00F4000014308A87F +:103FB00001740CA9022001910090029503A81099A8 +:103FC00002F053FA01002FD16068002828D0206940 +:103FD00000280DD10AA90EA8FFF7D5F9607880074F +:103FE00006D46946088D032109038843694608857C +:103FF000904968468773FE31818190492089891EE6 +:1040000012F00DF962680D9811AB019200900293C5 +:104010000A46002303A80A9902F027FA010003D1F7 +:104020002078C10603D400E086E080062AD56846E1 +:104030000586606900280DD109A90EA8FFF7A3F92C +:104040006846818C03208002814301208002091888 +:10405000684681846946888CC821084369468884FB +:1040600074488F73FF30888112AA0CA90220029233 +:10407000019100900023714A03A8099902F0F5F913 +:10408000010059D12078C00729D068460586A0696B +:1040900000280DD10BA90EA8FFF775F96846818D90 +:1040A000032080028143012080020918684681852F +:1040B0006846818D40200143684681858773604949 +:1040C000818113AA0CA90220029201910090002381 +:1040D0005A4A03A80B9902F0C8F901002CD1E068F4 +:1040E00000282DD010A8149901805549684687737F +:1040F000491C8181E16808A80A78027449784174F2 +:10410000E0684122418868464186E06800230179E1 +:1041100008A80175E068D200C18808A84175090A9D +:1041200081750CA8072101900091029503A81099B0 +:1041300002F09BF9010003D00F9800F0EAFEFDE5C4 +:104140003D480321001F0170002E0AD08088308076 +:1041500010A88088708010A80089B08010A880897D +:10416000F0800020EAE530B501248BB015460B46FF +:10417000012802D002281CD104E06846052184737E +:10418000C90203E02B4968468473891E8181002B94 +:1041900012D003210020890288430121890240189E +:1041A0006946888405AA04A91846FEF7A6FD0028DA +:1041B00004D007200BB030BD1020FBE76A46127C0C +:1041C0001D480092801E05A9FF3201910290FF3226 +:1041D000002303A80332099902F047F9002802D00E +:1041E000FEF75FFFE6E71448001F002D01D041886D +:1041F000298004700020DDE770B592B004460126E6 +:1042000008A886700F496846018410AA08A930469C +:10421000FFF7A9FF00284DD12078074DC0070024E3 +:104220002D1F002848D01C21684611F0DDFF0BE04F +:1042300000800100032800000409002003020000A0 +:10424000032900000118000068460178202001437E +:104250006846017008A88670F9496846018411947F +:104260000794817FF92001406846891C81770020EE +:1042700001466846017700200146684641770421DF +:104280008185C485018607A80A9011A80D9008A809 +:1042900009900EAA09A96846FFF730FD002809D148 +:1042A0006846008FE8806846808F2881401C6881BE +:1042B0002C70002012B070BDEC802C8110A80088FA +:1042C000F4E7F7B5DF4900260A789EB0012A04D04A +:1042D000022A02D0082021B0F0BD4A88824201D0D3 +:1042E0000620F8E71F98824201D10720F3E7012258 +:1042F00010A98A75D4488882002003239B020146B6 +:1043000099439302CB1810A90B8669468A81CF4A3C +:10431000CA8118A9887110A9888419A904916946CD +:10432000CA820690FF20087503A802F072F90024E3 +:104330002546274608AA052103A802F06DF90028A2 +:1043400010D082286FD1002C6FD0002D6DD010A816 +:104350008480C5800021017418A8807B11AC0128DD +:1043600065D06DE008A88079002F21D0012857D1B1 +:104370006846818CB44881421CD113AA0DA905203E +:104380006B4607C36846408C10230022FF2102F0D1 +:10439000B5F9002868D110A88089042801D0062822 +:1043A0004CD16846818E1F98814239D10F2092E707 +:1043B000012835D16846808C0521C902884202D087 +:1043C000491C88422CD19F4841886846408C8142D4 +:1043D00001D1012700E00027002C01D0002D10D0D2 +:1043E0001F9988421CD113AB0DAA05216E460EC63B +:1043F000044610230022FF2102F080F9002833D167 +:1044000001E035460CE010A88089022801D0102870 +:1044100014D1C0B21BAA0DA9FEF749FC00280DD18A +:104420006846468C86E71FE0FFE7052053E714A99E +:104430001BA8221DFEF761FC002801D003204AE7DB +:1044400010A8007C0023001DC2B210A8027420989E +:1044500002900194009215A81C9902F006F8002819 +:1044600002D1784902220A70FEF71BFE33E710B52D +:104470000B46401E86B084B203AA00211846FEF700 +:1044800039FF04AA052103A802920191009001239B +:104490000022FF21204601F04DFF04466846008AB5 +:1044A000012804D06D206A49000111F0BCFF2046AC +:1044B000FEF7F7FD06B010BDF0B5624F0446387840 +:1044C00087B00E46032804D0042802D0082007B085 +:1044D000F0BD04AA03A92046FEF7E5FE0500F6D1CB +:1044E000606880784007800F02280DD16846808977 +:1044F0008004800F08D02069002805D0554909683C +:10450000884201D21020E2E7208905AA6B46216982 +:1045100007C369460A8A63892068039901F0A5FFE9 +:10452000002802D0FEF7BDFDD1E7002E02D068467C +:10453000808A3080042038702846C8E738B50C00DF +:10454000054609D000236A46FF2102F039F9002808 +:1045500004D0FEF7A6FD38BD102038BD69462046C0 +:10456000FEF74BFE0028F8D1A078FF21C307DB0F30 +:104570002846009A02F04CF9EBE73EB50C0009D052 +:1045800002AB6A46FF2102F01BF9002804D0FEF7B7 +:1045900088FD3EBD10203EBD0321204611F022FEC5 +:1045A0006846008801A90005800FFEF712FE00286A +:1045B0000BD16846007920706846008801A9800404 +:1045C000800FFEF706FE002801D003203EBD68469E +:1045D00000796070A278EF20024068460088C10B25 +:1045E00009010A43F7210A404104C90FC9000A43DF +:1045F000A270F9210A40800601D5022000E00120C6 +:10460000400069460243097A50084000C907C90FB3 +:104610000843A07000203EBD7FB5144605220192DC +:1046200003AD029500930A462388FF2101F082FE24 +:10463000694689892180FEF734FD04B070BD000011 +:10464000052A00000009002002280000FFFF0000EA +:10465000E838000028000020F3B5002799B068462C +:104660000C4607873D4600291ED0E068002806D08A +:10467000A068002818D001886A4611870780199819 +:1046800004F0BDFD002812D0007822287ED31998AE +:1046900000F03BFC002300901A460321199808F013 +:1046A00069FA060009D104E010201BB0F0BDFD48F6 +:1046B000FBE7FD49FD4811F0B6FEA078012803D0C4 +:1046C000022801D00720F0E72088002808D0401EEB +:1046D00080B203AA009901F070FF002859D11DE0B3 +:1046E000F048401CE1E76946498A228891420BD292 +:1046F0006846807D0025012810D16846808AEC49F3 +:1047000088420BD1012509E0914203D1002D2AD026 +:104710006D1C01E0022D0BD0032D04D203A801F083 +:1047200055FF0028DFD082281BD0002831D11DE0A2 +:104730006946897D0129F1D16946DD4B8A8A5B1E74 +:10474000D11A9A420FD005DCDA48101A0BD0012892 +:10475000E4D108E0012906D0FF390129DED1032583 +:10476000E1E7022D15D10D2080029EE7E0680028C8 +:1047700016D00EA9052202910192009069460B8F76 +:10478000A2882088FF2101F0D5FD00E01EE000286E +:1047900002D0FEF786FC88E76846A168008F088093 +:1047A0006846008AC00601D5C3487EE707980028FE +:1047B00003D06846008B022801D0032075E70798D4 +:1047C000A1780078012903D0800710D408206CE775 +:1047D000C007FBD000220721199808F010F8002824 +:1047E00002D00725022004E0AE48801C5DE70225C8 +:1047F000032008A908702188684681851998083621 +:104800000A90099617216846818712AB02330FAAD6 +:10481000052108A800970CF018F8002802D0FEF730 +:10482000ACFC42E710A800906846838F042229461A +:10483000199807F0FCFC38E770B5064615460C469B +:104840000846FEF7EBFB002804D12A4621463046F5 +:10485000FFF789FCF2E610B5FFF733FD10BD70B528 +:104860001E4614460D0014D0002C12D06168002999 +:104870000FD00121FEF741FE002809D12068FEF784 +:10488000CDFB002804D1324621462846FFF736FAF0 +:10489000D4E61020D2E670B515460C000ED00221E9 +:1048A000FEF72BFE002808D12068FEF7B7FB002892 +:1048B00003D129462046FFF7FFFDBFE61020BDE6E5 +:1048C000F8B506467D480D46016814468A4231D344 +:1048D0006068002808D07A4A90422BD301229204C3 +:1048E000904201D3884225D37648864204D0304690 +:1048F00004F085FC00280CD0304600F006FB06468C +:10490000284600F0BFFA002804D16068002802D0D1 +:1049100012E06448F8BD00236A463146284601F09B +:104920004FFF002802D0FEF7BCFBF8BD68460088A8 +:10493000800601D41020F8BD6188224628466368AD +:10494000FFF76AFEF8BDF7B55C4E0746306886B0E3 +:104950001446824202D2102009B0F0BD384600F061 +:10496000D4FA05465748874201D0FF2D08D00023CE +:1049700004AA2946079801F023FF002826D101E068 +:104980004848E9E76846008AC00601D54A48E3E797 +:1049900003A9002002910527019000976288494BE6 +:1049A0002946079801F0AAFE00280FD161683268F5 +:1049B000914208D30191029000972388628829468A +:1049C000079801F09BFE694689892180FEF769FB03 +:1049D000C2E7002907D03C4B0A881B899A4202D8BB +:1049E0003048401C704737E610B586B004236C464B +:1049F000A382354BDC88002C07D01B898B4201D267 +:104A0000914204D92748401C54E5062052E56B46E4 +:104A100019825A820021009101911C800221997013 +:104A200005A9029104A903916946FFF715FE41E526 +:104A3000F3B50C4685B0812069460873002C1BD065 +:104A4000059804F0DCFB070018D03878222869D3D9 +:104A5000059800F05AFA049000220121059807F009 +:104A6000CEFE00280CD000231A460321059808F03A +:104A700081F805000AD105E0102028E5094826E55F +:104A8000112024E50849114811F0CDFC28460830D2 +:104A90000BF032FB06462078012819D0022838D0C6 +:104AA000072014E502300000E8380000E1080000AB +:104AB0000328000000280000013400002800002026 +:104AC00000800100FFFF000000090020840A0000B0 +:104AD000A18803AAFEF71CFB0028CED1B00721D580 +:104AE0006846007B00281FD1A079C0071CD0E06871 +:104AF000002205216B4607C36389228968880499CF +:104B000001F018FC6946087300280DD0FEF7C9FAB9 +:104B1000DDE4A18803AAFEF7FBFA0028ADD134201A +:104B2000064201D10820D2E46846037B2946384674 +:104B3000059AFEF70BFDCAE4FFB597B0002001907F +:104B40001F4615460C460E46179804F058FB0028E1 +:104B500004D00078222803D20820A6E5F448A4E572 +:104B6000B80801D00720A0E5032F00D1002717982F +:104B700000F0CBF90890002C1BD0022D77D3ED4824 +:104B8000006884427CD361190091012902D0491E3A +:104B9000814275D3AD1EAAB22146E74810F036F81F +:104BA00000991E394A7F0B7F11021943884267D151 +:104BB000ADB2E248B90702D50189491C00E00121E4 +:104BC00089B20091F90701D0078900E0DA4F03AA02 +:104BD0000899009801F0F1FC0DE0F078B17800023E +:104BE000084310284CD80199091D401880B2019043 +:104BF000A84245D82618002E60D07078317800027F +:104C0000084300998842E8D358E06946098A0A07B0 +:104C100054D5002C3FD0019AA618121D92B20992C9 +:104C2000F278B37812021A439446102A28D8099AC7 +:104C30006244AA4224D87278337812021A4390420E +:104C40001ED1C8061ED509980AAA052120186B4650 +:104C500007C3707831780002084363460022089940 +:104C600001F068FB002803D0FEF71BFA1DE507E002 +:104C7000F078B178000208436946098D884201D076 +:104C80000B2012E5F078B17800020843099940182A +:104C900080B2019006E0C90604D50899FEF793FC9E +:104CA0000028E3D16946088A1021884369460882B2 +:104CB000488AFF23049A089901F0AAFD03A801F08D +:104CC00085FC002803D16846408AB8429DD900235C +:104CD0001A460321179807F04DFF040003D19849A5 +:104CE000984811F0A0FB20880028BFD0012108A817 +:104CF00001700173002646732188684601862046AC +:104D00000830099017980A90FCF712FE05001BD096 +:104D10001798688017206946888010AB023301AA73 +:104D2000052108A800950BF090FD0746687800075C +:104D300004D584488249223011F075FB002F09D038 +:104D40003846FEF71AFAB0E41321179805F04AFD29 +:104D50000320AAE40EA8009068468388042201215B +:104D6000179807F064FA00288BD126809DE4F0B5EF +:104D700000248DB01F4615460E46002A04D0B908FF +:104D800004D007200DB0F0BD1020FBE7032F00D1A9 +:104D9000002700F0BAF80390FF2804D06749B8074D +:104DA00003D5488902E06248ECE70120FA0702D007 +:104DB0004989491E00E0604906AA8FB2039901F0B3 +:104DC000FCFB38E06946898B090734D504AB052123 +:104DD0000022029300910192574B039901F08EFC3F +:104DE000002821D1002E21D06A46128A2988A218D3 +:104DF0003019121D914234D36946CA8B0270120ACF +:104E000042700A8A8270120AC27004A90522001D2B +:104E10000092029101906946C88B0B8A0022039987 +:104E200001F06CFC002801D00320ABE76846008A43 +:104E30002018001D84B206A801F0C8FB002804D089 +:104E4000822806D0FEF72DF99CE76846C08BB84251 +:104E5000B8D9002C07D0002E10D02988A01C814280 +:104E600003D20C208EE705208CE7224631463248DB +:104E70000FF0CCFE31190870000A4870A41C2C8079 +:104E800000207FE700B585B06946FEF79FFA00284D +:104E90000AD16846007C030011F0B6FB08052F2FED +:104EA0002F2F08080531032005B000BD6846807823 +:104EB000012807D1684600880321C902401A1CD086 +:104EC00001281AD068468079012806D16846808872 +:104ED00015214902401A05280FD96846807A012811 +:104EE00011D16846018929200002081A05D002283C +:104EF00003D0032801D0042805D10F20D4E712A144 +:104F0000164811F090FA0020CEE710B507F028FE01 +:104F100010BD10B50C4601F023FB002803D00AA1F8 +:104F20000F4811F080FA2046FEF7BBF810BD0000D4 +:104F30000230000028000020FFFF000000090020D0 +:104F4000E83800003F0B00007372635C67617474A3 +:104F5000735F636F72652E63000000002202000021 +:104F6000BB060000F8B500780C46164610340E3625 +:104F7000069F022809D0032836D005287ED0FF20BE +:104F8000F6A1E53011F04FFAF8BDCD890A2068434B +:104F90000E30188031203880002AF5D0087B9581AA +:104FA000801FC7B21AE020886168308048780A788C +:104FB00000021043F080C8788A78000210433081E4 +:104FC000B21C3846091DFDF772FE002F01D00028E3 +:104FD00002D000203071708008340A3628466D1ED9 +:104FE000ADB20028DFD1F8BDCD890A2068430E306C +:104FF000188032203880002AF5D0087B9581401F28 +:10500000C7B243E0616822880878F2803279C3072A +:1050100052085200DB0F1A43FD231A408307DB0FAF +:105020005B001A43FB231A404307DB0F9B001A4324 +:10503000F7231A400307DB0FDB001A43EF231A4064 +:10504000C306DB0F1B011A43DF231A408306DB0F65 +:105050005B011A43BF231A404306DB0F9B011A432F +:105060003271C00970718A784B7810021843308110 +:1050700032463846C91CFDF71AFE00E00CE0002855 +:1050800002D00020B070308008340A3628466D1EE9 +:10509000ADB20028B6D1F8BD087BCD89801E86B29E +:1050A0003046083068431030188034203880002A99 +:1050B000F1D0174695811037E800D681C0190090CD +:1050C0000DE020883880009878603246616800984A +:1050D00011F02BF800980834801908370090284602 +:1050E0006D1EADB20028ECD1F8BDFFB581B00A9DB0 +:1050F0001E460C46002A05D0607AFF300130D08071 +:10510000E089108101980E270078030011F07CFAE5 +:105110000B7E0719293541536C7878787E00009210 +:10512000087B082805D0032803D091A1954811F0E9 +:105130007AF9378030200FE000990020888105B08F +:10514000F0BD0092087B042804D08E4888A114305A +:1051500011F069F937803120288000980028EBD1C0 +:10516000EDE70092087B042804D0932080A1800002 +:1051700011F059F937803220EEE70092087B0228BF +:1051800004D080487AA13A3011F04DF937803320AD +:10519000E2E7087B1746042804D07A4874A14C3013 +:1051A00011F041F91020308034202880002FC6D023 +:1051B0000020B88116E0207B1746052806D0062877 +:1051C00004D070486AA1603011F02DF912203080AF +:1051D00035202880002FB2D0E089B88100203882A5 +:1051E00001984088F881AAE70092087B072804D03C +:1051F00064485FA1713011F016F937803620ABE7B3 +:1052000033460095019800F00EFC98E72F2053A13B +:10521000000111F008F992E770B50C46054603F05D +:10522000EEFF002804D00078222803D2082070BDA9 +:10523000554870BD00231A460421284607F09AFC01 +:105240002060002801D0002070BD032070BDFFB594 +:105250008BB00D4607461720694608850E98032631 +:105260001446002805D10EA93846FFF7D5FF0028BF +:1052700034D1002D0BD000220321384607F0BFFAAD +:10528000002834D00E980078002830D108E020782B +:10529000092819D00F2823D030A13C4811F0C3F8B9 +:1052A0000E98A760801D03AA606002320AA92046FA +:1052B00000F00FFC002827D0030011F0A5F9071A11 +:1052C000182323211C1E23000726002231463846BE +:1052D00007F095FA0028E3D12B48801C0FB0F0BDF1 +:1052E00000220321384607F08AFA0028D8D111207D +:1052F000F4E70020F2E70820F0E72348401CEDE740 +:105300000720EBE70320E9E701A800906846038D3A +:1053100004223146384606F08AFF0028DED1002DEF +:10532000DCD00E990D70D9E730B587B01D460C461C +:10533000002A11D0042369460B7013888B81528890 +:10534000CA81A2788A7422880A8200236A46294682 +:10535000FFF77DFF07B030BD1020FBE77372635C81 +:1053600067617474635F636F72652E630000000091 +:105370007372635C67617474635F636F72652E63DD +:105380000000000025020000023000004F03000072 +:10539000F3B581B001980C4600780826030011F09F +:1053A00033F9125F47471B134B0A0A0A0A0A0A0A13 +:1053B0000A0A0A0A0A5F002C02D1F849F84808E0F4 +:1053C0006078304360703CE0002CF9D1F448F34938 +:1053D000083011F028F8F3E70198002380880122B3 +:1053E00087B20421384607F0C5FB0546002C04D0DF +:1053F0007520EA49C00011F016F8002D04D1E848E4 +:10540000E649143011F00FF83946A81D00F058FB9A +:10541000FCF78EFA040006D0607830436070678035 +:10542000FCF767FA0FE01321384605F0DBF915E0C9 +:10543000DB48DA49283002E0D948D8492D3010F04D +:10544000F2FF002C0AD06078000707D59320207067 +:105450002046582208300199FBF7B6FE0020FEBD19 +:10546000CF48CE493130EAE710B500210170801DE8 +:1054700000F023FB10BD0A4610B50146901D00F058 +:1054800027FB10BD70B5002305461A46042107F01E +:1054900071FB040004D1F920C049800010F0C3FF63 +:1054A0002946A01D00F00CFB70BDF7B5054684B081 +:1054B0000C4600206946088188806F8803460122D7 +:1054C0000421384607F056FB060004D1FD20B349FD +:1054D000800010F0A8FF002C03D0A7800020E080FF +:1054E0002081297A20461230C91E142700900B0013 +:1054F00011F08AF80FFEFDFC3809A95E657A2FB21B +:10550000C9E99191FC003078012804D0A3497020AA +:10551000143110F088FFA9896A46C8000E309080C7 +:1055200030201081002C13D0A18100200DE0C1009B +:10553000327909190A747288CA8182005319DA898A +:105540004A821A8A401C8A8280B2A1898142EED89E +:10555000F1E002A8009001AB22462946304600F057 +:105560002BFAE8E03078042804D08C49BD201431AF +:1055700010F059FFA8890622014650436A460E30B2 +:10558000908033201081002CE2D0A18100200BE01C +:10559000062141434F190919FA89CA81BA7C8A74D4 +:1055A0003A8A401C0A8280B2A1898142F0D8C2E0C6 +:1055B000307806280BD079491431D72005E03078AF +:1055C000062804D07549EB20143110F02CFFE8892F +:1055D00069461230888035200881002CB8D0A9890E +:1055E000A1817188E18126E03078072804D06B49D9 +:1055F000FF20143110F017FFA8896A4601460E30CB +:10560000908036201081002CA2D0A1812046AA894A +:105610000E30296954E0E8896946123080B2382298 +:1056200088800A81002C7ED0A989A181287A10283F +:1056300007D00221A173E9892182EA8929690098AA +:105640003EE00121F6E702A8009001AB2246294680 +:105650003046FFF787FC6EE03078082805D04F49C8 +:10566000FF201431EE3010F0DEFE684637218780CF +:105670000181002C5FD0A989A18100206082208255 +:105680000120A07357E03078092805D04349FF2056 +:105690001431FF3010F0C7FE288A69461430888024 +:1056A00037200881002C46D00421A173A989A1814B +:1056B000E9892182298A618220462A8A143069690F +:1056C00010F033FD37E030780A2804D033493548EC +:1056D000143110F0A8FE6846372187800181002C24 +:1056E00029D00521A1730020A08102E01EE003E083 +:1056F0000CE0208260821EE002A8009001AB2246EE +:1057000029463046FFF7F1FC15E00CE00D20694614 +:10571000392288800A81002C05D00120E0800020F9 +:105720002081207307E00699088019E01C481B4976 +:10573000A43010F078FE6846069980880880002C16 +:105740000ED0684600892080684680886080287A6C +:10575000032805D0102803D0112801D00020307074 +:10576000002007B0F0BDF7B5568815460F46002358 +:1057700082B01A460421304607F0FCF9040004D137 +:1057800007480649C43010F04EFEA41D33462A4691 +:1057900039460094029800F022FBD0E45C530000EC +:1057A0009503000013020000F7B58CB00D461446B7 +:1057B00007A90C98FFF730FD002812D1B64E01273B +:1057C000002C0FD00321684601701021818208A8A7 +:1057D00002460690204605A9FDF78FFA00280BD057 +:1057E00007207BE50821684601708581C681052177 +:1057F0008774C90201820BE00798A17801712188A2 +:105800004180684605218774C90201828581C6816D +:1058100002460121079B0C98FFF719FD5EE508B5CC +:1058200001236A4693709D4B13800A460223694602 +:10583000FFF77AFD08BD08B501236A469370974BC0 +:105840005B1C13800A4603236946FFF76DFD08BD04 +:1058500000B587B000290CD002236A4613700B886C +:1058600093814988D18100230421FFF7F0FC07B020 +:1058700000BD1020FBE710B5002903D00523FFF77A +:1058800053FD10BD072010BD70B588B00D461446FD +:10589000064607A9FFF7C0FC00280DD1002C0DD04B +:1058A0000621684601708581C481079B02465C80A1 +:1058B00006213046FFF7CBFC08B070BD05216846D5 +:1058C00001708581F1E710B588B000290BD007245D +:1058D0006B461C709A81049100236A462146FFF7AB +:1058E000B6FC08B010BD1020FBE770B500241722ED +:1058F00088B0002914D00D782B0010F085FE062307 +:10590000050519041B231522D21E93B2CA88002A4A +:1059100002D08E68002E03D09A4203D90C20CBE728 +:105920001020C9E7042D05D08A88002A0AD101E099 +:105930000620C1E7012D11D0022D05D0042D18D06D +:10594000052D23D00720B7E709236A4613704B883B +:105950009381CB88D381896804911DE00C236A462A +:1059600013704B889381CB88D38189680824049174 +:1059700012E00D236A4613704B8893818B88D38184 +:10598000CB88138289680924059105E00E236A46B5 +:105990001370497811730A2400232146FFF757FC3E +:1059A0008AE700B587B00F236A4613709181002300 +:1059B0001946FFF74CFC5AE7FEB50078089D1C46D7 +:1059C00016460F46012803D03549912010F02BFDD3 +:1059D000F889C0000E30208030202880387B001FDE +:1059E000C0B20190002E1DD0F889B081002516E0CC +:1059F000E8008419C0190090224641690E320198CE +:105A0000FDF755F9002802D000202074E0810098AD +:105A10006D1C008A60820098ADB2408AA082B08975 +:105A2000A842E5D8FEBD70B514461425049A1D8021 +:105A300037231380002C0ED0CA89A28100226282F3 +:105A40000078082808D0092810D00A2819D014494D +:105A5000144810F0E8FC70BD087B0C2804D01148F5 +:105A60000F490C3810F0DFFC012008E0087B0D28FE +:105A700004D00C480A49083810F0D5FC0420A07363 +:105A800070BD087B0E2804D006480549001F10F0A1 +:105A9000CAFC0520F3E70000FFFF00000228000019 +:105AA00070530000BB02000010B5FE4B5860197225 +:105AB0001A80C90010F098FB10BD002101807047CA +:105AC00010B50022D2430280032007F0F8FC10BD7D +:105AD0007047F0B50E460446017801208840F2492F +:105AE00099B008400090616815460888EF4A9042D6 +:105AF00006D0009A002A06D0EB4A521E104202D06D +:105B0000012019B0F0BD009A10430880002D12D07A +:105B1000002028702178EA1C0027681C01920B00E5 +:105B200010F072FD10F30E16233A59616F3CB4B0B9 +:105B30008AB8F2F1F0F320780B28EBD00420E0E7EC +:105B400002212970A1890170090A4170032097E0A0 +:105B500004212970A1890170090A41700198E18925 +:105B60000170090A417005208AE006212970A18987 +:105B70000170090A41700199E2890A70120A4A709B +:105B8000218A0171090A4171A28AE81DA16910F0F8 +:105B9000CCFAA08AC01D73E0082129702178082959 +:105BA00001D110212970A1890170090A4170019861 +:105BB000E1890170090A41700520308020466A1D84 +:105BC00002A91030FDF799F800287DD16946308888 +:105BD000097A401854E00A212970A1890170090A44 +:105BE000417003200BE00C212970A1890170090A82 +:105BF00041700198E1890170090A417005203080E7 +:105C00009CE0A08984464000401C81B230888842D4 +:105C10005AD3052958D30E202870002008E02369A4 +:105C200042009B5A521953701B0A401C937080B259 +:105C30006045F4D33180B9E09A48417A002973D0A5 +:105C4000491E4172217B4068C9004518A98828680F +:105C5000082240180838216910F067FA02216846C6 +:105C600001710021417128680390A988684601816B +:105C7000002101A8FFF78CFB0020A880002E00D097 +:105C8000308093E0297880221143297029784022BE +:105C90001143297029788909890112312970A18954 +:105CA0000170090A4170E289E81C216910F03DFA8F +:105CB000E089C01C3080287841063FD5C00975D0E6 +:105CC00001216846017200E02CE000214172318818 +:105CD000091D81810495E189019808180590001D2E +:105CE00006907048017A68460177002102A8FFF704 +:105CF0004FFB074630880C303080022F06D0002F33 +:105D000054D065E03DE033E01CE05EE06548694664 +:105D1000097F4268CB00D218037A994202D2918857 +:105D2000002902D0042753E02FE0417A491C417238 +:105D30001560308890800020308049E06168A0893B +:105D4000888033E029788909890116312970A18971 +:105D50000170090A41700198E1890170090A4170D6 +:105D6000228A681D616910F0E0F9208A401D46E72B +:105D700028788009800118302870207B6870022004 +:105D80007EE760680188090401D4052720E0C08807 +:105D9000A189884201D006271AE01E202870012020 +:105DA0003080606801884904490C0180009800280F +:105DB0000ED03C4800220088A1688300032007F031 +:105DC000D9FA61682078887007E0002030800327C6 +:105DD0006068009902888A430280384691E6FFB5E0 +:105DE0009FB0289D0E46002805D0172803D82A8882 +:105DF0002E4B9A4202D1072023B0F0BD32785306D1 +:105E000001D4D20901D00820F6E700226B461A71AE +:105E10005A7114463278431E1D939BB2189303ABFC +:105E20001A939706CB1CBF0E1B93821E711C3B005E +:105E300010F0EAFB209011EE66EE74EEB0EED4EEB8 +:105E4000EDEEECEEEBEEEAEEE9EEEEEEE8EEE7EE8E +:105E5000E6EEE5EE90EE05287CD10421684601715E +:105E6000A9780172F078B278010211436846418145 +:105E70003179417170788006800E0C282ED009DCB3 +:105E8000801E030010F0C0FB0919661C6621662401 +:105E90006627660012282AD00ADC0E2821D0102896 +:105EA000DAD121E00C090020FF710000FFFF0000A3 +:105EB00016281FD01828CFD11FE02878800701E0CE +:105EC00028784007002845DA45E128780007F9E7F7 +:105ED0002878C006F6E728788006F3E72878400699 +:105EE000F0E728780006EDE72888C005EAE728886B +:105EF000C004E7E728888004E4E728884004E1E755 +:105F00002A78920726D50328A6D105206A46107163 +:105F1000487809780002084310811CE12978490774 +:105F2000F0D5062816D3717890B2012902D0022943 +:105F300092D101E0022100E01021189106216A4669 +:105F400011710021118102AF189AB11C0237921C05 +:105F50001B921AE0B3E04A780B7812021A433A8097 +:105F6000801E891C1790BA1C1A911898FCF79FFE86 +:105F70001A991898189A091817986B46801A1A894E +:105F800080B2521C1A811B9ABF1D8242E3D900289D +:105F900086D1E0E028780007B4D51D98694682B222 +:105FA0000720087100200881701C0A3111E0437835 +:105FB00007781B023B430B80C37887781B023B4367 +:105FC0004B806F463B89121F5B1C001D92B23B81C8 +:105FD000091D042AEBD2002A71D1BCE02978C90638 +:105FE0006DD502286BD308206946087100204881CE +:105FF00070780872844692B2B01C1A9919E089E050 +:1060000090E07EE067E05BE030E025E019E013E03F +:10601000BCE0437807781B023B430B80831C4B603A +:106020006346D21A6F467B8960445B1C92B27B81C7 +:1060300008319445EDD9CEE7287880063FD509226E +:1060400003E0287840063AD50A2268460271AA88F9 +:106050000281189A428107E0287800062FD50B208C +:106060006A46107118981081039174E02988C90557 +:1060700025D5022823D30C206946087100204881C9 +:1060800070780872844692B2B01C1A9914E0437872 +:1060900007781B023B430B80C37887781B023B4386 +:1060A0004B80031D4B606346D21A6F467B89604468 +:1060B0005B1C92B27B8108319445E8D98BE763E0A1 +:1060C0002988C90460D501285ED10D216846017177 +:1060D000A98801813FE02988890455D5052853D333 +:1060E0000E2269460A71AA880A811B99401F4A78C4 +:1060F000097812020A4369464A818881701D04901A +:1061000029E0298849043FD501283DD10F2069465F +:10611000087120E02A88120436D44A780B781202DB +:106120001A43EA8003282FD332789206920E1B2A54 +:1061300026D011226B461A712A880123DB031A43E9 +:106140002A804A78097812020A4369460A81C01EE9 +:1061500048811B98039030788006800E1B2809D058 +:106160001D2807D00320229907F0A9F92888C00B21 +:10617000C003288001A82199FFF70AF920463BE6D1 +:1061800010226B461A71DCE70724F7E70824F5E7CD +:1061900000B597B0032806D16A461070019100211E +:1061A0006846FFF7F5F817B000BD000010B58B7812 +:1061B000002B11D082789A4207D10B88002B0BD08C +:1061C00003E08B79091D002B08D08B789A42F8D117 +:1061D00003880C88A342F4D1002010BD812010BD9B +:1061E000052826D0002A02D0012A0DD102E0098814 +:1061F000090501E009888904890F07D0012918D011 +:10620000022909D003290ED081207047002A01D02D +:10621000032070470220704703280AD0042808D0C2 +:10622000002804D007E0042803D0022803D005206A +:106230007047002070470F20704770B513880546DF +:1062400014460B8018061DD5FE481022807AA842FD +:1062500003D813430B80002070BDA06893430078DF +:10626000E840C007C00E03430B802078A178800768 +:10627000800D0843F4490FF0D2FFA0686943081865 +:10628000401C70BD906870BD37B569468B8813801F +:1062900019061BD5EB4C0125A47A9168844209D8D4 +:1062A000FE280FD1D80602D5A5406D1E00E00025BE +:1062B0000D7007E085400C78DB06DB0FAC438340B4 +:1062C0001C430C7010881021884310803EBDF8B527 +:1062D0000746C81C80080E468000B04201D08620C8 +:1062E000F8BD082A01D90E20F8BDD64D00202E6039 +:1062F000AF802881AA723446E88016E0E988491CFC +:10630000E980810610D48007A178800D0843CE492A +:106310000FF085FF206800F0BAFA2989401880B292 +:106320002881381A8019A0600C3420884107E5D4F0 +:106330000020F8BDFFB589B09F041646139DBF0C21 +:106340000193099800F095FA04000AD0207800061D +:1063500009D5BC48817A0A98814204D887200DB0BB +:10636000F0BD0120FBE7224669460A98FFF765FF6A +:106370000690002069460872052D14D0012221469E +:106380002846FFF72DFF0028E9D1207840060AD5DE +:10639000022168460172099981810188C1810682C2 +:1063A0004782129805900198000404D500273E46C4 +:1063B0000125079709E02078A1788007800D084320 +:1063C000A14907900FF02BFF0D46019840040AD514 +:1063D0000798A84207D12088E1788005800F000245 +:1063E0000843B04201D3AE4201D90720B7E7B8193C +:1063F00080B20190A84201D90D20B0E76846007A2A +:10640000002804D002A8FDF706F90028A7D10798B4 +:10641000A8420BD1208803210902884301998905EC +:10642000890F0902084320800198E0701498002821 +:1064300000D007801298002815D006983A46801997 +:1064400012990FF072FE224669460A98FFF7F5FE90 +:1064500069460888102188436946088022460099C9 +:106460000A98FFF711FF002079E7FFB5754D0C2260 +:10647000E8882968504383B00C180D9F724905982D +:106480000FF0CDFE0091049800F001FA29682A89E6 +:106490008E46611A0C310918944651188AB2A9889F +:1064A000914202D8842007B0F0BD6A46168A3206AF +:1064B00003D5B20601D58520F5E7EA88521C92B2D1 +:1064C000EA800E9B002B00D01A80B20601D5A7608F +:1064D00006E0604480B22881091A70460818A0605E +:1064E0002246FE200499FFF7CFFE0598A070009881 +:1064F000E07020880599800889058000890F08438D +:1065000003210902884300998905890F090208437C +:1065100004210843208003988078A07103980088A4 +:10652000A08000202073310601D5AC7A00E0012460 +:10653000B10600D5002700260EE0052100200191BC +:1065400002900097E88831460C9B069AFFF7F2FE0E +:106550000028A8D1761CF6B2A642EED30020A2E70E +:10656000F1B5009800F085F9060002D00025009CE6 +:1065700014E00120F8BD204600F07BF907460078C2 +:1065800031498007820DB87810430FF048FE386813 +:1065900000F07DF94019641C85B2A4B22948C18875 +:1065A000601E8142E7DC00992648491EC1800189AE +:1065B000491B018100203070F8BD002804D0401E26 +:1065C00010809170002070470120704710B504467C +:1065D00001881C48C288914201D3822010BD006806 +:1065E0000C22514342189079A07290882081108823 +:1065F000D1788005800F00020843A081A078211D7A +:10660000FFF71BFE20612088401C2080E0800020D6 +:1066100010BD012101827047F7B50546002084B006 +:10662000C043108068681746817868468170686842 +:1066300001886846018000218171288A2C88A04247 +:1066400005D303E0180900200102000004462C8253 +:1066500035E0288A401C2882301D6968FFF7A6FDB6 +:1066600000282AD139889248814201D1601E3880A1 +:106670006888A04228D33088F1788005800F000216 +:10668000084302906946301DFFF790FD002814D1A1 +:106690006989874881421BD0002231460598FFF75F +:1066A0009FFD002809D16A890298824205D1E968D4 +:1066B000B0680FF00DFD00280AD0641CA4B220467B +:1066C00000F0D7F80600C4D1641E2C828220EAE6CE +:1066D0007C80B079B871B088B8803078B1788007A4 +:1066E000800D084378810298B8813946287A32466D +:1066F0000831FFF7A2FD38610020D4E6FFB585B070 +:106700001C460F46059800F0B4F8050009D028781B +:10671000000608D56748807AB84204D8872009B0B7 +:10672000F0BD0120FBE707982A468605B60D6946AD +:106730003846FFF782FD07460E98052816D000223E +:106740002946FFF74DFD0028E9D1287840060DD5F0 +:106750000121684601710599018101884181868185 +:10676000C48101A8FCF757FF0028D8D12888AA784F +:106770008107890D11438005800FEA7800021043DC +:10678000079A964207D04C4A914204D3611E814237 +:1067900001DD0B20C3E7864201D90720BFE7801B3C +:1067A00082B2A24200D922461098002800D002806E +:1067B0000F98002802D0B9190FF0B7FC0020AEE7FF +:1067C000F8B51D4617460E4600F053F8040008D0F1 +:1067D0002078000607D53748807AB04203D8872052 +:1067E000F8BD0120F8BD224639463046FFF725FDA9 +:1067F000002D0BD02078A1788007800D08432E490A +:10680000884201D2012000E0002028700020F8BD5D +:10681000F8B51E4617460D4600F02BF8040008D0C8 +:106820002078000607D52348807AA84203D887201D +:10683000F8BD0120F8BD224639462846FFF724FD61 +:10684000FF2E14D02588A178A807800D08431A4987 +:106850000FF0E5FC002E03D1FF31FF31033189B287 +:10686000A170A80880008905890F084320800020B6 +:10687000F8BD1049CA88824207D3002805D00C22EF +:10688000096850430C38081870470020704703B55A +:106890000846694609888A0607D4090604D50549C9 +:1068A000897A4143491C88B20CBD00200CBD000010 +:1068B000FFFF00001809002001020000F8B507786A +:1068C0000D460446012F19D0072F02D00C2F19D1E5 +:1068D00014E0A068216906780B2E0BD0052006F085 +:1068E000EEFD052E0ED0782300220520216906F04A +:1068F00041FD07E0782300220620F8E70520216902 +:1069000006F0DDFD002D0ED000202870294620461F +:1069100004F0AEF9FE482978C05D884201D1032019 +:10692000F8BD0220F8BD0021204604F0A1F90020A6 +:10693000F8BD70B50E460C462036317901208AB07C +:106940001546002909D0012905D12978042902D149 +:106950000520107000200AB070BD6068019005A885 +:1069600002900D21C01C0FF03DFC032205A8A16878 +:106970000FF0DBFB01203071062069460870206AA9 +:10698000049029466846FFF799FFE4E770B50C4686 +:10699000154620310A790120062686B0002A2CD01F +:1069A000012A28D12978042925D169681022A068F4 +:1069B00001F0B4F96868C07B000606D5D44AA06827 +:1069C0001023103A014601F09EF91022A168E068F8 +:1069D00001F0A4F9A068C07B000606D5CC4AE068A7 +:1069E0001023103A014601F08EF92E70A0686860FD +:1069F000E068A860002006B070BD60680190C448DF +:106A0000203802900120087168460670206A0490C0 +:106A100029466846FFF752FFEDE7027B032A06D0BE +:106A2000002224235A540B78092B02D003E00420BF +:106A300070470A76CA61027B9300521C0273C150F0 +:106A400003207047F0B50E4615460C462036024628 +:106A500031790120072393B000290CD0012924D0DB +:106A600002292ED0032904D12978042901D12B70C1 +:106A7000002013B0F0BD01203071606800280DD0F7 +:106A8000A1690B7060684860206988606069C860AF +:106A9000206A08621046FFF7C0FFEAE70620287068 +:106AA000206968606069A86009E029780629E0D15A +:106AB0000220307104202870954820386860032037 +:106AC000D7E729780429D4D1A08910280AD9103809 +:106AD00080B2A081A1681023091805A86A6801F096 +:106AE00012F923E010282FD0C2B21020801AA1681A +:106AF0000DAF1190C0190FF018FB11980006000E91 +:106B000006D0401EC1B28020785438460FF06AFB90 +:106B1000626910230DA909A801F0F5F8102309A94D +:106B200005A86A6801F0EFF80320307160680190F1 +:106B300005A80290062069460870206A049029463C +:106B40006846FFF7BBFE94E710232269A168E2E7DD +:106B5000F0B50E460C4620363179012006278FB05D +:106B6000154600290BD0012932D0022905D12978F8 +:106B7000042902D10820107000200FB0F0BD217D43 +:106B800008A8CA07D20F02718807C10F08A80171AF +:106B90006846027041700722801CE1680FF0C5FA58 +:106BA00002A80722013021690FF0BFFA6068059042 +:106BB0000AA8069010236A46A16801F0A4F80120F3 +:106BC000307168460774206A0890294604A820E0BE +:106BD00029780429D1D1062205A8E1690FF0A5FA88 +:106BE00006A806220230A1690FF09FFA0020089043 +:106BF0006068019009A80290102305AA696801F055 +:106C000082F80220307168460770206A0490294695 +:106C10006846FFF753FEB0E770B50D460C462035C9 +:106C2000297901208CB01646002909D0012905D107 +:106C30003178042902D10920107000200CB070BDF9 +:106C40006068019006A802900822E1680FF06DFAD2 +:106C5000082208A8A1680FF068FA01202871062010 +:106C600069460870206A049031466846FFF726FEA0 +:106C7000E4E770B50D460C462035297901208CB02B +:106C80001646002908D00129D8D131780429D5D158 +:106C90000A2010700020D1E76068019006A80290D9 +:106CA0000822A1680FF041FA002008900990012005 +:106CB0002871062069460870206A049031466846AB +:106CC000FFF7FCFDBAE730B50B4620331C790120F5 +:106CD0008BB0002C09D0012C05D11178042902D1E8 +:106CE0000B20107000200BB030BD4868019005A843 +:106CF00002908C6868462578057564784475CC6880 +:106D0000257885756478C47500200690079001E0A9 +:106D10002867010008900120187106236846037057 +:106D2000086A049011466846FFF7C8FDDBE770B5B6 +:106D30000C462034034625790120002D0AD0012D70 +:106D400014D0022D05D111780A2902D10C2010701F +:106D5000002070BD01202071C868052202704A68B9 +:106D60004260F84A8260921CC2600BE015780B2DDD +:106D7000EFD102202071C868042404705268426078 +:106D80008A688260096A016201461846FFF745FE7B +:106D900070BD30B5011D02463132947803258379E8 +:106DA000ED432C4323408371DB070DD04B7954799D +:106DB00023404B710B79127913400B718278C9789B +:106DC0008A4200D9817030BD00224A710A71F5E70C +:106DD000F7B50C4686B00020694626460870203676 +:106DE000317901271E2015461F2977D24B007B449D +:106DF0009B885B009F441E0017023E0256026902F8 +:106E000088029A02D102F5022E03590371037F030F +:106E1000AE03C303CC03F7031A0464049A04AB045F +:106E2000DF04FE0410052A0565059B05C6058305DC +:106E300087058B056069002802D0007813287DD073 +:106E4000A0680590002849D0012168460170206A99 +:106E500004900321684601710A214171E0690290A2 +:106E600020790028EFD0059909780029E7D00C296E +:106E700064D20B000FF0C8FB0CFD1A4B90B5E8FC78 +:106E8000FBFAF9F807FD022828D16069002802D032 +:106E90000078082852D1022168460170206A0490C7 +:106EA00005984178684601710021B9E20620216AFF +:106EB00006F005FB20790728E6D1606900F050FF55 +:106EC00002280CD0606900F04BFF042807D06069ED +:106ED0000028B8D000780128D6D103E01BE2616910 +:106EE0000120087005980079C11F0A2901D30A20E2 +:106EF00050E06169072288706069059930300FF0B1 +:106F000014F90120307161690320087034E007280A +:106F1000BAD16069002896D001780929B4D10599C1 +:106F2000C978890707D1059949790029DFD10599E1 +:106F300089790029DBD105994A7900E04EE20146C2 +:106F400020314B7D9A43D2D1059A8B7D92799A4319 +:106F5000CDD1059A1279D31F0A2BC8D20979914253 +:106F600036D80722C01C05990FF0DFF801203071D8 +:106F700061690A200870032069460870206A04903D +:106F80006069313001906069001D029060691C30B9 +:106F90000390A1E22076F2E311288DD1606900F020 +:106FA000DFFE042804D0606900F0DAFE0B2893D1DC +:106FB0006069059910223730491C0FF0B6F86069F6 +:106FC000017804297CD12421095C8278914201D97D +:106FD0000620DFE70521017003203071684601704B +:106FE000E2E3112894D1606900F0BAFE062804D0CB +:106FF000606900F0B5FE0C288AD1E068002813D043 +:107000002069002810D060690178062910D00D2170 +:1070100001706069059910225730491C0FF085F8FE +:107020006069573009218CE100206946087072E1DF +:10703000072101706069059910224730491C0FF043 +:1070400074F860694730EDE70228F0D1606900F01C +:1070500087FE0028EBD0606900F082FE0128E6D0B0 +:10706000606900F07DFE05E0B1E08DE06CE02AE0B3 +:107070000AE0D6E00828DAD00521684601710598B3 +:1070800041786846417146E11128D0D160690028F5 +:10709000CDD001780E29CAD1C16A4078022810D01B +:1070A0000020142250431430085805991022491C1E +:1070B0000FF03BF80520216A00F040FE0F205EE053 +:1070C000F1E10120EDE70B28B1D160690028AED0D5 +:1070D00001780F29ABD1C16A4078022826D0002060 +:1070E000142250430C300958059842780A70807871 +:1070F00048706069C16A4078022819D000201422C3 +:1071000050431030085805990822C91C0FF00DF89B +:107110000520216A00F012FE60694178022909D039 +:1071200000220832825C5208520073E00120D7E747 +:107130000120E4E70122F4E7012100E00021083109 +:107140004254BCE30267010011289CD16069002809 +:1071500099D00178102996D1C16A4078022811D0BF +:107160000020142250431830085805991022491C59 +:107170000EF0DBFF0520216A00F0E0FD11206169BF +:107180000870B4E30120ECE7082884D16069002886 +:107190009DD00178112997D10599C06A497801706D +:1071A00060690599C06A0622401C891C0EF0BDFF6B +:1071B0000520216A00F0C2FD60694178022904D0EF +:1071C00000220832825CFD2323E00122F9E7112826 +:1071D000BBD160690028BBD001781229B5D1C16A42 +:1071E0004078022819D00020142250431C3008583F +:1071F00005991022491C0EF098FF0520216A00F025 +:107200009DFD60694178022909D000220832825C24 +:10721000FB231A40022991D18EE70120E4E70122E5 +:10722000F4E70720B6E6287801288ED160696968FE +:1072300014221C30F9F7C8FF6069017F002901D0D2 +:107240002176ACE30178032901D0032037E002273F +:10725000C77081794907490F8171017A4907490F40 +:107260000172417A4907490F41726069FFF791FD48 +:10727000377196E228780F28E3D107206946087015 +:10728000216A049191680291694608716169072237 +:10729000C91C02980EF049FF6169042008700020A3 +:1072A0003071BBE028780328CBD1606901780529CB +:1072B000696807D0082247300EF037FF042030718C +:1072C00005206FE208225730F6E728780328B8D166 +:1072D000606901780529696811D008224F300EF0E5 +:1072E00024FF052030716069006A00280AD002205E +:1072F0002870002028716069006AA860F9E00822FF +:107300005F30ECE704204DE22878022899D12879F3 +:10731000002801D0207642E36069A96801626069B3 +:10732000002901D1F949016206200BE228780F28D3 +:1073300087D1A868E0616069017805292BD04730C2 +:1073400007213171E16802220A706269126A4A609B +:10735000886060693030C8606069C01C086162691B +:10736000087D926A400812784000D207D20F10437D +:1073700008756269926A521C8A61FD221040626936 +:10738000D26A1278D207920F104308756069C06AFA +:10739000401CC86153E25730D2E728780828BAD198 +:1073A0006069017805291AD00B2101700720694610 +:1073B0000870206A0490E069029011200871029818 +:1073C0000321017051681022401C0EF0AEFE002116 +:1073D0006846FFF773FA00203071E06187E206210A +:1073E000E3E728780F2896D1072069460870206ABD +:1073F0000490A8680290112008710298042101707D +:1074000061690A78072A0ED0002232710C220A70B4 +:1074100061691022401C47310EF087FE002168464A +:10742000FFF74CFA63E21022401C57310EF07DFE4C +:1074300000216846FFF742FA0A203071E168032014 +:1074400008706069006A48606069573088606069E8 +:107450004730F3E128780828A1D1606969681022D3 +:1074600037300EF035FE002801D0042092E5606927 +:107470000078072817D00A203071E16803200870CF +:107480006069006A486060695730886060694730A9 +:10749000C860206A08620698FFF7BFFA074660696D +:1074A000FFF777FC6BE208207AE1287809289AD167 +:1074B0000B20307161696868897810224018511A70 +:1074C0000EF090FE082069460870206A04906868F3 +:1074D000019060698078087268E129780D29BBD134 +:1074E00061698979C90703D00C20307109203EE019 +:1074F0003071032770E228780E28ADD1606914221C +:10750000291D1C30F9F760FE6069018DC06A417267 +:10751000090A817260698178C06AC1716169CA6A49 +:10752000081D117AC909C9011172437962691943A9 +:107530008378D26A9B079B0F012B00D00023007930 +:107540009B01C00003431943117260694078012810 +:1075500076D0B4E160694178022901D0012100E0D0 +:1075600000210831405CC00707D00E20EAE06946E0 +:107570000870206A1146049019E11320B8E72878B2 +:107580000F2894D1A868E0610F2030710520EEE744 +:10759000287803288BD16069C16A4078022801D01D +:1075A000012000E000201422504310300858082227 +:1075B00069680EF0BAFD10203071E168062022697A +:1075C00008706069406A48606069C36A4078022850 +:1075D00001D0012000E00020142778431030185813 +:1075E000CA6088602BE128780C2886D16069C26A5D +:1075F0004078022801D0012000E0002014214843F7 +:107600000C30105802230932696800F07CFB11200D +:107610003071E168052008706069006A486060693F +:10762000C06A093088603948001F07E128780B28B4 +:10763000A7D161694878CA6A022802D0012001E016 +:1076400059E1002014235843143010588A7869688F +:107650000EF06BFD60694178C26A022901D00121F8 +:1076600000E00021142359431431525881785018F6 +:107670001022511A0EF0B6FD072069460870206AE4 +:107680000490E069029011200871029806210170AF +:107690006169CA6A4978022901D0012100E000210C +:1076A00014235943143151581022401C0EF03DFD53 +:1076B00000216846FFF702F90020E06112206FE028 +:1076C00028780F2891D1072168460170206A04901C +:1076D000906802900B2268460271029801706169FD +:1076E000CA6A4978022901D0012100E0002114234F +:1076F00059430C3151580A78427049788170616958 +:10770000CA6A4978022903D0012102E00867010012 +:10771000002114235943103151580822C01C0EF087 +:1077200004FD00216846FFF7C9F826E76069417843 +:10773000022901D0012100E000210831405C8007CE +:1077400003D5142030710A2011E71620D0E62878DE +:107750000F287AD1A868E061072069460870206A7E +:107760000490E069029011200871029808210170CC +:107770006169CA6A4978022902D0012101E011E158 +:10778000002114235943183151581022401C0EF087 +:10779000CCFC00216846FFF791F80020E06115203D +:1077A00030710A2069460870206A049029466846AC +:1077B000FFF784F82BE028780F2846D10720694688 +:1077C0000870206A0490906802900820087102985E +:1077D0000921017061690622C969097841706169EE +:1077E000801CC969491C0EF0A0FC00216846FFF707 +:1077F00065F8AAE760694178022901D0012200E01A +:1078000000220832805C400703D51720C8E70746EE +:10781000B5E0012953D070E028780F2815D1A86869 +:10782000E06118203071E168052008706069006A25 +:1078300048606069C06A09308860F848C860206A9A +:1078400008620698FFF7E9F8E1E76FE028780B286F +:107850006CD16069C16A4078022801D0012000E043 +:107860000020142250431C300858102269680EF082 +:107870005CFC072069460870206A0490E069029069 +:107880001120087102980A2101706169CA6A497859 +:10789000022901D0012100E00021142359431C31A9 +:1078A00051581022401C0EF040FC00216846FFF7A2 +:1078B00005F80020E0616069407801281DD1192099 +:1078C00016E660694278022A09D000210831411881 +:1078D000097800290DD0CA0703D00E2106E0012146 +:1078E000F4E7890701D5102100E01221017000277B +:1078F00072E0012A01D00D20FAE51C20F8E51D20D8 +:1079000030710B2033E62978102948D1F0E5606901 +:107910000178012943D0082941D00021317100F0BC +:1079200019FA0C2069460870206A049037E028781C +:107930000F2805D01020107003271B2030714BE05A +:10794000072168460170206A0490A868029002210D +:1079500068460171029805210170217E4170002165 +:107960006846FEF7ABFF0B2168460170206A049061 +:1079700029466846FEF7A2FF07461B203071012FFB +:107980000DD029E0012168460170206A049004218D +:1079900068460171217E41710020207612E0207E30 +:1079A00000280FD06169132008701A2030710A2056 +:1079B00069460870206A049029466846FEF77EFFF3 +:1079C000074609E06069002801D01421017068466B +:1079D0000078002800D021E5384609B0F0BDF7B5A1 +:1079E0000F4620373879012686B00C46002804D08F +:1079F000012828D002281CD197E02079012804D042 +:107A0000022811D0032814D10AE0A0684078012888 +:107A10000ED10620216A05F02CFD00287FD10CE054 +:107A2000A1681320087008E0A0684178022901D0FD +:107A3000052674E00078082871D1012038710A20E9 +:107A40006946087033E0089800780F2867D107214D +:107A500068460170206A049008988568029522792A +:107A60000220012A04D0022A29D0032A57D10FE08C +:107A70000646684606710B202870207B00214007CF +:107A8000400F68706846FEF719FFA068067045E071 +:107A900006466846067105202870207B6870002124 +:107AA0006846FEF70BFF3E710B2168460170206AA5 +:107AB000049068460899FEF701FF06462FE06846E5 +:107AC000017101202870207C6870607CC007C00FA5 +:107AD000A870A07C4007400FE870E17C2971C007C6 +:107AE0001FD0207D4007400F6871607D4007400F28 +:107AF000A87100216846FEF7E1FEA068072229462A +:107B000030300EF012FBE068017AA068203001717D +:107B1000A16828798870A16809200870002630467D +:107B20005BE70020A8716871E3E7A1681420087082 +:107B3000012168460170206A0490042168460171A1 +:107B4000217B41710021FEF7B9FEE7E7F0B585B072 +:107B50000F4605460124287B800040198038C66FF7 +:107B60003078411E0A290AD22C498000323140184F +:107B70008038C36F3A463146284698470446002C61 +:107B800001D0012C11D1287B401E0006000E287365 +:107B900001D00324DFE70D2069460870306A0490A5 +:107BA000002101966846FEF789FE032CD3D02046BB +:107BB00005B0F0BD70B515460A4604462946104684 +:107BC000FFF7C4FF0646002C0FD0207814280CD1F4 +:107BD000207E002806D000202870204629460C3040 +:107BE000FFF7B4FF204600F0B5F8304670BD70478F +:107BF00010B5012903D0022901D0052010BD417024 +:107C000000F0A8F8002010BD002809D0027E002A4C +:107C100006D00A4601460C31CCE700000667010099 +:107C20000120704730B5044687B00D46062005F0A8 +:107C300046FC2946052005F042FC2078142805D092 +:107C40000020694608702046FFF7DEFF07B030BD10 +:107C50007FB50E4600216A4611730178092903D0C9 +:107C60000A2903D0002407E0446900E08468002C5E +:107C700002D0217E002912D0154601462846FEF783 +:107C8000CCFE032809D1324629462046FFF792FF51 +:107C90006946097B002900D0042004B070BD254648 +:107CA0000C35EAE700B50023012285B005280CD089 +:107CB000062808D1684602700491022101714371BF +:107CC0000021FEF7FBFD05B000BD6846027004917F +:107CD0000271F4E710B590B00C4605216A461170A8 +:107CE000019022480290001D03900AA96846FFF700 +:107CF000AFFF002805D1102220460B990EF015FA8F +:107D0000002010B010BD30B505E05B1EDBB2CC5CCE +:107D1000D55C6C40C454002BF7D130BD10B50024A5 +:107D200009E00B78521E5B00234303700B78401C64 +:107D3000DC09D2B2491C002AF3D110BD70B50C4643 +:107D4000054605F0BCFB782300222146284605F0B5 +:107D500011FB70BD4178012900D0082101707047E6 +:107D6000002801D0007870470820704700670100A4 +:107D700038B50446002069460870204609F053FDD6 +:107D8000002803D1FBA1A3200EF04DFB204609F0F3 +:107D900099FC002803D1F7A1A8200EF044FB684607 +:107DA000007838BD70B5F84D002428462C77203077 +:107DB0008471C47101F09AF928464038047020306B +:107DC0008473847484772C75AC7170BD10B50C46C7 +:107DD000EE4982888A8042884A8000780870084686 +:107DE0000E38847009F050FC08F0FDFFFFF7DAFF51 +:107DF00020460BF013F8E449A8310846813809F011 +:107E0000ADFEE2480CF021FBE0480A3808F0FEFF26 +:107E1000002803D0D7A1C5200EF005FB01F066F9BC +:107E200010BD7CB50E461D46144601A909F008F8A0 +:107E3000002807D10AF091FB022803D1D248007D27 +:107E4000002801D001207CBD01988030807C09F0A1 +:107E50004DFC00280CD0684609F052FC0028F2D0F6 +:107E6000002C03D009F011FCA04206D200207CBDFA +:107E7000C0A1C7480EF0D7FAF8E7009809F0D8F883 +:107E80003146009809F0DBF8E2B22946009809F083 +:107E9000F0F909F045FC002804D1BD48B5A11E3019 +:107EA0000EF0C1FAB94C00250E3C6068A030417953 +:107EB000002902D045710BF0D8F860688030458306 +:107EC000C0E730B40179002904D0012907D030BCC3 +:107ED00000207047831D42880488022103E0428805 +:107EE0000488831D0121204630BC9AE7F8B51D4661 +:107EF00014460E4607460AF030FB022803D0A2487B +:107F0000007D002823D0A1480E3841684988398077 +:107F100040688030807C09F069FD002804D153203E +:107F200094A1C0000EF07FFA684609F069FD0028B0 +:107F30000DD0009809F0BAF83070022808D0012856 +:107F400006D093488BA167300EF06DFA0020F8BD83 +:107F50002946009809F0A4F92080002804D1552072 +:107F600084A1C0000EF05FFA09F05DFD002804D185 +:107F7000874880A160300EF056FA0120F8BD38B570 +:107F80000446831D821C6946FFF7B0FF00280DD010 +:107F90000020607168460078012808D0022806D0C9 +:107FA000FF2074A101300EF03EFA012038BD20718F +:107FB000FBE7F8B50AF0D1FA744D734C0E3D022878 +:107FC00002D0207D00287DD0207F0026102818D1E7 +:107FD000A079002803D067A16E480EF024FA6868E3 +:107FE00001464030827F92070BD526724988618115 +:107FF000C17F2173018CE181408C20820120A0711E +:108000002677614F203FB87C00285ED168686946BA +:108010008030807C09F007FC002805D0694668782C +:1080200009784018687004E05A4852A119300EF0DF +:10803000FAF9207D00283AD06868418852484038D3 +:10804000806D4088814204D00F204AA1C0010EF00B +:10805000EAF968688030807C09F0C8FC002804D107 +:108060004C4844A124300EF0DEF909F0EEFC002863 +:108070001DD068688030807CFFF77AFE69784018F0 +:10808000687041484038806D4030417A01290DD1F7 +:108090002670696849886180807A20710120B877EC +:1080A000207F102801D0282800D1267726756978EE +:1080B00000290AD06868428833484038C286018760 +:1080C000012000E001E0B8746E700AF029FA00287F +:1080D00005D1207D002802D0A878FAF7F9F8F8BD7C +:1080E000F8B50446FFF765FF274D0026203DA87E22 +:1080F000002808D0667010202070E87EA070287FCD +:10810000E070AE769AE0204F403F3878002808D0E3 +:108110002C22B91C20460EF008F80E2020703E706C +:108120008CE0A87B184F002815D0387F102808D085 +:10813000282806D0002804D0FF200EA1C2300EF05F +:1081400072F90120E070E87BA070287C60700F203D +:108150002070AE7372E00121204609F099FC0028DE +:108160001AD0387D002857D10021204609F090FC14 +:10817000F8BD00007372635C6C6C5F6374726C2E8C +:1081800073302E630000000094090020720000206C +:108190004F02000062070000A97CF8480090F848F0 +:1081A000002910D0017805290DD2491C0170667094 +:1081B0000D202070012028750622A01C00990DF0CA +:1081C000B4FFAE743AE0EE480670B879002812D0D9 +:1081D000387F002804D00120EA4940020EF023F93C +:1081E00066700120E54920700A221431A01C0DF0B0 +:1081F0009CFFBE7122E020460CF083F800281DD1C0 +:10820000A87C002802D0DE480178CEE7A87F0028AD +:1082100002D0387D002801D00020A9E7387F00284F +:1082200003D0D849D8480EF0FEF866700A202070B6 +:1082300006223946A01C0DF078FFAE77012097E7A3 +:108240004EE710B5CD4C343C2178002904D01321E1 +:108250000E2000F052FF10BDC9490088091D08F02A +:10826000EFFD002801D0022007E0C5484068014624 +:1082700020318A79012A02D00C20207105E00022E9 +:108280002271097E21724088E080012060711321F3 +:10829000E1700E21A170207010BDB84810B53438BF +:1082A0000178002904D024210E2000F026FF10BD03 +:1082B000012101702422C2700C220271417110BD93 +:1082C00070B5AE4C0546343C2078002804D03E21E1 +:1082D0000E2000F012FF70BD0AF03FF9002808D10F +:1082E0000AF03EF9002804D1A4480C30007F002891 +:1082F00001D00C2003E0287809F033FD0020207124 +:10830000012060713E21E170207070BD9B4810B566 +:1083100034380178002904D03C210E2000F0EDFE15 +:1083200010BD00210171012141713C22C270017018 +:1083300010BDF8B5914C343C2078002804D03B2186 +:108340000E2000F0DAFE13E70020A0710AF005F914 +:108350008A4E01250C36022802D0307D002840D0FC +:10836000874F694678688030807C09F073FA00286E +:1083700003D1844985480EF056F8307D002806D098 +:10838000A06D4030407A002801D0012600E0002690 +:1083900078688030807C09F029FB002804D17B4874 +:1083A000784908300EF03FF809F04FFB684031463D +:1083B000014316D07968FD2249882181217E400041 +:1083C000490849003143114001432176684600784D +:1083D000002802D00420014301E0FB200140217667 +:1083E000A5710020207165713B20E0702570BFE60B +:1083F00010B5624C343C2078002804D00E21084689 +:1084000000F07BFE10BD5E4906220831A01D0DF074 +:108410008CFE00202071012060710E21E17020701F +:1084200010BD70B5554C0546343C2078002804D06A +:1084300038210E2000F061FE70BD50480C30007FE6 +:10844000002807D00C202071012060713821E170D4 +:10845000207070BD287809F072FC28780CF05BF968 +:108460000020F0E770B5454D0446343D28780028DB +:1084700004D037210E2000F040FE70BD3F480C3084 +:10848000007F002801D00C200AE03D4E2188706852 +:108490004088884203D10AF060F8022807D0022001 +:1084A0002871012068713721E970287070BD7168EA +:1084B0007F2020310876487600208876A2788A715D +:1084C000E278CA7122790A72EAE710B52B4C343C83 +:1084D0002078002804D039210E2000F00EFE10BDB7 +:1084E0000AF03BF8032808D00AF03AF8032804D031 +:1084F00022480C30007F002801D00C2003E01F49E7 +:1085000000202C31C8712071012060713921E17087 +:10851000207010BD70B5194C0646343C20780028F8 +:1085200004D03A210E2000F0E8FD70BD0AF015F8E5 +:10853000032808D00AF014F8032804D00F480C30A0 +:10854000007F002801D00C2011E00C4D2C35E8797B +:1085500008280BD20001001910223146683000F0C3 +:10856000D6FDE879401CE871002000E0072020716A +:10857000012060713A21E170207070BD88090020EF +:108580006400002074810000210200001708000030 +:10859000F8B5FA4E04463078002804D03D210E206C +:1085A00000F0ABFDE4E5F5484030007F002801D045 +:1085B0000C2034E0F24D218868684088884203D15D +:1085C00009F0CBFF022801D0022028E06F68648800 +:1085D000FD883A896800B988401C844218D3E9486C +:1085E00041431046E84A50430DF019FE401EFF215A +:1085F00080B2F531884200D90846844200D2204634 +:10860000691C401C0DF00BFE6D1C6843401E85B2BA +:10861000E620C05D002800D1BD84F58000203071C7 +:10862000012070713D21F1703070A1E5F8B5D34C97 +:1086300005462078002804D035210E2000F05DFD8D +:1086400096E5CE484030007F002801D00C2016E08F +:10865000A878002801D0012804D1A888FF21F5318D +:10866000884201D912200AE0C54F298878684088DD +:10867000884203D109F071FF022807D0022020713F +:10868000012060713521E170207071E57968002664 +:108690000846C0310E70AA884A800122A0300271BB +:1086A000AA78012A00D000220A704079002801D05F +:1086B0000AF0DBFC2671E3E770B5B04C0546207884 +:1086C000002804D030210E2000F017FD55E709F0F6 +:1086D00044FF002804D1A9484030007F002801D081 +:1086E0000C2003E028780AF0E0FB00202071012034 +:1086F00060713021E17020703FE770B59F4C0546F6 +:108700002078002804D033210E2000F0F6FC34E756 +:1087100009F023FF002804D198484030007F00284A +:1087200001D00C2018E02978002911D00A290FD097 +:1087300014290DD01E290BD0282909D0322907D0A1 +:108740004B2905D0642903D0FF2901D0122003E072 +:1087500028460AF023FC002020710120607133219B +:10876000E170207009E770B5844C06462078251D1D +:10877000002804D032210E2000F0BFFCFDE6314677 +:10878000002009F0AEFA2870002805D17C480622A6 +:10879000314608300DF0C9FC012060713221E170D2 +:1087A0002070EAE670B5754C2178002904D031219B +:1087B0000E2000F0A2FCE0E600214156012504292C +:1087C00012D0002910D0081D0ED0001D0CD0001DA5 +:1087D0000AD0001D08D0001D06D00A3004D00A308F +:1087E00002D01220207103E0084606F079FD657181 +:1087F0003120E0702570C0E6FEB5604C0746207859 +:10880000002804D025210E2000F077FCFEBD38881A +:10881000694608F015FB594D01460020083500292E +:1088200004D002212171286028710FE00098009E79 +:108830000A30019060360020B07105222846019967 +:108840000DF073FCB0790028F5D13888E0800E2057 +:10885000A0702520E070012060712070FEBD10B571 +:10886000464C2078002804D005210E2000F045FC5D +:1088700010BD0020207108F008FFE08008F0D1FF53 +:108880002072012060710521E170207010BDF1B5EA +:108890003A4C2034A07B002804D010210F2000F097 +:1088A0002CFC65E4354D4035A8790C2610270028AE +:1088B00016D1287F002813D109F04FFE022824D1B9 +:1088C0002F4800994068098842888A421DD1014694 +:1088D000C0310A7A002A05D04030807F80070DD44D +:1088E000E6730EE05E22125C920707D406220A723B +:1088F000A0304079002801D00AF0B7FB2F77002084 +:10890000E07327740120A07332E40220F8E710B569 +:108910001A480178002904D00F210E2000F0EDFB49 +:1089200010BD00210171FF2181710021C943018126 +:1089300013490E310A7882728A8882814988C181FE +:10894000012141710E2282700F22C270017010BD90 +:1089500010B50A4C2078002804D02B210E2000F0FE +:10896000CCFB10BD0821A01D04F024FB00202071C9 +:10897000012060712B21E170207010BD540900208E +:1089800064000020C40900001027000070B5FA4DF3 +:1089900004462878002804D02A210E2000F0ADFBE0 +:1089A000EBE5F54810222146303800F0B0FBF248E4 +:1089B0001022A118203800F0AAFBEF4830380CF044 +:1089C000BCFBED49102210392C46A81D00F09FFB7E +:1089D000002020710E20A0702A20E070012060711C +:1089E0002070CAE5F8B50546E348E34C40300090F6 +:1089F000007F0C2628272034002801D0E6733EE0B3 +:108A0000A07B002804D028210F2000F076FB04E48E +:108A1000A87805280DD013280BD0142809D01528C4 +:108A200007D01A2805D0292803D03D2801D03B289B +:108A300003D12888D149884201D912201EE009F0CB +:108A40008CFD0228DAD1CE482A88406841889142BC +:108A500013D10146C0310A79002ACFD1AA784A71D0 +:108A600001220A710099A0300F770021E17340794B +:108A7000002804D00AF0F9FA01E00220E07327741C +:108A80000120A0735FE4F8B5BB4F064638783D1D62 +:108A9000002804D017210E2000F02FFB53E43146AC +:108AA000012009F01EF901242870002807D1B248DE +:108AB00006226030314605460DF037FBAC717C7103 +:108AC0001720F8703C703EE470B5AB4C0646207839 +:108AD000002804D00B210E2000F00FFB4DE509F01B +:108AE0003CFD032808D009F03BFD032804D0A24830 +:108AF0004030007F002801D00C2016E03378002B96 +:108B000003D0012B01D012200FE09B4DE035297AD4 +:108B1000082909D22846721C0C3006F097FB287AE7 +:108B2000401C2872002000E00720207101206071A5 +:108B30000B21E170207020E510B58F4C20780028C3 +:108B400004D00A210E2000F0D8FA16E709F005FD3E +:108B5000032808D009F004FD032804D086484030DB +:108B6000007F002801D00C2002E000F0BFFA0020B6 +:108B70002071012060710A21E1702070FDE610B5BE +:108B80000AF032F9002803D07E497F480DF04BFCF3 +:108B900008F04BFD0BF051FC002804D01720794958 +:108BA00040010DF040FC08F0ACFF002804D0B920D3 +:108BB000744980000DF037FC00F098FAFFF7F2F8E6 +:108BC0006D4800210171012141710222C2700170C2 +:108BD000D3E610B5684C2178002904D020210E205E +:108BE00000F08BFAC9E601781F290ED8411C0CD081 +:108BF000002121710278411C104609F08FF80120F4 +:108C000060712021E1702070B7E612202071F6E734 +:108C1000F8B5594C2178002904D01B210E2000F012 +:108C20006CFABFE401216171534E0C212171403671 +:108C3000317F00296FD10078514F0025012804D0E1 +:108C400000284AD01220207165E009F086FC002837 +:108C500003D109F085FC002804D009F07EFC02282D +:108C600022D058E008F08FFF002854D0307D002833 +:108C700051D1786801224580032108F0B4FB78685F +:108C800009F05AF97868923008F001FD002803D104 +:108C90003C493E480DF0C7FB0AF00BF9002839D0DB +:108CA00085203849C00015E009F05AFC002832D16F +:108CB000707F00282FD001282DD004282BD008F059 +:108CC00062FF002827D00AF0F4F8002822D02F48AD +:108CD0002C4918300DF0A7FB1CE009F03EFC0328DE +:108CE00004D009F03DFC03280FD014E000200AF066 +:108CF00005F800280FD12571307D00280BD1786848 +:108D00008030807CFFF734F805E0002009F0F6FFA2 +:108D1000002800D125711B20E0700120207041E463 +:108D200010B5154C2178002904D01A210E2000F02E +:108D3000E4F922E601781F290ED8411C0CD000214D +:108D400021710278411C104608F0FDFF012060717E +:108D50001A21E170207010E612202071F6E770B53C +:108D6000054E044630780C25002811D018210E201D +:108D700000F0C3F9AAE4000054090020FF0E00002F +:108D80006400002074810000D3020000240400006D +:108D900009F0E3FB03285AD009F0E2FB032856D080 +:108DA000E14A107F002852D16079002801D00128C3 +:108DB0002DD1A079002801D0012828D1A07B00283E +:108DC00005D0012803D0022801D003281FD1607BE1 +:108DD00000281CD0C0081AD161880120800381427C +:108DE00002D82388834203D9207901280FD119E0C2 +:108DF0002079002806D0012814D0022805D00328A5 +:108E000005D102E020290BD30CE0A02B0AD2207957 +:108E1000042805D12088202802D36188884201D9FE +:108E2000122514E0207950776079002802D00128BB +:108E300003D00CE0BD4A002105E0BB4A2032907906 +:108E4000002804D00121204608F0CEFE054601206E +:108E5000357170711821F170307037E470B5B24C13 +:108E60000546403C2078002804D02E210E2000F03A +:108E700044F92BE409F071FB0C22022815D1AA4811 +:108E8000007F002811D1A9482B88083841684888FC +:108E900083421AD10846C030037A002B05D1203115 +:108EA000C97E0F2903D0102901D0227103E00521CA +:108EB0000172002020710E20A0702E20E070288802 +:108EC000E08001206071207016E40220F2E770B5A6 +:108ED000954C0546403C2078002804D02D210E20DA +:108EE00000F00BF908E409F038FB0C21022814D13A +:108EF0008D48007F002810D18C4E2A88083E70686B +:108F000043889A4220D1C822125C002A05D13B2214 +:108F1000125C0F2A03D0102A01D021710AE010221E +:108F2000A91CD6300DF001F970680421C03001721F +:108F3000002020710E20A0702D20E0702888E08095 +:108F40000120607120700DE40220F2E710B5017875 +:108F50000B000DF059FB3F9E9E399E9E599E9E9E92 +:108F60009E3C3F9E9E8752559E9E999E9E9E432963 +:108F70009E2D319E9E9E9E359E9E9E955C9E9E47FA +:108F80009E4B4F9E21259E6C6064689E709E7F83E1 +:108F90007C788A8D74919E00801CFFF798FF76E0A4 +:108FA000801CFFF75BFF72E0801CFFF7D8FE6EE0CD +:108FB000801CFFF7B5FE6AE0801CFFF729FE66E023 +:108FC000801CFFF706FE62E0FFF7D9FD5FE0FFF7C8 +:108FD000B3FD5CE0801CFFF777FD58E0801CFFF7D5 +:108FE00052FD54E0801CFFF7FDFC50E0801CFFF7B1 +:108FF000CDFC4CE0FFF7ACFC49E0FFF788FC46E015 +:10900000801CFFF744FC42E0FFF729FC3FE0801C96 +:10901000FFF7F2FB3BE0801CFFF7C4FB37E0801C4E +:10902000FFF7A1FB33E0801CFFF767FB2FE0801CFC +:10903000FFF742FB2BE0801CFFF7F8FA27E0801CCB +:10904000FFF7A6FA23E0801CFFF764FA1FE0FFF7A2 +:109050003CFA1CE0801CFFF705FA18E0801CFFF7C3 +:10906000E0F914E0FFF7C4F911E0FFF762F90EE050 +:10907000801CFFF74BF90AE0801CFFF721F906E09E +:10908000801CFFF70AF902E0801CFFF7DAF80120E4 +:1090900073E4002071E470B52349244C054640393F +:1090A000083C0A460126403260682B000DF0ACFAFD +:1090B00005171A1A04171A000122002108F093F963 +:1090C000616800220846C0310A724A7209F067FFDF +:1090D000002803D016A11B480DF0A5F960E4167511 +:1090E00088655DE4174812A13330F5E70E4900208A +:1090F000C031C8612039087270470B4A203A937E0C +:10910000002B03D1D076117701209076704730B5CF +:10911000134606E0CC18203CE47FD51A44555B1E6C +:10912000DBB2002BF6D130BD940900206C0000208A +:109130007372635C6C6C5F6374726C2E73302E633D +:10914000000000005108000070B5FD4D040008D07B +:10915000012C10D0022C07D0032C05D0F9A17020CF +:1091600007E0F8A1672004E02878012803D0F5A1E2 +:109170006D200DF058F92C7070BD70B5F04D04469F +:1091800010280AD0112C16D028468178122C07D02E +:10919000132C0AD0EBA19F200BE0EAA1942008E059 +:1091A000112908D0E7A1992003E0112903D0E5A1F6 +:1091B0009C200DF038F9AC7070BD10B5E04894B04B +:1091C000007B002819D0172069460870DC4900A8E8 +:1091D00006220D3102300CF0A8FF09A96846F9F704 +:1091E000C2FE0446112805D0002C03D0D5A1BB2017 +:1091F0000DF019F9204614B010BD3220E4E710B587 +:1092000001220023114603F0B5FC10BDFFB595B057 +:109210001D460E460746FFF7F2FF04000AD02078ED +:10922000222804D3A07F8006C00FA84204D10820C2 +:1092300019B0F0BDC748FBE7372168460170478089 +:10924000002D05D00121017146711799817102E04D +:1092500000206946087109A96846F9F784FEA07FD5 +:10926000DF21084069010843A0770020E0E770B5DE +:109270000446084620380D4603000DF0C5F90A06DD +:109280000A11232C334249505761FF20ADA1083009 +:1092900052E02078202851D1FF20AAA10B304BE0CA +:1092A000A7480178032949D08078132846D0207830 +:1092B000242843D0252841D023283FD0FF20A1A136 +:1092C0000E3039E02078222838D0232836D8FF20E5 +:1092D0009CA1153030E0207822282FD0FF2099A1C2 +:1092E000193029E02078222828D0242826D02628C2 +:1092F00024D0272822D0292820D0FF2091A11C305B +:109300001AE02078252819D0FF208EA1233013E001 +:109310002078252812D0FF208AA126300CE0207862 +:1093200025280BD0FF2087A1293005E020782828A8 +:1093300004D0FF2083A12C300DF075F8257070BD8E +:10934000FF2080A12F30F7E730B5834C0B88834A8C +:10935000022801D0934204D09D1FA54225D20228A5 +:1093600002D04D88954203D04D88AD1FA5421CD236 +:109370004C88A34219D88B88FF25F435AB4214D80A +:10938000022802D0C888904205D0C888724D0A3899 +:109390002D1FA84209D2C888904208D0944206D016 +:1093A0005B1C63438000834201DB072030BD00204B +:1093B00030BDF0B56A49884245D36A4A0125AD04FB +:1093C0001368A84201D398423DD30279002A06D0FF +:1093D000082A02D8067B082E05D90720F0BD047B99 +:1093E000002CFAD0F6E7002A06D004688C422AD373 +:1093F000AC4201D39C4226D3002E06D084688C4216 +:1094000021D3AC4201D39C421DD300240CE005685B +:10941000A700ED598D4216D30127BF04BD4201D3E9 +:109420009D4210D3641CE4B2A242F0D80022012570 +:10943000AD040CE084689700E4598C4203D3AC423D +:1094400003D39C4201D21020F0BD521CD2B29642EE +:10945000F0D80020F0BDFFB50022099B002802D003 +:10946000994205DC58E0002902D1002004B0F0BD8B +:109470000920FBE7845C002C12D087187D78112D21 +:1094800043D010DC2B000DF0BFF80A401726262C25 +:109490002C2E2E363640835C002B30D1521CD2B29B +:1094A0008A42F8DBE1E71C2D2FDA123D2B000DF08C +:1094B000ABF8042C2C121A2C022CD9D1BB78039CAB +:1094C000072B237001D25B0701D40A20CEE7029B51 +:1094D00001241B7816E0E343DB0708E0012C08D0E9 +:1094E00013E00620C2E70F2523072D075B19002B89 +:1094F000F4D03046BAE7029B1B789C0701D50B20BD +:10950000B4E702242343029C2370835C521C9A1804 +:10951000D2B28A4202DDABE7192676028A42A9DB83 +:10952000A3E710B504780B46002C1FD001210E4A8A +:10953000012C1ED0022C22D0032C2AD125E00000C1 +:10954000740A00207372635C6761705F636F726599 +:109550002E630000023000007B0C0000FFFF0000C3 +:109560000080010028000020023200000021197054 +:1095700011E019708179890903290AD10BE019706A +:1095800081798909012904D105E019708179890956 +:1095900001D0104610BD411C0622581C0CF0C5FD20 +:1095A000002010BD08B51346002806D0FEA00068B4 +:1095B000009048796A468009105C18700622581C91 +:1095C0000CF0B3FD08BD30B50C46097895B02229E2 +:1095D00002D2082015B030BD282369460B704880A0 +:1095E000132A03D03B2A01D00720F3E708460A716B +:1095F00009A9F9F7B8FC050003D121212046FFF79E +:1096000036FE2846E6E700B595B0232369460B7081 +:109610004880108888805088C880D0884881908889 +:10962000088100208881C88109A96846F9F79BFC58 +:1096300015B000BD70B50C00064610D0FFF7DFFD79 +:10964000050003D1D949DA480CF0EDFEA68028893F +:10965000E0802889208168896081A889A08170BD07 +:1096600070B50E46050003D00021092003F027FF46 +:109670000120D04C022E207324D0032E04D0CC48DD +:10968000CA491E300CF0CFFECA4806210D3003F047 +:1096900091FCA07C8006800EA074FFF78EFDA08B4D +:1096A00000280ED0002D0CD08300012200210920BB +:1096B00003F060FE092804D0BD48BC4928300CF0F6 +:1096C000B2FE70BDBB480321103003F073FCA07CD8 +:1096D00040218006800E0843A074B6480C3002F08A +:1096E00015F9DAE77FB501A9012003F0C3FA0028D4 +:1096F00004D0AF48AD4967300CF095FEAE4E01A8DE +:1097000003F0C6FA050002D0052D4CD048E0029CBB +:10971000A07F01072CD520462230009068462346C2 +:10972000628E80882146343301F07BFA0546A07FA3 +:10973000F7210840A077002D05D0B5422FD09C48D6 +:109740009A49783029E0E17F480889074000C90F2D +:1097500008432021095D4007400FC9000843E07716 +:10976000207828281CD129212046FFF780FD17E00A +:109770004007C4D568462246808821460E32FFF74E +:1097800042FF0546A07FFB210840A077002D07D0AF +:10979000B54204D08648854992300CF044FE00253D +:1097A000284604B070BD0020FBE7F8B5040004D1E2 +:1097B000ED207E4980000CF036FE7220207060683B +:1097C00008250178091F0B000CF01EFF11F90A3D56 +:1097D0005FF83D0EF8F83E3D3D3D3DF986F93D0010 +:1097E00073487249AA3074E087883846FFF707FD4E +:1097F000060004D16E486D49B2300CF014FE60785A +:109800000421284360706B4CA07F0843A07721217E +:109810003046FFF72CFDB07F8007800F012801D173 +:10982000801EA080384602F057FE3846FBF72AFE1D +:109830003846FAF7C6F93946022003F040FEB07FF9 +:10984000EF210840B077F8BD86883046FFF7D7FC97 +:10985000002804D156485549D0300CF0E4FD60682A +:109860008078012804D052485049D2300CF0DBFDFA +:1098700060688179304602F04EFF0028E3D06178BD +:10988000294361706168C880F8BD87883846FFF752 +:10989000B6FC060004D146484449E3300CF0C3FD51 +:1098A00060783946284360706068C088308160689D +:1098B0000089708160684089B081022003F0FFFD5B +:1098C0000020B075FFF70EFF0028DDD001203749DA +:1098D00080020CF0A8FDF8BD80783C2815D0002748 +:1098E000022815D00026002804D031482F49F8302E +:1098F0000CF099FD0021084603F0E1FD002107204E +:1099000003F0DDFD002E05D046E001270026F1E73B +:109910000126EAE76078284360702648817F294362 +:109920008177002F38D160688688304601F055F87D +:109930000546807F6168800889798000012900D010 +:1099400002210843A87760680622C08A28816068DF +:10995000008B68816068408BA8816068C079E87579 +:1099600061682846183008310CF0DFFB6068062279 +:10997000807B68706168A81C0F310CF0D6FBA87F53 +:109980008107890F304602F090FDA87F8007800F85 +:10999000012801D10748868006480178032913D0A1 +:1099A0008078132814D00BE00302FF0144950000D7 +:1099B00013030000740A0020023000000CE00FE0E6 +:1099C000FF20FCA1453084E70120FFF7BDFBF8BD77 +:1099D0001120FFF7D2FBF8BD204601F02AFCF8BDAC +:1099E000607828436070F8BDF7B505460078002719 +:1099F00000090C463E4601287ED00022F14902288B +:109A00007BD0072804D00A2878D0EAA1EE482DE1BF +:109A1000686803780D2B31D006DC042B6FD0072B40 +:109A200036D00A2B6AD106E0122B38D0132B40D047 +:109A3000142BF7D1B2E011270726002C72D08088B2 +:109A4000A0806968FB238979A171E04905468A7F76 +:109A50001A408A77032103F0C5F80421284603F051 +:109A6000C1F80021284603F0BDF80221284603F082 +:109A7000B9F80121284603F0B5F8F9E001270926D5 +:109A8000002CDBD08088A080686880792072EFE0AD +:109A900012270E2680882146FFF7CCFDE8E01A2722 +:109AA0000726002CCAD04088A08068680079A07181 +:109AB000DEE081783C2936D010271E26002CBDD050 +:109AC0008088A0806868C08A20836868C08AE08235 +:109AD0006868008B60836868408BA0836968207D1C +:109AE000497F4008C9074000C90F084320756968CD +:109AF000C007C00F497F03E05FE08AE0ADE01CE0F3 +:109B000049084900084320756968A21DC8790831D1 +:109B1000FFF748FD69682246887B0D320F31FFF759 +:109B200041FD05E074E019270726002C70D0A271D2 +:109B3000A648F722817F11407DE01B272E26002CAE +:109B400066D0A1806968A21D0879491DFFF72AFD2A +:109B500068682030C07A60736868C0780428A07B89 +:109B600019D040084000A073F921084069681F22FD +:109B7000C9788907490F0843A07369684007C97A03 +:109B8000400FC9000843A073696820460F300C31AC +:109B90000CF0CBFA6CE001210843E4E71E270E2607 +:109BA000002C6DD0A1806868E21D407AA0716968C0 +:109BB0008878C91CFFF7F6FC5AE0287A012805D0FE +:109BC000022815D080487BA132384FE01D270E2691 +:109BD000002C55D06888A080A889E080E889208181 +:109BE000288A6081688AA0817848DF22817FA2E785 +:109BF00012270E266888FFF71DFD002C40D06878DC +:109C00004007400F032833D17048FD22817F92E73F +:109C100036E0287A03000CF0F7FC06041010202030 +:109C2000202619270726002C2AD0A1806748A27178 +:109C3000817F4908490081771AE019270726002CFF +:109C40001ED0A180287A012805D00320A0715F488A +:109C5000EF22817F6FE70220F8E721462846029A2B +:109C600001F04BFCFEBD532052A100010CF0DBFBC8 +:109C70000298002C068001D0278066800020FEBD5F +:109C800002980680FAE710B5504894B080781328FF +:109C900002D0082014B010BD22206946087009A91E +:109CA0006846F9F760F904460021072003F007FC35 +:109CB0002046EFE700B5454895B08078122801D0DE +:109CC0000820B5E41E216846017000218170C17032 +:109CD00009A9F9F748F90028F3D10021072003F07A +:109CE000EEFB1120FFF749FA0020A1E400B5374848 +:109CF00095B00078022801D0032818D11B2108A8AC +:109D000001730021817369460BA8F9F72CF900282B +:109D100004D1684640781B2801D0032088E4002144 +:109D2000084603F0CCFB68468078002801D0082064 +:109D30007EE40120FFF708FA002079E4F8B5234C0F +:109D400003000CF061FC0A068017808080804B3590 +:109D50006E80FFF7CBFF00282AD1F7F7E9FD002836 +:109D600026D02221017000210172F7F7C2FDA07FE9 +:109D7000012152E08EB23046FFF741FA050004D1CE +:109D800011480CA12E300CF04EFB287821280FD062 +:109D9000F7F7CEFD00281BD01221017002270772B1 +:109DA00046800020A875F7F7A4FDA07F3843A07770 +:109DB000F8BD00007372635C6761705F636F72650A +:109DC0002E630000FFFF000036050000740A00202B +:109DD000132229463046FFF7F6FBE9E7A578122D56 +:109DE00006D0132D07D0FA49FA480CF01CFBDFE728 +:109DF000FFF760FF01E0FFF746FF0028D8D1F7F733 +:109E000097FD0028D4D022210170122D07D0022105 +:109E10000172F7F76EFDA07F10210843C7E701210B +:109E2000F6E7A07C810901290BD0800904D0E9481C +:109E3000E74922300CF0F7FA03210020FFF710FC6D +:109E4000B6E70221F9E7E348E1492930CDE7F7B564 +:109E500014460D0004D1DF48DD4931300CF0E3FA3F +:109E600028780827012807D002281FD0D948D849C8 +:109E700062300CF0D8FAFEBD0098FFF7C0F906007A +:109E800004D1D448D24938300CF0CDFA0220B07554 +:109E90001030207060783843607007CD083407C4F4 +:109EA000CD482022817F11438177FEBD0098FFF7C6 +:109EB000A6F9060004D1C748C54946300CF0B3FAEC +:109EC000A988C648814208D1EA88824205D1132276 +:109ED00031460098FFF777FBFEBD814202D1E8884A +:109EE000002809D01220207060783843607007CDB8 +:109EF000083407C4002006E07823002202200099DD +:109F000003F038FA0120B075FEBDB34840897047B0 +:109F1000FFB591B01498F8F721FF00285DD1012416 +:109F2000684603218471C9028180002201A920466C +:109F3000FAF719F9002850D16846152184714902B1 +:109F4000818000261C2102A800960CF04DF901200A +:109F50000146684610310170002001466846417094 +:109F60008178F9273940891C21438170017A0225C3 +:109F70002943017212998186C6861F2101870C90A0 +:109F800011980F9001A80B9009AA0BA902A8F9F744 +:109F9000B5FE002821D168468F4E808CF08068463F +:109FA00084718F498180807809AA3840801C4108DB +:109FB0004900684681708586058713A80F900BA914 +:109FC00002A8F9F79BFE002807D16846808C3081F3 +:109FD00031460A311498F8F7D4FE15B0F0BD30B50B +:109FE0000C46804995B08C4241D37F4901229204AE +:109FF0000968944201D38C4239D3203800220125CC +:10A0000003000CF001FB06042F494D535C64002152 +:10A01000082003F02EFA002802D0112015B030BD20 +:10A0200024206946087000A80522A11C02300CF00B +:10A030007CF809A96846F8F796FF050002D0082DBC +:10A040000ED031E0082300221146184603F092F9A1 +:10A05000082829D05F485E49D6300CF0E4F923E0A7 +:10A060000620DBE76068002803D0884201D2102078 +:10A07000D4E73D2168460170218841806188818054 +:10A0800009A9F8F770FF05000ED1606800280BD011 +:10A090006946098D018007E0206801F079FC02E043 +:10A0A000204600F0D8FC05462846B7E73E2007E0EA +:10A0B000857000E0827009A9F8F755FFF3E73420B6 +:10A0C000694608702078C0076846F3D0F0E707209B +:10A0D000A4E730B50C46444995B009688C4201D2DA +:10A0E00010209BE7203803000CF08EFA0504212194 +:10A0F000232132002088FFF782F8002804D000785E +:10A10000222803D2082089E7384887E725216846B6 +:10A1100001702188418009A9F8F725FF050015D1B4 +:10A120000AA905220231A01C0BF0FFFF0EE0062554 +:10A130000CE02068002805D0884201D2102505E0F7 +:10A1400001F01BFC24480025808BA080284665E791 +:10A15000072063E720481330704710B520211E48C0 +:10A160000CF040F80120FEF7EFFF1120FFF705F893 +:10A1700000211948C943818000218176E1218900AD +:10A18000818301460C300D310446F7F751FC12482B +:10A190000722214613300BF0C8FFFFF70EF8002806 +:10A1A00003D00B4912480CF03EF900F0D5FF10BD6A +:10A1B00010B504463C210CF015F8A07F8008800003 +:10A1C000A077202020700020A0752034607010BD82 +:10A1D000B49D00008C050000740A0020FFFF000001 +:10A1E000012A000000800100280000200230000049 +:10A1F000FB0600007047FEB50546FF480C4681424D +:10A2000007D301208004844205D3FC4800688442BF +:10A2100001D21020FEBD002D02D0012D32D126E04A +:10A22000F74908220F4668460BF07FFF3946204663 +:10A23000FFF777F90028EDD1FEF7BFFF060006D043 +:10A240000722694638460BF070FF3046FEBD207885 +:10A25000002801D0012805D1E94807223946C01D50 +:10A260000BF063FF0021092003F029F90FE00978C2 +:10A27000002907D0012905D0022905D0032903D0E0 +:10A28000E048FEBD0720FEBD0120FFF7E9F9DC48EC +:10A290000C3885760020FEBD10B5D8490968884283 +:10A2A00001D2102093E7D64902460C390B7B0D31C1 +:10A2B0001846FFF777F9002089E7FFB599B0054602 +:10A2C000002069460871087208A9087408751446C8 +:10A2D000CA480122C849920400681E46002D05D0D4 +:10A2E0008D420BD3954201D3854207D3002C08D071 +:10A2F0008C4203D3944204D3844202D210201DB076 +:10A30000F0BD2846204318D01F270CAB01AA0097A8 +:10A3100028461A99FFF79FF80028F0D10DAB02AA42 +:10A32000314620460097FFF796F80028E7D16846A7 +:10A33000007AC10703D00A20E1E70720DFE78007A2 +:10A3400005D568460079800701D50B20D7E703AF14 +:10A35000002D0FD01A20694608731A988873294671 +:10A36000F81C1A9A0BF0E1FE0EA903A8F8F7FBFD02 +:10A370000028C4D1002C0ED02021684601738673BA +:10A3800032462146F81C0BF0D0FE0EA903A8F8F7C0 +:10A39000EAFD0028B3D19A4908A8007C0C3948701E +:10A3A0000020ACE770B504460A2020700D46204618 +:10A3B000F8F7D9FD002805D139202070294620461C +:10A3C000F8F7D1FD70BDF7B500260C4605460B2702 +:10A3D0001AE02968B00009580978002903D001293A +:10A3E00001D00720FEBDA170296806220958E01C93 +:10A3F000491C0BF09AFE277020460299F8F7B3FD2E +:10A400000028EFD1761CF6B22879B042E1D80026B8 +:10A410003A270FE0A868B10041581022A01C0BF0A9 +:10A4200084FE277020460299F8F79DFD0028D9D1B7 +:10A43000761CF6B2287BB042ECD80020FEBDF0B509 +:10A44000044671A003C897B06B4B00271591149078 +:10A450009C4211D369480125AD040268AC4201D386 +:10A46000944209D32078012809D16168994203D325 +:10A47000A94204D3914202D2102017B0F0BD604926 +:10A480000C390A78012A0CD18A88614B9A4203D090 +:10A49000002806D0012804D08A7F13079B0F06D11D +:10A4A00001E00820E9E7D30701D1910701D5112088 +:10A4B000E3E7218A574B0A46203A9A4207D30128FC +:10A4C00075D1002973D1628A002A70D111E0022867 +:10A4D00001D0032801D1A02969D3012809D0484A15 +:10A4E0000C3A5278D20704D0628A002A5FD0B42A8C +:10A4F0005DD8002806D0012808D0022804D00328FF +:10A5000055D117E0002518E0022516E0002902D1F8 +:10A51000608A00280CD004256068007800280CD0E0 +:10A52000012809D0022807D0032805D03548A4E720 +:10A530000125F1E7032500E00127207A002806D055 +:10A54000012806D0022806D003287CD105E0002689 +:10A5500004E0012602E0022600E00326002D01D0DF +:10A56000022D14D1002E12D0E068FEF722FF002841 +:10A5700083D123480C384078800702D02148401E00 +:10A580007BE7022D03D1022E5DD0032E5BD0182174 +:10A5900068460170218A4180218A8180857118482E +:10A5A0000C38007B002803D001286FD104E04AE07A +:10A5B00000216846C17102E001206946C871684601 +:10A5C000077221780930012937D006210BF00AFEE5 +:10A5D00069460E74207D8207C107D20F4007C90F5C +:10A5E0005200C00F11438000014314A8405C69462B +:10A5F000C873002827D00FE0008001002800002049 +:10A60000800A002002320000070605040302010050 +:10A61000FFFF0000E13F000009A96846F8F7A3FC2E +:10A62000002884D109A96846FFF7BCFE0028A7D1FD +:10A63000002D0AD0022D08D010E061680622491CC6 +:10A640000BF073FDC4E7072017E7002E06D009AA18 +:10A650006946E068FFF7B7FE002891D11B206946E4 +:10A6600008700120887009A96846F8F77CFC00286A +:10A6700086D108A840791B2819D12B000BF0C4FF04 +:10A680000504040707040A00032001E00FE002208C +:10A69000FEF75AFD012D0CD0608A002809D0002257 +:10A6A00083001146104602F065FE002801D0032009 +:10A6B000E3E60020E1E6F3B5032687B00D46002966 +:10A6C0000AD0FA4885426FD301208004854203D323 +:10A6D000F7480068854267D30798FEF790FD0400AD +:10A6E00005D02078222804D2082009B0F0BDF14816 +:10A6F000FBE7A07F8707BF0F002D05D0294638460E +:10A70000FEF722FE0600F0D139460027EA4801296B +:10A7100007D0022931D0E949E9480BF084FE3046E0 +:10A72000E3E7A27D2946012A02D0827F920701D564 +:10A730001120DAE700291BD108216A46049711820B +:10A740000592418904AADF48FAF7FDF80028CCD128 +:10A750006846008A082801D00320C6E768460188B9 +:10A7600001814188418181888181C188C18102A99B +:10A77000079801F061FF0646D1E7A17D022916D1B5 +:10A78000807F800613D4002D04D0A07F40070CD416 +:10A79000002100E00121079801F08FFF0600BED1E3 +:10A7A000A775002DBBD004E01AE01126B7E7002DF5 +:10A7B00016D02A4621460798FEF725FF064611289F +:10A7C000ADD1A07F4007AAD42046082229460E30EA +:10A7D0000BF0ABFCA07F04210843A07700269EE786 +:10A7E000102082E770B50C460546FEF708FD010013 +:10A7F00004D022462846FEF7E6FE70BDAD4870BD87 +:10A8000000B50146143195B0192901D2810707D04E +:10A8100001461E3104D00A3102D0072015B000BD18 +:10A82000312269460A70887009A96846F8F79BFBCF +:10A83000F4E701B582B00220694608809E4802AB69 +:10A8400000896A460021F9F7E7FE6946098802296E +:10A8500000D003200EBD1CB50021009102216A46E4 +:10A860001180934901900968884201D210201CBDD3 +:10A87000914801899348FAF766F8694609880229E0 +:10A88000F5D003201CBDF0B50E46884985B01746AB +:10A8900005468E4207D386480122920400689642FC +:10A8A00004D3864202D2102005B0F0BD1F2F01D97B +:10A8B0000C20F9E7804C8D4226D3954201D3854286 +:10A8C00022D3E08803A9F9F758FE0028ECD12878B4 +:10A8D00069464873E08803A9F9F730FE0028E3D100 +:10A8E0006946009008780221084369460870497B50 +:10A8F000090703D00821084369460870E0886946C3 +:10A90000F9F7B5FD0028CFD169468F80E08833463E +:10A9100001AA0021F9F780FE69468988B942C3D0AF +:10A920000320C1E71CB50C4600210091019122884B +:10A9300069460A805E4901900968002801D0884272 +:10A9400001D38C4201D210201CBD002801D0002A66 +:10A9500009D059486A46C1885A48F9F7F4FF694650 +:10A96000098821801CBD0C201CBD10B50123FEF7F9 +:10A970004DFC2CE4002310B51A461946FEF746FCA0 +:10A9800025E430B505464A4895B000680C4681423A +:10A9900002D2102015B030BD2846FEF730FC00284A +:10A9A00007D00178222902D3807F800603D40820B3 +:10A9B000F0E74048EEE7132168460170458009A999 +:10A9C000F8F7D1FA0028E5D108AA0A2151567F29C3 +:10A9D00001D02170DEE70520DCE7F8B5012304464D +:10A9E0001A46194602F0C6F8074601231A46022104 +:10A9F000204602F0BFF8064601231A4604212046ED +:10AA000002F0B8F8054601231A460321204602F059 +:10AA1000B1F80446002F03D128492B480BF003FD61 +:10AA2000002E04D1AD20254980000BF0FCFC002D48 +:10AA300004D125482149801C0BF0F5FC002C04D1E1 +:10AA400021481E49C01C0BF0EEFC22213846FEF7BF +:10AA50000EFC3846F8BD10B50446006800280CD03E +:10AA60001249884207D301218904884205D310493D +:10AA70000968884201D2102014E400F071FFA08818 +:10AA80000D4CA083A07E01280DD10021092002F0E9 +:10AA9000F0FC002800D00120A17C8909012915D0F3 +:10AAA0000321FEF7DDFD002006E400000080010028 +:10AAB0002800002002300000740A0020B49D00002D +:10AAC000C6090000FFFF0000B30200000221E8E712 +:10AAD00030B5F74B9A4207D301239B049A4205D322 +:10AAE000F44B1B689A4201D2102030BD1578EB065A +:10AAF0005B0F042B07D85478072C04D39378102BC2 +:10AB000001D8A34201D2072030BDD3785B0702D41D +:10AB100013795B0701D5062030BDC37FAC075B0806 +:10AB20005B00E40F2343C3770878EF2318401378C2 +:10AB30009B06DB0F1B0118430870F12318401378A4 +:10AB4000DB065B0F5B001843087050780873002029 +:10AB500030BD30B500240C70C378DB07DB0F0B7001 +:10AB6000C578AD07ED0F6D002B430B70C5786D07F1 +:10AB7000ED0FAD002B430B7014700179C907C90F9D +:10AB8000117003799B07DB0F5B001943117000798B +:10AB90004007C00F80000143117030BD70B51446EE +:10ABA0000D460646F6F7C4FE002809D0A221017022 +:10ABB000142221460830F6F707FBF6F79AFE70BD1F +:10ABC000132229463046FEF7FEFC70BD70B51446D0 +:10ABD0000E460546F6F7ACFE002809D0222101708A +:10ABE00045802178017261784172F6F782FE70BD6E +:10ABF000132231462846FEF7E6FC70BD10B5AE4C78 +:10AC0000207C00280CD1204621461038FDF762F840 +:10AC1000002803D0A9A1F2200BF005FC012020742C +:10AC200010BD70B594B015460C462C226946189E8E +:10AC30000A704880002B17D00822194601A80BF093 +:10AC400074FA68468581102231460E300BF06DFA99 +:10AC500009A96846F8F787F9002803D1A17F1022D7 +:10AC60001143A17714B070BD002001900290E8E775 +:10AC7000F0B50646008A97B080B20D460190FEF707 +:10AC8000BEFA04468C48317848380746E8370990C0 +:10AC90000B000BF0B9FC0EFCFB48085F8798B8D995 +:10ACA000FAF9F8F7F6FC002301221946019801F0A1 +:10ACB00061FF050004D1FF2080A130300BF0B3FB11 +:10ACC000002C04D1FF207DA131300BF0ACFB387E8D +:10ACD000C00904D078486030C06DA86112E02B2014 +:10ACE000694608720BA902A8F8F73DF9002804D0BC +:10ACF000FF2072A13C300BF096FB74490C980BF0CE +:10AD00008EFAA9617068A862B068E862A07F8007C7 +:10AD1000800F012820780DD0252804D0FF2067A1BE +:10AD20004D300BF080FB324621460198FFF736FF8D +:10AD300017B0F0BD2528F6D0222806D0242804D04C +:10AD4000FF205EA146300BF06EFB25212046FEF76A +:10AD50008EFAE8E7002301221946019801F00AFF64 +:10AD6000060004D1FF2055A158300BF05CFB002CED +:10AD700004D1FF2051A159300BF055FB2078252834 +:10AD800004D03078012108433070D1E702202870C8 +:10AD9000B068A860B068002802D000202871C7E71A +:10ADA0000120FBE72B2069460870434968464C396F +:10ADB000F8F7D9F8002804D0FF2040A178300BF034 +:10ADC00032FB03201BE02A206946087000A81022ED +:10ADD000023071680BF0A9F904A810220230B168A2 +:10ADE0000BF0A3F9344968464C39F8F7BCF8002851 +:10ADF00004D0FF2031A189300BF015FB042028700E +:10AE00000998686094E7B068002804D1FF202BA15E +:10AE100095300BF008FBE07F400704D5FF2027A109 +:10AE200096300BF000FBB06806220A3800903379A8 +:10AE30000421019801F0FBF90028A6D0FF201FA1F2 +:10AE40009B300BF0F0FA73E7002C04D1FF201BA11C +:10AE5000A3300BF0E8FA2046223010220546716834 +:10AE60000BF063F928212046FEF701FAA07F800746 +:10AE7000800F022814D100231A462146009501981C +:10AE800006E04BE1BAE0B0E095E03FE071E05FE161 +:10AE9000FFF7C7FE11281BD029212046FEF7E7F94E +:10AEA000E07F317A4007400FC9000843E0773FE771 +:10AEB0000080010028000020400B00207372635CBA +:10AEC0006761705F7365632E6300000040420F008E +:10AED000A07F000704D5FF20FD49B0300BF0A3FA96 +:10AEE000A07F08210843A0770020608620463430E8 +:10AEF0000BF078F9E07FFD220146C9071040890F69 +:10AF00000843E077307A2034207011E700230122D3 +:10AF10001946019801F02EFE040004D1FF20EC49EF +:10AF2000CD300BF080FA2B2069460872E94902A85F +:10AF3000F8F719F8002804D0FF20E549D2300BF0CB +:10AF400072FAE4488188204621300176090A417668 +:10AF50000E2129702146FC316960017E2974407EF2 +:10AF60006874DC482C30A860103030346C61E860C4 +:10AF7000DEE6002C04D1FF20D549E6300BF053FA71 +:10AF80002078212893D93079012802D0022808D1CD +:10AF900003E0E07F04210843E077387E0121084385 +:10AFA0003876324621460198FFF7F8FD23212046E6 +:10AFB000FEF75DF9BCE601220421019801F01FFCB7 +:10AFC0000028A2D0002301221946019801F0D2FDE9 +:10AFD000040003D1BE49C0480BF025FA0F202870A9 +:10AFE000172028716E34AC60A2E60421019801F0AC +:10AFF00056FC002889D11020287099E600230122F0 +:10B000001946019801F0B6FD050004D18720B0492A +:10B0100080000BF008FA2E462036307E41064DD5D2 +:10B02000A17F8F07BF0FC00713D029468031486F1B +:10B0300000280ED0027CF37DD207D20F5B001A43AA +:10B040000274486F5108E27F4900D207D20F1143C2 +:10B050000174307E000713D52A468032116F002913 +:10B060000ED0087CF37DC007C00F5B001843087446 +:10B07000116FE27F40084000D207D20F10430874DE +:10B08000307E80070BD5F8204259002A07D0012FC7 +:10B0900005D02946307C31311032FEF783FA307EFC +:10B0A000C0060BD5F8204259002A07D0012F05D140 +:10B0B0002946307C31311032FEF774FA0523684698 +:10B0C0000370357E4570834822216038019A0170F3 +:10B0D0004178C908C900C91C417042800372457299 +:10B0E000F6F78EFD2078252809D021280BD07A4844 +:10B0F00077495B300BF097F92078222803D9222179 +:10B100002046FEF7B4F80021019801F06BFD0028FD +:10B1100000D10DE670486E49633092E674686D4D5B +:10B1200020786035092802D00A28F2D10BE0E168C6 +:10B13000002902D02846F7F7E8FE2169002902D04D +:10B140002846F7F7E2FE21462846F7F7DEFEEFE550 +:10B1500061485F49883074E65E4810B504222821B2 +:10B160006030F7F7B9FE5B480024EC30017E4906F9 +:10B17000490E01764038C465FCF739FD55493C312C +:10B1800008461038F6F78BFC52484C30047410BD5A +:10B1900070B50D46FEF733F8040004D14E484C4913 +:10B1A000A7300BF040F9FF21053128460BF01CF8C1 +:10B1B000A07F8007800F01280CD00221284688300C +:10B1C000FCF716FD002804D043484149AC300BF091 +:10B1D0002AF970BD0121F1E70A46014610B5104673 +:10B1E0008830FCF71FFD10BD70B5054611200C46D8 +:10B1F0000870002161702121495D002908D00329D0 +:10B200000ED0042910D034483149C6300BF00BF968 +:10B2100020780009012802D9E87FC008607070BD5D +:10B220000007000F203002E00007000F30302070D0 +:10B23000EEE7F0B504464068082601789BB008297F +:10B240000DD00B2903D00C294BD1012181716068ED +:10B2500087883846FDF7D3FF05004CD147E0478883 +:10B260003846FDF7CCFF050004D1172018494001EE +:10B270000BF0D9F82878212833D0282833D16068FA +:10B2800002210C3000F050FF00282CD0606808210B +:10B29000001D00F049FF002825D02D2168460170CF +:10B2A000478029461022223101A80AF03EFF0FA94B +:10B2B0006846F7F758FE002804D007480449EF30E5 +:10B2C0000BF0B1F8A87F10210843A877292105E0E9 +:10B2D000BCAE0000F40A0020030200002846FDF77F +:10B2E000C6FF1BB0F0BD607830436070F9E7FE49DF +:10B2F000FE480BF098F8A87FEF210840A87729783E +:10B3000021290FD061688A79002A02D08978002922 +:10B3100012D08007800F022849D0F448F249343017 +:10B320000BF081F8FEF7DEF90028DAD0EF48EE499D +:10B330003F300BF078F8D4E7607830436070E87FF6 +:10B34000C00701D0042100E00321212041552878C5 +:10B3500029280BD03946062002F0B1F82878242895 +:10B36000E0D122212846FDF782FFDBE700230122FE +:10B370001946384601F0FEFB040004D1C920DA4921 +:10B3800080000BF050F825212846FDF770FF0D20B6 +:10B3900008A90871204609A98830FCF735FC022865 +:10B3A000C0D00028BED0D148CF491D30B8E7607862 +:10B3B00030436070B6E7F7B58AB015460646FDF72C +:10B3C0001EFF002841D0017822293ED323293CD0FA +:10B3D000C17F490739D4807F8007800F01280DD0B5 +:10B3E000002301220021304601F0C4FB0746C0487B +:10B3F0000290F7F781FD040007D101E00123F0E797 +:10B40000BA48B94959300BF00EF8002F1FD08837D1 +:10B4100067610298F7F770FD07460298F7F76CFD31 +:10B4200009212170266225710B99E760A1602061D6 +:10B4300003A92046FCF70CFC022806D0002804D003 +:10B44000AA48A94975300AF0EEFF0DB0F0BD002002 +:10B4500007466061E4E730B5002387B00546012266 +:10B46000194601F087FB04462846FDF7C8FE007820 +:10B4700022281BD9002C04D19C489B4981300AF01A +:10B48000D2FF0F21684601701721017120466E30EE +:10B49000029069461A30FCF7B7FB022806D0002854 +:10B4A00004D0E520904980000AF0BDFF07B030BD10 +:10B4B00030B5002387B005460122194601F05AFB3A +:10B4C00004462846FDF79BFE00782228EED9002C82 +:10B4D00004D18648844993300AF0A5FF10206946BC +:10B4E000087020468830FCF78FFB0028DED0E9206A +:10B4F0007D4980000AF097FFD8E7F7B50546007848 +:10B500000027000982B00C463E4602287ED007285C +:10B5100002D00A284AD14AE068680178082907D091 +:10B520000B2930D00C292ED070486F49D33060E100 +:10B5300014271A26002C6AD04088A080FDF75FFEF1 +:10B540000090002804D169486749AF300AF06BFFCA +:10B5500000980099C07DA21D1831FEF723F8686895 +:10B5600008228089E081696820461030091D0AF0B0 +:10B57000DCFD207E01210843F92108402076009857 +:10B580004021807F47E018270826002CD3D08088F0 +:10B59000A080FDF734FE050004D1F7205249800059 +:10B5A0000AF041FFA11D2846FFF71EFE23E1002CF3 +:10B5B00001D0288BA080287A01287DD0022804D0D1 +:10B5C00003282FD048494B4813E11C270726002C9D +:10B5D000B1D0A088FDF713FE0090002804D1FD2013 +:10B5E000414980000AF01FFF287B8007800F012857 +:10B5F000A07914D040084000A071FD210840297BAB +:10B600004907C90F49000843A07101E0E3E0DFE00A +:10B6100000988021807F084300998877EBE0012122 +:10B620000843E9E713270B26002C84D0A088FDF7F8 +:10B63000E6FD00900023A0880122194601F09AFA45 +:10B6400005460098002804D12A48274960380AF0A6 +:10B65000EAFE002D04D181202349C0000AF0E3FE58 +:10B660000098807F8007800F012859D0E86A817890 +:10B670008907890F0129A17954D049084900A1718E +:10B680008278FD255207D20F294052001143A17143 +:10B69000E322114002785207D20E1143A171DF223A +:10B6A00011404278D207920E1143A1710021E1713D +:10B6B000C1782172427900E037E00179607AD307DE +:10B6C00040084000DB0F18439307DB0F28405B0066 +:10B6D00018435207FB23D20F1840920010436072A8 +:10B6E000A07A4008400007E0BCAE00000E03000056 +:10B6F000540B002067040000CA07D20F10438A07CA +:10B70000D20F2840520049071043C90F1840890042 +:10B710000843A0720098007823286CD92621AFE056 +:10B72000A86AA4E701221143A9E7297BFE48022960 +:10B7300010D017270C26002C4AD0012911D003293C +:10B740001ED004291FD005291DD0F849F8480AF059 +:10B750006AFE23E019270726002C4CD00121A17195 +:10B7600005E00121A171E17989088900E171017E7B +:10B77000CA094906D201890E49000A4302760DE042 +:10B780000220A07106E0687B0007000F8030A071E6 +:10B79000052918D0E07980088000E071A088FDF7C5 +:10B7A0002EFD05460078212825D0232804D0E04826 +:10B7B000DE490C300AF037FEA088002101F012FAB1 +:10B7C000222128465DE0E07980088000401CE4E703 +:10B7D0000498068015E0002C01D06888A080287AA3 +:10B7E000032828D004280FD005284DD0D048CF49B1 +:10B7F00064300AF018FE0498002C068001D02780DF +:10B800006680002005B0F0BD15270C26002CDFD087 +:10B810000023A0880122194601F0ACF9050004D1EB +:10B82000C348C2492A300AF0FEFD0622A11DA869BC +:10B8300009F0DCF9DFE716270726002CC8D0A0881E +:10B84000FDF7DDFC00900023A0880122194601F0DD +:10B8500091F905460098002801D0002D04D1B44884 +:10B86000B24938300AF0DFFD2878C00601D5022041 +:10B8700000E00120A071009800782328BBD927217F +:10B880000098FDF7F4FCB6E717270C26002C9FD094 +:10B89000A088FDF7B4FC00906D7A002804D1A4487C +:10B8A000A2494B300AF0BFFD0621A01D0AF09AFC08 +:10B8B0000020A071207A032108432072FB21084058 +:10B8C0000099C97FC907490F08432072680692D5BD +:10B8D000E07904210843E071A07AE90740084000BC +:10B8E000C90F0843E17A2A0749084900D20F1143DA +:10B8F000FD22AB07DB0F10405B001843A072E80687 +:10B90000C00F114040000143E17274E710B50446D6 +:10B91000807990B08009012804D04D20834900012E +:10B920000AF081FDFFF76AF90120694608707E4838 +:10B930000AA9A0380190201D0290601C0B90684657 +:10B94000FCF786F9002804D07948784987300AF056 +:10B950006AFD0322601C0B990AF0E7FB10B010BDD2 +:10B9600010B5714CA03C002805D00146102220469D +:10B970000AF0DBFB0120207410BD10B50446FFF770 +:10B980003DF969491022A03920460AF0CEFB10BDCE +:10B9900070B50025644C00281CD06649884207D346 +:10B9A00001218904884205D363490968884201D28C +:10B9B00010250DE0062109F003F9411C07D05A4972 +:10B9C0004039C865207E80210843207600E00725A5 +:10B9D000284670BD207E4006400EF6E7F3B50020F5 +:10B9E00089B00D46029000290AD0524885421CD3E6 +:10B9F00001208004854203D34F480068854214D358 +:10BA00000998FDF7FCFB060003D03078222815D1F9 +:10BA100002E04A480BB0F0BD002D08D1B07FC1094B +:10BA200003D08007800F022801D01020F2E7B07FFA +:10BA3000C10601D4000703D5002D01D00820E9E795 +:10BA40003948007EC00712D1F07F400701D50D2094 +:10BA5000E0E7002201231146099801F08BF8070066 +:10BA600005D0B07F8007800F022802D00BE01120A4 +:10BA7000D0E7002D07D02A4639463046FFF728F890 +:10BA800002900028C6D128488C38F7F735FA040010 +:10BA900003D126492A480AF0C6FC0A2020700998DA +:10BAA000206238468830A060B07FFB218007800F7D +:10BAB000012829D0002D4CD002202071381DE060D3 +:10BAC00038780007400F20743878C006C00F6074C3 +:10BAD000A07C2A788008D2078000D20F1043A0747F +:10BAE0000840F17F01AAC907490F0843A074A8784C +:10BAF000E07469462846FFF72CF8684600792075FF +:10BB000068460078607528E001202071207B2A7843 +:10BB10008008D2078000D20F104320730840297894 +:10BB20008907C90F89000DE0E00B0020BCAE0000C2 +:10BB300053040000008001002800002002300000B3 +:10BB4000630500000843207324213046FDF78FFB76 +:10BB50000BE0032020710520207325213046FDF7DE +:10BB600086FBB07F4006400EB07703A92046FCF765 +:10BB70006FF8022805D0002803D0FD49FD480AF0DF +:10BB800052FC029846E7FFB581B00A9D06461C4666 +:10BB90001746142128460AF027FB0B980021016064 +:10BBA000F8070ED0F44920680968884239D312306A +:10BBB00028602068143068602068A8600B982168AD +:10BBC0000160B80726D56068002803D0EA490968F3 +:10BBD000884226D3029900290AD0FC3600280ED0CC +:10BBE00031461030FDF79DFC00281BD1606810E045 +:10BBF000002816D0E86080366068B0670AE0FEF77B +:10BC0000A9FA0146072230460AF08FFAFEF7F6FF3E +:10BC1000DA48E860780707D5D749A06809688842FC +:10BC200001D21020EEE528610020EBE5FFB5D44AF3 +:10BC30000E4607CA97B002AB07C3002700970197CB +:10BC40001798FDF7DCFA050005D02878262804D0DF +:10BC500008201BB0F0BDCB48FBE700231A4619466D +:10BC6000179800F087FF040004D1C248C049803013 +:10BC70000AF0D9FBA87F8007800F1690012814D006 +:10BC8000022824D0BB48BA4999300AF0CCFB0121E4 +:10BC90000022852E31D01EDC002E26D0812E26D00B +:10BCA000822E26D0832E1ED125E0002EEFD12146F4 +:10BCB0002846199AFEF70CFF0028CAD119988078F7 +:10BCC000009019980078C007C00F0190DFE719981D +:10BCD000002808D1DBE7862E11D0882E11D0892EBE +:10BCE00011D08A2E11D00720B3E710460EE0084687 +:10BCF0000CE002200AE0032008E0052006E0062010 +:10BD000004E0082002E0092000E00A20002222715D +:10BD100001216A461176211D0791002801D020716A +:10BD2000FAE0169801280CD0A66AE06A02220121E6 +:10BD300010900020A0602846173002291AD0012157 +:10BD400019E0E66AA06A1090032030702078FB2387 +:10BD5000C006C00F7070B07801221840009BF370CD +:10BD60008008019B800018430221B0700020707190 +:10BD70003071DEE70021890009190861681C022A78 +:10BD800001D0012100E00021890009190861B07883 +:10BD90008007800F01285ED1109880788007800F7F +:10BDA000012858D110980079844610984079009065 +:10BDB000169801281DD0317908A801747179017590 +:10BDC00008A8027C6046024008A8007D009908404F +:10BDD000139010433FD06C491A98884207D3012131 +:10BDE0008904884215D364490968884211D2102019 +:10BDF0002FE70CAA0DA91998FEF7ABFE08A8007C46 +:10BE000061460840307108A8007D009908407071B3 +:10BE1000D6E720463C3021460090F031169801913B +:10BE2000022834D000211A9B20460C33FFF7ABFECA +:10BE30000028DDD12046503021460090F43116987C +:10BE40000191012825D0002120461A9B139AFFF763 +:10BE50009AFE0028CCD110988078400702D4E87F61 +:10BE6000C0072BD0169902A8012914D0109909787F +:10BE70004900405A21780907490F4900C8408707FF +:10BE8000BF0F2AD0012F14D0022F0FD113E00121B0 +:10BE9000C9E70121D8E721780907490F4900405A2D +:10BEA000109909784900C8408707BF0F032F04D0B5 +:10BEB00004E0022711E001270FE00227169801286D +:10BEC0000BD1B078FB210840E97FC907490F08432F +:10BED000B07020780007400F3070207810224008A2 +:10BEE000400020701099D2434978C907C90E114308 +:10BEF00008402070C00623D4022F21D0012F21D06A +:10BF00000020A061E0612062606220461830A060DD +:10BF1000E87F40084000E877204606A98830FBF714 +:10BF200073FE002806D0022804D06F2010490001BB +:10BF30000AF079FA25212846FDF799F9002088E6CC +:10BF4000032008E020460D211B300AF04BF9204663 +:10BF50001830A060042069460875E87F0121084375 +:10BF6000E87705AA29461798FEF730FED4E70000C7 +:10BF7000BCAE00008E05000028000020400B002011 +:10BF8000606701000230000000800100F0B587B05A +:10BF900015460E0004460DD06A48854207D301209D +:10BFA0008004854206D368480068854202D210208A +:10BFB00007B0F0BD2046FDF722F9070004D038781D +:10BFC000272803D00820F3E76048F1E700231A464A +:10BFD0001946204600F0CEFD040003D15C495D48BF +:10BFE0000AF021FA0020002E05D0022E08D0012EE2 +:10BFF00011D00720DCE701216A461171A06018E02A +:10C00000234618336946A360087110222946184652 +:10C010000AF08BF80DE021461831A16069460871DD +:10C02000A061E061206260620621284608F0C8FD38 +:10C03000A0612078C10714D0400840002070022081 +:10C04000694608702046183002907030FBF7DCFD1E +:10C05000022806D0002804D03E483D4923300AF08B +:10C06000E2F925213846FDF702F90020A0E770B576 +:10C0700094B00D460646002B02D0072014B070BDC8 +:10C08000FDF7BDF8040007D02078222802D3A07F56 +:10C09000400603D40820F1E72C48EFE7002D19D023 +:10C0A0002D216846017046801022294601A80AF019 +:10C0B0003CF8E07F297C4008C9074000C90F0843CD +:10C0C000E077297C40078906400FC90EC900084364 +:10C0D000E07703E02E2168460170468009A9684692 +:10C0E000F6F741FF694609782D2905D1002803D1CB +:10C0F000A17F10221143A177A17FBF221140A17718 +:10C10000BCE710B50C46FDF77AF8002805D00E49BB +:10C1100009688C4203D2102010BD0C4810BD214686 +:10C12000FFF762F8002010BD05E00278401C002AED +:10C1300001D0002070470A46491E89B2002AF4D176 +:10C14000012070470080010028000020023000001C +:10C15000BCAE00000F07000030B50346072903D02E +:10C160000820DA781C7916E00720FAE707290BD0B7 +:10C170005500ED186D79072D01D0401EC0B2521C3C +:10C18000D2B20F2A07D105E05500ED186D79072DC1 +:10C19000F3D0F4E700222546641EE4B2002DE5D179 +:10C1A00030BDFFB581B00C461646114620460A9FA9 +:10C1B0000B9DFFF7D1FF00280AD020790F2803D369 +:10C1C000FEA1A0200AF02FF9A078C00907D019E03D +:10C1D000072E02D0112005B0F0BDFD48FBE7019805 +:10C1E0002880381D6880002068712871EF800498CD +:10C1F00028812846F6F7DFFE002803D1EFA1AD2005 +:10C200000AF011F9E07821794018491CC0B2217177 +:10C210000F2801D30F38C0B2400000194671817950 +:10C22000F12249084900114081710020D3E7FFB590 +:10C2300083B01C4616460F4600231A4602210C9D69 +:10C24000039800F097FC010008D033463A46019568 +:10C2500000940398FFF7A5FF07B0F0BDDC48801EEF +:10C26000FAE7F0B5054616460F4650888DB0002314 +:10C270000122022100F07EFC040003D1CFA1DF20C7 +:10C280000AF0D1F8002069460871A078400603D171 +:10C29000CAA1E3200AF0C7F8042F5ED32A78D0079A +:10C2A000C017401C06D161786B78994255D121782E +:10C2B000090752D00121142A46DA012A42D0122A53 +:10C2C00002D0132A40D128E00C2F3DD1A27852068B +:10C2D000520E012A38D0207800090001401C20703D +:10C2E000687860706846017168792A7901021143A3 +:10C2F00068460181E879AA790102114368464181C3 +:10C30000687A2A7A0102114368468181E87AAA7A1A +:10C31000010211436846C1811AE0062F14D120782A +:10C320000009000120707188012001F0C8F8022185 +:10C3300068460171C91E018168792A790102114399 +:10C3400068461FE0062F0AD06A461279002A1BD0E1 +:10C350007088324601A9FDF77AFD0DB0F0BD207856 +:10C360000009000120707188012001F0A8F8022165 +:10C370006846017168792A79010211436846018192 +:10C380000021C9434181E3E70028E6D0748868466C +:10C3900081766978C176022181830021C18304A856 +:10C3A00005220090062311462046FFF740FF002893 +:10C3B000D3D088A1D6200AF036F8CEE7F7B58CB0F6 +:10C3C00015460C990D98F9F7CEF9C0B2082851D14D +:10C3D000002069468885688800230122022100F038 +:10C3E000C9FB040004D1FF2074A163300AF01BF8DC +:10C3F00001230021E07822790BE046003619767996 +:10C400009E4201D1491CC9B2401CC0B20F2800D1C4 +:10C4100000201646521ED2B2002EEED1002902D1C3 +:10C4200017206946888504AB02330BAA00950C9946 +:10C430000D98F7F73BFC0006000E07D002281BD032 +:10C44000032817D0FF205DA1893011E06846808D58 +:10C4500000280FD002A901910090688804230122CE +:10C460002146FFF79EFE002804D0FF2053A176301E +:10C4700009F0D9FF0FB0F0BD68781021084368704B +:10C48000F8E70020584902464300401CCA520828D9 +:10C49000FAD3704700218170017809090901017000 +:10C4A00000214170C1700171704770B50D460023C5 +:10C4B0000122022100F05EFB040004D1FF203FA115 +:10C4C000CF3009F0B0FFA0786906C009C001490E5D +:10C4D0000843A07070BD704710B50146012000F000 +:10C4E000EEFF10BD3EB58DB2002301220221284689 +:10C4F00000F040FB040004D1FF2030A1E43009F03B +:10C5000092FF20786946000900012070022008701F +:10C5100036488880C88000222846FDF798FC3EBD3A +:10C52000F7B505460078002700090C463E4601286D +:10C5300004D0FF2021A1F33009F075FF287A0328E9 +:10C540000CD041201DA1C00009F06DFF0298002C05 +:10C55000068001D0278066800020FEBDEA89702712 +:10C5600010460A3086B2002C0AD06888A080A889BC +:10C570002081E28020460A30296909F0D6FDE5E7EE +:10C5800002980680E8E7F8B543680246D9799C79B5 +:10C59000090221435C7A1E7A25025C88981D354386 +:10C5A000241FA14238D11B79022B35D1042D34D060 +:10C5B000052D3DD0062D34D0402D19E07372635CFB +:10C5C0006C326361705F636F72652E630000000000 +:10C5D000043000007372635C6C326361705F636F80 +:10C5E00072652E6300000000000C0020FFFF0000B9 +:10C5F00012D3061D0F461446284600F0E9F9082814 +:10C600000AD01120207003202072A581E7812661C5 +:10C610006078082108436070F8BD001DFFF7CEFE6A +:10C62000F8BD031D50880A461946FEF7C4FEF8BD42 +:10C63000001DFFF716FEF8BD70B50D4600238CB047 +:10C6400006461A46022100F095FA040031D02078FF +:10C650000007000F01282ED01220694688746078E8 +:10C660000523801CC874082088822888C8826888AE +:10C670000883A8884883E888888302A90C20019150 +:10C6800000901A4621463046FFF78BFD00280ED158 +:10C69000F02300223146012000F06CFE20780009D2 +:10C6A0000001401C20706078801C607000200CB07D +:10C6B00070BDCD48FBE71120F9E770B50D460023AA +:10C6C0008CB006461A46022100F054FA040006D047 +:10C6D00020780007000F012803D00820E7E7C248B0 +:10C6E000E5E71321684681746178C1740221818273 +:10C6F000C58202A906200523019100901A46214611 +:10C700003046FFF74EFD0028D1D120780009000106 +:10C7100020700020CBE7F3B581B00D460023012245 +:10C720000221019800F026FA00260446002803D1D1 +:10C73000AE49AF4809F077FE2079A8423BD2AC4819 +:10C74000AA49401C09F06FFE35E0E07841000F195E +:10C75000401C7979C0B20091E0700F2801D100200F +:10C76000E0702079401E2071B879C00708D0009889 +:10C770000199042815D09D498220183109F053FEF3 +:10C78000B8790007410F08D0400F019904280CD058 +:10C7900096498F20183109F046FE009807280AD1E3 +:10C7A00007E00846FEF784FEEAE70846FEF753FE78 +:10C7B000F3E7761CF6B228466D1EEDB20028C4D110 +:10C7C0003046FEBD10B500230122022100F0D2F94F +:10C7D000040004D1B5208549800009F024FEE078EA +:10C7E00021794018C0B2E0700F2801D30F38E070F3 +:10C7F00000202071A07880210843A07010BDF8B5FA +:10C8000017460D4600231A46022100F0B3F9040032 +:10C8100005D0002D0CD0002F07D0062006E0072DF4 +:10C8200001D00820F8BD0720F8BD0820A84204D890 +:10C830006F486E49423009F0F6FD29462046FFF761 +:10C840008BFC0646002F28D0002E26D1E0782179D7 +:10C850001CE0420012195379072B03D093791B0770 +:10C860005B0F04D0401CC0B20F280CD00CE040007D +:10C8700000198079F12318406B071B0F1843907142 +:10C8800000290AD104E00020491EC9B20029E0D1E4 +:10C89000574856495A3009F0C6FD3046F8BDF8B53C +:10C8A0000D4600231A46022100F064F9040004D169 +:10C8B0004F484E49683009F0B6FD681E052804D37C +:10C8C0004B484A49693009F0AEFD0F21E2782079E2 +:10C8D000002310E0560036197779AF4206D1B179BE +:10C8E00049084900B1715B1CDBB21146521CD2B23F +:10C8F0000F2A00D100220646401EC0B2002EE9D108 +:10C900000F2905D248000019817901221143817154 +:10C910001846F8BD10B50446402801D2072010BDC6 +:10C9200000F056F8082802D03120000210BD002186 +:10C93000304802E0491C082903D24A00825A002AE2 +:10C94000F8D1082903D049004452002010BD04202A +:10C9500010BD10B5402801D2072010BD00F038F8F6 +:10C96000082805D00021234A40001152084610BD76 +:10C97000052010BDF0B58BB016460C00074607D059 +:10C98000002E05D06188402904D207200BB0F0BDED +:10C990001020FBE72088002801D0172801D90C209F +:10C9A000F4E7084600F014F808280FD0258803A8FB +:10C9B0002A463146023009F0B8FB01A8009062888F +:10C9C0002B4607213846FFF732FCDFE70520DDE77D +:10C9D00001460020074A02E0401C082803D2430019 +:10C9E000D35A8B42F8D1704702300000BCC500001A +:10C9F000AD020000000C0020F8B50546E54C079E8E +:10CA0000069821706270A370E6702071681C42085D +:10CA10005200E14B0021880000198446C261605C2D +:10CA200040008218002D0AD0002005E0664647002D +:10CA3000F669401CF353C0B2665C8642F6D8491CC6 +:10CA4000C9B20529E7D30026D21C9708B000BF0061 +:10CA500000198760304600F042F9A15D761C48431A +:10CA6000C219F6B2052EEFD3501B80B2F8BDF0B557 +:10CA70000546C84F8C460020FF247E5DA9009646DF +:10CA80000346CF190CE0F9695A008A5AC2498A4212 +:10CA900004D1401CC0B2FF2C00D11C465B1CDBB291 +:10CAA0009E42F0D86146002909D100280BD0002D04 +:10CAB00007D0B84949788E4203D2401EC0B2002840 +:10CAC00001D071460C70F0BD70B5B24C8D000023E2 +:10CAD0002D19615C09E0EC695E00A45B844202D11F +:10CAE0001370012070BD5B1CDBB29942F3D80020AB +:10CAF00070BDFEB51C4617460D46060008D0002D39 +:10CB000006D0F01C80088000B04203D01020FEBD8B +:10CB10000E20FEBD002F03D0002C01D0A74201D96A +:10CB20000720FEBD0094234622463946002001948A +:10CB3000FFF762FF2988814207D0814201D2042198 +:10CB400000E0092128800846FEBD009423462246C5 +:10CB5000394630460194FFF74FFF28800020FEBD84 +:10CB600010B5044600F0C5F8002801D0E0B210BDB1 +:10CB7000FF2010BDFFB50546874881B01E460C4614 +:10CB8000854204D0052C02D20398022802D300204B +:10CB900005B0F0BD002769460F7028466A46214659 +:10CBA000FFF792FF00280ED068460178204600F07B +:10CBB000A8F8002EECD00028EAD1284600F099F819 +:10CBC000002809D103E03846002EF6D1E0E7FF2027 +:10CBD00072A15C3009F027FC21462846039A00F038 +:10CBE0009CF8D5E7F8B505460C4600206A4E694624 +:10CBF0006E4F0870B5423BD0052C01D30720F8BD1D +:10CC00000A4621462846FFF75FFF002830D06846D5 +:10CC10000178204600F075F8230009F0F5FC0504C2 +:10CC2000090C11161B0001462846FEF7D5FA15E03F +:10CC3000FDF7E0FA12E001462846FFF74CFC0DE054 +:10CC400001462846F6F7B5FF08E001462846F8F702 +:10CC500012FC03E056A17B2009F0E5FB4D4A684633 +:10CC6000A10000788918C96940000E520020F8BD63 +:10CC70003846F8BD524A1268914201D210207047DE +:10CC8000052801D3072070470872002048727047BA +:10CC9000F8B504464A480068844201D21020F8BD25 +:10CCA000207A3C4A83009B18617A3B4D125C11E06C +:10CCB000DE694F00F65BAE420AD04A1C6272DA6946 +:10CCC0004B00D25A228000F01CF860600020F8BDB2 +:10CCD000491CC9B28A42EBD861720520F8BD0EB575 +:10CCE000384B40000ECB0091029301926946085ADE +:10CCF0000EBD28494978814201D9012070470020A2 +:10CD0000704770B50C460546FFF7E9FF214AA900B8 +:10CD1000891889686043401870BDF8B50C4606460E +:10CD200000206946134608706A4619462046FFF7F8 +:10CD30009EFE002500282BD0164A6846A1000078E8 +:10CD40008918C96940000E52684601782046FFF7ED +:10CD5000D8FF0546230009F057FC0504090C0F1401 +:10CD6000170029463046FEF713FA11E0FDF720FAC6 +:10CD70000EE0FFF78FFB0BE029463046F6F7E0FEAA +:10CD800006E0F8F771FB03E009A1622009F04BFB14 +:10CD90002846F8BD100C0020FFFF00007372635C92 +:10CDA000686F73745F636D2E6300000002300000D3 +:10CDB0007372635C686F73745F636D2E6300000051 +:10CDC000280000206C67010010B5014620220948A8 +:10CDD00009F0ABF907490020C877084610BD06499D +:10CDE000012048610548064A0168914201D10021AD +:10CDF00001607047400C00200005004078000020D2 +:10CE0000BEBAFECA8107C90E002808DA0007000F63 +:10CE100008388008C24A80008018C06904E0800891 +:10CE2000C04A800080180068C8400006800F704724 +:10CE3000BD4948788978884201D3401A02E021220E +:10CE4000511A0818C0B27047B74923314878897819 +:10CE5000884201D3401A02E02122511A0818C0B2B8 +:10CE60007047B149463148788978884201D3401AE1 +:10CE700002E02122511A0818C0B27047A94910B522 +:10CE80000C310868FF22120290430122D2031043A2 +:10CE90000860A54900202331487088702339487004 +:10CEA0008870463148708870A04808F0C8F89F48DC +:10CEB000401C08F0C4F8F5F741FC00F028F910BD5B +:10CEC00020207047B4E770B50C4605460026FFF7F2 +:10CED000AFFF9549A04214D30A46203A00232046CA +:10CEE000641EE4B200280BD08878105C2870887823 +:10CEF0006D1C401CC0B288702128F0D18B70EEE709 +:10CF0000012600F004F9304670BD202070479BE7F1 +:10CF100070B50C4605460026FFF796FF824923317F +:10CF2000A04214D30A46203A00232046641EE4B2ED +:10CF300000280BD08878105C287088786D1C401C05 +:10CF4000C0B288702128F0D18B70EEE7012600F086 +:10CF5000DEF8304670BD202101700020704710B50A +:10CF60000446FFF77EFF2070002010BD70B50C4610 +:10CF70000546FFF776FF6C494631A04215D30A46B5 +:10CF8000203A00232046641EE4B200280BD08878A3 +:10CF9000105C287088786D1C401CC0B288702128F5 +:10CFA000F0D18B70EEE7002400E0614C00F0AFF8A8 +:10CFB000204670BD70B50C460546212904D9FF20D6 +:10CFC0005CA1473009F02FFA55484068103840B24C +:10CFD000FFF718FFC6B20D20FFF714FFC0B286425C +:10CFE00007D2FF2053A14D3009F01DFA01E0F5F7FB +:10CFF000E8FB21462846FFF766FF0028F7D070BD02 +:10D00000F8B507464948484C401E474E007825462B +:10D0100046362335002806D1A9786878212200F009 +:10D020006BF800280ED0A1786078212200F064F817 +:10D03000002814D0B1787078212200F05DF8002823 +:10D0400028D033E038496878C91C0F546878401CF0 +:10D05000C0B26870212829D10020687026E03249CA +:10D06000607820390F546078401CC0B2607021286D +:10D0700001D1002060702D4F7F1E3878002815D018 +:10D08000A1786078212200F037F800280ED0002027 +:10D0900038700BE02449707826310F547078401CAA +:10D0A000C0B27070212801D100207070A978687812 +:10D0B000212200F021F800281DD0A17860782122DB +:10D0C00000F01AF8002816D0B1787078212200F00C +:10D0D00013F800280FD0F5F756FB144807F0B7FFF8 +:10D0E00001214903884203D016A1C12009F09BF910 +:10D0F0000E4807F0C4FFF8BD401C884205D090429E +:10D1000001D1002901D0002070470120704710B5DF +:10D11000064807F09CFF002801D1F5F723FB10BD5E +:10D1200000ED00E000E400E0800C00207D00002025 +:10D13000072000007372635C736F635F72616E64DB +:10D140002E6300007372635C736F635F72616E6461 +:10D150002E6300000C4908784A78401CC0B2904207 +:10D1600000D008707047094A074820BF40BF20BF61 +:10D170004178037843701368002B02D103788B4207 +:10D18000F3D00020704700007F00002000E200E0A4 +:10D19000FEB5F34C07466068FF213E0181552178BA +:10D1A000FF2913D00901083141583246491E08327F +:10D1B00009020192090A805800F0C8F9002802D03B +:10D1C0002478254615E06168207888552770FEBDD3 +:10D1D000E34842680198115828010090083010581F +:10D1E00000F0B4F9002806D1DD482C4641680098CB +:10D1F0000D5CFF2DECD1DA4821014068855547547C +:10D20000FEBD70B5D64A04460020157A53680AE080 +:10D210000201561C9E5DA64203D10C329A588A42E6 +:10D2200004D0401CC0B28542F2D8FF2070BDF8B5D2 +:10D23000CB4F3E7801F013FE0146FF2E68D034013B +:10D24000254678680835405900F080F9022802D94F +:10D25000786840595AE0C2494868025D0A70A11CCA +:10D26000425C002A0CD0521E425441590122D20580 +:10D2700089180902090A41513046FFF789FF30E059 +:10D28000631CC25C0092221D94468258002A10D072 +:10D2900001239B029A420FD99205920D43595703DD +:10D2A000DB191B021B0A43516346C3589A1A920AA0 +:10D2B00009E0FF21C1540AE0435952039A181202AF +:10D2C000120A4251002242543046FFF761FFA4483F +:10D2D0000C344168C26800980959800012580098BF +:10D2E00090479F4C2078FF2812D001F0B8FD0146EE +:10D2F0002078626800010830105800F027F90128F2 +:10D3000096D92078616800010830085801F09AFD2C +:10D31000F8BDF8B51C4615460E460746FF2B03D34D +:10D3200090A1D32009F07FF88D48FF21C7604560A8 +:10D3300004720674017000224270104604E002017B +:10D34000521C401CA954C0B2A042F8D3F8BD70B51D +:10D35000834C06466578207C854203D381A1E62074 +:10D3600009F061F8E068A90046506078401C6070E0 +:10D37000284670BDFFB581B01D46FF2401F06FFD4A +:10D38000774F064679780198814203D875A1F42039 +:10D3900009F049F872480021037A406810E00A0158 +:10D3A0009446521C825CFF2A24D0019FBA4205D1C8 +:10D3B00062460C328758029A97421DD0491CC9B266 +:10D3C0008B42ECD8FF2C17D021014B1C019AC25480 +:10D3D0000B33029AC250039B614F0022012B0ED0E7 +:10D3E0000B1DC25001239B029D4216D9AA05920D26 +:10D3F00008D008E00C46E1E7FF2005B0F0BD0B1DAA +:10D40000C550EFE71A4653039B190E461B02083618 +:10D410001B0AAA1A8351920A09E0002D00D10125A6 +:10D420006B039B191D022D0A0B460833C550891C3E +:10D4300042543D463E782046FFF7AAFE2878B04287 +:10D4400015D001F00CFD014628786A68000108300B +:10D45000105800F07BF8012807D928786968000186 +:10D460000830085801F0EEFC01E0FFF7E0FE0198FB +:10D47000C3E770B50C46054601F0F1FC06462146AF +:10D480002846FFF7BEFEFF2817D0354D0401204681 +:10D49000696808300858314600F058F8012109033E +:10D4A00040186968A41C095D400B002901D089025D +:10D4B0000818002800D1012070BD002070BDF3B510 +:10D4C00081B00F460198FFF79CFEFF282AD0244D1B +:10D4D0002E7869683246344604E0844205D02646F8 +:10D4E0002301CC5CFF2CF8D11CE0FF2C1AD0A64203 +:10D4F0001FD11001085C2870FF2818D001F0AFFC84 +:10D500002A780146120168680832805800F01EF837 +:10D51000012809D92878696800010830085801F005 +:10D5200091FC06E00020FEBDFFF781FE01E001F066 +:10D5300091FC39460198FFF79CFF22016968FF239F +:10D54000541C0B558A5C3301CA54FEBD401A0002BC +:10D550000121000AC905884200D900207047000057 +:10D56000CC0C00207372635C736F635F74696D65CC +:10D57000722E6300F0B500241C4A01211C4B0803E5 +:10D58000546018601B4B1C601B4C20601B480469D6 +:10D59000E443E406E617046910252C430461184CA3 +:10D5A0006160184D2960761C00E020BF1F68002FC5 +:10D5B000FBD0002E03D107691026B743076190689E +:10D5C0008005906801D5104A10436960A160002170 +:10D5D00019600121084A09031160F0BD10B5044625 +:10D5E000FFF7C8FF2060002010BD000000C500400C +:10D5F00080E100E000C1004080E200E000ED00E0DA +:10D6000000C3004000C0004000FCFFFF70B51F4990 +:10D610000A68002A17D000231D4601244A68521CBC +:10D620004A60092A00D34D600E792246B2400E6846 +:10D6300016420AD072B60B6893430B6062B6496813 +:10D640000160002070BD052070BD5B1C092BE5D377 +:10D650000FA1362008F0E7FEF5E70120104980050C +:10D6600008607047EFF31081CA07D20F72B601212C +:10D6700081400648036819430160002A00D162B660 +:10D68000EBE7024800210160416070478400002000 +:10D690007372635C736F635F6576742E6300000062 +:10D6A00000E200E001208107086070470120810747 +:10D6B000486070471048C068C00700D0012070471C +:10D6C0000D488068C00700D0012070470A484069B3 +:10D6D000C00700D0012070470748C069704706495D +:10D6E0008A69D20306D589698907890F814201D1E8 +:10D6F000012070470020704700040040F8B5F84C46 +:10D70000207BE17A88421CD00126F64D0027E07A82 +:10D71000215C14200A4642435019037C052B11D08A +:10D72000037C062B1CD0037C072B28D0437C012BC9 +:10D7300033D0EDA1EF4808F076FE207BE17A8842F5 +:10D74000E5D1F8BD0674E07A0A2807D0E07A401CDB +:10D75000E072491CC8B2AA5802210CE00020F7E789 +:10D760000674E07A0A2808D0E07A401CE072491C6E +:10D77000C8B2AA5803219047DFE70020F6E70674F5 +:10D78000E07A0A2807D0E07A401CE072491CC8B24F +:10D79000AA580821EFE70020F7E74774E07A0A2843 +:10D7A00007D0E07A401CE072491CC8B2AA58072191 +:10D7B000E1E70020F7E770B50024CF4E0620707235 +:10D7C000CE4825464477047738300473C472CC4879 +:10D7D00007F035FCCB480575F572CB49601E8860B3 +:10D7E0007571B570F57035717570C848643905701C +:10D7F00045701420604340180574641CE4B2052C85 +:10D80000F7D30120F5F764F80020F5F761F801205F +:10D81000B071F4F727FDBE48F4F736FDBD4C20701B +:10D82000BD48F4F731FD6070F4F7F2FF70BD10B53C +:10D83000F5F719F8B74C2078F4F744FD6078F4F761 +:10D8400041FDAD4C207A002803D0F4F7CAFD00203A +:10D85000207210BD70B5A84CA079002804D0A2A1F8 +:10D86000AE4808F0E0FD70BDE07A002803D19EA12B +:10D87000AB4808F0D8FD0126A6710025E572607A54 +:10D88000042114225043974A801801749E488168ED +:10D89000491C04D0691E81600120F5F719F80020A9 +:10D8A000F5F716F8F4F7FAFF07F00AFDF5F7FBF8BD +:10D8B0009C480560056001209B49C0030860F5F79E +:10D8C00071F992480078022804D0032804D1E07846 +:10D8D000002801D0A67000E0A570F5F7D0F870BD63 +:10D8E000034680490520142242435218203A127FF1 +:10D8F000002A04D0401E0006000EF4D17047142206 +:10D90000424351180A46803AD366012220390A77E9 +:10D910007047012805D0032805D1002903D1002034 +:10D9200070470029FBD010B4734C00236370774A12 +:10D93000002890700CD002280AD007291AD20800BB +:10D9400078440079001887441505070D0F1113005E +:10D95000D37003E01B2000E03A20D07001206070FB +:10D9600010BC70475820F8E77720F6E79620F4E7D8 +:10D97000B520F2E710BC0020704710B5634840782E +:10D98000F5F798F880B210BD411E1422504310B52F +:10D99000544A8418203C042902D8207F002803D14F +:10D9A00051A1624808F03FFD207F012804D0B32038 +:10D9B0004DA1800008F037FD0020207710BD70B524 +:10D9C0004E4C607F217F884201D1012500E0002577 +:10D9D000F5F709F8F5F76EF8617F227F914201D1E2 +:10D9E000012100E00021A942EBD170BDF7B5074647 +:10D9F000481E84468EB0C0B2142205905043394A66 +:10DA000085180495287C2D1D07282AD1344C002622 +:10DA1000E07A227B824221D0235C059A934201D195 +:10DA2000012601E0002E04D00A2811D0421CA25C7D +:10DA300022540A280ED0401C227BC0B28242EBD175 +:10DA4000002E0BD0207B002806D0207B401E04E057 +:10DA50000022ECE70020EFE70A202073049A01205F +:10DA600010746046244C042813D8142041431D48E8 +:10DA700008182038007F00280BD00498007C01286B +:10DA80000BD00498007C012803D01098807A0128DC +:10DA900007D015A1264808F0C6FC1098807A012806 +:10DAA0006FD104980F4B007C022845D00C4C207B92 +:10DAB0000A2872D0207BE17A401C884203D10AA157 +:10DAC0001C4808F0B0FC049901204874217B05989B +:10DAD0006054207B0A2864D0207B401C20731CE10A +:10DAE000D80D0020E80D00207372635C72656D2E06 +:10DAF00063000000CF0500006C0E0020A00D002088 +:10DB0000780E0020C00D00204C0E00208E0000205A +:10DB10002FD200008C000020FDD600007D02000006 +:10DB20005E02000000F5004080E200E0CB02000051 +:10DB30001503000022030000607A059A0146904216 +:10DB400006D0014614267043C018807C9042F8D15C +:10DB5000627A824208D1617A14225143C918897CC1 +:10DB600061720121A17207E014224243D2181426E7 +:10DB70007143927CC9188A74142206215043C0183C +:10DB800081741098007A062819D201007944097925 +:10DB900049188F440812100E0C0AE07A00288ED023 +:10DBA00091E700209AE700200FE0B4200DE07320F9 +:10DBB0000BE0322009E00A2007E0062005E0FF2004 +:10DBC000FDA1E03008F02FFC0020029010980168C1 +:10DBD0000298081A28601099097A002912D00221A7 +:10DBE000401A0102090A296010980268406810185A +:10DBF0000002000A68601098807A0228109803D00A +:10DC0000007B74E00421EBE7007A002813D00222A5 +:10DC1000029810188446109842686046083016181A +:10DC2000E848029A4078904202D9E278002A04D06B +:10DC30003046083005E00422EAE7029A801A80198B +:10DC40000830627A062A1CD0627A14235A43DE4BCB +:10DC5000D2185268914214D0DC4B0793617A142297 +:10DC60005143D94A89184A688968D21BC91B1202D4 +:10DC70000902120A090A90423AD89A4238D89942BF +:10DC800036D83818801B0002000A286010996044BA +:10DC9000CF4AC9680002000A9446421A01239B0534 +:10DCA00007929A4201D2104614E00A1A09929A4247 +:10DCB00001D207980EE0079A6346624503D9591AC4 +:10DCC0000818401C06E0099A624506D9181A40183F +:10DCD000401C4042002860DC03E0B7A1BD4808F0CA +:10DCE000A2FB286880190002000A686000202872E0 +:10DCF0006868082608300002000A68601098407AB8 +:10DD0000A8721098007A687203280ED200280CD0EE +:10DD1000FFF7D0FC002803D007E0002011B0F0BDD1 +:10DD200002983A210E1A32200290A6480178012961 +:10DD300001D0032909D141780298814205D9E078C0 +:10DD4000002802D10298081A861928689F4AC01B29 +:10DD5000844601026868090AC01B03021B0A029379 +:10DD60008E421AD81346914217D80299994214D874 +:10DD7000617A062915D0667A6146062203920092DE +:10DD80001422914B7243D2189368DB1B8B4216D836 +:10DD90000396967C062EF3D177E0059801F055F9AD +:10DDA000BBE70499022205980A74627A062A00D019 +:10DDB000627A8A7460720120A07211B0F0BD062EE2 +:10DDC00063D000223146944614227F4B4A43D21836 +:10DDD0005368DB1B834229D2917BAB7A99421FD8CF +:10DDE00004980521059C01747B4D287B0A2811D0DD +:10DDF000287BE97A401C884203D16FA1774808F05C +:10DE000012FB287B2C54287B0A2807D0287B401C37 +:10DE1000287382E7E87A0028EFD0F2E70020F7E7DE +:10DE200001218C46917C0629CED102E06046002873 +:10DE30002AD03546009114202A46424362480621E2 +:10DE4000171839741038007B0A28634816D0017BF4 +:10DE5000C07A491C814203D157A1614808F0E3FA16 +:10DE60005D48017B4554017B0A290BD0017B491C8D +:10DE70000173BD7C0098A842DDD106E0C07A00287D +:10DE8000EAD0EDE70021F3E70096049902204E4D19 +:10DE90000874607AB04207D1049900988874059894 +:10DEA00060720120A07221E00398062E0FD0062890 +:10DEB00003D141A14B4808F0B6FA0398142250430D +:10DEC0004019059981740499009888740EE0062819 +:10DED00003D139A1444808F0A6FA0398142250430C +:10DEE000401905998174049906208874012011B0A5 +:10DEF000F0BD70B50D463D4A441900210B46101A7D +:10DF00008B4103D22CA13A4808F08DFA394885425A +:10DF100003DD29A1384808F086FA3848854203DA3B +:10DF200025A1374808F07FFA3648844205DA002CEC +:10DF300001DB204670BD334800E03348201870BD37 +:10DF4000401E70B5C0B2142148431F494418607B7D +:10DF5000062813D201007944097949188F44020C2C +:10DF60000A080604002068E0B42010E073200EE0E8 +:10DF700032200CE00A200AE0062008E0FF200EA173 +:10DF8000E03008F050FA617B0020002955D00221D2 +:10DF90004018616840180002000AF4F78BFD0C2558 +:10DFA0006557124A441900210B46101A8B412FD293 +:10DFB00001A10F482AE000007372635C72656D2E48 +:10DFC000630000008E000020E80D0020FFFF3F00EE +:10DFD000FFFFFF000E070000D80D00200702000021 +:10DFE000C5030000DD030000E3030000FF7F841E83 +:10DFF000F50300000020A107F603000000E05EF832 +:10E00000F70300000080841E00807BE108F00BFA1B +:10E01000FB48854203DDFB49FB4808F004FAFB4856 +:10E02000854203DAF749FA4808F0FDF9F9488442D5 +:10E0300007DA002C03DB204670BD0421A8E7F54871 +:10E0400000E0F548201870BDF0B5064683B0F348EF +:10E050000190457A029534687068001B0702F04809 +:10E060003F0A001B0090062D2DD014202946414365 +:10E07000EC480122081884464168E9489205864622 +:10E08000081B904210D3631A93420DD30246704688 +:10E09000724503D900984018401C05E073450ED91D +:10E0A000411A0819401C404200280CDA60460295CB +:10E0B000857C0198C0790028D5D003B0F0BDD14946 +:10E0C000D94808F0B0F90298854226D01421484377 +:10E0D000D4490123401802908068D1499B058C46A1 +:10E0E000011B8646994210D3221A9A420DD36346E9 +:10E0F000614503D900997144491C06E019466245FF +:10E100002DD9091A0819401C4142002905DD029841 +:10E11000B17A807B814200D37446062D15D0C14967 +:10E120001420454368184268121B1202120ABA42B0 +:10E130000BD2B37A827B934200D38468857C0198AA +:10E14000C0790028B9D1062DEAD13068A042B4D0F8 +:10E15000E0190002000A3460706003B0F0BDA94904 +:10E16000B14808F060F9D8E7F0B5B049044648680E +:10E1700085B0C005C00D1CD0103840B200280CDAA4 +:10E180000207120F083A920892005118C9698007D5 +:10E19000C00EC1400806800F09E08108A44A89002A +:10E1A000891809688007C00EC1400806800F002842 +:10E1B00008D000272078002806D0012804D00020AD +:10E1C00005B0F0BD0127F5E72079062813D201003C +:10E1D0007944097949188F44020C0A080604002082 +:10E1E00018E0B42010E073200EE032200CE00A208A +:10E1F0000AE0062008E0FF208249E03008F013F929 +:10E2000021790020002905D002214618834D002FD6 +:10E2100002D003E00421F8E70020E871694602AA71 +:10E22000A068F4F751FC694608228A56E06801A903 +:10E2300080180122C01C1F2801DA019209E003AAFC +:10E24000F4F742FC6846007B002802D00198401C8D +:10E25000019000990198401808300002000A0190CE +:10E26000881B0002000A0090607969468872009855 +:10E270000390F4F7B8FB009A019B121A181A6D4923 +:10E2800012020002120A000A8A4216D8884214D8E2 +:10E290006846FFF7D9FE00990398814205D0881996 +:10E2A0000002000AF4F706FCA0600120E9790029C9 +:10E2B00086D0002FB0D005B0F0BD0020F6E7F3B552 +:10E2C0008FB05D480C460B9006F0C1FE5B4A0F997B +:10E2D000524F56185A4D203E00280BD05948007D09 +:10E2E000002803D058A15B4808F09DF82078012849 +:10E2F0007ED060E1687F0A280CD0687F297F401CAF +:10E30000884203D150A1544808F08DF820780128A4 +:10E3100004D00CE0287F0028F4D0F7E7F07F002835 +:10E3200003D049A14D4808F07EF80120F077697FBD +:10E330000F9814224A4E51438919087420780228F4 +:10E3400022D0687F14214843861920793072607981 +:10E35000707232460C323146A068F4F7B5FB0C20DF +:10E3600030560F2804DD1F3830733068401C306091 +:10E370000C217156301DE26801905018C01C1F28F6 +:10E3800070DA01200199FDE028494868C005C00DF8 +:10E3900021D0103840B200280CDA0207120F083AD8 +:10E3A000920892005118C9698007C00EC140080642 +:10E3B000800F09E081081E4A8900891809688007D2 +:10E3C000C00EC1400806800F002804D105201EA100 +:10E3D000000208F028F8687F1421484386190021BC +:10E3E000E0686A460691117006A9F4F76DFB00E03B +:10E3F000D7E06A46002010560F2834DD012033E0B4 +:10E400000020A107B8DF0000F603000000E05EF87E +:10E41000F70300000080841E00807BE16C0E00206A +:10E42000FFFFFF00E80D00200E07000000ED00E0F8 +:10E4300000E400E0FFFF3F00780E00209200002083 +:10E44000A00D0020C00D00207372635C72656D2EFC +:10E450006300000011050000EF040000F404000058 +:10E46000E00C002082E0002006994018079002206E +:10E47000B0722079307260797072A068311DC01C52 +:10E4800006911F2801DA012009E0F4F71DFB684618 +:10E490000078002804D0069806990068401C08609F +:10E4A000307A062813D201007944097949188F443B +:10E4B000020C0A08060400200FE0B4200DE07320CF +:10E4C0000BE0322009E00A2007E0062005E0FF20EB +:10E4D000FD49E03007F0A7FF00202179002943D053 +:10E4E00002214018069071680830081807990890B2 +:10E4F00009180698081A0C900020F871F4F773FABE +:10E5000004463060079820180002000AF060787A0C +:10E51000062825D0797A14204143EC480818406831 +:10E520000899029040180002000A0390707A694628 +:10E53000887402A8FFF788FD0299039A091B121B31 +:10E5400009021202E24B090A120A0C98994207D8F2 +:10E55000824205D80299069808180002000A306025 +:10E56000F8790028C8D110E00421BAE704AA01997B +:10E57000F4F7AAFA6846007C002804D001980199B3 +:10E580000068401C08602078B072687F0A2806D0B6 +:10E59000687F401C68770B9806F071FD47E000200B +:10E5A000F8E7F07F002804D0A320CAA1C00007F03C +:10E5B0003AFF0120F077CA490F98087420780228A2 +:10E5C00003D1C4A1C74807F02EFFC54E2079307291 +:10E5D0006079707232460C323146A068F4F774FAF2 +:10E5E0000C2030560F2804DD1F3830733068401C73 +:10E5F00030600C22B256301DE16801908818C01CB2 +:10E600001F2802DA012001990BE003AA0199F4F70F +:10E610005BFA6846007B002804D0019801990068E5 +:10E62000401C08602078B072AD4901200875687FF1 +:10E63000297F884224D07C7A062C23D0F4F7D3F9A2 +:10E6400014214C43A14961180A7C042A18D00A7C81 +:10E65000032A15D04B6889681B1A081A1B0200028E +:10E660009B4A1B0A000A082B0AD31146934207D87B +:10E67000884205D8687F297F884201D0F4F7FFF9E6 +:10E6800011B0F0BD687F297F8842F7D111B0F0BD8D +:10E6900010B50020F4F709F910BD10B50120F4F70A +:10E6A00004F910BDF1B5009802281ED08E4C607A96 +:10E6B000062803D187A18D4807F0B5FE0026A67174 +:10E6C0000125E572607A03211422804F5043C0195E +:10E6D0000174F4F7D9F9009800280BD0012829D04B +:10E6E000032879D07BA1824844E082480078F3F780 +:10E6F000EFFDF8BD8048007F002803D075A17F485A +:10E7000007F091FE65717C4D00202E60F4F7E0F873 +:10E71000A968481C04D0012300221846F4F70EF91A +:10E72000607A617A401CC0B2142251437A580121A8 +:10E730009047F8BD0120F4F7CBF8607900280DD0A0 +:10E740006D488068401C09D0607A617A401CC0B274 +:10E75000142251437A5806219047F8BD6648007F3D +:10E7600001280AD0022812D0032822D0042834D04D +:10E7700058A1634807F057FEF8BD2079002803D060 +:10E780002671F4F786F9E5705B480677F8BD207AC4 +:10E79000002802D1F3F7FCFD2572607A617A401CF3 +:10E7A000C0B2142251437A5800219047524806774C +:10E7B000F8BD514F0123397B78680022411A184671 +:10E7C000F4F7BCF82079002803D02671F4F761F93A +:10E7D000E57002203877F8BD19E0474E217870685F +:10E7E0000123411A00221846F4F7A8F8207A0028DD +:10E7F00002D1F3F7CDFD2572607A617A401CC0B278 +:10E80000142251437A58002190473577F8BD607A39 +:10E81000617A401CC0B2142251437A5805219047B6 +:10E82000F8BD10B5304C607A062803D129A13548CF +:10E8300007F0F9FD607A617A401CC0B2142251439E +:10E84000224A52580421904710BDF0B583B00620EB +:10E850000290F4F7C8F8244C0090617A2A4801909D +:10E86000062920D0617A1420414318480918097CF0 +:10E87000042918D0617A142251430818007C032817 +:10E880007BD0019900980B6849681B1A081A1B0273 +:10E8900000020F4A1B0A000A082B6ED3114693424E +:10E8A0006BD8884269D814488068401C03D009A1FD +:10E8B000164807F0B8FD00206071607A06282CD158 +:10E8C0006078002829D023E0B8DF0000E80D0020A0 +:10E8D000FFFF3F007372635C72656D2E6300000082 +:10E8E000C00D00201E0500006C0E00204F0500002A +:10E8F000A20500008C0000204C0E00205B050000EB +:10E9000096050000A90500005C0E0020E50500004A +:10E91000FE48C178417081780170607A062815D070 +:10E92000607A1421FA4A48438018007C04280DD1EB +:10E93000607A0290607A0121142358438018017490 +:10E94000607A58438018807C6072A172F14D687FB4 +:10E95000297FF14F884233D0F04E287F142148435D +:10E960008019007CC05D0128287F07D048438019AA +:10E97000007CC05D02282FD044E0FDE11421484313 +:10E980008019807A01280AD0287F0221142250435E +:10E990008019007CC155287F0A2808D009E0287F0B +:10E9A0000021142250438019007CC1552AE0002028 +:10E9B00001E0287F401C2877687F297F8842CCD1DE +:10E9C000D74D287D00284CD0287CC15D012928D056 +:10E9D000C05D022830D03AE0287F142148438019D6 +:10E9E000807A012803D0CFA1D14807F01CFD297FF0 +:10E9F00000201422514389198872297F51438919B3 +:10EA0000097CC855287F142148438219287F484330 +:10EA10008019017C0098FEF7E9FF287F0A28C8D1F9 +:10EA2000C5E7A97A012904D00221C1550020287523 +:10EA30000DE00021C1550AE0A87A012803D0B9A150 +:10EA4000BC4807F0F0FC0020A872297CC855287D3E +:10EA5000002806D0297CB24A0098FEF7C7FF0020A4 +:10EA60002875029806281ED014214843A84940184A +:10EA7000017C012917D107210174AF4D287B0A2899 +:10EA80003CD0287BE97A401C884203D1A5A1AB4841 +:10EA900007F0C9FC297B02986854287B0A2831D0EA +:10EAA000287B401C2873607A06287DD0A07A002835 +:10EAB0007BD00020A072617A1420414394480E1844 +:10EAC0009F49B56873680A46F6687C32CB679660E2 +:10EAD00055609C4D697E002916D00226617A142269 +:10EAE0008B4851430818407B06281BD2010079440B +:10EAF000097949188F440A1412100E0CE87A00287C +:10EB0000C4D0C7E70020CDE70426E7E700210FE0E7 +:10EB1000B4210DE073210BE0322109E00A2107E066 +:10EB2000062105E0FF208849E03007F07CFC002149 +:10EB30002973687E022801D0012810D12869009A23 +:10EB40004018821A1202120A3A2A08D932380321CE +:10EB500000026976000A28613220287308E0322911 +:10EB600006D2207A00280AD1F3F712FC012005E032 +:10EB7000207A002803D0F3F734FC00202072634988 +:10EB80000822487820700978012901D0032906D18C +:10EB900001212171297B884201D9421A0832A378C8 +:10EBA000002B00D0921C01E08DE09BE02179002930 +:10EBB00001D1002B5DD09446644A00990092019ADD +:10EBC000176852687F1A511A3F0209023F0A090A60 +:10EBD000BC451BD85D4A974218D8009A914215D877 +:10EBE000297B884223D92B69421A9A1A1202120AE7 +:10EBF000101880190002000A2A616860002914D0E8 +:10EC0000032028770006000E3ED14CE00020207142 +:10EC1000A070297B002925D028694018801900029E +:10EC2000000A6860022028772EE00120E9E781428F +:10EC30000BD92A69511889190902090A6960002843 +:10EC400001D00420DDE70220DBE7002B03D135A152 +:10EC50003F4807F0E8FB286980190002000A686055 +:10EC6000002004E0296989190902090A69602877E6 +:10EC700019E0287B00280FD02969081880190002A4 +:10EC8000000A686002202877286901238119002280 +:10EC90001846F3F753FE09E0286980190002000ABC +:10ECA0006860002028770120F3F712FE607A1421B3 +:10ECB000484317490C2240188256012300206968F6 +:10ECC000F3F73CFE0EE00120F3F702FE0020F3F71D +:10ECD000FFFDF3F7E3FD207A002803D0F3F781FB73 +:10ECE00000202072A078002804D0F3F7D2FE002084 +:10ECF000E070A0706078002804D00448C1784170AA +:10ED000081780170207900282BD023E08E0000202C +:10ED1000E80D0020A00D002091000020E00C002054 +:10ED2000C00D00207372635C72656D2E630000007D +:10ED30000706000023060000D80D0020350600005D +:10ED4000E00D00204C0E0020B8DF0000FFFF3F0068 +:10ED5000870600000020CF49E0700978002900D123 +:10ED60002071CD48017BC07A814203D0CB484078E6 +:10ED7000F3F7AEFA0120E07103B0F0BDF0B5C84C76 +:10ED80000746607A83B0062803D1C6A1C84807F0B9 +:10ED90004AFB607A1421C74E48438019007C03283F +:10EDA00003D0C0A1C44807F03EFBC44DA868401C76 +:10EDB00003D0BCA1C24807F036FB607A1421484357 +:10EDC00081190C20085600216A4600911171C01962 +:10EDD00001AA6946F3F778FE6A46042010560F2808 +:10EDE00001DD012000E0002000994018696840180A +:10EDF0000102090AA9606079002804D001230022D9 +:10EE00001846F3F79BFD03B0F0BD70B5AE4CAD4AAC +:10EE10000B1AA34214D3451AA54211D3934203D926 +:10EE2000101A43185B1C0BE0954204D9511A0818BC +:10EE3000401C434204E0A549A54807F0F4FA00232A +:10EE4000184670BD10B50146012300220220F3F7D9 +:10EE500075FD10BD10B50220F3F73AFD10BD10B5D9 +:10EE6000F3F7C1FD10BDF0B58D4D0446E87A83B0CF +:10EE7000002803D18BA1974807F0D5FA642C4DD315 +:10EE8000954900200246091B824147D39348417FA0 +:10EE9000007F814242D19248007D00283ED1687AAD +:10EEA0001421844F4843854EC519306801AA0019C2 +:10EEB0006946F3F709FE694604200856002802DD7A +:10EEC0000098401C0090A96800986B680A18D21A34 +:10EED0001202844B120A9A4220D8AA7C062A08D031 +:10EEE00014235A43D2195268511A0902090A81425D +:10EEF00014D3B068401C05D00120F3F7E9FC0020D2 +:10EF0000C043B060306800193060A86800994018AC +:10EF10000002000A7061012003B0F0BD002003B0C0 +:10EF2000F0BDF8B50646401EC5B2142061496843DD +:10EF30004418207C002803D15AA16B4807F073FACB +:10EF40006648017F407F81420CD0684A14234B43BE +:10EF50009B181B7CB3420CD00A290CD0491CC9B2A7 +:10EF60008142F3D15E48017D002964D0007CB0422B +:10EF700061D10020F8BD0021F1E7217C052905D0F1 +:10EF8000217C062902D0217C072928D10121217466 +:10EF9000C17A0023027B8A4221D00246565CAE42EF +:10EFA00001D1012301E0002B04D00A2911D04E1C0D +:10EFB000965D56540A290ED0491C167BC9B28E4262 +:10EFC000ECD1002B0BD0117B002906D0117B491E00 +:10EFD00004E00026ECE70021EFE70A211173617CD1 +:10EFE00000292AD06774C17A0023027B8A4224D088 +:10EFF000425CAA4201D1012301E0002B04D00A297E +:10F0000012D04A1C825C42540A290FD0491C027B50 +:10F01000C9B28A42ECD1002B0FD0027B0146002AF4 +:10F0200006D00A7B521E04E00022EBE70021EEE747 +:10F030000A220A7301E018480027217C01299CD18B +:10F04000617C002999D10120F8BD70B505461420D6 +:10F05000184A05216843801801740F4C207B0A2848 +:10F0600011D0207BE17A401C884203D11749204807 +:10F0700007F0D9F9207B2554207B0A2807D0207B74 +:10F08000401C207370BDE07A0028EFD0F2E700202A +:10F09000F7E700008E000020D80D00208C00002033 +:10F0A0006C0E00207372635C72656D2E630000004D +:10F0B000EA060000E80D0020EB0600004C0E0020E0 +:10F0C000EC060000FF7F841E0020A107B8DF0000CF +:10F0D0000E0700002D070000FF1FA107A00D002054 +:10F0E000C00D0020FFFF3F006A070000E00C002079 +:10F0F0000702000070B5FF4D00246C702C70AC61ED +:10F1000000F0CEFC284620304470C473AC6214304A +:10F110002C6305F094FF002804D0FF20F6A14E30A8 +:10F1200007F081F92C7770BD0B23DB4310B5C21AB1 +:10F13000F54998421FD008DC1C3222D00A2A20D080 +:10F14000142A1CD0182A08D117E0083011D004283E +:10F150000DD0082809D00C2805D0FF20E6A1753075 +:10F1600007F061F910BD04200CE000200AE0FC204B +:10F1700008E0F82006E0F42004E0F02002E0EC20B3 +:10F1800000E0D820C86010BD70B50125DF49022617 +:10F190000E60DF490022CA63CD63DE49C96A0907F0 +:10F1A0000ED4DC494031CB6ADB4A53620B6B93626D +:10F1B0004B6BD3628B6B1363C96BD30519435163DC +:10F1C000D14C002826D0012828D0FF20CAA1A13088 +:10F1D00007F029F9D148A063FF200430606325635C +:10F1E00003202061C849962040314860C1491C2055 +:10F1F0000856FFF799FFCB49C9488860C948CA49F2 +:10F2000080304160C9490160C9480660C949102081 +:10F21000486070BDC8486061C84803E0C848606184 +:10F22000C648801FA061D5E770B50C46B14D0146B8 +:10F230000622A81C06F079FF2C7270BDAD48203064 +:10F2400040787047AB4A517010707047F8B504466B +:10F250000D465079117900020843690009190884A4 +:10F260001F461646501C06F0C1FF317800020843C5 +:10F27000A90060502846083001268640002F0ED095 +:10F28000012F04D0FF209CA1E83007F0CCF8206BC0 +:10F29000304301460120A84001432163F8BD206BA3 +:10F2A000B043F6E770B50D460446082904D9FF209F +:10F2B00091A1F93007F0B7F80022A24809E09100C7 +:10F2C000635809180B6053001B191B8C0B62521CEE +:10F2D000D2B2AA42F3D3206B9A494031086070BD84 +:10F2E00010B50446FFF720FF8248047710BD81481F +:10F2F0002030007B704710B5834CC178616206F006 +:10F3000075FF0002E06110BD252808D0262808D02E +:10F31000272808D041000A2807D8091D06E0022145 +:10F3200005E01A2103E0502101E0891DC9B2764AA7 +:10F33000916075494031486170476E4988617047F6 +:10F3400070B5002818D002226A4C784B0320A272B4 +:10F35000F0331860734D72486860002001262075F4 +:10F3600000290BD0012910D002291BD0952062A1C1 +:10F37000800007F058F870BD0122E5E77248012AC5 +:10F3800001D0466070BD066070BD5A48012A006B0E +:10F3900005D00121490508432063696070BD012142 +:10F3A0000905F8E7A069002803D153A1674807F0D1 +:10F3B0003AF8A169A06A40186549886059486549CA +:10F3C0008030816060491031C1600120216BC00331 +:10F3D00001432163686047482030C67370BD08B59B +:10F3E0000C20694608705148002110380161564AC6 +:10F3F000012111610BE000BF00BF00BF00BF00BFD3 +:10F4000000BF00BF00BF6A461178491E11706946EF +:10F410000978002902D001690029ECD068460078FB +:10F42000002804D1494834A1203006F0FCFF08BD73 +:10F43000F8B53E4CF034206886083E48B600416876 +:10F44000C906CD0F10218160002727603549344857 +:10F450008860FFF7C4FF35481038076100F020FBD3 +:10F460002660002D02D0334910204860F8BD10B549 +:10F4700006F0BCFE00022449000AC86310BD2349FF +:10F48000022008602A49086070472049022080391C +:10F4900008607047304908707047164810B534301E +:10F4A00005F0D5FD002804D0284813A15A3006F0F5 +:10F4B000BAFF10BD0F4810B5343005F0E0FD10BDA7 +:10F4C00011494860704770B50A4D0446A86AA042C9 +:10F4D00004D31E4808A16B3006F0A5FF0120287355 +:10F4E0001C49002008392C6148601948446000F02C +:10F4F000DEFA70BD7C0E00207372635C68616C5F25 +:10F500007263732E630000000015004080E100E08C +:10F51000C01F004080000010001700405B06000084 +:10F520000040000400F50140408000401011004000 +:10F5300080E200E000130040060102002500030203 +:10F5400005010300001600400010004047020000C3 +:10F5500040850040488100409700002010B5FF48DA +:10F5600002210173C6210161FD4A00215160806AB8 +:10F57000FC49C630486000F09AFA10BD0121FA48F3 +:10F5800089058160F548026B8A430021026301739B +:10F590007047F64801214160C160F1490020486090 +:10F5A000F0494860ED4988627047F149402008629F +:10F5B000F0490A6802430A607047EE480168402239 +:10F5C00091430160EA49002008627047E9480168F8 +:10F5D000102291430160E849012088617047E749A2 +:10F5E0000020C861E34801681022114301607047A0 +:10F5F000E249CA69012A01D000207047DC4A9268BA +:10F600005206520E524202700020C861012070471B +:10F6100070B5D248D24D017B002902D0696801291A +:10F6200009D00024D5490A69012A06D00023807A2E +:10F63000012804D006E00124F4E74023F7E7CA6874 +:10F64000012A04D000221A43012802D004E020221B +:10F65000F9E74B68012B05D000231343C84A022861 +:10F6600002D007E01023F8E71668012E02D1CE6819 +:10F67000012E04D000261E43022802D007E00826EF +:10F68000F9E71268002A02D1CA68012A04D00022D0 +:10F690003243022802D005E00422F9E7002C01D011 +:10F6A000022300E000231343022807D14868012801 +:10F6B00004D16868012801D0012600E00026B14885 +:10F6C0001E4302681206120E02D04A69012A00D0B7 +:10F6D0000022A24C2034227300680006000E02D0E3 +:10F6E0008869012800D000206073A148006A0028C2 +:10F6F00003D000F0A8FA012800D00020A07300F089 +:10F70000C7F9002068603046F3E670B50C00054686 +:10F7100003D19D499D4806F086FEE00706D0012CE6 +:10F7200004D06D209849C00006F07DFE002D0ED05B +:10F7300002218A4801294172C4728E4809D00229E7 +:10F740000AD0924890491A3006F06DFED1E60121A8 +:10F75000EFE70168042201E001680822114301601B +:10F76000C7E670B57D4C0022E37A990701D54107C1 +:10F7700014D47A49DD062031002D05DA4D7B002DA9 +:10F7800002D08D7B002D09D01D0702D50D78002DEC +:10F7900004D15B0703D54978002900D10122637A9F +:10F7A0007449002B06D00225284010430CD0FFF7E7 +:10F7B0003FFE9EE66C4A76489060086880088000AC +:10F7C000086000F06DF994E6012B07D0022B0ED0F3 +:10F7D0006E486D496B3006F026FE8AE60868042202 +:10F7E0009043086000F05CF90120A07281E608688F +:10F7F00008229043086000F053F9A57279E6574952 +:10F8000008757047F8B5554F544D2037FA7B564C64 +:10F810000021286B002A31D00122D203A26090433C +:10F820002A46544D10632E685A4A102090600020DA +:10F8300028601014A060FFF7D2FD00F029F92E60B7 +:10F84000281460605349102048604448817A4A482F +:10F8500001290DD002290ED04C484FA1801F06F07F +:10F86000E2FD0020F8733D48007D022874D0F8BD09 +:10F8700001210160F5E701214160F2E73A4A906019 +:10F880000E462963FFF7C4FE044636482E754168CC +:10F8900069620068A862AA7A022A0AD16A78002AF4 +:10F8A00007D0334B403B5B681B7813402A789A4360 +:10F8B00008D03E70E20708D0084603F04AFD012157 +:10F8C000A86A09E001223A70F4E7A10601D50221F5 +:10F8D00002E0A10702D5002103F04BFD2448403887 +:10F8E00041680622A81C093106F0F2FB002809D164 +:10F8F0001F48297A403840680078C009814201D108 +:10F90000012000E0002078702046FFF72AFF2648FB +:10F91000007800280DD001284AD002285BD00328A7 +:10F9200078D01DA1214806F07EFDA87A022870D06B +:10F93000A3E0A00701D502F0EDFB200702D50120CE +:10F9400002F020FC600702D5002002F01BFCA0069C +:10F95000EBD502F07CFBE8E793E000007C0E002092 +:10F96000408100404085004000F50140008000409B +:10F9700040150040001200400010004000110040FF +:10F980000014004040160040F8F40000630300003B +:10F9900000400004001300407372635C68616C5F98 +:10F9A0007263732E6300000097000020E6040000DD +:10F9B000A00701D504F0BBFF200702D5012004F009 +:10F9C00021FF600702D5002004F01CFFA006ACD583 +:10F9D00004F0A4FEA9E7A007BF27002802DA3C40F4 +:10F9E000F3F702FB200703D53C400120F3F7FBFAB5 +:10F9F000600703D53C400020F3F7F5FAA00602D5D6 +:10FA00003C40F3F7EFFA60068FD5F3F7EEFA8CE798 +:10FA100000E012E0A00701D5F3F7EAFA200702D5CB +:10FA20000120F3F7E4FA600702D50020F3F7DFFACC +:10FA3000A00690D5F3F7DAFA77E7287B00281CD0E8 +:10FA40001F494E6002281FD0012803D01D491E48BF +:10FA500006F0E9FCA96A2869884204D81A481949BD +:10FA6000401C06F0E0FC2969184841600120296B20 +:10FA700080050143296316494860287D012800D08C +:10FA8000F5E6F3F7C5FAF8BD2969A86A4118EBE76E +:10FA900010480021C160016141604161816170478E +:10FAA0000D480021417281720121C17270470A48DC +:10FAB0000121026B89050A430263054841607047D2 +:10FAC0004081004098F90000FB04000040850040A0 +:10FAD00000F50140001100407C0E00202E4800215E +:10FAE00001704170704770B5064614460D460120FE +:10FAF000F1F758FC28490120284B08709E60DC6013 +:10FB00001D6170BDF8B504460120F1F74BFC224998 +:10FB10000120087021494C60214900264E600321D4 +:10FB2000204D0906A960204F002C0AD0012C03D0DB +:10FB30001EA1412006F077FC3E60032000066860AD +:10FB4000F8BD386001200006F9E710B512480178C9 +:10FB500000290ED00321134A0906916010494A6812 +:10FB60000021002A03D0154A1268427000E041705B +:10FB700001700020F1F716FC10BD0748017800293C +:10FB800007D007484068002802D00C480068C0B27F +:10FB900070474078704700009800002000F5004052 +:10FBA00000F1004000F5014000F200407372635C18 +:10FBB00068616C5F63636D2E6300000000F40040B9 +:10FBC0003A4800210170417010218170704770B572 +:10FBD000064614460D460220F1F7E4FB01203349A6 +:10FBE000334A0870E41E14619660556070BD10B50C +:10FBF0000220F1F7D7FB2D49012008702D48002184 +:10FC000001604160816001202B49C005486010BD42 +:10FC100010B5264C2078002811D001202649C005B7 +:10FC2000886000F034F80021002804D001206070C2 +:10FC30002248006801E061701020A070217000204F +:10FC4000F1F7B0FB10BD10B51848017800290BD0B2 +:10FC500018480068002805D000F019F8002800D0E6 +:10FC6000012010BD022010BD407810BD10B50F4816 +:10FC70000178002909D000F00AF8002803D00F48C5 +:10FC80000068C0B210BD102010BD807810BD0948BA +:10FC90000168002905D04168002902D08068002849 +:10FCA00001D0002070470120704700009A0000201A +:10FCB00000F5004000F1004000F5014000F4004074 +:10FCC000FFB593B0044600201D9E049015981C9D1E +:10FCD0001027082806D0E06901F014F8002809D0A0 +:10FCE0003770CCE028880921384328801F980227E4 +:10FCF000017016E0E169012088710521E269C902FD +:10FD00009180E1698872E169F9480881E169002020 +:10FD10008873288820210843288011211F980427F0 +:10FD200001701F980225801C0390307810900A20E3 +:10FD30003070204618301190F6F76BFC00206FE011 +:10FD40001598102809D1022D07D06846828A049997 +:10FD50000398401A8270110AC1706846C08A1699C9 +:10FD6000884203D9E349097A149106E0884204D114 +:10FD70001099002901D0317021E003990870000A20 +:10FD800048701E980088401BC01B83B2FF20C01B18 +:10FD9000984200D203460398149AC0190CA9009205 +:10FDA000019002912020015D6846C08A0022F6F78A +:10FDB000A5FC3070002806D0C0B2832862D0684607 +:10FDC000C08A208345E00F98002805D0C948006804 +:10FDD00000790A2830D33CE06846008EC119C9B2C8 +:10FDE0000491022D0FD01F99049A4978914203D1B2 +:10FDF0006A46128C824209D0BE480491006801789C +:10FE0000032909D027E008461F994870B9480068BF +:10FE10000178042906D008E000790A281BD20120C5 +:10FE20000F9009E06946C98A8180039904980818EF +:10FE300003900498281885B205AA14991198F6F72A +:10FE4000EBFB002805D11E980088401BB84200DB60 +:10FE500076E7022D0ED01598102807D1049A039941 +:10FE60006846808A891A8870000AC8701E980580C2 +:10FE7000002030709F4800680078032802D00020DE +:10FE800017B0F0BD0220FBE7F8B50446406B002632 +:10FE9000134600282BD0491F8DB2618F2A460832A5 +:10FEA000278F8A18BA4221D89A7840185F781102B1 +:10FEB00039430170090A41701A79DF781102394318 +:10FEC0008170090AC1700571290A41712A46591DBC +:10FED000801D06F02AF9608FAD1D401980B2608741 +:10FEE000626B002110180170417000E00926304655 +:10FEF000F8BD30B50B88048F9C4212D9446BE018D2 +:10FF00004478057824022C430BD0447905792402E7 +:10FF10002C436404640CA41D1B190B80106000208A +:10FF200030BD822030BDF7B588B000256846058217 +:10FF300005275DE00398417802780E021643417967 +:10FF4000027908021043000452D40A980123068063 +:10FF500005A802905B02002200970195304609999E +:10FF6000F6F7CCFB04004AD16846018A0183039866 +:10FF70004179027909021143437802781C02144343 +:10FF8000B4421ED10A041CD44B0401215B0C89032A +:10FF900000950B4301970295C17880780A020243CD +:10FFA00020460999F6F7C6F9040011D1039948795A +:10FFB0000A79000210430122D20310430871000A9B +:10FFC000487103AA06A90898FFF793FF0400CED052 +:10FFD0000399009501970295487809780002084333 +:10FFE00069468B8A00220999F6F7A4F9822C06D17A +:10FFF00003AA04A90898FFF77CFF04009AD068467A +:020000040001F9 +:10000000058209E003984179027909021143490404 +:10001000490C0171090A417103AA04A90898FFF764 +:1000200068FF0028EED0822C02D020460BB0F0BD35 +:100030000020FBE730B50446406B002597B0002850 +:100040000DD00B2268460270228F0281606B0391F3 +:10005000019000216846F3F7E2FA6846057065638F +:100060006587258717B030BDF8B50F460546696B23 +:100070000020069E144600290FD0012B0DD13246D8 +:1000800039462846FFF74FFF002806D1002C04D040 +:1000900032463946284600F044FEF8BD0022028070 +:1000A000C262831D0263C3614263428702872030BC +:1000B0000170704710B50022D24302800420FDF782 +:1000C000FEF910BD10B596B00446FFF7B3FF208EC1 +:1000D000002808D0012069460870E06A01900021DC +:1000E0006846F3F79CFA0020E062206316B010BD6A +:1000F00001280000B40E00200146098800200A07EC +:1001000000D501200A06120F01D002221043CA05B1 +:1001100001D5042210438A0501D510221043490558 +:1001200001D5202108437047FFB5A9B00600329DD4 +:10013000359C2B981F46229016D0007841060FD48C +:100140008106890E1E2909D021884A05520E0BD13D +:100150003A88172A08D3FE4A914205D0C10906D031 +:100160008006800E122802D003202DB0F0BD20465C +:100170002C302690F7492A980872002018AA03907C +:1001800010726A46107404AA0A60339A4A6020AA60 +:10019000908090812298007801908106681C1C90C4 +:1001A000701F1D902B98890EC21C2492224620326B +:1001B0001B92083A401C02920B0006F025FA1FFD24 +:1001C000FD11FD1FFD8EFDFCFDFBFDFAFDF9FDFCA3 +:1001D000FDF8FDFDFDF7FDF6FDFDFDFDFDF5FD0066 +:1001E000032E76D102E018A9087219E303202870C3 +:1001F0001C9917220A7000224A70CFE2052EF0D116 +:100200004178027808021043208320A98880249A2C +:100210005178127809021143618300287ED0884208 +:100220007CD800202072E080401E60840298F6F79F +:10023000F0F905202870A81C0190022000901BAA4C +:100240002A990298F6F7E8F9002868D118A8807C66 +:10025000012803D002206870102002E0012068709D +:1002600002202490002225A91CA8F2F746FD0028B0 +:100270002BD120A8007D2499814226D13A8800996B +:10028000801C511A814220DB10A8C18D0198017099 +:10029000090A417001991CA8891C01910099019AD1 +:1002A000891C009125A9F2F728FD20A8007D01995D +:1002B0001BAA091801910099081880B200902A9988 +:1002C0000298F6F7A9F90028CCD00098022826D089 +:1002D00064E272E018A9087261E2072E6DD34178DA +:1002E0000346027808021043208320A98880249ABC +:1002F0005178127809021143618300280ED0884298 +:100300000CD8012020725879197900020843E08046 +:1003100000202073E06900F0F5FC01E098E0A9E01E +:1003200000280ED1E169012088710521E269C90226 +:100330009180E1698872E16987480881E16900205C +:100340008873F01F60842298C01D60620298F6F7DF +:1003500060F907202870681C00900120019000209F +:1003600010A9C8852FE00198012814D0E069807990 +:10037000012830D000981E38417F007F09020143D8 +:1003800000980170090A41700098801C0090019843 +:10039000801C80B2019010A8C18D00980170090ADC +:1003A00041700098801C09E00AE296E13BE1DFE041 +:1003B00004E29BE077E036E016E2AFE000900198BF +:1003C000801C80B201901BAA2A990298F6F724F9A2 +:1003D000002803D007E010A8818DD1E73988019863 +:1003E000081A0428BFDA0198012843D0E06980790F +:1003F000012804D010A8818D5548814206D110A84B +:10040000818D00980170090A417009E000981E383A +:10041000417F027F0802009910430870000A48706B +:100420000198801CBAE1072E01D0152E76D14178B3 +:10043000027808021043208320A98880249A5178EA +:100440001278090211436183002801D0884201D942 +:1004500001203FE7012020720020E0802073052E5C +:100460000AD01D982299E269C0B2491DF2F71FFC1B +:10047000002801D00A202DE70020C04360841AA87C +:10048000019023A9229802970395009100780023F8 +:100490008206920E20462A99FFF712FC0390208BC9 +:1004A00020A988807BE1032EC0D1402220A98A8127 +:1004B0004178027808021043208320A988802A9975 +:1004C0001EAB1C9A02930192009139880022491EAA +:1004D0008BB21B990978F6F711F918A90872002850 +:1004E00033D10B20287010A8008F3FE0052E9DD13E +:1004F000802220A98A814178027808021043208353 +:10050000249984464A78097812020A43628420A911 +:1005100088801248824202D30720DBE6AFE03F200A +:100520008002024362842A981FAB1C9902930191B6 +:1005300000903888401E83B21B9801786046F6F719 +:10054000DDF818A9087200280CD08328AAD107E08A +:10055000FFFF0000B40E002001280000010200008F +:100560000220B8E00D20287010A8808F401C15E1F3 +:1005700001990C22C9095143C91CB14204D90198FF +:1005800040067CD5002009E1427803781002184328 +:1005900020AA9080844622980078400609D505203C +:1005A0006A46107422980078C00905D000201074A3 +:1005B0001DE106206A46107424981F902A9A009024 +:1005C0000023701A029383B21E9001921B9800229E +:1005D00001786046F5F7AEFE18A908720022694658 +:1005E0000A74832801D102200390229800784006E3 +:1005F0000DD52088C00506D520A9208B8988884282 +:1006000001D100206062002018A90872C6E0FF2115 +:10061000013120A88181808820831E9860841F98E2 +:1006200060621320B8E0052E29D3417802780802D1 +:10063000104320A98880218F002902D0FE4A9142D0 +:1006400006D10A216A4611740121C943218702E0BB +:1006500007216A46117422992A9A491D0192009134 +:1006600001221D990023D203029311438BB22499D6 +:100670004A78097812020A431B99097800E0C9E018 +:10068000F5F758FE18A90872002269460A7401227B +:10069000520220A98A81832808D0002809D0218FFE +:1006A000E54881427ED10020208778E08888208339 +:1006B0004DE7606B002808D031462046229AFFF7AC +:1006C000E3FB18A90872002869D12B463A46304648 +:1006D000229900F056FB039061E02298022E4078A8 +:1006E00001907DD1002801D0012879D108206946E8 +:1006F00008740198087521A800901B9800220178C1 +:100700002046019BFFF7B0FC6946002248758A75B8 +:10071000002802D10198012809D0208F002806D096 +:10072000002008740120800220A988810EE004A81E +:100730003399F2F774FF0390002069460874012092 +:10074000800220A988810398022807D0BB4800684E +:100750008079002805D018A908722BE00198208321 +:100760001DE00398002803D0812018A9087240E0FA +:1007700021A800901B98012201782046019BFFF7D9 +:1007800073FC18A9087220463499FFF753FC18A986 +:10079000087A002803D11920287001203880684683 +:1007A000007C00E03CE0002804D004A83399F2F774 +:1007B00036FF0390039800282ED01AE0062012E599 +:1007C0002078000713D5012E11D109216846017444 +:1007D000A188818204203499FCF771FE082100E091 +:1007E00005E020A88181CDE60198400612D50320BE +:1007F000039020A9208889890843208020A988891E +:100800004005400E04D026992B98086026988680D3 +:100810000398AAE40420E6E418A8007A00280ED081 +:100820000120287022980078687020A88088A8701D +:10083000000AE87018A8007A28710520388020A9DD +:100840002088898988432080E2E7FFB50746A1B068 +:1008500000201C903A7801209040794A7C68104032 +:1008600010AA1087744B22885B1C9A4203D0002880 +:1008700004D0100702D5012025B0F0BD249E002031 +:10088000307023980025028810A8028518A80575E5 +:100890006A4B68461972057404A8186020462C300B +:1008A0001B902A985860249E94463878721C052123 +:1008B000039201282DD0022808D003287DD130785A +:1008C000800980011D303070B889A08038780228F6 +:1008D00004D13078800980011B303070F01C1FAAD1 +:1008E00001900292009110A8008D0022C01E83B2D8 +:1008F0002020015DB889F5F701FF0028DED10398BB +:10090000B9890170090A417010A9888FC01C088537 +:1009100028E1787B18AA10753A7B012A02D0022AB6 +:10092000CCD1FCE022887F231B011A4010AB1A8730 +:10093000802A4AD006DC102A10D0202A0ED0402A65 +:100940000AD124E0FF3A013A65D0FF3A013A79D062 +:10095000FF3AFF3A022A76D00525A2E02078C006A9 +:1009600001D5082000E010201C9004206A46107475 +:10097000002090821AA81DAA1EAB03960192029035 +:1009800000933B8A20461C9AFFF79AF984E0228B59 +:100990003B8A9646934268D10A221C92002839D19C +:1009A000039801906046401E1FAA83B20292202045 +:1009B0000091015D0022704600E0BAE0F5F79EFE6E +:1009C000014618A801750B201AE0228B3B8A964637 +:1009D00093424AD10C221C92002862D103980190C4 +:1009E00060461FAA401E0292009183B22020015D42 +:1009F000628C7046F5F782FE014618A801750D203D +:100A0000307010A8818F491C01850421684601744B +:100A1000218B818245E0238B3A8A9C469A4224D1DD +:100A200012221C9200283CD1606A002813D00022B8 +:100A30006B4607C3638C07E0FEFF0000B40E002086 +:100A400009F800000DE04BE02020015D6046F5F75D +:100A500071FC18A9087513203070012010A90885B1 +:100A60001FE0398A228B914201D00425B6E016217D +:100A70001C91002815D11B98818802682046FFF739 +:100A800003FA18A9087500280BD11B983346016892 +:100A900080881AAA00F075F9054602281BD0042D9B +:100AA00019D01B988088002811D06846007C002847 +:100AB00004D004A82A99F2F7B2FD05460120694640 +:100AC00008741B981B990068059000208880002DF1 +:100AD00048D0052D2ED06846007C032878D07DE0D4 +:100AE00018211C91002806D0388A20832046B96836 +:100AF000FFF7A0FAD5E72046183000902020015DCE +:100B0000237E01222046FFF7AFFA18A908750028B6 +:100B1000ECD119203070012010A90885E6E7208863 +:100B200001214902084010A90887FF38FF38022830 +:100B300006D0052510A92088098F884320804DE024 +:100B4000208F9849884290D116201C90386900283F +:100B500005D06063B88A20870020608702E000200B +:100B6000C043208710A8008F7F21090102468A43D5 +:100B70000DD0782300220420B968FCF7FBFB3878FD +:100B8000A07010A92088098F0843208002E02188E6 +:100B9000814321806846007C002805D08248416856 +:100BA00004A8F2F73CFD054618A8007D002815D0E2 +:100BB0001C98707001203070208BB070000AF070AB +:100BC00018A8007D3071052110A8018506E0FFE717 +:100BD0007548416804A8F2F722FD05467248017A7B +:100BE00020884005400E22D11B98808800281ED006 +:100BF000239A0026138810AA1385249A2A9B6F46ED +:100C00004CC71B9A039412681AABFFF78DFA05467E +:100C100002280CD00120694608741B982A990068A4 +:100C2000059004A8F2F7FBFC05461B98868010A8E7 +:100C3000018D2398018028461EE600B597B0042850 +:100C400007D102206A461070019100216846F2F730 +:100C5000E6FC17B000BD10B5534C037800222168A4 +:100C6000012B02D0022B42D126E00B78002B01D0C1 +:100C7000042B03D10A712268032111702168838833 +:100C80000A79D200921D8B5221680A79D20008326B +:100C90008918C2880A80216803890A79D2000A3239 +:100CA0008B52428920680179C9000C314252216877 +:100CB0000879401C08711EE00A7482888A802168C5 +:100CC000C288CA80226801891181226841895181C4 +:100CD000C1682068C1606168F2F7A1FC0146022882 +:100CE00007D02068007C002802D1002903D0812091 +:100CF00010BD832010BD002010BD406B002800D027 +:100D0000012070478178012909D100880521C90295 +:100D1000884202D0491C884201D10020704705203A +:100D20007047F7B586B00024684615460F468481A3 +:100D300005261AE0049841780278090211432980B7 +:100D4000811D019602940091417902790B021343AF +:100D5000C178827809020A43417800780902084381 +:100D60003946F5F7E7FA002806D104AA03A9069840 +:100D7000FFF7BFF80028DDD0822800D1002009B09D +:100D8000F0BD10B51488844201D2052010BD17248F +:100D90001C701080421E581C491C05F0C6F900202A +:100DA00010BD0000FEFF0000B40E002010B540484A +:100DB00004F04DF9002801D00C2010BDFF211131A5 +:100DC0003C4805F011FA3B4901200870002048809A +:100DD000E03188718874887520310871344804F0D6 +:100DE0004EF9002010BD10B5314804F028F9002854 +:100DF00003D031A1312005F016FBFFF7D7FF002803 +:100E000003D02DA1382005F00EFB10BD10B504460F +:100E1000274804F01CF9002801D00C2010BD2549FA +:100E20000878002807D0002008702148216004F0CD +:100E300026F9002010BD1E4804F021F91F2010BD26 +:100E400070B505460C461A4804F001F9002801D097 +:100E50000C2070BD174A5088A84202D11078002893 +:100E600004D0134804F00BF9122070BD1048226022 +:100E700004F005F9002070BD10B504460C4804F0DC +:100E8000E6F8002801D00C2010BD0A48017800299E +:100E900007D00020C0432080054804F0F0F812205D +:100EA00010BD40882080024804F0E9F8002010BD01 +:100EB0009D000020C00E00207372635C6C6C5F6448 +:100EC000622E630010B5282105F08CF910BD70B5B5 +:100ED000054600780A0700090001120F1043287028 +:100EE0000B0005F091FB07050705070509050B0039 +:100EF000062408E00C2406E0222404E00024F2A1E9 +:100F0000572005F090FA68788009800120436870C6 +:100F100070BD00780007000F704710B50622C01C96 +:100F200005F003F910BD10B50622093005F0FDF8F3 +:100F300010BD0278BF23C9071A40490E0A43027048 +:100F4000704702785206520EC9010A430270704778 +:100F500070B515460E4604461F2A03D9DAA1A8200B +:100F600005F061FA20462A463146093005F0DDF8E1 +:100F70006078AD1D80098001A906890E0843607064 +:100F800070BD70B515460E4604461F2A03D9CEA182 +:100F9000CC2005F048FA20462A463146093005F0B3 +:100FA000C4F86078AD1D80098001A906890E084348 +:100FB000607070BD70B501780907090F03292ED044 +:100FC000052931D1411C827E0C46437E1102194312 +:100FD000037FC27D1D02037EC67E1B021343827DFA +:100FE000407835438006800E22281DD106291BD368 +:100FF0001920C001814217D8FF26F436B54213D814 +:10100000002A11D0082A0FD88A420DD28B420BD861 +:10101000617F227F09021143814207D904E04078B1 +:101020008006800E0C2801D0002070BD012070BD0C +:1010300000210A464254491C2229FBDB704710B5A7 +:1010400002788B07920892009B0F1A430270427835 +:10105000520952014270012908D0022906D0032901 +:1010600005D0FF2098A1EE3005F0DDF910BD01217B +:101070000A43427010BD10B502788B0792089200A7 +:101080009B0F1A43027042785209520142700129A3 +:1010900007D0022905D0032904D08BA18E4805F082 +:1010A000C2F910BD01210A43427010BD00788007CB +:1010B000800F70470278EF23C9071A40C90E0A4310 +:1010C0000270704770B50546C1700B0005F09CFAC0 +:1010D0000E080A0C0E1012120C14141212160C1810 +:1010E0000C2413E0082411E002240FE017240DE083 +:1010F0000D240BE0012409E0092407E0062405E0A3 +:101100007548002470A1A03005F08DF96878400979 +:1011100040012043687070BDC0787047017AC27981 +:10112000080210437047817A427A080210437047E0 +:10113000017BC27A08021043704781794279080224 +:101140001043704700797047817B427B080210434F +:10115000704770B5017AC37909021943431C857A37 +:101160001C46467A2B023343657926792C02344398 +:10117000C21C5A4E00798D1FB54214D8FF25F43594 +:10118000AB4210D800280ED008280CD888420AD2CA +:101190008C4208D8507A117A00020843B11D884267 +:1011A00001D8012070BD002070BD0B4610B5011D97 +:1011B0000522184604F0B9FF10BD817A427A080270 +:1011C0001043704701717047007970470B4610B5A6 +:1011D000011D0822184604F0A8FF10BD027B0A700A +:1011E000407B487070470B46014610B508220E310F +:1011F000184604F09AFF10BD0B46014610B50422B4 +:101200001631184604F091FF10BD10B50822001DDC +:1012100004F08BFF10BD10B504220C3004F085FFE4 +:1012200010BD017170474171090A81717047C17128 +:10123000090A017270470079704781794279080282 +:1012400010437047017AC279080210437047017158 +:101250007047017170470B4610B5011D08221846F2 +:1012600004F063FF10BD10B50822001D04F05DFFFF +:1012700010BD70B515460E4604461B2A03D912A1AF +:10128000174805F0D0F82A463146E01C04F04DFF1F +:101290006078E90640094001C90E0843607070BDDE +:1012A00070B5054640780E46C406E40E1B2C04D9E2 +:1012B0000B4805A10C3005F0B6F82246E91C304673 +:1012C00004F033FF204670BD7372635C756C5F7011 +:1012D00064752E6300000000070200007A0C000015 +:1012E000F7030000C1074008C207C90FD20F511809 +:1012F0004008C207D20F51184008C207D20F511838 +:101300004008C207D20F51184208D007C00F40183A +:101310005208D107C90F0918500840187047002219 +:1013200002808271C271C2720273427382738270D0 +:10133000C270027142714276828303464284203336 +:101340009A7102859A72C2750276C2730274DA7259 +:101350001A739A7319750284FF21603081709A752F +:10136000704770B504460020A083208C1E46484379 +:101370001546114604F061FF2084F000294604F070 +:101380004EFF401C80B20146192269439202E0835D +:10139000914201DD401EE0837D202946000204F0D9 +:1013A0003EFF401CA08470BD70B50546087B0E460C +:1013B000C006C00E08730020A87504463019007AD4 +:1013C000FFF790FF29194874A97D641C0818E4B23E +:1013D000A875052CF2D3C0B2252803D979A18A209B +:1013E00005F021F870BDF8B5044630302646274692 +:1013F0002546C036A03780350090032909D0002942 +:101400001AD0012924D0022902D1A11CFFF7CCFF58 +:10141000F8BD1146FFF783FF002028836883A88367 +:10142000E883288468847871E88538732621085514 +:10143000A08430703071F8BD0020E885B871A188B3 +:1014400023890A460098FFF78CFFA11C0098DDE76E +:101450000020E885B38A328AA1880098FFF781FFCF +:10146000F8BD70B5867D0D460446002E01D0252EB0 +:1014700001D9122070BD002A18D0287EE17D50438A +:101480000818252104F0CBFE0846E1754207520FEB +:10149000C908504B69189A5C097A8A4368D031466A +:1014A00004F0BDFE491CCAB2002007E0002070BD58 +:1014B000002803D02118097C511ACAB22118497C8E +:1014C00091423AD32918097AC943CB07DB17D21ABC +:1014D000521E1206120E35D08B07DB17D21A521E7F +:1014E0001206120E30D04B07DB17D21A521E12060C +:1014F000120E2CD00B07DB17D21A521E1206120E38 +:1015000028D0CB06DB17D21A521E1206120E24D098 +:101510008B06DB17D21A521E1206120E20D04B0673 +:10152000DB17D21A521E1206120E1CD00906C9175A +:10153000511A491E0A06120E18D0401C0528B7DBA6 +:101540001F2070BDC00013E0C000401C10E0C000B0 +:10155000801C0DE0C000C01C0AE0C000001D07E0B8 +:10156000C000401D04E0C000801D01E0C000C01D9F +:1015700020769BE738B505460C466846FEF738F8F6 +:1015800000281ED0694600200856207209216156A5 +:101590000022411A00D5494220356B798B420FDC7D +:1015A000FF2B0DD0A17A491CC9B2A172AB79994227 +:1015B00002D8617A7F2903D160720020A0720122D3 +:1015C000104638BD7372635C6C6C5F7574696C2E09 +:1015D000630000007667010010B5040004D0FF200E +:1015E000FAA1AB3004F01FFFFB4821464143FB4802 +:1015F000FF230918FF330022581C5A544254C81DB7 +:10160000FF30FA3002704270F448001FC378A342E2 +:1016100002D18270FF23C370EF48EF4BC01E081841 +:101620009B1EC91802700A7010BD70B5EB480026E9 +:10163000001F8670FF24C47035462846FFF7CCFF94 +:101640006D1C2D062D0EF8D00020E4490B229201CE +:10165000E14B43435B189B181E74401C0006000EB0 +:10166000F6D0DF48FFF7E4FC0021DD48FFF722FD5C +:101670000121DB48FFF7E3FCDA4804704470847012 +:10168000C4700471447170BDCFE71B20704730B542 +:101690000021D24A0B239B01CF4C4C43A418E418E1 +:1016A000247C002C05D0491C0906090EF4D000202A +:1016B00030BDC94C01254C43A218D21815740170D5 +:1016C000284630BD10B5044600F0D0F900280CD0F3 +:1016D0002046FFF781FFC0490B224C43BF49002041 +:1016E0006118920189180874012010BD10B50446D4 +:1016F00000F0BCF9002802D0BA484471012010BDA6 +:10170000034610B5B748B44940794843B349421835 +:101710001046FF30E130C17F807F04F0D5FF10BD5F +:1017200010B5B048AC4940790F224843AB49401846 +:10173000A949D239095CFF30FF3004F09FFF10BD8A +:1017400010B5044600F092F9002802D0A5480471B3 +:10175000012010BD034610B5A2489F4900794843B7 +:101760009E4942181046FF30E130C17F807F04F06F +:1017700098FF10BD70B59B4C97492079974D484311 +:101780004019C11DFF31F931FF30E130807F0F2258 +:1017900004F064FF002813D020798F494843401992 +:1017A000FF30FF3002300178491C01700178407829 +:1017B000814204D1884885A1773804F034FE0120A5 +:1017C00070BD884884490079484384494018FF30F7 +:1017D000E130C17F807F814201D10120704700202C +:1017E000704770B57F487C49007948437B49401871 +:1017F000FF30E130867FC57F0F242946304604F054 +:1018000026FF002801D0204670BD70066906400EF4 +:10181000490E884201D3401A01E0081A201AC0B2CA +:1018200070BD0F20704770B50C46054600F01EF9DC +:1018300000280ED0002020706748454367482818CC +:10184000FF30FF300230017842788A1A22704170EE +:10185000012070BD70B50C46054600F007F9002860 +:101860000BD05D4845435D482818FF30FF300230FB +:1018700001784078081A2070012070BD5849016035 +:10188000704710B5044600F0F1F8002802D0554822 +:101890000470012010BD5149091FCA78FF2A02D0E7 +:1018A0000021016007E08A784C492439012A02D0DE +:1018B000016001207047002070474848801E017871 +:1018C000012908D001210170464801784348001FD2 +:1018D000C170012070470020704710B5044600F029 +:1018E000C5F8002802D03F484470012010BD3B4994 +:1018F0003C4B091FCA785B789A4206D18A78203916 +:10190000002A02D001600120704700207047334850 +:10191000344A001FC1785278914209D1FF21C17029 +:10192000801C0178002903D000210170012070473C +:101930000020704729482B4A001FC17852789142F5 +:1019400004D18078002801D0002070470120704722 +:1019500010B5044600F08AF8002802D02148C4706F +:10196000012010BD034610B51E481B49C0784843EE +:101970001A494018C21DFF320B21FC328901401860 +:10198000C17B807B04F0A0FE10BD10B51548124944 +:10199000C0784843114940180B2189014118C97B7F +:1019A0000D4AD21E8018062204F068FE10BD0D48B4 +:1019B0000949C0784843094941180B20800108189B +:1019C000C17B807B81420FD1012070477372635CC1 +:1019D000646D5F712E630000D1020000F40F0020DF +:1019E000C51200209E0000200020EEE710B504463E +:1019F00000F03CF8002802D021488470012010BD7E +:101A0000034610B51E481F49807848431E494018B8 +:101A1000C21DFF320B21FC3289014018C17B807B43 +:101A200004F03FFE10BD10B51548164980780B2212 +:101A300048431549920140181249891E41188018DF +:101A4000807B062204F00AFE10BD0D480D49807807 +:101A500048430D4941180B2080010818C17B807B49 +:101A6000814201D10120B0E70020AEE7002805D176 +:101A70000648007C002801D00120A6E70020A4E74A +:101A80009E000020D1020000F40F0020B4120020BC +:101A9000F8B5FF4E0446B079002500280AD0002989 +:101AA0002DD1657010202070F079A070307AE07030 +:101AB000B57124E0F64F203F387A012804D0707ABF +:101AC000012810D00020F8BD002918D1657013201E +:101AD000EF4920701C221639A01C04F026FB0120BF +:101AE000A0713D720BE0002909D165701420E8490E +:101AF000207008220A31A01C04F017FB7572012027 +:101B0000F8BDF8B5E3480178002902D00C2630462C +:101B1000F8BD0026DE4D3446403D2E756E75EE75DF +:101B20002E76AE75294620396E730F464E734037B8 +:101B30007E717F218170687E002804D0FDF73DFD15 +:101B4000FEF766F86C763C72D14884711430FFF76A +:101B5000B9F9CF483C30FFF7B5F9D8E710B5CD4B10 +:101B600000221A70CA4B203B1A711A46603A11665D +:101B7000D065FFF7C6FF002804D0FF20C6A187303C +:101B800004F051FC10BDC2484038007D7047C04988 +:101B900010B54039C87B897B42078307D20FDB0F22 +:101BA000D218C007C00F101840000B0004F02CFD25 +:101BB000050B060B04080F00BB4906E0BB4810BD2F +:101BC000B949083101E0B8490839085A10BDFF2069 +:101BD000B1A1A73004F027FC002010BDAC48B449E7 +:101BE0004038008A48437047F8B5A94C0646407B08 +:101BF000403CE07337791346A773012F26D0308815 +:101C00002082A348B27B203882710546603D29704E +:101C100006221946681C04F088FAB0796873062217 +:101C2000F11DE81D04F081FA607B0126002800D038 +:101C3000667597486038407B002800D0A6753B0049 +:101C400004F0E2FC0506082549084B000020D7E710 +:101C500000211DE08E4801211430FFF738F98C482F +:101C6000E91D1430FFF75FF9687B002807D00128D1 +:101C700007D0FF2088A1EE3004F0D5FB0CE0002156 +:101C800000E0012182481430FFF75BF904E00621EF +:101C90007F481430FFF71BF90020E07520767C4860 +:101CA000691C1430FFF739F9794829781430FFF7A7 +:101CB00040F9774804213C30FFF709F97448691C62 +:101CC0003C30FFF72AF9724829783C30FFF731F9A8 +:101CD00026750020F8BD0221DAE7FF206EA1F8305A +:101CE000CAE770B56A4C0125403C0346257620467C +:101CF0002030007A002801D03A2070BD64480022CC +:101D0000803806789E4206D1E2750622401C04F017 +:101D10000CFAE57500E02276002070BD70B504462F +:101D20005B4D0020403DA87528462246323804F01D +:101D3000FCF92846203844730120A87570BD544929 +:101D400020390871704710B5514C0022403C627533 +:101D5000607302462046123804F0E7F901206075EE +:101D600010BD4B49203948717047F8B500F0A4FB0D +:101D7000474C0025403C607E002804D0FDF71DFC48 +:101D8000FDF746FF6576434F3D70FDF793FBA07B63 +:101D9000012804D00021084601F0A6FAF8BD002170 +:101DA000022001F0A1FA3A4C203C207A002809D008 +:101DB000374881790029F1D11321C17105720121C0 +:101DC0008171F8BD78780028FBD0314E0622803E24 +:101DD000707BE0733078A0753046F11D703004F0F0 +:101DE000A4F930460622711C773004F09EF93C209D +:101DF000A072012020727D70F8BD10B5244C403CCB +:101E0000E17BA07CCA0701D0C2070BD08A070FD59F +:101E100082070DD42620FDF777FAA07C0221084323 +:101E2000A07410BD2520FDF76FFAA07C0121F6E714 +:101E30004907F6D54007F4D42720FDF765FAA07CC2 +:101E40000421ECE770B5134E3078002872D1104CA5 +:101E5000403C207D00286DD0FDF71FFB0025A574B8 +:101E6000E57475702846FDF715FB0020FDF78CF929 +:101E70000D480D38FDF73FFA0B481038FDF7F7FA1B +:101E8000FDF76CFBFFF7B9FFFDF7FFFA012111E049 +:101E900068130020A40000207372635C6C6C5F61A7 +:101EA00064762E63000000008E6701009A8913009B +:101EB000710200000020FDF743FA0F210520FDF715 +:101EC000C1F92646403E3178701CFDF7ADF9A07B84 +:101ED00001280CD004280AD0607D002807D02146B4 +:101EE00012390846627B6630FFF732F86575A07DCF +:101EF000002807D0FE480146427B12399C30FFF78C +:101F000040F8A575306E0178002903D00178001DD6 +:101F1000FDF7C8F9F06D0178002906D0F44A401C9D +:101F2000C732FDF754FE01206076FDF7C3FA0020AA +:101F300070BDFFE70C20FBE7EE494860704770B5C5 +:101F4000050001D0FFF759FFE94C2034E07C002860 +:101F50000AD0A07B012804D19920E749C00004F0F1 +:101F600062FAFFF702FFE3E7002D0DD00221002007 +:101F7000FDF7E6F9DE4840300079032801D001285A +:101F800002D10220FDF73BFCE07D002600280DD0A9 +:101F9000D74D203D2846691C9430FEF7BEFF2846E9 +:101FA000691CBC30FEF7B9FFE6752676D048743060 +:101FB000FDF786FAA07B030004F026FB0504040469 +:101FC0000D04090001210846FDF79FFB03E0CA4903 +:101FD000CA4804F028FAE17BA07C81430120002953 +:101FE00003D1A17B012903D0E074C24908709FE7A7 +:101FF000A674FAE710B5FDF750FABE48007800283D +:1020000018D1BB482030007D002813D00020FFF7F6 +:1020100096FFB74840300079002809D001280FD03A +:10202000022805D003280BD0B349B54804F0FBF9CA +:10203000002010BD00F040FAFDF73CFA0C2010BD66 +:10204000F0F7E6FFF4E7AB49012048707047F8B5B8 +:10205000002400F0E0FF002824D0FF202D30FDF701 +:102060006CF9A44D2878A24F403701281DD00228D2 +:1020700001D0032834D0A2489F496B3004F0D3F933 +:10208000287800280DD0387900280AD0012808D0F7 +:10209000022838D0032836D099489749803004F078 +:1020A000C2F9F8BDFFF761FEF8BD914E2036B07B56 +:1020B000032815D0707E002803D0FDF798FDFDF7AA +:1020C00074FA8B48C430FDF7FBF9B07B012812D0BD +:1020D000042810D0B879012806D0032804D004E0E1 +:1020E0000120FFF72CFFCBE7102421460E200143EF +:1020F0000020FDF70AFB7879012801D1FDF76FFA7E +:1021000002202870BCE728780228CDD10120FDF7F5 +:1021100076FBF8BD70B5764840304079012801D192 +:1021200000F0D4F9724C2034607E002803D0FDF713 +:1021300044FAFDF76DFD00F06EFF00280CD06D4DE8 +:102140002878022804D06E486B49A33004F06BF95C +:10215000A07B012803D006E0FFF707FEE8E6992000 +:102160008000FDF7EAF80120FFF7E9FE2878002853 +:10217000F4D028780128F1D039205F49000104F01B +:1021800052F9D5E6F0B5074689B000200690FDF774 +:10219000AEF800900020019056480078022804D044 +:1021A00057485549F03004F03EF9514D40356879B3 +:1021B000012801D100F08AF94D48C430FEF7A9FE8C +:1021C0004B4E04462036002F70D03046A430FEF728 +:1021D000F1FE0028F8D0FDF731F80028F4D0707E29 +:1021E00000280AD005277F1EFFB2FDF72CFD02282C +:1021F0000FD0012800D0002001903D492046C43175 +:102200000C46643C030004F0FFF906A4A4A40CA44B +:1022100056A4002FE7D177203AA1C00004F003F9BB +:10222000E9E7B07B012841D004283FD0019A00980B +:10223000104304D1A879002801D0022836D168794A +:1022400001281DD1607A00281AD101206072087817 +:1022500006224006C00FA0722548C91C6B3003F04F +:1022600064FF244C224FA07871377F2804D1A92025 +:1022700024A1C00004F0D7F8A07838707F20A070A7 +:102280001B489C30FDF71CF91A480321017028797E +:10229000002860D001280AD002285CD0032806D08C +:1022A000164818A1E03804F0BEF854E051E00120CF +:1022B000FDF7A5FA4FE00E480F462038C978C079DF +:1022C000814230D10A4839792038027A91422AD1A4 +:1022D0007979427A914226D1B979827A914222D192 +:1022E000F979C27A91421ED1397A027B914211E08A +:1022F00008130020A4000020981E0100F60400002E +:10230000DE0200007372635C6C6C5F6164762E6346 +:102310000000000007D13978407B4906C90F81428F +:1023200001D1012100E00021B07B012801D0042867 +:1023300001D100290AD100280BD101990098084346 +:1023400004D1A879002801D0012802D1307E0028CC +:102350001FD001200690707E002803D0FDF72DF9D4 +:10236000FDF756FC0698002802D00120FFF7E7FD94 +:102370005D48017800290AD00178012907D000784A +:10238000032804D095205949C00004F04CF809B046 +:10239000F0BD55480422406855490F3003F0C5FE92 +:1023A000387806224006C10F4F4840680177F91C73 +:1023B0001D3003F0BAFE4C484D4940680322091D08 +:1023C000133003F0B2FE4848494A4068B97D817530 +:1023D0000F3A117ED37D09021943018311468B7E8A +:1023E0004F7E1B023B438380137FD77E1A023A4302 +:1023F000C2808A7F4B7F1102194301813C4905222B +:1024000010310A3003F091FE3948374A1130017912 +:102410005768C906C90EB97600794009F876287A56 +:10242000002809D0A07900283AD11320E0710020BB +:1024300020720120A07133E00020A8727888B08556 +:10244000387FE8732A48394606221D31833803F065 +:102450006CFE27490622F3390878A87508467730BC +:10246000491C03F062FEB888F087F888208038891C +:102470006080F87E20710198002860790BD00121DE +:1024800008436071FDF7F2FB61794000C907C90F8D +:102490000143617102E04008400060710120287230 +:1024A000114C0020207000F007F8FDF703F8012020 +:1024B000616800F019FF4EE710B5FDF76AF8FDF707 +:1024C0005DF8FCF7B5FFFCF7DAFF10BD064810B564 +:1024D000801CFDF78DF8002802D103497F20887009 +:1024E000FDF774F810BD0000A400002004230100D3 +:1024F000DB1300208107C90E002808DA0007000F4F +:1025000008388008F74A80008018C06904E0800815 +:10251000F54A800080180068C8400006800F7047A8 +:1025200010B500F03BFF10BD70B5F04C0546626879 +:10253000002908D0002A04D0FF20EDA10C3003F0C0 +:1025400072FF656070BD002A04D1FF20E8A112303F +:1025500003F069FF0020606070BDE948C07E7047ED +:10256000E7482830C07E704738B5E04C20680168E5 +:102570004978012925D001216846FAF7C9FC684647 +:102580000078E049000203F04AFE2068426AC06811 +:1025900012685118FBF7ADFC2168C860D84A206862 +:1025A00028320321904218D0028B002A15D0012234 +:1025B0004272017200210171021D017F00F0FBFED9 +:1025C00038BD7D21C068C900FBF793FC2168C86055 +:1025D000FFF7DDFA21680861E0E7028B521C0283F5 +:1025E0004172E6E7FFB5C64E85B0706A346805688B +:1025F00060680190306A0390298E0798401A80B273 +:1026000002900898002804D02746383720464830E2 +:1026100002E0371D2846A830009003203871059845 +:10262000002820D001287DD002285ED003287AD04F +:10263000AFA1B54803F0F7FE0898002807D0387915 +:10264000032804D0B048AAA1093003F0ECFEA16A27 +:102650007069FBF74EFCB860616A206A88427DD9D8 +:10266000009801601FE1306A002804D1A648A0A1AB +:102670007A3803F0D8FEA449288B373948434018EC +:10268000069900F0A6FEA0619F49A8883739484303 +:10269000069900F09EFEE061316A9B48891CA162A8 +:1026A0002A8B37384243A069974B121AE63BD2185F +:1026B0005118A162944BAA7D373B5A4340008018C1 +:1026C000FF30193020626062306A081AED21FF384D +:1026D000C90015388842AFD28C49884204D28A4852 +:1026E00083A15D3803F09FFEB6E0874A288B373A16 +:1026F000E16850430818069900F06BFEA06182491A +:10270000A88837394843069900F063FEE061306AD3 +:10271000002804D17C4876A1553803F084FEAE2011 +:10272000405B01E02CE05AE00028288B784AE16801 +:102730001DD050430818A169401AA0622169A06801 +:10274000734A4843A1694018A97D4000514340188D +:10275000FF3017302062A888504300E0A1E0E16913 +:10276000411A6F20C000081A6062A06A34E050432A +:102770000818A169401A3168D63849684018DCE762 +:10278000284680300190C08D002802D0306A002891 +:1027900004D15F4856A1401F03F045FEA8885C495C +:1027A000E3694843C01AA06201999C46CA8D216919 +:1027B000A368521A4B43A169591863465343C91879 +:1027C000AA7D534B49005A438918FF3117312162C2 +:1027D0006F21C900411A6162316A401A35E00898D8 +:1027E000002803D03420005D002878D1A88848490B +:1027F0004843E169401A02994843A0622846803064 +:102800000490C08D0028019829D0002804D03E48AB +:1028100037A1163803F007FE04983D4AC18D02988F +:102820000818E16948434000FF3017302062A8884B +:102830005043411A6F20C000081A606200F0AEFDDC +:1028400000281CD0A16A0398081AED21FF38C9009E +:102850005538884200D3EFE601203871ECE60028B5 +:1028600002D00398002804D1294821A11A3003F08E +:10287000DAFD0198A16AD6380818A062CCE7FBF708 +:102880009EF8726901461046FCF7BFFAA16A081A61 +:10289000ED21FF38C90050388842DCD2012009B050 +:1028A000F0BD0099086000981A4900688035081842 +:1028B000F860298B0798081A00B2002804DD0598F3 +:1028C000022801D0032000E00120787108983870B8 +:1028D0000898002820D03420005D00281CD0022059 +:1028E000DDE7000000ED00E000E400E0B4000020BF +:1028F0007372635C6C6C5F6C6D2E73302E630000C2 +:10290000F413002010270000190500002902000020 +:10291000E20400004B1700000898012148402034D1 +:102920006075317F3A46304600F045FD0020B6E73D +:1029300010B5FE4900280A68516A096807D0126874 +:102940008988FB4BD2695943891A03F068FC10BD92 +:10295000F8B5F64F38680468416A26460D68203697 +:10296000717D00290AD0618E2A8E914206D1407A6B +:10297000012803D1EF49F04803F055FDFBF71FF89C +:10298000014638684069FCF740FAFFF7D1FF2A8E0C +:10299000618E1318994202DB491C618602E0401CDB +:1029A00010186086B07D002806D19C21608E495B9E +:1029B000884201D1401C6086DC480168088B0328EE +:1029C00002D2401C088302E0618E982041532846C1 +:1029D00040300646C1898089081A298E401E401859 +:1029E00087B218E0D148EB7E00685B00406A00794E +:1029F0004100D248415AC05A401881B2207D00237C +:102A0000FFF7F0FD00280FD001280ED0CA48C949B1 +:102A10003A3003F008FD628EB81A00B20028E1DAFD +:102A20000820B07200F010FEF8BD608E401C608679 +:102A3000F1E770B5BD4D002168680162C27E1300E8 +:102A400003F0E2FD045656034A56426A14680268CF +:102A500011700268516000682030407D002808D164 +:102A6000FAF7ADFF69680968096CFCF7CEF9002830 +:102A700018DC6868228E0168498E914206D1214691 +:102A800080318B8B9A1ACA83238605E0891A9E228D +:102A900011530168498E21860268C1681164C168BA +:102AA000416111E068680168098E228E8B1A224606 +:102AB0008032D3830168098E218601680B6CC36064 +:102AC0000B6C4361886C9062204601F0D8FC0028B2 +:102AD0000DD098499A4808E0C1684161FFF7B2F902 +:102AE000002804D096489349801D03F09CFC70BDDB +:102AF000934890490D30F8E710B58C4A0B001268E6 +:102B000003F082FD0906090F1F0C2E2E082B2E0044 +:102B1000FFF78FFF10BD00F068FC10BDFCF772FEE0 +:102B200010BDD07E022806D0D07E032806D0FF201C +:102B30008049A3300EE0FFF70BFF10BDFFF714FD37 +:102B400010BDD07E0228F6D0D07E0328F6D0FF201C +:102B50007849AE3003F067FCF0E7FAF715FF10BDD7 +:102B6000FF207449BC3003F05EFC10BDF3B581B0AA +:102B70000E4601276D4D734C0B0003F045FD090611 +:102B80002F39392F40403939400001216D48FFF776 +:102B9000CBFC31460198FFF7AFFFE07E022826D13B +:102BA00068680568406A0668FAF7E7FEB188604A17 +:102BB0005143EA69891AD639E962B72802D26248D4 +:102BC000081803E0081A6049B7314018E8625F4806 +:102BD000E96A814200D80846E86205E00198FFF7FB +:102BE0008BFFE07E022802D1206820300775FEBDF1 +:102BF0002C600198FFF780FF00202860FEBDFF20B9 +:102C00004C495C3003F00FFCFEBD70B50C46064627 +:102C10000B0003F0F9FC09060D10100D1A1A101024 +:102C20001A00484801212830FFF77EFC2146304633 +:102C3000FFF762FF70BD43483C4D283028603046A6 +:102C4000FFF75AFF0020286070BDFF20394982300D +:102C500003F0E9FB70BDF0B5344C0020216885B06D +:102C600003258D76CA7E0746032A03D0C97E002934 +:102C700029D029E0087F002803D12E49344803F0E9 +:102C8000D2FB2068067F684605714571FAF797FE0A +:102C90000290FF20F53003900121684601706946DB +:102CA0003046FBF70CFB00E020BF2068007FFCF7FC +:102CB00038F90028F8D02068007FFAF765FE206810 +:102CC000077700F072FB012021688F7605B0F0BD18 +:102CD00016490A68907600E020BF0A68D07E002876 +:102CE00003D0D07E937E9842F6D0D07E002803D0C9 +:102CF00000200021917670470120FAE770B5114954 +:102D00000024CA7E094D032A03D02831CA7E032A33 +:102D10002ED12960002827D0012821D00C48054950 +:102D2000973003F080FB0020296813E0B4000020F6 +:102D3000E2040000F0280100F70500009E67010092 +:102D4000A1030000F4130020C4F8FFFF38120000B4 +:102D500072020000086048622860002C08D070BD34 +:102D60000320FFF7B5FF01E0FFF775FF0446DAE740 +:102D70000C2070BDF8B5F94F04461F25E67E3300E0 +:102D800003F042FC042920031B20F548844204D0B0 +:102D9000FF20F449FC3003F046FB02203C60FFF7C3 +:102DA00097FF002805D03968002008604862386025 +:102DB00011E00C25002038600AE00120FFF79EFF9B +:102DC000054603E0E749E84803F02DFB002D02D05B +:102DD000E07EB042D2D1E07E002804D0E248E14952 +:102DE000801D03F020FBF8BD10B5DD48FFF7C2FFE2 +:102DF000DB482830FFF7BEFFD94900205031087565 +:102E0000D649C91F4870D64948610A4628325061E0 +:102E100088769076D1494860086010BD70B5044648 +:102E20000120FFF767FBC5B20B20FFF763FBC0B2C1 +:102E3000854204D0FF20CB49C63003F0F4FA0120CC +:102E4000FFF758FBC5B21820FFF754FBC0B285420C +:102E500004D0FF20C349C73003F0E5FA0420C04383 +:102E6000FFF748FBC5B21920FFF744FBC0B285420B +:102E700004D0FF20BB49C83003F0D5FAB748B849A1 +:102E8000083804700020C87688760A462832D07642 +:102E90009076B24B012408331C711860486250626E +:102EA00008601060FFF7A0FF70BDAC4908310871E1 +:102EB0007047FEB5AA49CA7E08462830A74C002AAA +:102EC00002D1C27E002A03D0C97E022903D005E0C8 +:102ED000A648216006E0C17E002901D00C20FEBD7D +:102EE0002060A348FAF7FCFC216808779B4920681A +:102EF000C91F0160C91C4162007F002804D1AD20B8 +:102F00009849800003F08FFAFAF737FD9949884213 +:102F100000D20846FF30C83086B220680325C57647 +:102F2000FEF735FE21680861FEF758FE00270028ED +:102F300027D0FEF753FE21684A6A10600968012015 +:102F4000087001466846F9F7E3FF684600788A4949 +:102F5000000203F064F90191FAF731FD019971184B +:102F6000FAF7C7FF2168C8602068057245720771CB +:102F7000021D017F00F01FFA2068078300202760F0 +:102F8000FEBDFAF71CFD3146FAF7B3FF2168C860B1 +:102F900008680770096801204870E5E77047F8B5D0 +:102FA0006F4EF17E002904D131462831C97E0029B7 +:102FB00001D00C20F8BD0221F176694C674F5034E6 +:102FC0000837776234600025386025753979C07E0E +:102FD0004A006A4940008A5A085A2B46101881B2A2 +:102FE0002A462846FFF7FEFA002804D0CF205D4984 +:102FF000800003F018FA25610120A5602075658620 +:1030000025865748703085753968088E401E0886B9 +:1030100035830020F8BD10B5504801244068817EFA +:1030200003290CD001684978002906D0006A544968 +:10303000884202D90024FFF706F8204610BD00247C +:10304000FBE74648406802681178491C1170016A24 +:103050000068C26A914204D8007D012801D0012095 +:1030600070470020704700207047F8B53B4C3C4843 +:103070002060416A00680D68002634210E54A621A4 +:10308000495D00294BD1007D032848D1FAF797FC10 +:10309000014620684069FBF7B8FE00283FDDFFF7D6 +:1030A00047FC298E401C4118206802681186006880 +:1030B000018E9C22525B511A09B200292FDD012199 +:1030C0002030817528464030C1898089081A298EB0 +:1030D000401E401887B21BE0496A09794A00274917 +:1030E0008B5A028E007D9446EA7E5200895AC91896 +:1030F00089B201236246FFF775FA00280FD0012834 +:103100000FD002280BD01B481649193803F08BF951 +:1031100021680868028EBA1A12B2002ADCDA266028 +:10312000F8BD20680068018E491C0186F0E7F8B5FB +:103130000A4D00266A680128516A0C6853D1087943 +:103140000E4940000B5A1068077D032F1AD0027DEC +:10315000022A24D0007D012834D044E0B4000020AD +:10316000F4130020F0280100070200006D2B01007D +:103170000B2C0100F6050000102700009E670100DF +:10318000D98213000661106886609C20025BE07E95 +:103190004000085AC01881B2002303201BE02246D9 +:1031A0008032D78D0761E07E928B4000085AC018AC +:1031B00081B200230220FFF715FA6A680121126824 +:1031C00011750AE09C20025BE07E4000085AC0189E +:1031D00081B200230120FFF705FA002803D09C49A3 +:1031E0009C4803F020F9FAF735FB9B480078EFF78D +:1031F0006FF8686806830268218E51860068203067 +:103200008675F8BD38B5944C0021083460680D46C9 +:1032100000684278002A01D045701FE0007800283D +:1032200009D001216846F9F773FE684600788B499A +:10323000000202F0F4FF6068426AC0681268511828 +:10324000FAF757FE01466068C160057103214172BB +:10325000021D017F00F0AFF860680583FAF7FAFA03 +:103260007D480078EFF734F838BD7B4A10B5014649 +:10327000083250680B0003F0C7F9060D1504081753 +:103280000C31012100F0D1F807E00021106800F0B6 +:10329000CCF810BD0120FFF74AFF00210846FFF7D8 +:1032A00043F910BD032116E0416A02680968D36939 +:1032B00093608A886A4B5A430368DA600A46C032D0 +:1032C000D3890B83137B8B75138A8B80538ACB80B6 +:1032D000928A0A8102210068017510BD5D485C492F +:1032E000913003F0A0F810BD70B500280BD05A4CF7 +:1032F000083401280ED002281ED056485449B43054 +:1033000003F091F870BDFFF77DFF00210846FFF73D +:103310000BF970BD6068002501684D7000F045F83C +:103320000320F5F7B8FEFAF795FA4B486560007888 +:10333000EEF7CEFF656070BDFFF764FF606800F0D8 +:1033400034F800210846FFF7EFF80420F5F7A3FE54 +:1033500070BD414908314968CA7E022A08D10A680D +:103360001378002B04D150600968CA6A1018C8622B +:103370007047394A10B50832526800290CD001292B +:1033800007D0022907D033483149D93003F04BF830 +:1033900010BD801E00E0401F106210BD2E48083096 +:1033A0004068002800D0012070470021C176817656 +:1033B00001604162704710B50B46C17E847EA14218 +:1033C00004D011461846FAF77AFF10BDFFF7EDFF5B +:1033D00010BD024610B50020002905D00846504314 +:1033E000204902F01CFF401C10BD1B4810B50830DE +:1033F0004068C07E030003F007F9041515030B15A0 +:1034000001F05EF900280CD00F2017A1800106E022 +:10341000FEF7F0FD002804D0F12013A1800003F096 +:1034200002F810BD10A11448F9E710B504460029B0 +:1034300003D00020FFF77BFE03E007480078EEF79B +:1034400047FF2046FFF7B1FF0020F5F724FE10BD2F +:10345000F028010092060000AC00002010270000B8 +:10346000E204000040420F007372635C6C6C5F6C9E +:103470006D2E73302E630000CB030000F8B5FEF70D +:10348000B0F90446FEF756FAF84E0546706920304A +:10349000407D002809D0012827D002282AD00328FF +:1034A00032D0FF20F2A19A3037E0F0481830FEF712 +:1034B0001EFA002801D003200FE0EC481830FEF778 +:1034C00049F9002804D070695B21095C002908D003 +:1034D000E6481830FEF7D2F90120716920314875AD +:1034E0001DE002212030417519E0E0481830FEF758 +:1034F000C5F914E0DD481830FEF72CF900280ED18C +:10350000FF20DBA18C3008E0D8481830FEF7EFF937 +:10351000002804D1FF20D6A1943002F084FFB069C6 +:10352000F72201781140017072692032937DDB0728 +:103530001B0F1943FB2319400170D37DDB075B0F81 +:1035400019430170577DEF23022F04D0012F07D0BC +:10355000032F07D00CE0012C06D8002D04D007E083 +:103560006D1E2C43002C03D019401023194300E09A +:1035700019400170D17F002916D0517D012913D047 +:10358000BF48FBF79DFFBE480021283001767269D5 +:10359000916ED26E42610161B949B269FCF7A3FA3A +:1035A0000020FCF7AFFA03E0FBF78AFFFCF7CDFA47 +:1035B000B0690078C00606D4F0690078C00602D46D +:1035C000F079002806D0B079002803D101210846FF +:1035D000FCF79BF8032030703079002803D1FBF70B +:1035E000BDFF01203071F8BD70B5A0481C30FEF75A +:1035F000B9F901259D4C002802D00020607002E03E +:1036000065709F48E061606940300078002802D012 +:103610006078002805D0E069FBF752FFFCF795FAC7 +:1036200070BD9748FBF74CFF9548283005766269D6 +:10363000116F526F42610161914AE169FCF753FADF +:103640000120FCF75FFA70BD10B588490023486976 +:1036500002462030C3768377012049239854A03254 +:103660009279002A03D008700021022001E0002195 +:103670000320FFF7FAFD10BD70B57C4C6079C206DF +:103680002046406901468031002A01DA002202E02A +:10369000CA8DCB8BD218CA850246C0321379002B53 +:1036A00005D0034640331D8AC98B69181982617A97 +:1036B000002903D03D2001F051F94AE003462033B0 +:1036C000D97E042945D0217A002913D0480701D496 +:1036D000C80601D51E2030E0080701D53D202CE0AA +:1036E000C80705D1880703D461A1664802F09BFE94 +:1036F0002A2022E04030817D002905D0418A4D1CDE +:103700004582858AA9420FD2517A062902D0117AC0 +:10371000062905D1018B4A1C0283828A914203D279 +:10372000028AC1898A4201D3222006E09A7F8089D9 +:10373000002A0AD088420FD3082001F00FF96069EF +:103740002030C07E042804D006E0062804D33E20A2 +:10375000F3E7FFF779FF70BD0120207000210846D4 +:10376000FFF783FD70BD10B5404840690146203128 +:103770008A7F002A29D0012A27D0022A06D0032ACC +:1037800004D03BA1404802F04EFE10BDC97E032983 +:103790000FD0082919D001464031CA898989511AA8 +:1037A000891E89B2032900D303218030828B5118EE +:1037B00009E0014640318A89032A06D3028EC9896D +:1037C00080305118491C018310BD8030818BFAE78D +:1037D00000B5030002F018FF0604070B0F121217C2 +:1037E00000290ED00FE0891E02290AD90BE0891F9B +:1037F000012906D907E0082903D004E00B390C2978 +:1038000001D8012000BD002000BDFEB505461748C7 +:103810001830FEF740F8002804D11B4814A1D13815 +:1038200002F001FE114CA069FDF702FC0321A06922 +:10383000FDF721FCA069EF220178114001702946B3 +:10384000FDF740FC002601272B0002F0DDFE0E5C98 +:103850005C085C2C6060255C4C5C603C375C60699B +:103860006521095C002911D0062111E0C400002067 +:103870007372635C6C6C5F736C6176652E630000C1 +:1038800090140020430200005C080000C030417921 +:10389000A069FDF797FC3AE060698030417CA0693F +:1038A000FDF7D7FC33E06169A069B831FDF7ADFCE5 +:1038B0006169A0698C31FDF7AEFC28E00621A069A2 +:1038C000FDF7C5FC23E020690178A069FDF7A9FC9C +:1038D00020698188A069FDF7A6FC20694188A0695C +:1038E000FDF7A5FC13E00096019660696030007951 +:1038F000002803D069460878384308706946A069F3 +:10390000FDF7B1FC03E0F949F94802F08CFDFDF741 +:10391000D4FF002804D1F648F449801D02F083FD4D +:103920000C2D06D0072D03D0606940304682877584 +:10393000FEBD606940300683FEBDF0B5ED4CC82089 +:1039400061698DB0405C04280AD0052835D15C201F +:10395000405C00282AD0012060314871022026E016 +:1039600010226846D63101F030F86169102204A8AF +:10397000B03101F02AF8684601F0DFFB08AE8DCEC9 +:10398000616984250E4678360DC66F5000250D6797 +:103990004D67012540267554D74D88318DC5284681 +:1039A0000822093002F0C1FB052000E00D20FFF7DE +:1039B0002CFF61690020C03108720DB0F0BDF8B570 +:1039C000CC481830FDF767FF002848D0C94C207A52 +:1039D000002844D16069C421095C002500290ED06B +:1039E0002030C17E0120FFF7F3FE002807D1606977 +:1039F0002030C17E0420FFF7EBFE002806D060696E +:103A0000C921095C0126062907D00DE06069502113 +:103A10000D526030457102204EE02030C17E0420FE +:103A2000FFF7D6FE002813D0616908462030C27E19 +:103A3000921E130002F0E8FD166262621D6262626D +:103A400060621F6262622843626262626262466210 +:103A500060695E21095CC90702D0C0304572F8BDBB +:103A60000C20FFF7D2FE60694030817F31438177BF +:103A7000F8BD072020E0FDF79AFF0028F8D0606924 +:103A8000403005700B2017E0F9F741FA0C28EFD30E +:103A900060690821B830F9F73BFA002806D0606960 +:103AA00004218C30F9F734FA002804D1C72093A1FF +:103AB000C00002F0B8FC0420FFF7A7FEF8BDFFF736 +:103AC0003CFFF8BD00228A66CA66C6770A4678318E +:103AD000C8C9894878322838D26842632830C8C0BB +:103AE00008220D30091D02F020FB0620FFF78DFE95 +:103AF000606940308575F8BD0920DDE700F036FFCC +:103B0000F8BD70B57B4C3B216069095C08292FD159 +:103B10000146028EC0314B89521C9A4228D1227A2A +:103B2000002A25D10A8A83889A4207D14B8AC58800 +:103B3000AB4203D18B8A0589AB4209D043884B85C0 +:103B40008A854A8ACA858A8A0A860122E6210A5417 +:103B500001221146FDF747FC00210420FFF785FBF9 +:103B600060690021C92211542030C1760321817778 +:103B700070BD70B55F4C60692030C07E172803D0DF +:103B80005EA1624802F04FFC616900220B4640339F +:103B9000DA7608469A75E030867D0B240125002EE2 +:103BA00006D0837C002B14D1C4740275857410E098 +:103BB0001E7F002E07D01A774C88FA235C520276BB +:103BC0000C23837505E04E88FA235E520276057752 +:103BD00084752031CA7670BD70B5464CA0798007D7 +:103BE00036D5207A002833D160692030C17E01208B +:103BF000FFF7EEFD00282BD1A0690126C078002533 +:103C0000030002F001FD0E8585088537465F0A85B1 +:103C1000168526625285032152E060692030C07EFD +:103C2000052804D0394835A1333802F0FCFB60691F +:103C30000CE060692030C07E092804D033482FA1F1 +:103C40002D3802F0F0FB606956210D542030C57606 +:103C500070BD60692030C07E0B2804D02B4827A19E +:103C6000263802F0E0FB60695B210E540C21203005 +:103C7000C17670BD60692030C07E0F2804D0234813 +:103C80001EA11F3802F0CFFB60695B210E5410218A +:103C9000EDE760692030C07E102804D01B4817A1D2 +:103CA000183802F0C0FB12210AE060692030C07EA3 +:103CB000102804D0154811A1123802F0B4FB1421C9 +:103CC0006069D4E7FFF755FF70BD60690146C030F9 +:103CD000027A062A04D14031897F890700D505720E +:103CE000417A0629F0D1457270BD0000703801009C +:103CF000CD070000C4000020B81400207372635C7C +:103D00006C6C5F736C6176652E6300004C0500007F +:103D1000FD49FE4802F087FBE6E710B5FC4C606900 +:103D20002030C17E0020FFF753FD002803D1207A08 +:103D3000012108432072207A002808D1E069FDF7AC +:103D4000EBF961699122505405202031C87610BDED +:103D500010B5EF4C60690146C0314A7A002A06D09E +:103D6000097A062903D0217A012211432172217A8E +:103D7000002928D14030807F800715D4E069FDF705 +:103D80005AFA61694031C877E069FDF756FA61690E +:103D900040310884E069FDF755FA6169022240313B +:103DA0004884887F10438877606900220146C031CB +:103DB0000B7A062B00D10A724030837FDB0702D1D9 +:103DC00006234B72028310BDF8B5D14C60692030D8 +:103DD000C17E0020FFF7FCFC0125002807D16069A7 +:103DE0004030007F002802D1207A28432072207AB8 +:103DF000002830D160690026014640304682857532 +:103E0000B031E069FDF7EFF96169E0698831FDF7EC +:103E1000F3F960690146E030827D0827002A06D068 +:103E2000817C002913D1C774067585740FE04A8818 +:103E3000F8204252FA31E069FDF7C8F96169E0699A +:103E4000FF310331FDF7CAF96069E03087756069B9 +:103E50000F212030C176F8BD10B5AD4C606920301F +:103E6000C17E0020FFF7B4FC002803D1207A012195 +:103E700008432072207A002812D1E069FDF769F921 +:103E800000280ED0E069FDF75FF96169CA2250523F +:103E9000098E00F0D6FD002806D0282000F05EFD37 +:103EA00010BDFFF73AFF10BDE069FDF74BF96169FE +:103EB000C0310873E069FDF740F96169C031C8811C +:103EC000E069FDF72BF96169C0310882E069FDF70F +:103ED0002AF96169C0314882E069FDF729F9616911 +:103EE000D422505208202031C87610BDF8B5884C35 +:103EF000A079C00776D0207A002873D1606920307D +:103F0000C17E0120FFF764FC002863D1E069002531 +:103F1000C178022701260B0002F076FB0D1613086C +:103F2000415A5A445C575A192F545A00FDF74CF91C +:103F30006169C62250543B20475440314D828E75F2 +:103F400048E000F093FD45E0FFF786FF42E060693E +:103F50002030C17E0020FFF73BFC002802D1207AF0 +:103F600030432072207A002834D160690146403104 +:103F70004D828E750B2120300FE0606901462030A4 +:103F8000C27E0C2A02D0227A3A432272227A002A76 +:103F900020D1C57740310E770D21C1761AE0FFF7A9 +:103FA00013FF17E0606901462030C27E122A02D05A +:103FB000227A3A432272227A002A0BD140318D753F +:103FC0001721EAE7FFF7C4FE04E000F00DFD01E071 +:103FD000FFF7A3FE62690023106F516F401C594127 +:103FE00051671067F8BDF8B5494C05466069203047 +:103FF0008079012801D1FBF7E9FA012D14D160691C +:104000004021095C002903D12030C07F002801D065 +:10401000FBF79BFDFBF7BDFAFBF7B0FAFBF708FADD +:10402000FBF72DFAFBF746FA60790225C107012656 +:10403000002901D180070ED560692030817F0029D9 +:1040400002D0032902D006E0867700E085770021C0 +:104050000120FFF70AF960692030817F012903D12F +:104060006179090700D58577607A002803D100F0CF +:1040700027FDFFF7A4FC207900250028606902D005 +:104080008030058403E08030018C491C0184607914 +:10409000C00705D06069AC210D544030858104E033 +:1040A000616940318889401C8881E079002806D008 +:1040B0006169A031087B022806D8401C087360693A +:1040C000A030007B022806D9606901468030058453 +:1040D0004584A0310D7360692030C17E0020FFF758 +:1040E00077FB002804D160692030C07E072855D1B5 +:1040F00060690146C0310A7A062A4FD0497A0629FA +:104100004CD03E21095C05E0FC3C0100BA050000F2 +:10411000C4000020022941D1A030007B00283DD1FD +:10412000FDF74FFB002839D0FDF704FC002835D0FF +:1041300061690A468032508B01282FD90846A03089 +:10414000844646716038C7898389B81E834201DB83 +:10415000012002E0F81A401E80B2138CA789BB42EE +:1041600001D3012302E0FB1A5B1C9BB2984200D9E9 +:104170001846012801D163465D71C0310B78002BD0 +:1041800010D0528C49888A4201D3012102E0891A59 +:10419000491C89B2884205D9084603E061690120BB +:1041A000A0314D7161690A8E803110188883FFF744 +:1041B000DAFAFFF761FAFEF756FF002809D06069C6 +:1041C0000146FF3001300279002A02D14988C180BE +:1041D00006716069A0308571F8BD70B5F84C6069F2 +:1041E0002030407D00283ED0022810D1FDF7C2FAD1 +:1041F000002804D17120F349000102F014F962692A +:104200000023916ED06E491C58419166D06660695A +:10421000002520304575017D012904D10575A1795E +:1042200010221143A171C17C012915D1C574A07957 +:1042300008210843A071FDF76AFB002804D1E5209E +:10424000E049C00002F0EFF860690023816EC26EA1 +:10425000491C5A41C266816660692030817D01290E +:1042600002D0012181753FE585753DE570B5D44CDF +:104270000026E169012508788207920F0420012AAF +:1042800015D0022A13D0032A03D0217A01432172C8 +:104290002AE560780028FBD1606920308574A17917 +:1042A0002943A17122E0C6751EE5C5751CE5497854 +:1042B000CA0624D06278002AEAD1C906C90E1B2991 +:1042C00018D8617901436171FDF75FFB002804D1C3 +:1042D0003B20BC49400102F0A6F860690023016F51 +:1042E000426F491C5A41426701672030C17D012954 +:1042F000DBD1D8E7207A102108432072F4E460690A +:10430000F3E77CB504460020C0436946888001A8D5 +:10431000FCF7B2FD00287AD169468888FCF790FD49 +:10432000002803D0A749A84802F07DF8009801466C +:10433000E030827C0025002A08D0657010212170B1 +:10434000C17CA170017DE170857472E082799C4E20 +:10435000002A13D065700720207008E07169E620FC +:104360008D8445540A22A01CE83101F0DEFE00983D +:10437000E03080790028F1D1A5705AE0827D002AD2 +:1043800038D0827D130002F03FF90D2F2F2F2F2FF1 +:104390002F2F2F112F2F24082F0065700C21217033 +:1043A000017EA17071694988A18010E065700820C4 +:1043B00020707069082240886080201DFA3101F069 +:1043C000B4FEFF2100980331095AA181E0308575C0 +:1043D0002FE065700B212170017EA1707169498801 +:1043E000A180017FA171F2E7774876495D3002F044 +:1043F0001AF81EE0C81DF9300279002A08D01122EF +:1044000065702270811C89886180057111E012E05D +:10441000027A002A0FD012226570FF312270033118 +:1044200004E005720A8962804A89A280027A002A21 +:10443000F7D101207CBD00207CBD614800780128B7 +:1044400001D00C2070470020704770B55C4C0546C9 +:104450002078002804D05C485A49933001F0E3FFEB +:1044600000202561A07201202070FFF7E6FF0028E0 +:1044700004D0554853499E3001F0D5FF34E4F8B5D7 +:104480004F4F3978012901D00C20F8BD0126A62113 +:1044900078610E548030807CFDF752F900282FD0CF +:1044A00078698030807CFDF753FA002828D078693D +:1044B0008030807CFDF7E5F9002821D078698030D4 +:1044C000807CFDF70AFA00281AD0FAF7E6FF78692F +:1044D00000258030408B002827D039481830FDF760 +:1044E000DAF9002821D07869C421095C00291CD0A0 +:1044F0002030C17E0120FFF76BF9002802D014E0C4 +:104500001220F8BD78692030C17E0420FFF760F9E1 +:1045100000280AD1786950210D526030457102207F +:10452000FFF773F97869A03045717869E621095C75 +:10453000002903D1818CC288914200D8C188B981F9 +:1045400001468031CA8B521E93B20A8CD21892B2A5 +:104550000A8494460246A0321479002C02D04D847D +:10456000157102E04C8CE4184C8404464034A78951 +:10457000FF18A7814C8B012C01D8641C4C83002BA5 +:1045800000D015732030C07E0D4C04281ED0507909 +:1045900000281DD0A1898C451AD2FDF712F90028F8 +:1045A00016D060690146C0310A78002A10D08030E8 +:1045B000408C498888420BD3A570E6700AE0000061 +:1045C000C4000020FC3C010081080000A67001E04E +:1045D000A570E5706069A5210D543B21095C062991 +:1045E00001D0072918D1CA21028E095A511A09B2DD +:1045F000002911DB01460522CC310A3001F095FD7E +:10460000012202216069FCF7EEFE6069C9210D54A8 +:104610003B210D546030867160699E210A5A811CCD +:104620003030FCF71EFFA07800283DD16069C02122 +:10463000095C002901D0803045840120FAF7A4FDEF +:1046400060691330FAF713FF60690F30FAF753FE11 +:104650000120FAF71FFF61694020405C002803D168 +:104660003F20405C00280DD00A467831C8C9F9487F +:104670007832D26842632830C8C008220D30091D44 +:1046800001F053FDFAF701FF01210846FAF758FE41 +:1046900060698030806AFAF716FFFEF7A5FF60694F +:1046A0004030007AFAF730FE6571E571A571257228 +:1046B0006572257102202070FAF7FCFE0020F8BD1B +:1046C00010B5E54C2078022801D00C2010BDA07850 +:1046D000002803D00020FFF786FC17E0FAF7DDFE84 +:1046E00000F033F9606920308079012801D1FAF7B0 +:1046F00076FFA07A002809D0012807D0022807D029 +:10470000032805D0D549D64801F08DFE002010BD04 +:10471000EEF77EFCFAE7D0498872704710B5CE4CB0 +:104720002078032804D0CE48CC49293001F07BFE04 +:10473000606901212030827C002A06D00022827428 +:104740000175A27904231A43A271A2691378DB438D +:104750009B0707D1C37C002B04D1C174A07902212F +:104760000843A0711078C00606D4E0690078C0063E +:1047700002D4E07900280CD06078002809D1A07913 +:10478000002806D1FEF75DFC002802D0207A002820 +:1047900003D00120FFF727FC03E0FEF725FF00F020 +:1047A000D4F8207801280DD0A07A00280AD001285A +:1047B00008D0022807D0032805D0A948A7496830A7 +:1047C00001F031FE10BD0120FBF719F810BD10B546 +:1047D000A14C606920308079012812D1FAF7F6FEE9 +:1047E0006169881C3031FCF7C5FE002809D060697A +:1047F000C21D4388F93253812030007E107301209E +:10480000107210BD70B5944C05462078042804D071 +:1048100093489249803001F006FE617910200143EF +:104820006171002D50D0FBF7A8F96178012508438C +:10483000002811D160694021095C00290CD0E16990 +:104840004A78D20608D0097820300907C07DC90F00 +:10485000814201D165724EE0E078002809D0E0691C +:104860004178C90605D10078C00602D4FFF7AFFF32 +:1048700041E0FFF7ACFFE06900784007C10F6069D5 +:104880002030807D814205D0FFF7A7FC60790821A8 +:1048900008436071E06900780007C10F606920304B +:1048A000C07D814201D1FFF7E1FC6079284360714E +:1048B0000020E071A079000704D560692030C07E37 +:1048C000032818D0207A14E0022001436171E079B6 +:1048D000401CC0B2E07101280DD8606940300078FA +:1048E00000280CD05B484078C106C90E052906D2C5 +:1048F000C006002803D00120FFF775FB01E0FEF79A +:10490000BDFD207801280DD0A07A00280AD001280A +:1049100009D0022806D0032805D051484F49E2307B +:1049200001F081FD9FE40120FAF769FF9BE410B5D7 +:1049300049480078042804D049484849EA3001F041 +:1049400072FD0120FFF74FFB10BD10B501210020C3 +:10495000FAF7DBFE40490420087010BD3E494A22A8 +:104960004969505404202031C876704710B53A4C3C +:10497000C8206169405C00281CD0062806D0203180 +:10498000C97E0020FEF724FF002813D0606901468D +:10499000C0310A7A130001F037FE070D0D0D0D0D21 +:1049A0000D050D004030807FC20704D0C043800752 +:1049B00000D1087210BD0C20FEF727FF60690122AC +:1049C0004030817F1143817710BD10B5002A0AD095 +:1049D000002306E0D41A6418203CE47FC4545B1C16 +:1049E000DBB29342F6D310BD7CB51B4C606920301E +:1049F000C17E0020FEF7ECFE0125002802D1207ABE +:104A000028432072207A00281AD16946E069FCF711 +:104A100022FC684600780022C107C90F6846017071 +:104A20006069002902D06030057101E060300271D8 +:104A30006069014640304282857509202031C87680 +:104A40007CBD401A074900B2884201DC00280BDC1B +:104A50000120704790140020C4000020FC3C01009D +:104A6000F4090000FE7F00000020F2E710B5534C6F +:104A700060692030C17E0020FEF7AAFE0028207A5F +:104A800010D000280DD1E069FCF797FB6169CA22BC +:104A90005052098EFFF7D5FF002807D02820FFF7D6 +:104AA0005DFF10BD01210843207210BD6169E069FE +:104AB000CC31FCF77AFB606906212030C17610BD4D +:104AC00010B500F04EF83D4C607940070BD5606999 +:104AD0002030C17E0520FEF77BFE002803D0207A1F +:104AE000082108432072FFF701FA00F018F8FFF7D9 +:104AF00073F8A079C0060FD5207A00280CD1606920 +:104B00002030C17E0B0001F07FFD07070707070774 +:104B1000070507000721C176FEF7F3FF10BD10B5AA +:104B200026488179490715D5017A002912D14069B3 +:104B30003B21095C891E0B0001F066FD07050C0C8A +:104B40000C0D0C0F0C00002256210A54C030807945 +:104B5000FFF704FF10BD012100E00221C0304172C7 +:104B600010BD10B515488179090720D5017A0029B3 +:104B70001DD1406902462032D47EA41E230001F0DC +:104B800043FD13160B1616161616161616161616BF +:104B90001616161616171600562211546030407954 +:104BA000002801D0062000E01620FFF7D7FE10BD38 +:104BB0004030C1768175D17610BD0000C400002060 +:104BC00030B50346002002460DE09C5C2546303D92 +:104BD0000A2D02D30020C04330BD0A256843303877 +:104BE0002018521CD2B28A42EFD330BD70B50D46A8 +:104BF000144608E00A2101F012FB2A193031203A4C +:104C0000641ED177E4B2002CF4D170BD10B500233E +:104C100010E0040A00020443A0B2CC5C4440200629 +:104C2000000F60400407240C44402006C00C604084 +:104C30005B1C9BB29342ECD310BD000010B572B662 +:104C400000F0DCF800280BD0ECF72AFBF8F7EFFDBA +:104C500000F0A5FD6E490020C86288626D490860B9 +:104C600062B6002010BDF3B5002501200007C06A20 +:104C700081B0C0430006000E04D167480068401CA4 +:104C800000D1012572B600F0B9F8002802D062B652 +:104C90000820FEBDECF75AFAECF706FB5F4B604EBE +:104CA00000211A68CA40D2071FD00246CA40D20764 +:104CB00018D14AB2002A07DA1407240F083CA408C6 +:104CC000A400A419E46904E09408564FA400E41970 +:104CD00024689207D20ED4402206920F012A04D0F3 +:104CE000032A02D062B65048FEBD491C2029D8D301 +:104CF0000198030001F088FC14212323232323239C +:104D000023230B0D0F11131F1517191B1D2E002424 +:104D100016E0012414E0022412E0032410E004242D +:104D20000EE008240CE009240AE00A2408E00B2421 +:104D300006E00C2404E0052402E0072400E0062439 +:104D4000F06901210002000AC9070843F061002D43 +:104D500004D009E062B601200003FEBD2C4D3348AB +:104D6000E862ECF7A1FAA8622A49314808603149A3 +:104D700002980860ECF798FA214600F0F7FCF8F783 +:104D80001AFD00F0FDFE00F073FD0198ECF756FAF5 +:104D9000040062B603D0FFF751FF2046FEBD00209D +:104DA000FEBD10B5044600F029F8002800D001200F +:104DB0002070002010BD204908600020704710B509 +:104DC0000C46102808D011280BD012280CD013281C +:104DD0000ED00120086010BD03CC083CFFF743FF54 +:104DE0000AE0FFF72BFF07E02068FFF7DAFF03E098 +:104DF0001149206808600020206010BD05480C495A +:104E00000068884201D101207047002070470000EF +:104E100000050040780000200010001000E100E0D4 +:104E200000ED00E000E400E00110000000190000C7 +:104E3000BEBAFECAE40000200400002010B52038ED +:104E40000C46030001F0E0FB33A6AAAEB2B8BCC02A +:104E5000C5E0DBE41B1F23272C31373C41474D5075 +:104E600054585C606D71656974787C8084888C901E +:104E700094989C9FA2CACFE9F0F3D3D7F80020689A +:104E800000F0DDF8D6E0206800F0E1F8D2E020681C +:104E900000F0F5F8CEE0207840B200F0D7FAC9E093 +:104EA000207840B200F0F5FAC4E02078616840B2A2 +:104EB00000F008FBBEE0207840B200F018FBB9E03B +:104EC000207840B200F023FBB4E02078217940B292 +:104ED00000F02EFBAEE02078616840B200F058FB95 +:104EE000A8E000F064FBA5E0206800F068FBA1E00A +:104EF000207800F07DFB9DE02068F8F72CF899E021 +:104F00002068F8F72CF895E021792068F8F72EF85A +:104F100090E0206800F0E6F98CE0206800F0E7F906 +:104F200088E0207800F0E7F984E000F0F1F981E012 +:104F3000207800F0F3F97DE0207800F005FA79E0C0 +:104F4000206800F01EFA75E0206800F020FA71E099 +:104F5000206800F022FA6DE0206800F023FA69E092 +:104F6000206800F025FA65E0206800F027FA61E08B +:104F7000206800F028FA5DE00846ECF7FFF859E0F9 +:104F8000EDF719FA56E0EDF746FA53E02068EDF731 +:104F90004EFA4FE0206800F0E1F84BE0206800F0A6 +:104FA000E9F847E0206800F0F0F843E02078A268D4 +:104FB000616800F0F5F83DE0207800F006F939E08E +:104FC000207800F017F935E02078616800F027F9C3 +:104FD00030E02078616800F03AF92BE02179207800 +:104FE00000F016FC26E0206800F06BF822E0206854 +:104FF000F8F70CFB1EE02068F8F7F0FA1AE007CC8F +:105000000C3C00F0FFFC15E0206800F052FD11E0C0 +:1050100003CC083C00F07DFD0CE0206800F06EFF42 +:1050200008E009E003E0FFE700F080FF02E020680D +:1050300000F0B8FF206010BD0120086010BD002105 +:105040000170084670470146002008707047EFF372 +:105050001081C907C90F72B60278012A01D0012256 +:1050600000E0002201230370002900D162B6002A6B +:1050700001D000207047012040037047E7E7EFF3BD +:105080001081C907C90F72B600220270002900D131 +:1050900062B600207047F2E710B52848FFF7CFFF4F +:1050A000002803D026A11D2001F0BDF92348401C93 +:1050B000FFF7C5FF002803D021A1212001F0B3F99B +:1050C00010BDF1B5224D6F6801261C48FFF7BFFFE8 +:1050D0001A4C002803D10026601CFFF7D0FF1D4AA0 +:1050E0001D490120506000BF00BF00BF00BF00BFCE +:1050F00000230B604B60009B6B60106000BF00BF23 +:1051000000BF00BF00BF0868002802D1486800281F +:10511000F9D048680028E4D1002E04D06F60601CEC +:10512000FFF795FF07E0601CFFF791FF0028D3D140 +:105130000248FFF7A4FF0020F8BDC2E7E800002006 +:105140007372635C736F635F6563622E630000005C +:1051500000E5004000E0004000E100405A495B4BA0 +:105160000A685B499A42096801D18904890C016087 +:10517000002070475449554B0A6855499A4201D15D +:105180008004800C4860002070474F494F4B0A68EC +:105190004F499A4201D18004800C886000207047FA +:1051A00030B5494B494D1C684A4BAC4202D01028DF +:1051B00002D203E00E2801D3184630BDC300444894 +:1051C000181801614261002030BD3F493F4B0A6819 +:1051D0004049491C9A4202D0042802D203E0022826 +:1051E00001D3084670473C4A0121C0008018016085 +:1051F000002070473449354B0A683649491C9A42A9 +:1052000002D0042802D203E0022801D308467047E6 +:10521000314A0121C000801841600020704770B5FC +:10522000294A2C4B14682D4E284D82005B1C921984 +:10523000AC4203D0042803D2116006E0022801D357 +:10524000184670BD8804800C1060002070BD70B5D9 +:105250001D4A204B1468214E1C4D82005B1C921984 +:10526000AC4203D0042803D2106806E0022801D320 +:10527000184670BD10688004800C0860002070BD66 +:1052800010B5134A164890600E200021C3009B18E9 +:1052900019615961401C1028F8D300200F4A05E01D +:1052A000022803D383009B18196005E083009B1834 +:1052B0001C68A404A40C1C60401C0428F0D310BD7E +:1052C000034907488860704778000020BEBAFECACC +:1052D00000F501400820000000F0014000F8014006 +:1052E00000C0FFFF47490968016000207047454939 +:1052F0000860002070470121434A002803D001289C +:1053000003D042487047916300E0D16300207047AA +:105310003F49012008603D48801C704704223D4BF6 +:105320003B49002805D05A600869012210430861F2 +:1053300008E008694008400008619A60324900208E +:10534000C03188600020704731490622002808D00B +:10535000012809D002280DD003280FD02B48401C6B +:1053600070470869904302E008699043801C086117 +:105370000020704708699043001DF8E70869104352 +:10538000F5E723494A6A02434A62002070472049F0 +:105390004A6A82434A62002070471D49496A016097 +:1053A000002070471A49CA690243CA610020704749 +:1053B0001749CA698243CA61002070471449C96904 +:1053C0000160002070471249024600204031002A47 +:1053D00003D0012A01D0072070478A6370470D4926 +:1053E0000420886008490020C03188600A480168AC +:1053F0008022090A0902114301600849012008605E +:1054000070470000000400404000004004200000FD +:10541000000500400003004000E400E000E100E07F +:105420008107C90E002808DA0007000F0838800835 +:10543000814A80008018C06904E080087F4A8000AB +:1054400080180068C8400006800F704710B50446F9 +:1054500000F0DBF8002813D02046FFF7E1FFC0B2D0 +:1054600000F0E1F800280DD07549E2060B78D20E65 +:1054700001209040002B08D04A681043486006E0A5 +:10548000704810BD6F48401C10BD6F490860002077 +:1054900010BD10B5044600F0B8F800280BD06849DC +:1054A000E2060B78D20E01209040002B05D04A680E +:1054B00082434A6004E0634810BD6349803108605C +:1054C000002010BD70B50D46044600F09EF800287F +:1054D0000BD05E480068E206D20E012191400840E0 +:1054E00000D001202860002070BD564870BD10B566 +:1054F000044600F08AF8002807D0E106C90E012012 +:10550000884052490860002010BD4E4810BD10B5BB +:10551000044600F07AF8002808D0E106C90E012000 +:1055200088404A4980310860002010BD454810BDC0 +:1055300070B50D46044600F068F8002819D02846DA +:1055400000F071F8002816D0A007C10EFF228A4093 +:10555000A807000E8840002C10DA2107090F08392F +:105560008B0835499B005B18D96991430143D96188 +:105570000CE0344870BD3348401C70BDA3082F496F +:105580009B005B181968914301431960002070BDAE +:1055900070B50C46054600F038F8002805D02846BE +:1055A000FFF73EFF2070002070BD264870BDBFF39E +:1055B0004F8F21492648C860BFF34F8FFEE770B573 +:1055C0001F4C05462178012000290ED1207072B6AB +:1055D00000F0F4F81C4E803631688143616000F0C1 +:1055E000EDF8C043306062B600202870002070BD26 +:1055F00013490A78002A06D0002804D1124A4868C4 +:105600001060002008700020704710B50446202864 +:1056100007DA00F0D3F80121A140084201D10120AE +:1056200010BD002010BD012803D0032801D00020A8 +:10563000704701207047000000ED00E000E400E04A +:10564000EC0000200120000000E100E000E200E0AA +:105650000400FA05F8B50446800700250126002855 +:1056600004DA5848C563C66302208443E00404D5C5 +:105670005548C563C66380148443600003D553480E +:10568000456080058443E00504D55148C563C66381 +:1056900080158443A00404D54E48C563C6634014F6 +:1056A000844360042704C00FF90F884203D04AA145 +:1056B000612000F0B8FEB80F0AD04C49CD634C48C9 +:1056C000C563C563CE63C663C6630320800384439A +:1056D00020050AD5474FFD632F20EBF765FDFE63DC +:1056E0002F20EBF761FDF8148443FFF7C9FD424812 +:1056F000044203D038A18D2000F095FEF8BDF0B52E +:1057000000210A46FF230446CC40E4072AD04CB2CD +:10571000E606F60E0125B540384E3560384E356048 +:10572000002C11DA25072D0F083DAE08354DB600C7 +:105730007719FD69A407E60E1C46B440A54314463C +:10574000B4402543FD610DE0A6082F4DB600761943 +:105750003568A407E70E1C46BC40A5431446BC4070 +:1057600025433560491C2029CDD3F0BD70B5274CA9 +:105770000D462060FFF76EFF2068FFF7C0FF284648 +:10578000ECF7EAFEFFF788FCF7F778FBFFF778FD08 +:10579000FFF725FEECF766FD00F06AF870BD10B566 +:1057A0001A4C2068FFF756FF2068FFF7A8FFFFF7A5 +:1057B00067FDECF74BFF0020206010BD1348006828 +:1057C00070470000C01F0040C0CF004000E501400E +:1057D000C08F0040C0DF00407372635C736F635F13 +:1057E000636F6E6669672E6300000000C0EF0040C3 +:1057F000C0FF0040C0BF0040FEFF0FFC80E100E0A2 +:1058000080E200E000ED00E000E400E0F4000020B1 +:1058100070B5002402460D4620462146002A1ED0BF +:10582000012A04D0022A04D0032A1ED103E0012059 +:1058300002E0022013E003202B0000F0E5FE071633 +:105840000507090B0D0F1600012108E0022106E0F3 +:10585000032104E0042102E0052100E00621F8F71D +:1058600058F8002801D0204670BD0724FBE700004F +:10587000B348002101708170704770B5B14D0123AC +:105880006B60B14B1C68002CFCD0002407E00E6854 +:1058900006601E68002EFCD0001D091D641C944289 +:1058A000F5D30020686018680028FCD070BD70B582 +:1058B000A34C0E466178884203D0A4A16F2000F06B +:1058C000B2FD0325330000F09FFE09520624245246 +:1058D0005252524952002078022803D09BA17320D3 +:1058E00000F0A1FD2570A078022802D0012804D084 +:1058F00008E0A06800F0D2FB04E02046083007C8AA +:10590000FFF7BBFF0020A070F7F7A4FF0420207072 +:1059100070BDF8F754F801466068F9F776FA064664 +:105920002078022803D089A1872000F07CFD8B4AD3 +:105930008B498C48964205D86269032A02D2521CD0 +:10594000626102E0864207D84D71801BC8608449BD +:105950006078F8F7B4FC70BD032003E0A07800285D +:10596000FAD10220F7F77EFE00F0E1F870BD77A1D2 +:10597000B12000F058FD70BD70B50546F8F71FF86E +:105980006F4C60602078012803D070A1B82000F02F +:105990004AFD73490220087000220A718D600422BA +:1059A0004A71704ACA6020706078F8F788FC70BD50 +:1059B00010B5634CA078002802D12078002801D0CF +:1059C000112010BD6848F7F78BFF607060780028E1 +:1059D00004D0012020700020606110BD032010BDA4 +:1059E00010B50124020B64040121604BA04202D2D5 +:1059F0009140186802E0203A58689140084000D071 +:105A0000012010BDF8B50E46910005464F19144609 +:105A10003F1F009100F053FB009980028919091F74 +:105A2000B14201D2012200E00022002C03D0FF216C +:105A300001318C4201D90920F8BD4D498D4219D35D +:105A4000AF4217D3854205D2874203D2284630435E +:105A5000800701D01020F8BD8E420BD3002A09D157 +:105A60002846FFF7BDFF002804D13846FFF7B8FFEE +:105A7000002801D00F20F8BD3E483F490068884209 +:105A800005D0224631462846FFF7F7FE0FE0FFF724 +:105A90008FFF0028EFD12A480121C660856004618C +:105AA00081702046302148431830FFF765FF002001 +:105AB000F8BD10B504462E48800A84420BD300F08E +:105AC000FEFAA04201D8102010BDA0020446FFF744 +:105AD00087FF002801D00F2010BD26482649006806 +:105AE000884203D0204600F0D9FA0AE0FFF760FFB1 +:105AF0000028F1D112480221846081701F48FFF70D +:105B00003BFF002010BD1A48010B01208840401EB9 +:105B1000704700B50B460246FFF7F5FF104201D073 +:105B20000F2000BD114802604360002000BD10B589 +:105B3000034C6078F7F728FF00202070A07010BD9C +:105B4000F800002000E5014000E401407372635C4E +:105B5000736F635F666C6173682E6300307500005D +:105B6000E0140020D0FB0100AF5801000006004007 +:105B70000080010078000020BEBAFECA3A5600003C +:105B8000F74805218170002101704170C17081606A +:105B9000704710B5F3490A78022A07D0CA6810186E +:105BA000C860C8689638F9F7E9F810BD8A68101817 +:105BB00088608868F6E70378EB49EC4A002B02D04E +:105BC000012B10D014E00379002B01D0012B0FD151 +:105BD0004379002B01D0012B0AD18368643B8B42AF +:105BE00006D2C06810E00379002B03D0012B01D04E +:105BF000002070474379002B01D0012BF8D1C368F6 +:105C0000643B8B42F4D280689042F1D80120704707 +:105C1000F8B504460226F8F740FD0068002803D0D6 +:105C2000D3A1BD2000F0FFFB0127CD4D002C08D0F3 +:105C30002078002817D0012805D0022811D0032889 +:105C400013D02F710DE06068C82808D3F9F70BF95D +:105C5000002804D06068FFF79CFF012603E00026BF +:105C600001E000F0F9F93046F8BD28780028F8D1B5 +:105C70006068FFF7A0FF0028E3D060680078002884 +:105C800026D0A878042803D0B9A1F72000F0CBFBD8 +:105C9000B44F0020387060680079012800D00020DF +:105CA000387160684079002837D0042078716068C6 +:105CB0008168E868F8F71DF9B8606068C0689630D8 +:105CC000F8600320A870A749E878F8F7F8FAC8E761 +:105CD000A4480221017061680979012919D00021C5 +:105CE000017161684979002915D004214171616809 +:105CF0008968963181606168C968C160C068984CE4 +:105D000014346060F7F75BFE20606F700220A870AB +:105D1000A7E70321E4E70321E8E70320C6E7F8B596 +:105D20008F4C0D46E178884204D0FF2090A11930B5 +:105D300000F079FB28468A4F00250126143703001E +:105D400000F062FC090612375A7C8D97C4A0C4008B +:105D5000A078032807D0A078022804D0FF2084A1CF +:105D60001D3000F060FBF8BDA078032807D0A078B4 +:105D7000022804D0FF207EA1213000F054FB042033 +:105D8000A07025712078002810D1FFF702FFE0787D +:105D9000F8F7D6F8E0607D49886A7D4A02402261C2 +:105DA0007B4AD24310408862002050E000F054F952 +:105DB000F8BDA078032807D0A078022804D0FF20DF +:105DC0006BA1423000F02FFB2078002802D000F0B9 +:105DD0004FF9F8BDA07803281FD104202AE0091A42 +:105DE0006048C1600146E078F8F769FAF8BD042020 +:105DF000F7F738FCA570F8BDA078032807D0A07885 +:105E0000022804D0FF205AA1633000F00CFB207858 +:105E10000028DCD1A07803280BD0F7F7D0FD01468D +:105E20003868F8F7F2FF0028E1DB79688142DEDBB1 +:105E3000D5E70520F7F716FCA670F8BDA078042872 +:105E400004D0FF204AA1843000F0EDFA0220A168BE +:105E50008847FFF7DDFEFF260546BD3642E0A07805 +:105E6000042804D0FF2042A1893000F0DCFA012090 +:105E7000EDE7A078042899D0FF203DA18E3000F0F6 +:105E8000D2FA93E7A07804280AD06078002802D0DC +:105E9000A078022804D0FF2035A1933000F0C3FA87 +:105EA0002078002893D12079002804D00620F7F725 +:105EB000D9FB2571C0E76078002805D02949E07832 +:105EC000F8F7FDF96570F8BD0720B3E7FF2028A1BA +:105ED000AE3046E7002D0AD0012D06D024A1304671 +:105EE00000F0A1FA022DF5D1F8BD042000E0032056 +:105EF000A1688847FFF78CFE0546F3E770B50500FB +:105F000005D0174CA078052803D0112070BD1020B3 +:105F100070BD2048F7F7E4FCE070E078002803D07B +:105F2000A5600020A07070BD032070BD10B50C48A6 +:105F30000178002901D0112010BD817805292BD0CE +:105F4000817801292AD08178002927D00121017088 +:105F50008178012922D0807800281FD020E000001D +:105F600010010020F01400203D860100FF1FA10752 +:105F70007372635C736F635F726164696F5F74698E +:105F80006D65736C6F742E630000000000050040A7 +:105F9000028100001F5D01000F2010BD00F068F8B5 +:105FA000002010BDF8B5394E0446B078002801D065 +:105FB00001280DD1002C0DD02046FFF7FCFD002854 +:105FC0000AD02078324D002808D0B078012823D09C +:105FD0000F20F8BD1020F8BD0720F8BD02272F7054 +:105FE0002079012814D0002028716079002811D070 +:105FF00004206871A0689630A860E068E860E868EE +:10600000224C14346060F7F7DAFC2060B77019E0B6 +:106010000320E9E70320ECE700202870207901281D +:1060200016D0002028716079002813D004206871F0 +:10603000A168F068F7F75DFFA860E0689630E86057 +:106040000320B0701249F078F8F739F90020F8BD54 +:106050000320E7E70320EAE710B50E48816A0E4AFD +:1060600011400A4A126911438162F7F7F3FB10BD30 +:1060700010B5064CE078F7F787FC0820F7F7F2FA3E +:106080000520A07000202070607010BD100100205D +:10609000F014002000050040FD7EFFFF0A4A0221A7 +:1060A00051600A490B68002BFCD0906008680028FA +:1060B000FCD00020506008680028FCD07047012008 +:1060C000000740697047000000E5014000E401401E +:1060D000034610B50B439B070FD1042A0DD308C804 +:1060E00010C9121FA342F8D018BA21BA884201D9A8 +:1060F000012010BD0020C04310BD002A03D0D307EB +:1061000003D0521C07E0002010BD03780C78401C1F +:10611000491C1B1B07D103780C78401C491C1B1B16 +:1061200001D1921EF1D1184610BDF8B5042A2CD326 +:10613000830712D00B78491C0370401C521E830742 +:106140000BD00B78491C0370401C521E830704D0EF +:106150000B78491C0370401C521E8B079B0F05D007 +:10616000C91ADF002023DE1B08C90AE0EBF72CF870 +:10617000F8BD1D4608C9FD401C46B4402C4310C064 +:10618000121F042AF5D2F308C91A521EF0D40B7854 +:10619000491C0370401C521EEAD40B78491C037042 +:1061A000401C012AE4D409780170F8BD01E004C064 +:1061B000091F0429FBD28B0701D50280801CC90767 +:1061C00000D00270704700290BD0C30702D00270C4 +:1061D000401C491E022904D3830702D50280801C7B +:1061E000891EE3E70022EEE70022DFE70378C278AA +:1061F0001946437812061B0219438378C0781B04A2 +:10620000194311430902090A000608437047020AAC +:1062100008704A70020C8A70020ECA707047002221 +:1062200003098B4273D3030A8B4258D3030B8B426F +:106230003CD3030C8B4221D312E003460B437FD4A3 +:10624000002243088B4274D303098B425FD3030AB5 +:106250008B4244D3030B8B4228D3030C8B420DD3C8 +:10626000FF22090212BA030C8B4202D31212090256 +:1062700065D0030B8B4219D300E0090AC30B8B4294 +:1062800001D3CB03C01A5241830B8B4201D38B0342 +:10629000C01A5241430B8B4201D34B03C01A5241E7 +:1062A000030B8B4201D30B03C01A5241C30A8B422A +:1062B00001D3CB02C01A5241830A8B4201D38B0215 +:1062C000C01A5241430A8B4201D34B02C01A5241B9 +:1062D000030A8B4201D30B02C01A5241CDD2C3092B +:1062E0008B4201D3CB01C01A524183098B4201D3A7 +:1062F0008B01C01A524143098B4201D34B01C01A92 +:10630000524103098B4201D30B01C01A5241C30809 +:106310008B4201D3CB00C01A524183088B4201D378 +:106320008B00C01A524143088B4201D34B00C01A64 +:106330005241411A00D201465241104670475DE079 +:10634000CA0F00D04942031000D3404253400022FC +:106350009C4603098B422DD3030A8B4212D3FC22A5 +:10636000890112BA030A8B420CD3890192118B4224 +:1063700008D3890192118B4204D389013AD092113A +:1063800000E08909C3098B4201D3CB01C01A5241F5 +:1063900083098B4201D38B01C01A524143098B42BE +:1063A00001D34B01C01A524103098B4201D30B01A7 +:1063B000C01A5241C3088B4201D3CB00C01A5241CC +:1063C00083088B4201D38B00C01A5241D9D24308B3 +:1063D0008B4201D34B00C01A5241411A00D20146F0 +:1063E000634652415B10104601D34042002B00D55A +:1063F0004942704763465B1000D3404201B500201C +:10640000C046C04602BD70477047704710B500F0E7 +:106410003BF810BD012308CB134B1860134B1960D8 +:10642000134B1A607047134A134B13607246053AB8 +:10643000F0E7114A0F4B1B689A420ED10D4B00201A +:10644000186001980D4B04B598470CBC9E46024657 +:10645000029800990A4B1B68184706980599094B42 +:106460001B68DB6818470000340100203801002059 +:106470003C0100202C010020EFBEADDEC9CD0000A4 +:10648000E4000020040000201D481E497047FFF76B +:10649000FBFFEAF753FE00BD01200007C06AC0B24F +:1064A000FF2804D1184819490968884202D01848C1 +:1064B00018490160184819490968884203D1184AE7 +:1064C00013605B68184700BD20BFFDE71248134901 +:1064D000096888420ED1134B18680B498842F3D0E3 +:1064E00080F308881049884204DD104802680221C0 +:1064F0000A4302600E4880470E4880470E48004716 +:106500000015002000150020FFFFFFFF0010001005 +:106510002C050040080000000010000000000020D2 +:10652000040000200080010000200020240500401D +:10653000DFCD000099640100156401001348704527 +:1065400002D1EFF3098101E0EFF308818869023895 +:106550000078102814DB202810DB2B280BDB0C4ADA +:1065600012680C4B9A4203D1602804DB0A4A104798 +:10657000022008607047094A10470000084A104787 +:10658000084A12682C32126810470000FDFFFFFF16 +:1065900078000020BEBAFECAAD1200003D4E0100D8 +:1065A000BF4D0100040000200D4B0E4908470E4B63 +:1065B0000C4908470D4B0B4908470D4B0949084743 +:1065C0000C4B084908470C4B064908470B4B05493B +:1065D00008470B4B034908470A4B0249084700008C +:1065E00079250000192200009D2B00003F2A0000A1 +:1065F000ED2900009F270000B912000013140000CD +:10660000012B00000F23000030B47446641E25786F +:10661000641CAB4200D21D46635D5B00E31830BCD6 +:10662000184703B5684600784006400E401C884273 +:1066300005D269460878401CC0B208700CBD684697 +:106640000078000601D500200CBD80200CBD414023 +:10665000802901D0002070470120704737B50878A5 +:106660000C4669460978884206D020781146FFF723 +:10667000D8FF207001203EBD00203EBD37B5044646 +:106680000078154669460979FFF7E1FF002801D037 +:1066900000203EBD20782946FFF7C3FF207001206F +:1066A0003EBD0FB568460179007881420AD0684640 +:1066B000007922214006400E4843801818600120CE +:1066C00004B000BD0020FBE77FB5684601791C4699 +:1066D00015460078FFF7BBFF002802D0002004B069 +:1066E00070BD6846007822214006400E484340199C +:1066F00020600120F3E70000FFFFFFFF0000FFFF25 +:106700000100030000000100000000000000000084 +:1067100000000000000000008700000000000000F2 +:10672000000000000000000000000001020304005F +:106730000D0E0F100000000033690000516B0000C7 +:10674000196C0000736C0000C76C00002F6D000016 +:106750008D690000456A0000D16D0000DF790000FE +:10676000100110013A0200001A02000004013C006E +:10677000230044000E0001020408102040805555FB +:1067800055D6BE898E0000007006120DB4130000AD +:1067900014035A06A00900006004F208840DF401F5 +:1067A000FA00960064004B0032001E001400000046 +:1067B000E067010008000020100000000411000044 +:1067C000F0670100180000202801000004110000FB +:1067D0001869010040010020C013000020110000D2 +:1067E0000249022208681042FCD0704700E200E033 +:1067F0000000000000000000000000000000000099 +:106800000000000000000000000000000000000088 +:106810000000000000000000000000000000000078 +:10682000000000000100010054000020FB349B5FC9 +:106830008000008000100000000000000000000048 +:106840000000000000000000000000000000000048 +:106850000000000001000000000000000000000037 +:106860000000000000000000000000000000000028 +:106870000000000000000000000000000000000018 +:106880000000000000000000000000000000000008 +:1068900000000000000000000000000000000000F8 +:1068A00000000000000000000000000000000000E8 +:1068B00000000000000000000000000000000000D8 +:1068C00000000000000000000000000000000000C8 +:1068D00000000000000000000000000000000000B8 +:1068E00000000000000000000000000000000000A8 +:1068F0000000000000000000000000000000000098 +:106900000000000000000000196401000000000009 +:0869100000000000000000007F +:1080000000400020CD3C0200093D02000B3D020073 +:108010000000000000000000000000000000000060 +:108020000000000000000000000000000D3D020004 +:1080300000000000000000000F3D0200113D0200A2 +:10804000133D020089D80100BD3F0200133D02002C +:10805000133D020000000000C9400200133D020071 +:10806000133D0200653D020045440200133D02003D +:10807000133D0200133D0200133D0200133D0200B8 +:10808000133D0200133D0200133D0200133D0200A8 +:10809000133D0200F136020085380200133D020054 +:1080A000133D0200133D020000000000000000002C +:1080B00000000000000000000000000000000000C0 +:1080C000054B0648033310B51B1A062B03D9044B86 +:1080D000002B00D0984710BDC0200020C0200020F9 +:1080E000000000000648074910B5091A8910CB0F97 +:1080F0005918491003D0044B002B00D0984710BDED +:10810000C0200020C02000200000000010B5074C57 +:108110002378002B09D1FFF7D3FF054B002B02D0AA +:10812000044800E000BF0123237010BDD8200020C8 +:1081300000000000B8450300094B10B5002B03D028 +:108140000849094800E000BF08480368002B02D135 +:10815000FFF7C8FF10BD064B002BF9D09847F7E793 +:1081600000000000DC200020B8450300C0200020F3 +:1081700000000000164B002B00D1144B9D464022FE +:1081800092029A1A924600218B460F461348144ACF +:10819000121A1AF0FDFA0F4B002B00D098470E4B25 +:1081A000002B00D098470020002104000D000D484E +:1081B000002802D00C4800E000BF14F081FD200030 +:1081C00029001AF07CF814F065FDC0460000080094 +:1081D000004000200000000000000000C02000203F +:1081E00010290020000000000000000010B504006D +:1081F000034B41600360080017F002F8200010BD37 +:10820000282E030070B50500082001F051FE041E61 +:1082100005D0044B45600360280016F0F1FF2000F4 +:1082200070BDC046282E03001FB50C00416803A88E +:1082300003F0B4F9002362420193009303A90348B9 +:1082400004F07AFC03A816F052FE1FBD1C22002089 +:1082500030B585B00C00416803A8150003F09EF905 +:1082600000236242009303A90195044804F064FCD2 +:1082700003A816F03CFE05B030BDC0461C2200200D +:1082800030B585B00D00416802A8140003F086F9EE +:1082900002A903A816F038FE00230193FF3B220039 +:1082A00003A9009305482B0004F002FD03A816F073 +:1082B0001EFE02A816F01BFE05B030BD1C220020D9 +:1082C00010B50AB2FF2301B2014803F07FF910BDD7 +:1082D00090220020F8B5FF2304000D00161E9E42D8 +:1082E0000CDC00239A4209DDFF339A4206D0094F85 +:1082F000380017F035FD012807D133002AB2DBB270 +:1083000021B2054803F062F9F8BD0121380017F0E9 +:1083100009FDF2E71C2200209022002010B50AB2CD +:10832000002301B2014803F051F910BD9022002052 +:1083300010B50AB201B2034803F05EF9C317181A68 +:10834000C00F10BD9022002010B5024817F00AFDA2 +:1083500010BDC0461C22002010B50100014804F0E9 +:10836000D5FC10BD1C22002010B5024804F02CFBE7 +:1083700010BDC0461C22002010B5C1B2014817F044 +:10838000D1FC10BD1C22002010B5024817F0E8FCFB +:1083900010BDC0461C220020030010B50448002B6D +:1083A00002D017F023FD01E017F025FD10BDC046F7 +:1083B0001C22002037B50C4901A817F026FD01A8A2 +:1083C00003F0FCF8050001A816F091FD082001F06B +:1083D0006FFD041E02D02900FFF708FF280016F0E9 +:1083E00019FF20003EBDC0461C220020F8B5040045 +:1083F0000E00082809D1E425134F6D007859036851 +:10840000DB699847022819DD03E00300093B012BD3 +:1084100006D93200102321001B2002F025F8F8BDF8 +:10842000E425094F6D0078590368DB6998470528F2 +:10843000EFDC7859082103689B6903E0042178592F +:1084400003689B699847E4E72C210020E423064A4F +:108450005B0010B50400D05816F0DBFF001B434250 +:108460005841C0B210BDC0462C210020030010B5F9 +:108470000948012B02D0022B03D1084816F0D7FF80 +:1084800005E000201A2B05D1054817F0E9FF431E2F +:108490009841C0B210BDC04694220020BC220020EA +:1084A000E4220020F7B5E422214B5200985816F040 +:1084B00081FF0FF07DFCE4221D4B52000400985810 +:1084C0000D0016F07EFF0FF073FCE422184B5200F3 +:1084D000060098580F0016F07BFF0FF069FC220091 +:1084E000009001912B00200029000EF03DFE32008B +:1084F0003B0004000D00300039000EF035FE020094 +:108500000B00200029000DF0DFFE009A019B0D00FA +:108510000400190010000EF027FE02000B002000DE +:1085200029000DF0D1FE11F031F90FF00BFCFEBD6A +:108530002C210020030010B50020032B1BD81800AD +:108540000CF0ECFC02091017E4230B4A5B00D05836 +:1085500016F030FF0FE0E423074A5B00D05816F016 +:1085600030FF08E0E423044A5B00D05816F030FFE7 +:1085700001E0FFF797FF10BD2C21002010B5024845 +:1085800017F04FFC10BDC0461C220020E62310B59A +:10859000024A5B00D05803F071FE10BD2C21002070 +:1085A00010B5024818F07EF910BDC0460C2300201B +:1085B00010B5002808D001280DD1E423074A5B003C +:1085C000D05803F0C1FB07E0E423044A5B00D05815 +:1085D00003F0A4FB00E0002010BDC0462C210020C9 +:1085E00070B5E624134D64000600285916F08CFF80 +:1085F000002802D1285903F043FD0020032E17D88C +:1086000030000CF08BFC02060A0E285916F0EFFF22 +:108610000AE0285916F0F2FF06E0285916F0F5FF97 +:1086200002E0285916F0A6FFFA2189000CF00AFD95 +:1086300070BDC0462C210020E62310B5024A5B0025 +:10864000D05803F01DFD10BD2C210020E423044A66 +:108650005B0010B50100D05802689269904710BDC8 +:108660002C21002013B50423C25E811D684602F050 +:1086700037FF02236A4601A8084905F051FD019819 +:108680000223C15E043014F0ABFF040001A816F011 +:1086900071FB684616F06EFB200016BD30210020ED +:1086A00013B50E4C200017F0FDFF021E05D101008E +:1086B0000B4814F095FF04000EE00023210001A8F0 +:1086C00018F033F801980223C15E043014F088FFDB +:1086D000040001A816F04EFB200016BD302100203A +:1086E0006442030037B50D000423C25E811D01A85A +:1086F00002F0F6FE094C01A90022200005F042FB21 +:1087000001A816F037FB2A0010230121202001F0D8 +:10871000ABFE0021200005F081FC37BD3021002098 +:1087200007B500280DD00423C25E811D01A802F008 +:10873000D7FE022201A9034817F0EEFF01A816F0A8 +:1087400019FB07BD3021002010B5002806D001001C +:10875000426808310223024805F0F0FB10BDC04614 +:108760003021002070B5051E00DC402529000020C6 +:1087700000F0CEF8060008364268310004000223FB +:10878000054805F06DFC0100854203D0300000F083 +:10879000BFF80400200070BD302100200C4B10B544 +:1087A0000C00984206D00B4B984207D119230B704E +:1087B000183B0AE018230B70173B06E000F0DEFEC2 +:1087C000031E02D0837B23700123180010BDC04616 +:1087D000E9030000EA030000F0B585B002AB9E1D7E +:1087E0000F0031000192FFF7D9FF0C4C002807D091 +:1087F00002ABDD1D29003800FFF7D0FF002805D1AE +:108800000199200005F03EFA05B0F0BD00220021DC +:10881000AA567156200005F087FDF1E730210020AF +:1088200010B5064C19221821200005F07DFDE1212C +:108830002000490205F026FA10BDC0463021002074 +:1088400010B50100014805F053FD10BD3021002096 +:1088500010B50100014805F0D1FA10BD302100200B +:1088600010B5034B0A000100186814F0AAFE10BDF1 +:10887000F4200020F7B50700134E009135680192EF +:10888000002D0BD06B68BB4203D1AB68009A9342BA +:1088900001D02D68F4E7019BEB6014E0102019F083 +:1088A00022FF04001022290019F072FF2000336813 +:1088B0000C302360009B0121A360019B6760E36093 +:1088C00001F0CAFB3460F7BDF420002070B506004B +:1088D0000D1E02DA19F09CFF05000B48002D12D086 +:1088E000E81D01F0E5FA041E01D0084B0360A580E5 +:1088F000002E04D0A01D2A00310019F02BFF002308 +:1089000020006519AB7170BDDC2E0300702F0300D1 +:1089100070B506000D1E0B4813DD0800083001F08D +:10892000C7FA041E01D0084B0360200065600830C0 +:108930002A00311E02D019F00DFF01E019F028FFC6 +:10894000200070BDA02E0300AC2E0300014B186068 +:108950007047C04604200020F7B5050001260F49E6 +:108960000B6801912C000020DF0FBC4661469F0977 +:108970004F405F4019095A084F409B087B405340C5 +:10898000DB0713431A004000324010436408EBD168 +:108990008542E7D3019A1360FEBDC0460420002043 +:1089A00000487047DC2E0300F7B504000D000028D6 +:1089B0000AD0154B002922D008009C4223D0124B2C +:1089C00020009D4204D11EE0104C0029F7D1250063 +:1089D000A688AF880020F119FFF778FF030006335F +:1089E0000090A11D32001800019319F0B3FE019B05 +:1089F000A91D98193A0019F0ADFE009803E0034D47 +:108A000028009C42E4D1FEBDDC2E0300582E03005A +:108A1000F0B5040085B002912378202B01D10134F8 +:108A2000FAE72B3B5A425341E41823782D2B03D10C +:108A300001340022394B01E00022394B00920193AE +:108A40002378302B04D1202263781343782B03D072 +:108A50000025002600272BE010220299200014F0A8 +:108A600035FA0FF0A5F9009A019B4DE01A00303A53 +:108A70000392092A20D800222A4B300039000EF038 +:108A800073FB06000F0003980FF092F932003B00D1 +:108A90000DF01AFC06000F00002D08D00098019977 +:108AA0000022204B0DF03CFF009001910125013484 +:108AB0002378002BDAD10EE0002D01D12E2BF5D03A +:108AC00020229343452B06D02378202B01D101345B +:108AD000FAE7002B1ED1009801993B0032000EF0FE +:108AE00043FB237806000F00002B10D00A220299C6 +:108AF000601C14F0EBF90B49020000200CF026FC7E +:108B000002000B00300039000EF02EFB04E0029B47 +:108B10001C6001E00020044905B0F0BD0000F0BF7A +:108B20000000F03F000024400000F87F70B50B000B +:108B300004000D48002A15DDA588002903DA6B180A +:108B4000D943C9170B40E91A8A4203DB06480029BA +:108B500001DC07E0110000209D4201D90634E01835 +:108B6000FFF7B4FE70BDC046DC2E030070B50A00EE +:108B700005000C000600002902D10120002D4CD078 +:108B8000630026495B0D59181D2908D91E2931D1CA +:108B9000002E2FD1224B9A422CD122483DE014299D +:108BA0000EDC002E26D120481B182000984021D131 +:108BB0008020E302000618431F23591AC84010E022 +:108BC0001A481B182800984014D18020E3020006A0 +:108BD00018431F235B1AD8403423591A2B00CB406B +:108BE00018430123002A02DA4042984000E0400086 +:108BF000184312D123002A00280021000FF082F828 +:108C000003000E20002B08D1023801F051F9002892 +:108C100001D0074B03604560846070BD01FCFFFF1D +:108C20000000D0C1010000800DFCFFFFEDFBFFFF45 +:108C3000002F0300F0B5851D85B0060003A92800AC +:108C4000FFF7E6FE0400B088039B28180F0083425C +:108C50003AD10022002320000CF0F0FA002835D190 +:108C600001236A46D37101227E00760852421A4BD4 +:108C7000200031000FF046F800280AD10122164BDF +:108C80005242200031000CF0F3FA002801D16B466B +:108C9000D871802300225B032000310001250FF0F2 +:108CA00031F8002809D1802300225B032000310025 +:108CB0000CF0CAFA002800D1051C01235D406B4668 +:108CC000DB79EDB2AB4201D30024044F2000390020 +:108CD000FFF74CFF05B0F0BDFFFFEF7F0000F87F0E +:108CE00010B514F0FBFC041E05480E2C07D0E3075A +:108CF00002D4044801F0B4FA601014F075FC10BD01 +:108D0000DC2E030071030000064B10B5984203D817 +:108D100001234000184303E00FF08CF8FFF726FF13 +:108D200010BDC046FFFFFF3FF0B5002385B0140023 +:108D3000002206000D000CF087FA002805D02D2334 +:108D4000237080231B06ED1801340022002330001D +:108D500029000CF073FA002802D0302323707BE046 +:108D60003000290010F018FC0EF0ECFF3C4A070020 +:108D70003C4B300029000CF085FA00281AD03A4A02 +:108D80003A4B300029000CF05FFA002812D0002F77 +:108D900020DD3A00002036490CF0D8FA0B00020022 +:108DA000290030000DF0BCFD7B1C06000D00019376 +:108DB000012712E03A0000202D490CF0C7FA0B0001 +:108DC0000200290030000DF0ABFD012306000D006C +:108DD000019302E001231F00019300230293290065 +:108DE00030000EF0AFFF03003033237003900EF01D +:108DF000DFFF02000B00300029000EF02FFC1C4B9F +:108E000000220EF0B1F9019B0600013B0D00019319 +:108E1000002B01D0013402E02E2363700234039B47 +:108E2000029A1343DAD0130001330293102BD6DDDC +:108E3000019B002BD3DC013C2378302BFBD02E3B55 +:108E40005A425341E41A012F06D06523A11C6370D6 +:108E5000380001F001FD01E00023637005B0F0BDB2 +:108E60008DEDB5A0F7C6B03E50EFE2D6E41A4B4404 +:108E700000002440012070B54042FFF76DFD040062 +:108E80000D48FFF769FD060020000EF0D3FF002219 +:108E90000A4B0EF069F9040030000D000EF0CAFF15 +:108EA000074A084B0DF03CFD02000B002000290092 +:108EB0000DF00AFA70BDC046FFFFFF000000F03D54 +:108EC0000000E0DFFFFF6F43024B1B68588CC000BF +:108ED0007047C04608210020134B70B51B68060080 +:108EE0005A6A0D00002399005458B44203D101334B +:108EF0009B009B5816E0002C01D00233F3E714F0DE +:108F00004AFC2B0000280DD023009A00825896427C +:108F100003D101339B001B5804E0002A01D0023327 +:108F2000F3E72B00180070BD0821002070B5050084 +:108F30000C00160000290CDB8388994209DAA40092 +:108F40002C19E368002B09D00B21064815F015FCFD +:108F500004E00A21034815F010FCF0E72800E66061 +:108F600070BDC04686030000031E03D0024A904233 +:108F700000D1002318007047DC2E03001C4BF7B50E +:108F80001B680600DA6A131D0193136852685D1EA0 +:108F9000904215D3174A9B18019A9B009B58984200 +:108FA0000ED8002358194008019982005258964261 +:108FB0001CD003D9431C9D42F4D216E0451EFAE7AB +:108FC00000277C196408019AA3003100985814F016 +:108FD00015FB002801D1200008E0002803DA671CF7 +:108FE000AF42EED901E0651EFAE70020FEBDC046A3 +:108FF00008210020FFFFFF3F044B10B51B68013123 +:10900000DB6A8900C95814F0E7FB10BD0821002075 +:10901000044B10B51B680131DB6A8900C95814F094 +:10902000EAFB10BD08210020014B18687047C046BC +:109030000421002010B5040014F0BBFA002808D069 +:10904000201E1CD0012302201C4218D10E2C09D155 +:1090500015E00122236804209343DA78F92A0ED11F +:1090600098780CE01800422C09D018000A2C06D081 +:109070000420062C03D0024801F0F2F8042010BDB1 +:109080002103000010B5041E0E2C19D0002817D0A3 +:1090900014F08FFA002805D0200000F017F80EF029 +:1090A00087FE0FE02000FFF7C5FF022802D16068AD +:1090B000A16807E0032803D12000FFF7BBFDE2E72A +:1090C0000020014910BDC0460000F87FF7B501241B +:1090D000204201D020415CE0830703D58011431E6C +:1090E000984156E0002801D1002052E0FFF7CAFF66 +:1090F0006B46060001224D006D080F00DC715242E4 +:10910000244B300029000EF0FDFD00280AD1012279 +:10911000204B5242300029000CF0AAF8002801D15F +:109120006B46D871802300225B03300029000124A4 +:109130000EF0E8FD002809D1802300225B033000F7 +:1091400029000CF081F8002800D1041C01235C40A8 +:109150006B46DB79E4B2A342C6D2300039000FF08F +:1091600097FE00220C4B10F027F900220023040088 +:109170000D000CF069F8002807D02000290000221B +:10918000054B0DF0A1F804000D00200029000CF0A3 +:109190003BF9FEBDFFFFEF7F0000F04110B5FFF788 +:1091A00071FF0022034B0DF08FF80FF0A9FAFFF7C3 +:1091B000DDFC10BD0000E03F70B5040014F0F9F9CB +:1091C00000280BD00A2C29D0002C27D00E2C25D01B +:1091D000062C23D0601E441EA04120E02000FFF793 +:1091E00029FF032803D10E4B9C4215D116E002281B +:1091F00012D12000FFF746FF02000B0004000D0013 +:109200000EF080FD002809D1002200232000290053 +:109210000CF014F8002801D1012000E0002070BDFE +:10922000DC2E030070B590B00400FFF703FF0300CD +:109230002000032B55D0022B40D1E30704D560104A +:10924000694601F009FB33E00E2C01D1264848E0C5 +:109250002000FFF717FF01224E0076080D00524252 +:10926000224B310004000EF04DFD002813D10122E5 +:109270001E4B5242200031000BF0F0FF00280AD1B3 +:1092800000230022200029000BF0DEFF031E1848F7 +:1092900027D1184825E022002B00200029000EF0DD +:1092A00031FD0028D2D16A4620002900FFF73CFD9D +:1092B000012168464942FFF709FB12E00E48052BE1 +:1092C0000FD00E48002C0CD00D480A2C09D00648AF +:1092D0000E2C06D00B48422C03D00B48062C00D095 +:1092E0000A4810B070BDC046A02F0300FFFFEF7FFB +:1092F000642E0300F02E0300CC2F0300402F030048 +:10930000E42E0300742E0300582E0300302F0300B8 +:1093100010B50400FFF78EFE042812D1200014F0CF +:1093200048F9002810D1012322689A431300DB8AF0 +:10933000928A1B041343054A934205D020009847A4 +:1093400002E02000FFF76EFF10BDC0461193010040 +:1093500010B5FFF76FFE05280ED80BF0DFFD1203E6 +:109360000507090B08480DE008480BE0084809E02C +:10937000084807E0084805E0084800F071FF0020B1 +:1093800000E0074810BDC046BC2F0300602F03005B +:10939000AC2F0300502F0300902E03002203000087 +:1093A000802E030010B5062805D0FFF743FEF523F5 +:1093B0009B00C01800E0024800F052FF10BDC046FC +:1093C000DD03000070B50400436800205900FFF77A +:1093D0007DFA0F262200094D6168131B0132994264 +:1093E0000ADDD1795B000911695CC3189971D179E3 +:1093F0003140695CD971EFE770BDC046043E03009F +:1094000070B50E4C200004F087FA051E03D02B2007 +:1094100001F09CFA0FE00A4E3378002B0BD100F0DC +:1094200063FAC1B2200004F063FA0621200004F0C0 +:10943000D3F901233370280070BDC0467824002082 +:109440003628002030B587B004000D00FFF7D8FFA4 +:10945000031E0ED1AAB2A1B202A815F025FD082262 +:1094600004A9684619F076F9029A039B024817F09E +:10947000C7F807B030BDC0469824002037B5FFF7C5 +:10948000BFFF002802D00021080014E00B4901A80A +:1094900004F054FB0A4C01A9200015F07EFE01A83F +:1094A00015F03AFE200015F09BFE0500200015F097 +:1094B0009AFE01002800FFF72BFA3EBD9024002001 +:1094C000F820002010B50400FFF79AFF002807D10C +:1094D000002C05D0210062680831024804F04EFBE0 +:1094E00010BDC0469024002037B5FFF789FF011E4C +:1094F00001D0002010E001A815F040FE074C01A9A2 +:10950000200015F059FE050001A815F005FE002DFC +:10951000EFD1200015F06AFE3EBDC046F8200020C5 +:1095200010B50400FFF76CFF002803D1E1B2024838 +:1095300004F0DEF910BDC0467824002010B5040008 +:10954000FFF75EFF002803D12100024804F044F930 +:1095500010BDC0467824002010B5054C200015F041 +:1095600004FE044A0449200019F0B6F810BDC046B4 +:10957000F82000200020002019F10200C31F002065 +:10958000122B02D8014A9B0098587047E02F030025 +:10959000014B98687047C046C020002010B50C00F1 +:1095A000FFF7ECFF002805D0FA22034BD200210080 +:1095B00004F048F810BDC046DC05000010B5FFF708 +:1095C000DDFF014B186010BD0021002070B5154C67 +:1095D000060023680D00002B02D10720FFF7EEFFE5 +:1095E000002E04DC0021206803F09AFF0CE08021AB +:1095F0002068890003F094FF31000B480BF022FD36 +:109600000100206804F04AF8002D09DD280001F06F +:1096100009FD0021206803F083FF052018F048FFB2 +:1096200070BDC0460021002040420F00F7B5040085 +:1096300008000E00170014F049FF02000500009713 +:10964000330008326100024803F06AFB2800FEBDC7 +:10965000E4210020130007B50A00400000934B6886 +:1096600008320100014803F06BFB0EBDE42100202D +:1096700037B5094C2368002B0CD11C2019F033F8A6 +:10968000012305005B4200931622183315210AF0CE +:1096900099FA256020683EBDFC200020F0B5164CEC +:1096A0000700206885B00D001600002804D003686C +:1096B0009B689847002323603800FFF75FFF837B98 +:1096C00028000393FFF75AFF857B3000FFF756FF12 +:1096D000867B1C2019F007F8694607000120097BEA +:1096E0004042009073B26AB249B238000AF06AFA96 +:1096F000276005B0F0BDC046FC200020024B4000B2 +:109700001B6818187047C04608210020030010B5D8 +:109710000420002B11D058003F2B0EDD074A934246 +:1097200005DC0520032158430BF08CFC05E0581C98 +:10973000034BFF30984200D9024810BDFF010000E2 +:10974000FEFF0000FFFF0000012370B50A6805005E +:109750009A4313890E00042B02D00D4800F080FDBF +:109760003000002D12D0A8000C3000F0A1FB041E28 +:1097700001D0084B03602000B368AAB2A580A360A3 +:1097800092000C30002119F003F8200070BDC04693 +:10979000850300005C3003000B4B026970B50500C7 +:1097A0009A4203D0E220800000F05AFD288800F0A1 +:1097B0007FFB041E00D005602A88201D043A00218A +:1097C00018F0E6FF200070BDE3E502001C4BF7B582 +:1097D00005000E1E9E4232D8C488A14223D9200023 +:1097E000FFF794FF071EB74200DA3700B80001F018 +:1097F0003DFDA30000900193002C03D01A002968BE +:1098000018F0A8FF0099019B8C463A1B634418008E +:109810009200002118F0BCFF286801F05DFD009B5C +:10982000EF802B600AE08288914207D22B68521A9F +:10983000880092001818002118F0AAFFAE80F7BD2A +:10984000FFFF0000084B70B505000C0016009942A0 +:1098500008D88388994202D30131FFF7B7FF2B68FC +:10986000A400E65070BDC046FEFF0000C38870B57E +:1098700005000C0016008B4206D8084B99420BD805 +:10988000013189B214F0CEFE2A68A3009E50AB8845 +:109890009C4201D30134AC8070BDC046FEFF000085 +:1098A000034B036000234360038143817047C0463C +:1098B0002C300300024B0360002343607047C04616 +:1098C0008C300300044B0360002343600381438119 +:1098D000C360038243827047BC300300014B1B68A6 +:1098E0001869704708210020014B1B689869704770 +:1098F00008210020014B1B68188C704708210020AC +:10990000F8B50268164B06009A4200D0FEE743689D +:10991000144D188C2B60800014F0B6FF04002B68E7 +:10992000114F1A8C00219200386018F031FF276027 +:109930002C680E4B22689A4203D1B36822699A427E +:1099400000D0FEE700F0D4FC2B6820001C6B002345 +:1099500040301A001900A04715F01CF8F8BDC046A9 +:10996000104200000821002004210020708E3B924C +:1099700010B50248FFF7C4FF10BDC04640290300E0 +:1099800070B506000C2000F093FA041E05D00D4BB4 +:1099900003600023436003814381300014F001FE23 +:1099A000094B98420BD13589002D08D0201D290084 +:1099B00014F064FEAA007168606818F0CBFE200005 +:1099C00070BDC0462C300300BC300300014B5888EA +:1099D0007047C046C0200020014B98687047C046C1 +:1099E000C0200020074B1B68002B09D01A0008324A +:1099F0008242F8D8596852189042F4D2012000E00F +:109A00001800704714210020032370B50468050076 +:109A10009C43A30F002C03D10C4800F021FC04E070 +:109A2000002B02D02503AD0B03E02800E369984723 +:109A30000500002D04D0064B9D4205D9002C03DB08 +:109A4000D420800000F00CFC280070BD5103000001 +:109A5000CA080000104A70B59188060001391068E4 +:109A60008B00C3180D0010006A1C0FD01C00043BB3 +:109A70005A68B24208D18D4202D114F0C5FD09E006 +:109A800014F0C2FD206005E0013DEDE7D22080002A +:109A900000F0E6FB70BDC0460C210020802010B510 +:109AA000400001F0E3FBF82343600F4B83600F4B52 +:109AB0001A68C260020008321A6000230C4A8361EF +:109AC0001368002B01D0984205D20360106007E0B4 +:109AD000904203D313001A68002AF9D1026018607B +:109AE000044B4630186010BDF8000080282100208B +:109AF000142100201C21002010B5041F2368DB075F +:109B000002D5084800F0ACFB2000FFF76BFF0028EF +:109B100002D1044800F0A4FB012322681343236010 +:109B200010BDC0464F03000010B5040014F065FEE0 +:109B3000002816D123680B4A134212D1DB78F92B87 +:109B40000FD12000FFF74EFF002802D1064800F099 +:109B500087FB01232268210013432360034814F08C +:109B600057FE10BD030000404F03000020210020DD +:109B7000F8B506000F000025BD421FD0AB00F45819 +:109B8000200014F03AFE002816D123680C4A134234 +:109B900012D1DB78F92B0FD12000FFF723FF00282B +:109BA00002D1084800F05CFB012322682100134326 +:109BB0002360054814F02CFE0135DDE7F8BDC046F2 +:109BC000030000404F0300002021002010B50400D6 +:109BD00014F013FE002827D12368144A134223D11E +:109BE000DB78F92B20D12000FFF7FCFE002802D102 +:109BF0000F4800F035FB012223681A43226003223C +:109C000093439B69002B01D0200098470324094807 +:109C10008388002B08D014F0F7FC0368A3439B69EA +:109C2000002BF4D09847F2E710BDC0460300004077 +:109C30004F0300002021002070B5050001F016FB45 +:109C4000083D04004560AB0703D0D220800000F03F +:109C500007FB80222000636812061A43A2600D4AA7 +:109C6000083011681060E1600B490A68002A01D0D1 +:109C7000944205D222600C6007E08C4203D30A00B4 +:109C800011680029F9D121601460044A9B08C318A7 +:109C9000136070BD28210020142100201C21002009 +:109CA000F0B56F4C87B0237806009B0703D5D22010 +:109CB000800000F0D5FA0222237801251343237097 +:109CC0000024684B1A689F880192A7420ED9019A16 +:109CD000A300D058284205D00300AB4358881A8807 +:109CE00000041043FFF772FF0134EEE7300000F08C +:109CF00029FB5D4E3368002B11D05C4B1B685C8DDB +:109D0000FFF7F8FD33680026051BA4001C19B542B7 +:109D100005D0B300E058FFF759FF0136F7E70024FC +:109D2000534B1D68534B1E78A64205D9A300E85833 +:109D3000FFF74CFF0134F7E700231F004E4A019361 +:109D400013604E4A02931668002E61D03400736887 +:109D500008349B089A00A2180492FF18049BA3429F +:109D600054D901222368134203D11A0F2500062A71 +:109D70001BD10122934323602000FFF745FE85009D +:109D800065192C00EAE7012213421CD11A0F062A9A +:109D900019D08022D20513420BD02800FFF734FEE1 +:109DA000049B80002D18AB420DD92B68002BEADAFA +:109DB000F3E7DB78F92B02D0314800F051FA2800A4 +:109DC00014F012FCE9E72B1B9B100393039A019BF1 +:109DD00094466344019393001A00FF2120000593E9 +:109DE00018F0D6FC8023059A1B0613432360039BBF +:109DF000012BC6DD00236360029B002B02D11E4BAA +:109E00001C6001E0029B5C600294BAE736689BE745 +:109E10001C490B68002B13D0019B9C08164B1A6839 +:109E20003300002A0CD010680003800B1B189C42E2 +:109E300004D21B1B9B00D3180B6001E05268F0E7B3 +:109E40000A21019ABB0092004A43934201D3FFF7D3 +:109E500025FE0221024A13788B43137007B0F0BD30 +:109E6000372800200C210020042100200821002098 +:109E7000182100203828002028210020142100204B +:109E8000490300001C21002070B5041F2368050051 +:109E90005B0F032B02D0054800F0E2F98023226813 +:109EA0001B0613432800236070BDC0464903000011 +:109EB000F0B5C31C9B1085B00293404B984202DD65 +:109EC000162000F0CDF93E4B3E4E5B68DB0569D1B4 +:109ED0003378DB0766D4012233781343337000F004 +:109EE00023FA002805D04368002B02D1364800F041 +:109EF000B7F900270022354B01921D680393002D0E +:109F00003FD0002F03D1324B1B689D423BD8280025 +:109F100014F073FC002802D02E4800F0A1F92C6840 +:109F2000002C02DB2C4800F09BF9029B2403A40BBD +:109F3000E41A6B6822D40BD08020029AA100920010 +:109F40000006AA1801431160012C01D053601300D0 +:109F5000019A002A01D0536001E0039A13600022A5 +:109F60002A60934222D05B6893421FD01B0D93421C +:109F70001CD1D420800000F073F917E001951D007A +:109F8000BDE7002F03D10020FFF78AFE08E0012F74 +:109F900002D1FFF783FD03E0D320800000F060F9D9 +:109FA0000137A7E70D4800F05BF994E7012228008C +:109FB00033789343337005B0F0BDC04628230000CA +:109FC00000ED00E0372800204E030000282100208B +:109FD0001C210020510300004B03000092030000ED +:109FE000184B70B55B6806000D00DB0502D0164803 +:109FF00000F036F900F098F9144B04001D60144B82 +:10A00000751BAD101D701D0000280AD00C2014F027 +:10A010003BFC63680360A3684360E3688360E060BF +:10A020000AE0102014F030FC0A4B04001B680360A7 +:10A030000023C36000F080F90023A6602B7020008D +:10A04000636070BD00ED00E0920300001821002065 +:10A05000382800200421002070B50C1E0ED00129E4 +:10A0600007DD013C0AD3051D0121FFF7F5FF28009C +:10A07000F7E701210143024814F0CAFB70BDC04656 +:10A080000C21002010B5040014F0B7FB002803D108 +:10A090002100024814F0BCFB10BDC0460C2100207A +:10A0A0000023044A13609380D380034A1360938093 +:10A0B000D38070470C210020202100201FB50C0008 +:10A0C000010003A801F06AFA002203A9009213001C +:10A0D0000194034802F030FD03A814F008FF1FBDEF +:10A0E0001C22002037B50C1E00DC0124124D002874 +:10A0F00002D08288002A07D1280015F081FE0520B1 +:10A10000604300F08FFF15E0012A0DD0811D12B2CF +:10A1100001A801F0E5F9220001A9280002F068FD7C +:10A1200001A814F027FE05E005228179624328008A +:10A1300002F0E0FC37BDC0461C22002010B50248EA +:10A1400014F0F9FE10BDC046902200201FB50C008F +:10A15000010003A801F022FA0023220001930093DA +:10A1600003A90533034802F0A3FD03A814F0BFFEC2 +:10A170001FBDC0461C2200201FB5010002A801F02F +:10A180000DFA02A903A814F0BFFE002203A9019250 +:10A1900000921300054802F0CFFC03A814F0A7FEBC +:10A1A00002A814F0A4FE05B000BDC0461C22002089 +:10A1B000034B10B51B681C6B00231A00A04710BD91 +:10A1C00008210020044B10B51B681C6B00231A00EB +:10A1D0001900A04710BDC046082100207FB505002A +:10A1E00000902D0C0191029284B2102269460F4812 +:10A1F000039318F0AFFA29002000FEF731FB0600A8 +:10A20000280013F051FA0500002E03D00100F06879 +:10A21000FFF7CEFF00212000FEF722FB002803D02D +:10A220002900C068FFF7C4FF7FBDC046C0200020E2 +:10A2300010B50A00010003480223043003F07EFE3B +:10A2400010BDC0462C21002010B50400034B036054 +:10A25000403014F08FFD200010BDC046F4300300E4 +:10A2600010B50400034818F018F9200000F06EFB48 +:10A2700010BDC046E093040010B500F045FC09484D +:10A2800000F018FCFEF762FB012000F0DDFF064B3A +:10A29000984206D9012000F0D7FF044BC018FFF701 +:10A2A000CBFC10BDFFFFFF7F0404000000FCFFFF9C +:10A2B00010B5041E06D0FFF7E5FE034A210003484F +:10A2C00014F053FC10BDC046A9EB02006FE9020078 +:10A2D00010B5041E06D0FFF7D5FE034A210003483F +:10A2E00014F043FC10BDC04663E90200C5A10100A3 +:10A2F00010B5044800F09EF9042000F021FBFFF7A0 +:10A30000BBFF10BD2C210020054B10B51C68FEF7CB +:10A31000DBFD044BE4182018800A800210BDC04603 +:10A3200008210020FF030000024B1B68181E00D00C +:10A33000D86D7047B0240020014B1B68D86570476A +:10A34000B0240020F0B5264B87B01A680393002A8A +:10A3500005D1012000F08AFF059005983BE0002020 +:10A3600000F034FC0090800000F080FF019000F0CD +:10A370002DFC009B834203D0CB208000FFF770FFB1 +:10A380000027009B9F4225DA019ABB00D458E36D59 +:10A390001E1D002B04D10137F3E7B668002EFAD05A +:10A3A000039B35681A68944203D0636CE16B5B1AB7 +:10A3B000ED1873680293944205D0E26B636C9B1AAC +:10A3C000029AD3180293029B9D42E6D201CDFFF779 +:10A3D000FDFBF8E7019800F07FFF07B0F0BDC04635 +:10A3E000B024002010B5064C200000F06BF8054AA0 +:10A3F0000549200018F070F9044814F04AFD10BD1A +:10A400002C2100200020002011A40100C0200020E9 +:10A41000CA23144A9B0010B5C2501C330400C01854 +:10A4200014F0A8FCD0239B00E01814F0A3FC20003B +:10A430009130FF3001F09EFC20006930FF3001F0C8 +:10A4400099FC2000F03002F0A3F92000D03002F097 +:10A4500095FE2000643009F02DFB201DFFF7F4FE6F +:10A46000200010BD90350300F0B585B005000E004A +:10A4700017000393FEF7F4F9002818D1283018F0DC +:10A4800032F96B4604009B89A9B20093B2B20B4B20 +:10A4900014F00FFC0A482100D03002F0F7FD00282C +:10A4A00005D0200014F01CFC200018F02EF93A0012 +:10A4B00031002800FEF7DEF905B0F0BDDDA1010096 +:10A4C0002C2100201423F0B5040093B0192200932E +:10A4D0001821043003F0E0FB23002500260064333C +:10A4E0001800B43513211093B83609F0EFFA28009C +:10A4F00016F080F900221E21300015F0A6FC200085 +:10A50000D03002F05BFE2300F033474A06211800EA +:10A51000119302F061F920000027012369301A002D +:10A5200000971121FF3001F0A1FC2000913000972D +:10A53000012302221A21FF3001F098FC2000B930DB +:10A54000022201211A23FF3002F0F8FE300001F050 +:10A55000F5F9E4235B00E050300001F0E3FCE62372 +:10A560005B00E0500100E42220005200D130119B3A +:10A57000A2580095FF3002F03FF82000E13029009A +:10A580001C22FF3004F092F8192320000F93013BA6 +:10A590000E93013B0D93013B0C93013B0B93013B4D +:10A5A0000A93013B0993013B0893013B0793013B4D +:10A5B0000693013B0593013B0493013B0393013B4D +:10A5C0000293013B0193F930013B082200930721DC +:10A5D000013BFF3015F05AFCCA239B00E01829000C +:10A5E00005F024F9D3239B00E0181D2103F0D2F8D5 +:10A5F000DD239B00E75010982770032117F06CFDB6 +:10A6000023002200200009499C33A0321C60116005 +:10A610005760074A80305A610221012209F006FE84 +:10A62000200013B0F0BDC046FC300300B9E90200C1 +:10A63000A5E902000123F0B5057891B007001D409F +:10A6400000D0DFE00300D0331800049300F0AAFB31 +:10A6500000F05AFA282018F046F80400103014F0E0 +:10A6600018FC694B65802380182018F03CF8060020 +:10A67000664B80C603901022290030000E930F9580 +:10A6800018F086F808220EA9300018F063F8604B25 +:10A69000039AE56053611223A260A380256265627C +:10A6A0002100049802F0F2FC002805D0200014F0EC +:10A6B00017FB200018F029F801223B785549134375 +:10A6C0003B703B00B4331800059316F099F85249DB +:10A6D0000390059816F094F800260690642000F088 +:10A6E000A1FC340035003B006933FF3318000793A9 +:10A6F00014F09DFE002803D1039B002B0DD109E02F +:10A7000038009130FF3014F092FE0028F4D0182D5C +:10A7100003DDF1E7069B002B70D03800653021B2D5 +:10A72000FF2332B2FF3000F051FF322000F07AFCFC +:10A73000631CDCB20135052C02D10024731CDEB28F +:10A74000039B192D02D0002B02D1CCE7002B03D0A4 +:10A750003049059803F03EFF039817F0D6FF06989E +:10A7600017F0D3FF2D492E4800F040FDDD239B005C +:10A77000FB580893002B38D100F0AEF801000AA86E +:10A7800000F09EFE14F09DF9089014F09AF96B46C3 +:10A790000990198C0CA814F009FB099B0DA8190C41 +:10A7A00014F004FB0DAA0CA90BA814F04FFB0DA884 +:10A7B00014F0E0FA0CA814F0DDFACA20012380009E +:10A7C0000BAA0AA900933818049B05F083F80BA87C +:10A7D00014F0D0FA0AA814F0CDFACC239B00FB5851 +:10A7E0000893DD23089A9B00FA50CA2339009B0086 +:10A7F000079AF031F81805F067FA74E70749094835 +:10A8000000F0F4FC11B0F0BDFD0300002DEA0200E1 +:10A81000EDE902004B3E0300563E030000200020FD +:10A82000001C00200800002010B5041E0DD017F0F9 +:10A83000EFFF230001382018834208D21A780178EC +:10A840000138197042700133F6E7024800E0002039 +:10A8500010BDC04617FCFFFFF0B585B001900C1E7F +:10A8600028D00027C217161A56407D1C6319029380 +:10A870003000013B0A2103930AF0CAFCCB17C91828 +:10A880005940039B3031197030000A210AF0DAFB7D +:10A89000061E01D02F00E8E7019B002B03DA2D23D1 +:10A8A000029ABD1C1370002620006655FFF7BCFFFE +:10A8B000300000E0014805B0F0BDC04617FCFFFFC6 +:10A8C000BFF34F8F024A034BDA60BFF34F8FFEE7AF +:10A8D0000400FA0500ED00E0F0B58DB005AF1922D7 +:10A8E0001549380017F036FF0022144B05245A7121 +:10A8F00080225205566E0122250001940292039394 +:10A90000019930000AF09AFB080002990AF010FB46 +:10A91000019B03996B430193029B361A6B4302938D +:10A92000631E2C1B6C433C19225C1C1ECA54E7D1CD +:10A9300008000DB0F0BDC046663E03003928002077 +:10A94000014B18607047C046A4240020F0B595B0B4 +:10A950001822002106000EA817F01AFF13210EA8D6 +:10A9600017F017FD03210EA817F0BEFD01224A4B78 +:10A9700000921B68002B01D0DBB200930123474AF1 +:10A98000002109A809F0D4FE454B9E4200D90026BB +:10A9900072B6444B1022002105A81D6817F0F8FE7E +:10A9A000414B64213000059305240AF04BFB6043C2 +:10A9B0005030281806900A2130000AF043FB0A2183 +:10A9C0000AF026FC614350316918079130000A21D2 +:10A9D0000AF01EFC4C43210050316C18802608946C +:10A9E0000024B601009B002B3CD004AD0027032CB3 +:10A9F00002D180260024B6016B682C4A02936300C2 +:10AA00000133D318002201921021581E0078014111 +:10AA1000039119788C4660460299095C03980142BB +:10AA200004D0012090400199014301910132063385 +:10AA3000092AE9D1019B2A68D9431D4B0901194014 +:10AA4000029B934203D1312F01DC002100E031430E +:10AA500009A817F0A2FDFA23139A0F99DB001068DA +:10AA6000014201D1FFF72CFF013B002BF7D1FA2364 +:10AA7000013401377600E4B25B009F42B7D1043560 +:10AA800008ABAB42B2D1044B1B68002BAAD0009B91 +:10AA9000013BDBB20093A5E7A4240020F0FF0000F7 +:10AAA000E703000008200020B53E03007F3E0300BE +:10AAB000F01F0000F7B500281FDD0126104C421ED4 +:10AAC0002368019415000020DF0FBC4664469F09EF +:10AAD00067405F401C09590867409B087B404B401A +:10AAE000DB070B4319004000314008436D08EBD1F0 +:10AAF0008242E7D3019A136000E00248FEBDC046DF +:10AB0000A824002017FCFFFFF8B50023144C236095 +:10AB100013F0C9FF2500002808D00421200013F0FD +:10AB2000BEFF00281BD00F4B236018E00122A12795 +:10AB300004210D4B0D4E1A602368FF000B4A706014 +:10AB4000944662465268084C002AFAD0E2591B0229 +:10AB5000013913430029F1D12B6001236360F8BD53 +:10AB6000A8240020ED5EBC0B00D00040FCD00040CB +:10AB7000F0B585B01F000AAB1B88060002911500D6 +:10AB80000393002F1AD0282017F0ADFD6B46040068 +:10AB90001989039BAAB200933B0014F08AF833682A +:10ABA00021005B6830009847002808D0200014F08E +:10ABB00097F8200017F0A9FD024800E0024805B010 +:10ABC000F0BDC04616FCFFFF17FCFFFF1FB50023BA +:10ABD0000190039372B60E4B03A91A6801A813F0F3 +:10ABE0007CFF0C4B03A91A6801A813F076FF0A4BEF +:10ABF00003A91A6801A813F070FF62B6019B002B2D +:10AC000002D0064A12681A60039B581C05B000BDAA +:10AC1000D8240020D0240020CC240020E0240020D0 +:10AC20000B4B70B51C68002C11D0656D00F004FC56 +:10AC3000A36C002903D1834201D92C00F3E7200043 +:10AC400013F07CFF0349200013F065FFF5E770BDAA +:10AC5000D0240020D8240020F0B5040093B007933E +:10AC6000230C0293294B04901C68294B05911E6804 +:10AC7000069285B20027002E46D0002C30D0636D9E +:10AC800024480393A36C9AB21B0C99B2854216D147 +:10AC90002148824213D1002B04D0029B994201D05B +:10ACA000039CEAE7002F01D00127F9E7200013F009 +:10ACB00045FF1A49200013F02EFF0137F0E7002A64 +:10ACC00001D09542ECD1002B02D0029B9942E7D1F2 +:10ACD000200013F033FF1149200013F01CFFDFE7C1 +:10ACE0000F4BEB18012B0FD91023029A0093290068 +:10ACF0000C4B08A813F0DDFF336808A99B683000EF +:10AD0000984708A813F0ECFF13B0F0BDCC24002046 +:10AD1000DC240020FE030000FF030000D8240020F4 +:10AD200002FCFFFF59AC010010B572B60B4B1C685A +:10AD3000002C03D0200013F001FF08E062B6602071 +:10AD400017F0D1FC60220021040017F021FD002340 +:10AD5000034A2000E364E263E36510BDAC240020F5 +:10AD600000400020094B10B51C68E36CDB070AD5D6 +:10AD7000FFF7DAFF064B1860002804D0E36DC365C7 +:10AD80000023E3650400200010BDC046B02400206D +:10AD9000D4240020024B1878012318407047C04685 +:10ADA0003F280020F7B50600FFF7F4FF051E33D15A +:10ADB0001A4C2660FFF7B8FF194B1A49186013F0B8 +:10ADC000AAFEFFF7B1FF184B1860184B4363184BEE +:10ADD0008363206800280ED0C027164E2A00330057 +:10ADE00015490097FFF7C4FE009733002A00134966 +:10ADF0002068FFF7BDFE0C2017F075FC0023838050 +:10AE000083710F4B03600F4B836000F02DFB01211A +:10AE10000D4A13780B431370F7BDC046DC240020A5 +:10AE2000B0240020D8240020E0240020FC3F002093 +:10AE3000D1EB020059AC0100FF030000FE0300004B +:10AE40001C31030021AC01003F280020F7B50600AB +:10AE50000D0017000193002801D1002015E0002902 +:10AE6000FBD0FFF761FF041EF7D0084B019A436344 +:10AE7000066045608760064B002A00D0054B200025 +:10AE8000A363054913F047FE2000FEBDFC3F0020F0 +:10AE90009BEB0200B9EB0200D8240020F8B50500B6 +:10AEA000EFF30884C36B006C1C1B6B6C1B1A9C4279 +:10AEB00010D91F23084F20343E689C433D60002872 +:10AEC00001D000F009FA200000F0D0F92864201821 +:10AED00068643E60F8BDC046B0240020024B18688C +:10AEE000434258417047C046D8240020002310B583 +:10AEF00004499C006258002A01D00133F9E76050F0 +:10AF0000100010BDB4240020002310B5044A99009D +:10AF10008C58844201D00133F9E70020885010BDDD +:10AF2000B424002010B50024074BE058002802D0BC +:10AF300003685B6898470434182CF5D1034B1B68F1 +:10AF4000002B00D120BF10BDB4240020D824002045 +:10AF5000F8B5FFF71FFF002856D02C4E3468350097 +:10AF6000E36CDA0718D502273B43E364284B1D68DE +:10AF70000423EA6C28001343EB64636BEB63FFF775 +:10AF80008DFF2800696C05F020FD3068C36C3B42E2 +:10AF90003AD005F054FD37E01E4F1F4E3A68002AA4 +:10AFA00001D1326808E0216DB94205D1616D0029F7 +:10AFB00000D11100296000E02A602A6831688A42C5 +:10AFC00008D11B0706D52C60FFF7ACFF3B68002BB0 +:10AFD000FAD02B6029688C4216D03368994204D18C +:10AFE0000E4B4B630E4B8B6305E09C4203D100225A +:10AFF0004B6C100006E02000FFF750FF200029688E +:10B00000626C4B6C05F0A0FCF8BDC046B02400207B +:10B01000D4240020D8240020E0240020FC3F00207D +:10B02000D1EB020070B50500FFF7B4FE002803D194 +:10B03000280017F03DFA0FE0FFF794FE040000F03F +:10B04000FBF92818A064200013F078FD03492000C4 +:10B0500013F061FDFFF77CFF70BDC046D0240020D7 +:10B06000F7B51A4D06002B680F00002B03D0FFF731 +:10B0700091FE002801D1164827E0FFF773FE154B1B +:10B08000041E1B689C4208D0200013F057FD124993 +:10B09000200013F040FDFFF75BFF3B043343A36444 +:10B0A000200013F04BFD20000C4913F034FD0C4B35 +:10B0B0000020F318012B08D9C02300933A00094B54 +:10B0C00031002868FFF754FD0020FEBDDC2400207D +:10B0D00016FCFFFFB0240020D8240020CC24002040 +:10B0E00002FCFFFF59AC010070B5FFF753FE0028CA +:10B0F0001FD0104D286813F021FD00220E4E346839 +:10B10000002C10D0636D002B0AD1032A08DDA26D3C +:10B11000206C536500F0E0F8200000F0DDF802E05C +:10B1200001321C00ECE73100286813F0F4FCFFF753 +:10B130000FFF70BDB0240020AC240020F7B507003D +:10B140000D00002830D0FFF725FE00282ED0194E24 +:10B150003068C36C5B0703D1C36D0193002B06D02D +:10B16000154A2900380013F000FD00241FE00224D6 +:10B1700005F04DFC3268D36C1C4003D003218B4397 +:10B18000D364F2E701210B43D3642800B847336846 +:10B190000120DA6CDC6511008143D964530706D5C0 +:10B1A000280013F001FD02E0044C00E0044C2000F4 +:10B1B000FEBDC046B0240020A9EB020017FCFFFF33 +:10B1C00016FCFFFF020010B5014B12CB12C210BDDE +:10B1D000E4240020034A044B12681A607E225A605D +:10B1E0007047C04608200020E424002070B5124EAD +:10B1F00005003278022A1AD081421AD90C1A072C7B +:10B2000017D9080003232843034012D172B60B4814 +:10B21000D2001550821851608022A40812061443EF +:10B220002C6032780132327062B6180002E00448B5 +:10B2300000E0044870BDC04640280020EC240020F7 +:10B2400013FCFFFF17FCFFFF064B1A780023824216 +:10B2500005D9054AC00013185B6880581B1A1800EE +:10B260007047C04640280020EC24002070B5051E21 +:10B2700024D0134A134E13781400002B0CD112491A +:10B2800012483370FFF7B2FF114B984202D11E20D3 +:10B29000FFF75CFB01232370002433789C4209DA1A +:10B2A0000C49E300C918280013F098FC002805D1C8 +:10B2B0000134F2E71420FFF749FB002070BDC046BF +:10B2C00041280020402800200038002010290020BC +:10B2D00017FCFFFFEC24002070B500281FD0104B96 +:10B2E00010491C780023A34216DADA005558A84208 +:10B2F00010D98A18526890420CD2041F2368002B80 +:10B3000002DC1E20FFF722FB802322681B0613436A +:10B31000236004E00133E6E71E20FFF717FB70BD52 +:10B3200040280020EC24002070B5051E15DD0C4BD4 +:10B330000C4E1A681C00002A02D0306816F02EFF4E +:10B34000FA21256000243068074B89008361C462BC +:10B35000694316F02BFF200000E0044870BDC04692 +:10B360002C250020FC24002015B4010017FCFFFF51 +:10B37000F8B5114F06003D68002D0AD1302017F0B6 +:10B38000B2F9040008F0C6FB0C4BA5612360E5622E +:10B390003C600B4D2B68002B09D1102017F0A3F94E +:10B3A000040016F07BFE20002C6016F051FE3000E9 +:10B3B000FFF7BAFFF8BDC046FC2400204039030067 +:10B3C00028250020014B18687047C0462C25002016 +:10B3D00070B50D4C2368002B03D00C4B1B68002B61 +:10B3E00002D10620FFF7C4FF206816F048FE0200D5 +:10B3F0000749C3170D684E685219734120680A60E7 +:10B400004B6016F042FE70BD28250020FC24002071 +:10B41000D020002010B5FFF7DBFF0024054BE058DB +:10B42000002802D003681B6898470434282CF5D103 +:10B4300010BDC0460025002010B5FFF7C9FFFA2255 +:10B44000034B920018685968002309F05FFF10BD94 +:10B45000D020002010B5FFF7BBFF024B18685968D9 +:10B4600010BDC046D02000200B4B10B51B68040057 +:10B47000002B03D0094B1B68002B02D10620FFF7DD +:10B4800077FF0023064A99008858002801D001332D +:10B49000F9E78C5010BDC04628250020FC24002070 +:10B4A00000250020002310B5044A99008C588442DE +:10B4B00001D00133F9E70020885010BD002500209D +:10B4C00010B50400002902D00B78002B02D1034BE9 +:10B4D000236001E013F055FC200010BD2C31030067 +:10B4E000F8B505000E00140000290AD00B78002BD7 +:10B4F00007D0002A05D0080097B217F089F98742D3 +:10B5000002D90B4B2B6010E0601DFFF7AFFE2860E7 +:10B5100013F06FFE2868220047803100043017F0D6 +:10B5200019F92B681C19002323712800F8BDC046A7 +:10B530002C310300014B03607047C0462C310300DF +:10B5400010B50548054C206013F05AFE044A054921 +:10B55000200017F0C1F810BD2C3103003025002069 +:10B560000020002075ED0200084B73B51C68050033 +:10B57000002C0AD00100266808310822684617F01E +:10B58000E9F80CCD31682000884773BD34250020D0 +:10B59000014B03607047C0463431030010B504000E +:10B5A000002902D1044B036003E00160080013F09E +:10B5B00027FE200010BDC046343103000300024ABC +:10B5C00000681A607047C0463431030030B5046823 +:10B5D0006088814206DAA588AA4203DA002901DBE5 +:10B5E000002A01DA034804E042436018801883719E +:10B5F000002030BD17FCFFFF10B50068438899425A +:10B6000006DA8488A24203DA002901DB002A01DA83 +:10B61000034803E05A4343189B18987910BDC0466D +:10B6200017FCFFFFF0B5070085B00E001D000029D4 +:10B6300021DD002A1FDD002B1DD0046863880393E1 +:10B640008B4200DD0391A3880293934200DD0292B6 +:10B65000002306340193019B029A93420DDA2900DC +:10B660002000039A17F076F83B68AD195B88E41860 +:10B67000019B0133EEE7024800E0002005B0F0BD79 +:10B6800017FCFFFFF8B504000D0016001F0000298D +:10B6900001DB002A02DA0D4B236016E0100048435C +:10B6A0000630FFF7E3FD206013F0A3FD23685D8003 +:10B6B0009E80002F06D03B00320029002000FFF7BB +:10B6C000B1FF02E0200013F036FCF8BD3431030076 +:10B6D000F7B505000C1E05D000200F0006000190F4 +:10B6E000010015E0224B03603FE0302252429446B5 +:10B6F0009C446246092A14D90A2B0DD1019B3618A5 +:10B7000001330193B14200DA310000200600013715 +:10B710003B78002BE9D106E00028F8D00136002064 +:10B72000F5E70120F3E76A46928809B212B22800D1 +:10B73000FFF7A8FF2B680A26991D01235B4220789A +:10B74000002812D00200303A092A06D8DA43D2176C +:10B75000134073431B18303B05E0002B03DB0B70D9 +:10B76000012301315B420134E9E72800FEBDC046F8 +:10B7700034310300F0B5040087B004A815001E00A2 +:10B780000F00FFF71FFD23685A88954208DA9B884F +:10B79000B34205DD1F2F03D9059B00939F4201DDB6 +:10B7A00018482DE0052300217B430093049B01935F +:10B7B000009B019ACB18A03BD35C00220293731824 +:10B7C0009C465319276803937888834202DABB8822 +:10B7D0009C4507DB0132052AF3D101310529E7D168 +:10B7E00000200DE0634658435319FB1810271741FA +:10B7F0001B1802980740781E87417F429F71E9E736 +:10B8000007B0F0BD17FCFFFFF7B5036806009C1DED +:10B810005B880D005A1A0192002918DD0027994211 +:10B8200002DB13F088FB14E033689B889F4210DA38 +:10B830006119019A200016F08DFF019B2900E01884 +:10B8400013F05CFB336801375B88E418ECE70248CF +:10B8500000E00020FEBDC04617FCFFFF10B5054804 +:10B86000054C206013F0CCFC044A0549200016F07A +:10B8700033FF10BD343103003825002000200020A4 +:10B88000EFEE020010B5054C0121200013F076FC0C +:10B89000034A0449200016F01FFF10BD3C2500207C +:10B8A0000020002019F102000388074A10B501208A +:10B8B000934208D0834202D00020DB0703D41E202D +:10B8C000FFF744F8002010BDFFFF0000004870475C +:10B8D00016FCFFFF10B53220FFF738F8004810BD06 +:10B8E00016FCFFFF8280142210B5134C028108342D +:10B8F000020000230460416204000221303283719F +:10B900008172C360036143618361C3610362363442 +:10B9100013705370227843868A43F1310A4083863C +:10B920002270020040321370021DD3870133438717 +:10B930008387C38710BDC04654310300F0B5544F10 +:10B9400097B03B6806000593002B00D094E006AC4E +:10B950000B331C222121200001F028FD0EAD0B230A +:10B960001D2222210AA801F021FD0B231B222321E5 +:10B97000280001F01BFD082016F0B5FE0122059BF2 +:10B980001100049015F0BEFA3A21300014F0DEFFE9 +:10B9900000281CD0A38812ADAB80A3795C20AB71CA +:10B9A0003C4B1293A3681493237B2B73637B6B73C1 +:10B9B000A37BAB7316F097FE0423019336330093F9 +:10B9C0002A00049B3100040003F00AFA53E03221FC +:10B9D000300014F0E9FF00281CD0A38812ADAB8022 +:10B9E000A3795C20AB712B4B1293A3681493237B38 +:10B9F0002B73637B6B73A37BAB7316F074FE042312 +:10BA000001932E3300932A00049B3100040003F0BD +:10BA10008BFB30E03C21300014F081FF002822D065 +:10BA2000AB8812ACA380AB79A420A371194B1293FD +:10BA3000AB6814932B7B23736B7B6373AB7BA37318 +:10BA400016F051FE052305000293013B01933833A4 +:10BA500000932200049B310003F0E0F80E4B3D60A0 +:10BA600044351D6008E0442016F03DFE0422049990 +:10BA70000400FFF737FF3C60074B054C18680028AF +:10BA800002D0216813F053FD206817B0F0BDC04606 +:10BA9000402500204431030044250020F0B56049D2 +:10BAA000C56885B08D4206DA030036331A78022362 +:10BAB00013400BD117E0C82200235200954212DD3B +:10BAC000030036331A78002392070CD401230600B2 +:10BAD0001F00363632785408A7433C0002279C40AA +:10BAE000BA432243327004698C4205DA02003632CE +:10BAF0001278520709D415E0C8225200944211DD91 +:10BB000002003632127852070CD406000122363673 +:10BB100033789F08BA439700042293431A00012305 +:10BB20003A433270426901920200019E40328E42D5 +:10BB300005DA01003631097809070AD415E0C82171 +:10BB4000019E49008E4210DD010036310978090757 +:10BB50000BD40600012136363378DF08B9430827B5 +:10BB6000C900BB430B43337001E0002B18D013789E +:10BB7000032B15D80133DBB21370012B03D1002145 +:10BB8000031DD9870CE0042B0AD1020001213632B3 +:10BB9000137804300B4313700023C3870B333CE04E +:10BBA00013780293002B1BD006000127011DCB8FB9 +:10BBB000363601339BB2CB8703963678BC46374086 +:10BBC00008D01D2B0CD963469E43039B1E70002397 +:10BBD000CB8704E0092B03D9029BCF87013B13706D +:10BBE00013F050FB0F4A0723904216D90E49043B2D +:10BBF0008D4212DBC8220133920095420DDC023BDC +:10BC00008C420ADB013B944207DC019804338842F2 +:10BC100003DB0133904200DC0023180005B0F0BDC7 +:10BC200070FEFFFFFF700200E0FCFFFFF0B50400B4 +:10BC300089B0C0680CF0BCF80090019120690CF04C +:10BC4000B7F80690079160690CF0B2F80200029014 +:10BC5000802000060B180391009801990DF052FA0C +:10BC60000CF074F9E0620CF01DF906000F000DF005 +:10BC70001FF804900591300039000CF0F7FC049A8D +:10BC8000059B06000F00009801990BF06DFA320039 +:10BC9000009001913B00029803990BF065FA0200B5 +:10BCA0000B00009801990BF0D9FC02000B000698DC +:10BCB00007990DF027FA0CF049F90022051C002322 +:10BCC0000298039909F0D4FA002801D1A56219E07D +:10BCD0000021281C09F006FB0D4E002801D10D4F54 +:10BCE00000E00D4F281C0CF0DDF802000B003000C6 +:10BCF00039000BF0B3FC32003B000AF0E5FA0CF01F +:10BD000025F9A0620222A3791343A37109B0F0BD03 +:10BD1000EA2E4454FB21F9BFFB21F93F10B513F083 +:10BD20005EFB064909F08EFF0CF0BCF8044A054B97 +:10BD30000AF0F6FD0CF006F810BDC0460000B44352 +:10BD4000EA2E4454FB21194010B513F055FB064967 +:10BD500009F078FF0CF0A6F8044A054B0AF0E0FD64 +:10BD60000BF0F0FF10BDC0460000B443EA2E44546F +:10BD7000FB21194010B50400034B08330360FFF7A3 +:10BD800091FB200010BDC0468831030070B5C36927 +:10BD9000C2681B688AB00400451D1A4250D0EB7F70 +:10BDA000002B01D0013BEB77EB7F082B0DD9012253 +:10BDB000A379134209D11343A371A188130006A8E4 +:10BDC00013F072F8FFF738FB2062EB7F012B26D8C7 +:10BDD0000123A2791A4222D00025A188A57102224E +:10BDE00002A813F061F8A31DDE7F012E17D1FFF723 +:10BDF00023FB2B00226A801A994100900191019B3C +:10BE0000A188AB4203D1174B009A9A4202D9012371 +:10BE1000042201E03300032206A813F045F80323AF +:10BE2000A2791340012B1AD1FFF706FB0023226AE7 +:10BE3000801A9941994208D10B4B984205D80EE0DF +:10BE4000EB7F0B2BB0D80133ADE70222A379A18899 +:10BE50001343A3710332012306A813F025F80AB097 +:10BE600070BDC046E7030000DB050000F0B5070029 +:10BE700000250E0085B002930AAB1B7808370393A8 +:10BE8000104B0400083303600192858085712900FE +:10BE90001822380016F07CFC039A3100380016F0A6 +:10BEA0007DFA6B466A469B88127AA380A31DE671D1 +:10BEB000DA77631D25622000DD77FFF7D5FA2000D1 +:10BEC00005B0F0BD883103000048704716FCFFFF45 +:10BED00010B53320FEF73AFD004810BD16FCFFFFF9 +:10BEE000002310B50400838083710D48216408305D +:10BEF00020608020C000A061E0612062E36020003B +:10BF0000236163616362A362E36223636363A36388 +:10BF1000E3636364110013F0D0FA200010BDC04643 +:10BF2000A0310300F0B5534F97B03B68060005936E +:10BF3000002B00D094E00B331C22212106A80AAC70 +:10BF400001F034FA0EAD0B231D222221200001F056 +:10BF50002DFA0B231B222321280001F027FA0820A9 +:10BF600016F0C1FB0122059B1100049014F0CAFFDA +:10BF70001D21300014F001FD00281CD0A38812AD53 +:10BF8000AB80A3796020AB713B4B1293A3681493F1 +:10BF9000237B2B73637B6B73A37BAB7316F0A3FBC9 +:10BFA00005230193183300932A00049B31000400F9 +:10BFB00002F0EAFF53E03C21300014F00CFD0028B1 +:10BFC0001CD0A38812ADAB80A3796020AB712A4B43 +:10BFD0001293A3681493237B2B73637B6B73A37BF4 +:10BFE000AB7316F080FB05230193373300932A00CF +:10BFF000049B3100040003F039F930E03C213000AB +:10C0000014F08DFC002822D0AB8812ACA380AB7951 +:10C01000A420A371184B1293AB6814932B7B23734A +:10C020006B7B6373AB7BA37316F05DFB052305008D +:10C030000293013B0193383300932200049B3100AB +:10C0400002F0ECFD0D4B1D6044353D6008E04820DA +:10C0500016F049FB052204990400FFF741FF3C60FC +:10C06000064B1A68034B002A01D019684A64186805 +:10C0700017B0F0BD442500204431030040250020C6 +:10C080007FB50426040080793040051E18D123684E +:10C090002000DB699847200013F03AFAA3790322C5 +:10C0A0003343A371A1880123684612F0FDFEA379F2 +:10C0B00028001A00B243A2719B0702D4024800E094 +:10C0C000024804B070BDC04614FCFFFF15FCFFFF22 +:10C0D000F0B504008BB0406C13F08EF9061C606C58 +:10C0E00013F07DF902222100051C07A813F021FAA4 +:10C0F00008980AF063F8041C09980AF05FF80090A9 +:10C10000301C0BF0CFFE06000F000CF0D1FD0BF041 +:10C110001DFF3900019030000CF0A8FA0BF016FF5B +:10C120000290281C0BF0BEFE06000F000CF0C0FDB4 +:10C130000BF00CFF3900039030000CF097FA06006A +:10C140000F000098019909F07DFD0299051C201C43 +:10C1500009F078FD011C281C09F088FE0BF0A2FEF6 +:10C160000490059107980AF029F83900051C300061 +:10C170000BF0ECFE011C281C09F064FD0399051C62 +:10C18000201C09F05FFD019909F05CFD011C281CD1 +:10C1900009F018FA0399041C009809F053FD02995C +:10C1A00009F050FD011C201C09F00CFA0BF07AFE7E +:10C1B000049A059B0CF0A6FF00220E4B0AF0D4FF58 +:10C1C0000D4A0E4B0AF0ACFB0BF0C0FE011C0C48F4 +:10C1D00009F04CFE0021041C09F070F8002804D07E +:10C1E000201C084909F0EEF9041C201C09F0C4FFCA +:10C1F0000BB0F0BD00807640EA2E4454FB2119407C +:10C200000000B4420000B44330B585B00122010003 +:10C2100001A813F08EF9029809F0D0FF0BF042FE4E +:10C2200004000D00019809F0C9FF0BF03BFE22004D +:10C230002B000CF067FF00220C4B0AF095FF0C4A14 +:10C240000C4B0AF06DFB0BF081FE0021041C09F081 +:10C2500035F8002804D0201C074909F0B3F9041C64 +:10C26000201C09F089FF05B030BDC0460080664043 +:10C27000EA2E4454FB2109400000B44310B58379F1 +:10C2800004005A070DD49B0701D4FFF7F9FE636C35 +:10C290002000002B02D0FFF71BFF03E0FFF7B4FFE5 +:10C2A00000E0014810BDC04615FCFFFF82B0F0B5AC +:10C2B0000400EBB064207193709216F0F9F8052237 +:10C2C0000EA8110012F040FE98490FA8FFF700FADF +:10C2D000002396251A001FA86D001A50C1180C33B0 +:10C2E0004A608A60AB42F8D11922002111A816F0E9 +:10C2F0004FFAA06813F036FD00260990FF21A068D0 +:10C3000000F004FD8A4FA06800F05EFB07960896D7 +:10C31000874A3BB2934202D0864A934212DAA0681F +:10C3200013F06EFDA568844918A8FFF7C9F87822B4 +:10C3300018A9280000F032FC18A812F01BFD7C4F51 +:10C34000002606E0002F01D00F2E02D1A06800F0D9 +:10C350003BFB0322089B606801331A40089213F0EC +:10C3600029F80500606813F02CF80022734B069240 +:10C370009D4210DB013206922A00C8320BDB0422F8 +:10C380000692AA229200954205DC03220692C82D4D +:10C3900001DC013A069200220492984210DB01234C +:10C3A00004930300C8330BDB04230493AA239B00EC +:10C3B000984205DC03230493C82801DC013B049365 +:10C3C0000EA812F0B8FD002511ABEB5C012B08D1D3 +:10C3D0005B496B00CA185278C95C0EA8FF23FFF7AF +:10C3E000F5F80135192DEFD16B4610229A5E6B4698 +:10C3F0000EA81821595E089BFFF7E8F83BB2002B06 +:10C4000001DB0F2E07D90023A068009374301A00B7 +:10C410000EA912F0A6FD00230593059B484A5B0078 +:10C42000995C0698814227D1D3185B78049A93428D +:10C4300022D12C2206AB9B18059A9B5C012B1BD0AA +:10C440000C23079A216853431D0000220AA813F009 +:10C4500070F81FAA2B0094460AAA634423CA23C378 +:10C460002C2206AB05999B182B3A5A54079B013393 +:10C47000DBB20793731CDEB2059B01330593192BC6 +:10C48000CBD1642016F014F83B00643B9FB2079BAD +:10C49000182B00D83CE71A001FA918A813F0B6FA09 +:10C4A0006A461BAB23CB23C21B6813601899199AE9 +:10C4B0001A9B206813F012F8E568002D0CD0214972 +:10C4C00010A8FEF7FDFF1C2318AA10A9280014F0DD +:10C4D000CAF910A812F04EFCA06813F091FC0FA945 +:10C4E00010A8A56812F010FD0022174B009210A9A9 +:10C4F00001932800130000F0D1FA10A812F0F7FC05 +:10C50000FA20800015F0D4FFA06813F079FC099997 +:10C51000A06800F0FBFB0FA812F0E9FC0EA812F0D7 +:10C52000E6FC6BB0F0BC08BC02B01847C740030083 +:10C530008C3C0000D18AFFFF0C41030058FDFFFF37 +:10C540009540030021410300DC050000F0B587B0F1 +:10C5500001930EAB1B88060003930D9B0D00009307 +:10C56000019B02920C9F002B3DD0002F02D1009B1B +:10C57000DB0738D5282016F0B6F80400103012F08A +:10C5800088FC6B461B8918202580638016F0ABF869 +:10C59000049707000500009B10220593019B0021D2 +:10C5A00008C7380016F0F4F8082204A9380016F07D +:10C5B000D1F80E4B02226B6100230399E3602362E2 +:10C5C000636233680A43A560A2805B682100300083 +:10C5D0009847002808D0200012F082FB200016F0B7 +:10C5E00094F8034800E0034807B0F0BD19F60200D4 +:10C5F00016FCFFFF17FCFFFF70B58CB08360109B2B +:10C6000001604260C36004001849180014F0F8F893 +:10C61000051E14D001001C22103105A816F09AF84E +:10C620006A4608AB43CB43C21B6813602068059978 +:10C63000069A079B12F052FF280016F066F80C4B82 +:10C64000186800280ED00B4A05AB0592002206920E +:10C65000C03202926A4622CB22C223000322052165 +:10C66000FFF774FF20000CB070BDC04621410300ED +:10C6700034250020ADC20100F0B5040085B0637A16 +:10C680009C46002B03D1200013F0DDF969E0A37A6A +:10C69000266F01931023019AF35600259B1801225F +:10C6A0009A402900F36802920393039B9D4231DA7A +:10C6B000B368019A6B439B1872695B00E77AD318E1 +:10C6C0001A785878E379012F04D15F1E3F1A1000C1 +:10C6D0003A000EE0022F05D15F1EBA1A277A013FF9 +:10C6E000381A06E0032F04D1277A013FBF1A02004F +:10C6F00038005B004343606F8218D3189B79634511 +:10C7000000DD6346627B1A4202D00123AB4019432D +:10C710000135CAE71123C943F356606C9940236978 +:10C720001940029B194315F038FFA37B072B18D83B +:10C73000627B581C520062730B499A00A073022B53 +:10C7400003D8885815F0A9FE99E7084B2000236309 +:10C7500000236363064B8958E4622364143015F0A8 +:10C7600025FD05B0F0BDC046E431030079C60100E7 +:10C7700033FA020010B50400044B036015F00EFDFF +:10C78000200007F0DDF9200010BDC046403903004D +:10C7900010B504000E4B08330360FEF783FE200043 +:10C7A000743012F0A4FB2000603012F0A0FB2000D7 +:10C7B000583012F0DFFA2000503012F0DBFA20007F +:10C7C000044B14306361FFF7D5FF200010BDC04655 +:10C7D000CC3103002C390300F8B500250400324B9E +:10C7E0008580083303608571143016000F0007F050 +:10C7F00091F920002D4BE562636125645030FEF70E +:10C8000099FE20005830FEF795FE20006030FEF7BC +:10C81000BFFE20000423F25E33682667590009B288 +:10C82000743012F091FB3378226FE3717368012644 +:10C8300023721023E572A572A7802561D3569168F3 +:10C8400059188B4204DA3000984001330543F8E769 +:10C8500011230120D356D16859188B4206DA020001 +:10C860009A402669013332432261F6E7142015F01D +:10C870003AFF226900212A430123060007F058FFEE +:10C88000FF2262722200002301254832666465732C +:10C89000A373237320001370A366FEF7E5FDA3794D +:10C8A00020002B43A371F8BDCC3103002C390300C9 +:10C8B000F0B5437A85B00400002B03D1200013F0BB +:10C8C000C2F866E00122837A11009C461023066FAD +:10C8D0000025F35603926344994001912900F368BF +:10C8E0000293029B9D422CDAB36872696B436344E6 +:10C8F0005B00E77AD3181A785878E379012F04D1CE +:10C900005F1E3F1A10003A000EE0022F05D15F1E95 +:10C91000BA1A277A013F381A06E0032F04D1277A82 +:10C92000013FBF1A020038005B004343606F82186A +:10C93000D3189B79002B02D0039BAB4019430135E0 +:10C94000CFE71123C943F356606C9940236919401E +:10C95000019B194315F021FE667AB31EDBB2FC2B56 +:10C9600014D8FEF72FFD0C4B0500236300230B4862 +:10C9700063630B4BFF21E4622364704308F062FBA6 +:10C98000290041432000143015F010FC637A012B7C +:10C9900094D905B0F0BDC04647FA0200B6030000C6 +:10C9A00033FA02001FB5012381881A00684612F08D +:10C9B0007BFA012303491A00684612F075FA05B0A4 +:10C9C00000BDC046FE0300001FB5030048331A78BF +:10C9D0000400002A0DD000221A70012381881A0059 +:10C9E000684612F061FA012304491A00684612F001 +:10C9F0005BFA2000743012F09EFA1FBDFF030000A6 +:10CA000010B548300378002B06D00378012B03D0F3 +:10CA10000121024812F0B8F810BDC046FF03000023 +:10CA200010B501210400062012F0AEF8064B984222 +:10CA300009D1230048331A78002A04D01B78012B2F +:10CA400001D020BFF5E710BD16FCFFFF70B5050053 +:10CA5000141E09DB060048363378002B06D03378E5 +:10CA6000012B03D00B4813E00B4811E000232800F2 +:10CA70001A007430FEF77EFE0020844207D02B009F +:10CA80004A331C8007234C352880337000E0200097 +:10CA900070BDC04612FCFFFF17FCFFFF73B5079C7B +:10CAA0000500002C09DB060048363078002806D047 +:10CAB0003078012803D00D4816E00D4814E00698A0 +:10CAC0001BB2C0B20090280012B2743012F049FAC2 +:10CAD0000020844207D02B004A331C8007234C35AA +:10CAE0002880337000E0200076BDC04612FCFFFFB6 +:10CAF00017FCFFFFF8B505000F00161E13DBFFF74C +:10CB00007FFF2B0048331C78E4B2002C0DD132009B +:10CB100039002800FFF79AFF301E07D02800FFF7E2 +:10CB20007FFF200002E0024800E00248F8BDC04656 +:10CB300017FCFFFF11FCFFFFF0B587B00D9E05004D +:10CB40000F0002920393002E1EDBFFF759FF2B000C +:10CB500048331C78E4B2002C18D1390005A812F033 +:10CB6000D3F90C9B029A009305A9039B0196280018 +:10CB7000FFF794FF05A812F0BAF9301E07D028007D +:10CB8000FFF74EFF200002E0024800E0024807B035 +:10CB9000F0BDC04617FCFFFF11FCFFFFF8B5040015 +:10CBA000171E09DD060048363378002B06D033788F +:10CBB000012B03D00C4816E00C4814E02200E37966 +:10CBC0005632013B137023000025200054331D8092 +:10CBD000503012F02CF923004A331F800223280022 +:10CBE0004C3425803370F8BD12FCFFFF17FCFFFFAB +:10CBF000F7B505000F00161E18DDFFF701FF2B002B +:10CC000048331878C4B2002C12D1390001A812F0B0 +:10CC100006F9320001A92800FFF7C0FF01A812F0B1 +:10CC2000A9F82800FFF7FCFE200002E0014800E020 +:10CC30000148FEBD17FCFFFF11FCFFFFF8B5040023 +:10CC4000161E09DD070048373A78002A06D03A78E0 +:10CC5000012A03D0144826E0144824E05D42069BD4 +:10CC6000FF3301D16B1D00E0069B22009BB26432B2 +:10CC700013802300200066331D70603012F04CF9E1 +:10CC8000220000236C3213709D4200D0B3B2220008 +:10CC90004A321380079B00205A1E9341013E4C34B8 +:10CCA000053326803B70F8BD12FCFFFF17FCFFFF29 +:10CCB000F0B587B005000F00161E03931DDDFFF7CA +:10CCC0009FFE2B0048331C78E4B2002C17D13900AA +:10CCD00005A812F019F90D9B320001930C9B05A9D0 +:10CCE00000932800039BFFF7A9FF05A812F0FFF8A7 +:10CCF0002800FFF795FE200002E0024800E002480D +:10CD000007B0F0BD17FCFFFF11FCFFFFFF2902D8A1 +:10CD10004172002000E001487047C04617FCFFFF49 +:10CD200013B5040004A800780090200015F0A9FABB +:10CD3000002801D1207500E0004816BD0EFCFFFF61 +:10CD400013B5040004A800780090200015F081FAC3 +:10CD5000002801D1207500E0004816BD0EFCFFFF41 +:10CD60007FB50D0011000F226A4404001E1E1170D1 +:10CD700015D0089B002B12DD012329000093FFF73B +:10CD8000DFFF002801D007480AE00090089B32002E +:10CD900029002000FFF7C4FF002801D0F3E7024874 +:10CDA00004B070BD0EFCFFFF17FCFFFF30B50400A0 +:10CDB00087B0057B006C08F023F8A02200210E4B01 +:10CDC000AD00D200285199500C4A14319950636C2F +:10CDD0006846597C237BC91849B213F00BF9039BB1 +:10CDE000019A03211A60207B0130C0B208F026F9B5 +:10CDF000217307B030BDC04600700040040500003C +:10CE000082B070B50400002588B00C920D93636C5D +:10CE10009A6895420ADA197C02A8491949B213F0B6 +:10CE2000E9F8069B039A01351A60F0E75D7C237BE5 +:10CE300002A8ED186DB2290013F0DCF8039A059BE7 +:10CE400001921A600021182202A815F0A1FC02A884 +:10CE50000022290015F0A2FA206C002801D015F05C +:10CE600054FC082015F03FFC2900060007F0A0FF45 +:10CE7000094B2000E3620023FA212363074B266459 +:10CE8000A462E3631030090115F090F908B070BC9A +:10CE900008BC02B01847C046ADCD0100A1FF02009A +:10CEA000F0B504000E00150085B000930CAB1B8894 +:10CEB0001030019311F0EDFF26806580182015F0E9 +:10CEC00012FC070002AE33003D000AAA03CA03C3E6 +:10CED000009B102208C50021280015F059FC3100E4 +:10CEE0000822280015F036FC064B02227B61200048 +:10CEF00000230199A7600A43E360A2802362636272 +:10CF000005B0F0BDB5FF020070B505000400103596 +:10CF10000E00302286B00021280015F039FC2800D0 +:10CF200006F0F8FD0023194A66642261184AA362DC +:10CF30001668E363237323606360A3609E421FD07F +:10CF4000144A28200492059315F0CDFBC023050058 +:10CF50006A46029304AB03CB03C2230006210222DC +:10CF60002800FFF79DFF336829005B683000984771 +:10CF7000002805D0280011F0B3FE280015F0C5FBED +:10CF800000232000236406B070BDC0462C39030086 +:10CF90003425002001CE010030B5134B91B01D683F +:10CFA0000400002D17D0114B6A460493002305930B +:10CFB0001033029304AB03CB03C2230002220621E9 +:10CFC00006A8FFF76DFF2B6806A99B682800984705 +:10CFD00006A811F085FE2000054B10302361FFF7F5 +:10CFE000C9FB200011B030BD3425002001CE010066 +:10CFF0002C390300F7B507000D1E27D000230226A9 +:10D0000004690193002C1DD0AA88A38853403342A1 +:10D0100016D1324203D1AB88334207D010E0A96861 +:10D02000A06813F054FF002804D1F4E7A368AA68AD +:10D03000934205D12B88002B0AD022889A4207D030 +:10D04000646ADFE7019B2000002B1ADC0D4818E022 +:10D050006B88002B02D062889A42F1D1EB68E268BB +:10D06000934201D0002BEBD17B68002B01D0200034 +:10D070009847A388044A1343A380019B013301937B +:10D08000DEE7FEBD17FCFFFF0080FFFFF0B50600E6 +:10D0900085B00D1E5CD001270469002C1DD0022133 +:10D0A000AA8800230A4202D0A3885B083B4022687A +:10D0B00029688A4257D1002B0AD0A968A06813F0CA +:10D0C00006FF00284FD0EB68E26893424BD141E065 +:10D0D000A368AA68934246D1F5E731692A880F0010 +:10D0E0000B1E0CD1356101232149684611F0DCFE8D +:10D0F00020003AE0586A1F00002812D00300188868 +:10D100009042F7D318003B000488944209D1478825 +:10D110006C88A74205D8446A0300002C01D0200087 +:10D12000F2E799420AD10888824204D306D14C889A +:10D130006888844202D96962356102E0596A69628D +:10D140005D6201230A49684611F0AEFE00200CE042 +:10D1500008480AE0A3881AB2002A02DA5B045B0CD2 +:10D16000A380054801E0646A97E705B0F0BDC046BA +:10D17000FD03000017FCFFFF16FCFFFF064B10B578 +:10D180001A00040008322C33026083600830FDF777 +:10D19000BBFE200010BDC0460432030008B4024BA1 +:10D1A0009C46083808BC60477DD1010008B4024B9A +:10D1B0009C46083808BC60475B0003000C4A00230B +:10D1C00011002C32083110B5436083818373826073 +:10D1D000036143618361C383016004000830FDF78C +:10D1E00085FE044B1A68002A00D11C60200010BD87 +:10D1F0000432030034250020F7B50E000125046930 +:10D200000192002C37D0238832889A4201D0002B1B +:10D2100026D1638872889A4201D0002B20D1FDF775 +:10D22000B9FD0123002806D0A288BF331340C03BBC +:10D230005A425341DBB2019A934210D1A7883BB2C4 +:10D24000002B0CDB10223100A01815F083FA4023CC +:10D250001F4207D1FDF79EFD002803D006E0002500 +:10D26000646ACEE7200012F001FFF9E721000348CD +:10D27000FDF764FFF4E72800FEBDC0466D00030023 +:10D2800008B4024B9C46083808BC6047F70103000D +:10D29000F0B587B001930EAB1B88060003930D9B7E +:10D2A0000D000093019B02920C9F002B3DD0002F9C +:10D2B00002D1009BDB0738D5282015F014FA0400B2 +:10D2C000103011F0E6FD6B461B8918202580638025 +:10D2D00015F009FA049707000500009B102205933A +:10D2E000019B002108C7380015F052FA082204A952 +:10D2F000380015F02FFA0E4B02226B6100230399C0 +:10D30000E3602362636233680A43A560A2805B68BE +:10D31000210030009847002808D0200011F0E0FCE0 +:10D32000200015F0F2F9034800E0034807B0F0BD13 +:10D330002302030016FCFFFF17FCFFFFF0B50400FB +:10D34000160000258380164A164B857102602181E4 +:10D3500046810573186889B08C46A8421DD0124AD0 +:10D3600005950492C02202926A4604AB82CB82C227 +:10D37000614623002A00FFF78BFF0B4A094B0692F8 +:10D38000C022186802926A4606AB079582CB82C219 +:10D3900023002A003100FFF77BFF200009B0F0BD19 +:10D3A00048320300342500204D03030030B500242B +:10D3B00003730123034D847105608180827343737D +:10D3C000846030BD4431030070B583790400DB070D +:10D3D00002D5806815F099F9A3799B0702D5A0685A +:10D3E00015F093F9A3795B0707D5A0230021144A10 +:10D3F000DB00D150A06815F088F9A3791B0708D588 +:10D40000A568002D05D0280013F0D8FD280015F0E0 +:10D410007CF9A379DB0605D5A068002802D0036853 +:10D42000DB6898476023A2791A4205D0A0680028DB +:10D4300002D003685B6898470023A360A37170BDA6 +:10D4400000700040F7B50222037B04000F00134276 +:10D4500025D0012925D88579154016D1FFF7B4FFCD +:10D46000182015F040F9A37B18222900060001932B +:10D4700015F08EF96B4604213000595614F0A0FFC8 +:10D480000222A379A6601343A371A3685A68002FF0 +:10D4900003D0DB681A60002004E01B69FAE7024849 +:10D4A00000E00248FEBDC04616FCFFFF17FCFFFF70 +:10D4B000F7B50127037B04003B422CD0612385791B +:10D4C0001D4018D1FFF780FF182015F00CF9A37B41 +:10D4D00018220093637B29000600019315F058F988 +:10D4E0006B460021019A5956300014F057FFA3797A +:10D4F000A6603B43A3716023A2791A4203D0A068BF +:10D5000014F0E3FD08E0A268536950681B681840F6 +:10D51000431E984100E00148FEBDC04616FCFFFFD7 +:10D5200070B5037B04000D001B0713D50B4B99420C +:10D5300012D812F0A6FF0300002083420DD128006C +:10D5400008F03CFE064908F0B3F9011CA06803F09E +:10D550009FFA02E0034800E0034870BDFF030000AB +:10D5600000C07F4416FCFFFF17FCFFFF70B50425C9 +:10D57000037B04002B4214D083792B420DD1FFF79B +:10D5800023FF082015F0AFF80E210600615607F0C2 +:10D590000FFCA379A6602B43A371A06807F030FCB1 +:10D5A00000E0014870BDC04616FCFFFFF7B501273B +:10D5B000037B04003B4219D0102385791D4011D113 +:10D5C000FFF702FF282015F08EF80E21A2883B00FD +:10D5D000615600950600FEF749FC1022A379A6606B +:10D5E0001343A371A06811F022FF00E00048FEBDC4 +:10D5F00016FCFFFF70B5037B05000E001B0713D55B +:10D60000002913DB12F03DFF041E11D1A86803F0BE +:10D6100053FA0949884202D0A86803F053FA31004E +:10D62000A86806F043FF04E0044C02E0044C00E06C +:10D630000024200070BDC046204E000016FCFFFFF5 +:10D6400017FCFFFFF8B51400027B070012071CD57A +:10D6500000291CDB002C1ADD002B18DDB42900DDAD +:10D66000B421FA26B600714365100800B4215D1B91 +:10D6700007F0E8FC754360433100281807F0E2FC2E +:10D6800001003800FFF7B6FF02E0024800E0024860 +:10D69000F8BDC04616FCFFFF17FCFFFF10B58379ED +:10D6A0001B0703D5806803F00DFA00E0004810BDA9 +:10D6B00016FCFFFF10B50124837941731C4004D090 +:10D6C000806814F011FF002007E06022134203D0AD +:10D6D000806814F001FDF6E7004810BD16FCFFFF5E +:10D6E000F8B56023867904000D001E4025D1FFF7B0 +:10D6F0006BFE582014F0F7FF0E210700615601F071 +:10D700004BF83800A760617B14F0E6FC0122A068AA +:10D71000104B114F436204628662476311001C3054 +:10D7200006F084FDA0680D4B8463C3630664C76480 +:10D7300001221C30022106F079FD6022A379934377 +:10D74000403A012D02D0022D01D140221343002086 +:10D75000A371F8BD050503006F040300290503004C +:10D7600010B50300032911D8080007F0D7FB0B02FE +:10D7700002061800FFF7B4FF02E01800FFF716FFDB +:10D78000002004E0180012F0E1FEF9E7004810BDA7 +:10D7900017FCFFFF70B5040000250D4B0E00083389 +:10D7A0008580857103602100183012F006FF20008B +:10D7B0002100203012F043FF064BA680A571E571D1 +:10D7C0002572E5602561656120001C6070BDC04662 +:10D7D0005832030048250020072906D8044B054A83 +:10D7E0005956054B0020D15000E004487047C04610 +:10D7F000B3420300001000400C05000017FCFFFFBF +:10D800008379DB0702D5C160002000E00048704743 +:10D8100016FCFFFF8379DB0701D5C06800E00148F3 +:10D820007047C04616FCFFFF70B545690400002D27 +:10D8300021D0037A032B20D8FFF7ECFFA8622C201D +:10D8400014F051FF2C220021050014F0A1FF002349 +:10D85000626953622369002B01D1226105E0596A94 +:10D86000002901D00B00FAE75A62237A656101337F +:10D870002372002002E0024800E0024870BDC0466A +:10D8800017FCFFFF13FCFFFF154B70B55A68154DD1 +:10D89000002A03D000225A600132AA601B69114E8F +:10D8A000002B1CD000210E4B0F4C19618023DB0094 +:10D8B000F358012B0ED1A923DB00F158206849420F +:10D8C000FFF79EFF2068FFF7AFFF23685A69074BF9 +:10D8D000F25002E02068FFF793FF0123AB6070BDB8 +:10D8E000FC10004000100040482500200405000006 +:10D8F00070B505000C0011F0D6F8002804D1034BD8 +:10D90000034AEC71D45000E0024870BD24050000C9 +:10D910000010004016FCFFFFF8B5837905000020D9 +:10D92000DB076FD411F0BFF8002868D16E69002EB4 +:10D9300008D12C3014F0D7FE04002C22310014F052 +:10D9400027FF6C616B69002B5BD000222E4B0121FD +:10D950005A608022D20511605A68002AFCD0062243 +:10D960002A4B2B4C9A562B4B0026E2500722043BA5 +:10D97000E2500833E650284A284B2800E250E97963 +:10D98000FFF7B6FF01220821254B2648E650043355 +:10D99000E250254B254FE1500433E0500223244848 +:10D9A000235024482750244F043827501827234851 +:10D9B00027506F6922482750C120800021502149FB +:10D9C0008538FF380B500B6080218900635871380F +:10D9D000FF38034363501C4B5E6062605A68002A44 +:10D9E000FCD000240126184B28001C61084B9E60C7 +:10D9F000FDF77CFAAB7920003343AB7102E01348AA +:10DA000000E01348F8BDC046FC000040B3420300EC +:10DA1000001000400C050000746962751C050000D0 +:10DA20002C0500002000040214050000FFFF000088 +:10DA3000340500003C0500002110010054050000E1 +:10DA40000405000000E100E0FC10004016FCFFFFB0 +:10DA500013FCFFFF03000069002809D00221054ADA +:10DA6000D167426A1A611A7A013A1A72024B196036 +:10DA70007047C04604E100E000E100E070B504003A +:10DA80000D0011F010F8002845D1002D45D02B785D +:10DA9000232B42D802220121214BDA67214B224A53 +:10DAA000586111615A692049002AFBD01F4A1D485C +:10DAB0008D50002545600120086011005A68002A39 +:10DAC000FCD00020174A1061174A01309060186995 +:10DAD000154A0028FBD06069505000201149486168 +:10DAE000012111615A69002AFCD000210D4A5160C0 +:10DAF0000D4A013151605A68002AFCD000200122F1 +:10DB0000C021084B49001861074B9A60084B9218D6 +:10DB10005A501A6002E0074800E0074870BDC0464E +:10DB200004E100E0FC10004000100040040500008B +:10DB300000E100E016FCFFFF17FCFFFF37B54C6863 +:10DB40000500002C03D10C4911F0EDFA12E0636AD4 +:10DB500001A84B602278211D033AA36A11F017FB3C +:10DB6000200014F0D2FD01A9280011F0DCFA01A870 +:10DB700011F0D2FA28003EBD3C25002030B505004A +:10DB80008DB0002911D0232A0FD801ACD31C00205E +:10DB900023700123A07002A86370E37014F0DAFD13 +:10DBA00021002868FFF76AFF00E001480DB030BD92 +:10DBB00017FCFFFFF0B585B0040014F031FB204BDB +:10DBC0001B785B073AD50025236CC6B20227DF5FBE +:10DBD000BD420EDA200029B2403011F04DF98642E4 +:10DBE00005D1012320211A00684611F05DF90135A5 +:10DBF000EEE7250023004E3528884C331978013094 +:10DC000007F006FB230050331B8889B28B420FD0EC +:10DC10002B88A26CD654636C2980002B0EDB2A88DB +:10DC200093420BD101235B4263640222023301E081 +:10DC3000012303222021684611F036F905B0F0BD1A +:10DC4000422800200121024A13780B4313707047C9 +:10DC5000422800200221024A13780B4313707047B8 +:10DC6000422800200121024A13788B431370704729 +:10DC7000422800200221024A13788B431370704718 +:10DC80004228002010B5002903DB024B196014F074 +:10DC9000B3FA10BD4C25002070B504001E0004AB83 +:10DCA0001D7805F085FF20000E4B40302360FDF706 +:10DCB00041FC230001364C33013522001E701D73D8 +:10DCC0000023E1214E32A364636513805380938166 +:10DCD000D381013B200063644902FFF7D3FF20009A +:10DCE00070BDC046F430030070B50500141E012C51 +:10DCF00010D003004E331888023B4018197807F003 +:10DD000087FA69640025022C05D12100202010F03B +:10DD10003BFF00E0014D280070BDC04617FCFFFF2F +:10DD200070B5050004000A005035002907D1030032 +:10DD30004E331B882A889A4212D111481FE00129CC +:10DD400006D101002A884E310B889A42FCD007E0A8 +:10DD5000022905D103004E331B88298899420AD035 +:10DD6000A36C28884C341E5C2178013007F050FAEF +:10DD70003000298003E00121FFF7B6FFF0E770BD16 +:10DD80000CFCFFFF70B5151E012D0AD0403011F0BC +:10DD90004EF80024022D05D10121202010F0F4FEC0 +:10DDA00000E0014C200070BD17FCFFFFF8B5114DDD +:10DDB00004002B781B0705D5012112F0A7FC606D2C +:10DDC000FDF78AFA082723002E785833BE432E70B9 +:10DDD0001878FDF74BFA6065002808D02300002072 +:10DDE0005A335C343E4318802E70208000E0024895 +:10DDF000F8BDC0464228002013FCFFFF70B50B4B56 +:10DE000005001B780C009B070ED4FFF723FF2B00A7 +:10DE1000013458331C702800FFF7C8FF04002800A5 +:10DE2000FFF728FF200000E0014870BD42280020D5 +:10DE30000DFCFFFFF0B5060007005C365A3733884B +:10DE40003A8885B004009A421ED0104B1B781B07FD +:10DE50001AD53388426DD15C14F0E6F9230030887E +:10DE600058331978013007F0D3F93B888DB2AB42B3 +:10DE700009D1074901230222684611F015F8012152 +:10DE8000200012F043FC358005B0F0BD4228002090 +:10DE9000FF03000073B50D0006A9040009780430E3 +:10DEA000002A01D1DE070DD5002D0BD00C34260041 +:10DEB00018244C433419A360044B626025606361ED +:10DEC000012200E0002206F0ABF873BD69060300F2 +:10DED000F0B507000400002589B003910492059372 +:10DEE0005A37049B9D4213DA23003E885833197831 +:10DEF000701C07F08DF923005C331B8889B29942AE +:10DF000006D0039B626D5B5D013593553980E8E770 +:10DF1000059B012B03D002210648FDF7A1F8012340 +:10DF200020000093044A00232100FFF7B3FF2800DC +:10DF300009B0F0BDFF03000035DE0100F7B5194C54 +:10DF40001F0023780500019116009B0725D4002AA5 +:10DF500025DD002923D0FFF77DFE23781B0701D59F +:10DF6000002407E02800FFF721FF0028F8D017E081 +:10DF7000A6420DDD019B321B191928003B00FFF75B +:10DF8000A7FF39002418280012F0B0FB002FEFD1B2 +:10DF90002800FFF76FFE200002E0034800E003487E +:10DFA000FEBDC046422800200DFCFFFF17FCFFFF0E +:10DFB000F0B5174E87B0337805005B0705D5002113 +:10DFC00012F0A4FBA86CFDF787F904273378BB4354 +:10DFD00003936B461B7B33702B004C331878FDF793 +:10DFE00045F9A864002810D02B0000244E331C8073 +:10DFF0005C80039B28001F433770064A009423006F +:10E000002900FFF747FF200000E0034807B0F0BDFC +:10E0100042280020B5DB010013FCFFFF70B50E4C59 +:10E02000050023780E00DB0714D4FFF70BFE2378DE +:10E030005B0709D531002800FFF772FE04002800B5 +:10E04000FFF710FE200006E02800FFF7B1FF0028D0 +:10E05000F0D000E0014870BD422800200DFCFFFF19 +:10E06000F7B52C4C0193237805000F001600DB0751 +:10E070004DD4FFF7E7FD23785B0703D5019B1C1EFA +:10E080000AD011E02800FFF793FF0028F6D03FE008 +:10E09000B44237DA3855013400212800FFF740FE3A +:10E0A0001D4B9842F4D12DE0019B012B0AD13C007D +:10E0B000E31BB3421BDA01212800FFF731FE207079 +:10E0C0000134F5E7019B0024022B1BD1280012F03C +:10E0D000ECFA864207DD280012F0E7FA019A311ABD +:10E0E0002800FFF701FE3C00E31B9E4203DCF443E3 +:10E0F000E417344006E002212800FFF711FE2070EB +:10E100000134F1E72800FFF7ADFD200000E00348EF +:10E11000FEBDC046422800200CFCFFFF0DFCFFFFA7 +:10E12000F0B58BB002AF7B60704BB8601B780C0011 +:10E130001500DA072CD45B0708D40800FFF738FF76 +:10E14000011E03D0B86810F031FECAE02000FFF7CE +:10E1500079FD230050331B88FB603B6101235B4248 +:10E160007B6126004E3633883A699A4203D07B6938 +:10E17000013300D197E07B68012B21D07B68022B13 +:10E180002FD07B69002B50DA2000FFF76BFDB868B9 +:10E19000FDF7D0F9A5E0138839699942FBD0002634 +:10E1A000A36C5B5C7B602B6802229B5E9E420DDB56 +:10E1B000230038694C331978013007F029F83961A8 +:10E1C0007B690133DDD122004E32E4E731B2280011 +:10E1D00010F052FE7B68834201D13B697B610136BE +:10E1E000E1E77B690133CCD11C232900F81810F03A +:10E1F00016FE1C237A68F9182000FFF7C3FD1C23C4 +:10E20000F81810F0B7FD3388013B7B611C23F81828 +:10E21000FDF790F91C232000F918403010F007FE9C +:10E220001C23F81810F0A6FDABE76B46FA687B607C +:10E230007B699D1A934205DA23004C331D787B6974 +:10E24000AD1AED182B0069460833DB08DB00CB1A4A +:10E250009D4602AE6A1C0021300014F099FA23009A +:10E260004C333B611A78BB8A20000193FB68009312 +:10E27000A16C330012F002FA230050337B6118883E +:10E280003B6901301978401906F0C2FF7B69200014 +:10E290001980FFF7E7FC2AB23100B868FDF720F9D2 +:10E2A0007B689D461DE00026A36C3A699B5C3B6041 +:10E2B0002B6802229B5E9E420ADA31B2280010F0DF +:10E2C000DBFD3B68834201D13B697B610136EFE7AF +:10E2D000230038694C331978013006F099FF396111 +:10E2E0003FE7BD46B86809B0F0BDC04642280020EF +:10E2F00070B50B4B05001B780C00DB070ED4FFF745 +:10E30000A1FC2B0001344C331C702800FFF750FE99 +:10E3100004002800FFF7A6FC200000E0014870BDC3 +:10E32000422800200DFCFFFF70B5224B86B01B7801 +:10E3300004000D0016009B0701D01F4837E0FFF7CF +:10E3400089FC2000FFF77EFC200012F0BEF90028B7 +:10E3500003DD0121200012F0D9F90021200012F084 +:10E36000D5F929000025201D320005F0BBFD200055 +:10E370000095124A2B002100FFF78CFD200012F0BF +:10E38000A4F9A84207DD01230D4A009321002B00C8 +:10E390002000FFF77FFD0B4B20001968FFF772FC90 +:10E3A0002000FFF75FFC2000FFF764FC002006B0B0 +:10E3B00070BDC046422800200DFCFFFFB5DB010008 +:10E3C00035DE01004C250020F7B580277F053D692B +:10E3D0007C690822113C6C4306002100684614F059 +:10E3E000B9F9104B009A9A4219D000930023019377 +:10E3F000796930001339694312F0BDF9019A009927 +:10E40000300012F0D0F92100300012F0B4F979692F +:10E41000AB08133969432200300012F0B6F90198B5 +:10E42000FEBDC046FECA0000F0B50D00ABB00D92B7 +:10E4300000213022060012A80B9314F0A9F928003D +:10E4400014F0E6F9431C0C93102B00DDB6E00B9B97 +:10E45000202B00D9B2E02900300012F0D1F9071EBC +:10E4600029D129000C9A12A814F074F90D990B9A6D +:10E4700016A814F06FF980235B051F695A693000F4 +:10E48000113A7A435D690D92FFF79EFF0D9B302292 +:10E490000833002104001EA80F9314F079F9290015 +:10E4A00013397943300012F066F90F9B0B93002368 +:10E4B0000C930E9335E010300B9A0D9914F03BF944 +:10E4C0000400380014F021F9002C7AD0C9E70B9928 +:10E4D00030221EA814F03EF912A91EA814F08EF9DD +:10E4E000002822D13849300022001091119412F0F6 +:10E4F0005AF96A460B9B099315AB23CB23C223CB56 +:10E5000023C223CB23C23000149B1299139A12F01A +:10E5100058F901230E930B9B30330B930C9B013363 +:10E520000C930C9BA342D2DB10E06A460B9B099331 +:10E5300021AB23CB23C223CB23C223CB23C2300066 +:10E540001E991F9A209B12F03CF9E4E7E543302125 +:10E55000ED1725404D430F9B5D190E9B002B1BD1E2 +:10E56000B81E06F0E5FC84422AD017490134300079 +:10E5700022001091119412F016F96A46099515AB14 +:10E5800023CB23C223CB23C223CB23C23000129937 +:10E59000139A149B12F015F90D99300012F0EBF854 +:10E5A00080235B0559690C23634313390233794394 +:10E5B0000D9A300012F0E9F8002402E0034C00E06C +:10E5C000034C20002BB0F0BDFECA000017FCFFFF7B +:10E5D00013FCFFFF8023F0B55B051A6995B002922A +:10E5E0005A6905910299113A51435C69029B133CA7 +:10E5F000050003915C43FFF7E7FE061E4ED000279F +:10E60000039B302208330021083408A8019314F03A +:10E61000BFF82100280012F0AEF80497B74220DAC4 +:10E620000199302208A814F095F8059908A814F06B +:10E63000E5F8002809D11B49721E280006910792AF +:10E6400012F0B1F80123049306E022000C23019993 +:10E65000280012F09AF83034019B013730330193CF +:10E66000DCE7049B002B05D10E493200280012F094 +:10E670009AF813E00399280012F07DF880235B05D7 +:10E6800059690C23029A13394A4373431100280035 +:10E690000233039A12F079F8002000E0024815B026 +:10E6A000F0BDC046FECA00000CFCFFFF70B50400C0 +:10E6B000A280FA22002308000C4992000831216050 +:10E6C000A3716061E260A3606382094912F098F867 +:10E6D000051E09D00100200010310222123014F072 +:10E6E00039F8280014F011F8200070BD70320300D2 +:10E6F0002C41030030B50225837987B004002B42FA +:10E7000004D1FCF7F3FBA3792B43A371200012F093 +:10E71000BBF800282DD06B46DD1C280012F0ABF8AA +:10E720002B78002B03D001A812F0A3F80FE00122F0 +:10E73000114B1A60114A5368002BFCD000220F4B7A +:10E740005A600F4B01321B6801930B4B5A60032236 +:10E75000019BD9170A40D3189B102382FCF76CFE4B +:10E76000E368A18818180123A0601A0002A810F01D +:10E770009BFB002007B030BD00C00040FCC0004043 +:10E7800008C5004010B50400024B036005F092F983 +:10E79000200010BD9032030010B5040005F096F97A +:10E7A000034B00222360002320002265636510BD17 +:10E7B00090320300022802D10122014B1A707047E7 +:10E7C0004328002070B5064C05002378002B04D1A7 +:10E7D000044802F03BFE01232370280070BDC046B0 +:10E7E00044280020B5E7010070B50C0010F05BF97B +:10E7F000002811D0164B0022A50A1C001A70280010 +:10E8000012F06FF8002803D00A2013F051FEF6E74B +:10E810002378002BFCD019E0022180250D4B0E4AF5 +:10E82000ED00995080205959C0000029FAD0A1214B +:10E83000084DC9006C5019580029FCD0002005492A +:10E8400088508021C9005A58002AFCD070BDC046AB +:10E850004328002000E0014004050000F8B50C004A +:10E8600015001E0010F01FF9002812D0194B0022CD +:10E870001F001A7032002900200012F030F8002822 +:10E8800003D00A2013F014FEF4E73B78002BFCD0F1 +:10E890001EE00121104A114B944699508021C90075 +:10E8A0005A58002AFCD080270022FF008021C9008E +:10E8B000964207DD910068586050D9590029FCD074 +:10E8C0000132F3E7002260461A505A58002AFCD061 +:10E8D000F8BDC046432800200405000000E00140C8 +:10E8E000F0B589B00E9D06000F000592002D05D1F0 +:10E8F000802252055569314AAD18AD02AC05A40D10 +:10E9000057D1BA0A92020192BA05920D0292D21818 +:10E91000049205993A00300011F0E5FF00280AD171 +:10E92000FF2403223900049BA400043393432140B5 +:10E930000393019D14E0002D3BD029003000FFF728 +:10E9400053FF8023019A5B0029003000FFF786FF08 +:10E9500001993000FFF748FF80232100DB0003937B +:10E9600000230793039B8B4225DD0322029B0A4071 +:10E97000D200994207DB049B994204DA059B029876 +:10E980001B1A5B5C00E06B5C93400327079A4C1CEE +:10E9900013430793274001D02100E3E7019B89102F +:10E9A0008900591807AA01233000FFF757FF07977E +:10E9B000F2E7034800E0002009B0F0BDEDFF3F00A2 +:10E9C00017FCFFFF08B4024B9C46443808BC604764 +:10E9D00003090300F8B5FA230189DB000400594359 +:10E9E000324812F08AFAFA21890006F0A1FA304F73 +:10E9F0002081A17A380012F080FA23002600250039 +:10EA000022894C33A072A0361A808C3531780023CD +:10EA10002A22286811F021FA002801D0254844E074 +:10EA200031781F235B22286811F017FA0028F5D1EE +:10EA3000317820235C22286811F00FFA0028EDD1EC +:10EA4000317801232C22286811F007FA0028E5D13B +:10EA5000317801232D22286811F0FFF90028DDD13B +:10EA6000317801232E22286811F0F7F90028D5D13A +:10EA7000A17A380012F03CFA3178C3B20E2228682D +:10EA800011F0EBF90028C9D1FA2321899B005943E1 +:10EA9000064812F02DFA01231843C3B231782A2216 +:10EAA000286811F0DAF90028B8D1F8BD583303000E +:10EAB000D83203000EFCFFFF08B4024B9C464438DA +:10EAC00008BC6047D5E90100074B10B51A000400E7 +:10EAD00008323C3302604364443010F0BCFC200038 +:10EAE00010F0C9FB200010BDF832030008B4024B3F +:10EAF0009C46443808BC6047C9EA010008B4024B90 +:10EB00009C46443808BC60470D090300F0B5042555 +:10EB100083798BB004002B4204D1FCF7E7F9A37989 +:10EB20002B43A37120009030FEF7C2FC061E66D175 +:10EB30002300A033197820000C2307AD00938C30FC +:10EB40002B0001220068FEF70BF9002801D02E4EA1 +:10EB500056E00A2304AA9B182A785A706A781A7019 +:10EB60000022995EAA785A70EA781A7000201A5E1C +:10EB70000392287958706879187000201F5EA87970 +:10EB80005870E87918700022985E0490287A5870BE +:10EB9000687A18700022985E0590A87A5870E87A12 +:10EBA00018701F2000229B5E039A9C46A37A524253 +:10EBB0005A435943D5177B430540AA185211A26105 +:10EBC000DF17CA1702403840C3185B112362642361 +:10EBD0005118059A5B4253434911A3676423E161CD +:10EBE0006146049A20005A434B43E267221DD367D3 +:10EBF00010F0B2FB2000443010F034FC00E000269E +:10EC000030000BB0F0BDC0460EFCFFFF08B4024B55 +:10EC10009C46443808BC60470DEB0100F7B51E0068 +:10EC2000040008AB1B881500019309AB00911A88FA +:10EC300031000AAB1F88FCF755FE20003A00310076 +:10EC40004430FDF74DF9134B20001A003C33636448 +:10EC5000230008322260009A8C331A60AB8890300F +:10EC60008380AB796A4683710B4B92880360AB68F3 +:10EC7000032183602B7B03736B7B4373AB7B8373B9 +:10EC80002300A0331A80FEF715FD2000FFF7A2FE37 +:10EC90002000FEBDF832030044310300F8B5FA2627 +:10ECA0000189B60004007143264812F026F93100AC +:10ECB00006F03EF9244F2081A17A380012F01DF9A8 +:10ECC0002500A0725835297800232A22606C11F0A3 +:10ECD000C4F8002801D01D4832E0297810232B22E7 +:10ECE000606C11F0BAF80028F5D1297801232D22A3 +:10ECF000606C11F0B2F80028EDD1297801232E22A2 +:10ED0000606C11F0AAF80028E5D1A17A380012F061 +:10ED1000EFF82978C3B20E22606C11F09EF800283B +:10ED2000D9D121890748714312F0E2F80123184331 +:10ED3000C3B229782A22606C11F08FF80028CAD15A +:10ED4000F8BDC046F4330300A03303000EFCFFFF00 +:10ED500010B50400034B0833036010F08CFA200058 +:10ED600010BDC046C03303007FB50425837904007D +:10ED70002B4204D1FCF7BAF8A3792B43A3712000EE +:10ED80004830FEF795FB051E24D12300583319782F +:10ED9000062302AE009301223300606CFDF7E0FF12 +:10EDA000002801D00D4D16E0042302200022A17A94 +:10EDB000F3563056B2564B43C0004A43404241439B +:10EDC000DB0023622368D200A161E2619B6A20001C +:10EDD000984700E00025280004B070BD0EFCFFFF3E +:10EDE000F8B50400150006AA168807AA0F001288B5 +:10EDF0001900FCF777FD0F4B67640833236023008D +:10EE0000AA8848339A80AA7920009A710A4AA26493 +:10EE1000AA6822652A7B1A736A7B5A73AA7B9A7343 +:10EE20000023A371230058331E80FFF737FF200013 +:10EE3000F8BDC046C03303004431030010B50400E0 +:10EE4000034B0833036010F006FB200010BDC046E2 +:10EE5000FC33030070B50825837986B004002B428B +:10EE600004D1FCF743F8A3792B43A37120004C3065 +:10EE7000FEF71EFB002830D023005C3319780623F0 +:10EE800004AE009301223300A06CFDF769FF051E5C +:10EE900001D0134821E00E2332786B445A70727807 +:10EEA00020001A700022995E64224A43A263B2785D +:10EEB0005A70F2781A700022995E642252425143CD +:10EEC0006163317959707179197000215B5E5A4321 +:10EED0002368E2631B6A9847280006B070BDC046ED +:10EEE0000EFCFFFFF0B507005C3787B004003978EF +:10EEF00000231022806C10F0B0FF0326002807D0FA +:10EF00001F483AE02B78334211D06420FCF78AF88E +:10EF10000F2502ABED180123397808220093A06C6D +:10EF20002B00FDF71DFF164B9842EBD1E8E7FA25C1 +:10EF30002189144EAD006943300011F0DEFF290035 +:10EF400005F0F6FF20813978A0231122A06C10F083 +:10EF500084FF0028D4D1A36C218903936943300036 +:10EF60003F7811F0C5FF01231843C3B210223900C6 +:10EF7000039810F072FF0028C2D107B0F0BDC04660 +:10EF80000EFCFFFF80340300F8B50400150006AA4C +:10EF9000168807AA0F0012881900FCF7A1FF0D4B75 +:10EFA000A764083323602300AA884C339A80AA7987 +:10EFB00020009A71084AE264AA6862652A7B1A7383 +:10EFC0006A7B5A73AA7B1E829A73FFF78BFF20001D +:10EFD000F8BDC046FC33030044310300F7B5FA2501 +:10EFE0000189204FAD0004006943380011F085FF0E +:10EFF000290005F09DFFA17A20811B4811F07DFFBB +:10F000002600636CA07200932189583633786943D7 +:10F010003800019311F06CFF07231843C3B220227C +:10F020000199009810F019FF002801D00F4818E04E +:10F03000317810232222606C10F00FFF0028F5D1E8 +:10F04000A17A0948656C377811F052FF80235B4242 +:10F050001843C3B223223900280010F0FEFE002816 +:10F06000E4D1FEBD2C350300043503000EFCFFFF88 +:10F0700010B50400034B0833036010F0FCF82000C7 +:10F0800010BDC04688340300F0B50425837985B0EF +:10F0900004002B4204D1FBF729FFA3792B43A37172 +:10F0A00020004830FEF704FA002838D023005833F7 +:10F0B0001978062302AE0093A8223300606CFDF796 +:10F0C0004FFE051E01D0174829E01F210023F25EE4 +:10F0D000D3170B409A18521193B20222B75E3380B5 +:10F0E000FA170A40D7197F11BAB20427F05F1BB292 +:10F0F000C71739400818401181B2A07A5B424343D8 +:10F10000728012B2B180524209B242434843E36175 +:10F1100023682062A2619B6A20009847280005B0FE +:10F12000F0BDC0460EFCFFFFF8B50400150006AAAE +:10F13000168807AA0F0012881900FCF7D3FB0F4BA3 +:10F140006764083323602300AA8848339A80AA7929 +:10F1500020009A710A4AA264AA6822652A7B1A735F +:10F160006A7B5A73AA7B9A730023A37123005833D6 +:10F170001E80FFF733FF2000F8BDC046883403002F +:10F1800044310300F7B5FA2504000189134EAD00A0 +:10F190006943300011F0B1FE290005F0C9FE2700D7 +:10F1A000A36C208100935C373B7881B269433000C7 +:10F1B000019311F09DFE6022C3B20199009810F0F6 +:10F1C0004CFE002801D0064807E03978012362226E +:10F1D000A06C10F042FE0028F5D1FEBD8035030082 +:10F1E0000EFCFFFF10B50400034B0833036010F062 +:10F1F00032F9200010BDC046343503007FB5082524 +:10F20000837904002B4204D1FBF770FEA3792B43D2 +:10F21000A37120004C30FEF74BF9002822D02300C8 +:10F220005C331978062302AE0093E8223300A06C09 +:10F23000FDF796FD051E01D00B4813E00223F25E98 +:10F2400096235B425A4362630021725E200053435F +:10F25000A3630423F25E96235343E36323681B6A8C +:10F260009847280004B070BD0EFCFFFFF8B50400FD +:10F27000150006AA168807AA0F0012881900FCF7C5 +:10F280002FFE0D4BA764083323602300AA884C335C +:10F290009A80AA7920009A71084AE264AA68626595 +:10F2A0002A7B1A736A7B5A73AA7B1E829A73FFF7B2 +:10F2B00069FF2000F8BDC046343503004431030027 +:10F2C00010B50400054B083303601C300FF052FDED +:10F2D000200018300FF04EFD200010BD88350300CF +:10F2E000FF23F0B52B4C8DB0237000230500694639 +:10F2F0000088009303F028FC002802D16B469B781D +:10F300002370254E3368DB68002B06D10023288844 +:10F310001A00190011F06AFB3AE02378032BF5D8A4 +:10F320001E4901A8FCF7CCF8336801A9DE6804A8DF +:10F330000FF075FD04A9300011F08FFA060004A843 +:10F340000FF018FD371E1ED031002022103104A806 +:10F3500013F000FA300013F0D8F9217804ABC9009B +:10F360005918082202A813F0F5F928880123082269 +:10F3700002A911F03BFB0127002804D12888084A84 +:10F380000C2111F031FB01A80FF0F4FC002FBDD0CF +:10F390000DB0F0BD9020002050250020B7410300A3 +:10F3A000FFFF0000F0B5837991B004005B071BD527 +:10F3B000FCF742F800232269801A9941994203D14F +:10F3C000F423FF3398420FD9A068002808D0364BA9 +:10F3D0001D8801F04FFC036815221B6A290098471D +:10F3E0000422A3799343A371A3799B075AD52F4D88 +:10F3F0002B68DB68002B51D02D4B1A780193032A20 +:10F400004CD8294B2B491B8804A80093FCF758F8CB +:10F410002B6804A9DE6808A80FF001FD08A93000D8 +:10F4200011F01BFA070008A80FF0A4FC02AB9E1D08 +:10F4300008233200338006A9073B009811F0D8FA60 +:10F44000002F08D039002022103108A813F082F9CB +:10F45000380013F05AF9019B32881B7806A9DE00A8 +:10F4600008AB9E19300013F066F9002813D008226B +:10F4700006A9300013F06EF92B6804A9DD6805A811 +:10F480000FF0CDFC202308AA05A9280011F0EBF904 +:10F4900005A80FF06FFC04A80FF06CFC0222A37902 +:10F4A0009343A37111B0F0BDE82700205025002040 +:10F4B00090200020B7410300F7B504000025019219 +:10F4C000C77FAF4254D966197078884202D1152996 +:10F4D00027D804E0605D2D180135EDB2F1E7012277 +:10F4E0008A40264802421CD0D91901201F2943DC3A +:10F4F000E1193718B94210D80021C8B2834205D9A2 +:10F50000019A7018575C01318770F6E7625D9A18AE +:10F510006255E27F9B18E37728E00878C8540139E8 +:10F52000E8E7655D013DEDB2AB4209D10021C8B20B +:10F5300083421BD9019A7018545C01318470F6E73C +:10F54000FF187F1B01201F2F16DC0227A81C7F42FB +:10F5500036187F1BE07F2218964203D23078F05590 +:10F560000136F7E7451B023DE57701E0002003E0A7 +:10F57000019A200011F086FAFEBDC046FC00200072 +:10F58000F0B585B001930AAB1E880BAB1B78451C08 +:10F5900002930EAB1B78040003930B7817000370E3 +:10F5A0004B8A102243820131280013F0D3F86B46B6 +:10F5B0009B88268363836B461B7B002623776B46E1 +:10F5C00001221B7A6761E683EB77A31CDA770C9B39 +:10F5D0000C256362230020000D9A28331A705E7098 +:10F5E0009E702A0031002C3013F0D2F82000074B17 +:10F5F000E663A3632A003100403013F0C9F820000D +:10F60000034B2665E36405B0F0BDC046070A03005E +:10F61000F909030070B50D0001F02CFB040003682C +:10F62000002D02D15B69984708E09B6898478542A6 +:10F6300004D2236820009B6898470500FA208000C8 +:10F640006843024905F074FCE08070BD710200005F +:10F65000F0B507001600A1B002C704006B4918A856 +:10F660001D0011F041FA331E03D0300013F0D0F822 +:10F6700083B201220492002203920292023201928A +:10F680000093320018A93800FFF77AFF2300604981 +:10F69000583318A8079311F027FA2B1E03D028001F +:10F6A00013F0B6F883B20122049200220392029270 +:10F6B0000232019200932A0018A90798FFF760FF11 +:10F6C00023005449AC3318A8089311F00DFA269B77 +:10F6D000002B03D0180013F09BF883B20122049290 +:10F6E000002203920292023201920093269A18A9F4 +:10F6F0000898FFF745FF631CFF33474918A8099393 +:10F7000011F0F2F9279B002B03D0180013F080F8BA +:10F7100083B2012204920022601C03920292023200 +:10F7200001920093279A18A9FF30FFF729FF2300C1 +:10F730005533FF33394918A8099311F0D5F9289B9F +:10F74000002B03D0180013F063F883B20122049257 +:10F75000002203920292023201920093289A18A981 +:10F760000998FFF70DFF2300A933FF332C4918A890 +:10F770000A9311F0B9F9299B002B03D0180013F05C +:10F7800047F883B201220492002218AD039202923C +:10F79000023201920093299A29000A98FFF7F0FE9D +:10F7A000204B1B780B93002B2DD1079B12971393A3 +:10F7B000089B0DAF1493631CFF331593099B1A49E3 +:10F7C00016930A9B3800179311F08EF91D214920DA +:10F7D0003B7810222B707B8A12AE6B8206ABC91865 +:10F7E000C01812F0B7FF06232B756B469B8D20685F +:10F7F000AB83AE6101F04EFA036829001B6898479D +:10F800000122084B1A70200021B0F0BD292A000007 +:10F81000242A0000252A0000272A0000262A0000AA +:10F82000282A0000452800200A18000070B500258D +:10F8300004000B4B8580083385710360C16018306C +:10F84000FBF778FE20001C30FBF774FE0123621CDE +:10F85000D377044AA560656120001460A37170BD70 +:10F860008835030050250020FA2130B585B0050009 +:10F8700001230222890068460FF016FB074C20681E +:10F88000002809D011F07AF92988054B22681980DF +:10F89000022193790B43937105B030BD50250020B0 +:10F8A000E827002010B50C1E072C0BD8806801F04B +:10F8B000E1F9054B195703685B6C9847002802D0A3 +:10F8C000024800E0024810BDB342030016FCFFFFEF +:10F8D00017FCFFFFF0B5A54C0D00A54404000493F0 +:10F8E0009AAB1B78A24909A805930792FBF7E8FD9C +:10F8F000200029001C300FF09AFAC020800001F08F +:10F900009BFD082012F0EFFE0700002101F07AF9BC +:10F9100015AD0021A7600C220EA812F039FF2B00B4 +:10F920000EAA43CA43C3934B2900EB60002338005F +:10F930002B6111F04CFBA06801F09CF90C22002116 +:10F940000690280012F024FF142012F0CCFE8A4BFF +:10F950002A0015930300C2CAC2C3884B069EC36027 +:10F960000023A43603613368002B00D003613060AC +:10F97000A06801F08FF90C2200210600280012F087 +:10F9800007FF142012F0AFFE7D4B1593030086CDC8 +:10F9900086C37C4BC36000230361336B002B00D014 +:10F9A00003613063A06801F065F915AD0C220021F8 +:10F9B0000600280012F0ECFE142012F094FE724BA8 +:10F9C00098361593030086CD86C3704BC360002321 +:10F9D00003613368002B00D003613060012004AB69 +:10F9E0001B7C04AA034308A9137411F003F8A06850 +:10F9F00001F060F9036866495B6A9847A06801F006 +:10FA000059F9036863499B699847A06801F052F966 +:10FA10000022036800921D6805990323A847059BEF +:10FA2000002B0AD0200011F0B2F8032805DDA068F1 +:10FA300001F040F90368DB6898470EA811F019F847 +:10FA40002F2004ABC01811F014F8362004ABC018F6 +:10FA500011F00FF83D20042504ABC01811F009F88F +:10FA60000EAB0A93A06804AB5D7701F023F903683D +:10FA70000AA91B699847A06801F0FCF803680AA965 +:10FA80005B6D9847A06801F0F5F803680021DB6D15 +:10FA90009847A06801F0EEF8036802219B6D984733 +:10FAA00006212000FFF7FEFE182012F01CFEA168C0 +:10FAB00000F062FA542012F016FE049AA16800F0D9 +:10FAC00053FD354B354A1B68A1680393344B15A889 +:10FAD0001B680CAE0293334B00271B680193079BF6 +:10FAE0001B685B190093304B12681B68FFF7B0FD71 +:10FAF000302012F0F8FD049AA16800F0FBFAA0682B +:10FB000001F0B8F8036831009B6A98470823A068A1 +:10FB10003380DB187380B78001F0ACF803683100E4 +:10FB2000DB6A98472900A06810F0EAFF099A0921CA +:10FB30009378A068521910F0F6FFA06801F09AF8C7 +:10FB400032210771A068FFF765FD04AB1B7FBB4244 +:10FB500004D0A06801F08EF810F0BCFF09A80FF0E7 +:10FB600009F995239B009D44F0BDC046ACFDFFFF05 +:10FB7000C3410300150A030069F80100230A0300CA +:10FB8000E1F20100310A03005F0A03003F0A0300AB +:10FB9000ADFB0100E1FB01005825002054250020A9 +:10FBA000102000205C2500200C20002013B5062228 +:10FBB0006846FBF795FC094B1C68002C0AD0694687 +:10FBC00001A80FF02CF9200001A911F001F801A8FB +:10FBD0000FF0D0F868460FF0CDF813BD5025002087 +:10FBE000002373B501AE0C0031000500019302F053 +:10FBF000ABFF002802D1B278064B1A70064B18688A +:10FC0000002806D061426141044BC9B21D8010F04A +:10FC1000E7FF73BD9020002050250020E82700203A +:10FC200030B5284CA9B06A220D000DA8210012F0B1 +:10FC300091FD0DA903A8FBF7B1FC03A906A80FF0DD +:10FC400063F901230193013BFF3B00930533FF332D +:10FC5000642206A92800FDF72BF806A80FF047F943 +:10FC6000210019226A3106A812F074FD0522002431 +:10FC7000110006AB04A80FF06EF904A905A80FF057 +:10FC800043F9019400942300220005A92800FCF701 +:10FC900053FF05A80FF02BF921002800FDF736F8D7 +:10FCA00005340520FBF7BEF9FF2CF5D1FA208000C2 +:10FCB000FBF7B8F904A80FF01AF903A80FF017F929 +:10FCC00029B030BD34410300F0B5954B95B0059295 +:10FCD0001A68082304000291D16C06A80B43D36470 +:10FCE0009049FBF7EDFB904907A8FBF7E9FB2200E1 +:10FCF00000250DAE30001C3206A90FF0A7F807AAA8 +:10FD0000310008A80FF0A2F830000FF033F8631CA0 +:10FD1000DD77A06800F0AEFF03680BAF5B69984722 +:10FD2000300010F0A6FE2B2004ABC01810F0A1FE8E +:10FD3000322004ABC01810F09CFE392004ABC01870 +:10FD400010F097FE0B960426A0687E713D7100F0BE +:10FD500091FF036839005B6D9847A06800F08AFF47 +:10FD6000036829009B6D9847A06810F0F6FE0621F5 +:10FD7000A06810F0C5FE089A09219378A06892192E +:10FD800010F0D1FEA06800F075FFC8210571A068D1 +:10FD9000FFF740FCA06800F06DFFFF270581A06819 +:10FDA00000F068FF10F096FE0298FCF70DFE2000B0 +:10FDB000FBF79CF802992000FFF732FF0299200020 +:10FDC00010F021FF039504966369DB0735D5574989 +:10FDD00009A8FBF77DFC09A90AA80FF095F80022F5 +:10FDE0000AA91300019200920298FCF7A5FE0AA846 +:10FDF0000FF07DF8039B002B01D1043F00E0043796 +:10FE0000282F03DD0023FE2F06DC06E002980FF00A +:10FE1000F7FF0123002F00DC039305980FF007FB89 +:10FE2000002806D0012362699A431300049A134301 +:10FE3000636109A80FF05BF800256369049A134217 +:10FE40002AD0FF210298FCF761FF0025A369022256 +:10FE50009B5E9D421BDA200029B218300FF00CF88F +:10FE60000023010002981A007430FBF783FCC820BD +:10FE70008000FBF7D7F802980FF0C2FFC820FBF70D +:10FE8000D1F802226369134201D10135DEE7FA207D +:10FE90008000FBF7C7F8002502226369134233D0C4 +:10FEA00008261E401AD0224909A8FBF711FC09A90F +:10FEB0000AA80FF029F800220AA901920092130063 +:10FEC0000298FCF739FE0AA80FF011F81948FBF761 +:10FED000A9F809A80FF00BF8174D15E0174909A864 +:10FEE000FBF7F6FB09A90AA80FF00EF83300320061 +:10FEF0000AA9019600960298FCF71EFE0AA80EF0C9 +:10FF0000F6FF09A80EF0F3FF6420FBF78BF80C4B0B +:10FF100001359D4200DC57E70EF0D7FD54E7C0469F +:10FF2000B0240020D1410300E1410300E34103007C +:10FF300028420300983A00008C0A00006542030042 +:10FF40008B0A000073B50B4E05003100C06810F03D +:10FF500057FC041E0AD16B46DA1D107004233100D1 +:10FF6000E868FEF761FA200012F0CFFB0EF0ADFD5D +:10FF700073BDC0464B3E0300F0B505000024574B4F +:10FF8000A9B0083303600391A96021000BAB1A19D3 +:10FF900001345170102CFAD1012251481A701A1BE9 +:10FFA000013C015D5174002CF9D19A7B597B1202FE +:10FFB0000A43290045270C31029125211B7813AEF5 +:10FFC000337002ABFF18C91872823800102212F089 +:10FFD000C1FB029B02AA7361012333833377093388 +:10FFE000FB771DAB1C706D239B181C706E232100CA +:10FFF0009B1874830C22F4831EA81C70746212F088 +:020000040002F8 +:10000000C7FB384B0C22B3632100F46323A812F022 +:10001000BFFB354B0222F364462302A95B18DA7753 +:10002000220034652C73059606AF3B1901345A70D3 +:10003000102CFAD101232D493B703B1B013C0A5D7A +:100040005A74002CF9D111212520BB7B7A7B1B022D +:100050000BAE13433A78738202ABC9183270C018E2 +:10006000102212F077FB01230398337505ABB361BF +:10007000B48300F00FFE036831001B68984713AB90 +:10008000DB8BA868AB8200F005FE03680094A98AA8 +:10009000029ADE680123B047A86800F0FBFD0290D9 +:1000A000142012F020FB06000C22210012F070FB3D +:1000B000300001233461082220C0390007930694E0 +:1000C00012F048FB0A4BF360029B9B69002B00D0A7 +:1000D00033612800029B9E6129B0F0BDA03503006A +:1000E000CB420300070A0300F9090300BB420300E7 +:1000F0006F0C0300F0B500260400764BDDB008332A +:1001000003608160C260868086713200724947A8B0 +:1001100010F04DFE230014330893122301250193A0 +:100120000E3B04950093089A330047A90396029664 +:100130001DA8FFF725FA3200684947A810F037FEDE +:100140000C2322000193083B15AF10320495009355 +:1001500047A933000396029632A8FFF711FA32003E +:100160005F49380010F023FE23001C330993082355 +:100170000193043B390004950093099A33000396D8 +:10018000029647A8FFF7FCF932005649380010F0F4 +:100190000EFE542012F0A7FA2300183307931223FF +:1001A00001930E3B390004950093079A33000396A0 +:1001B00002960690FFF7E4F9069B0822A3624A4BD9 +:1001C0000AA90A93069B0B961800DC62303012F0E5 +:1001D000C1FA069A454B268293631300668229333F +:1001E0001D7023690422E3610999079812F0B2FA9D +:1001F00004220799089812F0ADFA6622022304A996 +:100200005218D377BA225218D37787225200521845 +:10021000D377069A3649D218D3771DAB0C9332ABFD +:100220000D9347AB0E93069B3200A68510A80F9343 +:1002300010F0BDFD30223121452004AB9B181B7806 +:1002400012323B7004AB9B181B88323A7B8204ABA2 +:10025000C918C01812F07EFA04230CADA0683B75D3 +:10026000BD61BE8300F016FD036839001B68984726 +:10027000822204AB9B181B885432238404AB9B1846 +:100280001B885432A38404AB9B181B88A06863842A +:1002900000F000FD0700142012F025FA05000C22E2 +:1002A000310012F075FA2800124B2E61082210C09E +:1002B00010A91093119612F04DFA0F4BEB60BB6929 +:1002C000B34200D02B61BD612000FAF70FFE200081 +:1002D0005DB0F0BDAC350300EB4203001B430300EF +:1002E0000B430300DB420300810D0300ED0C030010 +:1002F000FB42030065030200170D0300F0B5040084 +:100300000E00150085B000930CAB1B8810300193D4 +:100310000EF0BFFD26806580182012F0E4F907007A +:1003200002AE33003D000AAA03CA03C3009B102299 +:1003300008C50021280012F02BFA310008222800FD +:1003400012F008FA064B02227B612000002301997B +:10035000A7600A43E360A2802362636205B0F0BD38 +:10036000410D0300F0B50B898DB00593CB680500F6 +:1003700004934B88828C9A420ED1049C059B049A6C +:100380001B1BD318032B39DD62882188012308A8A1 +:100390000EF08AFD0434F1E7428C9A422ED1049C7F +:1003A000059B049A1B1BD318032B27DD23882820C9 +:1003B00006936388EF680793114B08930023099312 +:1003C00012F091F9C0236A460600029308AB03CBF2 +:1003D00003C22B000699079A3000FFF78FFF3B6896 +:1003E00031005B6838009847002805D030000EF0D7 +:1003F00077FC300012F089F90434D1E70DB0F0BD7C +:10040000010E030070B5040090B0806810F0F3FC9A +:100410000223010019401AD1A38D002B17D00D4BD8 +:100420006A4604931023E568A1850591029304AB05 +:1004300041CB41C20A00230006A8FFF75FFF2B68EB +:1004400006A99B682800984706A80EF049FC10B042 +:1004500070BDC046010E030082B0F0B587B0040045 +:1004600003A80D930C92FEF7ADF90CAB5D88022D3D +:1004700034D0FF2D62D0012D64D104A810F0BAF958 +:10048000334904A810F0BCF905AE071E06D12B00B5 +:1004900032002F4904A83570FDF7C6FF380012F06E +:1004A00034F9256DAB0503D1290003A8FEF79CF9AB +:1004B00022001023290003A80C32FEF7CFF90222F4 +:1004C0002449300012F046F9206800F0E3FB03688D +:1004D000218932005C690223A04733E02200256DA8 +:1004E000102329000C3203A8FEF7B8F980235B0122 +:1004F000EC1880256D056B69174A9B189B029C427E +:1005000012D2164B22689A420CD1154B62689A425D +:1005100008D1002305AA13702100009303A801331A +:10052000FEF7DEF90834E6E705A810F063F908499C +:1005300005A8FEF74FF80EF0C8FA03E0094B18685B +:10054000FFF700FD07B0F0BC08BC02B01847C0467A +:10055000563E03002B430300EDFF3F00EF40110424 +:10056000BBA22FB850250020F0B5002504000300E1 +:10057000216042602A00A9B04C338572C5721D709B +:1005800002AB00910565DD700BAF7B1901355A7028 +:10059000102DFAD1012365493B707B1B013D4A5D5B +:1005A0005A74002DF9D12521BB7B7A7B1B0213AE37 +:1005B0001343738202ABC91845233A7802A81B186B +:1005C00032701800102212F0C5F8012202AB03337A +:1005D0006421736114237283327702AA5218137054 +:1005E00033831DAB1D706D2302AA9B181D706E23F3 +:1005F00029009B18F5830C221EA81D70756212F04D +:10060000C7F84B4B0C22B3632900F56323A812F003 +:10061000BFF8484B02A9F364462302225B18290065 +:10062000DA773565039606AB5A1901355170102DEE +:10063000FAD1012240481A705A1B013D415D5174A4 +:10064000002DF9D19A7B597B12020A4325201121F2 +:100650001B787A823B7002AB1022C918C01812F0C6 +:1006600079F8012300983B7503ABBB61BD8300F0B3 +:1006700011FB036839001B689847F38B20682381BE +:1006800000F008FB0700142012F02DF806000C22E1 +:10069000290012F07DF83000284B3561082210C087 +:1006A00004A90493059512F055F8254BF360BB6936 +:1006B000002B00D03361BE6163682820019312F0E3 +:1006C00012F8050010300EF0E4FB002624236E80A3 +:1006D0002B80182012F007F807001A4B10C7009063 +:1006E0001022310038000693079612F051F80822C4 +:1006F00006A9380012F02EF8134B009AEE605361F1 +:100700001223AB80019BAA601B682E626E625B683D +:10071000290001989847B04205D028000EF0E0FA71 +:10072000280011F0F2FF200029B0F0BD2F43030094 +:10073000070A0300F90903003F43030015080200FC +:100740003B0E030059040200650E03007FB5CB7811 +:10075000827A04000D00934226D006D2D31A0721D4 +:100760000022DD0F9942554104E09B1A0125F82B28 +:1007700000DC0025EDB2002D49D102222449684653 +:10078000891811F0E7FF206800F084FA03682189D6 +:100790005E696A460223B047E37A0433DBB2E37250 +:1007A000A3724C34257032E00600013383722300BB +:1007B0004C3630780C33000118180431102211F037 +:1007C000C9FF3378012B16D0002B0DD0032B1CD181 +:1007D000012324211A0068460EF066FB00233370C3 +:1007E000E37A0433E37212E06B78AA781B021343B6 +:1007F000236501230AE06B781A06AB781B041343C8 +:10080000226D13432365022300E0013333707FBD63 +:100810002B430300F0B54A88038997B007009A423A +:1008200000D08DE00B89002B00D189E0CD682C78B9 +:10083000022C00D17EE008D8002C0BD0012C00D077 +:100840007EE02900FFF782FF7AE0EE2C52D0FF2CE9 +:1008500068D075E006A800F089F9142101AE347063 +:100860006B7806AA73706B780E204B43D3189B6885 +:1008700068441B0EB3706B784B43D3189B681B0CFA +:10088000F3706B784B43D3189B681B0A33716B78FA +:100890004B43D3189B6873716B784B43D318DB6859 +:1008A0001B0EB3716B784B43D318DB681B0CF371D1 +:1008B0006B784B43D318DB681B0A33726B784B435E +:1008C000D318DB6873726B785943511810310822C2 +:1008D00011F040FF386800F0DDF9036839895D697F +:1008E00032001223A8473B004C33BC72FC721C70D0 +:1008F0003C6525E006AD03220021280011F048FFE9 +:1009000001236B700F4B2C70186810F0ADF9A870B4 +:10091000386800F0BFF9036839895C692A0003234D +:10092000A0470DE06B78002B04D0012B08D10EF00E +:10093000CCF805E001232200242106A80EF0B4FA29 +:1009400017B0F0BD50250020002815D00060416090 +:100950008260C360046145618661C7614446046288 +:100960004C464462544684625C46C46264460463F6 +:100970006E46466374468463002A06D0C46B043C0A +:10098000043A25681560B442F9D18C6BA6464E6BCB +:10099000B546002B06D0CC6B043C043B1D6825609B +:1009A000B442F9D10C6BA446CC6AA3468C6AA24629 +:1009B0004C6AA1460C6AA046CF698E694D690C69E4 +:1009C000CB688A6808684968704700604160826047 +:1009D000C360046145618661C761444604624C4658 +:1009E0004462544684625C46C462644604636E4654 +:1009F000466374468463C46B043C043925680D6007 +:100A0000B442F9D1C76986694569046970470060D5 +:100A100041608260C360046145618661C76144468C +:100A200004624C464462544684625C46C462644636 +:100A300004636C4644637446846304697047846B42 +:100A4000A646446BA546046BA446C46AA346846AC2 +:100A5000A246446AA146046AA046C76986694569F8 +:100A60000469C36882680068416870470CC8074819 +:100A700010B51B18DB00D3181800934205D31C686F +:100A80008C4202D31800083BF7E710BDFFFFFF1FA1 +:100A900070B50D1C06000021281C04F00FFC041E7C +:100AA00006D13000291C03F0BDFD7560200000E078 +:100AB000004870BD17FCFFFF014B18687047C04627 +:100AC0001420002070B504000D0003F0BFFD616824 +:100AD0002000FFF7DDFF024B00201D6070BDC04607 +:100AE00014200020F8B51B4C0500A3059B0D03D076 +:100AF0008022D200A418E41A80235B05164A5B69A1 +:100B000016499B181648174A174E9B029C421FD243 +:100B10002768974218D167688F4215D1A768874226 +:100B200012D1E768B7420FD1280021000822103106 +:100B3000243011F00FFE280021003830183108222F +:100B400011F008FE2C6303E08027FF00E419DDE7C5 +:100B5000F8BDC046C4450300EDFF3F00C615A841DF +:100B6000C49866C9708E3B9275EE5197F8B5002314 +:100B7000070004000370061D403700253000357063 +:100B80007560B5600C3008222900143611F000FEA3 +:100B9000BE42F2D12278032A09D01423C021534344 +:100BA0004902E31801329D60D96022701D712178DD +:100BB000124B03290AD01422C0204A434002A21833 +:100BC00001319060D3602170012111718022D20027 +:100BD00099189B0522789B0DC91A032A09D0142362 +:100BE0005343E318996006490132D960227002220A +:100BF0001A712000FFF776FF2000F8BDC4450300FE +:100C0000FFBB0300002370B50400016043609942FC +:100C10000AD1064D2B68002B02D110F00AFC286087 +:100C200023689B00EB586360200070BD6C2500209A +:100C300070B500280DD10C4C2668002E07D1083065 +:100C400011F051FD05003100FFF7DCFF2560206841 +:100C500008E00122054906480B68134002D10260F2 +:100C600043600A6070BDC0466025002070250020EA +:100C700064250020436810B50400002B02D104480D +:100C800011F05EFB606803681B69984710BDC046A1 +:100C90004F430300436810B50400002B02D1044801 +:100CA00011F04EFB606803689B69984710BDC04611 +:100CB0004F430300436810B50400002B02D10448E1 +:100CC00011F03EFB606803685B6A984710BDC04640 +:100CD0004F43030000487047FFFF0000F0B597B096 +:100CE0000593036807AD1B680491039311002B0063 +:100CF000060091C991C30024D36821000C220CA8DE +:100D0000EB602C6111F044FD21000B4B10940F930C +:100D100011AB1C701A1901345170102CFAD1002239 +:100D20005A820193059B2A00009304990CAB300072 +:100D3000039CA04717B0F0BD1B110300FC3070B539 +:100D4000046C0500002C0DD1242011F0CCFC064BC6 +:100D500044608361054B8460C46004614461C46184 +:100D600003602864286C70BD983603008037030048 +:100D7000FC3070B5C56B0600002D16D1342011F083 +:100D8000B2FC04003422290011F002FD084BA560DA +:100D90006360084B65612361074B2562E361074B84 +:100DA000E562A362064BF4632360F06B70BDC0463E +:100DB000C8360300B836030028370300383703006D +:100DC000483703007FB503791548002B26D0154D11 +:100DD000154C2B782000002B20D102AE300010F0F3 +:100DE00079F9002814D17388592B11D13378B2883E +:100DF000D91F012902D800920C4A01E000920C4A46 +:100E0000202120000BF09EFF01232B70200005E025 +:100E100020220849200011F002FDF7E704B070BD60 +:100E20007243030046280020472800208C4303001B +:100E3000A9430300CE43030010B50400024B08C0D1 +:100E400010F0DAF9200010BD3837030010B50400A7 +:100E5000024B08C010F0D0F9200010BDD8360300B6 +:100E600010B50400024B08C010F0C6F9200010BDF8 +:100E7000C836030010B50400024B08C010F0BCF9DE +:100E8000200010BDB836030010B50400024B08C0A6 +:100E900010F0B2F9200010BDA836030010B5040010 +:100EA000024B08C010F0A8F9200010BDE83603007E +:100EB00010B50400024B08C010F09EF9200010BDD0 +:100EC0009836030010B50400024B08C010F094F9E6 +:100ED000200010BDEC35030010B50400024B08C023 +:100EE00010F08AF9200010BDDC35030010B50400B5 +:100EF000024B08C010F080F9200010BDCC35030073 +:100F000010B50400024B08C010F076F9200010BDA7 +:100F1000FC35030010B50400024B08C010F06CF95A +:100F2000200010BD28370300FC3070B5046C0500AC +:100F3000002C0DD1242011F0D6FB064B44608361B8 +:100F4000054B8460C46004614461C461036028642B +:100F5000286C70BD9836030080370300104B10B525 +:100F6000083303600F4B0400C36080230E4A5B000C +:100F7000C250C018FBF7FEFB20000C4BB830E360FA +:100F8000FFF7BEFF2000AC30FFF79CFF2000A03031 +:100F9000FFF7A2FF20006C30FFF7A8FF200010BD74 +:100FA000AC370300F43703002C3903000C36030080 +:100FB000F0B50500040087B0AC356B68AB60AE6877 +:100FC000002E08D0F368210030009847AB68002B52 +:100FD000F3D01B69F2E72000B03010F00DF92200C9 +:100FE000FC235832117820000B40137023005C332F +:100FF0001E700A3010F014FA2000343010F010FA8D +:101000002000643010F0F8F82000983010F0F4F868 +:10101000200001ADA43010F0EFF831000C222800C0 +:1010200011F0B6FB23002A006C3383CA83C3094B3B +:10103000E667A3670C223100280011F0A9FB23000A +:10104000803307CD07C33000034A90341A6026600E +:1010500007B0F0BDFF100300F1100300454AF0B5E2 +:101060000600C260A022444B16360833036001001C +:10107000002342820400320085B003718360037450 +:10108000838235311370013200259142FAD18027D5 +:1010900080222000D201BF001100F57737842B0099 +:1010A0000095383000F020FF2300210040330393E7 +:1010B0001A002B005F311370013200258A42FAD1E9 +:1010C000039B2200DD77230060331F80FC23643202 +:1010D000117820000B401370230068331D70274BDC +:1010E0002900E36625670C22783011F051FB2300BC +:1010F000270088331D60224B0837FB67843729009F +:101100000C22380011F044FB1E4B1F4AFB602300E9 +:10111000A0333D611A601D4A5D60DA601C4A1D61A2 +:101120009A61DD61300010F07BF9039810F078F9D6 +:10113000184B601CE3602300C4331D705D709D700C +:10114000FF3002F0E7FC8C235B00E55023001933ED +:10115000FF335D618023104A5B00E25023000122CF +:101160002000FE3352425A86023B9D63DD631D64BC +:1011700005B0F0BD0C360300AC370300CC350300DE +:10118000FF100300F1100300DC350300EC35030011 +:10119000FC350300F43703002C39030070B5074C0D +:1011A0002368002B07D1A020400011F09CFA050015 +:1011B000FFF754FF2560206870BDC04674250020ED +:1011C00070B50C220D000021040011F0E1FA00239B +:1011D0002361024B25602000E36070BD0D11030008 +:1011E00070B500250400264B05710360254B457141 +:1011F0008360254BC5604361244B85610362244BAA +:101200004562C362234B05638363C5632900443091 +:10121000FFF7D6FF200029005830FFF7D1FF20004C +:1012200029006C30FFF7CCFF1B4B2200236023000A +:10123000F832803320C39342FCD126001D00E936EA +:10124000FF36280008220021083511F0A1FAAE422D +:10125000F7D18E22330000209200A11801C3002292 +:101260009942FBD18E239B00E2540C490C4B611830 +:10127000E3181A8002339942FBD1200070BDC046AA +:10128000F8360300A8360300B8360300C83603005A +:10129000D8360300E83603008038030062020000FD +:1012A0003A02000010B5040002F01CF8034B1B6862 +:1012B000002B01D02000984710BDC04678250020A3 +:1012C000F0B58DB0050001F07FFA0020FFF766FF52 +:1012D000036807001B6998473B6804009B69380056 +:1012E00098473B6806005B6A3800984703002888E7 +:1012F00010380B2800D997E003F010FE063D9696B3 +:10130000965A969696619673AF882000390010F031 +:10131000A9FA22006B7B583201931378A87919003F +:101320000223194306AB11701F80012306AA937094 +:10133000D07013006A461279E91D9A722B000622BA +:10134000163307A80B9311F005FA29000B2006AB02 +:1013500006220E31C01811F0FDF994346368A360C1 +:10136000A068002860D0C36806A99847A368002B2E +:10137000F4D01B69F3E720002E49AF8810F072FA11 +:101380002200022058321378A9798343137006ABE8 +:101390001F809970A0346368A360A068002843D0C0 +:1013A000C36806A99847A368002BF4D01B69F3E72C +:1013B0005B69A91D002B37D0A888984734E0636E7D +:1013C000AF79002B30D0A366A06E00282CD0C36864 +:1013D00039009847A36E002B01D1636EF3E71B69B8 +:1013E000F1E70122AB7BE91D1A4001925A07920FE7 +:1013F000DB08029206A806226F7B049311F0AAF97B +:101400006A46127906ABDA716A46127A9F711A72CD +:101410006A46127C20005A722B000F3309938C34D9 +:101420008030236806A998472900300010F00DFB92 +:101430000DB0F0BDFFFF00000723D72802D9024BF3 +:1014400018600023180070477C250020014B1860AD +:101450007047C046782500201FB5A3238022DB00FB +:10146000D205D3580820DB0700D405301E4B482294 +:101470001E4902F0C3F900280AD080B2002807D123 +:10148000BFF34F8F1A4A1B4BDA60BFF34F8FFEE753 +:1014900002AC08220021200011F07AF90123237008 +:1014A000154B20001B68636010F03BF8002801D04A +:1014B000072017E0684610F032F80028F8D1694696 +:1014C00010F02BF80028F3D10C4802F0C7F980B2D5 +:1014D000002807D10A4802F0CBF980B2002801D1D8 +:1014E00000F080FC04B010BD291503008025002009 +:1014F0000400FA0500ED00E07C250020C112020086 +:10150000A512020080B2002807D1BFF34F8F034A13 +:10151000034BDA60BFF34F8FFEE770470400FA0514 +:1015200000ED00E070B500200C00FFF737FE036807 +:101530005B6A98472378142B17D002D8132B05D059 +:101540003FE0152B18D0222B35D03AE064680122F9 +:10155000A37819005D0811402A404568DB065B0F3F +:10156000002D2ED02088A8472BE08368002B28D0A0 +:101570006268917810881CE06468A27813091207E9 +:10158000120F012A02D0022A08D00DE0013BDBB283 +:101590000021022B09D80C4AD15C06E00421012B62 +:1015A00003D00131022B00D00021C368002B08D0EA +:1015B0002088984705E00369002B02D062681088F4 +:1015C0009847002070BDC046D6430300014B1878F1 +:1015D0007047C04668280020F0B51E002F4B87B02A +:1015E000009201931A78002305000C009A4252D110 +:1015F00001F0AAFE002801D00B234CE0002E0ED0F3 +:1016000003A9222003960FF097FF002807D0062396 +:10161000082840D011384342434104333BE00023C3 +:1016200002AA1000137000F093FE011EE4D10126FF +:101630001B4F35403A783440B2432A4363000225B9 +:1016400014000720009AAC4302401C431C23AA400C +:101650009C4314433C7003AC0C22200011F098F81A +:101660000920104B3900039302AB0522C0182571E5 +:1016700011F070F821000C4800F0D6FE002807D0C9 +:101680000723042807D0013B082804D0053302E0D3 +:10169000019B1E700300180007B0F0BD68280020F1 +:1016A00091200020251502006728002010B507486A +:1016B00000F084FF0023984206D00733042803D0AB +:1016C000013B082800D00533180010BD6728002012 +:1016D000002373B501930F4B01AD1B780E00290059 +:1016E0002B7001F031FA041E04D0042305280FD01A +:1016F00007330DE03100280000F0D0FE2300002861 +:1017000006D00723042803D0013B082800D0053366 +:10171000180076BD6728002073B5104C0E00050038 +:1017200005222100684611F015F8012E06D0022E80 +:1017300011D1012223781343B34303E0022223781B +:10174000B34393436946280023700FF0F3FE031E52 +:1017500002D00B2300E00223180076BD9120002068 +:10176000094B10B51A7801000923002A09D007484F +:1017700000F0CCFE0023984203D003330E2800D0A3 +:101780000333180010BDC0466828002067280020D9 +:10179000024B0B60092313607047C046D943030016 +:1017A00010B504000020FFF7F9FC03681B69984797 +:1017B0000300F3331C7086235B00C050030000213C +:1017C000044AFC335A61044A99615A62F43010F0B9 +:1017D000EDFC10BD2717030039170300012110B5D8 +:1017E000044A080001F094FF031E00D00B231800E8 +:1017F00010BDC046A1170200F0B593B001900020C3 +:101800000C00FFF7CBFC03685B6A9847FFF7DEFE2E +:1018100006AB00280DD000221A7105AA06920822F4 +:1018200018001A730AAA9A60FFF79AFF002802D0DC +:1018300052E01871187300231F0023732371019B5A +:10184000BA331B78BB4246D907237B43019AD2188F +:10185000BB321278022A31D1002506AE337BAB426F +:1018600036D907207843AB000293019BAA001818D1 +:10187000089BBB3099580FF061FE00281BD0B3685D +:10188000AA009A58237BA1689B005A50237B0133FE +:101890002373337B5A1E954208D01049B2685B18F7 +:1018A0009B009B5803930399029BD15006AA137B7C +:1018B000013B13730CE00135EDB2CEE701992279BB +:1018C000CB182168BB339200535023790133237125 +:1018D0007B1CDFB2B3E7002013B0F0BDFFFFFF3F7A +:1018E000F0B59DB01F006B4605001A70581C06220B +:1018F000229E02AC10F02EFF002F07D03B882380E1 +:101900007B886380BB88A380FB8806E0322323802A +:10191000DB186380F533A780FF33E3800CAB04A9A9 +:10192000049314AB8B602F000023B9370B710B733A +:101930003B78002B17D101203B78022708A90340F0 +:101940005A000B78BB4304AF4F601343002E10D0F6 +:10195000B2798343024013430B7033880B81738841 +:101960004B81B38811E02800FFF746FF0028E2D042 +:1019700029E02A00323212788343024013430B706D +:10198000AB8D0B81EB8D4B812B8E220068468B81BA +:101990000FF002FE03000020834214D00630082B13 +:1019A00011D005D80130042B0DD0834208D109E0B5 +:1019B0000520112B07D0054A934203D0102B01D0EC +:1019C0000B2000E004201DB0F0BDC0460232000034 +:1019D000F0B50A7804009BB00D000220012A42D025 +:1019E0004B88032A04D1A03B10009BB21F4A03E09E +:1019F0000320203B1E4A9BB2934234D8AA881D4B39 +:101A000003209A422FD80AAB009312AB02936A4686 +:101A10000023260013711373B8363378002B05D0DA +:101A200069462000FFF7E8FE00281CD104AF182209 +:101A30000021380010F0ACFE2B7838003B70337872 +:101A40003B726B46FB606B883B82AB887B820FF0FE +:101A50008DFD02000320002A05D101211000583419 +:101A600023780B4323701BB0F0BDC046603F0000DD +:101A7000E03F0000FF3F000013B504680093A46836 +:101A800013000A000149A04716BDC046FFFF000031 +:101A900037B506AC257804680195009324691300D6 +:101AA0000A000149A0473EBDFFFF0000F0B589B024 +:101AB000019307000FAB0D0016000021082202A8B9 +:101AC0001C7810F065FE0EAB1B8802AA1380019BE8 +:101AD0000393002C06D0310028000FF0CBFE002825 +:101AE00041D154E03B007A79F833A2423DD9083322 +:101AF000190008390988B14208D130222034A400E5 +:101B0000E3590133DB7F134202D12EE00134ECE7CD +:101B100002220020DB06DB0F04ACD31AA370019B6A +:101B20002680E3600EABA3601A4BA0809D4207D1D4 +:101B3000FFF734FB03681B6998470FF096FE05001A +:101B4000210028000FF09AFE80B200281FD0112833 +:101B50001CD013D8082817D002AA310028000FF093 +:101B600089FE002812D0032011E002AA31002800CB +:101B70000FF080FE0028F6D1063008E0064B9842B0 +:101B800004D0064B9842E7D1062000E0052009B0BA +:101B9000F0BDC046FFFF000003300000013400002C +:101BA000F0B5050097B008002E240B9100F046F91F +:101BB00004ABE4181090220010A901200FF058FE89 +:101BC000002801D00320D4E023880B9A0A90938345 +:101BD0000B9B0A9A1B7D934250D96B791D2B01D91F +:101BE0000720C6E00B9B9B690C930A9B0C9A9B00F9 +:101BF0009C586369002B46D1638B002B43D1631C37 +:101C0000DB7F022B3FD134E06979A31C1F31C9006F +:101C10006918621CDB7FD27F089121002A31097884 +:101C20000020079121002931097806910D9905912D +:101C30000C990491217F0391218B0291618B019179 +:101C40006169009110A910F041F80028BAD16B79B0 +:101C500007001A00203292001F335451DB005B5BF7 +:101C6000E3836B7901336B71230028331B78BB420C +:101C700037D80A980130C3B20A93A9E72B7900201C +:101C800001332B7175E0200000F0D8F80026109089 +:101C90000D960C96230028331B78B342B4D9626AA0 +:101CA000B3009F58342204AB9B1800221A70002303 +:101CB000002111AAD21801335170102BF8D14622FD +:101CC00004AB9B182C4A11A938001A800FF059FE5A +:101CD000002803D07B690C937B8B0D93731CDEB2C1 +:101CE000D8E78E239B00EB5C132B00D978E7626A60 +:101CF000BB009E580023180011A90B70CA180133AD +:101D00005070102BFAD11C4B30004B820FF039FE73 +:101D10000C9000282AD1300000F090F88E2292001A +:101D2000AA5C738B1D32FF325200AA180232029253 +:101D3000327F10900192328B10A9009272690C9838 +:101D400010F0A0F8002800D03CE78E238E219B00E5 +:101D5000EA5C8900531CDBB26B541D337A32FF33CB +:101D600092005B005651EB185B88F383781CC7B276 +:101D70007AE717B0F0BDC0460129000070B5050034 +:101D80000FF07CFB041E1CD128007822210080303B +:101D900010F0FEFC2800E93050222100FF3010F046 +:101DA000F7FC280008222100F83010F0F1FC064B67 +:101DB0002822E818210010F0EBFC8E239B00EC5445 +:101DC00000E00624200070BD3A0200000B68002BE2 +:101DD00001D1036002E0024B0360002343607047BF +:101DE000271503001FB502AC08220021200010F0C7 +:101DF000CFFC282323806933FF336380E380803B5B +:101E000001A8FF3B05220C4903700FF040FF80B290 +:101E100000280FD1802080000FF035FF80B200280D +:101E200008D120000FF031FF80B2002802D10FF05E +:101E300028FF80B204B010BDE2430300F0B5438A2E +:101E400087B00293037804000126002B3ED0244B78 +:101E500024491A680393112301929C460022851994 +:101E6000019B934214D0674600235743CF19981E15 +:101E7000012803D9FE5CE85C864207D10133102BB0 +:101E8000F5D111235A4389180E7C1FE00132E7E790 +:101E900028000FF004FF237807000600002B01D173 +:101EA00012342500019B042B10D011245C430D4BF0 +:101EB00010221C192900200010F04CFC0023A370F4 +:101EC000E370019B039A01332774136005AB9E7086 +:101ED0005888029B00040343180007B0F0BDC046B9 +:101EE000C825002069280020F7B5FA26B6007143FE +:101EF000009308AB1B7804000800154917000193F4 +:101F000003F016F885B2300025807843104903F0BD +:101F10000FF86B461B8880B2A3806B461B796080EC +:101F2000A371032D01D80423238080232288DB01A1 +:101F30009A4200D92380032801D804226280628853 +:101F40009A4202D98023DB0163802000FEBDC04697 +:101F500071020000F0B58BB004AB9C1D0E230C2267 +:101F60000390019123804B7806A95343234AD31849 +:101F70001889220003230FF0C2FF00283AD1182746 +:101F8000019B1F4D5B7826885F4300933B0008331D +:101F9000EB18320006A91800029310F0CCFB2C00BD +:101FA00000280DD10C22009B5343144AD318997A70 +:101FB000022319401ED1E819182210F0E9FB19E09C +:101FC000E81943680F4F002B00D10F4F182503224B +:101FD000009B06A96B43E250E3185E603200029852 +:101FE00010F0B8FB019B2A00597803986943382305 +:101FF0006118B84700200BB0F0BDC046EA270020AA +:102000009026002059350200E1340200F0B585B079 +:1020100004000E0002AA8178214801F03BFA002852 +:102020003CD10C2361781F4A4B43D3189B7A019211 +:102030001D4F5B0605D4022E03D01C4F012E00D08D +:102040001B4F1C25A1781B4B69432A00591802A875 +:102050000023B847002813D1022E1FD00C234021A3 +:10206000627802A85343019AD3189A7A8A439A72E3 +:102070006178114B69432A0059182B00B84701E0D9 +:10208000022E0BD00C232278210053430B4A02A8C6 +:10209000D3189B7A0A4A9B009B58984705B0F0BD1D +:1020A000B8260020EA27002059350200E13402005A +:1020B000031F0300CC25002074260020A826002042 +:1020C000B8380300F7B518220190437826485A43E0 +:1020D00081184C68254F002C0FD00C2159437918DA +:1020E000897A4DB2002D07DA490605D41500083566 +:1020F000A6B24519145802E00024260025000C223F +:102100005343FB1818893200230029000FF0F5FE15 +:102110000B2816D10C22019B29005B785343FB1836 +:102120001889320001230FF0E8FE0C21019B104AB0 +:102130005B784B43FF1838890FF0DDFE002806D18D +:1021400011E0002800D00B48012C0CD1EDE7022251 +:10215000094BC318934305D0082803D0112801D098 +:10216000002000E00348FEBD90260020EA27002062 +:10217000FFFF000041800000FECFFFFFF8B5070021 +:102180004878182403006343084D0E00E818220025 +:102190003823390001F01CFA002806D173785C431B +:1021A0002C196368013300D16060F8BD90260020CF +:1021B00070B51C2444430D4E050030190622341915 +:1021C0000021113010F0E4FA10220021200010F05C +:1021D000DFFAFF232374A376013BFF3B2383023303 +:1021E000AB40034A11689943116070BDCC250020B3 +:1021F000B426002037B581B205006A46074801F0D1 +:1022000049F9041E08D15421684601F02DFA041E34 +:1022100002D12800FFF7CCFF20003EBDB8260020E9 +:10222000F0B51D00434B93B01B6801900F001600E2 +:10223000002B7CD0189B542B79D8FF22002403ABB1 +:102240005A709A70DA701C7002AB1C74189B0B9554 +:102250000A93A1B204AA384801F01CF9002809D158 +:10226000082204A9019810F066FA002802D103ABF5 +:102270009C7002E00134062CEBD103ACA178FF295D +:1022800055D0032F0AD1189A06AB542A01D1343AFB +:1022900000E040221A701A7803213AE0274BEB1A2B +:1022A000A72B10D8264B002E04D101228A40186893 +:1022B00010423CD001228A401968914320221960C3 +:1022C00006AB1A7020E01F4BEB1A1B2B09D82022FB +:1022D00006AB1A70002363700CAB0B9318230A93A0 +:1022E00012E019482D1A172D21D8302302AA137491 +:1022F000002363700133E370144B997A0223194071 +:1023000002D1182210F044FA06AB022F0CD10121A1 +:102310001A780A431A7009AB0793064B32001B6800 +:1023200006A92000984702E01A780221F1E713B0CD +:10233000F0BDC046A8260020B8260020CC250020ED +:10234000B42600207426002090260020EA270020D2 +:10235000F0B5040085B0002852D000252A4B2B4848 +:102360001D605D729D7201238372023B072229006A +:102370000381C37210F00CFA18222900244810F0CF +:1023800007FA28000135FFF713FF062DF9D1542372 +:102390006A46204F9380204B39006846D5800093D1 +:1023A00001F014F800282CD101231C4D24782B7047 +:1023B000002C1BD11C27A1B202AA164801F06AF812 +:1023C000061E0CD13B00634315481C22C01802A90D +:1023D000330001F0FDF8002804D02E7011E0002336 +:1023E0002B700EE00134062CE5D10AE06B466A46FC +:1023F0009B88D1883800594389B201F035F900E053 +:10240000084805B0F0BDC046A8260020EA270020F5 +:1024100090260020B826002021220200AD280020AE +:10242000CC2500200E800000F8B5174B06001B7865 +:102430000F00002B22D0002822D0002920D00B68CA +:10244000002B1DD0114D2C68002C1BD1280005310C +:1024500008C0052210F07EF93B790220AB720123FF +:1024600004212A7A9A4302438A432A72EA7913435F +:1024700003438B43EB712000347004E0044802E016 +:10248000044800E00448F8BDAD280020A82600203C +:10249000088000000E80000004800000154B1B78AF +:1024A000002B22D000281ED000291CD00378002B3E +:1024B0001BD1114B1B68002B17D04278002A16D174 +:1024C0000E4B9B7A012B12D02420184003D00123FD +:1024D00010000B700CE05BB2002B02DA02230B70D1 +:1024E00006E0087004E0064802E0064800E00648FE +:1024F0007047C046AD280020A8260020EA2700200B +:102500000E8000000880000010800000254BF0B510 +:102510001B78002B26D0002822D0002920D00B6861 +:10252000002B1DD08B68002B1AD00378002B19D1FB +:102530001D4A1268002A15D01C0018001B4A1032D0 +:102540001B4DEF7A9F420FD1AF7A02252F420BD05D +:1025500001331C32062BF3D108710C7300201FE0ED +:1025600014481DE014481BE00F7BBC420CD203252D +:10257000977A2F40022F07D1133DAC46944466460C +:102580008D68A7007E5101340F79B842E0D2022550 +:10259000977A2F42DCD10D6887007A510130D7E756 +:1025A000F0BDC046AD280020A8260020CC25002084 +:1025B000EA2700200E80000008800000104B70B554 +:1025C0001B78002B1AD0002816D00478002C15D1C7 +:1025D0000C4B1B68002B11D020001C252B006343E3 +:1025E000094AD3189B7EFF2B02D02000FFF702FE82 +:1025F0000134062CF2D102E0044800E0044870BD2A +:10260000AD280020A8260020CC2500200E80000048 +:10261000088000000048704791800000194A0300BC +:10262000127810B50800002A28D0002B24D00029E9 +:1026300022D01C78002C21D1134A1268002A1DD008 +:102640009978FF290AD15978FF2919D00C235943C9 +:102650000E4B59188B7A9B0712D508E01C2359435F +:102660000B4B591802238C7E1C4009D110310722D4 +:1026700010F070F8200004E0064802E0064800E090 +:10268000064810BDAD280020A8260020EA2700201B +:10269000CC2500200E80000008800000058000008E +:1026A000F0B5244B8BB01B7806000C00002B3CD0FF +:1026B000002838D0002936D00278002A35D11E4BA8 +:1026C0001B68002B31D08378052B30D81C256B4339 +:1026D0001A49CB189B7EFF2B29D0E260837803AF89 +:1026E0006B43CB182361164B6261A2606360276065 +:1026F000817801AA134800F0CDFE002818D12B00E4 +:102700002A0001A9380000F063FF002810D1E06022 +:10271000B37860615D43094BA0605D19084B25618A +:102720006360276004E0084802E0084800E00848C9 +:102730000BB0F0BDAD280020A8260020CC2500203D +:10274000AE280020B82600200E800000088000007F +:102750001080000013B5040081786A460B4800F031 +:1027600099FE002810D11C226078094B504369461D +:102770001818130000F02CFF064B074A9B7A210023 +:102780009B009B586846984713BDC046B82600205A +:1027900074260020A8260020C838030070B5050064 +:1027A00000241C263300634306492800C9180FF093 +:1027B0002CFC002804D10134062CF3D1FF3000E0BA +:1027C000200070BDCC250020FF23F0B5BD4A8FB09E +:1027D000127805000393002A00D1AEE1BA4A1168CD +:1027E0000192002900D1A8E104AF7B70BB70FB709F +:1027F000031D06932A23002602AA938203883E70B3 +:10280000B24C102B0AD0A67AB2075ED58288B049A6 +:102810008A4207D02189914257D103E0A37ADB078E +:1028200005D48AE1E27ABA7000227A704DE0112371 +:1028300002AA13737E708388063523810223072240 +:10284000A372290020000FF085FF2800FFF7A6FFE4 +:102850000390FF282DD11C2070439E4B1030181878 +:10286000072229000FF067FF002801D1039620E01E +:102870000136062EEFD102E0EB7903423DD1002272 +:10288000019B05AC1B682100380098472378122B68 +:1028900000D052E18D48837A012B00D14DE1012314 +:1028A0008372023B0381C372072200210FF070FF85 +:1028B00043E10821A27A039B0A43DBB2E372A272CE +:1028C0003800BB70FFF746FFD9E7172B46D101222E +:1028D00004201424019B01995B7A864393434B7235 +:1028E0007A4B05A90C709E72AC791900002CC3D0EC +:1028F000D87AFFF77FFCAA79C2E7BB78FF2BBED05E +:1029000008200643E87A8E72800706D51C205843BB +:10291000704C2018847E94438476CA7AFF2AAED005 +:102920001C2208786B4C5A4302280AD0A4182000B5 +:10293000072210300FF00EFF0222A37E9343A376EE +:1029400007E00121A318644A528A1A839A7E8A43B7 +:102950009A7601213800FFF759FB90E7172B00D931 +:10296000A0E0132B59D102AA137304231E43A672AD +:10297000A81DFFF713FF0390FF2802D0C0B2B87064 +:10298000E072E37AFF2B21D10026E33B180070436D +:10299000504A1018827EFF2A13D12378022B07D0C9 +:1029A000FD23F83A8376210010300FF0D3FE01E0CA +:1029B000FE23837603AB1E70039BDBB2BB70E37216 +:1029C00011E00136062EE1D1444C0DE016234448B7 +:1029D00002AA137300210E2208300FF0D9FE402204 +:1029E000A37A1343A37200240021384B0B91DA7AA7 +:1029F0001C235343374A0D91D3180C93364B09913E +:102A00000893019B0A911A1DA88808AB0FF06FFA72 +:102A1000002800D091E0220032E7142B26D1E37A7F +:102A2000FF2B18D11C2200239446E98962465A43A1 +:102A300028488218128B8A420AD10822039316432F +:102A4000DBB2E372A6723800BB70FFF783FE02E0D0 +:102A50000133062BEAD1E37A1F49FF2B00D1002175 +:102A6000A88800231B4A0FF044FA66E0112B64D1BA +:102A7000022332009A431300A272320707D55BB2D9 +:102A8000002B0BDA00213800FFF7C0FA06E0B87817 +:102A9000FF2803D0FFF78CFBFF23BB701023A3722A +:102AA000023302E01C2B03D1132302AA1373E6E6C0 +:102AB000522B19D1019B0B4A9B7A38009B009B58E3 +:102AC00098473AE0AD280020A8260020EA270020F9 +:102AD000FFFF0000CC25002074260020438000006A +:102AE00090260020A8380300182B26D1AB79112B93 +:102AF00014D1330712D512480E22002108300FF0EE +:102B000047FE162302AA137302224A331E43019B77 +:102B1000A6725B7A1343019A5372B0E680235B423C +:102B20001E4302AA95331373019BA6729B7A054A32 +:102B30009B009B5838009847A1E60FB0F0BDC046F7 +:102B400090260020A838030030B5002912D00A785A +:102B5000002A11D10A4B1B68002B0DD0FF23094C12 +:102B60008B702589FA3B854207D14A70E37A8B70D6 +:102B7000130002E0044B00E0044B180030BDC046D7 +:102B8000A8260020EA2700200E8000000880000010 +:102B900010B5064B586980235B05421C04D01969A7 +:102BA00089B202F0C5F900E0586910BD00100010AC +:102BB000034B10B51B78034A9B009B58984710BDE8 +:102BC000C5280020D83803000B0037B50C240200BC +:102BD00018009D6809786C43044D08302D680095F5 +:102BE000034D1B696459A04737BDC0460827002024 +:102BF000F4260020802252051169142210B50E48D7 +:102C000089B203785343C3181A69501EDA881B89A6 +:102C10008018C01802F08CF9084B02001B680120D4 +:102C20009A4207D800209A4204D1054B1B685842AB +:102C30005841C0B210BDC046C0260020EC2600207E +:102C4000F0260020082310B5034A1168994311604B +:102C5000FFF7AEFF10BDC04600270020094A10B59F +:102C6000136819070AD4990702D501210B43136091 +:102C70000222054B1A70FFF79BFF01E0FFF7E2FF0E +:102C800010BDC04600270020C5280020064B10B507 +:102C90001B681B0705D40122044B1A70FFF788FF3D +:102CA00001E0FFF7CFFF10BD00270020C52800205E +:102CB00010B5002814D0112805D10823094A11683D +:102CC0000B4313600CE01423074A11785943511841 +:102CD0000431FFF779FF0422044B1A7000F092F8D8 +:102CE00010BDC04600270020C0260020C6280020B6 +:102CF000F8B514238025124A6D051478114E5C43F3 +:102D00002B691419E2889BB2278920699A420ED94F +:102D10002B6961699BB2D31A2A69381892B2C91813 +:102D2000C01892080FF00BF92B699BB205E09208CE +:102D3000381861690FF003F9E3883360F8BDC046C5 +:102D4000C02600201427002070B58025094B6D0592 +:102D50002A691C68631E94B25C43FFF719FF2B6954 +:102D6000411E9BB25943044B20001A680FF0E7F84C +:102D700070BDC046EC26002010270020142270B53C +:102D800080260E4976050B785343CB181A89DC88C8 +:102D90001B69A4183169E418200089B202F04EF9C9 +:102DA0000D00FFF7F5FE3369411E9BB25943044BFA +:102DB00049191A6820000FF0C2F870BDC026002023 +:102DC000F026002010B5FFF7E3FE8022074C5205E5 +:102DD00013691169126924689BB292B289B20138F1 +:102DE0009208614358430FF0AAF810BDEC2600206A +:102DF00010B5034B18680FF0A0F8FFF759FF10BD8E +:102E0000EC260020F0B52B4B85B0187803284ED85F +:102E100002F084F8020E114B0023274A1360274A60 +:102E20001360274B5B78002B41D000F0F9F83EE0AF +:102E3000FFF75EFF3BE0234C802723687F0501936B +:102E40000123019A9A431423226002921C4A396991 +:102E5000157889B25D4355192B691800039302F068 +:102E600067F8194B039A18603969EB880600501E01 +:102E7000181889B202F05CF8864203D10223029A44 +:102E8000134303E00323019A9A43130023600F4B7B +:102E90001A680F4B002A03D121680232114200D078 +:102EA00000221A70FFF784FE01E0FFF7A1FF05B0D2 +:102EB000F0BDC046C62800200C27002014270020A3 +:102EC000C026002000270020EC260020102700202C +:102ED000C52800201422F0B580254B494B480B78BB +:102EE00085B05343CB18DF68083A7A4382181489B7 +:102EF0005089526860436D05821829691C890192C6 +:102F0000DA881E6913199B19009300230292404A24 +:102F100089B21360300002F091F83D4B2A00039310 +:102F200000290BD12B6902999BB2994208D0019BD1 +:102F300000998B424FD1002C59D101E0022F08D1CA +:102F40001169300089B201F0F3FF324B186003239E +:102F50003BE02969301989B202F070F82E4B8908DC +:102F60001960009A019B296993422DD089B200987B +:102F700002F064F8002927D080246B46640521699B +:102F8000988889B21F8801F0D3FF26690500B1B285 +:102F9000380001F0CDFFADB280B2854208D16B465A +:102FA0006A469B8812889B1A039A9B0813600BE061 +:102FB00023692169380089B29CB202F03FF889B2D6 +:102FC000641A039BA4081C600223144A1370FFF7C1 +:102FD00019FF05B0F0BD022FB2D02969301989B2AE +:102FE00002F02CF80C4B890819602969BEE7022F02 +:102FF000A6D02969301989B202F020F8064B890859 +:1030000019602B69E0E7C046C0260020F4260020A6 +:10301000F0260020EC26002010270020C6280020E3 +:10302000142210B50A490B785343CB18D988094AA2 +:103030001B791160032B08D0042B06D0012B06D17D +:10304000054A1370FFF7DEFE01E0FFF743FF10BDF6 +:10305000C026002008270020C6280020F7B5124D02 +:1030600001936E7808AC27880424022E1AD02C789D +:10307000A419012C00DD023C14235C432C1962616D +:10308000220020710C3209C909C26B469B88278136 +:10309000E3800024054B01361B786E70A34201D1FA +:1030A000FFF7BEFF2000FEBDC0260020C62800207E +:1030B00070B51424114D002029786143691804313A +:1030C000FFF782FD23000022012029784B43EB18F3 +:1030D0001A71DA80D8601A615A611A816B780918FE +:1030E000013B6B70CBB2022B01D02B7000E02A7039 +:1030F000034B1A70FFF786FE70BDC046C026002045 +:10310000C6280020142210B507490B785343CB186A +:103110001B79042B02D0FFF7CBFF04E00122034B05 +:103120001A70FFF76FFE10BDC0260020C6280020D1 +:10313000F8B508241D4F3D682C4022D180235B0543 +:1031400019691B4B1E68002E1ED01422194889B223 +:1031500003785343C3181A69501EDA881B898018F4 +:10316000C01801F0E5FE144B1B6898420CD1134BBC +:103170001C6001231D43124B3D601C70FFF718FDBE +:1031800013E0FFF75FFD10E0FFF734FD002804D0E7 +:1031900000220A4B1A60023202E0002E03D0032202 +:1031A000074B1A70EAE7FFF7ADFFF8BD00270020D4 +:1031B000F0260020C0260020EC260020102700204A +:1031C000C5280020054B10B51B681B0702D4FFF76C +:1031D00099FF01E0FFF736FD10BDC0460027002033 +:1031E00070B5154D2C68230723D4144A1368013396 +:1031F0001360134B04221B68002B04D1FFF7FAFC69 +:10320000002802D002220F4B0CE00F4B1B68002B52 +:103210000CD0012122000B4B0A4002D10C432C6040 +:1032200000E003221A70FFF7C3FC04E0FFF76AFF17 +:1032300001E0FFF707FD70BD00270020EC2600200D +:1032400010270020C5280020F02600201E4B10B5B6 +:103250001B78022B30D0032B19D0012B32D108213F +:103260001A4A13680B4222D1142319490A785A4387 +:10327000184B8A181968D3885B1A9BB2D380002B2D +:1032800002D1FFF715FF1DE0FFF732FD1AE008211C +:103290000E4A13680B420AD10F4A136801331360B8 +:1032A000FFF7A8FC002804D1FFF72CFF0AE08B43AE +:1032B0001360FFF7A7FD05E0084B094A1B789B0048 +:1032C0009B58984710BDC046C62800200027002004 +:1032D000C026002014270020EC260020C52800204E +:1032E000EC38030070B5144C042522781300AB436E +:1032F00021D002281DD003281DD1104B1B681B07AD +:1033000017D40F490B6801330B60032B04D0022A3A +:103310000CD1FFF74DFC0EE014230A4A0D20117862 +:10332000594351180431FFF74FFC2570FFF76AFD30 +:1033300001E0FFF78BFF70BDC628002000270020AA +:103340000C270020C026002010B501220024164BB7 +:103350001C705C701C71DC80DA601C615C611C811B +:103360001C765C831A625C629C629C830F4B1C809F +:10337000FFF70EFC802304225B051B6902389BB219 +:1033800058430B4B18600B4B20001C600A4B1C6011 +:103390001C815C81094B1C70094B1C60094B1C6033 +:1033A000094B1A6010BDC046C0260020F627002039 +:1033B00004270020EC260020F4260020C628002048 +:1033C0000C2700201427002000270020F7B5042236 +:1033D0002C4B04001B680E000820134251D006300D +:1033E000002C4ED000294CD02368002B49D08027D8 +:1033F0007F053A69A38892B2934201D9072040E041 +:103400000F2BFBD9E288002AF8D01F4953430D68DF +:103410005B190093FFF7BCFB3B6901389BB2584333 +:10342000194B0193009B8342E8D8A3889C469B07D5 +:10343000E4D1164B04201F88012F22D00C237B439C +:10344000134A2068D1189850634680203760756011 +:103450004D600B81E288400503694A810169046976 +:10346000604650439BB2C018013889B201F0EAFDB2 +:10347000A4B2604345190020019B01371D60034B36 +:103480001F80FEBD0027002004270020F627002013 +:10349000F4260020104B30B51C680823640719D5AA +:1034A0000633002816D0002A14D00368002B10D150 +:1034B0000A4D2C68002C0CD02C89406861430918F7 +:1034C0006889444368682418A14202D2136051609D +:1034D00000E00723180030BD00270020F42600205C +:1034E000F0B504001A4885B0056808206D072DD591 +:1034F000063000292AD0002C28D025680738002D56 +:1035000024D1144D2E68002E20D0666803962E8993 +:103510006F896D687743BC46039F6544AF4215D2FF +:10352000002A13D0964211D3D518AE420EDB0325E4 +:10353000093029420AD12B4208D12F4206D10093EB +:103540000F3813000A002100FFF788FD05B0F0BD19 +:1035500000270020F4260020F0B504001A4885B0AA +:10356000056808206D072DD5063000292AD0002CCB +:1035700028D025680738002D24D1144D2E68002E40 +:1035800020D0666803962E896F896D687743BC46A4 +:10359000039F6544AF4215D2002A13D0964211D33F +:1035A000D518AE420EDB0325093029420AD12B4241 +:1035B00008D12F4206D100930C3813000A002100D5 +:1035C000FFF74CFD05B0F0BD00270020F4260020D9 +:1035D000F0B51700224A85B0126802900E009C4692 +:1035E0000824530739D50634002936D0002834D0B2 +:1035F0000C68002C2ED11B4D2A68002A2AD04A685C +:10360000688929896B684843C018824222D2002FFA +:1036100020D0B9421ED36346F81881421ADB032139 +:10362000029B0B4218D163460B4215D11140039106 +:1036300012D16244110002983A000FF08BF80C236B +:103640003268009753430221ED58039A029B3000E1 +:10365000A84702E0072400E01024200005B0F0BDD8 +:1036600000270020F4260020F0B51F4B85B01B6812 +:1036700005000E0008245B0733D50634002830D03F +:103680000368073C002B2CD1184B1A68002A28D05D +:103690001A894768029258685B8953431B18039341 +:1036A0009F421ED20934BB071BD1381A110001F00A +:1036B000C5FC093C002914D10299300001F0BEFC80 +:1036C00089B200290DD1002E0BD0039AF3199A422A +:1036D00007D300223300009229000320FFF7BEFC2D +:1036E0000400200005B0F0BD00270020F4260020D3 +:1036F0000120054A10B513785840044B10701B6820 +:10370000002B00D0984710BDC728002018270020A4 +:103710000C4B70B5050015200C001A600EF029FC4A +:1037200000280ED1290015300EF025FC002808D104 +:1037300015300EF01CFC002803D1210003300EF0E0 +:103740001CFC70BD18270020F0B5274B85B01B78F6 +:10375000002B47D0254D264E2B6834685A425341E2 +:10376000DBB2009363425C41E4B2009B002B37D193 +:1037700003A80EF006FC05280AD0002804D0002279 +:103780001100FDF7BFFE05E003982B68984701E0A4 +:1037900001230093002C1FD1164B03A91B88012481 +:1037A0000B80154B1B68180001930EF0F0FB071EF1 +:1037B000052F0BD0002805D000221100FDF7A2FE36 +:1037C000002403E00198336898473C00009B002BDD +:1037D000CED0002CC9D005E0009B002BC8D001E062 +:1037E000002CD9D005B0F0BDC8280020202700202B +:1037F00024270020F82700201C27002070B5040093 +:103800000720002913D08D0711D10948016009490B +:1038100020000A80084A094913600EF0B4FB002812 +:1038200005D10122064B16301A700EF0A8FB70BDB0 +:103830001C270020F827002028270020931F0300C2 +:10384000C828002010B50EF0A0FB03005A1E9341BB +:10385000014ADBB2137010BDC82800200E230028D7 +:1038600002D0024B18600023180070472427002064 +:103870000E23002802D0024B186000231800704766 +:1038800020270020074B10B51B68002B07D0984756 +:10389000002806D000221100FDF734FE01E0FFF7FA +:1038A00053FF10BD28270020F0B50E788FB0002EF2 +:1038B00000D097E0514C02AB9A1D210008230588E7 +:1038C00013803431073B28000EF069FB4C4B1B681A +:1038D0009847B1200EF065FB002803D0320031007C +:1038E000FDF710FE0EF05FFB002803D00022110050 +:1038F000FDF708FE434E70690EF057FB0196002855 +:1039000003D000221100FDF7FDFD00233E4E2800EC +:1039100031000493FFF718F9051E4CD108A93A4865 +:10392000FEF7BEFE071E33D10C9D072229002000A2 +:1039300010310EF00FFF29001022E01D0EF00AFFDB +:103940002000089D1122290018300EF003FF2000EE +:1039500029002A3012310A220EF0FCFE20000EF05F +:1039600026FB002803D03A003900FDF7CBFD0123E8 +:10397000002404930333069305A904AB224807935C +:103980000594FEF747FEA04215D02200210010E06A +:1039900021003000FEF742FE002803D02A00290053 +:1039A000FDF7B0FD20000EF002FB002803D000223E +:1039B0001100FDF7A7FD8021C022144BC90352005E +:1039C0009950196801200023114C02009A401142BD +:1039D00000D0E2670133202BF7D1019B586900F03A +:1039E0004BF809E00322012100F014F8002803D06D +:1039F00000221100FDF786FD0FB0F0BDFA27002070 +:103A00001820002000100010C928002000E100E06C +:103A100004E100E0F0B5060087B00E20002E22D0B1 +:103A20003788124B06389F421DD0114B1B78002B54 +:103A300019D0104D102369706846032102ACC18073 +:103A4000AA7000211A0020002B700EF0A1FE338A0C +:103A5000210023800123A3706B4638000633A36046 +:103A6000E5600EF0F3FA07B0F0BDC046FFFF0000BE +:103A7000CD280020CE280020F0B50300186880F380 +:103A800008885868FF2464B2EFF30585002D01D142 +:103A9000A6460047251C061C21273FBAF0B4002487 +:103AA000002500260027F0B4F92040B20047C046A8 +:103AB000F0BDC04610B50400034B083303601C3052 +:103AC00000F0ACFB200010BD0039030070B505000C +:103AD00004000E4B0E00083308C5280018220021F0 +:103AE0000EF056FE002320003100E3612362636381 +:103AF000A363E364064A23001C3000F05FFB280048 +:103B000031000EF046FC200070BDC04600390300B5 +:103B100003210300084B10B5083303600023436002 +:103B20008360C360040000F0C5F8044920610EF012 +:103B30004CFC200010BDC0461039030019210300C1 +:103B400010B50400034B083303600EF0F2FA2000B6 +:103B500010BDC0461039030010B50400044B0360CB +:103B60000EF01CFB2000FFF7EBFF200010BDC0464D +:103B7000403903000C4B70B5036000234360836041 +:103B8000C360036243628363962304009B01051DA7 +:103B9000C363280000F0A6F928002200034900F0C2 +:103BA00033FA200070BDC04654390300C921030018 +:103BB00010B50400FFF7DEFF014B2000236010BDAD +:103BC00064390300F7B50027040008A8C7570E485A +:103BD000002508302060082020610C48261D656003 +:103BE000A56025736561A0610097300000F04EFF6D +:103BF0002B0030006269216900F0CEFE3000A1691F +:103C000000F002FF2000FEBD6C39030040420F00AF +:103C100070B5094D04002B6883420BD0061D426924 +:103C200001690023300000F0B7FEA169300000F008 +:103C3000EBFE2C6070BDC0462C27002042610022A4 +:103C400010B5034B01611A60FFF7E2FF10BDC046DB +:103C50002C270020002210B5024B81611A60FFF76B +:103C6000D7FF10BD2C27002070B504000D001600F2 +:103C7000002110220EF08CFD054B3200236129003B +:103C8000200000F0E1FD034B20001C6070BDC04629 +:103C9000A08601003027002070B5054D04002B6878 +:103CA000834203D0016900F089FD2C6070BDC046DD +:103CB00030270020004870479439030010B50248AF +:103CC0000EF08CFB10BDC046943903000848026812 +:103CD00003210A4302600749074A084B9B1A03DD88 +:103CE000043BC858D050FBDC0548804705480047D6 +:103CF00024050040C445030000200020C02000200F +:103D0000614E020075810100FEE7FEE7FEE7FEE777 +:103D1000FEE7FEE701230E4A10B5936480230D49A8 +:103D20009B00CB670C491400086D0C4A002804D096 +:103D30000020086511680131116009490B60A92351 +:103D4000DB001068E358010C9BB20004184310BD5F +:103D50000090004004E100E0FC900040402700207B +:103D600000E100E0F8B50F4C636C002B0FD000278A +:103D70000D4E67643378BB4209D00C4B1D68FFF7CA +:103D8000C9FF2D1ABD4202DC3770FFF797FF236D84 +:103D9000002B06D0064A1368013313600022014B42 +:103DA0001A65F8BDFC900040D62800203C27002072 +:103DB000402700201B4970B50C78002C30D1012021 +:103DC000194B1A4A586054608024E40520605068FA +:103DD0000028FCD000220124042515481A500C307C +:103DE000DC601D5008381A501248C2251A50C122F2 +:103DF00080209200000398508020400298500E4886 +:103E0000AD0046590D4A3240C02636023243425177 +:103E10008022893D9200FF3D425102601C600C707F +:103E200070BDC046D528002000900040FC00004036 +:103E3000040500004C05000000E100E0FF00FFFF6A +:103E4000044B10B51B78002B01D1FFF7B3FFFFF730 +:103E500061FF10BDD5280020104B70B51B78040001 +:103E6000002B01D1FFF7A6FF0D4D0E4E2B78002B36 +:103E700002D033689C4210D0FFF74CFF201A0A286A +:103E800003DCFFF747FF0A30040001232B70A8234F +:103E9000054A3460DB00A4B2D45070BDD5280020A0 +:103EA000D62800203C27002000900040012310B5B8 +:103EB0000A4ADC00A4588C4207DD013BDB00D31822 +:103EC0005A680168064BCA5007E00133112BF0D144 +:103ED00080210268024B4905D15010BD9C39030076 +:103EE00024050000F8B50F000121254BB9400360FF +:103EF000A023244CDB0516001A5905000A43802133 +:103F00001A511A5909060A430121B1401A511A5986 +:103F10008A4396211A511A598901520052081A519E +:103F2000FFF7C4FF002204202B6817495A506C3950 +:103F300058500121996019601900FC31CA60134979 +:103F40005A506A6014391F325A5011495F5009188B +:103F50005A501E517B1C03D0032138000EF0D7FAB3 +:103F6000731C03D0032130000EF0D1FA0122094B5B +:103F700029001A60084807320EF0ECFBF8BDC04675 +:103F800000200040140500006C0500001C05000026 +:103F90000C0500004427002004290020962310B5BA +:103FA000DB00994202DDFFF781FF04E09E210268F9 +:103FB000014BC902D15010BD24050000C1230E4A97 +:103FC0009B00D15810B5090603D50C49096A002990 +:103FD00008D1D3585B070DD5084B0021DB68002BB7 +:103FE00001D107E00121064B1868002802D0054BDB +:103FF0001B68984710BDC04600200040FC200040D0 +:10400000482700204C270020034B196043680349D0 +:104010009B005A507047C0464C270020482700207C +:1040200000681F4B70B5C3185C4263415B00002AF7 +:104030001BD0002903D0012905D1802100E00421F3 +:10404000C122920081505CB2FF23C025E600B3403C +:104050001449AD004A599A431000C0220123B240CE +:10406000A34002434A510B6018E0002908D00129FF +:1040700014D1C2228024920084508258920806E013 +:10408000C22204219200815082580339D2099143FF +:1040900004D001229A401300034AD36770BDC04682 +:1040A00000E0FFBF00E100E004E100E003681A0067 +:1040B000FC32106A0128FCD100201062014AC9B20A +:1040C000995070471C050000F7B5A223A022DB0021 +:1040D000D205D358BE220193314B52009958002982 +:1040E0005DD0C12189005958002958DA0024E02503 +:1040F000C0269C50ED00B6022A4BA700F8580028B5 +:104100004AD0294BE35C002B30D0019B0121E340D6 +:104110000B4212D02300A022C133FF339B00D205F3 +:104120009B589B039B0F032B07D0204B1B68E3403E +:104130000B4202D01E4B1B6817E0019B0122E3409B +:10414000134213D12300A021C133FF339B00C905C3 +:104150005B589B039B0F032B08D1164B1B68E34056 +:10416000134203D00221124B1B689847A023DB05A2 +:10417000FB185A5932420FD059590F4A0A405A5126 +:10418000019AE240D20702D55A59324303E0802116 +:104190005A5989020A435A5101341F2CACD1F7BD38 +:1041A0000060004054270020D7280020D02700209E +:1041B00050270020D4270020FFFFFCFF30B504006B +:1041C00008004D1C1CD00F482160BE240260002056 +:1041D0000D4A640010510D4C8D002B5101240C4BE5 +:1041E0005C54C121802389001B065350094A0A4BA5 +:1041F00054582340C02424042343535040231360C5 +:1042000030BDC046502700200060004054270020E9 +:10421000D728002000E100E0FFFF00FF0021036835 +:10422000014A9B00995070475427002070B5A02484 +:10423000E0250068E40583001B19ED005E59204C61 +:1042400034405C511F4D0124002A0ED0A14204D1FC +:1042500081402A681143296015E0022913D1844066 +:10426000194A11680C4314600DE0012904D1814002 +:104270002A688A432A6006E0022904D18440124950 +:104280000A68A2430A602A680121C2400A4204D196 +:104290000D4A1268C2400A4211D0A222A021D200C7 +:1042A000C9058958F132C140FF32C90702D5995872 +:1042B000C02001E08020995880020143995070BDD0 +:1042C000FFFFFCFFD0270020D427002000220B4B4B +:1042D0009A5682420AD001229A56824208D002227D +:1042E0009A56FF23824207D1022002E0002000E01C +:1042F0000120034B1870C3B258B2704797200020BA +:10430000F62800200022134B30B59A56824209D07D +:1043100001229A56824207D002229A5602218242F4 +:1043200017D102E0002100E001210A0045320A4CC9 +:104330000A48FF3292001450012215004800441C24 +:10434000A5408240A120064C2A43C0002250FF22F3 +:104350005A5430BD97200020031F02000060004027 +:1043600000F001400022F8B5124F0600BA563B009B +:10437000114D013209D00122BA56013207D0022272 +:10438000BA560220013207D102E0002000E00120ED +:104390001E542870C0B20BE028780321013000F0D1 +:1043A00037FF0C0078562970FFF7ACFF3E55E0B29E +:1043B00040B2F8BD97200020F6280020012370B5F8 +:1043C0001E000200A0258640C132FF32ED0592009A +:1043D0005351134A0002AE50A226124A4C00104319 +:1043E000114A89008D18F600E4B2A851C046C046B3 +:1043F000C0460E48E20012180D482B6015500D48BB +:10440000091891510C490D48555004395050190064 +:10441000E2189140A3400A4A0B4304498B5070BDF7 +:104420000C050000030013000060004000F0014094 +:104430001405000040A100401C0500004CA10040F4 +:1044400004050000A820012110B5124A124B14885F +:10445000C00059601C50548810481C509088A922F4 +:10446000D200985080220820920098508020093273 +:104470000003FF3298500A4A1078A222D2009850C6 +:10448000084A1088084A985000221960FC331A65BF +:1044900010BDC0468A20002000A000404405000056 +:1044A00096200020882000204C05000070B50125D2 +:1044B00045570E002800FFF709FF0400431C0ED1EA +:1044C0002800FFF74FFF030051331D49FF331D4AFA +:1044D0009B0004009950C1B22800FFF76FFF64B23F +:1044E000194BA200D6503200184B64001B78043BD5 +:1044F000DA40174BE252002E03D0164B1B689E4247 +:104500000ED32800FFF7FEFE0123A022AB40D20508 +:10451000002E02D0A121C90000E00F4953500EE047 +:1045200072B600210D4A074B11658021C122090393 +:10453000920099500A49053AFF3A995062B670BD07 +:10454000FFFF000000A00040D82700209620002098 +:104550008A2000201C2000200C050000FCA0004048 +:1045600008080000F8B5254B06001A780D00002A4F +:1045700028D10121224B234859601A501950224852 +:10458000C2271A5004301A50204ABF001078A222C5 +:10459000D200985080220820920098501C4A10881F +:1045A0001C4A98501C48C259944664461B4A2240F3 +:1045B0008024E4032243C2518022D20002601960A9 +:1045C0000E4B19702800FFF781FE0400431C0ED12A +:1045D0002800FFF7C7FE030051331149FF33084A93 +:1045E0009B0004009950C1B22800FFF7E7FE7570E8 +:1045F000347030000021FFF759FFF8BDF728002084 +:1046000000A00040FC0F00000405000096200020E0 +:10461000882000204C05000000E100E0FFFF00FFC3 +:10462000FFFF0000084B70B50D1C0400186801F076 +:104630000DFE291C01F006FB01F09EFD010020008B +:10464000FFF734FF70BDC0461C200020F0B5254B9D +:1046500085B01F680D001A008F4240D080210423CE +:104660004902A9420ED3092B39DC15602A001E49E4 +:1046700003AE0B70043BDA401C4B00241A80FF236E +:10468000337007E0132B2AD049000133E9E70134E6 +:10469000032C24D0164B6200D25A164B9A42F6D005 +:1046A000154BA200E35C7370144BD05801F0CEFDA3 +:1046B0000090280001F082FD0190380001F0C6FD55 +:1046C000011C019801F0F4F8011C009801F0BAFAFD +:1046D00000F082FE01003000FFF7E8FED7E705B0EA +:1046E000F0BDC0461C20002096200020882000201D +:1046F0008A200020FFFF000097200020D8270020FC +:1047000001704B1C0AD001238B404360044BC360F3 +:10471000044B0361044B4361044B83607047C04604 +:10472000080500500C0500501005005014050050FD +:104730000261064A10B54260054A01738260054A6B +:10474000190002600DF005FF10BDC04604050050C1 +:1047500010050050000700500368074A9950074AA7 +:10476000FC33196A002904D1013A002AF9D1012049 +:1047700001E00020186270471C050000A1860100BE +:1047800010B50368002A03D08022022092009850BE +:1047900001221C001A62084AFC34E068002804D197 +:1047A000013A002AF9D1012005E00020A322E060AF +:1047B000D2009B580B7010BDA186010010B50B4CA8 +:1047C00002680B4BA14204DC0A498160CC214904F8 +:1047D0000AE0094CA14203DC08498160802102E023 +:1047E00007498160CD21C904D15010BD8FD003008D +:1047F00024050000A08601007F1A060090D0030067 +:10480000801A060070B504001000A025C026C13033 +:10481000FF30F600ED05800046510800C130FF3042 +:1048200080004651A1252068ED004251054A815083 +:1048300019002000FFF7C2FFA02305212268DB003A +:10484000D15070BD0C050000F8B50E001500040035 +:1048500000F074FA2648F2B203780100DBB2012BB3 +:1048600006D14778974203D18778E8B2874211D0C2 +:104870002048EFB20378012B05D14378934202D14F +:104880008078B84211D00878002806D101230B7037 +:104890004A708F706373184B15E0164B1978002916 +:1048A00007D1013119705A709F7002236373134B43 +:1048B00009E013480DF044FD0023FC2223606571DC +:1048C00026719362FFDE19000022FC3123606571BE +:1048D00026718A62A021C9005A500A4920005A5004 +:1048E00001325A502A003100074BFFF78BFFF8BD09 +:1048F000F8280020FC280020003000400040004044 +:10490000E8430300FC0F0000A086010003680022BA +:104910001900FC3110B58A62A021C9005A5006491D +:104920005A5001325A50052204218256415683685A +:10493000FFF768FF10BDC046FC0F000003680021B0 +:104940001A00FC3210B5916001315961074B916832 +:10495000002904D1013B002BF9D1012004E00024FF +:104960000473FFF7D3FF200010BDC046A1860100ED +:10497000036810B51900FC318A6A0020012A08D1A9 +:10498000044C1C5988625A610238A40701D40120E2 +:10499000404210BDC404000070B51D00A0230400F7 +:1049A0001600DB00002D03D000224068C25001E059 +:1049B0000268D550082902D010480DF0C1FC032E22 +:1049C0000AD8300000F0AAFA0B020406022307E01E +:1049D000042305E0062303E009480DF0B1FC0023A1 +:1049E000A0220848D200002D03D061680B5002239A +:1049F00002E021680B5001238B5070BDF943030086 +:104A00001244030054050000036810B55A1C2ED050 +:104A1000A0220020164CD20098501000154AA14246 +:104A200002DC802189041FE0134CA14202DC8021BA +:104A3000C90419E0114CA14202DC8021090513E0F0 +:104A40000F4CA14202DC802149050DE00D4CA14232 +:104A500002DC8021890507E00B4CA14202DC8021A9 +:104A6000C90501E080210906995001221A5010BDA4 +:104A70008FD00300240500001FA107003F420F0054 +:104A80007F841E00FF083D00FF117A00F7B50093F8 +:104A900008AB1B7805005BB20F00160001930133D1 +:104AA00029D1624B1A78022A10D15978FAB2914270 +:104AB0000CD19978F2B2914208D1DA786B461B7822 +:104AC0009A4203D101235A4C03723BE0594A1378AE +:104AD000DBB2022B0FD15078F9B288420BD190781B +:104AE000F1B2884207D1D1786A461278914202D158 +:104AF0002B72514C26E04F4B1A78002A0BD1023210 +:104B0000F9B21A705970F1B29970694609782A722F +:104B1000D970494C13E0454B1A78002A0CD1023267 +:104B20001A70FAB25A70F2B29A706A461278404C11 +:104B3000DA7001232B7202E040480DF001FC019B6A +:104B400001332ED10123002201205B426B6039002A +:104B50003B4B2C60E250E050A023C131FF31DB051C +:104B60008900C850374967500099C131FF31890029 +:104B7000C850A1210098C90060503100C131FF31F7 +:104B80008900CA50A223DB00E650FC342800E26012 +:104B900013000821FFF700FF2B492800FFF734FF1F +:104BA00042E0012300225B422B60254B6C60E25007 +:104BB0000123234938006350A021C130FF30C905CB +:104BC000800042503000C130FF30800042500098D9 +:104BD000C130FF30800042500198C130FF3080006A +:104BE0004250A221C9006750164900986650043906 +:104BF00060501649019860502100FC318A60CA62F9 +:104C0000A721C90063501031635011481149605009 +:104C10001149124860508021042089006050F93900 +:104C2000FF392800FFF7B8FEF7BDC046F82800207E +:104C300000300040FC2800200040004023440300D6 +:104C4000FC0F00000C05000040420F00140500009E +:104C5000012900204405000034050000002900203F +:104C600003681A00FC32D0680028FCD105481950AE +:104C7000D1680129FCD10021D160A322D20098582B +:104C80007047C0461C050000A023F0B5284FDB008C +:104C9000FA5885B001920022A024FA50E023254A58 +:104CA000E405DB00E658E2507833E1580125029133 +:104CB000E250A1238022DB00D205E2500420E5501F +:104CC0000DF0E7FCA222D200A35803979B0F2B42C2 +:104CD00005D0A35813242B4202D0012018E013243E +:104CE000A0250127ED05013C002C10D0124B04201B +:104CF000EF500DF0CEFCA123DB00EF5004200DF0AF +:104D0000C8FCA223DB00EB585B00ECD5E5E72000F4 +:104D1000A023E0220299DB05D2009E507832995000 +:104D2000A023039A0199DB00D15005B0F0BDC04625 +:104D3000004000400D0600000C050000A023E0210B +:104D4000134ADB05C90010B55A5078315A50114B3F +:104D500000221900FC31CA600A62A1211E20C9008C +:104D60005A500D4A0D4C9850CC200D4A4004985092 +:104D7000A2200C4AC00014500B4C0C4814500120C7 +:104D80005050A0220521D2009950FFF77DFF10BDA1 +:104D90000C060000004000400C05000038410040B7 +:104DA0002405000000F001401C40004014050000F4 +:104DB00070B50E000F4C05002100300000F040F8E7 +:104DC000210028600023CB565A1C05D09E4201D1F9 +:104DD0008B6802E00C31F5E70023A0210120064A90 +:104DE000C9002B7150506A211B020B4303495350D9 +:104DF00070BDC046243A0300007000400405000066 +:104E00000C4B0D4A10B50D499C5821409950017921 +:104E10009C5809022143995080200122C0001A6049 +:104E200019581142FCD1A123024ADB00D05880B2AC +:104E300010BDC0460070004004050000FF00FFFFE9 +:104E400010B50400431C07D00DF03AFC0400431CCD +:104E500002D102480DF074FA200010BD5644030040 +:104E6000234A10B513781100012B19D1214B1B686F +:104E70001B0715D1204BE0241A68F02310001840BE +:104E800022420BD11D4A12681A4209D11C4A1D4BFD +:104E90001A6080221C4B12021A6001E03028F1D007 +:104EA0000B68DBB2012B0DD1124A1268120709D12F +:104EB000F021114A12680A40402A03D10F4A1268B1 +:104EC0000A420DD08022A3230021D205DB00D1505D +:104ED0000E4B9960013191609A68002AFCD005E080 +:104EE000C1228021D200C9058B50EBE710BDC0461E +:104EF000E00F00F0E40F00F0E80F00F0EC0F00F01E +:104F0000DFFF07C004050040186C0040FC000040B3 +:104F1000014B18687047C046E427002002B4714670 +:104F200049084900095C49008E4402BC7047C046EC +:104F3000002243088B4274D303098B425FD3030AD8 +:104F40008B4244D3030B8B4228D3030C8B420DD3EB +:104F5000FF22090212BA030C8B4202D31212090279 +:104F600065D0030B8B4219D300E0090AC30B8B42B7 +:104F700001D3CB03C01A5241830B8B4201D38B0365 +:104F8000C01A5241430B8B4201D34B03C01A52410A +:104F9000030B8B4201D30B03C01A5241C30A8B424D +:104FA00001D3CB02C01A5241830A8B4201D38B0238 +:104FB000C01A5241430A8B4201D34B02C01A5241DC +:104FC000030A8B4201D30B02C01A5241CDD2C3094E +:104FD0008B4201D3CB01C01A524183098B4201D3CA +:104FE0008B01C01A524143098B4201D34B01C01AB5 +:104FF000524103098B4201D30B01C01A5241C3082D +:105000008B4201D3CB00C01A524183088B4201D39B +:105010008B00C01A524143088B4201D34B00C01A87 +:105020005241411A00D20146524110467047FFE7F3 +:1050300001B5002000F0F0F802BDC0460029F7D00D +:1050400076E7704703460B437FD4002243088B4228 +:1050500074D303098B425FD3030A8B4244D3030BFF +:105060008B4228D3030C8B420DD3FF22090212BAC4 +:10507000030C8B4202D31212090265D0030B8B4240 +:1050800019D300E0090AC30B8B4201D3CB03C01A2A +:105090005241830B8B4201D38B03C01A5241430B05 +:1050A0008B4201D34B03C01A5241030B8B4201D3F5 +:1050B0000B03C01A5241C30A8B4201D3CB02C01A60 +:1050C0005241830A8B4201D38B02C01A5241430AD8 +:1050D0008B4201D34B02C01A5241030A8B4201D3C7 +:1050E0000B02C01A5241CDD2C3098B4201D3CB016E +:1050F000C01A524183098B4201D38B01C01A52411D +:1051000043098B4201D34B01C01A524103098B4220 +:1051100001D30B01C01A5241C3088B4201D3CB000B +:10512000C01A524183088B4201D38B00C01A5241EE +:1051300043088B4201D34B00C01A5241411A00D29E +:1051400001465241104670475DE0CA0F00D0494207 +:10515000031000D34042534000229C4603098B4277 +:105160002DD3030A8B4212D3FC22890112BA030AFF +:105170008B420CD3890192118B4208D38901921181 +:105180008B4204D389013AD0921100E08909C30906 +:105190008B4201D3CB01C01A524183098B4201D308 +:1051A0008B01C01A524143098B4201D34B01C01AF3 +:1051B000524103098B4201D30B01C01A5241C3086B +:1051C0008B4201D3CB00C01A524183088B4201D3DA +:1051D0008B00C01A5241D9D243088B4201D34B00F5 +:1051E000C01A5241411A00D20146634652415B1037 +:1051F000104601D34042002B00D549427047634618 +:105200005B1000D3404201B5002000F005F802BD5C +:105210000029F8D016E770477047C0468446101C36 +:1052200062468C46191C634600E0C0461FB501F07B +:1052300031FF002801D40021C8421FBD10B501F084 +:1052400085FE4042013010BD10B501F023FF00285B +:1052500001DB002010BD012010BDC04610B501F0DB +:1052600019FF002801DD002010BD012010BDC0463F +:1052700010B501F0ABFE002801DC002010BD0120BC +:1052800010BDC04610B501F0A1FE002801DA0020D3 +:1052900010BD012010BDC0468446081C6146FFE7D2 +:1052A0001FB500F08BFC002801D40021C8421FBDAF +:1052B00010B500F017FC4042013010BD10B500F0F1 +:1052C0007DFC002801DB002010BD012010BDC04680 +:1052D00010B500F073FC002801DD002010BD012096 +:1052E00010BDC04610B500F025FC002801DC0020F0 +:1052F00010BD012010BDC04610B500F01BFC0028F9 +:1053000001DA002010BD012010BDC046002B11D1D4 +:10531000002A0FD1002900D1002802D00021C94362 +:10532000081C07B4024802A14018029003BDC04601 +:10533000E9FEFFFF03B4684601B5029800F082F869 +:10534000019B9E4602B00CBC7047C0461300F0B5EE +:1053500045464E4657469146D2179B185340E0B4F7 +:1053600004000D009846DB0730D506000F0001232E +:105370009A4643465B08984618D022002B0020002E +:10538000290001F0F1FE5346424604000D0013428D +:10539000EFD00B0002003900300001F0E5FE43467B +:1053A0005B0806000F009846002BE6D14B46300004 +:1053B0003900002B05DA32003B000020054901F0DE +:1053C000AFFA1CBC90469946A246F0BD0026014F9C +:1053D000CDE7C0460000F03F9E2110B5C905041C72 +:1053E000FFF78AFF002803D1201C00F0C5FE10BD86 +:1053F0009E21201CC90500F039FD00F0BDFE802370 +:105400001B069C466044F2E770B500220C4B04007A +:105410000D00FFF737FF002804D12000290002F01B +:1054200091FC70BD064B00222000290002F016F905 +:1054300002F088FC80231B069C466044F1E7C046CE +:105440000000E041F0B54D46564644465F46F0B494 +:10545000924683B004000D0099468B422FD82CD081 +:105460004946504602F01CFE29000600200002F0CA +:1054700017FE331A9846203B9B4600D574E05346EE +:105480005A4693401F005346424693401E00AF4287 +:1054900029D826D05B46A41BBD41002B00DA79E059 +:1054A000002200230092019301235A469340019366 +:1054B000012342469340009319E08242D0D9002252 +:1054C0000023009201930C9B002B01D01C605D60B7 +:1054D0000098019903B03CBC90469946A246AB4661 +:1054E000F0BDA342D6D90022002300920193434687 +:1054F000002BE8D0FB0772081A4346467B080EE0F3 +:10550000AB4201D1A2420CD8A41A9D41012024191A +:105510006D410021013E24184D41002E06D0AB42C2 +:10552000EED9013E24196D41002EF8D15B4600985A +:10553000019900196941002B22DB2B005A46D34008 +:105540002A004446E2401C005B461500002B2CDB81 +:1055500026009E40330026004746BE403200801A97 +:10556000994100900191AEE7424620239B1A524692 +:10557000DA40414613004A468A4017001F4382E73B +:10558000424620239B1A2A0046469A402300F340B5 +:105590001343D5E74246202300219B1A00220091A5 +:1055A00001920122DA40019282E74246202326003E +:1055B0009B1ADE402F00B446974066463B003343BB +:1055C000C9E7C046F8B54A02430244004E00C50F81 +:1055D000240E28009B09360EC90F92098D4259D01E +:1055E000A01B002800DC8DE0002E1AD1002A00D07C +:1055F00079E05A0704D00F221A40042A00D004335D +:105600005A0138D50134FF2C00D189E028009B01D4 +:105610005B0AE4B25B02E4055B0A2343C00718435C +:10562000F8BDFF2CE5D08021C9040A431B2800DD0A +:1056300089E016002021C640081A8240511E8A4186 +:1056400032439B1A5A0114D59B019E09300002F087 +:1056500009FD05388640844265DC041B33002020A8 +:105660000134E340041BA640721E964100243343DC +:10567000BFE75A07BFD1DF082800FF2C2FD1002F2A +:1056800000D187E08022D20313003B435B025B0A18 +:10569000FF24BFE7A11B002949DD002E29D0FF2CE4 +:1056A000A7D08026F60432431B2900DD8DE01700C9 +:1056B0002026CF40711A8A40511E8A413A439B18D6 +:1056C0005A01D6D50134FF2C64D0012276491A4004 +:1056D0005B080B4013438CE7031ECAD100207B02FA +:1056E0005B0AE4B296E701380028AAD0FF2C9DD1CE +:1056F0007FE7002A00D17CE701390029DFD0FF2CA9 +:10570000D2D176E7002820D1601CC0B2012853DD39 +:1057100080279E1AFF0437402FD0D61A0D0095E738 +:105720002800002376E7614B241A334061E7002903 +:105730004DD1611CCEB2012E2FDDFF292AD09B183E +:105740005B080C0055E701227BE7002C1BD1002BE6 +:105750005BD0C04300280CD0FF2E7ED01B2800DD7C +:1057600092E01D002024C540201A8340581E83412A +:105770002B43D31A34000D0064E7002E00D065E7F8 +:1057800000200024ABE7FF2E67D08024E4044042D1 +:105790002343E3E7FF2400233CE7002C61D1002BE7 +:1057A0007ED0002A00D124E79B185A0100D460E77C +:1057B0003E4A0C0013401CE7002C1ED1002B2FD1B9 +:1057C000002A66D013000D0013E7012277E7002CB2 +:1057D0001FD1002B5AD0C94300290BD0FF2E50D027 +:1057E0001B295FDC1F002024CF40611A8B40591E0B +:1057F0008B413B439B18340062E7002B1CD1002AED +:105800004AD013000D00FF24F3E6130034000D000E +:10581000EFE6FF2E35D08024E40449422343DFE73E +:10582000002A00D1E5E68027981AFF04074000D13E +:1058300052E7D31A0D00DCE6FF24002A00D1D8E697 +:105840008020DB08C003034204D0D208024201D109 +:1058500013000D00DB00FF24CBE61300FF240D0036 +:10586000C7E6002B0DD0FF24002A00D1C1E680211D +:10587000DB08C9030B42EDD0D2080A42EAD113007B +:10588000E8E71300FF24B4E6012372E713003400B5 +:10589000AFE60027002022E780270020FF03F1E683 +:1058A0001300A6E60123A5E7FFFFFF7DFFFFFFFB37 +:1058B000F0B5564644465F464D46F0B444024600B5 +:1058C000C70F83B08846650A360EBA463DD0FF2E14 +:1058D00022D00023EC00802599469B46ED04254309 +:1058E0007F3E43465C025800DB0F640A000E984678 +:1058F00036D0FF2830D080230021E400DB041C4395 +:105900007F38301A0190484642460843724E800064 +:1059100030587A4013008746002D44D10823994619 +:10592000063B9B46DDE70122FF2000241A4064026B +:10593000C305640AD2071C431443200003B03CBCD7 +:1059400090469946A246AB46F0BD002D20D10423D7 +:105950009946033B9B46C4E7002C17D1022102E085 +:10596000002C0AD10121321A01924A4643460A43C9 +:105970005A48920082587B409746200002F072FB02 +:10598000431F76309C4040420021BAE70321B8E72C +:10599000280002F067FB431F9D40002376304642FB +:1059A00099469B469DE70C239946093B9B4698E701 +:1059B00080240022E403FF20B9E70024C2468B467E +:1059C0005A465346022AAED0032A7DD0012A31D14D +:1059D000012200201A400024A9E70122101A1B28E6 +:1059E00056DD1A4000200024A1E78023DB031D427E +:1059F0004BD18023DB032B435C02640A3A00FF2077 +:105A000095E76D016001854230D2019A0024013A88 +:105A100001921B220127290064006D00002901DB8F +:105A2000A84201D82D1A3C43013A002AF3D16A1E3C +:105A300095412C4301987F300028CEDD620704D0C9 +:105A40000F222240042A00D00434220103D5244A24 +:105A5000019814408030FE2800DD64E70122A40193 +:105A6000640AC0B21A4062E72C00A9E72D1A1A2274 +:105A70000124CFE76B02BCD500248023DB031C4349 +:105A80006402640A4246FF2051E71C42B3D1F4E7A6 +:105A900021002022C140101A8440621E94410C4310 +:105AA000620704D00F222240042A00D0043462018D +:105AB00004D5012201201A40002438E70122A40164 +:105AC000640A1A40002032E78023DB031C4364028F +:105AD000640A5246FF202AE7783A0300B83A0300E6 +:105AE000FFFFFFF7430270B542004C005D0AC30F91 +:105AF0004802120E460A240EC90FFF2A0FD0FF2CAF +:105B000011D00120A24200D070BDB542FCD18B4221 +:105B10000DD0002AF8D12800431E9841F4E7012057 +:105B2000002DF1D1EBE70120002EEDD1E9E70020B7 +:105B3000EAE7C0464302F0B542005D0AC30F4802DF +:105B4000440A4800120E000EC90FFF2A1FD0FF287A +:105B500022D0002A09D16E426E4100280FD1002CBC +:105B60000DD10020002D09D005E0002801D1002C26 +:105B700001D08B4213D0584201231843F0BD002EB0 +:105B8000F7D048424141012049420843F6E7002D41 +:105B9000DDD002204042F1E7002CDAD0F9E7824262 +:105BA000E9DC04DBA542E6D80020A542E6D2584253 +:105BB000434101205B421843E0E7C0464302F0B591 +:105BC00042004C005E0AC30F4802120E450A240E22 +:105BD000C90FFF2A17D0FF2C19D0002A0BD1704211 +:105BE0007041002C17D0002807D0484241410120C5 +:105BF00049420843F0BD002C13D08B4214D05842C8 +:105C000001231843F6E70220002EF3D1E3E7022038 +:105C1000002DEFD1E1E7002DE5D10020002EE9D0E5 +:105C2000EDE7002DE9D1EAE7A242E8DC04DBAE4271 +:105C3000E5D80020AE42DDD25842434101205B420C +:105C40001843D7E7F0B557464E4645464300E0B403 +:105C500046028846760A1F0EC40F002F47D0FF2F3A +:105C600025D0002380259A469946F600ED042E4360 +:105C70007F3F434642465D02D20F5B006D0A1B0E1A +:105C8000904640D0FF2B39D080220020ED00D20476 +:105C900015437F3BFB1842465746591C62408C46D1 +:105CA00007430F2F5CD86F49BF00C9598F46002E9C +:105CB00045D108239A46063B9946DAE74246022830 +:105CC0002DD0032800D1C3E0012800D0A2E0002598 +:105CD00000260240D4B27602ED05760A2E43E40790 +:105CE000264330001CBC90469946A246F0BD002ECB +:105CF0001AD104239A46033B9946BAE72A00511E5B +:105D00008A41901CC6E70120002DC3D0280002F074 +:105D1000A9F9431F76309D4043420020BAE7012491 +:105D2000FF2514400026D6E7300002F09BF9431F00 +:105D30009E400023763047429A46994699E70C23C5 +:105D40009A46093B994694E780260024F603FF25EE +:105D5000C1E735004846B2E7350022004846AEE7C5 +:105D60002904090C0800370C3604360C2C0C794336 +:105D7000704367437443060C64183619B14203D963 +:105D800080214902884647440004000C3104091868 +:105D90008D01681E8541890E2943350CED19AD0131 +:105DA0000D43290104D5012369081D4063460D43B5 +:105DB00019007F31002925DD680704D00F20284015 +:105DC000042800D00435280103D5274980330D402D +:105DD0001900FE29A3DC0124AD016E0A1440CDB2E6 +:105DE00079E78020C003064207D0054205D1284349 +:105DF0004602760A4446FF256DE706437602760A98 +:105E0000FF2568E70124611A1B2905DD14400025E0 +:105E1000002660E76346CBE72E002023CE40591AC8 +:105E20008D406B1E9D412E43730704D00F233340DA +:105E3000042B00D00436730104D50124012514403D +:105E4000002648E70124B601760A1440002542E7FF +:105E500080260124F6032E437602760A1440FF259D +:105E600039E7C046F83A0300FFFFFFF7F8B54A02EA +:105E70004E0043024400240EC50F9B09360EC90F85 +:105E80009209FF2E00D183E001204140A01BA942CE +:105E90005CD0002800DC95E0002E1CD1002A00D048 +:105EA00081E05A0704D00F221A40042A00D004339C +:105EB0005A013BD50134FF2C00D191E001209B0118 +:105EC0005B0AE4B205405B02E4055B0AED0723438D +:105ED0002B431800F8BDFF2CE3D08021C9040A43EE +:105EE0001B2800DD90E016002021C640081A8240E1 +:105EF000511E8A4132439B1A5A0115D59B019E09B6 +:105F0000300002F0AFF80538864084426CDC041B98 +:105F1000330020200134E340041BA640721E96414A +:105F200000243343BDE70D005A07BCD1DF0801232D +:105F30001D40FF2C33D1002F00D190E08022D203EE +:105F400013003B435B025B0AFF24BCE700284FDDE4 +:105F5000002E2ED0FF2CA4D08025ED042A431B2830 +:105F600000DD97E016002025C640281A8240501E0A +:105F7000824132439B185A01D5D50134FF2C6DD094 +:105F800001227B481A405B08034013430D0088E759 +:105F9000002A00D07AE777E7031EC5D100257B02EF +:105FA0005B0AE4B28FE701380028A4D0FF2C97D118 +:105FB00077E7002A00D174E701380028DAD0FF2CF7 +:105FC000CDD16EE7002821D1601CC0B2012858DD78 +:105FD00080279E1AFF0437402FD0D61A0D008FE776 +:105FE00001231D4000236EE7624B241A334058E71B +:105FF000002851D1601CC6B2012E33DDFF282DD000 +:106000009B185B0804004CE7012274E7002C1AD0AF +:10601000FF2E1FD08024E404404223431B2800DDD0 +:1060200096E01D002024C540201A8340581E83415D +:106030002B43D31A34000D005EE7002E00D05FE73B +:1060400000250024ABE7002B44D0C0430028F0D04B +:10605000FF2EE3D11300FF240D0022E70D00FF24E3 +:10606000002330E7002C5DD1002B7DD0002A00D129 +:1060700017E79B185A0100D456E73E4A0400134024 +:106080000FE7002C1ED1002B2FD1002A65D0130062 +:106090000D0006E701226DE7002C1FD1002B59D01F +:1060A000C04300280BD0FF2E4FD01B285EDC1D0004 +:1060B0002024C540201A8340581E83412B439B183F +:1060C000340058E7002B1CD1002A49D013000D00E2 +:1060D000FF24E6E6130034000D00E2E6FF2E34D084 +:1060E0008024E40440422343DFE7002A00D1D8E6BD +:1060F0008027981AFF04074000D14DE7D31A0D00FE +:10610000CFE6FF24002A00D1CBE68020DB08C003C5 +:10611000034204D0D208024201D113000D00DB007B +:10612000FF24BEE6002B10D0FF24002A00D1B8E6E1 +:106130008020DB08C003034203D0D208024200D112 +:106140001300DB000D00FF24ABE61300FF24A8E6DC +:1061500001236EE713003400A3E6002700251EE7A5 +:1061600080270025FF03E9E613009AE60123A6E74E +:10617000FFFFFF7DFFFFFFFB4302590A4300C20FF1 +:106180001B0E00207E2B0EDD9D2B0DDC80200004DD +:106190000143952B0BDC9620C31AD9400B005842C3 +:1061A000002A00D118007047034BD018FBE7963B3C +:1061B00099400B00F3E7C046FFFFFF7F70B5002852 +:1061C00030D0C317C5185D40C40F280001F04AFF46 +:1061D0009E231B1A962B0DDC9622D21A95406A023A +:1061E000520AD8B25202C005520AE40702432243BF +:1061F000100070BD992B19DC9922D21A9540124AD1 +:106200002A40690704D00F210D40042D00D004322C +:10621000510103D50C4B1A409F231B1A9201520ABD +:10622000D8B2DFE7002400200022DBE705222E00A1 +:10623000121AB921D6402A00C91A8A40551EAA410D +:1062400035001543DBE7C046FFFFFFFB70B5041EBA +:1062500028D001F007FF9E231B1A962B0ADC9622FA +:10626000D21A94406202520AD8B25202520AC005AF +:10627000104370BD992B18DC9922D21A9440114A10 +:106280002240610704D00F210C40042C00D00432BE +:10629000510103D50B4B1A409F231B1A9201520A3E +:1062A000D8B2E2E700200022DFE705222500121A1B +:1062B000B921D5402200C91A8A40541EA2412C009F +:1062C0001443DCE7FFFFFFFBF8B556465F464D463B +:1062D0004446F0B40F00FD0FAA4609037C002E00CF +:1062E0005F00450F490A7F0D2943C5001803BC46CE +:1062F000400A570F640DDB0F3843D2009A4500D196 +:10630000AAE06646A61B002E00DCFFE06346002BD9 +:1063100039D10300134300D0D9E06B0709D00F2314 +:106320002B40042B05D02B1DAB42AD416D424919CA +:106330001D000B0200D482E0CA4B01349C4200D104 +:10634000FEE00A005646C84BED081A4050076405A7 +:1063500052020543120B640D002112030B0D1B05A5 +:106360006405120B1A436308C04CF60714401C4323 +:10637000640064083443280021003CBC90469946E0 +:10638000A246AB46F8BDB74B9C42C6D080231B0447 +:106390001843382E00DDEBE01F2E00DD1EE1202328 +:1063A0009B1B9C4603006746BB409846130047462C +:1063B000F3403B436746BA40571EBA4113430200BD +:1063C000F240EB1A9D42B6411D008A1A7642911B9B +:1063D0000B0231D54A02560A002E00D1B4E030003B +:1063E00001F040FE0300083B1F2B00DDB5E020223A +:1063F0002900D21AD1409E400A009D4032439C425F +:1064000000DDB1E01C1B631C1F2B00DDD5E020214B +:1064100014002800C91A8C40D8408D400443DA404B +:10642000681E854111002543002476E7414631432B +:1064300000D134E2310045466B0700D06FE7564685 +:106440004807ED08C9080543864B9C4235D00A032E +:106450006405120B640D7FE76346E31A9B46002B2D +:1064600000DC8BE06746002F3CD07E4FBC4200D161 +:1064700053E780273F0438435B46382B00DCF7E0C6 +:106480000243501E82410020D2B253194218AB423F +:1064900089411D00494289180B02CDD5714B013449 +:1064A0009C4200D13DE101206F4A6B080A40284020 +:1064B0001843D507054351082FE72B000B4300D1A4 +:1064C000CBE180231B030B431A03120B44E7013E6D +:1064D000002E6DD1AE1AB5429B41091A5B42C91A12 +:1064E000350075E70700174300D116E701235B422B +:1064F0009C46E3445B46002B00D0E0E0AA18AA4289 +:106500009B4109185B4259181500C5E7002E75D14B +:10651000661C7605760D012E00DCF3E0AE1AB0465F +:106520004545BF410E1A7F42F61B370200D48FE06B +:10653000551BAA42B641411A76428E1B9A464BE73A +:1065400056460022002507E7280001F08BFD203089 +:106550000300083B1F2B00DC49E72A002838824053 +:1065600000259C4200DC4DE73F49E41A1140D4E687 +:106570000243501E8241D3B2002222E7002B00D0FA +:10658000F3E0631C9C465B055B0D012B00DC9FE088 +:10659000344B9C4500D1C3E0AA180918AA42804197 +:1065A00040424118CD075208154349086446B4E6F5 +:1065B0002C4B9C4200D0ECE6AFE611001F3CE140C2 +:1065C0000C00202B00D17FE04021CB1A9A401543CC +:1065D0006A1E95410021254300242DE73300070062 +:1065E000203BDF403B00202E70D04027BE1BB04038 +:1065F0000243501E824113430022E2E6002C4FD09A +:10660000184CA44500D1ABE08024240476422143F9 +:10661000382E00DDDFE01F2E00DD43E12027BC1B0C +:10662000A1460C004F46BC40A0462C004746F44013 +:106630003C434F46BD406F1EBD41F1402C43151BEE +:10664000AA429241411A5242891A64469A46BFE6CA +:1066500041464546314300D0BEE6002600240025D1 +:10666000F2E6C046FF070000FFFF7FFFFFFF0F803D +:106670001F2B59DC2027FF1ABC46070063469F40AA +:106680005B46B9461700DF40B8464F4643461F43B6 +:1066900063469A40531E9A415B463A43D840F4E61B +:1066A0000C002C435CD0F643002E55D1551BAA425A +:1066B000A441411A6442091B9A46644688E6964FF3 +:1066C000BC4200D0D8E628E6002280E700208FE711 +:1066D0000B002B43002C00D0C2E0002B00D101E1C5 +:1066E0000300134300D118E6AB18AB42B6410918BA +:1066F000764271180A0200D409E1884A1D0011404F +:1067000064460AE6002C5BD10E002E4300D08AE0DE +:106710000100114300D1C2E0010015009A46FCE5DA +:106720006446002100258FE620235B429C46DC4422 +:1067300063460700DF405B46BC46202B00D1ACE03F +:1067400040235F46DB1B98400243501E8241634654 +:1067500013431A00002098E66F4CA44500D057E779 +:106760000100150064469A46D7E5002C39D10C008B +:106770002C436ED0DB43002B1AD0674CA44568D065 +:10678000382B00DDA4E01F2B00DDAEE020240F003D +:10679000E41AA740B9462F00DF40B846A3464F464B +:1067A000444627435C46A5406C1EA541D9403D4365 +:1067B000AD1895429B4109185B42591864466BE637 +:1067C0000C002C4315D1010011437BD001001500B2 +:1067D0009A46514CA1E50D43691E8D410021ECB252 +:1067E0002DE74D4CA44534D0802424045B42214342 +:1067F000C6E7040014434ED0ED084C072C43802517 +:10680000C9082D03294208D0C6082E4205D1D20856 +:10681000410711430C009A463100620FC900E500A0 +:1068200011433D4C79E50600164300D175E5AE1ADB +:10683000B0464545BF410E1A7F42F61B370200D4D1 +:10684000F4E5551BAA42B641411A7642891B9A4685 +:1068500063E50100150064465FE5002200257BE545 +:10686000002B3BD00300134315D0ED084B072B43FF +:106870008025C9082D03294207D0C4082C4204D121 +:1068800041070B002100D2081343C9005A0F1143DE +:10689000DD00214C41E5204C3FE5002054E7002677 +:1068A0000025D1E534000F00203CE7403C00202EBD +:1068B0002BD04027BE1BB1400D43691E8D410021E6 +:1068C0002C43BCE6802100260903134C0025BBE5C0 +:1068D0000D43691E8D410021EDB269E701001500ED +:1068E0000D4C1AE50100150017E51C000F00203CB7 +:1068F000E7403C00202B0CD04027FB1A99400D4369 +:10690000691E8D410021254352E70021D4E71D0077 +:1069100092E50021F3E7C046FF070000FFFF7FFF7D +:10692000F0B556464D4644465F46F0B41D000E0392 +:106930004C00CB0F87B0070092468146360B640DA2 +:1069400098466AD06D4B9C4235D08022430F12048A +:106950001343F6001E43C3009946694B00279C462B +:106960000023644402932B0368001B0BED0F514678 +:106970009B46400D009500D178E0604B98426CD06A +:106980005B46DA004B0F802109040B4313439B46FF +:106990005346D9005A4B9C46002360444246201A75 +:1069A0006A40924601901F430F2F00D9B0E055482E +:1069B000BF00C0598746374300D088E0002399467E +:1069C0000233082700260293CDE74346B3464946E3 +:1069D0000093029B009A9246022B00D0BFE1002157 +:1069E00053460122002689461A40444B00213603B3 +:1069F0000C0D2405360B2643434C1B0526401E4335 +:106A00007600D207760816434846310007B03CBCF2 +:106A100090469946A246AB46F0BD330003434FD0A3 +:106A2000002E00D1BCE1300001F01CFB03000B3B49 +:106A30001C2B00DDADE11D220100D31A08393A00FC +:106A40008F408E40DA40B9461643304B00279C46B3 +:106A5000002360444442029385E753465A46134359 +:106A60002CD1002300219B46023397E70B4320D013 +:106A70005B46002B00D19EE1584601F0F3FA03007B +:106A80000B3B1C2B00DD8FE102005946083A914078 +:106A90008B461D21CB1A5146D9400B0059460B435A +:106AA00051469B469140194B9C466044404200230E +:106AB00074E7002300219B4601336FE703236DE752 +:106AC0000023994601330427002602934BE7032352 +:106AD0000C27029347E70122D51A382D00DCB0E1DC +:106AE00053461A4000210023002689467EE70023F2 +:106AF0008026994600223603004B77E7FF07000007 +:106B000001FCFFFF383B0300FFFF0F80F303000091 +:106B10005E4500D972E100D16DE1019B4D46013B1C +:106B200001930023340002935B461E020B0E1E43AA +:106B30000B020393330C994633041B0C4946200087 +:106B40000093FEF7F5F9009B3700434306004946E2 +:106B500020009846FEF772FA2C0C09040C43A0455D +:106B600009D9E419731EA74200D95CE1A04500D8F9 +:106B700059E1023EE4194346E41A49462000FEF773 +:106B8000D7F90300009A80465343494620009B46AC +:106B9000FEF754FA2A040904120C0A4393450DD94E +:106BA0004346D219013B974200D93AE1934500D8B8 +:106BB00037E102235B429C46D219E0445B46D21A7D +:106BC0004346360433439B460399180C0B0C1D00B7 +:106BD000059309045B46090C0C001B041B0C444381 +:106BE000049159436B4368431B190D0CEB189C42ED +:106BF00003D980246402A44660441C0C09041B04CD +:106C0000090C20185D18824200D2DEE000D1D7E0E6 +:106C1000161A029B9C465D1BAC459B415B42F61AD3 +:106C2000B74200D106E149463000FEF781F9009BEA +:106C300004004343494630009846FEF7FFF92E0C06 +:106C400009040E43B04509D9F619631EB74200D9AD +:106C5000F3E0B04500D8F0E0023CF6194346F31AE1 +:106C6000494618000293FEF763F9009B0600434370 +:106C7000494602989846FEF7E1F92D0409042D0CC7 +:106C80000D43A84509D9ED19731EAF4200D9D6E0CE +:106C9000A84500D8D3E0023EED1924042100434664 +:106CA0003143049E059A3000ED1A0B040C0C1B0CAA +:106CB00058436643534354439A19030C9B189E420E +:106CC00003D980225202944664441A0C00041B0427 +:106CD000000C14191B18A54250D34DD001231943A1 +:106CE000964A019B94466344002B00DCF3E64A0776 +:106CF00009D00F220A40042A05D00A1D8A42894180 +:106D000049428B4411005A46D20108D55A468C4B51 +:106D10001A4093468022D2009446019B6344894ADC +:106D2000934200DD5BE65A46C90850070843560205 +:106D3000514601225B058146360B5B0D0A4055E644 +:106D400080231B031E4211D05A461A420ED15E46C2 +:106D50001E433603360B2A0089467B4B46E6032B3F +:106D600000D1E1E0012BBBD11A40BBE61E43360344 +:106D7000360B4246744B39E6002BB1D07D194A1EC2 +:106D8000AF4252D91100A542A8D1039A9A42A5D187 +:106D9000A6E703003E00283B9E400023994654E6A8 +:106DA00001F060F9203041E603005246283B9A404A +:106DB0000021934677E6504601F054F920305EE614 +:106DC000029B0026AB4200D323E7039E0299B44600 +:106DD00061448846B045B6415B467642F619B21822 +:106DE000013B0291974213D290424FD800D18EE0DE +:106DF000161A9B460DE7894500D28EE674084B466D +:106E0000F60735005B081D434B46DB0702938BE614 +:106E10009742EDD10399029CA142E5D93E1A9B46C7 +:106E2000F7E69846CAE61E00A5E6AC423ED874D006 +:106E3000110053E70121494252E71C000EE71E00F2 +:106E40002BE71F2D3CDC20230A0058465B1B984093 +:106E5000EA4099400243481E81415E461143EE409C +:106E60004B0709D00F230B40042B05D00B00191D35 +:106E700099429B415B42F61833023CD553460122AE +:106E800000211A40002601238946AFE502235B4218 +:106E90009C46039CE344A446029B63449846A04559 +:106EA000B6417642F6190293B218B1E603988A1EEB +:106EB00041008142B6417642F619AD19039161E76E +:106EC0001F225242D31A5A46DA401300202D29D0ED +:106ED00040225846551BA8400143481E81410720C7 +:106EE0000B4318400026002809D00F2200261A4024 +:106EF0001900042ABBD10B0070077602360BDB08A1 +:106F000003439946012253461A4000236EE5029935 +:106F10008D42BBD89B4600267BE603989842C5D39A +:106F2000110032E70020D7E780265B4636031E4378 +:106F30003603360B009A8946034B57E5FF030000E2 +:106F4000FFFFFFFEFE070000FF070000F0B55F46F1 +:106F500056464D464446F0B41F035C00DB0F9A468C +:106F6000194B0E034D00C90F8046360B6D0D8B4635 +:106F700091463F0B640D9D4219D0134B9C421BD090 +:106F80000123A54206D018003CBC90469946A24673 +:106F9000AB46F0BDBE42F6D1C845F4D1D34510D0C2 +:106FA000002DF0D1304303005A1E9341EBE731002E +:106FB00001230143E7D1E0E73A430123002AE2D16C +:106FC000DEE70023DFE7C046FF070000F0B55F46BD +:106FD000444656464D46F0B41F033C0B2C4F0E035F +:106FE0004D00A3465C008446360B6D0DC90F9046DC +:106FF000640DDB0FBD422BD0254FBC422ED0002D9F +:107000000ED130430700814678427841002C17D1D9 +:107010005F463A4314D14B460020002B0AD006E0CD +:10702000002C02D15846024301D099421AD00123C4 +:10703000484218433CBC90469946A246AB46F0BD38 +:107040000028F2D058425841012240421043F1E753 +:1070500037000743D0D002204042EBE75F4617439A +:10706000CDD0F8E7A542E2DC05DB5E45DFD808D0ED +:1070700000205E45DED24842484101234042184389 +:10708000D8E7C445D3D80020C445F4D3D2E7C046DE +:10709000FF070000F0B55F464D4644465646F0B443 +:1070A0001C03240BA4462F4C0F034D005E00C90F98 +:1070B00080463F0B6D0D8B469146760DDB0FA5424A +:1070C00020D0284CA64222D0002D12D13843444271 +:1070D0004441002E20D0002C0DD05C42634101249D +:1070E0005B421C4320003CBC90469946A246AB46FE +:1070F000F0BD002E17D05B4519D05B465C420123E2 +:107100001C43EFE7390002240143EBD1D9E7614684 +:1071100002241143E6D1D7E761460A43DBD10024BC +:107120000028DFD0E9E761460A43E4D1E5E7B5424C +:1071300003DD01225C421443D4E7B542CDDB674551 +:10714000DBD809D000246745CCD259464C42614176 +:10715000012449420C43C5E7C845CED80024C845A0 +:10716000F3D3BFE7FF070000F0B55F4656464D4634 +:107170004446F0B40D0399464E002B0B87B0070030 +:10718000924680469B46760DCC0F002E69D06D4B03 +:107190009E4235D05B468022DD001204430F13432C +:1071A0002B439B46C3009846674B00279C46002311 +:1071B000664401934A4615035000D20F53462D0BE7 +:1071C000400D914600D176E05E4A90426CD080221C +:1071D0005B0F120413435C4AED0094461D43534673 +:1071E0000022DB00604449463618701C6140029062 +:1071F00017430F2F00D9AFE05448BF00C759BF460F +:107200005B461F4300D088E000239B46984602332C +:1072100008270193CEE74946022A6AD0032A00D103 +:1072200009E2012A00D0BBE1114000220023002521 +:107230009046CCB200212D030A0D12052D0B1543EB +:10724000434A1B0515401D436D00E4076D082543A7 +:107250004046290007B03CBC90469946A246AB4642 +:10726000F0BD034352D05B46002B00D18AE1584663 +:1072700000F0F8FE03000B3B1C2B00DD7BE11D2220 +:10728000D31A3A0001005D46DA4008398D401300F8 +:107290008F402B439B46B8462E4B00279C4600232D +:1072A00060444642019385E752462A432CD100258B +:1072B0000023022297E752462A4321D0002D00D115 +:1072C00054E1280000F0CEFE03000B3B1C2B00DD38 +:1072D00046E11D21CB1A51460200D9405346083AD7 +:1072E000954093400D431B4A94466044404200221F +:1072F00079E7012400220C40124B0025904699E7C3 +:107300000025002301226EE703226CE700239B4641 +:1073100098460133042701934CE703230C2701937C +:1073200048E700238025984600242D03054B81E77C +:107330005D464346019A6FE75D4643462100019A48 +:107340006AE7C046FF07000001FCFFFF783B03002F +:10735000FFFF0F80F30300004246120C91461A0C07 +:107360009446424617044A461B041B0C5A43604687 +:1073700090464A4642431000039262461C003F0C6E +:107380007A437C4342440192220C9246019A524431 +:10739000904506D98246802040028046C24450462D +:1073A0000390100C049048462404240C1204121973 +:1073B00005922A0C2D042D0C68432C008246484669 +:1073C0007C4350438146200C8046574357444744F2 +:1073D000BA4503D9802040028046C144380C3F049E +:1073E000B84648442404240C01900498A044404426 +:1073F00004905846000C814658460404200C8246EE +:10740000070048465F434C4643436046604364463A +:10741000834650464443380C8446E4186444A342EF +:1074200003D980235B029C46E34448463F04230C77 +:107430003F0C2404E419574668436F4384464D4685 +:10744000504655434243380C814662444A445B44AB +:10745000944503D9802040028446654403983F0444 +:10746000834604983F0C8446E344C3458041404230 +:107470008246100484460198674484466744A344C6 +:10748000BC46A345A4419946D44464428742BF41C7 +:10749000D4458041E144A04699459B417F4240420A +:1074A000C8440743120CBA18A045A4415F423B00F0 +:1074B00064422343D71843467D19DB0D6D021D43FB +:1074C0005B465A02059B1A43531E9A415B46DB0DED +:1074D0001A4343465B021343EA0107D501225C08C5 +:1074E00013402343EA07029E13436D08574AB2181C +:1074F000002A4BDD580709D00F201840042805D07A +:10750000181D98429B415B42ED180300E80104D529 +:107510004F4A15408022D200B2184E48824200DD08 +:10752000E7E60124DB08680718436D02530580462F +:107530002D0B5B0D0C407DE6802259461203114253 +:1075400008D0154206D115432D0398462D0B4C4605 +:10755000414B6FE65D4615432D032D0B3E4B69E60F +:1075600003005546283B9D400023BCE6504600F0F2 +:1075700079FD2030A8E60300283B9F400023BB464E +:10758000984689E600F06EFD203073E60124A61AC5 +:10759000382E07DD00220C4000230025904649E6E6 +:1075A000029EA3E71F2E20DC20222C001800921B35 +:1075B000F040944093400443581E83411C43F540DF +:1075C000630709D00F232340042B05D023001C1D83 +:1075D0009C4292415242AD182B021FD50124002239 +:1075E0000C4001230025904624E61F202C00404239 +:1075F000821AD440202E1CD04022961BB5402B432B +:10760000581E83410720234318400025002809D035 +:107610000F2200251A401C00042AD8D12300680735 +:107620006D022D0B0124DB08034398460C40002318 +:1076300000E60025E3E780220124120315432D0311 +:1076400098462D0B0C40044BF4E5C046FF030000A8 +:10765000FFFFFFFEFE070000FF070000F0B55746E2 +:107660004E464546E0B40E001100F20F9246C500AA +:10767000420F180337037400400A4E0F7F0A30434D +:10768000CF4E17435A00640D520DDB0FC900B242B2 +:1076900000D1E5E001267340A61AB446534500D157 +:1076A000AFE0002E00DC0DE1002A3AD103000B43CD +:1076B00000D0E4E06B0709D00F232B40042B05D04A +:1076C0002B1DAB42AD416D427F191D003B0200D422 +:1076D00088E0BB4B01349C4200D110E13A00B94B29 +:1076E00051461A4001235007ED0852026405054334 +:1076F000120B640D0B400021280012030D0D120B1C +:1077000064052D0515436208AF4CDB072C4014437C +:10771000640064081C4321001CBC90469946A246A4 +:10772000F0BDA74B9C42C5D080231B041843634681 +:10773000382B00DDFDE01F2B00DD30E16246202309 +:107740009B1A02009A40664690460A009940F24011 +:1077500046464B1E99413243114363460200DA40CC +:10776000691A8D429B410D00BA1A5B42D71A3B023F +:1077700035D57A02530A98464346002B00D1C4E01F +:10778000404600F06FFC0300083B1F2B00DDC5E006 +:1077900020222900D21A4746D1409F400A009D402E +:1077A0003A439C4200DDC0E01C1B631C1F2B00DD24 +:1077B000E4E0202114002800C91AD8408C408D40F4 +:1077C0000443DA40681E854117002543002471E711 +:1077D000424663461A4300D14CE2674645466B0772 +:1077E00000D069E7012351467807ED08FA080B40FD +:1077F000054373498C4238D012036405120B640DA3 +:1078000079E7002E00DC9AE0002A47D06C4A9442C7 +:1078100000D14FE78022120410436246382A00DC70 +:1078200008E10143481E81410022C9B24919D21919 +:10783000A942BF410D007F42BF183A0200D442E185 +:107840005F4A0134944200D14EE101205D4A69084B +:107850003A4028400843D507054357089A4629E788 +:1078600006000E4300D017E714E72900114300D1AA +:10787000F9E1802109030A431203120B3BE70123BC +:107880005B429846C4446346002B72D1691A8D420C +:107890009B413F1A5B42FF1A0D0068E702000A4352 +:1078A00000D107E7012252429046C4446246002AB2 +:1078B00000D0E6E06918A942B6413F187642F719B0 +:1078C0000D00BAE7002E00D080E0621C5205520D78 +:1078D000012A00DCF9E06A1A91464D45B6413A1A90 +:1078E0007642921B9046120200D499E04D1BA942A9 +:1078F0008941C71B49427A1A90469A463CE752464C +:107900000123002513400022F5E6280000F0AAFB21 +:1079100020300300083B1F2B00DC39E72A00283801 +:10792000824000259C4200DC3EE7264FE41A1740C7 +:10793000C0E60143481E81410022C9B210E7002E73 +:1079400000D0F1E0621C94465205520D012A00DC81 +:10795000A0E01B4A944500D1C5E06918A9429241B4 +:107960003F185242D2194908D5070D4357086446BB +:10797000A0E6134B9C4200D0D9E69BE611001F3CC9 +:10798000E1400C00202B00D180E04021CB1A9A402E +:1079900015436A1E95410027254300241FE76346CF +:1079A0000200203BDA406346202B71D0402366461C +:1079B0009B1B98400143481E814111430022CFE6A2 +:1079C000FF070000FFFF7FFFFFFF0F80002C48D064 +:1079D000CA4CA24200D1A2E07442A14680242404F1 +:1079E00027434C46382C00DDDBE01F2C00DD44E152 +:1079F0004E462024A41B3E00A640A246B0464C465C +:107A00002E00E640B4464646644626435446A5400A +:107A10006C1EA54134002C434D46EF400D1B28E061 +:107A20004A4643464D461A4300D0A5E600230024AB +:107A30000025DEE61F2A5ADC66462022921B06003D +:107A400096409146B04662460E00D64042461643E6 +:107A50004A4691404A1E9141020060463143C2406D +:107A6000E4E63C002C435AD0F443A146002C52D10A +:107A70004D1BA9428941C71B49427F1A14009A46EF +:107A800075E69E4A944200D0C7E613E600227FE7DF +:107A900000208FE7002C00D0C8E03B002B4300D132 +:107AA0000FE103000B4300D104E66918A9429B4192 +:107AB0003F185B42DF193B0200D41AE1904B0D00E6 +:107AC0001F406446F6E59A4689E63A002A43002CB0 +:107AD0005CD1002A75D102000A4300D1CAE0070038 +:107AE0000D009A46E6E564460022002581E66246DE +:107AF0000600203AD6406246B046202A00D1B7E0C0 +:107B000040226646921B904001434246481E8141F6 +:107B1000114300228AE6794CA24200D061E70700B7 +:107B20000D0014009A46C5E5002C41D13C002C43C1 +:107B300078D0F443A146002C20D0704CA24271D0E2 +:107B40004C46382C00DDB2E01F2C00DDBCE02026C6 +:107B5000341BA2463C005646B4404E46A0462C007C +:107B6000F440A446444666463443A4465446A540E1 +:107B700064466E1EB54125434C46E7406D188D4264 +:107B800089413F184942CF19140056E6002A2FD1E7 +:107B900002000A4300D184E007000D009A46574CCA +:107BA00088E53D436F1EBD41ECB200270D1B60E729 +:107BB000524CA24236D0744280263604A146374346 +:107BC000BEE702000A4300D174E56A1A90464545B3 +:107BD000B6413A1A7642921B9446120200D4F7E557 +:107BE0004D1BA9428941C71B49427F1A9A4661E54C +:107BF00002000A433AD0ED087C072C438025FA089E +:107C00002D032A4208D0C7082F4205D145072C0072 +:107C10003A009A46C9080C43670FD200E5001743A3 +:107C2000364C47E507000D00140043E53A002A43AF +:107C300043D002000A4319D0ED087C072C4380256D +:107C4000FA082D032A4207D0C6082E4204D147075E +:107C50003C003200C9080C43D700620FE50017430F +:107C60009A46264C26E50022002544E5234C21E5D2 +:107C7000002049E700230025BBE54C463E00203CA0 +:107C8000E6404C46B446202C31D040244E46A61B3C +:107C9000B7403D436C1EA54164462C4300270D1B95 +:107CA000E7E6802200231203144C0025A1E53D43A2 +:107CB0006F1EBD410027EDB260E707000D000F4CBD +:107CC000F8E407000D00F5E44E463C00203EF44089 +:107CD000A0464C46202C0ED040244E46A41BA74064 +:107CE0003D436F1EBD4144460027254346E700271C +:107CF000CFE70D0073E50027F2E7C046FF0700005D +:107D0000FFFF7FFF70B50E4E0C031D0349005B00A3 +:107D1000240B490D2D0B5B0DB14204D00849002006 +:107D20008B4208D070BD04430120002CFAD10449D5 +:107D300000208B42F6D115432800451EA841F1E7EB +:107D4000FF0700000B0330B5134D1A0B4B005B0D02 +:107D5000C90F0024AB4211DD104CA34210DC80247B +:107D6000640322430E4CE41A1F2C0CDD0D48C31A89 +:107D7000DA4013005C42002900D11C00200030BD15 +:107D8000094BCC18FAE7E040084CA44663449A40FB +:107D900013000343EEE7C046FE0300001D0400008D +:107DA0003304000013040000FFFFFF7FEDFBFFFF23 +:107DB00070B5002830D0C317C4185C40C50F200030 +:107DC00000F050F9174B184A1B1AD21A1F2A18DD57 +:107DD000164AD21A9440002224035B05240B5B0D43 +:107DE0000021100024030A0D1205240B1443104A2D +:107DF0001B0514401C436400ED0764082C4321005C +:107E000070BD210091400A000B21081AC4405B0597 +:107E10002403240B5B0DE3E700250023002400224C +:107E2000DEE7C0461E040000330400001304000017 +:107E3000FFFF0F8070B5051E28D000F013F9154B19 +:107E4000154A1B1AD21A1F2A16DD2C00134A0025C8 +:107E5000D21A94405A052403240B520D0021240306 +:107E60000B0D240B1B0523430D4C1205234013431C +:107E70005B002800590870BD0B212C00081AC44073 +:107E8000954024035A05240B520DE7E700220024F5 +:107E9000E4E7C0461E0400003304000013040000A1 +:107EA000FFFF0F804200120E511C4302C9B270B591 +:107EB0005D0AC40F012915DDE02189008C466D079C +:107EC0001B0B6244002128000D0D2D052B431C4D7A +:107ED00052052B40520813435B00E4075B08234321 +:107EE000190070BD002A15D1002D1FD0280000F008 +:107EF000B9F80A281DDC0B232A001B1ADA401300EC +:107F00000200153295400F4A1B03121A52051B0B33 +:107F1000520DD7E7002D06D080221B0B120313430E +:107F20006D07094ACEE7084A0023CBE70022002369 +:107F3000C8E703000B3B9D402B000025E3E7C0464C +:107F4000FFFF0F8089030000FF0700004B0070B5A2 +:107F50005E0D0C03751C640A420F6D052243C90FA8 +:107F6000C4006D0D012D2ADD3B4BF318FE2B1ADCEE +:107F7000002B42DD8001451EA841D2001043620F54 +:107F80000243500704D00F201040042800D00432D0 +:107F90008020C004104021D00133FF2B03D0920178 +:107FA000520ADBB201E0FF2300225202520ADB0533 +:107FB00013435B00C9075B080B43180070BD002E1C +:107FC00007D01443EFD08020D20080040243FF2367 +:107FD000D7E722430023002A03D00522D208FF2B33 +:107FE00003D05202520ADBB2DFE7002A32D08020EF +:107FF000C00302435202520AD7E71800173014DBBD +:108000008020000402431E20C01A1F280FDC250018 +:10801000124BF3189D406E1EB5419A402B0013433E +:108020002200C2401A430023ABE70023D5E7022514 +:108030006D42EB1A1500DD40202809D0084BF318DB +:108040009A401443621E9441220000232A4398E779 +:108050000022F6E70022A8E780FCFFFF82FCFFFF7A +:10806000A2FCFFFF1C2101231B04984201D3000C3A +:1080700010391B0A984201D3000A08391B0998429B +:1080800001D30009043902A2105C40187047C046B1 +:1080900004030202010101010000000000000000D1 +:1080A00010B5002903D1FFF7DDFF203002E0081CE6 +:1080B000FFF7D8FF10BDC046F0B54746494A4B0010 +:1080C00080B406000F0088465B0893424BDC464AAA +:1080D00093420FDC454A464BFEF7F6F8454B00222B +:1080E000FDF7C6F83B00002854D03000190004BC4E +:1080F0009046F0BD404A93423CDC8022D205934238 +:1081000048DD00F0F9FA320004000D003B003000B9 +:108110003900FFF729F80022364BFEF7D5F803F0B7 +:10812000EBF902000B0020002900FEF7CDF8020059 +:108130000B0000202F49FEF7F3FB220006000F0082 +:108140002B0020002900FEF7BFF802000B003000D2 +:108150003900FEF7B9F802F063FC43460600002B35 +:1081600014DD0B00C1E70B000200FEF7ADF80600BE +:108170000B00BAE700F0C0FA02F052FC1F4B204A95 +:10818000FEF7A2F843460600002BEADC80231B061C +:10819000CB18AAE732003B0030003900FEF7E4FFBD +:1081A00004000D003000390000F0A6FA002206009D +:1081B0000F00104B20002900FEF786F803F09CF911 +:1081C00000220C4BFEF780F802000B002000290073 +:1081D000FEF7A6FB32003B00FEF776F800F028FB26 +:1081E000BBE7C046FFFFEF7FFFFF2F3E9C75008877 +:1081F0003CE4377E0000F03F0000B041422EE63FF5 +:10820000EF39FAFEF8B556464D4644465F46A54B53 +:10821000F0B44E00804689468A4676089E420CDDC0 +:10822000A14B9E4200DDA0E000D19BE05346002B15 +:1082300000DCE3E09D4B9E4A9FE09E4B9E4200DDAA +:10824000B1E09D4B9E4200DC9FE001235B429B46D8 +:1082500042464B4640464946FEF786FF02000B0069 +:1082600006000F00FEF780FF04000D00934A944BB8 +:10827000FEF77AFF934A944BFEF726F822002B0074 +:10828000FEF772FF914A924BFEF71EF822002B0078 +:10829000FEF76AFF8F4A904BFEF716F822002B007C +:1082A000FEF762FF8D4A8E4BFEF70EF822002B0080 +:1082B000FEF75AFF8B4A8C4BFEF706F832003B0064 +:1082C000FEF752FF894A8A4B06000F002000290062 +:1082D000FEF74AFF874A884BFFF7C0F922002B00C0 +:1082E000FEF742FF854A864BFFF7B8F922002B00C4 +:1082F000FEF73AFF834A844BFFF7B0F922002B00C8 +:10830000FEF732FF814A824BFFF7A8F922002B00CB +:10831000FEF72AFF0B0059460200013100D170E040 +:1083200059463000CC003900FDF7CEFF42464B469F +:10833000FEF71AFF774D784B2D191C1922686368D8 +:10834000FFF78CF942464B46FFF788F902000B0015 +:1083500028686968FFF782F953460A00002B48DB5A +:1083600003000AE0002800D160E742464B46404641 +:108370004946FDF7A9FF03000A00180011003CBCA4 +:1083800090469946A246AB46F8BD644A644BFDF759 +:108390009BFF0022634BFCF76BFF002800D154E7E2 +:1083A00043464A46E9E700F0A7F95F4B04000D0099 +:1083B0009E4237DC5D4B9E425DDC02000B00FDF708 +:1083C00083FF0022574BFFF749F9802306000F0077 +:1083D0000022DB0520002900FDF776FF0B000200DC +:1083E00039003000FEF79CFA0023804689469B4600 +:1083F0002EE78022120603008A18BEE72B4B4C4A58 +:10840000BBE730003900FDF75FFF42464B46FEF701 +:10841000ABFE02000B0040464946FFF71FF9030080 +:108420000A00AAE7434B9E421ADC0022424BFFF7A8 +:1084300015F9002206000F003F4B20002900FEF72F +:1084400093FE0022374BFDF73FFF0B00020039007F +:108450003000FEF765FA0223804689469B46F7E620 +:108460000B00020035490020FEF75AFA032380462C +:1084700089469B46ECE600222A4BFFF7EFF80022E4 +:1084800006000F00274B20002900FDF71DFF0B0001 +:10849000020039003000FEF743FA01238046894686 +:1084A0009B46D5E6FFFF0F440000F07F182D445493 +:1084B000FB21F93FFFFFDB3FFFFF1F3E11DA22E305 +:1084C0003AAD903FEB0D76244B7BA93F513DD0A0B8 +:1084D000660DB13F6E204CC5CD45B73FFF8300927E +:1084E0002449C23F0D5555555555D53F2F6C6A2C23 +:1084F00044B4A2BF9AFDDE522DDEAD3F6D9A74AF3B +:10850000F2B0B33F711623FEC671BC3FC4EB98991D +:108510009999C93F882D0300682D03009C75008838 +:108520003CE4377E0000F03FFFFFF23FFFFFE53FF6 +:10853000FB21F9BFFF7F03400000F83F0000F0BFC0 +:10854000444AF8B5564692464B005B0D9A44444661 +:108550005F464D465246F0B4884605000C000E00BA +:108560000700132A27DC002A59DB52463A4B1341F5 +:1085700099460B004A461340034316D0374A384BFE +:10858000FDF7A2FE00220023FCF772FE00280AD0AD +:10859000002C04DD802352465B0313419844464679 +:1085A0004B4600279E43380031003CBC904699461C +:1085B000A246AB46F8BD5246332A08DD8023DB00D5 +:1085C0009A45F2D102000B00FDF77EFEEDE7254A49 +:1085D0009446012263445242DA4093460242E4D078 +:1085E0001E4A1F4BFDF770FE00220023FCF740FEE1 +:1085F0000028D8D0002C0CDD5346142B26D0342371 +:10860000524601279B1A9F407F19AF429B415B4214 +:1086100098445B4646469F4338003100C5E70F4A01 +:108620000F4BFDF751FE00220023FCF721FE00282E +:10863000B9D0002C06DB2C4300270026002CB2D03A +:10864000094EB0E7802600273606ACE7133B9C4670 +:10865000E044DEE701FCFFFFFFFF0F009C75008890 +:108660003CE4377EEDFBFFFF0000F03F30B5204AD1 +:108670004B0087B05B0893421CDD1E4A934205DD28 +:1086800002000B00FEF7EAFF07B030BD02AA02F0BD +:108690005DFC03231840049A059B012818D002288A +:1086A0000DD000281ED0029803990124009403F0F5 +:1086B0007FFDE9E70022002303F014F8E4E70298C5 +:1086C000039903F00FF880231B069C466144DBE707 +:1086D00000900298039903F06BFD80231B069C46D3 +:1086E0006144D1E70298039902F0FCFFCCE7C04651 +:1086F000FB21E93FFFFFEF7F49004B08190070475E +:10870000454AF8B5564692464B005B0D9A444D4695 +:108710005F4644465246F0B4894605000C000E0000 +:108720000700132A22DC002A47DB52463B4B134149 +:1087300098460B0042461340034311D0384A394B48 +:10874000FDF7C2FD00220023FCF792FD002805D0B2 +:10875000002C41DB4E46434600279E433800310043 +:108760003CBC90469946A246AB46F8BD5246332AD9 +:1087700008DD8023DB009A45F2D102000B00FDF7F3 +:10878000A3FDEDE7284A9446012263445242DA40B1 +:1087900093460242E4D0224A224BFDF795FD002287 +:1087A0000023FCF765FD0028D8D0002C1ADB5B46BF +:1087B0004E469F4338003100D2E7194A194BFDF766 +:1087C00083FD00220023FCF753FD0028C6D0002CB7 +:1087D00016DB00270026C1E7802352465B031341C6 +:1087E0009944B7E75346142B12D03423524601273D +:1087F0009B1A9F407F19AF429B415B429944D6E749 +:108800006400640825430027002DA7D0074EA5E784 +:10881000133B9C46E144CAE701FCFFFFFFFF0F004A +:108820009C7500883CE4377EEDFBFFFF0000F0BF45 +:10883000F0B54F464646C0B4CA4A8BB004000D009E +:108840000B1E934212DCC84A4E00760896421BDD8E +:108850000022C64BFCF7F2FC002800D181E0002288 +:1088600000230020C249FEF75BF808E0C14A9142AC +:1088700036DD22002B0020002900FDF725FD0BB07E +:108880000CBC90469946F0BDBB4A964274DDBB4A8B +:1088900094466344934200D98FE00022B84B2000F5 +:1088A0002900FDF711FDB74A0B15914699444B4637 +:1088B00080460F000E00002B00DCD7E122002B00C9 +:1088C000FEF7CCFE02000B000020AD49FEF7C6FE0D +:1088D00042463B00FEF724F84446029003910BE029 +:1088E000A94A9342D9DDA74A1E0091461B15994417 +:1088F000002200230292039333031B0B9846A34BE1 +:10890000984500DDEDE042469D4B20001A431100E2 +:1089100000229B4BFEF7A2FE04000D0000229C4BA0 +:1089200006000F00FEF720FC22002B00FEF71CFCC7 +:108930000B00020004920593009201934346002B22 +:1089400049D10022002320002900FCF777FC0028F1 +:1089500000D1D5E04B46002B00D06BE10020002178 +:108960008DE722002B0020002900FEF777FE020091 +:108970000B00FDF7D5FF82E70022864BFDF7A4FC34 +:1089800000220023FCF774FC002805D0824B200055 +:1089900029009E4200DC72E722002B002000290003 +:1089A000FEF7E2FB00227A4BFEF7DEFB02000B0033 +:1089B00020002900FEF752FE61E70022744BFEF70B +:1089C000D3FB2B002200FEF7CFFB002326002F0055 +:1089D00099460090019180230022DB053000390088 +:1089E000FDF772FC02000B0030003900FDF798FF24 +:1089F00002000B0004900591FEF7B6FB04000D0089 +:108A0000664A674BFEF7B0FB664A674BFDF75CFCB6 +:108A100022002B00FEF7A8FB644A654BFDF754FCCF +:108A200022002B00FEF7A0FB624A634BFDF74CFCD3 +:108A300022002B00FEF798FB604A614BFDF744FCD7 +:108A400022002B00FEF790FB5E4A5F4BFDF73CFCDB +:108A500022002B00FEF788FB5C4A5D4BFDF734FCDF +:108A60002B002200FEF780FB4B4604000D00002B7C +:108A700062D04846FFF79CF9564A574B069007913B +:108A8000FEF772FB009A019B0890099120002900D3 +:108A9000FDF71AFC049A059BFEF766FB4F4A04009B +:108AA0000D00069807994E4BFEF75EFB029A039B5A +:108AB000FDF70AFC02000B0020002900FDF704FC72 +:108AC00002000B0000980199FEF7C8FD32003B0040 +:108AD000FEF7C4FD02000B0008980999FEF7BEFDE1 +:108AE000CDE6012342469C46294BE1441A438023AC +:108AF000110042465B039B1A9B102000984607E733 +:108B0000384A334B20002900FEF72EFB02000B00F1 +:108B100000201B49FEF7A2FD049A059BFEF724FBEB +:108B20004B4606000F00002B5ED102000B00200018 +:108B30002900FEF793FDA2E6009A019BFDF7C4FB16 +:108B4000049A059BFEF710FB02000B0000980199A8 +:108B5000FEF784FD02000B0030003900FEF77EFDB9 +:108B60008DE6C0467982DA3FFFFFEF3F0000F0BF9D +:108B7000000050C3FFFFEF7FFFFF1F3E3C412D4031 +:108B80000000F03F01FCFFFFFFFF3F439DA00600F8 +:108B90000000E03F00005043FFFF8F3C44523EDFA7 +:108BA00012F1C23F9FC678D0099AC33FDE03CB962D +:108BB0006446C73FAF788E1DC571CC3F5993229450 +:108BC0002449D23F04FA97999999D93F935555551D +:108BD0005555E53F0000E0FE422EE63F763C7935F4 +:108BE000EF39EA3D555555554846FFF7E1F8254A16 +:108BF000254B00900191FEF7B7FA244A04900591A5 +:108C000000980199224BFEF7AFFA029A039BFDF7F9 +:108C10005BFB02000B0030003900FEF71FFD220055 +:108C20002B00FEF71BFD02000B0004980599FEF7D0 +:108C300015FD24E64846FFF7BBF8144A144B040020 +:108C40000D00FEF791FA029A039BFDF73DFB0D4ADA +:108C500006000F000C4B20002900FEF785FA0200E9 +:108C60000B0030003900FDF72FFB08E60022094B0E +:108C7000FEF7F4FC02000B0020002900FEF7EEFCDA +:108C800026E6C0460000E0FE422EE63F763C7935FF +:108C9000EF39EA3D0000F03F10B500F0F1FB024A69 +:108CA000024BFDF73DFE10BDEF39FAFE422EE63FC6 +:108CB00030B5214A4B0087B05B0893421EDD1F4A46 +:108CC000934205DD02000B00FEF7C8FC07B030BD83 +:108CD00002AA02F03BF903231840049A059B0128DD +:108CE0001ED0022811D000281FD00298039902F04C +:108CF000F9FC80231B069C466144E7E70023002221 +:108D00000093002303F054FAE0E70124029803994A +:108D1000009403F04DFA80231B069C466144D5E77E +:108D20000298039902F0DEFCD0E70124029803992F +:108D3000009403F03DFAC9E7FB21E93FFFFFEF7F15 +:108D400030B5134A4B0087B05B08934218DD114AD7 +:108D5000934205DD02000B00FEF780FC07B030BD3A +:108D600002AA02F0F3F8049A059B02214000084091 +:108D70000139081A00900298039903F0C9FAEDE747 +:108D8000012300220093002303F0C2FAE6E7C04665 +:108D9000FB21E93FFFFFEF7F384AF8B54B000500A4 +:108DA0000C000E005B0893420EDD02000B00002059 +:108DB0003349002C36DBFDF7B3FD314B0022FDF7C4 +:108DC00083FA03001800F8BD2E4A934209DD002003 +:108DD0002B490300002EF5DA8022120694466144E6 +:108DE000F0E7294A934225DD284A93422CDDFFF71C +:108DF00083FC02000B00FDF767FA03F04FFC8023B1 +:108E00000022DB05FDF760FA0B0080210200C90596 +:108E10000020FDF785FD02000B0000201849FEF739 +:108E20001DFCD6E7FDF77CFD154B0022FEF716FC76 +:108E30000300C7E70022124BFDF746FA23002A0081 +:108E4000FEF792F90300BDE7FFF756FCC0230022AE +:108E50001B06FEF789F903F021FC80231B06CF18BF +:108E600080230022DB050400FDF72EFA02000B0030 +:108E700020003900FDF754FDABE7C046FFFFEF7F50 +:108E80000000F03FFFFF3540FFFF7F3CFFFFEF3F5B +:108E90004B00134A5B0D9A1870B5132A0ADCCB0FEE +:108EA000DB07002A19DB0F48002410418143200012 +:108EB000194370BD332A08DD8023DB009A42F8D1C4 +:108EC00002000B00FDF700FAF3E7074A944601227F +:108ED00063445242DA409043EBE700201900E8E790 +:108EE00001FCFFFFFFFF0F00EDFBFFFFF0B5474662 +:108EF00080B48CB004000D0000F0A4FC244B0600EC +:108F000098461B780F005BB2013305D02000290082 +:108F100003F006FE002805D1300039000CB004BC77 +:108F20009046F0BD20002900FFF7E6FB0022194B18 +:108F3000FCF79EF90028EFD001230293164B174847 +:108F400003930023069407950A930494059503F070 +:108F500017FE43461B78089009915BB2022B0BD099 +:108F600002A803F00BFE002806D00A9B0193002BF9 +:108F700007D1089E099FCFE703F086FE21230360F7 +:108F8000F3E703F081FE0A9B01930360F1E7C0461B +:108F90009A2000200000F03FB83B0300E83B0300AC +:108FA000F0B5474680B48CB004000D0000F040FEE0 +:108FB000244B060098461B780F005BB201330DD09E +:108FC0002000290003F0ACFD002807D000221E4B32 +:108FD00020002900FCF738F9002805D130003900BD +:108FE0000CB004BC9046F0BD01230293174B002245 +:108FF000039300230A930023100019000694079599 +:1090000004940595FDF78CFC43461B780890099164 +:109010005BB2022B0BD002A803F0B0FD002806D0F3 +:109020000A9B0193002B07D1089E099FD6E703F006 +:109030002BFE21230360F3E703F026FE0A9B019336 +:109040000360F1E79A2000200000F03FC03B0300DE +:10905000F0B5474680B48CB004000D0000F070FEFF +:10906000244B060098461B780F005BB2013305D0F5 +:109070002000290003F054FD002805D130003900FC +:109080000CB004BC9046F0BD20002900FFF734FB73 +:109090000022194BFCF7ECF80028EFD001230293D3 +:1090A000164B174803930023069407950A930494DC +:1090B000059503F065FD43461B78089009915BB266 +:1090C000022B0BD002A803F059FD002806D00A9B02 +:1090D0000193002B07D1089E099FCFE703F0D4FD31 +:1090E00021230360F3E703F0CFFD0A9B01930360A4 +:1090F000F1E7C0469A2000200000F03FC83B030083 +:10910000E83B030010B501F001F810BDF0B547468B +:1091100080B48CB004000D0001F0B4F8314B0600AF +:1091200098461B780F005BB2013305D02000290060 +:1091300003F0F6FC002805D1300039000CB004BC67 +:109140009046F0BD20002900FFF7D6FA0022264BFA +:1091500000900191FCF796F80028EDD00098019955 +:109160000022214BFCF784F802AE00282BD001230B +:1091700002931E4B00227360002333620023100011 +:10918000190034617561B460F560FDF7C9FB4346B1 +:109190001B78B061F1615BB2022B0AD0300003F0A2 +:1091A000EDFC002805D0336A002B07D1F769B669BA +:1091B000C2E703F069FD21230360F4E703F064FDD7 +:1091C000336A0360F2E702230293084B3062736054 +:1091D00034617561B460F56000220023200029002D +:1091E000D3E7C0469A2000200000F03FD03B0300A8 +:1091F000F0B5474680B48CB004000D0001F0CAF809 +:10920000264B060098461B780F005BB2013305D051 +:109210002000290003F084FC002805D1300039002B +:109220000CB004BC9046F0BD20002900FFF764FAA2 +:109230001B4A1C4BFCF71CF80028EFD003230293B9 +:10924000194B06940795039300230A9343461B7812 +:1092500004940595002B10D1E022144B12060892BD +:10926000099302A803F08AFC00280CD00A9B019302 +:10927000002B0DD1089E099FD0E700200C490890D3 +:109280000991022BEDD103F0FFFC22230360EDE7EF +:1092900003F0FAFC0A9B01930360EBE79A2000209D +:1092A0007DF8B98FCE338640D83B0300FFFFEF47F0 +:1092B0000000F07FF0B546464F46C0B48BB00400C6 +:1092C0000D0001F011F9344B060098461B780F0091 +:1092D0005BB2013338D02000290003F017FC0028CE +:1092E00032D02E4A2E4B20002900FBF7C1FF8146C9 +:1092F000002830D12B4A2C4B20002900FBF7A4FF7B +:10930000002821D004230093284B002201934B46D0 +:10931000089300230692079343461B786E465BB280 +:109320000494059502940395022B2FD0300003F08E +:1093300025FC00282AD0336A002B03D003F0A4FCBC +:10934000336A0360F769B669300039000BB00CBCB2 +:1093500090469946F0BD03230093144B6E4601934B +:109360000023089343461B780494059502940395C3 +:10937000002B05D1E0220E4B120606920793D5E78B +:1093800000200C4906900791022BCFD103F07CFC02 +:1093900022230360CFE7C0469A200020EF39FAFE6F +:1093A000422E864051302DD5104987C0E03B030046 +:1093B000FFFFEF470000F07FF0B5474680B48CB068 +:1093C0001D0006000F00140001F000FA2A4B009067 +:1093D000019198461B785BB2013305D0200029002B +:1093E00003F09EFB002805D1009801990CB004BC45 +:1093F0009046F0BD3000390003F092FB0028F3D016 +:109400000022002320002900FBF718FF0028EBD0E2 +:1094100001230293194B06940795039300230A93A3 +:1094200043461C7804960597002C16D00022002392 +:1094300010001900FDF774FA08900991022C0ED162 +:1094400003F022FC212303600A9B0093002B0CD124 +:10945000089B099C00930194C6E70896099702A807 +:1094600003F08CFB0028EFD1EAE703F00DFC0A9B28 +:1094700000930360ECE7C0469A200020E43B030021 +:10948000F0B5474680B48CB004000D0001F0C8FA76 +:109490000F00002106003B4B3200595698463B0016 +:1094A000013111D02000290003F03AFB32003B00CB +:1094B000002809D00022002320002900FBF7D8FE55 +:1094C00032003B00002805D0100019000CB004BC8D +:1094D0009046F0BD2C4B0A90039343461E780494AB +:1094E000059506940795002E18D1E022274B120609 +:1094F000089209932000002200232900FBF79EFE1A +:1095000000282BD00223029302A803F037FB002887 +:109510001DD103F0B9FB2223036018E000221C4B8D +:10952000200008920993290000220023FBF786FE01 +:1095300000281BD101230293022E11D103F0A4FBBA +:1095400021230360134803F01BFB089009910A9B39 +:109550000193002B0FD1089A099BB5E701230293D1 +:1095600002A803F00BFB0028ECD1E7E702230293EB +:10957000022ECED0C8E703F087FB0A9B019303605D +:10958000E9E7C0469A200020EC3B0300FFFFEFC74D +:109590000000F0FFE83B0300F0B5474680B48CB014 +:1095A00004000D0001F03EFC394B060098461B7884 +:1095B0000F005BB201330DD02000290003F0B0FA98 +:1095C000002807D00022002320002900FBF746FED8 +:1095D000002805D1300039000CB004BC9046F0BD25 +:1095E0002C4B04940595039300230A9343461E785D +:1095F00006940795002E18D1E022274B12060892F8 +:1096000009932000002200232900FBF717FE002801 +:109610002BD00223029302A803F0B0FA00281DD138 +:1096200003F032FB2223036018E000221B4B2000D2 +:1096300008920993290000220023FBF7FFFD002870 +:109640001BD101230293022E11D103F01DFB212314 +:109650000360134803F094FA089009910A9B019360 +:10966000002B0FD1089E099FB4E70123029302A8A3 +:1096700003F084FA0028ECD1E7E702230293022EDC +:10968000CED0C8E703F000FB0A9B01930360E9E733 +:109690009A200020F03B0300FFFFEFC70000F0FF1F +:1096A000E83B0300F0B546464F46C0B48DB0060017 +:1096B0000F0001F051FE2F4B040098461B780D005F +:1096C0005BB2013307D003F021FA81464B462000FC +:1096D0002900002B04D00DB00CBC90469946F0BD7B +:1096E0003900300003F012FA290003002000002B9B +:1096F000F1D003230293204B0696079703934B4622 +:109700000A9343461C7804960597002200233000F4 +:109710003900002C14D1FBF7ABFDE0221206002823 +:1097200023D0164B0892099302A803F027FA0028C9 +:1097300010D00A9B0193002B11D108980999CAE710 +:10974000FBF796FD0022002811D00D4B08920993DB +:10975000022CE9D103F098FA22230360E9E703F031 +:1097600093FA0A9B01930360E7E7064BDAE7064B9F +:10977000ECE7C0469A200020F83B0300FFFFEF47CC +:109780000000F07FFFFFEFC70000F0FFF0B5474695 +:1097900080B48CB004000D0001F0AEFE274B060033 +:1097A00098461B780F005BB201330DD020002900D2 +:1097B00003F0B6F9002807D000220023200029007A +:1097C000FBF742FD002805D1300039000CB004BC85 +:1097D0009046F0BD01230293194B0694079503931D +:1097E00000230A934346049405951C78002C0FD15E +:1097F000002300240893099402A803F0BFF900286D +:1098000010D00A9B0193002B11D1089E099FDBE722 +:109810000022002310001900FDF782F8089009913A +:10982000022CE9D103F030FA21230360E9E703F0C9 +:109830002BFA0A9B01930360E7E7C0469A200020B9 +:10984000003C0300F0B5DB4A4B0085B007000E007A +:109850005B0893420CDDD84A94466344034300D02E +:10986000ACE0002900DC25E10020002105B0F0BDBE +:10987000D24A934200DC9BE0002900DA1DE102009D +:109880000B000020CE49FDF7E9FE0022CD4BFDF78D +:109890006BFC04000D0001F02FFECB4A0F0000907E +:1098A0000191CA4B20002900FDF75EFCC84AC94B54 +:1098B000FCF70AFD22002B00FDF756FCC64AC74BF9 +:1098C000FDF7CCFE22002B00FDF74EFCC44AC54B31 +:1098D000FCF7FAFC22002B00FDF746FCC24AC34B02 +:1098E000FDF7BCFE22002B00FDF73EFCC04AC14B39 +:1098F000FCF7EAFC22002B00FDF736FCBE4A029082 +:109900000391BE4B20002900FDF72EFCBC4ABD4B45 +:10991000FDF7A4FE22002B00FDF726FCBA4ABB4B44 +:10992000FCF7D2FC22002B00FDF71EFCB84AB94B15 +:10993000FDF794FE22002B00FDF716FC0022A04B41 +:10994000FCF7C2FC02000B0002980399FCF7E8FF49 +:10995000009A019BFDF708FC00260290039132005B +:109960003B0030003900FDF7FFFB02000B00200038 +:109970002900FDF773FE320004000D0000980199E4 +:109980003B00FCF7A1FC02000B0020002900FCF7C3 +:10999000C7FF02000B0002980399FCF795FC320008 +:1099A0003B00FCF791FC02000B00FCF78DFC5DE72F +:1099B000994A93420BDC9948994957E702000B00FA +:1099C000FDF74CFE02000B00FCF7AAFF4EE7020079 +:1099D0000B00FDF7C9FB04000D007B4A7B4BFDF734 +:1099E000C3FB7B4A7B4BFCF76FFC22002B00FDF78F +:1099F000BBFB794A794BFDF731FE22002B00FDF7C6 +:109A0000B3FB774A774BFCF75FFC22002B00FDF796 +:109A1000ABFB754A754BFDF721FE22002B00FDF7CD +:109A2000A3FB734A734BFCF74FFC22002B00FDF79E +:109A30009BFB714A00900191704B20002900FDF7BB +:109A400093FB6F4A6F4BFDF709FE22002B00FDF7D9 +:109A50008BFB6D4A6D4BFCF737FC22002B00FDF7AA +:109A600083FB6B4A6B4BFDF7F9FD22002B00FDF7E2 +:109A70007BFB0022524BFCF727FC02000B000098F6 +:109A80000199FCF74DFF3A003300FDF76DFB020032 +:109A90000B0064486449FDF7E1FD02000B0038004B +:109AA0003100FDF7DBFD02000B005C485C49FDF76F +:109AB000D5FDDBE659485D49D8E60022404BFCF76E +:109AC00003FC00223F4BFDF74FFB04000D003E4A14 +:109AD0003E4BFDF749FB3E4A3E4BFCF7F5FB2200AF +:109AE0002B00FDF741FB3C4A3C4BFDF7B7FD220044 +:109AF0002B00FDF739FB3A4A3A4BFCF7E5FB220015 +:109B00002B00FDF731FB384A384BFDF7A7FD22004B +:109B10002B00FDF729FB364A364BFCF7D5FB22001C +:109B20002B00FDF721FB009001912000290001F09E +:109B3000E3FC314A06000F00304B20002900FDF7FE +:109B400013FB2F4A2F4BFDF789FD22002B00FDF759 +:109B50000BFB2D4A2D4BFCF7B7FB22002B00FDF72A +:109B600003FB2B4A2B4BFDF779FD22002B00FDF761 +:109B7000FBFA0022124BFCF7A7FB02000B00009837 +:109B80000199FCF7CDFE32003B00FDF7EDFA254AC6 +:109B9000254BFDF763FD32003B00FCF795FB02000F +:109BA0000B00FCF791FB02000B001C481F49FDF75E +:109BB00055FD5BE6FFFFEF3F000010C0FFFFDF3FFA +:109BC0000000F03F0000E03F09F7FD0DE13D023FDE +:109BD00088B20175E0EF493F3B8F68B52882A43F0A +:109BE0005544880E55C1C93F7D6FEB0312D6D43F53 +:109BF000555555555555C53F82922EB1C5B8B33F01 +:109C000059018D1B6C06E63FC88A599CE52A004025 +:109C10004B2D8A1C273A03400000603C182D445409 +:109C2000FB21F93F075C143326A6913CFB21094038 +:109C3000F0B53C4A83B005000C1E944236DD3A4A2A +:109C4000914208DD394A91423CDD02000B00FCF7ED +:109C50003BFB03B0F0BD364A8A1802432FD0802266 +:109C6000D205914235DC0022324BFDF7F7FC0200B1 +:109C70000B0004000D00FCF727FB220006000F007C +:109C80002B0020002900FDF76FFA02000B003000C6 +:109C90003900FCF719FB01F02FFC02000B0020003B +:109CA0002900FCF711FBFEF7C3FDD2E702000B0011 +:109CB000FDF7D4FC02000B00FCF732FEC9E70020E0 +:109CC0000021C6E700F0ACFE1B4A1C4BFCF7FCFA77 +:109CD000BFE702000B00FDF747FA0022154BFDF726 +:109CE000BDFC01F009FC2A0006000F00230028003B +:109CF0002100FCF7E9FA3200009001913B002800B6 +:109D00002100FCF7E1FA02000B0000200949FCF7F2 +:109D100007FE02000B0000980199FDF79FFC00F080 +:109D20007FFE96E7FFFFEF3FFFFFAF41FFFFEF7FB3 +:109D3000000010C00000F03FEF39FAFE422EE63F6F +:109D4000F0B557464E464B005B089A46C0B4CD4B23 +:109D500087B006000F0089469A4512DDCA4B53446E +:109D6000034322D002000B00FDF778FC0B00020039 +:109D7000FCF7D6FD0300180007B00CBC91469A46CC +:109D8000F0BDC24B9A4524DCC14B9A4500DD0CE185 +:109D9000C04AC14BFCF798FA0022C04BFBF768FAA7 +:109DA000002816D033003900E5E7BD4ABD4BFDF76A +:109DB000DBF9BD4A04000D00BC4B30003900FDF753 +:109DC000D3F90B00020029002000FCF77DFA030004 +:109DD000D1E730003900FEF78FFC02000B000020B5 +:109DE000AE49FDF73BFC0022B14BFDF7BDF9040085 +:109DF0000D00B04AB04BFDF7B7F9B04AB04BFCF7D5 +:109E000063FA22002B00FDF7AFF9AE4AAE4BFDF727 +:109E100025FC22002B00FDF7A7F9AC4AAC4BFCF760 +:109E200053FA22002B00FDF79FF9AA4AAA4BFDF72F +:109E300015FC22002B00FDF797F9A84AA84BFCF768 +:109E400043FA22002B00FDF78FF9A64A02900391F6 +:109E5000A54B20002900FDF787F9A44AA44BFDF784 +:109E6000FDFB22002B00FDF77FF9A24AA24BFCF775 +:109E70002BFA22002B00FDF777F9A04AA04BFDF743 +:109E8000EDFB22002B00FDF76FF9844B0022FCF75D +:109E90001BFA049005912000290001F02DFB994B3D +:109EA00006000F009A4563DC0B000298039900221C +:109EB00000920193049A059BFCF732FD3200029058 +:109EC00003913B0030003900FCF7FEF902000B0063 +:109ED00002980399FDF748F90290039100980199BF +:109EE00002000B00FDF740F902000B0020002900E2 +:109EF000FDF7B4FB009A019B04000D00300039000F +:109F0000FCF7E2F902000B0020002900FCF708FD35 +:109F100002000B00FCF7D8F902000B00624863490D +:109F2000FDF79CFB02000B0002980399FDF796FBDE +:109F300004000D000098019902000B00FCF7C4F921 +:109F400002000B0056487049FDF788FB02000B0029 +:109F500020002900FDF782FB02000B0050486A49EF +:109F6000FDF77CFB4B46002B00DC84E0030002E79E +:109F7000049A059B02980399FCF7D2FC32003B003F +:109F8000FDF7F2F832003B00FCF79EF902000B00EF +:109F9000FCF79AF9444A454BFDF760FB02000B00C1 +:109FA0003F484049FDF75AFBDCE702000B00FDF794 +:109FB000DBF804000D003F4A3F4BFDF7D5F83F4A60 +:109FC0003F4BFCF781F922002B00FDF7CDF83D4A0D +:109FD0003D4BFDF743FB22002B00FDF7C5F83B4A44 +:109FE0003B4BFCF771F922002B00FDF7BDF8394A15 +:109FF000394BFDF733FB22002B00FDF7B5F8374A4C +:10A00000374BFCF761F922002B00FDF7ADF8354A1C +:10A0100000900191344B20002900FDF7A5F8334A48 +:10A02000334BFDF71BFB22002B00FDF79DF8314A57 +:10A03000314BFCF749F922002B00FDF795F82F4A28 +:10A040002F4BFDF70BFB22002B00FDF78DF80022B4 +:10A05000124BFCF739F902000B0000980199FCF74C +:10A060005FFC32003B00FDF77FF83B003200FCF75D +:10A070002BF903007FE68022120694460300614418 +:10A0800079E6C046FFFFEF3F000010C0FFFFDF3F53 +:10A09000FFFF3F3E9C7500883CE4377E0000F03FA8 +:10A0A000182D4454FB21F93F075C143326A6913C3C +:10A0B0000000E03F09F7FD0DE13D023F88B2017568 +:10A0C000E0EF493F3B8F68B52882A43F5544880E96 +:10A0D00055C1C93F7D6FEB0312D6D43F5555555539 +:10A0E0005555C53F82922EB1C5B8B33F59018D1B5E +:10A0F0006C06E63FC88A599CE52A00404B2D8A1C15 +:10A10000273A03403233EF3FFB21E93FF8B5150012 +:10A110004F4646465A001C006B42C0B42B434B4F7F +:10A120005208DB0F88461343BB423AD84B005B080A +:10A1300099464E4643420343DB0F3343BB4230D87C +:10A14000434BE3182B4343D00226A3171E40CB0FEB +:10A150001E434B4603432ED013002B4332D0BA424A +:10A1600041D0B9452ED04B469A1A12153C2A32DC02 +:10A17000002C55DB2A002300FCF7D2FBFEF7BCFACB +:10A18000FEF740F8012E46D0022E39D0002E0ED018 +:10A19000304A314BFDF762FA304A314BFDF75EFA37 +:10A1A00005E002000B0028002100FCF78DF80CBC34 +:10A1B00090469946F8BD022E10D0032EF7D12748BD +:10A1C0002849F4E743462548002B0ADB2649EEE7F9 +:10A1D000FEF718F8EBE721482349D3E71F48204949 +:10A1E000E5E72249E3E791451FD0022EF6D0032E82 +:10A1F000E5D000200021012ED9D180210906D6E723 +:10A20000144A154BFDF72AFA02000B0013481449B3 +:10A21000FDF724FACBE7802424060B191900C6E7C2 +:10A220003C32A7DA00200021ACE7022E06D0032E34 +:10A2300009D00A48012E04D00D49B8E70D480E494F +:10A24000B5E70E49B3E70B480D49B0E70000F07FD2 +:10A25000000010C0075C143326A6A13C182D4454FE +:10A26000FB210940FB2109C0FB21F93FFB21F9BF7C +:10A27000FB21E93FD221337F7CD90240FB21E9BF9A +:10A280007CD902C0F0B5474680B443424E00034338 +:10A290003A4A7608DB0F82B004000D0007008846BA +:10A2A0003343934214D8964242D0354B9E4219DC38 +:10A2B000344A354BFCF708F800220023FAF7D8FFA0 +:10A2C000290000283AD0380002B004BC9046F0BD06 +:10A2D00002000B00FDF7C2F902000B00FCF720FBA7 +:10A2E0000700F0E7294B351E9D4228DD33000200B0 +:10A2F0003100FBF7E9FF220006000F002B000020D1 +:10A300001E49FDF7ABF902000B0030003900FCF7E5 +:10A3100007FBFEF78DFA1E4B0022FCF725FF434694 +:10A320000700002BCFDA80231B069C466144CAE756 +:10A3300000220023FCF7F4FA0700C4E735002200EE +:10A340002B0020002900FBF7BFFF22002B00060096 +:10A350000F00FCF709FF2200009001912B00002064 +:10A360000649FDF77BF902000B0000980199FCF704 +:10A37000D7FA32003B00FBF7A7FFCAE70000F03F27 +:10A38000FFFF2F3E9C7500883CE4377EFFFFDF3FD8 +:10A390000000E03FF0B54B005E08474B83B09E42A3 +:10A3A00018DC464B9E421FDD454B9E425EDD454B11 +:10A3B0009E4200DC75E0444B9E4242DD434B9E4290 +:10A3C0003CD0434A434B10001900FCF7CDFE04007B +:10A3D0000D0005E002000B00FCF7C6FE04000D00B6 +:10A3E0002000290003B0F0BDFEF786F902F056F90F +:10A3F000394B002200900191FBF766FF374B0400B8 +:10A400000D009E42ECDD009A019B10001900FCF744 +:10A41000ABFE22002B0006000F0020002900FBF7F6 +:10A4200053FF02000B0030003900FCF779FA0022DC +:10A43000294BFBF749FF04000D00D1E7284B984258 +:10A44000BFD8FEF759F90022264BFCF78DFE00F02D +:10A450004BF804000D000022224BFCF785FE220081 +:10A460002B00FCF781FE04000D00B9E7FEF744F96C +:10A4700000F03AF800221B4B04000D00FCF774FEBC +:10A4800022002B0006000F0000201649FCF748FAB6 +:10A4900002000B0030003900FBF716FF04000D002E +:10A4A0009EE7FEF729F900F01FF800220D4BFCF79C +:10A4B0005BFE04000D0093E7FFFFEF7F422ED63FC7 +:10A4C000FFFF3540412E8640CD338640CE33864057 +:10A4D0009C7500883CE4377E0000F03FFFFF7F3C26 +:10A4E0007DF8B98F0000E03FF0B5574680B44B00CF +:10A4F0000E00CC0F954984B007005B088B420ED943 +:10A5000093498B4200D884E03203120B024300D0FF +:10A51000F7E03100002C78D00020002175E08D4A52 +:10A52000934200D9B6E08C4A934200D8CAE0002397 +:10A530009A463A00330038003100FCF715FE04005B +:10A540000D00864A864BFCF70FFE864A864BFDF7C8 +:10A5500085F822002B00FCF707FE844A844BFBF7AA +:10A56000B3FE22002B00FCF7FFFD824A824BFDF771 +:10A5700075F822002B00FCF7F7FD804A804BFBF7B3 +:10A58000A3FE22002B00FCF7EFFD02000B003800B9 +:10A590003100FDF763F8534604000D000200002B64 +:10A5A00000D1B4E00B0038003100FCF7DDFD0F00F6 +:10A5B0008021060022002B000020C905FDF74EF87F +:10A5C00002000B0030003900FCF7AAF902000B0072 +:10A5D00002980399FDF742F8009A019BFDF73EF8B7 +:10A5E0000B00020067490020FDF738F8664B9A45DA +:10A5F00000DB7AE0FA24A40054442405631819000F +:10A60000B82300225B04FCF7AFFD04B004BC924603 +:10A61000F0BD5E4A5E4B3100FAF72AFE002869D190 +:10A620005C4A5D4B38003100FAF70EFE002800D07E +:10A6300072E75A4BE4001C19594A5A4B3800310052 +:10A64000FCF792FD22686368FBF73EFEFDF77AFB9C +:10A650008246FDF7ADFB544A544B04000D00FCF755 +:10A6600083FD02000B0038003100FCF7F7FF504A71 +:10A67000009001914F4B20002900FCF775FD0290DE +:10A680000391029A039B00980199FCF7E7FF0700EA +:10A690000E004EE7484A9342CBD8484BE5005B1981 +:10A6A0001A685B683100FCF7D9FF454B00900191B7 +:10A6B0005D192A686B680292039301231B1B1B1B05 +:10A6C0009A46DEE73F4A404B3100FBF7FDFD002292 +:10A6D0002C4BFAF7CDFD002800D128E70022294BAA +:10A6E00038003100FBF7F0FD8FE75446240563186E +:10A6F00019008AE7334A344B10001900FCF734FD87 +:10A7000083E7020033003100FBF7DEFD7DE70B003D +:10A7100038003100FCF728FD8023009001910022D1 +:10A72000DB0520002900FCF799FF02000B000098D0 +:10A730000199FCF7F5F83A003300FCF78FFF0200AF +:10A740000B0000200F49FCF789FF5EE7412E864091 +:10A75000FFFFEF7F422ED63FFFFF2F3ED0A4BE72F9 +:10A760006937663EF16BD2C541BDBB3E2CDE25AFDD +:10A770006A56113F93BDBE166CC1663F3E55555596 +:10A780005555C53F0000F03F03FCFFFFEF39FAFECF +:10A79000422E864051302DD5104987C0A82D030088 +:10A7A000FE822B654715F73F0000E0FE422EE63F94 +:10A7B000763C7935EF39EA3DB1A2F03FC82D030070 +:10A7C000B82D03009C7500883CE4377EF8B55646EA +:10A7D00044465F464D4698465B005B08F0B41E0059 +:10A7E0008246040015001700164326D0CE0FF60748 +:10A7F000B3464E40B146804EB1451EDC564216432C +:10A80000F60F1E43B4467D4EB44516D8994504DC78 +:10A8100084461ADB904218D35FD0794989451BDC06 +:10A820004946002900D0AAE056467649002E18DD98 +:10A8300001397600002EFBDC13E04346FCF794FC64 +:10A8400002000B00FCF76CF8844660463CBC904666 +:10A850009946A246AB46F8BD6B4E4946B44609152B +:10A860006144674EB3420ADC002B00D09EE0654E87 +:10A87000002D07DD013E6D00002DFBDC02E0624E85 +:10A880001D15AE19614DA94267DB484605038020BE +:10A890002D0B400305435D4886424FDB4346802233 +:10A8A0001B031B0B52031343881BEA1A00281DD0FD +:10A8B000BC4289414942521A09D41100E41B214388 +:10A8C0000BD0E50F5200551964000138EDE7E10F98 +:10A8D0006A00551864000138E7E75B46DE0F4C4B11 +:10A8E000F6009E19336871689C46AEE7BC429B41F6 +:10A8F0005B42D21A6CD4E41B13002343EDD0404BCF +:10A9000018009A4206DCE10F53005A186400013E19 +:10A910008242F8DD3D498E424FDA891B142959DC09 +:10A92000202023001400401ACB4084401C43130015 +:10A930000B415A461A431100A44686E7801B844601 +:10A940001F282DDC20273F1A1000F8400700604622 +:10A95000834082403B431700A6E76C1AA4461F2C95 +:10A9600018DC20252D1B0400EC404D46A246644611 +:10A97000A540544625436446A04004008BE7494661 +:10A98000CE022249002E00DC6BE701397600002E52 +:10A99000FBDC66E71F4C641AA040002405007AE740 +:10A9A0001C4B00279B1B9A4013007DE7174EDD02CE +:10A9B000013E6D00002DFBDC64E7174BA446D31865 +:10A9C0005A461343154AB5182D052B4319003CE789 +:10A9D0002A0091E71F2908DC23002020CB40411AE0 +:10A9E0008A4014001C435B46A3E70A4B9B1B1A4199 +:10A9F0005B4614009DE7C046FFFFEF7F0000F07F3D +:10AA0000FFFF0F00EDFBFFFF01FCFFFF02FCFFFF5C +:10AA1000D82D0300E2FBFFFF0000F0FFFF03000062 +:10AA2000F0B557464E464546E0B4DA4A88B00B1EAC +:10AA3000934255DC4A005208024300D1EFE000295E +:10AA400000DA79E1D44B0022FCF78EFB3625D34C9B +:10AA50000B006D42A34247DC1A151B031B0B9846E3 +:10AA6000CF4C8023A446CF4C5B0344442340CE4CC0 +:10AA7000624452195C4045461B1599462543CA4B12 +:10AA8000290091440022FCF7E9FD434602331B03F1 +:10AA900006000F001B0B0022022B2FDC0023FAF70D +:10AAA000CDFB002800D1C1E04B46002B00D14CE18A +:10AAB0004846FDF77DF9BD4ABD4B04000D00FCF78B +:10AAC00053FBBC4A06000F00BB4B20002900FCF7DB +:10AAD0004BFB02000B0030003900FBF7F5FB07E0F1 +:10AAE000AE4C0025A342B7DD02000B00FBF7ECFBE8 +:10AAF00008B01CBC90469946A246F0BD8023DB05F9 +:10AB0000FBF7E2FB02000B0030003900FBF708FF07 +:10AB1000040048460D00FDF74BF922000290039116 +:10AB20002B002000290004940595FCF71DFB040070 +:10AB30000D00A24B020043449A460B00009401957D +:10AB4000FCF712FB04000D009D4A9E4BFCF70CFB2A +:10AB50009D4A9E4BFBF7B8FB22002B00FCF704FB41 +:10AB60009B4A9C4BFBF7B0FB22002B00FCF7FCFA46 +:10AB7000994A9A4BFBF7A8FB009A019BFCF7F4FA61 +:10AB8000974A00900191974B20002900FCF7ECFABE +:10AB9000954A964BFBF798FB22002B00FCF7E4FA52 +:10ABA000934A944BFBF790FB22002B00FCF7DCFA56 +:10ABB0000B00020000980199FBF786FB0D0041464F +:10ABC0008D4B04005B1A51460B43002B54DD0022D1 +:10ABD0008A4B30003900FCF7C7FA32003B00FCF723 +:10ABE000C3FA4B460A00010000910192002B72D17A +:10ABF0001300290002002000FBF766FB049A059B66 +:10AC0000FCF7B2FA02000B0000980199FCF726FD50 +:10AC100002000B0030003900FCF720FD68E700223D +:10AC2000002300207649FBF77BFE61E7754A764BEF +:10AC300030003900FCF798FA02000B0000206F4941 +:10AC4000FCF70CFD320004000D003B003000390021 +:10AC5000FCF78AFA0B00020029002000FCF784FAB6 +:10AC60004B4604000D00002B72D102000B00300097 +:10AC70003900FCF7F3FC3BE74B46002B00D1C5E065 +:10AC800002980399494A4A4BFCF76EFA2200009059 +:10AC900001912B0030003900FCF7E0FC049A059B81 +:10ACA000FCF762FA434A04000D0002980399424BF4 +:10ACB000FCF75AFA02000B0020002900FCF7CEFC3A +:10ACC00032003B00FCF7CAFC02000B00009801991F +:10ACD000FCF7C4FC0CE7354A354B02980399FCF7A6 +:10ACE00043FA009A019B0690079120002900FBF788 +:10ACF000EBFA049A059BFCF737FA2E4A04000D0084 +:10AD0000029803992C4BFCF72FFA02000B0020004D +:10AD10002900FBF7D9FA02000B0000980199FCF713 +:10AD20009DFC32003B00FCF799FC02000B000698EA +:10AD30000799FCF793FCDBE602000B00FCF78EFCA6 +:10AD400000220023FBF7ECFDD2E600200021CFE635 +:10AD50004846FDF72DF8154A154B00900191FCF778 +:10AD600003FA144A0290039100980199124BFCF7E0 +:10AD7000FBF902000B0020002900FCF76FFC3200F9 +:10AD80003B00FCF76BFC02000B0002980399FCF7F8 +:10AD900065FCADE6FFFF0F0000005043FFFFEF7FB3 +:10ADA00001FCFFFF645F09000000F03F0000E0FECF +:10ADB000422EE63F763C7935EF39EA3D86EBF9FFE6 +:10ADC00044523EDF12F1C23FDE03CB966446C73FDA +:10ADD000599322942449D23F935555555555E53FF3 +:10ADE0009FC678D0099AC33FAF788E1DC571CC3FFE +:10ADF00004FA97999999D93F51B806000000E03FAD +:10AE0000000050C3555555555555D53F22002B00D0 +:10AE100030003900FCF722FC049A059BFCF7A4F9EA +:10AE2000F6E6C046F0B54F464646C0B43B4A83B04E +:10AE300004000D000B1E93421CDC4A005208024322 +:10AE40005BD0002960DB0022354BFCF78DF9362200 +:10AE50000D000B003349040052428B420EDD2200EC +:10AE60002B0020002900FBF72FFA03B00CBC904602 +:10AE70009946F0BD2B4900228B42F0DC2A49181577 +:10AE80008C4660448218D10F89461B034A441B0B31 +:10AE900010009846FCF78CFF4A46244B06009B1A8C +:10AEA00042461B051A430F0020001100FFF7B8FDB2 +:10AEB0001F4A04000D001F4B30003900FCF754F905 +:10AEC0001D4A009001911D4B20002900FCF74CF910 +:10AED00002000B0000980199FBF7F6F9184A0400EC +:10AEE0000D00184B30003900FCF73EF902000B0052 +:10AEF00020002900FBF7E8F9B7E700220023002033 +:10AF00001149FBF70DFDB0E702000B00FCF7A6FBB3 +:10AF100000220023FBF704FDA7E7C046FFFF0F0058 +:10AF200000005043FFFFEF7F01FCFFFFFF03000025 +:10AF3000362BF111F3FE593D0EE526157BCBDB3F99 +:10AF400000609F501344D33F000050C3F0B54E46FD +:10AF500057464546E0B4DC4B4E0090B0170089469A +:10AF600076089E4200DC81E0D84B9E4220DCD84A25 +:10AF7000002900DC89E1D74BFCF770FBD54B0400BE +:10AF80000D009E4200D18AE0D34AD44BFCF766FB09 +:10AF900002000B0020003A607B602900FCF75EFB9A +:10AFA000CD4ACE4BFCF75AFBB860F960012066E051 +:10AFB000CB4B9E4200DC8DE0CA4B9E4265DCCA4909 +:10AFC00032158A46924453461B05F51A290004009F +:10AFD000FCF7B8FEFCF7ECFE02000B002000290095 +:10AFE0000A920B93FCF73AFB0022C04BFCF7BCF82B +:10AFF00002900391FCF7A6FEFCF7DAFE04000D00B8 +:10B0000002000B00029803990C940D95FCF726FBA7 +:10B010000022B64BFCF7A8F8002200230E900F91F7 +:10B02000FAF70CF9002800D14CE10023002220009F +:10B030002900FAF703F90222431E9841131AAC4A79 +:10B040003900019202220AA80092524600F064FCE4 +:10B050004B46002B13DA8022120694467B6840424E +:10B0600063447B60FB686344FB6008E002000B0004 +:10B070003A607B60002200230020BA60FB6010B0C1 +:10B080001CBC90469946A246F0BD02000B00FCF79E +:10B09000E5FAB860F960386079600020EFE7D32204 +:10B0A0008E4B5205FCF7DAFA924A934B04000D00DE +:10B0B000FCF7D4FA02000B0020003A607B60290004 +:10B0C000FCF7CCFA8B4A8C4BFCF7C8FAB860F960F5 +:10B0D0000120D4E7FDF710FB884A894B04000D00DE +:10B0E000FCF742F80022874BFBF7EEF8FCF72AFE4C +:10B0F0008046FCF75DFE764A764B06900791FCF79A +:10B1000033F802000B0020002900FCF7A7FA734B6C +:10B1100002900391069807996F4AFCF725F8434679 +:10B1200004000D00049405951F2B30DC013B764A8A +:10B130009B009B589E422AD002000B000298039964 +:10B14000FCF78CFA02000B0005000C003A607B60F3 +:10B15000029803992A002300FCF780FA049A059BC1 +:10B16000FCF77CFA06000B003200BA60FB604B462D +:10B170004046002B00DB82E780231B069C4664448C +:10B1800061443D607C60BE60F960404277E7049AAC +:10B19000059B02980399FCF761FA0B0002003A60E4 +:10B1A0007B604B0036155B0D05000C00F31A102B6D +:10B1B000CEDD06980799D322484B5205FBF7D4FF02 +:10B1C00004000D0002000B0002980399FCF746FAF8 +:10B1D00002000B000298039908920993FCF73EFACB +:10B1E00022002B00FCF73AFA04000D00069807999C +:10B1F000404A414BFBF7B8FF22002B00FCF72EFA28 +:10B2000002000B000490059108980999FCF726FAB2 +:10B2100002000B003A607B604B005B0DF61A0500E4 +:10B22000089A099B0C0002920393312E90DD069838 +:10B230000799B822304B9205FBF796FF04000D00EA +:10B2400002000B0002980399FCF708FA0A000100BB +:10B25000130002910392020008980999FCF7FEF985 +:10B2600022002B00FCF7FAF904000D00069807995C +:10B27000264A274BFBF778FF22002B00FCF7EEF95C +:10B2800002000B000492059358E7124BFBF71CF8E1 +:10B29000104B04000D009E423CD00F4A0F4BFBF7B1 +:10B2A00013F802000B0020003A607B602900FCF7D5 +:10B2B000D5F9094A094BFBF707F8B860F960012096 +:10B2C0004042DCE60323BAE6FB21E93F7BD902409A +:10B2D00000004054FB21F93F3163621A61B4D03D54 +:10B2E000FB213941FFFFEF7FEAFBFFFF00007041C8 +:10B2F000883C03007370032E8A19A33B83C8C96D71 +:10B30000305FE43F0000E03F083C0300C1492025D6 +:10B310009A837B39D3220D4B5205FAF7D5FF0C4A9D +:10B320000C4B04000D00FAF7CFFF02000B002000C9 +:10B330003A607B602900FCF791F9054A054BFAF762 +:10B34000C3FFB860F9600120404298E661B4D03D87 +:10B350007370032E8A19A33BF0B54B005C08594B60 +:10B3600085B007000E009C421DDC002930DB002266 +:10B37000554B00920193554B9C4219DC544B9C4217 +:10B3800000DD73E0534A544B38003100FAF79CFF5C +:10B39000524B0022F9F76CFF310003003800002BFC +:10B3A0001BD005B0F0BD02000B00FAF78DFFF8E7E7 +:10B3B0004B4B9C4278DD4B4B9C4240DD4A4B9C42C0 +:10B3C0003AD0444A444B38003100FBF7CDFEE8E761 +:10B3D0000022464B00920193CDE738003100FDF783 +:10B3E0008BF901F05BF906000F0032003B003000E2 +:10B3F0003900FAF769FF320004000D003B0030000D +:10B400003900FBF7B1FE002202900391334B30006C +:10B410003900FAF759FF02000B0002980399FBF775 +:10B420007FFA02000B0020002900FCF717F9009AB0 +:10B43000019BFBF799FEB4E72D4B9F42C1D8380022 +:10B440003100FDF759F900221F4BFBF78DFEFFF786 +:10B450004BF806000F0002000B0000980199FBF763 +:10B4600083FE32003B00FBF77FFE9AE73800310095 +:10B47000FDF742F901F012F91E4B06000F009C4245 +:10B48000B3DD0022154BFAF71FFF02000B0030005E +:10B490003900FBF745FA32003B00FAF715FF009A36 +:10B4A000019BFBF761FE7CE738003100FDF724F9D2 +:10B4B000FFF71AF802000B0000980199FBF754FE01 +:10B4C0006FE7C046FFFFEF7F0000E03FFFFF354022 +:10B4D000FFFF2F3E3374AC3C1F7BAC7F0000F03F7E +:10B4E000412E8640CD338640CE3386400000E0BFFB +:10B4F0007DF8B98FFFFFEF3FF0B556464D46444605 +:10B500005F46754BF0B40A000D00190083B00600C9 +:10B5100004002940994200D1BAE0002D00DC94E0FB +:10B520002D1500D1A3E06D4B12039C468023120B16 +:10B530005B0365441A43EB0700D581E06B10984626 +:10B54000E30F9B189B188022162100260027640019 +:10B550009203B818984202DC87181B1AB618E00F3D +:10B560005B0001391B18640052080029F1D1002248 +:10B5700001929446802212062020914609E09F42C3 +:10B5800041D0E10FC9180138CB18640052080028D7 +:10B590001ED0614651189F42F1DA8D18AC46CD0F8E +:10B5A000ED07BA464D4539D0DB1B8C42BF417F4287 +:10B5B000DB1B641A019901388B469344594601916B +:10B5C000E10FC9185746CB18640052080028E0D193 +:10B5D00023432BD1019B5B08414972108C46624486 +:10B5E000F10702D5802109060B43414609058D1854 +:10B5F0001E002F003000390003B03CBC9046994635 +:10B60000A246AB46F0BDA1420ED88D18AC46CD0F78 +:10B61000ED074D4548D09A460023CAE76546002D00 +:10B62000C2DB7D1CAA46BFE73B00AAE7019B0133B2 +:10B630003ED0019A01239446134063445B08CBE754 +:10B64000E30F52009A18640078E76B005B0803432D +:10B650002F00002BCED00025002A31D1E20A153D63 +:10B660006405002AFAD080235B031A4223D180208C +:10B670000023400300E00B005200591C0242FAD0A4 +:10B680002020401AED1A2300C3408C401A434AE799 +:10B6900002002B002900FBF767FD32002B00FAF7B0 +:10B6A00013FE06000F00A5E76546002DB3DBB8E7E3 +:10B6B0000136002390E7012320205B420021E1E7CF +:10B6C0003B0002003900FBF7C9FF02000B00FBF74B +:10B6D00027F906000F008DE70000F07F01FCFFFF57 +:10B6E0000000E03FF0B54F464646C0B487B0009238 +:10B6F0000193754B4F00814688467F089F4263DC6B +:10B70000FCF720FB002800D1DAE04A4643464846D1 +:10B710004146FBF729FD04000D006C4A6C4BFBF71A +:10B7200023FD6C4A6C4BFAF7CFFD22002B00FBF790 +:10B730001BFD6A4A6A4BFBF791FF22002B00FBF7C7 +:10B7400013FD684A684BFAF7BFFD22002B00FBF798 +:10B750000BFD664A664BFBF781FF22002B00FBF7CF +:10B7600003FD644A644BFAF7AFFD22002B00FBF7A0 +:10B77000FBFC029003910022604B20002900FBF7A4 +:10B78000F3FC029A039B06000F0020002900FBF740 +:10B79000EBFC009A019B04000D0048464146FBF774 +:10B7A000E3FC02000B0020002900FBF757FF02001A +:10B7B0000B0030003900FBF751FF02000B000020A6 +:10B7C0004F49FBF74BFF70E002000B00FBF7CCFC8E +:10B7D00004000D003D4A3E4BFBF7C6FC3D4A3E4B84 +:10B7E000FAF772FD22002B00FBF7BEFC3B4A3C4BF4 +:10B7F000FBF734FF22002B00FBF7B6FC394A3A4B2B +:10B80000FAF762FD22002B00FBF7AEFC374A384BFB +:10B81000FBF724FF22002B00FBF7A6FC354A364B32 +:10B82000FAF752FD2B002200FBF79EFC354B0290ED +:10B8300003919F429FDD344B00229F423ADC334903 +:10B8400000207B182E4916001F00FBF707FF04900D +:10B8500005910022294B20002900FBF785FC3200CE +:10B860003B00FBF7FBFE029A039B06000F00200043 +:10B870002900FBF779FC009A019B04000D00484663 +:10B880004146FBF771FC02000B0020002900FBF78A +:10B89000E5FE02000B0030003900FBF7DFFE02007E +:10B8A0000B0004980599FBF7D9FE07B00CBC904635 +:10B8B0009946F0BD164B002604920593154FC8E734 +:10B8C00000200F49F1E7C046FFFF3F3ED43888BE55 +:10B8D000E9FAA8BDC4B1B4BD9EEE213EAD529C8034 +:10B8E0004F7E923E9015CB19A001FA3E7751C116BA +:10B8F0006CC1563F4C5555555555A53F0000E03F8E +:10B900000000F03F3233D33F0000E93F0000E0FF8A +:10B910000000E73F0000D23FF0B556464D46444692 +:10B920005F46F0B48E4CA544099119001400A89A02 +:10B930000B938C4B9200D2580B000290013BE01EFF +:10B9400018211D00160008920093F9F77BFBC343F2 +:10B950000200DB171A401300110001330E929A0007 +:10B960009B1ADB001B1906934C1B761918D4A99B54 +:10B97000A5009C46361926AF6544013607E02868C5 +:10B98000FCF716FA013403C70435B44208D0002C82 +:10B99000F5DA00200021013403C70435B442F6D1A2 +:10B9A000089B002B01DA00F0F9FB76AB19008B46FF +:10B9B00026AA9146089A0A930132D2009344029A29 +:10B9C0009A469046009BDB00994408339844009BBC +:10B9D000002B00DAB5E14C4600260027029D2268C4 +:10B9E000636803CDFBF7C0FB02000B003000390099 +:10B9F000FAF76AFC083C06000F004545EFD15346B4 +:10BA0000C0C39A4608239C46E144DA45DFD1089931 +:10BA1000554A0B00944663449B0012A884461A00C2 +:10BA20000298624483460D920B9A0433D200634419 +:10BA300093440F930591059A0A98D30019000C932B +:10BA40008C46030063441E685F68002A34DD12AB35 +:10BA500099461300454A804694466344DB00984467 +:10BA600074AB9A460022424B30003900FBF77CFB56 +:10BA7000FCF768F9FCF79CF900223E4B04000D002E +:10BA8000FBF772FB02000B0030003900FBF7E6FD0C +:10BA9000FCF758F94B4601C39946434620001A6803 +:10BAA0005B682900FAF710FC08235B429C46E044DF +:10BAB00006000F00D045D5D1069B30001A00390092 +:10BAC000994601F063F8FF2300229B0504000D0056 +:10BAD000FBF74AFBFCF714FE0022274BFBF744FB65 +:10BAE00002000B0020002900FBF7B8FD04000D0048 +:10BAF000FCF728F98046FCF75BF902000B002000F8 +:10BB00002900FBF7ABFD4C4606000F00002C00DCC3 +:10BB1000F8E0059B18205A1E920012AB9B58001BA0 +:10BB200019000141884481405B1A12A98B501722E9 +:10BB3000121B13410793079B002B4BDD01239C46EF +:10BB4000059BE044002B00DCF2E280251096119763 +:10BB500012AB0021002409486D04059F19E0C0467E +:10BB600084FDFFFF903D0300FEFFFF3FFFFFFF1F2F +:10BB70000000703E0000704100002040FFFFFF0009 +:10BB8000002A02D0AA1A1A600134013104338F420C +:10BB900009DD1A68002CF3D0821A01311A600124E1 +:10BBA00004338F42F5DC109E119F069B002B0EDDA7 +:10BBB000012B00D1B1E0022B09D1059B12A95A1E1D +:10BBC000920012AB9B5810939B029B0A8B50079BD1 +:10BBD000022B7ED00023002230003900F9F72EFB23 +:10BBE000059B002800D16BE208995A1E914210DC97 +:10BBF000BF490F988C4612A963448C4600219B00D4 +:10BC000063441C68043B21438342FAD1002900D0DD +:10BC1000B5E0089B12AA013B9B00D358002B00D033 +:10BC200084E201220D9B043B596801320029FAD0BD +:10BC300005990B008C46013362440792934242DC23 +:10BC40000E9A9446A99A634492460B9A9B00944696 +:10BC500026AA90469A44059B0A9A6344DB009844BE +:10BC60000C9B94469946079BE144DB006344059393 +:10BC700053461868FCF79CF8434618605960009BCF +:10BC8000002B23DB444600260027029D22686368C0 +:10BC900003CDFBF769FA02000B0030003900FAF718 +:10BCA00013FB083C06000F005D45EFD14B469E603C +:10BCB000DF6004239C460433E2449C46059BE14438 +:10BCC000E0449945D4D1079B0593B4E600260027AC +:10BCD000ECE732003B0000208649FBF7BFFC060082 +:10BCE0000F00002C00D175E7069A0020814900F072 +:10BCF0004DFF02000B0030003900FBF7AFFC0600DF +:10BD00000F0067E7069B002B12D1059B12AA013B8F +:10BD10009B00D558EB1507930DE7059B12A95A1EFA +:10BD2000920012AB9B5810935B025B0A8B504EE75C +:10BD30000022714BF9F7A6FA00280ED100230793D1 +:10BD400048E7534600260027C0C39A4608239C466E +:10BD5000E144DA4500D03AE659E601239C46013336 +:10BD60000793059BE044002B00DDEEE632003B002C +:10BD700000206049FBF772FC06000F002AE74346EB +:10BD80000B93069B12A8183B190006939300C35807 +:10BD90000092002B0FD156481300844612A863442A +:10BDA00084469B006344043B5868013A18390028D4 +:10BDB000F9D000920691069A00204E4900F0E6FE66 +:10BDC000009B04000D00002B00DAB3E112AA944698 +:10BDD0009F00DB0067449C460A9A059362449346A1 +:10BDE00016003868FBF7E4FF22002B00FBF7BCF9D4 +:10BDF000424B30607160002220002900FBF7B4F94B +:10BE0000083E74AB04000D00043FB342E9D10023A7 +:10BE10009A464EAB0293089B99464B460026002754 +:10BE2000002B21DB8020364B5D469846C005354906 +:10BE300000260027002408E008239C460835E0443B +:10BE4000A24511DB4346186859682A686B68FBF7FE +:10BE50008BF902000B0030003900FAF735FA013493 +:10BE600006000F00A145E7DA029A53469446DB002C +:10BE700063441E605F6001239C46093BE2449C468C +:10BE800074ABE3449B45C8D1029B9946A89B022B07 +:10BE900000DD82E0002B37DC1DD1059B00254B44E3 +:10BEA0001E0000243268736828002100FAF70CFA9B +:10BEB000009B05000C00083E5A1E0092F2D2079B20 +:10BEC000002B03D080231B069C4664442A002300D9 +:10BED00009990A604B6007200B9B18409F239B0029 +:10BEE0009D443CBC90469946A246AB46F0BDC04638 +:10BEF000FFFFFF3F0000F03F0000E03F0000703E0A +:10BF0000E82D0300FB21F93F059B00204B441E0058 +:10BF100000214CAF32687368083EFAF7D5F9BE428B +:10BF2000F8D1079B002B24D08023099A1B06CB183D +:10BF3000106053600B0002004E984F99FBF78EFB88 +:10BF4000009B002B0BDD012450AD0CCDFAF7BCF9A2 +:10BF5000009B0134A342F8DA079B002B03D0802317 +:10BF60001B069C4661440B00020009998A60CB6065 +:10BF7000B1E702000B00099C226063600B00020025 +:10BF80004E984F99FBF76AFB009B002BDBDC0B0004 +:10BF9000020009998A60CB609DE7A89B032B9AD188 +:10BFA000009B002B00DCE3E07E4A059B94464B445B +:10BFB0001E685F68009B63449A46DB004B449846CA +:10BFC0004CAB9B4643465C681B681800210032005E +:10BFD0003B0002900391FAF777F904000D0002008C +:10BFE0000B0002980399FBF739FB3B003200FAF78C +:10BFF0006BF943469860D9601C605D6008235B4222 +:10C000009C46E04426002F00C345DBD1009B012B5A +:10C0100000DCADE0059BC8464B441E685F68534694 +:10C02000DB009B46D844434630005C681B683900FF +:10C03000009301941A002300FAF746F904000D005A +:10C0400002000B0000980199FBF708FB3B0032004F +:10C05000FAF73AF943469860D9601C605D6008239E +:10C060005B429C46E04426002F00C145DBD15D4683 +:10C070000027002408354D4450AE2A686B6838000C +:10C080002100FAF721F9083D07000C00AE42F4D177 +:10C09000079B002B71D08021099A4E9B09061360E3 +:10C0A0004B468C465B686444634453604B469B68D4 +:10C0B000176193604B46DB6854616344D3600AE7C1 +:10C0C000994643460B93069B30005A42390000F0D4 +:10C0D0005DFD0022344B04000D00F9F7D3F8002871 +:10C0E00032D0324B002220002900FBF73DF8FBF74D +:10C0F00029FE4A4606009700FBF75AFE00222A4B0B +:10C10000FBF732F802000B0020002900FBF7A6FA2B +:10C11000FBF718FE12AAD0514A46069B013218338B +:10C1200000920693930012AAD65044E601227FE5BE +:10C1300000243AE5A89B022B14DC002B0FDC00D076 +:10C14000C9E600250024BAE64B46200029009E00DF +:10C15000FBF7F8FD12AB98514B4600932BE60020FD +:10C160000021DEE64EAB9946A89B032B00D0B2E639 +:10C17000079B00270024002B8DD14E9A4F9B0999D5 +:10C180000A604B604B469A68DB68009201938A60B4 +:10C19000CB603A0023000A614B619CE676AB0A93C0 +:10C1A00035E4C046FFFFFF1F000070410000703EF5 +:10C1B000F0B54F464646C0B487B000920193464A58 +:10C1C0004B00814688465B08934205DCFBF7BAFDCD +:10C1D0004146031E484666D04A46434648464146C5 +:10C1E000FAF7C2FF04000D0002000B00484641466A +:10C1F000FAF7BAFF394A3A4B06000F00200029002F +:10C20000FAF7B2FF374A384BFBF728FA22002B0027 +:10C21000FAF7AAFF354A364BFAF756F822002B00F8 +:10C22000FAF7A2FF334A344BFBF718FA22002B002F +:10C23000FAF79AFF314B324AFAF746F80E9B029012 +:10C240000391002B34D00098019900222D4BFAF76E +:10C250008BFF029A039B0490059130003900FAF796 +:10C2600083FF02000B0004980599FBF7F7F9220001 +:10C270002B00FAF779FF009A019BFBF7EFF9224AAE +:10C2800004000D00214B30003900FAF76DFF020069 +:10C290000B0020002900FAF717F802000B004846AF +:10C2A0004146FBF7DBF907B00CBC90469946F0BD60 +:10C2B00002000B0020002900FAF756FF124A134B28 +:10C2C000FBF7CCF932003B00FAF74EFF4A464346F3 +:10C2D000F9F7FAFFE7E7C046FFFF3F3E7CD5CF5AAC +:10C2E0003AD9E53DEB9C2B8AE6E55A3E7DFEB157F7 +:10C2F000E31DC73ED561C119A0012A3F1111813F3D +:10C30000A6F810110000E03F495555555555C53F59 +:10C31000F0B55F4656464D464446F0B489B00093AA +:10C320004B005B089A46BB4B8146884602928B467F +:10C330009A4516DCFBF706FD00282FD14B465246E6 +:10C340001A43129B0133134300D148E1129B012B86 +:10C3500000D15BE14A4643460020AF49FAF7E0FAD4 +:10C36000F8E0AE4B9A4519DD002900DA42E14A4671 +:10C370004346AB48AB49FBF771F904000D00029A44 +:10C38000009BA948A949FBF769F92B002200F9F79E +:10C390009BFF002381468846029300934A4643460A +:10C3A00048464146FAF7E0FE02000B0006000F0087 +:10C3B000FAF7DAFE320004000D003B004846414621 +:10C3C000FAF7D2FE9A4A049005919A4B2000290070 +:10C3D000FAF7CAFE984A994BF9F776FF22002B002C +:10C3E000FAF7C2FE964A974BF9F76EFF22002B0030 +:10C3F000FAF7BAFE944A954BF9F766FF22002B0034 +:10C40000FAF7B2FE924A934BF9F75EFF22002B0037 +:10C41000FAF7AAFE904A914BF9F756FF32003B001B +:10C42000FAF7A2FE8E4A069007918E4B2000290053 +:10C43000FAF79AFE8C4A8D4BF9F746FF22002B0043 +:10C44000FAF792FE8A4A8B4BF9F73EFF22002B0047 +:10C45000FAF78AFE884A894BF9F736FF22002B004B +:10C46000FAF782FE864A874BF9F72EFF22002B004F +:10C47000FAF77AFE844A854BF9F726FF02000B0093 +:10C4800006980799F9F720FF049A059BFAF76CFEC6 +:10C49000029D009C2A002300F9F716FF32003B00A2 +:10C4A000FAF762FE02000B0028002100F9F70CFFEA +:10C4B00004000D0004980599754A764BFAF754FE6E +:10C4C00022002B00F9F700FF0B000200414648460E +:10C4D00000920193F9F7F8FE504B04000D009A45C5 +:10C4E0003FDC129B012B35D00F0002000B00002017 +:10C4F0004949FAF715FA00260D00029003914A46C1 +:10C50000434630003900FBF7A9F8002402000B0075 +:10C5100000980199FBF7A2F822002B00FAF724FEFD +:10C520002200009001912B0030003900FAF71CFE28 +:10C530000022594BF9F7C8FE02000B000098019940 +:10C54000F9F7C2FE029A039BFAF70EFE22002B00B7 +:10C55000F9F7BAFE09B03CBC90469946A246AB46F4 +:10C56000F0BD1298FBF724FC220006000F002B0000 +:10C5700020002900FAF7F8FD3200029003913B00F9 +:10C5800020002900F9F7A0FE02000B000298039991 +:10C59000FAF7C6F9009A019BFBF760F802000B005E +:10C5A00048464146FBF75AF802000B00F9F78CFEAB +:10C5B00002000B0030003900FBF750F85B46040026 +:10C5C000981702231840013B181A0D00FBF7F0FBE7 +:10C5D00002000B0020002900FAF7C6FDBAE7484622 +:10C5E0004146FCF789F802000B0000202A49FAF7BF +:10C5F00097F9AFE78022802112069446009B090636 +:10C6000041446344814688460093B0E6484641462B +:10C61000A0E7C046FFFF2F3E0000F0BF2794E53F94 +:10C62000182D4454FB21E93F075C143326A6813CB6 +:10C63000D47ABF74702AFB3EE9A7F0320FB8123FDC +:10C6400068108D1AF726303F1583E0FEC8DB573F90 +:10C6500093846EE9E326823FFE41B31BBAA1AB3F50 +:10C66000735360DBCB75F3BEA69237A0887E143F70 +:10C670000165F2F2D844433F280356C9226D6D3F4D +:10C6800037D60684F464963F7AFE10111111C13F2B +:10C69000635555555555D53F0000F03FF0B54E4612 +:10C6A00045465746E0B4DF4ACC0F4B0084B0814684 +:10C6B0008846E4075B0893424FD9DB4A934200D98E +:10C6C000F9E0002C00D17AE1D84AD94B48464146DE +:10C6D000F9F7FAFD00220023F8F7B6FD002800D094 +:10C6E000F4E0D44AD44B48464146FAF73DFD0200F7 +:10C6F0000B000020D149F9F7E7FDFBF723FB824649 +:10C70000FBF756FBCE4ACF4B06000F00FAF72CFD85 +:10C7100002000B0048464146FAF7A0FFCA4A04004F +:10C720000D0030003900C94BFAF71EFD06000F005E +:10C7300032003B0020002900FAF790FF02000B00B6 +:10C740008146884620002900FAF788FF32003B0026 +:10C75000FAF784FF0290039109E0BD4A934200D9A1 +:10C76000DBE000229246BB4A934200D805E100225A +:10C77000B94B48464146FAF7F7FC04000D000200A9 +:10C780000B0048464146FAF7EFFC06000F00B34A9B +:10C79000B34BFAF7E9FCB34AB34BF9F795FD320016 +:10C7A0003B00FAF7E1FCB14AB14BFAF757FF320010 +:10C7B0003B00FAF7D9FCAF4AAF4BF9F785FD3200E1 +:10C7C0003B00FAF7D1FCAD4AAD4BFAF747FF320018 +:10C7D0003B00FAF7C9FC0022AA4BF9F775FD00905F +:10C7E000019102000B0020002900FAF7BDFC0200B5 +:10C7F0000B000020A449FAF731FF02000B000400EF +:10C800000D0000980199FAF729FF2200009001918C +:10C810002B0048464146FAF7A7FC02000B00002017 +:10C820009A49FAF71BFF02000B0000980199FAF7EA +:10C8300077F83B003200FAF797FC5346002B48D0BC +:10C84000029C039D22002B00FAF708FF4A4643464C +:10C85000FAF78AFC22002B00FAF700FF3B003200B7 +:10C86000FAF7FCFE534604000D00013300D1B1E09D +:10C870005346012B00D187E053460133392B5ED854 +:10C880005346132B00DCB4E081490022C91A0B0582 +:10C8900020002900F9F718FD02000B004846414628 +:10C8A000FAF7DCFE774B0022F9F70EFD53461B0525 +:10C8B0005D1829001DE0774A934220D90903090B2E +:10C8C000014300D013E14146002C12D000207249F0 +:10C8D0000FE002000B0048464146FAF745FC3200E3 +:10C8E0003B00FAF7BBFE02000B0048464146FAF750 +:10C8F000B5FE04B01CBC90469946A246F0BD674AFE +:10C90000674BF8F7B5FC002800D1DAE6654A664BBC +:10C9100010001900FAF728FCEBE7644A934200D9AB +:10C92000CAE0474A474B002C1ED0F9F7CDFC012343 +:10C930005B4204000D009A46434E5D4FF8E64A46BE +:10C940004346FAF78BFE02000B0000204D49FAF730 +:10C9500085FE544602002005431819001000494B7B +:10C960000022FAF77BFEC4E7FAF778FE0123040001 +:10C970000D009A46344E354FDAE64A4A4A4BF9F7EB +:10C98000A3FC02000B00ACE700224A4B484641469C +:10C99000F8F75AFC002800D19AE000222E4B4846B6 +:10C9A0004146F9F791FC02000B0020002900FAF73C +:10C9B00055FEC02300221B06FAF7D6FB99E71D4A55 +:10C9C0001D4B48464146FAF7CFFB02000B00002002 +:10C9D000214990E602000B0048464146FAF73EFE28 +:10C9E00000221D4BFAF7C0FB00221B4BFAF736FE64 +:10C9F0007FE7802352469B031341224A0026D71A21 +:10CA00004A464346FAF72AFE02000B00300039007E +:10CA1000FAF724FE544602002005431819001000BE +:10CA200067E7C04679684340412E864059F3F8C213 +:10CA30001F6EA501FE822B654715F73F0000E0BF82 +:10CA40000000E0FE422EE63F763C7935EF39EA3DC4 +:10CA5000422ED63FFFFF8F3C0000E03F2DC3096E02 +:10CA6000B7FD8ABE3952E686CACFD03EB7DBAA9E52 +:10CA700019CE143F8555FE19A0015A3FF41011112B +:10CA80001111A13F0000F03F0000084000001840D5 +:10CA9000FF030000FFFFEF7F0000F0BFEF39FAFE59 +:10CAA000422E86409C7500883CE4377EB1A2F03F60 +:10CAB000EF39EABD0000D0BF104A114BFAF754FB22 +:10CAC00002000B000020002C00D013E60D4912E6F6 +:10CAD00022002B0048464146FAF7C0FD02000B0039 +:10CAE000F9F7F2FB0022084BF9F7EEFB01E7020031 +:10CAF00043464146F9F7E8FBFBE6C046FE822B655C +:10CB00004715F73F0000E03F0000F03F034B4800AF +:10CB10009C4640086044C00F7047C046000010802B +:10CB20000A000300024330B50220002A00D130BDC4 +:10CB300080221206914216D00C4A0D4C8A1804200D +:10CB4000A242F4D90B4A8A18A242F0D90A4A4900F3 +:10CB5000490803209142EAD9064A00209142E6D1D1 +:10CB600058425841E3E7002BE1D0EFE70000F0FF27 +:10CB7000FFFFDF7F0000F07FFFFF0F000020704706 +:10CB8000002001497047C0460000F87F4B0070B597 +:10CB90005B0D14000A00002B1AD14B005B08034305 +:10CBA00015D00022224BFAF7DFFA224B0A009C42F2 +:10CBB00022DB4B005B0D363B1F4DE318AB4220DC04 +:10CBC000002B0DDD1D4C1B0522401A43110070BDCA +:10CBD0001B4DAB42F0D102000B00F9F775FBF6E7F5 +:10CBE0001D00353518DA174B02009C420ADC0B0099 +:10CBF0001548164900F032F8134A144BFAF7B4FA04 +:10CC0000E5E702000B001248124900F027F8104A2D +:10CC1000104BFAF7A9FADAE7084C363322401B0525 +:10CC20001343190000220C4BFAF79EFACFE7C046D7 +:10CC300000005043B03CFFFFFE070000FFFF0F80E5 +:10CC4000FF07000050C3000059F3F8C21F6EA50192 +:10CC50009C7500883CE4377E0000903C30B54A006B +:10CC6000DB0FDB0752081A43110030BD70B5054CCD +:10CC700005001300201E04D00A000220290000E055 +:10CC800000BF70BD00000000014B18687047C0462F +:10CC900080200020084B10B50400002B02D000219A +:10CCA00000E000BF054B1868836A002B00D098474E +:10CCB000200005F00CFBC04600000000003E030011 +:10CCC0000E4B70B500251E000D4CE41AA410A542B1 +:10CCD00004D0AB00F35898470135F8E705F020FE83 +:10CCE000084B00251E00084CE41AA410A54204D0ED +:10CCF000AB00F35898470135F8E770BD9C20002041 +:10CD00009C2000209C200020BC20002010B5034B5C +:10CD10000100186805F044FD10BDC04680200020C9 +:10CD2000002370B5064C050008001100236000F0D8 +:10CD300063FB431C03D12368002B00D02B6070BD24 +:10CD40000C2900200CB430B5164B9DB00C1E1D688C +:10CD500004DA8B2301202B6040421DE0822302A9CC +:10CD60009B008B810023029008619C4200D0631ECF +:10CD70008B604B6101235B42CB81209A21AB280061 +:10CD8000019300F011F9431C01DA8B232B60002C76 +:10CD900002D00023029A13701DB030BC08BC02B050 +:10CDA0001847C04680200020F0B51E00454B87B0D4 +:10CDB0001B680192029308220B00059003911C78D6 +:10CDC00002995D1C09194878104001D02B00F6E744 +:10CDD0002D2C04D19D1C5C780123009304E000906D +:10CDE0002B2C01D15C789D1C002E02D0102E0AD174 +:10CDF00062E0302C5ED120222B789343582B54D103 +:10CE000010266C780235009F31007B1E9F412E4B0F +:10CE1000FF183800F8F712F9380004913100F8F7DC +:10CE200087F800230322070094461800029A12197B +:10CE300051780422114201D0303C07E06246114093 +:10CE400017D03722012900D02032A41AA64210DDC3 +:10CE50005A1C0BD0B84207D802D1049B9C4203DC79 +:10CE600070430123201801E001235B422C78013537 +:10CE7000DCE75A1C0BD10098059A431E9841124BCF +:10CE8000C01822231360019B002B0AD117E0009ADF +:10CE9000002A00D04042019A002A10D0039A002BA9 +:10CEA00000D06A1E019B1A6009E03024002EAAD12E +:10CEB0000826A8E70A26A6E7302C9CD0A3E707B0EF +:10CEC000F0BDC04684200020FFFFFF7F10B5130097 +:10CED0000A00010002480068FFF766FF10BDC04667 +:10CEE00080200020F0B58E6885B007000C0003920A +:10CEF00001939E4243D890238A89DB001A423ED098 +:10CF000003250969236801985B1A029363695D43ED +:10CF1000EB0F5D19029B6D1001331B18AB4200D95A +:10CF20001D00530510D52900380001F0B2FE061E81 +:10CF300014D0029A216905F00DFCA289194B134007 +:10CF400080221343A38112E02A00380001F0ABFED7 +:10CF5000061E0CD12169380001F0A0FE0C234022EE +:10CF600001203B60A38940421343A38117E0029B49 +:10CF70002661F61826606561019EED1AA560019B89 +:10CF8000B34200D21E0032000399206805F0EBFB8B +:10CF90000020A3689B1BA36023689E19266005B030 +:10CFA000F0BDC0467FFBFFFFF0B59FB00290059338 +:10CFB0008B890F0016001B0610D50B69002B0DD1B5 +:10CFC000402101F066FE38603861002804D10C234E +:10CFD000029A01381360D8E040237B61002306AD3C +:10CFE0006B6120336B761033AB7634002378002BE3 +:10CFF00003D1A31B049312D003E0252BF9D00134F5 +:10D00000F4E7A31B320039000298FFF76BFF431CC3 +:10D0100000D1B4E06A69049B944663446B61237851 +:10D02000002B00D1ABE00122002352426A6002A92A +:10D030005432521801342B60EB60AB601370AB6557 +:10D04000534E21780522300005F06AFB002807D0F6 +:10D050000123801B83402A68013413432B60EFE7D0 +:10D060002B68DA0604D55322202102A81218117069 +:10D070001A0704D553222B2102A812181170227806 +:10D080002A2A03D0099B00200A210EE0059A111DCF +:10D0900012680591002A01DB099204E05242EA601D +:10D0A000022213432B6001340BE02278303A092A24 +:10D0B00004D84B4301349B180120F6E7002800D028 +:10D0C000099323782E2B1ED163782A2B0AD1059B36 +:10D0D00002341A1D1B680592002B01DA01235B4202 +:10D0E000079310E000230A201A0001346B602178B6 +:10D0F0003039092904D84243013452180123F6E794 +:10D10000002B00D00792234E21780322300005F037 +:10D1100007FB002806D04023801B83402A68013487 +:10D1200013432B60217806221B48661C297605F0E4 +:10D13000F7FA002812D0194B002B06D10722059BC5 +:10D14000073393430833059314E005AB00933A008B +:10D15000134B2900029800E000BF07E005AB0093E5 +:10D160003A000F4B2900029800F01CF80390039B33 +:10D17000013304D06B69039A9B186B6135E7BB8957 +:10D180000B985B0601D5012040421FB0F0BDC046A0 +:10D19000954503009B4503009F45030000000000E8 +:10D1A000E5CE0200F0B58BB006920A004332079339 +:10D1B000059004920A7E0C00109B6E2A00D1ABE011 +:10D1C00011D8632A22D009D8002A00D1B5E0582A04 +:10D1D00000D0C5E045310A70814A4FE0642A1DD075 +:10D1E000692A1BD0BCE0732A00D1AAE009D86F2AB3 +:10D1F00029D0702A00D0B3E0202209680A432260B7 +:10D2000037E0752A1FD0782A33D0A9E00E001A68BB +:10D210004236111D196013683370A4E021681A6842 +:10D22000080606D4490604D5111D19600023D55EF1 +:10D2300002E0111D19601568002D3BDA2D23049AB8 +:10D240006D42137036E021681A68080606D4490654 +:10D2500004D51568111D1960ADB202E0111D1960E9 +:10D2600015685F4B227E039308276F2A1DD00A277B +:10D270001BE022007821453211705A4A1968039246 +:10D28000081D226818600D68100602D4500600D5EB +:10D29000ADB2D30702D520231A4322601027002DF8 +:10D2A00003D1202322689A432260230000224333C3 +:10D2B0001A7002E00A274A4B03936368A360002BAD +:10D2C00009DB0422216891432160002D05D1049ED1 +:10D2D000002B11D07BE0002D79D0049E280039006E +:10D2E000F7F7ACFE039B013E5B5C2800337039000E +:10D2F000F7F71EFE051EF1D1082F09D12368DB07C1 +:10D3000006D563682269934202DC3023013E337004 +:10D31000049B9B1B23612BE009681A68080607D44D +:10D32000490605D5111D19601368A28A1A8004E008 +:10D33000111D1960136862691A600023049E23613D +:10D3400016E01A68111D1960166800216268300025 +:10D3500005F0E6F9002801D0801B6060636803E0F7 +:10D36000260042363270012323610023049A137091 +:10D37000079B09AA00932100069B059805F062FA15 +:10D38000431C02D10120404227E023693200069964 +:10D390000598079DA847431CF4D0236800259B07E8 +:10D3A0000FD4099BE068984217DA180015E02200B4 +:10D3B0000123193206990598079EB047431CE1D016 +:10D3C0000135E368099A9B1A9D42F0DBE9E72600E4 +:10D3D000039B42361B7833708EE70BB0F0BDC0461E +:10D3E000A6450300043E030058220120014B4042A1 +:10D3F0001A6070470C29002058220120014B40423E +:10D400001A6070470C29002070470220704710B541 +:10D41000406801F0FFFE10BD704713B5040040687E +:10D4200001F0EAFE002811D061686846EEF7B6F810 +:10D43000694601A801F063FE01A8EEF7BFF860603D +:10D4400001A801F054FD684601F051FD13BD10B56F +:10D45000EAF7D8FE10BD052310B55943EAF7E4FEFC +:10D4600010BD13B50400FFF7D8FF616801A8EEF7FF +:10D4700095F801A801F05FFD01A801F038FD13BD8A +:10D48000F7B5070015001E000C00FFF7C6FF79680E +:10D4900001A8EEF783F8F3B22AB221B201A8EEF7A1 +:10D4A00095F801A801F023FDF7BD37B515000C0074 +:10D4B000416801A8EEF772F82AB221B201A8EEF78E +:10D4C0009BF8040001A801F012FDE043C0172040C2 +:10D4D0003EBD43685888704743689888704710B5C8 +:10D4E0005C1EA3415B42DBB2FFF7CAFF10BD10B563 +:10D4F000FFF7DBFFC317181AC00F10BD052310B5C7 +:10D500005943EAF7A5FE10BD10B50A001023032108 +:10D51000ECF7AAFF10BD70B504000D00ECF72EF873 +:10D52000002807D0F0F742F810232A00032120003A +:10D53000ECF79AFF70BD70B504000D00ECF71EF813 +:10D54000002807D0F0F732F810232A00022120002B +:10D55000ECF78AFF70BD10B5ECF710F8031E04D08D +:10D56000F0F724F8431E9841C3B2180010BD10B55F +:10D57000EDF762FF10BD10B5EDF76CFF10BD704701 +:10D5800080880A3080107047704706307047808866 +:10D5900070478288030000208A4201D3063358185E +:10D5A00070470320704740680B30800870478088C0 +:10D5B00070470123820702D143425841C3B2180089 +:10D5C000704700280BD043688B4201D0002B04D158 +:10D5D0008368934203D0002B01D00068F1E77047C5 +:10D5E00010B5EBF773F910BD07B5002201AB1A8037 +:10D5F000012118701800EBF769F90EBD030030B572 +:10D6000000208B4214D08D1D9A888988981D9142E4 +:10D6100000D911000022835CAC5CA34204D0A34279 +:10D620009B410120184303E001328A42F3D90020D4 +:10D6300030BD80887047F7B5002821D000291FD061 +:10D6400087888E88002A1BDB9219974218D3851D84 +:10D650002C008B1D01938B7900933B1BEB18B3427D +:10D660000ED32378009A934208D13200019920000A +:10D6700005F061F8002801D1601B03E00134ECE7FC +:10D6800001204042FEBD10B5FFF7D5FF0130431E1B +:10D69000984110BD43425841C0B2704710B5FAF7E7 +:10D6A00001FCEBF763FA10BD430010B55A1090422D +:10D6B00002D10120184303E0FAF77AFBEBF756FAA0 +:10D6C00010BD030010B50E20002906DB9A88914298 +:10D6D00003DA59188879FFF7E7FF10BD10B50E235C +:10D6E000002802D0FFF7EDFF0300180010BD422311 +:10D6F000002800D1383B180070470023062806D0C8 +:10D700000333422803D0023B0A2800D0030018004C +:10D71000704710B5EBF7AEFBEBF728FA10BD4843A6 +:10D72000704710B5F7F78EFC10BD10B50C20ECF764 +:10D73000BFFB041E01D0ECF7B3F8200010BD008938 +:10D74000704710B5043000F099FF10BD10B50A0005 +:10D7500004308188ECF78AF810BD10B5043000F071 +:10D7600098FF10BD02890023914202D243688900CC +:10D77000CB581800704710B50430ECF777F810BD9F +:10D7800010B5043000F093FF10BD10B5043000F068 +:10D79000ACFF10BD70470020704740687047416083 +:10D7A000704710B50820ECF783FB041E01D0ECF79E +:10D7B00081F8200010BD10B5ECF752FD10BD431EDE +:10D7C0009841704710B51420ECF772FB041E01D08D +:10D7D000ECF778F8200010BD10B5040000F0A6FFAB +:10D7E0000023984205DB228A904202D2E36880003F +:10D7F000C358180010BDF8B504000F00160025002E +:10D8000000F094FF0C35011E05DA2189201D3A0035 +:10D81000ECF72CF8218A32002800ECF727F8F8BD45 +:10D82000704710B5EBF752FC10BD70B50D00EBF76B +:10D830004DFC04002800EBF749FC84402000FFF772 +:10D8400033FF70BD70B50D00EBF740FC04002800FD +:10D85000EBF73CFC04412000FFF726FF70BD70B5DC +:10D860000D00EBF733FC04002800EBF72FFC6040C1 +:10D87000FFF71AFF70BD70B50D00EBF727FC040031 +:10D880002800EBF723FC2043FFF70EFF70BD10B517 +:10D89000EBF71CFCC043FFF707FF10BD70B50D0090 +:10D8A000EBF714FC04002800EBF710FC2040FFF716 +:10D8B000FBFE70BD70B50D00EBF708FC04002800FE +:10D8C000EBF704FCC4402000EBF71EFA70BD10B566 +:10D8D000EBF7D8FBFAF73AFB10BDD0B50C0001000E +:10D8E00021430023890720D1032A05D12100FFF716 +:10D8F00085FE4342434117E0022A12D1EBF7C2FBF7 +:10D90000060020000F00EBF7BDFB02000B0030000B +:10D9100039000124F7F792FC002800D1041CE3B27F +:10D9200003E0031B58424341DBB21800D0BD70B581 +:10D930000E00EBF7A7FB040030000D00EBF7A2FB95 +:10D9400002000B0020002900F8F7BEFCEBF70EF9EF +:10D9500070BD70B50E00EBF795FB040030000D00B4 +:10D96000EBF790FB02000B0020002900F9F776FE90 +:10D97000EBF7FCF870BD0B000340D0B50C00DB07E3 +:10D980000DD5C3130133012B09D8CB130133012B60 +:10D9900005D84C1040106043FFF786FE0EE0EBF711 +:10D9A00071FB060020000F00EBF76CFB02000B0080 +:10D9B00030003900F9F7D8FBEBF7D8F8D0BD70B5D7 +:10D9C0000E00EBF75FFB040030000D00EBF75AFB95 +:10D9D00002000B0020002900F8F7A2FFEBF7C6F8C1 +:10D9E00070BDF8B501230C00184211D019420FD0B8 +:10D9F0004B100DD0EBF76AFB05002000EBF766FB40 +:10DA000001002800F7F704FC0800FFF74DFE0EE0C8 +:10DA1000EBF738FB060020000F00EBF733FB0200AA +:10DA20000B0030003900FBF7C7FCEBF79FF8F8BD9F +:10DA300070B50E00EBF726FB040030000D00EBF78D +:10DA400045FB290002002000F7F780FCEBF78EF879 +:10DA500070BD0123F7B50E00184201D0194236D12E +:10DA6000EBF710FB040030000D00EBF70BFB06009A +:10DA70000F0002000B0020002900F7F7F9FB002837 +:10DA800005D022002B0034003D0016001F0032009C +:10DA90003B0020002900F7F7D1FB002802D020002E +:10DAA000290011E0EBF7E6F92200009001912B002C +:10DAB00030003900F9F7D2FD009A019BF9F754FBC9 +:10DAC00022002B00F8F700FCEBF750F811E04410AF +:10DAD0004910A14209DB201E884203D0081BEAF747 +:10DAE0003BFF2018FFF7E0FD03E023000C001900C6 +:10DAF000F1E7FEBD10B5EBF7C5FAFBF7C1FCEBF79C +:10DB000035F810BD10B5EBF7BDFAFBF745FDEBF7A7 +:10DB10002DF810BD10B5EBF7B5FAFAF7F1FDEBF7FC +:10DB200025F810BD10B5EBF7ADFAFAF709FDEBF7E4 +:10DB30001DF810BD10B5EBF7A5FAFBF7A9F9EBF747 +:10DB400015F810BD70B504000D000E2801D100209D +:10DB500016E00E29FBD0012318008C4210D00B4098 +:10DB60001C42F4D12000EBF765FA06002800EBF721 +:10DB700061FA8642EBD1320029002000FFF7ADFEAA +:10DB800070BD10B5FFF7DEFF4223002800D1383BFF +:10DB9000180010BD10B5FFF7D5FF4223002800D0B4 +:10DBA000383B180010BDF7B504000D000E2801D158 +:10DBB000002051E00E29FBD0FFF79FFD0600280052 +:10DBC000FFF79BFD01230190019A1800964243D074 +:10DBD0002B401C42ECD12000EBF72CFA0090070000 +:10DBE0002800EBF727FA0300032F01D1022803D006 +:10DBF000032815D1022F29D12000EBF743FA0600A4 +:10DC000028000F00EBF73EFA02000B00300039004D +:10DC10000124F7F713FB002800D1041CE0B21BE03D +:10DC2000012F09D0012801D0019500E00223009ABC +:10DC300026009342BCD103E0012809D102230093BE +:10DC4000009A01993000FFF748FE05E0012FEBD163 +:10DC5000022234000092E7E7FEBD10B5FFF7A3FFF4 +:10DC600010BD10B5FFF79FFF4223002800D1383BBD +:10DC7000180010BD10B5FFF796FF4223002800D012 +:10DC8000383B180010BDF8B50F0000244668058920 +:10DC9000AC420AD2A3003900F058FFF784FF0028F5 +:10DCA00001D0200003E00134F2E701204042F8BD3A +:10DCB00010B500220400FFF7E6FF010000208142BA +:10DCC00003DB201D00F0F3FC012010BD10B5012383 +:10DCD000422805D000230A2802D0EBF76DFA030092 +:10DCE000180010BDF8B504000E000E2801D1022066 +:10DCF0002FE00E29FBD0EBF79DF905003000EBF784 +:10DD000099F9032D06D1032804D131002000FFF733 +:10DD100075FC33E00020B44230D02000EBF7B2F9BC +:10DD2000040030000D00EBF7ADF9220006000F00F3 +:10DD30002B0020002900F9F7E5FF0028D7D1320099 +:10DD40003B0030003900F9F7DDFF002803D0CEE7B3 +:10DD50000120404212E032003B0020002900F7F78A +:10DD600073FA0028F4D13B00320020002900F7F7B5 +:10DD70007FFA431E9841012340421840F8BD10B578 +:10DD800001230C001C40044004D0884200DB002327 +:10DD9000D8B206E0FFF7A6FF030020009A1C00D0CF +:10DDA000D80F10BD0B00034010B5DB0703D5884228 +:10DDB00005DC422008E0FFF795FF831C01D10A2013 +:10DDC00002E00028FBDCF4E710BD0B00034010B5B7 +:10DDD000DB0703D5884205DA422008E0FFF782FF1F +:10DDE000831C01D10A2002E00028FBDAF4E710BD11 +:10DDF0000B00034010B5DB0703D5884205DB42204A +:10DE000004E0FFF76FFF0028F9DA0A2010BD0B00CD +:10DE1000034010B5DB0703D5884205DD422004E04E +:10DE2000FFF760FF0028F9DC0A2010BDE42010B5E0 +:10DE30008000ECF715FA10BD70B50E00EBF722F973 +:10DE4000040030000D00EBF71DF902000B0020006C +:10DE50002900FBF757F9EAF789FE70BD10B5EBF71B +:10DE600011F9FAF76DFFEAF781FE10BD10B5EBF777 +:10DE700009F9FAF71DFFEAF779FE10BD10B5EBF7C7 +:10DE800001F9FAF7F3FBEAF771FE10BD10B5EBF7F5 +:10DE9000F9F8FAF7B7F9EAF769FE10BD10B5EBF734 +:10DEA000F1F8FBF7D5F8EAF761FE10BD10B5EBF716 +:10DEB000E9F8FBF71BF8EAF759FE10BD10B5EBF7D0 +:10DEC000E1F8FBF763FCEAF751FE10BD10B5029CC8 +:10DED00094421FDB002B09D00B0080185C1A94427F +:10DEE0001BDA1C78013804700133F7E7042A06D1E5 +:10DEF000032303400BD10A68026018000EE0022AD7 +:10DF000005D10123034002D10A88028005E004F014 +:10DF100021FC02E00120404200E0002010BD10B5CD +:10DF2000040008000299914205DA002104F030FC57 +:10DF30000120404220E0002B09D00300A418191A48 +:10DF4000914218DA013C217819700133F7E7042A6D +:10DF500005D1032323400BD12268026006E0022A88 +:10DF600006D10123234003D122880280180003E058 +:10DF7000210004F0EFFB002010BD08307047031EA5 +:10DF800007D00023994204DB4268914201DA41182C +:10DF90000B7A18007047002806D0002904DB43687C +:10DFA000994201DA41180A72704710B5FFF7E7FF8E +:10DFB00010BD10B5FFF7EFFF10BD70B50C001600D7 +:10DFC000002B1CDB00291ADB41688C4217DC5268ED +:10DFD000091BD21A8A4200DD0A00002A0FDB350035 +:10DFE0000835864204D1E918281904F0BCFB04E086 +:10DFF00008300019E91804F0ADFB002001E0012011 +:10E00000404270BD4068704710B5002A0EDB44687E +:10E01000A2420BDC002B00DA2300A41A9C4200DD94 +:10E020001C0008308018220004F0B2FB10BD4368C9 +:10E0300010B51C1E8C4200DD0C00002A00DA1A000C +:10E04000191B914200DD110008300019EAF760FC4D +:10E0500010BD70B50D00002B01DA43689B1A002A31 +:10E060002EDB44689918A1422ADC8A4228DC002B66 +:10E0700026D0690024D059428D4201DDAB4206DC36 +:10E080000022012311005B42FFF7BEFF18E00830B9 +:10E090008618002D09DA6C425A193100301904F043 +:10E0A00062FB22000021300008E05C1B7119220095 +:10E0B000300004F058FB2A000021301904F068FBFE +:10E0C00070BD030010B508305968FFF789FA10BD1C +:10E0D00070B50400160008001D1E01DA63689D1A61 +:10E0E000002E2BDB6268AB19934227DC9E4225DCB5 +:10E0F000002D23D0430021D0002801DA2B02C018C4 +:10E100002900F7F785F8002900DA491922000832BA +:10E11000921951180B0055199A420FD014781E7895 +:10E120000132501E0670581C1C70854202D1080036 +:10E130000300F1E79142FBD10100F9E770BD012333 +:10E1400007B55B4200930023FFF737FF07BD10B50B +:10E1500001000020EAF7DCFB10BD10B58188063015 +:10E16000EAF7D6FB10BD30B50400501E85B00D0097 +:10E170000F2869D8F6F7D2FE080C14141C25252E9A +:10E180002E37203B404F475C1800FFF74AFB03E067 +:10E190001800FFF746FBC0B2002D55DD207053E09C +:10E1A0001800FFF73EFB02A908800023009518E045 +:10E1B0001800FFF736FB02E01800EAF787FF02902D +:10E1C0001EE01800FFF72DFB012302A908701A00BA +:10E1D000009536E01800FFF724FB012302A9088010 +:10E1E000009502222DE01800FFF71BFB02E018004B +:10E1F000EAF76CFF02900AE01800FFF768FB029054 +:10E200000095002305E01800FFF761FB0290012351 +:10E210000095042214E01800EAF734FF02900391FD +:10E22000072D11DD082202A9200004F093FA0BE06B +:10E230001800EAF727FF01230822029003910095B6 +:10E2400002A92000FFF742FE05B030BD10B50C005A +:10E25000002A06DB41680830891A80182200FFF77F +:10E2600082FF10BD30B5013A050085B000200F2AAD +:10E2700068D8100002AC0091F6F750FE080B151795 +:10E28000191D2629323A1B424C584E5A00230122AE +:10E2900013E00023012221002800FFF740FE207830 +:10E2A000FFF702FA4EE0002312E0002319E00023FA +:10E2B0001FE0002325E001231A0021002800FFF7BA +:10E2C0002EFE00202056EBE701231A00E3E701238E +:10E2D000022221002800FFF722FE0023E05EDFE794 +:10E2E0000123022221002800FFF719FE2088D7E72A +:10E2F0000123042221002800FFF711FE0298CFE736 +:10E300000123042221002800FFF709FE0298EAF702 +:10E31000FBFC17E0002300E0012304222100280079 +:10E32000FFF7FDFD0298FFF7B9F90BE0002300E0CD +:10E330000123210008222800FFF7F1FD029803992C +:10E34000EAF714FC05B030BD10B5002A03DA00204E +:10E35000FFF7AAF907E0436808309B1A80180A0003 +:10E360001900FFF77FFF10BD10B50400EBF748F868 +:10E37000002807D11023220001211D30ECF774F88A +:10E38000EBF77CF810BD10B5EBF7F8F810BD10B541 +:10E39000EBF7F4F8002801D0EFF78AF810BD10B5BC +:10E3A0000C00EBF7EBF8002802D02100EFF74AF859 +:10E3B00010BD10B5EBF7E2F8002801D0EFF7D6F862 +:10E3C00010BD10B50C00EBF7D9F8002802D02100E1 +:10E3D000EFF7A6F810BD10B50C00EBF7CFF800284A +:10E3E00002D02100EFF75AF910BD70B504000D00FE +:10E3F0001600EBF7C3F8002808D00221EFF7B0F9B8 +:10E400001023320029002000ECF72EF870BDF0B583 +:10E4100085B00C001500EBF7B1F8061E01D1002005 +:10E4200030E0EDF717F800900191043C6742674136 +:10E43000EC173000EFF73CF8B8420BD0EDF70AF8D4 +:10E44000009A019B801A9941A142E8D8F1D18542F6 +:10E45000EFD2E4E7ECF7FEFF03903000EFF728F887 +:10E46000B8420BD1ECF7F6FF009A019B801A994154 +:10E47000A142D4D8F1D18542EFD2D0E7ECF7EAFF40 +:10E48000039BC01A05B0F0BD10B50C00EBF776F891 +:10E49000002802D02100EFF7ADF810BD10B501241F +:10E4A000002903D00234012900D00024EBF766F8DC +:10E4B000002802D02100EFF7FDF810BD10B50C00C8 +:10E4C000EBF75CF82100EFF74BF910BD10B5010038 +:10E4D0000020EAF71DFA10BD10B50400EBF7C8F8EC +:10E4E000036821001B68984710BD10B50400EBF7C6 +:10E4F000BFF82100F5F7AEFB10BD70B50D000400AC +:10E50000EBF7B6F82A002100F5F798FB70BD10B5BF +:10E51000EBF72EFA002010BD704770477047704728 +:10E52000704710B5EAF7AEFDFAF7B6FBEAF71EFB47 +:10E5300010BD10B5EAF7A6FDFAF7BCFEEAF716FB28 +:10E5400010BD10B5EAF79EFDFAF726FCEAF70EFBC0 +:10E5500010BD10B5EAF796FDFBF7A4F8EAF706FB45 +:10E5600010BD10B5EAF78EFDFAF742FEEAF7FEFAA3 +:10E5700010BD10B5EAF786FDFAF7C8FDEAF7F6FA1E +:10E5800010BD10B5EAF77EFDF9F796FDEAF7EEFA51 +:10E5900010BD10B5EAF776FDFAF702FDEAF7E6FAE4 +:10E5A00010BD0323020003400020834208D18242B1 +:10E5B00006D0106801229043C278F92A00D01800D2 +:10E5C00070470023438103814360704700234381E8 +:10E5D0000381436043820382C36070477047704782 +:10E5E00070477047704770470123026810B59A431F +:10E5F00013005B8A128A1B041343984710BD10B5A1 +:10E60000FFF7F2FF10BD704783880200181E08D084 +:10E61000013B9BB2938012689B00D31800221868BC +:10E620001A607047F8B5C688050030000F00EBF798 +:10E630006DF8041C80B2B84200D23C1CA4B2A642C1 +:10E6400014D2A00000F013F9EA880600002A03D0D3 +:10E650009200296804F07EF8E8880021221A8000E0 +:10E660009200301804F094F82E60EC80F8BDC38856 +:10E6700010B58B4201D8FFF7D5FF10BDC38870B528 +:10E6800004000D008B4202D28188FFF7F0FFA580C5 +:10E6900070BD83880200181E08D0013B9BB2938096 +:10E6A00012689B00D318002218681A607047F8B5EA +:10E6B0008388040000208B4216D927688E00B81981 +:10E6C0004A1C0568934206D9013B5A1A311D920033 +:10E6D000791804F048F800212800A3882268013B3B +:10E6E0009BB2A3809B009950F8BDF8B50D008188BE +:10E6F00004001600A94214D9013189B2FFF7B7FF0F +:10E70000A288681C23688000071F521BD91918189B +:10E71000920004F028F82368DE51A3880133A38017 +:10E7200002E02900EBF7A2F8F8BD7047F7B50689BB +:10E7300047680020B04205D28300FB588B421AD0B4 +:10E740000130F7E700248B1D8D880193B4420CD271 +:10E75000A300F9588B889D420AD106312A000198FE +:10E7600003F0E9FF002803D104E00120404202E069 +:10E770000134EBE72000FEBD704710B5EBF770FDEC +:10E7800010BD10B5FFF70DFF002804D00089063832 +:10E7900043425841C0B210BD10B5EBF799FD10BD12 +:10E7A00010B500F092F910BD10B503F076FE10BD63 +:10E7B0001FB5D3B28AB281B2684600F075FB05B0CE +:10E7C00000BD10B5002B00D11033EBF74DFE10BD8E +:10E7D00010B5ECF781F801214942FEF701FF10BDA9 +:10E7E00010B500F06EF910BD704710B5002803D0C9 +:10E7F0008188063000F0D2F810BD0123820705D1D0 +:10E80000002803D0000F43425841C3B2180070479C +:10E8100010B50A008188EBF715F810BD01220368D6 +:10E82000934318888010704770B504680500002C69 +:10E8300006D02000EBF760F9A9882000EBF798F9E3 +:10E8400070BD10B5002811D0C468002C09D0236811 +:10E85000436063688360A368C3602000EBF714FB28 +:10E8600004E0EBF711FB2000EBF766FD10BD03237E +:10E870000330984310B5041D2000EBF719FB8023EB +:10E88000DB051C4310C010BD10B5031E08D0FFF7F8 +:10E89000EEFF8023021F11689B050B4313600300EA +:10E8A000180010BD10B50400FFF7A7FF002802D123 +:10E8B0002000EBF7CFF810BD10B50430FFF7B4FF20 +:10E8C00010BD10B581880C30EBF752F910BD10B5B2 +:10E8D0004068EBF729F910BD10B504000430FFF7CC +:10E8E000A3FF20000C30FFF79FFF10BD012210B5E1 +:10E8F00008C89343198804398908EBF739F910BD22 +:10E9000003207047808880000F3080087047022005 +:10E9100070470520704710B5EBF7CAFC10BD10B565 +:10E92000ECF780FB10BD7047704770477047704729 +:10E93000704710B5040003F0E8FE200010BD10B5CC +:10E94000040003F0E2FE200010BD10B5040003F047 +:10E95000DCFE200010BD10B5040003F0D6FE200040 +:10E9600010BD10B5FFF79EFFECF7BEFB10BD10B554 +:10E9700004002000EBF726FC1420ECF753FBF8E72B +:10E9800010B50400EBF760FC200003F0BEFE200091 +:10E9900010BD704710B5ECF7A7FB10BD10B5EBF735 +:10E9A00047FC10BD10B518C96210E10701D58158A8 +:10E9B000CB588018984710BD70B5DD24A400050021 +:10E9C0000059002804D002F019FB836D9B0702D484 +:10E9D00000F07BF870BD2859F2F74CF90368132159 +:10E9E0005B6A9847642003F063FDF1E782B030B5BD +:10E9F00085B008920500082202A8099303F0AAFE38 +:10EA0000039B029C5810DB0701D52B581C592D186D +:10EA10000AA90822684603F09DFE089A099B28006F +:10EA2000A04705B030BC08BC02B0184782B01FB583 +:10EA3000040006920793120C1A2A14D00AD8042A4A +:10EA400023D0052A27D1E6235B00C15801A800F096 +:10EA500083FD20E01B2A18D01C2A1CD1E130FF3096 +:10EA6000EFF748FE17E06930FF30002100F0DCFCD2 +:10EA700020009130FF30002100F0D6FC2000B9309A +:10EA8000FF30012101F0EAFC05E0E4235B00E158DE +:10EA900001A800F081FC1FBC08BC02B018473ADF97 +:10EAA000704712DF704713B56B46DC1D0023200052 +:10EAB0002370FFF7F6FF2078013843425841C0B277 +:10EAC00016BD80235B05586E704710B5EBF7F8FE56 +:10EAD00010B58368984710BD704770B506000D00EB +:10EAE000141E11D0936D002B02D01E20EBF72EFFC9 +:10EAF0002B683268002A02D0111D31601460646DE9 +:10EB00000133002CF5D12B6070BD10B5040003F06B +:10EB1000FCFD200010BD72B601650B68002B03D10F +:10EB200043658365086007E05A6D002A01D0130031 +:10EB3000FAE758658365426562B67047036D002B3E +:10EB400012D072B6826D436D002A01D0536501E088 +:10EB5000026D1360436D002B01D0826D9A65002316 +:10EB600043658365036562B6704770B504000E00A7 +:10EB70001500ECF70FF9002805D001233200290019 +:10EB80002000ECF763F970BD10B5ECF769FA041ECC +:10EB900001D1ECF7DDF9200010BD10B50C00804765 +:10EBA000A047ECF7A1FA10BD10B5ECF7F3F8002878 +:10EBB00001D0ECF799FA10BD70B5140003001000F5 +:10EBC0000D0098472000A8472000FFF7EDFF70BD1B +:10EBD00010B5ECF7A7F9ECF7BBF9FAE70300F0B5CD +:10EBE0008208980702D1181E01D137E00132541C67 +:10EBF00072B6802621C93606A84217D20368002BB8 +:10EC000011DA5B005B08990041180F68002F08DAE1 +:10EC1000A94206D231007F007F08DB191943016049 +:10EC2000F1E7A34205D29B00C018E5E762B60020D9 +:10EC300014E00232934203D992008218954204D81C +:10EC400003685B005B08036006E080211B1B09066C +:10EC5000043A0B431360046062B60430F0BD70B533 +:10EC6000040008000E00ECF701FB0500002C0ED09C +:10EC700000280CD0231F1A689200B24200DD320037 +:10EC80002100280003F066FD2000ECF725FB28009A +:10EC900070BD10B50800ECF7E9FA10BD10B508001A +:10ECA000ECF71AFB10BD10B508001100FFF7D7FFF5 +:10ECB00010BDF7B51D0008AB1B880400103016000E +:10ECC0000F00019300F0E5F86A4600239288278040 +:10ECD0006680A5602000E360A28063622362FEBDBF +:10ECE00010B5838804009B0702D5806803F00DFDF2 +:10ECF000200010BD82B030B5046A87B00B930500C8 +:10ED00000A920123002C14D110220AA902A803F0B0 +:10ED100021FD182003F0E7FC0400082204A968463E +:10ED200003F018FD029A039B200000F0CDF82C623E +:10ED30001BE02269002A02D001331400F9E7092BF5 +:10ED400013DC10220AA902A803F004FD182003F026 +:10ED5000CAFC0500082204A9684603F0FBFC029ADD +:10ED6000039B280000F0B0F8256107B030BC08BC58 +:10ED700002B0184710B50400006800F04BFA2000FC +:10ED800010BD70B5060008000D0003F041FD040041 +:10ED90000530ECF76BFA306000F02BFA3068290090 +:10EDA0004480621C043003F0D5FC70BD1FB5040024 +:10EDB000080001A9EBF750FD200001A9FFF7E1FFD2 +:10EDC000200004B010BDF8B50B68170002241C5FCA +:10EDD0001368050002229B5E0E00E418601DECF72C +:10EDE00045FA286000F005FA28683168448002235B +:10EDF000CA5E0430043103F0ADFC2B683968181D7D +:10EE0000336802229B5EC0180223CA5E043103F0FD +:10EE1000A1FC2B6828001C1900232371F8BD10B534 +:10EE200004000868206000F0EBF9200010BD70B508 +:10EE30000B68040000680D00984205D000F0EAF964 +:10EE40002868206000F0DCF9200070BD70B5136800 +:10EE500004005D880868002D01D1206004E040882E +:10EE6000002804D11800236000F0CAF902E0200055 +:10EE7000FFF7A9FF200070BD0023994207DB02685D +:10EE80000223D05E0023884201DD51180B7918005F +:10EE90007047002310B5038043800400ECF7DAFAD2 +:10EEA000A060E160200010BD70B5018042800400C8 +:10EEB0001D00ECF7CFFAA060E160002D02D0200029 +:10EEC000ECF752FB200070BD82B010B50400039334 +:10EED0000292FFF7DEFF102202A9200003F03AFCA5 +:10EEE00000232000236110BC08BC02B0184710B5F5 +:10EEF0000400006800F08EF9200010BD10B50A0073 +:10EF0000002103F045FC10BD10B504000868206026 +:10EF100000F076F9200010BD70B50B6804000068A1 +:10EF20000D00984205D000F075F92868206000F0C7 +:10EF300067F9200070BD10B50068418883880630ED +:10EF40005943FFF7DBFF10BD10B504000023ECF7B9 +:10EF500099FB200010BD10B50400ECF793FB2000D6 +:10EF600010BDF0B587B004910CA909780700059190 +:10EF7000016800200391498801918A4277DA039958 +:10EF800089888B4273DA049C2468A4466488151926 +:10EF9000029485426BDD6446A4881E19864266DDB4 +:10EFA000002A03DA00952800019D03E00198029DE4 +:10EFB000801A0090A84200DD0095002B03DA8E42F3 +:10EFC00005DD0E0003E0CE1AA64200DD26006046F5 +:10EFD0000024D117554206302940A34202DA029C90 +:10EFE00064425C43641804190398111C0630002A1B +:10EFF00000DA0021002509B2AB4201DD019D5D432D +:10F00000059B69184518002B27D000221000B2423A +:10F010002DDA002300998B4206DAE15C002901D049 +:10F02000E95401300133F5E7049B01321B68019379 +:10F030005B88E4183B685B88ED18E8E7210028004E +:10F04000009A03F087FB049B1B6802935B88E4181B +:10F050003B685B88ED18019B01330193019BB34230 +:10F06000ECDBF043009BC01730404343180007B06F +:10F07000F0BDF0B587B000AF09687B613B6BB8604D +:10F080003961D418786B7B6949881B188C4201DA86 +:10F09000002C00DC0C0038698688B34202DA002BB1 +:10F0A00000DD1E003300684663430733DB08DB00E6 +:10F0B000C31A9D4678697B6041433B6989180633D2 +:10F0C0005D186B46FB607B699E420EDD29002200C5 +:10F0D000F86803F03FFB3B695B88ED18FB689B1900 +:10F0E000FB607B6901337B61EDE7B86832B221B226 +:10F0F0007B68ECF7C7FABD46B86807B0F0BD10B53D +:10F100000400096804200A5E8B1D0220095E2000AD +:10F11000ECF7B8FA200010BD10B50400006800F04C +:10F1200079F8200010BD10B504000868206000F0D8 +:10F1300067F8200010BDF8B5D443E4171440070069 +:10F1400020000C301E000D00ECF790F8386000F045 +:10F1500050F83B681C7238684660002D04D00930B6 +:10F160002200290003F0F6FAF8BD002310B50400D0 +:10F170001A001900FFF7DFFF200010BD002310B5B3 +:10F1800004000A001900FFF7D6FF200010BD10B5DB +:10F190000400FFF7D0FF200010BD70B50B6804001D +:10F1A00000680D00984205D000F034F8286820600F +:10F1B00000F026F8200070BD0368096810B5012032 +:10F1C0008B420CD01C7A0A7A0020A24207D1093364 +:10F1D0001800093103F0AFFA43425841C0B210BDE4 +:10F1E0000068093070470368187A704703685868E8 +:10F1F000704703230380704710B5ECF755FB10BD33 +:10F2000010B50400ECF750FB002802D1238802332C +:10F21000238010BD10B50400ECF746FB002809D18F +:10F220002388023B9BB2012B01D0238002E0200007 +:10F23000ECF752F810BD036870B5040001811B6A39 +:10F240009847236805005B692000984720812800C3 +:10F2500070BD00897047036870B5040081721B6A35 +:10F26000984723680500DB6920009847A0722800B2 +:10F2700070BD807A7047704710B5040003F045FAFE +:10F28000200010BD0C300EC80800524348435B43B9 +:10F290008018C01870477FB50400FFF7F3FF250002 +:10F2A0009023060031351B0498422AD9638F002B26 +:10F2B00007D1013308221B216846FFF7F5FD012322 +:10F2C000638790239B049E4219D9A38F002B07D1FB +:10F2D000013309221B216846FFF7E6FD0123A387BE +:10F2E0008023DB049E420AD9E38F002B07D1013330 +:10F2F0000A221B216846FFF7D7FD0123E38700237D +:10F300002B702B78042B02D801332B7003E00023E1 +:10F31000E387A38763872000ECF7C0FB021E0B2A5C +:10F3200013D02300A18E3033814204D11A78042AED +:10F3300004D8013201E00022A0861A70A28E618EEC +:10F34000914208D01B78042B05D9628601231B212A +:10F350006846FFF7A9FD7FBD30B50400036A8BB096 +:10F36000009302AD416A8269C369280001F00DFE75 +:10F3700023000C3307CD07C30222A3792000934357 +:10F38000A371FFF788FF0123A1881A0006A8FFF7E1 +:10F390008BFD00200BB030BD70B50C0005000B6874 +:10F3A00008005B6A984721002B000C3115C915C372 +:10F3B000280070BD10B5040003685B6A9847E068D8 +:10F3C00010BD10B5040003685B6A9847206910BD42 +:10F3D00010B5040003685B6A9847606910BD10B5FA +:10F3E000040003685B6A9847A3799B0702D4200056 +:10F3F000ECF71CFCA06A10BD10B5040003685B6A42 +:10F400009847A3799B0702D42000ECF70FFCE06A31 +:10F4100010BD408E704710B50400ECF7ABFC200027 +:10F4200003F073F9200010BD0630C1777047012347 +:10F43000807918407047036870B5040001811B692A +:10F440009847236805009B69200098472081280081 +:10F4500070BD00897047704710B5040003F055F97E +:10F46000200010BD30B50400436BC26801699A1AD0 +:10F4700083698BB05A43836B92125B1AC1694263F2 +:10F480004B439B128363C16B406902AD091A206A2A +:10F4900041438912E16300912800216C01F075FD60 +:10F4A0002300283307CD07C30123A1881A0006A82B +:10F4B000FFF7FAFC00200BB030BD002310B58371BC +:10F4C000643303810368040081801B69984702222A +:10F4D000A3799343013A1343A37110BD84B030B5AF +:10F4E000069303000491059204AC0C3326CC26C38A +:10F4F00026CC26C322681A600222837913438371C3 +:10F5000030BC08BC04B0184702238079184070470B +:10F5100080220023D2008261C26102620222C360A3 +:10F52000036143614362837993438371704741640C +:10F53000704773B50C00050016000B680800DB6906 +:10F540009847E36B280001960093626BA36B216CD4 +:10F5500001F0DCFC280076BD70B50C0005000B68DE +:10F560000800DB69984721002B00283115C915C315 +:10F57000280070BDF0B587B0010003A8FFF7ECFFCD +:10F580000398F8F715FC040004980D00F8F710FC38 +:10F59000060005980F00F8F70BFC2200009001917F +:10F5A0002B0020002900F7F7DFFD320004000D00DA +:10F5B0003B0030003900F7F7D7FD02000B002000B8 +:10F5C0002900F6F781FE009A019B04000D0010004F +:10F5D0001900F7F7C9FD02000B0020002900F6F71B +:10F5E00073FEFAF7D3F8F8F7ADFB07B0F0BD10B52E +:10F5F00004000368DB699847A06A10BD10B50400D9 +:10F600000368DB699847E06A10BD10B50400036821 +:10F61000DB699847206B10BD82B030B585B0089289 +:10F620000500082202A8099303F094F8039B029CAA +:10F630005810DB0701D52B581C592D180AA9082290 +:10F64000684603F087F8089A099B2800A04705B090 +:10F6500030BC08BC02B01847F8B50A6803680E0051 +:10F660000700981AF6F7AAFD72687B68051C981ABD +:10F67000F6F7A4FDBB68041CB068181AF6F79EFDE7 +:10F68000291C061C281CF6F7DDFA211C051C201C71 +:10F69000F6F7D8FA011C281CF5F794FF311C041C5E +:10F6A000301CF6F7CFFA011C201CF5F78BFFF8BDD4 +:10F6B000F0B585B0019002910392FFF7CDFF0127CD +:10F6C000041C061C039B9F4217DA0C217943029B02 +:10F6D00001985918FFF7C0FF051C011C201CF5F705 +:10F6E00001FE002800D02C1C291C301CF5F7E6FD7B +:10F6F000002800D02E1C0137E4E7211C301CF6F74F +:10F70000B5FB05B0F0BDF0B58BB009938023DB00ED +:10F710000025C36003614361002304000C270791A7 +:10F72000089205604560856085610293119B9D424A +:10F7300018DA39006943109B07A85918FFF78CFFA6 +:10F74000F8F7B0FBFAF722F8F8F7FCFAF6F736FD0F +:10F75000061C011C0298F5F7B1FD002800D00296A6 +:10F760000135E3E700260023109D059301960096DE +:10F77000371C059B119A93425EDA290007A8FFF710 +:10F780006BFFF8F78FFBFAF701F8F8F7DFFB011CC6 +:10F7900003900298F6F78CF8FE218905F6F766FBD0 +:10F7A0000490381CF6F7E8FC07000498F6F7E4FC30 +:10F7B000874200DA07003800F6F700FD2B68079A49 +:10F7C000071C981AF6F7FAFC0399F6F771F840004F +:10F7D00004994008F6F736FA011C0098F5F7F2FE96 +:10F7E000089B00900693069A6B68981AF6F7E6FC59 +:10F7F0000399F6F75DF8400004994008F6F722FAFD +:10F80000011C0198F5F7DEFEAB68019009980C35F4 +:10F81000181AF6F7D3FC0399F6F74AF84000049952 +:10F820004008F6F70FFA011C301CF5F7CBFE059BDC +:10F83000061C013305939CE70099081CF6F702FAB1 +:10F840000199051C081CF6F7FDF9011C281CF5F7A9 +:10F85000B9FE311C051C301CF6F7F4F9011C281CFC +:10F86000F5F7B0FEF8F71EFBF9F790FFF8F76EFB1F +:10F87000051C011C0098F6F71BF8391CF6F7E2F995 +:10F88000FE218905F5F79EFE8921C905F6F7DAF90B +:10F89000F6F772FC291CE0600198F6F709F8391CAC +:10F8A000F6F7D0F9FE218905F5F78CFE8921C90507 +:10F8B000F6F7C8F9F6F760FC291C2061301CF5F753 +:10F8C000F7FF391CF6F7BEF9FE218905F5F77AFE38 +:10F8D0008921C905F6F7B6F9F6F74EFC079B60617A +:10F8E0002360089B029800936360099BA360F6F76E +:10F8F00043FCA06120000BB0F0BDF0B50025040072 +:10F9000017000B002E0028002A0091B00791BA4280 +:10F9100008DA1968013240185968761899680C336A +:10F920006D18F4E73900F5F78DFB390020603000E1 +:10F93000F5F788FB390060602800F5F783FB3A0093 +:10F94000A06007992000FFF7B3FE00260DAB0890DA +:10F95000069605960393C8235B420493C8235B4233 +:10F960000293C8235B4201932200039B23CA23C353 +:10F970002268049B9446039A6344136062681D00E6 +:10F980009446029B039A63445360A2680993944689 +:10F99000019B039A6344936007993A0003980A9382 +:10F9A000FFF786FE0B90011C0898F5F79BFC0028DA +:10F9B00005D0099B0A9E06930B9B05950893019B16 +:10F9C000C83301931A00C8235B009A42CCD1029B32 +:10F9D000C83302939342C4D1049B029AC833049360 +:10F9E0009342BBD1059B2268934206D16368069A75 +:10F9F000934202D1A368B34205D0059BA660236061 +:10FA0000069B6360A7E7200011B0F0BD70B504004D +:10FA10000D00160086B003A8FFF76FFF20000196C7 +:10FA200000950399049A059BFFF76DFE200006B030 +:10FA300070BD10B518C96210E10701D58158CB58C7 +:10FA40008018984710BD10B50021406C02F0A5FD4C +:10FA500010BD10B50400ECF79BFE200002F055FE2F +:10FA6000200010BD10B50400ECF784FE200002F069 +:10FA70004CFE200010BD70B5050004007435012156 +:10FA80002800EBF7C1FE2200563213780133DBB2B7 +:10FA90001370E17901318B4225D1002326001370C8 +:10FAA000226D54360221525E33882021934205DABA +:10FAB000200019B25030FFF7DFF90100E27900238E +:10FAC0002800EBF757FE226D33880221525E9342E5 +:10FAD00007DD2300002248331A702000ECF762FF94 +:10FAE00001E00133338070BD70B505000600826D02 +:10FAF0005C350221525E2B8804007436202193422B +:10FB000004DA19B25830FFF7B7F9010000233000CA +:10FB10001A00EBF72FFEA26D2B880221525E934252 +:10FB200007DD2300002248331A702000ECF73AFF6B +:10FB300001E001332B8070BD73B504000600250081 +:10FB4000743630006435FFF7F6F90023EA5E2100D1 +:10FB50000023603100933000FFF703FA002804D13E +:10FB600023006C331B78002B04D1230066331B78F1 +:10FB7000002B07D12300002248331A702000ECF735 +:10FB800011FF06E02A885BB29B182B8001236C349E +:10FB9000237073BDF0B50600002105000400663631 +:10FBA000006E7156408864350023EA5E4B1D1B1AB7 +:10FBB000200085B06C3003909A4202DC0378002B61 +:10FBC00024D127007437002A04DD494209B23800E5 +:10FBD000EBF71AFE0023EA5E210000236031009358 +:10FBE0003800FFF7BEF90023F356002B05D12200A1 +:10FBF000483213702000ECF7D5FE0123039A1370EE +:10FC000000222B88B256D3182B800DE025004835F2 +:10FC10002B78062B03D120007430FFF78CF90023DA +:10FC200020002B70ECF7BEFE05B0F0BD70B50500EE +:10FC300048352B780400002B33D0EBF7C3FB2300AF +:10FC40004C331A881018220080B218804A32128869 +:10FC5000824226D800221A802B78022B02D1200063 +:10FC6000FFF709FF2B78032B02D12000FFF73CFFA1 +:10FC70002B78042B02D12000FFF75EFF2B78052B99 +:10FC80000BD02B78062B08D02B78072B09D100231B +:10FC900020002B70ECF786FE03E02000FFF77AFFD0 +:10FCA000F2E770BD1FB5036F827A9B6804000133D1 +:10FCB0009A4207D18188012302226846FFF7F4F8AF +:10FCC000002306E0ECF7F4FD2000FFF7AFFFA37A76 +:10FCD0000133A3721FBD10B583790400DB0720D563 +:10FCE000027B022A02D1FFF7DDFF1AE0837A016F5F +:10FCF0000133DBB2837289688B4201D100238372A6 +:10FD0000002A02D12000ECF7D3FD237B012B05D183 +:10FD1000637300232000A373ECF7AEFC2000FFF711 +:10FD200085FF10BD70B504000D1E022D06D1EBF746 +:10FD300049FB052802D00520EBF7F6FA237B022BBE +:10FD40000CD1022D0AD0A66E002E05D03000EDF7A2 +:10FD500023F9300002F0D9FC0023A366257370BD9F +:10FD6000007B7047407A7047F0B5837987B0040014 +:10FD70000D00DB0702D5002902D035E0002933D081 +:10FD8000102100220127206F41568368CB188B4237 +:10FD900004DD3E008E4001313243F8E7112100239B +:10FDA00001274156C0680818884204DD3E008E4095 +:10FDB00001313343F8E71A43002D08D00123002115 +:10FDC00001A8F4F7B5FC0122A37913430BE02B0043 +:10FDD000290001A8F4F7ACFC290001A802F0A7FB58 +:10FDE0000122A3799343A37107B0F0BD10B501219F +:10FDF000FFF7BAFF10BD10B50021FFF7B5FF10BD2A +:10FE000010B57430FFF797F810BD052313B50193B3 +:10FE100000930023040074311A00FFF72AF9200030 +:10FE200016BD70B5037B0400022B0AD00221FFF738 +:10FE300079FF482002F057FC0500216FEDF764F8C8 +:10FE4000A566A06E00F0E3F870BD10B50400F3F7EE +:10FE50000BFF00232000237510BD1FB503AC63709A +:10FE600000232270009322000233ECF769FF04B0F4 +:10FE700010BD1FB50F2401236C4400932300ECF741 +:10FE80006FFF002800D1207804B010BD70B50400C9 +:10FE900016001D0003220F23EDF788FA2000310021 +:10FEA0000F2302221030EDF781FA200029000F23E2 +:10FEB00001222030EDF77AFA200004990F23042262 +:10FEC0003030EDF773FA200005990F2305224030FA +:10FED000EDF76CFA200006990B2311225030EDF754 +:10FEE00065FA200007990B230C226030EDF75EFACB +:10FEF0000B2320001A0008997030EDF757FA200004 +:10FF000009990B2312228030EDF750FA20000A994C +:10FF10000B230A229030EDF749FA20000B990F23AA +:10FF20000622A030EDF742FA20000C990B231A228A +:10FF3000B030EDF73BFA20000D990B231422C030AE +:10FF4000EDF734FA20000E990B231722D030EDF78D +:10FF50002DFA20000F990B231622E030EDF726FA38 +:10FF6000200010990B231522F030EDF71FFA601CCA +:10FF700011990B231022FF30EDF718FA20001130F1 +:10FF800012990B230022FF30EDF710FA20002130E8 +:10FF90000B231E221399FF30EDF708FA200070BDE5 +:10FFA00010B518C96210E10701D58158CB588018E7 +:10FFB000984710BD82B030B585B008920500082280 +:10FFC00002A8099302F0C6FB039B029C5810DB07B2 +:10FFD00001D52B581C592D180AA90822684602F091 +:10FFE000B9FB089A099B2800A04705B030BC08BCA3 +:10FFF00002B0184770B504000D001822002102F06D +:020000040003F7 +:10000000C7FB2900200002F0DBF9200070BD036867 +:10001000426803219A18836810B5D018F5F712F8D2 +:10002000A92352215B00FF311A00884204DC083A00 +:10003000FF3A904200DD0200FF2008219B1A58433E +:10004000FF31F4F7FFFF10BD0069002904DD00282F +:1000500002D00139406AF8E7704710B50400EDF7A7 +:100060008DF8200002F051FB200010BDF7B5838809 +:1000700004005A070FD59A0648D4DA060BD50100BA +:1000800008221831684602F065FB22696369200086 +:10009000FEF730FE3AE00422022601271343A38034 +:1000A000A38833420BD0210008221831684602F0A1 +:1000B00051FB22696369A06800F0F4FE10E03B4246 +:1000C00008D0E368206900936169A269E369A568C3 +:1000D000A84705E020696169A269E369A568A847A6 +:1000E0001022A38813420ED0256A002D0BD02900C0 +:1000F000A01802F02FFB2B692800236202F005FBF9 +:10010000EAF726FFCCE704229343A380F7BD030060 +:1001100072B64069002807D002695A61002A00D1EE +:100120009A61DA8B013ADA8362B67047F7B5002537 +:1001300007002E000469002C1BD0A288636A11B24C +:10014000002914DA04210A4211D1002E01D13B61A9 +:1001500000E07362636A20000193FEF7C1FD200096 +:1001600002F0D3FA340001352600019CE3E7019345 +:10017000FAE72800FEBD70B5012286B004000D002C +:100180008669EDF739F8002827D1E38B092B24D8AD +:100190002900102202A802F0DDFA182002F0A3FACA +:1001A000050004A90822684602F0D4FA029A039BCB +:1001B0002800FEF789FE72B6002E03D163696561DF +:1001C0002B6102E033692B6135612B69002B00D173 +:1001D000A561E38B0133E38362B606B070BD82B0E4 +:1001E00010B502A902920393FFF7C5FF002010BCCF +:1001F00008BC02B0184770B50500FFF797FF28004C +:10020000FFF785FF041E0BD0010000222800ECF749 +:10021000F3FF200002F079FAEAF760FE0028EED141 +:1002200070BD82B030B585B008920500082202A8E2 +:10023000099302F08FFA039B029C5810DB0701D54B +:100240002B581C592D180AA90822684602F082FA78 +:10025000089A099B2800A04705B030BC08BC02B032 +:100260001847028903008A4202D18079012305E000 +:10027000428900208A4202D19879022318407047AF +:10028000028903008A4202D18079042305E0428971 +:1002900000208A4202D198790823184070470289C9 +:1002A00003008A4202D18079102305E042890020B0 +:1002B0008A4202D19879202318407047038910B5EB +:1002C0008B4207D183790124002A01D0234300E027 +:1002D000A343837143898B4207D183790221002A8A +:1002E00001D00B4300E08B43837110BD038910B52F +:1002F0008B4207D183790424002A01D0234300E0F4 +:10030000A343837143898B4207D183790821002A53 +:1003100001D00B4300E08B43837110BD038910B5FE +:100320008B4207D183791024002A01D0234300E0B7 +:10033000A343837143898B4207D183792021002A0B +:1003400001D00B4300E08B43837110BD82B0F0B548 +:1003500089B00E920F93078995B20400BD4200D177 +:1003600047890EAB5E88022E23D0052E0FD0012EBA +:100370006FD1290020003200FFF7A0FF39002000D4 +:10038000FFF76FFF002864D0A18833000CE029003C +:1003900020000122FFF7AAFF39002000FFF770FFBD +:1003A000002856D00123A188320004A8FEF77CFD66 +:1003B0004FE039002000FFF754FF002815D032002D +:1003C000A18801236846FEF76FFD29002000FFF792 +:1003D00057FFA68800282DD039002000FFF750FFD6 +:1003E000002827D00123042226E029002000FFF75F +:1003F00056FF00280ED1267B012E0BD129002000AC +:10040000FFF73EFF002821D033000422290004A872 +:10041000FEF74AFD290020000022FFF74FFF2900C8 +:1004200020000022FFF762FF002229002000FFF7D2 +:1004300075FF0EE001230322310004A8FEF734FD0E +:10044000012239002000FFF769FFE3E733000322B0 +:10045000DCE709B0F0BC08BC02B018470173704774 +:10046000032380791840033843425841704710B540 +:1004700018C96210E10701D58158CB5880189847F8 +:1004800010BD70B5837904001B0706D5806800F0A5 +:100490009BFD0E23E35683420FD02000ECF794FF20 +:1004A000082002F020F90E216156050000F080FDC1 +:1004B0000822A379A5601343A371002070BDD0B5B5 +:1004C000040086B08AB20023818802A8FEF7ECFC03 +:1004D000049E059FA06800F0FFF903000B430AD0BB +:1004E000049A059B00920193121A8B4102A8049270 +:1004F0000593EBF739F832003B00A06800F0E9F90A +:1005000006B0D0BD1FB5837904005B0602D5052176 +:10051000FFF7D5FFA3799B0605D5A1880123022209 +:100520006846FEF7C1FC1FBD1FB5837904005B065A +:1005300002D50421FFF7C3FFA3799B0605D5A18847 +:10054000012303226846FEF7AFFC1FBD702310B5E0 +:1005500082791A4201D0ECF737FF002010BD7047B6 +:1005600010B5040002F0D1F8200010BD30B5040031 +:1005700085B02569002D1ED0EA78012A06D0022A0E +:1005800009D12000203000F05EF80AE02000183089 +:1005900000F017F805E092B201231E216846FEF72D +:1005A00083FC23699D42E4D12000EDF753FA280033 +:1005B00002F0ABF8DDE705B030BD00230160436019 +:1005C00070471FB504000068EDF744FA0023626825 +:1005D00043629A4201D160600BE0516A002902D067 +:1005E00001330A00F9E7032B02DD02F08EF806E082 +:1005F000506201231D211A006846FEF755FC1FBDFD +:1006000082B070B58CB0119303781092002B11D189 +:10061000132201A90A708B70123A02334A70CB7010 +:1006200010AC02AB64CC64C31A002368136040684A +:10063000EDF724FA0CB070BC08BC02B018470023D8 +:1006400041600370704770B504004068EDF702FA2E +:100650000123050023700430EAF786FF00232800F9 +:10066000237002F052F870BD10B518C96210E1078E +:1006700001D58158CB588018984710BDF8B50E00A9 +:100680001C00150006AA108807AA1788B84208D0CF +:10069000335C290023700130F4F7BAFD013488B2CD +:1006A000F4E7F8BD4C300078704703000200503387 +:1006B0004E321B8811888B4204D91188023A107877 +:1006C000401800E01088C01A7047020003005C3236 +:1006D0005A3311881B88994205D91188043A107839 +:1006E000C318581A01E01088181A704710B5040092 +:1006F000012905D12000FFF7E8FF0028FADC04E01B +:10070000022902D10020EAF78DFC10BD10B504309B +:100710000022F3F785FC10BD10B509681300022410 +:100720000A5F0431EDF70AFC10BDF7B5150000AF04 +:100730007B602B000E0069460833DB08DB00CB1A18 +:100740009D46013200210400684602F021F87B68D2 +:100750002A0069463000EDF783FC002803DC200006 +:10076000EAF7E8FE04E002B269462000EAF7B8FEC4 +:10077000BD462000FEBD13B50C0001A8EEF722F81F +:10078000210001A8EEF730F813BD73B50D00140079 +:100790001E0001A8EEF716F833002A00210001A878 +:1007A000EEF75CF873BD07B5019280220091520507 +:1007B000136952696946133A5A430223FFF7E5FF6A +:1007C00007BD84B010B504928022039105935205B1 +:1007D000116953695269113B133A4A4359430F9BBC +:1007E0005B1AD21803A90C23FFF7CFFF10BC08BC7B +:1007F00004B0184710B50400EDF7E6FD200010BD69 +:100800008023F7B55B051A695D690191113D554378 +:10081000EDF7DAFD061E1FD0302001F064FF302214 +:1008200000210400002701F0B3FF0835B7420DDABC +:1008300029003022200001F08DFF2100019801F0F5 +:10084000DDFF002802D030350137EFE72000B74246 +:1008500002D101F05AFF0020FEBD10B50968043135 +:10086000FFF7CEFF10BD10B509680431EDF7DCFDD0 +:1008700010BD52DF704712DF7047704710B504009B +:1008800001F043FF200010BD10B50400EAF7D4FDCD +:100890000022A46801238A4202D1844200D91300B5 +:1008A000180010BD10B50400EDF724FF1022A35E60 +:1008B0001222A05E181A10BD10B5EDF71BFF10BD77 +:1008C00010B50400EDF75EFF200001F01EFF2000D0 +:1008D00010BD026543657047416D006D704729DFAB +:1008E000704728DF7047002030B51C1A002C06DD49 +:1008F000155C0C5C0130AC43F7D0012000E0002017 +:1009000030BD10B503685B6A984710BD10B5040090 +:10091000EEF7DAF8200001F0F8FE200010BD10B567 +:10092000C9B20D22FFF7A5FAC7384342584110BD9E +:1009300010B503685B6A984710BD10B50400EEF768 +:1009400007FA200001F0E1FE200010BD10B5C9B289 +:100950000D22FFF78EFA5A384342584110BD10B5A8 +:100960000368DB69984710BD10B50400EEF766FA1E +:10097000200001F0CAFE200010BD10B5C9B2072248 +:10098000FFF777FAC4384342584110BD10B50368E9 +:100990005B6A984710BD10B50400EEF769FB2000B4 +:1009A00001F0B3FE200010BD10B5C9B20F22FFF751 +:1009B00060FA33384342584110BD10B50368DB6913 +:1009C000984710BD10B50400EEF70CFC200001F0B4 +:1009D0009CFE200010BD10B5C9B24F22FFF749FAA6 +:1009E00040384342584110BDA7DF7047A9DF704728 +:1009F000AADF704768DF704710B50368002B01D08D +:100A00000800984710BD10B50368002B01D00800FE +:100A1000984710BD10B50368002B01D00800984717 +:100A200010BD10B50368002B01D00800984710BD19 +:100A300010B50368002B01D00800984710BD10B511 +:100A40000368002B01D00800984710BD10B50400C2 +:100A5000EEF736FC200001F058FE200010BD1FB557 +:100A60000123FA211A0089006846FEF71DFA05B035 +:100A700000BD0022431C0270C11D1A7001338B425D +:100A8000FBD1704770B51D000E001100C27F04003D +:100A9000931C5B1901201F2B12DC2B18A354E37F3E +:100AA0002A001B18DBB2E377E654E07F0130C0B2C6 +:100AB000E077201801F04EFE0020E37FED18E57787 +:100AC00070BD0200010010B5036834320A319B6F1B +:100AD000984710BD10B50400FFF7F3FF2368211DF0 +:100AE000DB6F2000984710BD10B500220400027093 +:100AF000431C11341A700133A342FBD1418210BD53 +:100B000037B50D00F0F7B6F86B46DA1D0123040087 +:100B100019000A301570EEF7CFFC002802D1200032 +:100B2000FFF7CFFF3EBDF8B50D0016001F00F0F730 +:100B3000A1F80400092D03D1036831005B6B9847CD +:100B400020003B00320029000A30EEF7B5FC0028F7 +:100B500002D12000FFF7B5FFF8BD70B5F0F78AF8B5 +:100B600005000A3504001F220021280001F010FEB4 +:100B700000232000EB77FFF7A4FF70BD806810B55D +:100B8000002803D0F0F776F8FFF7A4FF10BD70B58A +:100B90008AB003AD06002800FFF76BFF13206844FE +:100BA000FFF767FF1A206844FFF763FF21206844BE +:100BB000FFF75FFF042301ACB06863710195F0F7A4 +:100BC00079F8036821001B699847A0790AB070BDC5 +:100BD00010B504001830FEF72AF90123636110BD37 +:100BE000022370B5436104000D00EAF725FC206183 +:100BF000002D07D008236269134304226361A3799F +:100C00001343A37170BD8023F0B55B0585B0080068 +:100C10005F6E0291FFF7F4F8012304240525019388 +:100C200029003800F4F70AFA08000199F4F780F96E +:100C30000523052200265D43019B039053433F1A81 +:100C40000193039B01339E420ADA042302989A1B04 +:100C500012B221B2FB337430EAF7B8FC0136F0E788 +:100C6000013CDDD205B0F0BD0130C07F704737B523 +:100C700004680D00002C0ED0011D0822684601F00A +:100C800069FD019A009B5010D20701D52258D35814 +:100C900020182900984737BD10B54A88838A90B03C +:100CA0000C009A4219D10B89002B16D0CB681B7807 +:100CB000012B12D18068EFF7DDFF036815215B6A15 +:100CC0009847FA20800001F0F3FB238804A80380F2 +:100CD000002301A90B70F2F7E7FD10B010BD7047BB +:100CE00010B5040001F011FD200010BD37B50468F7 +:100CF0000D00002C0ED0011D0822684601F02AFDCF +:100D0000019A009B5010D20701D52258D3582018C1 +:100D10002900984737BD37B504680D00002C0ED068 +:100D2000011D0822684601F015FD019A009B501034 +:100D3000D20701D52258D35820182900984737BD2B +:100D400082B030B585B008920500082202A8099348 +:100D500001F000FD039B029C5810DB0701D52B58C6 +:100D60001C592D180AA90822684601F0F3FC089ABC +:100D7000099B2800A04705B030BC08BC02B018474A +:100D800013B5836A4A88DB8B04009A420ED1838DA7 +:100D9000013383858068EFF77DFFA36A2200D98B3A +:100DA0000023046800931832E468A04713BD70B5AF +:100DB0000400013025000300002611351E700133A8 +:100DC0009D42FBD10023638201332370002A08D1A6 +:100DD0000B001033994207D0013B1A7802700130A2 +:100DE000F8E7102201F0BFFCA37B627B1B021343D8 +:100DF0002000638270BD10B500F000F9806D10BD59 +:100E000082B010B50400806803930292FFF7F3FFED +:100E100083070ED502AB1A88A068A2825B88E382A2 +:100E2000EFF738FF22000368218C14325C69042339 +:100E3000A04710BC08BC02B0184737B504680D00C5 +:100E4000002C0ED0011D0822684601F083FC019A97 +:100E5000009B5010D20701D52258D35820182900E2 +:100E6000984737BD82B030B585B00892050008229A +:100E700002A8099301F06EFC039B029C5810DB074B +:100E800001D52B581C592D180AA90822684601F0D3 +:100E900061FC089A099B2800A04705B030BC08BC3B +:100EA00002B0184782B073B50400061D069208A967 +:100EB00008226846079301F04DFC65693100069AE7 +:100EC000079B2068A84773BC08BC02B0184702689B +:100ED00010B594460A680023944507D104310430C4 +:100EE000102201F028FC43424341DBB2180010BD40 +:100EF00010B5EFF7BBFD406810BD10B5EFF7B6FDBC +:100F0000006810BD017042704360704782B0F0B558 +:100F100005920200069308AB1B7805ACE0CCE0C25A +:100F2000002B2ED04A78002A05D0069A5242426001 +:100F3000079A524282604A68022A08D0032A0DD0DA +:100F4000012A10D1026841685242016004E002683F +:100F50005242026042685242426004E042680168C4 +:100F6000524202604160012B04D0022B09D1436838 +:100F70005B4202E0426803680260436083685B4250 +:100F80008360F0BC08BC02B0184782B037B50400DB +:100F9000180007930B7806920193089B00930300B7 +:100FA0002000FFF7B3FF20003EBC08BC02B018478A +:100FB00010B50400F3F7D6FA200010BD10B50400F8 +:100FC00001F08CFA200010BD407840B2704702005A +:100FD0000B00F0B5126889B0019203AA15001E003B +:100FE0004068016809688C4692CE92C5DB68019919 +:100FF000D36000231361E04709B0F0BD10B5EFF7EF +:1010000039FE10BD02207047022070470020704753 +:10101000002070470220704702207047022070476E +:10102000022070470220704702207047022070475C +:10103000022070470220704702207047022070474C +:101040000220704702207047002313607047002081 +:10105000704702207047022070470220704702202C +:101060007047022070470020704700207047002022 +:1010700070470220704702207047416070478160CE +:101080007047C1607047016170474161704702203D +:1010900070470220704702207047022070470220EC +:1010A00070470220704702207047022070470020DE +:1010B0007047022070470220704700207047704739 +:1010C00002207047022070477047022070470020BE +:1010D0007047704766DF704748DF70470079704798 +:1010E0000C3070470C30704710B5FFF7F5FF10BD9E +:1010F00010B50368002B01D00800984710BD10B54B +:101100000368002B01D00800984710BD10B5036894 +:10111000002B01D00800984710BD10B50368002BC4 +:1011200001D00800984710BD0823F0B597B002AA77 +:10113000137106AA029202AA137310000EAB049355 +:101140000C00F0F70DFB0023061E9E4202D0237117 +:10115000A37136E00500072702AB1B7BA37102AB2E +:101160001B79AB4213D96379AB4201D8257128E0D2 +:101170003800684323681818029B0193019AAB005A +:1011800099580135072201F0E5FAEDB2E7E725713C +:101190000727002502AB21791B7B6918AB420FD9C9 +:1011A000637999420CDA794323685918049B0193B7 +:1011B000019AAB009858013500F0C4F9EDB2E9E7A7 +:1011C0002171300017B0F0BD10B5F0F76FFA10BD07 +:1011D00010B508001100F0F79FFA10BD10B5080017 +:1011E0001100F0F775FA10BD10B5080011001A00D3 +:1011F000029BF0F7F1F910BD70B5040000680028FB +:1012000004D0056901F081FA2800F8E7206070BD7C +:1012100010B50400EFF710FE200001F076FA200070 +:1012200010BD10B50400EFF711FE200001F06DFABB +:10123000200010BD10B50400EFF712FE200001F0F1 +:1012400064FA200010BD10B50400EFF713FE200073 +:1012500001F05BFA200010BD10B50400EFF714FE9A +:10126000200001F052FA200010BD10B50400EFF785 +:1012700015FE200001F049FA200010BD10B5040051 +:10128000EFF716FE200001F040FA200010BD70B507 +:101290000400E3692362256A002D08D0EB68210071 +:1012A00028009847236A002BF3D01B69F2E720003F +:1012B0001C30FFF7A1FF28006560A560E56025618F +:1012C000656170BD10B5FFF7E2FF002800D0062071 +:1012D00010BD10B50400EFF7F5FD200001F015FA80 +:1012E000200010BD10B50400EFF7F6FD200001F05E +:1012F0000CFA200010BD10B50400EFF7F7FD200038 +:1013000001F003FA200010BD10B50400EFF7F8FD5E +:10131000200001F0FAF9200010BD10B50400EFF72D +:10132000F9FD200001F0F1F9200010BD70B50400B6 +:10133000E36A2363256B002D08D0EB6821002800A9 +:101340009847236B002BF3D01B69F2E720002C3069 +:10135000FFF752FF20000830FFF74EFF2000143047 +:10136000FFF74AFF20002030FFF746FF280070BD3E +:1013700070B5037904000920002B20D0F2F762FA3F +:1013800003000520002B1AD12500FC35A86B00288E +:1013900003D1286C002806D10AE003685B6A9847ED +:1013A0000028F6D00BE003689B6A9847002806D116 +:1013B00020000C3000F043FA002800D1207170BDED +:1013C000F7B5037907000E001400002B08D008229F +:1013D0000021684601F0DCF90A256B461D710CE01E +:1013E000F0F73AF805000C20002D0FD10123082258 +:1013F0003B712900684601F0CBF93000EFF718FC8B +:10140000E36800906946200098472800FEBD10B5AB +:101410000400EFF7A3FD200001F077F9200010BDD4 +:1014200010B51F220021040001F0B2F90023E37778 +:1014300010BD10B50020EFF7B1FE10BDFC30836B7E +:1014400070B50400002B07D19920800001F04BF902 +:101450000500EFF7C5FEA563A06B70BDFC30836B84 +:1014600070B50400002B07D19920800001F03BF9F2 +:101470000500EFF7B5FEA563A06B70BDF0B50400E5 +:1014800087B0E36B2364266C002E08D0F36821003C +:1014900030009847236C002BF3D01B69F2E7200043 +:1014A0003C30FFF7A9FE2000267166710C30FFF773 +:1014B000A3FE20001830FFF79FFE20002430FFF726 +:1014C0009BFE200001AD3030FFF796FE3100280072 +:1014D000EFF776FE23002A00443383CA83C3EB6808 +:1014E0003100236566652800EFF76AFE23002A00B5 +:1014F000583383CA83C3EB6831006366A66628004D +:10150000EFF75EFE23002A006C3383CA83C33000EA +:10151000EB68E667A36707B0F0BD70DF704771DF67 +:10152000704760DF7047704710B5F2F70DF9002083 +:1015300010BD70477EDF704768DF704710B500F060 +:1015400064FD10BD022310B50B708C330B713F3B53 +:101550004B712D338B714A1C043100F02DFD10BDF1 +:1015600070DF704771DF704772DF704773DF70475D +:1015700074DF704775DF704776DF704777DF70473D +:1015800078DF704779DF70477ADF70477BDF70471D +:101590007CDF70477DDF704788DF7047142070471D +:1015A00064207047A0208001704710B50400FFF749 +:1015B000DFFF0323002806D12300012158331A78C6 +:1015C0008A431A700300180010BD03000800FC21B4 +:1015D000583310B51C78214019703B218A4200D045 +:1015E0002839FFF7C9FF03005A1E934103205B42CD +:1015F000184010BD030010B5FE330A00D98C0368F3 +:101600001B6A984710BD10B50800FFF7BFFF030025 +:101610005A1E934103205B42184010BD10B50800CC +:10162000FFF7B2FF03005A1E934103205B421840AC +:1016300010BD080010B51100FFF79CFF031E00D07D +:101640000323180010BD13B50C001100012C06D89F +:101650006B460622581C01F07DF8002005E0A31E11 +:10166000012B01D9032007E001206B4669461C705D +:10167000FFF776FF0028F5D116BD37B568460D0097 +:101680001400FFF76FFF032300280DD1002D02D0B7 +:101690006B461B782B70231E06D06B460622591C06 +:1016A000200001F057F8002318003EBD080010B5D7 +:1016B0001100FFF76FFF031E00D00323180010BDB9 +:1016C00010B50800FFF75CFF031E00D003231800CD +:1016D00010BD10B50800FFF755FF031E00D003230F +:1016E000180010BD10B50800FFF748FF002398420E +:1016F00003D00533112800D0023B180010BD08208C +:101700007047B830017000207047B9300170002078 +:10171000704702207047B83000787047B9300078C1 +:101720007047002070470200030010B5F3321178B3 +:101730006C309B6F984710BD10B518C96210E10757 +:1017400001D58158CB588018984710BD112337B563 +:10175000080001AC23700D0001F05AF8290082B294 +:101760002000FFF715FF031E00D0032318003EBD25 +:10177000F8B506000D00002407273300BA331B78A4 +:10178000A3420ED96B79A3420BD9390061432B6870 +:10179000072258187118BB31013400F0DBFFE4B2A6 +:1017A000EBE72C710020F8BD10B50C00C97F0120BB +:1017B0001F290ED8002901D103200AE0D37F200081 +:1017C000FFF7D2FE0028F7D1208CFFF7D9FE0028C2 +:1017D000F2D110BDF8B503680700DB6C0D000C7981 +:1017E00098470323844228D8002307212879DAB2B6 +:1017F000904208D90A005A432C680133125D032A2B +:10180000F5D1042319E03E000024BA3634702B7958 +:10181000A34211D9072319003078614358432B683C +:1018200038185918BB30072200F094FF3378013480 +:1018300001333370E4B2EAE700231800F8BD10B5B5 +:101840000400EFF7B5FB00280AD123000122FE3384 +:101850005242DA84BA34463B18705870207000E067 +:10186000062010BDFE30C1847047FE30C08C70472A +:10187000A0DF7047A4DF7047A5DF7047A6DF704781 +:10188000A8DF7047F7B50D00160000210822684652 +:101890001F00089C00F07CFF6A4623883100280066 +:1018A00013800197FFF7E8FF0323002803D16B465D +:1018B0001B88238003001800FEBD70B586B015009C +:1018C0006A4600200E00941DD380EFF767FC036882 +:1018D0001B699847FFF7C9FF012302A98B700023FA +:1018E0000E808B80CD608C60FFF7C8FF83B2181E1E +:1018F00000D0052006B070BDF8B5040000200D0032 +:101900001600EFF74BFC03681B6998472368DF69F3 +:10191000FFF7ABFF330001002A002000B847F8BDF5 +:10192000F0B5D48B02001E000023457985B0F83253 +:101930009D4223D908321700083F3F88A74210D1A3 +:101940001F33DB00C3180E249A8802236C442380C3 +:10195000036803AD00949F682B00B847021E02D0B5 +:101960000DE00133E4E723880620022B07D12B8802 +:1019700010009B0703D00123337000E0042005B062 +:10198000F0BD10B50278002A09D10C781300002CA4 +:1019900013D1438A488A1B1A584243410CE0002362 +:1019A000012A0AD10A78012A07D1013101300F3208 +:1019B00000F0C1FE43424341DBB2180010BD70B5D8 +:1019C00004000D006368A360A068002807D0C36806 +:1019D00029009847A368002BF4D01B69F3E770BD7A +:1019E00010B5C368984710BD30B5150087B00429FD +:1019F0000ED0052917D0032925D144300100040059 +:101A000004A8F0F7E3F9049B002B18D1059B14E020 +:101A10005830010004006846F0F7D8F9009B002B0D +:101A20000DD1019B09E06C300100040002A8F0F721 +:101A3000CDF9029B002B02D1039BDB0703D52900C4 +:101A40002000FFF7CDFF07B030BDF0B50B888FB099 +:101A500005000C00502B0ED004D8012B25D0182BDC +:101A600032D00CE1522B2FD03FD3532B00D006E1C4 +:101A7000CE88052146E002000023CE884179FC3261 +:101A800099423ED90832100008380088B0420AD185 +:101A9000302120339B005A59531CDB7F0B4200D06E +:101AA000D2E02E392EE00133EAE70C7AEB682B61A5 +:101AB0002869002800D1E2E0C368210098472B691B +:101AC000002BF3D01B69F2E7A3880AAE33802B6B9F +:101AD0006B63686B002800D1D1E0C3683100984780 +:101AE0006B6B002BF3D01B69F2E78B79012B05D0D0 +:101AF000022B00D0C3E00E89072103E00E890621E6 +:101B000000E002212B0000206A79F8330090009851 +:101B1000824200D8B3E00833180008380088B04289 +:101B200014D1062958D0072913D03200022900D039 +:101B300096E0A3880AA90B804E80237A0B71A38BB1 +:101B4000CB80E38B20340B81CC6040E000980130E7 +:101B5000DCE71022002102A800F01AFEA38802AAE6 +:101B600013805680E38B06AF9380238C0021D380B3 +:101B700023001022223338000193049300F008FE62 +:101B800002233B70009B20339B005B591A002A32D2 +:101B900011780022914206D0180002A9DB6C403077 +:101BA000984702AB9A89A0883900BA80FFF768FE8F +:101BB000BB88002B63D1A3880AA90B804E80A37A2F +:101BC0000B71E38BCB80238C0B81019BCB602800B6 +:101BD0001430FFF7F4FE52E006AF10220021380067 +:101BE00000F0D6FDA3887E803B80A38B0AAE102236 +:101BF00000213000BB8000F0CBFD01233370009B3F +:101C000020339B005B591A0029321178002291423F +:101C100005D0180039002C309B6B9847BA89B280E8 +:101C2000BB89002B0BD1BA68002A08D00121B379F7 +:101C30000B43B371BB883381FB88F2607381A0884A +:101C40003100FFF71DFE1AE0A11CC97F0134E07FBF +:101C500009020843990607D50321840704D5D28BCE +:101C60002800FFF7C1FE0AE00421DB06F7D50123B7 +:101C7000010019400B00594259410331EFE70FB001 +:101C8000F0BD77DF704778DF70477ADF70477CDF21 +:101C90007047A2DF7047A3DF704763DF704710B55E +:101CA00086B06B46DC1D00232370C15C02AA9954E8 +:101CB0000133102BF9D121001000FFF7EEFF0023B4 +:101CC000984200D12378180006B010BDF0B5160078 +:101CD000302497B000931CAB04CB01901B88029179 +:101CE00003931EAB1B88344004931FAB1B780593F2 +:101CF00021AB1F8822AB1B78069323AB1B7807937D +:101D0000002C33D00322002108A800F041FD01255A +:101D1000022308AA937010212A0008A80A4302701F +:101D2000009A0D33501E08AA52789A43042818D8F6 +:101D3000F3F7F4F80305070C1100012107E0012176 +:101D40000AE001210A431340302208E002210A433D +:101D50001340102203E002210A43134020221343C0 +:101D600002E02A4313400B4308AA53700FAD1C2214 +:101D70000021280000F00CFD621E944108AB644273 +:101D800023402E706B61002F05D0209B002B02D0CA +:101D90006B602F816F8109AC03220021200000F0CD +:101DA000F7FC0120069B079A03400240DB0011016B +:101DB000DBB20B431A00059B0340180002231343B8 +:101DC0000343A37032231E421FD0009B581E0428D9 +:101DD0001BD80F2223789343F3F7A0F80305070CD1 +:101DE0001100012107E001210AE001210B4313400A +:101DF000302208E002210B431340102203E00221AD +:101E00000B4313402022134323700C231E421FD088 +:101E10000098013804281BD80F2263789343F3F706 +:101E20007DF80305070C1100012107E001210AE0FC +:101E300001210B431340302208E002210B431340E1 +:101E4000102203E002210B4313402022134363704E +:101E50000AAD14220021280000F09AFC029B2A00FF +:101E60000A936B469B890FA92B816B461B8A0198AD +:101E7000AB811C9B6C602B61249BFFF70AFF80B237 +:101E800017B0F0BDF0B589B000930EAB1B8805000C +:101E90000F001600019303220FAB002102A81C784B +:101EA00000F076FC012302221C40144302AA947025 +:101EB0001900102202A81143020003AC01705170F6 +:101EC00020001422002100F063FC02AB63606B462B +:101ED0001B88109A23816B469B882100280003975A +:101EE000A3812661FFF7D7FE80B209B0F0BD7FDF86 +:101EF000704782DF7047A7DF7047A9DF7047AADF0E +:101F0000704700207047002070470020704710B5D0 +:101F1000F0F720F810BD10B5F0F7D4F810BD10B5EB +:101F2000F0F72CF910BD002070470020704700200A +:101F300070470020704729DF704728DF704710B5D1 +:101F4000FFF7F9FFF0F7B4FE10BD10B5F0F720FE73 +:101F500080225205136911699BB20138584389B236 +:101F6000F2F7E6FFFFF7E9FFF0F7A2FE10BD2EDF64 +:101F7000704732DF704733DF70474CDF70472EDF2A +:101F8000704751DF704710DF704711DF704761DF26 +:101F9000704710B508001100FFF7CBFA10BDAADF9B +:101FA000704744DF704711DF704713DF704700DF71 +:101FB000704770474DDF704730B500230D001400A7 +:101FC0008DB06946C21AD27B5A540133102BF8D116 +:101FD00000210D2204A800F0DBFB6A462B7868463E +:101FE000D3776B789377AB785377FFF7E3FF2F23A3 +:101FF0006B441B7823702E236B441B7863702D2356 +:102000006B441B78A3700DB030BD30B5037804006D +:1020100085B00D000020022B16D1611C032201A8FF +:1020200000F098FB211D032203A800F093FB02AAF5 +:1020300003A92800FFF7C0FF032202A901A800F0AE +:102040007AFB43425841C0B205B030BDA6DF7047AD +:10205000036810B50400002B05D1C06800F018FA21 +:1020600001236060236010BD10B5040000680028E3 +:1020700004D0E06800F00CFA6368C01A10BD10B517 +:102080008468FFF7F1FF201810BD10B50400C06888 +:1020900000F0FEF900236060A36010BD002310B5BE +:1020A0000360436083600400F1F704FEE0602000F9 +:1020B000FFF7EBFF200010BD10B50400F1F7FAFCAC +:1020C000200000F022FB200010BD836980681B689F +:1020D0001840431E9841704710B5043000F004FAD0 +:1020E00010BD436910B50100002B04D10368002B1B +:1020F00006D0984704E00068002801D004319847D2 +:1021000010BD10B5012903D0022904D1383000E0F8 +:102110002030FFF7E6FF10BD10B503689B689847B5 +:1021200010BD10B50A000300011D006900F078F928 +:1021300010BD10B5011D006900F08EF910BDC36A15 +:1021400010B50100002B04D18369002B06D09847FD +:1021500004E08069002801D01C31984710BD10B5FB +:102160000400F1F7F9FC200000F0CFFA200010BDC8 +:1021700010B50400436842699918FFF7D2FFE36A7B +:10218000002B04D1A369002B07D0984705E0A06974 +:10219000002802D021001C31984710BD10B5040062 +:1021A000FFF7C7FF0023A361E36210BD70B50D0008 +:1021B0000400FFF7BEFF6561206900F069F9291886 +:1021C0002000FFF7AEFF70BD18234A1C5A43821847 +:1021D000926810B55943002A05D14118CB68002BED +:1021E00009D0984707E04318DB68002B03D041185B +:1021F00010311800904710BD70B50D000400043078 +:10220000F1F7CCFEE56370BD10B5043000F059F96C +:1022100010BD10B50C000430F1F748FF200010BDD0 +:1022200010B5FFF7F1FF10BD10B5FFF7F2FF10BDBD +:10223000704710B5040000F068FA200010BD70B5BA +:102240000D000400F1F7E4FC2900201DF2F708FD61 +:1022500070BDF0B585B01C000AAB060003911700F5 +:102260001D78F1F719FD01235D40009523003A0028 +:102270000399300000F0DCF9201A441EA04105B09B +:10228000F0BDF0B585B01C000AAB06000391170045 +:102290001D78F1F701FD01235D40009523003A0010 +:1022A0000399300000F081F9201A441EA04105B0C6 +:1022B000F0BD10B50120FAF7EDFC7047704710B57E +:1022C000FFF7FCFFFFF7F9FFFCF721F910BD10B590 +:1022D000002801D000F001F8FEE700B59BB0032113 +:1022E00002A800F06DF8022108A800F069F80121A9 +:1022F0000EA800F065F8102114A800F061F8059B05 +:10230000039A96201A60099A0C9B1A600F9A129BE6 +:102310001A60159A179B01921A6000F0C9F8069B83 +:10232000039A96201A60099A0B9B1A600F9A119BC8 +:1023300001921A60159A189B1A6000F0B9F8DEE74E +:102340000FB4012010B5FAF7A5FC70B50D0004001C +:102350001600F2F7D5F96B1C07D00021200000F021 +:10236000C9F83100200000F0BFF870BD70B54368B7 +:1023700004000D00002A01D0C26800E00269136069 +:102380002000012100F0B6F82900200000F0ACF890 +:1023900070BD10B50322FFF7D8FF10BD10B5FFF7D1 +:1023A000D4FF10BD70B50D0004001600F2F7A8F9B7 +:1023B0006B1C04D0320000212000FFF7D7FF70BD56 +:1023C00010B50022FFF7EEFF10BD70B504000D0040 +:1023D00003681B68984763681D6070BD036870B52B +:1023E000DB680400984763685A682368002A02D1B2 +:1023F0009B68984713E05B681568984763682D1AD7 +:102400005A68002D07DC916859601B68002BEAD0E0 +:1024100050689847E7E7236810681B69984770BDC4 +:1024200070B50D0072B64B60002346680A60746890 +:10243000002C05D02168511A02D42300A468F7E7C4 +:10244000002B05D1036875601B691000984700E0F8 +:102450009D60AC6062B670BD10B572B642685368DC +:102460008B420CD19B6853600268002B02D19368A9 +:1024700098470BE012691868904707E01300002B9B +:1024800004D09A689142F9D18A689A6062B610BD08 +:1024900010B503685B68984710BD70B50400F1F78C +:1024A000CFFC0500F1F7CCFC401BA042FAD370BD75 +:1024B000FA2310B59B005843FFF7EFFF10BD70479C +:1024C000704703681A00FC32D1680129FCD1002151 +:1024D000D160A322D2009858C0B2704710B540789E +:1024E00040B2F1F70FFF10BD10B5007840B200F018 +:1024F0000EF810BD002901D0012907D10023A02228 +:10250000C356D205C133FF339B0099507047A023B7 +:102510008000DB05C018E02310B50C24DB00C25896 +:102520008900A243C250C2581143C15010BDF8B532 +:1025300005000E00002401273B00A3402A691A422F +:1025400003D060B23100FFF7E2FF01341F2CF3D15A +:10255000F8BD30B5002903D001291DD1002311E0B9 +:1025600001220C0013008B4005691D4203D0056851 +:102570008B00EB181C6001311F29F3D10CE00133F3 +:102580001F2B09D00A009A4004691442F7D004684E +:102590009A00A2181160F2E730BD42680069136822 +:1025A00059400140594011607047F7B50192B1227E +:1025B0001F0003684910D200995080210122890030 +:1025C0005A50190000240600FC31CC601A607D1EB0 +:1025D000019BAC4213DA191900223000F2F7D0F84F +:1025E00000280AD03000F2F7C3F907003000F2F7F4 +:1025F0008DF93D1E1ADB250018E00134E7E7591973 +:1026000001223000F2F7BCF8002803D03000F2F7C6 +:102610007DF90BE0089B3D00002B07D03368FC33AD +:102620009A68002AFCD000223D009A602800FEBD76 +:10263000F8B51700B1221D000368D2004910995067 +:102640008022002492009C50012206009A60AC4235 +:1026500011DA395D3000F2F77FF8002809D0300038 +:10266000F2F754F93000F2F783F9031E0FDB230071 +:102670000DE00134EBE7069B002B04D03000F2F7AD +:102680005DF9002801D12B0001E001235B42180015 +:10269000F8BD82B00190C046C046C046C046C046A4 +:1026A000C046C046C046C046C046C046C046C046FA +:1026B000C046019B013B0193002BECD102B0704757 +:1026C0000023CB565A1C05D0834201D1486802E052 +:1026D0000C31F5E7180070470B0010B50100180029 +:1026E000FAF7C4FA10BD10B5041E00D10134200061 +:1026F000E8F7BCFD002807D1F2F70AFC002801D159 +:1027000000F007F88047F2E710BD10B5E8F7E4FDE8 +:1027100010BD10B50620FAF7F9FA0120FFF7D7FD32 +:10272000C9B28218904204D003788B4202D00130A3 +:10273000F8E70020704730B50024A24208D0035DBE +:10274000651C0C5DA34201D0181B02E02C00F4E7CD +:10275000002030BD002310B59A4203D0CC5CC45495 +:102760000133F9E710BD10B5884202D98B189842A1 +:1027700001D3002305E09B1A013A08D3995C8154E8 +:10278000FAE7934203D0CC5CC4540133F9E710BD9F +:1027900003008218934202D019700133FAE77047A0 +:1027A00070B504000D1E1F2D04D9162303600120EF +:1027B00040421EE0426C002A04D08B00D2181368FD +:1027C000002B08D1200000F015F82A00010020009D +:1027D000FAF7A6FA0DE00020012B0AD0591C03D10C +:1027E00017332360013004E0002428001460984768 +:1027F000200070BD10B5FAF7F7FD10BD02780B7818 +:10280000002A03D0013001319A42F7D0D01A704724 +:102810000023C25C0133002AFBD1581E704703001D +:1028200030B5002A0DD00C7801335D1E013A2C70B2 +:102830000131002CF5D19A189A4202D01C70013354 +:10284000FAE730BDF7B5170001938A680B6900906D +:102850000C00934200DA130022003B6043321278EE +:10286000002A01D001333B6023689B0602D53B68F8 +:1028700002333B60062523681D401ED023004333EE +:102880001B785A1E9341226892061CD53020E1180D +:102890004331087021005A1C45310978A21843328F +:1028A000023311700FE022000123193201990098C0 +:1028B000089EB047431C0ED00135E3683A689B1A66 +:1028C0009D42F0DBDAE72200019943320098089D2F +:1028D000A847431C02D10120404220E00623206883 +:1028E000E1683A6803400025042B03D18D1AEB43BD +:1028F000DB171D40A3682269934201DD9B1AED1886 +:102900000027BD420AD0220001231A320199009803 +:10291000089EB047431CDED00137F2E70020FEBD21 +:10292000F8B5C046F8BC08BC9E467047F8B5C0462E +:10293000F8BC08BC9E467047000000000000000084 +:1029400010420000004803003F2F7C185C30B53E69 +:10295000FFE5020083E702008199010009A301005D +:1029600093E9020049970100DD980100E998010010 +:10297000C98E0100F59801009997010079E70200DE +:1029800011930100D98E010023D80200CD900100DF +:1029900085900100CFD802006D8B01009DD602000A +:1029A000A9D60200098D0100EFD60200A7DB0200C4 +:1029B00045DB0200A59301002DDE020019E50200AF +:1029C0001BE50200702F0300AC2E0300002F030054 +:1029D0005C300300E3E5020007E60200EDE80200D8 +:1029E0001DE8020021E502001DE502001FE50200CE +:1029F00025920100B9910100CDDC0200FDD5020055 +:102A00002BD702003FD7020043D702004DD7020068 +:102A10005BD7020065D7020077D7020081D702009A +:102A20008BD7020087DC0200B1DC0200A189010023 +:102A3000E9D50200DDD60200E18C0100A989010080 +:102A400033D60200358C01002D8B010037D60200F1 +:102A500087D6020095D602005BDC02002FD9020067 +:102A600053D9020077D90200BFD90200E3D902008E +:102A70002BD80200B5D8020045D802005FD802006A +:102A800077D802008FD802009DD802007FDD0200B7 +:102A9000A5DD0200CBDD0200F1DD02000FDE020049 +:102AA00063DC020075DC020083DB020095DB0200C0 +:102AB00031DA020013D7020053DA0200F5DA02001D +:102AC00005DB020015DB020025DB020035DB02001E +:102AD0009D9101001FD7020023D70200FD9601003F +:102AE000C98E010095D70200D98E01009BD7020044 +:102AF0009FD70200A3D702002D8F0100B7D7020095 +:102B0000698F0100BFD70200C5D70200D9D70200E4 +:102B10007D8F0100F98F0100F7D7020011900100AD +:102B20002990010021D80200359001005193010045 +:102B300043E80200E19F0100C9620200495202001D +:102B4000715202005D760200216902006971020083 +:102B500009A30100058201004FD40200298201006F +:102B60005182010057D402008182010063D4020027 +:102B700081D40200ABD40200D3D40200D9D4020025 +:102B8000DFD40200EFD40200FDD40200BDA001009A +:102B9000E5A001003DA101004DA1010079A10100C6 +:102BA00017E902001FE9020009D50200ED830100C8 +:102BB0004D84010017D5020037D502006D84010055 +:102BC00057D50200358501007D8501008D85010006 +:102BD000A1850100B1850100E18501006FD50200EA +:102BE00077D50200398601004D86010099E7020081 +:102BF000A1E70200A9E70200B1E70200C3E7020073 +:102C0000CD990100D9990100D1E70200E1E7020066 +:102C1000E9E70200EBE70200C1820100D582010072 +:102C20001D830100318301004983010059830100A4 +:102C30006983010079830100898301009983010080 +:102C4000B583010087E302008FE302009FE30200E7 +:102C5000B3E30200C3E30200D7E30200EBE30200A8 +:102C6000919501000FE402009D95010089E40200A6 +:102C7000BD950100CD9501009DE40200BDE4020078 +:102C8000CDE402002D96010055960100D9E4020022 +:102C9000EBE40200FBE402009D9601006586010062 +:102CA000A1860100E5860100218701004987010016 +:102CB00065870100D9870100218801004188010052 +:102CC000518801007BDF02007FDF020097DF0200F6 +:102CD000ABDF0200B3DF02004DE2020049E3020075 +:102CE00005E0020009E002002FE0020053E00200CC +:102CF000C3E00200C5930100D1E002003FE1020001 +:102D00004FE102005BE1020023E5020033E502002F +:102D100043E5020053E5020063E5020073E50200AB +:102D200083E5020093E5020039DE02005DDE020069 +:102D30006DDE02007DDE02008DDE02009DDE0200FF +:102D4000ADDE0200BDDE0200459401007D9401006D +:102D5000C594010069E30200E99401002195010096 +:102D60003D95010000000000E2652F227F2B7A3C98 +:102D7000075C143326A6813CBDCBF07A8807703CF3 +:102D8000075C143326A6913C4FBB610567ACDD3F61 +:102D9000182D4454FB21E93F9BF681D20B73EF3F82 +:102DA000182D4454FB21F93F000000000000E03FD3 +:102DB000000000000000E0BF763C7935EF39EA3DC5 +:102DC000763C7935EF39EABD0000E0FE422EE63F61 +:102DD0000000E0FE422EE6BF000000000000000000 +:102DE000000000000000008000000040FB21F93FCF +:102DF000000000002D44743E000000809846F83C1E +:102E00000000006051CC783B00000080831BF0394B +:102E10000000004020257A38000000802282E3363E +:102E2000000000001DF36935080004F900000000EF +:102E300009000000000000000FD4020019D40200B5 +:102E400009D402000BD402000000000000000000C2 +:102E50000000000000000000702F030004006E75E9 +:102E60006C6C0000702F030009002D496E66696EBE +:102E700069747900702F0300040074727565000096 +:102E8000702F03000900756E646566696E656400E5 +:102E9000702F0300080066756E6374696F6E000022 +:102EA000AC2E03000000000000000000080004F940 +:102EB0000000000003000000000000007FD50200B9 +:102EC0001193010000000000A7D5020000000000DF +:102ED000000000000000000000000000702F030050 +:102EE00000000000702F0300050066616C73650030 +:102EF000702F03000800496E66696E6974790000DE +:102F00000C0002F9000000000200000000000000B8 +:102F10007FD502001193010000000000A3D502003C +:102F200000000000000000000000000000000000A1 +:102F3000702F030008005B4F626A6563745D0000D8 +:102F4000702F03000900756E646566696E65640024 +:102F5000702F030006006F626A6563740000000052 +:102F6000702F030006006E756D6265720000000030 +:102F7000080003F90000000001000000000000004C +:102F80007FD502001193010089D5020081D502008E +:102F90008BD50200AFD502008FD5020093D5020079 +:102FA000702F030003004E614E0000004050585443 +:102FB000403A737472696E6700000000702F03005E +:102FC0000700626F6F6C65616E000000702F030078 +:102FD0000A005B46756E6374696F6E5D00000000E9 +:102FE00024230020342300204423002054230020E5 +:102FF00064230020742300208423002094230020D5 +:10300000A4230020B4230020C4230020D4230020C4 +:10301000E4230020F42300200424002014240020B2 +:103020002424002034240020442400200C0004F92F +:10303000000000000600000000000000C3E50200E0 +:103040002BE70200B9E8020001E9020000000000DD +:103050000000000000000000000000000C0004F967 +:10306000000000000400000000000000DFE5020096 +:10307000E1E50200C3E8020005E9020000000000EB +:10308000000000000000000000000000080004F93B +:10309000000000000700000000000000E7E502005B +:1030A000E5E50200CFE802000FE9020000000000A1 +:1030B000000000000000000000000000140004F9FF +:1030C000000000000800000000000000CDE5020044 +:1030D000DDE50200D9E8020013E90200000000006B +:1030E00000000000000000000000000000000000E0 +:1030F0000000000049A2010081E902000500000073 +:103100000500000003000000090000000D0400009D +:10311000153E03000000000000000000D1EA02009C +:103120002BE90200D9EA02000BEB0200FFFF0000CE +:1031300000000000FFFF010001000000000000008F +:103140000000000029E902002BE9020031E9020039 +:1031500033E90200000000000000000029E902003D +:103160002BE9020077F2020079F2020037F2020046 +:1031700053F2020057F2020073F20200CDB80100D0 +:10318000D5B8010059F30200000000000000000063 +:103190008DBD01002BE9020075BD010017F402008E +:1031A000000000000000000029E902002BE90200F5 +:1031B00057F4020059F40200C9BE010037F40200BE +:1031C00053F40200D1BE010065F4020000000000CB +:1031D00000000000D7FC02002BE9020091C70100AB +:1031E00053FA020001000000170000004600000032 +:1031F000A30000005F010000D6020000C40500002B +:10320000A00B00000000000000000000DF01030030 +:103210008DD00100F5CF0100490003007DD10100F0 +:103220005B000300F7010300F8FFFFFF0000000050 +:1032300029E9020081D201009DD10100ADD1010038 +:10324000000000000000000029E902002BE9020054 +:103250002FE902003FE9020000000000000000002A +:1032600029E902006D0503005F0503006105030005 +:10327000000000000000000029E90200B908030076 +:103280007B0803007D080300000000000000000030 +:1032900085E70100C1080300C40900000000000028 +:1032A0008813000008000000102700001000000034 +:1032B000204E0000180000008038010020000000AF +:1032C000007102002800000000E20400300000004D +:1032D0000088130038000000E03203000300000003 +:1032E00002000000000000000400000001000000D7 +:1032F00008000000020000000000000000000000C4 +:1033000029E9020003090300C9EA01000D090300CD +:1033100037F2020053F2020057F2020073F2020089 +:10332000D5E901000DEB010059F30200BCFFFFFFDE +:103330000000000029E90200C5E90100EDEA0100F2 +:10334000FDEA0100B9EA010037F4020053F402007B +:103350000DEC010065F40200983203000800000043 +:10336000E204000000000000C409000008000000A2 +:103370008813000010000000102700001800000053 +:10338000204E0000200000008038010028000000CE +:10339000007102003000000000C409003800000085 +:1033A000A83303000300000002000000000000003A +:1033B00004000000010000000800000002000000FE +:1033C000000000000000000029E9020031090300AC +:1033D00051ED01003B09030037F2020053F20200F5 +:1033E00057F2020073F202009DEC010069ED01004A +:1033F00059F30200603303000800000000000000E1 +:103400000000000029E902005F0903003DEE010011 +:1034100069090300E5EE010037F4020053F40200ED +:1034200055EE010065F40200D430000000000000F9 +:10343000A86100002000000050C300004000000010 +:10344000A086010060000000400D03008000000025 +:10345000801A06008800000000350C009000000073 +:10346000006A1800B000000000D43000D000000056 +:1034700000A86100F00000000050C300F800000048 +:10348000283403000B0000000000000000000000D2 +:1034900029E902008D09030071F00100970903007A +:1034A00037F2020053F2020057F2020073F20200F8 +:1034B000DDEF010089F0010059F30200690200000C +:1034C00080000000E802000090000000C409000035 +:1034D000700000008813000060000000102700004A +:1034E00050000000204E000040000000409C000002 +:1034F00030000000A08601002000000040420F00C4 +:10350000100000000C350300040000000200000061 +:10351000000000000400000010000000080000008F +:10352000200000001000000030000000BC34030048 +:1035300009000000000000000000000029E902006E +:10354000BB090300E5F10100C509030085F1010095 +:1035500037F4020053F40200FDF1010065F40200AB +:10356000102700000C000000204E000008000000A2 +:1035700050C3000004000000A0860100000000000D +:10358000603503000400000000000000000000009F +:1035900029E90200A5F30100C1F201004D0A030070 +:1035A0000000000000000000990C03000000000073 +:1035B0000000000029E9020005040200DF0C0300FE +:1035C000E10C03000000000000000000ED0E02000E +:1035D000F71203000000000000000000D90E0200F6 +:1035E000E51203000000000000000000C50E02000C +:1035F000D31203000000000000000000010F0200D1 +:103600000913030000000000000000000510030083 +:10361000091003000D10030011100300D50C020067 +:1036200015100300191003001D10030021100300E2 +:1036300025100300291003002D1003003110030092 +:1036400035100300391003003D1003004110030042 +:1036500045100300491003004F10030053100300EE +:10366000571003005B1003005F100300631003009A +:10367000671003006B1003006F100300731003004A +:1036800077100300B3220300B3220300B10F02003E +:103690000000000000000000B10E02007D120300D7 +:1036A0000000000000000000890E02005912030013 +:1036B0000000000000000000750E02004712030029 +:1036C0000000000000000000610E0200351203003F +:1036D00000000000000000004D0E02002312030055 +:1036E00000000000000000009D0E02006B120300AD +:1036F00000000000000000008F1003009310030082 +:10370000971003009B1003009F100300A3100300F9 +:10371000A7100300AB100300AF1003007D140300DB +:103720000000000000000000150F02001B13030042 +:103730000000000000000000390E0200111203001A +:103740000000000000000000B3100300DD0C0200C8 +:10375000B7100300BB100300BF100300C11003002B +:10376000C5100300C9100300CB100300CF100300E5 +:10377000D31003002D130300000000000000000020 +:10378000E9110300DD110300D1110300C911030089 +:10379000291103007B1003007F1003008310030036 +:1037A000871003008B100300C51203000000000007 +:1037B00000000000C1130300DD10030071130300BB +:1037C000C50D0200E1100300E51003005D140300C5 +:1037D0003D140300710D0200290F02003D0D02008F +:1037E000E91003005D0F02000F1403000000000049 +:1037F00000000000471603007B1603009D15030020 +:10380000A1150300A5150300AB1503001910030053 +:10381000E1180200CB150300F5150300071603009D +:103820001D160300331603004D170300AD160300E9 +:10383000C1160300D3160300E5160300911702001A +:10384000FF16030071170300D517030003170300C9 +:103850000B17030013170300171703001D170300AE +:103860002317030073100300DD170200A9170300DC +:10387000D11902003F180300000000000000000002 +:10388000A11B0200791A020085180300911A020098 +:10389000AD1A0200BB180300F91803002119030038 +:1038A000AF1003007D1D0200331F0300C52002007E +:1038B0000B1F0300171F03002B1F0300551F0200DF +:1038C0002F1F03000F1F0300271F03007D2102008D +:1038D000071F03001F1F03004B1F0300C52D02001D +:1038E000F12D02007D2D0200492D02008D2C0200D9 +:1038F0005D2C0200E1310200C531020031310200CD +:103900000000000000000000B53A0200B9200300EA +:1039100000000000000000000000000000000000A7 +:10392000B32203000000000000000000593B020029 +:103930005F2103003F2103000000000000000000A1 +:1039400075C7010065FA0200712103000000000044 +:103950000000000027E9020057E902000000000013 +:10396000000000002DE902004BE902000000000009 +:10397000000000003F220300312203003322030035 +:10398000B53D0200413E0200BF240300C1240300F4 +:10399000593E02008039030034270020B0040000A3 +:1039A00000F004006009000000D00900C01200000F +:1039B00000B01300802500000050270040380000B0 +:1039C00000003B00004B000000A04E008070000093 +:1039D00000F07500127A00000000800000960000E0 +:1039E00000509D0000E1000000F0EB00002C010001 +:1039F00000903A0100C2010000E0D70100840300FA +:103A000000B0AF0390D003000000000400080700DE +:103A100000705F0700100E00A4DFBE0E40420F00D2 +:103A200000000010010000000070004004000000D1 +:103A300002000000007000400800000003000000C9 +:103A40000070004010000000040000000070004002 +:103A50002000000005000000007000404000000051 +:103A6000060000000070004080000000FF00000021 +:103A7000FFFFFFFF00000000025A0200265902006B +:103A8000E4590200BC590200E4590200B059020096 +:103A9000E4590200BC5902002659020026590200CE +:103AA000B0590200BC590200685A0200685A02006C +:103AB000685A0200EA5902002659020026590200FB +:103AC000D0590200BA590200D0590200B059020080 +:103AD000D0590200BA5902002659020026590200A4 +:103AE000B0590200BA590200685A0200685A02002E +:103AF000685A0200745A0200605D0200BE5C020057 +:103B0000BE5C0200BC5C0200525D0200525D02001D +:103B1000485D0200BC5C0200525D0200485D02008C +:103B2000525D0200BC5C0200585D0200585D02005C +:103B3000585D0200E25D0200106B0200DE690200C7 +:103B4000E46A0200D4690200E46A0200EE6A02003C +:103B5000E46A0200D4690200DE690200DE69020044 +:103B6000EE6A0200D4690200CA690200CA69020052 +:103B7000CA690200406D0200587302001872020008 +:103B800018720200167202003073020030730200D5 +:103B900022730200167202003073020022730200C8 +:103BA000307302001672020038730200387302008C +:103BB000387302003875020061636F730000000003 +:103BC00061636F73680000006173696E000000003C +:103BD0006174616E68000000636F7368000000002C +:103BE00065787000666D6F64000000006C6F6700A0 +:103BF0006C6F67313000000073696E680000000070 +:103C00007371727400000000FB21F93FFB21094031 +:103C10007CD91240FB2119407A6A1F407CD922408E +:103C2000BBFD2540FB2129403A462C407A6A2F40B3 +:103C30005C4731407CD932409C6B3440BBFD354001 +:103C4000DB8F3740FB2139401BB43A403A463C40B9 +:103C50005AD83D407A6A3F404C7E40405C474140E4 +:103C60006C1042407CD942408CA243409C6B444043 +:103C7000AC344540BBFD4540CBC64640DB8F47409A +:103C8000EB584840FB21494083F9A200444E6E00A6 +:103C9000FC291500D1572700DD34F50062DBC00098 +:103CA0003C999500419043006351FE00BBDEAB00A0 +:103CB000B761C5003A6E2400D24D42004906E000CB +:103CC00009EA2E001C92D100EB1DFE0029B11C0058 +:103CD000E83EA700F535820044BB2E009CE9840035 +:103CE000B4267000417E5F00D691390053833900BD +:103CF0009CF439008B5F840028F9BD00F81F3B005D +:103D0000DEFF97000F980500112FEF000A5A8B0075 +:103D10006D1F6D00CF7E360009CB2700464FB700E0 +:103D20009E663F002DEA5F00BA277500E5EBC700ED +:103D30003D7BF100F739070092528A00FB6BEA00E5 +:103D40001FB15F00085D8D00300356007BFC46000C +:103D5000F0AB6B0020BCCF0036F49A00E3A91D0045 +:103D60005E619100081BE60085996500A0145F0064 +:103D70008D40680080D8FF0027734D000606310093 +:103D8000CA561500C9A873007BE260006B8CC000A6 +:103D90000200000003000000040000000600000014 +:103DA0000000000000000000000000000000000013 +:103DB0000000000000000000000000000000000003 +:103DC00000000000000000000000000000000000F3 +:103DD00000000000000000000000000000000000E3 +:103DE00000000000000000000000000000000000D3 +:103DF00000000000000000000000000000000000C3 +:103E00002020002030313233343536373839616282 +:103E100063646566000000040202040200000204FC +:103E20000404000202000404030100000103030370 +:103E30000001010203030402010103010403010064 +:103E400003000004010102000003025265626F6F6B +:103E5000744D6F646500666C617368496E636F6D65 +:103E6000706C657465007A76677074756F696561EA +:103E70007A76677074756F6965617A7667707400B9 +:103E80000004020204020000020404040002020012 +:103E90000404030100000103030300010102030302 +:103EA00004020101030104030100030000040101F5 +:103EB00002000003021B1B000E110000000000089E +:103EC000080800080A4A4000000A5FEA5FEA0ED9C3 +:103ED0002ED36E19324489330C924C924D0808004F +:103EE000000004880808040804848488000A448ABE +:103EF0004000048EC480000000048800000EC00052 +:103F0000000000080001224488100C9252524C0418 +:103F10008C84848E1C824C901E1EC244924C06CA15 +:103F2000525FE21FF01EC13E02448ED12E1FE244BA +:103F300088100ED12ED12E0ED12EC4880008000874 +:103F40000000048004880244880482000EC00EC071 +:103F500008048244880ED126C0040ED135B36C0CFF +:103F6000925ED2521C925C925C0ED010100E1C928B +:103F700052525C1ED01C901E1ED01C90100ED013EE +:103F8000712E12525ED2521C8808081C1FE2425247 +:103F90004C1254981492101010101E113B75B13130 +:103FA000113935B3710C9252524C1C925C90100C2A +:103FB00092524C861C925C92510ED00C825C1FE493 +:103FC000848484125252524C1131312A44113135B9 +:103FD000BB7112524C9252112A4484841EC4881020 +:103FE0001E0EC808080E10080482410EC242424E3E +:103FF000048A400000000000001F08048000000048 +:104000000ED2524F10101C925C000ED0100E0242C5 +:104010004ED24E0C925C900E06C81C88080ED24EF2 +:10402000C24C10101C9252080008080802400242BC +:104030004C10149814920808080806001B75B1313A +:10404000001C925252000C92524C001C925C900048 +:104050000ED24EC2000ED010100006C804980808F8 +:104060000EC807001252524F0011312A440011317C +:1040700035BB00124C8C9200112A4498001EC48853 +:104080001E06C48C8486080808080818080C8818BE +:1040900000000C8360000001000200030004000027 +:1040A00001010102010301040100020102020203F5 +:1040B00002040200030103020303030403000401DA +:1040C00004020403040404302C3235352C302C3225 +:1040D00035352C300A302C3235352C302C323535F4 +:1040E0002C300A302C302C302C302C300A32353524 +:1040F0002C302C302C302C3235350A302C323535E2 +:104100002C3235352C3235352C300A0054494C547C +:1041100020544F2046494C4C2053435245454E2095 +:1041200000636F6D7061737343616C0074656D70D3 +:1041300043616C00FFFF14000500FFFFFFFFFFFF5E +:10414000FFFFFFFFFFFF00FFFFFF000000FFFFFF7B +:10415000FFFFFFFFFF00FFFFFF000000FF00000068 +:104160000000FFFF00FFFFFF000000FF0000000055 +:10417000000000000000FFFFFFFFFFFFFF00FFFF48 +:10418000FF000000FF0000000000FFFFFFFFFFFF37 +:10419000FFFFFFFFFFFF00FFFFFF000000FF000029 +:1041A000FFFF00FF00FF00FF00FFFFFF00FF00FF19 +:1041B00000FF0000FFFF00626C6553797341747467 +:1041C000727300424243206D6963726F3A62697490 +:1041D00000424243206D6963726F3A626974205BEA +:1041E000005D00302C302C3235352C302C300A302C +:1041F0002C3235352C302C302C300A3235352C32DF +:1042000035352C3235352C3235352C3235350A30B2 +:104210002C3235352C302C302C300A302C302C32CE +:1042200035352C302C300A00302C302C302C302CF2 +:10423000300A302C302C302C302C3235350A302CD2 +:10424000302C302C3235352C300A3235352C302C90 +:104250003235352C302C300A302C3235352C302C80 +:10426000302C300A003235352C302C302C302C32AA +:1042700035350A302C3235352C302C3235352C3052 +:104280000A302C302C3235352C302C300A302C3280 +:1042900035352C302C3235352C300A3235352C3032 +:1042A0002C302C302C3235350A00322E312E312D67 +:1042B0002D6700E2ECF0F4F8FC0004E95D93B02512 +:1042C0001D470AA062FA1922DFA9A8E95D93B1256A +:1042D0001D470AA062FA1922DFA9A8E95DB84C259A +:1042E0001D470AA062FA1922DFA9A8E95D97752582 +:1042F0001D470AA062FA1922DFA9A8E95D93AF253C +:104300001D470AA062FA1922DFA9A8E95D23C42586 +:104310001D470AA062FA1922DFA9A8E95D54042505 +:104320001D470AA062FA1922DFA9A801FF01AAE924 +:104330007D3B10251D470AA062FA1922DFA9A8E9D2 +:104340007DD91D251D470AA062FA1922DFA9A8629E +:1043500061642068616E646C6520746F20756E64A2 +:1043600065726C79696E67207472616E73706F72BA +:104370007400494E495449414C495A4154494F4EA1 +:104380005F494E434F4D504C455445004E6F72644B +:10439000696320424C45342E31207665723A25758A +:1043A0002066773A25303478004E6F726469632056 +:1043B000287370656320756E6B6E6F776E2920763B +:1043C00065723A25752066773A2530347800756E27 +:1043D0006B6E6F776E00010203D8E2ECF0F4F8FC2C +:1043E00000046E52463578004E6F20617661696C2C +:1043F00061626C6520493243004F6E6C79203862EF +:104400006974732053504920737570706F727465AE +:10441000640053504920666F726D6174206572723A +:104420006F72004E6F20617661696C61626C65200D +:1044300053504900636F756C64206E6F742070690F +:104440006E6F75740070696E6D6170206D69732D8B +:104450006D617463680070696E6D6170206E6F7459 +:1044600020666F756E6420666F7220706572697069 +:10447000686572616C0070696E6D6170206E6F743A +:1044800020666F756E6420666F722066756E637449 +:10449000696F6E0000202020202020202020282866 +:1044A00028282820202020202020202020202020F4 +:1044B0002020202020881010101010101010101034 +:1044C0001010101010040404040404040404041064 +:1044D00010101010101041414141414101010101F2 +:1044E00001010101010101010101010101010101BC +:1044F00010101010101042424242424202020202C8 +:10450000020202020202020202020202020202028B +:10451000101010102000000000000000000000003B +:10452000000000000000000000000000000000008B +:10453000000000000000000000000000000000007B +:10454000000000000000000000000000000000006B +:10455000000000000000000000000000000000005B +:10456000000000000000000000000000000000004B +:10457000000000000000000000000000000000003B +:10458000000000000000000000000000000000002B +:104590000000000000232D302B2000686C4C0065CB +:1045A000666745464700303132333435363738395F +:1045B000414243444546000000000000B83BFE7FF6 +:1045C0000100000000000000A10D0C00BA3E030035 +:1045D000C3410300AA420300204E0000B31F0300A2 +:1045E000204E000000000000A03D0300C03D03007D +:1045F000E03D03000000000000000000000000009B +:1046000000000000F743030000000000000000006D +:10461000000000000000000000000000000000009A +:10462000000000000000000000000000000000008A +:10463000000000000000000000000000000000007A +:10464000000000002020002094440300204EFFFFC3 +:1046500000000000FF0F1010070004FF0000010021 +:104660003981010059950100A1A00100E5A30100D5 +:10467000D5B1010041B501005DB8010085B8010068 +:104680000D8101000000000000000000000000009B +:10469000000000000000000000000000000000001A +:1046A000000000000000000000000000000000000A +:1046B00000000000000000000000000000000000FA +:1046C00000000000000000000000000000000000EA +:1046D00000000000000000000000000000000000DA +:1046E00000000000000000000000000000000000CA +:1046F00000000000000000000000000000000000BA +:1047000000000000000000000000000000000000A9 +:104710000000000000000000000000000000000099 +:104720000000000000000000000000000000000089 +:104730000000000000000000000000000000000079 +:104740000000000000000000000000000000000069 +:104750000000000000000000000000000000000059 +:104760000000000000000000000000000000000049 +:104770000000000000000000000000000000000039 +:104780000000000000000000000000000000000029 +:104790000000000000000000000000000000000019 +:1047A0000000000000000000000000000000000009 +:1047B00000000000000000000000000000000000F9 +:1047C00000000000000000000000000000000000E9 +:1047D00000000000000000000000000000000000D9 +:1047E00000000000000000000000000000000000C9 +:1047F00000000000000000000000000000000000B9 +:10480000708E3B92C615A841C49866C975EE519743 +:104810003F2F7C185C30B53EB693FD508E44782710 +:1048200021008D02105B030000000100C05A03004C +:104830003D520300645C0300000000000000000023 +:104840005C300300000000004D48030000B5E04864 +:1048500080213768785041203768F8670120376831 +:10486000786003203768B86005203768F860D94859 +:104870006F467760E4F790FF01B46F467760F8F712 +:1048800054FF01B42D216F467760F8F75FFF009861 +:104890002F216F467760F8F759FF0098032001B485 +:1048A000029801B400F0B6FC03B001BC376838616F +:1048B000C8486F467760E4F76FFF01B46F467760D2 +:1048C000F8F733FF01B425216F467760F8F73EFF14 +:1048D000009827216F467760F8F738FF0098052089 +:1048E00001B4029801B400F095FC03B001BC376834 +:1048F0007861B9486F467760E4F74EFF01B4052050 +:1049000001B4032001B4029801B400F075FC03B0B7 +:1049100001BC3768B861B0486F467760E4F73CFF88 +:1049200001B4072001B4052001B4029801B400F0DD +:1049300063FC03B001BC3768F861A7486F46776035 +:10494000E4F72AFF01B4512001B4072001B4029812 +:1049500001B400F051FC03B001BC376838629E48D6 +:104960006F467760E4F718FF01B4532001B40920C3 +:1049700001B4029801B400F03FFC03B001BC3768F9 +:10498000786295486F467760E4F706FF01B4172018 +:1049900001B40B2001B4029801B400F02DFC03B067 +:1049A00001BC3768B8628C486F467760E4F7F4FE64 +:1049B00001B4152001B40D2001B4029801B400F037 +:1049C0001BFC03B001BC3768F86283486F46776010 +:1049D000E4F7E2FE01B4132001B40F2001B4029801 +:1049E00001B400F009FC03B001BC376838637A48B1 +:1049F0006F467760E4F7D0FE01B4112001B41120B6 +:104A000001B4029801B400F0F7FB03B001BC3768B1 +:104A1000786372486F467760E4F7BEFE01B42320E6 +:104A200001B4032001B4029801B400F0D7FB03B035 +:104A300001BC3768B86369486F467760E4F7ACFE3D +:104A400001B4212001B4052001B4029801B400F0A2 +:104A5000C5FB03B001BC3768F86360486F467760F8 +:104A6000E4F79AFE01B41F2001B4072001B40298B4 +:104A700001B400F0B3FB03B001BC37683864574899 +:104A80006F467760E4F788FE01B41D2001B4092069 +:104A900001B4029801B400F0A1FB03B001BC376877 +:104AA00078644F486F467760E4F776FE01B40120E2 +:104AB00001B4032001B4029801B400F081FB03B0FB +:104AC00001BC3768B86446486F467760E4F764FE17 +:104AD00001B4032001B4052001B4029801B400F030 +:104AE0006FFB03B001BC3768F8643D486F467760E0 +:104AF000E4F752FE01B4052001B4072001B4029886 +:104B000001B400F05DFB03B001BC37683865344880 +:104B10006F467760E4F740FE01B4072001B4092036 +:104B200001B4029801B400F04BFB03B001BC37683C +:104B300078652C486F467760E4F72EFE01B41B20A1 +:104B400001B4032001B4029801B400F02BFB03B0C0 +:104B500001BC3768B86523486F467760E4F71CFEF0 +:104B600001B4192001B4052001B4029801B400F089 +:104B700019FB03B001BC3768F8651A486F467760C7 +:104B8000E4F70AFE01B4572001B4072001B40298EB +:104B900001B400F007FB03B001BC37683866114868 +:104BA0006F467760E4F7F8FD01B4552001B40920A1 +:104BB00001B4029801B400F0F5FA03B001BC376803 +:104BC0007866012040423768B86601200CE000009A +:104BD000405C030054580300A8580300F058030039 +:104BE000385903008059030040423768F866D348BB +:104BF0006F467760E4F7D0FD376838676F467760B7 +:104C0000F8F793FD01B405216F467760F8F79EFD34 +:104C1000009807216F467760F8F798FD00985121BA +:104C20006F467760F8F792FD009853216F467760E2 +:104C3000F8F78CFD009817216F467760F8F786FD2E +:104C4000009815216F467760F8F780FD00981321D2 +:104C50006F467760F8F77AFD009811216F4677600C +:104C6000F8F774FD3768386F02BC00F055FC4160FE +:104C70003768386F212100F04FFC81606F46776004 +:104C8000F8F753FD01B41D216F467760F8F75EFD1C +:104C900000981F216F467760F8F758FD0098212192 +:104CA0006F467760F8F752FD009823216F467760D2 +:104CB000F8F74CFD009825216F467760F8F746FD20 +:104CC000009827216F467760F8F740FD00982D2166 +:104CD0006F467760F8F73AFD00982F216F467760AE +:104CE000F8F734FD009855216F467760F8F72EFDF0 +:104CF000009857216F467760F8F728FD0098192132 +:104D00006F467760F8F722FD00981B216F467760A9 +:104D1000F8F71CFD3768386F02BC00F0FDFBC1607E +:104D20006F467760F8F701FD01B401216F467760A7 +:104D3000F8F70CFD009803216F467760F8F706FD41 +:104D4000009805216F467760F8F700FD009807216D +:104D50006F467760F8F7FAFC3768386F02BC00F0EE +:104D6000DBFB0161092001216F467760F9F796FBB3 +:104D7000082001216F467760F9F790FB062037681D +:104D80007867012001B40B2001B42F2001B400F09A +:104D900077F903B03768786701203768B867012072 +:104DA0006F467760E4F7BCFB6548192109016F463F +:104DB0007760E5F783F9634801B400F0C7FB6F46FD +:104DC0007760F9F7A8FD01B000BD00005C3003007A +:104DD00000000000D94D030000B503200002E930B7 +:104DE00001B4032001B4132001B41F2001B400F06A +:104DF000C7F804B03768B8673768B86F01B452486D +:104E000001B400F003F802B000BD000000B5019845 +:104E10006F467760F8F75AFF00280AD0019801B46E +:104E200000F099FB49496F467760E3F7BDFD01B09B +:104E300003E06F467760E3F7B3FD01B4039801B474 +:104E400000F08FFB6F467760E3F7AEFD02B001B470 +:104E500000F002F801B000BD00B5002001B401B4BB +:104E600003986F467760F8F731FF6F467760F8F781 +:104E700011FC6F467760F8F73AFC6F467760F8F7F9 +:104E800025FF002804D06F467760E3F789FD039083 +:104E9000039801B400F05FFB6F467760E3F740FCD6 +:104EA00001B03768F86F012100F048FC5BD037682B +:104EB000F86F01B4049801B400F04DFB6F467760C1 +:104EC000F8F7B7FB01B000F019FC01B48020376897 +:104ED000385801B400F03FFB6F467760F8F7A9FB44 +:104EE00001B000F00BFC01B40198009900F0B4FB94 +:104EF00002B001B43768F86F01B4019800996F46A9 +:104F00007760F8F76EFD02B001B40198009900F0E7 +:104F1000B3FB02B001B43768F86F01B4019800998F +:104F20006F467760F8F75DFD02B0009001200190B8 +:104F30000198009900F0EEFB0AD114E0C859030073 +:104F4000145B0300CC4D03005C5C0300545C030065 +:104F5000B8486F467760E3F7E3FB0198032100F060 +:104F60007BFB0190E4E780203768385801B400F0FB +:104F7000F2FA6F467760E3F7D3FB01B002B000BDF1 +:104F800000B5002001B4029801B400F0F6FA022145 +:104F90006F467760F9F782FA01B0029801B400F029 +:104FA000ECFA00216F467760F9F7F9F901B00220B9 +:104FB0006F467760F9F7F8FB029801B400F0DDFA6C +:104FC00001216F467760F9F7EAF901B00A206F46D0 +:104FD0007760F9F7E9FB029801B400F0CEFA0021FE +:104FE0006F467760F9F7DBF901B0039801B40698D2 +:104FF00001B475216F467760F8F7BDFC01B001B4CC +:1050000000F0C3FA04216F467760F9F700FA02B0A6 +:1050100000F074FB0090049801B4014603206F4631 +:105020007760F8F71AFE002801D001B00BE00520E8 +:1050300000996F467760F8F710FE002801D001B0A4 +:105040000EE001BC19E0009801B400F096FA3A2194 +:105050006F467760F8F765FB01B000F04FFB0DE09D +:10506000009801B400F089FA94216F467760F8F750 +:1050700058FB01B000F042FB00E0009801B000BD19 +:1050800000B5002001B401B46B486F467760E4F7C7 +:1050900083FB00900598032100F0A0FB01D00920BC +:1050A00000E007200190009801B4059801B403982E +:1050B00001B4019800996F467760F8F75CFC02B084 +:1050C00001B400F05AFA6F467760F9F7FFF901B0C2 +:1050D00001B40198009900F068FA416002B00098AC +:1050E000012100F062FA01610098049900F05DFA74 +:1050F00041610098059900F058FA816100980121FA +:1051000000F053FAC16101200002FF3001B40198A0 +:1051100001B400F032F802B0039801B4019801B470 +:1051200000F00DF802B0009802B000BD022C0BDABE +:1051300000B500F047FA00F007F802B000BD77466E +:10514000009800F032FABE4600B5019802998160DD +:105150000198806801B400F010FA00216F46776072 +:10516000F9F71DF901B000BD022C0BDA00B500F013 +:1051700029FA00F007F802B000BD7746009800F069 +:1051800014FABE4600B5019801B403980121090242 +:10519000FF3100F081FA01B401980099C16002B0BA +:1051A00000BD00007746009800F015FABE4600B535 +:1051B00001980299416001980399816000BD000047 +:1051C0007746009800F014FABE4600B5019802999F +:1051D000416001980399816000BD00007746009806 +:1051E00000F013FABE4600B501980299416001989B +:1051F0000399816000BD00007746009800F012FA24 +:10520000BE4600B5019802994160019803998160FA +:1052100000BD00007746009800F011FABE4600B5C8 +:1052200001980299416001980399816001980A21CF +:10523000C16000BD4C5C0300245A0300F0B50C466D +:1052400015461E46074600F074F96846F0B46946F4 +:10525000E4F7C6FE06463D46A86803248047074695 +:1052600004B03046F9F7EDFA3846F0BD82070ED1AA +:1052700000280CD003681A89012A00D170471F6AE0 +:10528000002F04D001B50124B847009000E001B51B +:105290006F467760E3F7C6FF02BD84071FD1002881 +:1052A0001DD003681C89032C19D1491007D3446809 +:1052B000A14216D24418207A4000013070474900BC +:1052C00005B508466F467760F8F7ABFA014605BCAE +:1052D0006F467760F8F746FA4000013000BDE4F70A +:1052E00061F80120704784071CD100281AD0036898 +:1052F0001C89062C16D1491006D30489A14213D269 +:105300008900446860587047490005B508466F46F3 +:105310007760F8F786FA014605BC6F467760F8F7C4 +:1053200021FA00BDE4F73EF80020704784071BD146 +:10533000002819D003681C89032C15D1491005D306 +:105340004468A14212D2441822727047490005B540 +:1053500008466F467760F8F764FA014605BC6F4669 +:105360007760F8F708FA00BDE4F71CF800B5F6E737 +:1053700084071CD100281AD003681C89062C16D17A +:10538000491006D30489A14213D2890044686250AF +:105390007047490005B508466F467760F8F741FA4F +:1053A000014605BC6F467760F8F7E5F900BDE3F705 +:1053B000F9FF00B5F6E7840737D1002835D0036838 +:1053C0001C89082C05D100B56F467760F8F704FA00 +:1053D00000BD1C4601B50846E3F7D0FD0146009824 +:1053E000234600F002F801B000BDDA6817001CD0B7 +:1053F0004F43D7407F005B68DB191A88D75A8F422A +:105400000BD002331A88D75A8F4206D002331A883B +:10541000D75A8F4201D0002070479B185A68D7078F +:1054200001D001241047805870476F467760E3F73A +:10543000B9FF6F467760F8F7F9FC84073AD1002886 +:1054400038D003681C89082C05D100B56F467760F9 +:10545000F8F7D1F900BD1C4605B50846E3F78EFD07 +:1054600001460098234600F002F802B000BDDA6859 +:1054700017001FD04F43D7407F005B68DB191A88A5 +:10548000D75A8F4209D002331A88D75A8F4204D094 +:1054900002331A88D75A8F4210D19B185A68D707FF +:1054A00005D01F898F4209D1DA6802241047019B79 +:1054B000835070476F467760E3F774FF6F467760FD +:1054C000F8F7B4FCF0B504460E462046F8F79AFD0E +:1054D00005462046F8F751FD044630460021F8F70E +:1054E0005EFF3046F8F74FFF806841680269C36885 +:1054F00072B608E01960064200D11160760807D143 +:105500000134013D05D38026C04611602078F1E7C3 +:10551000FBE7116062B6F0BD820706D1002804D017 +:1055200003681A89152A00D170476F467760E3F740 +:1055300039FF820706D1002804D003681A89042A9B +:1055400000D170476F467760E3F72CFF00B50198F4 +:10555000FFF7EFFF00BD00B50198FFF787FE019050 +:1055600000BD00B50298FFF781FE029001B40298D9 +:10557000FFF77CFE0290014601BD00B50198401086 +:1055800002D2400000F0B0F800BD00B50298401013 +:1055900002D2400000F0A8F801B40298401002D2F4 +:1055A000400000F0A1F8024601BD820706D10028A4 +:1055B00004D003681A89162A00D170476F467760B5 +:1055C000E3F7F0FE0020002101B4012C01DB02987A +:1055D000029101B47047820706D1002804D0036805 +:1055E0001A89142A00D170476F467760E3F7DAFE14 +:1055F000820706D1002804D003681A89132A00D133 +:1056000070476F467760E3F7CDFE820706D100282A +:1056100004D003681A89122A00D170476F46776058 +:10562000E3F7C0FE820706D1002804D003681A8978 +:10563000112A00D170476F467760E3F7B3FE820707 +:1056400006D1002804D003681A89102A00D17047B7 +:105650006F467760E3F7A6FEC20706D0CA0704D0FC +:105660004A1E821801D61000F04703B56F467760D6 +:10567000F8F75DF902B000BDC20706D0CA0704D032 +:105680004A1E821A01D61000F04703B56F467760B4 +:10569000F8F75FF902B000BDC20703D0CA0701D016 +:1056A0000840F04703B56F467760F8F7F7F802B0A7 +:1056B00000BDC20703D0CA0701D00843F04703B5B5 +:1056C0006F467760F8F7D7F802B000BDC20704D084 +:1056D000CA0702D04840401CF04703B56F467760C8 +:1056E000F8F7BDF802B000BD401000D3F04740000D +:1056F00000B56F467760F8F794F800BD420051108E +:10570000884201D1501CF04700B56F467760F7F72B +:10571000CBFF00BDC20707D0CA0705D0401A01DB86 +:10572000002070470120704703B56F467760F8F797 +:105730004CFBF8F7CBFA002802B000BDC20707D037 +:10574000CA0705D0401A01DC0020704701207047CD +:1057500003B56F467760F8F75AFBF8F7B7FA0028F9 +:1057600002B000BDC20707D0CA0705D0401A01DD4C +:10577000002070470120704703B56F467760F8F747 +:1057800011FBF8F7A3FA002802B000BDC20707D04A +:10579000CA0705D0401A01DA00207047012070477F +:1057A00003B56F467760F8F723FBF8F78FFA002808 +:1057B00002B000BDC20707D0CA0705D0401A01D009 +:1057C000002070470120704703B56F467760F8F7F7 +:1057D00048FAF8F77BFA002802B000BDC20707D0EC +:1057E000CA0705D0401A01D0002070470120704739 +:1057F00003B56F467760F8F7C4F9F8F767FA002841 +:1058000002B000BDC20707D0CA0705D0401A01D1B7 +:10581000002070470120704703B56F467760F8F7A6 +:1058200029FAF8F753FA002802B000BDC20707D0E2 +:10583000CA0705D0401A01D10020704701207047E7 +:1058400003B56F467760F8F7A5F9F8F73FFA002837 +:1058500002B000BD100004F97858030010000000E9 +:105860001E49A041E3E5020007E60200EDE8020060 +:105870001DE802000000000010000E001C001200D5 +:1058800008000600040002000100040004000000FB +:10589000070008000800000002000C000C000000D7 +:1058A00000000000000000000C0004F9CC580300C8 +:1058B000110000001F49A041E3E5020007E60200D5 +:1058C000EDE802001DE80200000000000C001200DC +:1058D00008000600040002000100040004000000AB +:1058E00006000800080000000000000000000000A2 +:1058F0000C0004F914590300120000001F49A041D4 +:10590000E3E5020007E60200EDE802001DE8020000 +:10591000000000000C001200080006000400020055 +:105920000100040004000000060008000800000058 +:1059300000000000000000000C0004F95C590300A6 +:10594000130000001F49A041E3E5020007E6020042 +:10595000EDE802001DE80200000000000C0012004B +:10596000080006000400020001000400040000001A +:105970000600080008000000000000000000000011 +:105980000C0004F9A4590300140000001F49A041B1 +:10599000E3E5020007E60200EDE802001DE8020070 +:1059A000000000000C0012000800060004000200C5 +:1059B00001000400040000000600080008000000C8 +:1059C0000000000000000000140004F9EC5903007E +:1059D000150000001E2BA629E3E5020007E60200E1 +:1059E000EDE802001DE802000000000018000E00B3 +:1059F0000C001A0020000600040002000800040049 +:105A0000040000000D000800080000000C000C005D +:105A10000C00000011001000100000000000000049 +:105A200000000000200004F9485A0300160000009E +:105A30001C395E47E3E5020007E60200EDE80200DC +:105A40001DE802000000000028002E005400620043 +:105A500020001E004400320028001600140012002E +:105A600010002E0044000A00080006000400020096 +:105A70000A000400040000000B00080008000000F9 +:105A800009000C000C0000001000100010000000C5 +:105A900003001400140000000500180018000000A6 +:105AA00004001C001C0000000E00000069510300EF +:105AB0000F0000002D510300000000000000000056 +:105AC00012000000345B03003C5B0300485B0300F2 +:105AD000585B0300685B03007C5B0300885B03008A +:105AE000945B0300A05B0300B45B0300C85B03008E +:105AF000D45B0300E05B0300F05B0300005C030089 +:105B0000145C0300245C0300305C03000000000010 +:105B100000000000FFFF05000500FFFF00FFFFFF82 +:105B2000FF00FFFF0000000000FF000000FF00FF7B +:105B3000FFFF0000702F030000000000702F030023 +:105B400003005F6964000000702F030009005F69B3 +:105B50006E76657274656400702F030007005F6CD9 +:105B6000656E677468000000702F03000C005F6DA5 +:105B7000617472697857696474680000702F03005B +:105B800005005F6D6F646500702F030004005F7097 +:105B9000696E0000702F030005005F70696E73006E +:105BA000702F03000A00616E616C6F6750696E733D +:105BB00000000000702F03000A00627269676874B9 +:105BC0006E65737300000000702F030003006275A0 +:105BD00066000000702F0300030070696E00000073 +:105BE000702F0300070070776D50696E730000001E +:105BF000702F0300080070776D57696474680000A7 +:105C0000702F03000D007365744272696768746ECB +:105C100065737300702F0300060073657450696E1E +:105C200000000000702F030005007374617274009F +:105C3000702F03000900746F75636850696E7300FC +:105C4000702F030002000D0A00000000702F0300F7 +:105C500001002000702F030001003A00702F0300A4 +:105C600001007800000000000000000000000000BB +:10C00000903C002061DC030073DC030075DC03005E +:10C010000000000000000000000000000000000020 +:10C0200000000000000000000000000069C10300E3 +:10C03000000000000000000079DC03007BDC03004E +:10C040007DDC03007DDC03007DDC03007DDC030080 +:10C050007DDC0300000000007DDC03007DDC0300CC +:10C060007DDC03007DDC03007DDC03007DDC030060 +:10C070007DDC03007DDC03007DDC03007DDC030050 +:10C080007DDC0300B3D703007DDC03007DDC03000F +:10C09000C9D703007DDC0300A9F303007DDC0300A6 +:10C0A0007DDC03007DDC03000000000000000000D8 +:10C0B0000000000000000000000000000000000080 +:10C0C00000F002F800F040F80CA030C8083824183E +:10C0D0002D18A246671EAB4654465D46AC4201D1C0 +:10C0E00000F032F87E460F3E0FCCB64601263342B2 +:10C0F00000D0FB1AA246AB46334318476C3600000B +:10C100008C360000103A02D378C878C1FAD85207AA +:10C1100001D330C830C101D504680C6070470000FD +:10C120000023002400250026103A01D378C1FBD853 +:10C13000520700D330C100D50B6070471FB5C04611 +:10C14000C0461FBD10B510BD03F091FA1146FFF7B0 +:10C15000F5FF00F0D3F803F0A9FA03B4FFF7F2FFFC +:10C1600003BC03F0ADFA00000648704502D1EFF3BE +:10C17000098101E0EFF30881886902380078024AFA +:10C1800010470000FDFFFFFF95D40300401E00BFD5 +:10C1900000BF00BF00BF00BF00BF00BF00BF00BFA7 +:10C1A00000BF00BF00BFF1D170470000401E00BFBC +:10C1B00000BF00BF00BF00BF00BF00BF00BF00BF87 +:10C1C00000BF00BF00BFF1D170470000401E00BF9C +:10C1D00000BF00BF00BF00BF00BF00BF00BF00BF67 +:10C1E00000BF00BF00BFF1D170470000056885F3B4 +:10C1F000088846680A4AEFF305839A42304602D11E +:10C20000084CA6463047074C064D0646064FF0B48C +:10C21000034C034D024E024FF0B4044800470000A7 +:10C2200000000000FFFFFFFF00000021F9FFFFFFFB +:10C2300070B505460C46164602E00FCC0FC5103E01 +:10C24000102EFAD2082E02D303CC03C5083E042ECA +:10C2500007D301CC01C5361F03E021782970641C87 +:10C260006D1C761EF9D270BD0A4610B501466648AF +:10C2700003F012F810BD10B502F026FC10BD10B589 +:10C28000624C86B01ECC03946C460EC4002807D0C6 +:10C29000684618DF002803D00022114602F0FCFF98 +:10C2A0000F20800313DF002803D00022114602F084 +:10C2B000F3FF574B48225749092003F051F8002853 +:10C2C00003D00022114602F0E7FF00200490059001 +:10C2D00001206946087404A860DF002803D000220A +:10C2E000114602F0D9FF4C4803F056F8002803D05D +:10C2F0000022114602F0D0FF06B010BD08B5474835 +:10C30000C169B12943D0002445480F214069890300 +:10C31000884204D000221146104602F0BDFF0120E1 +:10C320000007006901218902884204D000221146D9 +:10C33000104602F0B1FF3B4800903B4B0522032121 +:10C34000002001F068FA002803D00022114602F014 +:10C35000A3FF00F015FC00F058FC012500281AD0BE +:10C3600000F062FC002803D00022114602F094FF86 +:10C3700020466840FFF783FF00F038F800F07AFCB1 +:10C3800000280ED00022114602F086FF09E00124A9 +:10C390000021C161B8E720466840FFF770FF00F058 +:10C3A00025F803252D03002C04D1A86800F03EFBDE +:10C3B000002807D100F0F5FB002803D00022114629 +:10C3C00002F06AFFA86800F031FB002806D000F0F8 +:10C3D0001CFC002802D1A86800F0EFFBBFF34F8FD0 +:10C3E00013491248C860BFF34F8FFEE7094A10B5E2 +:10C3F00048321421082002F0B9FE002803D00022A0 +:10C40000114602F049FF10BDEFBEADDEE8F60300B5 +:10C41000C7F203002C2B002077C203000005004068 +:10C42000001000104BDC0300EC2800200400FA058B +:10C4300000ED00E070B5FF4C1E46A06815460229CD +:10C4400002D0042916D108E0052813D1A369002BD6 +:10C4500010D03246294604200BE002280AD1F648C3 +:10C46000406880470320A060A369002B02D03246B9 +:10C4700029469847280003D00022114602F00CFFFD +:10C4800070BD4CB5EB4E0120307005200195009435 +:10C4900000F006FB4CBD10B5E64C2078002801D01A +:10C4A000082010BD206901F0A2FA002803D0002264 +:10C4B000114602F0F1FE0F2100228904206901F0EB +:10C4C00059FA040003D00022114602F0E5FE20468E +:10C4D00010BDD84910B5D7481C3141610221816097 +:10C4E000C1681C3002F007FD002803D0002211466D +:10C4F00002F0D2FE10BD00B589B01822CF4902A8C3 +:10C50000FFF796FE069807990090019102A80FC8C0 +:10C5100000F0C6FA09B000BD00B5C64987B0498829 +:10C520006A4611810321090389680691C2490120E5 +:10C5300050394A6803928A680492C9680591069A3C +:10C540000091019202A90EC900F0AAFA002007B0DA +:10C5500000BD10B588B0182102A802F0C5FF002464 +:10C56000B4480294408869468881B3480799503896 +:10C57000C06806900191009003A90EC9204600F002 +:10C580008FFA204608B010BD00B5AA4987B0498887 +:10C590006A461181A849032050394A6803928A6883 +:10C5A0000492C9680591069A0091019202A90EC9E8 +:10C5B00000F076FA0020CAE73EB5A04A6B46183272 +:10C5C00007CA07C39B4D00246C7029466C801C3140 +:10C5D000684602F044FC002801D0AC603EBD032058 +:10C5E0009449000380681C3148609248944A0021B5 +:10C5F000103001F063F9002803D00022114602F048 +:10C600004BFE0F2100228904286901F0B3F90028AC +:10C6100003D00022114602F03FFE01206C60A860AA +:10C6200000203EBD83498861704770B542688248EA +:10C630001468536891685038D26804604360C260DF +:10C6400081600078440701D5840705D19C0703D198 +:10C650008C0701D1940701D0062070BD5B189A1891 +:10C66000744D0F239B02EA60994207D80321090306 +:10C6700089687723DB02591A914201D20C2070BDE0 +:10C680006D4C7049216070496160C10701D06F48ED +:10C6900004E0800701D56E4800E06E48A060A868FD +:10C6A000012802D00826304670BDFFF7F4FE0600D0 +:10C6B000FAD12168E8688847F5E770B5050004D02D +:10C6C000287A800703D0102070BD0E2070BD594C11 +:10C6D000A068032805D0042801D0052803D008202D +:10C6E00070BD0520A0606868E168860060688019F8 +:10C6F000884204D90020C04360600C2070BDFFF761 +:10C70000CAFE0028FAD1A96832466368606902F05F +:10C71000C2FB0028F2D1616889196160E268914228 +:10C72000ECD0092070BD10B5424C0820616800298A +:10C7300000D010BDA1680429FBD13F486178403882 +:10C7400002F010FC002802D00021617010BD05210C +:10C75000A16010BDF8B5374C0746A068032804D087 +:10C76000042804D008252846F8BD0420A06060688D +:10C77000002801D00820F8BDFFF78DFE0500FAD192 +:10C780007868860060788119402901D90920F8BDB0 +:10C79000294AB968403A1018324602F046FE6078DD +:10C7A00080196070DFE710B5224CA068052813D10E +:10C7B000E168606888420FD10620A060FFF76BFE39 +:10C7C000002808D16069E168406802F005FC002893 +:10C7D00001D10721A16010BD082010BD10B515487A +:10C7E0008168072901D0082010BD006901F0FFF819 +:10C7F000002803D00022114602F04EFD0E4880684A +:10C80000804710BD1CB506200195009400F048F942 +:10C810001CBDF8B51C4617460D46064600F0CEF87E +:10C8200000282AD00120000385421AD9291B301B79 +:10C83000234611E000280020142D0020F8F6030004 +:10C8400083C40300D3C40300F7C4030019C5030065 +:10C8500089C5030053C503001A46FFF7DAFF002815 +:10C860000BD13A462946304600F0B3F8002804D1EF +:10C870003A462946304600F0A1F8F8BDF0B589B037 +:10C88000684600F00BFA049800282AD00121090319 +:10C89000079A4018904226D9501A45081046049A23 +:10C8A0000C468718024668001618001908900320E5 +:10C8B00000038068049988420DD261190846042259 +:10C8C00000F087F800280CD121460422084600F029 +:10C8D00080F8002805D1BA1B2B4630460899FFF78F +:10C8E00098FF09B0F0BD049A079800F072F8F8E7D5 +:10C8F00000B58DB004A800F0D1F9099800280DD03A +:10C90000089800280CD008990B9840180190002135 +:10C910000998009180080290684618DF0DB000BDAC +:10C92000032000038068F1E700B58DB004A800F093 +:10C93000B5F909980028F1D0089800280ED0089978 +:10C940000B984018032100910F2102908903099848 +:10C95000019180080390684618DFDFE70320000399 +:10C960008068EFE730B591B0684600F097F9049819 +:10C97000002814D001210903079A4018904214D9C5 +:10C98000501A43081046049A5C0082180019611876 +:10C9900003242403A468049DAC4202D20E2011B0EB +:10C9A00030BD121AFFF735FFF9E703200CAB07C3C0 +:10C9B000049880080F900CA818DFF0E71FB5032338 +:10C9C00001909008039000930291684618DF04B02C +:10C9D00010BD1FB5012301909008039000930291B0 +:10C9E000684618DFF3E7000010B5BB480368012B69 +:10C9F00002D1022900D10160100003D000221146AB +:10CA000002F04AFC10BD10B5B34C48DF002803D03B +:10CA10000022114602F040FC02F0FCFB20680228D4 +:10CA200003D0032801D00428EFD110BD38B5006829 +:10CA3000401C19D00024684600F058F9009801689D +:10CA4000012910D1818800290AD0C1680320000380 +:10CA50008068002202F0CEFA00998988814201D1D3 +:10CA6000012400E00024204638BD10B504469A4851 +:10CA70002021001D02F0B9F9002803D00022114640 +:10CA800002F00AFC9448002320222146001D02F0F7 +:10CA90001BF9002803D00022114602F0FDFB10BD57 +:10CAA0000FB4F8B5684600F021F96846818B069D01 +:10CAB0000122894CFF238948002D13D0012D17D066 +:10CAC000032D2BD00021022D37D02A46052D46D02C +:10CAD000042D4ED0062A01D104202060F8BC08BCE9 +:10CAE00004B0184781800A9983600260C16010E039 +:10CAF0008180099D089949190A9D4919C160A5219C +:10CB000083600160089901610999856141610B9910 +:10CB1000C16122607148FFF7A8FFDFE700990B6849 +:10CB200003608B888380C968C160AA2181600899ED +:10CB30000161099941610A990BE0009D2E68A52EBB +:10CB400009D00660AE888680ED68C56001618360AB +:10CB500041618161DDE781800360C160F6E700F03B +:10CB600085F9002803D00022114602F095FB03202E +:10CB7000B3E781800360C160009989688160C9E77B +:10CB80000EB557480090202001900120029002F03D +:10CB900001F8002804D150496846091D02F023F825 +:10CBA0000EBD10B5FFF708FD002805D100F02FFBE2 +:10CBB0000446FFF728FF204610BD70B511DF00289E +:10CBC00003D00022114602F067FB464900200B68A3 +:10CBD000444C012180340A4682401A4204D0C506E2 +:10CBE000ED0E0A46AA402260401C2028F3D30324FD +:10CBF0002403A06813DF002803D00022114602F0AE +:10CC00004BFBA06802F0F2F970BD08B5684600F071 +:10CC10006DF800980168A52904D08068AA2801D081 +:10CC2000002008BD012008BD10B5FFF79BFE0028BD +:10CC300003D1FFF779FE00281BD0642001F0F2FD3C +:10CC4000FFF71CFE002803D00022114602F024FB4F +:10CC5000FFF788FE002803D00022114602F01CFBDB +:10CC6000FFF746FE040003D00022114602F014FB39 +:10CC7000204610BD00B589B018221B4902A8FFF755 +:10CC8000D7FA069807990090019102A80FC8FFF7FC +:10CC900007FFFFF7B8FE002009B000BD10B50E4930 +:10CCA00088B0044600232022091D684602F04FF890 +:10CCB0000098206068468088A0800398E060029811 +:10CCC000A06004982061059860610698A0610798AB +:10CCD000E06108B010BD000024280020202D0020B5 +:10CCE000E9C9030000E100E01CF70300014901600D +:10CCF0007047000000FC030008280CD004DC00286A +:10CD000007D006280FD108E00B280AD00C280AD13A +:10CD100005E001207047022070470320704704207F +:10CD20007047042901D0062070470520704770B570 +:10CD300015460A46032823D0042820D1FE4C00299A +:10CD400006D0E088FD49884219D0132176DF10E033 +:10CD5000284602F0A3F9002803D00022114602F071 +:10CD60009BFAE069A8420AD101220321F44801F0AC +:10CD700003F8002803D00022114602F08DFA70BD9E +:10CD800001211046FFF7B8FF02460121EEE7F0B59A +:10CD9000054608790E4685B081070CD0032211465E +:10CDA000284600F0E9FF002803D00022114602F0D7 +:10CDB00073FA05B0F0BDE0490090183102F047F970 +:10CDC000010011D1DC4CB168009AA06902F02DFB82 +:10CDD000009802F097F9010006D120466946183004 +:10CDE00002F09CF9010003D0284600F0AFFAE0E71A +:10CDF00004200190009880080290A069039001A887 +:10CE0000FFF75BFC07000BD0092F10D0A06902F0E0 +:10CE100045F9010002D0284600F098FA3946E3E7C8 +:10CE20003079616940186061A069E061C1E73079DB +:10CE300061694118616160780028BAD06089401E3C +:10CE40000004000C6081B4D1284601F0E9F8002804 +:10CE500003D00022114602F01FFA20896081A8E762 +:10CE600010B50022114602F017FA10BD10B5B24CF1 +:10CE700001202070E088B149884208D0132176DF74 +:10CE8000002810D00022114602F006FA0BE0A0782C +:10CE9000002808D074DF002803D00022114602F0D9 +:10CEA000FBF90020A07001F034FC002803D0002220 +:10CEB000114602F0F1F9002010BD70B50D6804466E +:10CEC00001209D4A2B0002F002FC0A2B304306137E +:10CED00020575C466012FFF766FC0421FFF70CFF49 +:10CEE000024604212EE00022114602F0D5F970BD61 +:10CEF000FFF7BCFF002803D00022114602F0CCF956 +:10CF0000FFF76CFC002808D170BDFFF7AFFF0028C9 +:10CF100003D00022114602F0BFF9FFF773FC70BD89 +:10CF2000106188680078107170BD022010618868F7 +:10CF300000780128F8D1FFF7F6FB0221FFF7DCFEAD +:10CF400002460221204600F017FF0028CBD170BD19 +:10CF50000320106170BD12692046012A06D0022A02 +:10CF600007D0032AF6D1FFF712FF70BD00F001FAD7 +:10CF700070BD00F03BFA70BD507088881081508100 +:10CF800070BD00205070108170BD2046516901F0C5 +:10CF900010F8DAE710B5044669488EB08179684622 +:10CFA000817068490180342101A802F09DFA0220B5 +:10CFB000019000216846417284720121018205902E +:10CFC000002101A801F03FFA002803D000221146F9 +:10CFD00002F062F90EB010BDF0B5574C8BB0A078DE +:10CFE00000283AD156481821183802F07DFA204618 +:10CFF000534CC078183C00250126002837D027461E +:10D00000483700950195029510226946F81D039551 +:10D0100002F0DEF9002822D0F81D08900997684632 +:10D02000067509A804906846067708A806900420AB +:10D03000FFF7B0FF25700220207204A8E0602820CE +:10D0400020823F486582183873DF002803D0002211 +:10D05000114602F021F9384886700BB0F0BD05206A +:10D06000FFF798FF2670676025722582E9E70620A2 +:10D07000FFF790FF257065602572E0E770B52E4CD4 +:10D0800001880022E588A6B017290AD01EDC1129E4 +:10D090003FD008DC022977D0102902D18088E080B7 +:10D0A000A27026B070BD264C30342646183613299F +:10D0B00051D01429F5D1C289638D00219A4200D143 +:10D0C000314600238088E21D82DF1BE0512970D0A9 +:10D0D0000EDC18296CD01929E3D180790028E0D121 +:10D0E000A270E068401EE0604FD0FFF775FFD8E700 +:10D0F000522976D05529D4D180790028D1D1132155 +:10D10000284676DF0028CCD00022114602F0C4F871 +:10D11000C7E78020694688803220E060012301AAA9 +:10D1200006A92846AADF002803D00022114602F0F3 +:10D13000B3F82078002807E030280020FFFF000027 +:10D14000582D00203015000001D1FFF745FF0020C9 +:10D15000C043E080A5E70722C14910A802F065F9A5 +:10D160001022E11D0CA802F060F91C22314612A821 +:10D1700002F05BF90CA80A9012A8099006ABB94A14 +:10D18000852128467FDFBDE70DE01822B64906A8B5 +:10D19000FFF74EF80A980B990090019106A80FC866 +:10D1A000FFF77EFC7DE70021284667DFAAE700E065 +:10D1B00017E0817900299AD0807A042803D00628C4 +:10D1C00001D0052893D1022909D0012069460872AF +:10D1D000FF208330888102A92846A8DF92E7022039 +:10D1E000F4E700F08DF88DE710B5044601F0C2FABF +:10D1F0009B482146303800F09AFE2046FFF73EFF5C +:10D2000010BD10B50022114602F046F810BD30B531 +:10D21000944D87B00024203D2C7094482C6102F07E +:10D22000B3F800286AD19248FFF7FCF901F000FF3B +:10D23000002863D18A4800F059F9002801D1012063 +:10D24000E87011206946087207228AA102A87CDFD3 +:10D25000002803D00022114602F01EF800940C2191 +:10D2600068460194018018214180FF21848091311A +:10D27000C1807ADF002803D00022114602F00CF8AA +:10D2800004206946009408807C4801907C48029004 +:10D290007348303800F00BFE002803D000221146FE +:10D2A00001F0FAFF1C21684602F01EF97548019052 +:10D2B0000120800302900094032168460173C48119 +:10D2C0000474714806900594684601F0FEF9002840 +:10D2D00003D00022114601F0DFFF6249E122087805 +:10D2E0004008400010400C30DF221040087007203A +:10D2F000487010208870FFF76FFE002007B030BD27 +:10D3000070B5584C614D203CE088A84201D10820FE +:10D3100070BDE178002914D051490123082234312D +:10D32000A9DF0028F4D12A460C21E088A7DF58495C +:10D33000884204D0082802D0891C8842E8D1002005 +:10D3400070BD00231A461946A9DF70BD10B50A4604 +:10D35000044603211046FFF7CFFC02460321204676 +:10D3600000F00AFD002803D00022114601F094FFCE +:10D3700010BD30B5054687B00020009001900290A6 +:10D38000039038486A46203800791070364A0C3AC3 +:10D3900010689268049068460692059008790C28F7 +:10D3A00006D003221BE00022114601F075FFA5E71D +:10D3B0008C68204600F049F80190201D00F045F8E7 +:10D3C00002902046083000F040F8039004A8FFF7D0 +:10D3D0002CF9002892D00121FFF78EFC0246012192 +:10D3E000284600F0C9FC0028DDD187E7FEB50446D9 +:10D3F000087982070ED08207920F04239B1A00221D +:10D40000154604E08E683554401CC0B2521C9A4246 +:10D41000F8D308710120009088680290087980088C +:10D4200001906846FFF796F900280DD00221FFF71A +:10D4300063FC02460221204600F09EFC002803D037 +:10D440000022114601F028FFFEBD10B5044602F08F +:10D450004DF80002E178000A0906084310BD0000FB +:10D46000882D00205028002040F70300E9D1030058 +:10D470002FCD03004466755461726700BBCE030074 +:10D4800003D20300CD0C000061CE0300FFFF0000BB +:10D490000230000010B50C46002802D001200860C0 +:10D4A00010BD2168002911D01C48421A814212D0B7 +:10D4B0003C2A0DD23C303C3101220B7803701346DC +:10D4C000491E401E521C3C2BF7D904E00E200BE0F5 +:10D4D0003C2201F0AAFF00223C21104801F08AFD05 +:10D4E0000E49891E08800020206010BD70B50546D9 +:10D4F00000223C21094801F07DFD084CA41E218832 +:10D50000884201D00B2070BD3C220449284601F01E +:10D510008CFF2088401C2080002070BD823F0020AE +:10D520008307FF22DB0E9A408907090E99400028E5 +:10D530000BDA0007000F08388308FA489B001B1815 +:10D54000D86990430843D86170478308F6489B0028 +:10D550001B181868904308431860704770B5012481 +:10D56000F24960040860F24940108860F04940398F +:10D570008860F04D6C602F20FEF708FEAC60EE4D29 +:10D5800000242F206C61FEF701FE2C7170BDF0B5F8 +:10D59000E94F2821BC6841430D1939694A1C09D05B +:10D5A00028224A431619AB68B268934204D8D21AAB +:10D5B000B26069623861F0BD0A4602E00A46796AE3 +:10D5C0009B1B4E1C0BD028264E433719BE689E422B +:10D5D000F4D328264E433619B768FF1AB760AB60FC +:10D5E000696228214A4311194862F0BD70B5D24CD6 +:10D5F0002269A5681346114606E0814207D00A4613 +:10D60000282671434919496A4E1CF6D170BD002E77 +:10D61000FCD08A420CD1282043435819406A20612B +:10D62000401C05D1C34B01209860002363616071E9 +:10D63000282041434819282381685A43406A5219D7 +:10D640005062421CE2D0282250434019826851188F +:10D65000816070BDF8B5B84C2569681C35D0B748F5 +:10D66000002640686169401A07023F0A19E0282035 +:10D670004543A0682A189068B84214D8A3693F1A95 +:10D680008619556A002B09D0116AD069984700287D +:10D6900007D00022114601F0FFFD02E0D169106AB7 +:10D6A0008847681CE3D1A178E078814206D1401C0C +:10D6B000C0B2E070022801D10020E0709E4900064F +:10D6C000800D1C310E5000F0BAF9F8BDF8B50446D3 +:10D6D000994800270169009146785CE09648F1007E +:10D6E000C2688D1851E0601C07D0934A28209268C8 +:10D6F000604321468018446A24E028781821414379 +:10D700006A68401CC0B252182870A978884200D1BB +:10D710002F70894B516828209B684843C0181368B4 +:10D72000012B34D1037E002B31D19368C360D368C1 +:10D73000036113694361526902627F4A5279002A88 +:10D7400000D0C7607C4BC2685B6996469C46D31A82 +:10D750001A027B4B120A9A4202D20369D21808E0DD +:10D76000724663469A1A12020369120A934202D958 +:10D770009A1A826000E08760C76001220761027622 +:10D78000921E42620846FFF702FF601CABD1287868 +:10D7900069788842A7D13046761EF6B200289DD11E +:10D7A000654801690098814201D00120F8BD002040 +:10D7B000F8BD64490020086048608860C86061491D +:10D7C00040390860486045E7FEB50020C0435A4D27 +:10D7D00002906869019068462E6900F035F90746A5 +:10D7E00000F04FF90446002F08D002AA01990098D2 +:10D7F00000F08FF90298FFF769FF06E00298FFF743 +:10D8000065FF002801D1002C02D0304600F0AAF9B3 +:10D8100000206871FEBDFFB59807002481B01E4648 +:10D8200015460F4600280BD1002E09D0FFF796FEB3 +:10D8300041490A9888610F70324600208E6008E0E6 +:10D84000072005B0F0BD28234343D4509B181C7615 +:10D85000401CB842F7DB28204743BB19032048701F +:10D860000F461846CB6019461830002218232E4662 +:10D870005E43D3005B181C705C709D70586030185C +:10D88000521C032AF5DB0020C0433861BC70FC70D9 +:10D8900001242D482405046003211420FFF740FED5 +:10D8A000224880380460254C0198A0600321112093 +:10D8B000FFF736FE606878610020C2E770B51E4C45 +:10D8C000A568002D06D0002A06D0002804D0002329 +:10D8D000247809E0082070BD072070BD28265E432B +:10D8E000AE59002E04D05B1CA342F7DB042070BDB0 +:10D8F000282401265C432E516419E26161600360B3 +:10D90000002070BD07494868C005C00D2CD01038F4 +:10D910001CD50207120F083A920892005118C969E3 +:10D9200019E0000000ED00E000E400E080E100E02C +:10D93000401301400010014058280020001501400C +:10D94000FFFF7F004011014080E200E08108B14A02 +:10D950008900891809688007C00EC1400806800F39 +:10D96000012803D0032803D002207047002070470D +:10D9700001207047FEB50446A748174682680D4649 +:10D98000002A0CD001788C4201D2052D01D207204B +:10D99000FEBD2146282359435358012B01D00820AE +:10D9A000FEBD8818406801281DD00026FFF7AAFF99 +:10D9B000C00099490190C9684018694600F018F9FB +:10D9C000002812D001214460016094494968083060 +:10D9D000E2C091490198C96841180098487000F068 +:10D9E0002EF80020FEBD2E46E0E70420FEBDF8B56F +:10D9F000894D0446A868002809D029788C4201D3B3 +:10DA00000720F8BD282161434058012801D0082093 +:10DA1000F8BDFFF777FFC600E8686946301800F0E8 +:10DA2000E7F8002809D0022112C0E86831180098F0 +:10DA3000487000F004F80020F8BD0420F8BD012073 +:10DA4000774900050860704710B5734900238A784C +:10DA5000CC78A24212D0521CD2B28A70022A00D1D3 +:10DA60008B708A786C4B92001C339A58026048691C +:10DA700010180002000A4861012010BD0360002058 +:10DA800010BDF8B5644801690091457833E06248FB +:10DA9000E900C0680E1834782AE0182060437168E5 +:10DAA000641C0818B178E4B2A14200D100240168D6 +:10DAB000022902D003291BD113E0574A40682821CC +:10DAC000926841438F18397E002911D0FFF78EFDEF +:10DAD000002038760CE028277843C0180276406A88 +:10DAE00003E04D4900228B680869471CF3D10861A7 +:10DAF0007078A042D1D128466D1EEDB20028C6D163 +:10DB0000454801690098814201D00120F8BD0020FC +:10DB1000F8BDF7B5404C0025A76823691EE0282111 +:10DB20005943C9198E68864202D9301A886017E0B5 +:10DB3000801B751900268E600E764E699C464B6AD6 +:10DB4000B646002E0AD0019E76193602360ACE60FD +:10DB500076460E6116684E6261461160591CDED130 +:10DB60002361FEBDF8B52C4801694A1C3DD028222E +:10DB70005143826889188E6828494C684769007942 +:10DB8000E11B0D022D0AED1C002815D10120254AAC +:10DB900000045060234A403A5060214940008031DF +:10DBA0000860214908602149012008602F20FEF704 +:10DBB000EDFA194901200871B54200D23546E8193D +:10DBC00000021649000A4031086014494968001BE8 +:10DBD000091B0902090A0002C91C000A814203D973 +:10DBE00001200F4940040860F8BDFFF7B7FCF8BDFD +:10DBF00042788378521C934200D1002203789342EA +:10DC000001D1002070470A604168407818225043D3 +:10DC10000818704700E400E0582800200015014073 +:10DC200000E200E04013014000E100E0001001408C +:10DC300010B50446082904D000221146104601F010 +:10DC40002BFB21686068884710BD1CB501910090CE +:10DC5000024A0821684601F09DFA1CBD31DC030030 +:10DC60000A48026803210A430260094880470948BC +:10DC70000047FEE7FEE7FEE7FEE7FEE7FEE70000FF +:10DC800005480649064A074B704700002405004036 +:10DC9000A9DC0300C1C0030090300020903C0020AC +:10DCA0009034002090340020F8B500F035F82B4E69 +:10DCB000002804D02A4870602A49F01388612A4855 +:10DCC0000124018CC9B201290DD1818C09070AD127 +:10DCD000018D0906090F042905D1808D0006000F6A +:10DCE00001D1224884600027B461214D6F60A805EE +:10DCF0008460686800280ED1C820FEF757FA1D48D6 +:10DD00007F1C8742F5D30020B0610120800784602A +:10DD100068680028FCD0F8BD1348018CC9B20129FD +:10DD200017D1818C090714D1018D09060A0F03D17F +:10DD3000828D1206120F0ED0090F012903D1828D98 +:10DD40001206120F07D0032903D1808D0006000FA1 +:10DD500001D00020704701207047000000050040FE +:10DD6000DFFF07C0006C0040C00F00F0000600405D +:10DD7000000100408813000030B585B0002822D093 +:10DD80000388FE4CA34220D0FD4B1B78002B1CD0F7 +:10DD9000FB4B10255B1C1D705970002401259A70E7 +:10DDA000032269460A820094019402940394028A31 +:10DDB0000A808D708C8004A90291039300886946C3 +:10DDC000A6DF05B030BD0E20FBE70820F9E7F0B56F +:10DDD0008BB004460227684607730026099687849D +:10DDE000C68408A80A900D46A18A208809AAA5DF42 +:10DDF000002804D0E16A00291AD0884718E0684654 +:10DE0000008CC007C00F13D068460682208803A983 +:10DE1000A8DF002813D1A97E28461B3001220B0061 +:10DE200001F055FC09430F1B202224263E28430005 +:10DE3000FF20FE3069460882208803A9A8DF0BB0C6 +:10DE4000F0BD00960AE0062219E069460A710290C8 +:10DE500022E0204690470020F1E700922B8B022B16 +:10DE6000F3D2F0E700971DE003201AE0042018E049 +:10DE7000052016E0298B032905D20322082120461C +:10DE8000FFF77AFFDBE74178027808021043694622 +:10DE9000888003D006200090A26ADAE70720FAE71C +:10DEA000092000906946A26AD3E70322E7E730B56C +:10DEB00085B00D46040038D0002D36D068680028A3 +:10DEC00033D00020C043AF4B20800FCB049301AB75 +:10DED00007C3AD4869460880891C01A863DF002894 +:10DEE00022D1221D69460120A0DF00281CD16846EE +:10DEF0008078A071204600F0CEF8002814D120468A +:10DF000000F055F900280FD12946204600F002F90B +:10DF1000002809D16868A062A868002800D0E062E3 +:10DF200097490120087000204BE70E2049E73EB5D5 +:10DF3000002828D0002926D0826A002A23D00A8807 +:10DF4000102A21D0112A30D0502A1FD0512A1AD19C +:10DF500004460846891D0A78022A14D14A88238A71 +:10DF60009A4210D1807A04280DD006280BD00528BB +:10DF700009D0891C2046FFF72AFF002803D0E16A58 +:10DF8000002900D088473EBD898810E0CA880389EF +:10DF90009A42F8D1082200928A7F6B461A7120318A +:10DFA0000291826A694690473EBD0021C9430180C3 +:10DFB0003EBDF0B585B00A4605002DD028886F49D2 +:10DFC00088422BD06E480078002827D06C4C102057 +:10DFD000641C2070072060700127A7700321684629 +:10DFE00001820026E11C104600F04CF8014668460C +:10DFF000008A0918684601820096019602960396E7 +:10E00000298A01808770868004A80394029028885A +:10E010006946A6DF05B0F0BD0E20FBE70820F9E752 +:10E02000F0B585B00A46050028D0288853498842B3 +:10E0300026D053480078002822D0514C1120641C6F +:10E0400020700127684607820026611C104600F0F8 +:10E0500019F801466846008A091868460182009648 +:10E06000019602960396298A01808770868004A80B +:10E070000394029028886946A6DFCBE70E20C9E703 +:10E080000820C7E70870020A4A70020C8A70000E66 +:10E09000C8700420704730B58FB005461C21684613 +:10E0A00001F022FA6946087804210843694608709D +:10E0B000002401940394049405940694A87908A973 +:10E0C000887031486946801C0884601C00070794EA +:10E0D000000F0C77103048778A7FF9200240921C9D +:10E0E000E7200240012002438A77142109A801F0A9 +:10E0F000FBF908A8099007A80A9069468C851420A6 +:10E10000CC8508860D942B46A888083309AAA2DF7F +:10E110000FB030BDF0B58FB00F4605461C216846E4 +:10E1200001F0E2F9684601780226314301700024CB +:10E1300001940394049405940694A97908A8817025 +:10E1400011496846091D0184601C0107090F10313F +:10E150006846079401770020014668464177817F31 +:10E16000F9200140891CE720014001200143684655 +:10E170008177142109A801F0B7F907E0FFFF00003B +:10E180008028002058F703003015000008A80990E7 +:10E1900007A80A9068468685C48506860D972B4693 +:10E1A000A888203309AA6946A2DF0FB0F0BD30B5B8 +:10E1B0008FB005461C21684601F096F9694608783B +:10E1C0000821084310221043694608700024019476 +:10E1D0000394049405940694A87908A988701448B7 +:10E1E00069460884601C00070794000F0C77103004 +:10E1F0004877887FF9210840801CF72108401043A8 +:10E200000121084369468877142109A801F06CF9B7 +:10E2100008A8099007A80A9069468C851720CC8524 +:10E2200008860D942B46A888103309AAA2DF6FE751 +:10E2300031150000FFB583B0074600200C9C8646D0 +:10E24000267805463AE07868A90041180A886846A9 +:10E2500082804988C1800022694601A865DF0028C4 +:10E2600010D1684601780598814226D17046002871 +:10E2700001D0002200E002222078891841181F29CD +:10E2800002D90C2007B0F0BD7146002908D1401C0E +:10E29000C0B2411C069B049A21701A540120864684 +:10E2A000217806980A18694601A865DF0028E9D197 +:10E2B000694620780978401820706D1C3888A8427B +:10E2C000C1DC7046002804D020780699801B401ECF +:10E2D00088550020D6E7F8B51546069C1E46074629 +:10E2E00002220094FFF7A6FF002806D13346102231 +:10E2F000294638460094FFF79DFFF8BDF7B582B078 +:10E3000000260546167000681446002805D02846E9 +:10E31000039900F0CAF8060008D1687900281ED0D9 +:10E320002078039F001D1F2802D90C2005B0F0BDE6 +:10E33000684679DF0028F9D121780322481C207033 +:10E340007A5421781922481C20707A542078C119F7 +:10E350006846008800F0A4F8217840182070A87959 +:10E360000223002810D02078039A411C21701354F6 +:10E3700020780399471C012227700A542078AA7933 +:10E38000471C039927700A54A868002815D000215B +:10E39000415620788C460246C01C03991F28C4D8D9 +:10E3A000501C20708B5422780A23501C20708B54F0 +:10E3B00020786246431C23700A54A889002809D09B +:10E3C00028460094062202210C30039BFFF783FFAE +:10E3D0000600ABD1A88A002809D02846009407225D +:10E3E00003211430039BFFF776FF06009ED1A88B14 +:10E3F000002809D028460094152214211C30039BC4 +:10E40000FFF769FF060091D1686A002805D022460F +:10E41000039900F07FF8060088D1A86A002805D08B +:10E420002246039900F0B5F8060084D13020405D03 +:10E43000002806D022462846039900F0DCF80600A2 +:10E44000C7D1304672E770B50C4692B000216A46DB +:10E45000117007251171002809D0817949070CD561 +:10E4600002A9FFF74BFF002808D102AE00E000260A +:10E47000002C0ED0A079002802D0284612B070BD22 +:10E4800001AA0AA92046FFF739FF0028F6D10AAAF7 +:10E4900000E00022684603790178304672DFEDE73C +:10E4A0000870000A487002207047F8B514780746D3 +:10E4B000A01C15460E461F2803D83879801C1F283B +:10E4C00001D90C20F8BD1D20001B80B2694686468C +:10E4D00008803019801C7DDF0028F3D138680228BD +:10E4E00005D168460088704501D8092107E03879D0 +:10E4F0000821002801D0704501D968460088421CD7 +:10E500003255641CE2B2B1542978801C0818287076 +:10E510000020F8BDF8B50D4611780646881D144652 +:10E520001F2801D90C20F8BD33880720062BFAD309 +:10E530001927FF01BB4202D94D4A9342F3D1728899 +:10E54000062AF0D3BA4202D9494FBA42EBD1484F1A +:10E55000BB4203D0BA4201D09342E4D8481C052202 +:10E5600020706A5420781222411C21702A5420788D +:10E5700041193088FFF794FF21784018C0B220700D +:10E5800041197088FFF78CFF217840182070002017 +:10E59000F8BD70B5054600790E46801C1446C0B221 +:10E5A0001178821C8A181F2A01D90C2070BD0A46D6 +:10E5B000491C401C2170B0542078FF22411C21705E +:10E5C0003254207881192888FFF76AFF2178401893 +:10E5D000C0B22070AA88002A09D0A968002908D0F2 +:10E5E000801900F022FF207829794018207000203F +:10E5F00070BD072070BDF7B582B002981446C06A9E +:10E600000F46002832D0029800252030009028E0E4 +:10E610000298C16A0C2068430E18217830794A1C90 +:10E62000C01C2270785421781622481C20707A541D +:10E630002078C1193088FFF733FF21784018C0B225 +:10E640002070B288002A09D0B16800290ED0C01904 +:10E6500000F0EBFE20783179401820706D1C009896 +:10E66000EDB2007CA842D3D800205FE607205DE62B +:10E67000FFFF000038B56749674A488890420FD0CD +:10E680004A78664C521CD2B24A70237B934208D31C +:10E69000083175DF002803D0A169002900D0884720 +:10E6A00038BD00254D70217C002907D03B2176DF45 +:10E6B000002803D0A169002900D08847616900299A +:10E6C000EED068460095884738BD70B505460146CE +:10E6D0001C225248FDF7ACFD4E4C002626702968DE +:10E6E000002907D00822A01800F09FFE204608301D +:10E6F0007ADF02E0474808307BDF002808D1401E5F +:10E70000608044486670464A0021001DFFF7D6F835 +:10E7100070BD10B53F484068FFF769F910BDF8B506 +:10E720003C48103000F069F800263A4D3B4C002878 +:10E7300006D06169002919D001200090684614E0D4 +:10E740002878002804D0616900290FD00096F5E7E9 +:10E75000687800280CD0A16800226868FFF70AF9E1 +:10E76000002803D0A169002900D088472E70F8BD89 +:10E770006168F1E7F8B5294C02880027254DE68944 +:10E78000102A18D029464968112A21D0122A2DD0E2 +:10E79000502A0FD1801D0288B2420BD1028B022A6F +:10E7A00008D1C27E837E10021843C007C00F13D069 +:10E7B000FFF7B5FFF8BD818869800146154808223A +:10E7C0001631103000F031FE6F70002EF0D0F8BD21 +:10E7D0000020C04368806F700846FFF708F90028E2 +:10E7E000F5D0A1690029F2D08847F8BD811D0948FC +:10E7F0000822103000F019FEDAE741880548083099 +:10E800000288914204D34088814201D80120704798 +:10E810000020704788280020FFFF0000C42D002042 +:10E8200075E6030031B5054C04E0401E009020461B +:10E83000FDF7CCFC00980028F7D138BDE7030000B5 +:10E8400018225043FE4A0021801801718160416105 +:10E85000012281610261C1607047FFB581B0F94C4E +:10E86000049B039A054626691A4303200092002E52 +:10E8700003D1002A0ED0012222612769039A0126C2 +:10E88000360792003B0000F022FF072707162940B9 +:10E89000526127000222EFE77069326992B2504359 +:10E8A000326933691204920C9BB2594329DF002864 +:10E8B00012D102210FE0084628DF00280CD103996D +:10E8C000002901D0032106E00499002916D12978F6 +:10E8D000042946D017E0216105B0F0BD70693269A6 +:10E8E00092B25043326993B24B4301461846039AA1 +:10E8F00029DF0028F0D10499002901D00421EAE79A +:10E900002978042920D00521E5E773693069366943 +:10E9100080B2434368681B189B18B6B24E43301848 +:10E9200080181946049A29DF0028E9D0D4E7306915 +:10E9300080B24843696880188A08696929DF00281D +:10E94000CAD1009900290CD00621C4E77069316949 +:10E9500089B24843316989B200F0D9FD28DF002827 +:10E96000BAD10721B7E7F8B5B54918230A780F20BF +:10E970005A435418241DB34922782669CF68022AC5 +:10E980001BD001252D07042A2AD0052A5BD128692E +:10E9900081B2304600F0BBFD0146A36828699A1990 +:10E9A00080B24843101A82086068181886192869CE +:10E9B0004B1C80B25843801B34E0B8026268616926 +:10E9C000121A0918A3683018181801239B029A42DA +:10E9D00002D2920829DF31E0FF22013229DF2DE047 +:10E9E000E268974914205043F4314018001D0BC8C9 +:10E9F000B04203D160685943814218D0022A16D030 +:10EA0000286981B2304600F082FD0146286980B253 +:10EA10004843301A820828694B1C80B25843636807 +:10EA20009B19C01A83082046FFF717FF06E02869E4 +:10EA300081B2304600F06BFDC01928DF002802D1FA +:10EA40007F4901228A70F8BDF8B57D4C069E657835 +:10EA50000A2D1DD027787D19EDB20A2D01D30A3D6C +:10EA6000EDB218277D432D192871AA6103C9EE6004 +:10EA7000AB6069612861A1780020002904D1FFF70B +:10EA800072FF112800D100206178491C6170F8BD27 +:10EA90000420F8BD38B50246694818230178594367 +:10EAA000081803690179022B0AD014246343644CCB +:10EAB000F434E4588368009383691030A04738BD6C +:10EAC000604B14331C68F5E7F8B55D4B9978012964 +:10EAD00014D100255B499D700A69082A05D00228D7 +:10EAE0000FD003280AD10D2006E0022807D00D70B0 +:10EAF00000F025FA002801D0FFF7CCFFF8BD0D612A +:10EB0000F6E74F48182403784E496343CC68181839 +:10EB1000641C001DCC600378022B05D14668A1025D +:10EB2000B14201D3012700E00027052B01D1072ABC +:10EB300003D00021042B02D003E00121FAE7072AC9 +:10EB400003D00026042B02D007E00126FAE7406834 +:10EB5000A302834201D3002A1AD00020314301438B +:10EB60003943C5D0374E28463561FFF793FF344C03 +:10EB70002078FFF765FEF5606078401E60702078B1 +:10EB8000401CC0B220700A28B2D30A382070AFE708 +:10EB90000120E3E770B500252A4C2948E56025618E +:10EBA0000570457085702E463046FFF749FE761C8D +:10EBB0000A2EF9D3012212076560516928461269AD +:10EBC000491E92B25143E560A1601D49F4310D60C8 +:10EBD0008D600D61CD601B4914310D60888001216D +:10EBE0002170206170BDF8B5164A044610780E46B3 +:10EBF000002830D0002C30D0002E2ED020680028E5 +:10EC00002BD0012000076768016989B28F4228D89C +:10EC1000102F26D3A168002923D095687943436932 +:10EC20004A19006980B243439A421AD8012000076A +:10EC3000006980B2814212D901200007006903E017 +:10EC4000E02D0020A028002080B2394600F05FFCB3 +:10EC5000002906D103E00820F8BD0E20F8BDB80752 +:10EC600001D00720F8BDBD49486801281CD00F46D7 +:10EC70001421BB4A21C641438E1875602368535046 +:10EC80006168B160A168F160A268616800235143C6 +:10EC9000012212075B1C14699BB2A4B28C4205D2FC +:10ECA0001469A4B2091B02E00420F8BD0021146914 +:10ECB000A4B265191469A4B28C42EBD9BD60401CA2 +:10ECC000336178600020F8BDF8B50446A3481E46BD +:10ECD000007815460F46002807D0002F07D0002CDB +:10ECE00005D02068002817D103E00820F8BD0E20C9 +:10ECF000F8BD9B48016800290ED0C2688168406851 +:10ED00004A4310186268904206D9002D04D0A942E7 +:10ED100002D3A819884201D90720F8BD384600F06F +:10ED200008F9002811D0304600F003F900280CD073 +:10ED3000606800F0FEF8002807D02B463A462146CE +:10ED400002200096FFF780FEF8BD1020F8BDFFB549 +:10ED5000824881B000781F4616460D46002808D02C +:10ED6000002D08D00198002805D02868002817D168 +:10ED700003E00820B0E50E20AEE5794C20680028BD +:10ED80000ED0E168A0686268414389186A689142C0 +:10ED900006D9002E04D0B04202D3F119814201D924 +:10EDA000072099E5019800F0C4F800281BD03846E8 +:10EDB00000F0BFF8002816D0686800F0BAF8002804 +:10EDC00011D068683246C119019800F02EFB0096F8 +:10EDD0002868142148432458002203212846019B17 +:10EDE000A047002078E5102076E5F8B505465B4899 +:10EDF0000F460078002805D0002D05D0286800288F +:10EE000021D103E00820F8BD0E20F8BD544C0026A7 +:10EE10002068002817D0A168E0684843616841185D +:10EE2000686881420FD900F084F800280DD0296865 +:10EE300014225143091968684A688968801A00F0E9 +:10EE400066FB002903D00720F8BD1020F8BD3B4623 +:10EE50000022294604200096FFF7F6FDF8BD3F4A40 +:10EE60001278002A0DD000280DD000290BD002689E +:10EE7000002A08D0394A14321368002B05D0042028 +:10EE80007047082070470E20704702230B6000680F +:10EE9000106000207047F8B5044630481E460078E0 +:10EEA00017460D46002807D0002D07D0002C05D0AE +:10EEB000206802281BD103E00820F8BD0E20F8BD11 +:10EEC000264814300068002811D0084600F031F8B8 +:10EED00000280ED0304600F02CF8002809D03B4620 +:10EEE0002A46214602200096FFF7AEFDF8BD072016 +:10EEF000F8BD1020F8BD08B5184A1278002A05D0D0 +:10EF0000002805D00268022A11D103E0082008BDBC +:10EF10000E2008BD114A14321268002A07D00B4691 +:10EF20000022014604200092FFF78EFD08BD072055 +:10EF300008BD800701D000207047012070470849B4 +:10EF400010B5F43949780020002906D0FFF70BFDF1 +:10EF5000002802D0112800D1002010BDA0280020D8 +:10EF6000D42E002070B500250C290ED3044643187A +:10EF7000008941000919581A0A38C2B21748022AF2 +:10EF8000027002D30A318B4201D2092070BD1448AD +:10EF900000F04BFA134914480A88824202D02388B1 +:10EFA000934217D14988814202D06088884211D1AA +:10EFB0000D4A0323521E20891B03A8420AD9690067 +:10EFC00009194989914203D09E896D1CB142F4D13F +:10EFD000002070BD0B2070BD00207047BC280020B1 +:10EFE000E82E002080100010FFFF000010B5FDF794 +:10EFF000FDF810BD10B50446002A02D0108800228A +:10F0000010E00A48FBE7030A00020343A05C5840F3 +:10F0100003061B0F43401803584083B21806C00C68 +:10F020005840521C8A42EED310BD0000FFFF000082 +:10F030004B48002101704C484A4A02608160C1601F +:10F04000016108224161426081610846704710B544 +:10F0500000291DD000220A60434A5368002B1BD0B0 +:10F06000202817D85B1E5360D0682423401CD06032 +:10F07000106914684343E3180B60012383409169CE +:10F08000401C19434007400F91611061002010BDE2 +:10F090000E2010BD0C2010BD042010BDF0B5324A6A +:10F0A0000646916800292BD057691020791A490724 +:10F0B000490F14680B4624254D436519B54206D106 +:10F0C000012495698C4065400020956104E0491C4D +:10F0D0004907490F8F42EED1491C4E07760F9569BB +:10F0E00001210C469C402B4623420AD19368002BF9 +:10F0F00007D05B1E936053685B1C53603346F0E798 +:10F100000420F0BD184A2423117C1268491E4907C7 +:10F11000490F5943203150500020704770B50028E6 +:10F120001AD0002918D0104AD368002B16D05B1EC5 +:10F13000D360936824265B1C9360536915681C4652 +:10F140007343EE1820330660E858641C08606007BB +:10F15000400F5061002070BD0E2070BD042070BDB6 +:10F16000BD280020F42E00201430002030B5CB0044 +:10F1700008339DB293070024002B01D0072030BD37 +:10F180003B4B9A605219DA605C701C705880998011 +:10F19000002030BDF7B5364C0E466088814237D826 +:10F1A000344F00F069F822786078A188884201DA4B +:10F1B000401C00E00020C0B2904202D100F062F892 +:10F1C00024E065786078884201DA401C00E0002085 +:10F1D000607000F057F8BD4218D0A068EF000299A7 +:10F1E000C151009900290CD0002E0AD06088324607 +:10F1F0004543E068281800F018F9A06838188680A0 +:10F2000002E00021381881800020FEBD0420FEBDF0 +:10F210000920FEBD0EB504E068468188029A009878 +:10F22000904702AA01A9684600F003F80028F3D02D +:10F230000EBD70B50E4B05241D785E78AE4215D01C +:10F240001D781C789E88B44201DA641C00E000241A +:10F250001C705C88DE686C43A41904609B68E8003D +:10F26000C418A4880C80185800241060204670BD73 +:10F27000C4280020FFFF000072B606480168491C40 +:10F280000160704703490868401E086000D162B6FB +:10F2900070470000D4280020BFF34F8F0349024875 +:10F2A000C860BFF34F8FFEE70400FA0500ED00E0F1 +:10F2B00010B5002904D0002211461046FFF7ECFFDC +:10F2C00000F010F810BD10B50021024A0846FFF703 +:10F2D00061FF10BDB1F2030010B508461146FCF7FE +:10F2E000C3FF10BDF8B5384C2078002837D020690E +:10F2F000002807D00026E068002805D00025002E51 +:10F3000004D013E00126F6E70125F8E7684651DF4F +:10F31000052806D0002806D000221146FFF7BCFFC2 +:10F3200004E0012602E0216900988847002D12D1EF +:10F33000608869460880A06861DF052806D000283B +:10F3400006D000221146FFF7A7FF04E0012502E0E6 +:10F35000E168A0688847002ED8D0002DCFD0F8BD36 +:10F3600070B5002901D08C0701D0072070BD164C64 +:10F370000125A16062801549636010DF0028F5D186 +:10F38000257016202EDF70BD002803D00E49C860FE +:10F39000002070470E207047002803D00A490861FA +:10F3A000002070470E20704710B5074840680028BD +:10F3B00007D08047002803D000221146FFF76CFFDA +:10F3C00010BDFFF78FFF10BDD8280020D9F2030031 +:10F3D000034610B50B439B070FD1042A0DD308C871 +:10F3E00010C9121FA342F8D018BA21BA884201D915 +:10F3F000012010BD0020C04310BD002A03D0D30758 +:10F4000003D0521C07E0002010BD03780C78401C8C +:10F41000491C1B1B07D103780C78401C491C1B1B83 +:10F4200001D1921EF1D1184610BDF8B5042A2CD393 +:10F43000830712D00B78491C0370401C521E8307AF +:10F440000BD00B78491C0370401C521E830704D05C +:10F450000B78491C0370401C521E8B079B0F05D074 +:10F46000C91ADF002023DE1B08C90AE0FCF7E0FE12 +:10F47000F8BD1D4608C9FD401C46B4402C4310C0D1 +:10F48000121F042AF5D2F308C91A521EF0D40B78C1 +:10F49000491C0370401C521EEAD40B78491C0370AF +:10F4A000401C521EE4D409780170F8BD01E004C08C +:10F4B000091F0429FBD28B0701D50280801CC907D4 +:10F4C00000D00270704700290BD0C30702D0027031 +:10F4D000401C491E022904D3830702D50280801CE8 +:10F4E000891EE3E70022EEE70022DFE70378C27817 +:10F4F0001946437812061B0219438378C0781B040F +:10F50000194311430902090A000608437047002203 +:10F5100003098B422CD3030A8B4211D300239C4650 +:10F520004EE003460B433CD4002243088B4231D3C8 +:10F5300003098B421CD3030A8B4201D394463FE05C +:10F54000C3098B4201D3CB01C01A524183098B42BC +:10F5500001D38B01C01A524143098B4201D34B01A5 +:10F56000C01A524103098B4201D30B01C01A524108 +:10F57000C3088B4201D3CB00C01A524183088B428F +:10F5800001D38B00C01A524143088B4201D34B0078 +:10F59000C01A5241411A00D20146524110467047EA +:10F5A0005DE0CA0F00D04942031000D340425340EF +:10F5B00000229C4603098B422DD3030A8B4212D3AF +:10F5C000FC22890112BA030A8B420CD389019211E1 +:10F5D0008B4208D3890192118B4204D389013AD01E +:10F5E000921100E08909C3098B4201D3CB01C01AF3 +:10F5F000524183098B4201D38B01C01A5241430906 +:10F600008B4201D34B01C01A524103098B4201D3F3 +:10F610000B01C01A5241C3088B4201D3CB00C01A60 +:10F62000524183088B4201D38B00C01A5241D9D278 +:10F6300043088B4201D34B00C01A5241411A00D2F9 +:10F640000146634652415B10104601D34042002BF5 +:10F6500000D54942704763465B1000D3404201B574 +:10F660000020C046C04602BD7047704770477546CF +:10F6700000F022F8AE46050069465346C008C000B7 +:10F68000854618B020B5FEF7FBFA60BC0027490894 +:10F69000B6460026C0C5C0C5C0C5C0C5C0C5C0C52A +:10F6A000C0C5C0C5403D49008D4670470446C046B0 +:10F6B000C0462046FCF751FD00487047303000201E +:10F6C00001491820ABBEFEE726000200704730B4A7 +:10F6D0007446641E2578641CAB4200D21D46635DEF +:10F6E0005B00E31830BC1847020000000000000077 +:10F6F0000000000000000000040000000000000006 +:10F7000000000000000000000000000000000000F9 +:10F7100035C40300000000000000000002000000EB +:10F7200000000000000000000000000000000000D9 +:10F7300000000000030000000000000000000000C6 +:10F7400005000000000000000000000000000000B4 +:10F75000000000000000000023D1BCEA5F78231500 +:10F76000DEEF12120000000088F7030000280020DE +:10F77000EC00000004C1030074F80300EC28002032 +:10F78000A413000020C103000000000000000000DE +:10F790000000000000000000000000000000000069 +:10F7A0000000000000000000000000000000000059 +:10F7B0000000000000000000000000000000FFFF4B +:10F7C0000000000032000000000000000000000007 +:10F7D0000000000000000000000000000000000029 +:10F7E0000000000000000000000000000000000019 +:10F7F0000000000000000000000000000000000009 +:10F80000000000000024F4000000000000000000E0 +:10F8100000000000000000000000000000000000E8 +:10F8200000000000000000000000000000000000D8 +:10F8300000000000000000000000000000000000C8 +:10F8400000000000000000000000000000000000B8 +:10F8500000000000000000000000000000000000A8 +:10F860000000000000000000000000000000000098 +:04F870000000000094 +:10FC00000100000000000000FE00000000000000F5 +:10FC100000000000000000000000000000000000E4 +:020000041000EA +:0410140000C0030015 +:040000050003C0C173 +:00000001FF + +:020000042000DA +:1000000041140E2FB82FA2BBA300E20F0000000086 +:100010007B22636F6D7072657373696F6E223A2213 +:100020004C5A4D41222C2268656164657253697A8D +:1000300065223A3330302C227465787453697A65BE +:10004000223A32343133352C226E616D65223A22E8 +:10005000437269636B657420726F626F7420736F93 +:100060006E6172222C226555524C223A22687474B9 +:1000700070733A2F2F6D616B65636F64652E6D69C8 +:1000800063726F6269742E6F72672F222C2265561D +:100090004552223A22322E302E36222C227078748B +:1000A000546172676574223A226D6963726F626986 +:1000B00074227D5D00008000735F0000000000007E +:1000C000003D8889C65436C3174FE4DCCBB3700EAD +:1000D000F2DEB67DB3DFFA51B5F51CE3747A5F3F0B +:1000E0003DE15EC698DDFC6682E288DE7C682D28F4 +:1000F00099CFFE0B78EC359D52E9C12F4C4D8D9375 +:1001000025FD66F8BC786691B41ED7DBBC9319D187 +:100110005E12720A90170E1DC6F72398FDFCE6C604 +:100120008EDC2B7AFE4A4E28DDD2B7EF3DD139BAAC +:1001300012B2868BD46D4A27D27605054F6DC676EE +:1001400093F68050876B10A966275C213EEB3599AA +:100150008625A7861F35602B71CE9E7B1C4FE04FF6 +:1001600022274ACFFE3BA7355F4C8E6BE373F744E3 +:1001700005600CEE88C1C0A955FEBB0A4CF8920A76 +:10018000E68A8CF46E662C23B11245C7EDE9713511 +:10019000F54FB99A13F9F1DE2D193B792EA4D099B8 +:1001A0004C0B7D9AEB28AFDC497EDE48900104744D +:1001B000C130C2A5FCA06FF68E022C60C668E99C17 +:1001C00055EE2740755AFC883231D7E164EEE81BC2 +:1001D000EE9FEDCC7A9D8D308638C890E886B9F5D3 +:1001E00054E6A5277050C426D62219A6DAEA71660D +:1001F000E12A0625E547639B1EE7518F72689A0C3A +:10020000EA8B3E4C21B70CB437485F835FA4B4A09F +:100210001D8E280288529F1AD9DE15F1695CDA35E5 +:10022000DC6295083F27EE6EC336411D0C038192B8 +:100230007D0E56BEADAF92EA2B17D63D22CF3A8C3B +:100240001E0E9B784476D53E35FFB2C8D3F94D39A2 +:1002500094C091D38F6D877B53115373C6BE4AFDF3 +:10026000AA5F396C3B021E97B553C404CF4C5AE1C8 +:10027000144A9CADDB296A42C0F9841D3A661DE828 +:100280000E5B777FCDE9BBA75E1CF98369B62A1B9D +:100290001EFA1DEA3C07064DBCCE6DA9CE82AB1DF1 +:1002A000B43CB91B0874D78413DEDF7FC4BD6E3243 +:1002B000E6A0498C223151C22B2688B16DB5B223FC +:1002C000BF7600CE0DA3CA9490F89F1B40D5FA5A72 +:1002D000243D6559D319692A26ECDF850810C39D92 +:1002E00015837B8BC9C8B8C8EB1BE6C65E38AE71F8 +:1002F0004D92DBA962A7B7154CE0C97099B7D77EBC +:10030000F077412E33A9C5357E56C0577F076FD28F +:100310005F9D908F099A1D510EE5CE06CF6536F68A +:1003200029FDFE663A1A36BDF38FCCBB96DA31FB57 +:100330005D15A109A7C4CF961193B5BD3723CF672B +:10034000020D5E56044DB329C598B0E13853A64955 +:10035000A74F3868FC53834206093CCAF006723145 +:100360006ED444270982F31634A7A4CEC07AC98A72 +:10037000C22641EFBFB7B5CA1FB550FAA49A1A0DED +:10038000FFFE7F9BA9FCD06C2734FB792F33AB8E0B +:100390009A6A9BE09A94890ED63040DCC02D786230 +:1003A000707B692888EA32A373403A9C1ACA79851F +:1003B0008FAC915B32C3153B7F1EA62B3D401F3D8A +:1003C000568F09C81D73783E14E6A6C1E9FBB7DC59 +:1003D000F3D72F5A74F03B72FCCDD924B966FC16C2 +:1003E0001C9596C1E5EF157D833E21EF0710346F14 +:1003F00009671DDEEA56BBF3236131AE6E83560BEF +:10040000C5B8A358B95ABAA45B0CAC1B1EE7643834 +:100410001A2B0B1726B3CDA0413192D818CA2CFA4B +:1004200009943B711305C6CE3C3502EACE0AB89159 +:10043000B186AA6AB59B379FF9F74E64B75E77DA43 +:10044000E44D31D1DB15C0E90329871B982459A657 +:10045000E93A11FA3684DA3E9C65E832728FAE4989 +:10046000B582BA8E8A1DF253E6C3A48CC72A65D81A +:10047000319AD247526E23A469479CC1AF5089B5C7 +:1004800074747C539BDEEBD7FD4595D6BBB5B55256 +:10049000447F5B17C367E1FFD1678472039759EF0D +:1004A000D31071F85EF6A4F8A4B87FFD1A14DD76B7 +:1004B00039C9993E98AAF75CBAA48DDF2D063CD8BD +:1004C000BD403DCC8BB09D2E0B48A5C8793EEF02B8 +:1004D00099ABF6EE504BB84CE5E1966EA42755D299 +:1004E000BA044078B6F489D094136B32C9C57C3114 +:1004F00016047B8B68326CE0753E19F0D2064CE333 +:10050000C5236035C7006426B42AFAE0AD66676784 +:10051000E86EDA37848860C19DBC5C06BE886729B6 +:10052000521E3C2792D71A8D9D8ED58657D8A26B26 +:100530000EAC85E6FD3F57B16DA90D0F829F04DC1F +:10054000636FB7BF77C495BB86D17E3B8CDCFE9BC7 +:10055000A1DD16580535CE53886E5F306BF0D4C9D7 +:100560001DF676DBFA5134BEB409B359AFBD7A1B20 +:1005700028F4D050D27B3FDAD05A2299484CDE9EE4 +:10058000999520A73BB4E3F3A4E147BB89C6470292 +:10059000A12060425141894A68ED17095DC5ECAA66 +:1005A00091C42A1D4D2CD271C4953906E086903530 +:1005B000E6B6DD513BAB8F81946679C79B0DBE9249 +:1005C000096C0B157030928E50E94A5CD089E1B30A +:1005D0006287679E2DC64BE62D4DF68F0D9B6F846F +:1005E00067AFC890F06A5520BCE8D504ADC6D58B7E +:1005F000744B3FB60DA9D5B75674CD87A031266888 +:10060000F2309E4911E594D347098686E83AE57DA4 +:10061000C7A8E53FC6FF15D8A37D03D09F0C980D52 +:10062000AD804B63874B214D6C16D4234373B13A95 +:100630008E532B833B69214469A33FFDAB163DDA02 +:10064000ABF0CA18774BE28C0BAC05F68788ED123D +:10065000E700296CBBD47581DAB9A76EDA2C90F16A +:1006600022F0F3D7DDAA46AD0361D4E3E38CF7E3D0 +:10067000001A1922E172A9F4092272BE6A1390B419 +:100680002D1A89B415AA9E5AA15A56B62763D529A0 +:1006900056165A7B838BE649C730132D9062457EF0 +:1006A00054B02571FB80377398AEAB57AA242E82C5 +:1006B0004F532E5CA07FB050A83D268E05CD1E570F +:1006C000549F3F4FBECCD45C46B307FA3F576DE210 +:1006D000CA7291AE0A0DF65E9181F99BAED89E2743 +:1006E000D3ED2C56983799CE911DFDDE14D3E53A03 +:1006F0001D3A0EA8A22A9450DD82BB5AF1764B9087 +:100700002A086769A8E8FB12988CB2E59C06CD1B05 +:10071000B6511D1660331E1513AD5FB076E6A8E81E +:100720005D9500CAC54FCEB69A80695E54F162FEEF +:10073000337C68885CEC86B8CD2DE82421BB9A63B5 +:10074000E9D89013B9B6A8E98053B78E38EFA8F16D +:1007500062EAA38685E61784F90E02F8484574C557 +:10076000887DB5805F462B9AC7456C5F47E729E1D6 +:10077000F015FB126156D4C6A286C38CBE8B83C80B +:1007800086C2F59B6963A761EC05978D8ECD14A099 +:100790007ABB0A1D7E09ABF4708B2CAEC779E136AB +:1007A000A70668AD2875E2828F6459FEB38F0D7F6E +:1007B0002E7820A1759681FF38EE754A03362F7585 +:1007C000A4878F6160B2D26E3A759ACEFB01C4A73E +:1007D00081CA727E1C390C0DC7064A2D838F810D8C +:1007E00015BAC10E73A435E999C06F8AEEAFD2482D +:1007F000EF5BDE8754E991DE368DBC9E79E6D24F01 +:10080000C8B96EDCB759F5A214E96D47EDEF419F09 +:10081000D008CF281FC7B79323D9E41C102B728EA2 +:10082000482D4ED80A57CDA42A6396194CCEBC62E7 +:100830000FDDEC3CC68C62CAF6C730EFFB30F59397 +:10084000239D15A1A1CFC3E6BAD04AB8C8BABC6DE2 +:1008500020C754DACF97B5926D68F06D11E80B049C +:1008600092F56C65BEC7C76EEA8B7D002128AA6E23 +:10087000ADBCF528CB82C2BD0C67F1FE8F77126844 +:1008800045AED56A9C0DD8BD5AD1F51C00A564595A +:1008900090E4E4FE8CC49D6B00192F6F251BEFD7ED +:1008A000CE4FD02CE3C94A30494F6B862A0DFE0348 +:1008B00055C8E69B151F428E295433F073349C387B +:1008C000019FB734BE25ECDEBC6CDE25F9A5FA111C +:1008D0003411079E36D553E3EF6EEAA3A4769AA0AF +:1008E000F2B7681E728D9584FFBF2207B2257ED2B3 +:1008F0007E750CD966E348787D34727F8698E2A3D2 +:100900005681FAFC99B359D096F1DDBE4A2AE60722 +:10091000028EAD8CBE95945551C5BAD25D68C16D3D +:100920003C7185D0DBC3C5CA302A8543607A80E339 +:1009300002580B532B7104ECAFD123CA5617B42EB7 +:10094000AC1F11DB1D5C920E2C905DF3D64BB2B246 +:100950007E605905630F9676884DAB514BB922AC3A +:100960000693633810F2EA734D7C239438E892EED4 +:100970000F60269BAAC3E10421A71CC0B374AC5D21 +:100980000CEF4F76C967F9AF8AFB53A43011AC9CCA +:100990001F4DC1BC4189A759A8FFFD91DBE0D4914F +:1009A000AC4CD638C62B13E933E405DA495493E24C +:1009B00022B30E743B24DF492AE9763A091F73E11A +:1009C00062961E1F1712D4B67654433E7F53EEED47 +:1009D0009CE8C34F5120AE9E0ADA1470E5F8022A53 +:1009E0002B530BC43727A8481204D03CA6E6F1AC21 +:1009F000BCD701B5FE4CC7EC4586670CACFDBA020E +:100A000080DF79CB1440DD8A968D6C80DD1D31EF5F +:100A10001ED12A7B0863298225E0B87CD6A4635BBB +:100A200086978EE385EF708C02A55D12331A165CF3 +:100A3000B4A774069AD59CEDC995746AEBC9801564 +:100A40006067FC4812C1687821AB6A5486128CE555 +:100A5000549A4970A6DBF6EBAA82DB25E2717F0887 +:100A60008D87C8C0D5FE4DACE05D99CFBD950B8894 +:100A700033697EBD19A668989D84C7F05C8E46DAFE +:100A80000F9B1CAA114DCAE36E7358EB20AFDE53C7 +:100A900086EBC1DC3031E2BD80BC0221082B7F0730 +:100AA000618C4C00DBA9399DC81B9172F2B4761A97 +:100AB0008225BCC4B7BF9F3BE26C850ADC1AFD7C73 +:100AC000BE51D44915F46767BD422FBF72E561C0BE +:100AD000D22F61796FFE7CC907342B9FE355CC057B +:100AE00011101EE14E60C6F0EFBFD199AF5EAA2093 +:100AF00051400095C63A09ABACC499FE7B324A0D11 +:100B0000B4534A3EA0E87EFA3B32C1A084D83832C2 +:100B10005D9B74DA73955BF9994EA7805D9AECED55 +:100B20009946AB4D3F77EB84C853C37C2C511732A9 +:100B300091EB1EC372C995265E95B960B24B430313 +:100B4000975DF19E9F933723AB706C119B89C30F08 +:100B50003F8F86E501551F876136567F4408CA449A +:100B60009E7AA7F91CA714EDFBECC9FD9EA2ED2906 +:100B7000A3F23222EB2B807E40099A2AA53C4756ED +:100B80009087CA0C4D9D56EDC297FD0C14EC691C64 +:100B90006C835A4EED6597D35D39E96F2F2FDFD304 +:100BA000A17CF3ACE7F9AD6994813F1BE372EB33B1 +:100BB000F9F8CAA41B8344403E33346D6B3B2605D1 +:100BC000E9CEBF33EFC286C06BA54578EE648C5B7F +:100BD0006408634B50DE635E63D61E4359FBEDBB76 +:100BE00027284CCA27E38A48EDCF47BA4D86892A81 +:100BF000595EEA2ED78242C760A59C32C9909F12E7 +:100C0000F333F486D04F8231E34A423231F2FED3DD +:100C1000D42D1039889E536B991E6DB10736E5E0CF +:100C200015819C04F3486C74E53A810B34006B1316 +:100C3000A2DAEA45D61E03F2D85DE29D34DD825584 +:100C4000682CB730CF432FDD30D47129803575E261 +:100C50006550C96C68150198606E5A45314882909C +:100C600009030CB8AF4B9573FCE3B553EE09F50CD3 +:100C70001E18F1CD524E6479C3EC067EE05B44E56C +:100C80003CD9A8EAAE63F95886C0D5E1156D534A40 +:100C900074EDE6C9470851FA0BEB44D9258E730968 +:100CA00056D4C12FAD8CCBFB6E1A23080D92F721C1 +:100CB0003185C298C89B30FDF96D0FD2B443CD93F6 +:100CC00083FAC0909BCFE130AFB08774665852145E +:100CD00030772B1AB17BCF844CC7943D38419F3F6E +:100CE000EBA1AA72F25D03DCC0BCE7FD0A7F7302D0 +:100CF000A559720D2791639266686F98473736F34E +:100D00001E527A22BAF3FF286AB9455256F0224899 +:100D10003D496C5B7DF9852B88E95627F888EF57AC +:100D20004DC27CA572A0B18145011A4C0167FB2020 +:100D300079A440D2A1A784F282B8C4E570D2810A16 +:100D40000B4CE924147E612698B370D419F7052A58 +:100D5000EC13C9B549C11048FEA38A71DFC8182534 +:100D6000E4FED1BCC26F76218492AB6390F1FE7A2F +:100D7000EEFA0F1A42671609001F3BBE2394183D76 +:100D8000E7D1D07851A37DAC2F08FA49D77795D811 +:100D90006123E5EA7EF62F8AE66D914F30509B6B1A +:100DA00055717852C8516866A5C71DE8DA59B3294C +:100DB000241B3691923E3A44BBBB6C57F648D83C54 +:100DC00081701796F3744B108AB5D6729A8886DBB9 +:100DD000667AC74B340BAFF561C90DD9A83E736075 +:100DE00061A94906E4A68150091EA0C48721AA4F23 +:100DF0004B9990A9C98214C78FD01CBDF0279FB40E +:100E0000D7ED55360A330BB2B8E0B60C50F2E0839A +:100E1000CC84FDDCC59F9C10D69B9AD145CCCF716C +:100E20007A18DCA60FB783A45DFCCA67C0B22D494F +:100E3000C3696454D71E5BF4F7AAC47CC4391B137E +:100E4000B1E97B9F043BBD4EBC9932FBE9EDB23F5B +:100E5000047B02AACAA26C8C05D599A4A6B325204E +:100E600086E4285B17EF9633F7EB4DE6D2A6D273F4 +:100E7000C989733189C45B225D995187DC28FFEFF2 +:100E80000B78CAD6B6864A3C5AAC9628B1A8E08EF2 +:100E90009740833DD30389BA7486D0328A005DEDD2 +:100EA000549B2CDED8AFA23E7295CD86913211D3E1 +:100EB0007F61817B7D7209E6117505CC252679C598 +:100EC000B91414AA1FC4370AE78B8D4637D3D6E36B +:100ED00079DFCA68F90A1EA1F99B692508057F8C8C +:100EE000D0CAEBFD1236500A2CE9BBF4BAB913761E +:100EF00013FD2354CEE9E606690E82CCCD02DF262F +:100F000070D01C7412877AD8021A363224A62C1498 +:100F10006ED41A3DCFF17EB0A0FAC984952AAEB541 +:100F20004FE8221B49BBE2ABE6CD3F846594E5EF79 +:100F3000BA6739C46F347F5B7D04EEFA1603D74E6F +:100F400079301C68DD40C8F07E5090766FC70892FB +:100F50004903C8928CCB037DE673778A992197EB7E +:100F60001C06979210CC6CF9CA23706689D18B84C9 +:100F7000A798FA1F76885DAB108DD9FC395BD47EBB +:100F8000024D0DF35C5804AA0F17AEA905FEE34FFE +:100F90000B9AC21BFB6B8C4CE88A107418AE6E72F5 +:100FA0000B2464A3EFE2BEDF3E49C1E08EDDAB7CE3 +:100FB0005448CA7A990999353B68AA9A5145075904 +:100FC000645806507EA53543C997236B760CD843E9 +:100FD000D022BAB3541EC784CFFC382527413F899D +:100FE000FF7CACEC2F4473F4B6CAE995A40AF1C1B6 +:100FF000E036C293944DC220B1ECFEBDA61997E431 +:1010000005E486C507F5A9DE97A53E89270113E902 +:10101000EB3F3BED50857943095202D38D083C8A62 +:1010200097CDB9D242F0BBFC04BAFC26367B9A6C51 +:10103000463F8782936D0BB4FF581AD161BCF3E22F +:101040004A8A12188B52E505B8AB1ED4F9EF58F056 +:1010500068FBFADCB1D059793DD2ABBAE7F75A6BED +:10106000162E0EB73EB7CA1AA2B9CA1D3A8622B4C6 +:10107000EC604783BCD76987B55F35FD82109B83E1 +:10108000B7DD54C3A2F69CF4C700270B95754695AF +:10109000FFDCA1F3CC000000000000000000000015 diff --git a/Crickit_Sparky_Automaton/code.py b/Crickits/Crickit_Sparky_Automaton/code.py similarity index 100% rename from Crickit_Sparky_Automaton/code.py rename to Crickits/Crickit_Sparky_Automaton/code.py diff --git a/Crickit_Sparky_Automaton/sparky.zip b/Crickits/Crickit_Sparky_Automaton/sparky.zip similarity index 100% rename from Crickit_Sparky_Automaton/sparky.zip rename to Crickits/Crickit_Sparky_Automaton/sparky.zip diff --git a/Crickit_Stumblebot/code.py b/Crickits/Crickit_Stumblebot/code.py similarity index 100% rename from Crickit_Stumblebot/code.py rename to Crickits/Crickit_Stumblebot/code.py diff --git a/Crickits/Crickit_WobblyBot/WobblyBot/.feather_m0_express.test.only b/Crickits/Crickit_WobblyBot/WobblyBot/.feather_m0_express.test.only new file mode 100644 index 000000000..8d1c8b69c --- /dev/null +++ b/Crickits/Crickit_WobblyBot/WobblyBot/.feather_m0_express.test.only @@ -0,0 +1 @@ + diff --git a/Crickit_WobblyBot/WobblyBot/BluefruitConfig.h b/Crickits/Crickit_WobblyBot/WobblyBot/BluefruitConfig.h similarity index 100% rename from Crickit_WobblyBot/WobblyBot/BluefruitConfig.h rename to Crickits/Crickit_WobblyBot/WobblyBot/BluefruitConfig.h diff --git a/Crickit_WobblyBot/WobblyBot/WobblyBot.ino b/Crickits/Crickit_WobblyBot/WobblyBot/WobblyBot.ino similarity index 100% rename from Crickit_WobblyBot/WobblyBot/WobblyBot.ino rename to Crickits/Crickit_WobblyBot/WobblyBot/WobblyBot.ino diff --git a/Crickit_WobblyBot/WobblyBot/packetParser.cpp b/Crickits/Crickit_WobblyBot/WobblyBot/packetParser.cpp similarity index 100% rename from Crickit_WobblyBot/WobblyBot/packetParser.cpp rename to Crickits/Crickit_WobblyBot/WobblyBot/packetParser.cpp diff --git a/Crickit_WobblyBot/code.py b/Crickits/Crickit_WobblyBot/code.py similarity index 100% rename from Crickit_WobblyBot/code.py rename to Crickits/Crickit_WobblyBot/code.py diff --git a/Crickit_microbit_MicroPython/.circuitpython.skip b/Crickits/Crickit_microbit_MicroPython/.circuitpython.skip similarity index 100% rename from Crickit_microbit_MicroPython/.circuitpython.skip rename to Crickits/Crickit_microbit_MicroPython/.circuitpython.skip diff --git a/Crickit_microbit_MicroPython/README.md b/Crickits/Crickit_microbit_MicroPython/README.md similarity index 100% rename from Crickit_microbit_MicroPython/README.md rename to Crickits/Crickit_microbit_MicroPython/README.md diff --git a/Crickit_microbit_MicroPython/main.py b/Crickits/Crickit_microbit_MicroPython/main.py similarity index 100% rename from Crickit_microbit_MicroPython/main.py rename to Crickits/Crickit_microbit_MicroPython/main.py diff --git a/Crickit_microbit_MicroPython/picture.png b/Crickits/Crickit_microbit_MicroPython/picture.png similarity index 100% rename from Crickit_microbit_MicroPython/picture.png rename to Crickits/Crickit_microbit_MicroPython/picture.png diff --git a/Crickit_microbit_MicroPython/seesaw.py b/Crickits/Crickit_microbit_MicroPython/seesaw.py similarity index 100% rename from Crickit_microbit_MicroPython/seesaw.py rename to Crickits/Crickit_microbit_MicroPython/seesaw.py diff --git a/Feather_Crickit_Accelerometer/code.py b/Crickits/Feather_Crickit_Accelerometer/code.py similarity index 100% rename from Feather_Crickit_Accelerometer/code.py rename to Crickits/Feather_Crickit_Accelerometer/code.py diff --git a/Music_Box_with_Crickit/code.py b/Crickits/Music_Box_with_Crickit/code.py similarity index 100% rename from Music_Box_with_Crickit/code.py rename to Crickits/Music_Box_with_Crickit/code.py diff --git a/DMX_NeoPixels/examples/DMX_Master/.cpb.test.skip b/DMX_NeoPixels/examples/DMX_Master/.cpb.test.skip deleted file mode 100644 index 064a28912..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.cpb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpb diff --git a/DMX_NeoPixels/examples/DMX_Master/.cpc.test.skip b/DMX_NeoPixels/examples/DMX_Master/.cpc.test.skip deleted file mode 100644 index 79763353d..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.cpc.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpc diff --git a/DMX_NeoPixels/examples/DMX_Master/.cpx_ada.test.skip b/DMX_NeoPixels/examples/DMX_Master/.cpx_ada.test.skip deleted file mode 100644 index d9c56cc11..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.cpx_ada.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpx_ada diff --git a/DMX_NeoPixels/examples/DMX_Master/.esp32.test.skip b/DMX_NeoPixels/examples/DMX_Master/.esp32.test.skip deleted file mode 100644 index 5faeb5064..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.esp32.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for esp32 diff --git a/DMX_NeoPixels/examples/DMX_Master/.esp8266.test.skip b/DMX_NeoPixels/examples/DMX_Master/.esp8266.test.skip deleted file mode 100644 index 15eb13221..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.esp8266.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for esp8266 diff --git a/DMX_NeoPixels/examples/DMX_Master/.feather32u4.test.skip b/DMX_NeoPixels/examples/DMX_Master/.feather32u4.test.skip deleted file mode 100644 index eb9fd87a1..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.feather32u4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather32u4 diff --git a/DMX_NeoPixels/examples/DMX_Master/.feather_esp32c6.test.skip b/DMX_NeoPixels/examples/DMX_Master/.feather_esp32c6.test.skip deleted file mode 100644 index 563448c75..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.feather_esp32c6.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_esp32c6 diff --git a/DMX_NeoPixels/examples/DMX_Master/.feather_m0_express.test.skip b/DMX_NeoPixels/examples/DMX_Master/.feather_m0_express.test.skip deleted file mode 100644 index c1118c563..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.feather_m0_express.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_m0_express diff --git a/DMX_NeoPixels/examples/DMX_Master/.feather_m4_express.test.skip b/DMX_NeoPixels/examples/DMX_Master/.feather_m4_express.test.skip deleted file mode 100644 index 9b961626f..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.feather_m4_express.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_m4_express diff --git a/DMX_NeoPixels/examples/DMX_Master/.feather_rp2040.test.skip b/DMX_NeoPixels/examples/DMX_Master/.feather_rp2040.test.skip deleted file mode 100644 index 90aa322a7..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.feather_rp2040.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_rp2040 diff --git a/DMX_NeoPixels/examples/DMX_Master/.feather_rp2040_adalogger.test.skip b/DMX_NeoPixels/examples/DMX_Master/.feather_rp2040_adalogger.test.skip deleted file mode 100644 index 29ebf0ea0..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.feather_rp2040_adalogger.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_rp2040_adalogger diff --git a/DMX_NeoPixels/examples/DMX_Master/.flora.test.skip b/DMX_NeoPixels/examples/DMX_Master/.flora.test.skip deleted file mode 100644 index e4cc7386e..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.flora.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for flora diff --git a/DMX_NeoPixels/examples/DMX_Master/.funhouse.test.skip b/DMX_NeoPixels/examples/DMX_Master/.funhouse.test.skip deleted file mode 100644 index 32a4e1e1a..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.funhouse.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for funhouse diff --git a/DMX_NeoPixels/examples/DMX_Master/.gemma.test.skip b/DMX_NeoPixels/examples/DMX_Master/.gemma.test.skip deleted file mode 100644 index 978f275e3..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.gemma.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for gemma diff --git a/DMX_NeoPixels/examples/DMX_Master/.gemma_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master/.gemma_m0.test.skip deleted file mode 100644 index c42614d7c..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.gemma_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for gemma_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master/.hallowing_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master/.hallowing_m0.test.skip deleted file mode 100644 index ed26fdf6a..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.hallowing_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for hallowing_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master/.hallowing_m4_tinyusb.test.skip b/DMX_NeoPixels/examples/DMX_Master/.hallowing_m4_tinyusb.test.skip deleted file mode 100644 index 0ab22cb8d..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.hallowing_m4_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for hallowing_m4_tinyusb diff --git a/DMX_NeoPixels/examples/DMX_Master/.ledglasses_nrf52840.test.skip b/DMX_NeoPixels/examples/DMX_Master/.ledglasses_nrf52840.test.skip deleted file mode 100644 index f540a7e4c..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.ledglasses_nrf52840.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for ledglasses_nrf52840 diff --git a/DMX_NeoPixels/examples/DMX_Master/.magtag.test.skip b/DMX_NeoPixels/examples/DMX_Master/.magtag.test.skip deleted file mode 100644 index 79d0d324c..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.magtag.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for magtag diff --git a/DMX_NeoPixels/examples/DMX_Master/.metro_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master/.metro_m0.test.skip deleted file mode 100644 index 91512a898..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.metro_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master/.metro_m0_tinyusb.test.skip b/DMX_NeoPixels/examples/DMX_Master/.metro_m0_tinyusb.test.skip deleted file mode 100644 index 486e4f67e..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.metro_m0_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m0_tinyusb diff --git a/DMX_NeoPixels/examples/DMX_Master/.metro_m4.test.skip b/DMX_NeoPixels/examples/DMX_Master/.metro_m4.test.skip deleted file mode 100644 index 5012f3737..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.metro_m4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m4 diff --git a/DMX_NeoPixels/examples/DMX_Master/.metro_m4_tinyusb.test.skip b/DMX_NeoPixels/examples/DMX_Master/.metro_m4_tinyusb.test.skip deleted file mode 100644 index 17edc54fe..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.metro_m4_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m4_tinyusb diff --git a/DMX_NeoPixels/examples/DMX_Master/.monster_m4sk.test.skip b/DMX_NeoPixels/examples/DMX_Master/.monster_m4sk.test.skip deleted file mode 100644 index ec7f80e48..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.monster_m4sk.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for monster_m4sk diff --git a/DMX_NeoPixels/examples/DMX_Master/.monster_m4sk_tinyusb.test.skip b/DMX_NeoPixels/examples/DMX_Master/.monster_m4sk_tinyusb.test.skip deleted file mode 100644 index a08b60688..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.monster_m4sk_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for monster_m4sk_tinyusb diff --git a/DMX_NeoPixels/examples/DMX_Master/.neokeytrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master/.neokeytrinkey_m0.test.skip deleted file mode 100644 index 7fb03fe33..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.neokeytrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for neokeytrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master/.neotrellis_m4.test.skip b/DMX_NeoPixels/examples/DMX_Master/.neotrellis_m4.test.skip deleted file mode 100644 index eebfceae8..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.neotrellis_m4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for neotrellis_m4 diff --git a/DMX_NeoPixels/examples/DMX_Master/.nrf52832.test.skip b/DMX_NeoPixels/examples/DMX_Master/.nrf52832.test.skip deleted file mode 100644 index ee506a55a..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.nrf52832.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for nrf52832 diff --git a/DMX_NeoPixels/examples/DMX_Master/.nrf52840.test.skip b/DMX_NeoPixels/examples/DMX_Master/.nrf52840.test.skip deleted file mode 100644 index a6bcf2c9d..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.nrf52840.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for nrf52840 diff --git a/DMX_NeoPixels/examples/DMX_Master/.pixeltrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master/.pixeltrinkey_m0.test.skip deleted file mode 100644 index 4a5f3b346..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.pixeltrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pixeltrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master/.protrinket_5v.test.skip b/DMX_NeoPixels/examples/DMX_Master/.protrinket_5v.test.skip deleted file mode 100644 index ec91a95cb..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.protrinket_5v.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for protrinket_5v diff --git a/DMX_NeoPixels/examples/DMX_Master/.proxlighttrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master/.proxlighttrinkey_m0.test.skip deleted file mode 100644 index 0d46213a9..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.proxlighttrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for proxlighttrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master/.pybadge.test.skip b/DMX_NeoPixels/examples/DMX_Master/.pybadge.test.skip deleted file mode 100644 index 82cd2ac9c..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.pybadge.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pybadge diff --git a/DMX_NeoPixels/examples/DMX_Master/.pycamera_s3.test.skip b/DMX_NeoPixels/examples/DMX_Master/.pycamera_s3.test.skip deleted file mode 100644 index 021a63e54..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.pycamera_s3.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pycamera_s3 diff --git a/DMX_NeoPixels/examples/DMX_Master/.pygamer.test.skip b/DMX_NeoPixels/examples/DMX_Master/.pygamer.test.skip deleted file mode 100644 index 430cf639c..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.pygamer.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pygamer diff --git a/DMX_NeoPixels/examples/DMX_Master/.pyportal.test.skip b/DMX_NeoPixels/examples/DMX_Master/.pyportal.test.skip deleted file mode 100644 index 6a18dce9f..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.pyportal.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pyportal diff --git a/DMX_NeoPixels/examples/DMX_Master/.qt2040_trinkey.test.skip b/DMX_NeoPixels/examples/DMX_Master/.qt2040_trinkey.test.skip deleted file mode 100644 index 263748866..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.qt2040_trinkey.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qt2040_trinkey diff --git a/DMX_NeoPixels/examples/DMX_Master/.qtpy_esp32s2.test.skip b/DMX_NeoPixels/examples/DMX_Master/.qtpy_esp32s2.test.skip deleted file mode 100644 index 627d7dd57..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.qtpy_esp32s2.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qtpy_esp32s2 diff --git a/DMX_NeoPixels/examples/DMX_Master/.qtpy_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master/.qtpy_m0.test.skip deleted file mode 100644 index fbc42f083..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.qtpy_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qtpy_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master/.qualia_s3_rgb666.test.skip b/DMX_NeoPixels/examples/DMX_Master/.qualia_s3_rgb666.test.skip deleted file mode 100644 index 1e14eea6e..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.qualia_s3_rgb666.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qualia_s3_rgb666 diff --git a/DMX_NeoPixels/examples/DMX_Master/.rotarytrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master/.rotarytrinkey_m0.test.skip deleted file mode 100644 index 8a2ec7327..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.rotarytrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for rotarytrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master/.sht4xtrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master/.sht4xtrinkey_m0.test.skip deleted file mode 100644 index 039d08b3e..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.sht4xtrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for sht4xtrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master/.slidetrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master/.slidetrinkey_m0.test.skip deleted file mode 100644 index d3f14ba82..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.slidetrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for slidetrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master/.trinket_5v.test.skip b/DMX_NeoPixels/examples/DMX_Master/.trinket_5v.test.skip deleted file mode 100644 index e2d3dded0..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.trinket_5v.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for trinket_5v diff --git a/DMX_NeoPixels/examples/DMX_Master/.trinket_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master/.trinket_m0.test.skip deleted file mode 100644 index 06ad7bf51..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.trinket_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for trinket_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master/.uno.test.only b/DMX_NeoPixels/examples/DMX_Master/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/DMX_NeoPixels/examples/DMX_Master/.uno.test.skip b/DMX_NeoPixels/examples/DMX_Master/.uno.test.skip deleted file mode 100644 index f3e164df1..000000000 --- a/DMX_NeoPixels/examples/DMX_Master/.uno.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for uno diff --git a/DMX_NeoPixels/examples/DMX_Master/Conceptinetics.cpp b/DMX_NeoPixels/examples/DMX_Master/Conceptinetics.cpp new file mode 100644 index 000000000..36ada5924 --- /dev/null +++ b/DMX_NeoPixels/examples/DMX_Master/Conceptinetics.cpp @@ -0,0 +1,1233 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Conceptinetics.cpp - DMX library for Arduino + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + This code has been tested using the following hardware: + + - Arduino UNO R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino MEGA2560 R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD +*/ + + +#include "pins_arduino.h" +#include "Conceptinetics.h" + +#include +#include + +#include +#include + +#include + + +#if defined (USE_DMX_SERIAL_0) + + #if defined (USART__TXC_vect) + #define USART_TX USART__TXC_vect + #elif defined(USART_TX_vect) + #define USART_TX USART_TX_vect + #elif defined(USART0_TX_vect) + #define USART_TX USART0_TX_vect + #endif + + #if defined (USART__RXC_vect) + #define USART_RX USART__RXC_vect + #elif defined(USART_RX_vect) + #define USART_RX USART_RX_vect + #elif defined(USART0_RX_vect) + #define USART_RX USART0_RX_vect + #endif + + #if defined UDR + #define DMX_UDR UDR + #elif defined UDR0 + #define DMX_UDR UDR0 + #endif + + #if defined(UBRRH) && defined(UBRRL) + #define DMX_UBRRH UBRRH + #define DMX_UBRRL UBRRL + #elif defined(UBRR0H) && defined(UBRR0L) + #define DMX_UBRRH UBRR0H + #define DMX_UBRRL UBRR0L + #endif + + #if defined(UCSRA) + #define DMX_UCSRA UCSRA + #elif defined(UCSR0A) + #define DMX_UCSRA UCSR0A + #endif + + #if defined(UCSRB) + #define DMX_UCSRB UCSRB + #elif defined (UCSR0B) + #define DMX_UCSRB UCSR0B + #endif + + #if defined(TXEN) && defined(TXCIE) + #define DMX_TXEN TXEN + #define DMX_TXCIE TXCIE + #elif defined(TXEN0) && defined(TXCIE0) + #define DMX_TXEN TXEN0 + #define DMX_TXCIE TXCIE0 + #endif + + #if defined(RXEN) && defined(RXCIE) + #define DMX_RXEN RXEN + #define DMX_RXCIE RXCIE + #elif defined(RXEN0) && defined(RXCIE0) + #define DMX_RXEN RXEN0 + #define DMX_RXCIE RXCIE0 + #endif + + #if defined(FE) + #define DMX_FE FE + #elif defined(FE0) + #define DMX_FE FE0 + #endif + + #define RX_PIN 0 + #define TX_PIN 1 + +#elif defined (USE_DMX_SERIAL_1) + #define USART_RX USART1_RX_vect + #define USART_TX USART1_TX_vect + #define DMX_UDR UDR1 + #define DMX_UBRRH UBRR1H + #define DMX_UBRRL UBRR1L + #define DMX_UCSRA UCSR1A + #define DMX_UCSRB UCSR1B + #define DMX_TXEN TXEN1 + #define DMX_TXCIE TXCIE1 + #define DMX_RXEN RXEN1 + #define DMX_RXCIE RXCIE1 + #define DMX_FE FE1 + #define RX_PIN 19 + #define TX_PIN 18 +#elif defined (USE_DMX_SERIAL_2) + #define USART_RX USART2_RX_vect + #define USART_TX USART2_TX_vect + #define DMX_UDR UDR2 + #define DMX_UBRRH UBRR2H + #define DMX_UBRRL UBRR2L + #define DMX_UCSRA UCSR2A + #define DMX_UCSRB UCSR2B + #define DMX_TXEN TXEN2 + #define DMX_TXCIE TXCIE2 + #define DMX_RXEN RXEN2 + #define DMX_RXCIE RXCIE2 + #define DMX_FE FE2 + #define RX_PIN 17 + #define TX_PIN 16 +#elif defined (USE_DMX_SERIAL_3) + #define USART_RX USART3_RX_vect + #define USART_TX USART3_TX_vect + #define DMX_UDR UDR3 + #define DMX_UBRRH UBRR3H + #define DMX_UBRRL UBRR3L + #define DMX_UCSRA UCSR3A + #define DMX_UCSRB UCSR3B + #define DMX_TXEN TXEN3 + #define DMX_TXCIE TXCIE3 + #define DMX_RXEN RXEN3 + #define DMX_RXCIE RXCIE3 + #define DMX_FE FE3 + #define RX_PIN 14 + #define TX_PIN 15 +#endif + + +#define LOWBYTE(v) ((uint8_t) (v)) +#define HIGHBYTE(v) ((uint8_t) (((uint16_t) (v)) >> 8)) + +#define BSWAP_16(x) ( (uint8_t)((x) >> 8) | ((uint8_t)(x)) << 8 ) + +namespace isr +{ + enum isrState + { + Idle, + Break, + DmxBreak, + DmxBreakManual, + DmxStartByte, + DmxRecordData, + DmxTransmitData, + RdmBreak, + RdmStartByte, + RdmRecordData, + RdmTransmitData, + RDMTransmitComplete, + }; + + enum isrMode + { + Disabled, + Receive, + DMXTransmit, + DMXTransmitManual, /* Manual break... */ + RDMTransmit, + RDMTransmitNoInt, /* Setup uart but leave interrupt disabled */ + }; +}; + + +DMX_Master *__dmx_master; +DMX_Slave *__dmx_slave; +RDM_Responder *__rdm_responder; + +int8_t __re_pin; // R/W Pin on shield + +isr::isrState __isr_txState; // TX ISR state +isr::isrState __isr_rxState; // RX ISR state + + +void SetISRMode ( isr::isrMode ); + + +DMX_FrameBuffer::DMX_FrameBuffer ( uint16_t buffer_size ) +{ + m_refcount = (uint8_t*) malloc ( sizeof ( uint8_t ) ); + + if ( buffer_size >= DMX_MIN_FRAMESIZE && buffer_size <= DMX_MAX_FRAMESIZE ) + { + m_buffer = (uint8_t*) malloc ( buffer_size ); + if ( m_buffer != NULL ) + { + memset ( (void *)m_buffer, 0x0, buffer_size ); + m_bufferSize = buffer_size; + } + else + m_buffer = 0x0; + } + else + m_bufferSize = 0x0; + + *m_refcount++; +} + +DMX_FrameBuffer::DMX_FrameBuffer ( DMX_FrameBuffer &buffer ) +{ + // Copy references and make sure the parent object does not dispose our + // buffer when deleted and we are still active + this->m_refcount = buffer.m_refcount; + (*this->m_refcount)++; + + this->m_buffer = buffer.m_buffer; + this->m_bufferSize = buffer.m_bufferSize; +} + +DMX_FrameBuffer::~DMX_FrameBuffer ( void ) +{ + // If we are the last object using the + // allocated buffer then free it together + // with the refcounter + if ( --(*m_refcount) == 0 ) + { + if ( m_buffer ) + free ( m_buffer ); + + free ( m_refcount ); + } +} + +uint16_t DMX_FrameBuffer::getBufferSize ( void ) +{ + return m_bufferSize; +} + + +uint8_t DMX_FrameBuffer::getSlotValue ( uint16_t index ) +{ + if (index < m_bufferSize) + return m_buffer[index]; + else + return 0x0; +} + + +void DMX_FrameBuffer::setSlotValue ( uint16_t index, uint8_t value ) +{ + if ( index < m_bufferSize ) + m_buffer[index] = value; +} + + +void DMX_FrameBuffer::setSlotRange ( uint16_t start, uint16_t end, uint8_t value ) +{ + if ( start < m_bufferSize && end < m_bufferSize && start < end ) + memset ( (void *) &m_buffer[start], value, end-start+1 ); +} + +void DMX_FrameBuffer::clear ( void ) +{ + memset ( (void *) m_buffer, 0x0, m_bufferSize ); +} + +uint8_t &DMX_FrameBuffer::operator[] ( uint16_t index ) +{ + return m_buffer[index]; +} + + +DMX_Master::DMX_Master ( DMX_FrameBuffer &buffer, int readEnablePin ) +: m_frameBuffer ( buffer ), + m_autoBreak ( 1 ) // Autobreak generation is default on +{ + setStartCode ( DMX_START_CODE ); + + __re_pin = readEnablePin; + pinMode ( __re_pin, OUTPUT ); + + ::SetISRMode ( isr::Disabled ); +} + +DMX_Master::DMX_Master ( uint16_t maxChannel, int readEnablePin ) +: m_frameBuffer ( maxChannel + DMX_STARTCODE_SIZE ), + m_autoBreak ( 1 ) // Autobreak generation is default on +{ + setStartCode ( DMX_START_CODE ); + + __re_pin = readEnablePin; + pinMode ( __re_pin, OUTPUT ); + + ::SetISRMode ( isr::Disabled ); +} + +DMX_Master::~DMX_Master ( void ) +{ + disable (); // Stop sending + __dmx_master = NULL; +} + +DMX_FrameBuffer &DMX_Master::getBuffer ( void ) +{ + return m_frameBuffer; // Return reference to frame buffer +} + +void DMX_Master::setStartCode ( uint8_t value ) +{ + m_frameBuffer[0] = value; // Set the first byte in our frame buffer +} + +void DMX_Master::setChannelValue ( uint16_t channel, uint8_t value ) +{ + if ( channel > 0 ) // Prevent overwriting the start code + m_frameBuffer.setSlotValue ( channel, value ); +} + +void DMX_Master::setChannelRange ( uint16_t start, uint16_t end, uint8_t value ) +{ + if ( start > 0 ) // Prevent overwriting the start code + m_frameBuffer.setSlotRange ( start, end, value ); +} + + +void DMX_Master::enable ( void ) +{ + __dmx_master = this; + + if ( m_autoBreak ) + ::SetISRMode ( isr::DMXTransmit ); + else + ::SetISRMode ( isr::DMXTransmitManual ); +} + +void DMX_Master::disable ( void ) +{ + ::SetISRMode ( isr::Disabled ); + __dmx_master = NULL; // No active master +} + +void DMX_Master::setAutoBreakMode ( void ) { m_autoBreak = 1; } +void DMX_Master::setManualBreakMode ( void ) { m_autoBreak = 0; } +uint8_t DMX_Master::autoBreakEnabled ( void ) { return m_autoBreak; } + + +uint8_t DMX_Master::waitingBreak ( void ) +{ + return ( __isr_txState == isr::DmxBreakManual ); +} + +void DMX_Master::breakAndContinue ( uint8_t breakLength_us ) +{ + // Only execute if we are the controlling master object + if ( __dmx_master == this && __isr_txState == isr::DmxBreakManual ) + { + pinMode ( TX_PIN, OUTPUT ); + digitalWrite ( TX_PIN, LOW ); // Begin BREAK + + for (uint8_t bl=0; bl(*this); +} + + uint8_t DMX_Slave::getChannelValue ( uint16_t channel ) +{ + return getSlotValue ( channel ); +} + + +uint16_t DMX_Slave::getStartAddress ( void ) +{ + return m_startAddress; +} + +void DMX_Slave::setStartAddress ( uint16_t addr ) +{ + m_startAddress = addr; +} + +void DMX_Slave::onReceiveComplete ( void (*func)(unsigned short) ) +{ + event_onFrameReceived = func; +} + + +bool DMX_Slave::processIncoming ( uint8_t val, bool first ) +{ + static uint16_t idx; + bool rval = false; + + if ( first ) + { + // We could have received less channels then we + // expected.. but still is a complete frame + if (m_state == dmx::dmxData && event_onFrameReceived) + event_onFrameReceived (idx); + + m_state = dmx::dmxStartByte; + } + + switch ( m_state ) + { + case dmx::dmxStartByte: + setSlotValue ( 0, val ); // Store start code + idx = m_startAddress; + m_state = dmx::dmxWaitStartAddress; + + case dmx::dmxWaitStartAddress: + if ( --idx == 0 ) + m_state = dmx::dmxData; + break; + + case dmx::dmxData: + if ( idx++ < getBufferSize() ) + setSlotValue ( idx, val ); + else + { + m_state = dmx::dmxFrameReady; + + // If a onFrameReceived callback is register... + if (event_onFrameReceived) + event_onFrameReceived (idx-2); + + rval = true; + } + break; + } + + return rval; +} + + +uint16_t RDM_FrameBuffer::getBufferSize ( void ) { return sizeof ( m_msg ); } + +uint8_t RDM_FrameBuffer::getSlotValue ( uint16_t index ) +{ + if ( index < sizeof ( m_msg ) ) + return m_msg.d[index]; + else + return 0x0; +} + + +void RDM_FrameBuffer::setSlotValue ( uint16_t index, uint8_t value ) +{ + if ( index < sizeof ( m_msg ) ) + m_msg.d[index] = value; +} + +void RDM_FrameBuffer::clear ( void ) +{ + memset ( (void*)m_msg.d, 0x0, sizeof( m_msg ) ); + m_state = rdm::rdmUnknown; +} + +bool RDM_FrameBuffer::processIncoming ( uint8_t val, bool first ) +{ + static uint16_t idx; + bool rval = false; + + if ( first ) + { + m_state = rdm::rdmStartByte; + m_csRecv.checksum = (uint16_t) 0x0000; + idx = 0; + } + + // Prevent buffer overflow for large messages + if (idx >= sizeof(m_msg)) + return true; + + switch ( m_state ) + { + case rdm::rdmStartByte: + m_msg.startCode = val; + m_state = rdm::rdmSubStartCode; + break; + + case rdm::rdmSubStartCode: + if ( val != 0x01 ) + { + rval = true; // Stop processing data + break; + } + + m_msg.subStartCode = val; + m_state = rdm::rdmMessageLength; + break; + + case rdm::rdmMessageLength: + m_msg.msgLength = val; + m_state = rdm::rdmData; + m_csRecv.checksum = 0xcc + 0x01 + val; // set initial checksum + idx = 3; // buffer index for next byte + break; + + case rdm::rdmData: + m_msg.d[idx++] = val; + m_csRecv.checksum += val; + if ( idx >= m_msg.msgLength ) + m_state = rdm::rdmChecksumHigh; + break; + + case rdm::rdmChecksumHigh: + m_csRecv.csh = val; + m_state = rdm::rdmChecksumLow; + + break; + + case rdm::rdmChecksumLow: + m_csRecv.csl = val; + + if ((m_csRecv.checksum % (uint16_t)0x10000) == m_csRecv.checksum) + { + m_state = rdm::rdmFrameReady; + + // valid checksum ... start processing + processFrame (); + } + + m_state = rdm::rdmUnknown; + rval = true; + break; + }; + + return rval; +} + +bool RDM_FrameBuffer::fetchOutgoing ( volatile uint8_t *udr, bool first ) +{ + static uint16_t idx; + static uint16_t cs; + bool rval = false; + + + if ( first ) + { + m_state = rdm::rdmData; + cs = 0x0; + idx = 0; + } + + switch ( m_state ) + { + case rdm::rdmData: + cs += m_msg.d[idx]; + *udr = m_msg.d[idx++]; + if ( idx >= m_msg.msgLength ) + { + m_state = rdm::rdmChecksumHigh; + } + break; + + case rdm::rdmChecksumHigh: + *udr = (cs >> 8); + m_state = rdm::rdmChecksumLow; + break; + + case rdm::rdmChecksumLow: + *udr = (cs & 0xff); + m_state = rdm::rdmUnknown; + rval = true; + break; + + } + + return rval; +} + + +void (*RDM_Responder::event_onIdentifyDevice)(bool); +void (*RDM_Responder::event_onDeviceLabelChanged)(const char*, uint8_t); +void (*RDM_Responder::event_onDMXStartAddressChanged)(uint16_t); +void (*RDM_Responder::event_onDMXPersonalityChanged)(uint8_t); + +// +// slave parameter is only used to ensure a slave object is present before +// initializing the rdm responder class +// +RDM_Responder::RDM_Responder ( uint16_t m, uint8_t d1, uint8_t d2, + uint8_t d3, uint8_t d4, DMX_Slave &slave ) +: RDM_FrameBuffer ( ), + m_Personalities (1), // Available personlities + m_Personality (1) // Default personality eq 1. +{ + __rdm_responder = this; + m_devid.Initialize ( m, d1, d2, d3, d4 ); + + // Default software version id = 0x00000000 + memset ( (void*)m_SoftwareVersionId, 0x0, 0x4 ); + + // Rdm responder is disabled by default + m_rdmStatus.enabled = false; +} + +RDM_Responder::~RDM_Responder ( void ) +{ + __rdm_responder = NULL; +} + +void RDM_Responder::onIdentifyDevice ( void (*func)(bool) ) +{ + event_onIdentifyDevice = func; +} + +void RDM_Responder::onDeviceLabelChanged ( void (*func) (const char*, uint8_t) ) +{ + event_onDeviceLabelChanged = func; +} + +void RDM_Responder::onDMXStartAddressChanged ( void (*func) (uint16_t) ) +{ + event_onDMXStartAddressChanged = func; +} + +void RDM_Responder::onDMXPersonalityChanged ( void (*func) (uint8_t) ) +{ + event_onDMXPersonalityChanged = func; +} + +void RDM_Responder::setDeviceLabel ( const char *label, size_t len ) +{ + if ( len > RDM_MAX_DEVICELABEL_LENGTH ) + len = RDM_MAX_DEVICELABEL_LENGTH; + + memcpy ( (void *)m_deviceLabel, (void *)label, len ); +} + +#define UID_0 0x12 //ESTA device ID +#define UID_1 0x34 +#define UID_2 0x56 +#define UID_3 0x88 +#define UID_4 0x00 +#define UID_5 0x00 + +#define UID_CS (0xFF *6 +UID_0 +UID_1 +UID_2 +UID_3 +UID_4 +UID_5) + +void RDM_Responder::repondDiscUniqueBranch ( void ) +{ + #if defined(UCSRB) + UCSRB = (1<>8) | 0xaa; + response [21] = (cs>>8) | 0x55; + response [22] = (cs&0xff) | 0xaa; + response [23] = (cs&0xff) | 0x55; + + + // Table 3-2 ANSI_E1-20-2010 <2ms + _delay_us ( MIN_RESPONDER_PACKET_SPACING_USEC ); + + // Fix: 2017, Feb 28: Moved data enable down in order to limit line in marking state time to comply with + // section 3.2.3 + // Set shield to transmit mode (turn arround) + digitalWrite ( __re_pin, HIGH ); + + + for ( int i=0; i<24; i++ ) + { + // Wait until data register is empty + #if defined (UCSR0A) && defined (UDRE0) + while((UCSR0A & (1 <(m_msg.PD); + + pd->protocolVersionMajor = 0x01; + pd->protocolVersionMinor = 0x00; + pd->deviceModelId = BSWAP_16(m_DeviceModelId); + pd->ProductCategory = BSWAP_16(m_ProductCategory); + memcpy ( (void*)pd->SoftwareVersionId, (void*)m_SoftwareVersionId, 4 ); + pd->DMX512FootPrint = BSWAP_16(__dmx_slave->getBufferSize()-1); // eq buffersize-startbyte + pd->DMX512CurrentPersonality = m_Personality; + pd->DMX512NumberPersonalities = m_Personalities; + pd->DMX512StartAddress = BSWAP_16(__dmx_slave->getStartAddress()); + + pd->SubDeviceCount = 0x0; // Sub devices are not supported by this library + pd->SensorCount = 0x0; // Sensors are not yet supported + + m_msg.PDL = sizeof (RDM__DeviceInfoPD); +} + +const uint8_t ManufacturerLabel_P[] PROGMEM = "Conceptinetics"; + +void RDM_Responder::processFrame ( void ) +{ + // If packet is a general broadcast + if ( + m_msg.dstUid.isBroadcast (m_devid.m_id) || + m_devid == m_msg.dstUid + ) + { + // Set default response type + m_msg.portId = rdm::ResponseTypeAck; + + switch ( BSWAP_16(m_msg.PID) ) + { + case rdm::DiscUniqueBranch: + // Check if we are inside the given unique branch... + if ( !m_rdmStatus.mute && + reinterpret_cast(m_msg.PD)->lbound < m_devid && + reinterpret_cast(m_msg.PD)->hbound > m_devid ) + { + // Discovery messages are responded with data only and no breaks + repondDiscUniqueBranch (); + } + break; + + case rdm::DiscMute: + reinterpret_cast(m_msg.PD)->ctrlField = 0x0; + m_msg.PDL = sizeof ( RDM_DiscMuteUnMutePD ); + m_rdmStatus.mute = true; + break; + + case rdm::DiscUnMute: + reinterpret_cast(m_msg.PD)->ctrlField = 0x0; + m_msg.PDL = sizeof ( RDM_DiscMuteUnMutePD ); + m_rdmStatus.mute = false; + break; + + case rdm::SupportedParameters: + // + // Temporary solution... this will become dynamic + // in a later version... + // + m_msg.PD[0] = HIGHBYTE(rdm::DmxStartAddress); // MSB + m_msg.PD[1] = LOWBYTE (rdm::DmxStartAddress); // LSB + + m_msg.PD[2] = HIGHBYTE(rdm::DmxPersonality); + m_msg.PD[3] = LOWBYTE (rdm::DmxPersonality); + + m_msg.PD[4] = HIGHBYTE(rdm::ManufacturerLabel); + m_msg.PD[5] = LOWBYTE (rdm::ManufacturerLabel); + + m_msg.PD[6] = HIGHBYTE(rdm::DeviceLabel); + m_msg.PD[7] = LOWBYTE (rdm::DeviceLabel); + + m_msg.PDL = 0x6; + break; + + // Only for manufacturer specific parameters + // case rdm::ParameterDescription: + // break; + + case rdm::DeviceInfo: + if ( m_msg.CC == rdm::GetCommand ) + populateDeviceInfo (); + break; + + case rdm::DmxStartAddress: + if ( m_msg.CC == rdm::GetCommand ) + { + m_msg.PD[0] = HIGHBYTE(__dmx_slave->getStartAddress ()); + m_msg.PD[1] = LOWBYTE (__dmx_slave->getStartAddress ()); + m_msg.PDL = 0x2; + } + else // if ( m_msg.CC == rdm::SetCommand ) + { + __dmx_slave->setStartAddress ( (m_msg.PD[0] << 8) + m_msg.PD[1] ); + m_msg.PDL = 0x0; + + if ( event_onDMXStartAddressChanged ) + event_onDMXStartAddressChanged ( (m_msg.PD[0] << 8) + m_msg.PD[1] ); + } + break; + + case rdm::DmxPersonality: + if ( m_msg.CC == rdm::GetCommand ) + { + reinterpret_cast + (m_msg.PD)->DMX512CurrentPersonality = m_Personality; + reinterpret_cast + (m_msg.PD)->DMX512CurrentPersonality = m_Personalities; + m_msg.PDL = sizeof (RDM_DeviceGetPersonality_PD); + } + else // if ( m_msg.CC == rdm::SetCommand ) + { + m_Personality = reinterpret_cast + (m_msg.PD)->DMX512Personality; + m_msg.PDL = 0x0; + + if ( event_onDMXPersonalityChanged ) + event_onDMXPersonalityChanged ( m_Personality ); + } + break; + + case rdm::IdentifyDevice: + if ( m_msg.CC == rdm::GetCommand ) + { + m_msg.PD[0] = (uint8_t)(m_rdmStatus.ident ? 1 : 0); + m_msg.PDL = 0x1; + } + else if ( m_msg.CC == rdm::SetCommand ) + { + // Look into first byte to see whether identification + // is turned on or off + m_rdmStatus.ident = m_msg.PD[0] ? true : false; + if ( event_onIdentifyDevice ) + event_onIdentifyDevice ( m_rdmStatus.ident ); + + m_msg.PDL = 0x0; + } + break; + + case rdm::ManufacturerLabel: + if ( m_msg.CC == rdm::GetCommand ) + { + memcpy_P( (void*)m_msg.PD, ManufacturerLabel_P, sizeof(ManufacturerLabel_P) ); + m_msg.PDL = sizeof ( ManufacturerLabel_P ); + } + break; + + case rdm::DeviceLabel: + if ( m_msg.CC == rdm::GetCommand ) + { + memcpy ( m_msg.PD, (void*) m_deviceLabel, 32 ); + m_msg.PDL = 32; + } + else if ( m_msg.CC == rdm::SetCommand ) + { + memset ( (void*) m_deviceLabel, ' ', 32 ); + memcpy ( (void*) m_deviceLabel, m_msg.PD, (m_msg.PDL < 32 ? m_msg.PDL : 32) ); + m_msg.PDL = 0; + + // Notify application + if ( event_onDeviceLabelChanged ) + event_onDeviceLabelChanged ( m_deviceLabel, 32 ); + } + break; + + + default: + // Unknown parameter ID response + m_msg.portId = rdm::ResponseTypeNackReason; + m_msg.PD[0] = rdm::UnknownPid; + m_msg.PD[1] = 0x0; + m_msg.PDL = 0x2; + break; + }; + } + + // + // Only respond if this this message + // was destined to us only + if ( m_msg.dstUid == m_devid ) + { + m_msg.startCode = RDM_START_CODE; + m_msg.subStartCode = 0x01; + m_msg.msgLength = RDM_HDR_LEN + m_msg.PDL; + m_msg.msgCount = 0; + + /* + switch ( m_msg.msg.CC ) + { + case rdm::DiscoveryCommand: + m_msg.msg.CC = rdm::DiscoveryCommandResponse; + break; + case rdm::GetCommand: + m_msg.msg.CC = rdm::GetCommandResponse; + break; + case rdm::SetCommand: + m_msg.msg.CC = rdm::SetCommandResponse; + break; + } + */ + /* Above replaced by next line */ + m_msg.CC++; + + m_msg.dstUid.copy ( m_msg.srcUid ); + m_msg.srcUid.copy ( m_devid ); + + //_delay_us ( MIN_RESPONDER_PACKET_SPACING_USEC ); + SetISRMode ( isr::RDMTransmit ); + + } +} + + +void SetISRMode ( isr::isrMode mode ) +{ + uint8_t readEnable; + +#if defined(USE_DMX_SERIAL_0) + #if defined(UCSRB) && defined (UCSRC) + UCSRC |= (1<>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + + // Prepare before kicking off ISR + //DMX_UDR = 0x0; + __isr_rxState = isr::Idle; + readEnable = LOW; + DMX_UCSRB = (1<>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + DMX_UDR = 0x0; + DMX_UCSRB = 0x0; + readEnable = HIGH; + __isr_txState = isr::DmxBreakManual; + break; + + case isr::RDMTransmit: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + //DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + //DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + DMX_UCSRB = (1< -1) + digitalWrite ( __re_pin, readEnable ); + +} + +// +// TX UART (DMX Transmission ISR) +// +ISR (USART_TX) +{ + static uint16_t current_slot; + + switch ( __isr_txState ) + { + case isr::DmxBreak: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + if ( __isr_txState == isr::DmxBreak ) + __isr_txState = isr::DmxStartByte; + + break; + + case isr::DmxStartByte: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + current_slot = 0; + DMX_UDR = __dmx_master->getBuffer()[ current_slot++ ]; + __isr_txState = isr::DmxTransmitData; + break; + + + case isr::DmxTransmitData: + // NOTE: we always send full frames of 513 bytes, this will bring us + // close to 40 frames / sec with no interslot delays + #ifdef DMX_IBG + _delay_us (DMX_IBG); + #endif + + DMX_UDR = __dmx_master->getBuffer().getSlotValue( current_slot++ ); + + // Send 512 channels + if ( current_slot >= DMX_MAX_FRAMESIZE ) + { + if ( __dmx_master->autoBreakEnabled () ) + __isr_txState = isr::DmxBreak; + else + SetISRMode ( isr::DMXTransmitManual ); + } + + break; + +/* case isr::RdmBreak: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + __isr_txState = isr::RdmStartByte; + + break; +*/ + + case isr::RdmStartByte: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + + // Write start byte + __rdm_responder->fetchOutgoing ( &DMX_UDR, true ); + __isr_txState = isr::RdmTransmitData; + + break; + + case isr::RdmTransmitData: + // Write rest of data + if ( __rdm_responder->fetchOutgoing ( &DMX_UDR ) ) + __isr_txState = isr::RDMTransmitComplete; + break; + + case isr::RDMTransmitComplete: + SetISRMode ( isr::Receive ); // Start waitin for new data + __isr_txState = isr::Idle; // No tx state + break; + + } +} + + + +// +// RX UART (DMX Reception ISR) +// +ISR (USART_RX) +{ + uint8_t usart_state = DMX_UCSRA; + uint8_t usart_data = DMX_UDR; + + // + // Check for framing error and reset if found + // A framing most likely* indicate a break in our ocasion + // + if ( usart_state & (1<processIncoming ( usart_data, true ); + __isr_rxState = isr::DmxRecordData; + } + else if ( __rdm_responder && + usart_data == RDM_START_CODE && + __rdm_responder->m_rdmStatus.enabled ) + { + // __rdm_responder->clear (); + __rdm_responder->processIncoming ( usart_data, true ); + __isr_rxState = isr::RdmRecordData; + } + else + { + __isr_rxState = isr::Idle; + } + break; + + // Process DMX Data + case isr::DmxRecordData: + if ( __dmx_slave->processIncoming ( usart_data ) ) + __isr_rxState = isr::Idle; + break; + + // Process RDM Data + case isr::RdmRecordData: + if ( __rdm_responder->processIncoming ( usart_data ) ) + __isr_rxState = isr::Idle; + break; + + } + +} + diff --git a/DMX_NeoPixels/examples/DMX_Master/Conceptinetics.h b/DMX_NeoPixels/examples/DMX_Master/Conceptinetics.h new file mode 100644 index 000000000..0f03da619 --- /dev/null +++ b/DMX_NeoPixels/examples/DMX_Master/Conceptinetics.h @@ -0,0 +1,383 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Conceptinetics.h - DMX library for Arduino + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + This code has been tested using the following hardware: + + - Arduino / Genuino UNO R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino / Genuino MEGA2560 R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino / Genuino Leonardo using a CTC-DRA-13-R2 ISOLATED DMX-RDM SHIELD + + - CTC-DRA-10-1 and CTC-DRA-10-R2 is the Non-isolated costs effective DMX-RDM shield +*/ + + +#ifndef CONCEPTINETICS_H_ +#define CONCEPTINETICS_H_ + +#include +#include + +#include "Rdm_Uid.h" +#include "Rdm_Defines.h" + +#define DMX_MAX_FRAMESIZE 513 // Startbyte + 512 Slots +#define DMX_MIN_FRAMESIZE 2 // Startbyte + 1 Slot + +#define DMX_MAX_FRAMECHANNELS 512 // Maxmim number of channer per frame + +#define DMX_STARTCODE_SIZE 1 // Size of startcode in bytes + +#define DMX_START_CODE 0x0 // Start code for a DMX frame +#define RDM_START_CODE 0xcc // Start code for a RDM frame + +// Uncomment to enable Inter slot delay ) (avg < 76uSec) ... +// mimum is zero according to specification +// #define DMX_IBG 10 // Inter slot time + +// Speed your Arduino is running on in Hz. +#define F_OSC 16000000UL + +// DMX Baudrate, this should be 250000 +#define DMX_BAUD_RATE 250000 + +// The baudrate used to automaticly generate a break within +// your ISR.. make it lower to generate longer breaks +//#define DMX_BREAK_RATE 99900 + +// 2017, Feb 28: Set to appox 176us +#define DMX_BREAK_RATE 49950 + +// Tabel 3-2 ANSI_E1-20-2010 +// Minimum time to allow the datalink to 'turn arround' +#define MIN_RESPONDER_PACKET_SPACING_USEC 176 /*176*/ + +// Define which serial port to use as DMX port, only one can be +// selected at the time by uncommenting one of the following +// lines +#define USE_DMX_SERIAL_0 +//#define USE_DMX_SERIAL_1 +//#define USE_DMX_SERIAL_2 +//#define USE_DMX_SERIAL_3 + +namespace dmx +{ + enum dmxState + { + dmxUnknown, + dmxStartByte, + dmxWaitStartAddress, + dmxData, + dmxFrameReady, + }; +}; + +namespace rdm +{ + enum rdmState + { + rdmUnknown, + rdmStartByte, + rdmSubStartCode, + rdmMessageLength, + rdmData, + rdmChecksumHigh, + rdmChecksumLow, + rdmFrameReady, + }; +}; + +struct IFrameBuffer +{ + virtual uint16_t getBufferSize ( void ) = 0; + + virtual uint8_t getSlotValue ( uint16_t index ) = 0; + virtual void setSlotValue ( uint16_t index, uint8_t value ) = 0; +}; + +class DMX_FrameBuffer : IFrameBuffer +{ + public: + // + // Constructor buffersize = 1-513 + // + DMX_FrameBuffer ( uint16_t buffer_size ); + DMX_FrameBuffer ( DMX_FrameBuffer &buffer ); + ~DMX_FrameBuffer ( void ); + + uint16_t getBufferSize ( void ); + + uint8_t getSlotValue ( uint16_t index ); + void setSlotValue ( uint16_t index, uint8_t value ); + void setSlotRange ( uint16_t start, uint16_t end, uint8_t value ); + void clear ( void ); + + uint8_t &operator[] ( uint16_t index ); + + private: + + uint8_t *m_refcount; + uint16_t m_bufferSize; + uint8_t *m_buffer; +}; + + +// +// DMX Master controller +// +class DMX_Master +{ + public: + // Run the DMX master from a pre allocated frame buffer which + // you have fully under your own control + DMX_Master ( DMX_FrameBuffer &buffer, int readEnablePin ); + + // Run the DMX master by giving a predefined maximum number of + // channels to support + DMX_Master ( uint16_t maxChannel, int readEnablePin ); + + ~DMX_Master ( void ); + + void enable ( void ); // Start transmitting + void disable ( void ); // Stop transmitting + + // Get reference to the internal framebuffer + DMX_FrameBuffer &getBuffer ( void ); + + // Update channel values + void setChannelValue ( uint16_t channel, uint8_t value ); + void setChannelRange ( uint16_t start, uint16_t end, uint8_t value ); + + public: + // + // Manual control over the break period + // + void setAutoBreakMode ( void ); // Generated from ISR + void setManualBreakMode ( void ); // Generate manually + + uint8_t autoBreakEnabled ( void ); + + // We are waiting for a manual break to be generated + uint8_t waitingBreak ( void ); + + // Generate break and start transmission of frame + void breakAndContinue ( uint8_t breakLength_us = 100 ); + + + protected: + void setStartCode ( uint8_t value ); + + + private: + DMX_FrameBuffer m_frameBuffer; + uint8_t m_autoBreak; +}; + + +// +// DMX Slave controller +// +class DMX_Slave : public DMX_FrameBuffer +{ + public: + DMX_Slave ( DMX_FrameBuffer &buffer, int readEnablePin = -1 ); + + // nrChannels is the consecutive DMX512 slots required + // to operate this slave device + DMX_Slave ( uint16_t nrChannels, int readEnablePin = -1 ); + + ~DMX_Slave ( void ); + + void enable ( void ); // Enable receiver + void disable ( void ); // Disable receiver + + + // Get reference to the internal framebuffer + DMX_FrameBuffer &getBuffer ( void ); + + uint8_t getChannelValue ( uint16_t channel ); + + uint16_t getStartAddress ( void ); + void setStartAddress ( uint16_t ); + + + // Process incoming byte from USART + bool processIncoming ( uint8_t val, bool first = false ); + + // Register on receive complete callback in case + // of time critical applications + void onReceiveComplete ( void (*func)(unsigned short) ); + + protected: + + + private: + uint16_t m_startAddress; // Slave start address + dmx::dmxState m_state; + + static void (*event_onFrameReceived)(unsigned short channelsReceived); +}; + + +class RDM_FrameBuffer : public IFrameBuffer +{ + public: + // + // Constructor + // + RDM_FrameBuffer ( void ) {}; + ~RDM_FrameBuffer ( void ) {}; + + uint16_t getBufferSize ( void ); + + uint8_t getSlotValue ( uint16_t index ); + void setSlotValue ( uint16_t index, uint8_t value ); + void clear ( void ); + + uint8_t &operator[] ( uint16_t index ); + + public: // functions to provide access from USART + // Process incoming byte from USART, + // returns false when no more data is accepted + bool processIncoming ( uint8_t val, bool first = false ); + + // Process outgoing byte to USART + // returns false when no more data is available + bool fetchOutgoing ( volatile uint8_t *udr, bool first = false ); + + protected: + // Process received frame + virtual void processFrame ( void ) = 0; + + //private: + protected: + rdm::rdmState m_state; // State for pushing the message in + RDM_Message m_msg; + RDM_Checksum m_csRecv; // Checksum received in rdm message +}; + +// +// RDM_Responder +// +class RDM_Responder : public RDM_FrameBuffer +{ + public: + // + // m = manufacturer id (16bits) + // d1-d4 = device id (32bits) + // + RDM_Responder ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4, DMX_Slave &slave); + ~RDM_Responder ( void ); + + void setDeviceInfo + ( + uint16_t deviceModelId, + rdm::RdmProductCategory productCategory, + uint8_t personalities = 1, + uint8_t personality = 1 + ) + { + m_DeviceModelId = deviceModelId; + m_ProductCategory = productCategory; + m_Personalities = personalities; + m_Personality = personality; + }; + + // + // Set vendor software version id + // + // v1 = MOST SIGNIFICANT + // v2... + // v3... + // v4 = LEAST SIGNIFICANT + // + void setSoftwareVersionId ( uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4 ) + { + m_SoftwareVersionId[0] = v1; + m_SoftwareVersionId[1] = v2; + m_SoftwareVersionId[2] = v3; + m_SoftwareVersionId[3] = v4; + } + + // Currently no sensors and subdevices supported + // void AddSensor ( void ); + // void AddSubDevice ( void ); + + uint8_t getPersonality ( void ) { return m_Personality; }; + void setPersonality ( uint8_t personality ) { m_Personality = personality; }; + + // Register on identify device event handler + void onIdentifyDevice ( void (*func)(bool) ); + void onDeviceLabelChanged ( void (*func) (const char*, uint8_t) ); + void onDMXStartAddressChanged ( void (*func) (uint16_t) ); + void onDMXPersonalityChanged ( void (*func) (uint8_t) ); + + + // Set the device label + void setDeviceLabel ( const char *label, size_t len ); + + // Enable, Disable rdm responder + void enable ( void ) { m_rdmStatus.enabled = true; m_rdmStatus.mute = false; }; + void disable ( void ) { m_rdmStatus.enabled = false; }; + + union + { + uint8_t raw; + struct + { + uint8_t mute:1; + uint8_t ident:1; + uint8_t enabled:1; // Rdm responder enable/disable + }; + } m_rdmStatus; + + + protected: + virtual void processFrame ( void ); + + // Discovery to unque brach packets only requires + // the data part of the packet to be transmitted + // without breaks or header + void repondDiscUniqueBranch ( void ); + + // Helpers for generating response packets which + // have larger datafields + void populateDeviceInfo ( void ); + + private: + RDM_Uid m_devid; // Holds our unique device ID + uint8_t m_Personalities; // The total number of supported personalities + uint8_t m_Personality; // The currently active personality + uint16_t m_DeviceModelId; + uint8_t m_SoftwareVersionId[4]; // 32 bit Software version + rdm::RdmProductCategory m_ProductCategory; + + char m_deviceLabel[32]; // Device label + + static void (*event_onIdentifyDevice)(bool); + static void (*event_onDeviceLabelChanged)(const char*, uint8_t); + static void (*event_onDMXStartAddressChanged)(uint16_t); + static void (*event_onDMXPersonalityChanged)(uint8_t); +}; + + +#endif /* CONCEPTINETICS_H_ */ diff --git a/DMX_NeoPixels/examples/DMX_Master/DMX_Master.ino b/DMX_NeoPixels/examples/DMX_Master/DMX_Master.ino index e6cf3e9af..98d7284e8 100644 --- a/DMX_NeoPixels/examples/DMX_Master/DMX_Master.ino +++ b/DMX_NeoPixels/examples/DMX_Master/DMX_Master.ino @@ -21,7 +21,7 @@ */ -#include +#include "Conceptinetics.h" // diff --git a/DMX_NeoPixels/examples/DMX_Master/Rdm_Defines.h b/DMX_NeoPixels/examples/DMX_Master/Rdm_Defines.h new file mode 100644 index 000000000..0accca63d --- /dev/null +++ b/DMX_NeoPixels/examples/DMX_Master/Rdm_Defines.h @@ -0,0 +1,315 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Rdm_Defines.h - DMX library for Arduino with RDM (Remote Device Management) support + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef RDM_DEFINES_H_ +#define RDM_DEFINES_H_ + +#include "Rdm_Uid.h" + +#define RDM_MAX_DEVICELABEL_LENGTH 32 + +namespace rdm +{ + enum RdmCommandClass + { + DiscoveryCommand = 0x10, + DiscoveryCommandResponse, + GetCommand = 0x20, + GetCommandResponse, + SetCommand = 0x30, + SetCommandResponse, + }; + + enum RdmResponseTypes + { + ResponseTypeAck = 0x00, + ResponseTypeAckTimer, + ResponseTypeNackReason, + ResponseTypeAckOverflow, // Additional response data available (see spec) + }; + + enum RdmParameters + { + // Category - Network Management + DiscUniqueBranch = 0x0001, // Required + DiscMute = 0x0002, // Required + DiscUnMute = 0x0003, // Required + + CommsStatus = 0x0015, // Get,Set + + // Category - Status Collection + QueuedMessage = 0x0020, // Get [enum RdmStatusTypes] + StatusMessages = 0x0030, // Get [enum RdmStatusTypes] + StatusIdDescription = 0x0031, // Get + ClearStatusId = 0x0032, // Set + SubDeviceStatusReportThreshold = 0x0033, // Get, Set [enum RdmStatusTypes] + + // Category - RDM Information + // ** Only required if supporting parameters + // beyond the minimum required set + SupportedParameters = 0x0005, // Get, **Required + ParameterDescription = 0x0051, // Get, **Required + + // Category = Product Information + DeviceInfo = 0x0060, // Get, Required + ProductDetailIdList = 0x0070, // Get + DeviceModelDescription = 0x0080, // Get + ManufacturerLabel = 0x0081, // Get + DeviceLabel = 0x0082, // Get, Set + FactoryDefaults = 0x0009, // Get, Set ** + SoftwareVersionLabel = 0x000c, // Get + + // Category - DMX512 Setup + DmxPersonality = 0x00e0, // Get, Set + DmxPersonalityDescription = 0x00e1, // Get + DmxStartAddress = 0x00f0, // Get, Set ** Required if DMX device + SlotInfo = 0x0120, // Get + SlotDescription = 0x0121, // Get + DefaultSlotValue = 0x0122, // Get + + // Category - Sensors + // Category - Dimmer Settings + // Category - Power/Lamp Settings + // Category - Display Settings + // Category - Configuration + + // Category - Control + IdentifyDevice = 0x1000, // Get, Set, Required + ResetDevice = 0x1001, // Set + PowerState = 0x1010, // Get, Set + PerformSelftest = 0x1020, // Get, Set + SelfTestDescription = 0x1021, // Get + }; + + + enum RdmStatusTypes + { + StatusNone = 0x00, + StatusGetLastMessage, + StatusAdvisory, + StatusWarning, + StatusError, + StatusAdvisoryCleared = 0x12, + StatusWarningCleared, + StatusErrorCleared, + }; + + enum RdmProductCategory + { + CategoryNotDeclared = 0x0000, + + // Fixtures - intended as source for illumination + CategoryFixture = 0x0100, + CategoryFixtureFixed = 0x0101, + CategoryFixtureMovingYoke = 0x0102, + CategoryFixtureMovingMirror = 0x0103, + CategoryFixtureOther = 0x01ff, + + // Fixture Accessories - add-ons to fixtures or projectors + CategoryFixtureAccessory = 0x0200, + CategoryFixtureAccessoryColor = 0x0201, + CategoryFixtureAccessoryYoke = 0x0202, + CategoryFixtureAccessoryMirror = 0x0203, + CategoryFixtureAccessoryEffect = 0x0204, + CategoryFixtureAccessoryBeam = 0x0205, + CategoryFixtureAccessoryOther = 0x02ff, + + // Projectors - Light source capable of producing + // realistic images from another media + CategoryProjector = 0x0300, + CategoryProjectorFixed = 0x0301, + CategoryProjectorMovingYoke = 0x0302, + CategoryProjectorMovingMirror = 0x0303, + CategoryProjectorOther = 0x03ff, + + // Atmospheric Effect - earth/wind/fire + CategoryAtmospheric = 0x0400, + CategoryAtmosphericEffect = 0x0401, // Fogger, Hazer, Flame + CategoryAtmosphericPyro = 0x0402, + CategoryAtmosphericOther = 0x04ff, + + // Insensity Control (Specifically dimming equipment) + CategoryDimmer = 0x0500, + CategoryDimmer_AC_Incandescent = 0x0501, + CategoryDimmer_AC_Fluorescent = 0x0502, + CategoryDimmer_AC_Coldcathode = 0x0503, + CategoryDimmer_AC_Nondim = 0x0504, + CategoryDimmer_AC_Elv = 0x0505, + CategoryDimmer_AC_Other = 0x0506, + CategoryDimmer_DC_Level = 0x0507, + CategoryDimmer_DC_PWM = 0x0508, + CategoryDimmer_CS_LED = 0x0509, + CategoryDimmer_Other = 0x05ff, + + // Power control (Other than dimming equipment) + CategoryPower = 0x0600, + CategoryPowerControl = 0x0601, + CategoryPowerSource = 0x0602, + CategoryPowerOther = 0x06ff, + + // Scenic Drive - Including motorized effects + // unrelated to light source + CategoryScenic = 0x0700, + CategoryScenicDrive = 0x0701, + CategoryScenicOther = 0x07ff, + + // DMX Infrastructure, conversion and interfaces + CategoryData = 0x0800, + CategoryDataDistribution = 0x0801, + CategoryDataConversion = 0x0802, + CategoryDataOther = 0x08ff, + + // Audio visual equipment + Category_AV = 0x0900, + Category_AV_Audio = 0x0901, + Category_AV_Video = 0x0902, + Category_AV_Other = 0x09ff, + + // Parameter monitoring equipment + CategoryMonitor = 0x0a00, + CategoryMonitorACLinePower = 0x0a01, + CategoryMonitorDCPower = 0x0a02, + CategoryMonitorEnvironmental = 0x0a03, + CategoryMonitorOther = 0x0aff, + + // Controllers, backup devices + CategoryControl = 0x7000, + CategoryControlController = 0x7001, + CategoryControlBackupdevice = 0x7002, + CategoryControlOther = 0x70ff, + + // Test equipment + CategoryTest = 0x7100, + CategoryTestEquipment = 0x7101, + CategoryTestEquipmentOther = 0x71ff, + + // Miscellaneous + CategoryOther = 0x7fff, + }; + + // + // Product details not yet supported in + // this library + // + enum RdmProductDetail + { + ProductDetailNotDeclared = 0x0000, + }; + + // Only LSB + enum RdmNackReasons + { + UnknownPid = 0x00, + FormatError, + HardwareFault, + ProxyReject, + WriteProtect, + UnsupportedCmdClass, + DataOutOfRange, + BufferFull, + PacketSizeUnsupported, + SubDeviceOutOfRange, + ProxyBufferFull + }; + +}; + + +#define RDM_HDR_LEN 24 // RDM Message header length ** fixed +#define RDM_PD_MAXLEN 32 // RDM Maximum parameter data length 1 - 231 + + +union RDM_Message +{ + uint8_t d[ RDM_HDR_LEN + RDM_PD_MAXLEN ]; + struct + { + uint8_t startCode; // 0 SC_RDM + uint8_t subStartCode; // 1 SC_SUB_MESSAGE + uint8_t msgLength; // 2 Range 24 - 255 + RDM_Uid dstUid; // 3-8 Destination UID + RDM_Uid srcUid; // 9-14 Source UID (sender) + uint8_t TN; // 15 Transaction number + uint8_t portId; // 16 Port ID / Response type + uint8_t msgCount; // 17 + uint16_t subDevice; // 18,19 0=root, 0xffff=all + uint8_t CC; // 20 GET_COMMAND + uint16_t PID; // 21,22 Parameter ID + uint8_t PDL; // 23 Parameter Data length 1-231 + + uint8_t PD[RDM_PD_MAXLEN]; // Parameter Data ... variable length + }; +}; + +union RDM_Checksum +{ + uint16_t checksum; + struct + { + uint8_t csl; + uint8_t csh; + }; +}; + +struct RDM_DiscUniqueBranchPD +{ + RDM_Uid lbound; + RDM_Uid hbound; +}; + +struct RDM_DiscMuteUnMutePD +{ + uint16_t ctrlField; + +// Only for multiple ports +// RDM_Uid bindingUid; +}; + +struct RDM__DeviceInfoPD +{ + uint8_t protocolVersionMajor; + uint8_t protocolVersionMinor; + uint16_t deviceModelId; + uint16_t ProductCategory; // enum RdmProductCategory + uint8_t SoftwareVersionId[4]; + uint16_t DMX512FootPrint; + uint8_t DMX512CurrentPersonality; + uint8_t DMX512NumberPersonalities; + uint16_t DMX512StartAddress; + uint16_t SubDeviceCount; + uint8_t SensorCount; +}; + +struct RDM_DeviceGetPersonality_PD +{ + uint8_t DMX512CurrentPersonality; + uint8_t DMX512NumberPersonalities; +}; + +struct RDM_DeviceSetPersonality_PD +{ + uint8_t DMX512Personality; +}; + + +#endif /* RDM_DEFINES_H_ */ diff --git a/DMX_NeoPixels/examples/DMX_Master/Rdm_Uid.h b/DMX_NeoPixels/examples/DMX_Master/Rdm_Uid.h new file mode 100644 index 000000000..35c802c63 --- /dev/null +++ b/DMX_NeoPixels/examples/DMX_Master/Rdm_Uid.h @@ -0,0 +1,101 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Rdm_Uid.h - DMX library for Arduino with RDM (Remote Device Management) support + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef RDM_UID_H_ +#define RDM_UID_H_ + +#include + +// +//48 bit UID Representation to identify RDM transponders +// +struct RDM_Uid { + + void Initialize ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4 ) + { + m_id[0] = ((uint8_t) (((uint16_t) (m)) >> 8)); + m_id[1] = (uint8_t)m; + m_id[2] = d1; + m_id[3] = d2; + m_id[4] = d3; + m_id[5] = d4; + } + + void copy ( const RDM_Uid &orig ) + { + for ( uint8_t i = 0; i < 6; i++ ) + m_id[i] = orig.m_id[i]; + } + + bool operator == ( const RDM_Uid & orig ) const + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != orig.m_id[i] ) + return false; + + return true; + } + + bool operator != ( const RDM_Uid & orig ) const + { + return !(*this == orig); + } + + bool operator < ( const RDM_Uid & v ) const + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != v.m_id[i] ) + return ( m_id[i] < v.m_id[i] ); + } + + bool operator > ( const RDM_Uid & v ) + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != v.m_id[i] ) + return ( m_id[i] > v.m_id[i] ); + } + + // + // match_mid = manufacturer id to match + // + bool isBroadcast ( uint8_t match_mid[2] ) + { + // Check for genuine broadcast on device part + for ( uint8_t i = 2; i < 6; i++ ) + if ( m_id[i] != 0xff ) + return false; + + // Broadcast or manufacturer designated broadcast + if ( (m_id[0] == 0xff && m_id[1] == 0xff) || + (m_id[0] == match_mid[0] && m_id[1] == match_mid[1]) ) + return true; + + // No broadcast + return false; + } + + uint8_t m_id[6]; //16bit manufacturer id + 32 bits device id +}; + + +#endif /* RDM_UID_H_ */ diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.cpb.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.cpb.test.skip deleted file mode 100644 index 064a28912..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.cpb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpb diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.cpc.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.cpc.test.skip deleted file mode 100644 index 79763353d..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.cpc.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpc diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.cpx_ada.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.cpx_ada.test.skip deleted file mode 100644 index d9c56cc11..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.cpx_ada.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpx_ada diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.esp32.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.esp32.test.skip deleted file mode 100644 index 5faeb5064..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.esp32.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for esp32 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.esp8266.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.esp8266.test.skip deleted file mode 100644 index 15eb13221..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.esp8266.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for esp8266 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather32u4.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather32u4.test.skip deleted file mode 100644 index eb9fd87a1..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather32u4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather32u4 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather_esp32c6.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather_esp32c6.test.skip deleted file mode 100644 index 563448c75..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather_esp32c6.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_esp32c6 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather_m0_express.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather_m0_express.test.skip deleted file mode 100644 index c1118c563..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather_m0_express.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_m0_express diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather_m4_express.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather_m4_express.test.skip deleted file mode 100644 index 9b961626f..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather_m4_express.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_m4_express diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather_rp2040.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather_rp2040.test.skip deleted file mode 100644 index 90aa322a7..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather_rp2040.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_rp2040 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather_rp2040_adalogger.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather_rp2040_adalogger.test.skip deleted file mode 100644 index 29ebf0ea0..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.feather_rp2040_adalogger.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_rp2040_adalogger diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.flora.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.flora.test.skip deleted file mode 100644 index e4cc7386e..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.flora.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for flora diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.funhouse.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.funhouse.test.skip deleted file mode 100644 index 32a4e1e1a..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.funhouse.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for funhouse diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.gemma.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.gemma.test.skip deleted file mode 100644 index 978f275e3..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.gemma.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for gemma diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.gemma_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.gemma_m0.test.skip deleted file mode 100644 index c42614d7c..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.gemma_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for gemma_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.hallowing_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.hallowing_m0.test.skip deleted file mode 100644 index ed26fdf6a..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.hallowing_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for hallowing_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.hallowing_m4_tinyusb.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.hallowing_m4_tinyusb.test.skip deleted file mode 100644 index 0ab22cb8d..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.hallowing_m4_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for hallowing_m4_tinyusb diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.ledglasses_nrf52840.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.ledglasses_nrf52840.test.skip deleted file mode 100644 index f540a7e4c..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.ledglasses_nrf52840.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for ledglasses_nrf52840 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.magtag.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.magtag.test.skip deleted file mode 100644 index 79d0d324c..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.magtag.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for magtag diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.metro_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.metro_m0.test.skip deleted file mode 100644 index 91512a898..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.metro_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.metro_m0_tinyusb.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.metro_m0_tinyusb.test.skip deleted file mode 100644 index 486e4f67e..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.metro_m0_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m0_tinyusb diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.metro_m4.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.metro_m4.test.skip deleted file mode 100644 index 5012f3737..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.metro_m4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m4 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.metro_m4_tinyusb.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.metro_m4_tinyusb.test.skip deleted file mode 100644 index 17edc54fe..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.metro_m4_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m4_tinyusb diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.monster_m4sk.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.monster_m4sk.test.skip deleted file mode 100644 index ec7f80e48..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.monster_m4sk.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for monster_m4sk diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.monster_m4sk_tinyusb.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.monster_m4sk_tinyusb.test.skip deleted file mode 100644 index a08b60688..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.monster_m4sk_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for monster_m4sk_tinyusb diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.neokeytrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.neokeytrinkey_m0.test.skip deleted file mode 100644 index 7fb03fe33..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.neokeytrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for neokeytrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.neotrellis_m4.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.neotrellis_m4.test.skip deleted file mode 100644 index eebfceae8..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.neotrellis_m4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for neotrellis_m4 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.nrf52832.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.nrf52832.test.skip deleted file mode 100644 index ee506a55a..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.nrf52832.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for nrf52832 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.nrf52840.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.nrf52840.test.skip deleted file mode 100644 index a6bcf2c9d..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.nrf52840.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for nrf52840 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.pixeltrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.pixeltrinkey_m0.test.skip deleted file mode 100644 index 4a5f3b346..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.pixeltrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pixeltrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.protrinket_5v.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.protrinket_5v.test.skip deleted file mode 100644 index ec91a95cb..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.protrinket_5v.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for protrinket_5v diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.proxlighttrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.proxlighttrinkey_m0.test.skip deleted file mode 100644 index 0d46213a9..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.proxlighttrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for proxlighttrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.pybadge.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.pybadge.test.skip deleted file mode 100644 index 82cd2ac9c..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.pybadge.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pybadge diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.pycamera_s3.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.pycamera_s3.test.skip deleted file mode 100644 index 021a63e54..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.pycamera_s3.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pycamera_s3 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.pygamer.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.pygamer.test.skip deleted file mode 100644 index 430cf639c..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.pygamer.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pygamer diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.pyportal.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.pyportal.test.skip deleted file mode 100644 index 6a18dce9f..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.pyportal.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pyportal diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.qt2040_trinkey.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.qt2040_trinkey.test.skip deleted file mode 100644 index 263748866..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.qt2040_trinkey.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qt2040_trinkey diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.qtpy_esp32s2.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.qtpy_esp32s2.test.skip deleted file mode 100644 index 627d7dd57..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.qtpy_esp32s2.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qtpy_esp32s2 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.qtpy_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.qtpy_m0.test.skip deleted file mode 100644 index fbc42f083..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.qtpy_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qtpy_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.qualia_s3_rgb666.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.qualia_s3_rgb666.test.skip deleted file mode 100644 index 1e14eea6e..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.qualia_s3_rgb666.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qualia_s3_rgb666 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.rotarytrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.rotarytrinkey_m0.test.skip deleted file mode 100644 index 8a2ec7327..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.rotarytrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for rotarytrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.sht4xtrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.sht4xtrinkey_m0.test.skip deleted file mode 100644 index 039d08b3e..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.sht4xtrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for sht4xtrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.slidetrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.slidetrinkey_m0.test.skip deleted file mode 100644 index d3f14ba82..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.slidetrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for slidetrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.trinket_5v.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.trinket_5v.test.skip deleted file mode 100644 index e2d3dded0..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.trinket_5v.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for trinket_5v diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.trinket_m0.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.trinket_m0.test.skip deleted file mode 100644 index 06ad7bf51..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.trinket_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for trinket_m0 diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.uno.test.only b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.uno.test.skip b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.uno.test.skip deleted file mode 100644 index f3e164df1..000000000 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/.uno.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for uno diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/Conceptinetics.cpp b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/Conceptinetics.cpp new file mode 100644 index 000000000..36ada5924 --- /dev/null +++ b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/Conceptinetics.cpp @@ -0,0 +1,1233 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Conceptinetics.cpp - DMX library for Arduino + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + This code has been tested using the following hardware: + + - Arduino UNO R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino MEGA2560 R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD +*/ + + +#include "pins_arduino.h" +#include "Conceptinetics.h" + +#include +#include + +#include +#include + +#include + + +#if defined (USE_DMX_SERIAL_0) + + #if defined (USART__TXC_vect) + #define USART_TX USART__TXC_vect + #elif defined(USART_TX_vect) + #define USART_TX USART_TX_vect + #elif defined(USART0_TX_vect) + #define USART_TX USART0_TX_vect + #endif + + #if defined (USART__RXC_vect) + #define USART_RX USART__RXC_vect + #elif defined(USART_RX_vect) + #define USART_RX USART_RX_vect + #elif defined(USART0_RX_vect) + #define USART_RX USART0_RX_vect + #endif + + #if defined UDR + #define DMX_UDR UDR + #elif defined UDR0 + #define DMX_UDR UDR0 + #endif + + #if defined(UBRRH) && defined(UBRRL) + #define DMX_UBRRH UBRRH + #define DMX_UBRRL UBRRL + #elif defined(UBRR0H) && defined(UBRR0L) + #define DMX_UBRRH UBRR0H + #define DMX_UBRRL UBRR0L + #endif + + #if defined(UCSRA) + #define DMX_UCSRA UCSRA + #elif defined(UCSR0A) + #define DMX_UCSRA UCSR0A + #endif + + #if defined(UCSRB) + #define DMX_UCSRB UCSRB + #elif defined (UCSR0B) + #define DMX_UCSRB UCSR0B + #endif + + #if defined(TXEN) && defined(TXCIE) + #define DMX_TXEN TXEN + #define DMX_TXCIE TXCIE + #elif defined(TXEN0) && defined(TXCIE0) + #define DMX_TXEN TXEN0 + #define DMX_TXCIE TXCIE0 + #endif + + #if defined(RXEN) && defined(RXCIE) + #define DMX_RXEN RXEN + #define DMX_RXCIE RXCIE + #elif defined(RXEN0) && defined(RXCIE0) + #define DMX_RXEN RXEN0 + #define DMX_RXCIE RXCIE0 + #endif + + #if defined(FE) + #define DMX_FE FE + #elif defined(FE0) + #define DMX_FE FE0 + #endif + + #define RX_PIN 0 + #define TX_PIN 1 + +#elif defined (USE_DMX_SERIAL_1) + #define USART_RX USART1_RX_vect + #define USART_TX USART1_TX_vect + #define DMX_UDR UDR1 + #define DMX_UBRRH UBRR1H + #define DMX_UBRRL UBRR1L + #define DMX_UCSRA UCSR1A + #define DMX_UCSRB UCSR1B + #define DMX_TXEN TXEN1 + #define DMX_TXCIE TXCIE1 + #define DMX_RXEN RXEN1 + #define DMX_RXCIE RXCIE1 + #define DMX_FE FE1 + #define RX_PIN 19 + #define TX_PIN 18 +#elif defined (USE_DMX_SERIAL_2) + #define USART_RX USART2_RX_vect + #define USART_TX USART2_TX_vect + #define DMX_UDR UDR2 + #define DMX_UBRRH UBRR2H + #define DMX_UBRRL UBRR2L + #define DMX_UCSRA UCSR2A + #define DMX_UCSRB UCSR2B + #define DMX_TXEN TXEN2 + #define DMX_TXCIE TXCIE2 + #define DMX_RXEN RXEN2 + #define DMX_RXCIE RXCIE2 + #define DMX_FE FE2 + #define RX_PIN 17 + #define TX_PIN 16 +#elif defined (USE_DMX_SERIAL_3) + #define USART_RX USART3_RX_vect + #define USART_TX USART3_TX_vect + #define DMX_UDR UDR3 + #define DMX_UBRRH UBRR3H + #define DMX_UBRRL UBRR3L + #define DMX_UCSRA UCSR3A + #define DMX_UCSRB UCSR3B + #define DMX_TXEN TXEN3 + #define DMX_TXCIE TXCIE3 + #define DMX_RXEN RXEN3 + #define DMX_RXCIE RXCIE3 + #define DMX_FE FE3 + #define RX_PIN 14 + #define TX_PIN 15 +#endif + + +#define LOWBYTE(v) ((uint8_t) (v)) +#define HIGHBYTE(v) ((uint8_t) (((uint16_t) (v)) >> 8)) + +#define BSWAP_16(x) ( (uint8_t)((x) >> 8) | ((uint8_t)(x)) << 8 ) + +namespace isr +{ + enum isrState + { + Idle, + Break, + DmxBreak, + DmxBreakManual, + DmxStartByte, + DmxRecordData, + DmxTransmitData, + RdmBreak, + RdmStartByte, + RdmRecordData, + RdmTransmitData, + RDMTransmitComplete, + }; + + enum isrMode + { + Disabled, + Receive, + DMXTransmit, + DMXTransmitManual, /* Manual break... */ + RDMTransmit, + RDMTransmitNoInt, /* Setup uart but leave interrupt disabled */ + }; +}; + + +DMX_Master *__dmx_master; +DMX_Slave *__dmx_slave; +RDM_Responder *__rdm_responder; + +int8_t __re_pin; // R/W Pin on shield + +isr::isrState __isr_txState; // TX ISR state +isr::isrState __isr_rxState; // RX ISR state + + +void SetISRMode ( isr::isrMode ); + + +DMX_FrameBuffer::DMX_FrameBuffer ( uint16_t buffer_size ) +{ + m_refcount = (uint8_t*) malloc ( sizeof ( uint8_t ) ); + + if ( buffer_size >= DMX_MIN_FRAMESIZE && buffer_size <= DMX_MAX_FRAMESIZE ) + { + m_buffer = (uint8_t*) malloc ( buffer_size ); + if ( m_buffer != NULL ) + { + memset ( (void *)m_buffer, 0x0, buffer_size ); + m_bufferSize = buffer_size; + } + else + m_buffer = 0x0; + } + else + m_bufferSize = 0x0; + + *m_refcount++; +} + +DMX_FrameBuffer::DMX_FrameBuffer ( DMX_FrameBuffer &buffer ) +{ + // Copy references and make sure the parent object does not dispose our + // buffer when deleted and we are still active + this->m_refcount = buffer.m_refcount; + (*this->m_refcount)++; + + this->m_buffer = buffer.m_buffer; + this->m_bufferSize = buffer.m_bufferSize; +} + +DMX_FrameBuffer::~DMX_FrameBuffer ( void ) +{ + // If we are the last object using the + // allocated buffer then free it together + // with the refcounter + if ( --(*m_refcount) == 0 ) + { + if ( m_buffer ) + free ( m_buffer ); + + free ( m_refcount ); + } +} + +uint16_t DMX_FrameBuffer::getBufferSize ( void ) +{ + return m_bufferSize; +} + + +uint8_t DMX_FrameBuffer::getSlotValue ( uint16_t index ) +{ + if (index < m_bufferSize) + return m_buffer[index]; + else + return 0x0; +} + + +void DMX_FrameBuffer::setSlotValue ( uint16_t index, uint8_t value ) +{ + if ( index < m_bufferSize ) + m_buffer[index] = value; +} + + +void DMX_FrameBuffer::setSlotRange ( uint16_t start, uint16_t end, uint8_t value ) +{ + if ( start < m_bufferSize && end < m_bufferSize && start < end ) + memset ( (void *) &m_buffer[start], value, end-start+1 ); +} + +void DMX_FrameBuffer::clear ( void ) +{ + memset ( (void *) m_buffer, 0x0, m_bufferSize ); +} + +uint8_t &DMX_FrameBuffer::operator[] ( uint16_t index ) +{ + return m_buffer[index]; +} + + +DMX_Master::DMX_Master ( DMX_FrameBuffer &buffer, int readEnablePin ) +: m_frameBuffer ( buffer ), + m_autoBreak ( 1 ) // Autobreak generation is default on +{ + setStartCode ( DMX_START_CODE ); + + __re_pin = readEnablePin; + pinMode ( __re_pin, OUTPUT ); + + ::SetISRMode ( isr::Disabled ); +} + +DMX_Master::DMX_Master ( uint16_t maxChannel, int readEnablePin ) +: m_frameBuffer ( maxChannel + DMX_STARTCODE_SIZE ), + m_autoBreak ( 1 ) // Autobreak generation is default on +{ + setStartCode ( DMX_START_CODE ); + + __re_pin = readEnablePin; + pinMode ( __re_pin, OUTPUT ); + + ::SetISRMode ( isr::Disabled ); +} + +DMX_Master::~DMX_Master ( void ) +{ + disable (); // Stop sending + __dmx_master = NULL; +} + +DMX_FrameBuffer &DMX_Master::getBuffer ( void ) +{ + return m_frameBuffer; // Return reference to frame buffer +} + +void DMX_Master::setStartCode ( uint8_t value ) +{ + m_frameBuffer[0] = value; // Set the first byte in our frame buffer +} + +void DMX_Master::setChannelValue ( uint16_t channel, uint8_t value ) +{ + if ( channel > 0 ) // Prevent overwriting the start code + m_frameBuffer.setSlotValue ( channel, value ); +} + +void DMX_Master::setChannelRange ( uint16_t start, uint16_t end, uint8_t value ) +{ + if ( start > 0 ) // Prevent overwriting the start code + m_frameBuffer.setSlotRange ( start, end, value ); +} + + +void DMX_Master::enable ( void ) +{ + __dmx_master = this; + + if ( m_autoBreak ) + ::SetISRMode ( isr::DMXTransmit ); + else + ::SetISRMode ( isr::DMXTransmitManual ); +} + +void DMX_Master::disable ( void ) +{ + ::SetISRMode ( isr::Disabled ); + __dmx_master = NULL; // No active master +} + +void DMX_Master::setAutoBreakMode ( void ) { m_autoBreak = 1; } +void DMX_Master::setManualBreakMode ( void ) { m_autoBreak = 0; } +uint8_t DMX_Master::autoBreakEnabled ( void ) { return m_autoBreak; } + + +uint8_t DMX_Master::waitingBreak ( void ) +{ + return ( __isr_txState == isr::DmxBreakManual ); +} + +void DMX_Master::breakAndContinue ( uint8_t breakLength_us ) +{ + // Only execute if we are the controlling master object + if ( __dmx_master == this && __isr_txState == isr::DmxBreakManual ) + { + pinMode ( TX_PIN, OUTPUT ); + digitalWrite ( TX_PIN, LOW ); // Begin BREAK + + for (uint8_t bl=0; bl(*this); +} + + uint8_t DMX_Slave::getChannelValue ( uint16_t channel ) +{ + return getSlotValue ( channel ); +} + + +uint16_t DMX_Slave::getStartAddress ( void ) +{ + return m_startAddress; +} + +void DMX_Slave::setStartAddress ( uint16_t addr ) +{ + m_startAddress = addr; +} + +void DMX_Slave::onReceiveComplete ( void (*func)(unsigned short) ) +{ + event_onFrameReceived = func; +} + + +bool DMX_Slave::processIncoming ( uint8_t val, bool first ) +{ + static uint16_t idx; + bool rval = false; + + if ( first ) + { + // We could have received less channels then we + // expected.. but still is a complete frame + if (m_state == dmx::dmxData && event_onFrameReceived) + event_onFrameReceived (idx); + + m_state = dmx::dmxStartByte; + } + + switch ( m_state ) + { + case dmx::dmxStartByte: + setSlotValue ( 0, val ); // Store start code + idx = m_startAddress; + m_state = dmx::dmxWaitStartAddress; + + case dmx::dmxWaitStartAddress: + if ( --idx == 0 ) + m_state = dmx::dmxData; + break; + + case dmx::dmxData: + if ( idx++ < getBufferSize() ) + setSlotValue ( idx, val ); + else + { + m_state = dmx::dmxFrameReady; + + // If a onFrameReceived callback is register... + if (event_onFrameReceived) + event_onFrameReceived (idx-2); + + rval = true; + } + break; + } + + return rval; +} + + +uint16_t RDM_FrameBuffer::getBufferSize ( void ) { return sizeof ( m_msg ); } + +uint8_t RDM_FrameBuffer::getSlotValue ( uint16_t index ) +{ + if ( index < sizeof ( m_msg ) ) + return m_msg.d[index]; + else + return 0x0; +} + + +void RDM_FrameBuffer::setSlotValue ( uint16_t index, uint8_t value ) +{ + if ( index < sizeof ( m_msg ) ) + m_msg.d[index] = value; +} + +void RDM_FrameBuffer::clear ( void ) +{ + memset ( (void*)m_msg.d, 0x0, sizeof( m_msg ) ); + m_state = rdm::rdmUnknown; +} + +bool RDM_FrameBuffer::processIncoming ( uint8_t val, bool first ) +{ + static uint16_t idx; + bool rval = false; + + if ( first ) + { + m_state = rdm::rdmStartByte; + m_csRecv.checksum = (uint16_t) 0x0000; + idx = 0; + } + + // Prevent buffer overflow for large messages + if (idx >= sizeof(m_msg)) + return true; + + switch ( m_state ) + { + case rdm::rdmStartByte: + m_msg.startCode = val; + m_state = rdm::rdmSubStartCode; + break; + + case rdm::rdmSubStartCode: + if ( val != 0x01 ) + { + rval = true; // Stop processing data + break; + } + + m_msg.subStartCode = val; + m_state = rdm::rdmMessageLength; + break; + + case rdm::rdmMessageLength: + m_msg.msgLength = val; + m_state = rdm::rdmData; + m_csRecv.checksum = 0xcc + 0x01 + val; // set initial checksum + idx = 3; // buffer index for next byte + break; + + case rdm::rdmData: + m_msg.d[idx++] = val; + m_csRecv.checksum += val; + if ( idx >= m_msg.msgLength ) + m_state = rdm::rdmChecksumHigh; + break; + + case rdm::rdmChecksumHigh: + m_csRecv.csh = val; + m_state = rdm::rdmChecksumLow; + + break; + + case rdm::rdmChecksumLow: + m_csRecv.csl = val; + + if ((m_csRecv.checksum % (uint16_t)0x10000) == m_csRecv.checksum) + { + m_state = rdm::rdmFrameReady; + + // valid checksum ... start processing + processFrame (); + } + + m_state = rdm::rdmUnknown; + rval = true; + break; + }; + + return rval; +} + +bool RDM_FrameBuffer::fetchOutgoing ( volatile uint8_t *udr, bool first ) +{ + static uint16_t idx; + static uint16_t cs; + bool rval = false; + + + if ( first ) + { + m_state = rdm::rdmData; + cs = 0x0; + idx = 0; + } + + switch ( m_state ) + { + case rdm::rdmData: + cs += m_msg.d[idx]; + *udr = m_msg.d[idx++]; + if ( idx >= m_msg.msgLength ) + { + m_state = rdm::rdmChecksumHigh; + } + break; + + case rdm::rdmChecksumHigh: + *udr = (cs >> 8); + m_state = rdm::rdmChecksumLow; + break; + + case rdm::rdmChecksumLow: + *udr = (cs & 0xff); + m_state = rdm::rdmUnknown; + rval = true; + break; + + } + + return rval; +} + + +void (*RDM_Responder::event_onIdentifyDevice)(bool); +void (*RDM_Responder::event_onDeviceLabelChanged)(const char*, uint8_t); +void (*RDM_Responder::event_onDMXStartAddressChanged)(uint16_t); +void (*RDM_Responder::event_onDMXPersonalityChanged)(uint8_t); + +// +// slave parameter is only used to ensure a slave object is present before +// initializing the rdm responder class +// +RDM_Responder::RDM_Responder ( uint16_t m, uint8_t d1, uint8_t d2, + uint8_t d3, uint8_t d4, DMX_Slave &slave ) +: RDM_FrameBuffer ( ), + m_Personalities (1), // Available personlities + m_Personality (1) // Default personality eq 1. +{ + __rdm_responder = this; + m_devid.Initialize ( m, d1, d2, d3, d4 ); + + // Default software version id = 0x00000000 + memset ( (void*)m_SoftwareVersionId, 0x0, 0x4 ); + + // Rdm responder is disabled by default + m_rdmStatus.enabled = false; +} + +RDM_Responder::~RDM_Responder ( void ) +{ + __rdm_responder = NULL; +} + +void RDM_Responder::onIdentifyDevice ( void (*func)(bool) ) +{ + event_onIdentifyDevice = func; +} + +void RDM_Responder::onDeviceLabelChanged ( void (*func) (const char*, uint8_t) ) +{ + event_onDeviceLabelChanged = func; +} + +void RDM_Responder::onDMXStartAddressChanged ( void (*func) (uint16_t) ) +{ + event_onDMXStartAddressChanged = func; +} + +void RDM_Responder::onDMXPersonalityChanged ( void (*func) (uint8_t) ) +{ + event_onDMXPersonalityChanged = func; +} + +void RDM_Responder::setDeviceLabel ( const char *label, size_t len ) +{ + if ( len > RDM_MAX_DEVICELABEL_LENGTH ) + len = RDM_MAX_DEVICELABEL_LENGTH; + + memcpy ( (void *)m_deviceLabel, (void *)label, len ); +} + +#define UID_0 0x12 //ESTA device ID +#define UID_1 0x34 +#define UID_2 0x56 +#define UID_3 0x88 +#define UID_4 0x00 +#define UID_5 0x00 + +#define UID_CS (0xFF *6 +UID_0 +UID_1 +UID_2 +UID_3 +UID_4 +UID_5) + +void RDM_Responder::repondDiscUniqueBranch ( void ) +{ + #if defined(UCSRB) + UCSRB = (1<>8) | 0xaa; + response [21] = (cs>>8) | 0x55; + response [22] = (cs&0xff) | 0xaa; + response [23] = (cs&0xff) | 0x55; + + + // Table 3-2 ANSI_E1-20-2010 <2ms + _delay_us ( MIN_RESPONDER_PACKET_SPACING_USEC ); + + // Fix: 2017, Feb 28: Moved data enable down in order to limit line in marking state time to comply with + // section 3.2.3 + // Set shield to transmit mode (turn arround) + digitalWrite ( __re_pin, HIGH ); + + + for ( int i=0; i<24; i++ ) + { + // Wait until data register is empty + #if defined (UCSR0A) && defined (UDRE0) + while((UCSR0A & (1 <(m_msg.PD); + + pd->protocolVersionMajor = 0x01; + pd->protocolVersionMinor = 0x00; + pd->deviceModelId = BSWAP_16(m_DeviceModelId); + pd->ProductCategory = BSWAP_16(m_ProductCategory); + memcpy ( (void*)pd->SoftwareVersionId, (void*)m_SoftwareVersionId, 4 ); + pd->DMX512FootPrint = BSWAP_16(__dmx_slave->getBufferSize()-1); // eq buffersize-startbyte + pd->DMX512CurrentPersonality = m_Personality; + pd->DMX512NumberPersonalities = m_Personalities; + pd->DMX512StartAddress = BSWAP_16(__dmx_slave->getStartAddress()); + + pd->SubDeviceCount = 0x0; // Sub devices are not supported by this library + pd->SensorCount = 0x0; // Sensors are not yet supported + + m_msg.PDL = sizeof (RDM__DeviceInfoPD); +} + +const uint8_t ManufacturerLabel_P[] PROGMEM = "Conceptinetics"; + +void RDM_Responder::processFrame ( void ) +{ + // If packet is a general broadcast + if ( + m_msg.dstUid.isBroadcast (m_devid.m_id) || + m_devid == m_msg.dstUid + ) + { + // Set default response type + m_msg.portId = rdm::ResponseTypeAck; + + switch ( BSWAP_16(m_msg.PID) ) + { + case rdm::DiscUniqueBranch: + // Check if we are inside the given unique branch... + if ( !m_rdmStatus.mute && + reinterpret_cast(m_msg.PD)->lbound < m_devid && + reinterpret_cast(m_msg.PD)->hbound > m_devid ) + { + // Discovery messages are responded with data only and no breaks + repondDiscUniqueBranch (); + } + break; + + case rdm::DiscMute: + reinterpret_cast(m_msg.PD)->ctrlField = 0x0; + m_msg.PDL = sizeof ( RDM_DiscMuteUnMutePD ); + m_rdmStatus.mute = true; + break; + + case rdm::DiscUnMute: + reinterpret_cast(m_msg.PD)->ctrlField = 0x0; + m_msg.PDL = sizeof ( RDM_DiscMuteUnMutePD ); + m_rdmStatus.mute = false; + break; + + case rdm::SupportedParameters: + // + // Temporary solution... this will become dynamic + // in a later version... + // + m_msg.PD[0] = HIGHBYTE(rdm::DmxStartAddress); // MSB + m_msg.PD[1] = LOWBYTE (rdm::DmxStartAddress); // LSB + + m_msg.PD[2] = HIGHBYTE(rdm::DmxPersonality); + m_msg.PD[3] = LOWBYTE (rdm::DmxPersonality); + + m_msg.PD[4] = HIGHBYTE(rdm::ManufacturerLabel); + m_msg.PD[5] = LOWBYTE (rdm::ManufacturerLabel); + + m_msg.PD[6] = HIGHBYTE(rdm::DeviceLabel); + m_msg.PD[7] = LOWBYTE (rdm::DeviceLabel); + + m_msg.PDL = 0x6; + break; + + // Only for manufacturer specific parameters + // case rdm::ParameterDescription: + // break; + + case rdm::DeviceInfo: + if ( m_msg.CC == rdm::GetCommand ) + populateDeviceInfo (); + break; + + case rdm::DmxStartAddress: + if ( m_msg.CC == rdm::GetCommand ) + { + m_msg.PD[0] = HIGHBYTE(__dmx_slave->getStartAddress ()); + m_msg.PD[1] = LOWBYTE (__dmx_slave->getStartAddress ()); + m_msg.PDL = 0x2; + } + else // if ( m_msg.CC == rdm::SetCommand ) + { + __dmx_slave->setStartAddress ( (m_msg.PD[0] << 8) + m_msg.PD[1] ); + m_msg.PDL = 0x0; + + if ( event_onDMXStartAddressChanged ) + event_onDMXStartAddressChanged ( (m_msg.PD[0] << 8) + m_msg.PD[1] ); + } + break; + + case rdm::DmxPersonality: + if ( m_msg.CC == rdm::GetCommand ) + { + reinterpret_cast + (m_msg.PD)->DMX512CurrentPersonality = m_Personality; + reinterpret_cast + (m_msg.PD)->DMX512CurrentPersonality = m_Personalities; + m_msg.PDL = sizeof (RDM_DeviceGetPersonality_PD); + } + else // if ( m_msg.CC == rdm::SetCommand ) + { + m_Personality = reinterpret_cast + (m_msg.PD)->DMX512Personality; + m_msg.PDL = 0x0; + + if ( event_onDMXPersonalityChanged ) + event_onDMXPersonalityChanged ( m_Personality ); + } + break; + + case rdm::IdentifyDevice: + if ( m_msg.CC == rdm::GetCommand ) + { + m_msg.PD[0] = (uint8_t)(m_rdmStatus.ident ? 1 : 0); + m_msg.PDL = 0x1; + } + else if ( m_msg.CC == rdm::SetCommand ) + { + // Look into first byte to see whether identification + // is turned on or off + m_rdmStatus.ident = m_msg.PD[0] ? true : false; + if ( event_onIdentifyDevice ) + event_onIdentifyDevice ( m_rdmStatus.ident ); + + m_msg.PDL = 0x0; + } + break; + + case rdm::ManufacturerLabel: + if ( m_msg.CC == rdm::GetCommand ) + { + memcpy_P( (void*)m_msg.PD, ManufacturerLabel_P, sizeof(ManufacturerLabel_P) ); + m_msg.PDL = sizeof ( ManufacturerLabel_P ); + } + break; + + case rdm::DeviceLabel: + if ( m_msg.CC == rdm::GetCommand ) + { + memcpy ( m_msg.PD, (void*) m_deviceLabel, 32 ); + m_msg.PDL = 32; + } + else if ( m_msg.CC == rdm::SetCommand ) + { + memset ( (void*) m_deviceLabel, ' ', 32 ); + memcpy ( (void*) m_deviceLabel, m_msg.PD, (m_msg.PDL < 32 ? m_msg.PDL : 32) ); + m_msg.PDL = 0; + + // Notify application + if ( event_onDeviceLabelChanged ) + event_onDeviceLabelChanged ( m_deviceLabel, 32 ); + } + break; + + + default: + // Unknown parameter ID response + m_msg.portId = rdm::ResponseTypeNackReason; + m_msg.PD[0] = rdm::UnknownPid; + m_msg.PD[1] = 0x0; + m_msg.PDL = 0x2; + break; + }; + } + + // + // Only respond if this this message + // was destined to us only + if ( m_msg.dstUid == m_devid ) + { + m_msg.startCode = RDM_START_CODE; + m_msg.subStartCode = 0x01; + m_msg.msgLength = RDM_HDR_LEN + m_msg.PDL; + m_msg.msgCount = 0; + + /* + switch ( m_msg.msg.CC ) + { + case rdm::DiscoveryCommand: + m_msg.msg.CC = rdm::DiscoveryCommandResponse; + break; + case rdm::GetCommand: + m_msg.msg.CC = rdm::GetCommandResponse; + break; + case rdm::SetCommand: + m_msg.msg.CC = rdm::SetCommandResponse; + break; + } + */ + /* Above replaced by next line */ + m_msg.CC++; + + m_msg.dstUid.copy ( m_msg.srcUid ); + m_msg.srcUid.copy ( m_devid ); + + //_delay_us ( MIN_RESPONDER_PACKET_SPACING_USEC ); + SetISRMode ( isr::RDMTransmit ); + + } +} + + +void SetISRMode ( isr::isrMode mode ) +{ + uint8_t readEnable; + +#if defined(USE_DMX_SERIAL_0) + #if defined(UCSRB) && defined (UCSRC) + UCSRC |= (1<>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + + // Prepare before kicking off ISR + //DMX_UDR = 0x0; + __isr_rxState = isr::Idle; + readEnable = LOW; + DMX_UCSRB = (1<>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + DMX_UDR = 0x0; + DMX_UCSRB = 0x0; + readEnable = HIGH; + __isr_txState = isr::DmxBreakManual; + break; + + case isr::RDMTransmit: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + //DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + //DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + DMX_UCSRB = (1< -1) + digitalWrite ( __re_pin, readEnable ); + +} + +// +// TX UART (DMX Transmission ISR) +// +ISR (USART_TX) +{ + static uint16_t current_slot; + + switch ( __isr_txState ) + { + case isr::DmxBreak: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + if ( __isr_txState == isr::DmxBreak ) + __isr_txState = isr::DmxStartByte; + + break; + + case isr::DmxStartByte: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + current_slot = 0; + DMX_UDR = __dmx_master->getBuffer()[ current_slot++ ]; + __isr_txState = isr::DmxTransmitData; + break; + + + case isr::DmxTransmitData: + // NOTE: we always send full frames of 513 bytes, this will bring us + // close to 40 frames / sec with no interslot delays + #ifdef DMX_IBG + _delay_us (DMX_IBG); + #endif + + DMX_UDR = __dmx_master->getBuffer().getSlotValue( current_slot++ ); + + // Send 512 channels + if ( current_slot >= DMX_MAX_FRAMESIZE ) + { + if ( __dmx_master->autoBreakEnabled () ) + __isr_txState = isr::DmxBreak; + else + SetISRMode ( isr::DMXTransmitManual ); + } + + break; + +/* case isr::RdmBreak: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + __isr_txState = isr::RdmStartByte; + + break; +*/ + + case isr::RdmStartByte: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + + // Write start byte + __rdm_responder->fetchOutgoing ( &DMX_UDR, true ); + __isr_txState = isr::RdmTransmitData; + + break; + + case isr::RdmTransmitData: + // Write rest of data + if ( __rdm_responder->fetchOutgoing ( &DMX_UDR ) ) + __isr_txState = isr::RDMTransmitComplete; + break; + + case isr::RDMTransmitComplete: + SetISRMode ( isr::Receive ); // Start waitin for new data + __isr_txState = isr::Idle; // No tx state + break; + + } +} + + + +// +// RX UART (DMX Reception ISR) +// +ISR (USART_RX) +{ + uint8_t usart_state = DMX_UCSRA; + uint8_t usart_data = DMX_UDR; + + // + // Check for framing error and reset if found + // A framing most likely* indicate a break in our ocasion + // + if ( usart_state & (1<processIncoming ( usart_data, true ); + __isr_rxState = isr::DmxRecordData; + } + else if ( __rdm_responder && + usart_data == RDM_START_CODE && + __rdm_responder->m_rdmStatus.enabled ) + { + // __rdm_responder->clear (); + __rdm_responder->processIncoming ( usart_data, true ); + __isr_rxState = isr::RdmRecordData; + } + else + { + __isr_rxState = isr::Idle; + } + break; + + // Process DMX Data + case isr::DmxRecordData: + if ( __dmx_slave->processIncoming ( usart_data ) ) + __isr_rxState = isr::Idle; + break; + + // Process RDM Data + case isr::RdmRecordData: + if ( __rdm_responder->processIncoming ( usart_data ) ) + __isr_rxState = isr::Idle; + break; + + } + +} + diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/Conceptinetics.h b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/Conceptinetics.h new file mode 100644 index 000000000..0f03da619 --- /dev/null +++ b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/Conceptinetics.h @@ -0,0 +1,383 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Conceptinetics.h - DMX library for Arduino + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + This code has been tested using the following hardware: + + - Arduino / Genuino UNO R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino / Genuino MEGA2560 R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino / Genuino Leonardo using a CTC-DRA-13-R2 ISOLATED DMX-RDM SHIELD + + - CTC-DRA-10-1 and CTC-DRA-10-R2 is the Non-isolated costs effective DMX-RDM shield +*/ + + +#ifndef CONCEPTINETICS_H_ +#define CONCEPTINETICS_H_ + +#include +#include + +#include "Rdm_Uid.h" +#include "Rdm_Defines.h" + +#define DMX_MAX_FRAMESIZE 513 // Startbyte + 512 Slots +#define DMX_MIN_FRAMESIZE 2 // Startbyte + 1 Slot + +#define DMX_MAX_FRAMECHANNELS 512 // Maxmim number of channer per frame + +#define DMX_STARTCODE_SIZE 1 // Size of startcode in bytes + +#define DMX_START_CODE 0x0 // Start code for a DMX frame +#define RDM_START_CODE 0xcc // Start code for a RDM frame + +// Uncomment to enable Inter slot delay ) (avg < 76uSec) ... +// mimum is zero according to specification +// #define DMX_IBG 10 // Inter slot time + +// Speed your Arduino is running on in Hz. +#define F_OSC 16000000UL + +// DMX Baudrate, this should be 250000 +#define DMX_BAUD_RATE 250000 + +// The baudrate used to automaticly generate a break within +// your ISR.. make it lower to generate longer breaks +//#define DMX_BREAK_RATE 99900 + +// 2017, Feb 28: Set to appox 176us +#define DMX_BREAK_RATE 49950 + +// Tabel 3-2 ANSI_E1-20-2010 +// Minimum time to allow the datalink to 'turn arround' +#define MIN_RESPONDER_PACKET_SPACING_USEC 176 /*176*/ + +// Define which serial port to use as DMX port, only one can be +// selected at the time by uncommenting one of the following +// lines +#define USE_DMX_SERIAL_0 +//#define USE_DMX_SERIAL_1 +//#define USE_DMX_SERIAL_2 +//#define USE_DMX_SERIAL_3 + +namespace dmx +{ + enum dmxState + { + dmxUnknown, + dmxStartByte, + dmxWaitStartAddress, + dmxData, + dmxFrameReady, + }; +}; + +namespace rdm +{ + enum rdmState + { + rdmUnknown, + rdmStartByte, + rdmSubStartCode, + rdmMessageLength, + rdmData, + rdmChecksumHigh, + rdmChecksumLow, + rdmFrameReady, + }; +}; + +struct IFrameBuffer +{ + virtual uint16_t getBufferSize ( void ) = 0; + + virtual uint8_t getSlotValue ( uint16_t index ) = 0; + virtual void setSlotValue ( uint16_t index, uint8_t value ) = 0; +}; + +class DMX_FrameBuffer : IFrameBuffer +{ + public: + // + // Constructor buffersize = 1-513 + // + DMX_FrameBuffer ( uint16_t buffer_size ); + DMX_FrameBuffer ( DMX_FrameBuffer &buffer ); + ~DMX_FrameBuffer ( void ); + + uint16_t getBufferSize ( void ); + + uint8_t getSlotValue ( uint16_t index ); + void setSlotValue ( uint16_t index, uint8_t value ); + void setSlotRange ( uint16_t start, uint16_t end, uint8_t value ); + void clear ( void ); + + uint8_t &operator[] ( uint16_t index ); + + private: + + uint8_t *m_refcount; + uint16_t m_bufferSize; + uint8_t *m_buffer; +}; + + +// +// DMX Master controller +// +class DMX_Master +{ + public: + // Run the DMX master from a pre allocated frame buffer which + // you have fully under your own control + DMX_Master ( DMX_FrameBuffer &buffer, int readEnablePin ); + + // Run the DMX master by giving a predefined maximum number of + // channels to support + DMX_Master ( uint16_t maxChannel, int readEnablePin ); + + ~DMX_Master ( void ); + + void enable ( void ); // Start transmitting + void disable ( void ); // Stop transmitting + + // Get reference to the internal framebuffer + DMX_FrameBuffer &getBuffer ( void ); + + // Update channel values + void setChannelValue ( uint16_t channel, uint8_t value ); + void setChannelRange ( uint16_t start, uint16_t end, uint8_t value ); + + public: + // + // Manual control over the break period + // + void setAutoBreakMode ( void ); // Generated from ISR + void setManualBreakMode ( void ); // Generate manually + + uint8_t autoBreakEnabled ( void ); + + // We are waiting for a manual break to be generated + uint8_t waitingBreak ( void ); + + // Generate break and start transmission of frame + void breakAndContinue ( uint8_t breakLength_us = 100 ); + + + protected: + void setStartCode ( uint8_t value ); + + + private: + DMX_FrameBuffer m_frameBuffer; + uint8_t m_autoBreak; +}; + + +// +// DMX Slave controller +// +class DMX_Slave : public DMX_FrameBuffer +{ + public: + DMX_Slave ( DMX_FrameBuffer &buffer, int readEnablePin = -1 ); + + // nrChannels is the consecutive DMX512 slots required + // to operate this slave device + DMX_Slave ( uint16_t nrChannels, int readEnablePin = -1 ); + + ~DMX_Slave ( void ); + + void enable ( void ); // Enable receiver + void disable ( void ); // Disable receiver + + + // Get reference to the internal framebuffer + DMX_FrameBuffer &getBuffer ( void ); + + uint8_t getChannelValue ( uint16_t channel ); + + uint16_t getStartAddress ( void ); + void setStartAddress ( uint16_t ); + + + // Process incoming byte from USART + bool processIncoming ( uint8_t val, bool first = false ); + + // Register on receive complete callback in case + // of time critical applications + void onReceiveComplete ( void (*func)(unsigned short) ); + + protected: + + + private: + uint16_t m_startAddress; // Slave start address + dmx::dmxState m_state; + + static void (*event_onFrameReceived)(unsigned short channelsReceived); +}; + + +class RDM_FrameBuffer : public IFrameBuffer +{ + public: + // + // Constructor + // + RDM_FrameBuffer ( void ) {}; + ~RDM_FrameBuffer ( void ) {}; + + uint16_t getBufferSize ( void ); + + uint8_t getSlotValue ( uint16_t index ); + void setSlotValue ( uint16_t index, uint8_t value ); + void clear ( void ); + + uint8_t &operator[] ( uint16_t index ); + + public: // functions to provide access from USART + // Process incoming byte from USART, + // returns false when no more data is accepted + bool processIncoming ( uint8_t val, bool first = false ); + + // Process outgoing byte to USART + // returns false when no more data is available + bool fetchOutgoing ( volatile uint8_t *udr, bool first = false ); + + protected: + // Process received frame + virtual void processFrame ( void ) = 0; + + //private: + protected: + rdm::rdmState m_state; // State for pushing the message in + RDM_Message m_msg; + RDM_Checksum m_csRecv; // Checksum received in rdm message +}; + +// +// RDM_Responder +// +class RDM_Responder : public RDM_FrameBuffer +{ + public: + // + // m = manufacturer id (16bits) + // d1-d4 = device id (32bits) + // + RDM_Responder ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4, DMX_Slave &slave); + ~RDM_Responder ( void ); + + void setDeviceInfo + ( + uint16_t deviceModelId, + rdm::RdmProductCategory productCategory, + uint8_t personalities = 1, + uint8_t personality = 1 + ) + { + m_DeviceModelId = deviceModelId; + m_ProductCategory = productCategory; + m_Personalities = personalities; + m_Personality = personality; + }; + + // + // Set vendor software version id + // + // v1 = MOST SIGNIFICANT + // v2... + // v3... + // v4 = LEAST SIGNIFICANT + // + void setSoftwareVersionId ( uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4 ) + { + m_SoftwareVersionId[0] = v1; + m_SoftwareVersionId[1] = v2; + m_SoftwareVersionId[2] = v3; + m_SoftwareVersionId[3] = v4; + } + + // Currently no sensors and subdevices supported + // void AddSensor ( void ); + // void AddSubDevice ( void ); + + uint8_t getPersonality ( void ) { return m_Personality; }; + void setPersonality ( uint8_t personality ) { m_Personality = personality; }; + + // Register on identify device event handler + void onIdentifyDevice ( void (*func)(bool) ); + void onDeviceLabelChanged ( void (*func) (const char*, uint8_t) ); + void onDMXStartAddressChanged ( void (*func) (uint16_t) ); + void onDMXPersonalityChanged ( void (*func) (uint8_t) ); + + + // Set the device label + void setDeviceLabel ( const char *label, size_t len ); + + // Enable, Disable rdm responder + void enable ( void ) { m_rdmStatus.enabled = true; m_rdmStatus.mute = false; }; + void disable ( void ) { m_rdmStatus.enabled = false; }; + + union + { + uint8_t raw; + struct + { + uint8_t mute:1; + uint8_t ident:1; + uint8_t enabled:1; // Rdm responder enable/disable + }; + } m_rdmStatus; + + + protected: + virtual void processFrame ( void ); + + // Discovery to unque brach packets only requires + // the data part of the packet to be transmitted + // without breaks or header + void repondDiscUniqueBranch ( void ); + + // Helpers for generating response packets which + // have larger datafields + void populateDeviceInfo ( void ); + + private: + RDM_Uid m_devid; // Holds our unique device ID + uint8_t m_Personalities; // The total number of supported personalities + uint8_t m_Personality; // The currently active personality + uint16_t m_DeviceModelId; + uint8_t m_SoftwareVersionId[4]; // 32 bit Software version + rdm::RdmProductCategory m_ProductCategory; + + char m_deviceLabel[32]; // Device label + + static void (*event_onIdentifyDevice)(bool); + static void (*event_onDeviceLabelChanged)(const char*, uint8_t); + static void (*event_onDMXStartAddressChanged)(uint16_t); + static void (*event_onDMXPersonalityChanged)(uint8_t); +}; + + +#endif /* CONCEPTINETICS_H_ */ diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/DMX_Master_Manual_Break.ino b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/DMX_Master_Manual_Break.ino index 6d80a78a3..cb51afb53 100644 --- a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/DMX_Master_Manual_Break.ino +++ b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/DMX_Master_Manual_Break.ino @@ -21,7 +21,7 @@ */ -#include +#include "Conceptinetics.h" // // When configuring a DMX_Master it will normally automaticly diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/Rdm_Defines.h b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/Rdm_Defines.h new file mode 100644 index 000000000..0accca63d --- /dev/null +++ b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/Rdm_Defines.h @@ -0,0 +1,315 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Rdm_Defines.h - DMX library for Arduino with RDM (Remote Device Management) support + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef RDM_DEFINES_H_ +#define RDM_DEFINES_H_ + +#include "Rdm_Uid.h" + +#define RDM_MAX_DEVICELABEL_LENGTH 32 + +namespace rdm +{ + enum RdmCommandClass + { + DiscoveryCommand = 0x10, + DiscoveryCommandResponse, + GetCommand = 0x20, + GetCommandResponse, + SetCommand = 0x30, + SetCommandResponse, + }; + + enum RdmResponseTypes + { + ResponseTypeAck = 0x00, + ResponseTypeAckTimer, + ResponseTypeNackReason, + ResponseTypeAckOverflow, // Additional response data available (see spec) + }; + + enum RdmParameters + { + // Category - Network Management + DiscUniqueBranch = 0x0001, // Required + DiscMute = 0x0002, // Required + DiscUnMute = 0x0003, // Required + + CommsStatus = 0x0015, // Get,Set + + // Category - Status Collection + QueuedMessage = 0x0020, // Get [enum RdmStatusTypes] + StatusMessages = 0x0030, // Get [enum RdmStatusTypes] + StatusIdDescription = 0x0031, // Get + ClearStatusId = 0x0032, // Set + SubDeviceStatusReportThreshold = 0x0033, // Get, Set [enum RdmStatusTypes] + + // Category - RDM Information + // ** Only required if supporting parameters + // beyond the minimum required set + SupportedParameters = 0x0005, // Get, **Required + ParameterDescription = 0x0051, // Get, **Required + + // Category = Product Information + DeviceInfo = 0x0060, // Get, Required + ProductDetailIdList = 0x0070, // Get + DeviceModelDescription = 0x0080, // Get + ManufacturerLabel = 0x0081, // Get + DeviceLabel = 0x0082, // Get, Set + FactoryDefaults = 0x0009, // Get, Set ** + SoftwareVersionLabel = 0x000c, // Get + + // Category - DMX512 Setup + DmxPersonality = 0x00e0, // Get, Set + DmxPersonalityDescription = 0x00e1, // Get + DmxStartAddress = 0x00f0, // Get, Set ** Required if DMX device + SlotInfo = 0x0120, // Get + SlotDescription = 0x0121, // Get + DefaultSlotValue = 0x0122, // Get + + // Category - Sensors + // Category - Dimmer Settings + // Category - Power/Lamp Settings + // Category - Display Settings + // Category - Configuration + + // Category - Control + IdentifyDevice = 0x1000, // Get, Set, Required + ResetDevice = 0x1001, // Set + PowerState = 0x1010, // Get, Set + PerformSelftest = 0x1020, // Get, Set + SelfTestDescription = 0x1021, // Get + }; + + + enum RdmStatusTypes + { + StatusNone = 0x00, + StatusGetLastMessage, + StatusAdvisory, + StatusWarning, + StatusError, + StatusAdvisoryCleared = 0x12, + StatusWarningCleared, + StatusErrorCleared, + }; + + enum RdmProductCategory + { + CategoryNotDeclared = 0x0000, + + // Fixtures - intended as source for illumination + CategoryFixture = 0x0100, + CategoryFixtureFixed = 0x0101, + CategoryFixtureMovingYoke = 0x0102, + CategoryFixtureMovingMirror = 0x0103, + CategoryFixtureOther = 0x01ff, + + // Fixture Accessories - add-ons to fixtures or projectors + CategoryFixtureAccessory = 0x0200, + CategoryFixtureAccessoryColor = 0x0201, + CategoryFixtureAccessoryYoke = 0x0202, + CategoryFixtureAccessoryMirror = 0x0203, + CategoryFixtureAccessoryEffect = 0x0204, + CategoryFixtureAccessoryBeam = 0x0205, + CategoryFixtureAccessoryOther = 0x02ff, + + // Projectors - Light source capable of producing + // realistic images from another media + CategoryProjector = 0x0300, + CategoryProjectorFixed = 0x0301, + CategoryProjectorMovingYoke = 0x0302, + CategoryProjectorMovingMirror = 0x0303, + CategoryProjectorOther = 0x03ff, + + // Atmospheric Effect - earth/wind/fire + CategoryAtmospheric = 0x0400, + CategoryAtmosphericEffect = 0x0401, // Fogger, Hazer, Flame + CategoryAtmosphericPyro = 0x0402, + CategoryAtmosphericOther = 0x04ff, + + // Insensity Control (Specifically dimming equipment) + CategoryDimmer = 0x0500, + CategoryDimmer_AC_Incandescent = 0x0501, + CategoryDimmer_AC_Fluorescent = 0x0502, + CategoryDimmer_AC_Coldcathode = 0x0503, + CategoryDimmer_AC_Nondim = 0x0504, + CategoryDimmer_AC_Elv = 0x0505, + CategoryDimmer_AC_Other = 0x0506, + CategoryDimmer_DC_Level = 0x0507, + CategoryDimmer_DC_PWM = 0x0508, + CategoryDimmer_CS_LED = 0x0509, + CategoryDimmer_Other = 0x05ff, + + // Power control (Other than dimming equipment) + CategoryPower = 0x0600, + CategoryPowerControl = 0x0601, + CategoryPowerSource = 0x0602, + CategoryPowerOther = 0x06ff, + + // Scenic Drive - Including motorized effects + // unrelated to light source + CategoryScenic = 0x0700, + CategoryScenicDrive = 0x0701, + CategoryScenicOther = 0x07ff, + + // DMX Infrastructure, conversion and interfaces + CategoryData = 0x0800, + CategoryDataDistribution = 0x0801, + CategoryDataConversion = 0x0802, + CategoryDataOther = 0x08ff, + + // Audio visual equipment + Category_AV = 0x0900, + Category_AV_Audio = 0x0901, + Category_AV_Video = 0x0902, + Category_AV_Other = 0x09ff, + + // Parameter monitoring equipment + CategoryMonitor = 0x0a00, + CategoryMonitorACLinePower = 0x0a01, + CategoryMonitorDCPower = 0x0a02, + CategoryMonitorEnvironmental = 0x0a03, + CategoryMonitorOther = 0x0aff, + + // Controllers, backup devices + CategoryControl = 0x7000, + CategoryControlController = 0x7001, + CategoryControlBackupdevice = 0x7002, + CategoryControlOther = 0x70ff, + + // Test equipment + CategoryTest = 0x7100, + CategoryTestEquipment = 0x7101, + CategoryTestEquipmentOther = 0x71ff, + + // Miscellaneous + CategoryOther = 0x7fff, + }; + + // + // Product details not yet supported in + // this library + // + enum RdmProductDetail + { + ProductDetailNotDeclared = 0x0000, + }; + + // Only LSB + enum RdmNackReasons + { + UnknownPid = 0x00, + FormatError, + HardwareFault, + ProxyReject, + WriteProtect, + UnsupportedCmdClass, + DataOutOfRange, + BufferFull, + PacketSizeUnsupported, + SubDeviceOutOfRange, + ProxyBufferFull + }; + +}; + + +#define RDM_HDR_LEN 24 // RDM Message header length ** fixed +#define RDM_PD_MAXLEN 32 // RDM Maximum parameter data length 1 - 231 + + +union RDM_Message +{ + uint8_t d[ RDM_HDR_LEN + RDM_PD_MAXLEN ]; + struct + { + uint8_t startCode; // 0 SC_RDM + uint8_t subStartCode; // 1 SC_SUB_MESSAGE + uint8_t msgLength; // 2 Range 24 - 255 + RDM_Uid dstUid; // 3-8 Destination UID + RDM_Uid srcUid; // 9-14 Source UID (sender) + uint8_t TN; // 15 Transaction number + uint8_t portId; // 16 Port ID / Response type + uint8_t msgCount; // 17 + uint16_t subDevice; // 18,19 0=root, 0xffff=all + uint8_t CC; // 20 GET_COMMAND + uint16_t PID; // 21,22 Parameter ID + uint8_t PDL; // 23 Parameter Data length 1-231 + + uint8_t PD[RDM_PD_MAXLEN]; // Parameter Data ... variable length + }; +}; + +union RDM_Checksum +{ + uint16_t checksum; + struct + { + uint8_t csl; + uint8_t csh; + }; +}; + +struct RDM_DiscUniqueBranchPD +{ + RDM_Uid lbound; + RDM_Uid hbound; +}; + +struct RDM_DiscMuteUnMutePD +{ + uint16_t ctrlField; + +// Only for multiple ports +// RDM_Uid bindingUid; +}; + +struct RDM__DeviceInfoPD +{ + uint8_t protocolVersionMajor; + uint8_t protocolVersionMinor; + uint16_t deviceModelId; + uint16_t ProductCategory; // enum RdmProductCategory + uint8_t SoftwareVersionId[4]; + uint16_t DMX512FootPrint; + uint8_t DMX512CurrentPersonality; + uint8_t DMX512NumberPersonalities; + uint16_t DMX512StartAddress; + uint16_t SubDeviceCount; + uint8_t SensorCount; +}; + +struct RDM_DeviceGetPersonality_PD +{ + uint8_t DMX512CurrentPersonality; + uint8_t DMX512NumberPersonalities; +}; + +struct RDM_DeviceSetPersonality_PD +{ + uint8_t DMX512Personality; +}; + + +#endif /* RDM_DEFINES_H_ */ diff --git a/DMX_NeoPixels/examples/DMX_Master_Manual_Break/Rdm_Uid.h b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/Rdm_Uid.h new file mode 100644 index 000000000..35c802c63 --- /dev/null +++ b/DMX_NeoPixels/examples/DMX_Master_Manual_Break/Rdm_Uid.h @@ -0,0 +1,101 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Rdm_Uid.h - DMX library for Arduino with RDM (Remote Device Management) support + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef RDM_UID_H_ +#define RDM_UID_H_ + +#include + +// +//48 bit UID Representation to identify RDM transponders +// +struct RDM_Uid { + + void Initialize ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4 ) + { + m_id[0] = ((uint8_t) (((uint16_t) (m)) >> 8)); + m_id[1] = (uint8_t)m; + m_id[2] = d1; + m_id[3] = d2; + m_id[4] = d3; + m_id[5] = d4; + } + + void copy ( const RDM_Uid &orig ) + { + for ( uint8_t i = 0; i < 6; i++ ) + m_id[i] = orig.m_id[i]; + } + + bool operator == ( const RDM_Uid & orig ) const + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != orig.m_id[i] ) + return false; + + return true; + } + + bool operator != ( const RDM_Uid & orig ) const + { + return !(*this == orig); + } + + bool operator < ( const RDM_Uid & v ) const + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != v.m_id[i] ) + return ( m_id[i] < v.m_id[i] ); + } + + bool operator > ( const RDM_Uid & v ) + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != v.m_id[i] ) + return ( m_id[i] > v.m_id[i] ); + } + + // + // match_mid = manufacturer id to match + // + bool isBroadcast ( uint8_t match_mid[2] ) + { + // Check for genuine broadcast on device part + for ( uint8_t i = 2; i < 6; i++ ) + if ( m_id[i] != 0xff ) + return false; + + // Broadcast or manufacturer designated broadcast + if ( (m_id[0] == 0xff && m_id[1] == 0xff) || + (m_id[0] == match_mid[0] && m_id[1] == match_mid[1]) ) + return true; + + // No broadcast + return false; + } + + uint8_t m_id[6]; //16bit manufacturer id + 32 bits device id +}; + + +#endif /* RDM_UID_H_ */ diff --git a/DMX_NeoPixels/examples/DMX_Slave/.cpb.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.cpb.test.skip deleted file mode 100644 index 064a28912..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.cpb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpb diff --git a/DMX_NeoPixels/examples/DMX_Slave/.cpc.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.cpc.test.skip deleted file mode 100644 index 79763353d..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.cpc.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpc diff --git a/DMX_NeoPixels/examples/DMX_Slave/.cpx_ada.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.cpx_ada.test.skip deleted file mode 100644 index d9c56cc11..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.cpx_ada.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpx_ada diff --git a/DMX_NeoPixels/examples/DMX_Slave/.esp32.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.esp32.test.skip deleted file mode 100644 index 5faeb5064..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.esp32.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for esp32 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.esp8266.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.esp8266.test.skip deleted file mode 100644 index 15eb13221..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.esp8266.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for esp8266 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.feather32u4.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.feather32u4.test.skip deleted file mode 100644 index eb9fd87a1..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.feather32u4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather32u4 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.feather_esp32c6.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.feather_esp32c6.test.skip deleted file mode 100644 index 563448c75..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.feather_esp32c6.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_esp32c6 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.feather_m0_express.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.feather_m0_express.test.skip deleted file mode 100644 index c1118c563..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.feather_m0_express.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_m0_express diff --git a/DMX_NeoPixels/examples/DMX_Slave/.feather_m4_express.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.feather_m4_express.test.skip deleted file mode 100644 index 9b961626f..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.feather_m4_express.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_m4_express diff --git a/DMX_NeoPixels/examples/DMX_Slave/.feather_rp2040.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.feather_rp2040.test.skip deleted file mode 100644 index 90aa322a7..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.feather_rp2040.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_rp2040 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.feather_rp2040_adalogger.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.feather_rp2040_adalogger.test.skip deleted file mode 100644 index 29ebf0ea0..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.feather_rp2040_adalogger.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_rp2040_adalogger diff --git a/DMX_NeoPixels/examples/DMX_Slave/.flora.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.flora.test.skip deleted file mode 100644 index e4cc7386e..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.flora.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for flora diff --git a/DMX_NeoPixels/examples/DMX_Slave/.funhouse.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.funhouse.test.skip deleted file mode 100644 index 32a4e1e1a..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.funhouse.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for funhouse diff --git a/DMX_NeoPixels/examples/DMX_Slave/.gemma.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.gemma.test.skip deleted file mode 100644 index 978f275e3..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.gemma.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for gemma diff --git a/DMX_NeoPixels/examples/DMX_Slave/.gemma_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.gemma_m0.test.skip deleted file mode 100644 index c42614d7c..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.gemma_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for gemma_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.hallowing_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.hallowing_m0.test.skip deleted file mode 100644 index ed26fdf6a..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.hallowing_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for hallowing_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.hallowing_m4_tinyusb.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.hallowing_m4_tinyusb.test.skip deleted file mode 100644 index 0ab22cb8d..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.hallowing_m4_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for hallowing_m4_tinyusb diff --git a/DMX_NeoPixels/examples/DMX_Slave/.ledglasses_nrf52840.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.ledglasses_nrf52840.test.skip deleted file mode 100644 index f540a7e4c..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.ledglasses_nrf52840.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for ledglasses_nrf52840 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.magtag.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.magtag.test.skip deleted file mode 100644 index 79d0d324c..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.magtag.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for magtag diff --git a/DMX_NeoPixels/examples/DMX_Slave/.metro_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.metro_m0.test.skip deleted file mode 100644 index 91512a898..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.metro_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.metro_m0_tinyusb.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.metro_m0_tinyusb.test.skip deleted file mode 100644 index 486e4f67e..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.metro_m0_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m0_tinyusb diff --git a/DMX_NeoPixels/examples/DMX_Slave/.metro_m4.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.metro_m4.test.skip deleted file mode 100644 index 5012f3737..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.metro_m4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m4 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.metro_m4_tinyusb.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.metro_m4_tinyusb.test.skip deleted file mode 100644 index 17edc54fe..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.metro_m4_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m4_tinyusb diff --git a/DMX_NeoPixels/examples/DMX_Slave/.monster_m4sk.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.monster_m4sk.test.skip deleted file mode 100644 index ec7f80e48..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.monster_m4sk.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for monster_m4sk diff --git a/DMX_NeoPixels/examples/DMX_Slave/.monster_m4sk_tinyusb.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.monster_m4sk_tinyusb.test.skip deleted file mode 100644 index a08b60688..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.monster_m4sk_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for monster_m4sk_tinyusb diff --git a/DMX_NeoPixels/examples/DMX_Slave/.neokeytrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.neokeytrinkey_m0.test.skip deleted file mode 100644 index 7fb03fe33..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.neokeytrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for neokeytrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.neotrellis_m4.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.neotrellis_m4.test.skip deleted file mode 100644 index eebfceae8..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.neotrellis_m4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for neotrellis_m4 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.nrf52832.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.nrf52832.test.skip deleted file mode 100644 index ee506a55a..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.nrf52832.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for nrf52832 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.nrf52840.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.nrf52840.test.skip deleted file mode 100644 index a6bcf2c9d..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.nrf52840.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for nrf52840 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.pixeltrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.pixeltrinkey_m0.test.skip deleted file mode 100644 index 4a5f3b346..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.pixeltrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pixeltrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.protrinket_5v.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.protrinket_5v.test.skip deleted file mode 100644 index ec91a95cb..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.protrinket_5v.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for protrinket_5v diff --git a/DMX_NeoPixels/examples/DMX_Slave/.proxlighttrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.proxlighttrinkey_m0.test.skip deleted file mode 100644 index 0d46213a9..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.proxlighttrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for proxlighttrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.pybadge.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.pybadge.test.skip deleted file mode 100644 index 82cd2ac9c..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.pybadge.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pybadge diff --git a/DMX_NeoPixels/examples/DMX_Slave/.pycamera_s3.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.pycamera_s3.test.skip deleted file mode 100644 index 021a63e54..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.pycamera_s3.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pycamera_s3 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.pygamer.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.pygamer.test.skip deleted file mode 100644 index 430cf639c..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.pygamer.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pygamer diff --git a/DMX_NeoPixels/examples/DMX_Slave/.pyportal.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.pyportal.test.skip deleted file mode 100644 index 6a18dce9f..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.pyportal.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pyportal diff --git a/DMX_NeoPixels/examples/DMX_Slave/.qt2040_trinkey.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.qt2040_trinkey.test.skip deleted file mode 100644 index 263748866..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.qt2040_trinkey.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qt2040_trinkey diff --git a/DMX_NeoPixels/examples/DMX_Slave/.qtpy_esp32s2.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.qtpy_esp32s2.test.skip deleted file mode 100644 index 627d7dd57..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.qtpy_esp32s2.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qtpy_esp32s2 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.qtpy_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.qtpy_m0.test.skip deleted file mode 100644 index fbc42f083..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.qtpy_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qtpy_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.qualia_s3_rgb666.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.qualia_s3_rgb666.test.skip deleted file mode 100644 index 1e14eea6e..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.qualia_s3_rgb666.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qualia_s3_rgb666 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.rotarytrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.rotarytrinkey_m0.test.skip deleted file mode 100644 index 8a2ec7327..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.rotarytrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for rotarytrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.sht4xtrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.sht4xtrinkey_m0.test.skip deleted file mode 100644 index 039d08b3e..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.sht4xtrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for sht4xtrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.slidetrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.slidetrinkey_m0.test.skip deleted file mode 100644 index d3f14ba82..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.slidetrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for slidetrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.trinket_5v.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.trinket_5v.test.skip deleted file mode 100644 index e2d3dded0..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.trinket_5v.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for trinket_5v diff --git a/DMX_NeoPixels/examples/DMX_Slave/.trinket_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.trinket_m0.test.skip deleted file mode 100644 index 06ad7bf51..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.trinket_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for trinket_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave/.uno.test.only b/DMX_NeoPixels/examples/DMX_Slave/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/DMX_NeoPixels/examples/DMX_Slave/.uno.test.skip b/DMX_NeoPixels/examples/DMX_Slave/.uno.test.skip deleted file mode 100644 index f3e164df1..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave/.uno.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for uno diff --git a/DMX_NeoPixels/examples/DMX_Slave/Conceptinetics.cpp b/DMX_NeoPixels/examples/DMX_Slave/Conceptinetics.cpp new file mode 100644 index 000000000..36ada5924 --- /dev/null +++ b/DMX_NeoPixels/examples/DMX_Slave/Conceptinetics.cpp @@ -0,0 +1,1233 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Conceptinetics.cpp - DMX library for Arduino + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + This code has been tested using the following hardware: + + - Arduino UNO R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino MEGA2560 R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD +*/ + + +#include "pins_arduino.h" +#include "Conceptinetics.h" + +#include +#include + +#include +#include + +#include + + +#if defined (USE_DMX_SERIAL_0) + + #if defined (USART__TXC_vect) + #define USART_TX USART__TXC_vect + #elif defined(USART_TX_vect) + #define USART_TX USART_TX_vect + #elif defined(USART0_TX_vect) + #define USART_TX USART0_TX_vect + #endif + + #if defined (USART__RXC_vect) + #define USART_RX USART__RXC_vect + #elif defined(USART_RX_vect) + #define USART_RX USART_RX_vect + #elif defined(USART0_RX_vect) + #define USART_RX USART0_RX_vect + #endif + + #if defined UDR + #define DMX_UDR UDR + #elif defined UDR0 + #define DMX_UDR UDR0 + #endif + + #if defined(UBRRH) && defined(UBRRL) + #define DMX_UBRRH UBRRH + #define DMX_UBRRL UBRRL + #elif defined(UBRR0H) && defined(UBRR0L) + #define DMX_UBRRH UBRR0H + #define DMX_UBRRL UBRR0L + #endif + + #if defined(UCSRA) + #define DMX_UCSRA UCSRA + #elif defined(UCSR0A) + #define DMX_UCSRA UCSR0A + #endif + + #if defined(UCSRB) + #define DMX_UCSRB UCSRB + #elif defined (UCSR0B) + #define DMX_UCSRB UCSR0B + #endif + + #if defined(TXEN) && defined(TXCIE) + #define DMX_TXEN TXEN + #define DMX_TXCIE TXCIE + #elif defined(TXEN0) && defined(TXCIE0) + #define DMX_TXEN TXEN0 + #define DMX_TXCIE TXCIE0 + #endif + + #if defined(RXEN) && defined(RXCIE) + #define DMX_RXEN RXEN + #define DMX_RXCIE RXCIE + #elif defined(RXEN0) && defined(RXCIE0) + #define DMX_RXEN RXEN0 + #define DMX_RXCIE RXCIE0 + #endif + + #if defined(FE) + #define DMX_FE FE + #elif defined(FE0) + #define DMX_FE FE0 + #endif + + #define RX_PIN 0 + #define TX_PIN 1 + +#elif defined (USE_DMX_SERIAL_1) + #define USART_RX USART1_RX_vect + #define USART_TX USART1_TX_vect + #define DMX_UDR UDR1 + #define DMX_UBRRH UBRR1H + #define DMX_UBRRL UBRR1L + #define DMX_UCSRA UCSR1A + #define DMX_UCSRB UCSR1B + #define DMX_TXEN TXEN1 + #define DMX_TXCIE TXCIE1 + #define DMX_RXEN RXEN1 + #define DMX_RXCIE RXCIE1 + #define DMX_FE FE1 + #define RX_PIN 19 + #define TX_PIN 18 +#elif defined (USE_DMX_SERIAL_2) + #define USART_RX USART2_RX_vect + #define USART_TX USART2_TX_vect + #define DMX_UDR UDR2 + #define DMX_UBRRH UBRR2H + #define DMX_UBRRL UBRR2L + #define DMX_UCSRA UCSR2A + #define DMX_UCSRB UCSR2B + #define DMX_TXEN TXEN2 + #define DMX_TXCIE TXCIE2 + #define DMX_RXEN RXEN2 + #define DMX_RXCIE RXCIE2 + #define DMX_FE FE2 + #define RX_PIN 17 + #define TX_PIN 16 +#elif defined (USE_DMX_SERIAL_3) + #define USART_RX USART3_RX_vect + #define USART_TX USART3_TX_vect + #define DMX_UDR UDR3 + #define DMX_UBRRH UBRR3H + #define DMX_UBRRL UBRR3L + #define DMX_UCSRA UCSR3A + #define DMX_UCSRB UCSR3B + #define DMX_TXEN TXEN3 + #define DMX_TXCIE TXCIE3 + #define DMX_RXEN RXEN3 + #define DMX_RXCIE RXCIE3 + #define DMX_FE FE3 + #define RX_PIN 14 + #define TX_PIN 15 +#endif + + +#define LOWBYTE(v) ((uint8_t) (v)) +#define HIGHBYTE(v) ((uint8_t) (((uint16_t) (v)) >> 8)) + +#define BSWAP_16(x) ( (uint8_t)((x) >> 8) | ((uint8_t)(x)) << 8 ) + +namespace isr +{ + enum isrState + { + Idle, + Break, + DmxBreak, + DmxBreakManual, + DmxStartByte, + DmxRecordData, + DmxTransmitData, + RdmBreak, + RdmStartByte, + RdmRecordData, + RdmTransmitData, + RDMTransmitComplete, + }; + + enum isrMode + { + Disabled, + Receive, + DMXTransmit, + DMXTransmitManual, /* Manual break... */ + RDMTransmit, + RDMTransmitNoInt, /* Setup uart but leave interrupt disabled */ + }; +}; + + +DMX_Master *__dmx_master; +DMX_Slave *__dmx_slave; +RDM_Responder *__rdm_responder; + +int8_t __re_pin; // R/W Pin on shield + +isr::isrState __isr_txState; // TX ISR state +isr::isrState __isr_rxState; // RX ISR state + + +void SetISRMode ( isr::isrMode ); + + +DMX_FrameBuffer::DMX_FrameBuffer ( uint16_t buffer_size ) +{ + m_refcount = (uint8_t*) malloc ( sizeof ( uint8_t ) ); + + if ( buffer_size >= DMX_MIN_FRAMESIZE && buffer_size <= DMX_MAX_FRAMESIZE ) + { + m_buffer = (uint8_t*) malloc ( buffer_size ); + if ( m_buffer != NULL ) + { + memset ( (void *)m_buffer, 0x0, buffer_size ); + m_bufferSize = buffer_size; + } + else + m_buffer = 0x0; + } + else + m_bufferSize = 0x0; + + *m_refcount++; +} + +DMX_FrameBuffer::DMX_FrameBuffer ( DMX_FrameBuffer &buffer ) +{ + // Copy references and make sure the parent object does not dispose our + // buffer when deleted and we are still active + this->m_refcount = buffer.m_refcount; + (*this->m_refcount)++; + + this->m_buffer = buffer.m_buffer; + this->m_bufferSize = buffer.m_bufferSize; +} + +DMX_FrameBuffer::~DMX_FrameBuffer ( void ) +{ + // If we are the last object using the + // allocated buffer then free it together + // with the refcounter + if ( --(*m_refcount) == 0 ) + { + if ( m_buffer ) + free ( m_buffer ); + + free ( m_refcount ); + } +} + +uint16_t DMX_FrameBuffer::getBufferSize ( void ) +{ + return m_bufferSize; +} + + +uint8_t DMX_FrameBuffer::getSlotValue ( uint16_t index ) +{ + if (index < m_bufferSize) + return m_buffer[index]; + else + return 0x0; +} + + +void DMX_FrameBuffer::setSlotValue ( uint16_t index, uint8_t value ) +{ + if ( index < m_bufferSize ) + m_buffer[index] = value; +} + + +void DMX_FrameBuffer::setSlotRange ( uint16_t start, uint16_t end, uint8_t value ) +{ + if ( start < m_bufferSize && end < m_bufferSize && start < end ) + memset ( (void *) &m_buffer[start], value, end-start+1 ); +} + +void DMX_FrameBuffer::clear ( void ) +{ + memset ( (void *) m_buffer, 0x0, m_bufferSize ); +} + +uint8_t &DMX_FrameBuffer::operator[] ( uint16_t index ) +{ + return m_buffer[index]; +} + + +DMX_Master::DMX_Master ( DMX_FrameBuffer &buffer, int readEnablePin ) +: m_frameBuffer ( buffer ), + m_autoBreak ( 1 ) // Autobreak generation is default on +{ + setStartCode ( DMX_START_CODE ); + + __re_pin = readEnablePin; + pinMode ( __re_pin, OUTPUT ); + + ::SetISRMode ( isr::Disabled ); +} + +DMX_Master::DMX_Master ( uint16_t maxChannel, int readEnablePin ) +: m_frameBuffer ( maxChannel + DMX_STARTCODE_SIZE ), + m_autoBreak ( 1 ) // Autobreak generation is default on +{ + setStartCode ( DMX_START_CODE ); + + __re_pin = readEnablePin; + pinMode ( __re_pin, OUTPUT ); + + ::SetISRMode ( isr::Disabled ); +} + +DMX_Master::~DMX_Master ( void ) +{ + disable (); // Stop sending + __dmx_master = NULL; +} + +DMX_FrameBuffer &DMX_Master::getBuffer ( void ) +{ + return m_frameBuffer; // Return reference to frame buffer +} + +void DMX_Master::setStartCode ( uint8_t value ) +{ + m_frameBuffer[0] = value; // Set the first byte in our frame buffer +} + +void DMX_Master::setChannelValue ( uint16_t channel, uint8_t value ) +{ + if ( channel > 0 ) // Prevent overwriting the start code + m_frameBuffer.setSlotValue ( channel, value ); +} + +void DMX_Master::setChannelRange ( uint16_t start, uint16_t end, uint8_t value ) +{ + if ( start > 0 ) // Prevent overwriting the start code + m_frameBuffer.setSlotRange ( start, end, value ); +} + + +void DMX_Master::enable ( void ) +{ + __dmx_master = this; + + if ( m_autoBreak ) + ::SetISRMode ( isr::DMXTransmit ); + else + ::SetISRMode ( isr::DMXTransmitManual ); +} + +void DMX_Master::disable ( void ) +{ + ::SetISRMode ( isr::Disabled ); + __dmx_master = NULL; // No active master +} + +void DMX_Master::setAutoBreakMode ( void ) { m_autoBreak = 1; } +void DMX_Master::setManualBreakMode ( void ) { m_autoBreak = 0; } +uint8_t DMX_Master::autoBreakEnabled ( void ) { return m_autoBreak; } + + +uint8_t DMX_Master::waitingBreak ( void ) +{ + return ( __isr_txState == isr::DmxBreakManual ); +} + +void DMX_Master::breakAndContinue ( uint8_t breakLength_us ) +{ + // Only execute if we are the controlling master object + if ( __dmx_master == this && __isr_txState == isr::DmxBreakManual ) + { + pinMode ( TX_PIN, OUTPUT ); + digitalWrite ( TX_PIN, LOW ); // Begin BREAK + + for (uint8_t bl=0; bl(*this); +} + + uint8_t DMX_Slave::getChannelValue ( uint16_t channel ) +{ + return getSlotValue ( channel ); +} + + +uint16_t DMX_Slave::getStartAddress ( void ) +{ + return m_startAddress; +} + +void DMX_Slave::setStartAddress ( uint16_t addr ) +{ + m_startAddress = addr; +} + +void DMX_Slave::onReceiveComplete ( void (*func)(unsigned short) ) +{ + event_onFrameReceived = func; +} + + +bool DMX_Slave::processIncoming ( uint8_t val, bool first ) +{ + static uint16_t idx; + bool rval = false; + + if ( first ) + { + // We could have received less channels then we + // expected.. but still is a complete frame + if (m_state == dmx::dmxData && event_onFrameReceived) + event_onFrameReceived (idx); + + m_state = dmx::dmxStartByte; + } + + switch ( m_state ) + { + case dmx::dmxStartByte: + setSlotValue ( 0, val ); // Store start code + idx = m_startAddress; + m_state = dmx::dmxWaitStartAddress; + + case dmx::dmxWaitStartAddress: + if ( --idx == 0 ) + m_state = dmx::dmxData; + break; + + case dmx::dmxData: + if ( idx++ < getBufferSize() ) + setSlotValue ( idx, val ); + else + { + m_state = dmx::dmxFrameReady; + + // If a onFrameReceived callback is register... + if (event_onFrameReceived) + event_onFrameReceived (idx-2); + + rval = true; + } + break; + } + + return rval; +} + + +uint16_t RDM_FrameBuffer::getBufferSize ( void ) { return sizeof ( m_msg ); } + +uint8_t RDM_FrameBuffer::getSlotValue ( uint16_t index ) +{ + if ( index < sizeof ( m_msg ) ) + return m_msg.d[index]; + else + return 0x0; +} + + +void RDM_FrameBuffer::setSlotValue ( uint16_t index, uint8_t value ) +{ + if ( index < sizeof ( m_msg ) ) + m_msg.d[index] = value; +} + +void RDM_FrameBuffer::clear ( void ) +{ + memset ( (void*)m_msg.d, 0x0, sizeof( m_msg ) ); + m_state = rdm::rdmUnknown; +} + +bool RDM_FrameBuffer::processIncoming ( uint8_t val, bool first ) +{ + static uint16_t idx; + bool rval = false; + + if ( first ) + { + m_state = rdm::rdmStartByte; + m_csRecv.checksum = (uint16_t) 0x0000; + idx = 0; + } + + // Prevent buffer overflow for large messages + if (idx >= sizeof(m_msg)) + return true; + + switch ( m_state ) + { + case rdm::rdmStartByte: + m_msg.startCode = val; + m_state = rdm::rdmSubStartCode; + break; + + case rdm::rdmSubStartCode: + if ( val != 0x01 ) + { + rval = true; // Stop processing data + break; + } + + m_msg.subStartCode = val; + m_state = rdm::rdmMessageLength; + break; + + case rdm::rdmMessageLength: + m_msg.msgLength = val; + m_state = rdm::rdmData; + m_csRecv.checksum = 0xcc + 0x01 + val; // set initial checksum + idx = 3; // buffer index for next byte + break; + + case rdm::rdmData: + m_msg.d[idx++] = val; + m_csRecv.checksum += val; + if ( idx >= m_msg.msgLength ) + m_state = rdm::rdmChecksumHigh; + break; + + case rdm::rdmChecksumHigh: + m_csRecv.csh = val; + m_state = rdm::rdmChecksumLow; + + break; + + case rdm::rdmChecksumLow: + m_csRecv.csl = val; + + if ((m_csRecv.checksum % (uint16_t)0x10000) == m_csRecv.checksum) + { + m_state = rdm::rdmFrameReady; + + // valid checksum ... start processing + processFrame (); + } + + m_state = rdm::rdmUnknown; + rval = true; + break; + }; + + return rval; +} + +bool RDM_FrameBuffer::fetchOutgoing ( volatile uint8_t *udr, bool first ) +{ + static uint16_t idx; + static uint16_t cs; + bool rval = false; + + + if ( first ) + { + m_state = rdm::rdmData; + cs = 0x0; + idx = 0; + } + + switch ( m_state ) + { + case rdm::rdmData: + cs += m_msg.d[idx]; + *udr = m_msg.d[idx++]; + if ( idx >= m_msg.msgLength ) + { + m_state = rdm::rdmChecksumHigh; + } + break; + + case rdm::rdmChecksumHigh: + *udr = (cs >> 8); + m_state = rdm::rdmChecksumLow; + break; + + case rdm::rdmChecksumLow: + *udr = (cs & 0xff); + m_state = rdm::rdmUnknown; + rval = true; + break; + + } + + return rval; +} + + +void (*RDM_Responder::event_onIdentifyDevice)(bool); +void (*RDM_Responder::event_onDeviceLabelChanged)(const char*, uint8_t); +void (*RDM_Responder::event_onDMXStartAddressChanged)(uint16_t); +void (*RDM_Responder::event_onDMXPersonalityChanged)(uint8_t); + +// +// slave parameter is only used to ensure a slave object is present before +// initializing the rdm responder class +// +RDM_Responder::RDM_Responder ( uint16_t m, uint8_t d1, uint8_t d2, + uint8_t d3, uint8_t d4, DMX_Slave &slave ) +: RDM_FrameBuffer ( ), + m_Personalities (1), // Available personlities + m_Personality (1) // Default personality eq 1. +{ + __rdm_responder = this; + m_devid.Initialize ( m, d1, d2, d3, d4 ); + + // Default software version id = 0x00000000 + memset ( (void*)m_SoftwareVersionId, 0x0, 0x4 ); + + // Rdm responder is disabled by default + m_rdmStatus.enabled = false; +} + +RDM_Responder::~RDM_Responder ( void ) +{ + __rdm_responder = NULL; +} + +void RDM_Responder::onIdentifyDevice ( void (*func)(bool) ) +{ + event_onIdentifyDevice = func; +} + +void RDM_Responder::onDeviceLabelChanged ( void (*func) (const char*, uint8_t) ) +{ + event_onDeviceLabelChanged = func; +} + +void RDM_Responder::onDMXStartAddressChanged ( void (*func) (uint16_t) ) +{ + event_onDMXStartAddressChanged = func; +} + +void RDM_Responder::onDMXPersonalityChanged ( void (*func) (uint8_t) ) +{ + event_onDMXPersonalityChanged = func; +} + +void RDM_Responder::setDeviceLabel ( const char *label, size_t len ) +{ + if ( len > RDM_MAX_DEVICELABEL_LENGTH ) + len = RDM_MAX_DEVICELABEL_LENGTH; + + memcpy ( (void *)m_deviceLabel, (void *)label, len ); +} + +#define UID_0 0x12 //ESTA device ID +#define UID_1 0x34 +#define UID_2 0x56 +#define UID_3 0x88 +#define UID_4 0x00 +#define UID_5 0x00 + +#define UID_CS (0xFF *6 +UID_0 +UID_1 +UID_2 +UID_3 +UID_4 +UID_5) + +void RDM_Responder::repondDiscUniqueBranch ( void ) +{ + #if defined(UCSRB) + UCSRB = (1<>8) | 0xaa; + response [21] = (cs>>8) | 0x55; + response [22] = (cs&0xff) | 0xaa; + response [23] = (cs&0xff) | 0x55; + + + // Table 3-2 ANSI_E1-20-2010 <2ms + _delay_us ( MIN_RESPONDER_PACKET_SPACING_USEC ); + + // Fix: 2017, Feb 28: Moved data enable down in order to limit line in marking state time to comply with + // section 3.2.3 + // Set shield to transmit mode (turn arround) + digitalWrite ( __re_pin, HIGH ); + + + for ( int i=0; i<24; i++ ) + { + // Wait until data register is empty + #if defined (UCSR0A) && defined (UDRE0) + while((UCSR0A & (1 <(m_msg.PD); + + pd->protocolVersionMajor = 0x01; + pd->protocolVersionMinor = 0x00; + pd->deviceModelId = BSWAP_16(m_DeviceModelId); + pd->ProductCategory = BSWAP_16(m_ProductCategory); + memcpy ( (void*)pd->SoftwareVersionId, (void*)m_SoftwareVersionId, 4 ); + pd->DMX512FootPrint = BSWAP_16(__dmx_slave->getBufferSize()-1); // eq buffersize-startbyte + pd->DMX512CurrentPersonality = m_Personality; + pd->DMX512NumberPersonalities = m_Personalities; + pd->DMX512StartAddress = BSWAP_16(__dmx_slave->getStartAddress()); + + pd->SubDeviceCount = 0x0; // Sub devices are not supported by this library + pd->SensorCount = 0x0; // Sensors are not yet supported + + m_msg.PDL = sizeof (RDM__DeviceInfoPD); +} + +const uint8_t ManufacturerLabel_P[] PROGMEM = "Conceptinetics"; + +void RDM_Responder::processFrame ( void ) +{ + // If packet is a general broadcast + if ( + m_msg.dstUid.isBroadcast (m_devid.m_id) || + m_devid == m_msg.dstUid + ) + { + // Set default response type + m_msg.portId = rdm::ResponseTypeAck; + + switch ( BSWAP_16(m_msg.PID) ) + { + case rdm::DiscUniqueBranch: + // Check if we are inside the given unique branch... + if ( !m_rdmStatus.mute && + reinterpret_cast(m_msg.PD)->lbound < m_devid && + reinterpret_cast(m_msg.PD)->hbound > m_devid ) + { + // Discovery messages are responded with data only and no breaks + repondDiscUniqueBranch (); + } + break; + + case rdm::DiscMute: + reinterpret_cast(m_msg.PD)->ctrlField = 0x0; + m_msg.PDL = sizeof ( RDM_DiscMuteUnMutePD ); + m_rdmStatus.mute = true; + break; + + case rdm::DiscUnMute: + reinterpret_cast(m_msg.PD)->ctrlField = 0x0; + m_msg.PDL = sizeof ( RDM_DiscMuteUnMutePD ); + m_rdmStatus.mute = false; + break; + + case rdm::SupportedParameters: + // + // Temporary solution... this will become dynamic + // in a later version... + // + m_msg.PD[0] = HIGHBYTE(rdm::DmxStartAddress); // MSB + m_msg.PD[1] = LOWBYTE (rdm::DmxStartAddress); // LSB + + m_msg.PD[2] = HIGHBYTE(rdm::DmxPersonality); + m_msg.PD[3] = LOWBYTE (rdm::DmxPersonality); + + m_msg.PD[4] = HIGHBYTE(rdm::ManufacturerLabel); + m_msg.PD[5] = LOWBYTE (rdm::ManufacturerLabel); + + m_msg.PD[6] = HIGHBYTE(rdm::DeviceLabel); + m_msg.PD[7] = LOWBYTE (rdm::DeviceLabel); + + m_msg.PDL = 0x6; + break; + + // Only for manufacturer specific parameters + // case rdm::ParameterDescription: + // break; + + case rdm::DeviceInfo: + if ( m_msg.CC == rdm::GetCommand ) + populateDeviceInfo (); + break; + + case rdm::DmxStartAddress: + if ( m_msg.CC == rdm::GetCommand ) + { + m_msg.PD[0] = HIGHBYTE(__dmx_slave->getStartAddress ()); + m_msg.PD[1] = LOWBYTE (__dmx_slave->getStartAddress ()); + m_msg.PDL = 0x2; + } + else // if ( m_msg.CC == rdm::SetCommand ) + { + __dmx_slave->setStartAddress ( (m_msg.PD[0] << 8) + m_msg.PD[1] ); + m_msg.PDL = 0x0; + + if ( event_onDMXStartAddressChanged ) + event_onDMXStartAddressChanged ( (m_msg.PD[0] << 8) + m_msg.PD[1] ); + } + break; + + case rdm::DmxPersonality: + if ( m_msg.CC == rdm::GetCommand ) + { + reinterpret_cast + (m_msg.PD)->DMX512CurrentPersonality = m_Personality; + reinterpret_cast + (m_msg.PD)->DMX512CurrentPersonality = m_Personalities; + m_msg.PDL = sizeof (RDM_DeviceGetPersonality_PD); + } + else // if ( m_msg.CC == rdm::SetCommand ) + { + m_Personality = reinterpret_cast + (m_msg.PD)->DMX512Personality; + m_msg.PDL = 0x0; + + if ( event_onDMXPersonalityChanged ) + event_onDMXPersonalityChanged ( m_Personality ); + } + break; + + case rdm::IdentifyDevice: + if ( m_msg.CC == rdm::GetCommand ) + { + m_msg.PD[0] = (uint8_t)(m_rdmStatus.ident ? 1 : 0); + m_msg.PDL = 0x1; + } + else if ( m_msg.CC == rdm::SetCommand ) + { + // Look into first byte to see whether identification + // is turned on or off + m_rdmStatus.ident = m_msg.PD[0] ? true : false; + if ( event_onIdentifyDevice ) + event_onIdentifyDevice ( m_rdmStatus.ident ); + + m_msg.PDL = 0x0; + } + break; + + case rdm::ManufacturerLabel: + if ( m_msg.CC == rdm::GetCommand ) + { + memcpy_P( (void*)m_msg.PD, ManufacturerLabel_P, sizeof(ManufacturerLabel_P) ); + m_msg.PDL = sizeof ( ManufacturerLabel_P ); + } + break; + + case rdm::DeviceLabel: + if ( m_msg.CC == rdm::GetCommand ) + { + memcpy ( m_msg.PD, (void*) m_deviceLabel, 32 ); + m_msg.PDL = 32; + } + else if ( m_msg.CC == rdm::SetCommand ) + { + memset ( (void*) m_deviceLabel, ' ', 32 ); + memcpy ( (void*) m_deviceLabel, m_msg.PD, (m_msg.PDL < 32 ? m_msg.PDL : 32) ); + m_msg.PDL = 0; + + // Notify application + if ( event_onDeviceLabelChanged ) + event_onDeviceLabelChanged ( m_deviceLabel, 32 ); + } + break; + + + default: + // Unknown parameter ID response + m_msg.portId = rdm::ResponseTypeNackReason; + m_msg.PD[0] = rdm::UnknownPid; + m_msg.PD[1] = 0x0; + m_msg.PDL = 0x2; + break; + }; + } + + // + // Only respond if this this message + // was destined to us only + if ( m_msg.dstUid == m_devid ) + { + m_msg.startCode = RDM_START_CODE; + m_msg.subStartCode = 0x01; + m_msg.msgLength = RDM_HDR_LEN + m_msg.PDL; + m_msg.msgCount = 0; + + /* + switch ( m_msg.msg.CC ) + { + case rdm::DiscoveryCommand: + m_msg.msg.CC = rdm::DiscoveryCommandResponse; + break; + case rdm::GetCommand: + m_msg.msg.CC = rdm::GetCommandResponse; + break; + case rdm::SetCommand: + m_msg.msg.CC = rdm::SetCommandResponse; + break; + } + */ + /* Above replaced by next line */ + m_msg.CC++; + + m_msg.dstUid.copy ( m_msg.srcUid ); + m_msg.srcUid.copy ( m_devid ); + + //_delay_us ( MIN_RESPONDER_PACKET_SPACING_USEC ); + SetISRMode ( isr::RDMTransmit ); + + } +} + + +void SetISRMode ( isr::isrMode mode ) +{ + uint8_t readEnable; + +#if defined(USE_DMX_SERIAL_0) + #if defined(UCSRB) && defined (UCSRC) + UCSRC |= (1<>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + + // Prepare before kicking off ISR + //DMX_UDR = 0x0; + __isr_rxState = isr::Idle; + readEnable = LOW; + DMX_UCSRB = (1<>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + DMX_UDR = 0x0; + DMX_UCSRB = 0x0; + readEnable = HIGH; + __isr_txState = isr::DmxBreakManual; + break; + + case isr::RDMTransmit: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + //DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + //DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + DMX_UCSRB = (1< -1) + digitalWrite ( __re_pin, readEnable ); + +} + +// +// TX UART (DMX Transmission ISR) +// +ISR (USART_TX) +{ + static uint16_t current_slot; + + switch ( __isr_txState ) + { + case isr::DmxBreak: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + if ( __isr_txState == isr::DmxBreak ) + __isr_txState = isr::DmxStartByte; + + break; + + case isr::DmxStartByte: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + current_slot = 0; + DMX_UDR = __dmx_master->getBuffer()[ current_slot++ ]; + __isr_txState = isr::DmxTransmitData; + break; + + + case isr::DmxTransmitData: + // NOTE: we always send full frames of 513 bytes, this will bring us + // close to 40 frames / sec with no interslot delays + #ifdef DMX_IBG + _delay_us (DMX_IBG); + #endif + + DMX_UDR = __dmx_master->getBuffer().getSlotValue( current_slot++ ); + + // Send 512 channels + if ( current_slot >= DMX_MAX_FRAMESIZE ) + { + if ( __dmx_master->autoBreakEnabled () ) + __isr_txState = isr::DmxBreak; + else + SetISRMode ( isr::DMXTransmitManual ); + } + + break; + +/* case isr::RdmBreak: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + __isr_txState = isr::RdmStartByte; + + break; +*/ + + case isr::RdmStartByte: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + + // Write start byte + __rdm_responder->fetchOutgoing ( &DMX_UDR, true ); + __isr_txState = isr::RdmTransmitData; + + break; + + case isr::RdmTransmitData: + // Write rest of data + if ( __rdm_responder->fetchOutgoing ( &DMX_UDR ) ) + __isr_txState = isr::RDMTransmitComplete; + break; + + case isr::RDMTransmitComplete: + SetISRMode ( isr::Receive ); // Start waitin for new data + __isr_txState = isr::Idle; // No tx state + break; + + } +} + + + +// +// RX UART (DMX Reception ISR) +// +ISR (USART_RX) +{ + uint8_t usart_state = DMX_UCSRA; + uint8_t usart_data = DMX_UDR; + + // + // Check for framing error and reset if found + // A framing most likely* indicate a break in our ocasion + // + if ( usart_state & (1<processIncoming ( usart_data, true ); + __isr_rxState = isr::DmxRecordData; + } + else if ( __rdm_responder && + usart_data == RDM_START_CODE && + __rdm_responder->m_rdmStatus.enabled ) + { + // __rdm_responder->clear (); + __rdm_responder->processIncoming ( usart_data, true ); + __isr_rxState = isr::RdmRecordData; + } + else + { + __isr_rxState = isr::Idle; + } + break; + + // Process DMX Data + case isr::DmxRecordData: + if ( __dmx_slave->processIncoming ( usart_data ) ) + __isr_rxState = isr::Idle; + break; + + // Process RDM Data + case isr::RdmRecordData: + if ( __rdm_responder->processIncoming ( usart_data ) ) + __isr_rxState = isr::Idle; + break; + + } + +} + diff --git a/DMX_NeoPixels/examples/DMX_Slave/Conceptinetics.h b/DMX_NeoPixels/examples/DMX_Slave/Conceptinetics.h new file mode 100644 index 000000000..0f03da619 --- /dev/null +++ b/DMX_NeoPixels/examples/DMX_Slave/Conceptinetics.h @@ -0,0 +1,383 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Conceptinetics.h - DMX library for Arduino + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + This code has been tested using the following hardware: + + - Arduino / Genuino UNO R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino / Genuino MEGA2560 R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino / Genuino Leonardo using a CTC-DRA-13-R2 ISOLATED DMX-RDM SHIELD + + - CTC-DRA-10-1 and CTC-DRA-10-R2 is the Non-isolated costs effective DMX-RDM shield +*/ + + +#ifndef CONCEPTINETICS_H_ +#define CONCEPTINETICS_H_ + +#include +#include + +#include "Rdm_Uid.h" +#include "Rdm_Defines.h" + +#define DMX_MAX_FRAMESIZE 513 // Startbyte + 512 Slots +#define DMX_MIN_FRAMESIZE 2 // Startbyte + 1 Slot + +#define DMX_MAX_FRAMECHANNELS 512 // Maxmim number of channer per frame + +#define DMX_STARTCODE_SIZE 1 // Size of startcode in bytes + +#define DMX_START_CODE 0x0 // Start code for a DMX frame +#define RDM_START_CODE 0xcc // Start code for a RDM frame + +// Uncomment to enable Inter slot delay ) (avg < 76uSec) ... +// mimum is zero according to specification +// #define DMX_IBG 10 // Inter slot time + +// Speed your Arduino is running on in Hz. +#define F_OSC 16000000UL + +// DMX Baudrate, this should be 250000 +#define DMX_BAUD_RATE 250000 + +// The baudrate used to automaticly generate a break within +// your ISR.. make it lower to generate longer breaks +//#define DMX_BREAK_RATE 99900 + +// 2017, Feb 28: Set to appox 176us +#define DMX_BREAK_RATE 49950 + +// Tabel 3-2 ANSI_E1-20-2010 +// Minimum time to allow the datalink to 'turn arround' +#define MIN_RESPONDER_PACKET_SPACING_USEC 176 /*176*/ + +// Define which serial port to use as DMX port, only one can be +// selected at the time by uncommenting one of the following +// lines +#define USE_DMX_SERIAL_0 +//#define USE_DMX_SERIAL_1 +//#define USE_DMX_SERIAL_2 +//#define USE_DMX_SERIAL_3 + +namespace dmx +{ + enum dmxState + { + dmxUnknown, + dmxStartByte, + dmxWaitStartAddress, + dmxData, + dmxFrameReady, + }; +}; + +namespace rdm +{ + enum rdmState + { + rdmUnknown, + rdmStartByte, + rdmSubStartCode, + rdmMessageLength, + rdmData, + rdmChecksumHigh, + rdmChecksumLow, + rdmFrameReady, + }; +}; + +struct IFrameBuffer +{ + virtual uint16_t getBufferSize ( void ) = 0; + + virtual uint8_t getSlotValue ( uint16_t index ) = 0; + virtual void setSlotValue ( uint16_t index, uint8_t value ) = 0; +}; + +class DMX_FrameBuffer : IFrameBuffer +{ + public: + // + // Constructor buffersize = 1-513 + // + DMX_FrameBuffer ( uint16_t buffer_size ); + DMX_FrameBuffer ( DMX_FrameBuffer &buffer ); + ~DMX_FrameBuffer ( void ); + + uint16_t getBufferSize ( void ); + + uint8_t getSlotValue ( uint16_t index ); + void setSlotValue ( uint16_t index, uint8_t value ); + void setSlotRange ( uint16_t start, uint16_t end, uint8_t value ); + void clear ( void ); + + uint8_t &operator[] ( uint16_t index ); + + private: + + uint8_t *m_refcount; + uint16_t m_bufferSize; + uint8_t *m_buffer; +}; + + +// +// DMX Master controller +// +class DMX_Master +{ + public: + // Run the DMX master from a pre allocated frame buffer which + // you have fully under your own control + DMX_Master ( DMX_FrameBuffer &buffer, int readEnablePin ); + + // Run the DMX master by giving a predefined maximum number of + // channels to support + DMX_Master ( uint16_t maxChannel, int readEnablePin ); + + ~DMX_Master ( void ); + + void enable ( void ); // Start transmitting + void disable ( void ); // Stop transmitting + + // Get reference to the internal framebuffer + DMX_FrameBuffer &getBuffer ( void ); + + // Update channel values + void setChannelValue ( uint16_t channel, uint8_t value ); + void setChannelRange ( uint16_t start, uint16_t end, uint8_t value ); + + public: + // + // Manual control over the break period + // + void setAutoBreakMode ( void ); // Generated from ISR + void setManualBreakMode ( void ); // Generate manually + + uint8_t autoBreakEnabled ( void ); + + // We are waiting for a manual break to be generated + uint8_t waitingBreak ( void ); + + // Generate break and start transmission of frame + void breakAndContinue ( uint8_t breakLength_us = 100 ); + + + protected: + void setStartCode ( uint8_t value ); + + + private: + DMX_FrameBuffer m_frameBuffer; + uint8_t m_autoBreak; +}; + + +// +// DMX Slave controller +// +class DMX_Slave : public DMX_FrameBuffer +{ + public: + DMX_Slave ( DMX_FrameBuffer &buffer, int readEnablePin = -1 ); + + // nrChannels is the consecutive DMX512 slots required + // to operate this slave device + DMX_Slave ( uint16_t nrChannels, int readEnablePin = -1 ); + + ~DMX_Slave ( void ); + + void enable ( void ); // Enable receiver + void disable ( void ); // Disable receiver + + + // Get reference to the internal framebuffer + DMX_FrameBuffer &getBuffer ( void ); + + uint8_t getChannelValue ( uint16_t channel ); + + uint16_t getStartAddress ( void ); + void setStartAddress ( uint16_t ); + + + // Process incoming byte from USART + bool processIncoming ( uint8_t val, bool first = false ); + + // Register on receive complete callback in case + // of time critical applications + void onReceiveComplete ( void (*func)(unsigned short) ); + + protected: + + + private: + uint16_t m_startAddress; // Slave start address + dmx::dmxState m_state; + + static void (*event_onFrameReceived)(unsigned short channelsReceived); +}; + + +class RDM_FrameBuffer : public IFrameBuffer +{ + public: + // + // Constructor + // + RDM_FrameBuffer ( void ) {}; + ~RDM_FrameBuffer ( void ) {}; + + uint16_t getBufferSize ( void ); + + uint8_t getSlotValue ( uint16_t index ); + void setSlotValue ( uint16_t index, uint8_t value ); + void clear ( void ); + + uint8_t &operator[] ( uint16_t index ); + + public: // functions to provide access from USART + // Process incoming byte from USART, + // returns false when no more data is accepted + bool processIncoming ( uint8_t val, bool first = false ); + + // Process outgoing byte to USART + // returns false when no more data is available + bool fetchOutgoing ( volatile uint8_t *udr, bool first = false ); + + protected: + // Process received frame + virtual void processFrame ( void ) = 0; + + //private: + protected: + rdm::rdmState m_state; // State for pushing the message in + RDM_Message m_msg; + RDM_Checksum m_csRecv; // Checksum received in rdm message +}; + +// +// RDM_Responder +// +class RDM_Responder : public RDM_FrameBuffer +{ + public: + // + // m = manufacturer id (16bits) + // d1-d4 = device id (32bits) + // + RDM_Responder ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4, DMX_Slave &slave); + ~RDM_Responder ( void ); + + void setDeviceInfo + ( + uint16_t deviceModelId, + rdm::RdmProductCategory productCategory, + uint8_t personalities = 1, + uint8_t personality = 1 + ) + { + m_DeviceModelId = deviceModelId; + m_ProductCategory = productCategory; + m_Personalities = personalities; + m_Personality = personality; + }; + + // + // Set vendor software version id + // + // v1 = MOST SIGNIFICANT + // v2... + // v3... + // v4 = LEAST SIGNIFICANT + // + void setSoftwareVersionId ( uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4 ) + { + m_SoftwareVersionId[0] = v1; + m_SoftwareVersionId[1] = v2; + m_SoftwareVersionId[2] = v3; + m_SoftwareVersionId[3] = v4; + } + + // Currently no sensors and subdevices supported + // void AddSensor ( void ); + // void AddSubDevice ( void ); + + uint8_t getPersonality ( void ) { return m_Personality; }; + void setPersonality ( uint8_t personality ) { m_Personality = personality; }; + + // Register on identify device event handler + void onIdentifyDevice ( void (*func)(bool) ); + void onDeviceLabelChanged ( void (*func) (const char*, uint8_t) ); + void onDMXStartAddressChanged ( void (*func) (uint16_t) ); + void onDMXPersonalityChanged ( void (*func) (uint8_t) ); + + + // Set the device label + void setDeviceLabel ( const char *label, size_t len ); + + // Enable, Disable rdm responder + void enable ( void ) { m_rdmStatus.enabled = true; m_rdmStatus.mute = false; }; + void disable ( void ) { m_rdmStatus.enabled = false; }; + + union + { + uint8_t raw; + struct + { + uint8_t mute:1; + uint8_t ident:1; + uint8_t enabled:1; // Rdm responder enable/disable + }; + } m_rdmStatus; + + + protected: + virtual void processFrame ( void ); + + // Discovery to unque brach packets only requires + // the data part of the packet to be transmitted + // without breaks or header + void repondDiscUniqueBranch ( void ); + + // Helpers for generating response packets which + // have larger datafields + void populateDeviceInfo ( void ); + + private: + RDM_Uid m_devid; // Holds our unique device ID + uint8_t m_Personalities; // The total number of supported personalities + uint8_t m_Personality; // The currently active personality + uint16_t m_DeviceModelId; + uint8_t m_SoftwareVersionId[4]; // 32 bit Software version + rdm::RdmProductCategory m_ProductCategory; + + char m_deviceLabel[32]; // Device label + + static void (*event_onIdentifyDevice)(bool); + static void (*event_onDeviceLabelChanged)(const char*, uint8_t); + static void (*event_onDMXStartAddressChanged)(uint16_t); + static void (*event_onDMXPersonalityChanged)(uint8_t); +}; + + +#endif /* CONCEPTINETICS_H_ */ diff --git a/DMX_NeoPixels/examples/DMX_Slave/DMX_Slave.ino b/DMX_NeoPixels/examples/DMX_Slave/DMX_Slave.ino index 1e4fc2f21..655e04b72 100644 --- a/DMX_NeoPixels/examples/DMX_Slave/DMX_Slave.ino +++ b/DMX_NeoPixels/examples/DMX_Slave/DMX_Slave.ino @@ -21,7 +21,7 @@ */ -#include +#include "Conceptinetics.h" // // CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD JUMPER INSTRUCTIONS diff --git a/DMX_NeoPixels/examples/DMX_Slave/Rdm_Defines.h b/DMX_NeoPixels/examples/DMX_Slave/Rdm_Defines.h new file mode 100644 index 000000000..0accca63d --- /dev/null +++ b/DMX_NeoPixels/examples/DMX_Slave/Rdm_Defines.h @@ -0,0 +1,315 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Rdm_Defines.h - DMX library for Arduino with RDM (Remote Device Management) support + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef RDM_DEFINES_H_ +#define RDM_DEFINES_H_ + +#include "Rdm_Uid.h" + +#define RDM_MAX_DEVICELABEL_LENGTH 32 + +namespace rdm +{ + enum RdmCommandClass + { + DiscoveryCommand = 0x10, + DiscoveryCommandResponse, + GetCommand = 0x20, + GetCommandResponse, + SetCommand = 0x30, + SetCommandResponse, + }; + + enum RdmResponseTypes + { + ResponseTypeAck = 0x00, + ResponseTypeAckTimer, + ResponseTypeNackReason, + ResponseTypeAckOverflow, // Additional response data available (see spec) + }; + + enum RdmParameters + { + // Category - Network Management + DiscUniqueBranch = 0x0001, // Required + DiscMute = 0x0002, // Required + DiscUnMute = 0x0003, // Required + + CommsStatus = 0x0015, // Get,Set + + // Category - Status Collection + QueuedMessage = 0x0020, // Get [enum RdmStatusTypes] + StatusMessages = 0x0030, // Get [enum RdmStatusTypes] + StatusIdDescription = 0x0031, // Get + ClearStatusId = 0x0032, // Set + SubDeviceStatusReportThreshold = 0x0033, // Get, Set [enum RdmStatusTypes] + + // Category - RDM Information + // ** Only required if supporting parameters + // beyond the minimum required set + SupportedParameters = 0x0005, // Get, **Required + ParameterDescription = 0x0051, // Get, **Required + + // Category = Product Information + DeviceInfo = 0x0060, // Get, Required + ProductDetailIdList = 0x0070, // Get + DeviceModelDescription = 0x0080, // Get + ManufacturerLabel = 0x0081, // Get + DeviceLabel = 0x0082, // Get, Set + FactoryDefaults = 0x0009, // Get, Set ** + SoftwareVersionLabel = 0x000c, // Get + + // Category - DMX512 Setup + DmxPersonality = 0x00e0, // Get, Set + DmxPersonalityDescription = 0x00e1, // Get + DmxStartAddress = 0x00f0, // Get, Set ** Required if DMX device + SlotInfo = 0x0120, // Get + SlotDescription = 0x0121, // Get + DefaultSlotValue = 0x0122, // Get + + // Category - Sensors + // Category - Dimmer Settings + // Category - Power/Lamp Settings + // Category - Display Settings + // Category - Configuration + + // Category - Control + IdentifyDevice = 0x1000, // Get, Set, Required + ResetDevice = 0x1001, // Set + PowerState = 0x1010, // Get, Set + PerformSelftest = 0x1020, // Get, Set + SelfTestDescription = 0x1021, // Get + }; + + + enum RdmStatusTypes + { + StatusNone = 0x00, + StatusGetLastMessage, + StatusAdvisory, + StatusWarning, + StatusError, + StatusAdvisoryCleared = 0x12, + StatusWarningCleared, + StatusErrorCleared, + }; + + enum RdmProductCategory + { + CategoryNotDeclared = 0x0000, + + // Fixtures - intended as source for illumination + CategoryFixture = 0x0100, + CategoryFixtureFixed = 0x0101, + CategoryFixtureMovingYoke = 0x0102, + CategoryFixtureMovingMirror = 0x0103, + CategoryFixtureOther = 0x01ff, + + // Fixture Accessories - add-ons to fixtures or projectors + CategoryFixtureAccessory = 0x0200, + CategoryFixtureAccessoryColor = 0x0201, + CategoryFixtureAccessoryYoke = 0x0202, + CategoryFixtureAccessoryMirror = 0x0203, + CategoryFixtureAccessoryEffect = 0x0204, + CategoryFixtureAccessoryBeam = 0x0205, + CategoryFixtureAccessoryOther = 0x02ff, + + // Projectors - Light source capable of producing + // realistic images from another media + CategoryProjector = 0x0300, + CategoryProjectorFixed = 0x0301, + CategoryProjectorMovingYoke = 0x0302, + CategoryProjectorMovingMirror = 0x0303, + CategoryProjectorOther = 0x03ff, + + // Atmospheric Effect - earth/wind/fire + CategoryAtmospheric = 0x0400, + CategoryAtmosphericEffect = 0x0401, // Fogger, Hazer, Flame + CategoryAtmosphericPyro = 0x0402, + CategoryAtmosphericOther = 0x04ff, + + // Insensity Control (Specifically dimming equipment) + CategoryDimmer = 0x0500, + CategoryDimmer_AC_Incandescent = 0x0501, + CategoryDimmer_AC_Fluorescent = 0x0502, + CategoryDimmer_AC_Coldcathode = 0x0503, + CategoryDimmer_AC_Nondim = 0x0504, + CategoryDimmer_AC_Elv = 0x0505, + CategoryDimmer_AC_Other = 0x0506, + CategoryDimmer_DC_Level = 0x0507, + CategoryDimmer_DC_PWM = 0x0508, + CategoryDimmer_CS_LED = 0x0509, + CategoryDimmer_Other = 0x05ff, + + // Power control (Other than dimming equipment) + CategoryPower = 0x0600, + CategoryPowerControl = 0x0601, + CategoryPowerSource = 0x0602, + CategoryPowerOther = 0x06ff, + + // Scenic Drive - Including motorized effects + // unrelated to light source + CategoryScenic = 0x0700, + CategoryScenicDrive = 0x0701, + CategoryScenicOther = 0x07ff, + + // DMX Infrastructure, conversion and interfaces + CategoryData = 0x0800, + CategoryDataDistribution = 0x0801, + CategoryDataConversion = 0x0802, + CategoryDataOther = 0x08ff, + + // Audio visual equipment + Category_AV = 0x0900, + Category_AV_Audio = 0x0901, + Category_AV_Video = 0x0902, + Category_AV_Other = 0x09ff, + + // Parameter monitoring equipment + CategoryMonitor = 0x0a00, + CategoryMonitorACLinePower = 0x0a01, + CategoryMonitorDCPower = 0x0a02, + CategoryMonitorEnvironmental = 0x0a03, + CategoryMonitorOther = 0x0aff, + + // Controllers, backup devices + CategoryControl = 0x7000, + CategoryControlController = 0x7001, + CategoryControlBackupdevice = 0x7002, + CategoryControlOther = 0x70ff, + + // Test equipment + CategoryTest = 0x7100, + CategoryTestEquipment = 0x7101, + CategoryTestEquipmentOther = 0x71ff, + + // Miscellaneous + CategoryOther = 0x7fff, + }; + + // + // Product details not yet supported in + // this library + // + enum RdmProductDetail + { + ProductDetailNotDeclared = 0x0000, + }; + + // Only LSB + enum RdmNackReasons + { + UnknownPid = 0x00, + FormatError, + HardwareFault, + ProxyReject, + WriteProtect, + UnsupportedCmdClass, + DataOutOfRange, + BufferFull, + PacketSizeUnsupported, + SubDeviceOutOfRange, + ProxyBufferFull + }; + +}; + + +#define RDM_HDR_LEN 24 // RDM Message header length ** fixed +#define RDM_PD_MAXLEN 32 // RDM Maximum parameter data length 1 - 231 + + +union RDM_Message +{ + uint8_t d[ RDM_HDR_LEN + RDM_PD_MAXLEN ]; + struct + { + uint8_t startCode; // 0 SC_RDM + uint8_t subStartCode; // 1 SC_SUB_MESSAGE + uint8_t msgLength; // 2 Range 24 - 255 + RDM_Uid dstUid; // 3-8 Destination UID + RDM_Uid srcUid; // 9-14 Source UID (sender) + uint8_t TN; // 15 Transaction number + uint8_t portId; // 16 Port ID / Response type + uint8_t msgCount; // 17 + uint16_t subDevice; // 18,19 0=root, 0xffff=all + uint8_t CC; // 20 GET_COMMAND + uint16_t PID; // 21,22 Parameter ID + uint8_t PDL; // 23 Parameter Data length 1-231 + + uint8_t PD[RDM_PD_MAXLEN]; // Parameter Data ... variable length + }; +}; + +union RDM_Checksum +{ + uint16_t checksum; + struct + { + uint8_t csl; + uint8_t csh; + }; +}; + +struct RDM_DiscUniqueBranchPD +{ + RDM_Uid lbound; + RDM_Uid hbound; +}; + +struct RDM_DiscMuteUnMutePD +{ + uint16_t ctrlField; + +// Only for multiple ports +// RDM_Uid bindingUid; +}; + +struct RDM__DeviceInfoPD +{ + uint8_t protocolVersionMajor; + uint8_t protocolVersionMinor; + uint16_t deviceModelId; + uint16_t ProductCategory; // enum RdmProductCategory + uint8_t SoftwareVersionId[4]; + uint16_t DMX512FootPrint; + uint8_t DMX512CurrentPersonality; + uint8_t DMX512NumberPersonalities; + uint16_t DMX512StartAddress; + uint16_t SubDeviceCount; + uint8_t SensorCount; +}; + +struct RDM_DeviceGetPersonality_PD +{ + uint8_t DMX512CurrentPersonality; + uint8_t DMX512NumberPersonalities; +}; + +struct RDM_DeviceSetPersonality_PD +{ + uint8_t DMX512Personality; +}; + + +#endif /* RDM_DEFINES_H_ */ diff --git a/DMX_NeoPixels/examples/DMX_Slave/Rdm_Uid.h b/DMX_NeoPixels/examples/DMX_Slave/Rdm_Uid.h new file mode 100644 index 000000000..35c802c63 --- /dev/null +++ b/DMX_NeoPixels/examples/DMX_Slave/Rdm_Uid.h @@ -0,0 +1,101 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Rdm_Uid.h - DMX library for Arduino with RDM (Remote Device Management) support + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef RDM_UID_H_ +#define RDM_UID_H_ + +#include + +// +//48 bit UID Representation to identify RDM transponders +// +struct RDM_Uid { + + void Initialize ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4 ) + { + m_id[0] = ((uint8_t) (((uint16_t) (m)) >> 8)); + m_id[1] = (uint8_t)m; + m_id[2] = d1; + m_id[3] = d2; + m_id[4] = d3; + m_id[5] = d4; + } + + void copy ( const RDM_Uid &orig ) + { + for ( uint8_t i = 0; i < 6; i++ ) + m_id[i] = orig.m_id[i]; + } + + bool operator == ( const RDM_Uid & orig ) const + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != orig.m_id[i] ) + return false; + + return true; + } + + bool operator != ( const RDM_Uid & orig ) const + { + return !(*this == orig); + } + + bool operator < ( const RDM_Uid & v ) const + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != v.m_id[i] ) + return ( m_id[i] < v.m_id[i] ); + } + + bool operator > ( const RDM_Uid & v ) + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != v.m_id[i] ) + return ( m_id[i] > v.m_id[i] ); + } + + // + // match_mid = manufacturer id to match + // + bool isBroadcast ( uint8_t match_mid[2] ) + { + // Check for genuine broadcast on device part + for ( uint8_t i = 2; i < 6; i++ ) + if ( m_id[i] != 0xff ) + return false; + + // Broadcast or manufacturer designated broadcast + if ( (m_id[0] == 0xff && m_id[1] == 0xff) || + (m_id[0] == match_mid[0] && m_id[1] == match_mid[1]) ) + return true; + + // No broadcast + return false; + } + + uint8_t m_id[6]; //16bit manufacturer id + 32 bits device id +}; + + +#endif /* RDM_UID_H_ */ diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.cpb.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.cpb.test.skip deleted file mode 100644 index 064a28912..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.cpb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpb diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.cpc.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.cpc.test.skip deleted file mode 100644 index 79763353d..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.cpc.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpc diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.cpx_ada.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.cpx_ada.test.skip deleted file mode 100644 index d9c56cc11..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.cpx_ada.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpx_ada diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.esp32.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.esp32.test.skip deleted file mode 100644 index 5faeb5064..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.esp32.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for esp32 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.esp8266.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.esp8266.test.skip deleted file mode 100644 index 15eb13221..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.esp8266.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for esp8266 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather32u4.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather32u4.test.skip deleted file mode 100644 index eb9fd87a1..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather32u4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather32u4 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather_esp32c6.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather_esp32c6.test.skip deleted file mode 100644 index 563448c75..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather_esp32c6.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_esp32c6 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather_m0_express.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather_m0_express.test.skip deleted file mode 100644 index c1118c563..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather_m0_express.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_m0_express diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather_m4_express.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather_m4_express.test.skip deleted file mode 100644 index 9b961626f..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather_m4_express.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_m4_express diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather_rp2040.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather_rp2040.test.skip deleted file mode 100644 index 90aa322a7..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather_rp2040.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_rp2040 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather_rp2040_adalogger.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather_rp2040_adalogger.test.skip deleted file mode 100644 index 29ebf0ea0..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.feather_rp2040_adalogger.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_rp2040_adalogger diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.flora.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.flora.test.skip deleted file mode 100644 index e4cc7386e..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.flora.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for flora diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.funhouse.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.funhouse.test.skip deleted file mode 100644 index 32a4e1e1a..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.funhouse.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for funhouse diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.gemma.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.gemma.test.skip deleted file mode 100644 index 978f275e3..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.gemma.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for gemma diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.gemma_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.gemma_m0.test.skip deleted file mode 100644 index c42614d7c..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.gemma_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for gemma_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.hallowing_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.hallowing_m0.test.skip deleted file mode 100644 index ed26fdf6a..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.hallowing_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for hallowing_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.hallowing_m4_tinyusb.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.hallowing_m4_tinyusb.test.skip deleted file mode 100644 index 0ab22cb8d..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.hallowing_m4_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for hallowing_m4_tinyusb diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.ledglasses_nrf52840.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.ledglasses_nrf52840.test.skip deleted file mode 100644 index f540a7e4c..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.ledglasses_nrf52840.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for ledglasses_nrf52840 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.magtag.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.magtag.test.skip deleted file mode 100644 index 79d0d324c..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.magtag.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for magtag diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.metro_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.metro_m0.test.skip deleted file mode 100644 index 91512a898..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.metro_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.metro_m0_tinyusb.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.metro_m0_tinyusb.test.skip deleted file mode 100644 index 486e4f67e..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.metro_m0_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m0_tinyusb diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.metro_m4.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.metro_m4.test.skip deleted file mode 100644 index 5012f3737..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.metro_m4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m4 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.metro_m4_tinyusb.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.metro_m4_tinyusb.test.skip deleted file mode 100644 index 17edc54fe..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.metro_m4_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m4_tinyusb diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.monster_m4sk.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.monster_m4sk.test.skip deleted file mode 100644 index ec7f80e48..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.monster_m4sk.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for monster_m4sk diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.monster_m4sk_tinyusb.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.monster_m4sk_tinyusb.test.skip deleted file mode 100644 index a08b60688..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.monster_m4sk_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for monster_m4sk_tinyusb diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.neokeytrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.neokeytrinkey_m0.test.skip deleted file mode 100644 index 7fb03fe33..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.neokeytrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for neokeytrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.neotrellis_m4.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.neotrellis_m4.test.skip deleted file mode 100644 index eebfceae8..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.neotrellis_m4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for neotrellis_m4 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.nrf52832.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.nrf52832.test.skip deleted file mode 100644 index ee506a55a..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.nrf52832.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for nrf52832 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.nrf52840.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.nrf52840.test.skip deleted file mode 100644 index a6bcf2c9d..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.nrf52840.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for nrf52840 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.pixeltrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.pixeltrinkey_m0.test.skip deleted file mode 100644 index 4a5f3b346..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.pixeltrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pixeltrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.protrinket_5v.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.protrinket_5v.test.skip deleted file mode 100644 index ec91a95cb..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.protrinket_5v.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for protrinket_5v diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.proxlighttrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.proxlighttrinkey_m0.test.skip deleted file mode 100644 index 0d46213a9..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.proxlighttrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for proxlighttrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.pybadge.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.pybadge.test.skip deleted file mode 100644 index 82cd2ac9c..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.pybadge.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pybadge diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.pycamera_s3.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.pycamera_s3.test.skip deleted file mode 100644 index 021a63e54..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.pycamera_s3.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pycamera_s3 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.pygamer.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.pygamer.test.skip deleted file mode 100644 index 430cf639c..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.pygamer.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pygamer diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.pyportal.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.pyportal.test.skip deleted file mode 100644 index 6a18dce9f..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.pyportal.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pyportal diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.qt2040_trinkey.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.qt2040_trinkey.test.skip deleted file mode 100644 index 263748866..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.qt2040_trinkey.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qt2040_trinkey diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.qtpy_esp32s2.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.qtpy_esp32s2.test.skip deleted file mode 100644 index 627d7dd57..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.qtpy_esp32s2.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qtpy_esp32s2 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.qtpy_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.qtpy_m0.test.skip deleted file mode 100644 index fbc42f083..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.qtpy_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qtpy_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.qualia_s3_rgb666.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.qualia_s3_rgb666.test.skip deleted file mode 100644 index 1e14eea6e..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.qualia_s3_rgb666.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qualia_s3_rgb666 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.rotarytrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.rotarytrinkey_m0.test.skip deleted file mode 100644 index 8a2ec7327..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.rotarytrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for rotarytrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.sht4xtrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.sht4xtrinkey_m0.test.skip deleted file mode 100644 index 039d08b3e..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.sht4xtrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for sht4xtrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.slidetrinkey_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.slidetrinkey_m0.test.skip deleted file mode 100644 index d3f14ba82..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.slidetrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for slidetrinkey_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.trinket_5v.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.trinket_5v.test.skip deleted file mode 100644 index e2d3dded0..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.trinket_5v.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for trinket_5v diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.trinket_m0.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.trinket_m0.test.skip deleted file mode 100644 index 06ad7bf51..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.trinket_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for trinket_m0 diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.uno.test.only b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.uno.test.skip b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.uno.test.skip deleted file mode 100644 index f3e164df1..000000000 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/.uno.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for uno diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Conceptinetics.cpp b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Conceptinetics.cpp new file mode 100644 index 000000000..36ada5924 --- /dev/null +++ b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Conceptinetics.cpp @@ -0,0 +1,1233 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Conceptinetics.cpp - DMX library for Arduino + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + This code has been tested using the following hardware: + + - Arduino UNO R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino MEGA2560 R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD +*/ + + +#include "pins_arduino.h" +#include "Conceptinetics.h" + +#include +#include + +#include +#include + +#include + + +#if defined (USE_DMX_SERIAL_0) + + #if defined (USART__TXC_vect) + #define USART_TX USART__TXC_vect + #elif defined(USART_TX_vect) + #define USART_TX USART_TX_vect + #elif defined(USART0_TX_vect) + #define USART_TX USART0_TX_vect + #endif + + #if defined (USART__RXC_vect) + #define USART_RX USART__RXC_vect + #elif defined(USART_RX_vect) + #define USART_RX USART_RX_vect + #elif defined(USART0_RX_vect) + #define USART_RX USART0_RX_vect + #endif + + #if defined UDR + #define DMX_UDR UDR + #elif defined UDR0 + #define DMX_UDR UDR0 + #endif + + #if defined(UBRRH) && defined(UBRRL) + #define DMX_UBRRH UBRRH + #define DMX_UBRRL UBRRL + #elif defined(UBRR0H) && defined(UBRR0L) + #define DMX_UBRRH UBRR0H + #define DMX_UBRRL UBRR0L + #endif + + #if defined(UCSRA) + #define DMX_UCSRA UCSRA + #elif defined(UCSR0A) + #define DMX_UCSRA UCSR0A + #endif + + #if defined(UCSRB) + #define DMX_UCSRB UCSRB + #elif defined (UCSR0B) + #define DMX_UCSRB UCSR0B + #endif + + #if defined(TXEN) && defined(TXCIE) + #define DMX_TXEN TXEN + #define DMX_TXCIE TXCIE + #elif defined(TXEN0) && defined(TXCIE0) + #define DMX_TXEN TXEN0 + #define DMX_TXCIE TXCIE0 + #endif + + #if defined(RXEN) && defined(RXCIE) + #define DMX_RXEN RXEN + #define DMX_RXCIE RXCIE + #elif defined(RXEN0) && defined(RXCIE0) + #define DMX_RXEN RXEN0 + #define DMX_RXCIE RXCIE0 + #endif + + #if defined(FE) + #define DMX_FE FE + #elif defined(FE0) + #define DMX_FE FE0 + #endif + + #define RX_PIN 0 + #define TX_PIN 1 + +#elif defined (USE_DMX_SERIAL_1) + #define USART_RX USART1_RX_vect + #define USART_TX USART1_TX_vect + #define DMX_UDR UDR1 + #define DMX_UBRRH UBRR1H + #define DMX_UBRRL UBRR1L + #define DMX_UCSRA UCSR1A + #define DMX_UCSRB UCSR1B + #define DMX_TXEN TXEN1 + #define DMX_TXCIE TXCIE1 + #define DMX_RXEN RXEN1 + #define DMX_RXCIE RXCIE1 + #define DMX_FE FE1 + #define RX_PIN 19 + #define TX_PIN 18 +#elif defined (USE_DMX_SERIAL_2) + #define USART_RX USART2_RX_vect + #define USART_TX USART2_TX_vect + #define DMX_UDR UDR2 + #define DMX_UBRRH UBRR2H + #define DMX_UBRRL UBRR2L + #define DMX_UCSRA UCSR2A + #define DMX_UCSRB UCSR2B + #define DMX_TXEN TXEN2 + #define DMX_TXCIE TXCIE2 + #define DMX_RXEN RXEN2 + #define DMX_RXCIE RXCIE2 + #define DMX_FE FE2 + #define RX_PIN 17 + #define TX_PIN 16 +#elif defined (USE_DMX_SERIAL_3) + #define USART_RX USART3_RX_vect + #define USART_TX USART3_TX_vect + #define DMX_UDR UDR3 + #define DMX_UBRRH UBRR3H + #define DMX_UBRRL UBRR3L + #define DMX_UCSRA UCSR3A + #define DMX_UCSRB UCSR3B + #define DMX_TXEN TXEN3 + #define DMX_TXCIE TXCIE3 + #define DMX_RXEN RXEN3 + #define DMX_RXCIE RXCIE3 + #define DMX_FE FE3 + #define RX_PIN 14 + #define TX_PIN 15 +#endif + + +#define LOWBYTE(v) ((uint8_t) (v)) +#define HIGHBYTE(v) ((uint8_t) (((uint16_t) (v)) >> 8)) + +#define BSWAP_16(x) ( (uint8_t)((x) >> 8) | ((uint8_t)(x)) << 8 ) + +namespace isr +{ + enum isrState + { + Idle, + Break, + DmxBreak, + DmxBreakManual, + DmxStartByte, + DmxRecordData, + DmxTransmitData, + RdmBreak, + RdmStartByte, + RdmRecordData, + RdmTransmitData, + RDMTransmitComplete, + }; + + enum isrMode + { + Disabled, + Receive, + DMXTransmit, + DMXTransmitManual, /* Manual break... */ + RDMTransmit, + RDMTransmitNoInt, /* Setup uart but leave interrupt disabled */ + }; +}; + + +DMX_Master *__dmx_master; +DMX_Slave *__dmx_slave; +RDM_Responder *__rdm_responder; + +int8_t __re_pin; // R/W Pin on shield + +isr::isrState __isr_txState; // TX ISR state +isr::isrState __isr_rxState; // RX ISR state + + +void SetISRMode ( isr::isrMode ); + + +DMX_FrameBuffer::DMX_FrameBuffer ( uint16_t buffer_size ) +{ + m_refcount = (uint8_t*) malloc ( sizeof ( uint8_t ) ); + + if ( buffer_size >= DMX_MIN_FRAMESIZE && buffer_size <= DMX_MAX_FRAMESIZE ) + { + m_buffer = (uint8_t*) malloc ( buffer_size ); + if ( m_buffer != NULL ) + { + memset ( (void *)m_buffer, 0x0, buffer_size ); + m_bufferSize = buffer_size; + } + else + m_buffer = 0x0; + } + else + m_bufferSize = 0x0; + + *m_refcount++; +} + +DMX_FrameBuffer::DMX_FrameBuffer ( DMX_FrameBuffer &buffer ) +{ + // Copy references and make sure the parent object does not dispose our + // buffer when deleted and we are still active + this->m_refcount = buffer.m_refcount; + (*this->m_refcount)++; + + this->m_buffer = buffer.m_buffer; + this->m_bufferSize = buffer.m_bufferSize; +} + +DMX_FrameBuffer::~DMX_FrameBuffer ( void ) +{ + // If we are the last object using the + // allocated buffer then free it together + // with the refcounter + if ( --(*m_refcount) == 0 ) + { + if ( m_buffer ) + free ( m_buffer ); + + free ( m_refcount ); + } +} + +uint16_t DMX_FrameBuffer::getBufferSize ( void ) +{ + return m_bufferSize; +} + + +uint8_t DMX_FrameBuffer::getSlotValue ( uint16_t index ) +{ + if (index < m_bufferSize) + return m_buffer[index]; + else + return 0x0; +} + + +void DMX_FrameBuffer::setSlotValue ( uint16_t index, uint8_t value ) +{ + if ( index < m_bufferSize ) + m_buffer[index] = value; +} + + +void DMX_FrameBuffer::setSlotRange ( uint16_t start, uint16_t end, uint8_t value ) +{ + if ( start < m_bufferSize && end < m_bufferSize && start < end ) + memset ( (void *) &m_buffer[start], value, end-start+1 ); +} + +void DMX_FrameBuffer::clear ( void ) +{ + memset ( (void *) m_buffer, 0x0, m_bufferSize ); +} + +uint8_t &DMX_FrameBuffer::operator[] ( uint16_t index ) +{ + return m_buffer[index]; +} + + +DMX_Master::DMX_Master ( DMX_FrameBuffer &buffer, int readEnablePin ) +: m_frameBuffer ( buffer ), + m_autoBreak ( 1 ) // Autobreak generation is default on +{ + setStartCode ( DMX_START_CODE ); + + __re_pin = readEnablePin; + pinMode ( __re_pin, OUTPUT ); + + ::SetISRMode ( isr::Disabled ); +} + +DMX_Master::DMX_Master ( uint16_t maxChannel, int readEnablePin ) +: m_frameBuffer ( maxChannel + DMX_STARTCODE_SIZE ), + m_autoBreak ( 1 ) // Autobreak generation is default on +{ + setStartCode ( DMX_START_CODE ); + + __re_pin = readEnablePin; + pinMode ( __re_pin, OUTPUT ); + + ::SetISRMode ( isr::Disabled ); +} + +DMX_Master::~DMX_Master ( void ) +{ + disable (); // Stop sending + __dmx_master = NULL; +} + +DMX_FrameBuffer &DMX_Master::getBuffer ( void ) +{ + return m_frameBuffer; // Return reference to frame buffer +} + +void DMX_Master::setStartCode ( uint8_t value ) +{ + m_frameBuffer[0] = value; // Set the first byte in our frame buffer +} + +void DMX_Master::setChannelValue ( uint16_t channel, uint8_t value ) +{ + if ( channel > 0 ) // Prevent overwriting the start code + m_frameBuffer.setSlotValue ( channel, value ); +} + +void DMX_Master::setChannelRange ( uint16_t start, uint16_t end, uint8_t value ) +{ + if ( start > 0 ) // Prevent overwriting the start code + m_frameBuffer.setSlotRange ( start, end, value ); +} + + +void DMX_Master::enable ( void ) +{ + __dmx_master = this; + + if ( m_autoBreak ) + ::SetISRMode ( isr::DMXTransmit ); + else + ::SetISRMode ( isr::DMXTransmitManual ); +} + +void DMX_Master::disable ( void ) +{ + ::SetISRMode ( isr::Disabled ); + __dmx_master = NULL; // No active master +} + +void DMX_Master::setAutoBreakMode ( void ) { m_autoBreak = 1; } +void DMX_Master::setManualBreakMode ( void ) { m_autoBreak = 0; } +uint8_t DMX_Master::autoBreakEnabled ( void ) { return m_autoBreak; } + + +uint8_t DMX_Master::waitingBreak ( void ) +{ + return ( __isr_txState == isr::DmxBreakManual ); +} + +void DMX_Master::breakAndContinue ( uint8_t breakLength_us ) +{ + // Only execute if we are the controlling master object + if ( __dmx_master == this && __isr_txState == isr::DmxBreakManual ) + { + pinMode ( TX_PIN, OUTPUT ); + digitalWrite ( TX_PIN, LOW ); // Begin BREAK + + for (uint8_t bl=0; bl(*this); +} + + uint8_t DMX_Slave::getChannelValue ( uint16_t channel ) +{ + return getSlotValue ( channel ); +} + + +uint16_t DMX_Slave::getStartAddress ( void ) +{ + return m_startAddress; +} + +void DMX_Slave::setStartAddress ( uint16_t addr ) +{ + m_startAddress = addr; +} + +void DMX_Slave::onReceiveComplete ( void (*func)(unsigned short) ) +{ + event_onFrameReceived = func; +} + + +bool DMX_Slave::processIncoming ( uint8_t val, bool first ) +{ + static uint16_t idx; + bool rval = false; + + if ( first ) + { + // We could have received less channels then we + // expected.. but still is a complete frame + if (m_state == dmx::dmxData && event_onFrameReceived) + event_onFrameReceived (idx); + + m_state = dmx::dmxStartByte; + } + + switch ( m_state ) + { + case dmx::dmxStartByte: + setSlotValue ( 0, val ); // Store start code + idx = m_startAddress; + m_state = dmx::dmxWaitStartAddress; + + case dmx::dmxWaitStartAddress: + if ( --idx == 0 ) + m_state = dmx::dmxData; + break; + + case dmx::dmxData: + if ( idx++ < getBufferSize() ) + setSlotValue ( idx, val ); + else + { + m_state = dmx::dmxFrameReady; + + // If a onFrameReceived callback is register... + if (event_onFrameReceived) + event_onFrameReceived (idx-2); + + rval = true; + } + break; + } + + return rval; +} + + +uint16_t RDM_FrameBuffer::getBufferSize ( void ) { return sizeof ( m_msg ); } + +uint8_t RDM_FrameBuffer::getSlotValue ( uint16_t index ) +{ + if ( index < sizeof ( m_msg ) ) + return m_msg.d[index]; + else + return 0x0; +} + + +void RDM_FrameBuffer::setSlotValue ( uint16_t index, uint8_t value ) +{ + if ( index < sizeof ( m_msg ) ) + m_msg.d[index] = value; +} + +void RDM_FrameBuffer::clear ( void ) +{ + memset ( (void*)m_msg.d, 0x0, sizeof( m_msg ) ); + m_state = rdm::rdmUnknown; +} + +bool RDM_FrameBuffer::processIncoming ( uint8_t val, bool first ) +{ + static uint16_t idx; + bool rval = false; + + if ( first ) + { + m_state = rdm::rdmStartByte; + m_csRecv.checksum = (uint16_t) 0x0000; + idx = 0; + } + + // Prevent buffer overflow for large messages + if (idx >= sizeof(m_msg)) + return true; + + switch ( m_state ) + { + case rdm::rdmStartByte: + m_msg.startCode = val; + m_state = rdm::rdmSubStartCode; + break; + + case rdm::rdmSubStartCode: + if ( val != 0x01 ) + { + rval = true; // Stop processing data + break; + } + + m_msg.subStartCode = val; + m_state = rdm::rdmMessageLength; + break; + + case rdm::rdmMessageLength: + m_msg.msgLength = val; + m_state = rdm::rdmData; + m_csRecv.checksum = 0xcc + 0x01 + val; // set initial checksum + idx = 3; // buffer index for next byte + break; + + case rdm::rdmData: + m_msg.d[idx++] = val; + m_csRecv.checksum += val; + if ( idx >= m_msg.msgLength ) + m_state = rdm::rdmChecksumHigh; + break; + + case rdm::rdmChecksumHigh: + m_csRecv.csh = val; + m_state = rdm::rdmChecksumLow; + + break; + + case rdm::rdmChecksumLow: + m_csRecv.csl = val; + + if ((m_csRecv.checksum % (uint16_t)0x10000) == m_csRecv.checksum) + { + m_state = rdm::rdmFrameReady; + + // valid checksum ... start processing + processFrame (); + } + + m_state = rdm::rdmUnknown; + rval = true; + break; + }; + + return rval; +} + +bool RDM_FrameBuffer::fetchOutgoing ( volatile uint8_t *udr, bool first ) +{ + static uint16_t idx; + static uint16_t cs; + bool rval = false; + + + if ( first ) + { + m_state = rdm::rdmData; + cs = 0x0; + idx = 0; + } + + switch ( m_state ) + { + case rdm::rdmData: + cs += m_msg.d[idx]; + *udr = m_msg.d[idx++]; + if ( idx >= m_msg.msgLength ) + { + m_state = rdm::rdmChecksumHigh; + } + break; + + case rdm::rdmChecksumHigh: + *udr = (cs >> 8); + m_state = rdm::rdmChecksumLow; + break; + + case rdm::rdmChecksumLow: + *udr = (cs & 0xff); + m_state = rdm::rdmUnknown; + rval = true; + break; + + } + + return rval; +} + + +void (*RDM_Responder::event_onIdentifyDevice)(bool); +void (*RDM_Responder::event_onDeviceLabelChanged)(const char*, uint8_t); +void (*RDM_Responder::event_onDMXStartAddressChanged)(uint16_t); +void (*RDM_Responder::event_onDMXPersonalityChanged)(uint8_t); + +// +// slave parameter is only used to ensure a slave object is present before +// initializing the rdm responder class +// +RDM_Responder::RDM_Responder ( uint16_t m, uint8_t d1, uint8_t d2, + uint8_t d3, uint8_t d4, DMX_Slave &slave ) +: RDM_FrameBuffer ( ), + m_Personalities (1), // Available personlities + m_Personality (1) // Default personality eq 1. +{ + __rdm_responder = this; + m_devid.Initialize ( m, d1, d2, d3, d4 ); + + // Default software version id = 0x00000000 + memset ( (void*)m_SoftwareVersionId, 0x0, 0x4 ); + + // Rdm responder is disabled by default + m_rdmStatus.enabled = false; +} + +RDM_Responder::~RDM_Responder ( void ) +{ + __rdm_responder = NULL; +} + +void RDM_Responder::onIdentifyDevice ( void (*func)(bool) ) +{ + event_onIdentifyDevice = func; +} + +void RDM_Responder::onDeviceLabelChanged ( void (*func) (const char*, uint8_t) ) +{ + event_onDeviceLabelChanged = func; +} + +void RDM_Responder::onDMXStartAddressChanged ( void (*func) (uint16_t) ) +{ + event_onDMXStartAddressChanged = func; +} + +void RDM_Responder::onDMXPersonalityChanged ( void (*func) (uint8_t) ) +{ + event_onDMXPersonalityChanged = func; +} + +void RDM_Responder::setDeviceLabel ( const char *label, size_t len ) +{ + if ( len > RDM_MAX_DEVICELABEL_LENGTH ) + len = RDM_MAX_DEVICELABEL_LENGTH; + + memcpy ( (void *)m_deviceLabel, (void *)label, len ); +} + +#define UID_0 0x12 //ESTA device ID +#define UID_1 0x34 +#define UID_2 0x56 +#define UID_3 0x88 +#define UID_4 0x00 +#define UID_5 0x00 + +#define UID_CS (0xFF *6 +UID_0 +UID_1 +UID_2 +UID_3 +UID_4 +UID_5) + +void RDM_Responder::repondDiscUniqueBranch ( void ) +{ + #if defined(UCSRB) + UCSRB = (1<>8) | 0xaa; + response [21] = (cs>>8) | 0x55; + response [22] = (cs&0xff) | 0xaa; + response [23] = (cs&0xff) | 0x55; + + + // Table 3-2 ANSI_E1-20-2010 <2ms + _delay_us ( MIN_RESPONDER_PACKET_SPACING_USEC ); + + // Fix: 2017, Feb 28: Moved data enable down in order to limit line in marking state time to comply with + // section 3.2.3 + // Set shield to transmit mode (turn arround) + digitalWrite ( __re_pin, HIGH ); + + + for ( int i=0; i<24; i++ ) + { + // Wait until data register is empty + #if defined (UCSR0A) && defined (UDRE0) + while((UCSR0A & (1 <(m_msg.PD); + + pd->protocolVersionMajor = 0x01; + pd->protocolVersionMinor = 0x00; + pd->deviceModelId = BSWAP_16(m_DeviceModelId); + pd->ProductCategory = BSWAP_16(m_ProductCategory); + memcpy ( (void*)pd->SoftwareVersionId, (void*)m_SoftwareVersionId, 4 ); + pd->DMX512FootPrint = BSWAP_16(__dmx_slave->getBufferSize()-1); // eq buffersize-startbyte + pd->DMX512CurrentPersonality = m_Personality; + pd->DMX512NumberPersonalities = m_Personalities; + pd->DMX512StartAddress = BSWAP_16(__dmx_slave->getStartAddress()); + + pd->SubDeviceCount = 0x0; // Sub devices are not supported by this library + pd->SensorCount = 0x0; // Sensors are not yet supported + + m_msg.PDL = sizeof (RDM__DeviceInfoPD); +} + +const uint8_t ManufacturerLabel_P[] PROGMEM = "Conceptinetics"; + +void RDM_Responder::processFrame ( void ) +{ + // If packet is a general broadcast + if ( + m_msg.dstUid.isBroadcast (m_devid.m_id) || + m_devid == m_msg.dstUid + ) + { + // Set default response type + m_msg.portId = rdm::ResponseTypeAck; + + switch ( BSWAP_16(m_msg.PID) ) + { + case rdm::DiscUniqueBranch: + // Check if we are inside the given unique branch... + if ( !m_rdmStatus.mute && + reinterpret_cast(m_msg.PD)->lbound < m_devid && + reinterpret_cast(m_msg.PD)->hbound > m_devid ) + { + // Discovery messages are responded with data only and no breaks + repondDiscUniqueBranch (); + } + break; + + case rdm::DiscMute: + reinterpret_cast(m_msg.PD)->ctrlField = 0x0; + m_msg.PDL = sizeof ( RDM_DiscMuteUnMutePD ); + m_rdmStatus.mute = true; + break; + + case rdm::DiscUnMute: + reinterpret_cast(m_msg.PD)->ctrlField = 0x0; + m_msg.PDL = sizeof ( RDM_DiscMuteUnMutePD ); + m_rdmStatus.mute = false; + break; + + case rdm::SupportedParameters: + // + // Temporary solution... this will become dynamic + // in a later version... + // + m_msg.PD[0] = HIGHBYTE(rdm::DmxStartAddress); // MSB + m_msg.PD[1] = LOWBYTE (rdm::DmxStartAddress); // LSB + + m_msg.PD[2] = HIGHBYTE(rdm::DmxPersonality); + m_msg.PD[3] = LOWBYTE (rdm::DmxPersonality); + + m_msg.PD[4] = HIGHBYTE(rdm::ManufacturerLabel); + m_msg.PD[5] = LOWBYTE (rdm::ManufacturerLabel); + + m_msg.PD[6] = HIGHBYTE(rdm::DeviceLabel); + m_msg.PD[7] = LOWBYTE (rdm::DeviceLabel); + + m_msg.PDL = 0x6; + break; + + // Only for manufacturer specific parameters + // case rdm::ParameterDescription: + // break; + + case rdm::DeviceInfo: + if ( m_msg.CC == rdm::GetCommand ) + populateDeviceInfo (); + break; + + case rdm::DmxStartAddress: + if ( m_msg.CC == rdm::GetCommand ) + { + m_msg.PD[0] = HIGHBYTE(__dmx_slave->getStartAddress ()); + m_msg.PD[1] = LOWBYTE (__dmx_slave->getStartAddress ()); + m_msg.PDL = 0x2; + } + else // if ( m_msg.CC == rdm::SetCommand ) + { + __dmx_slave->setStartAddress ( (m_msg.PD[0] << 8) + m_msg.PD[1] ); + m_msg.PDL = 0x0; + + if ( event_onDMXStartAddressChanged ) + event_onDMXStartAddressChanged ( (m_msg.PD[0] << 8) + m_msg.PD[1] ); + } + break; + + case rdm::DmxPersonality: + if ( m_msg.CC == rdm::GetCommand ) + { + reinterpret_cast + (m_msg.PD)->DMX512CurrentPersonality = m_Personality; + reinterpret_cast + (m_msg.PD)->DMX512CurrentPersonality = m_Personalities; + m_msg.PDL = sizeof (RDM_DeviceGetPersonality_PD); + } + else // if ( m_msg.CC == rdm::SetCommand ) + { + m_Personality = reinterpret_cast + (m_msg.PD)->DMX512Personality; + m_msg.PDL = 0x0; + + if ( event_onDMXPersonalityChanged ) + event_onDMXPersonalityChanged ( m_Personality ); + } + break; + + case rdm::IdentifyDevice: + if ( m_msg.CC == rdm::GetCommand ) + { + m_msg.PD[0] = (uint8_t)(m_rdmStatus.ident ? 1 : 0); + m_msg.PDL = 0x1; + } + else if ( m_msg.CC == rdm::SetCommand ) + { + // Look into first byte to see whether identification + // is turned on or off + m_rdmStatus.ident = m_msg.PD[0] ? true : false; + if ( event_onIdentifyDevice ) + event_onIdentifyDevice ( m_rdmStatus.ident ); + + m_msg.PDL = 0x0; + } + break; + + case rdm::ManufacturerLabel: + if ( m_msg.CC == rdm::GetCommand ) + { + memcpy_P( (void*)m_msg.PD, ManufacturerLabel_P, sizeof(ManufacturerLabel_P) ); + m_msg.PDL = sizeof ( ManufacturerLabel_P ); + } + break; + + case rdm::DeviceLabel: + if ( m_msg.CC == rdm::GetCommand ) + { + memcpy ( m_msg.PD, (void*) m_deviceLabel, 32 ); + m_msg.PDL = 32; + } + else if ( m_msg.CC == rdm::SetCommand ) + { + memset ( (void*) m_deviceLabel, ' ', 32 ); + memcpy ( (void*) m_deviceLabel, m_msg.PD, (m_msg.PDL < 32 ? m_msg.PDL : 32) ); + m_msg.PDL = 0; + + // Notify application + if ( event_onDeviceLabelChanged ) + event_onDeviceLabelChanged ( m_deviceLabel, 32 ); + } + break; + + + default: + // Unknown parameter ID response + m_msg.portId = rdm::ResponseTypeNackReason; + m_msg.PD[0] = rdm::UnknownPid; + m_msg.PD[1] = 0x0; + m_msg.PDL = 0x2; + break; + }; + } + + // + // Only respond if this this message + // was destined to us only + if ( m_msg.dstUid == m_devid ) + { + m_msg.startCode = RDM_START_CODE; + m_msg.subStartCode = 0x01; + m_msg.msgLength = RDM_HDR_LEN + m_msg.PDL; + m_msg.msgCount = 0; + + /* + switch ( m_msg.msg.CC ) + { + case rdm::DiscoveryCommand: + m_msg.msg.CC = rdm::DiscoveryCommandResponse; + break; + case rdm::GetCommand: + m_msg.msg.CC = rdm::GetCommandResponse; + break; + case rdm::SetCommand: + m_msg.msg.CC = rdm::SetCommandResponse; + break; + } + */ + /* Above replaced by next line */ + m_msg.CC++; + + m_msg.dstUid.copy ( m_msg.srcUid ); + m_msg.srcUid.copy ( m_devid ); + + //_delay_us ( MIN_RESPONDER_PACKET_SPACING_USEC ); + SetISRMode ( isr::RDMTransmit ); + + } +} + + +void SetISRMode ( isr::isrMode mode ) +{ + uint8_t readEnable; + +#if defined(USE_DMX_SERIAL_0) + #if defined(UCSRB) && defined (UCSRC) + UCSRC |= (1<>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + + // Prepare before kicking off ISR + //DMX_UDR = 0x0; + __isr_rxState = isr::Idle; + readEnable = LOW; + DMX_UCSRB = (1<>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + DMX_UDR = 0x0; + DMX_UCSRB = 0x0; + readEnable = HIGH; + __isr_txState = isr::DmxBreakManual; + break; + + case isr::RDMTransmit: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + //DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + //DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + DMX_UCSRB = (1< -1) + digitalWrite ( __re_pin, readEnable ); + +} + +// +// TX UART (DMX Transmission ISR) +// +ISR (USART_TX) +{ + static uint16_t current_slot; + + switch ( __isr_txState ) + { + case isr::DmxBreak: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + if ( __isr_txState == isr::DmxBreak ) + __isr_txState = isr::DmxStartByte; + + break; + + case isr::DmxStartByte: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + current_slot = 0; + DMX_UDR = __dmx_master->getBuffer()[ current_slot++ ]; + __isr_txState = isr::DmxTransmitData; + break; + + + case isr::DmxTransmitData: + // NOTE: we always send full frames of 513 bytes, this will bring us + // close to 40 frames / sec with no interslot delays + #ifdef DMX_IBG + _delay_us (DMX_IBG); + #endif + + DMX_UDR = __dmx_master->getBuffer().getSlotValue( current_slot++ ); + + // Send 512 channels + if ( current_slot >= DMX_MAX_FRAMESIZE ) + { + if ( __dmx_master->autoBreakEnabled () ) + __isr_txState = isr::DmxBreak; + else + SetISRMode ( isr::DMXTransmitManual ); + } + + break; + +/* case isr::RdmBreak: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + __isr_txState = isr::RdmStartByte; + + break; +*/ + + case isr::RdmStartByte: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + + // Write start byte + __rdm_responder->fetchOutgoing ( &DMX_UDR, true ); + __isr_txState = isr::RdmTransmitData; + + break; + + case isr::RdmTransmitData: + // Write rest of data + if ( __rdm_responder->fetchOutgoing ( &DMX_UDR ) ) + __isr_txState = isr::RDMTransmitComplete; + break; + + case isr::RDMTransmitComplete: + SetISRMode ( isr::Receive ); // Start waitin for new data + __isr_txState = isr::Idle; // No tx state + break; + + } +} + + + +// +// RX UART (DMX Reception ISR) +// +ISR (USART_RX) +{ + uint8_t usart_state = DMX_UCSRA; + uint8_t usart_data = DMX_UDR; + + // + // Check for framing error and reset if found + // A framing most likely* indicate a break in our ocasion + // + if ( usart_state & (1<processIncoming ( usart_data, true ); + __isr_rxState = isr::DmxRecordData; + } + else if ( __rdm_responder && + usart_data == RDM_START_CODE && + __rdm_responder->m_rdmStatus.enabled ) + { + // __rdm_responder->clear (); + __rdm_responder->processIncoming ( usart_data, true ); + __isr_rxState = isr::RdmRecordData; + } + else + { + __isr_rxState = isr::Idle; + } + break; + + // Process DMX Data + case isr::DmxRecordData: + if ( __dmx_slave->processIncoming ( usart_data ) ) + __isr_rxState = isr::Idle; + break; + + // Process RDM Data + case isr::RdmRecordData: + if ( __rdm_responder->processIncoming ( usart_data ) ) + __isr_rxState = isr::Idle; + break; + + } + +} + diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Conceptinetics.h b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Conceptinetics.h new file mode 100644 index 000000000..0f03da619 --- /dev/null +++ b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Conceptinetics.h @@ -0,0 +1,383 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Conceptinetics.h - DMX library for Arduino + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + This code has been tested using the following hardware: + + - Arduino / Genuino UNO R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino / Genuino MEGA2560 R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino / Genuino Leonardo using a CTC-DRA-13-R2 ISOLATED DMX-RDM SHIELD + + - CTC-DRA-10-1 and CTC-DRA-10-R2 is the Non-isolated costs effective DMX-RDM shield +*/ + + +#ifndef CONCEPTINETICS_H_ +#define CONCEPTINETICS_H_ + +#include +#include + +#include "Rdm_Uid.h" +#include "Rdm_Defines.h" + +#define DMX_MAX_FRAMESIZE 513 // Startbyte + 512 Slots +#define DMX_MIN_FRAMESIZE 2 // Startbyte + 1 Slot + +#define DMX_MAX_FRAMECHANNELS 512 // Maxmim number of channer per frame + +#define DMX_STARTCODE_SIZE 1 // Size of startcode in bytes + +#define DMX_START_CODE 0x0 // Start code for a DMX frame +#define RDM_START_CODE 0xcc // Start code for a RDM frame + +// Uncomment to enable Inter slot delay ) (avg < 76uSec) ... +// mimum is zero according to specification +// #define DMX_IBG 10 // Inter slot time + +// Speed your Arduino is running on in Hz. +#define F_OSC 16000000UL + +// DMX Baudrate, this should be 250000 +#define DMX_BAUD_RATE 250000 + +// The baudrate used to automaticly generate a break within +// your ISR.. make it lower to generate longer breaks +//#define DMX_BREAK_RATE 99900 + +// 2017, Feb 28: Set to appox 176us +#define DMX_BREAK_RATE 49950 + +// Tabel 3-2 ANSI_E1-20-2010 +// Minimum time to allow the datalink to 'turn arround' +#define MIN_RESPONDER_PACKET_SPACING_USEC 176 /*176*/ + +// Define which serial port to use as DMX port, only one can be +// selected at the time by uncommenting one of the following +// lines +#define USE_DMX_SERIAL_0 +//#define USE_DMX_SERIAL_1 +//#define USE_DMX_SERIAL_2 +//#define USE_DMX_SERIAL_3 + +namespace dmx +{ + enum dmxState + { + dmxUnknown, + dmxStartByte, + dmxWaitStartAddress, + dmxData, + dmxFrameReady, + }; +}; + +namespace rdm +{ + enum rdmState + { + rdmUnknown, + rdmStartByte, + rdmSubStartCode, + rdmMessageLength, + rdmData, + rdmChecksumHigh, + rdmChecksumLow, + rdmFrameReady, + }; +}; + +struct IFrameBuffer +{ + virtual uint16_t getBufferSize ( void ) = 0; + + virtual uint8_t getSlotValue ( uint16_t index ) = 0; + virtual void setSlotValue ( uint16_t index, uint8_t value ) = 0; +}; + +class DMX_FrameBuffer : IFrameBuffer +{ + public: + // + // Constructor buffersize = 1-513 + // + DMX_FrameBuffer ( uint16_t buffer_size ); + DMX_FrameBuffer ( DMX_FrameBuffer &buffer ); + ~DMX_FrameBuffer ( void ); + + uint16_t getBufferSize ( void ); + + uint8_t getSlotValue ( uint16_t index ); + void setSlotValue ( uint16_t index, uint8_t value ); + void setSlotRange ( uint16_t start, uint16_t end, uint8_t value ); + void clear ( void ); + + uint8_t &operator[] ( uint16_t index ); + + private: + + uint8_t *m_refcount; + uint16_t m_bufferSize; + uint8_t *m_buffer; +}; + + +// +// DMX Master controller +// +class DMX_Master +{ + public: + // Run the DMX master from a pre allocated frame buffer which + // you have fully under your own control + DMX_Master ( DMX_FrameBuffer &buffer, int readEnablePin ); + + // Run the DMX master by giving a predefined maximum number of + // channels to support + DMX_Master ( uint16_t maxChannel, int readEnablePin ); + + ~DMX_Master ( void ); + + void enable ( void ); // Start transmitting + void disable ( void ); // Stop transmitting + + // Get reference to the internal framebuffer + DMX_FrameBuffer &getBuffer ( void ); + + // Update channel values + void setChannelValue ( uint16_t channel, uint8_t value ); + void setChannelRange ( uint16_t start, uint16_t end, uint8_t value ); + + public: + // + // Manual control over the break period + // + void setAutoBreakMode ( void ); // Generated from ISR + void setManualBreakMode ( void ); // Generate manually + + uint8_t autoBreakEnabled ( void ); + + // We are waiting for a manual break to be generated + uint8_t waitingBreak ( void ); + + // Generate break and start transmission of frame + void breakAndContinue ( uint8_t breakLength_us = 100 ); + + + protected: + void setStartCode ( uint8_t value ); + + + private: + DMX_FrameBuffer m_frameBuffer; + uint8_t m_autoBreak; +}; + + +// +// DMX Slave controller +// +class DMX_Slave : public DMX_FrameBuffer +{ + public: + DMX_Slave ( DMX_FrameBuffer &buffer, int readEnablePin = -1 ); + + // nrChannels is the consecutive DMX512 slots required + // to operate this slave device + DMX_Slave ( uint16_t nrChannels, int readEnablePin = -1 ); + + ~DMX_Slave ( void ); + + void enable ( void ); // Enable receiver + void disable ( void ); // Disable receiver + + + // Get reference to the internal framebuffer + DMX_FrameBuffer &getBuffer ( void ); + + uint8_t getChannelValue ( uint16_t channel ); + + uint16_t getStartAddress ( void ); + void setStartAddress ( uint16_t ); + + + // Process incoming byte from USART + bool processIncoming ( uint8_t val, bool first = false ); + + // Register on receive complete callback in case + // of time critical applications + void onReceiveComplete ( void (*func)(unsigned short) ); + + protected: + + + private: + uint16_t m_startAddress; // Slave start address + dmx::dmxState m_state; + + static void (*event_onFrameReceived)(unsigned short channelsReceived); +}; + + +class RDM_FrameBuffer : public IFrameBuffer +{ + public: + // + // Constructor + // + RDM_FrameBuffer ( void ) {}; + ~RDM_FrameBuffer ( void ) {}; + + uint16_t getBufferSize ( void ); + + uint8_t getSlotValue ( uint16_t index ); + void setSlotValue ( uint16_t index, uint8_t value ); + void clear ( void ); + + uint8_t &operator[] ( uint16_t index ); + + public: // functions to provide access from USART + // Process incoming byte from USART, + // returns false when no more data is accepted + bool processIncoming ( uint8_t val, bool first = false ); + + // Process outgoing byte to USART + // returns false when no more data is available + bool fetchOutgoing ( volatile uint8_t *udr, bool first = false ); + + protected: + // Process received frame + virtual void processFrame ( void ) = 0; + + //private: + protected: + rdm::rdmState m_state; // State for pushing the message in + RDM_Message m_msg; + RDM_Checksum m_csRecv; // Checksum received in rdm message +}; + +// +// RDM_Responder +// +class RDM_Responder : public RDM_FrameBuffer +{ + public: + // + // m = manufacturer id (16bits) + // d1-d4 = device id (32bits) + // + RDM_Responder ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4, DMX_Slave &slave); + ~RDM_Responder ( void ); + + void setDeviceInfo + ( + uint16_t deviceModelId, + rdm::RdmProductCategory productCategory, + uint8_t personalities = 1, + uint8_t personality = 1 + ) + { + m_DeviceModelId = deviceModelId; + m_ProductCategory = productCategory; + m_Personalities = personalities; + m_Personality = personality; + }; + + // + // Set vendor software version id + // + // v1 = MOST SIGNIFICANT + // v2... + // v3... + // v4 = LEAST SIGNIFICANT + // + void setSoftwareVersionId ( uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4 ) + { + m_SoftwareVersionId[0] = v1; + m_SoftwareVersionId[1] = v2; + m_SoftwareVersionId[2] = v3; + m_SoftwareVersionId[3] = v4; + } + + // Currently no sensors and subdevices supported + // void AddSensor ( void ); + // void AddSubDevice ( void ); + + uint8_t getPersonality ( void ) { return m_Personality; }; + void setPersonality ( uint8_t personality ) { m_Personality = personality; }; + + // Register on identify device event handler + void onIdentifyDevice ( void (*func)(bool) ); + void onDeviceLabelChanged ( void (*func) (const char*, uint8_t) ); + void onDMXStartAddressChanged ( void (*func) (uint16_t) ); + void onDMXPersonalityChanged ( void (*func) (uint8_t) ); + + + // Set the device label + void setDeviceLabel ( const char *label, size_t len ); + + // Enable, Disable rdm responder + void enable ( void ) { m_rdmStatus.enabled = true; m_rdmStatus.mute = false; }; + void disable ( void ) { m_rdmStatus.enabled = false; }; + + union + { + uint8_t raw; + struct + { + uint8_t mute:1; + uint8_t ident:1; + uint8_t enabled:1; // Rdm responder enable/disable + }; + } m_rdmStatus; + + + protected: + virtual void processFrame ( void ); + + // Discovery to unque brach packets only requires + // the data part of the packet to be transmitted + // without breaks or header + void repondDiscUniqueBranch ( void ); + + // Helpers for generating response packets which + // have larger datafields + void populateDeviceInfo ( void ); + + private: + RDM_Uid m_devid; // Holds our unique device ID + uint8_t m_Personalities; // The total number of supported personalities + uint8_t m_Personality; // The currently active personality + uint16_t m_DeviceModelId; + uint8_t m_SoftwareVersionId[4]; // 32 bit Software version + rdm::RdmProductCategory m_ProductCategory; + + char m_deviceLabel[32]; // Device label + + static void (*event_onIdentifyDevice)(bool); + static void (*event_onDeviceLabelChanged)(const char*, uint8_t); + static void (*event_onDMXStartAddressChanged)(uint16_t); + static void (*event_onDMXPersonalityChanged)(uint8_t); +}; + + +#endif /* CONCEPTINETICS_H_ */ diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/DMX_Slave_Signal_Timeout.ino b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/DMX_Slave_Signal_Timeout.ino index d36848135..617c323fa 100644 --- a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/DMX_Slave_Signal_Timeout.ino +++ b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/DMX_Slave_Signal_Timeout.ino @@ -21,7 +21,7 @@ */ -#include +#include "Conceptinetics.h" // // CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD JUMPER INSTRUCTIONS diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Rdm_Defines.h b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Rdm_Defines.h new file mode 100644 index 000000000..0accca63d --- /dev/null +++ b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Rdm_Defines.h @@ -0,0 +1,315 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Rdm_Defines.h - DMX library for Arduino with RDM (Remote Device Management) support + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef RDM_DEFINES_H_ +#define RDM_DEFINES_H_ + +#include "Rdm_Uid.h" + +#define RDM_MAX_DEVICELABEL_LENGTH 32 + +namespace rdm +{ + enum RdmCommandClass + { + DiscoveryCommand = 0x10, + DiscoveryCommandResponse, + GetCommand = 0x20, + GetCommandResponse, + SetCommand = 0x30, + SetCommandResponse, + }; + + enum RdmResponseTypes + { + ResponseTypeAck = 0x00, + ResponseTypeAckTimer, + ResponseTypeNackReason, + ResponseTypeAckOverflow, // Additional response data available (see spec) + }; + + enum RdmParameters + { + // Category - Network Management + DiscUniqueBranch = 0x0001, // Required + DiscMute = 0x0002, // Required + DiscUnMute = 0x0003, // Required + + CommsStatus = 0x0015, // Get,Set + + // Category - Status Collection + QueuedMessage = 0x0020, // Get [enum RdmStatusTypes] + StatusMessages = 0x0030, // Get [enum RdmStatusTypes] + StatusIdDescription = 0x0031, // Get + ClearStatusId = 0x0032, // Set + SubDeviceStatusReportThreshold = 0x0033, // Get, Set [enum RdmStatusTypes] + + // Category - RDM Information + // ** Only required if supporting parameters + // beyond the minimum required set + SupportedParameters = 0x0005, // Get, **Required + ParameterDescription = 0x0051, // Get, **Required + + // Category = Product Information + DeviceInfo = 0x0060, // Get, Required + ProductDetailIdList = 0x0070, // Get + DeviceModelDescription = 0x0080, // Get + ManufacturerLabel = 0x0081, // Get + DeviceLabel = 0x0082, // Get, Set + FactoryDefaults = 0x0009, // Get, Set ** + SoftwareVersionLabel = 0x000c, // Get + + // Category - DMX512 Setup + DmxPersonality = 0x00e0, // Get, Set + DmxPersonalityDescription = 0x00e1, // Get + DmxStartAddress = 0x00f0, // Get, Set ** Required if DMX device + SlotInfo = 0x0120, // Get + SlotDescription = 0x0121, // Get + DefaultSlotValue = 0x0122, // Get + + // Category - Sensors + // Category - Dimmer Settings + // Category - Power/Lamp Settings + // Category - Display Settings + // Category - Configuration + + // Category - Control + IdentifyDevice = 0x1000, // Get, Set, Required + ResetDevice = 0x1001, // Set + PowerState = 0x1010, // Get, Set + PerformSelftest = 0x1020, // Get, Set + SelfTestDescription = 0x1021, // Get + }; + + + enum RdmStatusTypes + { + StatusNone = 0x00, + StatusGetLastMessage, + StatusAdvisory, + StatusWarning, + StatusError, + StatusAdvisoryCleared = 0x12, + StatusWarningCleared, + StatusErrorCleared, + }; + + enum RdmProductCategory + { + CategoryNotDeclared = 0x0000, + + // Fixtures - intended as source for illumination + CategoryFixture = 0x0100, + CategoryFixtureFixed = 0x0101, + CategoryFixtureMovingYoke = 0x0102, + CategoryFixtureMovingMirror = 0x0103, + CategoryFixtureOther = 0x01ff, + + // Fixture Accessories - add-ons to fixtures or projectors + CategoryFixtureAccessory = 0x0200, + CategoryFixtureAccessoryColor = 0x0201, + CategoryFixtureAccessoryYoke = 0x0202, + CategoryFixtureAccessoryMirror = 0x0203, + CategoryFixtureAccessoryEffect = 0x0204, + CategoryFixtureAccessoryBeam = 0x0205, + CategoryFixtureAccessoryOther = 0x02ff, + + // Projectors - Light source capable of producing + // realistic images from another media + CategoryProjector = 0x0300, + CategoryProjectorFixed = 0x0301, + CategoryProjectorMovingYoke = 0x0302, + CategoryProjectorMovingMirror = 0x0303, + CategoryProjectorOther = 0x03ff, + + // Atmospheric Effect - earth/wind/fire + CategoryAtmospheric = 0x0400, + CategoryAtmosphericEffect = 0x0401, // Fogger, Hazer, Flame + CategoryAtmosphericPyro = 0x0402, + CategoryAtmosphericOther = 0x04ff, + + // Insensity Control (Specifically dimming equipment) + CategoryDimmer = 0x0500, + CategoryDimmer_AC_Incandescent = 0x0501, + CategoryDimmer_AC_Fluorescent = 0x0502, + CategoryDimmer_AC_Coldcathode = 0x0503, + CategoryDimmer_AC_Nondim = 0x0504, + CategoryDimmer_AC_Elv = 0x0505, + CategoryDimmer_AC_Other = 0x0506, + CategoryDimmer_DC_Level = 0x0507, + CategoryDimmer_DC_PWM = 0x0508, + CategoryDimmer_CS_LED = 0x0509, + CategoryDimmer_Other = 0x05ff, + + // Power control (Other than dimming equipment) + CategoryPower = 0x0600, + CategoryPowerControl = 0x0601, + CategoryPowerSource = 0x0602, + CategoryPowerOther = 0x06ff, + + // Scenic Drive - Including motorized effects + // unrelated to light source + CategoryScenic = 0x0700, + CategoryScenicDrive = 0x0701, + CategoryScenicOther = 0x07ff, + + // DMX Infrastructure, conversion and interfaces + CategoryData = 0x0800, + CategoryDataDistribution = 0x0801, + CategoryDataConversion = 0x0802, + CategoryDataOther = 0x08ff, + + // Audio visual equipment + Category_AV = 0x0900, + Category_AV_Audio = 0x0901, + Category_AV_Video = 0x0902, + Category_AV_Other = 0x09ff, + + // Parameter monitoring equipment + CategoryMonitor = 0x0a00, + CategoryMonitorACLinePower = 0x0a01, + CategoryMonitorDCPower = 0x0a02, + CategoryMonitorEnvironmental = 0x0a03, + CategoryMonitorOther = 0x0aff, + + // Controllers, backup devices + CategoryControl = 0x7000, + CategoryControlController = 0x7001, + CategoryControlBackupdevice = 0x7002, + CategoryControlOther = 0x70ff, + + // Test equipment + CategoryTest = 0x7100, + CategoryTestEquipment = 0x7101, + CategoryTestEquipmentOther = 0x71ff, + + // Miscellaneous + CategoryOther = 0x7fff, + }; + + // + // Product details not yet supported in + // this library + // + enum RdmProductDetail + { + ProductDetailNotDeclared = 0x0000, + }; + + // Only LSB + enum RdmNackReasons + { + UnknownPid = 0x00, + FormatError, + HardwareFault, + ProxyReject, + WriteProtect, + UnsupportedCmdClass, + DataOutOfRange, + BufferFull, + PacketSizeUnsupported, + SubDeviceOutOfRange, + ProxyBufferFull + }; + +}; + + +#define RDM_HDR_LEN 24 // RDM Message header length ** fixed +#define RDM_PD_MAXLEN 32 // RDM Maximum parameter data length 1 - 231 + + +union RDM_Message +{ + uint8_t d[ RDM_HDR_LEN + RDM_PD_MAXLEN ]; + struct + { + uint8_t startCode; // 0 SC_RDM + uint8_t subStartCode; // 1 SC_SUB_MESSAGE + uint8_t msgLength; // 2 Range 24 - 255 + RDM_Uid dstUid; // 3-8 Destination UID + RDM_Uid srcUid; // 9-14 Source UID (sender) + uint8_t TN; // 15 Transaction number + uint8_t portId; // 16 Port ID / Response type + uint8_t msgCount; // 17 + uint16_t subDevice; // 18,19 0=root, 0xffff=all + uint8_t CC; // 20 GET_COMMAND + uint16_t PID; // 21,22 Parameter ID + uint8_t PDL; // 23 Parameter Data length 1-231 + + uint8_t PD[RDM_PD_MAXLEN]; // Parameter Data ... variable length + }; +}; + +union RDM_Checksum +{ + uint16_t checksum; + struct + { + uint8_t csl; + uint8_t csh; + }; +}; + +struct RDM_DiscUniqueBranchPD +{ + RDM_Uid lbound; + RDM_Uid hbound; +}; + +struct RDM_DiscMuteUnMutePD +{ + uint16_t ctrlField; + +// Only for multiple ports +// RDM_Uid bindingUid; +}; + +struct RDM__DeviceInfoPD +{ + uint8_t protocolVersionMajor; + uint8_t protocolVersionMinor; + uint16_t deviceModelId; + uint16_t ProductCategory; // enum RdmProductCategory + uint8_t SoftwareVersionId[4]; + uint16_t DMX512FootPrint; + uint8_t DMX512CurrentPersonality; + uint8_t DMX512NumberPersonalities; + uint16_t DMX512StartAddress; + uint16_t SubDeviceCount; + uint8_t SensorCount; +}; + +struct RDM_DeviceGetPersonality_PD +{ + uint8_t DMX512CurrentPersonality; + uint8_t DMX512NumberPersonalities; +}; + +struct RDM_DeviceSetPersonality_PD +{ + uint8_t DMX512Personality; +}; + + +#endif /* RDM_DEFINES_H_ */ diff --git a/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Rdm_Uid.h b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Rdm_Uid.h new file mode 100644 index 000000000..35c802c63 --- /dev/null +++ b/DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Rdm_Uid.h @@ -0,0 +1,101 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Rdm_Uid.h - DMX library for Arduino with RDM (Remote Device Management) support + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef RDM_UID_H_ +#define RDM_UID_H_ + +#include + +// +//48 bit UID Representation to identify RDM transponders +// +struct RDM_Uid { + + void Initialize ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4 ) + { + m_id[0] = ((uint8_t) (((uint16_t) (m)) >> 8)); + m_id[1] = (uint8_t)m; + m_id[2] = d1; + m_id[3] = d2; + m_id[4] = d3; + m_id[5] = d4; + } + + void copy ( const RDM_Uid &orig ) + { + for ( uint8_t i = 0; i < 6; i++ ) + m_id[i] = orig.m_id[i]; + } + + bool operator == ( const RDM_Uid & orig ) const + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != orig.m_id[i] ) + return false; + + return true; + } + + bool operator != ( const RDM_Uid & orig ) const + { + return !(*this == orig); + } + + bool operator < ( const RDM_Uid & v ) const + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != v.m_id[i] ) + return ( m_id[i] < v.m_id[i] ); + } + + bool operator > ( const RDM_Uid & v ) + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != v.m_id[i] ) + return ( m_id[i] > v.m_id[i] ); + } + + // + // match_mid = manufacturer id to match + // + bool isBroadcast ( uint8_t match_mid[2] ) + { + // Check for genuine broadcast on device part + for ( uint8_t i = 2; i < 6; i++ ) + if ( m_id[i] != 0xff ) + return false; + + // Broadcast or manufacturer designated broadcast + if ( (m_id[0] == 0xff && m_id[1] == 0xff) || + (m_id[0] == match_mid[0] && m_id[1] == match_mid[1]) ) + return true; + + // No broadcast + return false; + } + + uint8_t m_id[6]; //16bit manufacturer id + 32 bits device id +}; + + +#endif /* RDM_UID_H_ */ diff --git a/DMX_NeoPixels/examples/RDM_Slave/.cpb.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.cpb.test.skip deleted file mode 100644 index 064a28912..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.cpb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpb diff --git a/DMX_NeoPixels/examples/RDM_Slave/.cpc.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.cpc.test.skip deleted file mode 100644 index 79763353d..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.cpc.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpc diff --git a/DMX_NeoPixels/examples/RDM_Slave/.cpx_ada.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.cpx_ada.test.skip deleted file mode 100644 index d9c56cc11..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.cpx_ada.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpx_ada diff --git a/DMX_NeoPixels/examples/RDM_Slave/.esp32.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.esp32.test.skip deleted file mode 100644 index 5faeb5064..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.esp32.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for esp32 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.esp8266.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.esp8266.test.skip deleted file mode 100644 index 15eb13221..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.esp8266.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for esp8266 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.feather32u4.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.feather32u4.test.skip deleted file mode 100644 index eb9fd87a1..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.feather32u4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather32u4 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.feather_esp32c6.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.feather_esp32c6.test.skip deleted file mode 100644 index 563448c75..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.feather_esp32c6.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_esp32c6 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.feather_m0_express.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.feather_m0_express.test.skip deleted file mode 100644 index c1118c563..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.feather_m0_express.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_m0_express diff --git a/DMX_NeoPixels/examples/RDM_Slave/.feather_m4_express.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.feather_m4_express.test.skip deleted file mode 100644 index 9b961626f..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.feather_m4_express.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_m4_express diff --git a/DMX_NeoPixels/examples/RDM_Slave/.feather_rp2040.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.feather_rp2040.test.skip deleted file mode 100644 index 90aa322a7..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.feather_rp2040.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_rp2040 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.feather_rp2040_adalogger.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.feather_rp2040_adalogger.test.skip deleted file mode 100644 index 29ebf0ea0..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.feather_rp2040_adalogger.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_rp2040_adalogger diff --git a/DMX_NeoPixels/examples/RDM_Slave/.flora.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.flora.test.skip deleted file mode 100644 index e4cc7386e..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.flora.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for flora diff --git a/DMX_NeoPixels/examples/RDM_Slave/.funhouse.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.funhouse.test.skip deleted file mode 100644 index 32a4e1e1a..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.funhouse.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for funhouse diff --git a/DMX_NeoPixels/examples/RDM_Slave/.gemma.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.gemma.test.skip deleted file mode 100644 index 978f275e3..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.gemma.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for gemma diff --git a/DMX_NeoPixels/examples/RDM_Slave/.gemma_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.gemma_m0.test.skip deleted file mode 100644 index c42614d7c..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.gemma_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for gemma_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.hallowing_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.hallowing_m0.test.skip deleted file mode 100644 index ed26fdf6a..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.hallowing_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for hallowing_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.hallowing_m4_tinyusb.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.hallowing_m4_tinyusb.test.skip deleted file mode 100644 index 0ab22cb8d..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.hallowing_m4_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for hallowing_m4_tinyusb diff --git a/DMX_NeoPixels/examples/RDM_Slave/.ledglasses_nrf52840.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.ledglasses_nrf52840.test.skip deleted file mode 100644 index f540a7e4c..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.ledglasses_nrf52840.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for ledglasses_nrf52840 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.magtag.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.magtag.test.skip deleted file mode 100644 index 79d0d324c..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.magtag.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for magtag diff --git a/DMX_NeoPixels/examples/RDM_Slave/.metro_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.metro_m0.test.skip deleted file mode 100644 index 91512a898..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.metro_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.metro_m0_tinyusb.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.metro_m0_tinyusb.test.skip deleted file mode 100644 index 486e4f67e..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.metro_m0_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m0_tinyusb diff --git a/DMX_NeoPixels/examples/RDM_Slave/.metro_m4.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.metro_m4.test.skip deleted file mode 100644 index 5012f3737..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.metro_m4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m4 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.metro_m4_tinyusb.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.metro_m4_tinyusb.test.skip deleted file mode 100644 index 17edc54fe..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.metro_m4_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m4_tinyusb diff --git a/DMX_NeoPixels/examples/RDM_Slave/.monster_m4sk.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.monster_m4sk.test.skip deleted file mode 100644 index ec7f80e48..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.monster_m4sk.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for monster_m4sk diff --git a/DMX_NeoPixels/examples/RDM_Slave/.monster_m4sk_tinyusb.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.monster_m4sk_tinyusb.test.skip deleted file mode 100644 index a08b60688..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.monster_m4sk_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for monster_m4sk_tinyusb diff --git a/DMX_NeoPixels/examples/RDM_Slave/.neokeytrinkey_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.neokeytrinkey_m0.test.skip deleted file mode 100644 index 7fb03fe33..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.neokeytrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for neokeytrinkey_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.neotrellis_m4.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.neotrellis_m4.test.skip deleted file mode 100644 index eebfceae8..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.neotrellis_m4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for neotrellis_m4 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.nrf52832.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.nrf52832.test.skip deleted file mode 100644 index ee506a55a..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.nrf52832.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for nrf52832 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.nrf52840.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.nrf52840.test.skip deleted file mode 100644 index a6bcf2c9d..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.nrf52840.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for nrf52840 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.pixeltrinkey_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.pixeltrinkey_m0.test.skip deleted file mode 100644 index 4a5f3b346..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.pixeltrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pixeltrinkey_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.protrinket_5v.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.protrinket_5v.test.skip deleted file mode 100644 index ec91a95cb..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.protrinket_5v.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for protrinket_5v diff --git a/DMX_NeoPixels/examples/RDM_Slave/.proxlighttrinkey_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.proxlighttrinkey_m0.test.skip deleted file mode 100644 index 0d46213a9..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.proxlighttrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for proxlighttrinkey_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.pybadge.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.pybadge.test.skip deleted file mode 100644 index 82cd2ac9c..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.pybadge.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pybadge diff --git a/DMX_NeoPixels/examples/RDM_Slave/.pycamera_s3.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.pycamera_s3.test.skip deleted file mode 100644 index 021a63e54..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.pycamera_s3.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pycamera_s3 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.pygamer.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.pygamer.test.skip deleted file mode 100644 index 430cf639c..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.pygamer.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pygamer diff --git a/DMX_NeoPixels/examples/RDM_Slave/.pyportal.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.pyportal.test.skip deleted file mode 100644 index 6a18dce9f..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.pyportal.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pyportal diff --git a/DMX_NeoPixels/examples/RDM_Slave/.qt2040_trinkey.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.qt2040_trinkey.test.skip deleted file mode 100644 index 263748866..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.qt2040_trinkey.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qt2040_trinkey diff --git a/DMX_NeoPixels/examples/RDM_Slave/.qtpy_esp32s2.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.qtpy_esp32s2.test.skip deleted file mode 100644 index 627d7dd57..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.qtpy_esp32s2.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qtpy_esp32s2 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.qtpy_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.qtpy_m0.test.skip deleted file mode 100644 index fbc42f083..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.qtpy_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qtpy_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.qualia_s3_rgb666.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.qualia_s3_rgb666.test.skip deleted file mode 100644 index 1e14eea6e..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.qualia_s3_rgb666.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qualia_s3_rgb666 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.rotarytrinkey_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.rotarytrinkey_m0.test.skip deleted file mode 100644 index 8a2ec7327..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.rotarytrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for rotarytrinkey_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.sht4xtrinkey_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.sht4xtrinkey_m0.test.skip deleted file mode 100644 index 039d08b3e..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.sht4xtrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for sht4xtrinkey_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.slidetrinkey_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.slidetrinkey_m0.test.skip deleted file mode 100644 index d3f14ba82..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.slidetrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for slidetrinkey_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.trinket_5v.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.trinket_5v.test.skip deleted file mode 100644 index e2d3dded0..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.trinket_5v.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for trinket_5v diff --git a/DMX_NeoPixels/examples/RDM_Slave/.trinket_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.trinket_m0.test.skip deleted file mode 100644 index 06ad7bf51..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.trinket_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for trinket_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave/.uno.test.only b/DMX_NeoPixels/examples/RDM_Slave/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/DMX_NeoPixels/examples/RDM_Slave/.uno.test.skip b/DMX_NeoPixels/examples/RDM_Slave/.uno.test.skip deleted file mode 100644 index f3e164df1..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave/.uno.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for uno diff --git a/DMX_NeoPixels/examples/RDM_Slave/Conceptinetics.cpp b/DMX_NeoPixels/examples/RDM_Slave/Conceptinetics.cpp new file mode 100644 index 000000000..36ada5924 --- /dev/null +++ b/DMX_NeoPixels/examples/RDM_Slave/Conceptinetics.cpp @@ -0,0 +1,1233 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Conceptinetics.cpp - DMX library for Arduino + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + This code has been tested using the following hardware: + + - Arduino UNO R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino MEGA2560 R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD +*/ + + +#include "pins_arduino.h" +#include "Conceptinetics.h" + +#include +#include + +#include +#include + +#include + + +#if defined (USE_DMX_SERIAL_0) + + #if defined (USART__TXC_vect) + #define USART_TX USART__TXC_vect + #elif defined(USART_TX_vect) + #define USART_TX USART_TX_vect + #elif defined(USART0_TX_vect) + #define USART_TX USART0_TX_vect + #endif + + #if defined (USART__RXC_vect) + #define USART_RX USART__RXC_vect + #elif defined(USART_RX_vect) + #define USART_RX USART_RX_vect + #elif defined(USART0_RX_vect) + #define USART_RX USART0_RX_vect + #endif + + #if defined UDR + #define DMX_UDR UDR + #elif defined UDR0 + #define DMX_UDR UDR0 + #endif + + #if defined(UBRRH) && defined(UBRRL) + #define DMX_UBRRH UBRRH + #define DMX_UBRRL UBRRL + #elif defined(UBRR0H) && defined(UBRR0L) + #define DMX_UBRRH UBRR0H + #define DMX_UBRRL UBRR0L + #endif + + #if defined(UCSRA) + #define DMX_UCSRA UCSRA + #elif defined(UCSR0A) + #define DMX_UCSRA UCSR0A + #endif + + #if defined(UCSRB) + #define DMX_UCSRB UCSRB + #elif defined (UCSR0B) + #define DMX_UCSRB UCSR0B + #endif + + #if defined(TXEN) && defined(TXCIE) + #define DMX_TXEN TXEN + #define DMX_TXCIE TXCIE + #elif defined(TXEN0) && defined(TXCIE0) + #define DMX_TXEN TXEN0 + #define DMX_TXCIE TXCIE0 + #endif + + #if defined(RXEN) && defined(RXCIE) + #define DMX_RXEN RXEN + #define DMX_RXCIE RXCIE + #elif defined(RXEN0) && defined(RXCIE0) + #define DMX_RXEN RXEN0 + #define DMX_RXCIE RXCIE0 + #endif + + #if defined(FE) + #define DMX_FE FE + #elif defined(FE0) + #define DMX_FE FE0 + #endif + + #define RX_PIN 0 + #define TX_PIN 1 + +#elif defined (USE_DMX_SERIAL_1) + #define USART_RX USART1_RX_vect + #define USART_TX USART1_TX_vect + #define DMX_UDR UDR1 + #define DMX_UBRRH UBRR1H + #define DMX_UBRRL UBRR1L + #define DMX_UCSRA UCSR1A + #define DMX_UCSRB UCSR1B + #define DMX_TXEN TXEN1 + #define DMX_TXCIE TXCIE1 + #define DMX_RXEN RXEN1 + #define DMX_RXCIE RXCIE1 + #define DMX_FE FE1 + #define RX_PIN 19 + #define TX_PIN 18 +#elif defined (USE_DMX_SERIAL_2) + #define USART_RX USART2_RX_vect + #define USART_TX USART2_TX_vect + #define DMX_UDR UDR2 + #define DMX_UBRRH UBRR2H + #define DMX_UBRRL UBRR2L + #define DMX_UCSRA UCSR2A + #define DMX_UCSRB UCSR2B + #define DMX_TXEN TXEN2 + #define DMX_TXCIE TXCIE2 + #define DMX_RXEN RXEN2 + #define DMX_RXCIE RXCIE2 + #define DMX_FE FE2 + #define RX_PIN 17 + #define TX_PIN 16 +#elif defined (USE_DMX_SERIAL_3) + #define USART_RX USART3_RX_vect + #define USART_TX USART3_TX_vect + #define DMX_UDR UDR3 + #define DMX_UBRRH UBRR3H + #define DMX_UBRRL UBRR3L + #define DMX_UCSRA UCSR3A + #define DMX_UCSRB UCSR3B + #define DMX_TXEN TXEN3 + #define DMX_TXCIE TXCIE3 + #define DMX_RXEN RXEN3 + #define DMX_RXCIE RXCIE3 + #define DMX_FE FE3 + #define RX_PIN 14 + #define TX_PIN 15 +#endif + + +#define LOWBYTE(v) ((uint8_t) (v)) +#define HIGHBYTE(v) ((uint8_t) (((uint16_t) (v)) >> 8)) + +#define BSWAP_16(x) ( (uint8_t)((x) >> 8) | ((uint8_t)(x)) << 8 ) + +namespace isr +{ + enum isrState + { + Idle, + Break, + DmxBreak, + DmxBreakManual, + DmxStartByte, + DmxRecordData, + DmxTransmitData, + RdmBreak, + RdmStartByte, + RdmRecordData, + RdmTransmitData, + RDMTransmitComplete, + }; + + enum isrMode + { + Disabled, + Receive, + DMXTransmit, + DMXTransmitManual, /* Manual break... */ + RDMTransmit, + RDMTransmitNoInt, /* Setup uart but leave interrupt disabled */ + }; +}; + + +DMX_Master *__dmx_master; +DMX_Slave *__dmx_slave; +RDM_Responder *__rdm_responder; + +int8_t __re_pin; // R/W Pin on shield + +isr::isrState __isr_txState; // TX ISR state +isr::isrState __isr_rxState; // RX ISR state + + +void SetISRMode ( isr::isrMode ); + + +DMX_FrameBuffer::DMX_FrameBuffer ( uint16_t buffer_size ) +{ + m_refcount = (uint8_t*) malloc ( sizeof ( uint8_t ) ); + + if ( buffer_size >= DMX_MIN_FRAMESIZE && buffer_size <= DMX_MAX_FRAMESIZE ) + { + m_buffer = (uint8_t*) malloc ( buffer_size ); + if ( m_buffer != NULL ) + { + memset ( (void *)m_buffer, 0x0, buffer_size ); + m_bufferSize = buffer_size; + } + else + m_buffer = 0x0; + } + else + m_bufferSize = 0x0; + + *m_refcount++; +} + +DMX_FrameBuffer::DMX_FrameBuffer ( DMX_FrameBuffer &buffer ) +{ + // Copy references and make sure the parent object does not dispose our + // buffer when deleted and we are still active + this->m_refcount = buffer.m_refcount; + (*this->m_refcount)++; + + this->m_buffer = buffer.m_buffer; + this->m_bufferSize = buffer.m_bufferSize; +} + +DMX_FrameBuffer::~DMX_FrameBuffer ( void ) +{ + // If we are the last object using the + // allocated buffer then free it together + // with the refcounter + if ( --(*m_refcount) == 0 ) + { + if ( m_buffer ) + free ( m_buffer ); + + free ( m_refcount ); + } +} + +uint16_t DMX_FrameBuffer::getBufferSize ( void ) +{ + return m_bufferSize; +} + + +uint8_t DMX_FrameBuffer::getSlotValue ( uint16_t index ) +{ + if (index < m_bufferSize) + return m_buffer[index]; + else + return 0x0; +} + + +void DMX_FrameBuffer::setSlotValue ( uint16_t index, uint8_t value ) +{ + if ( index < m_bufferSize ) + m_buffer[index] = value; +} + + +void DMX_FrameBuffer::setSlotRange ( uint16_t start, uint16_t end, uint8_t value ) +{ + if ( start < m_bufferSize && end < m_bufferSize && start < end ) + memset ( (void *) &m_buffer[start], value, end-start+1 ); +} + +void DMX_FrameBuffer::clear ( void ) +{ + memset ( (void *) m_buffer, 0x0, m_bufferSize ); +} + +uint8_t &DMX_FrameBuffer::operator[] ( uint16_t index ) +{ + return m_buffer[index]; +} + + +DMX_Master::DMX_Master ( DMX_FrameBuffer &buffer, int readEnablePin ) +: m_frameBuffer ( buffer ), + m_autoBreak ( 1 ) // Autobreak generation is default on +{ + setStartCode ( DMX_START_CODE ); + + __re_pin = readEnablePin; + pinMode ( __re_pin, OUTPUT ); + + ::SetISRMode ( isr::Disabled ); +} + +DMX_Master::DMX_Master ( uint16_t maxChannel, int readEnablePin ) +: m_frameBuffer ( maxChannel + DMX_STARTCODE_SIZE ), + m_autoBreak ( 1 ) // Autobreak generation is default on +{ + setStartCode ( DMX_START_CODE ); + + __re_pin = readEnablePin; + pinMode ( __re_pin, OUTPUT ); + + ::SetISRMode ( isr::Disabled ); +} + +DMX_Master::~DMX_Master ( void ) +{ + disable (); // Stop sending + __dmx_master = NULL; +} + +DMX_FrameBuffer &DMX_Master::getBuffer ( void ) +{ + return m_frameBuffer; // Return reference to frame buffer +} + +void DMX_Master::setStartCode ( uint8_t value ) +{ + m_frameBuffer[0] = value; // Set the first byte in our frame buffer +} + +void DMX_Master::setChannelValue ( uint16_t channel, uint8_t value ) +{ + if ( channel > 0 ) // Prevent overwriting the start code + m_frameBuffer.setSlotValue ( channel, value ); +} + +void DMX_Master::setChannelRange ( uint16_t start, uint16_t end, uint8_t value ) +{ + if ( start > 0 ) // Prevent overwriting the start code + m_frameBuffer.setSlotRange ( start, end, value ); +} + + +void DMX_Master::enable ( void ) +{ + __dmx_master = this; + + if ( m_autoBreak ) + ::SetISRMode ( isr::DMXTransmit ); + else + ::SetISRMode ( isr::DMXTransmitManual ); +} + +void DMX_Master::disable ( void ) +{ + ::SetISRMode ( isr::Disabled ); + __dmx_master = NULL; // No active master +} + +void DMX_Master::setAutoBreakMode ( void ) { m_autoBreak = 1; } +void DMX_Master::setManualBreakMode ( void ) { m_autoBreak = 0; } +uint8_t DMX_Master::autoBreakEnabled ( void ) { return m_autoBreak; } + + +uint8_t DMX_Master::waitingBreak ( void ) +{ + return ( __isr_txState == isr::DmxBreakManual ); +} + +void DMX_Master::breakAndContinue ( uint8_t breakLength_us ) +{ + // Only execute if we are the controlling master object + if ( __dmx_master == this && __isr_txState == isr::DmxBreakManual ) + { + pinMode ( TX_PIN, OUTPUT ); + digitalWrite ( TX_PIN, LOW ); // Begin BREAK + + for (uint8_t bl=0; bl(*this); +} + + uint8_t DMX_Slave::getChannelValue ( uint16_t channel ) +{ + return getSlotValue ( channel ); +} + + +uint16_t DMX_Slave::getStartAddress ( void ) +{ + return m_startAddress; +} + +void DMX_Slave::setStartAddress ( uint16_t addr ) +{ + m_startAddress = addr; +} + +void DMX_Slave::onReceiveComplete ( void (*func)(unsigned short) ) +{ + event_onFrameReceived = func; +} + + +bool DMX_Slave::processIncoming ( uint8_t val, bool first ) +{ + static uint16_t idx; + bool rval = false; + + if ( first ) + { + // We could have received less channels then we + // expected.. but still is a complete frame + if (m_state == dmx::dmxData && event_onFrameReceived) + event_onFrameReceived (idx); + + m_state = dmx::dmxStartByte; + } + + switch ( m_state ) + { + case dmx::dmxStartByte: + setSlotValue ( 0, val ); // Store start code + idx = m_startAddress; + m_state = dmx::dmxWaitStartAddress; + + case dmx::dmxWaitStartAddress: + if ( --idx == 0 ) + m_state = dmx::dmxData; + break; + + case dmx::dmxData: + if ( idx++ < getBufferSize() ) + setSlotValue ( idx, val ); + else + { + m_state = dmx::dmxFrameReady; + + // If a onFrameReceived callback is register... + if (event_onFrameReceived) + event_onFrameReceived (idx-2); + + rval = true; + } + break; + } + + return rval; +} + + +uint16_t RDM_FrameBuffer::getBufferSize ( void ) { return sizeof ( m_msg ); } + +uint8_t RDM_FrameBuffer::getSlotValue ( uint16_t index ) +{ + if ( index < sizeof ( m_msg ) ) + return m_msg.d[index]; + else + return 0x0; +} + + +void RDM_FrameBuffer::setSlotValue ( uint16_t index, uint8_t value ) +{ + if ( index < sizeof ( m_msg ) ) + m_msg.d[index] = value; +} + +void RDM_FrameBuffer::clear ( void ) +{ + memset ( (void*)m_msg.d, 0x0, sizeof( m_msg ) ); + m_state = rdm::rdmUnknown; +} + +bool RDM_FrameBuffer::processIncoming ( uint8_t val, bool first ) +{ + static uint16_t idx; + bool rval = false; + + if ( first ) + { + m_state = rdm::rdmStartByte; + m_csRecv.checksum = (uint16_t) 0x0000; + idx = 0; + } + + // Prevent buffer overflow for large messages + if (idx >= sizeof(m_msg)) + return true; + + switch ( m_state ) + { + case rdm::rdmStartByte: + m_msg.startCode = val; + m_state = rdm::rdmSubStartCode; + break; + + case rdm::rdmSubStartCode: + if ( val != 0x01 ) + { + rval = true; // Stop processing data + break; + } + + m_msg.subStartCode = val; + m_state = rdm::rdmMessageLength; + break; + + case rdm::rdmMessageLength: + m_msg.msgLength = val; + m_state = rdm::rdmData; + m_csRecv.checksum = 0xcc + 0x01 + val; // set initial checksum + idx = 3; // buffer index for next byte + break; + + case rdm::rdmData: + m_msg.d[idx++] = val; + m_csRecv.checksum += val; + if ( idx >= m_msg.msgLength ) + m_state = rdm::rdmChecksumHigh; + break; + + case rdm::rdmChecksumHigh: + m_csRecv.csh = val; + m_state = rdm::rdmChecksumLow; + + break; + + case rdm::rdmChecksumLow: + m_csRecv.csl = val; + + if ((m_csRecv.checksum % (uint16_t)0x10000) == m_csRecv.checksum) + { + m_state = rdm::rdmFrameReady; + + // valid checksum ... start processing + processFrame (); + } + + m_state = rdm::rdmUnknown; + rval = true; + break; + }; + + return rval; +} + +bool RDM_FrameBuffer::fetchOutgoing ( volatile uint8_t *udr, bool first ) +{ + static uint16_t idx; + static uint16_t cs; + bool rval = false; + + + if ( first ) + { + m_state = rdm::rdmData; + cs = 0x0; + idx = 0; + } + + switch ( m_state ) + { + case rdm::rdmData: + cs += m_msg.d[idx]; + *udr = m_msg.d[idx++]; + if ( idx >= m_msg.msgLength ) + { + m_state = rdm::rdmChecksumHigh; + } + break; + + case rdm::rdmChecksumHigh: + *udr = (cs >> 8); + m_state = rdm::rdmChecksumLow; + break; + + case rdm::rdmChecksumLow: + *udr = (cs & 0xff); + m_state = rdm::rdmUnknown; + rval = true; + break; + + } + + return rval; +} + + +void (*RDM_Responder::event_onIdentifyDevice)(bool); +void (*RDM_Responder::event_onDeviceLabelChanged)(const char*, uint8_t); +void (*RDM_Responder::event_onDMXStartAddressChanged)(uint16_t); +void (*RDM_Responder::event_onDMXPersonalityChanged)(uint8_t); + +// +// slave parameter is only used to ensure a slave object is present before +// initializing the rdm responder class +// +RDM_Responder::RDM_Responder ( uint16_t m, uint8_t d1, uint8_t d2, + uint8_t d3, uint8_t d4, DMX_Slave &slave ) +: RDM_FrameBuffer ( ), + m_Personalities (1), // Available personlities + m_Personality (1) // Default personality eq 1. +{ + __rdm_responder = this; + m_devid.Initialize ( m, d1, d2, d3, d4 ); + + // Default software version id = 0x00000000 + memset ( (void*)m_SoftwareVersionId, 0x0, 0x4 ); + + // Rdm responder is disabled by default + m_rdmStatus.enabled = false; +} + +RDM_Responder::~RDM_Responder ( void ) +{ + __rdm_responder = NULL; +} + +void RDM_Responder::onIdentifyDevice ( void (*func)(bool) ) +{ + event_onIdentifyDevice = func; +} + +void RDM_Responder::onDeviceLabelChanged ( void (*func) (const char*, uint8_t) ) +{ + event_onDeviceLabelChanged = func; +} + +void RDM_Responder::onDMXStartAddressChanged ( void (*func) (uint16_t) ) +{ + event_onDMXStartAddressChanged = func; +} + +void RDM_Responder::onDMXPersonalityChanged ( void (*func) (uint8_t) ) +{ + event_onDMXPersonalityChanged = func; +} + +void RDM_Responder::setDeviceLabel ( const char *label, size_t len ) +{ + if ( len > RDM_MAX_DEVICELABEL_LENGTH ) + len = RDM_MAX_DEVICELABEL_LENGTH; + + memcpy ( (void *)m_deviceLabel, (void *)label, len ); +} + +#define UID_0 0x12 //ESTA device ID +#define UID_1 0x34 +#define UID_2 0x56 +#define UID_3 0x88 +#define UID_4 0x00 +#define UID_5 0x00 + +#define UID_CS (0xFF *6 +UID_0 +UID_1 +UID_2 +UID_3 +UID_4 +UID_5) + +void RDM_Responder::repondDiscUniqueBranch ( void ) +{ + #if defined(UCSRB) + UCSRB = (1<>8) | 0xaa; + response [21] = (cs>>8) | 0x55; + response [22] = (cs&0xff) | 0xaa; + response [23] = (cs&0xff) | 0x55; + + + // Table 3-2 ANSI_E1-20-2010 <2ms + _delay_us ( MIN_RESPONDER_PACKET_SPACING_USEC ); + + // Fix: 2017, Feb 28: Moved data enable down in order to limit line in marking state time to comply with + // section 3.2.3 + // Set shield to transmit mode (turn arround) + digitalWrite ( __re_pin, HIGH ); + + + for ( int i=0; i<24; i++ ) + { + // Wait until data register is empty + #if defined (UCSR0A) && defined (UDRE0) + while((UCSR0A & (1 <(m_msg.PD); + + pd->protocolVersionMajor = 0x01; + pd->protocolVersionMinor = 0x00; + pd->deviceModelId = BSWAP_16(m_DeviceModelId); + pd->ProductCategory = BSWAP_16(m_ProductCategory); + memcpy ( (void*)pd->SoftwareVersionId, (void*)m_SoftwareVersionId, 4 ); + pd->DMX512FootPrint = BSWAP_16(__dmx_slave->getBufferSize()-1); // eq buffersize-startbyte + pd->DMX512CurrentPersonality = m_Personality; + pd->DMX512NumberPersonalities = m_Personalities; + pd->DMX512StartAddress = BSWAP_16(__dmx_slave->getStartAddress()); + + pd->SubDeviceCount = 0x0; // Sub devices are not supported by this library + pd->SensorCount = 0x0; // Sensors are not yet supported + + m_msg.PDL = sizeof (RDM__DeviceInfoPD); +} + +const uint8_t ManufacturerLabel_P[] PROGMEM = "Conceptinetics"; + +void RDM_Responder::processFrame ( void ) +{ + // If packet is a general broadcast + if ( + m_msg.dstUid.isBroadcast (m_devid.m_id) || + m_devid == m_msg.dstUid + ) + { + // Set default response type + m_msg.portId = rdm::ResponseTypeAck; + + switch ( BSWAP_16(m_msg.PID) ) + { + case rdm::DiscUniqueBranch: + // Check if we are inside the given unique branch... + if ( !m_rdmStatus.mute && + reinterpret_cast(m_msg.PD)->lbound < m_devid && + reinterpret_cast(m_msg.PD)->hbound > m_devid ) + { + // Discovery messages are responded with data only and no breaks + repondDiscUniqueBranch (); + } + break; + + case rdm::DiscMute: + reinterpret_cast(m_msg.PD)->ctrlField = 0x0; + m_msg.PDL = sizeof ( RDM_DiscMuteUnMutePD ); + m_rdmStatus.mute = true; + break; + + case rdm::DiscUnMute: + reinterpret_cast(m_msg.PD)->ctrlField = 0x0; + m_msg.PDL = sizeof ( RDM_DiscMuteUnMutePD ); + m_rdmStatus.mute = false; + break; + + case rdm::SupportedParameters: + // + // Temporary solution... this will become dynamic + // in a later version... + // + m_msg.PD[0] = HIGHBYTE(rdm::DmxStartAddress); // MSB + m_msg.PD[1] = LOWBYTE (rdm::DmxStartAddress); // LSB + + m_msg.PD[2] = HIGHBYTE(rdm::DmxPersonality); + m_msg.PD[3] = LOWBYTE (rdm::DmxPersonality); + + m_msg.PD[4] = HIGHBYTE(rdm::ManufacturerLabel); + m_msg.PD[5] = LOWBYTE (rdm::ManufacturerLabel); + + m_msg.PD[6] = HIGHBYTE(rdm::DeviceLabel); + m_msg.PD[7] = LOWBYTE (rdm::DeviceLabel); + + m_msg.PDL = 0x6; + break; + + // Only for manufacturer specific parameters + // case rdm::ParameterDescription: + // break; + + case rdm::DeviceInfo: + if ( m_msg.CC == rdm::GetCommand ) + populateDeviceInfo (); + break; + + case rdm::DmxStartAddress: + if ( m_msg.CC == rdm::GetCommand ) + { + m_msg.PD[0] = HIGHBYTE(__dmx_slave->getStartAddress ()); + m_msg.PD[1] = LOWBYTE (__dmx_slave->getStartAddress ()); + m_msg.PDL = 0x2; + } + else // if ( m_msg.CC == rdm::SetCommand ) + { + __dmx_slave->setStartAddress ( (m_msg.PD[0] << 8) + m_msg.PD[1] ); + m_msg.PDL = 0x0; + + if ( event_onDMXStartAddressChanged ) + event_onDMXStartAddressChanged ( (m_msg.PD[0] << 8) + m_msg.PD[1] ); + } + break; + + case rdm::DmxPersonality: + if ( m_msg.CC == rdm::GetCommand ) + { + reinterpret_cast + (m_msg.PD)->DMX512CurrentPersonality = m_Personality; + reinterpret_cast + (m_msg.PD)->DMX512CurrentPersonality = m_Personalities; + m_msg.PDL = sizeof (RDM_DeviceGetPersonality_PD); + } + else // if ( m_msg.CC == rdm::SetCommand ) + { + m_Personality = reinterpret_cast + (m_msg.PD)->DMX512Personality; + m_msg.PDL = 0x0; + + if ( event_onDMXPersonalityChanged ) + event_onDMXPersonalityChanged ( m_Personality ); + } + break; + + case rdm::IdentifyDevice: + if ( m_msg.CC == rdm::GetCommand ) + { + m_msg.PD[0] = (uint8_t)(m_rdmStatus.ident ? 1 : 0); + m_msg.PDL = 0x1; + } + else if ( m_msg.CC == rdm::SetCommand ) + { + // Look into first byte to see whether identification + // is turned on or off + m_rdmStatus.ident = m_msg.PD[0] ? true : false; + if ( event_onIdentifyDevice ) + event_onIdentifyDevice ( m_rdmStatus.ident ); + + m_msg.PDL = 0x0; + } + break; + + case rdm::ManufacturerLabel: + if ( m_msg.CC == rdm::GetCommand ) + { + memcpy_P( (void*)m_msg.PD, ManufacturerLabel_P, sizeof(ManufacturerLabel_P) ); + m_msg.PDL = sizeof ( ManufacturerLabel_P ); + } + break; + + case rdm::DeviceLabel: + if ( m_msg.CC == rdm::GetCommand ) + { + memcpy ( m_msg.PD, (void*) m_deviceLabel, 32 ); + m_msg.PDL = 32; + } + else if ( m_msg.CC == rdm::SetCommand ) + { + memset ( (void*) m_deviceLabel, ' ', 32 ); + memcpy ( (void*) m_deviceLabel, m_msg.PD, (m_msg.PDL < 32 ? m_msg.PDL : 32) ); + m_msg.PDL = 0; + + // Notify application + if ( event_onDeviceLabelChanged ) + event_onDeviceLabelChanged ( m_deviceLabel, 32 ); + } + break; + + + default: + // Unknown parameter ID response + m_msg.portId = rdm::ResponseTypeNackReason; + m_msg.PD[0] = rdm::UnknownPid; + m_msg.PD[1] = 0x0; + m_msg.PDL = 0x2; + break; + }; + } + + // + // Only respond if this this message + // was destined to us only + if ( m_msg.dstUid == m_devid ) + { + m_msg.startCode = RDM_START_CODE; + m_msg.subStartCode = 0x01; + m_msg.msgLength = RDM_HDR_LEN + m_msg.PDL; + m_msg.msgCount = 0; + + /* + switch ( m_msg.msg.CC ) + { + case rdm::DiscoveryCommand: + m_msg.msg.CC = rdm::DiscoveryCommandResponse; + break; + case rdm::GetCommand: + m_msg.msg.CC = rdm::GetCommandResponse; + break; + case rdm::SetCommand: + m_msg.msg.CC = rdm::SetCommandResponse; + break; + } + */ + /* Above replaced by next line */ + m_msg.CC++; + + m_msg.dstUid.copy ( m_msg.srcUid ); + m_msg.srcUid.copy ( m_devid ); + + //_delay_us ( MIN_RESPONDER_PACKET_SPACING_USEC ); + SetISRMode ( isr::RDMTransmit ); + + } +} + + +void SetISRMode ( isr::isrMode mode ) +{ + uint8_t readEnable; + +#if defined(USE_DMX_SERIAL_0) + #if defined(UCSRB) && defined (UCSRC) + UCSRC |= (1<>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + + // Prepare before kicking off ISR + //DMX_UDR = 0x0; + __isr_rxState = isr::Idle; + readEnable = LOW; + DMX_UCSRB = (1<>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + DMX_UDR = 0x0; + DMX_UCSRB = 0x0; + readEnable = HIGH; + __isr_txState = isr::DmxBreakManual; + break; + + case isr::RDMTransmit: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + //DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + //DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + DMX_UCSRB = (1< -1) + digitalWrite ( __re_pin, readEnable ); + +} + +// +// TX UART (DMX Transmission ISR) +// +ISR (USART_TX) +{ + static uint16_t current_slot; + + switch ( __isr_txState ) + { + case isr::DmxBreak: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + if ( __isr_txState == isr::DmxBreak ) + __isr_txState = isr::DmxStartByte; + + break; + + case isr::DmxStartByte: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + current_slot = 0; + DMX_UDR = __dmx_master->getBuffer()[ current_slot++ ]; + __isr_txState = isr::DmxTransmitData; + break; + + + case isr::DmxTransmitData: + // NOTE: we always send full frames of 513 bytes, this will bring us + // close to 40 frames / sec with no interslot delays + #ifdef DMX_IBG + _delay_us (DMX_IBG); + #endif + + DMX_UDR = __dmx_master->getBuffer().getSlotValue( current_slot++ ); + + // Send 512 channels + if ( current_slot >= DMX_MAX_FRAMESIZE ) + { + if ( __dmx_master->autoBreakEnabled () ) + __isr_txState = isr::DmxBreak; + else + SetISRMode ( isr::DMXTransmitManual ); + } + + break; + +/* case isr::RdmBreak: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + __isr_txState = isr::RdmStartByte; + + break; +*/ + + case isr::RdmStartByte: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + + // Write start byte + __rdm_responder->fetchOutgoing ( &DMX_UDR, true ); + __isr_txState = isr::RdmTransmitData; + + break; + + case isr::RdmTransmitData: + // Write rest of data + if ( __rdm_responder->fetchOutgoing ( &DMX_UDR ) ) + __isr_txState = isr::RDMTransmitComplete; + break; + + case isr::RDMTransmitComplete: + SetISRMode ( isr::Receive ); // Start waitin for new data + __isr_txState = isr::Idle; // No tx state + break; + + } +} + + + +// +// RX UART (DMX Reception ISR) +// +ISR (USART_RX) +{ + uint8_t usart_state = DMX_UCSRA; + uint8_t usart_data = DMX_UDR; + + // + // Check for framing error and reset if found + // A framing most likely* indicate a break in our ocasion + // + if ( usart_state & (1<processIncoming ( usart_data, true ); + __isr_rxState = isr::DmxRecordData; + } + else if ( __rdm_responder && + usart_data == RDM_START_CODE && + __rdm_responder->m_rdmStatus.enabled ) + { + // __rdm_responder->clear (); + __rdm_responder->processIncoming ( usart_data, true ); + __isr_rxState = isr::RdmRecordData; + } + else + { + __isr_rxState = isr::Idle; + } + break; + + // Process DMX Data + case isr::DmxRecordData: + if ( __dmx_slave->processIncoming ( usart_data ) ) + __isr_rxState = isr::Idle; + break; + + // Process RDM Data + case isr::RdmRecordData: + if ( __rdm_responder->processIncoming ( usart_data ) ) + __isr_rxState = isr::Idle; + break; + + } + +} + diff --git a/DMX_NeoPixels/examples/RDM_Slave/Conceptinetics.h b/DMX_NeoPixels/examples/RDM_Slave/Conceptinetics.h new file mode 100644 index 000000000..0f03da619 --- /dev/null +++ b/DMX_NeoPixels/examples/RDM_Slave/Conceptinetics.h @@ -0,0 +1,383 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Conceptinetics.h - DMX library for Arduino + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + This code has been tested using the following hardware: + + - Arduino / Genuino UNO R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino / Genuino MEGA2560 R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino / Genuino Leonardo using a CTC-DRA-13-R2 ISOLATED DMX-RDM SHIELD + + - CTC-DRA-10-1 and CTC-DRA-10-R2 is the Non-isolated costs effective DMX-RDM shield +*/ + + +#ifndef CONCEPTINETICS_H_ +#define CONCEPTINETICS_H_ + +#include +#include + +#include "Rdm_Uid.h" +#include "Rdm_Defines.h" + +#define DMX_MAX_FRAMESIZE 513 // Startbyte + 512 Slots +#define DMX_MIN_FRAMESIZE 2 // Startbyte + 1 Slot + +#define DMX_MAX_FRAMECHANNELS 512 // Maxmim number of channer per frame + +#define DMX_STARTCODE_SIZE 1 // Size of startcode in bytes + +#define DMX_START_CODE 0x0 // Start code for a DMX frame +#define RDM_START_CODE 0xcc // Start code for a RDM frame + +// Uncomment to enable Inter slot delay ) (avg < 76uSec) ... +// mimum is zero according to specification +// #define DMX_IBG 10 // Inter slot time + +// Speed your Arduino is running on in Hz. +#define F_OSC 16000000UL + +// DMX Baudrate, this should be 250000 +#define DMX_BAUD_RATE 250000 + +// The baudrate used to automaticly generate a break within +// your ISR.. make it lower to generate longer breaks +//#define DMX_BREAK_RATE 99900 + +// 2017, Feb 28: Set to appox 176us +#define DMX_BREAK_RATE 49950 + +// Tabel 3-2 ANSI_E1-20-2010 +// Minimum time to allow the datalink to 'turn arround' +#define MIN_RESPONDER_PACKET_SPACING_USEC 176 /*176*/ + +// Define which serial port to use as DMX port, only one can be +// selected at the time by uncommenting one of the following +// lines +#define USE_DMX_SERIAL_0 +//#define USE_DMX_SERIAL_1 +//#define USE_DMX_SERIAL_2 +//#define USE_DMX_SERIAL_3 + +namespace dmx +{ + enum dmxState + { + dmxUnknown, + dmxStartByte, + dmxWaitStartAddress, + dmxData, + dmxFrameReady, + }; +}; + +namespace rdm +{ + enum rdmState + { + rdmUnknown, + rdmStartByte, + rdmSubStartCode, + rdmMessageLength, + rdmData, + rdmChecksumHigh, + rdmChecksumLow, + rdmFrameReady, + }; +}; + +struct IFrameBuffer +{ + virtual uint16_t getBufferSize ( void ) = 0; + + virtual uint8_t getSlotValue ( uint16_t index ) = 0; + virtual void setSlotValue ( uint16_t index, uint8_t value ) = 0; +}; + +class DMX_FrameBuffer : IFrameBuffer +{ + public: + // + // Constructor buffersize = 1-513 + // + DMX_FrameBuffer ( uint16_t buffer_size ); + DMX_FrameBuffer ( DMX_FrameBuffer &buffer ); + ~DMX_FrameBuffer ( void ); + + uint16_t getBufferSize ( void ); + + uint8_t getSlotValue ( uint16_t index ); + void setSlotValue ( uint16_t index, uint8_t value ); + void setSlotRange ( uint16_t start, uint16_t end, uint8_t value ); + void clear ( void ); + + uint8_t &operator[] ( uint16_t index ); + + private: + + uint8_t *m_refcount; + uint16_t m_bufferSize; + uint8_t *m_buffer; +}; + + +// +// DMX Master controller +// +class DMX_Master +{ + public: + // Run the DMX master from a pre allocated frame buffer which + // you have fully under your own control + DMX_Master ( DMX_FrameBuffer &buffer, int readEnablePin ); + + // Run the DMX master by giving a predefined maximum number of + // channels to support + DMX_Master ( uint16_t maxChannel, int readEnablePin ); + + ~DMX_Master ( void ); + + void enable ( void ); // Start transmitting + void disable ( void ); // Stop transmitting + + // Get reference to the internal framebuffer + DMX_FrameBuffer &getBuffer ( void ); + + // Update channel values + void setChannelValue ( uint16_t channel, uint8_t value ); + void setChannelRange ( uint16_t start, uint16_t end, uint8_t value ); + + public: + // + // Manual control over the break period + // + void setAutoBreakMode ( void ); // Generated from ISR + void setManualBreakMode ( void ); // Generate manually + + uint8_t autoBreakEnabled ( void ); + + // We are waiting for a manual break to be generated + uint8_t waitingBreak ( void ); + + // Generate break and start transmission of frame + void breakAndContinue ( uint8_t breakLength_us = 100 ); + + + protected: + void setStartCode ( uint8_t value ); + + + private: + DMX_FrameBuffer m_frameBuffer; + uint8_t m_autoBreak; +}; + + +// +// DMX Slave controller +// +class DMX_Slave : public DMX_FrameBuffer +{ + public: + DMX_Slave ( DMX_FrameBuffer &buffer, int readEnablePin = -1 ); + + // nrChannels is the consecutive DMX512 slots required + // to operate this slave device + DMX_Slave ( uint16_t nrChannels, int readEnablePin = -1 ); + + ~DMX_Slave ( void ); + + void enable ( void ); // Enable receiver + void disable ( void ); // Disable receiver + + + // Get reference to the internal framebuffer + DMX_FrameBuffer &getBuffer ( void ); + + uint8_t getChannelValue ( uint16_t channel ); + + uint16_t getStartAddress ( void ); + void setStartAddress ( uint16_t ); + + + // Process incoming byte from USART + bool processIncoming ( uint8_t val, bool first = false ); + + // Register on receive complete callback in case + // of time critical applications + void onReceiveComplete ( void (*func)(unsigned short) ); + + protected: + + + private: + uint16_t m_startAddress; // Slave start address + dmx::dmxState m_state; + + static void (*event_onFrameReceived)(unsigned short channelsReceived); +}; + + +class RDM_FrameBuffer : public IFrameBuffer +{ + public: + // + // Constructor + // + RDM_FrameBuffer ( void ) {}; + ~RDM_FrameBuffer ( void ) {}; + + uint16_t getBufferSize ( void ); + + uint8_t getSlotValue ( uint16_t index ); + void setSlotValue ( uint16_t index, uint8_t value ); + void clear ( void ); + + uint8_t &operator[] ( uint16_t index ); + + public: // functions to provide access from USART + // Process incoming byte from USART, + // returns false when no more data is accepted + bool processIncoming ( uint8_t val, bool first = false ); + + // Process outgoing byte to USART + // returns false when no more data is available + bool fetchOutgoing ( volatile uint8_t *udr, bool first = false ); + + protected: + // Process received frame + virtual void processFrame ( void ) = 0; + + //private: + protected: + rdm::rdmState m_state; // State for pushing the message in + RDM_Message m_msg; + RDM_Checksum m_csRecv; // Checksum received in rdm message +}; + +// +// RDM_Responder +// +class RDM_Responder : public RDM_FrameBuffer +{ + public: + // + // m = manufacturer id (16bits) + // d1-d4 = device id (32bits) + // + RDM_Responder ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4, DMX_Slave &slave); + ~RDM_Responder ( void ); + + void setDeviceInfo + ( + uint16_t deviceModelId, + rdm::RdmProductCategory productCategory, + uint8_t personalities = 1, + uint8_t personality = 1 + ) + { + m_DeviceModelId = deviceModelId; + m_ProductCategory = productCategory; + m_Personalities = personalities; + m_Personality = personality; + }; + + // + // Set vendor software version id + // + // v1 = MOST SIGNIFICANT + // v2... + // v3... + // v4 = LEAST SIGNIFICANT + // + void setSoftwareVersionId ( uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4 ) + { + m_SoftwareVersionId[0] = v1; + m_SoftwareVersionId[1] = v2; + m_SoftwareVersionId[2] = v3; + m_SoftwareVersionId[3] = v4; + } + + // Currently no sensors and subdevices supported + // void AddSensor ( void ); + // void AddSubDevice ( void ); + + uint8_t getPersonality ( void ) { return m_Personality; }; + void setPersonality ( uint8_t personality ) { m_Personality = personality; }; + + // Register on identify device event handler + void onIdentifyDevice ( void (*func)(bool) ); + void onDeviceLabelChanged ( void (*func) (const char*, uint8_t) ); + void onDMXStartAddressChanged ( void (*func) (uint16_t) ); + void onDMXPersonalityChanged ( void (*func) (uint8_t) ); + + + // Set the device label + void setDeviceLabel ( const char *label, size_t len ); + + // Enable, Disable rdm responder + void enable ( void ) { m_rdmStatus.enabled = true; m_rdmStatus.mute = false; }; + void disable ( void ) { m_rdmStatus.enabled = false; }; + + union + { + uint8_t raw; + struct + { + uint8_t mute:1; + uint8_t ident:1; + uint8_t enabled:1; // Rdm responder enable/disable + }; + } m_rdmStatus; + + + protected: + virtual void processFrame ( void ); + + // Discovery to unque brach packets only requires + // the data part of the packet to be transmitted + // without breaks or header + void repondDiscUniqueBranch ( void ); + + // Helpers for generating response packets which + // have larger datafields + void populateDeviceInfo ( void ); + + private: + RDM_Uid m_devid; // Holds our unique device ID + uint8_t m_Personalities; // The total number of supported personalities + uint8_t m_Personality; // The currently active personality + uint16_t m_DeviceModelId; + uint8_t m_SoftwareVersionId[4]; // 32 bit Software version + rdm::RdmProductCategory m_ProductCategory; + + char m_deviceLabel[32]; // Device label + + static void (*event_onIdentifyDevice)(bool); + static void (*event_onDeviceLabelChanged)(const char*, uint8_t); + static void (*event_onDMXStartAddressChanged)(uint16_t); + static void (*event_onDMXPersonalityChanged)(uint8_t); +}; + + +#endif /* CONCEPTINETICS_H_ */ diff --git a/DMX_NeoPixels/examples/RDM_Slave/RDM_Slave.ino b/DMX_NeoPixels/examples/RDM_Slave/RDM_Slave.ino index a793d2f32..23f77aad7 100644 --- a/DMX_NeoPixels/examples/RDM_Slave/RDM_Slave.ino +++ b/DMX_NeoPixels/examples/RDM_Slave/RDM_Slave.ino @@ -21,7 +21,7 @@ */ -#include +#include "Conceptinetics.h" // // CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD JUMPER INSTRUCTIONS diff --git a/DMX_NeoPixels/examples/RDM_Slave/Rdm_Defines.h b/DMX_NeoPixels/examples/RDM_Slave/Rdm_Defines.h new file mode 100644 index 000000000..0accca63d --- /dev/null +++ b/DMX_NeoPixels/examples/RDM_Slave/Rdm_Defines.h @@ -0,0 +1,315 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Rdm_Defines.h - DMX library for Arduino with RDM (Remote Device Management) support + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef RDM_DEFINES_H_ +#define RDM_DEFINES_H_ + +#include "Rdm_Uid.h" + +#define RDM_MAX_DEVICELABEL_LENGTH 32 + +namespace rdm +{ + enum RdmCommandClass + { + DiscoveryCommand = 0x10, + DiscoveryCommandResponse, + GetCommand = 0x20, + GetCommandResponse, + SetCommand = 0x30, + SetCommandResponse, + }; + + enum RdmResponseTypes + { + ResponseTypeAck = 0x00, + ResponseTypeAckTimer, + ResponseTypeNackReason, + ResponseTypeAckOverflow, // Additional response data available (see spec) + }; + + enum RdmParameters + { + // Category - Network Management + DiscUniqueBranch = 0x0001, // Required + DiscMute = 0x0002, // Required + DiscUnMute = 0x0003, // Required + + CommsStatus = 0x0015, // Get,Set + + // Category - Status Collection + QueuedMessage = 0x0020, // Get [enum RdmStatusTypes] + StatusMessages = 0x0030, // Get [enum RdmStatusTypes] + StatusIdDescription = 0x0031, // Get + ClearStatusId = 0x0032, // Set + SubDeviceStatusReportThreshold = 0x0033, // Get, Set [enum RdmStatusTypes] + + // Category - RDM Information + // ** Only required if supporting parameters + // beyond the minimum required set + SupportedParameters = 0x0005, // Get, **Required + ParameterDescription = 0x0051, // Get, **Required + + // Category = Product Information + DeviceInfo = 0x0060, // Get, Required + ProductDetailIdList = 0x0070, // Get + DeviceModelDescription = 0x0080, // Get + ManufacturerLabel = 0x0081, // Get + DeviceLabel = 0x0082, // Get, Set + FactoryDefaults = 0x0009, // Get, Set ** + SoftwareVersionLabel = 0x000c, // Get + + // Category - DMX512 Setup + DmxPersonality = 0x00e0, // Get, Set + DmxPersonalityDescription = 0x00e1, // Get + DmxStartAddress = 0x00f0, // Get, Set ** Required if DMX device + SlotInfo = 0x0120, // Get + SlotDescription = 0x0121, // Get + DefaultSlotValue = 0x0122, // Get + + // Category - Sensors + // Category - Dimmer Settings + // Category - Power/Lamp Settings + // Category - Display Settings + // Category - Configuration + + // Category - Control + IdentifyDevice = 0x1000, // Get, Set, Required + ResetDevice = 0x1001, // Set + PowerState = 0x1010, // Get, Set + PerformSelftest = 0x1020, // Get, Set + SelfTestDescription = 0x1021, // Get + }; + + + enum RdmStatusTypes + { + StatusNone = 0x00, + StatusGetLastMessage, + StatusAdvisory, + StatusWarning, + StatusError, + StatusAdvisoryCleared = 0x12, + StatusWarningCleared, + StatusErrorCleared, + }; + + enum RdmProductCategory + { + CategoryNotDeclared = 0x0000, + + // Fixtures - intended as source for illumination + CategoryFixture = 0x0100, + CategoryFixtureFixed = 0x0101, + CategoryFixtureMovingYoke = 0x0102, + CategoryFixtureMovingMirror = 0x0103, + CategoryFixtureOther = 0x01ff, + + // Fixture Accessories - add-ons to fixtures or projectors + CategoryFixtureAccessory = 0x0200, + CategoryFixtureAccessoryColor = 0x0201, + CategoryFixtureAccessoryYoke = 0x0202, + CategoryFixtureAccessoryMirror = 0x0203, + CategoryFixtureAccessoryEffect = 0x0204, + CategoryFixtureAccessoryBeam = 0x0205, + CategoryFixtureAccessoryOther = 0x02ff, + + // Projectors - Light source capable of producing + // realistic images from another media + CategoryProjector = 0x0300, + CategoryProjectorFixed = 0x0301, + CategoryProjectorMovingYoke = 0x0302, + CategoryProjectorMovingMirror = 0x0303, + CategoryProjectorOther = 0x03ff, + + // Atmospheric Effect - earth/wind/fire + CategoryAtmospheric = 0x0400, + CategoryAtmosphericEffect = 0x0401, // Fogger, Hazer, Flame + CategoryAtmosphericPyro = 0x0402, + CategoryAtmosphericOther = 0x04ff, + + // Insensity Control (Specifically dimming equipment) + CategoryDimmer = 0x0500, + CategoryDimmer_AC_Incandescent = 0x0501, + CategoryDimmer_AC_Fluorescent = 0x0502, + CategoryDimmer_AC_Coldcathode = 0x0503, + CategoryDimmer_AC_Nondim = 0x0504, + CategoryDimmer_AC_Elv = 0x0505, + CategoryDimmer_AC_Other = 0x0506, + CategoryDimmer_DC_Level = 0x0507, + CategoryDimmer_DC_PWM = 0x0508, + CategoryDimmer_CS_LED = 0x0509, + CategoryDimmer_Other = 0x05ff, + + // Power control (Other than dimming equipment) + CategoryPower = 0x0600, + CategoryPowerControl = 0x0601, + CategoryPowerSource = 0x0602, + CategoryPowerOther = 0x06ff, + + // Scenic Drive - Including motorized effects + // unrelated to light source + CategoryScenic = 0x0700, + CategoryScenicDrive = 0x0701, + CategoryScenicOther = 0x07ff, + + // DMX Infrastructure, conversion and interfaces + CategoryData = 0x0800, + CategoryDataDistribution = 0x0801, + CategoryDataConversion = 0x0802, + CategoryDataOther = 0x08ff, + + // Audio visual equipment + Category_AV = 0x0900, + Category_AV_Audio = 0x0901, + Category_AV_Video = 0x0902, + Category_AV_Other = 0x09ff, + + // Parameter monitoring equipment + CategoryMonitor = 0x0a00, + CategoryMonitorACLinePower = 0x0a01, + CategoryMonitorDCPower = 0x0a02, + CategoryMonitorEnvironmental = 0x0a03, + CategoryMonitorOther = 0x0aff, + + // Controllers, backup devices + CategoryControl = 0x7000, + CategoryControlController = 0x7001, + CategoryControlBackupdevice = 0x7002, + CategoryControlOther = 0x70ff, + + // Test equipment + CategoryTest = 0x7100, + CategoryTestEquipment = 0x7101, + CategoryTestEquipmentOther = 0x71ff, + + // Miscellaneous + CategoryOther = 0x7fff, + }; + + // + // Product details not yet supported in + // this library + // + enum RdmProductDetail + { + ProductDetailNotDeclared = 0x0000, + }; + + // Only LSB + enum RdmNackReasons + { + UnknownPid = 0x00, + FormatError, + HardwareFault, + ProxyReject, + WriteProtect, + UnsupportedCmdClass, + DataOutOfRange, + BufferFull, + PacketSizeUnsupported, + SubDeviceOutOfRange, + ProxyBufferFull + }; + +}; + + +#define RDM_HDR_LEN 24 // RDM Message header length ** fixed +#define RDM_PD_MAXLEN 32 // RDM Maximum parameter data length 1 - 231 + + +union RDM_Message +{ + uint8_t d[ RDM_HDR_LEN + RDM_PD_MAXLEN ]; + struct + { + uint8_t startCode; // 0 SC_RDM + uint8_t subStartCode; // 1 SC_SUB_MESSAGE + uint8_t msgLength; // 2 Range 24 - 255 + RDM_Uid dstUid; // 3-8 Destination UID + RDM_Uid srcUid; // 9-14 Source UID (sender) + uint8_t TN; // 15 Transaction number + uint8_t portId; // 16 Port ID / Response type + uint8_t msgCount; // 17 + uint16_t subDevice; // 18,19 0=root, 0xffff=all + uint8_t CC; // 20 GET_COMMAND + uint16_t PID; // 21,22 Parameter ID + uint8_t PDL; // 23 Parameter Data length 1-231 + + uint8_t PD[RDM_PD_MAXLEN]; // Parameter Data ... variable length + }; +}; + +union RDM_Checksum +{ + uint16_t checksum; + struct + { + uint8_t csl; + uint8_t csh; + }; +}; + +struct RDM_DiscUniqueBranchPD +{ + RDM_Uid lbound; + RDM_Uid hbound; +}; + +struct RDM_DiscMuteUnMutePD +{ + uint16_t ctrlField; + +// Only for multiple ports +// RDM_Uid bindingUid; +}; + +struct RDM__DeviceInfoPD +{ + uint8_t protocolVersionMajor; + uint8_t protocolVersionMinor; + uint16_t deviceModelId; + uint16_t ProductCategory; // enum RdmProductCategory + uint8_t SoftwareVersionId[4]; + uint16_t DMX512FootPrint; + uint8_t DMX512CurrentPersonality; + uint8_t DMX512NumberPersonalities; + uint16_t DMX512StartAddress; + uint16_t SubDeviceCount; + uint8_t SensorCount; +}; + +struct RDM_DeviceGetPersonality_PD +{ + uint8_t DMX512CurrentPersonality; + uint8_t DMX512NumberPersonalities; +}; + +struct RDM_DeviceSetPersonality_PD +{ + uint8_t DMX512Personality; +}; + + +#endif /* RDM_DEFINES_H_ */ diff --git a/DMX_NeoPixels/examples/RDM_Slave/Rdm_Uid.h b/DMX_NeoPixels/examples/RDM_Slave/Rdm_Uid.h new file mode 100644 index 000000000..35c802c63 --- /dev/null +++ b/DMX_NeoPixels/examples/RDM_Slave/Rdm_Uid.h @@ -0,0 +1,101 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Rdm_Uid.h - DMX library for Arduino with RDM (Remote Device Management) support + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef RDM_UID_H_ +#define RDM_UID_H_ + +#include + +// +//48 bit UID Representation to identify RDM transponders +// +struct RDM_Uid { + + void Initialize ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4 ) + { + m_id[0] = ((uint8_t) (((uint16_t) (m)) >> 8)); + m_id[1] = (uint8_t)m; + m_id[2] = d1; + m_id[3] = d2; + m_id[4] = d3; + m_id[5] = d4; + } + + void copy ( const RDM_Uid &orig ) + { + for ( uint8_t i = 0; i < 6; i++ ) + m_id[i] = orig.m_id[i]; + } + + bool operator == ( const RDM_Uid & orig ) const + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != orig.m_id[i] ) + return false; + + return true; + } + + bool operator != ( const RDM_Uid & orig ) const + { + return !(*this == orig); + } + + bool operator < ( const RDM_Uid & v ) const + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != v.m_id[i] ) + return ( m_id[i] < v.m_id[i] ); + } + + bool operator > ( const RDM_Uid & v ) + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != v.m_id[i] ) + return ( m_id[i] > v.m_id[i] ); + } + + // + // match_mid = manufacturer id to match + // + bool isBroadcast ( uint8_t match_mid[2] ) + { + // Check for genuine broadcast on device part + for ( uint8_t i = 2; i < 6; i++ ) + if ( m_id[i] != 0xff ) + return false; + + // Broadcast or manufacturer designated broadcast + if ( (m_id[0] == 0xff && m_id[1] == 0xff) || + (m_id[0] == match_mid[0] && m_id[1] == match_mid[1]) ) + return true; + + // No broadcast + return false; + } + + uint8_t m_id[6]; //16bit manufacturer id + 32 bits device id +}; + + +#endif /* RDM_UID_H_ */ diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.cpb.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.cpb.test.skip deleted file mode 100644 index 064a28912..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.cpb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpb diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.cpc.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.cpc.test.skip deleted file mode 100644 index 79763353d..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.cpc.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpc diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.cpx_ada.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.cpx_ada.test.skip deleted file mode 100644 index d9c56cc11..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.cpx_ada.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for cpx_ada diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.esp32.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.esp32.test.skip deleted file mode 100644 index 5faeb5064..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.esp32.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for esp32 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.esp8266.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.esp8266.test.skip deleted file mode 100644 index 15eb13221..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.esp8266.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for esp8266 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather32u4.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather32u4.test.skip deleted file mode 100644 index eb9fd87a1..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather32u4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather32u4 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather_esp32c6.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather_esp32c6.test.skip deleted file mode 100644 index 563448c75..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather_esp32c6.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_esp32c6 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather_m0_express.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather_m0_express.test.skip deleted file mode 100644 index c1118c563..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather_m0_express.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_m0_express diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather_m4_express.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather_m4_express.test.skip deleted file mode 100644 index 9b961626f..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather_m4_express.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_m4_express diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather_rp2040.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather_rp2040.test.skip deleted file mode 100644 index 90aa322a7..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather_rp2040.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_rp2040 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather_rp2040_adalogger.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather_rp2040_adalogger.test.skip deleted file mode 100644 index 29ebf0ea0..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.feather_rp2040_adalogger.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for feather_rp2040_adalogger diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.flora.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.flora.test.skip deleted file mode 100644 index e4cc7386e..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.flora.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for flora diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.funhouse.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.funhouse.test.skip deleted file mode 100644 index 32a4e1e1a..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.funhouse.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for funhouse diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.gemma.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.gemma.test.skip deleted file mode 100644 index 978f275e3..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.gemma.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for gemma diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.gemma_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.gemma_m0.test.skip deleted file mode 100644 index c42614d7c..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.gemma_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for gemma_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.hallowing_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.hallowing_m0.test.skip deleted file mode 100644 index ed26fdf6a..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.hallowing_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for hallowing_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.hallowing_m4_tinyusb.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.hallowing_m4_tinyusb.test.skip deleted file mode 100644 index 0ab22cb8d..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.hallowing_m4_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for hallowing_m4_tinyusb diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.ledglasses_nrf52840.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.ledglasses_nrf52840.test.skip deleted file mode 100644 index f540a7e4c..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.ledglasses_nrf52840.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for ledglasses_nrf52840 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.magtag.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.magtag.test.skip deleted file mode 100644 index 79d0d324c..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.magtag.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for magtag diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.metro_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.metro_m0.test.skip deleted file mode 100644 index 91512a898..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.metro_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.metro_m0_tinyusb.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.metro_m0_tinyusb.test.skip deleted file mode 100644 index 486e4f67e..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.metro_m0_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m0_tinyusb diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.metro_m4.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.metro_m4.test.skip deleted file mode 100644 index 5012f3737..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.metro_m4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m4 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.metro_m4_tinyusb.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.metro_m4_tinyusb.test.skip deleted file mode 100644 index 17edc54fe..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.metro_m4_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for metro_m4_tinyusb diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.monster_m4sk.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.monster_m4sk.test.skip deleted file mode 100644 index ec7f80e48..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.monster_m4sk.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for monster_m4sk diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.monster_m4sk_tinyusb.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.monster_m4sk_tinyusb.test.skip deleted file mode 100644 index a08b60688..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.monster_m4sk_tinyusb.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for monster_m4sk_tinyusb diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.neokeytrinkey_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.neokeytrinkey_m0.test.skip deleted file mode 100644 index 7fb03fe33..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.neokeytrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for neokeytrinkey_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.neotrellis_m4.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.neotrellis_m4.test.skip deleted file mode 100644 index eebfceae8..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.neotrellis_m4.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for neotrellis_m4 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.nrf52832.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.nrf52832.test.skip deleted file mode 100644 index ee506a55a..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.nrf52832.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for nrf52832 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.nrf52840.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.nrf52840.test.skip deleted file mode 100644 index a6bcf2c9d..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.nrf52840.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for nrf52840 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.pixeltrinkey_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.pixeltrinkey_m0.test.skip deleted file mode 100644 index 4a5f3b346..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.pixeltrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pixeltrinkey_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.protrinket_5v.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.protrinket_5v.test.skip deleted file mode 100644 index ec91a95cb..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.protrinket_5v.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for protrinket_5v diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.proxlighttrinkey_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.proxlighttrinkey_m0.test.skip deleted file mode 100644 index 0d46213a9..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.proxlighttrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for proxlighttrinkey_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.pybadge.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.pybadge.test.skip deleted file mode 100644 index 82cd2ac9c..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.pybadge.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pybadge diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.pycamera_s3.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.pycamera_s3.test.skip deleted file mode 100644 index 021a63e54..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.pycamera_s3.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pycamera_s3 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.pygamer.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.pygamer.test.skip deleted file mode 100644 index 430cf639c..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.pygamer.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pygamer diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.pyportal.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.pyportal.test.skip deleted file mode 100644 index 6a18dce9f..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.pyportal.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for pyportal diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.qt2040_trinkey.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.qt2040_trinkey.test.skip deleted file mode 100644 index 263748866..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.qt2040_trinkey.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qt2040_trinkey diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.qtpy_esp32s2.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.qtpy_esp32s2.test.skip deleted file mode 100644 index 627d7dd57..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.qtpy_esp32s2.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qtpy_esp32s2 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.qtpy_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.qtpy_m0.test.skip deleted file mode 100644 index fbc42f083..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.qtpy_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qtpy_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.qualia_s3_rgb666.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.qualia_s3_rgb666.test.skip deleted file mode 100644 index 1e14eea6e..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.qualia_s3_rgb666.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for qualia_s3_rgb666 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.rotarytrinkey_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.rotarytrinkey_m0.test.skip deleted file mode 100644 index 8a2ec7327..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.rotarytrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for rotarytrinkey_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.sht4xtrinkey_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.sht4xtrinkey_m0.test.skip deleted file mode 100644 index 039d08b3e..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.sht4xtrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for sht4xtrinkey_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.slidetrinkey_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.slidetrinkey_m0.test.skip deleted file mode 100644 index d3f14ba82..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.slidetrinkey_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for slidetrinkey_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.trinket_5v.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.trinket_5v.test.skip deleted file mode 100644 index e2d3dded0..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.trinket_5v.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for trinket_5v diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.trinket_m0.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.trinket_m0.test.skip deleted file mode 100644 index 06ad7bf51..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.trinket_m0.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for trinket_m0 diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.uno.test.only b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.uno.test.skip b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.uno.test.skip deleted file mode 100644 index f3e164df1..000000000 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/.uno.test.skip +++ /dev/null @@ -1 +0,0 @@ -# Skip test for uno diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/Conceptinetics.cpp b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/Conceptinetics.cpp new file mode 100644 index 000000000..36ada5924 --- /dev/null +++ b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/Conceptinetics.cpp @@ -0,0 +1,1233 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Conceptinetics.cpp - DMX library for Arduino + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + This code has been tested using the following hardware: + + - Arduino UNO R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino MEGA2560 R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD +*/ + + +#include "pins_arduino.h" +#include "Conceptinetics.h" + +#include +#include + +#include +#include + +#include + + +#if defined (USE_DMX_SERIAL_0) + + #if defined (USART__TXC_vect) + #define USART_TX USART__TXC_vect + #elif defined(USART_TX_vect) + #define USART_TX USART_TX_vect + #elif defined(USART0_TX_vect) + #define USART_TX USART0_TX_vect + #endif + + #if defined (USART__RXC_vect) + #define USART_RX USART__RXC_vect + #elif defined(USART_RX_vect) + #define USART_RX USART_RX_vect + #elif defined(USART0_RX_vect) + #define USART_RX USART0_RX_vect + #endif + + #if defined UDR + #define DMX_UDR UDR + #elif defined UDR0 + #define DMX_UDR UDR0 + #endif + + #if defined(UBRRH) && defined(UBRRL) + #define DMX_UBRRH UBRRH + #define DMX_UBRRL UBRRL + #elif defined(UBRR0H) && defined(UBRR0L) + #define DMX_UBRRH UBRR0H + #define DMX_UBRRL UBRR0L + #endif + + #if defined(UCSRA) + #define DMX_UCSRA UCSRA + #elif defined(UCSR0A) + #define DMX_UCSRA UCSR0A + #endif + + #if defined(UCSRB) + #define DMX_UCSRB UCSRB + #elif defined (UCSR0B) + #define DMX_UCSRB UCSR0B + #endif + + #if defined(TXEN) && defined(TXCIE) + #define DMX_TXEN TXEN + #define DMX_TXCIE TXCIE + #elif defined(TXEN0) && defined(TXCIE0) + #define DMX_TXEN TXEN0 + #define DMX_TXCIE TXCIE0 + #endif + + #if defined(RXEN) && defined(RXCIE) + #define DMX_RXEN RXEN + #define DMX_RXCIE RXCIE + #elif defined(RXEN0) && defined(RXCIE0) + #define DMX_RXEN RXEN0 + #define DMX_RXCIE RXCIE0 + #endif + + #if defined(FE) + #define DMX_FE FE + #elif defined(FE0) + #define DMX_FE FE0 + #endif + + #define RX_PIN 0 + #define TX_PIN 1 + +#elif defined (USE_DMX_SERIAL_1) + #define USART_RX USART1_RX_vect + #define USART_TX USART1_TX_vect + #define DMX_UDR UDR1 + #define DMX_UBRRH UBRR1H + #define DMX_UBRRL UBRR1L + #define DMX_UCSRA UCSR1A + #define DMX_UCSRB UCSR1B + #define DMX_TXEN TXEN1 + #define DMX_TXCIE TXCIE1 + #define DMX_RXEN RXEN1 + #define DMX_RXCIE RXCIE1 + #define DMX_FE FE1 + #define RX_PIN 19 + #define TX_PIN 18 +#elif defined (USE_DMX_SERIAL_2) + #define USART_RX USART2_RX_vect + #define USART_TX USART2_TX_vect + #define DMX_UDR UDR2 + #define DMX_UBRRH UBRR2H + #define DMX_UBRRL UBRR2L + #define DMX_UCSRA UCSR2A + #define DMX_UCSRB UCSR2B + #define DMX_TXEN TXEN2 + #define DMX_TXCIE TXCIE2 + #define DMX_RXEN RXEN2 + #define DMX_RXCIE RXCIE2 + #define DMX_FE FE2 + #define RX_PIN 17 + #define TX_PIN 16 +#elif defined (USE_DMX_SERIAL_3) + #define USART_RX USART3_RX_vect + #define USART_TX USART3_TX_vect + #define DMX_UDR UDR3 + #define DMX_UBRRH UBRR3H + #define DMX_UBRRL UBRR3L + #define DMX_UCSRA UCSR3A + #define DMX_UCSRB UCSR3B + #define DMX_TXEN TXEN3 + #define DMX_TXCIE TXCIE3 + #define DMX_RXEN RXEN3 + #define DMX_RXCIE RXCIE3 + #define DMX_FE FE3 + #define RX_PIN 14 + #define TX_PIN 15 +#endif + + +#define LOWBYTE(v) ((uint8_t) (v)) +#define HIGHBYTE(v) ((uint8_t) (((uint16_t) (v)) >> 8)) + +#define BSWAP_16(x) ( (uint8_t)((x) >> 8) | ((uint8_t)(x)) << 8 ) + +namespace isr +{ + enum isrState + { + Idle, + Break, + DmxBreak, + DmxBreakManual, + DmxStartByte, + DmxRecordData, + DmxTransmitData, + RdmBreak, + RdmStartByte, + RdmRecordData, + RdmTransmitData, + RDMTransmitComplete, + }; + + enum isrMode + { + Disabled, + Receive, + DMXTransmit, + DMXTransmitManual, /* Manual break... */ + RDMTransmit, + RDMTransmitNoInt, /* Setup uart but leave interrupt disabled */ + }; +}; + + +DMX_Master *__dmx_master; +DMX_Slave *__dmx_slave; +RDM_Responder *__rdm_responder; + +int8_t __re_pin; // R/W Pin on shield + +isr::isrState __isr_txState; // TX ISR state +isr::isrState __isr_rxState; // RX ISR state + + +void SetISRMode ( isr::isrMode ); + + +DMX_FrameBuffer::DMX_FrameBuffer ( uint16_t buffer_size ) +{ + m_refcount = (uint8_t*) malloc ( sizeof ( uint8_t ) ); + + if ( buffer_size >= DMX_MIN_FRAMESIZE && buffer_size <= DMX_MAX_FRAMESIZE ) + { + m_buffer = (uint8_t*) malloc ( buffer_size ); + if ( m_buffer != NULL ) + { + memset ( (void *)m_buffer, 0x0, buffer_size ); + m_bufferSize = buffer_size; + } + else + m_buffer = 0x0; + } + else + m_bufferSize = 0x0; + + *m_refcount++; +} + +DMX_FrameBuffer::DMX_FrameBuffer ( DMX_FrameBuffer &buffer ) +{ + // Copy references and make sure the parent object does not dispose our + // buffer when deleted and we are still active + this->m_refcount = buffer.m_refcount; + (*this->m_refcount)++; + + this->m_buffer = buffer.m_buffer; + this->m_bufferSize = buffer.m_bufferSize; +} + +DMX_FrameBuffer::~DMX_FrameBuffer ( void ) +{ + // If we are the last object using the + // allocated buffer then free it together + // with the refcounter + if ( --(*m_refcount) == 0 ) + { + if ( m_buffer ) + free ( m_buffer ); + + free ( m_refcount ); + } +} + +uint16_t DMX_FrameBuffer::getBufferSize ( void ) +{ + return m_bufferSize; +} + + +uint8_t DMX_FrameBuffer::getSlotValue ( uint16_t index ) +{ + if (index < m_bufferSize) + return m_buffer[index]; + else + return 0x0; +} + + +void DMX_FrameBuffer::setSlotValue ( uint16_t index, uint8_t value ) +{ + if ( index < m_bufferSize ) + m_buffer[index] = value; +} + + +void DMX_FrameBuffer::setSlotRange ( uint16_t start, uint16_t end, uint8_t value ) +{ + if ( start < m_bufferSize && end < m_bufferSize && start < end ) + memset ( (void *) &m_buffer[start], value, end-start+1 ); +} + +void DMX_FrameBuffer::clear ( void ) +{ + memset ( (void *) m_buffer, 0x0, m_bufferSize ); +} + +uint8_t &DMX_FrameBuffer::operator[] ( uint16_t index ) +{ + return m_buffer[index]; +} + + +DMX_Master::DMX_Master ( DMX_FrameBuffer &buffer, int readEnablePin ) +: m_frameBuffer ( buffer ), + m_autoBreak ( 1 ) // Autobreak generation is default on +{ + setStartCode ( DMX_START_CODE ); + + __re_pin = readEnablePin; + pinMode ( __re_pin, OUTPUT ); + + ::SetISRMode ( isr::Disabled ); +} + +DMX_Master::DMX_Master ( uint16_t maxChannel, int readEnablePin ) +: m_frameBuffer ( maxChannel + DMX_STARTCODE_SIZE ), + m_autoBreak ( 1 ) // Autobreak generation is default on +{ + setStartCode ( DMX_START_CODE ); + + __re_pin = readEnablePin; + pinMode ( __re_pin, OUTPUT ); + + ::SetISRMode ( isr::Disabled ); +} + +DMX_Master::~DMX_Master ( void ) +{ + disable (); // Stop sending + __dmx_master = NULL; +} + +DMX_FrameBuffer &DMX_Master::getBuffer ( void ) +{ + return m_frameBuffer; // Return reference to frame buffer +} + +void DMX_Master::setStartCode ( uint8_t value ) +{ + m_frameBuffer[0] = value; // Set the first byte in our frame buffer +} + +void DMX_Master::setChannelValue ( uint16_t channel, uint8_t value ) +{ + if ( channel > 0 ) // Prevent overwriting the start code + m_frameBuffer.setSlotValue ( channel, value ); +} + +void DMX_Master::setChannelRange ( uint16_t start, uint16_t end, uint8_t value ) +{ + if ( start > 0 ) // Prevent overwriting the start code + m_frameBuffer.setSlotRange ( start, end, value ); +} + + +void DMX_Master::enable ( void ) +{ + __dmx_master = this; + + if ( m_autoBreak ) + ::SetISRMode ( isr::DMXTransmit ); + else + ::SetISRMode ( isr::DMXTransmitManual ); +} + +void DMX_Master::disable ( void ) +{ + ::SetISRMode ( isr::Disabled ); + __dmx_master = NULL; // No active master +} + +void DMX_Master::setAutoBreakMode ( void ) { m_autoBreak = 1; } +void DMX_Master::setManualBreakMode ( void ) { m_autoBreak = 0; } +uint8_t DMX_Master::autoBreakEnabled ( void ) { return m_autoBreak; } + + +uint8_t DMX_Master::waitingBreak ( void ) +{ + return ( __isr_txState == isr::DmxBreakManual ); +} + +void DMX_Master::breakAndContinue ( uint8_t breakLength_us ) +{ + // Only execute if we are the controlling master object + if ( __dmx_master == this && __isr_txState == isr::DmxBreakManual ) + { + pinMode ( TX_PIN, OUTPUT ); + digitalWrite ( TX_PIN, LOW ); // Begin BREAK + + for (uint8_t bl=0; bl(*this); +} + + uint8_t DMX_Slave::getChannelValue ( uint16_t channel ) +{ + return getSlotValue ( channel ); +} + + +uint16_t DMX_Slave::getStartAddress ( void ) +{ + return m_startAddress; +} + +void DMX_Slave::setStartAddress ( uint16_t addr ) +{ + m_startAddress = addr; +} + +void DMX_Slave::onReceiveComplete ( void (*func)(unsigned short) ) +{ + event_onFrameReceived = func; +} + + +bool DMX_Slave::processIncoming ( uint8_t val, bool first ) +{ + static uint16_t idx; + bool rval = false; + + if ( first ) + { + // We could have received less channels then we + // expected.. but still is a complete frame + if (m_state == dmx::dmxData && event_onFrameReceived) + event_onFrameReceived (idx); + + m_state = dmx::dmxStartByte; + } + + switch ( m_state ) + { + case dmx::dmxStartByte: + setSlotValue ( 0, val ); // Store start code + idx = m_startAddress; + m_state = dmx::dmxWaitStartAddress; + + case dmx::dmxWaitStartAddress: + if ( --idx == 0 ) + m_state = dmx::dmxData; + break; + + case dmx::dmxData: + if ( idx++ < getBufferSize() ) + setSlotValue ( idx, val ); + else + { + m_state = dmx::dmxFrameReady; + + // If a onFrameReceived callback is register... + if (event_onFrameReceived) + event_onFrameReceived (idx-2); + + rval = true; + } + break; + } + + return rval; +} + + +uint16_t RDM_FrameBuffer::getBufferSize ( void ) { return sizeof ( m_msg ); } + +uint8_t RDM_FrameBuffer::getSlotValue ( uint16_t index ) +{ + if ( index < sizeof ( m_msg ) ) + return m_msg.d[index]; + else + return 0x0; +} + + +void RDM_FrameBuffer::setSlotValue ( uint16_t index, uint8_t value ) +{ + if ( index < sizeof ( m_msg ) ) + m_msg.d[index] = value; +} + +void RDM_FrameBuffer::clear ( void ) +{ + memset ( (void*)m_msg.d, 0x0, sizeof( m_msg ) ); + m_state = rdm::rdmUnknown; +} + +bool RDM_FrameBuffer::processIncoming ( uint8_t val, bool first ) +{ + static uint16_t idx; + bool rval = false; + + if ( first ) + { + m_state = rdm::rdmStartByte; + m_csRecv.checksum = (uint16_t) 0x0000; + idx = 0; + } + + // Prevent buffer overflow for large messages + if (idx >= sizeof(m_msg)) + return true; + + switch ( m_state ) + { + case rdm::rdmStartByte: + m_msg.startCode = val; + m_state = rdm::rdmSubStartCode; + break; + + case rdm::rdmSubStartCode: + if ( val != 0x01 ) + { + rval = true; // Stop processing data + break; + } + + m_msg.subStartCode = val; + m_state = rdm::rdmMessageLength; + break; + + case rdm::rdmMessageLength: + m_msg.msgLength = val; + m_state = rdm::rdmData; + m_csRecv.checksum = 0xcc + 0x01 + val; // set initial checksum + idx = 3; // buffer index for next byte + break; + + case rdm::rdmData: + m_msg.d[idx++] = val; + m_csRecv.checksum += val; + if ( idx >= m_msg.msgLength ) + m_state = rdm::rdmChecksumHigh; + break; + + case rdm::rdmChecksumHigh: + m_csRecv.csh = val; + m_state = rdm::rdmChecksumLow; + + break; + + case rdm::rdmChecksumLow: + m_csRecv.csl = val; + + if ((m_csRecv.checksum % (uint16_t)0x10000) == m_csRecv.checksum) + { + m_state = rdm::rdmFrameReady; + + // valid checksum ... start processing + processFrame (); + } + + m_state = rdm::rdmUnknown; + rval = true; + break; + }; + + return rval; +} + +bool RDM_FrameBuffer::fetchOutgoing ( volatile uint8_t *udr, bool first ) +{ + static uint16_t idx; + static uint16_t cs; + bool rval = false; + + + if ( first ) + { + m_state = rdm::rdmData; + cs = 0x0; + idx = 0; + } + + switch ( m_state ) + { + case rdm::rdmData: + cs += m_msg.d[idx]; + *udr = m_msg.d[idx++]; + if ( idx >= m_msg.msgLength ) + { + m_state = rdm::rdmChecksumHigh; + } + break; + + case rdm::rdmChecksumHigh: + *udr = (cs >> 8); + m_state = rdm::rdmChecksumLow; + break; + + case rdm::rdmChecksumLow: + *udr = (cs & 0xff); + m_state = rdm::rdmUnknown; + rval = true; + break; + + } + + return rval; +} + + +void (*RDM_Responder::event_onIdentifyDevice)(bool); +void (*RDM_Responder::event_onDeviceLabelChanged)(const char*, uint8_t); +void (*RDM_Responder::event_onDMXStartAddressChanged)(uint16_t); +void (*RDM_Responder::event_onDMXPersonalityChanged)(uint8_t); + +// +// slave parameter is only used to ensure a slave object is present before +// initializing the rdm responder class +// +RDM_Responder::RDM_Responder ( uint16_t m, uint8_t d1, uint8_t d2, + uint8_t d3, uint8_t d4, DMX_Slave &slave ) +: RDM_FrameBuffer ( ), + m_Personalities (1), // Available personlities + m_Personality (1) // Default personality eq 1. +{ + __rdm_responder = this; + m_devid.Initialize ( m, d1, d2, d3, d4 ); + + // Default software version id = 0x00000000 + memset ( (void*)m_SoftwareVersionId, 0x0, 0x4 ); + + // Rdm responder is disabled by default + m_rdmStatus.enabled = false; +} + +RDM_Responder::~RDM_Responder ( void ) +{ + __rdm_responder = NULL; +} + +void RDM_Responder::onIdentifyDevice ( void (*func)(bool) ) +{ + event_onIdentifyDevice = func; +} + +void RDM_Responder::onDeviceLabelChanged ( void (*func) (const char*, uint8_t) ) +{ + event_onDeviceLabelChanged = func; +} + +void RDM_Responder::onDMXStartAddressChanged ( void (*func) (uint16_t) ) +{ + event_onDMXStartAddressChanged = func; +} + +void RDM_Responder::onDMXPersonalityChanged ( void (*func) (uint8_t) ) +{ + event_onDMXPersonalityChanged = func; +} + +void RDM_Responder::setDeviceLabel ( const char *label, size_t len ) +{ + if ( len > RDM_MAX_DEVICELABEL_LENGTH ) + len = RDM_MAX_DEVICELABEL_LENGTH; + + memcpy ( (void *)m_deviceLabel, (void *)label, len ); +} + +#define UID_0 0x12 //ESTA device ID +#define UID_1 0x34 +#define UID_2 0x56 +#define UID_3 0x88 +#define UID_4 0x00 +#define UID_5 0x00 + +#define UID_CS (0xFF *6 +UID_0 +UID_1 +UID_2 +UID_3 +UID_4 +UID_5) + +void RDM_Responder::repondDiscUniqueBranch ( void ) +{ + #if defined(UCSRB) + UCSRB = (1<>8) | 0xaa; + response [21] = (cs>>8) | 0x55; + response [22] = (cs&0xff) | 0xaa; + response [23] = (cs&0xff) | 0x55; + + + // Table 3-2 ANSI_E1-20-2010 <2ms + _delay_us ( MIN_RESPONDER_PACKET_SPACING_USEC ); + + // Fix: 2017, Feb 28: Moved data enable down in order to limit line in marking state time to comply with + // section 3.2.3 + // Set shield to transmit mode (turn arround) + digitalWrite ( __re_pin, HIGH ); + + + for ( int i=0; i<24; i++ ) + { + // Wait until data register is empty + #if defined (UCSR0A) && defined (UDRE0) + while((UCSR0A & (1 <(m_msg.PD); + + pd->protocolVersionMajor = 0x01; + pd->protocolVersionMinor = 0x00; + pd->deviceModelId = BSWAP_16(m_DeviceModelId); + pd->ProductCategory = BSWAP_16(m_ProductCategory); + memcpy ( (void*)pd->SoftwareVersionId, (void*)m_SoftwareVersionId, 4 ); + pd->DMX512FootPrint = BSWAP_16(__dmx_slave->getBufferSize()-1); // eq buffersize-startbyte + pd->DMX512CurrentPersonality = m_Personality; + pd->DMX512NumberPersonalities = m_Personalities; + pd->DMX512StartAddress = BSWAP_16(__dmx_slave->getStartAddress()); + + pd->SubDeviceCount = 0x0; // Sub devices are not supported by this library + pd->SensorCount = 0x0; // Sensors are not yet supported + + m_msg.PDL = sizeof (RDM__DeviceInfoPD); +} + +const uint8_t ManufacturerLabel_P[] PROGMEM = "Conceptinetics"; + +void RDM_Responder::processFrame ( void ) +{ + // If packet is a general broadcast + if ( + m_msg.dstUid.isBroadcast (m_devid.m_id) || + m_devid == m_msg.dstUid + ) + { + // Set default response type + m_msg.portId = rdm::ResponseTypeAck; + + switch ( BSWAP_16(m_msg.PID) ) + { + case rdm::DiscUniqueBranch: + // Check if we are inside the given unique branch... + if ( !m_rdmStatus.mute && + reinterpret_cast(m_msg.PD)->lbound < m_devid && + reinterpret_cast(m_msg.PD)->hbound > m_devid ) + { + // Discovery messages are responded with data only and no breaks + repondDiscUniqueBranch (); + } + break; + + case rdm::DiscMute: + reinterpret_cast(m_msg.PD)->ctrlField = 0x0; + m_msg.PDL = sizeof ( RDM_DiscMuteUnMutePD ); + m_rdmStatus.mute = true; + break; + + case rdm::DiscUnMute: + reinterpret_cast(m_msg.PD)->ctrlField = 0x0; + m_msg.PDL = sizeof ( RDM_DiscMuteUnMutePD ); + m_rdmStatus.mute = false; + break; + + case rdm::SupportedParameters: + // + // Temporary solution... this will become dynamic + // in a later version... + // + m_msg.PD[0] = HIGHBYTE(rdm::DmxStartAddress); // MSB + m_msg.PD[1] = LOWBYTE (rdm::DmxStartAddress); // LSB + + m_msg.PD[2] = HIGHBYTE(rdm::DmxPersonality); + m_msg.PD[3] = LOWBYTE (rdm::DmxPersonality); + + m_msg.PD[4] = HIGHBYTE(rdm::ManufacturerLabel); + m_msg.PD[5] = LOWBYTE (rdm::ManufacturerLabel); + + m_msg.PD[6] = HIGHBYTE(rdm::DeviceLabel); + m_msg.PD[7] = LOWBYTE (rdm::DeviceLabel); + + m_msg.PDL = 0x6; + break; + + // Only for manufacturer specific parameters + // case rdm::ParameterDescription: + // break; + + case rdm::DeviceInfo: + if ( m_msg.CC == rdm::GetCommand ) + populateDeviceInfo (); + break; + + case rdm::DmxStartAddress: + if ( m_msg.CC == rdm::GetCommand ) + { + m_msg.PD[0] = HIGHBYTE(__dmx_slave->getStartAddress ()); + m_msg.PD[1] = LOWBYTE (__dmx_slave->getStartAddress ()); + m_msg.PDL = 0x2; + } + else // if ( m_msg.CC == rdm::SetCommand ) + { + __dmx_slave->setStartAddress ( (m_msg.PD[0] << 8) + m_msg.PD[1] ); + m_msg.PDL = 0x0; + + if ( event_onDMXStartAddressChanged ) + event_onDMXStartAddressChanged ( (m_msg.PD[0] << 8) + m_msg.PD[1] ); + } + break; + + case rdm::DmxPersonality: + if ( m_msg.CC == rdm::GetCommand ) + { + reinterpret_cast + (m_msg.PD)->DMX512CurrentPersonality = m_Personality; + reinterpret_cast + (m_msg.PD)->DMX512CurrentPersonality = m_Personalities; + m_msg.PDL = sizeof (RDM_DeviceGetPersonality_PD); + } + else // if ( m_msg.CC == rdm::SetCommand ) + { + m_Personality = reinterpret_cast + (m_msg.PD)->DMX512Personality; + m_msg.PDL = 0x0; + + if ( event_onDMXPersonalityChanged ) + event_onDMXPersonalityChanged ( m_Personality ); + } + break; + + case rdm::IdentifyDevice: + if ( m_msg.CC == rdm::GetCommand ) + { + m_msg.PD[0] = (uint8_t)(m_rdmStatus.ident ? 1 : 0); + m_msg.PDL = 0x1; + } + else if ( m_msg.CC == rdm::SetCommand ) + { + // Look into first byte to see whether identification + // is turned on or off + m_rdmStatus.ident = m_msg.PD[0] ? true : false; + if ( event_onIdentifyDevice ) + event_onIdentifyDevice ( m_rdmStatus.ident ); + + m_msg.PDL = 0x0; + } + break; + + case rdm::ManufacturerLabel: + if ( m_msg.CC == rdm::GetCommand ) + { + memcpy_P( (void*)m_msg.PD, ManufacturerLabel_P, sizeof(ManufacturerLabel_P) ); + m_msg.PDL = sizeof ( ManufacturerLabel_P ); + } + break; + + case rdm::DeviceLabel: + if ( m_msg.CC == rdm::GetCommand ) + { + memcpy ( m_msg.PD, (void*) m_deviceLabel, 32 ); + m_msg.PDL = 32; + } + else if ( m_msg.CC == rdm::SetCommand ) + { + memset ( (void*) m_deviceLabel, ' ', 32 ); + memcpy ( (void*) m_deviceLabel, m_msg.PD, (m_msg.PDL < 32 ? m_msg.PDL : 32) ); + m_msg.PDL = 0; + + // Notify application + if ( event_onDeviceLabelChanged ) + event_onDeviceLabelChanged ( m_deviceLabel, 32 ); + } + break; + + + default: + // Unknown parameter ID response + m_msg.portId = rdm::ResponseTypeNackReason; + m_msg.PD[0] = rdm::UnknownPid; + m_msg.PD[1] = 0x0; + m_msg.PDL = 0x2; + break; + }; + } + + // + // Only respond if this this message + // was destined to us only + if ( m_msg.dstUid == m_devid ) + { + m_msg.startCode = RDM_START_CODE; + m_msg.subStartCode = 0x01; + m_msg.msgLength = RDM_HDR_LEN + m_msg.PDL; + m_msg.msgCount = 0; + + /* + switch ( m_msg.msg.CC ) + { + case rdm::DiscoveryCommand: + m_msg.msg.CC = rdm::DiscoveryCommandResponse; + break; + case rdm::GetCommand: + m_msg.msg.CC = rdm::GetCommandResponse; + break; + case rdm::SetCommand: + m_msg.msg.CC = rdm::SetCommandResponse; + break; + } + */ + /* Above replaced by next line */ + m_msg.CC++; + + m_msg.dstUid.copy ( m_msg.srcUid ); + m_msg.srcUid.copy ( m_devid ); + + //_delay_us ( MIN_RESPONDER_PACKET_SPACING_USEC ); + SetISRMode ( isr::RDMTransmit ); + + } +} + + +void SetISRMode ( isr::isrMode mode ) +{ + uint8_t readEnable; + +#if defined(USE_DMX_SERIAL_0) + #if defined(UCSRB) && defined (UCSRC) + UCSRC |= (1<>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + + // Prepare before kicking off ISR + //DMX_UDR = 0x0; + __isr_rxState = isr::Idle; + readEnable = LOW; + DMX_UCSRB = (1<>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + DMX_UDR = 0x0; + DMX_UCSRB = 0x0; + readEnable = HIGH; + __isr_txState = isr::DmxBreakManual; + break; + + case isr::RDMTransmit: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + //DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + //DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + DMX_UCSRB = (1< -1) + digitalWrite ( __re_pin, readEnable ); + +} + +// +// TX UART (DMX Transmission ISR) +// +ISR (USART_TX) +{ + static uint16_t current_slot; + + switch ( __isr_txState ) + { + case isr::DmxBreak: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + if ( __isr_txState == isr::DmxBreak ) + __isr_txState = isr::DmxStartByte; + + break; + + case isr::DmxStartByte: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + current_slot = 0; + DMX_UDR = __dmx_master->getBuffer()[ current_slot++ ]; + __isr_txState = isr::DmxTransmitData; + break; + + + case isr::DmxTransmitData: + // NOTE: we always send full frames of 513 bytes, this will bring us + // close to 40 frames / sec with no interslot delays + #ifdef DMX_IBG + _delay_us (DMX_IBG); + #endif + + DMX_UDR = __dmx_master->getBuffer().getSlotValue( current_slot++ ); + + // Send 512 channels + if ( current_slot >= DMX_MAX_FRAMESIZE ) + { + if ( __dmx_master->autoBreakEnabled () ) + __isr_txState = isr::DmxBreak; + else + SetISRMode ( isr::DMXTransmitManual ); + } + + break; + +/* case isr::RdmBreak: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BREAK_RATE * 8L) / (DMX_BREAK_RATE * 16L) - 1); + DMX_UDR = 0x0; + + __isr_txState = isr::RdmStartByte; + + break; +*/ + + case isr::RdmStartByte: + DMX_UCSRA = 0x0; + DMX_UBRRH = (unsigned char)(((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1)>>8); + DMX_UBRRL = (unsigned char) ((F_CPU + DMX_BAUD_RATE * 8L) / (DMX_BAUD_RATE * 16L) - 1); + + // Write start byte + __rdm_responder->fetchOutgoing ( &DMX_UDR, true ); + __isr_txState = isr::RdmTransmitData; + + break; + + case isr::RdmTransmitData: + // Write rest of data + if ( __rdm_responder->fetchOutgoing ( &DMX_UDR ) ) + __isr_txState = isr::RDMTransmitComplete; + break; + + case isr::RDMTransmitComplete: + SetISRMode ( isr::Receive ); // Start waitin for new data + __isr_txState = isr::Idle; // No tx state + break; + + } +} + + + +// +// RX UART (DMX Reception ISR) +// +ISR (USART_RX) +{ + uint8_t usart_state = DMX_UCSRA; + uint8_t usart_data = DMX_UDR; + + // + // Check for framing error and reset if found + // A framing most likely* indicate a break in our ocasion + // + if ( usart_state & (1<processIncoming ( usart_data, true ); + __isr_rxState = isr::DmxRecordData; + } + else if ( __rdm_responder && + usart_data == RDM_START_CODE && + __rdm_responder->m_rdmStatus.enabled ) + { + // __rdm_responder->clear (); + __rdm_responder->processIncoming ( usart_data, true ); + __isr_rxState = isr::RdmRecordData; + } + else + { + __isr_rxState = isr::Idle; + } + break; + + // Process DMX Data + case isr::DmxRecordData: + if ( __dmx_slave->processIncoming ( usart_data ) ) + __isr_rxState = isr::Idle; + break; + + // Process RDM Data + case isr::RdmRecordData: + if ( __rdm_responder->processIncoming ( usart_data ) ) + __isr_rxState = isr::Idle; + break; + + } + +} + diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/Conceptinetics.h b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/Conceptinetics.h new file mode 100644 index 000000000..0f03da619 --- /dev/null +++ b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/Conceptinetics.h @@ -0,0 +1,383 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Conceptinetics.h - DMX library for Arduino + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + This code has been tested using the following hardware: + + - Arduino / Genuino UNO R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino / Genuino MEGA2560 R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD + - Arduino / Genuino Leonardo using a CTC-DRA-13-R2 ISOLATED DMX-RDM SHIELD + + - CTC-DRA-10-1 and CTC-DRA-10-R2 is the Non-isolated costs effective DMX-RDM shield +*/ + + +#ifndef CONCEPTINETICS_H_ +#define CONCEPTINETICS_H_ + +#include +#include + +#include "Rdm_Uid.h" +#include "Rdm_Defines.h" + +#define DMX_MAX_FRAMESIZE 513 // Startbyte + 512 Slots +#define DMX_MIN_FRAMESIZE 2 // Startbyte + 1 Slot + +#define DMX_MAX_FRAMECHANNELS 512 // Maxmim number of channer per frame + +#define DMX_STARTCODE_SIZE 1 // Size of startcode in bytes + +#define DMX_START_CODE 0x0 // Start code for a DMX frame +#define RDM_START_CODE 0xcc // Start code for a RDM frame + +// Uncomment to enable Inter slot delay ) (avg < 76uSec) ... +// mimum is zero according to specification +// #define DMX_IBG 10 // Inter slot time + +// Speed your Arduino is running on in Hz. +#define F_OSC 16000000UL + +// DMX Baudrate, this should be 250000 +#define DMX_BAUD_RATE 250000 + +// The baudrate used to automaticly generate a break within +// your ISR.. make it lower to generate longer breaks +//#define DMX_BREAK_RATE 99900 + +// 2017, Feb 28: Set to appox 176us +#define DMX_BREAK_RATE 49950 + +// Tabel 3-2 ANSI_E1-20-2010 +// Minimum time to allow the datalink to 'turn arround' +#define MIN_RESPONDER_PACKET_SPACING_USEC 176 /*176*/ + +// Define which serial port to use as DMX port, only one can be +// selected at the time by uncommenting one of the following +// lines +#define USE_DMX_SERIAL_0 +//#define USE_DMX_SERIAL_1 +//#define USE_DMX_SERIAL_2 +//#define USE_DMX_SERIAL_3 + +namespace dmx +{ + enum dmxState + { + dmxUnknown, + dmxStartByte, + dmxWaitStartAddress, + dmxData, + dmxFrameReady, + }; +}; + +namespace rdm +{ + enum rdmState + { + rdmUnknown, + rdmStartByte, + rdmSubStartCode, + rdmMessageLength, + rdmData, + rdmChecksumHigh, + rdmChecksumLow, + rdmFrameReady, + }; +}; + +struct IFrameBuffer +{ + virtual uint16_t getBufferSize ( void ) = 0; + + virtual uint8_t getSlotValue ( uint16_t index ) = 0; + virtual void setSlotValue ( uint16_t index, uint8_t value ) = 0; +}; + +class DMX_FrameBuffer : IFrameBuffer +{ + public: + // + // Constructor buffersize = 1-513 + // + DMX_FrameBuffer ( uint16_t buffer_size ); + DMX_FrameBuffer ( DMX_FrameBuffer &buffer ); + ~DMX_FrameBuffer ( void ); + + uint16_t getBufferSize ( void ); + + uint8_t getSlotValue ( uint16_t index ); + void setSlotValue ( uint16_t index, uint8_t value ); + void setSlotRange ( uint16_t start, uint16_t end, uint8_t value ); + void clear ( void ); + + uint8_t &operator[] ( uint16_t index ); + + private: + + uint8_t *m_refcount; + uint16_t m_bufferSize; + uint8_t *m_buffer; +}; + + +// +// DMX Master controller +// +class DMX_Master +{ + public: + // Run the DMX master from a pre allocated frame buffer which + // you have fully under your own control + DMX_Master ( DMX_FrameBuffer &buffer, int readEnablePin ); + + // Run the DMX master by giving a predefined maximum number of + // channels to support + DMX_Master ( uint16_t maxChannel, int readEnablePin ); + + ~DMX_Master ( void ); + + void enable ( void ); // Start transmitting + void disable ( void ); // Stop transmitting + + // Get reference to the internal framebuffer + DMX_FrameBuffer &getBuffer ( void ); + + // Update channel values + void setChannelValue ( uint16_t channel, uint8_t value ); + void setChannelRange ( uint16_t start, uint16_t end, uint8_t value ); + + public: + // + // Manual control over the break period + // + void setAutoBreakMode ( void ); // Generated from ISR + void setManualBreakMode ( void ); // Generate manually + + uint8_t autoBreakEnabled ( void ); + + // We are waiting for a manual break to be generated + uint8_t waitingBreak ( void ); + + // Generate break and start transmission of frame + void breakAndContinue ( uint8_t breakLength_us = 100 ); + + + protected: + void setStartCode ( uint8_t value ); + + + private: + DMX_FrameBuffer m_frameBuffer; + uint8_t m_autoBreak; +}; + + +// +// DMX Slave controller +// +class DMX_Slave : public DMX_FrameBuffer +{ + public: + DMX_Slave ( DMX_FrameBuffer &buffer, int readEnablePin = -1 ); + + // nrChannels is the consecutive DMX512 slots required + // to operate this slave device + DMX_Slave ( uint16_t nrChannels, int readEnablePin = -1 ); + + ~DMX_Slave ( void ); + + void enable ( void ); // Enable receiver + void disable ( void ); // Disable receiver + + + // Get reference to the internal framebuffer + DMX_FrameBuffer &getBuffer ( void ); + + uint8_t getChannelValue ( uint16_t channel ); + + uint16_t getStartAddress ( void ); + void setStartAddress ( uint16_t ); + + + // Process incoming byte from USART + bool processIncoming ( uint8_t val, bool first = false ); + + // Register on receive complete callback in case + // of time critical applications + void onReceiveComplete ( void (*func)(unsigned short) ); + + protected: + + + private: + uint16_t m_startAddress; // Slave start address + dmx::dmxState m_state; + + static void (*event_onFrameReceived)(unsigned short channelsReceived); +}; + + +class RDM_FrameBuffer : public IFrameBuffer +{ + public: + // + // Constructor + // + RDM_FrameBuffer ( void ) {}; + ~RDM_FrameBuffer ( void ) {}; + + uint16_t getBufferSize ( void ); + + uint8_t getSlotValue ( uint16_t index ); + void setSlotValue ( uint16_t index, uint8_t value ); + void clear ( void ); + + uint8_t &operator[] ( uint16_t index ); + + public: // functions to provide access from USART + // Process incoming byte from USART, + // returns false when no more data is accepted + bool processIncoming ( uint8_t val, bool first = false ); + + // Process outgoing byte to USART + // returns false when no more data is available + bool fetchOutgoing ( volatile uint8_t *udr, bool first = false ); + + protected: + // Process received frame + virtual void processFrame ( void ) = 0; + + //private: + protected: + rdm::rdmState m_state; // State for pushing the message in + RDM_Message m_msg; + RDM_Checksum m_csRecv; // Checksum received in rdm message +}; + +// +// RDM_Responder +// +class RDM_Responder : public RDM_FrameBuffer +{ + public: + // + // m = manufacturer id (16bits) + // d1-d4 = device id (32bits) + // + RDM_Responder ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4, DMX_Slave &slave); + ~RDM_Responder ( void ); + + void setDeviceInfo + ( + uint16_t deviceModelId, + rdm::RdmProductCategory productCategory, + uint8_t personalities = 1, + uint8_t personality = 1 + ) + { + m_DeviceModelId = deviceModelId; + m_ProductCategory = productCategory; + m_Personalities = personalities; + m_Personality = personality; + }; + + // + // Set vendor software version id + // + // v1 = MOST SIGNIFICANT + // v2... + // v3... + // v4 = LEAST SIGNIFICANT + // + void setSoftwareVersionId ( uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4 ) + { + m_SoftwareVersionId[0] = v1; + m_SoftwareVersionId[1] = v2; + m_SoftwareVersionId[2] = v3; + m_SoftwareVersionId[3] = v4; + } + + // Currently no sensors and subdevices supported + // void AddSensor ( void ); + // void AddSubDevice ( void ); + + uint8_t getPersonality ( void ) { return m_Personality; }; + void setPersonality ( uint8_t personality ) { m_Personality = personality; }; + + // Register on identify device event handler + void onIdentifyDevice ( void (*func)(bool) ); + void onDeviceLabelChanged ( void (*func) (const char*, uint8_t) ); + void onDMXStartAddressChanged ( void (*func) (uint16_t) ); + void onDMXPersonalityChanged ( void (*func) (uint8_t) ); + + + // Set the device label + void setDeviceLabel ( const char *label, size_t len ); + + // Enable, Disable rdm responder + void enable ( void ) { m_rdmStatus.enabled = true; m_rdmStatus.mute = false; }; + void disable ( void ) { m_rdmStatus.enabled = false; }; + + union + { + uint8_t raw; + struct + { + uint8_t mute:1; + uint8_t ident:1; + uint8_t enabled:1; // Rdm responder enable/disable + }; + } m_rdmStatus; + + + protected: + virtual void processFrame ( void ); + + // Discovery to unque brach packets only requires + // the data part of the packet to be transmitted + // without breaks or header + void repondDiscUniqueBranch ( void ); + + // Helpers for generating response packets which + // have larger datafields + void populateDeviceInfo ( void ); + + private: + RDM_Uid m_devid; // Holds our unique device ID + uint8_t m_Personalities; // The total number of supported personalities + uint8_t m_Personality; // The currently active personality + uint16_t m_DeviceModelId; + uint8_t m_SoftwareVersionId[4]; // 32 bit Software version + rdm::RdmProductCategory m_ProductCategory; + + char m_deviceLabel[32]; // Device label + + static void (*event_onIdentifyDevice)(bool); + static void (*event_onDeviceLabelChanged)(const char*, uint8_t); + static void (*event_onDMXStartAddressChanged)(uint16_t); + static void (*event_onDMXPersonalityChanged)(uint8_t); +}; + + +#endif /* CONCEPTINETICS_H_ */ diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/RDM_Slave_Eeprom.ino b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/RDM_Slave_Eeprom.ino index f6aafbf7c..63e3e14b1 100644 --- a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/RDM_Slave_Eeprom.ino +++ b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/RDM_Slave_Eeprom.ino @@ -23,7 +23,7 @@ #include -#include +#include "Conceptinetics.h" // // CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD JUMPER INSTRUCTIONS diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/Rdm_Defines.h b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/Rdm_Defines.h new file mode 100644 index 000000000..0accca63d --- /dev/null +++ b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/Rdm_Defines.h @@ -0,0 +1,315 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Rdm_Defines.h - DMX library for Arduino with RDM (Remote Device Management) support + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef RDM_DEFINES_H_ +#define RDM_DEFINES_H_ + +#include "Rdm_Uid.h" + +#define RDM_MAX_DEVICELABEL_LENGTH 32 + +namespace rdm +{ + enum RdmCommandClass + { + DiscoveryCommand = 0x10, + DiscoveryCommandResponse, + GetCommand = 0x20, + GetCommandResponse, + SetCommand = 0x30, + SetCommandResponse, + }; + + enum RdmResponseTypes + { + ResponseTypeAck = 0x00, + ResponseTypeAckTimer, + ResponseTypeNackReason, + ResponseTypeAckOverflow, // Additional response data available (see spec) + }; + + enum RdmParameters + { + // Category - Network Management + DiscUniqueBranch = 0x0001, // Required + DiscMute = 0x0002, // Required + DiscUnMute = 0x0003, // Required + + CommsStatus = 0x0015, // Get,Set + + // Category - Status Collection + QueuedMessage = 0x0020, // Get [enum RdmStatusTypes] + StatusMessages = 0x0030, // Get [enum RdmStatusTypes] + StatusIdDescription = 0x0031, // Get + ClearStatusId = 0x0032, // Set + SubDeviceStatusReportThreshold = 0x0033, // Get, Set [enum RdmStatusTypes] + + // Category - RDM Information + // ** Only required if supporting parameters + // beyond the minimum required set + SupportedParameters = 0x0005, // Get, **Required + ParameterDescription = 0x0051, // Get, **Required + + // Category = Product Information + DeviceInfo = 0x0060, // Get, Required + ProductDetailIdList = 0x0070, // Get + DeviceModelDescription = 0x0080, // Get + ManufacturerLabel = 0x0081, // Get + DeviceLabel = 0x0082, // Get, Set + FactoryDefaults = 0x0009, // Get, Set ** + SoftwareVersionLabel = 0x000c, // Get + + // Category - DMX512 Setup + DmxPersonality = 0x00e0, // Get, Set + DmxPersonalityDescription = 0x00e1, // Get + DmxStartAddress = 0x00f0, // Get, Set ** Required if DMX device + SlotInfo = 0x0120, // Get + SlotDescription = 0x0121, // Get + DefaultSlotValue = 0x0122, // Get + + // Category - Sensors + // Category - Dimmer Settings + // Category - Power/Lamp Settings + // Category - Display Settings + // Category - Configuration + + // Category - Control + IdentifyDevice = 0x1000, // Get, Set, Required + ResetDevice = 0x1001, // Set + PowerState = 0x1010, // Get, Set + PerformSelftest = 0x1020, // Get, Set + SelfTestDescription = 0x1021, // Get + }; + + + enum RdmStatusTypes + { + StatusNone = 0x00, + StatusGetLastMessage, + StatusAdvisory, + StatusWarning, + StatusError, + StatusAdvisoryCleared = 0x12, + StatusWarningCleared, + StatusErrorCleared, + }; + + enum RdmProductCategory + { + CategoryNotDeclared = 0x0000, + + // Fixtures - intended as source for illumination + CategoryFixture = 0x0100, + CategoryFixtureFixed = 0x0101, + CategoryFixtureMovingYoke = 0x0102, + CategoryFixtureMovingMirror = 0x0103, + CategoryFixtureOther = 0x01ff, + + // Fixture Accessories - add-ons to fixtures or projectors + CategoryFixtureAccessory = 0x0200, + CategoryFixtureAccessoryColor = 0x0201, + CategoryFixtureAccessoryYoke = 0x0202, + CategoryFixtureAccessoryMirror = 0x0203, + CategoryFixtureAccessoryEffect = 0x0204, + CategoryFixtureAccessoryBeam = 0x0205, + CategoryFixtureAccessoryOther = 0x02ff, + + // Projectors - Light source capable of producing + // realistic images from another media + CategoryProjector = 0x0300, + CategoryProjectorFixed = 0x0301, + CategoryProjectorMovingYoke = 0x0302, + CategoryProjectorMovingMirror = 0x0303, + CategoryProjectorOther = 0x03ff, + + // Atmospheric Effect - earth/wind/fire + CategoryAtmospheric = 0x0400, + CategoryAtmosphericEffect = 0x0401, // Fogger, Hazer, Flame + CategoryAtmosphericPyro = 0x0402, + CategoryAtmosphericOther = 0x04ff, + + // Insensity Control (Specifically dimming equipment) + CategoryDimmer = 0x0500, + CategoryDimmer_AC_Incandescent = 0x0501, + CategoryDimmer_AC_Fluorescent = 0x0502, + CategoryDimmer_AC_Coldcathode = 0x0503, + CategoryDimmer_AC_Nondim = 0x0504, + CategoryDimmer_AC_Elv = 0x0505, + CategoryDimmer_AC_Other = 0x0506, + CategoryDimmer_DC_Level = 0x0507, + CategoryDimmer_DC_PWM = 0x0508, + CategoryDimmer_CS_LED = 0x0509, + CategoryDimmer_Other = 0x05ff, + + // Power control (Other than dimming equipment) + CategoryPower = 0x0600, + CategoryPowerControl = 0x0601, + CategoryPowerSource = 0x0602, + CategoryPowerOther = 0x06ff, + + // Scenic Drive - Including motorized effects + // unrelated to light source + CategoryScenic = 0x0700, + CategoryScenicDrive = 0x0701, + CategoryScenicOther = 0x07ff, + + // DMX Infrastructure, conversion and interfaces + CategoryData = 0x0800, + CategoryDataDistribution = 0x0801, + CategoryDataConversion = 0x0802, + CategoryDataOther = 0x08ff, + + // Audio visual equipment + Category_AV = 0x0900, + Category_AV_Audio = 0x0901, + Category_AV_Video = 0x0902, + Category_AV_Other = 0x09ff, + + // Parameter monitoring equipment + CategoryMonitor = 0x0a00, + CategoryMonitorACLinePower = 0x0a01, + CategoryMonitorDCPower = 0x0a02, + CategoryMonitorEnvironmental = 0x0a03, + CategoryMonitorOther = 0x0aff, + + // Controllers, backup devices + CategoryControl = 0x7000, + CategoryControlController = 0x7001, + CategoryControlBackupdevice = 0x7002, + CategoryControlOther = 0x70ff, + + // Test equipment + CategoryTest = 0x7100, + CategoryTestEquipment = 0x7101, + CategoryTestEquipmentOther = 0x71ff, + + // Miscellaneous + CategoryOther = 0x7fff, + }; + + // + // Product details not yet supported in + // this library + // + enum RdmProductDetail + { + ProductDetailNotDeclared = 0x0000, + }; + + // Only LSB + enum RdmNackReasons + { + UnknownPid = 0x00, + FormatError, + HardwareFault, + ProxyReject, + WriteProtect, + UnsupportedCmdClass, + DataOutOfRange, + BufferFull, + PacketSizeUnsupported, + SubDeviceOutOfRange, + ProxyBufferFull + }; + +}; + + +#define RDM_HDR_LEN 24 // RDM Message header length ** fixed +#define RDM_PD_MAXLEN 32 // RDM Maximum parameter data length 1 - 231 + + +union RDM_Message +{ + uint8_t d[ RDM_HDR_LEN + RDM_PD_MAXLEN ]; + struct + { + uint8_t startCode; // 0 SC_RDM + uint8_t subStartCode; // 1 SC_SUB_MESSAGE + uint8_t msgLength; // 2 Range 24 - 255 + RDM_Uid dstUid; // 3-8 Destination UID + RDM_Uid srcUid; // 9-14 Source UID (sender) + uint8_t TN; // 15 Transaction number + uint8_t portId; // 16 Port ID / Response type + uint8_t msgCount; // 17 + uint16_t subDevice; // 18,19 0=root, 0xffff=all + uint8_t CC; // 20 GET_COMMAND + uint16_t PID; // 21,22 Parameter ID + uint8_t PDL; // 23 Parameter Data length 1-231 + + uint8_t PD[RDM_PD_MAXLEN]; // Parameter Data ... variable length + }; +}; + +union RDM_Checksum +{ + uint16_t checksum; + struct + { + uint8_t csl; + uint8_t csh; + }; +}; + +struct RDM_DiscUniqueBranchPD +{ + RDM_Uid lbound; + RDM_Uid hbound; +}; + +struct RDM_DiscMuteUnMutePD +{ + uint16_t ctrlField; + +// Only for multiple ports +// RDM_Uid bindingUid; +}; + +struct RDM__DeviceInfoPD +{ + uint8_t protocolVersionMajor; + uint8_t protocolVersionMinor; + uint16_t deviceModelId; + uint16_t ProductCategory; // enum RdmProductCategory + uint8_t SoftwareVersionId[4]; + uint16_t DMX512FootPrint; + uint8_t DMX512CurrentPersonality; + uint8_t DMX512NumberPersonalities; + uint16_t DMX512StartAddress; + uint16_t SubDeviceCount; + uint8_t SensorCount; +}; + +struct RDM_DeviceGetPersonality_PD +{ + uint8_t DMX512CurrentPersonality; + uint8_t DMX512NumberPersonalities; +}; + +struct RDM_DeviceSetPersonality_PD +{ + uint8_t DMX512Personality; +}; + + +#endif /* RDM_DEFINES_H_ */ diff --git a/DMX_NeoPixels/examples/RDM_Slave_Eeprom/Rdm_Uid.h b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/Rdm_Uid.h new file mode 100644 index 000000000..35c802c63 --- /dev/null +++ b/DMX_NeoPixels/examples/RDM_Slave_Eeprom/Rdm_Uid.h @@ -0,0 +1,101 @@ +// SPDX-FileCopyrightText: 2013 W.A. van der Meeren +// +// SPDX-License-Identifier: LGPL-3.0-or-later +/* + Rdm_Uid.h - DMX library for Arduino with RDM (Remote Device Management) support + Copyright (c) 2013 W.A. van der Meeren . All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef RDM_UID_H_ +#define RDM_UID_H_ + +#include + +// +//48 bit UID Representation to identify RDM transponders +// +struct RDM_Uid { + + void Initialize ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4 ) + { + m_id[0] = ((uint8_t) (((uint16_t) (m)) >> 8)); + m_id[1] = (uint8_t)m; + m_id[2] = d1; + m_id[3] = d2; + m_id[4] = d3; + m_id[5] = d4; + } + + void copy ( const RDM_Uid &orig ) + { + for ( uint8_t i = 0; i < 6; i++ ) + m_id[i] = orig.m_id[i]; + } + + bool operator == ( const RDM_Uid & orig ) const + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != orig.m_id[i] ) + return false; + + return true; + } + + bool operator != ( const RDM_Uid & orig ) const + { + return !(*this == orig); + } + + bool operator < ( const RDM_Uid & v ) const + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != v.m_id[i] ) + return ( m_id[i] < v.m_id[i] ); + } + + bool operator > ( const RDM_Uid & v ) + { + for ( uint8_t i = 0; i < 6; i++ ) + if ( m_id[i] != v.m_id[i] ) + return ( m_id[i] > v.m_id[i] ); + } + + // + // match_mid = manufacturer id to match + // + bool isBroadcast ( uint8_t match_mid[2] ) + { + // Check for genuine broadcast on device part + for ( uint8_t i = 2; i < 6; i++ ) + if ( m_id[i] != 0xff ) + return false; + + // Broadcast or manufacturer designated broadcast + if ( (m_id[0] == 0xff && m_id[1] == 0xff) || + (m_id[0] == match_mid[0] && m_id[1] == match_mid[1]) ) + return true; + + // No broadcast + return false; + } + + uint8_t m_id[6]; //16bit manufacturer id + 32 bits device id +}; + + +#endif /* RDM_UID_H_ */ diff --git a/Digital_Clock_with_CircuitPython/code.py b/Digital_Clock_with_CircuitPython/code.py index 1d076aead..a7ffce765 100644 --- a/Digital_Clock_with_CircuitPython/code.py +++ b/Digital_Clock_with_CircuitPython/code.py @@ -58,7 +58,9 @@ def clock_conversion(h, m, set_brightness): hour_12 = h if h <= 12 else h - 12 if hour_12 == 0: hour_12 = 12 - display.print(f"{(hour_12):02}:{m:02}") + display.print(f"{(hour_12):02}:{m:02}") # Use for leading zero re. 09:35 + # display.print(f"{hour_12:2}:{m:02}") # uncomment to suppress leading zero + # # (shows 1:00 instead of 01:00) display.ampm = am_pm if set_brightness: if awake_hours[0] <= h <= awake_hours[1] - 1: diff --git a/E-Ink_Bonnet_Examples/Blinka_EPD_Demo/code.py b/E-Ink_Bonnet_Examples/Blinka_EPD_Demo/code.py new file mode 100644 index 000000000..feedd4f91 --- /dev/null +++ b/E-Ink_Bonnet_Examples/Blinka_EPD_Demo/code.py @@ -0,0 +1,102 @@ +# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +ePaper Display Shapes and Text demo using the Pillow Library. + +""" + +import board +import busio +import digitalio +from PIL import Image, ImageDraw, ImageFont +from adafruit_epd.epd import Adafruit_EPD +from adafruit_epd.uc8179 import Adafruit_UC8179 + +# First define some color constants +WHITE = (0xFF, 0xFF, 0xFF) +BLACK = (0x00, 0x00, 0x00) +RED = (0xFF, 0x00, 0x00) + +# Next define some constants to allow easy resizing of shapes and colors +BORDER = 20 +FONTSIZE = 24 +BACKGROUND_COLOR = BLACK +FOREGROUND_COLOR = WHITE +TEXT_COLOR = RED + +# create the spi device and pins we will need +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) +ecs = digitalio.DigitalInOut(board.CE0) +dc = digitalio.DigitalInOut(board.D22) +srcs = None +rst = digitalio.DigitalInOut(board.D27) +busy = digitalio.DigitalInOut(board.D17) + + +display = Adafruit_UC8179( # 7.5" tricolor 800x480 display + 800, + 480, + spi, + cs_pin=ecs, + dc_pin=dc, + sramcs_pin=srcs, + rst_pin=rst, + busy_pin=busy, + tri_color = True) + +width = display.width +height = display.height +image = Image.new("RGB", (width, height)) + +WHITE = (0xFF, 0xFF, 0xFF) +RED = (0xFF, 0x00, 0x00) +BLACK = (0x00, 0x00, 0x00) + +# clear the buffer +display.fill(Adafruit_EPD.WHITE) + +# Get drawing object to draw on image. +draw = ImageDraw.Draw(image) +# empty it +draw.rectangle((0, 0, width, height), fill=WHITE) + +# Draw an outline box +draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE) + +# Draw some shapes. +# First define some constants to allow easy resizing of shapes. +padding = 20 +shape_width = 120 +top = padding +bottom = height - padding +# Move left to right keeping track of the current x position for drawing shapes. +x = padding +# Draw an ellipse. +draw.ellipse((x, top, x + shape_width, bottom), outline=RED, fill=WHITE) +x += shape_width + padding +# Draw a rectangle. +draw.rectangle((x, top, x + shape_width, bottom), outline=RED, fill=BLACK) +x += shape_width + padding +# Draw a triangle. +draw.polygon( + [(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)], + outline=BLACK, + fill=RED, +) +x += shape_width + padding +# Draw an X. +draw.line((x, bottom, x + shape_width, top), fill=BLACK) +draw.line((x, top, x + shape_width, bottom), fill=RED) +x += shape_width + padding + +# Load default font. +font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 40) + +draw.text((x, top), "Hello", font=font, fill=BLACK) +draw.text((x, top + 40), "World!", font=font, fill=BLACK) + +# Display image. +display.image(image) + +display.display() diff --git a/E-Ink_Bonnet_Examples/Blinka_EPD_Pillow_Image/blinka.png b/E-Ink_Bonnet_Examples/Blinka_EPD_Pillow_Image/blinka.png new file mode 100644 index 000000000..1482c9dd8 Binary files /dev/null and b/E-Ink_Bonnet_Examples/Blinka_EPD_Pillow_Image/blinka.png differ diff --git a/E-Ink_Bonnet_Examples/Blinka_EPD_Pillow_Image/code.py b/E-Ink_Bonnet_Examples/Blinka_EPD_Pillow_Image/code.py new file mode 100644 index 000000000..948fa7d92 --- /dev/null +++ b/E-Ink_Bonnet_Examples/Blinka_EPD_Pillow_Image/code.py @@ -0,0 +1,64 @@ +# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +Image resizing and drawing using the Pillow Library +""" +import board +import busio +import digitalio +from PIL import Image +from adafruit_epd.uc8179 import Adafruit_UC8179 + +# First define some color constants +WHITE = (0xFF, 0xFF, 0xFF) +BLACK = (0x00, 0x00, 0x00) +RED = (0xFF, 0x00, 0x00) + +# Next define some constants to allow easy resizing of shapes and colors +BORDER = 20 +FONTSIZE = 24 +BACKGROUND_COLOR = BLACK +FOREGROUND_COLOR = WHITE +TEXT_COLOR = RED + +# create the spi device and pins we will need +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) +ecs = digitalio.DigitalInOut(board.CE0) +dc = digitalio.DigitalInOut(board.D22) +srcs = None +rst = digitalio.DigitalInOut(board.D27) +busy = digitalio.DigitalInOut(board.D17) + + +display = Adafruit_UC8179( # 7.5" tri-color 800x480 display + 800, + 480, + spi, + cs_pin=ecs, + dc_pin=dc, + sramcs_pin=srcs, + rst_pin=rst, + busy_pin=busy, + tri_color = True) + +image = Image.open("blinka.png") + +# Scale the image to the smaller screen dimension +image_ratio = image.width / image.height +screen_ratio = display.width / display.height +print(image_ratio, screen_ratio) +if screen_ratio < image_ratio: + scaled_width = image.width * display.height // image.height + scaled_height = display.height +else: + scaled_width = display.width + scaled_height = image.height * display.width // image.width +image = image.resize((scaled_width, scaled_height), Image.BICUBIC) + +# Crop and center the image +x = scaled_width // 2 - display.width // 2 +y = scaled_height // 2 - display.height // 2 +image = image.crop((x, y, x + display.width, y + display.height)).convert("RGB") + +display.image(image) +display.display() diff --git a/EInk_Bonnet_Event_Calendar/code.py b/EInk_Bonnet_Event_Calendar/code.py index 4a1ac5074..b3432aa9e 100644 --- a/EInk_Bonnet_Event_Calendar/code.py +++ b/EInk_Bonnet_Event_Calendar/code.py @@ -18,6 +18,7 @@ from adafruit_epd.epd import Adafruit_EPD from adafruit_epd.ssd1675 import Adafruit_SSD1675 from adafruit_epd.ssd1680 import Adafruit_SSD1680 +from adafruit_epd.ssd1680b import Adafruit_SSD1680B spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) ecs = digitalio.DigitalInOut(board.CE0) @@ -39,7 +40,8 @@ DEBOUNCE_DELAY = 0.3 # Initialize the Display -display = Adafruit_SSD1680( # Newer eInk Bonnet +display = Adafruit_SSD1680B( # Newer eInk Bonnet (GDEY0213B74 display) +# display = Adafruit_SSD1680( # Old eInk Bonnet # display = Adafruit_SSD1675( # Older eInk Bonnet 122, 250, spi, cs_pin=ecs, dc_pin=dc, sramcs_pin=None, rst_pin=rst, busy_pin=busy, ) diff --git a/EInk_Bonnet_Weather_Station/code.py b/EInk_Bonnet_Weather_Station/code.py index d0da8b3ef..73c8f65b8 100644 --- a/EInk_Bonnet_Weather_Station/code.py +++ b/EInk_Bonnet_Weather_Station/code.py @@ -15,7 +15,7 @@ import board from adafruit_epd.ssd1675 import Adafruit_SSD1675 from adafruit_epd.ssd1680 import Adafruit_SSD1680 -from adafruit_epd.ssd1680 import Adafruit_SSD1680Z +from adafruit_epd.ssd1680b import Adafruit_SSD1680B from weather_graphics import Weather_Graphics spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) @@ -43,8 +43,8 @@ data_source = DATA_SOURCE_URL + "?" + urllib.parse.urlencode(params) # Initialize the Display -display = Adafruit_SSD1680Z( # New Bonnet ssd1680z [GDEY0213B74] -#display = Adafruit_SSD1680( # Old eInk Bonnet ssd1680 +display = Adafruit_SSD1680B( # Newer eInk Bonnet (GDEY0213B74 display) +#display = Adafruit_SSD1680( # Old eInk Bonnet ssd1680 #display = Adafruit_SSD1675( # Older eInk Bonnet ssd1675 # 122, 250, spi, cs_pin=ecs, dc_pin=dc, sramcs_pin=None, rst_pin=rst, busy_pin=busy, 120, 250, spi, cs_pin=ecs, dc_pin=dc, sramcs_pin=None, rst_pin=rst, busy_pin=busy, diff --git a/EInk_CircuitPython_Quickstart/213_tricolor_eink_fw_badge/code.py b/EInk_CircuitPython_Quickstart/213_tricolor_eink_fw_badge/code.py index dfb39569c..5619cf175 100644 --- a/EInk_CircuitPython_Quickstart/213_tricolor_eink_fw_badge/code.py +++ b/EInk_CircuitPython_Quickstart/213_tricolor_eink_fw_badge/code.py @@ -17,6 +17,7 @@ import time import board import displayio +import fourwire import adafruit_il0373 import terminalio from adafruit_display_text import label @@ -43,7 +44,7 @@ epd_busy = board.D6 # Create the displayio connection to the display pins -display_bus = displayio.FourWire(spi, command=epd_dc, chip_select=epd_cs, +display_bus = fourwire.FourWire(spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=1000000) time.sleep(1) # Wait a bit @@ -76,19 +77,10 @@ filename = "/picture.bmp" # Create a Tilegrid with the bitmap and put in the displayio group - -# CircuitPython 6 & 7 compatible -pic = displayio.OnDiskBitmap(open(filename, "rb")) -t = displayio.TileGrid( - pic, pixel_shader=getattr(pic, 'pixel_shader', displayio.ColorConverter()) -) +pic = displayio.OnDiskBitmap(filename) +t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) g.append(t) -# # CircuitPython 7+ compatible -# pic = displayio.OnDiskBitmap(filename) -# t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) -# g.append(t) - # Draw simple text using the built-in font into a displayio group # For smaller text, change scale=2 to scale=1 text_group = displayio.Group(scale=2, diff --git a/EInk_CircuitPython_Quickstart/213_tricolor_eink_fw_text/code.py b/EInk_CircuitPython_Quickstart/213_tricolor_eink_fw_text/code.py index 1a0233bb9..8a1edaada 100644 --- a/EInk_CircuitPython_Quickstart/213_tricolor_eink_fw_text/code.py +++ b/EInk_CircuitPython_Quickstart/213_tricolor_eink_fw_text/code.py @@ -18,6 +18,7 @@ import time import board import displayio +import fourwire import adafruit_il0373 import terminalio from adafruit_display_text import label @@ -44,7 +45,7 @@ epd_busy = board.D6 # Create the displayio connection to the display pins -display_bus = displayio.FourWire(spi, command=epd_dc, chip_select=epd_cs, +display_bus = fourwire.FourWire(spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=1000000) time.sleep(1) # Wait a bit diff --git a/EInk_CircuitPython_Quickstart/27_tricolor_eink_shield_badge/code.py b/EInk_CircuitPython_Quickstart/27_tricolor_eink_shield_badge/code.py index 24ba5313f..947418f92 100644 --- a/EInk_CircuitPython_Quickstart/27_tricolor_eink_shield_badge/code.py +++ b/EInk_CircuitPython_Quickstart/27_tricolor_eink_shield_badge/code.py @@ -16,6 +16,7 @@ import time import board import displayio +import fourwire import adafruit_il91874 import terminalio from adafruit_display_text import label @@ -39,7 +40,7 @@ epd_dc = board.D9 # Create the displayio connection to the display pins -display_bus = displayio.FourWire(spi, command=epd_dc, chip_select=epd_cs, +display_bus = fourwire.FourWire(spi, command=epd_dc, chip_select=epd_cs, baudrate=1000000) time.sleep(1) # Wait a bit @@ -72,19 +73,10 @@ filename = "/picture.bmp" # Create a Tilegrid with the bitmap and put in the displayio group - -# CircuitPython 6 & 7 compatible -pic = displayio.OnDiskBitmap(open(filename, "rb")) -t = displayio.TileGrid( - pic, pixel_shader=getattr(pic, 'pixel_shader', displayio.ColorConverter()) -) +pic = displayio.OnDiskBitmap(filename) +t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) g.append(t) -# # CircuitPython 7+ compatible -# pic = displayio.OnDiskBitmap(filename) -# t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) -# g.append(t) - # Draw simple text using the built-in font into a displayio group # For smaller text, change scale=2 to scale=1 as scale 2 doesn't # allow for much text but the text is bigger. diff --git a/EInk_CircuitPython_Quickstart/27_tricolor_eink_shield_text/code.py b/EInk_CircuitPython_Quickstart/27_tricolor_eink_shield_text/code.py index 3efb92fc1..673af95aa 100644 --- a/EInk_CircuitPython_Quickstart/27_tricolor_eink_shield_text/code.py +++ b/EInk_CircuitPython_Quickstart/27_tricolor_eink_shield_text/code.py @@ -15,6 +15,7 @@ import time import board import displayio +import fourwire import adafruit_il91874 import terminalio from adafruit_display_text import label @@ -38,7 +39,7 @@ epd_dc = board.D9 # Create the displayio connection to the display pins -display_bus = displayio.FourWire(spi, command=epd_dc, chip_select=epd_cs, +display_bus = fourwire.FourWire(spi, command=epd_dc, chip_select=epd_cs, baudrate=1000000) time.sleep(1) # Wait a bit diff --git a/ESP-NOW_Juggling/boot.py b/ESP-NOW_Juggling/boot.py new file mode 100644 index 000000000..39abe5766 --- /dev/null +++ b/ESP-NOW_Juggling/boot.py @@ -0,0 +1,16 @@ +# SPDX-FileCopyrightText: 2025 John Park for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +ESP-NOW MIDI Juggling Bridge +boot.py - Minimal configuration for USB MIDI only +""" + +import usb_hid +import usb_midi + +# Disable everything except MIDI +usb_hid.disable() # No HID devices +usb_midi.enable() # Only MIDI + +print("Minimal USB MIDI configuration loaded") diff --git a/ESP-NOW_Juggling/esp-now-midi-ball.py b/ESP-NOW_Juggling/esp-now-midi-ball.py new file mode 100644 index 000000000..f2217cf07 --- /dev/null +++ b/ESP-NOW_Juggling/esp-now-midi-ball.py @@ -0,0 +1,254 @@ +# SPDX-FileCopyrightText: 2025 John Park for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +ESP-NOW MIDI Juggling Ball +communicates to Feather TFT connected to computer/synth via USB +""" + +import time +import wifi +import espnow +import board +import neopixel +import analogio +import adafruit_lis3dh + +# CONFIGURATION: Set this for each device +DEVICE_ID = "ball_A" # Options: "ball_A", "ball_B", "ball_C" + +# Sleep configuration -- light sleep, will wake on tap detection +SLEEP_AFTER = 30 # Seconds of inactivity before sleep turns off NeoPixels/radio + +# Device list +DEVICES = ["ball_A", "ball_B", "ball_C"] + +ALL_COLORS = [0xEE0010, 0x00FF00, 0x0010EE] # indexed to DEVICES + +# Current color state (starts with device's default) +current_color_index = DEVICES.index(DEVICE_ID) +CURRENT_COLOR = ALL_COLORS[current_color_index] + +NUM_PIX = 2 # 2 for PCB version, however many you want for BFF +# Set up NeoPixel and I2C for accelerometer +pixel = neopixel.NeoPixel(board.A0, NUM_PIX) # board.A0 for PCB, A3 for BFF +pixel.brightness = 1.0 +pixel.fill(CURRENT_COLOR) + +# Set up battery monitoring +voltage_pin = analogio.AnalogIn(board.A2) + + +def get_battery_voltage(): + """Read battery voltage from A2 pin""" + # Take the raw voltage pin value, and convert it to voltage + voltage = (voltage_pin.value / 65536) * 2 * 3.3 + return voltage + + +# Initialize I2C and LIS3DH accelerometer +try: + # i2c = board.STEMMA_I2C() # use this if connecting to STEMMA QT + i2c = board.I2C() + try: + lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c, address=0x18) + print("LIS3DH address: 0x18") + except ValueError: + lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c, address=0x19) + print("LIS3DH address: 0x19") + lis3dh.range = adafruit_lis3dh.RANGE_2_G + lis3dh.set_tap(1, 90) + has_accelerometer = True + print("LIS3DH accelerometer initialized with tap detection") +except Exception as e: # pylint:disable=broad-except + print(f"Accelerometer init failed: {e}") + has_accelerometer = False + + +# Channel switching hack +wifi.radio.start_ap(" ", "", channel=6, max_connections=0) +wifi.radio.stop_ap() + + +def format_mac(mac_bytes): + return ":".join(f"{b:02x}" for b in mac_bytes) + + +def get_my_mac(): + return format_mac(wifi.radio.mac_address) + + +def cycle_color(): + """Cycle to the next color in the list""" + global current_color_index, CURRENT_COLOR # pylint: disable=global-statement + current_color_index = (current_color_index + 1) % len(ALL_COLORS) + CURRENT_COLOR = ALL_COLORS[current_color_index] + pixel.fill(CURRENT_COLOR) + print(f"Color changed to: {CURRENT_COLOR:06X}") + + +def flash(): + """Quick flash for tap feedback""" + pixel.fill((200, 200, 200)) + time.sleep(0.15) + pixel.fill(CURRENT_COLOR) + + +def enter_sleep(): + """Enter low-power sleep mode""" + global is_sleeping # pylint: disable=global-statement + # print("Entering sleep mode - turning off NeoPixels and radio") + pixel.fill((0, 0, 0)) # Turn off all NeoPixels + pixel.brightness = 0 + wifi.radio.stop_ap() # Turn off radio + is_sleeping = True + + +def wake_up(): + """Wake from sleep mode""" + global is_sleeping, last_activity_time # pylint: disable=global-statement + # print("Waking up - restoring NeoPixels and radio") + pixel.brightness = 1.0 + pixel.fill(CURRENT_COLOR) + # Restart radio + wifi.radio.start_ap(" ", "", channel=6, max_connections=0) + wifi.radio.stop_ap() + is_sleeping = False + last_activity_time = time.monotonic() + + +def check_tap(): + """Check if accelerometer detects tap""" + if not has_accelerometer: + return False + try: + return lis3dh.tapped + except Exception as er: # pylint:disable=broad-except + print(f"Accelerometer read error: {er}") + return False + + +def send_trigger_message(trigger_type="tap"): + """Send trigger message with current device color""" + current_time = time.monotonic() # pylint: disable=redefined-outer-name + message = f"TRIGGER|{DEVICE_ID}|{trigger_type}|{current_time:.1f}" # pylint: disable=redefined-outer-name + + try: + e.send(message, broadcast_peer) + # print(f"TX: {message}") + flash() + return True + except Exception as exc: # pylint:disable=broad-except + print(f"Send error: {exc}") + return False + + +def send_battery_report(): + """Send battery voltage report to bridge with current color""" + voltage = get_battery_voltage() + current_time = time.monotonic() # pylint: disable=redefined-outer-name + message = ( # pylint: disable=redefined-outer-name + f"BATTERY|{DEVICE_ID}|{voltage:.2f}|{CURRENT_COLOR:06X}|{current_time:.1f}" + ) + + try: + e.send(message, broadcast_peer) + print(f"TX Battery: {message} ({voltage:.2f}V, color: {CURRENT_COLOR:06X})") + return True + except Exception as exb: # pylint:disable=broad-except + print(f"Battery report send error: {exb}") + return False + + +# Initialize ESP-NOW +e = espnow.ESPNow() +broadcast_peer = espnow.Peer(mac=b"\xff\xff\xff\xff\xff\xff", channel=6) +e.peers.append(broadcast_peer) + +my_mac = get_my_mac() +print(f"{DEVICE_ID} ball starting - MAC: {my_mac}, Color: {CURRENT_COLOR:06X}") + +# Clear accelerometer startup noise +print("Initializing accelerometer...") +time.sleep(0.5) +if has_accelerometer: + print("Clearing startup tap artifacts...") + for i in range(10): + try: + tap_state = lis3dh.tapped + if tap_state: + print(f"Cleared startup tap {i + 1}") + time.sleep(0.1) + except Exception: # pylint:disable=broad-except + pass + print("Accelerometer ready for tap detection") + +# Timing variables +last_tap_time = 0 +tap_debounce = 0.3 +startup_time = time.monotonic() +startup_protection = 0.5 + +# Sleep/wake tracking +last_activity_time = time.monotonic() +is_sleeping = False + +while True: + current_time = time.monotonic() # pylint: disable=redefined-outer-name + + # Check for sleep timeout + if not is_sleeping and (current_time - last_activity_time > SLEEP_AFTER): + enter_sleep() + + # Check for tap (primary trigger and wake-up source) + if has_accelerometer: + # Only check for taps after startup protection period + if current_time - startup_time > startup_protection: + if check_tap(): + # If sleeping, wake up first + if is_sleeping: + wake_up() + + # Check debounce for actual trigger + if current_time - last_tap_time > tap_debounce: + send_trigger_message("tap") + last_tap_time = current_time + last_activity_time = current_time + else: + # During startup protection, clear any false tap detections + if check_tap(): + print("Ignoring tap during startup protection period") + + # Check for incoming packets from bridge (only if not sleeping) + if not is_sleeping and e: + packet = e.read() + sender_mac = format_mac(packet.mac) + + if sender_mac != my_mac: + message = packet.msg.decode("utf-8") # pylint:disable=redefined-outer-name + last_activity_time = current_time # Any message counts as activity + + # Handle color change commands from bridge + if message.startswith("COLOR|"): + parts = message.split("|") + if len(parts) >= 3: + target_device = parts[1] + command = parts[2] + + # Only respond if this message is for us + if target_device == DEVICE_ID and command == "next": + cycle_color() + # Send battery report when color changes + send_battery_report() + + # Handle trigger messages from other balls for visual feedback + # elif message.startswith("TRIGGER|"): + # parts = message.split("|") + # if len(parts) >= 4: + # sender_device = parts[1] + # trigger_type = parts[2] + # print(f"Trigger from {sender_device} ({trigger_type})") + # # Brief red flash for other ball triggers + # flash() + + time.sleep(0.01) # Fast polling for responsive tap detection diff --git a/ESP-NOW_Juggling/esp-now-midi-bridge.py b/ESP-NOW_Juggling/esp-now-midi-bridge.py new file mode 100644 index 000000000..6c4ba9469 --- /dev/null +++ b/ESP-NOW_Juggling/esp-now-midi-bridge.py @@ -0,0 +1,394 @@ +# SPDX-FileCopyrightText: 2025 John Park for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +ESP-NOW MIDI Bridge +Bridge ESP-NOW messages to USB MIDI +Runs on ESP32-S3 Feather TFT connected to computer/synth via USB +""" + +import time +import wifi +import espnow +import usb_midi +import adafruit_midi +from adafruit_midi.note_on import NoteOn +from adafruit_midi.note_off import NoteOff +import board +import neopixel +import displayio +import terminalio +from adafruit_display_text import label +from adafruit_display_shapes.circle import Circle +import keypad + +# Set up NeoPixel for visual feedback +pixel = neopixel.NeoPixel(board.NEOPIXEL, 1) +pixel.brightness = 1 + +# Set up buttons for color control +# D0 has opposite pull direction from D1 and D2 +button_d0 = keypad.Keys( + (board.D0,), value_when_pressed=False, pull=True +) # Opposite pull +buttons_d1_d2 = keypad.Keys( + (board.D1, board.D2), value_when_pressed=True, pull=True +) # Normal pull + +# MIDI note mappings - centralized on the bridge +MIDI_MAPPINGS = { + "ball_A": { + "notes": [42, 43, 45, 47], # Sequence of notes to cycle through + "color": (238, 0, 16), # Pink (for bridge LED/display) + }, + "ball_B": { + "notes": [50, 50, 50, 50, 50, 62], # Single note + "color": (0, 255, 0), # Green (for bridge LED/display) + }, + "ball_C": { + "notes": [47, 45, 40], # Sequence + "color": (0, 16, 238), # Blue (for bridge LED/display) + }, +} + +# Track current position in each device's note sequence +note_positions = {device: 0 for device in MIDI_MAPPINGS.keys()} # pylint:disable=consider-iterating-dictionary + +# Track connection status for display (last seen time) +connection_status = {} +CONNECTION_TIMEOUT = 5.0 + +# Track current ball colors (start with defaults, update when COLOR command sent) +ball_colors = { + "ball_A": 0xEE0010, # Pink + "ball_B": 0x00FF00, # Green + "ball_C": 0x0010EE, # Blue +} + +# All available colors for cycling +ALL_COLORS = [0xEE0010, 0x00FF00, 0x0010EE] + +# Track battery voltages +ball_voltages = {"ball_A": "-.-V", "ball_B": "-.-V", "ball_C": "-.-V"} + +# Channel switching hack for ESP-NOW +wifi.radio.start_ap(" ", "", channel=6, max_connections=0) +wifi.radio.stop_ap() + +# Initialize MIDI +print("Available MIDI ports:", len(usb_midi.ports)) +for i, port in enumerate(usb_midi.ports): + print(f"Port {i}: {port}") + +midi_out_port = None +for port in usb_midi.ports: + if hasattr(port, "write"): + midi_out_port = port + break + +if midi_out_port: + midi = adafruit_midi.MIDI(midi_out=midi_out_port, out_channel=0) + print(f"MIDI initialized with port: {midi_out_port}") +else: + print("No MIDI output port found!") + midi = None + + +def format_mac(mac_bytes): + """Convert MAC address bytes to standard colon-separated format""" + return ":".join(f"{b:02x}" for b in mac_bytes) + + +def blink_color(color, count=1): + """Blink the NeoPixel with specified color and count""" + for _ in range(count): + pixel[0] = color + time.sleep(0.02) + pixel[0] = (0, 0, 0) + + +def parse_trigger_message(message_str): + """Parse trigger message and return device info""" + if not message_str.startswith("TRIGGER|"): + return None, None, None + + try: + parts = message_str.split("|") + if len(parts) >= 4: + device_id = parts[1] # pylint:disable=redefined-outer-name + trigger_type = parts[2] # pylint:disable=redefined-outer-name + timestamp = parts[3] # pylint:disable=redefined-outer-name + return device_id, trigger_type, timestamp + except Exception: # pylint:disable=broad-except + pass + + return None, None, None + + +def parse_battery_message(message_str): + """Parse battery voltage message with color""" + if not message_str.startswith("BATTERY|"): + return None, None, None + + try: + parts = message_str.split("|") + if len(parts) >= 4: + device_id = parts[1] # pylint:disable=redefined-outer-name + voltage = parts[2] # pylint:disable=redefined-outer-name + color_hex = int(parts[3], 16) # pylint:disable=redefined-outer-name + return device_id, voltage, color_hex + except Exception: # pylint:disable=broad-except + pass + + return None, None, None + + +def send_midi_note(device_id, velocity=100, duration=0.05): # pylint:disable=redefined-outer-name + """Send a MIDI note based on device mapping, cycling through sequence""" + if not midi or device_id not in MIDI_MAPPINGS: + print(f"MIDI not available or unknown device: {device_id}") + return + + mapping = MIDI_MAPPINGS[device_id] # pylint:disable=redefined-outer-name + notes_sequence = mapping["notes"] + + # Get current note from sequence + current_position = note_positions[device_id] + note = notes_sequence[current_position] + + # Move to next position in sequence (with wrap-around) + note_positions[device_id] = (current_position + 1) % len(notes_sequence) + + try: + midi.send(NoteOn(note, velocity)) + time.sleep(duration) + midi.send(NoteOff(note, 0)) + except Exception as err: # pylint:disable=broad-except + print(f"MIDI error: {err}") + + +def send_color_command(device_id): # pylint:disable=redefined-outer-name + """Send color cycle command to a specific ball""" + try: + message = f"COLOR|{device_id}|next" # pylint:disable=redefined-outer-name + e.send(message, broadcast_peer) + print(f"Sent color command: {message}") + + # Update tracked ball color + current_color_index = ALL_COLORS.index(ball_colors[device_id]) + next_color_index = (current_color_index + 1) % len(ALL_COLORS) + ball_colors[device_id] = ALL_COLORS[next_color_index] + print(f"{device_id} color now: {ball_colors[device_id]:06X}") + + return True + except Exception as ex: # pylint:disable=broad-except + print(f"Color send error: {ex}") + return False + + +def handle_button_presses(): + """Check for button presses and send color commands""" + # Handle D0 button (ball_A) - opposite pull direction + d0_event = button_d0.events.get() + if d0_event and d0_event.pressed: + send_color_command("ball_A") + print("ball_A color cycle") + + # Handle D1 and D2 buttons (ball_B and ball_C) + d1_d2_event = buttons_d1_d2.events.get() + if d1_d2_event and d1_d2_event.pressed: + if d1_d2_event.key_number == 0: # D1 pressed (ball_B) + send_color_command("ball_B") + print("ball_B color cycle") + elif d1_d2_event.key_number == 1: # D2 pressed (ball_C) + send_color_command("ball_C") + print("ball_C color cycle") + + +# Initialize TFT display +display = board.DISPLAY +group = displayio.Group() + +# Colors +BGCOLOR = 0x000000 +TEXT_COLOR = 0xFFFFFF +DISCONNECTED_COLOR = 0x404040 + + +def hex_to_rgb(hex_color): + """Convert hex color to RGB tuple""" + r = (hex_color >> 16) & 0xFF + g = (hex_color >> 8) & 0xFF + b = hex_color & 0xFF + return (r, g, b) + + +# Create display elements in A, B, C order - TWO LINES PER BALL +ball_info = [] +device_hex_colors = { + "ball_A": 0xEE0010, # Pink + "ball_B": 0x00FF00, # Green + "ball_C": 0x0010EE, # Blue +} + +# Display balls in A, B, C order with two lines each +ordered_devices = ["ball_A", "ball_B", "ball_C"] +for i, device_id in enumerate(ordered_devices): + if device_id in MIDI_MAPPINGS: + mapping = MIDI_MAPPINGS[device_id] + y_pos_line1 = 10 + (i * 50) # First line + y_pos_line2 = y_pos_line1 + 20 # Second line (20 pixels below) + + # Connection dot - use device hex color (fixed color for display) + dot_color = device_hex_colors[device_id] + dot = Circle(10, y_pos_line1 + 3, 4, fill=dot_color, outline=DISCONNECTED_COLOR) + group.append(dot) + + # Line 1: Ball name and voltage in ball's current color + ball_name = device_id.replace("ball_", "Ball ") + voltage_text = ball_voltages[device_id] + line1_text = f"{ball_name} {voltage_text}" + + line1_label = label.Label( + terminalio.FONT, + text=line1_text, + color=hex_to_rgb(ball_colors[device_id]), # Use ball's current color + scale=2, # Bigger font + x=25, + y=y_pos_line1, + ) + group.append(line1_label) + + # Line 2: MIDI notes + notes_list = ", ".join(str(n) for n in mapping["notes"]) + line2_text = f"notes: {notes_list}" + + line2_label = label.Label( + terminalio.FONT, + text=line2_text, + color=TEXT_COLOR, + scale=1, # Smaller font for notes line + x=25, + y=y_pos_line2, + ) + group.append(line2_label) + + ball_info.append( + { + "device_id": device_id, + "dot": dot, + "line1_label": line1_label, + "line2_label": line2_label, + "connected_color": dot_color, + "disconnected_color": DISCONNECTED_COLOR, + } + ) + +display.root_group = group + + +def update_connection_display(): + """Update connection status dots and text colors""" + current_time = time.monotonic() # pylint:disable=redefined-outer-name + for ball in ball_info: + device_id = ball["device_id"] # pylint:disable=redefined-outer-name + + # Update connection dot + if device_id in connection_status: + time_since_last = current_time - connection_status[device_id] + if time_since_last < CONNECTION_TIMEOUT: + ball["dot"].fill = ball["connected_color"] + else: + ball["dot"].fill = ball["disconnected_color"] + else: + ball["dot"].fill = ball["disconnected_color"] + + # Update line 1 text (ball name and voltage) with current ball color + ball_name = device_id.replace("ball_", "Ball ") # pylint:disable=redefined-outer-name + voltage_text = ball_voltages[device_id] # pylint:disable=redefined-outer-name + ball["line1_label"].text = f"{ball_name} {voltage_text}" + ball["line1_label"].color = hex_to_rgb(ball_colors[device_id]) + + +# Initialize ESP-NOW +e = espnow.ESPNow() +broadcast_peer = espnow.Peer(mac=b"\xff\xff\xff\xff\xff\xff", channel=6) +e.peers.append(broadcast_peer) + +print("ESP-NOW to MIDI Bridge starting...") +print("MIDI mappings loaded:") +for device, mapping in MIDI_MAPPINGS.items(): + notes = mapping["notes"] + if len(notes) == 1: + print(f" {device}: Note {notes[0]} (single)") + else: + print(f" {device}: Notes {notes} (sequence)") +print("Button controls: D0=ball_A, D1=ball_B, D2=ball_C (color cycling)") +print("Listening for ball trigger messages...") + +# Update display once at startup +update_connection_display() +last_display_update = time.monotonic() +last_message_time = {} + +while True: + if e: # Packet available + packet = e.read() + sender_mac = format_mac(packet.mac) + message = packet.msg.decode("utf-8") + + print(f"ESP-NOW RX from {sender_mac}: {message}") + + # Parse battery messages + battery_device_id, voltage, color_hex = parse_battery_message(message) + if battery_device_id: + ball_voltages[battery_device_id] = f"{voltage}V" + # Update ball color from battery report + if color_hex is not None: + ball_colors[battery_device_id] = color_hex + print( + f"Updated {battery_device_id} voltage: {voltage}V, color: {color_hex:06X}" + ) + else: + print(f"Updated {battery_device_id} voltage: {voltage}V") + # Trigger display update + update_connection_display() + + # Parse the trigger message + device_id, trigger_type, timestamp = parse_trigger_message(message) + + if device_id and device_id in MIDI_MAPPINGS: + current_time = time.monotonic() + + # Update connection status + connection_status[device_id] = current_time + + # Simple debouncing + if ( + device_id not in last_message_time + or current_time - last_message_time[device_id] > 0.3 + ): + print(f"Converting {device_id} trigger to MIDI") + + # Send MIDI note immediately + if trigger_type == "tap": + send_midi_note(device_id) + else: + send_midi_note(device_id) + + # Use bridge's fixed color for LED feedback + bridge_color = MIDI_MAPPINGS[device_id]["color"] + blink_color(bridge_color, count=1) + + last_message_time[device_id] = current_time + + # Handle button presses for color control + handle_button_presses() + + # Update display occasionally + current_time = time.monotonic() + if current_time - last_display_update > 2.0: + update_connection_display() + last_display_update = current_time + + time.sleep(0.01) diff --git a/ESP-NOW_basics/espnow_transceiver.py b/ESP-NOW_basics/espnow_transceiver.py new file mode 100644 index 000000000..39f828645 --- /dev/null +++ b/ESP-NOW_basics/espnow_transceiver.py @@ -0,0 +1,166 @@ +# SPDX-FileCopyrightText: John Park for Adafruit 2025 +# SPDX-License-Identifier: MIT +""" +ESP-NOW transciever demo for ESP32-S2/S3 TFT Feather boards with display +""" +import time +import wifi +import espnow +import board +import digitalio +import displayio +import terminalio +from adafruit_display_text import label +from adafruit_display_shapes.rect import Rect + + +# Setup the display (using built-in display like your example) +display = board.DISPLAY +group = displayio.Group() + +# Create background rectangles like your example +background_rect = Rect(0, 0, display.width, display.height, fill=0x000000) +group.append(background_rect) + +# Set up a button on pin D0/BOOT +button = digitalio.DigitalInOut(board.BUTTON) +button.direction = digitalio.Direction.INPUT +button.pull = digitalio.Pull.UP + +# CONFIGURATION: Set this for each device +DEVICE_ID = "board_A" # Options: "board_A", "board_B", "board_C", "board_D" + +# Channel switching hack +wifi.radio.start_ap(" ", "", channel=6, max_connections=0) +wifi.radio.stop_ap() + +def format_mac(mac_bytes): + return ':'.join(f'{b:02x}' for b in mac_bytes) + +def get_my_mac(): + return format_mac(wifi.radio.mac_address) + +# Initialize ESP-NOW +e = espnow.ESPNow() +peer = espnow.Peer(mac=b'\xff\xff\xff\xff\xff\xff', channel=6) +e.peers.append(peer) + +my_mac = get_my_mac() +print(f"{DEVICE_ID} board starting - MAC: {my_mac}") + +# Colors +TOMATO = 0xFF6347 +WHITE = 0xFFFFFF +GREEN = 0x00FF00 +BLUE = 0x0080FF +RED = 0xFF0000 + +# Sender colors mapping +SENDER_COLORS = { + "board_A": 0x32FF32, # Lime green + "board_B": 0x00FFFF, # Cyan + "board_C": 0xC8A2C8, # Lilac + "board_D": 0xFFFFFF # White +} + +def get_sender_color(rx_message): + """Extract sender ID from message and return corresponding color""" + for board_id in SENDER_COLORS: + if rx_message.startswith(board_id): + return SENDER_COLORS[board_id] + return WHITE # Default to white if sender not recognized + +# Create text labels using anchor positioning like your example +title_label = label.Label(terminalio.FONT, text=f"ESP-NOW {DEVICE_ID}", color=TOMATO, + scale=2, anchor_point=(0, 0), anchored_position=(5, 5)) +group.append(title_label) + +status_label = label.Label(terminalio.FONT, text="press D0 to send", color=TOMATO, + scale=2, anchor_point=(0, 0), anchored_position=(5, 35)) +group.append(status_label) + +sent_label = label.Label(terminalio.FONT, text="TX'd: --", color=TOMATO, + scale=2, anchor_point=(0, 0), anchored_position=(5, 65)) +group.append(sent_label) + +# Create a second label for the colored counter part +sent_counter_label = label.Label(terminalio.FONT, text="",color=SENDER_COLORS.get(DEVICE_ID, WHITE), + scale=2, anchor_point=(0, 0), anchored_position=(80, 65)) +group.append(sent_counter_label) + +received_label = label.Label(terminalio.FONT, text="RX'd: --", color=TOMATO, + scale=2, anchor_point=(0, 0), anchored_position=(5, 95)) +group.append(received_label) + +# Create a second label for the colored message part +received_message_label = label.Label(terminalio.FONT, text="", color=WHITE, + scale=2, anchor_point=(0, 0), anchored_position=(80, 95)) +group.append(received_message_label) + +# Show the display +display.root_group = group + +# Button debouncing and status tracking +last_button_time = 0 +button_debounce = 0.2 # 200ms debounce +message_count = 0 +status_reset_time = 0 +status_needs_reset = False + +while True: + current_time = time.monotonic() + + # Check for button press (button is active low due to pull-up) + if not button.value and (current_time - last_button_time > button_debounce): + message_count += 1 + message = f"{DEVICE_ID} {message_count}" + + try: + e.send(message, peer) + print(f"Sent: {message}") + + # Update display + status_label.text = "...>" + status_label.color = TOMATO + sent_label.text = "TX'd: " # Keep this tomato colored + sent_counter_label.text = str(message_count) # Color with sender color + sent_counter_label.color = SENDER_COLORS.get(DEVICE_ID, WHITE) + status_reset_time = current_time + 0.5 # Reset after 0.5 seconds + status_needs_reset = True + + except Exception as ex: # pylint: disable=broad-except + print(f"Send failed: {ex}") + status_label.text = "xxx" + status_label.color = RED + status_reset_time = current_time + 2.0 # Show error for 2 seconds + status_needs_reset = True + + last_button_time = current_time + + # Reset status only when needed and after appropriate delay + if status_needs_reset and current_time >= status_reset_time: + status_label.text = "press D0 to send" + status_label.color = TOMATO + status_needs_reset = False + + # Check for incoming packets + if e: + packet = e.read() + if packet: + sender_mac = format_mac(packet.mac) + + if sender_mac != my_mac: + message = packet.msg.decode('utf-8') + print(f"received: {message}") + + # Update display with sender color + status_label.text = "<..." + status_label.color = TOMATO + sender_color = get_sender_color(message) + received_label.text = "RX'd: " # Keep this tomato colored + received_message_label.text = message[-12:] # Color just the message + received_message_label.color = sender_color + status_reset_time = current_time + 0.5 # Reset after 0.5 seconds + status_needs_reset = True + + time.sleep(0.05) # Light polling diff --git a/ESP32-S3_BLE_iOS_Media/code.py b/ESP32-S3_BLE_iOS_Media/code.py index fcda43325..c0aa6aad9 100644 --- a/ESP32-S3_BLE_iOS_Media/code.py +++ b/ESP32-S3_BLE_iOS_Media/code.py @@ -5,6 +5,7 @@ import gc import board import displayio +import fourwire import terminalio import adafruit_ble from adafruit_ble.advertising.standard import SolicitServicesAdvertisement @@ -23,7 +24,7 @@ spi = board.SPI() tft_cs = board.D9 tft_dc = board.D10 -display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs) +display_bus = fourwire.FourWire(spi, command=tft_dc, chip_select=tft_cs) display = adafruit_hx8357.HX8357(display_bus, width=480, height=320) # touch i2c = board.I2C() diff --git a/ESP32_S2_WiFi_Tests/code.py b/ESP32_S2_WiFi_Tests/code.py index d20135e84..2fe6494e1 100644 --- a/ESP32_S2_WiFi_Tests/code.py +++ b/ESP32_S2_WiFi_Tests/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import ipaddress import ssl import wifi @@ -13,12 +14,17 @@ JSON_QUOTES_URL = "https://www.adafruit.com/api/quotes.php" JSON_STARS_URL = "https://api.github.com/repos/adafruit/circuitpython" -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) print("ESP32-S2 WebClient Test") @@ -30,10 +36,10 @@ network.rssi, network.channel)) wifi.radio.stop_scanning_networks() -print("Connecting to %s"%secrets["ssid"]) -wifi.radio.connect(secrets["ssid"], secrets["password"]) -print("Connected to %s!"%secrets["ssid"]) -print("My IP address is", wifi.radio.ipv4_address) +print(f"Connecting to {ssid}") +wifi.radio.connect(ssid, password) +print(f"Connected to {ssid}!") +print(f"My IP address is {wifi.radio.ipv4_address}") ipv4 = ipaddress.ip_address("8.8.4.4") print("Ping google.com: %f ms" % (wifi.radio.ping(ipv4)*1000)) diff --git a/EYESPI_BFF/CircuitPython_EYESPI_BFF/code.py b/EYESPI_BFF/CircuitPython_EYESPI_BFF/code.py index cab770b6c..8a9f3f214 100644 --- a/EYESPI_BFF/CircuitPython_EYESPI_BFF/code.py +++ b/EYESPI_BFF/CircuitPython_EYESPI_BFF/code.py @@ -10,6 +10,7 @@ from random import randint import time import displayio +import fourwire import board import vectorio import terminalio @@ -29,7 +30,7 @@ tft_cs = board.TX tft_dc = board.RX -display_bus = displayio.FourWire( +display_bus = fourwire.FourWire( spi, command=tft_dc, chip_select=tft_cs, reset=None ) diff --git a/Espresso_Water_Meter/code.py b/Espresso_Water_Meter/code.py index 7991e7b73..fba430e16 100644 --- a/Espresso_Water_Meter/code.py +++ b/Espresso_Water_Meter/code.py @@ -14,6 +14,7 @@ import socketpool import wifi import board +import digitalio import alarm import neopixel import adafruit_hcsr04 @@ -22,6 +23,20 @@ import adafruit_requests import adafruit_max1704x +# Initialize the power pin for the sensor +sensor_power = digitalio.DigitalInOut(board.A2) +sensor_power.direction = digitalio.Direction.OUTPUT +sensor_power.value = False # Start with sensor powered off + +def power_sensor_on(): + """Turn on power to the ultrasonic sensor and wait for it to stabilize.""" + sensor_power.value = True + time.sleep(0.55) # Give sensor time to power up and stabilize + +def power_sensor_off(): + """Turn off power to the ultrasonic sensor.""" + sensor_power.value = False + # Initialize the sonar sensor sonar = adafruit_hcsr04.HCSR04(trigger_pin=board.A0, echo_pin=board.A1) @@ -46,9 +61,9 @@ # Operating hours (24-hour format with minutes, e.g., "6:35" and "16:00") OPENING_TIME = "6:00" -CLOSING_TIME = "22:30" +CLOSING_TIME = "15:30" # Normal operation check interval -NORMAL_CHECK_MINUTES = 5 +NORMAL_CHECK_MINUTES = 10 # Sleep duration in seconds during operating hours SLEEP_DURATION = 60 * NORMAL_CHECK_MINUTES # Display duration in seconds @@ -64,6 +79,7 @@ def parse_time(time_str): def get_average_distance(): """Take multiple distance readings and return the average.""" + power_sensor_on() # Power on the sensor before taking measurements distances = [] for _ in range(NUM_SAMPLES): try: @@ -73,6 +89,7 @@ def get_average_distance(): except RuntimeError: print("Error reading distance") continue + power_sensor_off() # Power off the sensor after measurements # Only average valid readings if distances: @@ -248,6 +265,7 @@ def set_pixel_color(distance): sleep_seconds = SLEEP_DURATION # Use normal interval if we couldn't get readings # Prepare for deep sleep +power_sensor_off() # Make sure sensor is powered off before sleep pixel.brightness = 0 # Turn off NeoPixel # Flush the serial output before sleep diff --git a/Ever_Burning_Flame_Painting/Ever_Burning_Flame_Painting.ino b/Ever_Burning_Flame_Painting/Ever_Burning_Flame_Painting.ino index 50cf87102..90bf75968 100644 --- a/Ever_Burning_Flame_Painting/Ever_Burning_Flame_Painting.ino +++ b/Ever_Burning_Flame_Painting/Ever_Burning_Flame_Painting.ino @@ -5,6 +5,10 @@ #include #include // add FastLED library AFTER Circuit Playground library to avoid issues +#if defined(FASTLED_VERSION) && FASTLED_VERSION > 3010001 + #error "FastLED 3.10.2 has known compile issues with SAMD boards. Please downgrade to FastLED 3.10.1" +#endif + #define STRIP1_DATA_PIN 9 // define data pins for all 3 LED strips #define STRIP2_DATA_PIN 12 #define STRIP3_DATA_PIN 6 diff --git a/Factory_Tests/Adafruit_Sparkle_Motion_FactoryTest/.feather_esp32_v2.test.only b/Factory_Tests/Adafruit_Sparkle_Motion_FactoryTest/.feather_esp32_v2.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Factory_Tests/Adafruit_Sparkle_Motion_FactoryTest/Adafruit_Sparkle_Motion_FactoryTest.ino b/Factory_Tests/Adafruit_Sparkle_Motion_FactoryTest/Adafruit_Sparkle_Motion_FactoryTest.ino new file mode 100644 index 000000000..f59400cc6 --- /dev/null +++ b/Factory_Tests/Adafruit_Sparkle_Motion_FactoryTest/Adafruit_Sparkle_Motion_FactoryTest.ino @@ -0,0 +1,83 @@ +// SPDX-FileCopyrightText: 2025 Limor Fried for Adafruit Industries +// +// SPDX-License-Identifier: MIT +#include +#include "WiFi.h" +#include +#include "ESP_I2S.h" +extern Adafruit_TestBed TB; + +// I2S pin definitions +const uint8_t I2S_SCK = 26; // BCLK +const uint8_t I2S_WS = 33; // LRCLK +const uint8_t I2S_DIN = 25; // DATA_IN +I2SClass i2s; + +// the setup routine runs once when you press reset: +void setup() { + Serial.begin(115200); + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); + i2s.setPins(I2S_SCK, I2S_WS, -1, I2S_DIN); + if (!i2s.begin(I2S_MODE_STD, 44100, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO, I2S_STD_SLOT_LEFT)) { + Serial.println("Failed to initialize I2S bus!"); + return; + } + // TestBed will handle the neopixel swirl for us + TB.neopixelPin = PIN_NEOPIXEL; + TB.neopixelNum = 1; + TB.begin(); + + // Set WiFi to station mode and disconnect from an AP if it was previously connected + WiFi.mode(WIFI_STA); + WiFi.disconnect(); +} + +// the loop routine runs over and over again forever: +uint8_t wheelColor=0; +void loop() { + if (wheelColor == 0) { + // Test I2C! + Serial.print("I2C port "); + TB.theWire = &Wire; + TB.printI2CBusScan(); + + // Test WiFi Scan! + // WiFi.scanNetworks will return the number of networks found + int n = WiFi.scanNetworks(); + Serial.print("WiFi AP scan done..."); + if (n == 0) { + Serial.println("no networks found"); + } else { + Serial.print(n); + Serial.println(" networks found"); + for (int i = 0; i < n; ++i) { + // Print SSID and RSSI for each network found + Serial.print(i + 1); + Serial.print(": "); + Serial.print(WiFi.SSID(i)); + Serial.print(" ("); + Serial.print(WiFi.RSSI(i)); + Serial.print(")"); + Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN)?" ":"*"); + delay(10); + } + } + Serial.println(""); + for (int i=0; i < 5; i++) { + int32_t sample = i2s.read(); + if (sample >= 0){ + Serial.print("Amplitude: "); + Serial.println(sample); + + // Delay to avoid printing too quickly + delay(200); + } + } + } + + TB.setColor(TB.Wheel(wheelColor++)); // swirl NeoPixel + digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); + + delay(5); +} diff --git a/Factory_Tests/Adafruit_Sparkle_Motion_Stick_FactoryTest/.feather_esp32_v2.test.only b/Factory_Tests/Adafruit_Sparkle_Motion_Stick_FactoryTest/.feather_esp32_v2.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Factory_Tests/Adafruit_Sparkle_Motion_Stick_FactoryTest/Adafruit_Sparkle_Motion_Stick_FactoryTest.ino b/Factory_Tests/Adafruit_Sparkle_Motion_Stick_FactoryTest/Adafruit_Sparkle_Motion_Stick_FactoryTest.ino new file mode 100644 index 000000000..c3075dff6 --- /dev/null +++ b/Factory_Tests/Adafruit_Sparkle_Motion_Stick_FactoryTest/Adafruit_Sparkle_Motion_Stick_FactoryTest.ino @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: 2025 Limor Fried for Adafruit Industries +// +// SPDX-License-Identifier: MIT +#include +#include "WiFi.h" +#include +#include "ESP_I2S.h" +extern Adafruit_TestBed TB; + +// I2S pin definitions +const uint8_t I2S_SCK = 14; // BCLK +const uint8_t I2S_WS = 12; // LRCLK +const uint8_t I2S_DIN = 13; // DATA_IN +I2SClass i2s; + +// the setup routine runs once when you press reset: +void setup() { + Serial.begin(115200); + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); + i2s.setPins(I2S_SCK, I2S_WS, -1, I2S_DIN); + if (!i2s.begin(I2S_MODE_STD, 44100, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO, I2S_STD_SLOT_LEFT)) { + Serial.println("Failed to initialize I2S bus!"); + return; + } + // TestBed will handle the neopixel swirl for us + TB.neopixelPin = PIN_NEOPIXEL; + TB.neopixelNum = 1; + TB.begin(); + + // Set WiFi to station mode and disconnect from an AP if it was previously connected + WiFi.mode(WIFI_STA); + WiFi.disconnect(); +} + +// the loop routine runs over and over again forever: +uint8_t wheelColor=0; +void loop() { + if (wheelColor == 0) { + // Test WiFi Scan! + // WiFi.scanNetworks will return the number of networks found + int n = WiFi.scanNetworks(); + Serial.print("WiFi AP scan done..."); + if (n == 0) { + Serial.println("no networks found"); + } else { + Serial.print(n); + Serial.println(" networks found"); + for (int i = 0; i < n; ++i) { + // Print SSID and RSSI for each network found + Serial.print(i + 1); + Serial.print(": "); + Serial.print(WiFi.SSID(i)); + Serial.print(" ("); + Serial.print(WiFi.RSSI(i)); + Serial.print(")"); + Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN)?" ":"*"); + delay(10); + } + } + Serial.println(""); + for (int i=0; i < 5; i++) { + int32_t sample = i2s.read(); + if (sample >= 0){ + Serial.print("Amplitude: "); + Serial.println(sample); + + // Delay to avoid printing too quickly + delay(200); + } + } + } + + TB.setColor(TB.Wheel(wheelColor++)); // swirl NeoPixel + digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); + + delay(5); +} diff --git a/Factory_Tests/Feather_RP2040_Adalogger/.none.test.only b/Factory_Tests/Feather_RP2040_Adalogger/.none.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Factory_Tests/Feather_RP2040_Adalogger/Feather_RP2040_Adalogger.ino b/Factory_Tests/Feather_RP2040_Adalogger/Feather_RP2040_Adalogger.ino index ea74524b6..00d5482df 100644 --- a/Factory_Tests/Feather_RP2040_Adalogger/Feather_RP2040_Adalogger.ino +++ b/Factory_Tests/Feather_RP2040_Adalogger/Feather_RP2040_Adalogger.ino @@ -2,9 +2,8 @@ // // SPDX-License-Identifier: MIT -#include #include -#include "Adafruit_TestBed.h" +#include SdFat SD; SdFile file; diff --git a/Factory_Tests/Fruit_Jam_Factory_Test/.none.test.only b/Factory_Tests/Fruit_Jam_Factory_Test/.none.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Factory_Tests/Fruit_Jam_Factory_Test/Fruit_Jam_Factory_Test.ino b/Factory_Tests/Fruit_Jam_Factory_Test/Fruit_Jam_Factory_Test.ino new file mode 100644 index 000000000..6292cacd1 --- /dev/null +++ b/Factory_Tests/Fruit_Jam_Factory_Test/Fruit_Jam_Factory_Test.ino @@ -0,0 +1,497 @@ +// SPDX-FileCopyrightText: 2025 Limor Fried for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "hardware/pio.h" +#include "pio_usb.h" +#include "Adafruit_TinyUSB.h" +#include +#include "Adafruit_TestBed.h" +#include "Adafruit_NeoPixel.h" +#include +#include +#include +#include +#include + +// NeoPixel - Note we can't write to these all the time or DVI gets sad from the blocking +extern Adafruit_TestBed TB; +Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_NEOPIXEL, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); + +// DVI display using HSTX peripheral +DVHSTX16 display(DVHSTX_PINOUT_DEFAULT, DVHSTX_RESOLUTION_320x240); +volatile bool display_inited = false; +volatile bool usbhost_inited = false; + +// SD setup +SdFat SD; +SdFile file; +SdSpiConfig config(PIN_SD_DAT3_CS, DEDICATED_SPI, SD_SCK_MHZ(16), &SPI); +bool sd_initialized = false; +bool last_sd_detect_state = true; // Active low, so true means not detected + +// I2S +Adafruit_TLV320DAC3100 codec; // Create codec object +I2S i2s(OUTPUT, PIN_I2S_BITCLK, PIN_I2S_DATAOUT); // Create the I2S port using a PIO state machine + +int32_t headphone_gain = 60; // starting gain == -30dB see Table 6-24 +int32_t speaker_gain = 40; // starting gain == -20dB see Table 6-24 +// Octave of notes to play +uint32_t notes[] = {523, 587, 659, 698, 784, 880, 988, 1047}; +uint8_t note_idx = 0; +uint32_t amplitude = 10000; // amplitude of sine wave +uint32_t sampleRate = 44100; // sample rate in Hz +float phase_increment = 0; +float phase = 0.0; +uint32_t note_timer = 0; + + +void setup() { + Serial.begin(115200); + while ( !Serial ) delay(10); // wait for native usb + delay(100); + + Serial.println("TinyUSB Hardware demo + DVI demo"); + + Serial.println("initialize onboard NeoPixels"); + strip.begin(); + strip.setBrightness(10); + strip.show(); + strip.fill(0xFF00FF); + + Serial.println("init hstx display"); + if (!display.begin()) { // Blink LED if insufficient RAM + pinMode(LED_BUILTIN, OUTPUT); + for (;;) + digitalWrite(LED_BUILTIN, (millis() / 500) & 1); + } + Serial.println("display initialized"); + display_inited = true; + + // wait for USB host to be done initializing + while (! usbhost_inited) { + delay(1); + } + + Serial.println("Initialize testbed"); + TB.ledPin = LED_BUILTIN; + TB.begin(); + + Serial.println("Initialize onboard LED & buttons"); + pinMode(LED_BUILTIN, OUTPUT); + pinMode(PIN_BUTTON1, INPUT_PULLUP); + pinMode(PIN_BUTTON2, INPUT_PULLUP); + pinMode(PIN_BUTTON3, INPUT_PULLUP); + // Setup SD detect pin + pinMode(PIN_SD_DETECT, INPUT_PULLUP); + last_sd_detect_state = digitalRead(PIN_SD_DETECT); + + // Set up the wifi coproc + WiFi.setPins(SPIWIFI_SS, SPIWIFI_ACK, ESP32_RESETN, ESP32_GPIO0, &SPIWIFI); + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + } else { + String fv = WiFi.firmwareVersion(); + Serial.print("Firmware OK: "); + Serial.println(fv); + } + + // Set up the I2S + configI2S(); + note_timer = millis(); + phase_increment = 2.0 * PI * notes[note_idx] / sampleRate; + + + uint32_t sys_clock = clock_get_hz(clk_sys); + uint32_t peri_clock = clock_get_hz(clk_peri); + Serial.printf("System clock: %u Hz (%u MHz)\n", sys_clock, sys_clock/1000000); + Serial.printf("Peripheral clock: %u Hz (%u MHz)\n", peri_clock, peri_clock/1000000); + check_pio_status(); +} + +uint8_t j = 0; +uint32_t last_wifi_scan = 0; + +void loop() { + j++; + delay(10); + + // always add a line to the display! + display.drawLine(random(display.width()), random(display.height()), + random(display.width()), random(display.height()), + random(65536)); + + check_buttons(); + check_and_init_sd(); + + // every 300 ms toggle the onboard red LED + if ((j % 64) == 31) { + digitalWrite(LED_BUILTIN, HIGH); + } + if ((j % 64) == 0) { + digitalWrite(LED_BUILTIN, LOW); + } + + // every .6 sec print analog pin info + if ((j % 64) == 0) { + Serial.print("A0 = "); Serial.print(TB.readAnalogVoltage(A0)); Serial.print("\t"); + Serial.print("A1 = "); Serial.print(TB.readAnalogVoltage(A1)); Serial.print("\t"); + Serial.print("A2 = "); Serial.print(TB.readAnalogVoltage(A2)); Serial.print("\t"); + Serial.print("A3 = "); Serial.print(TB.readAnalogVoltage(A3)); Serial.print("\t"); + Serial.print("A4 = "); Serial.print(TB.readAnalogVoltage(A4)); Serial.print("\t"); + Serial.print("A5 = "); Serial.print(TB.readAnalogVoltage(A5)); Serial.print("\n\r"); + } + + // every 1.2 sec print I2C bus info + if (j == 127) { + TB.printI2CBusScan(); + } + + if ((millis() - last_wifi_scan) > 10000) { + // every 10 sec, scan wifi + Serial.println("** Scan Networks **"); + int numSsid = WiFi.scanNetworks(); + if (numSsid == -1) { + Serial.println("Couldn't get a wifi connection"); + return; + } + Serial.printf("Number of available networks: %d\n\r", numSsid); + + // print the network number and name for each network found: + for (int thisNet = 0; thisNet < numSsid; thisNet++) { + Serial.printf("%d) %s\tSignal: %d dBm\n\r", thisNet, WiFi.SSID(thisNet), WiFi.RSSI(thisNet)); + } + last_wifi_scan = millis(); + } +} + + +void check_pio_status() { + PIO pios[] = {pio0, pio1, pio2}; + + for (uint pio_idx = 0; pio_idx < 3; pio_idx++) { + PIO pio = pios[pio_idx]; + + Serial.printf("PIO%d:\n", pio_idx); + + // Check state machine status + for (uint sm = 0; sm < 4; sm++) { + Serial.printf(" SM%d: %s\n", sm, + pio_sm_is_claimed(pio, sm) ? "CLAIMED" : "FREE"); + } + Serial.printf("\n"); + } +} + +void check_buttons() { + if (!digitalRead(PIN_BUTTON1)) { + Serial.println("Button 1 pressed!"); + strip.fill(0xFF0000); // Red when button pressed + strip.show(); + delay(50); // Simple debounce + } + + if (!digitalRead(PIN_BUTTON2)) { + Serial.println("Button 2 pressed!"); + strip.fill(0x00FF00); // Green when button1 pressed + strip.show(); + delay(50); + } + + if (!digitalRead(PIN_BUTTON3)) { + Serial.println("Button 3 pressed!"); + strip.fill(0x0000FF); // Blue when button2 pressed + strip.show(); + delay(50); + } +} + + +void check_and_init_sd() { + bool current_sd_detect = digitalRead(PIN_SD_DETECT); + + // Check for SD card insertion (detect pin going high) + if (current_sd_detect && (last_sd_detect_state == false)) { + Serial.println("SD card inserted!"); + delay(100); // Give the card time to stabilize + + if (!SD.begin(config)) { + Serial.println("SD card initialization failed!"); + return; + } + + Serial.println("SD card initialized successfully."); + + // Print the SD card details + uint32_t size = SD.card()->sectorCount(); + if (size == 0) { + Serial.println("Can't determine the card size."); + return; + } + + uint32_t sizeMB = 0.000512 * size + 0.5; + Serial.printf("Card size: %lu MB (MB = 1,000,000 bytes)\n", sizeMB); + Serial.printf("Volume is FAT%d, Cluster size (bytes): %lu\n\n", + int(SD.vol()->fatType()), + SD.vol()->bytesPerCluster()); + + // List all files + Serial.println("Files on card:"); + SD.ls(LS_R | LS_DATE | LS_SIZE); + + sd_initialized = true; + } + + // Update last state + last_sd_detect_state = current_sd_detect; +} + + + +//------------- Core1 USB Host management -------------// + +Adafruit_USBH_Host USBHost; +#define LANGUAGE_ID 0x0409 + +typedef struct { + tusb_desc_device_t desc_device; + uint16_t manufacturer[32]; + uint16_t product[48]; + uint16_t serial[16]; + bool mounted; +} dev_info_t; + +// CFG_TUH_DEVICE_MAX is defined by tusb_config header +dev_info_t dev_info[CFG_TUH_DEVICE_MAX] = { 0 }; + + +void setup1() { + pinMode(PIN_5V_EN, OUTPUT); + digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE); + + while (! display_inited) { + delay(1); + yield(); + } + + Serial.println(clock_get_hz(clk_sys)); + + Serial.println("Core1 setup to run TinyUSB host with pio-usb"); + + pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG; + pio_cfg.pin_dp = PIN_USB_HOST_DP; + pio_cfg.tx_ch = dma_claim_unused_channel(true); + dma_channel_unclaim(pio_cfg.tx_ch); + USBHost.configure_pio_usb(1, &pio_cfg); + + USBHost.begin(1); + usbhost_inited = true; +} + +void loop1() { + USBHost.task(); + Serial.flush(); + + // Generate sine wave sample + int16_t sample = amplitude * sin(phase); + + // write the same sample twice, once for left and once for the right channel + i2s.write(sample); + i2s.write((int16_t)-sample); + + // Update phase for next sample + phase += phase_increment; + if (phase >= 2.0 * PI) { + phase -= 2.0 * PI; + } + // every 250ms change notes + if ((millis() - note_timer) > 250) { + note_idx = (note_idx + 1) % (sizeof(notes) / sizeof(notes[0])); + //Serial.println(notes[note_idx]); + phase_increment = 2.0 * PI * notes[note_idx] / sampleRate; + note_timer = millis(); + + static tlv320_headset_status_t last_status = TLV320_HEADSET_NONE; + + tlv320_headset_status_t status = codec.getHeadsetStatus(); + + if (last_status != status) { + switch (status) { + case TLV320_HEADSET_NONE: + Serial.println("Headset removed"); + // unmute speaker + codec.configureSPK_PGA(TLV320_SPK_GAIN_6DB, true); + // mute headphone + codec.configureHPL_PGA(0, false); + codec.configureHPR_PGA(0, false); + break; + case TLV320_HEADSET_WITH_MIC: + Serial.println("Headset with mic detected"); + case TLV320_HEADSET_WITHOUT_MIC: + Serial.println("Headphones detected"); + // mute speaker + codec.configureSPK_PGA(TLV320_SPK_GAIN_6DB, false); + // unmute headphone + codec.configureHPL_PGA(0, true); + codec.configureHPR_PGA(0, true); + break; + } + last_status = status; + } + } +} + +extern "C" { + +// Invoked when device with hid interface is mounted +// Report descriptor is also available for use. +// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough +// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, +// it will be skipped therefore report_desc = NULL, desc_len = 0 +void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) { + (void) desc_report; + (void) desc_len; + uint16_t vid, pid; + tuh_vid_pid_get(dev_addr, &vid, &pid); + + Serial.printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance); + Serial.printf("VID = %04x, PID = %04x\r\n", vid, pid); + if (!tuh_hid_receive_report(dev_addr, instance)) { + Serial.printf("Error: cannot request to receive report\r\n"); + } +} + +// Invoked when device with hid interface is un-mounted +void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) { + Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance); +} + +// Invoked when received report from device via interrupt endpoint +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) { + Serial.printf("HIDreport : "); + for (uint16_t i = 0; i < len; i++) { + Serial.printf("0x%02X ", report[i]); + } + Serial.println(); + // continue to request to receive report + if (!tuh_hid_receive_report(dev_addr, instance)) { + Serial.printf("Error: cannot request to receive report\r\n"); + } +} + +} // extern C + + +void configI2S() { + // reset + pinMode(PIN_PERIPHERAL_RESET, OUTPUT); + digitalWrite(PIN_PERIPHERAL_RESET, LOW); + delay(10); + digitalWrite(PIN_PERIPHERAL_RESET, HIGH); + + delay(100); + + Serial.println("Init TLV DAC"); + if (!codec.begin()) { + Serial.println("Failed to initialize codec!"); + return; + } + delay(10); + + // Interface Control + if (!codec.setCodecInterface(TLV320DAC3100_FORMAT_I2S, // Format: I2S + TLV320DAC3100_DATA_LEN_16)) { // Length: 16 bits + Serial.println("Failed to configure codec interface!"); + return; + } + + // Clock MUX and PLL settings + if (!codec.setCodecClockInput(TLV320DAC3100_CODEC_CLKIN_PLL) || + !codec.setPLLClockInput(TLV320DAC3100_PLL_CLKIN_BCLK)) { + Serial.println("Failed to configure codec clocks!"); + return; + } + + if (!codec.setPLLValues(1, 2, 32, 0)) { // P=2, R=2, J=32, D=0 + Serial.println("Failed to configure PLL values!"); + return; + } + + // DAC/ADC Config + if (!codec.setNDAC(true, 8) || // Enable NDAC with value 8 + !codec.setMDAC(true, 2)) { // Enable MDAC with value 2 + Serial.println("Failed to configure DAC dividers!"); + return; + } + + if (!codec.powerPLL(true)) { // Power up the PLL + Serial.println("Failed to power up PLL!"); + return; + } + + // DAC Setup + if (!codec.setDACDataPath(true, true, // Power up both DACs + TLV320_DAC_PATH_NORMAL, // Normal left path + TLV320_DAC_PATH_NORMAL, // Normal right path + TLV320_VOLUME_STEP_1SAMPLE)) { // Step: 1 per sample + Serial.println("Failed to configure DAC data path!"); + return; + } + + if (!codec.configureAnalogInputs(TLV320_DAC_ROUTE_MIXER, // Left DAC to mixer + TLV320_DAC_ROUTE_MIXER, // Right DAC to mixer + false, false, false, // No AIN routing + false)) { // No HPL->HPR + Serial.println("Failed to configure DAC routing!"); + return; + } + + // DAC Volume Control + if (!codec.setDACVolumeControl(false, false, TLV320_VOL_INDEPENDENT) || // Unmute both channels + !codec.setChannelVolume(false, 18) || // Left DAC +0dB + !codec.setChannelVolume(true, 18)) { // Right DAC +0dB + Serial.println("Failed to configure DAC volumes!"); + return; + } + + // Headphone and Speaker Setup + if (!codec.configureHeadphoneDriver(true, true, // Power up both drivers + TLV320_HP_COMMON_1_35V, // Default common mode + false) || // Don't power down on SCD + !codec.configureHPL_PGA(0, false) || // Set HPL gain, mute + !codec.configureHPR_PGA(0, false) || // Set HPR gain, mute + !codec.setHPLVolume(true, headphone_gain) || // Enable and set HPL volume + !codec.setHPRVolume(true, headphone_gain)) { // Enable and set HPR volume + Serial.println("Failed to configure headphone outputs!"); + return; + } + + if (!codec.enableSpeaker(true) || // Dis/Enable speaker amp + !codec.configureSPK_PGA(TLV320_SPK_GAIN_6DB, // Set gain to 6dB + true) || // Un-mute + !codec.setSPKVolume(true, speaker_gain)) { // Enable and set volume + Serial.println("Failed to configure speaker output!"); + return; + } + + + + if (!codec.configMicBias(false, true, TLV320_MICBIAS_AVDD) || + !codec.setHeadsetDetect(true) || + !codec.setInt1Source(true, true, false, false, false, + false) || // GPIO1 is detect headset or button press + !codec.setGPIO1Mode(TLV320_GPIO1_INT1)) { + Serial.println("Failed to configure headset detect"); + return; + } + + Serial.println("TLV config done!"); + + i2s.setBitsPerSample(16); + // start I2S at the sample rate with 16-bits per sample + if (!i2s.begin(sampleRate)) { + Serial.println("Failed to initialize I2S!"); + while (1); // do nothing + } +} diff --git a/Factory_Tests/KB2040_FactoryTest/.none.test.only b/Factory_Tests/KB2040_FactoryTest/.none.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Factory_Tests/Qualia_ESP32S3_RGB666_FactoryTest/Qualia_ESP32S3_RGB666_FactoryTest.ino b/Factory_Tests/Qualia_ESP32S3_RGB666_FactoryTest/Qualia_ESP32S3_RGB666_FactoryTest.ino index c0e944a88..8f9ecc963 100644 --- a/Factory_Tests/Qualia_ESP32S3_RGB666_FactoryTest/Qualia_ESP32S3_RGB666_FactoryTest.ino +++ b/Factory_Tests/Qualia_ESP32S3_RGB666_FactoryTest/Qualia_ESP32S3_RGB666_FactoryTest.ino @@ -9,7 +9,7 @@ Arduino_XCA9554SWSPI *expander = new Arduino_XCA9554SWSPI( PCA_TFT_RESET, PCA_TFT_CS, PCA_TFT_SCK, PCA_TFT_MOSI, &Wire, 0x3F); - + Arduino_ESP32RGBPanel *rgbpanel = new Arduino_ESP32RGBPanel( TFT_DE, TFT_VSYNC, TFT_HSYNC, TFT_PCLK, TFT_R1, TFT_R2, TFT_R3, TFT_R4, TFT_R5, @@ -33,6 +33,10 @@ Arduino_RGB_Display *gfx = new Arduino_RGB_Display( // 480 /* width */, 480 /* height */, rgbpanel, 0 /* rotation */, true /* auto_flush */, // expander, GFX_NOT_DEFINED /* RST */, tl034wvs05_b1477a_init_operations, sizeof(tl034wvs05_b1477a_init_operations)); +/* 4.0" 480x480 square */ +// 480 /* width */, 480 /* height */, rgbpanel, 0 /* rotation */, true /* auto_flush */, +// expander, GFX_NOT_DEFINED /* RST */, tl040wvs03_init_operations, sizeof(tl040wvs03_init_operations)); + // 3.2" 320x820 rectangle bar display // 320 /* width */, 820 /* height */, rgbpanel, 0 /* rotation */, true /* auto_flush */, // expander, GFX_NOT_DEFINED /* RST */, tl032fwv01_init_operations, sizeof(tl032fwv01_init_operations)); @@ -68,10 +72,10 @@ bool touchOK = false; // we will check if the touchscreen exists bool isFocalTouch = false; void setup(void) -{ +{ Serial.begin(115200); //while (!Serial) delay(100); - + #ifdef GFX_EXTRA_PRE_INIT GFX_EXTRA_PRE_INIT(); #endif @@ -79,7 +83,7 @@ void setup(void) Serial.println("Beginning"); // Init Display - Wire.setClock(1000000); // speed up I2C + Wire.setClock(1000000); // speed up I2C if (!gfx->begin()) { Serial.println("gfx->begin() failed!"); } @@ -128,7 +132,7 @@ void loop() gfx->fillRect(p.x, p.y, 5, 5, WHITE); } } - + // use the buttons to turn off if (! expander->digitalRead(PCA_BUTTON_DOWN)) { expander->digitalWrite(PCA_TFT_BACKLIGHT, LOW); diff --git a/Faderwave_Synth/code.py b/Faderwave_Synth/code.py index 5f4579e4f..08fb4f0dc 100644 --- a/Faderwave_Synth/code.py +++ b/Faderwave_Synth/code.py @@ -13,6 +13,7 @@ import rotaryio from digitalio import DigitalInOut, Pull import displayio +import fourwire from adafruit_display_text import label from adafruit_display_shapes.rect import Rect import terminalio @@ -88,7 +89,7 @@ OLED_CS = board.D11 spi = board.SPI() -display_bus = displayio.FourWire(spi, command=OLED_DC, chip_select=OLED_CS, +display_bus = fourwire.FourWire(spi, command=OLED_DC, chip_select=OLED_CS, reset=OLED_RST, baudrate=30_000_000) display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=64) diff --git a/Feather_ESP32-S2_TFT_Azure/code.py b/Feather_ESP32-S2_TFT_Azure/code.py index 64c3f1135..2571d3d10 100644 --- a/Feather_ESP32-S2_TFT_Azure/code.py +++ b/Feather_ESP32-S2_TFT_Azure/code.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries # SPDX-License-Identifier: MIT +from os import getenv import time import json import supervisor @@ -17,20 +18,24 @@ from adafruit_display_text import bitmap_label, wrap_text_to_lines from adafruit_bitmap_font import bitmap_font from adafruit_azureiot import IoTCentralDevice -import adafruit_bme680 import adafruit_max1704x +import adafruit_bme680 #from adafruit_lc709203f import LC709203F, PackSize +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) print("Connecting to WiFi...") -wifi.radio.connect(secrets["ssid"], secrets["password"]) +wifi.radio.connect(ssid, password) print("Connected to WiFi!") @@ -75,7 +80,7 @@ # # Next create a device using the device template, and select Connect to get the # device connection details. -# Add the connection details to your secrets.py file, using the following values: +# Add the connection details to your settings.toml file, using the following values: # # 'id_scope' - the devices ID scope # 'device_id' - the devices device id @@ -100,7 +105,7 @@ esp = None pool = socketpool.SocketPool(wifi.radio) device = IoTCentralDevice( - pool, ssl_context, secrets["id_scope"], secrets["device_id"], secrets["device_primary_key"] + pool, ssl_context, getenv("id_scope"), getenv("device_id"), getenv("device_primary_key") ) print("Connecting to Azure IoT Central...") diff --git a/Feather_Freezer_Alarm/code.py b/Feather_Freezer_Alarm/code.py index 013fbceb7..733999665 100644 --- a/Feather_Freezer_Alarm/code.py +++ b/Feather_Freezer_Alarm/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import ssl import microcontroller @@ -38,23 +39,26 @@ pir.direction = digitalio.Direction.INPUT motion = Debouncer(pir) -try: - from secrets import secrets -except ImportError: - print("WiFi and Adafruit IO credentials are kept in secrets.py - please add them there!") - raise +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") -# Add your Adafruit IO Username and Key to secrets.py -# (visit io.adafruit.com if you need to create an account, -# or if you need to obtain your Adafruit IO key.) -aio_username = secrets["aio_username"] -aio_key = secrets["aio_key"] +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) # WiFi try: - print("Connecting to %s" % secrets["ssid"]) - wifi.radio.connect(secrets["ssid"], secrets["password"]) - print("Connected to %s!" % secrets["ssid"]) + print(f"Connecting to {ssid}") + wifi.radio.connect(ssid, password) + print(f"Connected to {ssid}!") # Wi-Fi connectivity fails with error messages, not specific errors, so this except is broad. except Exception as e: # pylint: disable=broad-except print("Failed to connect to WiFi. Error:", e, "\nBoard will restart in 5 seconds.") @@ -67,8 +71,8 @@ # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", - username=secrets["aio_username"], - password=secrets["aio_key"], + username=aio_username, + password=aio_key, socket_pool=pool, ssl_context=ssl.create_default_context(), ) diff --git a/Feather_RP2040_ThinkInk_Examples/CircuitPython_ACeP_Example/code.py b/Feather_RP2040_ThinkInk_Examples/CircuitPython_ACeP_Example/code.py index 91f3be282..dd5e1e53a 100644 --- a/Feather_RP2040_ThinkInk_Examples/CircuitPython_ACeP_Example/code.py +++ b/Feather_RP2040_ThinkInk_Examples/CircuitPython_ACeP_Example/code.py @@ -8,6 +8,7 @@ import board import displayio +import fourwire import busio import adafruit_spd1656 @@ -19,7 +20,7 @@ epd_dc = board.EPD_DC epd_reset = board.EPD_RESET epd_busy = board.EPD_BUSY -display_bus = displayio.FourWire( +display_bus = fourwire.FourWire( spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=1000000 ) @@ -29,16 +30,13 @@ g = displayio.Group() -fn = "/display-ruler-720p.bmp" +pic = displayio.OnDiskBitmap("/display-ruler-720p.bmp") +t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) +g.append(t) -with open(fn, "rb") as f: - pic = displayio.OnDiskBitmap(f) - t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) - g.append(t) +display.root_group = g - display.root_group = g - - display.refresh() +display.refresh() while True: pass diff --git a/Feather_RP2040_ThinkInk_Examples/CircuitPython_Tri-Color_Example/code.py b/Feather_RP2040_ThinkInk_Examples/CircuitPython_Tri-Color_Example/code.py index f415eea80..074839f33 100644 --- a/Feather_RP2040_ThinkInk_Examples/CircuitPython_Tri-Color_Example/code.py +++ b/Feather_RP2040_ThinkInk_Examples/CircuitPython_Tri-Color_Example/code.py @@ -9,6 +9,7 @@ import time import board import displayio +import fourwire import busio import adafruit_ssd1680 @@ -20,7 +21,7 @@ epd_dc = board.EPD_DC epd_reset = board.EPD_RESET epd_busy = board.EPD_BUSY -display_bus = displayio.FourWire( +display_bus = fourwire.FourWire( spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=1000000 ) time.sleep(1) @@ -36,20 +37,17 @@ g = displayio.Group() -with open("/display-ruler.bmp", "rb") as f: - pic = displayio.OnDiskBitmap(f) - t = displayio.TileGrid( - pic, pixel_shader=getattr(pic, "pixel_shader", displayio.ColorConverter()) - ) +pic = displayio.OnDiskBitmap("/display-ruler.bmp") +t = displayio.TileGrid(pic, pixel_shader=pic.pixel_shader) - g.append(t) +g.append(t) - display.root_group = g +display.root_group = g - display.refresh() +display.refresh() - print("refreshed") +print("refreshed") while True: pass diff --git a/Feather_RP2040_USB_Host/CircuitPython_GamePad_ReadData/code.py b/Feather_RP2040_USB_Host/CircuitPython_GamePad_ReadData/code.py new file mode 100644 index 000000000..cfb34b3bb --- /dev/null +++ b/Feather_RP2040_USB_Host/CircuitPython_GamePad_ReadData/code.py @@ -0,0 +1,138 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import array +import time +import usb.core +import adafruit_usb_host_descriptors + +# Set to true to print detailed information about all devices found +VERBOSE_SCAN = True + +# indexes within the reports to ignore when determining equality. +# some devices send alternating values with each report, this +# allows to ignore those and focus only on bytes that are +# affected by buttons. Value of [19] will ignore data at index 19. +# Check your own output for values that change even when you don't +# do anything on the controller and add their indexes here. +IGNORE_INDEXES = [] + +DIR_IN = 0x80 +controller = None + +if VERBOSE_SCAN: + for device in usb.core.find(find_all=True): + controller = device + print("pid", hex(device.idProduct)) + print("vid", hex(device.idVendor)) + print("man", device.manufacturer) + print("product", device.product) + print("serial", device.serial_number) + print("config[0]:") + config_descriptor = adafruit_usb_host_descriptors.get_configuration_descriptor( + device, 0 + ) + + i = 0 + while i < len(config_descriptor): + descriptor_len = config_descriptor[i] + descriptor_type = config_descriptor[i + 1] + if descriptor_type == adafruit_usb_host_descriptors.DESC_CONFIGURATION: + config_value = config_descriptor[i + 5] + print(f" value {config_value:d}") + elif descriptor_type == adafruit_usb_host_descriptors.DESC_INTERFACE: + interface_number = config_descriptor[i + 2] + interface_class = config_descriptor[i + 5] + interface_subclass = config_descriptor[i + 6] + print(f" interface[{interface_number:d}]") + print( + f" class {interface_class:02x} subclass {interface_subclass:02x}" + ) + elif descriptor_type == adafruit_usb_host_descriptors.DESC_ENDPOINT: + endpoint_address = config_descriptor[i + 2] + if endpoint_address & DIR_IN: + print(f" IN {endpoint_address:02x}") + else: + print(f" OUT {endpoint_address:02x}") + i += descriptor_len + +# get the first device found +device = None +while device is None: + for d in usb.core.find(find_all=True): + device = d + break + time.sleep(0.1) + +# set configuration so we can read data from it +device.set_configuration() +print(f"configuration set for {device.manufacturer}, {device.product}, {device.serial_number}") + +# Test to see if the kernel is using the device and detach it. +if device.is_kernel_driver_active(0): + device.detach_kernel_driver(0) + +# buffer to hold 64 bytes +buf = array.array("B", [0] * 64) + + +def print_array(arr, max_index=None, fmt="hex"): + """ + Print the values of an array + :param arr: The array to print + :param max_index: The maximum index to print. None means print all. + :param fmt: The format to use, either "hex" or "bin" + :return: None + """ + out_str = "" + if max_index is None or max_index >= len(arr): + length = len(arr) + else: + length = max_index + + for _ in range(length): + if fmt == "hex": + out_str += f"{int(arr[_]):02x} " + elif fmt == "bin": + out_str += f"{int(arr[_]):08b} " + print(out_str) + + +def reports_equal(report_a, report_b): + """ + Test if two reports are equal. Accounting for any IGNORE_INDEXES + + :param report_a: First report data + :param report_b: Second report data + :return: True if the reports are equal, otherwise False. + """ + if report_a is None and report_b is not None or \ + report_b is None and report_a is not None: + return False + for _ in range(len(report_a)): + if IGNORE_INDEXES is not None and _ not in IGNORE_INDEXES: + if report_a[_] != report_b[_]: + return False + return True + + +idle_state = None +prev_state = None + +while True: + try: + count = device.read(0x81, buf) + # print(f"read size: {count}") + except usb.core.USBTimeoutError: + continue + + if idle_state is None: + idle_state = buf[:] + print("Idle state:") + print_array(idle_state, max_index=count) + print() + + if not reports_equal(buf, prev_state) and not reports_equal(buf, idle_state): + print_array(buf, max_index=count) + + prev_state = buf[:] diff --git a/Fruit_Jam/286_emulator/dos5_fdd0.img b/Fruit_Jam/286_emulator/dos5_fdd0.img new file mode 100644 index 000000000..f36752b00 Binary files /dev/null and b/Fruit_Jam/286_emulator/dos5_fdd0.img differ diff --git a/Fruit_Jam/286_emulator/dos6-fdd0.img b/Fruit_Jam/286_emulator/dos6-fdd0.img new file mode 100644 index 000000000..1d7b67535 Binary files /dev/null and b/Fruit_Jam/286_emulator/dos6-fdd0.img differ diff --git a/Fruit_Jam/286_emulator/joust_mario_fdd1.img b/Fruit_Jam/286_emulator/joust_mario_fdd1.img new file mode 100644 index 000000000..81622032f Binary files /dev/null and b/Fruit_Jam/286_emulator/joust_mario_fdd1.img differ diff --git a/Fruit_Jam/CircuitPython_DVI_Video/ANSI_color_terminal.py b/Fruit_Jam/CircuitPython_DVI_Video/ANSI_color_terminal.py new file mode 100644 index 000000000..3ec3cf6f5 --- /dev/null +++ b/Fruit_Jam/CircuitPython_DVI_Video/ANSI_color_terminal.py @@ -0,0 +1,152 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Tim C for Adafruit Industries +# SPDX-FileCopyrightText: Copyright (c) 2025 Anne Barela for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# +# Make an adafruit_color_terminal terminal with ASCI escape character support +# This uses a Code Page 437 LVGL font to draw a box also +# +import gc +import supervisor +import displayio +from lvfontio import OnDiskFont +from adafruit_fruitjam.peripherals import request_display_config +from adafruit_color_terminal import ColorTerminal + +# Routine goto - position output to row, column +def goto(row, column): + terminal.write(f"\x1B[{int(row)};{int(column)}H") + +# Routine cls - clear screen +def cls(): + terminal.write("\x1B[2J") + goto(1, 1) + +def draw_box(width, height, x, y, color_box): + top_left = '\xDA' + horizontal = '\xC4' + top_right = '\xBF' + vertical = '\xB3' + bottom_left = '\xC0' + bottom_right = '\xD9' + + if width < 3 or height < 3: + return + + # Top line + out_char(top_left + horizontal*(width - 2) + top_right, x, y, color_box) + + # Middle lines + for i in range(1, height - 1): + out_char(vertical + ' '*(width - 2) + vertical, x+i, y, color_box) + + # Bottom line + out_char(bottom_left + horizontal*(width - 2) + bottom_right, x+height-1, + y, color_box) + +def out_char(value, row, column, color): + goto(row, column) + terminal.write(f"\033[3{color}m"+value) + +def set_color(palette_index): + """Set FOREGROUND color only""" + if not (0 <= palette_index <= 7): # pylint: disable=superfluous-parens + raise ValueError("Palette index must be between 0 and 7") + terminal.write(f"\033[3{palette_index}m") + +def set_bgcolor(palette_index): + """Set BACKGROUND color only""" + if not (0 <= palette_index <= 7): # pylint: disable=superfluous-parens + raise ValueError("Palette index must be between 0 and 7") + terminal.write(f"\033[4{palette_index}m") + +def reset_ansi(): + """Reset to default colors (usually white on black)""" + terminal.write("\033[0m") + +def set_colors(fg_color=None, bg_color=None): + """Set both foreground and background colors""" + if fg_color is not None: + set_color(fg_color) + if bg_color is not None: + set_bgcolor(bg_color) + +# Use the easy library call to set the resolution +request_display_config(640, 480) + +print(f"\nFree before display init: {gc.mem_free()}") + +# Initialize display +main_group = displayio.Group() +display = supervisor.runtime.display +display.root_group = main_group + +print(f"free: {gc.mem_free()}") + +colors = 8 + +red = 0xff0000 +yellow = 0xcccc00 +orange = 0xff5500 +blue = 0x0000ff +pink = 0xff00ff +purple = 0x5500ff +white = 0xffffff +green = 0x00ff00 +aqua = 0x125690 +black = 0x000000 + +terminal_palette = displayio.Palette(colors) +terminal_palette[0] = black +terminal_palette[1] = red +terminal_palette[2] = green +terminal_palette[3] = yellow +terminal_palette[4] = blue +terminal_palette[5] = purple +terminal_palette[6] = aqua +terminal_palette[7] = white + +font = OnDiskFont("fonts/cp437_16h.bin") # LVGL .bin font + +char_size = font.get_bounding_box() +print(f"Character size: {char_size}") +print(f"font.bitmap info: {font.bitmap.width}, {font.bitmap.height}") + +screen_size = (display.width // char_size[0], display.height // char_size[1]) +print(f"Screen size: {screen_size}") +print(f"Screen depth: {display.framebuffer.color_depth} bits") + +terminal = ColorTerminal(font, screen_size[0], screen_size[1]) +main_group.append(terminal.tilegrid) +print("Created Color Terminal") + +# Clear screen and set initial colors properly +cls() + +# Test individual colored text - each should stay its own color +out_char("Red (1,1)", 1, 1, 1) # Red text, then reset +out_char("Green (10,1)", 10, 1, 2) # Green text, then reset +out_char("Blue (1,30)", 1, 30, 4) # Blue text, then reset +out_char("Yellow (10,30)", 10, 30, 3) # Yellow text, then reset +out_char("Magenta (15,1)", 15, 1, 5) # Magenta text, then reset +out_char("Cyan (15,30)", 15, 30, 6) # Cyan text, then reset + +# Draw box in a specific color (should be yellow) +draw_box(10, 8, 6, 17, 3) + +# Write some normal text (should be in default color) +goto(20, 5) +terminal.write("This should be default color") + +# Write more colored text using out_char +out_char("Isolated Red", 22, 5, 1) +out_char("Isolated Green", 23, 5, 2) +out_char("Isolated Blue", 24, 5, 4) + +# Final text should be in default color +goto(26, 5) +terminal.write("This should also be default color") + +print("Done - all colors should be visible simultaneously") +while True: + pass diff --git a/Fruit_Jam/CircuitPython_DVI_Video/DVI_Framebuffer.py b/Fruit_Jam/CircuitPython_DVI_Video/DVI_Framebuffer.py new file mode 100644 index 000000000..99abd96b3 --- /dev/null +++ b/Fruit_Jam/CircuitPython_DVI_Video/DVI_Framebuffer.py @@ -0,0 +1,56 @@ +# SPDX-FileCopyrightText: 2025 Anne Barela for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# +# Set up a DVI display using Framebufferio and displayio +# Text and drawing is all done vis displayio +# +import sys +import microcontroller +import board +import displayio +import terminalio +import framebufferio +import picodvi +from adafruit_display_text import label + +# Initialize displayio +displayio.release_displays() +try: + fb = picodvi.Framebuffer(640, 480, clk_dp=board.CKP, clk_dn=board.CKN, + red_dp=board.D0P, red_dn=board.D0N, + green_dp=board.D1P, green_dn=board.D1N, + blue_dp=board.D2P, blue_dn=board.D2N, + color_depth=4) +except ValueError as e: + print("Framebuffer error: ", e) + # Per picodvi/Framebuffer_RP2350.c only 320x240 at 8 & 16 bits work + # Show error + sys.exit(e) + +display = framebufferio.FramebufferDisplay(fb) +display_group = displayio.Group() + +display.root_group = display_group + +# Create labels +# pylint: disable=line-too-long +text = " 1 2 3 4 5 6 7 8 9 0 1 2" +text_area = label.Label(terminalio.FONT, text=text, color=0xFFFFFF) +text_area.x = 0 +text_area.y = 5 +display_group.append(text_area) +# pylint: disable=line-too-long +text = "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +text_area = label.Label(terminalio.FONT, text=text, color=0xFFFFFF) +text_area.x = 0 +text_area.y = 15 +display_group.append(text_area) +text = f"Microcontroller speed: {microcontroller.cpu.frequency}" +text_area = label.Label(terminalio.FONT, text=text, color=0xFFFFFF) +text_area.x = 5 +text_area.y = 40 +display_group.append(text_area) + +while True: + pass diff --git a/Fruit_Jam/CircuitPython_DVI_Video/Display_BDF_PCF_Font.py b/Fruit_Jam/CircuitPython_DVI_Video/Display_BDF_PCF_Font.py new file mode 100644 index 000000000..222c47182 --- /dev/null +++ b/Fruit_Jam/CircuitPython_DVI_Video/Display_BDF_PCF_Font.py @@ -0,0 +1,110 @@ +# SPDX-FileCopyrightText: 2025 Anne Barela for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# +# Take a BDF or PCF font file and display it on a CircuitPython +# HDMI/DVI display in 320x200 resolution. "." is used for unknown characters + +import gc +import displayio +import supervisor +from adafruit_bitmap_font import bitmap_font +from adafruit_display_text import label +from adafruit_fruitjam.peripherals import request_display_config + +# Use the easy library call to set the resolution +request_display_config(320, 240) + +# Initialize display +display = supervisor.runtime.display +main_group = displayio.Group() +display.root_group = main_group + +# Use Labels to display characters that exist in font +font_file = "fonts/cp437-8x12a.pcf" +font = bitmap_font.load_font(font_file) # Use font = terminalio.FONT for built-in +char_width = 8 # font character width +char_height = 12 # font character height +chars_per_line = 32 # Fixed at 32 characters per line +line_number_width = 35 # Space for line numbers like "000: " + +displayed_count = 0 +skipped_count = 0 + +current_x = line_number_width # Start after line number space +current_y = char_height +current_line_start = 0 + +# Add first line number +line_label = label.Label( + font, + text=f"{current_line_start:03d}: ", + color=0xFFFFFF, + x=0, + y=current_y +) +main_group.append(line_label) + +# Try all characters from 0-255 and display ones that exist +for char_code in range(256): + try: + # Check if we need to wrap to next line + if (char_code > 0) and (char_code % chars_per_line == 0): + current_x = line_number_width # Reset to after line number + current_y += char_height + 2 # Add some line spacing + current_line_start = char_code + + # Stop if we run out of vertical space + if current_y + char_height > display.height: + print(f"Display full, stopped at {char_code}") + break + + # Add line number for this new line + line_label = label.Label( + font, + text=f"{current_line_start:03d}: ", + color=0xFFFFFF, + x=0, + y=current_y + ) + main_group.append(line_label) + + # Check if glyph exists + glyph = font.get_glyph(char_code) + + if glyph is None: + # No glyph available - display a period instead + display_char = "." + skipped_count += 1 + else: + # Glyph exists - display the actual character + display_char = chr(char_code) + + # Create label for this character (or replacement) + char_label = label.Label( + font, + text=display_char, + color=0xFFFFFF, + x=current_x, + y=current_y + ) + + main_group.append(char_label) + current_x += char_width + displayed_count += 1 + + except (MemoryError, ValueError) as e: + print(f"Memory limit reached at char {char_code}") + break + + # Garbage collection every 16 characters + if char_code % 16 == 0: + gc.collect() + +print(f"Found {displayed_count - skipped_count} chars with glyphs") +print(f"{skipped_count} missing chars -> periods") +print(f"Free memory: {gc.mem_free()} bytes") + +# Keep display active +while True: + pass diff --git a/Fruit_Jam/CircuitPython_DVI_Video/Display_LVGL_Font.py b/Fruit_Jam/CircuitPython_DVI_Video/Display_LVGL_Font.py new file mode 100644 index 000000000..7acbc4a32 --- /dev/null +++ b/Fruit_Jam/CircuitPython_DVI_Video/Display_LVGL_Font.py @@ -0,0 +1,163 @@ +# SPDX-FileCopyrightText: 2025 Anne Barela for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# +# Display an LVGL (.bin) font on a CircuitPython board and +# 640x480 DVI display. Unknown characters will be "." +# +# pylint: disable=broad-except, bare-except + +import gc +import displayio +import supervisor +from adafruit_bitmap_font import bitmap_font +from adafruit_display_text import label +from adafruit_fruitjam.peripherals import request_display_config + +# Use the easy library call to set the resolution +request_display_config(640, 480) + +# Initialize display +display = supervisor.runtime.display +main_group = displayio.Group() +display.root_group = main_group + +print(f"Initial memory: {gc.mem_free()}") + +# Font loading with error handling and diagnostics +font_file = "fonts/CP437_16h.bin" +try: + font = bitmap_font.load_font(font_file) # pylint: disable=redefined-outer-name + print(f"Font loaded: {font_file}") + print(f"Memory after font load: {gc.mem_free()}") + + # Diagnostic: Check font properties + try: + bbox = font.get_bounding_box() + print(f"Font bounding box: {bbox}") + + # Test a few common characters + test_chars = [32, 65, 97] # space, 'A', 'a' + for char_code in test_chars: + glyph = font.get_glyph(char_code) + if glyph: + print(f"Char {char_code} ('{chr(char_code)}'): OK") + else: + print(f"Char {char_code} ('{chr(char_code)}'): Missing") + + except Exception as e: + print(f"Error checking font properties: {e}") + +except Exception as e: + print(f"Error loading font {font_file}: {e}") + # Fallback to terminalio font + import terminalio + font = terminalio.FONT + print("Using fallback terminalio.FONT") + +# Get actual font dimensions +try: + font_bbox = font.get_bounding_box() + char_width = font_bbox[0] + char_height = font_bbox[1] + print(f"Actual font size: {char_width}x{char_height}") +except: + char_width = 9 # fallback + char_height = 16 # fallback + print(f"Using fallback font size: {char_width}x{char_height}") + +chars_per_line = 32 # Fixed at 32 characters per line +line_number_width = 5 * char_width # Space for "000: " (5 characters) + +displayed_count = 0 +skipped_count = 0 +current_x = line_number_width # Start after line number space +current_y = char_height +current_line_start = 0 + +def create_char_label(thefont, ch, x, y): + """Helper function to create character labels with error handling""" + try: + return label.Label(thefont, text=ch, color=0xFFFFFF, x=x, y=y) + except Exception as e: + print(f"Error creating label for '{ch}': {e}") + return None + +# Add first line number +text = f"{current_line_start:03d}: " +print(f"Creating line number: '{text}'") + +for i, char in enumerate(text): + char_label = create_char_label(font, char, i * char_width, current_y) + if char_label: + main_group.append(char_label) + +print(f"Memory after first line number: {gc.mem_free()}") + +# Try all characters from 0-255 and display ones that exist +for char_code in range(256): + try: + # Check if we need to wrap to next line + if (char_code > 0) and (char_code % chars_per_line == 0): + current_x = line_number_width # Reset to after line number + current_y += char_height + 4 # Add some line spacing + current_line_start = char_code + + # Stop if we run out of vertical space + if current_y + char_height > display.height: + print(f"Display full, stopped at character {char_code}") + break + + # Add line number for this new line + text = f"{current_line_start:03d}: " + for i, char in enumerate(text): + char_label = create_char_label(font, char, i * char_width, current_y) + if char_label: + main_group.append(char_label) + + # Check if glyph exists + glyph = font.get_glyph(char_code) + + if glyph is None: + # No glyph available - display a period instead + display_char = "." + skipped_count += 1 + else: + # Glyph exists - display the actual character + display_char = chr(char_code) + + # Create label for this character (or replacement) + char_label = create_char_label(font, display_char, current_x, current_y) + if char_label: + main_group.append(char_label) + + current_x += char_width + displayed_count += 1 + + except (MemoryError, ValueError) as e: + print(f"Memory/Value error at character {char_code}: {e}") + break + except Exception as e: + print(f"Unexpected error at character {char_code}: {e}") + # Continue with next character + current_x += char_width + displayed_count += 1 + + # More frequent garbage collection + if char_code % 8 == 0: + gc.collect() + + # Progress indicator for debugging + if char_code % 32 == 0: + msg = f"Processed up to character {char_code}, memory: {gc.mem_free()}" # pylint: disable=f-string-without-interpolation + print(msg) + +print("\nCompleted character display:") +print(f"Found {displayed_count - skipped_count} characters with glyphs") +print(f"{skipped_count} missing characters displayed as periods") +print(f"Total labels created: {len(main_group)}") +print(f"Final free memory: {gc.mem_free()} bytes") + +# Keep display active +while True: + pass diff --git a/Fruit_Jam/CircuitPython_DVI_Video/Find_EDID_Values.py b/Fruit_Jam/CircuitPython_DVI_Video/Find_EDID_Values.py new file mode 100644 index 000000000..731ec9505 --- /dev/null +++ b/Fruit_Jam/CircuitPython_DVI_Video/Find_EDID_Values.py @@ -0,0 +1,244 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Anne Barela for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# +# Display the EDID monitor resolutions for a connected HDMI/DVI display +# +import sys +import board +import busio + +def parse_established_timings(edid): + # pylint: disable=redefined-outer-name + # pylint: disable=too-many-branches + """Parse established timings from EDID bytes 35-37""" + modes = [] + + # Byte 35 (established timings I) + if edid[35] & 0x80: + modes.append("720x400 @70Hz") + if edid[35] & 0x40: + modes.append("720x400 @88Hz") + if edid[35] & 0x20: + modes.append("640x480 @60Hz") + if edid[35] & 0x10: + modes.append("640x480 @67Hz") + if edid[35] & 0x08: + modes.append("640x480 @72Hz") + if edid[35] & 0x04: + modes.append("640x480 @75Hz") + if edid[35] & 0x02: + modes.append("800x600 @56Hz") + if edid[35] & 0x01: + modes.append("800x600 @60Hz") + + # Byte 36 (established timings II) + if edid[36] & 0x80: + modes.append("800x600 @72Hz") + if edid[36] & 0x40: + modes.append("800x600 @75Hz") + if edid[36] & 0x20: + modes.append("832x624 @75Hz") + if edid[36] & 0x10: + modes.append("1024x768 @87Hz") + if edid[36] & 0x08: + modes.append("1024x768 @60Hz") + if edid[36] & 0x04: + modes.append("1024x768 @70Hz") + if edid[36] & 0x02: + modes.append("1024x768 @75Hz") + if edid[36] & 0x01: + modes.append("1280x1024 @75Hz") + + # Byte 37 (manufacturer timings) + if edid[37] & 0x80: + modes.append("1152x870 @75Hz") + + return modes + +def parse_standard_timings(edid): + # pylint: disable=redefined-outer-name + """Parse standard timings from EDID bytes 38-53""" + modes = [] + + for i in range(38, 54, 2): # 8 standard timing descriptors, 2 bytes each + if edid[i] == 0x01 and edid[i+1] == 0x01: + continue # Unused timing + + if edid[i] == 0x00: + continue # Invalid timing + + # Calculate horizontal resolution + h_res = (edid[i] + 31) * 8 + + # Calculate aspect ratio and vertical resolution + aspect_ratio = (edid[i+1] & 0xC0) >> 6 + refresh_rate = (edid[i+1] & 0x3F) + 60 + + if aspect_ratio == 0: # 16:10 + aspect = "16:10" + v_res = (h_res * 10) // 16 + elif aspect_ratio == 1: # 4:3 + aspect = "4:3" + v_res = (h_res * 3) // 4 + elif aspect_ratio == 2: # 5:4 + aspect = "5:4" + v_res = (h_res * 4) // 5 + else: # aspect_ratio == 3, 16:9 + aspect = "16:9" + v_res = (h_res * 9) // 16 + + modes.append(f"{h_res}x{v_res} @{refresh_rate}Hz, Aspect: {aspect}") + + return modes + +def parse_detailed_timings(edid): + # pylint: disable=redefined-outer-name + # pylint: disable=unused-variable + # pylint: disable=too-many-locals + + """Parse detailed timing descriptors from EDID bytes 54-125""" + modes = [] + + for i in range(54, 126, 18): # 4 detailed timing descriptors, 18 bytes each + # Check if this is a timing descriptor (pixel clock != 0) + pixel_clock = edid[i] | (edid[i+1] << 8) + if pixel_clock == 0: + continue # Not a timing descriptor + + # Parse horizontal resolution + h_active_low = edid[i+2] + h_active_high = (edid[i+4] & 0xF0) >> 4 + h_active = h_active_low | (h_active_high << 8) + + # Parse vertical resolution + v_active_low = edid[i+5] + v_active_high = (edid[i+7] & 0xF0) >> 4 + v_active = v_active_low | (v_active_high << 8) + + # Parse horizontal sync + h_sync_offset_low = edid[i+8] + h_sync_width_low = edid[i+9] + h_sync_high = (edid[i+11] & 0xC0) >> 6 + h_sync_offset = h_sync_offset_low | ((h_sync_high & 0x3) << 8) + h_sync_width = h_sync_width_low | ((h_sync_high & 0xC) << 6) + + # Parse vertical sync + v_sync_offset_low = (edid[i+10] & 0xF0) >> 4 + v_sync_width_low = edid[i+10] & 0x0F + v_sync_high = (edid[i+11] & 0x0C) >> 2 + v_sync_offset = v_sync_offset_low | ((v_sync_high & 0x3) << 4) + v_sync_width = v_sync_width_low | ((v_sync_high & 0xC) << 2) + + # Calculate refresh rate (approximate) + h_blank_low = edid[i+3] + h_blank_high = edid[i+4] & 0x0F + h_blank = h_blank_low | (h_blank_high << 8) + h_total = h_active + h_blank + + v_blank_low = edid[i+6] + v_blank_high = edid[i+7] & 0x0F + v_blank = v_blank_low | (v_blank_high << 8) + v_total = v_active + v_blank + + if h_total > 0 and v_total > 0: + refresh_rate = (pixel_clock * 10000) // (h_total * v_total) + modes.append(f"{h_active}x{v_active} @{refresh_rate}Hz") + + return modes + +# Main EDID reading code +i2c = busio.I2C(board.SCL, board.SDA) +if not i2c: + print("Board doesn't have I2C") + sys.exit(1) +if not i2c.try_lock(): + print("Cannot lock I2C") + sys.exit(1) + +print("\nI2C Present") + +devices = i2c.scan() +if not 0x50 in devices: + print("No device found at EDID address 0x50, is the monitor plugged in " + + "& board power cycled?") + sys.exit(1) + +print("Device 0x50 found!") +device = 0x50 +edid = bytearray(128) +out = bytearray([0]) +i2c.writeto_then_readfrom(device, out, edid) +# pylint: disable=too-many-boolean-expressions +if edid[0] != 0x00 or edid[1] != 0xFF or edid[2] != 0xFF or \ + edid[3] != 0xFF or edid[4] != 0xFF or edid[5] != 0xFF or \ + edid[6] != 0xFF or edid[7] != 0x00: + print("EDID signature not recognized") + sys.exit(1) + +print("Valid EDID signature!") + +# Verify checksum +checksum = sum(edid) & 0xFF +if checksum != 0: + print("Bad EDID checksum detected") + sys.exit(1) + +print("Good EDID checksum!") + +# Parse all supported modes +supported_modes = [] + +# Get established timings +established_modes = parse_established_timings(edid) +supported_modes.extend(established_modes) + +# Get standard timings +standard_modes = parse_standard_timings(edid) +supported_modes.extend(standard_modes) + +# Get detailed timings +detailed_modes = parse_detailed_timings(edid) +supported_modes.extend(detailed_modes) + +# Remove duplicates while preserving order +unique_modes = [] +for mode in supported_modes: + if mode not in unique_modes: + unique_modes.append(mode) + +# Display results +print(f"\nSupported Display Modes ({len(unique_modes)} found):") +print("=" * 50) +for mode in unique_modes: + print(f" {mode}") + +# Original default resolution logic +established_timings = edid[35] +if (established_timings & 0xa0) == 0: + print("\nWarning: 720x400@70Hz and 640x480@60Hz not supported") + default_width = 640 + default_height = 480 +else: + offset = 54 + preferred_pixel_clock = edid[offset] | (edid[offset + 1] << 8) + if preferred_pixel_clock != 0: + preferred_width = ((edid[offset + 4] & 0xf0) << 4) | edid[offset + 2] + preferred_height = ((edid[offset + 7] & 0xf0) << 4) | edid[offset + 5] + if (established_timings & 0x80) != 0 and \ + preferred_width % 1920 == 0 and \ + preferred_height % 1080 == 0: + default_width = 720 + default_height = 400 + else: + default_width = 640 + default_height = 480 + else: + default_width = 640 + default_height = 480 + +print(f"\nDefault resolution: {default_width}x{default_height}") +print(f"Preferred resolution: {preferred_width}x{preferred_height}") + +i2c.unlock() +print("\nDone!") diff --git a/Fruit_Jam/CircuitPython_DVI_Video/LVGL_Font_Terminal.py b/Fruit_Jam/CircuitPython_DVI_Video/LVGL_Font_Terminal.py new file mode 100644 index 000000000..4e4815e42 --- /dev/null +++ b/Fruit_Jam/CircuitPython_DVI_Video/LVGL_Font_Terminal.py @@ -0,0 +1,57 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Tim C for Adafruit Industries +# SPDX-FileCopyrightText: Copyright (c) 2025 Anne Barela for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# +# Make a simple terminalio.Terminal using an LVGL .bin font +# Shows use of required OnDiskFont function +# +import gc +from terminalio import Terminal +import displayio +from lvfontio import OnDiskFont +from adafruit_fruitjam.peripherals import request_display_config +import supervisor + +# Use the easy library call to set the resolution +request_display_config(640, 480) + +print(f"\nfree: {gc.mem_free()}") + +# Initialize display + +main_group = displayio.Group() +display = supervisor.runtime.display +display.root_group = main_group + +print(f"free: {gc.mem_free()}") + +font = OnDiskFont("fonts/cp437_16h.bin") # LVGL .bin font + +char_size = font.get_bounding_box() +print(f"Character size: {char_size}") +screen_size = (display.width // char_size[0], display.height // char_size[1]) +print(f"Screen size: {screen_size}") + +terminal_palette = displayio.Palette(2) +terminal_palette[0] = 0x000000 +terminal_palette[1] = 0xFFFFFF + +print(f"free: {gc.mem_free()}") +terminal_area = displayio.TileGrid( + bitmap=font.bitmap, + width=screen_size[0], + height=screen_size[1], + tile_width=char_size[0], + tile_height=char_size[1], + pixel_shader=terminal_palette, +) + +main_group.append(terminal_area) +terminal = Terminal(terminal_area, font) + +message = " Hello World\n This is LVGL text\r\n " +terminal.write(message) + +while True: + pass diff --git a/Fruit_Jam/CircuitPython_DVI_Video/README.md b/Fruit_Jam/CircuitPython_DVI_Video/README.md new file mode 100644 index 000000000..40c3bbdd8 --- /dev/null +++ b/Fruit_Jam/CircuitPython_DVI_Video/README.md @@ -0,0 +1,4 @@ +# CircuitPython DVI + +This repository contains the code in the Adafruit Learning System + Tutorial Using DVI Video in CircuitPython diff --git a/Fruit_Jam/CircuitPython_DVI_Video/Simple_Terminal.py b/Fruit_Jam/CircuitPython_DVI_Video/Simple_Terminal.py new file mode 100644 index 000000000..e8143216c --- /dev/null +++ b/Fruit_Jam/CircuitPython_DVI_Video/Simple_Terminal.py @@ -0,0 +1,57 @@ +# SPDX-FileCopyrightText: Copyright (c) 2021 Randall Bohn (dexter) +# SPDX-FileCopyrightText: Copyright (c) 2021 Anne Barela for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# +# Simple terminalio.Terminal use with the built-in terminalio.FONT +# for a DVI display from an RP2350 HSTX connection +# +# Modeled on https://github.com/circuitpython/CircuitPython_Module_Examples/ +# blob/801475f745fe2a61738f1abed3bd01007118efa3/terminalio/ +# terminalio_terminal_example.py#L5 + +import board +import displayio +import terminalio +import picodvi +import framebufferio + +displayio.release_displays() +# Set up a 320x240x8 bit display space +fb = picodvi.Framebuffer(320, 240, clk_dp=board.CKP, clk_dn=board.CKN, + red_dp=board.D0P, red_dn=board.D0N, + green_dp=board.D1P, green_dn=board.D1N, + blue_dp=board.D2P, blue_dn=board.D2N, + color_depth=8) +display = framebufferio.FramebufferDisplay(fb) + +group = displayio.Group() +display.root_group = group + +palette = displayio.Palette(2) # A simple color palette +palette[0] = 0x220000 # not so dark Black +palette[1] = 0x00FFFF # Cyan + +ROWS = 12 +COLS = 40 + +w, h = terminalio.FONT.get_bounding_box() + +termgrid = displayio.TileGrid( + terminalio.FONT.bitmap, + pixel_shader=palette, + y=20, + width=COLS, + height=ROWS, + tile_width=w, + tile_height=h, +) +group.append(termgrid) +term = terminalio.Terminal(termgrid, terminalio.FONT) + +term.write("Terminal %dx%d:\r\n" % (COLS, ROWS)) +term.write(" %dx%d pixels.\r\n" % (COLS * w, ROWS * h)) +term.write("Both carriage return and line feed \r\n are required.\r\n") + +while True: + pass diff --git a/Fruit_Jam/CircuitPython_DVI_Video/fonts/README.md b/Fruit_Jam/CircuitPython_DVI_Video/fonts/README.md new file mode 100644 index 000000000..93124e09c --- /dev/null +++ b/Fruit_Jam/CircuitPython_DVI_Video/fonts/README.md @@ -0,0 +1 @@ +These are the CP437 fonts used in the guide Using DVI Video in CircuitPython diff --git a/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-6x8.bdf b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-6x8.bdf new file mode 100644 index 000000000..027cd83a7 --- /dev/null +++ b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-6x8.bdf @@ -0,0 +1,3857 @@ +STARTFONT 2.1 +FONT cp437-6x8 +SIZE 8 100 100 +FONTBOUNDINGBOX 6 8 0 0 +STARTPROPERTIES 9 +PIXEL_SIZE 8 +POINT_SIZE 1 +RESOLUTION_X 100 +RESOLUTION_Y 100 +FONT_ASCENT 8 +FONT_DESCENT 0 +AVERAGE_WIDTH 80 +SPACING "C" +DEFAULT_CHAR 32 +ENDPROPERTIES +CHARS 256 +STARTCHAR 0 +ENCODING 0 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 1 +ENCODING 1 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +6c +44 +54 +44 +38 +00 +ENDCHAR +STARTCHAR 2 +ENCODING 2 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +7c +54 +7c +44 +7c +38 +00 +ENDCHAR +STARTCHAR 3 +ENCODING 3 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +28 +7c +7c +7c +38 +10 +00 +ENDCHAR +STARTCHAR 4 +ENCODING 4 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +10 +38 +7c +7c +38 +10 +00 +ENDCHAR +STARTCHAR 5 +ENCODING 5 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +38 +38 +10 +7c +7c +10 +00 +ENDCHAR +STARTCHAR 6 +ENCODING 6 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +10 +38 +7c +7c +10 +38 +00 +ENDCHAR +STARTCHAR 7 +ENCODING 7 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +30 +30 +00 +00 +00 +ENDCHAR +STARTCHAR 8 +ENCODING 8 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +fc +fc +fc +cc +cc +fc +fc +fc +ENDCHAR +STARTCHAR 9 +ENCODING 9 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +78 +48 +48 +78 +00 +00 +ENDCHAR +STARTCHAR 10 +ENCODING 10 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +fc +fc +84 +b4 +b4 +84 +fc +fc +ENDCHAR +STARTCHAR 11 +ENCODING 11 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +1c +0c +34 +48 +48 +30 +00 +ENDCHAR +STARTCHAR 12 +ENCODING 12 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +44 +38 +10 +38 +10 +00 +ENDCHAR +STARTCHAR 13 +ENCODING 13 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +18 +14 +10 +30 +70 +60 +00 +ENDCHAR +STARTCHAR 14 +ENCODING 14 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +0c +34 +2c +34 +2c +6c +60 +00 +ENDCHAR +STARTCHAR 15 +ENCODING 15 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +54 +38 +6c +38 +54 +00 +00 +ENDCHAR +STARTCHAR 16 +ENCODING 16 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +20 +30 +38 +3c +38 +30 +20 +00 +ENDCHAR +STARTCHAR 17 +ENCODING 17 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +08 +18 +38 +78 +38 +18 +08 +00 +ENDCHAR +STARTCHAR 18 +ENCODING 18 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +38 +7c +10 +7c +38 +10 +00 +ENDCHAR +STARTCHAR 19 +ENCODING 19 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +28 +28 +28 +28 +28 +00 +28 +00 +ENDCHAR +STARTCHAR 20 +ENCODING 20 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +3c +54 +54 +34 +14 +14 +14 +00 +ENDCHAR +STARTCHAR 21 +ENCODING 21 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +30 +28 +18 +44 +38 +00 +ENDCHAR +STARTCHAR 22 +ENCODING 22 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +00 +00 +78 +78 +00 +ENDCHAR +STARTCHAR 23 +ENCODING 23 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +38 +7c +10 +7c +38 +10 +38 +ENDCHAR +STARTCHAR 24 +ENCODING 24 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +38 +7c +10 +10 +10 +10 +00 +ENDCHAR +STARTCHAR 25 +ENCODING 25 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +10 +10 +10 +7c +38 +10 +00 +ENDCHAR +STARTCHAR 26 +ENCODING 26 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +10 +18 +7c +18 +10 +00 +00 +ENDCHAR +STARTCHAR 27 +ENCODING 27 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +10 +30 +7c +30 +10 +00 +00 +ENDCHAR +STARTCHAR 28 +ENCODING 28 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +40 +40 +40 +7c +00 +ENDCHAR +STARTCHAR 29 +ENCODING 29 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +28 +28 +7c +28 +28 +00 +00 +ENDCHAR +STARTCHAR 30 +ENCODING 30 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +10 +38 +38 +7c +7c +00 +00 +ENDCHAR +STARTCHAR 31 +ENCODING 31 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +7c +7c +38 +38 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 32 +ENCODING 32 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 33 +ENCODING 33 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +38 +38 +10 +10 +00 +10 +00 +ENDCHAR +STARTCHAR 34 +ENCODING 34 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +6c +6c +48 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 35 +ENCODING 35 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +28 +7c +28 +28 +7c +28 +00 +ENDCHAR +STARTCHAR 36 +ENCODING 36 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +20 +38 +40 +30 +08 +70 +10 +00 +ENDCHAR +STARTCHAR 37 +ENCODING 37 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +64 +64 +08 +10 +20 +4c +4c +00 +ENDCHAR +STARTCHAR 38 +ENCODING 38 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +20 +50 +50 +20 +54 +48 +34 +00 +ENDCHAR +STARTCHAR 39 +ENCODING 39 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +30 +30 +20 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 40 +ENCODING 40 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +20 +20 +20 +20 +20 +10 +00 +ENDCHAR +STARTCHAR 41 +ENCODING 41 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +20 +10 +10 +10 +10 +10 +20 +00 +ENDCHAR +STARTCHAR 42 +ENCODING 42 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +28 +38 +7c +38 +28 +00 +00 +ENDCHAR +STARTCHAR 43 +ENCODING 43 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +10 +10 +7c +10 +10 +00 +00 +ENDCHAR +STARTCHAR 44 +ENCODING 44 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +00 +00 +30 +30 +20 +ENDCHAR +STARTCHAR 45 +ENCODING 45 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +7c +00 +00 +00 +00 +ENDCHAR +STARTCHAR 46 +ENCODING 46 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +00 +00 +30 +30 +00 +ENDCHAR +STARTCHAR 47 +ENCODING 47 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +04 +08 +10 +20 +40 +00 +00 +ENDCHAR +STARTCHAR 48 +ENCODING 48 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +4c +54 +64 +44 +38 +00 +ENDCHAR +STARTCHAR 49 +ENCODING 49 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +30 +10 +10 +10 +10 +38 +00 +ENDCHAR +STARTCHAR 50 +ENCODING 50 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +04 +18 +20 +40 +7c +00 +ENDCHAR +STARTCHAR 51 +ENCODING 51 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +04 +38 +04 +44 +38 +00 +ENDCHAR +STARTCHAR 52 +ENCODING 52 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +08 +18 +28 +48 +7c +08 +08 +00 +ENDCHAR +STARTCHAR 53 +ENCODING 53 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +7c +40 +40 +78 +04 +44 +38 +00 +ENDCHAR +STARTCHAR 54 +ENCODING 54 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +18 +20 +40 +78 +44 +44 +38 +00 +ENDCHAR +STARTCHAR 55 +ENCODING 55 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +7c +04 +08 +10 +20 +20 +20 +00 +ENDCHAR +STARTCHAR 56 +ENCODING 56 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +44 +38 +44 +44 +38 +00 +ENDCHAR +STARTCHAR 57 +ENCODING 57 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +44 +3c +04 +08 +30 +00 +ENDCHAR +STARTCHAR 58 +ENCODING 58 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +30 +30 +00 +30 +30 +00 +ENDCHAR +STARTCHAR 59 +ENCODING 59 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +30 +30 +00 +30 +30 +20 +ENDCHAR +STARTCHAR 60 +ENCODING 60 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +08 +10 +20 +40 +20 +10 +08 +00 +ENDCHAR +STARTCHAR 61 +ENCODING 61 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +7c +00 +00 +7c +00 +00 +ENDCHAR +STARTCHAR 62 +ENCODING 62 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +20 +10 +08 +04 +08 +10 +20 +00 +ENDCHAR +STARTCHAR 63 +ENCODING 63 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +04 +18 +10 +00 +10 +00 +ENDCHAR +STARTCHAR 64 +ENCODING 64 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +5c +54 +5c +40 +38 +00 +ENDCHAR +STARTCHAR 65 +ENCODING 65 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +44 +44 +7c +44 +44 +00 +ENDCHAR +STARTCHAR 66 +ENCODING 66 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +78 +44 +44 +78 +44 +44 +78 +00 +ENDCHAR +STARTCHAR 67 +ENCODING 67 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +40 +40 +40 +44 +38 +00 +ENDCHAR +STARTCHAR 68 +ENCODING 68 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +78 +44 +44 +44 +44 +44 +78 +00 +ENDCHAR +STARTCHAR 69 +ENCODING 69 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +7c +40 +40 +78 +40 +40 +7c +00 +ENDCHAR +STARTCHAR 70 +ENCODING 70 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +7c +40 +40 +78 +40 +40 +40 +00 +ENDCHAR +STARTCHAR 71 +ENCODING 71 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +40 +5c +44 +44 +3c +00 +ENDCHAR +STARTCHAR 72 +ENCODING 72 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +44 +44 +44 +7c +44 +44 +44 +00 +ENDCHAR +STARTCHAR 73 +ENCODING 73 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +10 +10 +10 +10 +10 +38 +00 +ENDCHAR +STARTCHAR 74 +ENCODING 74 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +04 +04 +04 +04 +44 +44 +38 +00 +ENDCHAR +STARTCHAR 75 +ENCODING 75 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +44 +48 +50 +60 +50 +48 +44 +00 +ENDCHAR +STARTCHAR 76 +ENCODING 76 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +40 +40 +40 +40 +40 +40 +7c +00 +ENDCHAR +STARTCHAR 77 +ENCODING 77 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +44 +6c +54 +44 +44 +44 +44 +00 +ENDCHAR +STARTCHAR 78 +ENCODING 78 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +44 +64 +54 +4c +44 +44 +44 +00 +ENDCHAR +STARTCHAR 79 +ENCODING 79 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +44 +44 +44 +44 +38 +00 +ENDCHAR +STARTCHAR 80 +ENCODING 80 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +78 +44 +44 +78 +40 +40 +40 +00 +ENDCHAR +STARTCHAR 81 +ENCODING 81 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +44 +44 +54 +48 +34 +00 +ENDCHAR +STARTCHAR 82 +ENCODING 82 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +78 +44 +44 +78 +48 +44 +44 +00 +ENDCHAR +STARTCHAR 83 +ENCODING 83 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +40 +38 +04 +44 +38 +00 +ENDCHAR +STARTCHAR 84 +ENCODING 84 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +7c +10 +10 +10 +10 +10 +10 +00 +ENDCHAR +STARTCHAR 85 +ENCODING 85 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +44 +44 +44 +44 +44 +44 +38 +00 +ENDCHAR +STARTCHAR 86 +ENCODING 86 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +44 +44 +44 +44 +44 +28 +10 +00 +ENDCHAR +STARTCHAR 87 +ENCODING 87 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +44 +44 +54 +54 +54 +54 +28 +00 +ENDCHAR +STARTCHAR 88 +ENCODING 88 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +44 +44 +28 +10 +28 +44 +44 +00 +ENDCHAR +STARTCHAR 89 +ENCODING 89 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +44 +44 +44 +28 +10 +10 +10 +00 +ENDCHAR +STARTCHAR 90 +ENCODING 90 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +78 +08 +10 +20 +40 +40 +78 +00 +ENDCHAR +STARTCHAR 91 +ENCODING 91 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +20 +20 +20 +20 +20 +38 +00 +ENDCHAR +STARTCHAR 92 +ENCODING 92 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +40 +20 +10 +08 +04 +00 +00 +ENDCHAR +STARTCHAR 93 +ENCODING 93 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +08 +08 +08 +08 +08 +38 +00 +ENDCHAR +STARTCHAR 94 +ENCODING 94 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +28 +44 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 95 +ENCODING 95 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +00 +00 +00 +00 +fc +ENDCHAR +STARTCHAR 96 +ENCODING 96 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +30 +30 +10 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 97 +ENCODING 97 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +38 +04 +3c +44 +3c +00 +ENDCHAR +STARTCHAR 98 +ENCODING 98 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +40 +40 +78 +44 +44 +44 +78 +00 +ENDCHAR +STARTCHAR 99 +ENCODING 99 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +38 +44 +40 +44 +38 +00 +ENDCHAR +STARTCHAR 100 +ENCODING 100 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +04 +04 +3c +44 +44 +44 +3c +00 +ENDCHAR +STARTCHAR 101 +ENCODING 101 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +38 +44 +78 +40 +38 +00 +ENDCHAR +STARTCHAR 102 +ENCODING 102 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +18 +20 +20 +78 +20 +20 +20 +00 +ENDCHAR +STARTCHAR 103 +ENCODING 103 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +3c +44 +44 +3c +04 +38 +ENDCHAR +STARTCHAR 104 +ENCODING 104 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +40 +40 +70 +48 +48 +48 +48 +00 +ENDCHAR +STARTCHAR 105 +ENCODING 105 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +00 +10 +10 +10 +10 +18 +00 +ENDCHAR +STARTCHAR 106 +ENCODING 106 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +08 +00 +18 +08 +08 +08 +48 +30 +ENDCHAR +STARTCHAR 107 +ENCODING 107 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +40 +40 +48 +50 +60 +50 +48 +00 +ENDCHAR +STARTCHAR 108 +ENCODING 108 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +10 +10 +10 +10 +10 +18 +00 +ENDCHAR +STARTCHAR 109 +ENCODING 109 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +68 +54 +54 +44 +44 +00 +ENDCHAR +STARTCHAR 110 +ENCODING 110 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +70 +48 +48 +48 +48 +00 +ENDCHAR +STARTCHAR 111 +ENCODING 111 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +38 +44 +44 +44 +38 +00 +ENDCHAR +STARTCHAR 112 +ENCODING 112 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +78 +44 +44 +44 +78 +40 +ENDCHAR +STARTCHAR 113 +ENCODING 113 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +3c +44 +44 +44 +3c +04 +ENDCHAR +STARTCHAR 114 +ENCODING 114 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +58 +24 +20 +20 +70 +00 +ENDCHAR +STARTCHAR 115 +ENCODING 115 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +38 +40 +38 +04 +38 +00 +ENDCHAR +STARTCHAR 116 +ENCODING 116 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +20 +78 +20 +20 +28 +10 +00 +ENDCHAR +STARTCHAR 117 +ENCODING 117 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +48 +48 +48 +58 +28 +00 +ENDCHAR +STARTCHAR 118 +ENCODING 118 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +44 +44 +44 +28 +10 +00 +ENDCHAR +STARTCHAR 119 +ENCODING 119 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +44 +44 +54 +7c +28 +00 +ENDCHAR +STARTCHAR 120 +ENCODING 120 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +48 +48 +30 +48 +48 +00 +ENDCHAR +STARTCHAR 121 +ENCODING 121 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +48 +48 +48 +38 +10 +60 +ENDCHAR +STARTCHAR 122 +ENCODING 122 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +78 +08 +30 +40 +78 +00 +ENDCHAR +STARTCHAR 123 +ENCODING 123 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +18 +20 +20 +60 +20 +20 +18 +00 +ENDCHAR +STARTCHAR 124 +ENCODING 124 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +10 +10 +00 +10 +10 +10 +00 +ENDCHAR +STARTCHAR 125 +ENCODING 125 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +30 +08 +08 +0c +08 +08 +30 +00 +ENDCHAR +STARTCHAR 126 +ENCODING 126 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +28 +50 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 127 +ENCODING 127 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +38 +6c +44 +44 +7c +00 +00 +ENDCHAR +STARTCHAR 128 +ENCODING 128 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +44 +40 +40 +44 +38 +10 +30 +ENDCHAR +STARTCHAR 129 +ENCODING 129 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +48 +00 +48 +48 +48 +58 +28 +00 +ENDCHAR +STARTCHAR 130 +ENCODING 130 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +0c +00 +38 +44 +78 +40 +38 +00 +ENDCHAR +STARTCHAR 131 +ENCODING 131 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +00 +38 +04 +3c +44 +3c +00 +ENDCHAR +STARTCHAR 132 +ENCODING 132 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +28 +00 +38 +04 +3c +44 +3c +00 +ENDCHAR +STARTCHAR 133 +ENCODING 133 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +30 +00 +38 +04 +3c +44 +3c +00 +ENDCHAR +STARTCHAR 134 +ENCODING 134 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +28 +38 +04 +3c +44 +3c +00 +ENDCHAR +STARTCHAR 135 +ENCODING 135 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +38 +44 +40 +44 +38 +10 +30 +ENDCHAR +STARTCHAR 136 +ENCODING 136 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +00 +38 +44 +78 +40 +38 +00 +ENDCHAR +STARTCHAR 137 +ENCODING 137 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +28 +00 +38 +44 +78 +40 +38 +00 +ENDCHAR +STARTCHAR 138 +ENCODING 138 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +30 +00 +38 +44 +78 +40 +38 +00 +ENDCHAR +STARTCHAR 139 +ENCODING 139 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +28 +00 +10 +10 +10 +10 +18 +00 +ENDCHAR +STARTCHAR 140 +ENCODING 140 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +28 +00 +10 +10 +10 +18 +00 +ENDCHAR +STARTCHAR 141 +ENCODING 141 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +20 +00 +10 +10 +10 +10 +18 +00 +ENDCHAR +STARTCHAR 142 +ENCODING 142 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +28 +00 +10 +28 +44 +7c +44 +00 +ENDCHAR +STARTCHAR 143 +ENCODING 143 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +28 +38 +6c +44 +7c +44 +00 +ENDCHAR +STARTCHAR 144 +ENCODING 144 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +0c +00 +7c +40 +78 +40 +7c +00 +ENDCHAR +STARTCHAR 145 +ENCODING 145 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +78 +14 +7c +50 +3c +00 +ENDCHAR +STARTCHAR 146 +ENCODING 146 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +3c +50 +50 +7c +50 +50 +5c +00 +ENDCHAR +STARTCHAR 147 +ENCODING 147 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +00 +30 +48 +48 +48 +30 +00 +ENDCHAR +STARTCHAR 148 +ENCODING 148 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +28 +00 +30 +48 +48 +48 +30 +00 +ENDCHAR +STARTCHAR 149 +ENCODING 149 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +60 +00 +30 +48 +48 +48 +30 +00 +ENDCHAR +STARTCHAR 150 +ENCODING 150 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +00 +48 +48 +48 +58 +28 +00 +ENDCHAR +STARTCHAR 151 +ENCODING 151 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +60 +00 +48 +48 +48 +58 +28 +00 +ENDCHAR +STARTCHAR 152 +ENCODING 152 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +28 +00 +48 +48 +48 +38 +10 +60 +ENDCHAR +STARTCHAR 153 +ENCODING 153 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +48 +30 +48 +48 +48 +48 +30 +00 +ENDCHAR +STARTCHAR 154 +ENCODING 154 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +28 +00 +48 +48 +48 +48 +30 +00 +ENDCHAR +STARTCHAR 155 +ENCODING 155 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +10 +38 +40 +40 +38 +10 +00 +ENDCHAR +STARTCHAR 156 +ENCODING 156 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +18 +24 +20 +78 +20 +24 +5c +00 +ENDCHAR +STARTCHAR 157 +ENCODING 157 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +44 +28 +10 +7c +10 +7c +10 +00 +ENDCHAR +STARTCHAR 158 +ENCODING 158 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +60 +50 +50 +68 +5c +48 +48 +00 +ENDCHAR +STARTCHAR 159 +ENCODING 159 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +08 +14 +10 +38 +10 +10 +50 +20 +ENDCHAR +STARTCHAR 160 +ENCODING 160 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +18 +00 +38 +04 +3c +44 +3c +00 +ENDCHAR +STARTCHAR 161 +ENCODING 161 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +18 +00 +10 +10 +10 +10 +18 +00 +ENDCHAR +STARTCHAR 162 +ENCODING 162 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +18 +00 +30 +48 +48 +48 +30 +00 +ENDCHAR +STARTCHAR 163 +ENCODING 163 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +18 +00 +48 +48 +48 +58 +28 +00 +ENDCHAR +STARTCHAR 164 +ENCODING 164 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +28 +50 +00 +70 +48 +48 +48 +00 +ENDCHAR +STARTCHAR 165 +ENCODING 165 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +28 +50 +00 +48 +68 +58 +48 +00 +ENDCHAR +STARTCHAR 166 +ENCODING 166 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +04 +3c +44 +3c +00 +3c +00 +ENDCHAR +STARTCHAR 167 +ENCODING 167 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +30 +48 +48 +48 +30 +00 +78 +00 +ENDCHAR +STARTCHAR 168 +ENCODING 168 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +00 +10 +30 +40 +44 +38 +00 +ENDCHAR +STARTCHAR 169 +ENCODING 169 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +7c +40 +40 +40 +00 +00 +ENDCHAR +STARTCHAR 170 +ENCODING 170 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +fc +04 +04 +00 +00 +00 +ENDCHAR +STARTCHAR 171 +ENCODING 171 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +40 +48 +50 +38 +44 +08 +1c +00 +ENDCHAR +STARTCHAR 172 +ENCODING 172 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +40 +48 +50 +2c +54 +1c +04 +00 +ENDCHAR +STARTCHAR 173 +ENCODING 173 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +00 +10 +10 +38 +38 +10 +00 +ENDCHAR +STARTCHAR 174 +ENCODING 174 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +24 +48 +24 +00 +00 +00 +ENDCHAR +STARTCHAR 175 +ENCODING 175 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +48 +24 +48 +00 +00 +00 +ENDCHAR +STARTCHAR 176 +ENCODING 176 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +54 +00 +a8 +00 +54 +00 +a8 +00 +ENDCHAR +STARTCHAR 177 +ENCODING 177 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +54 +a8 +54 +a8 +54 +a8 +54 +a8 +ENDCHAR +STARTCHAR 178 +ENCODING 178 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +a8 +fc +54 +fc +a8 +fc +54 +fc +ENDCHAR +STARTCHAR 179 +ENCODING 179 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +10 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 180 +ENCODING 180 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +10 +10 +f0 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 181 +ENCODING 181 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +f0 +10 +f0 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 182 +ENCODING 182 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +50 +50 +50 +d0 +50 +50 +50 +50 +ENDCHAR +STARTCHAR 183 +ENCODING 183 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +f0 +50 +50 +50 +50 +ENDCHAR +STARTCHAR 184 +ENCODING 184 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +f0 +10 +f0 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 185 +ENCODING 185 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +50 +d0 +10 +d0 +50 +50 +50 +50 +ENDCHAR +STARTCHAR 186 +ENCODING 186 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +50 +50 +50 +50 +50 +50 +50 +50 +ENDCHAR +STARTCHAR 187 +ENCODING 187 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +f0 +10 +d0 +50 +50 +50 +50 +ENDCHAR +STARTCHAR 188 +ENCODING 188 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +50 +d0 +10 +f0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 189 +ENCODING 189 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +50 +50 +50 +f0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 190 +ENCODING 190 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +f0 +10 +f0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 191 +ENCODING 191 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +f0 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 192 +ENCODING 192 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +10 +10 +1c +00 +00 +00 +00 +ENDCHAR +STARTCHAR 193 +ENCODING 193 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +10 +10 +fc +00 +00 +00 +00 +ENDCHAR +STARTCHAR 194 +ENCODING 194 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +fc +10 +10 +10 +10 +ENDCHAR +STARTCHAR 195 +ENCODING 195 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +10 +10 +1c +10 +10 +10 +10 +ENDCHAR +STARTCHAR 196 +ENCODING 196 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +fc +00 +00 +00 +00 +ENDCHAR +STARTCHAR 197 +ENCODING 197 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +10 +10 +fc +10 +10 +10 +10 +ENDCHAR +STARTCHAR 198 +ENCODING 198 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +1c +10 +1c +10 +10 +10 +10 +ENDCHAR +STARTCHAR 199 +ENCODING 199 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +50 +50 +50 +5c +50 +50 +50 +50 +ENDCHAR +STARTCHAR 200 +ENCODING 200 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +50 +5c +40 +7c +00 +00 +00 +00 +ENDCHAR +STARTCHAR 201 +ENCODING 201 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +7c +40 +5c +50 +50 +50 +50 +ENDCHAR +STARTCHAR 202 +ENCODING 202 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +50 +dc +00 +fc +00 +00 +00 +00 +ENDCHAR +STARTCHAR 203 +ENCODING 203 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +fc +00 +dc +50 +50 +50 +50 +ENDCHAR +STARTCHAR 204 +ENCODING 204 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +50 +5c +40 +5c +50 +50 +50 +50 +ENDCHAR +STARTCHAR 205 +ENCODING 205 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +fc +00 +fc +00 +00 +00 +00 +ENDCHAR +STARTCHAR 206 +ENCODING 206 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +50 +dc +00 +dc +50 +50 +50 +50 +ENDCHAR +STARTCHAR 207 +ENCODING 207 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +fc +00 +fc +00 +00 +00 +00 +ENDCHAR +STARTCHAR 208 +ENCODING 208 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +50 +50 +50 +fc +00 +00 +00 +00 +ENDCHAR +STARTCHAR 209 +ENCODING 209 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +fc +00 +fc +10 +10 +10 +10 +ENDCHAR +STARTCHAR 210 +ENCODING 210 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +fc +50 +50 +50 +50 +ENDCHAR +STARTCHAR 211 +ENCODING 211 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +50 +50 +50 +7c +00 +00 +00 +00 +ENDCHAR +STARTCHAR 212 +ENCODING 212 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +1c +10 +1c +00 +00 +00 +00 +ENDCHAR +STARTCHAR 213 +ENCODING 213 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +1c +10 +1c +10 +10 +10 +10 +ENDCHAR +STARTCHAR 214 +ENCODING 214 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +7c +50 +50 +50 +50 +ENDCHAR +STARTCHAR 215 +ENCODING 215 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +50 +50 +50 +dc +50 +50 +50 +50 +ENDCHAR +STARTCHAR 216 +ENCODING 216 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +fc +00 +fc +10 +10 +10 +10 +ENDCHAR +STARTCHAR 217 +ENCODING 217 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +10 +10 +f0 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 218 +ENCODING 218 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +1c +10 +10 +10 +10 +ENDCHAR +STARTCHAR 219 +ENCODING 219 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +fc +fc +fc +fc +fc +fc +fc +fc +ENDCHAR +STARTCHAR 220 +ENCODING 220 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +00 +fc +fc +fc +fc +ENDCHAR +STARTCHAR 221 +ENCODING 221 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +e0 +e0 +e0 +e0 +e0 +e0 +e0 +e0 +ENDCHAR +STARTCHAR 222 +ENCODING 222 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +1c +1c +1c +1c +1c +1c +1c +1c +ENDCHAR +STARTCHAR 223 +ENCODING 223 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +fc +fc +fc +fc +00 +00 +00 +00 +ENDCHAR +STARTCHAR 224 +ENCODING 224 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +34 +48 +48 +34 +00 +00 +ENDCHAR +STARTCHAR 225 +ENCODING 225 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +70 +48 +70 +48 +48 +70 +40 +ENDCHAR +STARTCHAR 226 +ENCODING 226 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +78 +48 +40 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR 227 +ENCODING 227 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +7c +28 +28 +28 +28 +28 +00 +ENDCHAR +STARTCHAR 228 +ENCODING 228 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +78 +48 +20 +10 +20 +48 +78 +00 +ENDCHAR +STARTCHAR 229 +ENCODING 229 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +3c +48 +48 +30 +00 +00 +ENDCHAR +STARTCHAR 230 +ENCODING 230 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +48 +48 +48 +70 +40 +40 +ENDCHAR +STARTCHAR 231 +ENCODING 231 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +28 +50 +10 +10 +10 +00 +ENDCHAR +STARTCHAR 232 +ENCODING 232 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +38 +10 +38 +44 +38 +10 +38 +00 +ENDCHAR +STARTCHAR 233 +ENCODING 233 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +30 +48 +48 +78 +48 +48 +30 +00 +ENDCHAR +STARTCHAR 234 +ENCODING 234 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +38 +44 +44 +28 +28 +6c +00 +ENDCHAR +STARTCHAR 235 +ENCODING 235 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +30 +40 +20 +10 +38 +48 +30 +00 +ENDCHAR +STARTCHAR 236 +ENCODING 236 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +28 +54 +54 +28 +00 +00 +ENDCHAR +STARTCHAR 237 +ENCODING 237 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +10 +38 +54 +54 +38 +10 +00 +ENDCHAR +STARTCHAR 238 +ENCODING 238 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +38 +40 +78 +40 +38 +00 +00 +ENDCHAR +STARTCHAR 239 +ENCODING 239 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +30 +48 +48 +48 +48 +00 +00 +ENDCHAR +STARTCHAR 240 +ENCODING 240 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +78 +00 +78 +00 +78 +00 +00 +ENDCHAR +STARTCHAR 241 +ENCODING 241 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +10 +38 +10 +00 +38 +00 +00 +ENDCHAR +STARTCHAR 242 +ENCODING 242 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +40 +30 +08 +30 +40 +00 +78 +00 +ENDCHAR +STARTCHAR 243 +ENCODING 243 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +08 +30 +40 +30 +08 +00 +78 +00 +ENDCHAR +STARTCHAR 244 +ENCODING 244 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +08 +14 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 245 +ENCODING 245 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +10 +10 +10 +10 +10 +50 +20 +00 +ENDCHAR +STARTCHAR 246 +ENCODING 246 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +10 +00 +7c +00 +10 +00 +00 +ENDCHAR +STARTCHAR 247 +ENCODING 247 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +28 +50 +00 +28 +50 +00 +00 +ENDCHAR +STARTCHAR 248 +ENCODING 248 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +30 +48 +48 +30 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 249 +ENCODING 249 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +30 +30 +00 +00 +00 +ENDCHAR +STARTCHAR 250 +ENCODING 250 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +20 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 251 +ENCODING 251 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +1c +10 +10 +50 +50 +20 +00 +ENDCHAR +STARTCHAR 252 +ENCODING 252 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +50 +28 +28 +28 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 253 +ENCODING 253 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +60 +10 +20 +70 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 254 +ENCODING 254 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +78 +78 +78 +78 +00 +00 +ENDCHAR +STARTCHAR 255 +ENCODING 255 +SWIDTH 540 0 +DWIDTH 6 0 +BBX 6 8 0 0 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +ENDFONT diff --git a/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-6x8a.pcf b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-6x8a.pcf new file mode 100644 index 000000000..d94a2098e Binary files /dev/null and b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-6x8a.pcf differ diff --git a/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-8x12.bdf b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-8x12.bdf new file mode 100644 index 000000000..c55320d6e --- /dev/null +++ b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-8x12.bdf @@ -0,0 +1,4881 @@ +STARTFONT 2.1 +FONT cp437-8x12 +SIZE 12 100 100 +FONTBOUNDINGBOX 8 12 0 0 +STARTPROPERTIES 9 +PIXEL_SIZE 12 +POINT_SIZE 1 +RESOLUTION_X 100 +RESOLUTION_Y 100 +FONT_ASCENT 12 +FONT_DESCENT 0 +AVERAGE_WIDTH 80 +SPACING "C" +DEFAULT_CHAR 32 +ENDPROPERTIES +CHARS 256 +STARTCHAR 0 +ENCODING 0 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 1 +ENCODING 1 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +7e +c3 +81 +a5 +81 +bd +99 +c3 +7e +00 +00 +ENDCHAR +STARTCHAR 2 +ENCODING 2 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +7e +ff +ff +db +ff +c3 +e7 +ff +7e +00 +00 +ENDCHAR +STARTCHAR 3 +ENCODING 3 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +44 +ee +fe +fe +fe +7c +38 +10 +00 +00 +ENDCHAR +STARTCHAR 4 +ENCODING 4 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +10 +38 +7c +fe +fe +7c +38 +10 +00 +00 +00 +ENDCHAR +STARTCHAR 5 +ENCODING 5 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +18 +3c +3c +ff +e7 +e7 +18 +18 +7e +00 +00 +ENDCHAR +STARTCHAR 6 +ENCODING 6 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +18 +3c +7e +ff +ff +7e +18 +18 +7e +00 +00 +ENDCHAR +STARTCHAR 7 +ENCODING 7 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +3c +7e +7e +3c +00 +00 +00 +00 +ENDCHAR +STARTCHAR 8 +ENCODING 8 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +ff +ff +ff +ff +c3 +81 +81 +c3 +ff +ff +ff +ff +ENDCHAR +STARTCHAR 9 +ENCODING 9 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +3c +7e +66 +42 +42 +66 +7e +3c +00 +00 +ENDCHAR +STARTCHAR 10 +ENCODING 10 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +ff +ff +c3 +81 +99 +bd +bd +99 +81 +c3 +ff +ff +ENDCHAR +STARTCHAR 11 +ENCODING 11 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +3e +0e +3a +72 +f8 +cc +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR 12 +ENCODING 12 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +3c +66 +66 +66 +3c +18 +7e +18 +18 +00 +00 +ENDCHAR +STARTCHAR 13 +ENCODING 13 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +1f +19 +19 +1f +18 +18 +78 +f8 +70 +00 +00 +ENDCHAR +STARTCHAR 14 +ENCODING 14 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +7f +63 +7f +63 +63 +63 +67 +e7 +e6 +c0 +00 +ENDCHAR +STARTCHAR 15 +ENCODING 15 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +18 +db +7e +e7 +e7 +7e +db +18 +00 +00 +ENDCHAR +STARTCHAR 16 +ENCODING 16 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +80 +c0 +e0 +f8 +fe +f8 +e0 +c0 +80 +00 +00 +ENDCHAR +STARTCHAR 17 +ENCODING 17 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +02 +06 +0e +3e +fe +3e +0e +06 +02 +00 +00 +ENDCHAR +STARTCHAR 18 +ENCODING 18 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +18 +3c +7e +18 +18 +18 +7e +3c +18 +00 +00 +ENDCHAR +STARTCHAR 19 +ENCODING 19 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +66 +66 +66 +66 +66 +00 +00 +66 +66 +00 +00 +ENDCHAR +STARTCHAR 20 +ENCODING 20 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +7f +db +db +db +7b +1b +1b +1b +1b +00 +00 +ENDCHAR +STARTCHAR 21 +ENCODING 21 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +7e +63 +30 +3c +66 +66 +3c +0c +c6 +7e +00 +ENDCHAR +STARTCHAR 22 +ENCODING 22 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +00 +00 +fe +fe +fe +00 +00 +ENDCHAR +STARTCHAR 23 +ENCODING 23 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +18 +3c +7e +18 +18 +18 +7e +3c +18 +7e +00 +ENDCHAR +STARTCHAR 24 +ENCODING 24 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +18 +3c +7e +18 +18 +18 +18 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 25 +ENCODING 25 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +18 +18 +18 +18 +18 +18 +7e +3c +18 +00 +00 +ENDCHAR +STARTCHAR 26 +ENCODING 26 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +18 +0c +fe +0c +18 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 27 +ENCODING 27 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +30 +60 +fe +60 +30 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 28 +ENCODING 28 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +c0 +c0 +c0 +fe +00 +00 +00 +00 +ENDCHAR +STARTCHAR 29 +ENCODING 29 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +24 +66 +ff +66 +24 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 30 +ENCODING 30 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +10 +10 +38 +38 +7c +7c +fe +fe +00 +00 +ENDCHAR +STARTCHAR 31 +ENCODING 31 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +fe +fe +7c +7c +38 +38 +10 +10 +00 +00 +ENDCHAR +STARTCHAR 32 +ENCODING 32 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 33 +ENCODING 33 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +30 +78 +78 +78 +30 +30 +00 +30 +30 +00 +00 +ENDCHAR +STARTCHAR 34 +ENCODING 34 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +66 +66 +66 +24 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 35 +ENCODING 35 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +6c +6c +fe +6c +6c +6c +fe +6c +6c +00 +00 +ENDCHAR +STARTCHAR 36 +ENCODING 36 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +30 +30 +7c +c0 +c0 +78 +0c +0c +f8 +30 +30 +00 +ENDCHAR +STARTCHAR 37 +ENCODING 37 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +c4 +cc +18 +30 +60 +cc +8c +00 +00 +ENDCHAR +STARTCHAR 38 +ENCODING 38 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +70 +d8 +d8 +70 +fa +de +cc +dc +76 +00 +00 +ENDCHAR +STARTCHAR 39 +ENCODING 39 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +30 +30 +30 +60 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 40 +ENCODING 40 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +0c +18 +30 +60 +60 +60 +30 +18 +0c +00 +00 +ENDCHAR +STARTCHAR 41 +ENCODING 41 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +60 +30 +18 +0c +0c +0c +18 +30 +60 +00 +00 +ENDCHAR +STARTCHAR 42 +ENCODING 42 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +66 +3c +ff +3c +66 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 43 +ENCODING 43 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +18 +18 +7e +18 +18 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 44 +ENCODING 44 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +38 +38 +60 +00 +ENDCHAR +STARTCHAR 45 +ENCODING 45 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +fe +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 46 +ENCODING 46 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +38 +38 +00 +00 +ENDCHAR +STARTCHAR 47 +ENCODING 47 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +02 +06 +0c +18 +30 +60 +c0 +80 +00 +00 +ENDCHAR +STARTCHAR 48 +ENCODING 48 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +7c +c6 +ce +de +d6 +f6 +e6 +c6 +7c +00 +00 +ENDCHAR +STARTCHAR 49 +ENCODING 49 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +10 +30 +f0 +30 +30 +30 +30 +30 +fc +00 +00 +ENDCHAR +STARTCHAR 50 +ENCODING 50 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +78 +cc +cc +0c +18 +30 +60 +cc +fc +00 +00 +ENDCHAR +STARTCHAR 51 +ENCODING 51 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +78 +cc +0c +0c +38 +0c +0c +cc +78 +00 +00 +ENDCHAR +STARTCHAR 52 +ENCODING 52 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +0c +1c +3c +6c +cc +fe +0c +0c +1e +00 +00 +ENDCHAR +STARTCHAR 53 +ENCODING 53 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +fc +c0 +c0 +c0 +f8 +0c +0c +cc +78 +00 +00 +ENDCHAR +STARTCHAR 54 +ENCODING 54 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +38 +60 +c0 +c0 +f8 +cc +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR 55 +ENCODING 55 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +fe +c6 +c6 +06 +0c +18 +30 +30 +30 +00 +00 +ENDCHAR +STARTCHAR 56 +ENCODING 56 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +78 +cc +cc +ec +78 +dc +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR 57 +ENCODING 57 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +78 +cc +cc +cc +7c +18 +18 +30 +70 +00 +00 +ENDCHAR +STARTCHAR 58 +ENCODING 58 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +38 +38 +00 +00 +38 +38 +00 +00 +00 +ENDCHAR +STARTCHAR 59 +ENCODING 59 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +38 +38 +00 +00 +38 +38 +18 +30 +00 +ENDCHAR +STARTCHAR 60 +ENCODING 60 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +0c +18 +30 +60 +c0 +60 +30 +18 +0c +00 +00 +ENDCHAR +STARTCHAR 61 +ENCODING 61 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +7e +00 +7e +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 62 +ENCODING 62 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +60 +30 +18 +0c +06 +0c +18 +30 +60 +00 +00 +ENDCHAR +STARTCHAR 63 +ENCODING 63 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +78 +cc +0c +18 +30 +30 +00 +30 +30 +00 +00 +ENDCHAR +STARTCHAR 64 +ENCODING 64 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +7c +c6 +c6 +de +de +de +c0 +c0 +7c +00 +00 +ENDCHAR +STARTCHAR 65 +ENCODING 65 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +30 +78 +cc +cc +cc +fc +cc +cc +cc +00 +00 +ENDCHAR +STARTCHAR 66 +ENCODING 66 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +fc +66 +66 +66 +7c +66 +66 +66 +fc +00 +00 +ENDCHAR +STARTCHAR 67 +ENCODING 67 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +3c +66 +c6 +c0 +c0 +c0 +c6 +66 +3c +00 +00 +ENDCHAR +STARTCHAR 68 +ENCODING 68 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +f8 +6c +66 +66 +66 +66 +66 +6c +f8 +00 +00 +ENDCHAR +STARTCHAR 69 +ENCODING 69 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +fe +62 +60 +64 +7c +64 +60 +62 +fe +00 +00 +ENDCHAR +STARTCHAR 70 +ENCODING 70 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +fe +66 +62 +64 +7c +64 +60 +60 +f0 +00 +00 +ENDCHAR +STARTCHAR 71 +ENCODING 71 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +3c +66 +c6 +c0 +c0 +ce +c6 +66 +3e +00 +00 +ENDCHAR +STARTCHAR 72 +ENCODING 72 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +cc +cc +cc +cc +fc +cc +cc +cc +cc +00 +00 +ENDCHAR +STARTCHAR 73 +ENCODING 73 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +78 +30 +30 +30 +30 +30 +30 +30 +78 +00 +00 +ENDCHAR +STARTCHAR 74 +ENCODING 74 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +1e +0c +0c +0c +0c +cc +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR 75 +ENCODING 75 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +e6 +66 +6c +6c +78 +6c +6c +66 +e6 +00 +00 +ENDCHAR +STARTCHAR 76 +ENCODING 76 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +f0 +60 +60 +60 +60 +62 +66 +66 +fe +00 +00 +ENDCHAR +STARTCHAR 77 +ENCODING 77 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +c6 +ee +fe +fe +d6 +c6 +c6 +c6 +c6 +00 +00 +ENDCHAR +STARTCHAR 78 +ENCODING 78 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +c6 +c6 +e6 +f6 +fe +de +ce +c6 +c6 +00 +00 +ENDCHAR +STARTCHAR 79 +ENCODING 79 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +38 +6c +c6 +c6 +c6 +c6 +c6 +6c +38 +00 +00 +ENDCHAR +STARTCHAR 80 +ENCODING 80 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +fc +66 +66 +66 +7c +60 +60 +60 +f0 +00 +00 +ENDCHAR +STARTCHAR 81 +ENCODING 81 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +38 +6c +c6 +c6 +c6 +ce +de +7c +0c +1e +00 +ENDCHAR +STARTCHAR 82 +ENCODING 82 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +fc +66 +66 +66 +7c +6c +66 +66 +e6 +00 +00 +ENDCHAR +STARTCHAR 83 +ENCODING 83 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +78 +cc +cc +c0 +70 +18 +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR 84 +ENCODING 84 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +fc +b4 +30 +30 +30 +30 +30 +30 +78 +00 +00 +ENDCHAR +STARTCHAR 85 +ENCODING 85 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +cc +cc +cc +cc +cc +cc +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR 86 +ENCODING 86 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +cc +cc +cc +cc +cc +cc +cc +78 +30 +00 +00 +ENDCHAR +STARTCHAR 87 +ENCODING 87 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +c6 +c6 +c6 +c6 +d6 +d6 +6c +6c +6c +00 +00 +ENDCHAR +STARTCHAR 88 +ENCODING 88 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +cc +cc +cc +78 +30 +78 +cc +cc +cc +00 +00 +ENDCHAR +STARTCHAR 89 +ENCODING 89 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +cc +cc +cc +cc +78 +30 +30 +30 +78 +00 +00 +ENDCHAR +STARTCHAR 90 +ENCODING 90 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +fe +ce +98 +18 +30 +60 +62 +c6 +fe +00 +00 +ENDCHAR +STARTCHAR 91 +ENCODING 91 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +3c +30 +30 +30 +30 +30 +30 +30 +3c +00 +00 +ENDCHAR +STARTCHAR 92 +ENCODING 92 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +80 +c0 +60 +30 +18 +0c +06 +02 +00 +00 +ENDCHAR +STARTCHAR 93 +ENCODING 93 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +3c +0c +0c +0c +0c +0c +0c +0c +3c +00 +00 +ENDCHAR +STARTCHAR 94 +ENCODING 94 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +10 +38 +6c +c6 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 95 +ENCODING 95 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ff +00 +ENDCHAR +STARTCHAR 96 +ENCODING 96 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +30 +30 +18 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 97 +ENCODING 97 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +78 +0c +7c +cc +cc +76 +00 +00 +ENDCHAR +STARTCHAR 98 +ENCODING 98 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +e0 +60 +60 +7c +66 +66 +66 +66 +dc +00 +00 +ENDCHAR +STARTCHAR 99 +ENCODING 99 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +78 +cc +c0 +c0 +cc +78 +00 +00 +ENDCHAR +STARTCHAR 100 +ENCODING 100 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +1c +0c +0c +7c +cc +cc +cc +cc +76 +00 +00 +ENDCHAR +STARTCHAR 101 +ENCODING 101 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +78 +cc +fc +c0 +cc +78 +00 +00 +ENDCHAR +STARTCHAR 102 +ENCODING 102 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +38 +6c +60 +60 +f8 +60 +60 +60 +f0 +00 +00 +ENDCHAR +STARTCHAR 103 +ENCODING 103 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +76 +cc +cc +cc +7c +0c +cc +78 +ENDCHAR +STARTCHAR 104 +ENCODING 104 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +e0 +60 +60 +6c +76 +66 +66 +66 +e6 +00 +00 +ENDCHAR +STARTCHAR 105 +ENCODING 105 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +18 +18 +00 +78 +18 +18 +18 +18 +7e +00 +00 +ENDCHAR +STARTCHAR 106 +ENCODING 106 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +0c +0c +00 +3c +0c +0c +0c +0c +cc +cc +78 +ENDCHAR +STARTCHAR 107 +ENCODING 107 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +e0 +60 +60 +66 +6c +78 +6c +66 +e6 +00 +00 +ENDCHAR +STARTCHAR 108 +ENCODING 108 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +78 +18 +18 +18 +18 +18 +18 +18 +7e +00 +00 +ENDCHAR +STARTCHAR 109 +ENCODING 109 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +fc +d6 +d6 +d6 +d6 +c6 +00 +00 +ENDCHAR +STARTCHAR 110 +ENCODING 110 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +f8 +cc +cc +cc +cc +cc +00 +00 +ENDCHAR +STARTCHAR 111 +ENCODING 111 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +78 +cc +cc +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR 112 +ENCODING 112 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +dc +66 +66 +66 +66 +7c +60 +f0 +ENDCHAR +STARTCHAR 113 +ENCODING 113 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +76 +cc +cc +cc +cc +7c +0c +1e +ENDCHAR +STARTCHAR 114 +ENCODING 114 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +ec +6e +76 +60 +60 +f0 +00 +00 +ENDCHAR +STARTCHAR 115 +ENCODING 115 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +78 +cc +60 +18 +cc +78 +00 +00 +ENDCHAR +STARTCHAR 116 +ENCODING 116 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +20 +60 +fc +60 +60 +60 +6c +38 +00 +00 +ENDCHAR +STARTCHAR 117 +ENCODING 117 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +cc +cc +cc +cc +cc +76 +00 +00 +ENDCHAR +STARTCHAR 118 +ENCODING 118 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +cc +cc +cc +cc +78 +30 +00 +00 +ENDCHAR +STARTCHAR 119 +ENCODING 119 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +c6 +c6 +d6 +d6 +6c +6c +00 +00 +ENDCHAR +STARTCHAR 120 +ENCODING 120 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +c6 +6c +38 +38 +6c +c6 +00 +00 +ENDCHAR +STARTCHAR 121 +ENCODING 121 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +66 +66 +66 +66 +3c +0c +18 +f0 +ENDCHAR +STARTCHAR 122 +ENCODING 122 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +fc +8c +18 +60 +c4 +fc +00 +00 +ENDCHAR +STARTCHAR 123 +ENCODING 123 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +1c +30 +30 +60 +c0 +60 +30 +30 +1c +00 +00 +ENDCHAR +STARTCHAR 124 +ENCODING 124 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +18 +18 +18 +18 +00 +18 +18 +18 +18 +00 +00 +ENDCHAR +STARTCHAR 125 +ENCODING 125 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +e0 +30 +30 +18 +0c +18 +30 +30 +e0 +00 +00 +ENDCHAR +STARTCHAR 126 +ENCODING 126 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +73 +da +ce +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 127 +ENCODING 127 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +10 +38 +6c +c6 +c6 +fe +00 +00 +00 +ENDCHAR +STARTCHAR 128 +ENCODING 128 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +78 +cc +cc +c0 +c0 +c0 +cc +cc +78 +30 +f0 +ENDCHAR +STARTCHAR 129 +ENCODING 129 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +cc +cc +00 +cc +cc +cc +cc +cc +76 +00 +00 +ENDCHAR +STARTCHAR 130 +ENCODING 130 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +0c +18 +30 +00 +78 +cc +fc +c0 +cc +78 +00 +00 +ENDCHAR +STARTCHAR 131 +ENCODING 131 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +30 +78 +cc +00 +78 +0c +7c +cc +cc +76 +00 +00 +ENDCHAR +STARTCHAR 132 +ENCODING 132 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +cc +cc +00 +78 +0c +7c +cc +cc +76 +00 +00 +ENDCHAR +STARTCHAR 133 +ENCODING 133 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +c0 +60 +30 +00 +78 +0c +7c +cc +cc +76 +00 +00 +ENDCHAR +STARTCHAR 134 +ENCODING 134 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +38 +6c +6c +38 +f8 +0c +7c +cc +cc +76 +00 +00 +ENDCHAR +STARTCHAR 135 +ENCODING 135 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +78 +cc +c0 +c0 +cc +78 +30 +f0 +ENDCHAR +STARTCHAR 136 +ENCODING 136 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +30 +78 +cc +00 +78 +cc +fc +c0 +c0 +7c +00 +00 +ENDCHAR +STARTCHAR 137 +ENCODING 137 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +cc +cc +00 +78 +cc +fc +c0 +c0 +7c +00 +00 +ENDCHAR +STARTCHAR 138 +ENCODING 138 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +c0 +60 +30 +00 +78 +cc +fc +c0 +c0 +7c +00 +00 +ENDCHAR +STARTCHAR 139 +ENCODING 139 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +6c +6c +00 +78 +18 +18 +18 +18 +7e +00 +00 +ENDCHAR +STARTCHAR 140 +ENCODING 140 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +10 +38 +6c +00 +78 +18 +18 +18 +18 +7e +00 +00 +ENDCHAR +STARTCHAR 141 +ENCODING 141 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +60 +30 +18 +00 +78 +18 +18 +18 +18 +7e +00 +00 +ENDCHAR +STARTCHAR 142 +ENCODING 142 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +cc +00 +30 +78 +cc +cc +fc +cc +cc +00 +00 +ENDCHAR +STARTCHAR 143 +ENCODING 143 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +78 +cc +cc +78 +78 +cc +cc +fc +cc +cc +00 +00 +ENDCHAR +STARTCHAR 144 +ENCODING 144 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +0c +18 +30 +fc +c4 +c0 +f8 +c0 +c4 +fc +00 +00 +ENDCHAR +STARTCHAR 145 +ENCODING 145 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +fe +1b +7f +d8 +d8 +ef +00 +00 +ENDCHAR +STARTCHAR 146 +ENCODING 146 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +3e +78 +d8 +d8 +fe +d8 +d8 +d8 +de +00 +00 +ENDCHAR +STARTCHAR 147 +ENCODING 147 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +30 +78 +cc +00 +78 +cc +cc +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR 148 +ENCODING 148 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +cc +cc +00 +78 +cc +cc +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR 149 +ENCODING 149 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +c0 +60 +30 +00 +78 +cc +cc +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR 150 +ENCODING 150 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +30 +78 +cc +00 +cc +cc +cc +cc +cc +76 +00 +00 +ENDCHAR +STARTCHAR 151 +ENCODING 151 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +c0 +60 +30 +00 +cc +cc +cc +cc +cc +76 +00 +00 +ENDCHAR +STARTCHAR 152 +ENCODING 152 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +66 +66 +00 +66 +66 +66 +66 +3c +0c +18 +f0 +ENDCHAR +STARTCHAR 153 +ENCODING 153 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +cc +00 +78 +cc +cc +cc +cc +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR 154 +ENCODING 154 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +cc +00 +cc +cc +cc +cc +cc +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR 155 +ENCODING 155 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +30 +30 +78 +cc +c0 +c0 +cc +78 +30 +30 +00 +ENDCHAR +STARTCHAR 156 +ENCODING 156 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +3c +66 +60 +60 +60 +fc +60 +60 +c0 +fe +00 +00 +ENDCHAR +STARTCHAR 157 +ENCODING 157 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +cc +cc +cc +cc +78 +fc +30 +fc +30 +30 +00 +00 +ENDCHAR +STARTCHAR 158 +ENCODING 158 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +f0 +88 +88 +88 +f0 +88 +9e +8c +8d +86 +00 +00 +ENDCHAR +STARTCHAR 159 +ENCODING 159 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +0e +1b +18 +18 +7e +18 +18 +18 +d8 +70 +00 +00 +ENDCHAR +STARTCHAR 160 +ENCODING 160 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +0c +18 +30 +00 +78 +0c +7c +cc +cc +76 +00 +00 +ENDCHAR +STARTCHAR 161 +ENCODING 161 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +0c +18 +30 +00 +78 +18 +18 +18 +18 +7e +00 +00 +ENDCHAR +STARTCHAR 162 +ENCODING 162 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +0c +18 +30 +00 +78 +cc +cc +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR 163 +ENCODING 163 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +0c +18 +30 +00 +cc +cc +cc +cc +cc +76 +00 +00 +ENDCHAR +STARTCHAR 164 +ENCODING 164 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +76 +dc +00 +f8 +cc +cc +cc +cc +cc +00 +00 +ENDCHAR +STARTCHAR 165 +ENCODING 165 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +76 +dc +00 +c6 +e6 +f6 +de +ce +c6 +c6 +00 +00 +ENDCHAR +STARTCHAR 166 +ENCODING 166 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +78 +cc +cc +7e +00 +fe +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 167 +ENCODING 167 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +78 +cc +cc +78 +00 +fe +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 168 +ENCODING 168 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +30 +30 +00 +30 +60 +c0 +c0 +cc +78 +00 +00 +ENDCHAR +STARTCHAR 169 +ENCODING 169 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +fc +c0 +c0 +c0 +00 +00 +00 +ENDCHAR +STARTCHAR 170 +ENCODING 170 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +fc +0c +0c +0c +00 +00 +00 +ENDCHAR +STARTCHAR 171 +ENCODING 171 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +42 +c6 +cc +d8 +30 +6e +c3 +86 +0c +1f +00 +ENDCHAR +STARTCHAR 172 +ENCODING 172 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +63 +e6 +6c +78 +37 +6f +db +b3 +3f +03 +00 +ENDCHAR +STARTCHAR 173 +ENCODING 173 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +30 +30 +00 +30 +30 +78 +78 +78 +30 +00 +00 +ENDCHAR +STARTCHAR 174 +ENCODING 174 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +33 +66 +cc +cc +66 +33 +00 +00 +ENDCHAR +STARTCHAR 175 +ENCODING 175 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +cc +66 +33 +33 +66 +cc +00 +00 +ENDCHAR +STARTCHAR 176 +ENCODING 176 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +24 +92 +49 +24 +92 +49 +24 +92 +49 +24 +92 +49 +ENDCHAR +STARTCHAR 177 +ENCODING 177 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +55 +aa +55 +aa +55 +aa +55 +aa +55 +aa +55 +aa +ENDCHAR +STARTCHAR 178 +ENCODING 178 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +6d +db +b6 +6d +db +b6 +6d +db +b6 +6d +db +b6 +ENDCHAR +STARTCHAR 179 +ENCODING 179 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 180 +ENCODING 180 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +18 +18 +18 +18 +18 +f8 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 181 +ENCODING 181 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +18 +18 +18 +18 +f8 +18 +18 +f8 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 182 +ENCODING 182 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +66 +66 +66 +66 +66 +e6 +66 +66 +66 +66 +66 +66 +ENDCHAR +STARTCHAR 183 +ENCODING 183 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +fe +66 +66 +66 +66 +66 +66 +ENDCHAR +STARTCHAR 184 +ENCODING 184 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +f8 +18 +18 +f8 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 185 +ENCODING 185 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +66 +66 +66 +66 +e6 +06 +06 +e6 +66 +66 +66 +66 +ENDCHAR +STARTCHAR 186 +ENCODING 186 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +66 +66 +66 +66 +66 +66 +66 +66 +66 +66 +66 +66 +ENDCHAR +STARTCHAR 187 +ENCODING 187 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +fe +06 +06 +e6 +66 +66 +66 +66 +ENDCHAR +STARTCHAR 188 +ENCODING 188 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +66 +66 +66 +66 +e6 +06 +06 +fe +00 +00 +00 +00 +ENDCHAR +STARTCHAR 189 +ENCODING 189 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +66 +66 +66 +66 +66 +fe +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 190 +ENCODING 190 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +18 +18 +18 +18 +f8 +18 +18 +f8 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 191 +ENCODING 191 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +f8 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 192 +ENCODING 192 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +18 +18 +18 +18 +18 +1f +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 193 +ENCODING 193 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +18 +18 +18 +18 +18 +ff +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 194 +ENCODING 194 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +ff +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 195 +ENCODING 195 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +18 +18 +18 +18 +18 +1f +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 196 +ENCODING 196 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +ff +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 197 +ENCODING 197 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +18 +18 +18 +18 +18 +ff +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 198 +ENCODING 198 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +18 +18 +18 +18 +1f +18 +18 +1f +18 +18 +18 +18 +ENDCHAR +STARTCHAR 199 +ENCODING 199 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +66 +66 +66 +66 +66 +67 +66 +66 +66 +66 +66 +66 +ENDCHAR +STARTCHAR 200 +ENCODING 200 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +66 +66 +66 +66 +67 +60 +60 +7f +00 +00 +00 +00 +ENDCHAR +STARTCHAR 201 +ENCODING 201 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +7f +60 +60 +67 +66 +66 +66 +66 +ENDCHAR +STARTCHAR 202 +ENCODING 202 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +66 +66 +66 +66 +e7 +00 +00 +ff +00 +00 +00 +00 +ENDCHAR +STARTCHAR 203 +ENCODING 203 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +ff +00 +00 +e7 +66 +66 +66 +66 +ENDCHAR +STARTCHAR 204 +ENCODING 204 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +66 +66 +66 +66 +67 +60 +60 +67 +66 +66 +66 +66 +ENDCHAR +STARTCHAR 205 +ENCODING 205 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +ff +00 +00 +ff +00 +00 +00 +00 +ENDCHAR +STARTCHAR 206 +ENCODING 206 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +66 +66 +66 +66 +e7 +00 +00 +e7 +66 +66 +66 +66 +ENDCHAR +STARTCHAR 207 +ENCODING 207 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +18 +18 +18 +18 +ff +00 +00 +ff +00 +00 +00 +00 +ENDCHAR +STARTCHAR 208 +ENCODING 208 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +66 +66 +66 +66 +66 +ff +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 209 +ENCODING 209 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +ff +00 +00 +ff +18 +18 +18 +18 +ENDCHAR +STARTCHAR 210 +ENCODING 210 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +ff +66 +66 +66 +66 +66 +66 +ENDCHAR +STARTCHAR 211 +ENCODING 211 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +66 +66 +66 +66 +66 +7f +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 212 +ENCODING 212 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +18 +18 +18 +18 +1f +18 +18 +1f +00 +00 +00 +00 +ENDCHAR +STARTCHAR 213 +ENCODING 213 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +1f +18 +18 +1f +18 +18 +18 +18 +ENDCHAR +STARTCHAR 214 +ENCODING 214 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +7f +66 +66 +66 +66 +66 +66 +ENDCHAR +STARTCHAR 215 +ENCODING 215 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +66 +66 +66 +66 +66 +e7 +66 +66 +66 +66 +66 +66 +ENDCHAR +STARTCHAR 216 +ENCODING 216 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +18 +18 +18 +18 +ff +00 +00 +ff +18 +18 +18 +18 +ENDCHAR +STARTCHAR 217 +ENCODING 217 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +18 +18 +18 +18 +18 +f8 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 218 +ENCODING 218 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +1f +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 219 +ENCODING 219 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +ff +ff +ff +ff +ff +ff +ff +ff +ff +ff +ff +ff +ENDCHAR +STARTCHAR 220 +ENCODING 220 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +00 +ff +ff +ff +ff +ff +ff +ENDCHAR +STARTCHAR 221 +ENCODING 221 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +f0 +f0 +f0 +f0 +f0 +f0 +f0 +f0 +f0 +f0 +f0 +f0 +ENDCHAR +STARTCHAR 222 +ENCODING 222 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +0f +0f +0f +0f +0f +0f +0f +0f +0f +0f +0f +0f +ENDCHAR +STARTCHAR 223 +ENCODING 223 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +ff +ff +ff +ff +ff +ff +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 224 +ENCODING 224 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +76 +de +cc +cc +de +76 +00 +00 +ENDCHAR +STARTCHAR 225 +ENCODING 225 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +78 +cc +cc +d8 +cc +cc +cc +f8 +c0 +60 +00 +ENDCHAR +STARTCHAR 226 +ENCODING 226 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +fc +cc +cc +c0 +c0 +c0 +c0 +c0 +c0 +00 +00 +ENDCHAR +STARTCHAR 227 +ENCODING 227 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +fe +6c +6c +6c +6c +6c +6c +6c +66 +00 +00 +ENDCHAR +STARTCHAR 228 +ENCODING 228 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +fc +c4 +64 +60 +30 +60 +64 +c4 +fc +00 +00 +ENDCHAR +STARTCHAR 229 +ENCODING 229 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +7e +c8 +cc +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR 230 +ENCODING 230 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +66 +66 +66 +66 +66 +7b +60 +c0 +ENDCHAR +STARTCHAR 231 +ENCODING 231 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +76 +dc +18 +18 +18 +18 +0e +00 +00 +ENDCHAR +STARTCHAR 232 +ENCODING 232 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +fc +30 +78 +cc +cc +cc +78 +30 +fc +00 +00 +ENDCHAR +STARTCHAR 233 +ENCODING 233 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +78 +cc +cc +cc +fc +cc +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR 234 +ENCODING 234 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +7c +c6 +c6 +c6 +c6 +6c +6c +6c +ee +00 +00 +ENDCHAR +STARTCHAR 235 +ENCODING 235 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +3c +60 +30 +78 +cc +cc +cc +cc +78 +00 +00 +ENDCHAR +STARTCHAR 236 +ENCODING 236 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +76 +db +db +db +6e +00 +00 +00 +00 +ENDCHAR +STARTCHAR 237 +ENCODING 237 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +06 +7c +de +d6 +f6 +7c +c0 +00 +00 +00 +ENDCHAR +STARTCHAR 238 +ENCODING 238 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +3c +60 +c0 +c0 +fc +c0 +c0 +60 +3c +00 +00 +ENDCHAR +STARTCHAR 239 +ENCODING 239 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +78 +cc +cc +cc +cc +cc +cc +cc +00 +00 +ENDCHAR +STARTCHAR 240 +ENCODING 240 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +fc +00 +00 +fc +00 +00 +fc +00 +00 +00 +ENDCHAR +STARTCHAR 241 +ENCODING 241 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +30 +30 +fc +30 +30 +00 +fc +00 +00 +00 +ENDCHAR +STARTCHAR 242 +ENCODING 242 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +60 +30 +18 +18 +30 +60 +00 +fc +00 +00 +00 +ENDCHAR +STARTCHAR 243 +ENCODING 243 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +18 +30 +60 +60 +30 +18 +00 +fc +00 +00 +00 +ENDCHAR +STARTCHAR 244 +ENCODING 244 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +0e +1b +1b +18 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 245 +ENCODING 245 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +18 +18 +18 +18 +18 +18 +18 +d8 +d8 +70 +00 +00 +ENDCHAR +STARTCHAR 246 +ENCODING 246 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +30 +30 +00 +fc +00 +30 +30 +00 +00 +00 +ENDCHAR +STARTCHAR 247 +ENCODING 247 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +73 +db +ce +00 +73 +db +ce +00 +00 +00 +ENDCHAR +STARTCHAR 248 +ENCODING 248 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +3c +66 +66 +66 +3c +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 249 +ENCODING 249 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +1c +1c +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 250 +ENCODING 250 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +18 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 251 +ENCODING 251 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +07 +04 +04 +04 +44 +64 +34 +1c +0c +00 +00 +ENDCHAR +STARTCHAR 252 +ENCODING 252 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +d8 +6c +6c +6c +6c +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 253 +ENCODING 253 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +78 +0c +18 +30 +7c +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 254 +ENCODING 254 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +3c +3c +3c +3c +3c +3c +3c +3c +00 +00 +ENDCHAR +STARTCHAR 255 +ENCODING 255 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +ENDFONT diff --git a/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-8x12a.pcf b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-8x12a.pcf new file mode 100644 index 000000000..41199dbf2 Binary files /dev/null and b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-8x12a.pcf differ diff --git a/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-8x8.bdf b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-8x8.bdf new file mode 100644 index 000000000..c30c0d1d6 --- /dev/null +++ b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-8x8.bdf @@ -0,0 +1,3857 @@ +STARTFONT 2.1 +FONT cp437-8x8 +SIZE 8 100 100 +FONTBOUNDINGBOX 8 8 0 0 +STARTPROPERTIES 9 +PIXEL_SIZE 8 +POINT_SIZE 1 +RESOLUTION_X 100 +RESOLUTION_Y 100 +FONT_ASCENT 8 +FONT_DESCENT 0 +AVERAGE_WIDTH 80 +SPACING "C" +DEFAULT_CHAR 32 +ENDPROPERTIES +CHARS 256 +STARTCHAR 0 +ENCODING 0 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 1 +ENCODING 1 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +7e +81 +a5 +81 +bd +99 +81 +7e +ENDCHAR +STARTCHAR 2 +ENCODING 2 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +7e +ff +db +ff +c3 +e7 +ff +7e +ENDCHAR +STARTCHAR 3 +ENCODING 3 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +6c +fe +fe +fe +7c +38 +10 +00 +ENDCHAR +STARTCHAR 4 +ENCODING 4 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +10 +38 +7c +fe +7c +38 +10 +00 +ENDCHAR +STARTCHAR 5 +ENCODING 5 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +38 +7c +38 +fe +fe +d6 +10 +38 +ENDCHAR +STARTCHAR 6 +ENCODING 6 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +10 +10 +38 +7c +fe +7c +10 +38 +ENDCHAR +STARTCHAR 7 +ENCODING 7 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +18 +3c +3c +18 +00 +00 +ENDCHAR +STARTCHAR 8 +ENCODING 8 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +ff +ff +e7 +c3 +c3 +e7 +ff +ff +ENDCHAR +STARTCHAR 9 +ENCODING 9 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +3c +66 +42 +42 +66 +3c +00 +ENDCHAR +STARTCHAR 10 +ENCODING 10 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +ff +c3 +99 +bd +bd +99 +c3 +ff +ENDCHAR +STARTCHAR 11 +ENCODING 11 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +0f +07 +0f +7d +cc +cc +cc +78 +ENDCHAR +STARTCHAR 12 +ENCODING 12 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +3c +66 +66 +66 +3c +18 +7e +18 +ENDCHAR +STARTCHAR 13 +ENCODING 13 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +3f +33 +3f +30 +30 +70 +f0 +e0 +ENDCHAR +STARTCHAR 14 +ENCODING 14 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +7f +63 +7f +63 +63 +67 +e6 +c0 +ENDCHAR +STARTCHAR 15 +ENCODING 15 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +99 +5a +3c +e7 +e7 +3c +5a +99 +ENDCHAR +STARTCHAR 16 +ENCODING 16 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +80 +e0 +f8 +fe +f8 +e0 +80 +00 +ENDCHAR +STARTCHAR 17 +ENCODING 17 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +02 +0e +3e +fe +3e +0e +02 +00 +ENDCHAR +STARTCHAR 18 +ENCODING 18 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +3c +7e +18 +18 +7e +3c +18 +ENDCHAR +STARTCHAR 19 +ENCODING 19 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +66 +66 +66 +66 +66 +00 +66 +00 +ENDCHAR +STARTCHAR 20 +ENCODING 20 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +7f +db +db +7b +1b +1b +1b +00 +ENDCHAR +STARTCHAR 21 +ENCODING 21 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +7e +c3 +78 +cc +cc +78 +8c +f8 +ENDCHAR +STARTCHAR 22 +ENCODING 22 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +00 +7e +7e +7e +00 +ENDCHAR +STARTCHAR 23 +ENCODING 23 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +3c +7e +18 +7e +3c +18 +ff +ENDCHAR +STARTCHAR 24 +ENCODING 24 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +3c +7e +18 +18 +18 +18 +00 +ENDCHAR +STARTCHAR 25 +ENCODING 25 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +18 +18 +7e +3c +18 +00 +ENDCHAR +STARTCHAR 26 +ENCODING 26 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +18 +0c +fe +0c +18 +00 +00 +ENDCHAR +STARTCHAR 27 +ENCODING 27 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +30 +60 +fe +60 +30 +00 +00 +ENDCHAR +STARTCHAR 28 +ENCODING 28 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +c0 +c0 +c0 +fe +00 +00 +ENDCHAR +STARTCHAR 29 +ENCODING 29 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +24 +66 +ff +66 +24 +00 +00 +ENDCHAR +STARTCHAR 30 +ENCODING 30 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +18 +3c +7e +ff +ff +00 +00 +ENDCHAR +STARTCHAR 31 +ENCODING 31 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +ff +ff +7e +3c +18 +00 +00 +ENDCHAR +STARTCHAR 32 +ENCODING 32 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 33 +ENCODING 33 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +30 +78 +78 +30 +30 +00 +30 +00 +ENDCHAR +STARTCHAR 34 +ENCODING 34 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +6c +6c +6c +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 35 +ENCODING 35 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +6c +6c +fe +6c +fe +6c +6c +00 +ENDCHAR +STARTCHAR 36 +ENCODING 36 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +30 +7c +c0 +78 +0c +f8 +30 +00 +ENDCHAR +STARTCHAR 37 +ENCODING 37 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +c6 +cc +18 +30 +66 +c6 +00 +ENDCHAR +STARTCHAR 38 +ENCODING 38 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +38 +6c +38 +76 +dc +cc +76 +00 +ENDCHAR +STARTCHAR 39 +ENCODING 39 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +60 +60 +c0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 40 +ENCODING 40 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +30 +60 +60 +60 +30 +18 +00 +ENDCHAR +STARTCHAR 41 +ENCODING 41 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +60 +30 +18 +18 +18 +30 +60 +00 +ENDCHAR +STARTCHAR 42 +ENCODING 42 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +66 +3c +ff +3c +66 +00 +00 +ENDCHAR +STARTCHAR 43 +ENCODING 43 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +30 +30 +fc +30 +30 +00 +00 +ENDCHAR +STARTCHAR 44 +ENCODING 44 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +00 +00 +70 +30 +60 +ENDCHAR +STARTCHAR 45 +ENCODING 45 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +fc +00 +00 +00 +00 +ENDCHAR +STARTCHAR 46 +ENCODING 46 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +00 +00 +30 +30 +00 +ENDCHAR +STARTCHAR 47 +ENCODING 47 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +06 +0c +18 +30 +60 +c0 +80 +00 +ENDCHAR +STARTCHAR 48 +ENCODING 48 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +cc +dc +fc +ec +cc +78 +00 +ENDCHAR +STARTCHAR 49 +ENCODING 49 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +30 +f0 +30 +30 +30 +30 +fc +00 +ENDCHAR +STARTCHAR 50 +ENCODING 50 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +cc +0c +38 +60 +cc +fc +00 +ENDCHAR +STARTCHAR 51 +ENCODING 51 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +cc +0c +38 +0c +cc +78 +00 +ENDCHAR +STARTCHAR 52 +ENCODING 52 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +1c +3c +6c +cc +fe +0c +0c +00 +ENDCHAR +STARTCHAR 53 +ENCODING 53 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +fc +c0 +f8 +0c +0c +cc +78 +00 +ENDCHAR +STARTCHAR 54 +ENCODING 54 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +38 +60 +c0 +f8 +cc +cc +78 +00 +ENDCHAR +STARTCHAR 55 +ENCODING 55 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +fc +cc +0c +18 +30 +60 +60 +00 +ENDCHAR +STARTCHAR 56 +ENCODING 56 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +cc +cc +78 +cc +cc +78 +00 +ENDCHAR +STARTCHAR 57 +ENCODING 57 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +cc +cc +7c +0c +18 +70 +00 +ENDCHAR +STARTCHAR 58 +ENCODING 58 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +30 +30 +00 +30 +30 +00 +ENDCHAR +STARTCHAR 59 +ENCODING 59 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +30 +30 +00 +70 +30 +60 +ENDCHAR +STARTCHAR 60 +ENCODING 60 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +30 +60 +c0 +60 +30 +18 +00 +ENDCHAR +STARTCHAR 61 +ENCODING 61 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +fc +00 +fc +00 +00 +00 +ENDCHAR +STARTCHAR 62 +ENCODING 62 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +60 +30 +18 +0c +18 +30 +60 +00 +ENDCHAR +STARTCHAR 63 +ENCODING 63 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +cc +0c +18 +30 +00 +30 +00 +ENDCHAR +STARTCHAR 64 +ENCODING 64 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +7c +c6 +de +de +de +c0 +78 +00 +ENDCHAR +STARTCHAR 65 +ENCODING 65 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +30 +78 +cc +cc +fc +cc +cc +00 +ENDCHAR +STARTCHAR 66 +ENCODING 66 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +fc +66 +66 +7c +66 +66 +fc +00 +ENDCHAR +STARTCHAR 67 +ENCODING 67 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +3c +66 +c0 +c0 +c0 +66 +3c +00 +ENDCHAR +STARTCHAR 68 +ENCODING 68 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +fc +6c +66 +66 +66 +6c +fc +00 +ENDCHAR +STARTCHAR 69 +ENCODING 69 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +fe +62 +68 +78 +68 +62 +fe +00 +ENDCHAR +STARTCHAR 70 +ENCODING 70 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +fe +62 +68 +78 +68 +60 +f0 +00 +ENDCHAR +STARTCHAR 71 +ENCODING 71 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +3c +66 +c0 +c0 +ce +66 +3e +00 +ENDCHAR +STARTCHAR 72 +ENCODING 72 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +cc +cc +cc +fc +cc +cc +cc +00 +ENDCHAR +STARTCHAR 73 +ENCODING 73 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +30 +30 +30 +30 +30 +78 +00 +ENDCHAR +STARTCHAR 74 +ENCODING 74 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +1e +0c +0c +0c +cc +cc +78 +00 +ENDCHAR +STARTCHAR 75 +ENCODING 75 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +e6 +66 +6c +78 +6c +66 +e6 +00 +ENDCHAR +STARTCHAR 76 +ENCODING 76 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +f0 +60 +60 +60 +62 +66 +fe +00 +ENDCHAR +STARTCHAR 77 +ENCODING 77 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +c6 +ee +fe +d6 +c6 +c6 +c6 +00 +ENDCHAR +STARTCHAR 78 +ENCODING 78 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +c6 +e6 +f6 +de +ce +c6 +c6 +00 +ENDCHAR +STARTCHAR 79 +ENCODING 79 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +38 +6c +c6 +c6 +c6 +6c +38 +00 +ENDCHAR +STARTCHAR 80 +ENCODING 80 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +fc +66 +66 +7c +60 +60 +f0 +00 +ENDCHAR +STARTCHAR 81 +ENCODING 81 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +cc +cc +cc +dc +78 +1c +00 +ENDCHAR +STARTCHAR 82 +ENCODING 82 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +fc +66 +66 +7c +78 +6c +e6 +00 +ENDCHAR +STARTCHAR 83 +ENCODING 83 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +cc +e0 +38 +1c +cc +78 +00 +ENDCHAR +STARTCHAR 84 +ENCODING 84 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +fc +b4 +30 +30 +30 +30 +78 +00 +ENDCHAR +STARTCHAR 85 +ENCODING 85 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +cc +cc +cc +cc +cc +cc +fc +00 +ENDCHAR +STARTCHAR 86 +ENCODING 86 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +cc +cc +cc +cc +cc +78 +30 +00 +ENDCHAR +STARTCHAR 87 +ENCODING 87 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +c6 +c6 +c6 +d6 +fe +ee +c6 +00 +ENDCHAR +STARTCHAR 88 +ENCODING 88 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +c6 +c6 +6c +38 +6c +c6 +c6 +00 +ENDCHAR +STARTCHAR 89 +ENCODING 89 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +cc +cc +cc +78 +30 +30 +78 +00 +ENDCHAR +STARTCHAR 90 +ENCODING 90 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +fe +cc +98 +30 +62 +c6 +fe +00 +ENDCHAR +STARTCHAR 91 +ENCODING 91 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +60 +60 +60 +60 +60 +78 +00 +ENDCHAR +STARTCHAR 92 +ENCODING 92 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +c0 +60 +30 +18 +0c +06 +02 +00 +ENDCHAR +STARTCHAR 93 +ENCODING 93 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +18 +18 +18 +18 +18 +78 +00 +ENDCHAR +STARTCHAR 94 +ENCODING 94 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +10 +38 +6c +c6 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 95 +ENCODING 95 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +00 +00 +00 +00 +ff +ENDCHAR +STARTCHAR 96 +ENCODING 96 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +30 +30 +18 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 97 +ENCODING 97 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +78 +0c +7c +cc +76 +00 +ENDCHAR +STARTCHAR 98 +ENCODING 98 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +e0 +60 +7c +66 +66 +66 +bc +00 +ENDCHAR +STARTCHAR 99 +ENCODING 99 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +78 +cc +c0 +cc +78 +00 +ENDCHAR +STARTCHAR 100 +ENCODING 100 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +1c +0c +0c +7c +cc +cc +76 +00 +ENDCHAR +STARTCHAR 101 +ENCODING 101 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +78 +cc +fc +c0 +78 +00 +ENDCHAR +STARTCHAR 102 +ENCODING 102 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +38 +6c +60 +f0 +60 +60 +f0 +00 +ENDCHAR +STARTCHAR 103 +ENCODING 103 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +76 +cc +cc +7c +0c +f8 +ENDCHAR +STARTCHAR 104 +ENCODING 104 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +e0 +60 +6c +76 +66 +66 +e6 +00 +ENDCHAR +STARTCHAR 105 +ENCODING 105 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +30 +00 +70 +30 +30 +30 +78 +00 +ENDCHAR +STARTCHAR 106 +ENCODING 106 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +00 +78 +18 +18 +18 +d8 +70 +ENDCHAR +STARTCHAR 107 +ENCODING 107 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +e0 +60 +66 +6c +78 +6c +e6 +00 +ENDCHAR +STARTCHAR 108 +ENCODING 108 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +70 +30 +30 +30 +30 +30 +78 +00 +ENDCHAR +STARTCHAR 109 +ENCODING 109 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +ec +fe +d6 +c6 +c6 +00 +ENDCHAR +STARTCHAR 110 +ENCODING 110 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +f8 +cc +cc +cc +cc +00 +ENDCHAR +STARTCHAR 111 +ENCODING 111 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +78 +cc +cc +cc +78 +00 +ENDCHAR +STARTCHAR 112 +ENCODING 112 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +dc +66 +66 +7c +60 +f0 +ENDCHAR +STARTCHAR 113 +ENCODING 113 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +76 +cc +cc +7c +0c +1e +ENDCHAR +STARTCHAR 114 +ENCODING 114 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +d8 +6c +6c +60 +f0 +00 +ENDCHAR +STARTCHAR 115 +ENCODING 115 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +7c +c0 +78 +0c +f8 +00 +ENDCHAR +STARTCHAR 116 +ENCODING 116 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +10 +30 +7c +30 +30 +34 +18 +00 +ENDCHAR +STARTCHAR 117 +ENCODING 117 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +cc +cc +cc +cc +76 +00 +ENDCHAR +STARTCHAR 118 +ENCODING 118 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +cc +cc +cc +78 +30 +00 +ENDCHAR +STARTCHAR 119 +ENCODING 119 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +c6 +c6 +d6 +fe +6c +00 +ENDCHAR +STARTCHAR 120 +ENCODING 120 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +c6 +6c +38 +6c +c6 +00 +ENDCHAR +STARTCHAR 121 +ENCODING 121 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +cc +cc +cc +7c +0c +f8 +ENDCHAR +STARTCHAR 122 +ENCODING 122 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +fc +98 +30 +64 +fc +00 +ENDCHAR +STARTCHAR 123 +ENCODING 123 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +1c +30 +30 +e0 +30 +30 +1c +00 +ENDCHAR +STARTCHAR 124 +ENCODING 124 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +18 +00 +18 +18 +18 +00 +ENDCHAR +STARTCHAR 125 +ENCODING 125 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +e0 +30 +30 +1c +30 +30 +e0 +00 +ENDCHAR +STARTCHAR 126 +ENCODING 126 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +76 +dc +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 127 +ENCODING 127 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +10 +38 +6c +c6 +c6 +c6 +fe +00 +ENDCHAR +STARTCHAR 128 +ENCODING 128 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +cc +c0 +cc +78 +18 +0c +78 +ENDCHAR +STARTCHAR 129 +ENCODING 129 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +cc +00 +cc +cc +cc +7e +00 +ENDCHAR +STARTCHAR 130 +ENCODING 130 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +1c +00 +78 +cc +fc +c0 +78 +00 +ENDCHAR +STARTCHAR 131 +ENCODING 131 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +7e +c3 +3c +06 +3e +66 +3f +00 +ENDCHAR +STARTCHAR 132 +ENCODING 132 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +cc +00 +78 +0c +7c +cc +7e +00 +ENDCHAR +STARTCHAR 133 +ENCODING 133 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +e0 +00 +78 +0c +7c +cc +7e +00 +ENDCHAR +STARTCHAR 134 +ENCODING 134 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +30 +30 +78 +0c +7c +cc +7e +00 +ENDCHAR +STARTCHAR 135 +ENCODING 135 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +7c +c0 +c0 +7c +06 +3c +ENDCHAR +STARTCHAR 136 +ENCODING 136 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +7e +c3 +3c +66 +7e +60 +3c +00 +ENDCHAR +STARTCHAR 137 +ENCODING 137 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +cc +00 +78 +cc +fc +c0 +78 +00 +ENDCHAR +STARTCHAR 138 +ENCODING 138 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +e0 +00 +78 +cc +fc +c0 +78 +00 +ENDCHAR +STARTCHAR 139 +ENCODING 139 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +cc +00 +70 +30 +30 +30 +78 +00 +ENDCHAR +STARTCHAR 140 +ENCODING 140 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +7c +c6 +38 +18 +18 +18 +3c +00 +ENDCHAR +STARTCHAR 141 +ENCODING 141 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +e0 +00 +70 +30 +30 +30 +78 +00 +ENDCHAR +STARTCHAR 142 +ENCODING 142 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +cc +30 +78 +cc +cc +fc +cc +00 +ENDCHAR +STARTCHAR 143 +ENCODING 143 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +30 +30 +00 +78 +cc +fc +cc +00 +ENDCHAR +STARTCHAR 144 +ENCODING 144 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +1c +00 +fc +60 +78 +60 +fc +00 +ENDCHAR +STARTCHAR 145 +ENCODING 145 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +7f +0c +7f +cc +7f +00 +ENDCHAR +STARTCHAR 146 +ENCODING 146 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +3e +6c +cc +fe +cc +cc +ce +00 +ENDCHAR +STARTCHAR 147 +ENCODING 147 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +cc +00 +78 +cc +cc +78 +00 +ENDCHAR +STARTCHAR 148 +ENCODING 148 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +cc +00 +78 +cc +cc +78 +00 +ENDCHAR +STARTCHAR 149 +ENCODING 149 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +e0 +00 +78 +cc +cc +78 +00 +ENDCHAR +STARTCHAR 150 +ENCODING 150 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +cc +00 +cc +cc +cc +7e +00 +ENDCHAR +STARTCHAR 151 +ENCODING 151 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +e0 +00 +cc +cc +cc +7e +00 +ENDCHAR +STARTCHAR 152 +ENCODING 152 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +cc +00 +cc +cc +fc +0c +f8 +ENDCHAR +STARTCHAR 153 +ENCODING 153 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +c6 +38 +7c +c6 +c6 +7c +38 +00 +ENDCHAR +STARTCHAR 154 +ENCODING 154 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +cc +00 +cc +cc +cc +cc +78 +00 +ENDCHAR +STARTCHAR 155 +ENCODING 155 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +7e +c0 +c0 +7e +18 +18 +ENDCHAR +STARTCHAR 156 +ENCODING 156 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +38 +6c +64 +f0 +60 +e6 +fc +00 +ENDCHAR +STARTCHAR 157 +ENCODING 157 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +cc +cc +78 +fc +30 +fc +30 +00 +ENDCHAR +STARTCHAR 158 +ENCODING 158 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +f0 +d8 +d8 +f4 +cc +de +cc +0e +ENDCHAR +STARTCHAR 159 +ENCODING 159 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +0e +1b +18 +7e +18 +18 +d8 +70 +ENDCHAR +STARTCHAR 160 +ENCODING 160 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +1c +00 +78 +0c +7c +cc +7e +00 +ENDCHAR +STARTCHAR 161 +ENCODING 161 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +38 +00 +70 +30 +30 +30 +78 +00 +ENDCHAR +STARTCHAR 162 +ENCODING 162 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +1c +00 +78 +cc +cc +78 +00 +ENDCHAR +STARTCHAR 163 +ENCODING 163 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +1c +00 +cc +cc +cc +7e +00 +ENDCHAR +STARTCHAR 164 +ENCODING 164 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +f8 +00 +f8 +cc +cc +cc +00 +ENDCHAR +STARTCHAR 165 +ENCODING 165 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +fc +00 +cc +ec +fc +dc +cc +00 +ENDCHAR +STARTCHAR 166 +ENCODING 166 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +3c +6c +6c +3e +00 +7e +00 +00 +ENDCHAR +STARTCHAR 167 +ENCODING 167 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +3c +66 +66 +3c +00 +7e +00 +00 +ENDCHAR +STARTCHAR 168 +ENCODING 168 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +30 +00 +30 +60 +c0 +cc +78 +00 +ENDCHAR +STARTCHAR 169 +ENCODING 169 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +fc +c0 +c0 +00 +00 +ENDCHAR +STARTCHAR 170 +ENCODING 170 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +fc +0c +0c +00 +00 +ENDCHAR +STARTCHAR 171 +ENCODING 171 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +c6 +cc +d8 +3e +63 +ce +98 +1f +ENDCHAR +STARTCHAR 172 +ENCODING 172 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +c6 +cc +d8 +f3 +67 +cf +9f +03 +ENDCHAR +STARTCHAR 173 +ENCODING 173 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +18 +00 +18 +18 +3c +3c +18 +ENDCHAR +STARTCHAR 174 +ENCODING 174 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +33 +66 +cc +66 +33 +00 +00 +ENDCHAR +STARTCHAR 175 +ENCODING 175 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +cc +66 +33 +66 +cc +00 +00 +ENDCHAR +STARTCHAR 176 +ENCODING 176 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +22 +88 +22 +88 +22 +88 +22 +88 +ENDCHAR +STARTCHAR 177 +ENCODING 177 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +55 +aa +55 +aa +55 +aa +55 +aa +ENDCHAR +STARTCHAR 178 +ENCODING 178 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +dd +77 +dd +77 +dd +77 +dd +77 +ENDCHAR +STARTCHAR 179 +ENCODING 179 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 180 +ENCODING 180 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +18 +18 +f8 +18 +18 +18 +ENDCHAR +STARTCHAR 181 +ENCODING 181 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +f8 +18 +f8 +18 +18 +18 +ENDCHAR +STARTCHAR 182 +ENCODING 182 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +36 +36 +36 +36 +f6 +36 +36 +36 +ENDCHAR +STARTCHAR 183 +ENCODING 183 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +00 +fe +36 +36 +36 +ENDCHAR +STARTCHAR 184 +ENCODING 184 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +f8 +18 +f8 +18 +18 +18 +ENDCHAR +STARTCHAR 185 +ENCODING 185 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +36 +36 +f6 +06 +f6 +36 +36 +36 +ENDCHAR +STARTCHAR 186 +ENCODING 186 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +36 +36 +36 +36 +36 +36 +36 +36 +ENDCHAR +STARTCHAR 187 +ENCODING 187 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +fe +06 +f6 +36 +36 +36 +ENDCHAR +STARTCHAR 188 +ENCODING 188 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +36 +36 +f6 +06 +fe +00 +00 +00 +ENDCHAR +STARTCHAR 189 +ENCODING 189 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +36 +36 +36 +36 +fe +00 +00 +00 +ENDCHAR +STARTCHAR 190 +ENCODING 190 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +f8 +18 +f8 +00 +00 +00 +ENDCHAR +STARTCHAR 191 +ENCODING 191 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +00 +f8 +18 +18 +18 +ENDCHAR +STARTCHAR 192 +ENCODING 192 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +18 +18 +1f +00 +00 +00 +ENDCHAR +STARTCHAR 193 +ENCODING 193 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +18 +18 +ff +00 +00 +00 +ENDCHAR +STARTCHAR 194 +ENCODING 194 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +00 +ff +18 +18 +18 +ENDCHAR +STARTCHAR 195 +ENCODING 195 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +18 +18 +1f +18 +18 +18 +ENDCHAR +STARTCHAR 196 +ENCODING 196 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +00 +ff +00 +00 +00 +ENDCHAR +STARTCHAR 197 +ENCODING 197 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +18 +18 +ff +18 +18 +18 +ENDCHAR +STARTCHAR 198 +ENCODING 198 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +1f +18 +1f +18 +18 +18 +ENDCHAR +STARTCHAR 199 +ENCODING 199 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +36 +36 +36 +36 +37 +36 +36 +36 +ENDCHAR +STARTCHAR 200 +ENCODING 200 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +36 +36 +37 +30 +3f +00 +00 +00 +ENDCHAR +STARTCHAR 201 +ENCODING 201 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +3f +30 +37 +36 +36 +36 +ENDCHAR +STARTCHAR 202 +ENCODING 202 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +36 +36 +f7 +00 +ff +00 +00 +00 +ENDCHAR +STARTCHAR 203 +ENCODING 203 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +ff +00 +f7 +36 +36 +36 +ENDCHAR +STARTCHAR 204 +ENCODING 204 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +36 +36 +37 +30 +37 +36 +36 +36 +ENDCHAR +STARTCHAR 205 +ENCODING 205 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +ff +00 +ff +00 +00 +00 +ENDCHAR +STARTCHAR 206 +ENCODING 206 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +36 +36 +f7 +00 +f7 +36 +36 +36 +ENDCHAR +STARTCHAR 207 +ENCODING 207 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +ff +00 +ff +00 +00 +00 +ENDCHAR +STARTCHAR 208 +ENCODING 208 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +36 +36 +36 +36 +ff +00 +00 +00 +ENDCHAR +STARTCHAR 209 +ENCODING 209 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +ff +00 +ff +18 +18 +18 +ENDCHAR +STARTCHAR 210 +ENCODING 210 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +00 +ff +36 +36 +36 +ENDCHAR +STARTCHAR 211 +ENCODING 211 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +36 +36 +36 +36 +3f +00 +00 +00 +ENDCHAR +STARTCHAR 212 +ENCODING 212 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +1f +18 +1f +00 +00 +00 +ENDCHAR +STARTCHAR 213 +ENCODING 213 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +1f +18 +1f +18 +18 +18 +ENDCHAR +STARTCHAR 214 +ENCODING 214 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +00 +3f +36 +36 +36 +ENDCHAR +STARTCHAR 215 +ENCODING 215 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +36 +36 +36 +36 +f7 +36 +36 +36 +ENDCHAR +STARTCHAR 216 +ENCODING 216 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +ff +00 +ff +18 +18 +18 +ENDCHAR +STARTCHAR 217 +ENCODING 217 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +18 +18 +f8 +00 +00 +00 +ENDCHAR +STARTCHAR 218 +ENCODING 218 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +00 +1f +18 +18 +18 +ENDCHAR +STARTCHAR 219 +ENCODING 219 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +ff +ff +ff +ff +ff +ff +ff +ff +ENDCHAR +STARTCHAR 220 +ENCODING 220 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +00 +ff +ff +ff +ff +ENDCHAR +STARTCHAR 221 +ENCODING 221 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +f0 +f0 +f0 +f0 +f0 +f0 +f0 +f0 +ENDCHAR +STARTCHAR 222 +ENCODING 222 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +0f +0f +0f +0f +0f +0f +0f +0f +ENDCHAR +STARTCHAR 223 +ENCODING 223 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +ff +ff +ff +ff +00 +00 +00 +00 +ENDCHAR +STARTCHAR 224 +ENCODING 224 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +76 +dc +c8 +dc +76 +00 +ENDCHAR +STARTCHAR 225 +ENCODING 225 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +78 +cc +f8 +cc +f8 +c0 +c0 +ENDCHAR +STARTCHAR 226 +ENCODING 226 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +fe +c6 +c0 +c0 +c0 +c0 +00 +ENDCHAR +STARTCHAR 227 +ENCODING 227 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +fe +6c +6c +6c +6c +6c +00 +ENDCHAR +STARTCHAR 228 +ENCODING 228 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +fe +66 +30 +18 +30 +66 +fe +00 +ENDCHAR +STARTCHAR 229 +ENCODING 229 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +7e +cc +cc +cc +78 +00 +ENDCHAR +STARTCHAR 230 +ENCODING 230 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +66 +66 +66 +66 +7c +60 +c0 +ENDCHAR +STARTCHAR 231 +ENCODING 231 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +76 +dc +18 +18 +18 +18 +00 +ENDCHAR +STARTCHAR 232 +ENCODING 232 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +fc +30 +78 +cc +cc +78 +30 +fc +ENDCHAR +STARTCHAR 233 +ENCODING 233 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +38 +6c +c6 +fe +c6 +6c +38 +00 +ENDCHAR +STARTCHAR 234 +ENCODING 234 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +38 +6c +c6 +c6 +6c +6c +ee +00 +ENDCHAR +STARTCHAR 235 +ENCODING 235 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +1c +30 +18 +7c +cc +cc +78 +00 +ENDCHAR +STARTCHAR 236 +ENCODING 236 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +7e +db +db +7e +00 +00 +ENDCHAR +STARTCHAR 237 +ENCODING 237 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +06 +0c +7e +db +db +7e +60 +c0 +ENDCHAR +STARTCHAR 238 +ENCODING 238 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +3c +60 +c0 +fc +c0 +60 +3c +00 +ENDCHAR +STARTCHAR 239 +ENCODING 239 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +cc +cc +cc +cc +cc +cc +00 +ENDCHAR +STARTCHAR 240 +ENCODING 240 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +fc +00 +fc +00 +fc +00 +00 +ENDCHAR +STARTCHAR 241 +ENCODING 241 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +30 +30 +fc +30 +30 +00 +fc +00 +ENDCHAR +STARTCHAR 242 +ENCODING 242 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +60 +30 +18 +30 +60 +00 +fc +00 +ENDCHAR +STARTCHAR 243 +ENCODING 243 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +30 +60 +30 +18 +00 +fc +00 +ENDCHAR +STARTCHAR 244 +ENCODING 244 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +0e +1b +1b +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 245 +ENCODING 245 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +18 +18 +18 +18 +18 +d8 +d8 +70 +ENDCHAR +STARTCHAR 246 +ENCODING 246 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +30 +30 +00 +fc +00 +30 +30 +00 +ENDCHAR +STARTCHAR 247 +ENCODING 247 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +72 +9c +00 +72 +9c +00 +00 +ENDCHAR +STARTCHAR 248 +ENCODING 248 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +38 +6c +6c +38 +00 +00 +00 +00 +ENDCHAR +STARTCHAR 249 +ENCODING 249 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +18 +18 +00 +00 +00 +ENDCHAR +STARTCHAR 250 +ENCODING 250 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +00 +18 +00 +00 +00 +ENDCHAR +STARTCHAR 251 +ENCODING 251 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +0f +0c +0c +0c +ec +6c +3c +1c +ENDCHAR +STARTCHAR 252 +ENCODING 252 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +6c +6c +6c +6c +00 +00 +00 +ENDCHAR +STARTCHAR 253 +ENCODING 253 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +78 +0c +38 +60 +7c +00 +00 +00 +ENDCHAR +STARTCHAR 254 +ENCODING 254 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +3c +3c +3c +3c +00 +00 +ENDCHAR +STARTCHAR 255 +ENCODING 255 +SWIDTH 720 0 +DWIDTH 8 0 +BBX 8 8 0 0 +BITMAP +00 +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +ENDFONT diff --git a/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-8x8a.pcf b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-8x8a.pcf new file mode 100644 index 000000000..ccc74c0cd Binary files /dev/null and b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437-8x8a.pcf differ diff --git a/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437_12h.bin b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437_12h.bin new file mode 100644 index 000000000..5a7074dbe Binary files /dev/null and b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437_12h.bin differ diff --git a/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437_16h.bin b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437_16h.bin new file mode 100644 index 000000000..c20c6f48c Binary files /dev/null and b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437_16h.bin differ diff --git a/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437_8h.bin b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437_8h.bin new file mode 100644 index 000000000..30e6a1ba4 Binary files /dev/null and b/Fruit_Jam/CircuitPython_DVI_Video/fonts/cp437_8h.bin differ diff --git a/Fruit_Jam/FruitJam_Breakout/README.md b/Fruit_Jam/FruitJam_Breakout/README.md new file mode 100644 index 000000000..f0de8f31a --- /dev/null +++ b/Fruit_Jam/FruitJam_Breakout/README.md @@ -0,0 +1 @@ +This is the source code for the Fruit Jam version of the game Breakout. It uses the library adafruit_circuitpython_fruitjam where possible. diff --git a/Fruit_Jam/FruitJam_Breakout/code.py b/Fruit_Jam/FruitJam_Breakout/code.py new file mode 100644 index 000000000..7dbe1a257 --- /dev/null +++ b/Fruit_Jam/FruitJam_Breakout/code.py @@ -0,0 +1,515 @@ +# SPDX-FileCopyrightText: 2025 Anne Barela for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# +# Breakout - Fruit Jam version + +import sys +import time +import array +import math +import random +import audiocore +from adafruit_fruitjam.peripherals import Peripherals +from adafruit_fruitjam.peripherals import request_display_config +import displayio +import supervisor +from adafruit_display_shapes.rect import Rect +from adafruit_display_shapes.circle import Circle +from adafruit_display_text import label +import terminalio + +displayio.release_displays() # Ensure there are no active displays + +# Initialize speaker +fruit_jam = Peripherals(audio_output="speaker") # or "headphone" +if fruit_jam.dac is None: + print("\nAre you running this on a Fruit Jam?") + sys.exit(1) + +# Initialize status LEDs +fruit_jam.neopixels.brightness = 0.4 +fruit_jam.neopixels.fill((0, 40, 0)) # Initial status: green + +# Configure speaker settings +fruit_jam.dac.speaker_output = True +fruit_jam.dac.dac_volume = 0 # Digital volume (-63.5 to 24.0 dB) +fruit_jam.dac.speaker_volume = -5 # Analog volume (-78.3 to 0 dB) +fruit_jam.dac.speaker_gain = 18 # Amplifier gain (6, 12, 18, or 24 dB) + +# Sound effect functions +def play_tone(frequency, duration, volume=0.5): + """Play a tone at the specified frequency for the specified duration + + Args: + frequency (int/float): Frequency in Hz (e.g., 440 for A4) + duration (float): Duration in seconds + volume (float): Volume level from 0.0 to 1.0 (default 0.5) + """ + # Get the sample rate from the DAC + sample_rate = fruit_jam.dac.sample_rate + + # Calculate length of one period of the waveform + length = sample_rate // int(frequency) + + # Generate a sine wave for one period + sine_wave = array.array("h", [0] * length) + for i in range(length): + sine_wave[i] = int((math.sin(math.pi * 2 * i / length)) * volume * (2**15 - 1)) + + # Create a RawSample from the sine wave + sine_wave_sample = audiocore.RawSample(sine_wave, sample_rate=sample_rate) + + # Play the tone + fruit_jam.audio.play(sine_wave_sample, loop=True) + time.sleep(duration) + fruit_jam.audio.stop() + +def play_paddle_hit(): + """Sound for ball hitting paddle""" + play_tone(440, 0.05) # A4, short duration + +def play_wall_hit(): + """Sound for ball hitting wall""" + play_tone(330, 0.03) # E4, very short + +def play_brick_hit(): + """Sound for ball hitting brick""" + play_tone(660, 0.05) # E5, short + +def play_game_over(): + """Sound for game over""" + # Descending tone + for i in range(5): + play_tone(330 - i*30, 0.1) + +def play_level_win(): + """Sound for winning the level""" + # Victory fanfare + sequence = [440, 440, 440, 587, 440, 587, 659] + durations = [0.1, 0.1, 0.1, 0.3, 0.1, 0.1, 0.4] + + for freq, dur in zip(sequence, durations): + play_tone(freq, dur) + time.sleep(0.01) # Small gap between notes + +def play_life_lost(): + """Sound for losing a life""" + play_tone(220, 0.1) + time.sleep(0.05) + play_tone(196, 0.2) + +def play_game_start(): + """Sound for game start""" + play_tone(440, 0.1) + time.sleep(0.05) + play_tone(554, 0.1) + time.sleep(0.05) + play_tone(659, 0.2) + +# Initialize display +request_display_config(320, 240) +display = supervisor.runtime.display + +# Game constants +PADDLE_WIDTH = 40 +PADDLE_HEIGHT = 5 +BALL_RADIUS = 2 +BRICK_ROWS = 5 +BRICK_COLS = 10 +BRICK_WIDTH = 30 +BRICK_HEIGHT = 10 +BRICK_GAP = 2 +PADDLE_SPEED = 6.0 # Change to make paddle speed up or slow down +BALL_SPEED_INITIAL = 2.75 # Change initial ball speed +BRICK_COLORS = [0xFF4136, 0xFF851B, 0xFFDC00, 0x2ECC40, 0x0074D9] +DISPLAY_LINE = 20 # Score is on the bottom of the display 20 px tall + +# Game state +game_active = False +game_over = False +brick_count = BRICK_ROWS * BRICK_COLS + +# Keyboard input state +key_left_pressed = False +key_right_pressed = False +key_space_pressed = False +space_key_released = True # Track space key release to prevent multiple actions + +# Track paddle position with float for smoother movement +paddle_pos_x = 0.0 + +def check_keys(): + """ + Check for keyboard input via supervisor.runtime.serial_bytes_available + Returns tuple of (left_pressed, right_pressed, space_pressed, any_input) + """ + l_pressed = False + r_pressed = False + s_pressed = False + any_key = False + + # Check if serial data is available + if supervisor.runtime.serial_bytes_available: + any_key = True + try: + key = sys.stdin.read(1) + if key in ('a', 'A'): # Left movement + l_pressed = True + elif key in ('d', 'D'): # Right movement + r_pressed = True + elif key == ' ': # Space for start/launch + s_pressed = True + elif key in ('q', 'Q') or ord(key) == 27: # q, Q, or ESC is quit + sys.exit(0) # We're out of here + except Exception as e: # pylint: disable=broad-except + print("Input error:", e) + + return (l_pressed, r_pressed, s_pressed, any_key) + +# pylint: disable=redefined-outer-name +def create_game_elements(): + """Create and return all game display elements""" + game_group = displayio.Group() + + # Paddle + paddle = Rect( + (display.width - PADDLE_WIDTH) // 2, + display.height - PADDLE_HEIGHT - DISPLAY_LINE, + PADDLE_WIDTH, + PADDLE_HEIGHT, + fill=0x00FFFF + ) + game_group.append(paddle) + + # Ball + ball = Circle( + display.width // 2, + display.height - PADDLE_HEIGHT - DISPLAY_LINE - BALL_RADIUS * 3, + BALL_RADIUS, + fill=0xFFFFFF + ) + game_group.append(ball) + + # Bricks + bricks = [] + for row in range(BRICK_ROWS): + for col in range(BRICK_COLS): + # Calculate brick position with appropriate spacing + brick_x = col * (BRICK_WIDTH + BRICK_GAP) + \ + (display.width - (BRICK_COLS * (BRICK_WIDTH + BRICK_GAP) + - BRICK_GAP)) // 2 + brick_y = row * (BRICK_HEIGHT + BRICK_GAP) + 30 # Start a bit down from top + + brick = Rect( + brick_x, + brick_y, + BRICK_WIDTH, + BRICK_HEIGHT, + fill=BRICK_COLORS[row % len(BRICK_COLORS)] + ) + bricks.append(brick) + game_group.append(brick) + + # Score and lives + score_label = label.Label( + terminalio.FONT, + text="Score: 0", + color=0xFFFFFF, + x=5, + y=display.height - 10 + ) + lives_label = label.Label( + terminalio.FONT, + text="Lives: 3", + color=0xFFFFFF, + x=display.width - 60, + y=display.height - 10 + ) + game_group.append(score_label) + game_group.append(lives_label) + + # Controls info + controls_label = label.Label( + terminalio.FONT, + text="A: Left D: Right", + color=0xFFFFFF, + x=10, + y=display.height - 30 + ) + game_group.append(controls_label) + + # Start/game over message + message_label = label.Label( + terminalio.FONT, + text="Press SPACE to begin", + color=0xFFFFFF, + x=(display.width - 130) // 2, + y=display.height // 2 + ) + game_group.append(message_label) + + return (game_group, paddle, ball, bricks, score_label, + lives_label, message_label, controls_label) + +# Create initial game elements +main_group, paddle, ball, bricks, score_label, lives_label, message_label, \ + controls_label = create_game_elements() +display.root_group = main_group + +# Game variables +score = 0 +lives = 3 +ball_dx = 0.0 +ball_dy = 0.0 +ball_speed = BALL_SPEED_INITIAL +last_hit_brick = None + +# Track actual ball position with floats +ball_pos_x = float(ball.x) +ball_pos_y = float(ball.y) + +# Initialize paddle position tracking +paddle_pos_x = float((display.width - PADDLE_WIDTH) // 2) + +def reset_ball(): + """Reset the ball position and set it initially stationary""" + global ball_dx, ball_dy, ball_pos_x, ball_pos_y # pylint: disable=global-statement + ball_pos_x = float(display.width // 2) + ball_pos_y = float(display.height - PADDLE_HEIGHT - DISPLAY_LINE - BALL_RADIUS * 3) + ball.x = int(ball_pos_x) + ball.y = int(ball_pos_y) + ball_dx = 0 + ball_dy = 0 + +def launch_ball(): + """Launch the ball in a random upward direction""" + global ball_dx, ball_dy, ball_speed # pylint: disable=global-statement + ball_speed = BALL_SPEED_INITIAL + angle = random.uniform(0.5, 0.8) # Launch at angle between 45-65 degrees + ball_dx = ball_speed * random.choice([-angle, angle]) + # Ensure consistent speed + ball_dy = -ball_speed * (1 - abs(ball_dx/ball_speed)) + controls_label.hidden = True + +def update_message(text): + """Update the message text""" + message_label.text = text + # Center text (approximate width) + message_label.x = (display.width - len(text) * 6) // 2 + +# Game loop +reset_ball() + +# Track last collision for sound effect throttling +last_wall_hit_time = 0 +sound_cooldown = 0.05 # Minimum time between similar sound effects + +# Play startup sound +play_game_start() + +while True: + current_time = time.monotonic() + + # Check keyboard input + left_pressed, right_pressed, space_pressed, any_input = check_keys() + + # Apply paddle movement ONLY if keys are currently pressed + if left_pressed and paddle_pos_x > 0: + paddle_pos_x -= PADDLE_SPEED + # Ensure paddle doesn't go offscreen + if paddle_pos_x < 0: + paddle_pos_x = 0 + + if right_pressed and paddle_pos_x < display.width - PADDLE_WIDTH: + paddle_pos_x += PADDLE_SPEED + # Ensure paddle doesn't go offscreen + if paddle_pos_x > display.width - PADDLE_WIDTH: + paddle_pos_x = display.width - PADDLE_WIDTH + + # Update paddle position with integer conversion + paddle.x = int(paddle_pos_x) + + # Handle space bar for start/launch with debouncing + if space_pressed and space_key_released: + space_key_released = False # Prevent multiple triggers until released + + if game_over: + # Reset everything for a new game + (main_group, paddle, ball, bricks, score_label, + lives_label, message_label, controls_label) = create_game_elements() + display.root_group = main_group + score = 0 + lives = 3 + brick_count = BRICK_ROWS * BRICK_COLS + game_over = False + reset_ball() + update_message("") + # Reset paddle position tracker + paddle_pos_x = float((display.width - PADDLE_WIDTH) // 2) + + # Play restart sound + play_game_start() + + if not game_active and not game_over: + game_active = True + launch_ball() + update_message("") + + # Play ball launch sound + play_tone(587, 0.1) # D5, short + + # Reset space key released state if no key is pressed + if not space_pressed: + space_key_released = True + + # Handle game logic when active + if game_active and not game_over: + # Update ball position (using float variables first) + ball_pos_x += ball_dx + ball_pos_y += ball_dy + # Update the actual ball object with integer positions + ball.x = int(ball_pos_x) + ball.y = int(ball_pos_y) + + # Ball collision with walls with sound + wall_hit = False + + if ball_pos_x - BALL_RADIUS <= 0: + ball_pos_x = BALL_RADIUS + 1 # Prevent sticking to wall + ball_dx = abs(ball_dx) # Move right + wall_hit = True + elif ball_pos_x + BALL_RADIUS >= display.width: + ball_pos_x = display.width - BALL_RADIUS - 1 # Prevent sticking to wall + ball_dx = -abs(ball_dx) # Move left + wall_hit = True + + if ball_pos_y - BALL_RADIUS <= 0: + ball_pos_y = BALL_RADIUS + 1 # Prevent sticking to wall + ball_dy = abs(ball_dy) # Move down + wall_hit = True + + # Play wall hit sound with cooldown to prevent sound overlap + if wall_hit and current_time - last_wall_hit_time > sound_cooldown: + play_wall_hit() + last_wall_hit_time = current_time + + # Ball fell below paddle + if ball_pos_y + BALL_RADIUS > display.height - DISPLAY_LINE: + lives -= 1 + lives_label.text = f"Lives: {lives}" + + # Play life lost sound + play_life_lost() + + if lives <= 0: + game_active = False + game_over = True + update_message("GAME OVER - Press SPACE to play again, Q to quit") + + # Play game over sound + play_game_over() + else: + reset_ball() + game_active = False + update_message("Press SPACE to continue") + + # Ball collision with paddle + paddle_collision = ( + ball_pos_y + BALL_RADIUS >= paddle.y and + ball_pos_y - BALL_RADIUS <= paddle.y + PADDLE_HEIGHT and + ball_pos_x + BALL_RADIUS >= paddle.x and + ball_pos_x - BALL_RADIUS <= paddle.x + PADDLE_WIDTH + ) + + if paddle_collision: + # Determine bounce angle based on where ball hit paddle + # Center of paddle gives straight bounce, edges give angled bounce + hit_position = (ball_pos_x - paddle.x) / PADDLE_WIDTH + angle_factor = 2 * (hit_position - 0.5) # -1 to 1 based on position + + # Set new ball direction with slight speed increase + ball_speed = min(ball_speed * 1.05, 4.5) # Speed up slightly, max at 4.5 + ball_dx = ball_speed * angle_factor + # Ensure upward movement + ball_dy = -ball_speed * (1 - 0.8 * abs(angle_factor)) + + # Ensure ball is above paddle (prevent sticking) + ball_pos_y = paddle.y - BALL_RADIUS - 1 + ball.y = int(ball_pos_y) + + # Play paddle hit sound + play_paddle_hit() + + # Ball collision with bricks + for brick in bricks: + brick_collision = ( + brick in main_group and + brick.x <= ball_pos_x + BALL_RADIUS and + brick.x + BRICK_WIDTH >= ball_pos_x - BALL_RADIUS and + brick.y <= ball_pos_y + BALL_RADIUS and + brick.y + BRICK_HEIGHT >= ball_pos_y - BALL_RADIUS + ) + + if brick_collision: + # Skip if this is the same brick we just hit (prevent double hits) + if brick == last_hit_brick: + continue + + last_hit_brick = brick + main_group.remove(brick) + brick_count -= 1 + + # Determine which side of the brick was hit + dx1 = ball_pos_x - brick.x # Distance from left edge + dx2 = brick.x + BRICK_WIDTH - ball_pos_x # Distance from right edge + dy1 = ball_pos_y - brick.y # Distance from top edge + dy2 = brick.y + BRICK_HEIGHT - ball_pos_y # Distance from bottom edge + + # Find the minimum distance + min_dist = min(dx1, dx2, dy1, dy2) + + # Bounce based on which side was hit + if min_dist in (dy1, dy2): # Top or bottom hit + ball_dy = -ball_dy + else: # Left or right hit + ball_dx = -ball_dx + + # Update score + score += 10 + score_label.text = f"Score: {score}" + + # Play brick hit sound + play_brick_hit() + + # Check win condition + if brick_count <= 0: + game_active = False + game_over = True + update_message("YOU WIN! Press SPACE to play again") + + # Play victory sound + play_level_win() + + # Only process one brick collision per frame + break + + # Reset last_hit_brick if we're not touching it anymore + if last_hit_brick: + still_touching = ( + last_hit_brick.x <= ball_pos_x + BALL_RADIUS and + last_hit_brick.x + BRICK_WIDTH >= ball_pos_x - BALL_RADIUS and + last_hit_brick.y <= ball_pos_y + BALL_RADIUS and + last_hit_brick.y + BRICK_HEIGHT >= ball_pos_y - BALL_RADIUS + ) + if not still_touching: + last_hit_brick = None + + elif not game_active and not game_over: + # Ball sticks to paddle when not active + ball.x = paddle.x + PADDLE_WIDTH // 2 + ball_pos_x = float(ball.x) + + # Refresh display + display.refresh() + time.sleep(0.016) # ~60fps diff --git a/Fruit_Jam/FruitJam_Breakout/icon.bmp b/Fruit_Jam/FruitJam_Breakout/icon.bmp new file mode 100644 index 000000000..d78c04e66 Binary files /dev/null and b/Fruit_Jam/FruitJam_Breakout/icon.bmp differ diff --git a/Fruit_Jam/FruitJam_Breakout/metadata.json b/Fruit_Jam/FruitJam_Breakout/metadata.json new file mode 100644 index 000000000..cbfe8bfdf --- /dev/null +++ b/Fruit_Jam/FruitJam_Breakout/metadata.json @@ -0,0 +1,4 @@ +{ + "title": "Breakout", + "icon": "icon.bmp" +} diff --git a/Fruit_Jam/Fruit_Jam_Examples/Arduino_SD_Card_Read_Write/.fruit_jam.test.only b/Fruit_Jam/Fruit_Jam_Examples/Arduino_SD_Card_Read_Write/.fruit_jam.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Fruit_Jam/Fruit_Jam_Examples/Arduino_SD_Card_Read_Write/Arduino_SD_Card_Read_Write.ino b/Fruit_Jam/Fruit_Jam_Examples/Arduino_SD_Card_Read_Write/Arduino_SD_Card_Read_Write.ino new file mode 100644 index 000000000..90e7fcca9 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Examples/Arduino_SD_Card_Read_Write/Arduino_SD_Card_Read_Write.ino @@ -0,0 +1,91 @@ +// SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +// +// SPDX-License-Identifier: MIT +/* + SD card read/write + + This example shows how to read and write data to and from an SD card file + The circuit: + * SD card attached to SPI bus as follows: + ** MOSI - pin 35 + ** MISO - pin 36 + ** CLK - pin 34 + + created Nov 2010 + by David A. Mellis + modified 9 Apr 2012 + by Tom Igoe + modified 14 Feb 2023 + by Liz Clark + modified 25 Aug 2023 + by Kattni Rembor + modified 18 Feb 2025, 5 Aug 2025 + by Tim Cocks + + + + This example code is in the public domain. + + */ + +#include +#include "SdFat.h" + +#define SD_CS_PIN 39 + +SdFat SD; +FsFile myFile; +SdSpiConfig config(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(16), &SPI); + +void setup() { + // Open serial communications and wait for port to open: + Serial.begin(115200); + while (!Serial) { yield(); delay(10); } // wait till serial port is opened + delay(100); // RP2040 delay is not a bad idea + + Serial.print("Initializing SD card..."); + + // Retry mechanism for SD card initialization + while (!SD.begin(config)) { + Serial.println("initialization failed! Retrying..."); + delay(1000); // Wait for a second before retrying + } + Serial.println("initialization done."); + + // open the file. note that only one file can be open at a time, + // so you have to close this one before opening another. + myFile = SD.open("test.txt", FILE_WRITE); + + // if the file opened okay, write to it: + if (myFile) { + Serial.print("Writing to test.txt..."); + myFile.println("testing 1, 2, 3."); + myFile.println("hello world!"); + // close the file: + myFile.close(); + Serial.println("done."); + } else { + // if the file didn't open, print an error: + Serial.println("error opening test.txt"); + } + + // re-open the file for reading: + myFile = SD.open("test.txt"); + if (myFile) { + Serial.println("test.txt:"); + + // read from the file until there's nothing else in it: + while (myFile.available()) { + Serial.write(myFile.read()); + } + // close the file: + myFile.close(); + } else { + // if the file didn't open, print an error: + Serial.println("error opening test.txt"); + } +} + +void loop() { + // nothing happens after setup +} diff --git a/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_Digital_Input/code.py b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_Digital_Input/code.py new file mode 100644 index 000000000..737378349 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_Digital_Input/code.py @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: 2022 Kattni Rembor for Adafruit Industries +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +CircuitPython Digital Input Example - Blinking an LED using the built-in button. +""" +import board +import digitalio + +led = digitalio.DigitalInOut(board.LED) +led.direction = digitalio.Direction.OUTPUT + +button = digitalio.DigitalInOut(board.BUTTON1) +button.switch_to_input(pull=digitalio.Pull.UP) + +while True: + if not button.value: + led.value = False + else: + led.value = True diff --git a/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_HSTX_DVI/Helvetica-Bold-16.pcf b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_HSTX_DVI/Helvetica-Bold-16.pcf new file mode 100644 index 000000000..deb9092d1 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_HSTX_DVI/Helvetica-Bold-16.pcf differ diff --git a/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_HSTX_DVI/blinka_computer.bmp b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_HSTX_DVI/blinka_computer.bmp new file mode 100644 index 000000000..a746387ba Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_HSTX_DVI/blinka_computer.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_HSTX_DVI/code.py b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_HSTX_DVI/code.py new file mode 100644 index 000000000..1c5ec7017 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_HSTX_DVI/code.py @@ -0,0 +1,314 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries +# SPDX-FileCopyrightText: Adapted from Phil B.'s 16bit_hello Arduino Code +# +# SPDX-License-Identifier: MIT + +import gc +import math +from random import randint +import time +import displayio +import vectorio +import terminalio +import supervisor +import simpleio +from adafruit_bitmap_font import bitmap_font +from adafruit_display_text import label, wrap_text_to_lines +from adafruit_display_shapes.rect import Rect +from adafruit_display_shapes.circle import Circle +from adafruit_display_shapes.roundrect import RoundRect +from adafruit_display_shapes.triangle import Triangle +from adafruit_display_shapes.line import Line + +display = supervisor.runtime.display + +bitmap = displayio.Bitmap(display.width, display.height, 3) + +red = 0xff0000 +yellow = 0xcccc00 +orange = 0xff5500 +blue = 0x0000ff +pink = 0xff00ff +purple = 0x5500ff +white = 0xffffff +green = 0x00ff00 +aqua = 0x125690 + +palette = displayio.Palette(3) +palette[0] = 0x000000 # black +palette[1] = white +palette[2] = yellow + +palette.make_transparent(0) + +tile_grid = displayio.TileGrid(bitmap, pixel_shader=palette) + +group = displayio.Group() + +def clean_up(group_name): + for _ in range(len(group_name)): + group_name.pop() + gc.collect() + +def show_shapes(): + gc.collect() + cx = int(display.width / 2) + cy = int(display.height / 2) + minor = min(cx, cy) + pad = 5 + size = minor - pad + half = int(size / 2) + rect = Rect(cx - minor, cy - minor, size, size, stroke = 1, fill=red, outline = red) + tri = Triangle(cx + pad, cy - pad, cx + pad + half, cy - minor, + cx + minor - 1, cy - pad, fill=green, outline = green) + circ = Circle(cx - pad - half, cy + pad + half, half, fill=blue, stroke = 1, outline = blue) + rnd = RoundRect(cx + pad, cy + pad, size, size, int(size / 5), stroke = 1, + fill=yellow, outline = yellow) + + group.append(rect) + group.append(tri) + group.append(circ) + group.append(rnd) + rect.fill = None + tri.fill = None + circ.fill = None + rnd.fill = None + + time.sleep(2) + + rect.fill = red + tri.fill = green + circ.fill = blue + rnd.fill = yellow + time.sleep(2) + clean_up(group) + del rect + del tri + del circ + del rnd + gc.collect() + +def sine_chart(): + gc.collect() + cx = int(display.width / 2) + cy = int(display.height / 2) + minor = min(cx, cy) + major = max(cx, cy) + + group.append(Line(cx, 0, cx, display.height, blue)) # v + group.append(Line(0, cy, display.width, cy, blue)) # h + + for i in range(10): + _n = simpleio.map_range(i, 0, 10, 0, major - 1) + n = int(_n) + group.append(Line(cx - n, cy - 5, cx - n, (cy - 5) + 11, blue)) # v + group.append(Line(cx + n, cy - 5, cx + n, (cy - 5) + 11, blue)) # v + group.append(Line(cx - 5, cy - n, (cx - 5) + 11, cy - n, blue)) # h + group.append(Line(cx - 5, cy + n, (cx - 5) + 11, cy + n, blue)) # h + + for x in range(display.width): + y = cy - int(math.sin((x - cx) * 0.05) * float(minor * 0.5)) + bitmap[x, y] = 1 + group.append(tile_grid) + time.sleep(2) + clean_up(group) + +def widget0(): + gc.collect() + data = [31, 42, 36, 58, 67, 88] + num_points = len(data) + + text_area = label.Label(terminalio.FONT, text="Widget Sales", color=white) + text_area.anchor_point = (0.5, 0.0) + text_area.anchored_position = (display.width / 2, 3) + group.append(text_area) + for i in range(11): + _x = simpleio.map_range(i, 0, 10, 0, display.width - 1) + x = int(_x) + group.append(Line(x, 20, x, display.height, blue)) + _y = simpleio.map_range(i, 0, 10, 20, display.height - 1) + y = int(_y) + group.append(Line(0, y, display.width, y, blue)) + prev_x = 0 + _prev_y = simpleio.map_range(data[0], 0, 100, display.height - 1, 20) + prev_y = int(_prev_y) + for i in range(1, num_points): + _new_x = simpleio.map_range(i, 0, num_points - 1, 0, display.width - 1) + new_x = int(_new_x) + _new_y = simpleio.map_range(data[i], 0, 100, display.height - 1, 20) + new_y = int(_new_y) + group.append(Line(prev_x, prev_y, new_x, new_y, aqua)) + prev_x = new_x + prev_y = new_y + + for i in range(num_points): + _x = simpleio.map_range(i, 0, num_points - 1, 0, display.width - 1) + x = int(_x) + _y = simpleio.map_range(data[i], 0, 100, display.height - 1, 20) + y = int(_y) + group.append(Circle(x, y, 5, fill=None, stroke = 2, outline = white)) + + time.sleep(2) + clean_up(group) + +def widget1(): + gc.collect() + data = [31, 42, 36, 58, 67, 88] + num_points = len(data) + bar_width = int(display.width / num_points) - 4 + x_mapped_w = display.width + 2 + h_mapped_h = display.height + 20 + + text_area = label.Label(terminalio.FONT, text="Widget Sales", color=white) + text_area.anchor_point = (0.5, 0.0) + text_area.anchored_position = (display.width / 2, 3) + group.append(text_area) + for i in range(11): + _y = simpleio.map_range(i, 0, 10, 20, display.height - 1) + y = int(_y) + group.append(Line(0, y, display.width, y, blue)) + for i in range(num_points): + _x = simpleio.map_range(i, 0, num_points, 0, x_mapped_w) + x = int(_x) + _height = simpleio.map_range(data[i], 0, 100, h_mapped_h, 0) + height = int(_height) + group.append(vectorio.Rectangle(pixel_shader=palette, width=bar_width, + height=display.height + 1, x=x, y=height, color_index = 2)) + + time.sleep(2) + clean_up(group) + +def text_align(): + gc.collect() + TEXT = "hello world" + + text_area_top_left = label.Label(terminalio.FONT, text=TEXT, color=red) + text_area_top_left.anchor_point = (0.0, 0.0) + text_area_top_left.anchored_position = (0, 0) + + text_area_top_middle = label.Label(terminalio.FONT, text=TEXT, color=orange) + text_area_top_middle.anchor_point = (0.5, 0.0) + text_area_top_middle.anchored_position = (display.width / 2, 0) + + text_area_top_right = label.Label(terminalio.FONT, text=TEXT, color=yellow) + text_area_top_right.anchor_point = (1.0, 0.0) + text_area_top_right.anchored_position = (display.width, 0) + + text_area_middle_left = label.Label(terminalio.FONT, text=TEXT, color=green) + text_area_middle_left.anchor_point = (0.0, 0.5) + text_area_middle_left.anchored_position = (0, display.height / 2) + + text_area_middle_middle = label.Label(terminalio.FONT, text=TEXT, color=aqua) + text_area_middle_middle.anchor_point = (0.5, 0.5) + text_area_middle_middle.anchored_position = (display.width / 2, display.height / 2) + + text_area_middle_right = label.Label(terminalio.FONT, text=TEXT, color=blue) + text_area_middle_right.anchor_point = (1.0, 0.5) + text_area_middle_right.anchored_position = (display.width, display.height / 2) + + text_area_bottom_left = label.Label(terminalio.FONT, text=TEXT, color=purple) + text_area_bottom_left.anchor_point = (0.0, 1.0) + text_area_bottom_left.anchored_position = (0, display.height) + + text_area_bottom_middle = label.Label(terminalio.FONT, text=TEXT, color=pink) + text_area_bottom_middle.anchor_point = (0.5, 1.0) + text_area_bottom_middle.anchored_position = (display.width / 2, display.height) + + text_area_bottom_right = label.Label(terminalio.FONT, text=TEXT, color=white) + text_area_bottom_right.anchor_point = (1.0, 1.0) + text_area_bottom_right.anchored_position = (display.width, display.height) + + group.append(text_area_top_middle) + group.append(text_area_top_left) + group.append(text_area_top_right) + group.append(text_area_middle_middle) + group.append(text_area_middle_left) + group.append(text_area_middle_right) + group.append(text_area_bottom_middle) + group.append(text_area_bottom_left) + group.append(text_area_bottom_right) + + time.sleep(2) + clean_up(group) + +def custom_font(): + gc.collect() + my_font = bitmap_font.load_font("/Helvetica-Bold-16.pcf") + text_sample = "The quick brown fox jumps over the lazy dog." + text_sample = "\n".join(wrap_text_to_lines(text_sample, 28)) + text_area = label.Label(my_font, text="Custom Font", color=white) + text_area.anchor_point = (0.0, 0.0) + text_area.anchored_position = (0, 0) + + sample_text = label.Label(my_font, text=text_sample) + sample_text.anchor_point = (0.5, 0.5) + sample_text.anchored_position = (display.width / 2, display.height / 2) + + group.append(text_area) + group.append(sample_text) + + time.sleep(2) + clean_up(group) + + del my_font + gc.collect() + +def bitmap_example(): + gc.collect() + blinka_bitmap = displayio.OnDiskBitmap("/blinka_computer.bmp") + blinka_grid = displayio.TileGrid(blinka_bitmap, pixel_shader=blinka_bitmap.pixel_shader) + gc.collect() + group.append(blinka_grid) + + time.sleep(2) + clean_up(group) + + del blinka_grid + del blinka_bitmap + gc.collect() + +def sensor_values(): + gc.collect() + text_x = "X: %d" % randint(-25, 25) + text_y = "Y: %d" % randint(-25, 25) + text_z = "Z: %d" % randint(-25, 25) + x_text = label.Label(terminalio.FONT, text=text_x, color=red) + x_text.anchor_point = (0.0, 0.0) + x_text.anchored_position = (2, 0) + y_text = label.Label(terminalio.FONT, text=text_y, color=green) + y_text.anchor_point = (0.0, 0.0) + y_text.anchored_position = (2, 10) + z_text = label.Label(terminalio.FONT, text=text_z, color=blue) + z_text.anchor_point = (0.0, 0.0) + z_text.anchored_position = (2, 20) + group.append(x_text) + group.append(y_text) + group.append(z_text) + + for i in range(40): + if i == 10: + group.scale = 2 + elif i == 20: + group.scale = 3 + elif i == 30: + group.scale = 4 + x_text.text = "X: %d" % randint(-50, 50) + y_text.text = "Y: %d" % randint(-50, 50) + z_text.text = "Z: %d" % randint(-50, 50) + time.sleep(0.1) + time.sleep(0.1) + clean_up(group) + group.scale = 1 + +display.root_group = group + +while True: + show_shapes() + sine_chart() + widget0() + widget1() + text_align() + custom_font() + bitmap_example() + sensor_values() diff --git a/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_I2C_Find_Pins/code.py b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_I2C_Find_Pins/code.py new file mode 100644 index 000000000..6817ed149 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_I2C_Find_Pins/code.py @@ -0,0 +1,71 @@ +# SPDX-FileCopyrightText: 2021-2023 Kattni Rembor for Adafruit Industries +# SPDX-License-Identifier: MIT +"""CircuitPython I2C possible pin-pair identifying script""" + + +import board +import busio +from microcontroller import Pin + + +def is_hardware_i2c(scl, sda): + try: + p = busio.I2C(scl, sda) + p.deinit() + return True + except ValueError: + return False + except RuntimeError: + return True + + +def get_unique_pins(): + exclude = [ + getattr(board, p) + for p in [ + # This is not an exhaustive list of unexposed pins. Your results + # may include other pins that you cannot easily connect to. + "NEOPIXEL", + "DOTSTAR_CLOCK", + "DOTSTAR_DATA", + "APA102_SCK", + "APA102_MOSI", + "LED", + "SWITCH", + "BUTTON", + "ACCELEROMETER_INTERRUPT", + "VOLTAGE_MONITOR", + "MICROPHONE_CLOCK", + "MICROPHONE_DATA", + "RFM_RST", + "RFM_CS", + "RFM_IO0", + "RFM_IO1", + "RFM_IO2", + "RFM_IO3", + "RFM_IO4", + "RFM_IO5", + "TFT_I2C_POWER", + "NEOPIXEL_POWER", + "USB_HOST_DATA_MINUS" + ] + if p in dir(board) + ] + pins = [ + pin + for pin in [getattr(board, p) for p in dir(board)] + if isinstance(pin, Pin) and pin not in exclude + ] + unique = [] + for p in pins: + if p not in unique: + unique.append(p) + return unique + + +for scl_pin in get_unique_pins(): + for sda_pin in get_unique_pins(): + if scl_pin is sda_pin: + continue + if is_hardware_i2c(scl_pin, sda_pin): + print("SCL pin:", scl_pin, "\t SDA pin:", sda_pin) diff --git a/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_I2S_Audio_Tone/code.py b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_I2S_Audio_Tone/code.py new file mode 100644 index 000000000..ce2200761 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_I2S_Audio_Tone/code.py @@ -0,0 +1,36 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark, Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import array +import math +import time + +import audiocore + +from adafruit_fruitjam.peripherals import Peripherals + +fruit_jam = Peripherals() + +# use headphones +fruit_jam.dac.headphone_output = True +fruit_jam.dac.dac_volume = -10 # dB +# or use speaker +# fruit_jam.dac.speaker_output = True +# fruit_jam.dac.speaker_volume = -20 # dB + +# generate a sine wave +tone_volume = 0.5 +frequency = 440 +sample_rate = fruit_jam.dac.sample_rate +length = sample_rate // frequency +sine_wave = array.array("h", [0] * length) +for i in range(length): + sine_wave[i] = int((math.sin(math.pi * 2 * i / length)) * tone_volume * (2**15 - 1)) +sine_wave_sample = audiocore.RawSample(sine_wave, sample_rate=sample_rate) + +while True: + fruit_jam.audio.stop() + time.sleep(1) + fruit_jam.audio.play(sine_wave_sample, loop=True) + time.sleep(1) diff --git a/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_I2S_Audio_Wave_File/StreetChicken.wav b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_I2S_Audio_Wave_File/StreetChicken.wav new file mode 100644 index 000000000..55d4eb0f2 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_I2S_Audio_Wave_File/StreetChicken.wav differ diff --git a/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_I2S_Audio_Wave_File/code.py b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_I2S_Audio_Wave_File/code.py new file mode 100644 index 000000000..2d1da1e05 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_I2S_Audio_Wave_File/code.py @@ -0,0 +1,28 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark, Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import audiocore + +from adafruit_fruitjam.peripherals import Peripherals + +fruit_jam = Peripherals() + +# use headphones +fruit_jam.dac.headphone_output = True +fruit_jam.dac.dac_volume = -10 # dB +# or use speaker +# fruit_jam.dac.speaker_output = True +# fruit_jam.dac.speaker_volume = -20 # dB + +# set sample rate & bit depth, use bclk +fruit_jam.dac.configure_clocks(sample_rate=44100, bit_depth=16) + +with open("StreetChicken.wav", "rb") as wave_file: + wav = audiocore.WaveFile(wave_file) + + print("Playing wav file!") + fruit_jam.audio.play(wav) + while fruit_jam.audio.playing: + pass + +print("Done!") diff --git a/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_NeoPixels_RGB/code.py b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_NeoPixels_RGB/code.py new file mode 100644 index 000000000..bc51fb6bb --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_NeoPixels_RGB/code.py @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries +# SPDX-License-Identifier: MIT +"""CircuitPython status NeoPixel red, green, blue example.""" +import time +import board +import neopixel + +pixel = neopixel.NeoPixel(board.NEOPIXEL, 5) + +pixel.brightness = 0.3 + +while True: + pixel.fill((255, 0, 0)) + time.sleep(0.5) + pixel.fill((0, 255, 0)) + time.sleep(0.5) + pixel.fill((0, 0, 255)) + time.sleep(0.5) diff --git a/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_NeoPixels_Rainbow/code.py b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_NeoPixels_Rainbow/code.py new file mode 100644 index 000000000..27d9f8cc4 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_NeoPixels_Rainbow/code.py @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +"""CircuitPython status NeoPixel rainbow example.""" +import time +import board +from rainbowio import colorwheel +import neopixel + +pixel = neopixel.NeoPixel(board.NEOPIXEL, 5) +pixel.brightness = 0.3 + + +def rainbow(delay): + for color_value in range(255): + pixel.fill(colorwheel(color_value)) + time.sleep(delay) + + +while True: + rainbow(0.02) diff --git a/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_SD_Card_Read/code.py b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_SD_Card_Read/code.py new file mode 100644 index 000000000..c7473419a --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_SD_Card_Read/code.py @@ -0,0 +1,40 @@ +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +CircuitPython Essentials SD Card Read Demo + +The SD Card is automatically mounted by CircuitPython on the Fruit Jam. +""" + +import os + +def print_directory(path, tabs=0): + for file in os.listdir(path): + stats = os.stat(path + "/" + file) + filesize = stats[6] + isdir = stats[0] & 0x4000 + + if filesize < 1000: + sizestr = str(filesize) + " bytes" + elif filesize < 1000000: + sizestr = "%0.1f KB" % (filesize / 1000) + else: + sizestr = "%0.1f MB" % (filesize / 1000000) + + prettyprintname = "" + for _ in range(tabs): + prettyprintname += " " + prettyprintname += file + if isdir: + prettyprintname += "/" + print("{0:<40} Size: {1:>10}".format(prettyprintname, sizestr)) + + # recursively print directory contents + if isdir: + print_directory(path + "/" + file, tabs + 1) + + +print("Files on filesystem:") +print("====================") +print_directory("/sd") diff --git a/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_SD_Card_Write/code.py b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_SD_Card_Write/code.py new file mode 100644 index 000000000..594447a32 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_SD_Card_Write/code.py @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: 2017 Limor Fried for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +CircuitPython Essentials SD Card Write Demo + +The SD Card is automatically mounted by CircuitPython on the Fruit Jam +""" + +import time +import microcontroller + +# Use the filesystem as normal! Our files are under /sd + +print("Logging temperature to filesystem") +# append to the file! +while True: + # open file for append + with open("/sd/temperature.txt", "a") as f: + t = microcontroller.cpu.temperature + print("Temperature = %0.1f" % t) + f.write("%0.1f\n" % t) + # file is saved + time.sleep(1) diff --git a/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_WIFI/code.py b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_WIFI/code.py new file mode 100644 index 000000000..80357c2b4 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Examples/CircuitPython_WIFI/code.py @@ -0,0 +1,72 @@ +# SPDX-FileCopyrightText: 2019 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT + +from os import getenv + +import adafruit_connection_manager +import adafruit_requests +import board +from digitalio import DigitalInOut + +from adafruit_esp32spi import adafruit_esp32spi + +# Get wifi details and more from a settings.toml file +# tokens used by this Demo: CIRCUITPY_WIFI_SSID, CIRCUITPY_WIFI_PASSWORD +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +print("ESP32 SPI webclient test") + +TEXT_URL = "http://wifitest.adafruit.com/testwifi/index.html" +JSON_URL = "http://wifitest.adafruit.com/testwifi/sample.json" + + +# If you are using a board with pre-defined ESP32 Pins: +esp32_cs = DigitalInOut(board.ESP_CS) +esp32_ready = DigitalInOut(board.ESP_BUSY) +esp32_reset = DigitalInOut(board.ESP_RESET) + +spi = board.SPI() +esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) + +pool = adafruit_connection_manager.get_radio_socketpool(esp) +ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp) +requests = adafruit_requests.Session(pool, ssl_context) + +if esp.status == adafruit_esp32spi.WL_IDLE_STATUS: + print("ESP32 found and in idle mode") +print("Firmware vers.", esp.firmware_version) +print("MAC addr:", ":".join("%02X" % byte for byte in esp.MAC_address)) + +for ap in esp.scan_networks(): + print("\t%-23s RSSI: %d" % (ap.ssid, ap.rssi)) + +print("Connecting to AP...") +while not esp.is_connected: + try: + esp.connect_AP(ssid, password) + except OSError as e: + print("could not connect to AP, retrying: ", e) + continue +print("Connected to", esp.ap_info.ssid, "\tRSSI:", esp.ap_info.rssi) +print("My IP address is", esp.ipv4_address) +print("IP lookup adafruit.com: %s" % esp.pretty_ip(esp.get_host_by_name("adafruit.com"))) +print("Ping google.com: %d ms" % esp.ping("google.com")) + +# esp._debug = True +print("Fetching text from", TEXT_URL) +r = requests.get(TEXT_URL) +print("-" * 40) +print(r.text) +print("-" * 40) +r.close() + +print() +print("Fetching json from", JSON_URL) +r = requests.get(JSON_URL) +print("-" * 40) +print(r.json()) +print("-" * 40) +r.close() + +print("Done!") diff --git a/Fruit_Jam/Fruit_Jam_IRC_Client/beep.wav b/Fruit_Jam/Fruit_Jam_IRC_Client/beep.wav new file mode 100644 index 000000000..65ec415b4 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_IRC_Client/beep.wav differ diff --git a/Fruit_Jam/Fruit_Jam_IRC_Client/code.py b/Fruit_Jam/Fruit_Jam_IRC_Client/code.py new file mode 100644 index 000000000..1ea8ea9f4 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_IRC_Client/code.py @@ -0,0 +1,75 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +from os import getenv +from displayio import Group +from terminalio import FONT +import supervisor +import audiocore +import board +import busio +from digitalio import DigitalInOut +from adafruit_esp32spi import adafruit_esp32spi +from adafruit_color_terminal import ColorTerminal +from adafruit_fruitjam.peripherals import Peripherals + +from curses_irc_client import run_irc_client + +# Configuration - modify these values as needed +IRC_CONFIG = { + "server": "irc.libera.chat", # Example: irc.libera.chat, irc.freenode.net + # "port": 6667, # 6667 - clear text + "port": 6697, # 6697 - TLS encrypted + "username": "", + "channel": "#adafruit-fruit-jam", +} + +if IRC_CONFIG["username"] == "": + raise ValueError("username must be set in IRC_CONFIG") + +main_group = Group() +display = supervisor.runtime.display + +font_bb = FONT.get_bounding_box() +screen_size = (display.width // font_bb[0], display.height // font_bb[1]) + +terminal = ColorTerminal(FONT, screen_size[0], screen_size[1]) +main_group.append(terminal.tilegrid) +display.root_group = main_group + +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +# If you are using a board with pre-defined ESP32 Pins: +esp32_cs = DigitalInOut(board.ESP_CS) +esp32_ready = DigitalInOut(board.ESP_BUSY) +esp32_reset = DigitalInOut(board.ESP_RESET) + +spi = busio.SPI(board.SCK, board.MOSI, board.MISO) +esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) + +print("Connecting to AP...") +while not esp.is_connected: + try: + esp.connect_AP(ssid, password) + except RuntimeError as e: + print("could not connect to AP, retrying: ", e) + continue + +print("IRC Configuration:") +print(f"Server: {IRC_CONFIG['server']}:{IRC_CONFIG['port']}") +print(f"Nickname: {IRC_CONFIG['username']}") +print(f"Channel: {IRC_CONFIG['channel']}") +print("-" * 40) + +fruit_jam_peripherals = Peripherals() +beep_wave = audiocore.WaveFile("beep.wav") +run_irc_client( + esp, + IRC_CONFIG, + terminal, + terminal.tilegrid, + audio_interface=fruit_jam_peripherals.audio, + beep_wave=beep_wave, +) diff --git a/Fruit_Jam/Fruit_Jam_IRC_Client/curses_irc_client.py b/Fruit_Jam/Fruit_Jam_IRC_Client/curses_irc_client.py new file mode 100644 index 000000000..e00bdc43f --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_IRC_Client/curses_irc_client.py @@ -0,0 +1,249 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +import time +import adafruit_dang as curses + +from irc_client import IRCClient + +ANSI_BLACK_ON_GREY = chr(27) + "[30;100m" +ANSI_RESET = chr(27) + "[0m" + + +class Window: + """ + Terminal Window class that supports basic scrolling. + """ + + def __init__(self, n_rows, n_cols, row=0, col=0): + self.n_rows = n_rows + self.n_cols = n_cols + self.row = row + self.col = col + + @property + def bottom(self): + return self.row + self.n_rows - 1 + + def up(self, cursor): # pylint: disable=invalid-name + if cursor.row == self.row - 1 and self.row > 0: + self.row -= 1 + + def down(self, buffer, cursor): + if cursor.row == self.bottom + 1 and self.bottom < len(buffer) - 1: + self.row += 1 + + def horizontal_scroll(self, cursor, left_margin=5, right_margin=2): + n_pages = cursor.col // (self.n_cols - right_margin) + self.col = max(n_pages * self.n_cols - right_margin - left_margin, 0) + + def translate(self, cursor): + return cursor.row - self.row, cursor.col - self.col + + +def irc_client_main( + stdscr, + radio, + irc_config, + terminal_tilegrid=None, + audio_interface=None, + beep_wave=None, +): + # pylint: disable=too-many-locals, too-many-branches, too-many-statements + """ + Main curses IRC client application loop. + """ + irc_client = IRCClient( + radio, irc_config, audio_interface=audio_interface, beep_wave=beep_wave + ) + irc_client.connect() + # irc_client.join() + + window = Window(terminal_tilegrid.height, terminal_tilegrid.width) + stdscr.erase() + img = [None] * window.n_rows + status_bar = { + "user_message": None, + "user_message_shown_time": 0, + } + + cur_row_index = 0 + + user_input = "" + + def show_user_message(message): + """ + Show a status message to the user + """ + status_bar["user_message"] = message + ( + " " * (window.n_cols - 1 - len(message)) + ) + status_bar["user_message_shown_time"] = time.monotonic() + + def setline(row, line): + """ + Set a line of text in the terminal window. + """ + if img[row] == line: + return + img[row] = line + line += " " * (window.n_cols - len(line) - 1) + stdscr.addstr(row, 0, line) + + def get_page(row_index): + """ + Get a page of messages from the message buffer. + """ + page_len = window.n_rows - 2 + + page_start = max((len(irc_client.message_buffer) + row_index) - page_len, 0) + page_end = page_start + page_len + + page = irc_client.message_buffer[page_start:page_end] + return page + + # pylint: disable=too-many-nested-blocks + try: + # main application loop + while True: + lastrow = 0 + lines_added = irc_client.update() + + cur_page = get_page(cur_row_index) + + if lines_added > 0 and len(cur_page) < window.n_rows - 2: + cur_row_index = max(cur_row_index - lines_added, 0) + cur_page = get_page(cur_row_index) + + for row, line in enumerate(cur_page): + lastrow = row + setline(row, line) + + for row in range(lastrow + 1, window.n_rows - 2): + setline(row, "") + + user_input_row = window.n_rows - 2 + if user_input: + setline(user_input_row, user_input) + else: + setline(user_input_row, " " * (window.n_cols - 1)) + + user_message_row = terminal_tilegrid.height - 1 + if status_bar["user_message"] is None: + message = f" {irc_config['username']} | {irc_config['server']} | {irc_config['channel']}" # pylint: disable=line-too-long + message += " " * (terminal_tilegrid.width - len(message) - 1) + line = f"{ANSI_BLACK_ON_GREY}{message}{ANSI_RESET}" + else: + line = f"{ANSI_BLACK_ON_GREY}{status_bar['user_message']}{ANSI_RESET}" + if status_bar["user_message_shown_time"] + 3.0 < time.monotonic(): + status_bar["user_message"] = None + setline(user_message_row, line) + + # read from the keyboard + k = stdscr.getkey() + if k is not None: + if len(k) == 1 and " " <= k <= "~": + user_input += k + + elif k == "\n": # enter key pressed + if not user_input.startswith("/"): + print(f"sending: {user_input}") + irc_client.send_message(user_input) + user_input = "" + else: # slash commands + parts = user_input.split(" ", 1) + if parts[0] in {"/j", "/join"}: + if len(parts) >= 2 and parts[1] != "": + if parts[1] != irc_client.config["channel"]: + irc_client.join(parts[1]) + user_input = "" + else: + show_user_message("Already in channel") + user_input = "" + + else: + show_user_message( + "Invalid /join arg. Use: /join " + ) + user_input = "" + elif parts[0] == "/msg": + to_user, message_to_send = parts[1].split(" ", 1) + irc_client.send_dm(to_user, message_to_send) + user_input = "" + elif parts[0] == "/beep": + to_user = parts[1] + message_to_send = "*Beep*\x07" + irc_client.send_dm(to_user, message_to_send) + user_input = "" + elif parts[0] == "/op": + user_to_op = parts[1] + irc_client.op(user_to_op) + user_input = "" + elif parts[0] == "/deop": + user_to_op = parts[1] + irc_client.deop(user_to_op) + user_input = "" + elif parts[0] == "/kick": + user_to_kick = parts[1] + irc_client.kick(user_to_kick) + user_input = "" + elif parts[0] == "/ban": + user_to_ban = parts[1] + irc_client.ban(user_to_ban) + user_input = "" + elif parts[0] == "/unban": + user_to_unban = parts[1] + irc_client.unban(user_to_unban) + user_input = "" + elif parts[0] == "/whois": + user_to_check = parts[1] + irc_client.whois(user_to_check) + user_input = "" + + elif k in ("KEY_BACKSPACE", "\x7f", "\x08"): + user_input = user_input[:-1] + elif k == "KEY_UP": + page_len = window.n_rows - 2 + if len(irc_client.message_buffer) > page_len: + page_start = ( + len(irc_client.message_buffer) + cur_row_index + ) - page_len + if page_start > 0: + cur_row_index -= 1 + elif k == "KEY_DOWN": + if cur_row_index < 0: + cur_row_index += 1 + + elif k == "KEY_PGUP": + page_len = window.n_rows - 2 + if len(irc_client.message_buffer) > page_len: + page_start = ( + len(irc_client.message_buffer) + cur_row_index + ) - page_len + if page_start > 0: + cur_row_index -= 6 + elif k == "KEY_PGDN": + if cur_row_index <= 0: + cur_row_index = cur_row_index + 6 + else: + print(f"unknown key: {k}") + + except KeyboardInterrupt as exc: + irc_client.disconnect() + raise KeyboardInterrupt from exc + + +def run_irc_client( + radio, irc_config, terminal, terminal_tilegrid, audio_interface=None, beep_wave=None +): + """ + Entry point to run the curses IRC client application. + """ + return curses.custom_terminal_wrapper( + terminal, + irc_client_main, + radio, + irc_config, + terminal_tilegrid, + audio_interface, + beep_wave, + ) diff --git a/Fruit_Jam/Fruit_Jam_IRC_Client/icon.bmp b/Fruit_Jam/Fruit_Jam_IRC_Client/icon.bmp new file mode 100644 index 000000000..879f8e836 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_IRC_Client/icon.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_IRC_Client/irc_client.py b/Fruit_Jam/Fruit_Jam_IRC_Client/irc_client.py new file mode 100644 index 000000000..09831ce6e --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_IRC_Client/irc_client.py @@ -0,0 +1,493 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +import time + +import adafruit_connection_manager + +ANSI_ESCAPE_CODES = [ + chr(27) + "[30m", + chr(27) + "[31m", + chr(27) + "[32m", + chr(27) + "[33m", + chr(27) + "[34m", + chr(27) + "[35m", + chr(27) + "[36m", +] +ANSI_RESET = chr(27) + "[0m" + + +class IRCClient: + """ + Handles interaction with IRC Server and makes incoming messages available. + + :param radio: The network radio to connect with. + :param dict irc_config: Dictionary containing IRC configration for + server, port, username and channel. + :param audio_interface: Optional interface to play audio from for beep messages + :param beep_wave: Optional wave file to use for beep messages + :param int max_line_length: Maximum characters per line to format messages into. + """ + + def __init__( + self, + radio, + irc_config, + audio_interface=None, + beep_wave=None, + max_line_length=120, + ): + self.radio = radio + self.config = irc_config + required = {"username", "server", "channel"} + for key in required: + if key not in self.config: + raise ValueError( + f"missing required config key. Required keys are: {required}" + ) + + if "port" not in self.config: + self.config["port"] = 6667 + if "timeout" not in self.config: + self.config["timeout"] = 120 + + self.pool = adafruit_connection_manager.get_radio_socketpool(radio) + self.connection_manager = adafruit_connection_manager.get_connection_manager( + self.pool + ) + + ssl_context = adafruit_connection_manager.get_radio_ssl_context(radio) + print(f"Connecting to {self.config['server']}:{self.config['port']}...") + self.socket = self.connection_manager.get_socket( + self.config["server"], + self.config["port"], + "", + timeout=0.01, + is_ssl=True, + ssl_context=ssl_context, + ) + print("Connected") + + # color to use for next unique username + self.next_color_index = 4 + + # map of unique usernames to color + self.user_color_map = {} + + # buffer for incoming data until it's a full line + self.line_buffer = "" + + # buffer for full incoming chat messages + self.message_buffer = [] + + # whether to show whois reply message on screen + self.show_whois_reply = False + + self.audio_interface = audio_interface + if audio_interface is not None: + self.beep_wave = beep_wave + + self.max_line_length = max_line_length + + def connect(self): + """ + Connect to IRC Server + """ + # Send nick and user info + self.socket.send(f"NICK {self.config['username']}\r\n".encode("utf-8")) + self.socket.send( + f"USER {self.config['username']} 0 * :{self.config['username']}\r\n".encode( + "utf-8" + ) + ) + + def disconnect(self): + """ + Disconnect from IRC Server + """ + self.socket.send("QUIT :Goodbye\r\n".encode("utf-8")) + self.socket.close() + + def readlines(self): + """ + Read incoming data from the socket and return a list of lines read. + """ + lines = [] + # Receive data + data = self.socket.recv(4096).decode("utf-8") + if not data: + raise RuntimeError("Connection closed by server") + + self.line_buffer += data + + # Process complete lines + while "\r\n" in self.line_buffer: + line, self.line_buffer = self.line_buffer.split("\r\n", 1) + + if line: + lines.append(line) + + return lines + + def update(self): + """ + Check for udpates from the server. Main loop of the program should call this. + """ + updated_display_lines = 0 + try: + lines = self.readlines() + for line in lines: + updated_display_lines += self.process_message(line) + + except OSError as e: + # no data before timeout + # print(e) + if "ETIMEDOUT" not in str(e): + raise RuntimeError(e) from e + # raise RuntimeError("Connection timed out") + return updated_display_lines + + def send_message(self, message): + """ + Send a message to the channel that the user is in. + """ + irc_command = f"PRIVMSG {self.config['channel']} :{message}\r\n" + self.socket.send(irc_command.encode("utf-8")) + self.process_message( + f":{self.config['username']}!~{self.config['username']}@localhost " + + irc_command[:-2] + ) + + def send_dm(self, to_user, message): + """ + Send a direct message to a specified user. + """ + irc_command = f"PRIVMSG {to_user} :{message}\r\n" + self.socket.send(irc_command.encode("utf-8")) + color = self.get_color_for_user(to_user) + self.message_buffer.append(f"DM out: <{color}{to_user}{ANSI_RESET}> {message}") + + def op(self, user): + """ + Make specified user an operator in the channel that the user is in. + You must already be an operator to grant operator privilege. + """ + op_cmd = f"MODE {self.config['channel']} +o {user}\r\n" + self.socket.send(op_cmd.encode("utf-8")) + + def deop(self, user): + """ + Remove operator privilege from the specified user for this channel. + """ + deop_cmd = f"MODE {self.config['channel']} -o {user}\r\n" + self.socket.send(deop_cmd.encode("utf-8")) + + def kick(self, user): + """ + Kick a specified user from the channel. + """ + kick_cmd = f"KICK {self.config['channel']} {user}\r\n" + self.socket.send(kick_cmd.encode("utf-8")) + + def get_technical_name(self, nickname): + """ + Get the full technical name of a user given a nickname + """ + start_time = time.monotonic() + whois_cmd = f"WHOIS {nickname}\r\n" + self.socket.send(whois_cmd.encode("utf-8")) + + whois_resp_lines = None + while whois_resp_lines is None and start_time + 3.0 > time.monotonic(): + try: + whois_resp_lines = self.readlines() + except OSError as e: + if "ETIMEDOUT" in str(e): + whois_resp_lines = None + else: + raise RuntimeError(e) from e + + if whois_resp_lines is None: + return None + + for line in whois_resp_lines: + line = line.lstrip("\0") + parts = line.split(" ", 2) + if len(parts) >= 2: + command = parts[1] + if command != "311": + self.process_message(line) + continue + + whois_response = parts[2].split(" ", 1)[1] + response_parts = whois_response.split(" ") + technical_name = f"*!{response_parts[1]}@{response_parts[2]}" + return technical_name + + return None + + def ban(self, user): + """ + Ban the specified user from the channel + """ + technical_name = self.get_technical_name(user) + if technical_name is not None: + ban_cmd = f"MODE {self.config['channel']} +b {technical_name}\r\n" + self.socket.send(ban_cmd.encode("utf-8")) + else: + self.message_buffer.append( + f"{ANSI_RESET} Error: failed whois lookup for ban" + ) + + def unban(self, user): + """ + Unban the specified user from the channel + """ + technical_name = self.get_technical_name(user) + if technical_name is not None: + ban_cmd = f"MODE {self.config['channel']} -b {technical_name}\r\n" + self.socket.send(ban_cmd.encode("utf-8")) + else: + self.message_buffer.append( + f"{ANSI_RESET} Error: failed whois lookup for unban" + ) + + def whois(self, user): + """ + Run a whois query on the specified user + """ + self.show_whois_reply = True + whois_cmd = f"WHOIS {user}\r\n" + self.socket.send(whois_cmd.encode("utf-8")) + + def leave_channel(self): + """ + Leave the channel + """ + + self.socket.send(f"PART {self.config['channel']}\r\n".encode("utf-8")) + + def join(self, new_channel=None): + """ + Join the specified channel. This will leave the prior channel. + """ + if new_channel is not None and new_channel != self.config["channel"]: + self.leave_channel() + self.config["channel"] = new_channel + + print(f"Joining channel {self.config['channel']}...") + self.socket.send(f"JOIN {self.config['channel']}\r\n".encode("utf-8")) + self.message_buffer.append(f"{ANSI_RESET}* Joined {self.config['channel']} *") + + def get_color_for_user(self, username): + """ + Get the color to use for the specified username + """ + if username not in self.user_color_map: + self.user_color_map[username] = self.next_color_index + self.next_color_index += 1 + if self.next_color_index > 6: + self.next_color_index = 1 + + return ANSI_ESCAPE_CODES[self.user_color_map[username]] + + @staticmethod + def split_string_chunks(s, chunk_size): + """ + Split a string into chunks of specified size. + """ + chunks = [] + for i in range(0, len(s), chunk_size): + chunks.append(s[i : i + chunk_size]) + return chunks + + def process_message(self, message): + # pylint: disable=too-many-branches, too-many-statements + """ + Process an incoming IRC message + :param message: The message that came from the IRC server. + + :return lines_added: The number of lines added to the display + """ + # pylint: disable=too-many-locals + lines_added = 0 + + message = message.lstrip("\x00") + print(f"RAW: {message.encode('utf-8')}") + + # Handle PING messages (keep connection alive) + if message.startswith("PING"): + pong_response = message.replace("PING", "PONG") + self.socket.send(f"{pong_response}\r\n".encode("utf-8")) + print("Responded to PING") + return 0 + + # Parse IRC message format: :prefix COMMAND params + parts = message.split(" ", 2) + # pylint: disable=too-many-nested-blocks + if len(parts) >= 2: + command = parts[1] + try: + command_num = int(command) + except ValueError: + command_num = None + + # End of MOTD - now we can join the channel + if command in {"376", "422"}: # 422 is "no MOTD" + # join channel + self.join() + + # Welcome messages (001-004 are standard welcome messages) + elif command in [ + "001", + "002", + "003", + "004", + "251", + "252", + "253", + "254", + "255", + "265", + "266", + "375", + "372", + ]: + if len(parts) >= 3: + welcome_text = parts[2] + if welcome_text.startswith(":"): + welcome_text = welcome_text[1:] + + print( + f"'{welcome_text[0:11]}' startswith '{self.config['username']}' ? {welcome_text.startswith(self.config['username'])}" # pylint: disable=line-too-long + ) + if welcome_text.startswith(self.config["username"]): + welcome_text = welcome_text.replace( + self.config["username"], "", 1 + ) + # terminal.write(f"WELCOME: {welcome_text}\n") + self.message_buffer.append(f"{welcome_text}") + lines_added += 1 + print(f"WELCOME: {welcome_text}") + + # Channel messages + elif command == "PRIVMSG": + if len(parts) >= 3: + # Extract sender nickname + sender = parts[0] + if sender.startswith(":"): + sender = sender[1:] + if "!" in sender: + sender = sender.split("!")[0] + + # Extract message content + message_content = parts[2] + + inc_channel, inc_message = message_content.split(" ", 1) + + message_content = inc_message[1:] + + if "*beep*" in message_content: + if ( + self.audio_interface is not None + and not self.audio_interface.playing + ): + print("playing beep") + self.audio_interface.play(self.beep_wave) + # print(f"is playing: {self.audio_interface.playing}") + while self.audio_interface.playing: + pass + + print(f"message_content: {message_content.encode('utf-8')}") + + color = self.get_color_for_user(sender) + + if inc_channel == self.config["channel"]: + full_line = f"<{color}{sender}{ANSI_RESET}> {message_content}" + if len(full_line) < self.max_line_length: + self.message_buffer.append(full_line) + lines_added += 1 + else: + chunks = self.split_string_chunks( + full_line, self.max_line_length + ) + for chunk in chunks: + self.message_buffer.append(f"{ANSI_RESET}{chunk}") + lines_added += 1 + elif inc_channel == self.config["username"]: + self.message_buffer.append( + f"DM in: <{color}{sender}{ANSI_RESET}> {message_content}" + ) + lines_added += 1 + print(f"<{sender}> {message_content}") + + # Join confirmations + elif command == "JOIN": + sender = parts[0] + if sender.startswith(":"): + sender = sender[1:] + if "!" in sender: + sender = sender.split("!")[0] + + if len(parts) >= 3: + joined_channel = parts[2] + if joined_channel.startswith(":"): + joined_channel = joined_channel[1:] + print(f"*** {sender} joined {joined_channel}") + + # error messages + elif command_num is not None and 400 <= command_num <= 553: + # message codes: https://www.alien.net.au/irc/irc2numerics.html + self.message_buffer.append(f"{ANSI_RESET}{command} {parts[2]}") + lines_added += 1 + + # whois reply + elif self.show_whois_reply and command == "311": + whois_response = parts[2].split(" ", 1)[1] + self.message_buffer.append(f"{ANSI_RESET}{whois_response}") + lines_added += 1 + self.show_whois_reply = False + + # Mode messages + elif command == "MODE": + action_user = parts[0].split("!", 1)[0][1:] + mode_msg_parts = parts[2].split(" ", 2) + if len(mode_msg_parts) >= 3: + channel, mode, target_user = ( # pylint: disable=unused-variable + mode_msg_parts + ) + action_user_color = self.get_color_for_user(action_user) + target_user_color = self.get_color_for_user(target_user) + self.message_buffer.append( + f"{action_user_color}{action_user}{ANSI_RESET} sets mode {mode} on {target_user_color}{target_user}{ANSI_RESET}" # pylint: disable=line-too-long + ) + lines_added += 1 + + # Part messages + elif command == "PART": + sender = parts[0] + if sender.startswith(":"): + sender = sender[1:] + if "!" in sender: + sender = sender.split("!")[0] + + if len(parts) >= 3: + left_channel = parts[2] + print(f"*** {sender} left {left_channel}") + + # Quit messages + elif command == "QUIT": + sender = parts[0] + if sender.startswith(":"): + sender = sender[1:] + if "!" in sender: + sender = sender.split("!")[0] + + quit_message = "" + if len(parts) >= 3: + quit_message = parts[2] + if quit_message.startswith(":"): + quit_message = quit_message[1:] + + print(f"*** {sender} quit ({quit_message})") + + return lines_added diff --git a/Fruit_Jam/Fruit_Jam_IRC_Client/metadata.json b/Fruit_Jam/Fruit_Jam_IRC_Client/metadata.json new file mode 100644 index 000000000..ef6803a63 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_IRC_Client/metadata.json @@ -0,0 +1,4 @@ +{ + "title": "IRC Client", + "icon": "icon.bmp" +} diff --git a/Fruit_Jam/Fruit_Jam_Logic_Gates/code.py b/Fruit_Jam/Fruit_Jam_Logic_Gates/code.py new file mode 100644 index 000000000..13819d2cb --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Logic_Gates/code.py @@ -0,0 +1,127 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +Fruit Jam Logic Gates Simulator +""" +import sys +import time + +import board +from digitalio import DigitalInOut, Pull, Direction +from displayio import Group + +import supervisor +from neopixel import NeoPixel +from adafruit_usb_host_mouse import find_and_init_boot_mouse +from adafruit_fruitjam.peripherals import request_display_config +from workspace import Workspace + +# cooldown time to ignore double clicks +CLICK_COOLDOWN = 0.15 +last_click_time = None + +# set the display size to 320,240 +request_display_config(320, 240) +display = supervisor.runtime.display + +# setup the mouse +mouse = find_and_init_boot_mouse() +mouse.sensitivity = 1.5 +if mouse is None: + raise RuntimeError( + "No mouse found connected to USB Host. A mouse is required for this app." + ) + +# setup displayio Group for visuals +main_group = Group() +display.root_group = main_group + +# setup physical hardware buttons +btn_1 = DigitalInOut(board.BUTTON1) +btn_1.direction = Direction.INPUT +btn_1.pull = Pull.UP +btn_2 = DigitalInOut(board.BUTTON2) +btn_2.direction = Direction.INPUT +btn_2.pull = Pull.UP +btn_3 = DigitalInOut(board.BUTTON3) +btn_3.direction = Direction.INPUT +btn_3.pull = Pull.UP + +# setup neopixels +neopixels = NeoPixel(board.NEOPIXEL, 5, brightness=0.2, auto_write=True) + +# setup Workspace object, giving it the neopixels, and hardware button objects +workspace = Workspace(neopixels, (btn_1, btn_2, btn_3)) + +# add workspace elements to the Group to be shown on display +main_group.append(workspace.group) +main_group.append(workspace.mouse_moving_tg) + +# add the mouse to the Group to be shown on top of everything else +main_group.append(mouse.tilegrid) + +# hardware button state variables +old_button_values = [True, True, True] +button_values_changed = False + +waiting_for_release = False + +while True: + # update mouse, and get any mouse buttons that are pressed + pressed_btns = mouse.update() + + # enforce click cooldown to ignore double clicks + now = time.monotonic() + if last_click_time is None or now > last_click_time + CLICK_COOLDOWN: + # if any buttons are pressed + if not waiting_for_release and pressed_btns is not None and len(pressed_btns) > 0: + waiting_for_release = True + click_x = mouse.x + click_y = mouse.y + click_btns = pressed_btns + elif waiting_for_release and not mouse.pressed_btns: + waiting_for_release = False + last_click_time = now + # let workspace handle the click event + workspace.handle_mouse_click(click_x, click_y, click_btns) + + # if there is an entity on the mouse being moved + if not workspace.mouse_moving_tg.hidden: + # update its TileGrid's location to follow the mouse + workspace.mouse_moving_tg.x = mouse.x - 12 + workspace.mouse_moving_tg.y = mouse.y - 24 - 12 + + # check how many bytes are available from keyboard + available = supervisor.runtime.serial_bytes_available + + # if there are some bytes available + if available: + # read data from the keyboard input + c = sys.stdin.read(available) + key_bytes = c.encode("utf-8") + # let workspace handle the key press event + workspace.handle_key_press(key_bytes, mouse.x, mouse.y) + + # get hardware button states + btn_1_current = btn_1.value + btn_2_current = btn_2.value + btn_3_current = btn_3.value + button_values_changed = False + + # check if any hardware button states have changed + if btn_1_current != old_button_values[0]: + button_values_changed = True + if btn_2_current != old_button_values[1]: + button_values_changed = True + if btn_3_current != old_button_values[2]: + button_values_changed = True + + # update the old button states to compare with next iteration + old_button_values[0] = btn_1_current + old_button_values[1] = btn_2_current + old_button_values[2] = btn_3_current + + # if any button state changed, update workspace to run simulation + if button_values_changed: + workspace.update() diff --git a/Fruit_Jam/Fruit_Jam_Logic_Gates/entity.py b/Fruit_Jam/Fruit_Jam_Logic_Gates/entity.py new file mode 100644 index 000000000..35b7586f9 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Logic_Gates/entity.py @@ -0,0 +1,1282 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# pylint: disable=abstract-method, attribute-defined-outside-init, unsubscriptable-object, useless-object-inheritance +# pylint: disable=unsupported-assignment-operation, line-too-long, too-many-lines, too-many-branches + +try: + from typing import Optional +except ImportError: + pass + +COLOR_COUNT = 8 +EMPTY = 8 +X = 0 +Y = 1 +WIDTH = 0 +HEIGHT = 1 + + +class Entity(object): + """ + Class representing an entity that can be added to a workspace. + All Gates and other objects that can be used in the simulation will extend this class. + """ + + size = (1, 1) + """Size in tiles of the rectangle that contains the entity. + Note that some tiles with this maybe unused.""" + + _location = (0, 0) + """The location of the top left tile of the entity within the workspace""" + + tile_locations = (_location,) + """Locations of all tiles used by the entity""" + + tiles = (EMPTY,) + """Tile indexes from the spritesheet used by the entity""" + + type = "None" + """The entity type""" + + _workspace = None + + def apply_state_palette_mapping(self): + """ + Apply the dynamic palette color mapping based on the + current state of the entity. + """ + raise NotImplementedError() + + @property + def value(self): + """ + The logic output value of the entity + """ + raise NotImplementedError() + + def _init_tile_locations(self): + """ + Initialize the tile locations and input entity tile locations. + """ + + raise NotImplementedError() + + @property + def location(self): + """Location of the top left tile of the entity within the workspace, in tile coordinates""" + return self._location + + @location.setter + def location(self, value): + self._location = value + # re-calculate tile locations + self._init_tile_locations() + + +class OutputPanel(Entity): + """ + Output panel that displays logic values as 1 or 0 + """ + + def __init__(self, location, workspace, add_to_workspace=True): + self.type = "output" + self.size = (2, 1) + self._workspace = workspace + self.location = location + self._init_tile_locations() + self.tiles = [2, 3] + self._input_one = False + if add_to_workspace: + self._workspace.add_entity(self) + + def _init_tile_locations(self): + self.tile_locations = (self.location, (self.location[X] + 1, self.location[Y])) + # Location of the entity connected to the input of the panel in x,y tile coords + self.input_entity_location = (self.location[X] - 1, self.location[Y]) + + @property + def palette_mapping(self): + """Dynamic palette mapping list of color indexes + based on the current state of the entity""" + pal = list(range(COLOR_COUNT)) + pal[3] = 7 if self._input_one else 1 + pal[4] = 1 if self._input_one else 2 + pal[5] = 1 if not self._input_one else 2 + return pal + + def apply_state_palette_mapping(self): + cur_state_palette = self.palette_mapping + for loc in self.tile_locations: + self._workspace.tilegrid.pixel_shader[loc] = cur_state_palette + + @property + def input_one(self): + """Logic value of input one""" + return self._input_one + + @input_one.setter + def input_one(self, value): + self._input_one = value + self.apply_state_palette_mapping() + + @property + def value(self): + # Output panel does not have a logic output value + return False + + def update(self): + """ + Run logic simulation for this entity + """ + input_entity = self.input_entity + # if no input entity then set logic value False + if input_entity is None: + self.input_one = False + self.apply_state_palette_mapping() + return + + # update logic value based on entity value + self.input_one = self.input_entity.value + + @property + def input_entity(self): + """Entity at the input location""" + return self._workspace.entity_at(self.input_entity_location) + + +class VirtualPushButton(Entity): + """ + Virtual push button that can be on or off, clicked by the mouse to change state + """ + + def __init__( + self, location, workspace, initial_pressed_state=False, add_to_workspace=True + ): + self.type = "input" + self.size = (1, 1) + self._workspace = workspace + self.location = location + self._init_tile_locations() + self.tiles = [21] + + self.pressed_state = initial_pressed_state + + if add_to_workspace: + self._workspace.add_entity(self) + + def _init_tile_locations(self): + self.tile_locations = (self.location,) + + @property + def value(self): + return self.pressed_state + + def apply_state_palette_mapping(self): + pal = list(range(COLOR_COUNT)) + pal[5] = 7 if self.value else 1 + pal[2] = 7 if self.value else 6 + + for loc in self.tile_locations: + self._workspace.tilegrid.pixel_shader[loc] = pal + + def handle_click(self): + self.pressed_state = not self.pressed_state + self.apply_state_palette_mapping() + self._workspace.update() + + +class PhysicalButton(Entity): + """ + Physical button tied to one of the hardware buttons on the Fruit Jam + """ + + SPRITE_INDEXES = (23, 26, 27) + + def __init__(self, location, workspace, index, add_to_workspace=True): + self.index = index + self.type = "input" + self.size = (1, 1) + self._workspace = workspace + self.location = location + self._init_tile_locations() + self.tiles = [self.SPRITE_INDEXES[index]] + + if add_to_workspace: + self._workspace.add_entity(self) + + def _init_tile_locations(self): + self.tile_locations = (self.location,) + + def update(self): + self.apply_state_palette_mapping() + + @property + def value(self): + return not self._workspace.buttons[self.index].value + + def apply_state_palette_mapping(self): + pal = list(range(COLOR_COUNT)) + pal[5] = 7 if self.value else 1 + pal[2] = 7 if self.value else 6 + + for loc in self.tile_locations: + self._workspace.tilegrid.pixel_shader[loc] = pal + +class SignalReceiver(Entity): + """ + Virtual Connector used to bring signals into an entity from a Signal Transmitter + """ + + def __init__(self, location, workspace, connector_number=None, add_to_workspace=True): + self.type = "input" + self.size = (1, 1) + self._workspace = workspace + self.location = location + self._init_tile_locations() + self.tiles = [30] + self.connector_number = None + self._overlay_tile = None + self._input_one = None + + if connector_number is None: + # Find the last SignalTransmitter entity added to the workspace to link to + for entity in self._workspace.entities: + if isinstance(entity, SignalTransmitter): + self.connector_number = entity.connector_number + self._input_one = entity + else: + self.connector_number = connector_number + + if add_to_workspace: + self._workspace.add_entity(self) + + self.apply_state_palette_mapping() + + def _init_tile_locations(self): + self.tile_locations = (self.location,) + + def update(self): + """ + Run logic simulation for this entity + """ + self.apply_state_palette_mapping() + + @property + def input_one(self): + """The input entity for this Wire.""" + return self._input_one + + @input_one.setter + def input_one(self, input_entity): + if isinstance(input_entity, SignalTransmitter): + self._input_one = input_entity + self.apply_state_palette_mapping() + + @property + def value(self): + if self.connector_number is None: + return False + elif self.input_one is None: + return False + elif self.input_one.input_one is None: + return False + elif self._input_one.input_one == self: + return False + + return self.input_one.input_one.value + + def apply_state_palette_mapping(self): + pal = list(range(COLOR_COUNT)) + pal[5] = 7 if self.value else 1 + pal[2] = 7 if self.value else 6 + + for loc in self.tile_locations: + self._workspace.tilegrid.pixel_shader[loc] = pal + + if self._overlay_tile is not None and self._overlay_tile != self.tile_locations[0]: + self._workspace.overlay_tilegrid[self._overlay_tile] = EMPTY + pal = list(range(COLOR_COUNT)) + pal[3] = 1 + pal[4] = 0 + if self.connector_number is not None: + self._workspace.overlay_palette_mapper[self.tile_locations[0]] = pal + self._workspace.overlay_tilegrid[self.tile_locations[0]] = 34 + self.connector_number + self._overlay_tile = self.tile_locations[0] + else: + self._workspace.overlay_tilegrid[self.tile_locations[0]] = EMPTY + self._overlay_tile = None + + def handle_click(self): + """ + Cycle through available SignalTransmitter entities on the workspace + """ + connector_outs = [] + inuse_connector_numbers = [] + for entity in self._workspace.entities: + if isinstance(entity, SignalTransmitter): + connector_outs.append(entity) + inuse_connector_numbers.append(entity.connector_number) + + if len(inuse_connector_numbers) == 0: + return + + inuse_connector_numbers.sort() + if self.connector_number is None: + self.connector_number = inuse_connector_numbers[0] + else: + if self.connector_number in inuse_connector_numbers: + connector_index = inuse_connector_numbers.index(self.connector_number) + else: + connector_index = -1 + + self.connector_number = \ + inuse_connector_numbers[(connector_index + 1) % max(len(connector_outs),1)] + + self.input_one = None + for entity in connector_outs: + if entity.connector_number == self.connector_number: + self.input_one = entity + +class SignalTransmitter(Entity): + """ + Virtual Connector used to send signals from an entity to a Signal Receiver + """ + + def __init__(self, location, workspace, connector_number=None, add_to_workspace=True): + self.type = "output" + self.size = (1, 1) + self._workspace = workspace + self.location = location + self._init_tile_locations() + self.tiles = [31] + self._input_one = None + self._overlay_tile = None + + if connector_number is None: + # Set the connection_number to the next value available + if len(self._workspace.available_connectors) > 0: + self.connector_number = self._workspace.available_connectors.pop(0) + else: + # Too many connectors, workspace shouldn't allow this to happen + raise RuntimeError("Too many Signal Transmitters") + else: + self.connector_number = connector_number + + self._tap = None + + if add_to_workspace: + self._workspace.add_entity(self) + + def _init_tile_locations(self): + self.tile_locations = (self.location,) + # Location of the entity connected to the left of the Signal Transmitter in x,y tile coords + self.input_entity_location = (self.location[X] - 1, self.location[Y]) + + def update(self): + """ + Run logic simulation for this entity + """ + # if no input entity + if self.input_entity is None: + self.input_one = None + self.apply_state_palette_mapping() + return + + # update logic value based on entity value + self.input_one = self.input_entity + self.apply_state_palette_mapping() + + @property + def input_entity(self): + """Entity at the input location""" + # Only recieve input from output wire on larger gates + if self._workspace.entity_at(self.input_entity_location) == \ + self._workspace.entity_at((self.location[X], self.location[Y] - 1)) or \ + self._workspace.entity_at(self.input_entity_location) == \ + self._workspace.entity_at((self.location[X], self.location[Y] + 1)): + + # If entity to left is also above or below us then we're not connected to it's output + return None + + return self._workspace.entity_at(self.input_entity_location) + + @property + def palette_mapping(self): + """The palette mapping for the current state. Used for + setting the appropriate color on the input and output lines.""" + pal = list(range(COLOR_COUNT)) + if self.input_one is not None: + pal[2] = 7 if self.input_one.value else 6 + pal[5] = 7 if self.input_one.value else 1 + else: + pal[2] = 6 + pal[5] = 1 + + return pal + + def apply_state_palette_mapping(self): + cur_state_palette = self.palette_mapping + for loc in self.tile_locations: + self._workspace.tilegrid.pixel_shader[loc] = cur_state_palette + + if self._tap is not None and self._tap != self.input_entity_location: + self._workspace.overlay_tilegrid[self._tap] = EMPTY + if self._overlay_tile is not None and self._overlay_tile != self.tile_locations[0]: + self._workspace.overlay_tilegrid[self._overlay_tile] = EMPTY + pal = list(range(COLOR_COUNT)) + + if isinstance(self.input_entity,Wire): + pal[3] = 7 if self.input_one.value else 1 + self._workspace.overlay_palette_mapper[self.input_entity_location] = pal + self._workspace.overlay_tilegrid[self.input_entity_location] = 33 + self._tap = self.input_entity_location + else: + self._tap = None + + if self.connector_number is not None: + pal[3] = 0 + pal[4] = 1 + self._workspace.overlay_palette_mapper[self.tile_locations[0]] = pal + self._workspace.overlay_tilegrid[self.tile_locations[0]] = 34 + self.connector_number + self._overlay_tile = self.tile_locations[0] + else: + self._overlay_tile = None + + @property + def input_one(self): + """Entity at input one""" + self._input_one = self.input_entity + return self._input_one + + @input_one.setter + def input_one(self, value): + self._input_one = value + self.apply_state_palette_mapping() + + @property + def value(self): + # Output panel does not have a logic output value + return False + +class Wire(Entity): + """ + Wire used to connect entities together + """ + + STATES = [ + "left_right", + "up_down", + "up_right", + "down_left", + "up_left", + "down_right", + # unused states + # "left_up_right", + # "left_down_right", + # "left_up_down", + # "right_up_down" + ] + + # sprite sheet tile indexes matching states from STATES list + TILE_INDEXES = [19, 9, 1, 0, 17, 32] + + def __init__(self, location, workspace, state=None, add_to_workspace=True): + self._recursion_guard = False + self.type = "wire" + self.size = (1, 1) + self._workspace = workspace + self._state = None + self.tiles = [19] + if state is None: + guessed_state = self.guess_appropriate_state(location) + self.state = guessed_state + else: + self.state = state + self.location = location + + self._output = False + + if add_to_workspace: + self._workspace.add_entity(self) + + # whether to keep the existing state after + # being placed on the workspace. + self.keep_state_after_drop = False + + def update(self): + _ = self.value + self._recursion_guard = False + + @property + def state(self): + """The index of the current state of the Wire. Different states + represent connections on different sides.""" + return self._state + + @state.setter + def state(self, value): + self._state = value + self._init_tile_locations() + self.tiles[0] = self.TILE_INDEXES[self.state] + try: + self._workspace.remove_entity(self) + self._workspace.add_entity(self) + except ValueError: + # This Wire entity was not on the Workspace + pass + + def guess_appropriate_state(self, location): + """ + Try to guess the appropriate state to use for the Wire based + on the surrounding entities. + + :param location: The location to check around + :return int: the index of the guessed most appropriate state + """ + entity_above = ( + self._workspace.entity_at((location[0], location[1] - 1)) is not None + ) + entity_left = ( + self._workspace.entity_at((location[0] - 1, location[1])) is not None + ) + entity_below = ( + self._workspace.entity_at((location[0], location[1] + 1)) is not None + ) + entity_right = ( + self._workspace.entity_at((location[0] + 1, location[1])) is not None + ) + + ret_val = 0 + if entity_left and entity_right: + ret_val = 0 + elif entity_above and entity_below: + ret_val = 1 + elif entity_above and entity_right: + ret_val = 2 + elif entity_below and entity_left: + ret_val = 3 + elif entity_above and entity_left: + ret_val = 4 + elif entity_below and entity_right: + ret_val = 5 + + return ret_val + + def handle_click(self): + """ + Change the state of the Wire cycling between all possible states. + """ + if self.state < 5: + self.state += 1 + else: + self.state = 0 + + def _init_tile_locations(self): + self.tile_locations = (self.location,) + + @property + def palette_mapping(self): + """ + Dynamic palette mapping list of colors based on the current state + """ + pal = list(range(COLOR_COUNT)) + pal[3] = 7 if self._output else 1 + return pal + + def apply_state_palette_mapping(self): + cur_state_palette = self.palette_mapping + for loc in self.tile_locations: + self._workspace.tilegrid.pixel_shader[loc] = cur_state_palette + + def find_neighboring_wire_end(self, direction, wire_segments=None): + """ + Find the end of the wire segment in the given direction. + + :param direction: Direction to search in ("left", "right", "up", "down") + :return: tuple of (end entity, list of wire segments in this direction) + """ + if wire_segments is None: + wire_segments = [] + + # exit recursion if we have already visited this wire segment + if self in wire_segments: + return (None, wire_segments) + + wire_segments.append(self) + current_location = self.location + + if direction == "left": + opposite = "right" + next_location = (current_location[X] - 1, current_location[Y]) + elif direction == "right": + opposite = "left" + next_location = (current_location[X] + 1, current_location[Y]) + elif direction == "up": + opposite = "down" + next_location = (current_location[X], current_location[Y] - 1) + elif direction == "down": + opposite = "up" + next_location = (current_location[X], current_location[Y] + 1) + + neighbor_entity = self._workspace.entity_at(next_location) + + if neighbor_entity is not None: + if neighbor_entity.type == "wire": + if opposite in self.STATES[neighbor_entity.state]: + # wire is properly connected to another wire segment, follow it + neighbor_state = self.STATES[neighbor_entity.state].split('_') + neighbor_direction = neighbor_state[1-neighbor_state.index(opposite)] + return neighbor_entity.find_neighboring_wire_end(neighbor_direction, wire_segments) + elif direction == "left" and neighbor_entity.type in ("input", "gate"): + # Only recieve input from output wire on larger gates + if self._workspace.entity_at(next_location) != \ + self._workspace.entity_at((current_location[X], current_location[Y] - 1)) and \ + self._workspace.entity_at(next_location) != \ + self._workspace.entity_at((current_location[X], current_location[Y] + 1)): + + # wire is properly connected to an entity that supplies a value + return(neighbor_entity, wire_segments) + + # no wire or input entity found, or not properly connected + return (None, wire_segments) + + @property + def output(self): + return self._output + + @output.setter + def output(self, value): + self._output = value + + @property + def recursion_guard(self): + return self._recursion_guard + + @recursion_guard.setter + def recursion_guard(self, value): + self._recursion_guard = value + + @property + def value(self): + + if self._recursion_guard: + if self._output is None: + self._output = False + self.apply_state_palette_mapping() + return self._output + + self._recursion_guard = True + + # traverse connected wire segments to find input entities and map entire wire + wires = [] + wire_value = False + # only check for entities connected to the two sides defined by the state + for direction in self.STATES[self.state].split('_'): + end_entity, wire_seg = self.find_neighboring_wire_end(direction,[]) + wires.append(wire_seg) + + # Set wire value to the value of the input entity found at the end of the wire segment + if end_entity is not None and end_entity.type in ("input", "gate"): + wire_value = end_entity.value + + # Set the output of all the line segments to the value of the input entity + for seg in wires[0]+wires[1]: + if seg is not self: + seg.output = wire_value + # _recursion_guard is now being used as a sort of "dirty" flag to improve performance + seg.recursion_guard = True + seg.apply_state_palette_mapping() + + self._output = wire_value + self.apply_state_palette_mapping() + return self._output + +class TwoInputOneOutputGate(Entity): + """ + Super class for all Gate objects that have two inputs and one output. + Implements function and logics that are shared between the different types of Gates. + """ + + _input_one = None + _input_two = None + _output = None + + size = (2, 3) + """Size in tiles of the rectangle that contains the entity. + Note that some tiles with this maybe unused.""" + + input_one_entity_location = None + """location of input entity one in x,y tile coordinates""" + + input_two_entity_location = None + """location of input entity two in x,y tile coordinates""" + + _inputs_left = True + """Whether the inputs are to the left (True), or top/bottom (False)""" + def __init__(self): + self._recursion_guard = False + self.type = "gate" + + self._input_one = False + self._input_two = False + self._output = False + + @property + def output(self) -> bool: + """Value of the output""" + return self._output + + @property + def input_one_entity(self) -> Optional[Entity]: + """Entity connected to input one""" + return self._workspace.entity_at(self.input_one_entity_location) + + @property + def input_two_entity(self) -> Entity: + """Entity connected to input two""" + return self._workspace.entity_at(self.input_two_entity_location) + + @property + def input_one(self) -> bool: + """Logic value of input one""" + return self._input_one + + @property + def input_two(self): + """Logic value of input one""" + return self._input_two + + @input_one.setter + def input_one(self, value): + raise NotImplementedError() + + @input_two.setter + def input_two(self, value): + raise NotImplementedError() + + @property + def value(self): + """Calculate the output logic value of this gate. Will call + value property on input entities.""" + if self._recursion_guard: + self._recursion_guard = False + return self.output + + self._recursion_guard = True + input_one_entity = self.input_one_entity + input_two_entity = self.input_two_entity + + # print(f"Gate.value input_one_entity: {input_one_entity}, input_two_entity: {input_two_entity}") + + if input_one_entity is None: + self.input_one = False + else: + self.input_one = input_one_entity.value + + if input_two_entity is None: + self.input_two = False + else: + self.input_two = input_two_entity.value + + self._recursion_guard = False + return self.output + + def handle_click(self): + """Toggle between inputs left and inputs above/below""" + self.inputs_left = not self._inputs_left + + @property + def inputs_left(self): + """True if inputs are to the left, False if they are above and below""" + return self._inputs_left + + @inputs_left.setter + def inputs_left(self, value): + self._inputs_left = value + if self._inputs_left: + self.input_one_entity_location = (self.location[X] - 1, self.location[Y]) + self.input_two_entity_location = ( + self.location[X] - 1, + self.location[Y] + 2, + ) + self.tiles[0] = 0 + self.tiles[3] = 20 + else: + self.input_one_entity_location = (self.location[X], self.location[Y] - 1) + self.input_two_entity_location = (self.location[X], self.location[Y] + 3) + self.tiles[0] = 9 + self.tiles[3] = 28 + + try: + self._workspace.remove_entity(self) + self._workspace.add_entity(self) + except ValueError: + # was not in entities list + pass + + def _init_tile_locations(self): + self.tile_locations = ( + self.location, + (self.location[X], self.location[Y] + 1), + (self.location[X] + 1, self.location[Y] + 1), + (self.location[X], self.location[Y] + 2), + ) + + self.input_one_entity_location = (self.location[X] - 1, self.location[Y]) + self.input_two_entity_location = (self.location[X] - 1, self.location[Y] + 2) + + @property + def palette_mapping(self): + """The palette mapping for the current state. Used for + setting the appropriate color on the input and output lines.""" + pal = list(range(COLOR_COUNT)) + pal[3] = 7 if self.input_one else 1 + pal[4] = 7 if self.input_two else 1 + pal[5] = 7 if self.output else 1 + return pal + + def apply_state_palette_mapping(self): + """ + Apply the current palette mapping to all tiles used by this Gate. + """ + cur_state_palette = self.palette_mapping + + for loc in self.tile_locations: + self._workspace.tilegrid.pixel_shader[loc] = cur_state_palette + + +class AndGate(TwoInputOneOutputGate): + """AndGate - When both inputs are True the output will be True, otherwise False.""" + + def __init__(self, location, workspace, add_to_workspace=True): + super().__init__() + + self._workspace = workspace + self.location = location + + self._init_tile_locations() + + self.tiles = [0, 10, 11, 20] + + if add_to_workspace: + self._workspace.add_entity(self) + + @TwoInputOneOutputGate.input_one.setter + def input_one(self, value): + self._input_one = value + self._output = self._input_one and self._input_two + self.apply_state_palette_mapping() + + @TwoInputOneOutputGate.input_two.setter + def input_two(self, value): + self._input_two = value + self._output = self._input_one and self._input_two + self.apply_state_palette_mapping() + + +class NandGate(TwoInputOneOutputGate): + """NandGate - When at least one input is False the output will be True, otherwise False.""" + + def __init__(self, location, workspace, add_to_workspace=True): + super().__init__() + + self._workspace = workspace + self.location = location + + self._init_tile_locations() + + self.tiles = [0, 14, 15, 20] + + if add_to_workspace: + self._workspace.add_entity(self) + + @TwoInputOneOutputGate.input_one.setter + def input_one(self, value): + self._input_one = value + self._output = not self._input_one or not self._input_two + self.apply_state_palette_mapping() + + @TwoInputOneOutputGate.input_two.setter + def input_two(self, value): + self._input_two = value + self._output = not self._input_one or not self._input_two + self.apply_state_palette_mapping() + + +class OrGate(TwoInputOneOutputGate): + """OrGate - When either input is True the output will be True, otherwise False.""" + + def __init__(self, location, workspace, add_to_workspace=True): + super().__init__() + + self._workspace = workspace + self.location = location + + self._init_tile_locations() + + self.tiles = [0, 12, 13, 20] + + if add_to_workspace: + self._workspace.add_entity(self) + + @TwoInputOneOutputGate.input_one.setter + def input_one(self, value): + self._input_one = value + self._output = self._input_one or self._input_two + self.apply_state_palette_mapping() + + @TwoInputOneOutputGate.input_two.setter + def input_two(self, value): + self._input_two = value + self._output = self._input_one or self._input_two + self.apply_state_palette_mapping() + + +class NorGate(TwoInputOneOutputGate): + """NorGate - When both inputs are False the output will be True, otherwise False.""" + + def __init__(self, location, workspace, add_to_workspace=True): + super().__init__() + + self._workspace = workspace + self.location = location + + self._init_tile_locations() + + self.tiles = [0, 6, 7, 20] + + if add_to_workspace: + self._workspace.add_entity(self) + + @TwoInputOneOutputGate.input_one.setter + def input_one(self, value): + self._input_one = value + self._output = not self._input_one and not self._input_two + self.apply_state_palette_mapping() + + @TwoInputOneOutputGate.input_two.setter + def input_two(self, value): + self._input_two = value + self._output = not self._input_one and not self._input_two + self.apply_state_palette_mapping() + + +class XorGate(TwoInputOneOutputGate): + """XorGate - When one input is True and the other input is False the output will be True, otherwise False.""" + + def __init__(self, location, workspace, add_to_workspace=True): + super().__init__() + + self._workspace = workspace + self.location = location + + self._init_tile_locations() + + self.tiles = [0, 4, 5, 20] + + if add_to_workspace: + self._workspace.add_entity(self) + + @TwoInputOneOutputGate.input_one.setter + def input_one(self, value): + self._input_one = value + self._output = False + if self._input_one and not self._input_two: + self._output = True + if not self._input_one and self._input_two: + self._output = True + self.apply_state_palette_mapping() + + @TwoInputOneOutputGate.input_two.setter + def input_two(self, value): + self._input_two = value + self._output = False + if self._input_one and not self._input_two: + self._output = True + if not self._input_one and self._input_two: + self._output = True + self.apply_state_palette_mapping() + + +class XnorGate(TwoInputOneOutputGate): + """XNOR Gate - When both inputs are True, or both inputs are False the output will be True, otherwise False""" + + def __init__(self, location, workspace, add_to_workspace=True): + super().__init__() + + self._workspace = workspace + self.location = location + + self._init_tile_locations() + + self.tiles = [0, 24, 25, 20] + + if add_to_workspace: + self._workspace.add_entity(self) + + @TwoInputOneOutputGate.input_one.setter + def input_one(self, value): + self._input_one = value + self._output = False + if self._input_one and self._input_two: + self._output = True + if not self._input_one and not self._input_two: + self._output = True + self.apply_state_palette_mapping() + + @TwoInputOneOutputGate.input_two.setter + def input_two(self, value): + self._input_two = value + self._output = False + if self._input_one and self._input_two: + self._output = True + if not self._input_one and not self._input_two: + self._output = True + self.apply_state_palette_mapping() + + +class NotGate(Entity): + """NOT Gate - When the input is False the output will be True, otherwise False.""" + + def __init__(self, location, workspace, add_to_workspace=True): + self._recursion_guard = False + + self.type = "gate" + + self._workspace = workspace + self.location = location + + self.tiles = [22] + + self._input_one = False + self._output = True + + if add_to_workspace: + self._workspace.add_entity(self) + + @property + def input_one(self): + return self._input_one + + @input_one.setter + def input_one(self, value): + self._input_one = value + self._output = not self._input_one + self.apply_state_palette_mapping() + + @property + def output(self): + return self._output + + def apply_state_palette_mapping(self): + pal = list(range(COLOR_COUNT)) + pal[4] = 7 if self.input_one else 1 + pal[5] = 7 if self.output else 1 + + for loc in self.tile_locations: + self._workspace.tilegrid.pixel_shader[loc] = pal + + @property + def input_one_entity(self): + return self._workspace.entity_at(self.input_one_entity_location) + + @property + def value(self): + if self._recursion_guard: + self._recursion_guard = False + return self.output + + self._recursion_guard = True + input_one_entity = self.input_one_entity + + if input_one_entity is not None: + self.input_one = input_one_entity.value + else: + self.input_one = False + + self._recursion_guard = False + return self.output + + def _init_tile_locations(self): + self.tile_locations = (self.location,) + self.input_one_entity_location = (self.location[X] - 1, self.location[Y]) + + +class NeoPixelOutput(Entity): + """ + NeoPixelOutput with 3 inputs that correspond to red, green, and blue. + Connected to physical NeoPixels on the Fruit Jam. + """ + + _input_red = None + _input_green = None + _input_blue = None + + size = (1, 3) + + input_one_entity_location = None + """location of input entity one in x,y tile coordinates""" + + input_two_entity_location = None + """location of input entity two in x,y tile coordinates""" + + input_three_entity_location = None + """location of input entity two in x,y tile coordinates""" + + def __init__(self, location, workspace, neopixel_obj, add_to_workspace=True): + self.type = "output" + self.neopixels = neopixel_obj + self.tiles = [0, 16, 20] + self._workspace = workspace + self.location = location + self._init_tile_locations() + self._inputs_left = False + + if add_to_workspace: + self._workspace.add_entity(self) + + @property + def input_one_entity(self) -> Optional[Entity]: + """Entity connected to input one""" + return self._workspace.entity_at(self.input_one_entity_location) + + @property + def input_two_entity(self) -> Entity: + """Entity connected to input two""" + return self._workspace.entity_at(self.input_two_entity_location) + + @property + def input_three_entity(self) -> Entity: + """Entity connected to input two""" + return self._workspace.entity_at(self.input_three_entity_location) + + @property + def input_one(self) -> bool: + """Logic value of input one""" + return self._input_red + + @property + def input_two(self): + """Logic value of input one""" + return self._input_green + + @property + def input_three(self): + """Logic value of input one""" + return self._input_blue + + @input_one.setter + def input_one(self, value): + self._input_red = value + + @input_two.setter + def input_two(self, value): + self._input_green = value + + @input_three.setter + def input_three(self, value): + self._input_blue = value + + def _init_tile_locations(self): + self.tile_locations = ( + self.location, + (self.location[X], self.location[Y] + 1), + (self.location[X], self.location[Y] + 2), + ) + + self.input_one_entity_location = (self.location[X] - 1, self.location[Y]) + self.input_two_entity_location = (self.location[X] - 1, self.location[Y] + 1) + self.input_three_entity_location = (self.location[X] - 1, self.location[Y] + 2) + + def handle_click(self): + """Toggle between inputs left and inputs above/below""" + self.inputs_left = not self._inputs_left + + @property + def inputs_left(self): + """True if the inputs are to the left, False if they are above and below""" + return self._inputs_left + + @inputs_left.setter + def inputs_left(self, value): + self._inputs_left = value + if self._inputs_left: + self.input_one_entity_location = (self.location[X] - 1, self.location[Y]) + self.input_three_entity_location = ( + self.location[X] - 1, + self.location[Y] + 2, + ) + self.tiles[0] = 0 + self.tiles[2] = 20 + else: + self.input_one_entity_location = (self.location[X], self.location[Y] - 1) + self.input_three_entity_location = (self.location[X], self.location[Y] + 3) + self.tiles[0] = 9 + self.tiles[2] = 28 + self._workspace.remove_entity(self) + self._workspace.add_entity(self) + + @property + def palette_mapping(self): + """The palette mapping for the current state. Used for + setting the appropriate color on the input and output lines.""" + pal = list(range(COLOR_COUNT)) + pal[3] = 7 if self.input_one else 1 + pal[4] = 7 if self.input_two else 1 + pal[5] = 7 if self.input_three else 1 + return pal + + @property + def value(self): + return False + + def apply_state_palette_mapping(self): + """ + Apply the current palette mapping to all tiles used by this Gate. + """ + cur_state_palette = self.palette_mapping + + # top and middle tile behave 'normally' + for loc in self.tile_locations[:-1]: + self._workspace.tilegrid.pixel_shader[loc] = cur_state_palette + + # bottom tile different behavior because extension wire + # is using palette index that is typically for input two, + # but on this object the same index is used for input two and + # input three. + pal = list(range(COLOR_COUNT)) + pal[4] = 7 if self.input_three else 1 + self._workspace.tilegrid.pixel_shader[self.tile_locations[-1]] = pal + + def update(self): + """Run the logic simulation with the current state of the inputs. + Update physical NeoPixels based on logic values of inputs.""" + input_one_entity = self.input_one_entity + input_two_entity = self.input_two_entity + input_three_entity = self.input_three_entity + + if input_one_entity is not None: + self.input_one = input_one_entity.value + else: + self.input_one = False + + if input_two_entity is not None: + self.input_two = input_two_entity.value + else: + self.input_two = False + + if input_three_entity is not None: + self.input_three = input_three_entity.value + else: + self.input_three = False + + self.neopixels.fill( + ( + 255 if self.input_one else 0, + 255 if self.input_two else 0, + 255 if self.input_three else 0, + ) + ) + self.apply_state_palette_mapping() diff --git a/Fruit_Jam/Fruit_Jam_Logic_Gates/icon.bmp b/Fruit_Jam/Fruit_Jam_Logic_Gates/icon.bmp new file mode 100644 index 000000000..dd053f4c6 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Logic_Gates/icon.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_Logic_Gates/logic_gates_assets/add_btn.bmp b/Fruit_Jam/Fruit_Jam_Logic_Gates/logic_gates_assets/add_btn.bmp new file mode 100644 index 000000000..2cfc49ded Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Logic_Gates/logic_gates_assets/add_btn.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_Logic_Gates/logic_gates_assets/sprites.bmp b/Fruit_Jam/Fruit_Jam_Logic_Gates/logic_gates_assets/sprites.bmp new file mode 100644 index 000000000..e3c9f3e86 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Logic_Gates/logic_gates_assets/sprites.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_Logic_Gates/metadata.json b/Fruit_Jam/Fruit_Jam_Logic_Gates/metadata.json new file mode 100644 index 000000000..57c2232ac --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Logic_Gates/metadata.json @@ -0,0 +1,4 @@ +{ + "title": "Logic Gates", + "icon": "icon.bmp" +} diff --git a/Fruit_Jam/Fruit_Jam_Logic_Gates/workspace.py b/Fruit_Jam/Fruit_Jam_Logic_Gates/workspace.py new file mode 100644 index 000000000..f8e30d428 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Logic_Gates/workspace.py @@ -0,0 +1,976 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import os +import json +import time + +import adafruit_imageload +from displayio import TileGrid, OnDiskBitmap, Palette, Group, Bitmap +from tilepalettemapper import TilePaletteMapper +from terminalio import FONT + +from adafruit_anchored_group import AnchoredGroup +from adafruit_display_text.text_box import TextBox +from adafruit_display_text.bitmap_label import Label +from adafruit_displayio_layout.layouts.grid_layout import GridLayout + +from entity import ( + TwoInputOneOutputGate, + AndGate, + OrGate, + NandGate, + NorGate, + NotGate, + XorGate, + XnorGate, + VirtualPushButton, + OutputPanel, + NeoPixelOutput, + PhysicalButton, + Wire, + SignalReceiver, + SignalTransmitter, +) + +# pylint: disable=too-many-branches, too-many-statements + +VALID_SAVE_SLOTS = tuple("0123456789") + +DEFAULT_HOTKEYS = { + b"\x1b[A": "scroll_up", # up arrow + b"\x1b[B": "scroll_down", # down arrow + b"\x1b[C": "scroll_right", # right arrow + b"\x1b[D": "scroll_left", # left arrow + b"q": "eyedropper", + b"s": "save", + b"o": "open", + b"a": "add", + b"i": "import", + b"\x08": "remove", # backspace + b"\x1b[3~": "remove", # delete +} + +# index of empty tile in the spritesheet +EMPTY = 8 + +# map class names to constructor functions +ENTITY_CLASS_CONSTRUCTOR_MAP = { + "AndGate": AndGate, + "OrGate": OrGate, + "NandGate": NandGate, + "NorGate": NorGate, + "XorGate": XorGate, + "XnorGate": XnorGate, + "NotGate": NotGate, + "Wire": Wire, + "SignalReceiver": SignalReceiver, + "SignalTransmitter": SignalTransmitter, + "OutputPanel": OutputPanel, + "VirtualPushButton": VirtualPushButton, + "PhysicalButton": PhysicalButton, + "NeoPixelOutput": NeoPixelOutput, +} + +# maximum number of connectors allowed on workspace +MAX_CONNECTORS = 5 + + +class Workspace: + """ + A scrollable area to place logic gates and other Entities. Handles interactions with the user + via mouse and keyboard event functions. Contains a Toolbox for selecting new parts to be + added to the workspace. + + :param neopixels: NeoPixel object used with NeoPixelOutput entities + :param buttons: Tuple containing DigitalInOut instances connected to the 3 + physical buttons on the Fruit Jam. + :param hotkeys: Optional hotkeys dictionary to override the defaults. + """ + + def __init__(self, neopixels, buttons, hotkeys=None): + # store hardware peripheral references + self.neopixels = neopixels + self.buttons = buttons + + # load default hotkeys if user has not supplied custom ones. + self.hotkeys = DEFAULT_HOTKEYS if hotkeys is None else hotkeys + + # load the spritesheet bitmap + self.spritesheet, palette = adafruit_imageload.load( + "logic_gates_assets/sprites.bmp" + ) + self.spritesheet_pixel_shader = palette + + # setup TilePaletteMapper + self.tile_palette_mapper = TilePaletteMapper( + self.spritesheet_pixel_shader, # input pixel_shader + len(self.spritesheet_pixel_shader), # input color count + ) + + # setup main workspace TileGrid + self.tilegrid = TileGrid( + bitmap=self.spritesheet, + pixel_shader=self.tile_palette_mapper, + default_tile=EMPTY, + width=26, + height=18, + tile_width=24, + tile_height=24, + ) + + # setup group to hold all visual elements + self.group = Group() + self.group.append(self.tilegrid) + + # setup overlay elements that float on top of the workspace + self.overlay_palette = Palette(18) + for i, color in enumerate(self.spritesheet_pixel_shader): + self.overlay_palette[i] = color + self.overlay_palette.make_transparent(0) + + # setup Overlay TilePaletteMapper + self.overlay_palette_mapper = TilePaletteMapper( + self.overlay_palette, # input pixel_shader + len(self.overlay_palette), # input color count + ) + + # setup overlay TileGrid + self.overlay_tilegrid = TileGrid( + bitmap=self.spritesheet, + pixel_shader=self.overlay_palette_mapper, + default_tile=EMPTY, + width=26, + height=18, + tile_width=24, + tile_height=24, + ) + + self.group.append(self.overlay_tilegrid) + + # setup add entity button bitmap and TileGrid + self.add_btn_bmp = OnDiskBitmap("logic_gates_assets/add_btn.bmp") + self.add_btn_tg = TileGrid( + bitmap=self.add_btn_bmp, pixel_shader=self.add_btn_bmp.pixel_shader + ) + self.group.append(self.add_btn_tg) + + # setup message label, empty for now, used to get input or give feedback to user + self.message_lbl = Label(FONT, text="") + self.message_lbl.anchor_point = (0, 0) + self.message_lbl.anchored_position = ( + self.add_btn_tg.x + self.add_btn_tg.tile_width + 2, + 2, + ) + self.group.append(self.message_lbl) + + # Setup moving entity graphics used when an entity is following the mouse + # waiting to be placed on the workspace + self.mouse_moving_palette = Palette(len(self.spritesheet_pixel_shader)) + for i, color in enumerate(self.spritesheet_pixel_shader): + self.mouse_moving_palette[i] = color + self.mouse_moving_palette.make_transparent(0) + self.mouse_moving_palette[3] = 0x000000 + self.mouse_moving_palette[4] = 0x000000 + self.mouse_moving_palette[5] = 0x000000 + self.mouse_moving_tg = TileGrid( + bitmap=self.spritesheet, + pixel_shader=self.mouse_moving_palette, + width=2, + height=3, + default_tile=EMPTY, + tile_width=24, + tile_height=24, + ) + self.mouse_moving_tg.hidden = True + + # list to hold all Entities on the workspace + self.entities = [] + + # list to hold available connectors + self.available_connectors = list(range(MAX_CONNECTORS)) + + # variable to hold an Entity that is moving with the mouse + self.moving_entity = None + + # workspace scroll offsets + self._scroll_x = 0 + self._scroll_y = 0 + + # setup ToolBox for selecting entities to add + self.toolbox = ToolBox(self.spritesheet, self) + self.group.append(self.toolbox.group) + + # variables for message control + self.waiting_for_save_slot_input = False + self.waiting_for_open_slot_input = False + self.waiting_for_import_slot_input = False + self.hide_message_at = None + + def add_entity(self, entity): + """ + Add the given entity to the workspace at the location specified by entity.location. + Setting the appropriate tile sprites. + """ + self.entities.append(entity) + for i in range(len(entity.tiles)): + self.tilegrid[entity.tile_locations[i]] = entity.tiles[i] + entity.apply_state_palette_mapping() + + def remove_entity(self, entity): + """ + Remove the given entity from the workspace. + """ + self.entities.remove(entity) + for i in range(len(entity.tiles)): + self.tilegrid[entity.tile_locations[i]] = EMPTY + self.overlay_tilegrid[entity.tile_locations[i]] = EMPTY + + # Special case for SignalTransmitter to clear its input wire tap overlay + if isinstance(entity, SignalTransmitter): + if isinstance(entity.input_entity, Wire): + self.overlay_tilegrid[entity.input_entity_location] = EMPTY + + def _set_mouse_moving_tiles(self, entity): + """ + Set the sprite tiles on the mouse moving TileGrid based on the given entity. + """ + for i in range(self.mouse_moving_tg.width * self.mouse_moving_tg.height): + self.mouse_moving_tg[i] = EMPTY + + midpoint_offset = 1 if entity.size[1] == 1 else 0 + + for i, loc in enumerate(entity.tile_locations): + self.mouse_moving_tg[ + loc[0] - entity.location[0], + loc[1] - entity.location[1] + midpoint_offset, + ] = entity.tiles[i] + + def _clear_cursor(self): + # Special SignalTransmitter case, add connection_number back into available list + if isinstance(self.moving_entity, SignalTransmitter): + self.available_connectors.append(self.moving_entity.connector_number) + self.available_connectors.sort() + # Remove connections from SignalReceivers pointing to this SignalTransmitter + for entity in self.entities: + if ( + isinstance(entity, SignalReceiver) + and entity.connector_number == self.moving_entity.connector_number + ): + + entity.connector_number = None + entity.input_one = None + + self.moving_entity = None + self.mouse_moving_tg.hidden = True + self.update() + + def handle_mouse_click(self, screen_x, screen_y, pressed_btns): + """ + Handle mouse click events sent from code.py + """ + + # hand add button click & Toolbox outside of scroll logic + # since it floats on top and is unaffected by scroll. + if "left" in pressed_btns: + # if the toolbox is visible let it handle the click event. + if not self.toolbox.hidden: + self.toolbox.handle_mouse_click((screen_x, screen_y)) + return + + # if the click is on the add button + if self.add_btn_tg.contains((screen_x, screen_y, 0)): + # if there is no entity on the mouse, open the ToolBox + if self.moving_entity is None: + self.toolbox.hidden = False + + # if there is an entity on the mouse, remove it + else: + self._clear_cursor() + return + + # apply offset value based on scroll position + screen_x -= self._scroll_x * self.tilegrid.tile_width * 1 + screen_y -= self._scroll_y * self.tilegrid.tile_height * 1 + + # calculate tile coordinates + tile_x = screen_x // self.tilegrid.tile_width + tile_y = screen_y // self.tilegrid.tile_height + + # get the entity at the coordinates if there is one + clicked_entity = self.entity_at((tile_x, tile_y)) + + # handle left click + if "left" in pressed_btns: + # if there is an entity moving with the mouse + if self.moving_entity is not None: + + # set the entities location to the clicked coordinates + if isinstance( + self.moving_entity, (TwoInputOneOutputGate, NeoPixelOutput) + ): + self.moving_entity.location = (tile_x, tile_y - 1) + else: + self.moving_entity.location = (tile_x, tile_y) + + # Ignore the click if the landing space is occupied + if self.landing_zone_clear(self.moving_entity): + # for Wires, guess the appropriate state if the flag to keep state is not set + if ( + isinstance(self.moving_entity, Wire) + and not self.moving_entity.keep_state_after_drop + ): + self.moving_entity.state = ( + self.moving_entity.guess_appropriate_state( + self.moving_entity.location + ) + ) + + # add the entity at the clicked coordinates + self.add_entity(self.moving_entity) + # run the logic simulation with the new entity in it + self.update() + # remove the moving entity from the mouse + self.moving_entity = None + self.mouse_moving_tg.hidden = True + return + + # ignore left click on empty space + if clicked_entity is None: + return + + # if the entity has a handle_click() function call + # it to allow entity to handle the click event + if hasattr(clicked_entity, "handle_click"): + clicked_entity.handle_click() + # update the logic simulation after click has been handled + self.update() + + # handle right click event + elif "right" in pressed_btns: + # if there is not a moving entity following the mouse + if self.moving_entity is None: + # if the click was on empty space do nothing + if clicked_entity is None: + return + + # remove the entity from the workspace and set it + # as the moving entity following the mouse + self.moving_entity = clicked_entity + self._set_mouse_moving_tiles(self.moving_entity) + self.mouse_moving_tg.hidden = False + self.remove_entity(self.moving_entity) + + # for Wires keep the existing state when they're dropped + if isinstance(self.moving_entity, Wire): + self.moving_entity.keep_state_after_drop = True + + def handle_key_press(self, key_bytes, mouse_x, mouse_y): + """ + Handle keyboard key press events sent from code.py. + Also receives the current mouse location. + """ + # pylint: disable=too-many-locals + + # if we're waiting for user to input the save slot number + if self.waiting_for_save_slot_input: + # convert keypress to string + key_str = key_bytes.decode("utf-8") + # if the entered value is a valid save slot 0-9 + if key_str in VALID_SAVE_SLOTS: + # update the message to the user with the value they typed + self.message_lbl.text += key_str + # get the JSON data to save + save_data = self.json() + # write JSON data to the save file with slot number in filename + with open(f"/saves/logic_gates_{key_str}.json", "w") as f: + f.write(save_data) + # update the message to user with save success + self.message_lbl.text = f"Saved in slot: {key_str}" + # set the time to hide the message to user + self.hide_message_at = time.monotonic() + 2.0 + # set flag back to not waiting for save slot input + self.waiting_for_save_slot_input = False + return + + # if we're waiting for user to input the open slot number + if self.waiting_for_open_slot_input: + # convert keypress to string + key_str = key_bytes.decode("utf-8") + # if the entered value is a valid save slot 0-9 + if key_str in VALID_SAVE_SLOTS: + # try to open and read JSON data from the specified save slot file + try: + with open(f"/saves/logic_gates_{key_str}.json", "r") as f: + save_data = json.loads(f.read()) + + # load the workspace state from the JSON data + self.load_from_json(save_data) + # update message to user with opened save slot success + self.message_lbl.text = f"Opened from slot: {key_str}" + # set the time to hide the user message + self.hide_message_at = time.monotonic() + 2.0 + except OSError: + # inform user no file was found at the entered save slot + self.message_lbl.text = f"No save in slot: {key_str}" + self.hide_message_at = time.monotonic() + 2.0 + self.waiting_for_open_slot_input = False + return + + # if we're waiting for user to input the import slot number + if self.waiting_for_import_slot_input: + # convert keypress to string + key_str = key_bytes.decode("utf-8") + # if the entered value is a valid save slot 0-9 + if key_str in VALID_SAVE_SLOTS: + # update the message to the user with the value they typed + self.message_lbl.text += key_str + if "logic_gates_import.json" in os.listdir("/"): + with open("/logic_gates_import.json", "r") as f: + import_data = f.read() + # write JSON data to the save file with slot number in filename + with open(f"/saves/logic_gates_{key_str}.json", "w") as f: + f.write(import_data) + # update the message to user with save success + self.message_lbl.text = f"Imported to slot: {key_str}" + # set the time to hide the message to user + self.hide_message_at = time.monotonic() + 2.0 + # set flag back to not waiting for import slot input + self.waiting_for_import_slot_input = False + else: + self.message_lbl.text = "logic_gates_import.json not found" + # set the time to hide the message to user + self.hide_message_at = time.monotonic() + 2.0 + # set flag back to not waiting for import slot input + self.waiting_for_import_slot_input = False + + return + + # lookup the pressed key int he hotkey map + action = self.hotkeys.get(key_bytes, None) + # if the pressed key doesn't map to any actions + # just print its bytes for debugging. + if action is None: + print(key_bytes) + return + + # scroll up + if action == "scroll_up": + self._scroll_y += 1 + self.apply_scroll() + + # scroll down + elif action == "scroll_down": + self._scroll_y -= 1 + self.apply_scroll() + + # scroll right + elif action == "scroll_right": + self._scroll_x -= 1 + self.apply_scroll() + + # scroll left + elif action == "scroll_left": + self._scroll_x += 1 + self.apply_scroll() + + # save action, ask user for the slot to save in + elif action == "save": + self.waiting_for_save_slot_input = True + self.message_lbl.text = "Save Slot: " + # keep message showing until user responds + self.hide_message_at = None + + # open action, ask user for slot to open from + elif action == "open": + self.waiting_for_open_slot_input = True + self.message_lbl.text = "Open Slot: " + # keep message showing until user responds + self.hide_message_at = None + + # import action, ask user for slot to import to + elif action == "import": + self.waiting_for_import_slot_input = True + self.message_lbl.text = "Import To Slot: " + # keep message showing until user responds + self.hide_message_at = None + + # add action, show the ToolBox to select a new entity to add + elif action == "add": + if self.moving_entity is None: + self.toolbox.hidden = False + + # remove action, clear out the entity moving with the mouse + elif action == "remove": + if self.moving_entity is not None: + self._clear_cursor() + + # eyedropper or pipette action + elif action == "eyedropper": + # if there is already an entity moving with the mouse + if self.moving_entity is not None: + self._clear_cursor() + return + + # adjust mouse coordinates for the scroll position + mouse_x -= self._scroll_x * self.tilegrid.tile_width * 1 + mouse_y -= self._scroll_y * self.tilegrid.tile_height * 1 + + # get the tile coordinates of mouse location + tile_x = mouse_x // self.tilegrid.tile_width + tile_y = mouse_y // self.tilegrid.tile_height + + # try to get the entity at the tile coordinates + target_entity = self.entity_at((tile_x, tile_y)) + + # special case only limited number of SignalTransmitters + if target_entity is not None and isinstance( + target_entity, SignalTransmitter + ): + num_SignalTransmitters = 0 + for entity in self.entities: + if isinstance(entity, SignalTransmitter): + num_SignalTransmitters += 1 + if num_SignalTransmitters >= MAX_CONNECTORS: + # Can't create additional SignalTransmitters + target_entity = None + + # if there was an entity at the coordinates + if target_entity is not None: + # set up an object to clone the entity at the coordinates + clone_json = { + "class": target_entity.__class__.__name__, + "location": (0, 0), + } + # apply any possible attributes to the clone object + if hasattr(target_entity, "state"): + clone_json["state"] = target_entity.state + if hasattr(target_entity, "pressed_state"): + clone_json["pressed_state"] = target_entity.pressed_state + if hasattr(target_entity, "index"): + clone_json["index"] = target_entity.index + if hasattr(target_entity, "inputs_left"): + clone_json["inputs_left"] = target_entity.inputs_left + + # create an Entity from the clone object + cloned_entity = self.create_entity_from_json( + clone_json, add_to_workspace=False + ) + + # set the newly created entity as the entity moving with mouse + self.moving_entity = cloned_entity + self._set_mouse_moving_tiles(cloned_entity) + self.mouse_moving_tg.x = mouse_x - 12 + self.mouse_moving_tg.y = mouse_y - 24 - 12 + self.mouse_moving_tg.hidden = False + + # for Wires keep the existing state when they're dropped + if isinstance(self.moving_entity, Wire): + self.moving_entity.keep_state_after_drop = True + + def landing_zone_clear(self, entity): + """True if there are no entities in the space that would be occupied by the given entity""" + for loc in entity.tile_locations: + if self.entity_at(loc) is not None: + return False + return True + + def read_input(self): + """ + Read input from the user stripping the prompt message + """ + return self.message_lbl.text.replace("Save Slot: ", "").replace( + "Open Slot: ", "" + ) + + def json(self): + """ + Build and return a JSON object representing the current workspace state. + """ + # loop over all entities and create serialized objects with their state + save_obj = {"entities": []} + for entity in self.entities: + entity_obj = { + "class": entity.__class__.__name__, + "location": entity.location, + } + if hasattr(entity, "state"): + entity_obj["state"] = entity.state + if hasattr(entity, "pressed_state"): + entity_obj["pressed_state"] = entity.pressed_state + if hasattr(entity, "index"): + entity_obj["index"] = entity.index + if hasattr(entity, "inputs_left"): + entity_obj["inputs_left"] = entity.inputs_left + if hasattr(entity, "connector_number"): + entity_obj["connector_number"] = entity.connector_number + save_obj["entities"].append(entity_obj) + return json.dumps(save_obj) + + def create_entity_from_json(self, entity_json, add_to_workspace=True): + """ + Create an entity from a JSON object representing an entity state. + """ + location = tuple(entity_json["location"]) + # special case NeoPixelOutput needs the NeoPixel object + if entity_json["class"] == "NeoPixelOutput": + new_entity = ENTITY_CLASS_CONSTRUCTOR_MAP[entity_json["class"]]( + location, self, self.neopixels, add_to_workspace=add_to_workspace + ) + # special case PhysicalButton needs the button index + elif entity_json["class"] == "PhysicalButton": + new_entity = ENTITY_CLASS_CONSTRUCTOR_MAP[entity_json["class"]]( + location, self, entity_json["index"], add_to_workspace=add_to_workspace + ) + # special case Wire needs the wire state number + elif entity_json["class"] == "Wire": + new_entity = ENTITY_CLASS_CONSTRUCTOR_MAP[entity_json["class"]]( + location, self, entity_json["state"], add_to_workspace=add_to_workspace + ) + # special case Connectors need the connector number + elif ( + entity_json["class"] == "SignalReceiver" + or entity_json["class"] == "SignalTransmitter" + ): + + if entity_json.get("connector_number") is not None: + new_entity = ENTITY_CLASS_CONSTRUCTOR_MAP[entity_json["class"]]( + location, + self, + entity_json["connector_number"], + add_to_workspace=add_to_workspace, + ) + else: + new_entity = ENTITY_CLASS_CONSTRUCTOR_MAP[entity_json["class"]]( + location, self, add_to_workspace=add_to_workspace + ) + # default case all other entity types + else: + new_entity = ENTITY_CLASS_CONSTRUCTOR_MAP[entity_json["class"]]( + location, self, add_to_workspace=add_to_workspace + ) + + # if the entity has the inputs_left property then set it according to object + if "inputs_left" in entity_json: + new_entity.inputs_left = entity_json["inputs_left"] + + return new_entity + + def load_from_json(self, json_data): + """ + Load the workspace state from a JSON object. + """ + # reset list of available SignalTransmitters + self.available_connectors = list(range(MAX_CONNECTORS)) + self.neopixels.fill(0) + # clear out all sprites in the tilegrid + for i in range(self.tilegrid.width * self.tilegrid.height): + self.tilegrid[i] = EMPTY + self.overlay_tilegrid[i] = EMPTY + + # clear out entities list + self.entities.clear() + + # loop over entities in JSON object + for entity_json in json_data["entities"]: + # create current entity + self.create_entity_from_json(entity_json) + + # Connect any connectors + for entity in self.entities: + if isinstance(entity, SignalTransmitter): + if entity.connector_number in self.available_connectors: + self.available_connectors.remove(entity.connector_number) + for entity_in in self.entities: + if ( + isinstance(entity_in, SignalReceiver) + and entity_in.connector_number is not None + and entity.connector_number == entity_in.connector_number + ): + + entity_in.input_one = entity + + # update the logic simulation with all new entities + self.update() + + def apply_scroll(self): + """ + Move the main workspace TileGrid based on the current scroll position + """ + self.tilegrid.x = self._scroll_x * self.tilegrid.tile_width * 1 + self.tilegrid.y = self._scroll_y * self.tilegrid.tile_height * 1 + self.overlay_tilegrid.x = self._scroll_x * self.overlay_tilegrid.tile_width * 1 + self.overlay_tilegrid.y = self._scroll_y * self.overlay_tilegrid.tile_height * 1 + + def entity_at(self, location): + """ + Get the Entity at the given location or None if there isn't one. + """ + for entity in self.entities: + if location in entity.tile_locations: + return entity + return None + + def update(self): + """ + Run the logic simulation based on everything's current state. + """ + + # hide the message label if it's time to + now = time.monotonic() + if self.hide_message_at is not None and self.hide_message_at < now: + self.hide_message_at = None + self.message_lbl.text = "" + + # loop over all entities and update each one + # with update() function or value property. + for entity in self.entities: + if hasattr(entity, "update"): + entity.update() + else: + _ = entity.value + + +class ToolBox: + """ + A grid of all possible Entities for the user to choose from to + add new entities to the workspace. + """ + + # basic objects representing each item in the Grid + # will be looped over to set up Grid dynamically + GRID_ITEMS = [ + { + "label": "And Gate", + "tiles": (10, 11), + "constructor": AndGate, + "size": (2, 1), + }, + { + "label": "Nand Gate", + "tiles": (14, 15), + "constructor": NandGate, + "size": (2, 1), + }, + {"label": "Or Gate", "tiles": (12, 13), "constructor": OrGate, "size": (2, 1)}, + {"label": "Nor Gate", "tiles": (6, 7), "constructor": NorGate, "size": (2, 1)}, + {"label": "Not Gate", "tiles": (22,), "constructor": NotGate, "size": (1, 1)}, + {"label": "Xor Gate", "tiles": (4, 5), "constructor": XorGate, "size": (2, 1)}, + { + "label": "Xnor Gate", + "tiles": (24, 25), + "constructor": XnorGate, + "size": (2, 1), + }, + { + "label": "Virtual PushButton", + "tiles": (21,), + "constructor": VirtualPushButton, + "size": (1, 1), + }, + { + "label": "Output Panel", + "tiles": (2, 3), + "constructor": OutputPanel, + "size": (2, 1), + }, + { + "label": "NeoPixel Output", + "tiles": (16,), + "constructor": NeoPixelOutput, + "size": (1, 1), + }, + { + "label": "Physical Button", + "tiles": (23,), + "constructor": PhysicalButton, + "index": 0, + "size": (1, 1), + }, + { + "label": "Physical Button", + "tiles": (26,), + "constructor": PhysicalButton, + "index": 1, + "size": (1, 1), + }, + { + "label": "Physical Button", + "tiles": (27,), + "constructor": PhysicalButton, + "index": 2, + "size": (1, 1), + }, + { + "label": "Signal Transmit'r", + "tiles": (31,), + "constructor": SignalTransmitter, + "size": (1, 1), + }, + { + "label": "Signal Receiver", + "tiles": (30,), + "constructor": SignalReceiver, + "size": (1, 1), + }, + { + "label": "Wire", + "tiles": (19,), + "constructor": Wire, + "size": (1, 1), + }, + ] + + def __init__(self, spritesheet_bmp, workspace): + self._workspace = workspace + + # main group to hold all visual elements + self.group = Group() + + # setup solid background to hide the workspace underneath the ToolBox + bg_group = Group(scale=20) + bg_bitmap = Bitmap(320 // 20, 240 // 20, 1) + bg_palette = Palette(1) + bg_palette[0] = 0x888888 + bg_tg = TileGrid(bitmap=bg_bitmap, pixel_shader=bg_palette) + bg_group.append(bg_tg) + self.group.append(bg_group) + + # setup GridLayout to hold entities to choose from + self.grid = GridLayout( + 0, 0, 320, 240, (5, 4), divider_lines=True, divider_line_color=0x666666 + ) + self.group.append(self.grid) + + # store spritesheet and palette for use later + self.spritesheet = spritesheet_bmp + self.spritesheet_pixel_shader = workspace.spritesheet_pixel_shader + + # initialize all Entities in the grid + self._init_grid() + + # ToolBox is hidden by default when created + self.hidden = True + + def _init_grid(self): + """ + Setup all Entities in the Grid + """ + # loop over objects in GRID_ITEMS + for i, item in enumerate(self.GRID_ITEMS): + # calculate x,y position in the grid + grid_pos = (i % self.grid.grid_size[0], i // self.grid.grid_size[0]) + + # setup a label for the entity + item_lbl = TextBox( + FONT, + text=item["label"], + width=320 // self.grid.grid_size[0], + height=TextBox.DYNAMIC_HEIGHT, + align=TextBox.ALIGN_CENTER, + y=8, + ) + x_pos = 6 if item["size"][0] == 2 else 18 + + # setup an icon TileGrid for the entity + item_icon = TileGrid( + bitmap=self.spritesheet, + pixel_shader=self.spritesheet_pixel_shader, + tile_width=24, + tile_height=24, + width=item["size"][0], + height=item["size"][1], + default_tile=EMPTY, + y=item_lbl.bounding_box[3] + 4, + x=x_pos, + ) + for tile_index in range(len(item["tiles"])): + item_icon[tile_index] = item["tiles"][tile_index] + item_icon[tile_index] = item["tiles"][tile_index] + + # put the entity label and icon in an AnchoredGroup + item_group = AnchoredGroup() + item_group.append(item_lbl) + item_group.append(item_icon) + + # Add the AnchoredGroup to the Grid. + self.grid.add_content(item_group, grid_position=grid_pos, cell_size=(1, 1)) + + @property + def hidden(self): + """ + True if the ToolBox is hidden, False if it is visible. + """ + return self._hidden + + @hidden.setter + def hidden(self, value): + self._hidden = value + self.group.hidden = value + + def handle_mouse_click(self, screen_coords): + """ + Handle mouse click event sent by code.py + """ + # get the grid cell location that was clicked + clicked_cell_coords = self.grid.which_cell_contains(screen_coords) + + # calculate the 0 based index of the clicked cell + clicked_cell_index = ( + clicked_cell_coords[0] + clicked_cell_coords[1] * self.grid.grid_size[0] + ) + + # if the click was on an empty cell close the ToolBox + if clicked_cell_index > len(self.GRID_ITEMS) - 1: + self.hidden = True + return + + # get the object representing the item at the clicked cell + clicked_item = self.GRID_ITEMS[clicked_cell_index] + + # special case NeoPixelOutout needs the NeoPixel object + if clicked_item["label"] == "NeoPixel Output": + new_entity = clicked_item["constructor"]( + (0, 0), + self._workspace, + self._workspace.neopixels, + add_to_workspace=False, + ) + + # special case PhysicalButton needs the button index + elif clicked_item["label"] == "Physical Button": + new_entity = clicked_item["constructor"]( + (0, 0), self._workspace, clicked_item["index"], add_to_workspace=False + ) + + # special case only limited number of SignalTransmitters + elif clicked_item["label"] == "Signal Transmit'r": + num_SignalTransmitters = 0 + for entity in self._workspace.entities: + if isinstance(entity, SignalTransmitter): + num_SignalTransmitters += 1 + if num_SignalTransmitters >= MAX_CONNECTORS: + # close the ToolBox + self.hidden = True + return + + new_entity = clicked_item["constructor"]( + (0, 0), self._workspace, add_to_workspace=False + ) + + # default behavior all other entity types + else: + new_entity = clicked_item["constructor"]( + (0, 0), self._workspace, add_to_workspace=False + ) + + # set the created entity as the entity moving with mouse + self._workspace.moving_entity = new_entity + self._workspace._set_mouse_moving_tiles( # pylint: disable=protected-access + new_entity + ) + self._workspace.mouse_moving_tg.hidden = False + + # close the ToolBox + self.hidden = True diff --git a/Fruit_Jam/Fruit_Jam_Matrix/.metro_rp2350.test.only b/Fruit_Jam/Fruit_Jam_Matrix/.metro_rp2350.test.only new file mode 100644 index 000000000..8d1c8b69c --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Matrix/.metro_rp2350.test.only @@ -0,0 +1 @@ + diff --git a/Fruit_Jam/Fruit_Jam_Matrix/Fruit_Jam_Matrix.ino b/Fruit_Jam/Fruit_Jam_Matrix/Fruit_Jam_Matrix.ino new file mode 100644 index 000000000..14bd056a5 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Matrix/Fruit_Jam_Matrix.ino @@ -0,0 +1,300 @@ +// SPDX-FileCopyrightText: 2021 Anne Barela for Adafruit Industries +// +// SPDX-License-Identifier: MIT +// +// Based on Adafruit-DVI-HSTX library code written by Jeff Epler +// and use of Claude 3.7 Sonnet on 3/2/2025 +// https://claude.site/artifacts/cf022b66-50c3-43eb-b334-17fbf0ed791c + +#include + +// Display configuration for text mode in Adafruit-DVI-HSTX +const int SCREEN_WIDTH = 91; +const int SCREEN_HEIGHT = 30; + +// Animation speed (lower = faster) +// Adjust this value to change the speed of the animation +const int ANIMATION_SPEED = 1; // milliseconds between updates + +// Initialize display for Adafruit Metro RP2350 +DVHSTXText display(DVHSTX_PINOUT_DEFAULT, true); // Adafruit Metro HSTX Pinout + +// Define structures for character streams +struct CharStream { + int x; // X position + int y; // Y position (head of the stream) + int length; // Length of the stream + int speed; // How many frames to wait before moving + int countdown; // Counter for movement + int headColor; + bool active; // Whether this stream is currently active + bool canFreeze; // Whether this stream is currently active + char chars[30]; // Characters in the stream +}; + +// Array of character streams - increased for higher density +// To fill 60-75% of the screen width (91 chars), we need around 55-68 active +// streams +CharStream streams[250]; // Allow for decent density + +// Stream creation rate (higher = more frequent new streams) +const int STREAM_CREATION_CHANCE = + 65; // % chance per frame to create new stream + +// Initial streams to create at startup +const int INITIAL_STREAMS = 30; + +// Random characters that appear in the streams +const char matrixChars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+[]{}|;:,.<>?/\\"; +const int numMatrixChars = sizeof(matrixChars) - 1; + +const char frozenLine1[] = " A D A F R U I T "; +const char frozenLine2[] = " "; +const char frozenLine3[] = "F R U I T J A M"; + +constexpr size_t nFrozen = sizeof(frozenLine1) - 1; +const char *const frozenLines[] = {frozenLine1, frozenLine2, frozenLine3}; +const int colorFrozen[3] = { + TextColor::TEXT_WHITE, + TextColor::TEXT_WHITE, + TextColor::TEXT_MAGENTA, +}; + +constexpr auto frozenFirstRow = (SCREEN_HEIGHT / 2) - 1; +constexpr auto frozenFirstCol = (SCREEN_WIDTH - nFrozen) / 2; +bool isFrozen[3][nFrozen]; + +// Function declarations +void initStreams(); +void updateStreams(); +void drawStream(CharStream &stream); +int createNewStream(); +char getRandomChar(); + +void setup() { + // Initialize the display + display.begin(); + display.clear(); + + // Seed the random number generator + randomSeed(analogRead(A0)); + + // Initialize all streams + initStreams(); + + for (int fy = 0; fy < 3; fy++) { + for (int fx = 0; fx < nFrozen; fx++) { + int c = frozenLines[fy][fx]; + if (c == ' ') + continue; + isFrozen[fy][fx] = true; + } + } +} + +bool anyActiveStreams() { + for (int i = 0; i < sizeof(streams) / sizeof(streams[0]); i++) { + if (streams[i].active) + return true; + } + return false; +} +bool allFrozen() { + for (int fy = 0; fy < 3; fy++) { + for (int fx = 0; fx < nFrozen; fx++) { + int c = frozenLines[fy][fx]; + if (c == ' ') + continue; + if (!isFrozen[fy][fx]) + return false; + } + } + return true; +} + +void loop() { + // Update and draw all streams + updateStreams(); + + // Randomly create new streams at a higher rate + if (random(100) < STREAM_CREATION_CHANCE) { + if (allFrozen()) { + if (!anyActiveStreams()) { + memset(isFrozen, 0, sizeof(isFrozen)); + for (int fy = 0; fy < 3; fy++) { + for (int fx = 0; fx < nFrozen; fx++) { + int c = frozenLines[fy][fx]; + if (c == ' ') + continue; + int st; + if ((st = createNewStream()) != -1) { + streams[st].x = fx + frozenFirstCol; + streams[st].y = fy + frozenFirstRow; + streams[st].chars[0] = c; + for (int i = 1; i < streams[st].length; i++) { + streams[st].chars[i] = ' '; + } + streams[st].canFreeze = false; + streams[st].headColor = colorFrozen[fy]; + } + } + } + } + } else { + createNewStream(); + } + } + + // Control animation speed + delay(ANIMATION_SPEED); +} + +void initStreams() { + // Initialize all streams as inactive + for (int i = 0; i < sizeof(streams) / sizeof(streams[0]); i++) { + streams[i].active = false; + } + + // Create more initial streams for immediate visual impact + for (int i = 0; i < INITIAL_STREAMS; i++) { + createNewStream(); + } +} + +int createNewStream() { + // Find an inactive stream + for (int i = 0; i < sizeof(streams) / sizeof(streams[0]); i++) { + if (!streams[i].active) { + // Initialize the stream + streams[i].x = random(SCREEN_WIDTH); + streams[i].y = random(5) - 5; // Start above the screen + streams[i].length = random(5, 20); + streams[i].speed = random(1, 4); + streams[i].countdown = streams[i].speed; + streams[i].active = true; + streams[i].headColor = TextColor::TEXT_WHITE; + streams[i].canFreeze = true; + + // Fill with random characters + for (int j = 0; j < streams[i].length; j++) { + streams[i].chars[j] = getRandomChar(); + } + + return i; + } + } + return -1; +} + +void updateStreams() { + display.clear(); + delay(30); + + // Count active streams (for debugging if needed) + int activeCount = 0; + + for (int i = 0; i < sizeof(streams) / sizeof(streams[0]); i++) { + if (streams[i].active) { + activeCount++; + streams[i].countdown--; + + // Time to move the stream down + if (streams[i].countdown <= 0) { + streams[i].y++; + streams[i].countdown = streams[i].speed; + + // Change a random character in the stream + int randomIndex = random(streams[i].length); + streams[i].chars[randomIndex] = getRandomChar(); + } + + // Draw the stream + drawStream(streams[i]); + + // Check if the stream has moved completely off the screen + if (streams[i].y - streams[i].length > SCREEN_HEIGHT) { + streams[i].active = false; + } + } + } + displayFrozen(); + display.swap(); +} + +bool handleFrozen(int x, int y, int i, bool canFreeze) { + if (x < frozenFirstCol || y < frozenFirstRow) + return false; + int fx = x - frozenFirstCol; + int fy = y - frozenFirstRow; + if (fy > 2 || fx >= nFrozen) + return false; +int c = frozenLines[fy][fx]; +if (c == ' ') + return false; + if (!isFrozen[fy][fx]) { + if (canFreeze && random(5) == 0) { + isFrozen[fy][fx] = true; + } else { + return false; + } + } + + return true; +} + +void displayFrozen() { + for (int fy = 0; fy < 3; fy++) { + display.setColor(colorFrozen[fy]); + for (int fx = 0; fx < nFrozen; fx++) { + int x = fx + frozenFirstCol; + int y = fy + frozenFirstRow; + if (isFrozen[fy][fx]) { + display.setCursor(x, y); + display.write(frozenLines[fy][fx]); + } + } + } +} + +void drawStream(CharStream &stream) { + for (int i = 0; i < stream.length; i++) { + int y = stream.y - i; + int x = stream.x; + // Only draw if the character is on screen + if (y >= 0 && y < SCREEN_HEIGHT) { + display.setCursor(x, y); + + // Set different colors/intensities based on position in the stream + if (i == 0) { + // Head of the stream is white (brightest) + display.setColor(stream.headColor); + } else if (i < 3) { + // First few characters are bright green + display.setColor(TextColor::TEXT_GREEN, TextColor::BG_BLACK, + TextColor::ATTR_NORMAL_INTEN); + } else if (i < 6) { + // Next few are medium green + display.setColor(TextColor::TEXT_GREEN, TextColor::BG_BLACK, + TextColor::ATTR_LOW_INTEN); + } else { + // The rest are dim green + display.setColor(TextColor::TEXT_GREEN, TextColor::BG_BLACK, + TextColor::ATTR_V_LOW_INTEN); + } + + // Draw the character + if (!handleFrozen(x, y, i, stream.canFreeze)) { + display.write(stream.chars[i]); + } + } + } + + // Occasionally change a character in the stream + if (random(100) < 25) { // 25% chance + int idx = random(stream.length); + stream.chars[idx] = getRandomChar(); + } +} + +char getRandomChar() { return matrixChars[random(numMatrixChars)]; } diff --git a/Fruit_Jam/Fruit_Jam_Pixelfed_Photos/code.py b/Fruit_Jam/Fruit_Jam_Pixelfed_Photos/code.py new file mode 100644 index 000000000..6e8de8a10 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Pixelfed_Photos/code.py @@ -0,0 +1,188 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import gc +import os +import json +import random +import time + +import board +import busio +from digitalio import DigitalInOut +from displayio import TileGrid, Group, OnDiskBitmap +import supervisor + +import adafruit_connection_manager +from adafruit_esp32spi import adafruit_esp32spi +from adafruit_fruitjam.peripherals import request_display_config +import adafruit_requests + +# what kind of images to search for +search_tag = "cats" + +# pixelfed search API URL +URL = f"https://pixelfed.social/api/v2/discover/tag?hashtag={search_tag}" + +# small screen size +request_display_config(320, 240) +display = supervisor.runtime.display + +# Get WiFi details, ensure these are setup in settings.toml +ssid = os.getenv("CIRCUITPY_WIFI_SSID") +password = os.getenv("CIRCUITPY_WIFI_PASSWORD") + +# Get AIO details, ensure these are setup in settings.toml +AIO_USERNAME = os.getenv("ADAFRUIT_AIO_USERNAME") +AIO_KEY = os.getenv("ADAFRUIT_AIO_KEY") + +# AIO image converter URL template +IMAGE_CONVERTER_SERVICE = ( + f"https://io.adafruit.com/api/v2/{AIO_USERNAME}/integrations/image-formatter?" + f"x-aio-key={AIO_KEY}&width={display.width}&height={display.height}&output=BMP16&url=%s" +) + +# Main group to hold visible elements +main_group = Group() +display.root_group = main_group + +# try to load the previously downloaded image +try: + img_bmp = OnDiskBitmap("/saves/downloaded_img.bmp") + img_tg = TileGrid(img_bmp, pixel_shader=img_bmp.pixel_shader) + main_group.append(img_tg) +except (ValueError, RuntimeError, OSError): + img_tg = None + +# Setup WIFI +esp32_cs = DigitalInOut(board.ESP_CS) +esp32_ready = DigitalInOut(board.ESP_BUSY) +esp32_reset = DigitalInOut(board.ESP_RESET) +spi = busio.SPI(board.SCK, board.MOSI, board.MISO) +radio = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) + +print("Connecting to AP...") +while not radio.is_connected: + try: + radio.connect_AP(ssid, password) + except RuntimeError as e: + print("could not connect to AP, retrying: ", e) + continue +print("Connected to", str(radio.ap_info.ssid, "utf-8"), "\tRSSI:", radio.ap_info.rssi) + +# Initialize a requests session +pool = adafruit_connection_manager.get_radio_socketpool(radio) +ssl_context = adafruit_connection_manager.get_radio_ssl_context(radio) +requests = adafruit_requests.Session(pool, ssl_context) + + +def fetch_pixelfed_search(): + """ + Fetch search data from the pixelfed JSON API and cache the results + in /saves/pixelfed.json + + :return: None + """ + with requests.get(URL) as search_response: + print(f"pixelfeld search status code: {search_response.status_code}") + resp_data = search_response.text + if search_response.status_code == 200: + with open("/saves/pixelfed.json", "w") as cache_file: + cache_file.write(resp_data) + print("wrote search results to /saves/pixelfed.json") + + +def build_img_url_list(): + """ + Extract a list of URLs for images from the cached search data in /saves/pixelfed.json + :return: The list of URLs + """ + image_urls_to_show = [] + for i in range(len(search_results_obj["tags"])): + post_obj = search_results_obj["tags"][i] + for attachment in post_obj["status"]["media_attachments"]: + if attachment["is_nsfw"] == 0: + _img_url = attachment["preview_url"] + image_urls_to_show.append(_img_url) + + # shuffle the order of the final list + randomized_image_urls = [] + while len(image_urls_to_show) > 0: + random_image_url = random.choice(image_urls_to_show) + image_urls_to_show.remove(random_image_url) + randomized_image_urls.append(random_image_url) + return randomized_image_urls + + +# variable to store a timestamp of when we last searched +last_search_time = 0 + +# try to read cached search data +try: + with open("/saves/pixelfed.json", "r") as cached_search_data: + search_results_obj = json.loads(cached_search_data.read()) + +except OSError: # if there is no cached search data + # fetch search data now + fetch_pixelfed_search() + # update the timestamp + last_search_time = time.monotonic() + # load the fetched data from the cache file + with open("/saves/pixelfed.json", "r") as cached_search_data: + search_results_obj = json.loads(cached_search_data.read()) + +# get the list of images to show +images = build_img_url_list() + +# main loop +while True: + # loop over all images in the list + for img_url in images: + # prepare the converter URL for the current image + converter_url = IMAGE_CONVERTER_SERVICE.replace("%s", img_url) + print("Fetching converted img") + # attempt to download the converted image + with requests.get(converter_url) as response: + print("conversion status code: ", response.status_code) + # if the conversion was successful + if response.status_code == 200: + # save the image CPSAVES + with open("/saves/downloaded_img.bmp", "wb") as outfile: + for chunk in response.iter_content(chunk_size=8192): + outfile.write(chunk) + img_download_success = True + + # if the conversion was not successful + elif response.status_code == 429: # rate limit error + print("Img converter rate limit") + img_download_success = False + time.sleep(60) + else: + print(response.content) + img_download_success = False + time.sleep(60) + + if img_download_success: + print("Loading img") + # load and show the downloaded image file + try: + img_bmp = OnDiskBitmap("/saves/downloaded_img.bmp") + if img_tg in main_group: + main_group.remove(img_tg) + gc.collect() + img_tg = TileGrid(img_bmp, pixel_shader=img_bmp.pixel_shader) + main_group.append(img_tg) + except (ValueError, RuntimeError, OSError): + pass + + # wait for 4 minutes + time.sleep(60 * 4) + + # if it has been at least an hour since the last search time + if time.monotonic() - last_search_time > (60 * 60): + # fetch new search data and load the list of images from it + fetch_pixelfed_search() + last_search_time = time.monotonic() + with open("/saves/pixelfed.json", "r") as cached_search_data: + search_results_obj = json.loads(cached_search_data.read()) + images = build_img_url_list() diff --git a/Fruit_Jam/Fruit_Jam_Product_Overlay/code.py b/Fruit_Jam/Fruit_Jam_Product_Overlay/code.py new file mode 100644 index 000000000..c1d45971e --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Product_Overlay/code.py @@ -0,0 +1,203 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import time +import board +import supervisor +import terminalio + +from adafruit_fruitjam import FruitJam +from adafruit_fruitjam.peripherals import request_display_config + +BG_COLOR = 0x0000FF + +# use built-in system font +OVERLAY_FONT = terminalio.FONT + +# or un-comment to use a custom font. Fill in the path to your font file. +# OVERLAY_FONT = "Free_Mono_10.pcf" + +request_display_config(320, 240) +display = supervisor.runtime.display + +FETCH_DELAY = 12 + +# Set up where we'll be fetching data from +DATA_SOURCE = "https://www.adafruit.com/api/products/6358" + +TITLE_LOCATION = ["product_name"] +SALE_PRICE_LOCATION = ["product_sale_price"] +REG_PRICE_LOCATION = ["product_price"] +STOCK_LOCATION = ["product_stock"] + +config_index = 0 + +TEXT_POSITIONS = [ + { + "title_anchor_point": (0, 0), + "title_anchored_position": (4, 205 + 4), + "stock_anchor_point": (1.0, 1.0), + "stock_anchored_position": (display.width - 4, display.height - 4), + "price_anchor_point": (1.0, 0), + "price_anchored_position": (display.width - 4, 200), + "outline_size": 1, + "outline_color": 0x000000, + }, + { + "title_anchor_point": (0, 0), + "title_anchored_position": (4, 205 + 4), + "stock_anchor_point": (1.0, 1.0), + "stock_anchored_position": (display.width - 4, display.height - 4), + "price_anchor_point": (1.0, 0), + "price_anchored_position": (display.width - 4, 200), + "outline_size": 0, + "outline_color": 0x000000, + }, + { + "title_anchor_point": (0, 0), + "title_anchored_position": (4, 4), + "stock_anchor_point": (1.0, 0), + "stock_anchored_position": (display.width - 4, 26), + "price_anchor_point": (1.0, 0), + "price_anchored_position": (display.width - 4, 4), + "outline_size": 0, + "outline_color": 0x000000, + }, + { + "title_anchor_point": (0, 0), + "title_anchored_position": (4, 4), + "stock_anchor_point": (1.0, 0), + "stock_anchored_position": (display.width - 4, 26), + "price_anchor_point": (1.0, 0), + "price_anchored_position": (display.width - 4, 4), + "outline_size": 1, + "outline_color": 0x000000, + }, + { + "title_anchor_point": (0, 0), + "title_anchored_position": (4, -104), + "stock_anchor_point": (1.0, 0), + "stock_anchored_position": (display.width - 4, -126), + "price_anchor_point": (1.0, 0), + "price_anchored_position": (display.width - 4, -104), + "outline_size": 1, + "outline_color": 0x000000, + }, +] + + +def apply_hotkey_visuals(index): + config = TEXT_POSITIONS[index] + fruitjam.text_fields[0]["anchor_point"] = config["title_anchor_point"] + fruitjam.text_fields[0]["position"] = config["title_anchored_position"] + fruitjam.text_fields[0]["outline_color"] = config["outline_color"] + fruitjam.text_fields[0]["outline_size"] = config["outline_size"] + if fruitjam.text_fields[0]["label"] is not None: + fruitjam.text_fields[0]["label"].anchor_point = config["title_anchor_point"] + fruitjam.text_fields[0]["label"].anchored_position = config[ + "title_anchored_position" + ] + fruitjam.text_fields[0]["label"].outline_size = config["outline_size"] + fruitjam.text_fields[0]["label"].outline_color = config["outline_color"] + fruitjam.text_fields[1]["anchor_point"] = config["stock_anchor_point"] + fruitjam.text_fields[1]["position"] = config["stock_anchored_position"] + fruitjam.text_fields[1]["outline_color"] = config["outline_color"] + fruitjam.text_fields[1]["outline_size"] = config["outline_size"] + if fruitjam.text_fields[1]["label"] is not None: + fruitjam.text_fields[1]["label"].anchor_point = config["stock_anchor_point"] + fruitjam.text_fields[1]["label"].anchored_position = config[ + "stock_anchored_position" + ] + fruitjam.text_fields[1]["label"].outline_size = config["outline_size"] + fruitjam.text_fields[1]["label"].outline_color = config["outline_color"] + fruitjam.text_fields[2]["anchor_point"] = config["price_anchor_point"] + fruitjam.text_fields[2]["position"] = config["price_anchored_position"] + fruitjam.text_fields[2]["outline_color"] = config["outline_color"] + fruitjam.text_fields[2]["outline_size"] = config["outline_size"] + if fruitjam.text_fields[2]["label"] is not None: + fruitjam.text_fields[2]["label"].anchor_point = config["price_anchor_point"] + fruitjam.text_fields[2]["label"].anchored_position = config[ + "price_anchored_position" + ] + fruitjam.text_fields[2]["label"].outline_size = config["outline_size"] + fruitjam.text_fields[2]["label"].outline_color = config["outline_color"] + + +def format_data(json_data): + if "product_sale_price" in json_data: + json_data["product_sale_price"] = f'${json_data["product_sale_price"]}' + else: + json_data["product_sale_price"] = f'${json_data["product_price"]}' + + json_data["product_stock"] = f'Stock: {json_data["product_stock"]}' + + +# the current working directory (where this file is) +cwd = ("/" + __file__).rsplit("/", 1)[0] + +fruitjam = FruitJam( + url=DATA_SOURCE, + json_path=(TITLE_LOCATION, STOCK_LOCATION, SALE_PRICE_LOCATION), + status_neopixel=board.NEOPIXEL, + default_bg=BG_COLOR, + json_transform=[format_data], + debug=True, +) +fruitjam.remove_all_text() +fruitjam.add_text( + text_font=OVERLAY_FONT, text_wrap=35, text_maxlen=180, text_color=0xFFFFFF, outline_size=1 +) # title +fruitjam.add_text( + text_font=OVERLAY_FONT, text_wrap=0, text_maxlen=30, text_color=0xFFFFFF, outline_size=1 +) # stock +fruitjam.add_text( + text_font=OVERLAY_FONT, text_wrap=0, text_maxlen=30, text_color=0xFFFFFF, outline_size=1 +) # price +apply_hotkey_visuals(config_index) + +fruitjam.neopixels.brightness = 0.1 + +fetch_success = False +data_values = None +last_fetch_time = 0 + +while not fetch_success: + try: + data_values = fruitjam.fetch() + fruitjam._text[2]["label"].scale = 2 # pylint: disable=protected-access + fetch_success = True + last_fetch_time = time.monotonic() + except ValueError as e: + # no value found for product_sale_price + print("product_sale_price not found. Using regular price.") + print(fruitjam.json_path) + fruitjam.json_path = (TITLE_LOCATION, STOCK_LOCATION, ["product_price"]) + print(fruitjam.json_path) + time.sleep(5) + except (RuntimeError, ConnectionError, OSError) as e: + print("Some error occured, retrying! -", e) + time.sleep(5) + +old_btn1 = False +old_btn2 = False +old_btn3 = False + +while True: + btn1_pressed = fruitjam.button1 + if btn1_pressed and not old_btn1: + config_index = (config_index + 1) % len(TEXT_POSITIONS) + apply_hotkey_visuals(config_index) + + now = time.monotonic() + if last_fetch_time + FETCH_DELAY <= now: + try: + data_values = fruitjam.fetch() + print(f"type: {fruitjam.text_fields[1]['label']}") + fruitjam._text[2]["label"].scale = 2 # pylint: disable=protected-access + fetch_success = True + last_fetch_time = time.monotonic() + except (ValueError, RuntimeError, ConnectionError, OSError) as e: + print("Some error occured, retrying! -", e) + + old_btn1 = btn1_pressed diff --git a/Fruit_Jam/Fruit_Jam_PyPaint/code.py b/Fruit_Jam/Fruit_Jam_PyPaint/code.py new file mode 100644 index 000000000..ffebdb230 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_PyPaint/code.py @@ -0,0 +1,651 @@ +# SPDX-FileCopyrightText: 2019 Dave Astels for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +Paint for PyPortal, PyBadge, PyGamer, and the like. + +Adafruit invests time and resources providing this open source code. +Please support Adafruit and open source hardware by purchasing +products from Adafruit! + +Written by Dave Astels for Adafruit Industries +Copyright (c) 2019 Adafruit Industries +Licensed under the MIT license. + +All text above must be included in any redistribution. +""" + +import gc +import time +import supervisor +import board +import displayio + +try: + from adafruit_usb_host_mouse import find_and_init_boot_mouse + usb_available = True +except ImportError: + usb_available = False + +try: + from adafruit_fruitjam.peripherals import request_display_config +except ImportError: + request_display_config = None +try: + import adafruit_touchscreen +except ImportError: + pass +try: + from adafruit_cursorcontrol.cursorcontrol import Cursor + from adafruit_cursorcontrol.cursorcontrol_cursormanager import DebouncedCursorManager +except ImportError: + pass + +class Color(): + """Standard colors""" + + WHITE = 0xFFFFFF + BLACK = 0x000000 + RED = 0xFF0000 + ORANGE = 0xFFA500 + YELLOW = 0xFFFF00 + GREEN = 0x00FF00 + BLUE = 0x0000FF + PURPLE = 0x800080 + PINK = 0xFFC0CB + + colors = (BLACK, RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE, WHITE) + + def __init__(self): + pass + + +################################################################################ + + +class TouchscreenPoller(): + """Get 'pressed' and location updates from a touch screen device.""" + + def __init__(self, splash, cursor_bmp): + print("Creating a TouchscreenPoller") + self._display_grp = splash + self._touchscreen = adafruit_touchscreen.Touchscreen( + board.TOUCH_XL, board.TOUCH_XR, + board.TOUCH_YD, board.TOUCH_YU, + calibration=((9000, 59000), (8000, 57000)), + size=(320, 240), + ) + self._cursor_grp = displayio.Group() + self._cur_palette = displayio.Palette(3) + self._cur_palette.make_transparent(0) + self._cur_palette[1] = 0xFFFFFF + self._cur_palette[2] = 0x0000 + self._cur_sprite = displayio.TileGrid( + cursor_bmp, pixel_shader=self._cur_palette + ) + self._cursor_grp.append(self._cur_sprite) + self._display_grp.append(self._cursor_grp) + self._x_offset = cursor_bmp.width // 2 + self._y_offset = cursor_bmp.height // 2 + + def poll(self): + """Check for input. Returns contact (a bool), False (no button B), + and it's location ((x,y) or None)""" + + p = self._touchscreen.touch_point + if p is not None: + self._cursor_grp.x = p[0] - self._x_offset + self._cursor_grp.y = p[1] - self._y_offset + return True, False, p + else: + return False, False, None + + def poke(self, location=None): + """Force a bitmap refresh.""" + self._display_grp.remove(self._cursor_grp) + if location is not None: + self._cursor_grp.x = location[0] - self._x_offset + self._cursor_grp.y = location[1] - self._y_offset + self._display_grp.append(self._cursor_grp) + + def set_cursor_bitmap(self, bmp): + """Update the cursor bitmap. + + :param bmp: the new cursor bitmap + """ + self._cursor_grp.remove(self._cur_sprite) + self._cur_sprite = displayio.TileGrid(bmp, pixel_shader=self._cur_palette) + self._cursor_grp.append(self._cur_sprite) + self.poke() + + +################################################################################ + + +class CursorPoller(): + """Get 'pressed' and location updates from a D-Pad/joystick device.""" + + def __init__(self, splash, cursor_bmp): + print("Creating a CursorPoller") + self._mouse_cursor = Cursor( + board.DISPLAY, display_group=splash, bmp=cursor_bmp, cursor_speed=2 + ) + self._x_offset = cursor_bmp.width // 2 + self._y_offset = cursor_bmp.height // 2 + self._cursor = DebouncedCursorManager(self._mouse_cursor) + + def poll(self): + """Check for input. Returns press of A (a bool), B, + and the cursor location ((x,y) or None)""" + location = None + self._cursor.update() + a_button = self._cursor.held + if a_button: + location = ( + self._mouse_cursor.x + self._x_offset, + self._mouse_cursor.y + self._y_offset, + ) + return a_button, False, location + + def poke(self): + """Force a bitmap refresh.""" + self._mouse_cursor.hide() + self._mouse_cursor.show() + + def set_cursor_bitmap(self, bmp): + """Update the cursor bitmap. + + :param bmp: the new cursor bitmap + """ + self._mouse_cursor.cursor_bitmap = bmp + self.poke() + + +################################################################################ + +class MousePoller(): + """Get 'pressed' and location updates from a USB mouse.""" + + def __init__(self, splash, cursor_bmp, screen_width, screen_height, sensitivity=3): + print("Creating a MousePoller") + self._display_grp = splash + self._cursor_grp = displayio.Group() + self._cur_palette = displayio.Palette(3) + self._cur_palette.make_transparent(0) + self._cur_palette[1] = 0xFFFFFF + self._cur_palette[2] = 0x0000 + self._cur_sprite = displayio.TileGrid( + cursor_bmp, pixel_shader=self._cur_palette + ) + self._cursor_grp.append(self._cur_sprite) + self._display_grp.append(self._cursor_grp) + self._x_offset = cursor_bmp.width // 2 + self._y_offset = cursor_bmp.height // 2 + + self.SCREEN_WIDTH = screen_width + self.SCREEN_HEIGHT = screen_height + + # Mouse state + self.last_left_button_state = 0 + self.last_right_button_state = 0 + self.left_button_pressed = False + self.right_button_pressed = False + self.mouse = None + + # Mouse position + self.mouse_x = screen_width // 2 + self.mouse_y = screen_height // 2 + + # Mouse resolution/sensitivity + self.sensitivity = sensitivity + + if not self.find_mouse(): + print("WARNING: Mouse not found after multiple attempts.") + print("The application will run, but mouse control may not work.") + + + def find_mouse(self): # pylint: disable=too-many-statements, too-many-locals + """Find and initialize the USB mouse.""" + self.mouse = find_and_init_boot_mouse() + if self.mouse is None: + print("No mouse found.") + return False + + # Change the mouse resolution so it's not too sensitive + self.mouse.display_size = (supervisor.runtime.display.width*self.sensitivity, + supervisor.runtime.display.height*self.sensitivity) + return True + + def poll(self): + """Check for input. Returns contact (a bool), False (no button B), + and it's location ((x,y) or None)""" + + if self._process_mouse_input(): + self._cursor_grp.x = self.mouse_x - self._x_offset + self._cursor_grp.y = self.mouse_y - self._y_offset + return self.left_button_pressed, self.right_button_pressed, \ + (self.mouse_x, self.mouse_y) + else: + return False, False, None + + def poke(self, location=None): + """Force a bitmap refresh.""" + self._display_grp.remove(self._cursor_grp) + if location is not None: + self._cursor_grp.x = location[0] - self._x_offset + self._cursor_grp.y = location[1] - self._y_offset + self._display_grp.append(self._cursor_grp) + + def set_cursor_bitmap(self, bmp): + """Update the cursor bitmap. + + :param bmp: the new cursor bitmap + """ + self._cursor_grp.remove(self._cur_sprite) + self._cur_sprite = displayio.TileGrid(bmp, pixel_shader=self._cur_palette) + self._cursor_grp.append(self._cur_sprite) + self.poke() + + def _process_mouse_input(self): + """Process mouse input - simplified version without wheel support""" + + buttons = self.mouse.update() + + # Extract button states + if buttons is None: + current_left_button_state = 0 + current_right_button_state = 0 + else: + current_left_button_state = 1 if 'left' in buttons else 0 + current_right_button_state = 1 if 'right' in buttons else 0 + + # Detect button presses + if current_left_button_state == 1 and self.last_left_button_state == 0: + self.left_button_pressed = True + elif current_left_button_state == 0 and self.last_left_button_state == 1: + self.left_button_pressed = False + + if current_right_button_state == 1 and self.last_right_button_state == 0: + self.right_button_pressed = True + elif current_right_button_state == 0 and self.last_right_button_state == 1: + self.right_button_pressed = False + + # Update button states + self.last_left_button_state = current_left_button_state + self.last_right_button_state = current_right_button_state + + # Update position + self.mouse_x = self.mouse.x // self.sensitivity + self.mouse_y = self.mouse.y // self.sensitivity + + # Ensure position stays within bounds + self.mouse_x = max(0, min(self.SCREEN_WIDTH - 1, self.mouse_x)) + self.mouse_y = max(0, min(self.SCREEN_HEIGHT - 1, self.mouse_y)) + + return True + +################################################################################ + +class Paint(): # pylint: disable=too-many-statements + def __init__(self, display=None): + + def _cursor_bitmap_1(): + bmp = displayio.Bitmap(9, 9, 3) + for i in range(9): + bmp[4, i] = 1 + bmp[i, 4] = 1 + bmp[4, 4] = 0 + return bmp + + def _cursor_bitmap_3(): + bmp = displayio.Bitmap(9, 9, 3) + for i in range(9): + bmp[3, i] = 1 + bmp[4, i] = 1 + bmp[5, i] = 1 + bmp[i, 3] = 1 + bmp[i, 4] = 1 + bmp[i, 5] = 1 + for i in range(3, 6): + for j in range(3, 6): + bmp[i, j] = 0 + return bmp + + if display is None: + if hasattr(board, "DISPLAY"): + display = board.DISPLAY + else: + if request_display_config is not None: + request_display_config(320, 240) + display = supervisor.runtime.display + else: + raise RuntimeError("No display found.") + + self._display = display + self._w = self._display.width + self._h = self._display.height + self._x = self._w // 2 + self._y = self._h // 2 + + self._splash = displayio.Group() + + self._bg_bitmap = displayio.Bitmap(self._w, self._h, 1) + self._bg_palette = displayio.Palette(1) + self._bg_palette[0] = Color.BLACK + self._bg_sprite = displayio.TileGrid( + self._bg_bitmap, pixel_shader=self._bg_palette, x=0, y=0 + ) + self._splash.append(self._bg_sprite) + + self._palette_bitmap = displayio.Bitmap(self._w, self._h, 8) + self._palette_palette = displayio.Palette(len(Color.colors)) + for i, c in enumerate(Color.colors): + self._palette_palette[i] = c + self._palette_sprite = displayio.TileGrid( + self._palette_bitmap, pixel_shader=self._palette_palette, x=0, y=0 + ) + self._splash.append(self._palette_sprite) + + self._fg_bitmap = displayio.Bitmap(self._w, self._h, 9) + self._fg_palette = displayio.Palette(len(Color.colors)+1) + for i, c in enumerate(Color.colors): + self._fg_palette[i] = c + self._fg_palette[8] = Color.PINK # Marker for filled areas + self._fg_sprite = displayio.TileGrid( + self._fg_bitmap, pixel_shader=self._fg_palette, x=0, y=0 + ) + self._splash.append(self._fg_sprite) + + self._number_of_palette_options = len(Color.colors) + 2 + self._swatch_height = self._h // self._number_of_palette_options + self._swatch_width = self._w // 10 + print(f"Height: {self._h}") + print(f"Swatch height: {self._swatch_height}") + + self._palette = self._make_palette() + self._splash.append(self._palette) + + self._display.root_group = self._splash + try: + gc.collect() + self._display.refresh(target_frames_per_second=60) + except AttributeError: + self._display.refresh_soon() + gc.collect() + self._display.wait_for_frame() + + self._brush = 0 + self._cursor_bitmaps = [_cursor_bitmap_1(), _cursor_bitmap_3()] + if hasattr(board, "TOUCH_XL"): + self._poller = TouchscreenPoller(self._splash, self._cursor_bitmaps[0]) + elif hasattr(board, "BUTTON_CLOCK"): + self._poller = CursorPoller(self._splash, self._cursor_bitmaps[0]) + elif usb_available: + self._poller = MousePoller(self._splash, self._cursor_bitmaps[0], self._w, self._h) + if not self._poller.mouse: + raise RuntimeError("No mouse found. Please connect a USB mouse.") + else: + raise AttributeError("PyPaint requires a touchscreen or cursor.") + + self._a_pressed = False + self._last_a_pressed = False + self._b_pressed = False + self._last_b_pressed = False + self._location = None + self._last_location = None + + self._pencolor = 7 + + def _make_palette(self): + self._palette_bitmap = displayio.Bitmap(self._w // 10, self._h, 8) + self._palette_palette = displayio.Palette(len(Color.colors)) + for i, c in enumerate(Color.colors): + self._palette_palette[i] = c + for y in range(self._swatch_height): + for x in range(self._swatch_width): + self._palette_bitmap[x, self._swatch_height * i + y] = i + + swatch_x_offset = (self._swatch_width - 9) // 2 + swatch_y_offset = (self._swatch_height - 9) // 2 + swatch_y = self._swatch_height * len(Color.colors) + swatch_y_offset + for i in range(9): + self._palette_bitmap[swatch_x_offset + 4, swatch_y + i] = 1 + self._palette_bitmap[swatch_x_offset + i, swatch_y + 4] = 1 + self._palette_bitmap[swatch_x_offset + 4, swatch_y + 4] = 0 + + swatch_y += self._swatch_height + for i in range(9): + self._palette_bitmap[swatch_x_offset + 3, swatch_y + i] = 1 + self._palette_bitmap[swatch_x_offset + 4, swatch_y + i] = 1 + self._palette_bitmap[swatch_x_offset + 5, swatch_y + i] = 1 + self._palette_bitmap[swatch_x_offset + i, swatch_y + 3] = 1 + self._palette_bitmap[swatch_x_offset + i, swatch_y + 4] = 1 + self._palette_bitmap[swatch_x_offset + i, swatch_y + 5] = 1 + for i in range(swatch_x_offset + 3, swatch_x_offset + 6): + for j in range(swatch_y + 3, swatch_y + 6): + self._palette_bitmap[i, j] = 0 + + for i in range(self._h): + self._palette_bitmap[self._swatch_width - 1, i] = 7 + + return displayio.TileGrid( + self._palette_bitmap, pixel_shader=self._palette_palette, x=0, y=0 + ) + + def _plot(self, x, y, c): + if self._brush == 0: + r = [0] + else: + r = [-1, 0, 1] + for i in r: + for j in r: + try: + self._fg_bitmap[int(x + i), int(y + j)] = c + except IndexError: + pass + + def _draw_line(self, start, end): + """Draw a line from the previous position to the current one. + + :param start: a tuple of (x, y) coordinatess to fram from + :param end: a tuple of (x, y) coordinates to draw to + """ + x0 = start[0] + y0 = start[1] + x1 = end[0] + y1 = end[1] + print(f"* GoTo from ({x0}, {y0}) to ({x1}, {y1})") + steep = abs(y1 - y0) > abs(x1 - x0) + rev = False + dx = x1 - x0 + + if steep: + x0, y0 = y0, x0 + x1, y1 = y1, x1 + dx = x1 - x0 + + if x0 > x1: + rev = True + dx = x0 - x1 + + dy = abs(y1 - y0) + err = dx / 2 + ystep = -1 + if y0 < y1: + ystep = 1 + + while (not rev and x0 <= x1) or (rev and x1 <= x0): + if steep: + try: + self._plot(int(y0), int(x0), self._pencolor) + except IndexError: + pass + self._x = y0 + self._y = x0 + self._poller.poke() + time.sleep(0.003) + else: + try: + self._plot(int(x0), int(y0), self._pencolor) + except IndexError: + pass + self._x = x0 + self._y = y0 + self._poller.poke() + time.sleep(0.003) + err -= dy + if err < 0: + y0 += ystep + err += dx + if rev: + x0 -= 1 + else: + x0 += 1 + + def _fill(self, x, y, c): # pylint: disable=too-many-branches,too-many-locals + """Fill an area with the current color. + + :param x: x coordinate to start filling from + :param y: y coordinate to start filling from + :param c: color to fill with + """ + MARKER = 8 # Marker for filled areas + print(f"Filling at ({x}, {y}) with color {c}") + + # pylint: disable=too-many-nested-blocks + if self._fg_bitmap[x, y] != c: + blank_color = self._fg_bitmap[x, y] + self._fg_bitmap[x, y] = MARKER + done = False + min_row = 0 + max_row = self._h - 1 + min_col = (self._w // 10) + 1 + max_col = self._w - 1 + while not done: + newmin_row = self._h - 1 + newmax_row = 0 + newmin_col = self._w - 1 + newmax_col = (self._w // 10) + 1 + done = True + for i in range(min_row,max_row): + for j in range(min_col,max_col): + if self._fg_bitmap[j, i] == MARKER: + newmarker = False + if j > self._w // 10 and self._fg_bitmap[j - 1, i] == blank_color: + self._fg_bitmap[j - 1, i] = MARKER + newmarker = True + if j < self._w - 1 and self._fg_bitmap[j + 1, i] == blank_color: + self._fg_bitmap[j + 1, i] = MARKER + newmarker = True + if i > 0 and self._fg_bitmap[j, i - 1] == blank_color: + self._fg_bitmap[j, i - 1] = MARKER + newmarker = True + if i < self._h - 1 and self._fg_bitmap[j, i + 1] == blank_color: + self._fg_bitmap[j, i + 1] = MARKER + newmarker = True + + if newmarker: + done = False + if i < newmin_row: + newmin_row = i + if i > newmax_row: + newmax_row = i + if j < newmin_col: + newmin_col = j + if j > newmax_col: + newmax_col = j + + max_row = min(newmax_row + 2, self._h - 1) + min_row = max(newmin_row - 2, 0) + max_col = min(newmax_col + 2, self._w - 1) + min_col = max(newmin_col - 2, (self._w // 10) + 1) + + self._poller.poke() + + for i in range(self._h): + for j in range(self._w): + if self._fg_bitmap[j, i] == MARKER: + self._fg_bitmap[j, i] = c + + self._poller.poke() + # pylint: enable=too-many-nested-blocks + + def _handle_palette_selection(self, location): + selected = location[1] // self._swatch_height + if selected >= self._number_of_palette_options: + return + print(f"Palette selection: {selected}") + if selected < len(Color.colors): + self._pencolor = selected + else: + self._brush = selected - len(Color.colors) + self._poller.set_cursor_bitmap(self._cursor_bitmaps[self._brush]) + + def _handle_motion(self, start, end): + print(f"Moved: ({start[0]}, {start[1]}) -> ({end[0]}, {end[1]})") + self._draw_line(start, end) + + def _handle_a_press(self, location): + print("A Pressed!") + if location[0] < self._w // 10: # in color picker + self._handle_palette_selection(location) + else: + self._plot(location[0], location[1], self._pencolor) + self._poller.poke() + + @staticmethod + def _handle_a_release(): + print("A Released!") + + def _handle_b_release(self, location): + print("B Released!") + if location[0] >= self._w // 10: # not in color picker + self._fill(location[0], location[1], self._pencolor) + self._poller.poke() + + @property + def _was_a_just_pressed(self): + return self._a_pressed and not self._last_a_pressed + + @property + def _was_a_just_released(self): + return not self._a_pressed and self._last_a_pressed + + @property + def _was_b_just_released(self): + return not self._b_pressed and self._last_b_pressed + + @property + def _did_move(self): + if self._location is not None and self._last_location is not None: + x_changed = self._location[0] != self._last_location[0] + y_changed = self._location[1] != self._last_location[1] + return x_changed or y_changed + else: + return False + + def _update(self): + self._last_a_pressed = self._a_pressed + self._last_b_pressed = self._b_pressed + if self._location is not None: + self._last_location = self._location + self._a_pressed, self._b_pressed, self._location = self._poller.poll() + + def run(self): + """Run the painting program.""" + while True: + self._update() + if self._was_a_just_pressed: + self._handle_a_press(self._location) + elif self._was_a_just_released: + self._handle_a_release() + if self._was_b_just_released: + self._handle_b_release(self._last_location) + if self._did_move and self._a_pressed: + self._handle_motion(self._last_location, self._location) + time.sleep(0.1) + + +painter = Paint() +painter.run() diff --git a/Fruit_Jam/Fruit_Jam_PyPaint/icon.bmp b/Fruit_Jam/Fruit_Jam_PyPaint/icon.bmp new file mode 100644 index 000000000..ed1e7b918 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_PyPaint/icon.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_PyPaint/metadata.json b/Fruit_Jam/Fruit_Jam_PyPaint/metadata.json new file mode 100644 index 000000000..21c325ddc --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_PyPaint/metadata.json @@ -0,0 +1,4 @@ +{ + "title": "PyPaint", + "icon": "icon.bmp" +} diff --git a/Fruit_Jam/Fruit_Jam_Quotes/code.py b/Fruit_Jam/Fruit_Jam_Quotes/code.py new file mode 100644 index 000000000..1e7592606 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Quotes/code.py @@ -0,0 +1,45 @@ +# SPDX-FileCopyrightText: 2019 Limor Fried for Adafruit Industries +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +Quotes example originally for PyPortal adapted for Fruit Jam +""" +import time +import board +from adafruit_fruitjam import FruitJam +from adafruit_fruitjam.peripherals import request_display_config + +request_display_config(320, 240) + +# Set up where we'll be fetching data from +DATA_SOURCE = "https://www.adafruit.com/api/quotes.php" +QUOTE_LOCATION = [0, 'text'] +AUTHOR_LOCATION = [0, 'author'] + +# the current working directory (where this file is) +cwd = ("/"+__file__).rsplit('/', 1)[0] +fruitjam = FruitJam(url=DATA_SOURCE, + json_path=(QUOTE_LOCATION, AUTHOR_LOCATION), + status_neopixel=board.NEOPIXEL, + default_bg=cwd+"/quote_background.bmp", + text_font=cwd+"/fonts/Arial-ItalicMT-17.bdf", + text_position=((20, 120), # quote location + (5, 200)), # author location + text_color=(0xFFFFFF, # quote text color + 0x8080FF), # author text color + text_wrap=(35, # characters to wrap for quote + 0), # no wrap for author + text_maxlen=(180, 30), # max text size for quote & author + ) + +# speed up projects with lots of text by preloading the font! +fruitjam.preload_font() + +while True: + try: + value = fruitjam.fetch() + print("Response is", value) + except (ValueError, RuntimeError, ConnectionError, OSError) as e: + print("Some error occured, retrying! -", e) + time.sleep(60) diff --git a/Fruit_Jam/Fruit_Jam_Quotes/fonts/Arial-ItalicMT-17.bdf b/Fruit_Jam/Fruit_Jam_Quotes/fonts/Arial-ItalicMT-17.bdf new file mode 100644 index 000000000..67c8a8fb1 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Quotes/fonts/Arial-ItalicMT-17.bdf @@ -0,0 +1,59260 @@ +STARTFONT 2.1 +FONT -FontForge-Arial-Book-I-Normal--17-160-75-75-P-88-ISO10646-1 +SIZE 16 75 75 +FONTBOUNDINGBOX 32 24 -9 -6 +COMMENT "Generated by fontforge, http://fontforge.sourceforge.net" +COMMENT "(c) 2017 The Monotype Corporation. All Rights Reserved. " +COMMENT "" +COMMENT "Hebrew OpenType Layout logic copyright (c) 2003 & 2007, Ralph Hancock & John Hudson. This layout logic for Biblical Hebrew is open source software under the MIT License; see embedded license description for details." +STARTPROPERTIES 41 +FOUNDRY "FontForge" +FAMILY_NAME "Arial" +WEIGHT_NAME "Book" +SLANT "I" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 17 +POINT_SIZE 160 +RESOLUTION_X 75 +RESOLUTION_Y 75 +SPACING "P" +AVERAGE_WIDTH 88 +CHARSET_REGISTRY "ISO10646" +CHARSET_ENCODING "1" +FONTNAME_REGISTRY "" +CHARSET_COLLECTIONS "ASCII ISOLatin1Encoding ISO8859-2 ISO8859-5 ISO8859-7 ISO8859-9 ISO8859-8 ISO8859-4 ISO10646-1" +FONT_NAME "Arial-ItalicMT" +FACE_NAME "Arial Italic" +COPYRIGHT "(c) 2017 The Monotype Corporation. All Rights Reserved. " +FONT_VERSION "7.00" +FONT_ASCENT 14 +FONT_DESCENT 3 +UNDERLINE_POSITION -2 +UNDERLINE_THICKNESS 2 +X_HEIGHT 8 +CAP_HEIGHT 11 +RAW_ASCENT 799 +RAW_DESCENT 200 +ITALIC_ANGLE 4992 +NORM_SPACE 5 +RELATIVE_WEIGHT 40 +RELATIVE_SETWIDTH 50 +SUPERSCRIPT_X 0 +SUPERSCRIPT_Y 8 +SUPERSCRIPT_SIZE 11 +SUBSCRIPT_X 0 +SUBSCRIPT_Y 2 +SUBSCRIPT_SIZE 11 +FIGURE_WIDTH 9 +AVG_LOWERCASE_WIDTH 91 +AVG_UPPERCASE_WIDTH 119 +ENDPROPERTIES +CHARS 3288 +STARTCHAR space +ENCODING 32 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR exclam +ENCODING 33 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 12 1 0 +BITMAP +30 +30 +30 +20 +20 +60 +60 +40 +40 +00 +00 +C0 +ENDCHAR +STARTCHAR quotedbl +ENCODING 34 +SWIDTH 354 0 +DWIDTH 6 0 +BBX 5 4 2 8 +BITMAP +48 +D8 +D8 +90 +ENDCHAR +STARTCHAR numbersign +ENCODING 35 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +1100 +1100 +3300 +3200 +FF80 +2200 +2200 +6600 +FF80 +4400 +4400 +4C00 +ENDCHAR +STARTCHAR dollar +ENCODING 36 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 14 1 -1 +BITMAP +0400 +1F00 +2580 +6400 +6800 +2800 +1800 +0E00 +0B00 +1300 +9300 +D600 +7C00 +2000 +ENDCHAR +STARTCHAR percent +ENCODING 37 +SWIDTH 889 0 +DWIDTH 15 0 +BBX 12 12 2 0 +BITMAP +7020 +C860 +88C0 +8980 +9100 +F200 +04F0 +0C90 +1990 +3110 +2130 +40E0 +ENDCHAR +STARTCHAR ampersand +ENCODING 38 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +0F00 +1900 +1180 +1B00 +1E00 +1C00 +6C00 +46C0 +C2C0 +C380 +6380 +3CC0 +ENDCHAR +STARTCHAR quotesingle +ENCODING 39 +SWIDTH 190 0 +DWIDTH 3 0 +BBX 2 4 2 8 +BITMAP +40 +C0 +C0 +80 +ENDCHAR +STARTCHAR parenleft +ENCODING 40 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 15 1 -3 +BITMAP +0C +08 +10 +30 +20 +60 +40 +40 +C0 +C0 +C0 +40 +40 +40 +20 +ENDCHAR +STARTCHAR parenright +ENCODING 41 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 15 0 -3 +BITMAP +30 +10 +10 +18 +18 +18 +18 +18 +10 +30 +30 +20 +40 +C0 +80 +ENDCHAR +STARTCHAR asterisk +ENCODING 42 +SWIDTH 389 0 +DWIDTH 7 0 +BBX 5 5 2 7 +BITMAP +20 +E8 +30 +50 +50 +ENDCHAR +STARTCHAR plus +ENCODING 43 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 8 7 2 2 +BITMAP +10 +10 +10 +FF +10 +10 +10 +ENDCHAR +STARTCHAR comma +ENCODING 44 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 3 4 0 -3 +BITMAP +60 +20 +40 +80 +ENDCHAR +STARTCHAR hyphen +ENCODING 45 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 1 1 4 +BITMAP +F8 +ENDCHAR +STARTCHAR period +ENCODING 46 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 2 1 1 0 +BITMAP +C0 +ENDCHAR +STARTCHAR slash +ENCODING 47 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 8 12 -1 0 +BITMAP +03 +02 +06 +04 +0C +08 +10 +10 +20 +20 +40 +C0 +ENDCHAR +STARTCHAR zero +ENCODING 48 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +0E00 +3100 +2100 +6180 +4180 +4100 +C100 +C100 +C300 +C200 +4400 +3800 +ENDCHAR +STARTCHAR one +ENCODING 49 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 5 12 3 0 +BITMAP +08 +18 +78 +90 +10 +30 +30 +30 +20 +20 +60 +60 +ENDCHAR +STARTCHAR two +ENCODING 50 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +1E00 +3300 +6100 +2180 +0100 +0300 +0600 +0C00 +3000 +6000 +4000 +FE00 +ENDCHAR +STARTCHAR three +ENCODING 51 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1E +33 +61 +01 +03 +0E +02 +03 +03 +C3 +C6 +3C +ENDCHAR +STARTCHAR four +ENCODING 52 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +03 +03 +07 +0A +1A +36 +66 +C6 +FF +04 +0C +0C +ENDCHAR +STARTCHAR five +ENCODING 53 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +1F80 +3000 +2000 +3E00 +6300 +6100 +0100 +0100 +C300 +C300 +6600 +3C00 +ENDCHAR +STARTCHAR six +ENCODING 54 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +0E00 +1100 +2180 +6000 +7E00 +6300 +4100 +C100 +C100 +4300 +6600 +3C00 +ENDCHAR +STARTCHAR seven +ENCODING 55 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 2 0 +BITMAP +FF +02 +04 +0C +18 +10 +30 +20 +60 +60 +40 +40 +ENDCHAR +STARTCHAR eight +ENCODING 56 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +1E00 +3100 +2180 +6180 +2300 +3E00 +6300 +C300 +C300 +C300 +4600 +3C00 +ENDCHAR +STARTCHAR nine +ENCODING 57 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1E +33 +61 +41 +41 +43 +63 +3F +02 +C6 +44 +78 +ENDCHAR +STARTCHAR colon +ENCODING 58 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 3 9 1 0 +BITMAP +20 +00 +00 +00 +00 +00 +00 +00 +C0 +ENDCHAR +STARTCHAR semicolon +ENCODING 59 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 12 0 -3 +BITMAP +10 +00 +00 +00 +00 +00 +00 +00 +60 +20 +40 +80 +ENDCHAR +STARTCHAR less +ENCODING 60 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 8 9 2 2 +BITMAP +01 +06 +18 +60 +80 +60 +18 +06 +01 +ENDCHAR +STARTCHAR equal +ENCODING 61 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 8 5 2 3 +BITMAP +FF +00 +00 +00 +FF +ENDCHAR +STARTCHAR greater +ENCODING 62 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 8 9 2 2 +BITMAP +80 +E0 +38 +0E +03 +0E +38 +E0 +80 +ENDCHAR +STARTCHAR question +ENCODING 63 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 2 0 +BITMAP +3C +42 +C3 +02 +06 +0C +10 +30 +20 +00 +00 +60 +ENDCHAR +STARTCHAR at +ENCODING 64 +SWIDTH 1015 0 +DWIDTH 17 0 +BBX 15 15 1 -3 +BITMAP +07E0 +1818 +300C +63B6 +4462 +C862 +9862 +9862 +9862 +9844 +C8C8 +4770 +2002 +180C +07F0 +ENDCHAR +STARTCHAR A +ENCODING 65 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 0 0 +BITMAP +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR B +ENCODING 66 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +3F80 +30C0 +2040 +20C0 +6080 +7F00 +4080 +40C0 +C0C0 +C0C0 +C180 +FF00 +ENDCHAR +STARTCHAR C +ENCODING 67 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 10 12 2 0 +BITMAP +1F00 +3080 +60C0 +C040 +C000 +8000 +8000 +8000 +80C0 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR D +ENCODING 68 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +3F80 +30C0 +2060 +2060 +6060 +6060 +6060 +4060 +C040 +C0C0 +C180 +FE00 +ENDCHAR +STARTCHAR E +ENCODING 69 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR F +ENCODING 70 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +3FC0 +3000 +2000 +2000 +6000 +6000 +7F80 +4000 +4000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR G +ENCODING 71 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +0F80 +30C0 +6060 +4060 +C000 +8000 +87C0 +8040 +80C0 +C0C0 +61C0 +3F00 +ENDCHAR +STARTCHAR H +ENCODING 72 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +3030 +3020 +2020 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C0C0 +8080 +ENDCHAR +STARTCHAR I +ENCODING 73 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 12 1 0 +BITMAP +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR J +ENCODING 74 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +03 +03 +03 +02 +02 +06 +06 +04 +04 +8C +8C +F8 +ENDCHAR +STARTCHAR K +ENCODING 75 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3060 +30C0 +2380 +2700 +6E00 +7C00 +7600 +6200 +C300 +C180 +C180 +80C0 +ENDCHAR +STARTCHAR L +ENCODING 76 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +30 +30 +20 +60 +60 +60 +60 +40 +C0 +C0 +C0 +FF +ENDCHAR +STARTCHAR M +ENCODING 77 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 14 12 1 0 +BITMAP +300C +381C +3838 +2828 +6878 +6858 +4890 +4890 +CD30 +CD30 +C630 +8620 +ENDCHAR +STARTCHAR N +ENCODING 78 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +3030 +3830 +2820 +2820 +6460 +6460 +6640 +4240 +4240 +C1C0 +C1C0 +C080 +ENDCHAR +STARTCHAR O +ENCODING 79 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR P +ENCODING 80 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3FC0 +3060 +2060 +2060 +6060 +60C0 +7F80 +4000 +C000 +C000 +C000 +8000 +ENDCHAR +STARTCHAR Q +ENCODING 81 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 13 2 -1 +BITMAP +1F00 +30C0 +6060 +C060 +C020 +8020 +8060 +8060 +8040 +C4C0 +6380 +3F80 +00C0 +ENDCHAR +STARTCHAR R +ENCODING 82 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +3FC0 +3060 +2020 +2020 +6020 +6060 +7F80 +4300 +4180 +C080 +C0C0 +C0C0 +ENDCHAR +STARTCHAR S +ENCODING 83 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +1F80 +30C0 +2040 +2000 +3000 +1E00 +0780 +0180 +C0C0 +C080 +6180 +3E00 +ENDCHAR +STARTCHAR T +ENCODING 84 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 12 2 0 +BITMAP +FFC0 +0C00 +0800 +0800 +1800 +1800 +1800 +1000 +1000 +3000 +3000 +3000 +ENDCHAR +STARTCHAR U +ENCODING 85 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 2 0 +BITMAP +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR V +ENCODING 86 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 2 0 +BITMAP +C060 +C0C0 +4080 +4180 +6100 +6300 +6200 +2600 +2C00 +3C00 +3800 +3000 +ENDCHAR +STARTCHAR W +ENCODING 87 +SWIDTH 943 0 +DWIDTH 16 0 +BBX 16 12 2 0 +BITMAP +C183 +C182 +C386 +C684 +C68C +CC88 +4898 +5890 +50B0 +70A0 +60E0 +60C0 +ENDCHAR +STARTCHAR X +ENCODING 88 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 13 12 0 0 +BITMAP +3038 +1870 +18E0 +0CC0 +0D80 +0700 +0600 +0F00 +1980 +3180 +60C0 +C0C0 +ENDCHAR +STARTCHAR Y +ENCODING 89 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 2 0 +BITMAP +C060 +60C0 +6180 +3300 +3300 +1600 +1C00 +0800 +0800 +1800 +1800 +1000 +ENDCHAR +STARTCHAR Z +ENCODING 90 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 11 12 0 0 +BITMAP +3FE0 +00C0 +0180 +0180 +0300 +0600 +0C00 +1800 +1800 +3000 +6000 +FFC0 +ENDCHAR +STARTCHAR bracketleft +ENCODING 91 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 7 15 0 -3 +BITMAP +1E +10 +10 +10 +30 +30 +20 +20 +60 +60 +60 +40 +40 +C0 +F0 +ENDCHAR +STARTCHAR backslash +ENCODING 92 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 3 12 2 0 +BITMAP +80 +80 +80 +80 +80 +C0 +40 +40 +40 +40 +40 +60 +ENDCHAR +STARTCHAR bracketright +ENCODING 93 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 15 -1 -3 +BITMAP +1C +04 +04 +0C +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +E0 +ENDCHAR +STARTCHAR asciicircum +ENCODING 94 +SWIDTH 469 0 +DWIDTH 8 0 +BBX 7 7 1 5 +BITMAP +18 +38 +28 +24 +64 +46 +C2 +ENDCHAR +STARTCHAR underscore +ENCODING 95 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 1 -1 -3 +BITMAP +FFC0 +ENDCHAR +STARTCHAR grave +ENCODING 96 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 3 3 9 +BITMAP +80 +C0 +40 +ENDCHAR +STARTCHAR a +ENCODING 97 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR b +ENCODING 98 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +20 +20 +20 +7E +63 +61 +41 +41 +C3 +C2 +C6 +BC +ENDCHAR +STARTCHAR c +ENCODING 99 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1C +62 +43 +C0 +C0 +80 +C6 +C4 +78 +ENDCHAR +STARTCHAR d +ENCODING 100 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +0080 +0180 +0180 +3D00 +6500 +4300 +C300 +8300 +8200 +C600 +C600 +7E00 +ENDCHAR +STARTCHAR e +ENCODING 101 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR f +ENCODING 102 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 12 1 0 +BITMAP +1C +30 +20 +F8 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR g +ENCODING 103 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +1E80 +3180 +2180 +6180 +4180 +4100 +4100 +6300 +3F00 +0300 +C600 +7C00 +ENDCHAR +STARTCHAR h +ENCODING 104 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +30 +20 +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR i +ENCODING 105 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 12 1 0 +BITMAP +20 +00 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR j +ENCODING 106 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 15 -2 -3 +BITMAP +04 +00 +00 +0C +0C +08 +08 +18 +18 +10 +10 +10 +30 +30 +E0 +ENDCHAR +STARTCHAR k +ENCODING 107 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +30 +20 +20 +63 +66 +4C +58 +68 +CC +CC +84 +86 +ENDCHAR +STARTCHAR l +ENCODING 108 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 12 1 0 +BITMAP +20 +20 +60 +60 +60 +40 +40 +C0 +C0 +80 +80 +80 +ENDCHAR +STARTCHAR m +ENCODING 109 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +6E70 +7398 +6318 +4218 +C210 +C610 +C630 +8630 +8430 +ENDCHAR +STARTCHAR n +ENCODING 110 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR o +ENCODING 111 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR p +ENCODING 112 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3F00 +3180 +3080 +2080 +6080 +6180 +6100 +6300 +5E00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR q +ENCODING 113 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +3D +67 +43 +C3 +82 +82 +86 +C6 +7E +04 +04 +0C +ENDCHAR +STARTCHAR r +ENCODING 114 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 9 1 0 +BITMAP +6C +70 +60 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR s +ENCODING 115 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +3C +66 +42 +60 +3C +0E +86 +C6 +7C +ENDCHAR +STARTCHAR t +ENCODING 116 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 12 1 0 +BITMAP +10 +20 +20 +F0 +60 +40 +40 +40 +C0 +C0 +C0 +E0 +ENDCHAR +STARTCHAR u +ENCODING 117 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR v +ENCODING 118 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +C1 +43 +42 +46 +6C +68 +78 +30 +30 +ENDCHAR +STARTCHAR w +ENCODING 119 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 9 1 0 +BITMAP +C630 +C620 +4E20 +4A60 +4A40 +52C0 +5280 +6280 +6300 +ENDCHAR +STARTCHAR x +ENCODING 120 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +2180 +3300 +1600 +1C00 +0800 +1C00 +3400 +6600 +C200 +ENDCHAR +STARTCHAR y +ENCODING 121 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +2080 +2180 +2100 +3300 +3600 +3400 +1C00 +1800 +1800 +1000 +2000 +E000 +ENDCHAR +STARTCHAR z +ENCODING 122 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +3F80 +0300 +0600 +0C00 +0800 +1800 +3000 +6000 +FF00 +ENDCHAR +STARTCHAR braceleft +ENCODING 123 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 15 1 -3 +BITMAP +0C +18 +10 +10 +30 +20 +60 +80 +40 +60 +40 +40 +40 +40 +60 +ENDCHAR +STARTCHAR bar +ENCODING 124 +SWIDTH 259 0 +DWIDTH 4 0 +BBX 1 15 2 -3 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR braceright +ENCODING 125 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 15 -1 -3 +BITMAP +18 +0C +08 +08 +08 +08 +08 +04 +18 +10 +30 +30 +20 +20 +C0 +ENDCHAR +STARTCHAR asciitilde +ENCODING 126 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 9 3 1 4 +BITMAP +7000 +8C80 +8700 +ENDCHAR +STARTCHAR space.dup1 +ENCODING 160 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR exclamdown +ENCODING 161 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 12 1 -3 +BITMAP +30 +00 +20 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR cent +ENCODING 162 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +01 +02 +02 +1E +27 +6B +48 +C8 +D0 +D2 +66 +38 +40 +40 +40 +ENDCHAR +STARTCHAR sterling +ENCODING 163 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +0F00 +1180 +3080 +2000 +2000 +2000 +FC00 +3000 +2000 +6000 +F100 +8E00 +ENDCHAR +STARTCHAR currency +ENCODING 164 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 1 +BITMAP +41 +DD +63 +43 +41 +43 +63 +DD +41 +ENDCHAR +STARTCHAR yen +ENCODING 165 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 12 1 0 +BITMAP +60C0 +2180 +2100 +3300 +1600 +1C00 +FF80 +1800 +FF00 +1000 +1000 +1000 +ENDCHAR +STARTCHAR brokenbar +ENCODING 166 +SWIDTH 259 0 +DWIDTH 4 0 +BBX 1 15 2 -3 +BITMAP +80 +80 +80 +80 +80 +80 +80 +00 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR section +ENCODING 167 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +1E +33 +21 +30 +38 +6C +C6 +C3 +61 +33 +1E +0C +84 +C4 +78 +ENDCHAR +STARTCHAR dieresis +ENCODING 168 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 1 2 11 +BITMAP +D8 +ENDCHAR +STARTCHAR copyright +ENCODING 169 +SWIDTH 736 0 +DWIDTH 13 0 +BBX 12 12 1 0 +BITMAP +1F00 +20C0 +4020 +8F10 +9090 +9010 +9010 +9090 +8F10 +4020 +2040 +1F80 +ENDCHAR +STARTCHAR ordfeminine +ENCODING 170 +SWIDTH 370 0 +DWIDTH 6 0 +BBX 6 6 1 6 +BITMAP +38 +44 +04 +7C +C8 +78 +ENDCHAR +STARTCHAR guillemotleft +ENCODING 171 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 7 8 2 1 +BITMAP +26 +64 +C8 +98 +90 +98 +C8 +48 +ENDCHAR +STARTCHAR logicalnot +ENCODING 172 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 8 5 2 4 +BITMAP +FF +03 +03 +03 +03 +ENDCHAR +STARTCHAR hyphen.dup2 +ENCODING 173 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 1 1 4 +BITMAP +F8 +ENDCHAR +STARTCHAR registered +ENCODING 174 +SWIDTH 736 0 +DWIDTH 13 0 +BBX 12 12 1 0 +BITMAP +1F00 +20C0 +4020 +9F10 +9110 +9110 +9F10 +9310 +9110 +4020 +2040 +1F80 +ENDCHAR +STARTCHAR macron +ENCODING 175 +SWIDTH 552 0 +DWIDTH 9 0 +BBX 9 1 2 13 +BITMAP +FF80 +ENDCHAR +STARTCHAR degree +ENCODING 176 +SWIDTH 399 0 +DWIDTH 7 0 +BBX 5 5 2 7 +BITMAP +70 +C8 +88 +C8 +70 +ENDCHAR +STARTCHAR plusminus +ENCODING 177 +SWIDTH 548 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +18 +18 +18 +FF +18 +18 +18 +00 +FF +ENDCHAR +STARTCHAR uni00B2 +ENCODING 178 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 6 1 6 +BITMAP +38 +44 +0C +30 +60 +F8 +ENDCHAR +STARTCHAR uni00B3 +ENCODING 179 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 6 2 6 +BITMAP +70 +C8 +30 +10 +90 +F0 +ENDCHAR +STARTCHAR acute +ENCODING 180 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 3 3 9 +BITMAP +60 +40 +80 +ENDCHAR +STARTCHAR mu +ENCODING 181 +SWIDTH 576 0 +DWIDTH 10 0 +BBX 10 12 0 -3 +BITMAP +10C0 +3080 +3080 +2080 +2180 +6180 +6100 +6300 +5D00 +4000 +C000 +C000 +ENDCHAR +STARTCHAR paragraph +ENCODING 182 +SWIDTH 537 0 +DWIDTH 9 0 +BBX 9 16 1 -4 +BITMAP +3F80 +7900 +F900 +F900 +F900 +7900 +3900 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +ENDCHAR +STARTCHAR periodcentered +ENCODING 183 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 1 1 3 5 +BITMAP +80 +ENDCHAR +STARTCHAR cedilla +ENCODING 184 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 3 1 -3 +BITMAP +40 +30 +E0 +ENDCHAR +STARTCHAR uni00B9 +ENCODING 185 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 6 2 6 +BITMAP +10 +30 +E0 +20 +20 +20 +ENDCHAR +STARTCHAR ordmasculine +ENCODING 186 +SWIDTH 365 0 +DWIDTH 6 0 +BBX 6 6 1 6 +BITMAP +38 +4C +C4 +84 +C8 +78 +ENDCHAR +STARTCHAR guillemotright +ENCODING 187 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 7 8 1 1 +BITMAP +24 +24 +32 +12 +32 +24 +4C +98 +ENDCHAR +STARTCHAR onequarter +ENCODING 188 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 12 13 2 -1 +BITMAP +1010 +3020 +E040 +2080 +2100 +2300 +0630 +0C60 +18E0 +1120 +21F0 +4060 +8000 +ENDCHAR +STARTCHAR onehalf +ENCODING 189 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 13 1 -1 +BITMAP +0818 +3830 +1060 +10C0 +1080 +1100 +0270 +04C8 +0818 +1830 +30C0 +60F0 +C000 +ENDCHAR +STARTCHAR threequarters +ENCODING 190 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 12 13 2 -1 +BITMAP +F010 +0820 +3040 +10C0 +9180 +F300 +0630 +0460 +08E0 +1120 +23F0 +4060 +8000 +ENDCHAR +STARTCHAR questiondown +ENCODING 191 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 8 12 1 -3 +BITMAP +06 +00 +00 +04 +0C +18 +30 +60 +40 +C3 +42 +3C +ENDCHAR +STARTCHAR Agrave +ENCODING 192 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 0 0 +BITMAP +0100 +0180 +0080 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR Aacute +ENCODING 193 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 0 0 +BITMAP +00C0 +0080 +0100 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR Acircumflex +ENCODING 194 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 0 0 +BITMAP +0180 +0280 +0680 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR Atilde +ENCODING 195 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 15 0 0 +BITMAP +0740 +05C0 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR Adieresis +ENCODING 196 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +06C0 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR Aring +ENCODING 197 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 15 0 0 +BITMAP +0180 +0240 +0240 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR AE +ENCODING 198 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 18 12 0 0 +BITMAP +03FFC0 +026000 +066000 +046000 +0C4000 +187F80 +10C000 +3FC000 +60C000 +408000 +C18000 +81FF00 +ENDCHAR +STARTCHAR Ccedilla +ENCODING 199 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 10 15 2 -3 +BITMAP +1F00 +3080 +60C0 +C040 +C000 +8000 +8000 +8000 +80C0 +C180 +6300 +3E00 +2000 +1800 +7000 +ENDCHAR +STARTCHAR Egrave +ENCODING 200 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 1 0 +BITMAP +0200 +0300 +0100 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR Eacute +ENCODING 201 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 1 0 +BITMAP +0300 +0200 +0400 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR Ecircumflex +ENCODING 202 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 1 0 +BITMAP +0300 +0500 +0D00 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR Edieresis +ENCODING 203 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 14 1 0 +BITMAP +0D80 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR Igrave +ENCODING 204 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 16 1 0 +BITMAP +10 +18 +08 +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR Iacute +ENCODING 205 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 16 1 0 +BITMAP +18 +10 +20 +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR Icircumflex +ENCODING 206 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 16 1 0 +BITMAP +18 +28 +68 +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR Idieresis +ENCODING 207 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 14 1 0 +BITMAP +6C +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR Eth +ENCODING 208 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +3F80 +30C0 +3060 +2060 +2020 +6020 +FC60 +6060 +4040 +C0C0 +C180 +FF00 +ENDCHAR +STARTCHAR Ntilde +ENCODING 209 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 15 1 0 +BITMAP +0740 +05C0 +0000 +3030 +3830 +2820 +2820 +6460 +6460 +6640 +4240 +4240 +C1C0 +C1C0 +C080 +ENDCHAR +STARTCHAR Ograve +ENCODING 210 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0200 +0300 +0100 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR Oacute +ENCODING 211 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0300 +0200 +0400 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR Ocircumflex +ENCODING 212 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0300 +0500 +0D00 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR Otilde +ENCODING 213 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 15 2 0 +BITMAP +0E80 +0B80 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR Odieresis +ENCODING 214 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 14 2 0 +BITMAP +0D80 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR multiply +ENCODING 215 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 6 7 3 3 +BITMAP +84 +CC +78 +30 +78 +CC +84 +ENDCHAR +STARTCHAR Oslash +ENCODING 216 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 14 2 -1 +BITMAP +0020 +1FE0 +30C0 +60E0 +C160 +C260 +8420 +8C60 +9860 +9040 +E0C0 +6180 +BE00 +8000 +ENDCHAR +STARTCHAR Ugrave +ENCODING 217 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 2 0 +BITMAP +0400 +0600 +0200 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR Uacute +ENCODING 218 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 2 0 +BITMAP +0300 +0200 +0400 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR Ucircumflex +ENCODING 219 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 2 0 +BITMAP +0300 +0500 +0D00 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR Udieresis +ENCODING 220 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 14 2 0 +BITMAP +0D80 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR Yacute +ENCODING 221 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 2 0 +BITMAP +0600 +0400 +0800 +0000 +C060 +60C0 +6180 +3300 +3300 +1600 +1C00 +0800 +0800 +1800 +1800 +1000 +ENDCHAR +STARTCHAR Thorn +ENCODING 222 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +3000 +3000 +3F80 +20C0 +6040 +6040 +6040 +40C0 +C180 +FF00 +C000 +8000 +ENDCHAR +STARTCHAR germandbls +ENCODING 223 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +0E00 +3100 +2100 +6300 +6600 +4400 +4600 +4300 +C100 +C180 +9100 +8E00 +ENDCHAR +STARTCHAR agrave +ENCODING 224 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +08 +0C +04 +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR aacute +ENCODING 225 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +04 +08 +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR acircumflex +ENCODING 226 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +0A +1A +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR atilde +ENCODING 227 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1D +17 +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR adieresis +ENCODING 228 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1B +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR aring +ENCODING 229 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +0C +12 +12 +0C +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR ae +ENCODING 230 +SWIDTH 889 0 +DWIDTH 15 0 +BBX 14 9 1 0 +BITMAP +3EF0 +6388 +430C +030C +7FFC +C600 +8618 +CF10 +71E0 +ENDCHAR +STARTCHAR ccedilla +ENCODING 231 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +1C +62 +43 +C0 +C0 +80 +C6 +C4 +78 +20 +18 +70 +ENDCHAR +STARTCHAR egrave +ENCODING 232 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +08 +0C +04 +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR eacute +ENCODING 233 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +04 +08 +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR ecircumflex +ENCODING 234 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +0A +1A +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR edieresis +ENCODING 235 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1B +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR igrave +ENCODING 236 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 13 1 0 +BITMAP +20 +30 +10 +00 +20 +20 +60 +60 +40 +40 +40 +C0 +C0 +ENDCHAR +STARTCHAR iacute +ENCODING 237 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 13 1 0 +BITMAP +18 +10 +20 +00 +20 +20 +60 +60 +40 +40 +40 +C0 +C0 +ENDCHAR +STARTCHAR icircumflex +ENCODING 238 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 13 1 0 +BITMAP +18 +28 +68 +00 +20 +20 +60 +60 +40 +40 +40 +C0 +C0 +ENDCHAR +STARTCHAR idieresis +ENCODING 239 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 11 1 0 +BITMAP +D8 +00 +20 +20 +60 +60 +40 +40 +40 +C0 +C0 +ENDCHAR +STARTCHAR eth +ENCODING 240 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +07 +0E +03 +3D +63 +41 +C1 +81 +83 +82 +C6 +7C +ENDCHAR +STARTCHAR ntilde +ENCODING 241 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1D +17 +00 +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR ograve +ENCODING 242 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +08 +0C +04 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR oacute +ENCODING 243 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +04 +08 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR ocircumflex +ENCODING 244 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +0A +1A +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR otilde +ENCODING 245 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1D +17 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR odieresis +ENCODING 246 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1B +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR divide +ENCODING 247 +SWIDTH 548 0 +DWIDTH 9 0 +BBX 8 5 1 3 +BITMAP +18 +00 +FF +00 +18 +ENDCHAR +STARTCHAR oslash +ENCODING 248 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 9 10 1 0 +BITMAP +0080 +1F00 +3300 +6380 +4580 +C980 +D100 +F300 +6600 +7C00 +ENDCHAR +STARTCHAR ugrave +ENCODING 249 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +08 +0C +04 +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uacute +ENCODING 250 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +04 +08 +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR ucircumflex +ENCODING 251 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +0A +1A +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR udieresis +ENCODING 252 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1B +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR yacute +ENCODING 253 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0600 +0400 +0800 +0000 +2080 +2180 +2100 +3300 +3600 +3400 +1C00 +1800 +1800 +1000 +2000 +E000 +ENDCHAR +STARTCHAR thorn +ENCODING 254 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 15 0 -3 +BITMAP +1000 +1000 +1000 +3F00 +3180 +3080 +2080 +6080 +6180 +6100 +6300 +5E00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR ydieresis +ENCODING 255 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 14 0 -3 +BITMAP +1B00 +0000 +2080 +2180 +2100 +3300 +3600 +3400 +1C00 +1800 +1800 +1000 +2000 +E000 +ENDCHAR +STARTCHAR Amacron +ENCODING 256 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +07C0 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR amacron +ENCODING 257 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1F +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR Abreve +ENCODING 258 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 15 0 0 +BITMAP +0260 +01C0 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR abreve +ENCODING 259 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +13 +0E +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR Aogonek +ENCODING 260 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 0 -4 +BITMAP +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +0040 +0080 +0080 +00C0 +ENDCHAR +STARTCHAR aogonek +ENCODING 261 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 -4 +BITMAP +1E +63 +43 +03 +7F +C2 +86 +CE +7A +02 +04 +04 +06 +ENDCHAR +STARTCHAR Cacute +ENCODING 262 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 10 16 2 0 +BITMAP +0300 +0200 +0400 +0000 +1F00 +3080 +60C0 +C040 +C000 +8000 +8000 +8000 +80C0 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR cacute +ENCODING 263 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +04 +08 +00 +1C +62 +43 +C0 +C0 +80 +C6 +C4 +78 +ENDCHAR +STARTCHAR Ccircumflex +ENCODING 264 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 10 16 2 0 +BITMAP +0300 +0500 +0D00 +0000 +1F00 +3080 +60C0 +C040 +C000 +8000 +8000 +8000 +80C0 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR ccircumflex +ENCODING 265 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +0A +1A +00 +1C +62 +43 +C0 +C0 +80 +C6 +C4 +78 +ENDCHAR +STARTCHAR Cdotaccent +ENCODING 266 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 10 14 2 0 +BITMAP +0600 +0000 +1F00 +3080 +60C0 +C040 +C000 +8000 +8000 +8000 +80C0 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR cdotaccent +ENCODING 267 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +18 +00 +1C +62 +43 +C0 +C0 +80 +C6 +C4 +78 +ENDCHAR +STARTCHAR Ccaron +ENCODING 268 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 10 16 2 0 +BITMAP +0D80 +0700 +0600 +0000 +1F00 +3080 +60C0 +C040 +C000 +8000 +8000 +8000 +80C0 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR ccaron +ENCODING 269 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +1B +0E +0C +00 +1C +62 +43 +C0 +C0 +80 +C6 +C4 +78 +ENDCHAR +STARTCHAR Dcaron +ENCODING 270 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 1 0 +BITMAP +0D80 +0700 +0600 +0000 +3F80 +30C0 +2060 +2060 +6060 +6060 +6060 +4060 +C040 +C0C0 +C180 +FE00 +ENDCHAR +STARTCHAR dcaron +ENCODING 271 +SWIDTH 625 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +00A0 +01A0 +01E0 +3D00 +6500 +4300 +C300 +8300 +8200 +C600 +C600 +7E00 +ENDCHAR +STARTCHAR Dcroat +ENCODING 272 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +3F80 +30C0 +3060 +2060 +2020 +6020 +FC60 +6060 +4040 +C0C0 +C180 +FF00 +ENDCHAR +STARTCHAR dcroat +ENCODING 273 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 12 1 0 +BITMAP +0080 +07C0 +0180 +3D00 +6500 +4300 +C300 +8300 +8200 +C600 +C600 +7E00 +ENDCHAR +STARTCHAR Emacron +ENCODING 274 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 14 1 0 +BITMAP +07C0 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR emacron +ENCODING 275 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1F +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR Ebreve +ENCODING 276 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 15 1 0 +BITMAP +04C0 +0380 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR ebreve +ENCODING 277 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +13 +0E +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR Edotaccent +ENCODING 278 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 14 1 0 +BITMAP +0300 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR edotaccent +ENCODING 279 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +0C +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR Eogonek +ENCODING 280 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 1 -4 +BITMAP +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +0100 +0200 +0200 +0300 +ENDCHAR +STARTCHAR eogonek +ENCODING 281 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 -4 +BITMAP +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +10 +20 +20 +30 +ENDCHAR +STARTCHAR Ecaron +ENCODING 282 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 1 0 +BITMAP +0D80 +0700 +0600 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR ecaron +ENCODING 283 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +1B +0E +0C +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR Gcircumflex +ENCODING 284 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0180 +0280 +0680 +0000 +0F80 +30C0 +6060 +4060 +C000 +8000 +87C0 +8040 +80C0 +C0C0 +61C0 +3F00 +ENDCHAR +STARTCHAR gcircumflex +ENCODING 285 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0300 +0500 +0D00 +0000 +1E80 +3180 +2180 +6180 +4180 +4100 +4100 +6300 +3F00 +0300 +C600 +7C00 +ENDCHAR +STARTCHAR Gbreve +ENCODING 286 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 15 2 0 +BITMAP +04C0 +0380 +0000 +0F80 +30C0 +6060 +4060 +C000 +8000 +87C0 +8040 +80C0 +C0C0 +61C0 +3F00 +ENDCHAR +STARTCHAR gbreve +ENCODING 287 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 15 0 -3 +BITMAP +0980 +0700 +0000 +1E80 +3180 +2180 +6180 +4180 +4100 +4100 +6300 +3F00 +0300 +C600 +7C00 +ENDCHAR +STARTCHAR Gdotaccent +ENCODING 288 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 14 2 0 +BITMAP +0600 +0000 +0F80 +30C0 +6060 +4060 +C000 +8000 +87C0 +8040 +80C0 +C0C0 +61C0 +3F00 +ENDCHAR +STARTCHAR gdotaccent +ENCODING 289 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 14 0 -3 +BITMAP +0600 +0000 +1E80 +3180 +2180 +6180 +4180 +4100 +4100 +6300 +3F00 +0300 +C600 +7C00 +ENDCHAR +STARTCHAR uni0122 +ENCODING 290 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 17 2 -5 +BITMAP +0F80 +30C0 +6060 +4060 +C000 +8000 +87C0 +8040 +80C0 +C0C0 +61C0 +3F00 +0000 +0C00 +0400 +0800 +1000 +ENDCHAR +STARTCHAR uni0123 +ENCODING 291 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0200 +0400 +0600 +0000 +1E80 +3180 +2180 +6180 +4180 +4100 +6100 +6300 +3F00 +0300 +C200 +7C00 +ENDCHAR +STARTCHAR Hcircumflex +ENCODING 292 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 16 1 0 +BITMAP +0180 +0280 +0680 +0000 +3030 +3020 +2020 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C0C0 +8080 +ENDCHAR +STARTCHAR hcircumflex +ENCODING 293 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +06 +0A +1A +00 +30 +20 +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR Hbar +ENCODING 294 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +3030 +3020 +7FF0 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C0C0 +8080 +ENDCHAR +STARTCHAR hbar +ENCODING 295 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +30 +7C +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR Itilde +ENCODING 296 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 15 1 0 +BITMAP +74 +5C +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR itilde +ENCODING 297 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 12 1 0 +BITMAP +E8 +B8 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR Imacron +ENCODING 298 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 14 1 0 +BITMAP +7C +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR imacron +ENCODING 299 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 11 1 0 +BITMAP +F8 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR Ibreve +ENCODING 300 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 7 15 1 0 +BITMAP +26 +1C +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR ibreve +ENCODING 301 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 12 1 0 +BITMAP +98 +70 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR Iogonek +ENCODING 302 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 16 0 -4 +BITMAP +18 +18 +18 +10 +10 +30 +30 +30 +20 +60 +60 +60 +40 +80 +80 +C0 +ENDCHAR +STARTCHAR iogonek +ENCODING 303 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 4 16 0 -4 +BITMAP +10 +00 +00 +30 +30 +20 +20 +60 +60 +60 +40 +40 +40 +80 +80 +C0 +ENDCHAR +STARTCHAR Idotaccent +ENCODING 304 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 14 1 0 +BITMAP +30 +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR dotlessi +ENCODING 305 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 3 9 1 0 +BITMAP +20 +20 +60 +60 +40 +40 +40 +C0 +C0 +ENDCHAR +STARTCHAR IJ +ENCODING 306 +SWIDTH 733 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +3030 +3030 +3030 +2020 +2020 +6060 +6060 +6040 +4040 +C8C0 +C8C0 +CF80 +ENDCHAR +STARTCHAR ij +ENCODING 307 +SWIDTH 443 0 +DWIDTH 8 0 +BBX 7 15 1 -3 +BITMAP +22 +00 +00 +66 +66 +44 +44 +CC +CC +C8 +88 +88 +18 +18 +70 +ENDCHAR +STARTCHAR Jcircumflex +ENCODING 308 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 16 1 0 +BITMAP +0180 +0280 +0680 +0000 +0300 +0300 +0300 +0200 +0200 +0600 +0600 +0400 +0400 +8C00 +8C00 +F800 +ENDCHAR +STARTCHAR jcircumflex +ENCODING 309 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 7 16 -2 -3 +BITMAP +06 +0A +1A +00 +0C +0C +08 +08 +18 +18 +10 +10 +10 +30 +20 +E0 +ENDCHAR +STARTCHAR uni0136 +ENCODING 310 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 17 1 -5 +BITMAP +3060 +30C0 +2380 +2700 +6E00 +7C00 +7600 +6200 +C300 +C180 +C180 +80C0 +0000 +0C00 +0400 +0800 +1000 +ENDCHAR +STARTCHAR uni0137 +ENCODING 311 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 17 1 -5 +BITMAP +30 +20 +20 +63 +66 +4C +58 +68 +CC +CC +84 +86 +00 +30 +10 +20 +40 +ENDCHAR +STARTCHAR kgreenlandic +ENCODING 312 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +63 +66 +4C +58 +E8 +CC +CC +84 +86 +ENDCHAR +STARTCHAR Lacute +ENCODING 313 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +0C +08 +10 +00 +30 +30 +20 +60 +60 +60 +60 +40 +C0 +C0 +C0 +FF +ENDCHAR +STARTCHAR lacute +ENCODING 314 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 16 1 0 +BITMAP +18 +10 +20 +00 +20 +20 +60 +60 +60 +40 +40 +C0 +C0 +80 +80 +80 +ENDCHAR +STARTCHAR uni013B +ENCODING 315 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 17 1 -5 +BITMAP +30 +30 +20 +60 +60 +60 +60 +40 +C0 +C0 +C0 +FF +00 +18 +08 +10 +20 +ENDCHAR +STARTCHAR uni013C +ENCODING 316 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 17 -1 -5 +BITMAP +08 +08 +18 +18 +18 +10 +10 +30 +30 +20 +20 +20 +00 +60 +20 +40 +80 +ENDCHAR +STARTCHAR Lcaron +ENCODING 317 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +31 +31 +23 +60 +60 +60 +60 +40 +C0 +C0 +C0 +FF +ENDCHAR +STARTCHAR lcaron +ENCODING 318 +SWIDTH 281 0 +DWIDTH 5 0 +BBX 6 12 1 0 +BITMAP +2C +28 +68 +60 +60 +40 +40 +C0 +C0 +80 +80 +80 +ENDCHAR +STARTCHAR Ldot +ENCODING 319 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +30 +30 +20 +60 +60 +60 +68 +40 +C0 +C0 +C0 +FF +ENDCHAR +STARTCHAR ldot +ENCODING 320 +SWIDTH 399 0 +DWIDTH 7 0 +BBX 5 12 1 0 +BITMAP +20 +20 +60 +60 +60 +40 +48 +C0 +C0 +80 +80 +80 +ENDCHAR +STARTCHAR Lslash +ENCODING 321 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 0 +BITMAP +1800 +1800 +1000 +1200 +3400 +3800 +7000 +A000 +6000 +6000 +6000 +7F80 +ENDCHAR +STARTCHAR lslash +ENCODING 322 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 12 0 0 +BITMAP +10 +10 +10 +30 +38 +30 +60 +E0 +60 +60 +40 +40 +ENDCHAR +STARTCHAR Nacute +ENCODING 323 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 16 1 0 +BITMAP +0180 +0100 +0200 +0000 +3030 +3830 +2820 +2820 +6460 +6460 +6640 +4240 +4240 +C1C0 +C1C0 +C080 +ENDCHAR +STARTCHAR nacute +ENCODING 324 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +04 +08 +00 +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR uni0145 +ENCODING 325 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 17 1 -5 +BITMAP +3030 +3830 +2820 +2820 +6460 +6460 +6640 +4240 +4240 +C1C0 +C1C0 +C080 +0000 +1800 +0800 +1000 +2000 +ENDCHAR +STARTCHAR uni0146 +ENCODING 326 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 -5 +BITMAP +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +00 +30 +10 +20 +40 +ENDCHAR +STARTCHAR Ncaron +ENCODING 327 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 16 1 0 +BITMAP +06C0 +0380 +0300 +0000 +3030 +3830 +2820 +2820 +6460 +6460 +6640 +4240 +4240 +C1C0 +C1C0 +C080 +ENDCHAR +STARTCHAR ncaron +ENCODING 328 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +1B +0E +0C +00 +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR napostrophe +ENCODING 329 +SWIDTH 614 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +6000 +4000 +4000 +B700 +3980 +3180 +2180 +6180 +6100 +6100 +4300 +4300 +ENDCHAR +STARTCHAR Eng +ENCODING 330 +SWIDTH 723 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +3780 +38C0 +3060 +2060 +6060 +6060 +6060 +4060 +4040 +C0C0 +C080 +CF00 +ENDCHAR +STARTCHAR eng +ENCODING 331 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +6E +53 +63 +43 +43 +C2 +C2 +86 +86 +06 +04 +1C +ENDCHAR +STARTCHAR Omacron +ENCODING 332 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 14 2 0 +BITMAP +0F80 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR omacron +ENCODING 333 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1F +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR Obreve +ENCODING 334 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 15 2 0 +BITMAP +0980 +0700 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR obreve +ENCODING 335 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +13 +0E +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR Ohungarumlaut +ENCODING 336 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0680 +0D80 +0900 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR ohungarumlaut +ENCODING 337 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +0D +1B +12 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR OE +ENCODING 338 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 17 12 1 0 +BITMAP +0FBF80 +18E000 +306000 +606000 +406000 +404000 +C07F00 +C0C000 +C0C000 +41C000 +638000 +1FFE00 +ENDCHAR +STARTCHAR oe +ENCODING 339 +SWIDTH 943 0 +DWIDTH 16 0 +BBX 15 9 1 0 +BITMAP +1E78 +63CC +4184 +C186 +C1FE +C300 +C30C +4798 +3CF0 +ENDCHAR +STARTCHAR Racute +ENCODING 340 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 1 0 +BITMAP +0300 +0200 +0400 +0000 +3FC0 +3060 +2020 +2020 +6020 +6060 +7F80 +4300 +4180 +C080 +C0C0 +C0C0 +ENDCHAR +STARTCHAR racute +ENCODING 341 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 13 1 0 +BITMAP +0C +08 +10 +00 +6C +70 +60 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni0156 +ENCODING 342 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 17 1 -5 +BITMAP +3FC0 +3060 +2020 +2020 +6020 +6060 +7F80 +4300 +4180 +C080 +C0C0 +C0C0 +0000 +0C00 +0400 +0800 +1000 +ENDCHAR +STARTCHAR uni0157 +ENCODING 343 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 8 14 -1 -5 +BITMAP +1B +1C +18 +10 +30 +30 +30 +20 +20 +00 +60 +20 +40 +80 +ENDCHAR +STARTCHAR Rcaron +ENCODING 344 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 1 0 +BITMAP +0D80 +0700 +0600 +0000 +3FC0 +3060 +2020 +2020 +6020 +6060 +7F80 +4300 +4180 +C080 +C0C0 +C0C0 +ENDCHAR +STARTCHAR rcaron +ENCODING 345 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 7 13 1 0 +BITMAP +36 +1C +18 +00 +6C +70 +60 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR Sacute +ENCODING 346 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 1 0 +BITMAP +0300 +0200 +0400 +0000 +1F80 +30C0 +2040 +2000 +3000 +1E00 +0780 +0180 +C0C0 +C080 +6180 +3E00 +ENDCHAR +STARTCHAR sacute +ENCODING 347 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 13 1 0 +BITMAP +0C +08 +10 +00 +3C +66 +42 +60 +3C +0E +86 +C6 +7C +ENDCHAR +STARTCHAR Scircumflex +ENCODING 348 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 1 0 +BITMAP +0300 +0500 +0D00 +0000 +1F80 +30C0 +2040 +2000 +3000 +1E00 +0780 +0180 +C0C0 +C080 +6180 +3E00 +ENDCHAR +STARTCHAR scircumflex +ENCODING 349 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 13 1 0 +BITMAP +06 +0A +1A +00 +3C +66 +42 +60 +3C +0E +86 +C6 +7C +ENDCHAR +STARTCHAR Scedilla +ENCODING 350 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 15 1 -3 +BITMAP +1F80 +30C0 +2040 +2000 +3000 +1E00 +0780 +0180 +C0C0 +C080 +6180 +3E00 +1000 +0C00 +3800 +ENDCHAR +STARTCHAR scedilla +ENCODING 351 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 12 1 -3 +BITMAP +3C +66 +42 +60 +3C +0E +86 +C6 +7C +20 +18 +70 +ENDCHAR +STARTCHAR Scaron +ENCODING 352 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 1 0 +BITMAP +0D80 +0700 +0600 +0000 +1F80 +30C0 +2040 +2000 +3000 +1E00 +0780 +0180 +C0C0 +C080 +6180 +3E00 +ENDCHAR +STARTCHAR scaron +ENCODING 353 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +1B +0E +0C +00 +3C +66 +42 +60 +3C +0E +86 +C6 +7C +ENDCHAR +STARTCHAR uni0162 +ENCODING 354 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 15 2 -3 +BITMAP +FFC0 +0C00 +0800 +0800 +1800 +1800 +1800 +1000 +1000 +3000 +3000 +3000 +2000 +1800 +7000 +ENDCHAR +STARTCHAR uni0163 +ENCODING 355 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 15 1 -3 +BITMAP +10 +20 +20 +F0 +60 +40 +40 +40 +C0 +C0 +C0 +E0 +40 +30 +E0 +ENDCHAR +STARTCHAR Tcaron +ENCODING 356 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 16 2 0 +BITMAP +1B00 +0E00 +0C00 +0000 +FFC0 +0C00 +0800 +0800 +1800 +1800 +1800 +1000 +1000 +3000 +3000 +3000 +ENDCHAR +STARTCHAR tcaron +ENCODING 357 +SWIDTH 354 0 +DWIDTH 6 0 +BBX 7 12 1 0 +BITMAP +26 +22 +24 +F0 +60 +40 +40 +C0 +C0 +C0 +80 +E0 +ENDCHAR +STARTCHAR Tbar +ENCODING 358 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 12 2 0 +BITMAP +FFC0 +0C00 +0800 +0800 +1800 +1800 +FF00 +1000 +1000 +3000 +3000 +3000 +ENDCHAR +STARTCHAR tbar +ENCODING 359 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 12 0 0 +BITMAP +08 +10 +10 +78 +30 +30 +20 +F8 +60 +60 +60 +70 +ENDCHAR +STARTCHAR Utilde +ENCODING 360 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 15 2 0 +BITMAP +0E80 +0B80 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR utilde +ENCODING 361 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1D +17 +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR Umacron +ENCODING 362 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 14 2 0 +BITMAP +0F80 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR umacron +ENCODING 363 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1F +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR Ubreve +ENCODING 364 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 15 2 0 +BITMAP +0980 +0700 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR ubreve +ENCODING 365 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +13 +0E +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR Uring +ENCODING 366 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 2 0 +BITMAP +0600 +0900 +0900 +0600 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uring +ENCODING 367 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +0C +12 +12 +0C +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR Uhungarumlaut +ENCODING 368 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 2 0 +BITMAP +0680 +0D80 +0900 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uhungarumlaut +ENCODING 369 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +0D +1B +12 +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR Uogonek +ENCODING 370 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 2 -4 +BITMAP +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +0800 +1000 +1000 +1800 +ENDCHAR +STARTCHAR uogonek +ENCODING 371 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 -4 +BITMAP +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +04 +08 +08 +0C +ENDCHAR +STARTCHAR Wcircumflex +ENCODING 372 +SWIDTH 943 0 +DWIDTH 16 0 +BBX 16 16 2 0 +BITMAP +00C0 +0140 +0340 +0000 +C183 +C182 +C386 +C684 +C68C +CC88 +4898 +5890 +50B0 +70A0 +60E0 +60C0 +ENDCHAR +STARTCHAR wcircumflex +ENCODING 373 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 13 1 0 +BITMAP +0300 +0500 +0D00 +0000 +C630 +C620 +4E20 +4A60 +4A40 +52C0 +5280 +6280 +6300 +ENDCHAR +STARTCHAR Ycircumflex +ENCODING 374 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 2 0 +BITMAP +0300 +0500 +0D00 +0000 +C060 +60C0 +6180 +3300 +3300 +1600 +1C00 +0800 +0800 +1800 +1800 +1000 +ENDCHAR +STARTCHAR ycircumflex +ENCODING 375 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0600 +0A00 +1A00 +0000 +2080 +2180 +2100 +3300 +3600 +3400 +1C00 +1800 +1800 +1000 +2000 +E000 +ENDCHAR +STARTCHAR Ydieresis +ENCODING 376 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 14 2 0 +BITMAP +1B00 +0000 +C060 +60C0 +6180 +3300 +3300 +1600 +1C00 +0800 +0800 +1800 +1800 +1000 +ENDCHAR +STARTCHAR Zacute +ENCODING 377 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 11 16 0 0 +BITMAP +0300 +0200 +0400 +0000 +3FE0 +00C0 +0180 +0180 +0300 +0600 +0C00 +1800 +1800 +3000 +6000 +FFC0 +ENDCHAR +STARTCHAR zacute +ENCODING 378 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 13 0 0 +BITMAP +0600 +0400 +0800 +0000 +3F80 +0300 +0600 +0C00 +0800 +1800 +3000 +6000 +FF00 +ENDCHAR +STARTCHAR Zdotaccent +ENCODING 379 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 11 14 0 0 +BITMAP +0600 +0000 +3FE0 +00C0 +0180 +0180 +0300 +0600 +0C00 +1800 +1800 +3000 +6000 +FFC0 +ENDCHAR +STARTCHAR zdotaccent +ENCODING 380 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 11 0 0 +BITMAP +0C00 +0000 +3F80 +0300 +0600 +0C00 +0800 +1800 +3000 +6000 +FF00 +ENDCHAR +STARTCHAR Zcaron +ENCODING 381 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 11 16 0 0 +BITMAP +0D80 +0700 +0600 +0000 +3FE0 +00C0 +0180 +0180 +0300 +0600 +0C00 +1800 +1800 +3000 +6000 +FFC0 +ENDCHAR +STARTCHAR zcaron +ENCODING 382 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 13 0 0 +BITMAP +1B00 +0E00 +0C00 +0000 +3F80 +0300 +0600 +0C00 +0800 +1800 +3000 +6000 +FF00 +ENDCHAR +STARTCHAR longs +ENCODING 383 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 12 1 0 +BITMAP +3C +20 +60 +60 +60 +40 +40 +C0 +C0 +80 +80 +80 +ENDCHAR +STARTCHAR uni0180 +ENCODING 384 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +20 +7C +20 +6E +73 +61 +41 +41 +C3 +C2 +C6 +BC +ENDCHAR +STARTCHAR uni0181 +ENCODING 385 +SWIDTH 730 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +7FC0 +D860 +9020 +1020 +3060 +3F80 +3040 +2060 +2060 +6060 +60C0 +7F80 +ENDCHAR +STARTCHAR uni0182 +ENCODING 386 +SWIDTH 650 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +3FC0 +3000 +2000 +2000 +6000 +7F00 +4080 +40C0 +C0C0 +C080 +C180 +FE00 +ENDCHAR +STARTCHAR uni0183 +ENCODING 387 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +3E +20 +20 +6E +73 +61 +41 +41 +C3 +C2 +C6 +BC +ENDCHAR +STARTCHAR uni0184 +ENCODING 388 +SWIDTH 650 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +1000 +3000 +6000 +6000 +6000 +7F00 +4080 +40C0 +C0C0 +C080 +C180 +FE00 +ENDCHAR +STARTCHAR uni0185 +ENCODING 389 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +30 +60 +60 +6E +73 +61 +41 +41 +C3 +C2 +C6 +BC +ENDCHAR +STARTCHAR uni0186 +ENCODING 390 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +0F80 +30C0 +2060 +6060 +0020 +0020 +0060 +0060 +C040 +40C0 +6180 +1E00 +ENDCHAR +STARTCHAR uni0187 +ENCODING 391 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 13 13 2 0 +BITMAP +0038 +1F20 +30E0 +60E0 +C040 +C000 +8000 +8000 +8000 +80C0 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR uni0188 +ENCODING 392 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 11 10 1 0 +BITMAP +01E0 +1D00 +6300 +4300 +C000 +C000 +8000 +C600 +C400 +7800 +ENDCHAR +STARTCHAR uni0189 +ENCODING 393 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +3F80 +30C0 +3060 +2060 +2020 +6020 +FC60 +6060 +4040 +C0C0 +C180 +FF00 +ENDCHAR +STARTCHAR uni018A +ENCODING 394 +SWIDTH 784 0 +DWIDTH 13 0 +BBX 12 12 1 0 +BITMAP +7FC0 +D860 +9030 +1030 +3030 +3030 +3030 +2030 +2020 +6060 +60C0 +7F00 +ENDCHAR +STARTCHAR uni018B +ENCODING 395 +SWIDTH 650 0 +DWIDTH 11 0 +BBX 12 12 0 0 +BITMAP +0FF0 +0020 +0060 +0060 +0060 +1FC0 +7040 +60C0 +40C0 +C0C0 +6080 +3F80 +ENDCHAR +STARTCHAR uni018C +ENCODING 396 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +0F80 +0180 +0180 +3D00 +6300 +4300 +C300 +8300 +8200 +C600 +C600 +7E00 +ENDCHAR +STARTCHAR uni018D +ENCODING 397 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +0F00 +3180 +2080 +6080 +6080 +4180 +6180 +6300 +3E00 +0800 +0400 +FE00 +ENDCHAR +STARTCHAR uni018E +ENCODING 398 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +7FE0 +0060 +0040 +0040 +00C0 +00C0 +7FC0 +0080 +0080 +0180 +0180 +FF00 +ENDCHAR +STARTCHAR uni018F +ENCODING 399 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +0F00 +30C0 +6040 +4040 +0060 +FFE0 +8060 +80C0 +80C0 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR uni0190 +ENCODING 400 +SWIDTH 613 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +0F00 +3080 +20C0 +20C0 +3000 +3C00 +6000 +C000 +C180 +C100 +C600 +7C00 +ENDCHAR +STARTCHAR uni0191 +ENCODING 401 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 13 15 -2 -3 +BITMAP +07F8 +0600 +0400 +0400 +0C00 +0FF0 +0800 +0800 +1800 +1800 +1800 +1000 +1000 +3000 +E000 +ENDCHAR +STARTCHAR florin +ENCODING 402 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 15 0 -3 +BITMAP +0380 +0600 +0400 +1F00 +0C00 +0C00 +0C00 +0800 +0800 +0800 +1800 +1800 +1800 +1000 +F000 +ENDCHAR +STARTCHAR uni0193 +ENCODING 403 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 14 13 2 0 +BITMAP +001C +0FB0 +30E0 +6060 +4060 +C000 +8000 +87C0 +8040 +80C0 +C0C0 +61C0 +3F00 +ENDCHAR +STARTCHAR uni0194 +ENCODING 404 +SWIDTH 496 0 +DWIDTH 8 0 +BBX 10 15 1 -3 +BITMAP +C0C0 +C080 +4180 +4300 +6200 +6600 +2C00 +2800 +3800 +3000 +3000 +7000 +D000 +D000 +E000 +ENDCHAR +STARTCHAR uni0195 +ENCODING 405 +SWIDTH 879 0 +DWIDTH 15 0 +BBX 14 12 1 0 +BITMAP +3000 +2000 +2000 +6E0C +730C +630C +4308 +4308 +C218 +C218 +8330 +81E0 +ENDCHAR +STARTCHAR uni0196 +ENCODING 406 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 12 1 0 +BITMAP +20 +20 +60 +60 +60 +40 +40 +C0 +C0 +80 +80 +80 +ENDCHAR +STARTCHAR uni0197 +ENCODING 407 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 12 1 0 +BITMAP +30 +30 +30 +20 +20 +60 +F0 +60 +40 +40 +C0 +C0 +ENDCHAR +STARTCHAR uni0198 +ENCODING 408 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +1C60 +30C0 +2380 +2700 +6C00 +7C00 +7600 +6200 +4300 +C180 +C180 +80C0 +ENDCHAR +STARTCHAR uni0199 +ENCODING 409 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +3C +20 +20 +63 +66 +4C +58 +68 +CC +CC +84 +86 +ENDCHAR +STARTCHAR uni019A +ENCODING 410 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 12 1 0 +BITMAP +20 +20 +20 +60 +60 +40 +E0 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni019B +ENCODING 411 +SWIDTH 492 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +0F +1C +34 +04 +0C +1E +16 +36 +22 +62 +C2 +83 +ENDCHAR +STARTCHAR uni019C +ENCODING 412 +SWIDTH 846 0 +DWIDTH 14 0 +BBX 14 12 1 0 +BITMAP +218C +218C +610C +6108 +6308 +4318 +4318 +C218 +C610 +C630 +CE70 +73B0 +ENDCHAR +STARTCHAR uni019D +ENCODING 413 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 15 15 -2 -3 +BITMAP +0606 +0706 +0704 +0584 +0D8C +0C8C +0CC8 +0848 +0878 +1838 +1838 +1030 +1000 +3000 +E000 +ENDCHAR +STARTCHAR uni019E +ENCODING 414 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +6E +53 +63 +43 +C3 +C2 +C2 +86 +86 +04 +04 +04 +ENDCHAR +STARTCHAR uni019F +ENCODING 415 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +1F00 +30C0 +6060 +C060 +C060 +8020 +FFE0 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR Ohorn +ENCODING 416 +SWIDTH 811 0 +DWIDTH 14 0 +BBX 13 12 2 0 +BITMAP +1F18 +30C8 +6068 +C070 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR ohorn +ENCODING 417 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 10 9 1 0 +BITMAP +3E40 +6340 +4140 +C180 +8100 +8300 +8200 +C600 +7800 +ENDCHAR +STARTCHAR uni01A2 +ENCODING 418 +SWIDTH 868 0 +DWIDTH 15 0 +BBX 13 15 2 -3 +BITMAP +1FB8 +30D8 +6098 +C098 +C190 +81B0 +81B0 +8130 +8120 +C360 +6360 +3E60 +0060 +0040 +00C0 +ENDCHAR +STARTCHAR uni01A3 +ENCODING 419 +SWIDTH 667 0 +DWIDTH 11 0 +BBX 10 12 1 -3 +BITMAP +3FC0 +6240 +46C0 +C6C0 +8480 +8480 +8580 +CD80 +7980 +0100 +0100 +0300 +ENDCHAR +STARTCHAR uni01A4 +ENCODING 420 +SWIDTH 730 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +7FE0 +D830 +9030 +1030 +3030 +3060 +3FC0 +2000 +2000 +6000 +6000 +6000 +ENDCHAR +STARTCHAR uni01A5 +ENCODING 421 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 15 0 -3 +BITMAP +1E00 +1000 +1000 +3700 +3980 +3180 +2080 +2080 +6180 +6100 +6300 +5E00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni01A6 +ENCODING 422 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 15 1 -3 +BITMAP +3000 +3F80 +2040 +2060 +6060 +6040 +60C0 +7F00 +C400 +C600 +C200 +8300 +0100 +0180 +0080 +ENDCHAR +STARTCHAR uni01A7 +ENCODING 423 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +0F80 +30C0 +20C0 +60C0 +0180 +0E00 +3800 +6000 +C0C0 +C180 +C300 +7E00 +ENDCHAR +STARTCHAR uni01A8 +ENCODING 424 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +3E +62 +42 +0C +38 +C0 +82 +84 +78 +ENDCHAR +STARTCHAR uni01A9 +ENCODING 425 +SWIDTH 599 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +3FC0 +3000 +3000 +1800 +0C00 +0400 +0E00 +1C00 +3800 +7000 +C000 +FF00 +ENDCHAR +STARTCHAR uni01AA +ENCODING 426 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 15 2 -3 +BITMAP +E0 +B0 +B0 +F0 +20 +20 +60 +60 +40 +40 +C0 +C0 +80 +80 +E0 +ENDCHAR +STARTCHAR uni01AB +ENCODING 427 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 15 0 -3 +BITMAP +08 +10 +10 +78 +30 +20 +20 +20 +60 +60 +60 +70 +30 +20 +E0 +ENDCHAR +STARTCHAR uni01AC +ENCODING 428 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 11 12 1 0 +BITMAP +7FE0 +C600 +C400 +0400 +0C00 +0C00 +0C00 +0800 +0800 +1800 +1800 +1800 +ENDCHAR +STARTCHAR uni01AD +ENCODING 429 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 12 1 0 +BITMAP +3C +20 +20 +F0 +60 +40 +40 +40 +C0 +C0 +C0 +E0 +ENDCHAR +STARTCHAR uni01AE +ENCODING 430 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 15 2 -3 +BITMAP +FFC0 +0C00 +0800 +0800 +1800 +1800 +1800 +1000 +1000 +3000 +3000 +3000 +2000 +6000 +3800 +ENDCHAR +STARTCHAR Uhorn +ENCODING 431 +SWIDTH 793 0 +DWIDTH 13 0 +BBX 14 12 2 0 +BITMAP +606C +6048 +4048 +40F0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uhorn +ENCODING 432 +SWIDTH 633 0 +DWIDTH 11 0 +BBX 11 9 1 0 +BITMAP +6160 +6120 +4320 +43C0 +C200 +C200 +C600 +CA00 +7600 +ENDCHAR +STARTCHAR uni01B1 +ENCODING 433 +SWIDTH 760 0 +DWIDTH 13 0 +BBX 12 12 2 0 +BITMAP +F9F0 +30C0 +6040 +C060 +8060 +8060 +8060 +8040 +80C0 +C080 +6300 +3E00 +ENDCHAR +STARTCHAR uni01B2 +ENCODING 434 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 10 12 2 0 +BITMAP +61C0 +6040 +4040 +40C0 +C0C0 +C0C0 +C080 +8180 +8180 +8300 +C600 +7C00 +ENDCHAR +STARTCHAR uni01B3 +ENCODING 435 +SWIDTH 717 0 +DWIDTH 12 0 +BBX 12 12 2 0 +BITMAP +C070 +C0D0 +6180 +2300 +3200 +1600 +1C00 +1800 +1800 +1800 +1000 +1000 +ENDCHAR +STARTCHAR uni01B4 +ENCODING 436 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 13 15 0 -3 +BITMAP +0038 +0048 +00C0 +2080 +2180 +2100 +3300 +3200 +3400 +1C00 +1800 +1800 +1000 +3000 +E000 +ENDCHAR +STARTCHAR uni01B5 +ENCODING 437 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +7FC0 +0180 +0180 +0300 +0600 +0C00 +FF80 +1800 +3000 +6000 +C000 +FF80 +ENDCHAR +STARTCHAR uni01B6 +ENCODING 438 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +3F80 +0300 +0600 +0C00 +7F00 +1000 +3000 +6000 +FF00 +ENDCHAR +STARTCHAR uni01B7 +ENCODING 439 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 12 15 -1 -3 +BITMAP +1FF0 +0060 +00C0 +0180 +0300 +0380 +00C0 +0060 +0060 +0060 +0040 +C0C0 +40C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni01B8 +ENCODING 440 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 11 15 0 -3 +BITMAP +1FE0 +1800 +0C00 +0C00 +0600 +1E00 +3800 +6000 +6000 +4000 +C000 +C0C0 +40C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni01B9 +ENCODING 441 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3F80 +3000 +1000 +1800 +0800 +1C00 +6000 +4000 +C100 +C300 +C600 +7800 +ENDCHAR +STARTCHAR uni01BA +ENCODING 442 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 0 -3 +BITMAP +3F +03 +06 +0C +1E +02 +06 +1C +70 +C2 +C6 +78 +ENDCHAR +STARTCHAR uni01BB +ENCODING 443 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +1E00 +3300 +6100 +6180 +0100 +0300 +7F00 +0C00 +3800 +6000 +4000 +FE00 +ENDCHAR +STARTCHAR uni01BC +ENCODING 444 +SWIDTH 510 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +7F +30 +30 +30 +3C +06 +03 +03 +83 +82 +C6 +78 +ENDCHAR +STARTCHAR uni01BD +ENCODING 445 +SWIDTH 437 0 +DWIDTH 7 0 +BBX 8 9 0 0 +BITMAP +7F +30 +30 +30 +3C +06 +C2 +46 +3C +ENDCHAR +STARTCHAR uni01BE +ENCODING 446 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +10 +20 +20 +F0 +60 +60 +70 +1C +06 +82 +C6 +7C +ENDCHAR +STARTCHAR uni01BF +ENCODING 447 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3700 +3980 +3080 +2080 +6180 +6180 +6300 +4600 +5C00 +E000 +C000 +8000 +ENDCHAR +STARTCHAR uni01C0 +ENCODING 448 +SWIDTH 259 0 +DWIDTH 4 0 +BBX 1 12 2 0 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni01C1 +ENCODING 449 +SWIDTH 413 0 +DWIDTH 7 0 +BBX 3 12 2 0 +BITMAP +A0 +A0 +A0 +A0 +A0 +A0 +A0 +A0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR uni01C2 +ENCODING 450 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +18 +18 +18 +18 +FF +18 +18 +FF +18 +18 +18 +18 +ENDCHAR +STARTCHAR uni01C3 +ENCODING 451 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 12 1 0 +BITMAP +30 +30 +30 +20 +20 +60 +60 +40 +40 +00 +00 +C0 +ENDCHAR +STARTCHAR uni01C4 +ENCODING 452 +SWIDTH 1333 0 +DWIDTH 23 0 +BBX 22 16 1 0 +BITMAP +0000D8 +000070 +000060 +000000 +3F87FC +30C018 +206030 +206030 +606060 +6060C0 +606180 +406300 +C04300 +C0C600 +C18C00 +FE1FF8 +ENDCHAR +STARTCHAR uni01C5 +ENCODING 453 +SWIDTH 1222 0 +DWIDTH 21 0 +BBX 20 13 1 0 +BITMAP +0001B0 +3F80E0 +30C0C0 +206000 +2067F0 +606060 +6060C0 +606180 +406100 +C04300 +C0C600 +C18C00 +FE1FE0 +ENDCHAR +STARTCHAR uni01C6 +ENCODING 454 +SWIDTH 1056 0 +DWIDTH 18 0 +BBX 17 13 1 0 +BITMAP +000D80 +008700 +018600 +018000 +3D3F80 +650300 +430600 +C30C00 +830800 +821800 +C63000 +C66000 +7EFF00 +ENDCHAR +STARTCHAR uni01C7 +ENCODING 455 +SWIDTH 1056 0 +DWIDTH 18 0 +BBX 17 12 1 0 +BITMAP +300180 +300180 +200180 +600100 +600100 +600300 +600300 +400200 +C00200 +C04600 +C04600 +FF7C00 +ENDCHAR +STARTCHAR uni01C8 +ENCODING 456 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 15 1 -3 +BITMAP +3010 +3000 +2000 +6030 +6030 +6020 +6020 +4060 +C060 +C040 +C040 +FF40 +00C0 +00C0 +0380 +ENDCHAR +STARTCHAR uni01C9 +ENCODING 457 +SWIDTH 444 0 +DWIDTH 8 0 +BBX 7 15 1 -3 +BITMAP +22 +20 +60 +66 +66 +44 +44 +CC +CC +88 +88 +88 +18 +18 +70 +ENDCHAR +STARTCHAR uni01CA +ENCODING 458 +SWIDTH 1222 0 +DWIDTH 21 0 +BBX 20 12 1 0 +BITMAP +303030 +383030 +282030 +282020 +646020 +646060 +664060 +424040 +424040 +C1C8C0 +C1C8C0 +C08F80 +ENDCHAR +STARTCHAR uni01CB +ENCODING 459 +SWIDTH 944 0 +DWIDTH 16 0 +BBX 15 15 1 -3 +BITMAP +3032 +3830 +2820 +2826 +6466 +6464 +6644 +424C +424C +C1C8 +C1C8 +C088 +0018 +0018 +0070 +ENDCHAR +STARTCHAR uni01CC +ENCODING 460 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 15 1 -3 +BITMAP +0010 +0000 +0000 +6E30 +7330 +6320 +4320 +C360 +C260 +C240 +8640 +8640 +00C0 +00C0 +0380 +ENDCHAR +STARTCHAR uni01CD +ENCODING 461 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 0 0 +BITMAP +0360 +01C0 +0180 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni01CE +ENCODING 462 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +1B +0E +0C +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni01CF +ENCODING 463 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 16 1 0 +BITMAP +6C +38 +30 +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni01D0 +ENCODING 464 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 13 1 0 +BITMAP +D8 +70 +60 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni01D1 +ENCODING 465 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0D80 +0700 +0600 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni01D2 +ENCODING 466 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +1B +0E +0C +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni01D3 +ENCODING 467 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 2 0 +BITMAP +0D80 +0700 +0600 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni01D4 +ENCODING 468 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +1B +0E +0C +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uni01D5 +ENCODING 469 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 2 0 +BITMAP +0780 +0000 +0480 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni01D6 +ENCODING 470 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +1F +00 +00 +1B +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uni01D7 +ENCODING 471 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 2 0 +BITMAP +0180 +0300 +0480 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni01D8 +ENCODING 472 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 0 +BITMAP +03 +02 +04 +00 +1B +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uni01D9 +ENCODING 473 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 2 0 +BITMAP +0780 +0300 +0480 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni01DA +ENCODING 474 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 15 1 0 +BITMAP +0D80 +0700 +0600 +0000 +1B00 +0000 +6100 +6100 +4300 +4300 +C300 +C200 +C600 +CA00 +7600 +ENDCHAR +STARTCHAR uni01DB +ENCODING 475 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 2 0 +BITMAP +0600 +0200 +0480 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni01DC +ENCODING 476 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 0 +BITMAP +08 +0C +04 +00 +1B +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uni01DD +ENCODING 477 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1E +63 +43 +01 +FF +83 +C2 +46 +38 +ENDCHAR +STARTCHAR uni01DE +ENCODING 478 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 0 0 +BITMAP +03C0 +0000 +0240 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni01DF +ENCODING 479 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +1F +00 +00 +1B +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni01E0 +ENCODING 480 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 0 0 +BITMAP +03C0 +0000 +0180 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni01E1 +ENCODING 481 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +1F +00 +00 +0C +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni01E2 +ENCODING 482 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 18 14 0 0 +BITMAP +003E00 +000000 +03FFC0 +026000 +066000 +046000 +0C4000 +187F80 +10C000 +3FC000 +60C000 +408000 +C18000 +81FF00 +ENDCHAR +STARTCHAR uni01E3 +ENCODING 483 +SWIDTH 889 0 +DWIDTH 15 0 +BBX 14 11 1 0 +BITMAP +07C0 +0000 +3EF0 +6388 +430C +030C +7FFC +C600 +8618 +CF10 +71E0 +ENDCHAR +STARTCHAR uni01E4 +ENCODING 484 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +0F80 +30C0 +6060 +4060 +C000 +8000 +87C0 +8040 +80C0 +C7E0 +61C0 +3F00 +ENDCHAR +STARTCHAR uni01E5 +ENCODING 485 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +1E80 +3180 +6180 +6180 +4180 +6100 +6300 +3F00 +0300 +FF00 +0200 +7C00 +ENDCHAR +STARTCHAR Gcaron +ENCODING 486 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0D80 +0700 +0600 +0000 +0F80 +30C0 +6060 +4060 +C000 +8000 +87C0 +8040 +80C0 +C0C0 +61C0 +3F00 +ENDCHAR +STARTCHAR gcaron +ENCODING 487 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +1B00 +0E00 +0C00 +0000 +1E80 +3180 +2180 +6180 +4180 +4100 +4100 +6300 +3F00 +0300 +C600 +7C00 +ENDCHAR +STARTCHAR uni01E8 +ENCODING 488 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 1 0 +BITMAP +0D80 +0700 +0600 +0000 +3060 +30C0 +2380 +2700 +6E00 +7C00 +7600 +6200 +C300 +C180 +C180 +80C0 +ENDCHAR +STARTCHAR uni01E9 +ENCODING 489 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +1B +0E +0C +00 +30 +20 +20 +63 +66 +4C +58 +68 +CC +CC +84 +86 +ENDCHAR +STARTCHAR uni01EA +ENCODING 490 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 -4 +BITMAP +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +0400 +0800 +0800 +0C00 +ENDCHAR +STARTCHAR uni01EB +ENCODING 491 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 -4 +BITMAP +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +10 +20 +20 +30 +ENDCHAR +STARTCHAR uni01EC +ENCODING 492 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 18 2 -4 +BITMAP +0F80 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +0400 +0800 +0800 +0C00 +ENDCHAR +STARTCHAR uni01ED +ENCODING 493 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -4 +BITMAP +1F +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +10 +20 +20 +30 +ENDCHAR +STARTCHAR uni01EE +ENCODING 494 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 12 19 -1 -3 +BITMAP +06C0 +0380 +0300 +0000 +1FF0 +0060 +00C0 +0180 +0300 +0380 +00C0 +0060 +0060 +0060 +0040 +C0C0 +40C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni01EF +ENCODING 495 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 10 16 -1 -3 +BITMAP +06C0 +0380 +0300 +0000 +1FC0 +0180 +0300 +0200 +0600 +0E00 +0300 +0100 +0100 +C100 +4200 +3C00 +ENDCHAR +STARTCHAR uni01F0 +ENCODING 496 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 8 16 -2 -3 +BITMAP +1B +0E +0C +00 +0C +0C +08 +08 +18 +18 +10 +10 +10 +30 +20 +E0 +ENDCHAR +STARTCHAR uni01F1 +ENCODING 497 +SWIDTH 1333 0 +DWIDTH 23 0 +BBX 22 12 1 0 +BITMAP +3F87FC +30C018 +206030 +206030 +606060 +6060C0 +606180 +406300 +C04300 +C0C600 +C18C00 +FE1FF8 +ENDCHAR +STARTCHAR uni01F2 +ENCODING 498 +SWIDTH 1222 0 +DWIDTH 21 0 +BBX 20 12 1 0 +BITMAP +3F8000 +30C000 +206000 +2067F0 +606060 +6060C0 +606180 +406100 +C04300 +C0C600 +C18C00 +FE1FE0 +ENDCHAR +STARTCHAR uni01F3 +ENCODING 499 +SWIDTH 1056 0 +DWIDTH 18 0 +BBX 17 12 1 0 +BITMAP +008000 +018000 +018000 +3D3F80 +650300 +430600 +C30C00 +830800 +821800 +C63000 +C66000 +7EFF00 +ENDCHAR +STARTCHAR uni01F4 +ENCODING 500 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0180 +0100 +0200 +0000 +0F80 +30C0 +6060 +4060 +C000 +8000 +87C0 +8040 +80C0 +C0C0 +61C0 +3F00 +ENDCHAR +STARTCHAR uni01F5 +ENCODING 501 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0300 +0200 +0400 +0000 +1E80 +3180 +2180 +6180 +4180 +4100 +4100 +6300 +3F00 +0300 +C600 +7C00 +ENDCHAR +STARTCHAR uni01F6 +ENCODING 502 +SWIDTH 1034 0 +DWIDTH 18 0 +BBX 17 12 1 0 +BITMAP +303000 +302000 +202000 +206180 +606100 +7FE100 +404300 +404300 +C0C200 +C0C200 +C04600 +803C00 +ENDCHAR +STARTCHAR uni01F7 +ENCODING 503 +SWIDTH 617 0 +DWIDTH 11 0 +BBX 11 15 0 -3 +BITMAP +1B80 +1CC0 +1860 +1060 +3060 +3040 +30C0 +20C0 +6180 +6300 +6600 +5800 +6000 +C000 +C000 +ENDCHAR +STARTCHAR uni01F8 +ENCODING 504 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 16 1 0 +BITMAP +0200 +0300 +0100 +0000 +3030 +3830 +2820 +2820 +6460 +6460 +6640 +4240 +4240 +C1C0 +C1C0 +C080 +ENDCHAR +STARTCHAR uni01F9 +ENCODING 505 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +08 +0C +04 +00 +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR Aringacute +ENCODING 506 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 17 0 0 +BITMAP +00C0 +0080 +0180 +0240 +0240 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR aringacute +ENCODING 507 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 18 1 0 +BITMAP +03 +02 +04 +00 +0C +12 +12 +0C +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR AEacute +ENCODING 508 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 18 16 0 0 +BITMAP +003000 +002000 +004000 +000000 +03FFC0 +026000 +066000 +046000 +0C4000 +187F80 +10C000 +3FC000 +60C000 +408000 +C18000 +81FF00 +ENDCHAR +STARTCHAR aeacute +ENCODING 509 +SWIDTH 889 0 +DWIDTH 15 0 +BBX 14 13 1 0 +BITMAP +00C0 +0080 +0100 +0000 +3EF0 +6388 +430C +030C +7FFC +C600 +8618 +CF10 +71E0 +ENDCHAR +STARTCHAR Oslashacute +ENCODING 510 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 17 2 -1 +BITMAP +0180 +0100 +0200 +0020 +1FE0 +30C0 +60E0 +C160 +C260 +8420 +8C60 +9860 +9040 +E0C0 +6180 +BE00 +8000 +ENDCHAR +STARTCHAR oslashacute +ENCODING 511 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +0300 +0200 +0400 +0080 +1F00 +3300 +6380 +4580 +C980 +D100 +F300 +6600 +7C00 +ENDCHAR +STARTCHAR uni0200 +ENCODING 512 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 15 0 0 +BITMAP +0D80 +0680 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni0201 +ENCODING 513 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +6C +34 +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni0202 +ENCODING 514 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 15 0 0 +BITMAP +03C0 +0240 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni0203 +ENCODING 515 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1E +12 +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni0204 +ENCODING 516 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 15 1 0 +BITMAP +1B00 +0D00 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR uni0205 +ENCODING 517 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +6C +34 +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR uni0206 +ENCODING 518 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 15 1 0 +BITMAP +0780 +0480 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR uni0207 +ENCODING 519 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1E +12 +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR uni0208 +ENCODING 520 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 15 1 0 +BITMAP +D8 +68 +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni0209 +ENCODING 521 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 12 0 0 +BITMAP +D8 +68 +00 +10 +10 +30 +30 +20 +20 +20 +60 +60 +ENDCHAR +STARTCHAR uni020A +ENCODING 522 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 15 1 0 +BITMAP +3C +24 +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni020B +ENCODING 523 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 12 1 0 +BITMAP +78 +48 +00 +20 +20 +60 +60 +40 +40 +40 +C0 +C0 +ENDCHAR +STARTCHAR uni020C +ENCODING 524 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 15 2 0 +BITMAP +1B00 +0D00 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni020D +ENCODING 525 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +6C +34 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni020E +ENCODING 526 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 15 2 0 +BITMAP +0F00 +0900 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni020F +ENCODING 527 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1E +12 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni0210 +ENCODING 528 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 15 1 0 +BITMAP +1B00 +0D00 +0000 +3FC0 +3060 +2020 +2020 +6020 +6060 +7F80 +4300 +4180 +C080 +C0C0 +C0C0 +ENDCHAR +STARTCHAR uni0211 +ENCODING 529 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 12 1 0 +BITMAP +D8 +68 +00 +6C +70 +60 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni0212 +ENCODING 530 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 15 1 0 +BITMAP +0780 +0480 +0000 +3FC0 +3060 +2020 +2020 +6020 +6060 +7F80 +4300 +4180 +C080 +C0C0 +C0C0 +ENDCHAR +STARTCHAR uni0213 +ENCODING 531 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 12 1 0 +BITMAP +3C +24 +00 +6C +70 +60 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni0214 +ENCODING 532 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 15 2 0 +BITMAP +1B00 +0D00 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni0215 +ENCODING 533 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +36 +1A +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uni0216 +ENCODING 534 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 15 2 0 +BITMAP +0F00 +0900 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni0217 +ENCODING 535 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1E +12 +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uni0218 +ENCODING 536 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 17 1 -5 +BITMAP +1F80 +30C0 +2040 +2000 +3000 +1E00 +0780 +0180 +C0C0 +C080 +6180 +3E00 +0000 +0C00 +0400 +0800 +1000 +ENDCHAR +STARTCHAR uni0219 +ENCODING 537 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 14 1 -5 +BITMAP +3C +66 +42 +60 +3C +0E +86 +C6 +7C +00 +30 +10 +20 +40 +ENDCHAR +STARTCHAR uni021A +ENCODING 538 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 16 2 -4 +BITMAP +FFC0 +0C00 +0800 +0800 +1800 +1800 +1800 +1000 +1000 +3000 +3000 +3000 +0000 +6000 +2000 +4000 +ENDCHAR +STARTCHAR uni021B +ENCODING 539 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 16 1 -4 +BITMAP +10 +20 +20 +F0 +60 +40 +40 +40 +C0 +C0 +C0 +E0 +00 +C0 +40 +80 +ENDCHAR +STARTCHAR uni021C +ENCODING 540 +SWIDTH 544 0 +DWIDTH 9 0 +BBX 10 15 0 -3 +BITMAP +0F80 +1880 +20C0 +0080 +0180 +0100 +0700 +1900 +6100 +0300 +0200 +0600 +0800 +7000 +8000 +ENDCHAR +STARTCHAR uni021D +ENCODING 541 +SWIDTH 436 0 +DWIDTH 7 0 +BBX 8 12 0 -3 +BITMAP +3E +63 +03 +02 +06 +3E +46 +04 +04 +18 +70 +80 +ENDCHAR +STARTCHAR uni021E +ENCODING 542 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 16 1 0 +BITMAP +06C0 +0380 +0300 +0000 +3030 +3020 +2020 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C0C0 +8080 +ENDCHAR +STARTCHAR uni021F +ENCODING 543 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +1B +0E +0C +00 +30 +20 +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR uni0220 +ENCODING 544 +SWIDTH 668 0 +DWIDTH 11 0 +BBX 11 15 1 -3 +BITMAP +37C0 +3860 +2060 +2060 +6060 +6040 +6040 +40C0 +C0C0 +C0C0 +C080 +8180 +0180 +0180 +0100 +ENDCHAR +STARTCHAR uni0221 +ENCODING 545 +SWIDTH 627 0 +DWIDTH 11 0 +BBX 10 15 1 -3 +BITMAP +0080 +0180 +0180 +3D00 +6300 +4300 +C300 +8300 +8200 +C600 +C600 +7F80 +04C0 +1CC0 +1780 +ENDCHAR +STARTCHAR uni0222 +ENCODING 546 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +0380 +1D80 +20C0 +6080 +2100 +1E00 +6100 +C180 +C180 +C100 +C600 +7C00 +ENDCHAR +STARTCHAR uni0223 +ENCODING 547 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +0900 +3180 +2080 +2180 +3100 +1E00 +6100 +C180 +C180 +C100 +C600 +7C00 +ENDCHAR +STARTCHAR uni0224 +ENCODING 548 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 14 1 -2 +BITMAP +7FC0 +0180 +0300 +0300 +0600 +0C00 +1800 +3000 +3000 +6000 +C000 +FF80 +0080 +0080 +ENDCHAR +STARTCHAR uni0225 +ENCODING 549 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 11 0 -2 +BITMAP +3F80 +0300 +0600 +0C00 +0800 +1800 +3000 +6000 +FF00 +0100 +0100 +ENDCHAR +STARTCHAR uni0226 +ENCODING 550 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +0300 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni0227 +ENCODING 551 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +0C +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni0228 +ENCODING 552 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 15 1 -3 +BITMAP +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +0C00 +0400 +3C00 +ENDCHAR +STARTCHAR uni0229 +ENCODING 553 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +18 +08 +78 +ENDCHAR +STARTCHAR uni022A +ENCODING 554 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0780 +0000 +0480 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni022B +ENCODING 555 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +1F +00 +00 +1B +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni022C +ENCODING 556 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0780 +0680 +0900 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni022D +ENCODING 557 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +1F +00 +1D +17 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni022E +ENCODING 558 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 14 2 0 +BITMAP +0600 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni022F +ENCODING 559 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +0C +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni0230 +ENCODING 560 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0F00 +0000 +0600 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni0231 +ENCODING 561 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +1F +00 +00 +0C +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni0232 +ENCODING 562 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 14 2 0 +BITMAP +1F00 +0000 +C060 +60C0 +6180 +3300 +3300 +1600 +1C00 +0800 +0800 +1800 +1800 +1000 +ENDCHAR +STARTCHAR uni0233 +ENCODING 563 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 14 0 -3 +BITMAP +0F80 +0000 +2080 +2180 +2100 +3300 +3600 +3400 +1C00 +1800 +1800 +1000 +2000 +E000 +ENDCHAR +STARTCHAR uni0234 +ENCODING 564 +SWIDTH 293 0 +DWIDTH 5 0 +BBX 7 15 -2 -3 +BITMAP +04 +04 +0C +0C +0C +08 +08 +18 +18 +10 +10 +1E +32 +76 +9C +ENDCHAR +STARTCHAR uni0235 +ENCODING 565 +SWIDTH 628 0 +DWIDTH 11 0 +BBX 10 12 1 -3 +BITMAP +6E00 +5300 +6300 +4300 +C300 +C200 +C200 +8600 +8780 +04C0 +1CC0 +1780 +ENDCHAR +STARTCHAR uni0236 +ENCODING 566 +SWIDTH 347 0 +DWIDTH 6 0 +BBX 7 12 -1 0 +BITMAP +04 +08 +08 +3C +18 +10 +10 +10 +3E +32 +76 +9C +ENDCHAR +STARTCHAR uni0237 +ENCODING 567 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 12 -2 -3 +BITMAP +0C +0C +08 +08 +18 +18 +10 +10 +10 +30 +20 +E0 +ENDCHAR +STARTCHAR uni0238 +ENCODING 568 +SWIDTH 883 0 +DWIDTH 15 0 +BBX 14 12 1 0 +BITMAP +0080 +0180 +0180 +3D70 +6388 +430C +C30C +820C +8208 +C618 +C710 +7EE0 +ENDCHAR +STARTCHAR uni0239 +ENCODING 569 +SWIDTH 880 0 +DWIDTH 15 0 +BBX 14 12 1 -3 +BITMAP +3D70 +6398 +430C +C30C +820C +8208 +C618 +C710 +7EE0 +0400 +0400 +0C00 +ENDCHAR +STARTCHAR uni023A +ENCODING 570 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 13 14 0 -1 +BITMAP +0018 +0390 +03A0 +07C0 +04C0 +0D80 +1980 +12C0 +3FC0 +28C0 +7040 +7040 +E040 +4000 +ENDCHAR +STARTCHAR uni023B +ENCODING 571 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 14 1 -1 +BITMAP +0010 +0FA0 +1860 +30E0 +60A0 +6100 +4200 +4600 +4C00 +4860 +70C0 +3180 +5F00 +8000 +ENDCHAR +STARTCHAR uni023C +ENCODING 572 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 11 15 -1 -3 +BITMAP +0020 +0040 +0040 +0780 +1980 +13C0 +3200 +3400 +2C00 +3980 +3100 +3E00 +2000 +4000 +C000 +ENDCHAR +STARTCHAR uni023D +ENCODING 573 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +30 +30 +20 +20 +60 +60 +FC +40 +C0 +C0 +C0 +FF +ENDCHAR +STARTCHAR uni023E +ENCODING 574 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 12 14 0 -1 +BITMAP +0030 +3FF0 +0340 +0280 +0300 +0700 +0600 +0600 +0C00 +1400 +3C00 +6C00 +4C00 +8000 +ENDCHAR +STARTCHAR uni023F +ENCODING 575 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 12 1 -3 +BITMAP +3C +62 +42 +70 +1C +06 +06 +C6 +7C +60 +24 +1C +ENDCHAR +STARTCHAR uni0240 +ENCODING 576 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3F80 +0300 +0600 +0C00 +0800 +1800 +3000 +6000 +F000 +1800 +0900 +0700 +ENDCHAR +STARTCHAR uni0241 +ENCODING 577 +SWIDTH 580 0 +DWIDTH 10 0 +BBX 8 12 2 0 +BITMAP +3E +C3 +81 +01 +01 +03 +02 +06 +38 +20 +60 +60 +ENDCHAR +STARTCHAR uni0242 +ENCODING 578 +SWIDTH 453 0 +DWIDTH 8 0 +BBX 7 9 1 0 +BITMAP +3C +46 +C6 +06 +0C +38 +20 +20 +20 +ENDCHAR +STARTCHAR uni0243 +ENCODING 579 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 0 0 +BITMAP +1FC0 +1860 +1020 +1020 +3060 +30C0 +3F80 +2060 +FC60 +6060 +60C0 +7F80 +ENDCHAR +STARTCHAR uni0244 +ENCODING 580 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +3030 +3020 +2020 +2060 +6060 +FFF0 +6040 +4040 +40C0 +4080 +6180 +1E00 +ENDCHAR +STARTCHAR uni0245 +ENCODING 581 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 0 0 +BITMAP +0300 +0380 +0780 +0580 +0C80 +1880 +18C0 +30C0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni0246 +ENCODING 582 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 14 1 -1 +BITMAP +0020 +3FE0 +3080 +2180 +2100 +6200 +7FC0 +4C00 +4800 +5000 +D000 +E000 +FF80 +C000 +ENDCHAR +STARTCHAR uni0247 +ENCODING 583 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 11 15 -1 -3 +BITMAP +0020 +0040 +0040 +0780 +19C0 +11C0 +3240 +3FC0 +2400 +3880 +3180 +3E00 +2000 +4000 +C000 +ENDCHAR +STARTCHAR uni0248 +ENCODING 584 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +03 +03 +03 +02 +02 +06 +0F +06 +84 +8C +88 +70 +ENDCHAR +STARTCHAR uni0249 +ENCODING 585 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 15 -2 -3 +BITMAP +04 +00 +00 +0C +0C +08 +08 +1C +18 +18 +10 +10 +30 +20 +E0 +ENDCHAR +STARTCHAR uni024A +ENCODING 586 +SWIDTH 754 0 +DWIDTH 13 0 +BBX 11 15 2 -3 +BITMAP +0FE0 +1860 +2060 +4060 +C040 +C040 +80C0 +80C0 +8080 +C080 +E180 +3F80 +0180 +0180 +01C0 +ENDCHAR +STARTCHAR uni024B +ENCODING 587 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +3D +63 +43 +C3 +82 +82 +C6 +C6 +7E +04 +04 +07 +ENDCHAR +STARTCHAR uni024C +ENCODING 588 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 12 0 0 +BITMAP +1FE0 +1830 +1010 +1010 +3030 +3030 +FFC0 +2180 +20C0 +6040 +6060 +6060 +ENDCHAR +STARTCHAR uni024D +ENCODING 589 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 9 1 0 +BITMAP +6C +50 +60 +40 +E0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni024E +ENCODING 590 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 12 12 1 0 +BITMAP +6030 +2060 +FFF0 +1980 +1980 +0F00 +0E00 +0400 +0C00 +0C00 +0C00 +0800 +ENDCHAR +STARTCHAR uni024F +ENCODING 591 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +2080 +2180 +2100 +7F80 +3600 +3400 +1C00 +1800 +1800 +1000 +2000 +C000 +ENDCHAR +STARTCHAR uni0250 +ENCODING 592 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +4E +71 +61 +43 +FE +C0 +C2 +C6 +7C +ENDCHAR +STARTCHAR uni0251 +ENCODING 593 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +3D +63 +43 +C3 +83 +82 +C6 +C6 +7E +ENDCHAR +STARTCHAR uni0252 +ENCODING 594 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +6E +73 +61 +41 +C1 +C3 +C2 +C6 +BC +ENDCHAR +STARTCHAR uni0253 +ENCODING 595 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +3C +20 +20 +6E +73 +61 +41 +41 +C3 +C2 +C6 +BC +ENDCHAR +STARTCHAR uni0254 +ENCODING 596 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +3C +66 +C2 +02 +02 +06 +86 +8C +78 +ENDCHAR +STARTCHAR uni0255 +ENCODING 597 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 10 0 -1 +BITMAP +1E00 +3100 +2180 +6000 +6000 +4F00 +7100 +6300 +7E00 +8000 +ENDCHAR +STARTCHAR uni0256 +ENCODING 598 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 15 1 -3 +BITMAP +0080 +0180 +0180 +3D00 +6300 +4300 +C300 +8300 +8200 +C600 +C600 +7E00 +0400 +0400 +0700 +ENDCHAR +STARTCHAR uni0257 +ENCODING 599 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 11 12 1 0 +BITMAP +00E0 +0180 +0180 +3D00 +6700 +4300 +C300 +8300 +8200 +C200 +C600 +7E00 +ENDCHAR +STARTCHAR uni0258 +ENCODING 600 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1E +63 +43 +C1 +FF +03 +C2 +C6 +78 +ENDCHAR +STARTCHAR uni0259 +ENCODING 601 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1E +63 +43 +01 +FF +83 +C2 +46 +38 +ENDCHAR +STARTCHAR uni025A +ENCODING 602 +SWIDTH 704 0 +DWIDTH 12 0 +BBX 12 9 1 0 +BITMAP +1E00 +6300 +4180 +3F80 +F1F0 +8300 +C200 +4600 +3800 +ENDCHAR +STARTCHAR uni025B +ENCODING 603 +SWIDTH 439 0 +DWIDTH 7 0 +BBX 6 9 1 0 +BITMAP +3C +64 +40 +60 +70 +C0 +80 +88 +78 +ENDCHAR +STARTCHAR uni025C +ENCODING 604 +SWIDTH 464 0 +DWIDTH 8 0 +BBX 8 9 0 0 +BITMAP +1E +23 +03 +02 +1C +06 +C2 +46 +3C +ENDCHAR +STARTCHAR uni025D +ENCODING 605 +SWIDTH 615 0 +DWIDTH 10 0 +BBX 11 9 0 0 +BITMAP +1E00 +2380 +0380 +02E0 +1C00 +0600 +C200 +4600 +3C00 +ENDCHAR +STARTCHAR uni025E +ENCODING 606 +SWIDTH 508 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +3E +62 +42 +C2 +9C +86 +86 +C6 +7C +ENDCHAR +STARTCHAR uni025F +ENCODING 607 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 12 -2 -3 +BITMAP +04 +04 +0C +0C +0C +08 +08 +18 +3C +18 +10 +F0 +ENDCHAR +STARTCHAR uni0260 +ENCODING 608 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 12 15 0 -3 +BITMAP +0070 +0040 +00C0 +1EC0 +3180 +2180 +6180 +4180 +4100 +4100 +6300 +3F00 +0200 +C600 +7C00 +ENDCHAR +STARTCHAR uni0261 +ENCODING 609 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +1E80 +3180 +2180 +6180 +4180 +4100 +4100 +6300 +3F00 +0300 +C600 +7C00 +ENDCHAR +STARTCHAR uni0262 +ENCODING 610 +SWIDTH 550 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1E +61 +40 +C0 +8F +83 +C3 +C2 +3C +ENDCHAR +STARTCHAR uni0263 +ENCODING 611 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +41 +43 +66 +64 +6C +38 +30 +30 +70 +50 +D0 +60 +ENDCHAR +STARTCHAR uni0264 +ENCODING 612 +SWIDTH 616 0 +DWIDTH 10 0 +BBX 10 9 1 0 +BITMAP +7380 +9A40 +1C00 +1C00 +0800 +1800 +3C00 +2C00 +3800 +ENDCHAR +STARTCHAR uni0265 +ENCODING 613 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +61 +61 +43 +43 +C3 +C2 +C6 +CE +76 +04 +04 +04 +ENDCHAR +STARTCHAR uni0266 +ENCODING 614 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +3C +20 +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR uni0267 +ENCODING 615 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +3C +20 +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +86 +04 +04 +18 +ENDCHAR +STARTCHAR uni0268 +ENCODING 616 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 4 12 0 0 +BITMAP +10 +00 +00 +30 +30 +20 +20 +F0 +60 +60 +40 +40 +ENDCHAR +STARTCHAR uni0269 +ENCODING 617 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 2 9 1 0 +BITMAP +40 +40 +40 +C0 +C0 +80 +80 +80 +C0 +ENDCHAR +STARTCHAR uni026A +ENCODING 618 +SWIDTH 355 0 +DWIDTH 6 0 +BBX 7 9 0 0 +BITMAP +3E +18 +10 +10 +10 +30 +30 +30 +F8 +ENDCHAR +STARTCHAR uni026B +ENCODING 619 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 12 0 0 +BITMAP +10 +10 +30 +30 +30 +E8 +B8 +60 +60 +40 +40 +40 +ENDCHAR +STARTCHAR uni026C +ENCODING 620 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 4 12 0 0 +BITMAP +10 +10 +30 +70 +B0 +A0 +F0 +60 +60 +40 +40 +40 +ENDCHAR +STARTCHAR uni026D +ENCODING 621 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 4 15 0 -3 +BITMAP +10 +10 +30 +30 +30 +20 +20 +60 +60 +40 +40 +C0 +C0 +C0 +E0 +ENDCHAR +STARTCHAR uni026E +ENCODING 622 +SWIDTH 563 0 +DWIDTH 10 0 +BBX 9 15 1 -3 +BITMAP +2000 +2000 +6000 +7F80 +4300 +4200 +4600 +CC00 +DC00 +8600 +8200 +8200 +0200 +8600 +7800 +ENDCHAR +STARTCHAR uni026F +ENCODING 623 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +6308 +4318 +4218 +4210 +C210 +C630 +8630 +8E70 +F3A0 +ENDCHAR +STARTCHAR uni0270 +ENCODING 624 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 12 1 -3 +BITMAP +6308 +4318 +4218 +4210 +C210 +C630 +8630 +8E70 +F3A0 +0020 +0060 +0060 +ENDCHAR +STARTCHAR uni0271 +ENCODING 625 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 12 1 -3 +BITMAP +6E70 +7398 +6318 +4218 +C210 +C610 +C630 +8630 +8420 +0020 +0060 +01C0 +ENDCHAR +STARTCHAR uni0272 +ENCODING 626 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 11 12 -2 -3 +BITMAP +0DC0 +0A60 +0C60 +0860 +1860 +1840 +1840 +10C0 +10C0 +3000 +3000 +E000 +ENDCHAR +STARTCHAR uni0273 +ENCODING 627 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +6E +53 +63 +43 +C3 +C2 +C2 +86 +86 +04 +04 +07 +ENDCHAR +STARTCHAR uni0274 +ENCODING 628 +SWIDTH 582 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +6180 +7180 +5100 +5900 +D900 +CB00 +CF00 +8600 +8600 +ENDCHAR +STARTCHAR uni0275 +ENCODING 629 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +3E +63 +43 +C1 +FF +83 +82 +C6 +78 +ENDCHAR +STARTCHAR uni0276 +ENCODING 630 +SWIDTH 765 0 +DWIDTH 13 0 +BBX 12 9 1 0 +BITMAP +3DF0 +6300 +4300 +C300 +83F0 +8200 +8200 +C600 +7FE0 +ENDCHAR +STARTCHAR uni0277 +ENCODING 631 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 9 1 0 +BITMAP +0FC0 +3060 +6230 +C630 +C630 +8630 +8E20 +CA60 +73C0 +ENDCHAR +STARTCHAR uni0278 +ENCODING 632 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +04 +04 +0C +3E +6B +49 +D9 +99 +9B +93 +D6 +7C +30 +20 +20 +ENDCHAR +STARTCHAR uni0279 +ENCODING 633 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 7 9 -1 0 +BITMAP +06 +06 +04 +04 +04 +0C +0C +18 +E8 +ENDCHAR +STARTCHAR uni027A +ENCODING 634 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 7 12 -1 0 +BITMAP +02 +02 +02 +06 +06 +04 +04 +04 +0C +0C +18 +E8 +ENDCHAR +STARTCHAR uni027B +ENCODING 635 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 7 12 -1 -3 +BITMAP +06 +06 +04 +04 +04 +0C +0C +18 +E8 +08 +18 +0C +ENDCHAR +STARTCHAR uni027C +ENCODING 636 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 7 12 0 -3 +BITMAP +36 +28 +30 +20 +60 +60 +40 +40 +40 +C0 +C0 +80 +ENDCHAR +STARTCHAR uni027D +ENCODING 637 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 7 12 0 -3 +BITMAP +36 +28 +30 +20 +60 +60 +60 +40 +40 +C0 +C0 +E0 +ENDCHAR +STARTCHAR uni027E +ENCODING 638 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 9 1 0 +BITMAP +1C +20 +40 +40 +40 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni027F +ENCODING 639 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 12 1 -3 +BITMAP +E0 +30 +10 +30 +30 +30 +20 +20 +60 +60 +60 +40 +ENDCHAR +STARTCHAR uni0280 +ENCODING 640 +SWIDTH 534 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +7F +61 +41 +43 +FC +CC +C4 +86 +86 +ENDCHAR +STARTCHAR uni0281 +ENCODING 641 +SWIDTH 534 0 +DWIDTH 9 0 +BBX 9 9 1 0 +BITMAP +6180 +6300 +4200 +4400 +7C00 +C200 +C200 +8600 +FC00 +ENDCHAR +STARTCHAR uni0282 +ENCODING 642 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 0 -3 +BITMAP +1E +31 +21 +18 +0C +02 +43 +E3 +FE +80 +80 +E0 +ENDCHAR +STARTCHAR uni0283 +ENCODING 643 +SWIDTH 290 0 +DWIDTH 5 0 +BBX 9 15 -2 -3 +BITMAP +0380 +0600 +0400 +0400 +0400 +0C00 +0C00 +0800 +0800 +1800 +1800 +1000 +1000 +3000 +E000 +ENDCHAR +STARTCHAR uni0284 +ENCODING 644 +SWIDTH 305 0 +DWIDTH 5 0 +BBX 9 15 -2 -3 +BITMAP +0380 +0600 +0600 +0400 +0400 +0400 +0C00 +0C00 +0800 +0800 +1800 +3C00 +1800 +1000 +F000 +ENDCHAR +STARTCHAR uni0285 +ENCODING 645 +SWIDTH 289 0 +DWIDTH 5 0 +BBX 3 12 1 -3 +BITMAP +E0 +20 +60 +60 +60 +40 +40 +C0 +C0 +80 +80 +E0 +ENDCHAR +STARTCHAR uni0286 +ENCODING 646 +SWIDTH 347 0 +DWIDTH 6 0 +BBX 10 15 -2 -3 +BITMAP +01C0 +0300 +0200 +0200 +0600 +0600 +0400 +0400 +0400 +0C00 +0C00 +7800 +CC00 +D400 +7400 +ENDCHAR +STARTCHAR uni0287 +ENCODING 647 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 12 0 0 +BITMAP +38 +18 +18 +10 +10 +10 +30 +30 +F8 +20 +60 +40 +ENDCHAR +STARTCHAR uni0288 +ENCODING 648 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 15 0 -3 +BITMAP +08 +10 +10 +78 +30 +20 +20 +20 +60 +60 +40 +40 +40 +C0 +60 +ENDCHAR +STARTCHAR uni0289 +ENCODING 649 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +61 +61 +43 +43 +FF +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uni028A +ENCODING 650 +SWIDTH 562 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +6180 +2200 +6300 +C100 +C100 +8100 +8300 +C600 +7800 +ENDCHAR +STARTCHAR uni028B +ENCODING 651 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +67 +63 +43 +43 +C3 +C2 +C6 +CC +78 +ENDCHAR +STARTCHAR uni028C +ENCODING 652 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 0 0 +BITMAP +0C +0E +1E +16 +32 +22 +62 +C3 +C3 +ENDCHAR +STARTCHAR uni028D +ENCODING 653 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 9 0 0 +BITMAP +0C60 +1CE0 +1CA0 +3DA0 +2520 +6520 +4620 +C620 +8620 +ENDCHAR +STARTCHAR uni028E +ENCODING 654 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +03 +02 +06 +04 +0C +1E +16 +32 +22 +62 +42 +C3 +ENDCHAR +STARTCHAR uni028F +ENCODING 655 +SWIDTH 514 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +C1 +63 +66 +3C +38 +18 +10 +10 +30 +ENDCHAR +STARTCHAR uni0290 +ENCODING 656 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3F80 +0300 +0600 +0C00 +0800 +1800 +3000 +6000 +FF00 +0200 +0200 +0300 +ENDCHAR +STARTCHAR uni0291 +ENCODING 657 +SWIDTH 547 0 +DWIDTH 9 0 +BBX 9 10 0 -1 +BITMAP +3F80 +0300 +0600 +0C00 +0800 +1800 +3380 +6C80 +FF80 +3000 +ENDCHAR +STARTCHAR uni0292 +ENCODING 658 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 10 12 -1 -3 +BITMAP +1FC0 +0180 +0300 +0200 +0600 +0E00 +0300 +0100 +0100 +C100 +4200 +3C00 +ENDCHAR +STARTCHAR uni0293 +ENCODING 659 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3F80 +0300 +0600 +0400 +0C00 +1C00 +0600 +0200 +7A00 +8E00 +8E00 +FA00 +ENDCHAR +STARTCHAR uni0294 +ENCODING 660 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 12 2 0 +BITMAP +3C +C4 +86 +06 +06 +06 +04 +0C +30 +60 +60 +40 +ENDCHAR +STARTCHAR uni0295 +ENCODING 661 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 12 2 0 +BITMAP +3C +66 +C2 +C0 +80 +80 +80 +C0 +70 +20 +20 +60 +ENDCHAR +STARTCHAR uni0296 +ENCODING 662 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +04 +04 +0C +0E +03 +01 +01 +01 +03 +C2 +46 +3C +ENDCHAR +STARTCHAR uni0297 +ENCODING 663 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +1E00 +3100 +2180 +6000 +6000 +4000 +4000 +C000 +C000 +C200 +4600 +3C00 +ENDCHAR +STARTCHAR uni0298 +ENCODING 664 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +1F00 +30C0 +6060 +C060 +C060 +8020 +8C60 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni0299 +ENCODING 665 +SWIDTH 511 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +7C +62 +42 +46 +FC +C6 +C6 +86 +FC +ENDCHAR +STARTCHAR uni029A +ENCODING 666 +SWIDTH 508 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +3C +46 +C2 +C2 +72 +C2 +86 +8C +78 +ENDCHAR +STARTCHAR uni029B +ENCODING 667 +SWIDTH 550 0 +DWIDTH 9 0 +BBX 11 10 1 0 +BITMAP +00E0 +1F80 +6180 +4000 +C000 +8F00 +8300 +C300 +C200 +3C00 +ENDCHAR +STARTCHAR uni029C +ENCODING 668 +SWIDTH 550 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +61 +61 +43 +43 +FF +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR uni029D +ENCODING 669 +SWIDTH 292 0 +DWIDTH 5 0 +BBX 8 15 -2 -3 +BITMAP +03 +00 +00 +06 +06 +06 +04 +04 +0C +0C +08 +7C +C8 +D8 +70 +ENDCHAR +STARTCHAR uni029E +ENCODING 670 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 0 -3 +BITMAP +61 +21 +33 +13 +17 +1E +12 +66 +C6 +04 +04 +04 +ENDCHAR +STARTCHAR uni029F +ENCODING 671 +SWIDTH 447 0 +DWIDTH 8 0 +BBX 6 9 1 0 +BITMAP +60 +60 +40 +40 +C0 +C0 +C0 +80 +FC +ENDCHAR +STARTCHAR uni02A0 +ENCODING 672 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 11 15 1 -3 +BITMAP +00E0 +0180 +0180 +3D00 +6700 +4300 +C300 +8200 +8200 +C600 +C600 +7E00 +0400 +0400 +0C00 +ENDCHAR +STARTCHAR uni02A1 +ENCODING 673 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1E +62 +43 +03 +03 +03 +02 +06 +18 +30 +FC +20 +ENDCHAR +STARTCHAR uni02A2 +ENCODING 674 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1E +33 +61 +60 +40 +40 +40 +60 +38 +10 +FE +30 +ENDCHAR +STARTCHAR uni02A3 +ENCODING 675 +SWIDTH 927 0 +DWIDTH 16 0 +BBX 15 12 1 0 +BITMAP +0080 +0180 +0180 +3DFE +630C +4318 +C310 +8330 +8260 +C6C0 +C780 +7FFC +ENDCHAR +STARTCHAR uni02A4 +ENCODING 676 +SWIDTH 905 0 +DWIDTH 15 0 +BBX 15 15 1 -3 +BITMAP +0080 +0180 +0180 +3DFE +630C +4318 +C330 +8330 +8270 +C618 +C608 +7E08 +0018 +0610 +03E0 +ENDCHAR +STARTCHAR uni02A5 +ENCODING 677 +SWIDTH 972 0 +DWIDTH 17 0 +BBX 15 13 1 -1 +BITMAP +0080 +0180 +0180 +3DFE +630C +4318 +C310 +8330 +8260 +C6CE +C792 +7FFE +0040 +ENDCHAR +STARTCHAR uni02A6 +ENCODING 678 +SWIDTH 670 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +1000 +2000 +2000 +FF80 +6CC0 +4840 +4E00 +4780 +C1C0 +C0C0 +C0C0 +FF80 +ENDCHAR +STARTCHAR uni02A7 +ENCODING 679 +SWIDTH 460 0 +DWIDTH 8 0 +BBX 9 15 1 -3 +BITMAP +1380 +2600 +2400 +FC00 +6C00 +4C00 +4800 +4800 +C800 +D800 +D800 +F000 +1000 +3000 +E000 +ENDCHAR +STARTCHAR uni02A8 +ENCODING 680 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +1000 +2000 +2000 +F3C0 +6660 +4C20 +4800 +4800 +C9C0 +CE60 +CC40 +F780 +ENDCHAR +STARTCHAR uni02A9 +ENCODING 681 +SWIDTH 750 0 +DWIDTH 13 0 +BBX 11 15 1 -3 +BITMAP +1C00 +3000 +2000 +FDE0 +6E20 +6C20 +4C20 +4860 +C860 +D840 +D840 +9840 +00C0 +0080 +0380 +ENDCHAR +STARTCHAR uni02AA +ENCODING 682 +SWIDTH 641 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +2000 +2000 +6000 +6F80 +68C0 +58C0 +4C00 +C700 +C180 +8080 +E180 +BF00 +ENDCHAR +STARTCHAR uni02AB +ENCODING 683 +SWIDTH 593 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +2000 +2000 +6000 +7F80 +4100 +4300 +4600 +CC00 +D800 +F000 +B000 +FF00 +ENDCHAR +STARTCHAR uni02AC +ENCODING 684 +SWIDTH 485 0 +DWIDTH 8 0 +BBX 9 12 1 0 +BITMAP +4C80 +4D00 +5500 +5600 +6600 +6400 +0000 +9200 +B200 +B400 +CC00 +8800 +ENDCHAR +STARTCHAR uni02AD +ENCODING 685 +SWIDTH 527 0 +DWIDTH 9 0 +BBX 10 12 0 0 +BITMAP +1FC0 +30C0 +30C0 +2080 +0000 +0000 +0000 +0000 +7F00 +4300 +C300 +C300 +ENDCHAR +STARTCHAR uni02AE +ENCODING 686 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 1 -3 +BITMAP +E040 +3040 +10C0 +30C0 +3080 +3080 +2180 +3380 +1D80 +0100 +0100 +0300 +ENDCHAR +STARTCHAR uni02AF +ENCODING 687 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 -3 +BITMAP +E040 +3040 +10C0 +30C0 +3080 +3080 +2180 +3380 +1D80 +0100 +0180 +00E0 +ENDCHAR +STARTCHAR uni02B0 +ENCODING 688 +SWIDTH 308 0 +DWIDTH 5 0 +BBX 5 8 1 4 +BITMAP +40 +40 +78 +C8 +88 +88 +88 +90 +ENDCHAR +STARTCHAR uni02B1 +ENCODING 689 +SWIDTH 308 0 +DWIDTH 5 0 +BBX 5 8 1 4 +BITMAP +70 +40 +78 +C8 +88 +88 +88 +90 +ENDCHAR +STARTCHAR uni02B2 +ENCODING 690 +SWIDTH 122 0 +DWIDTH 2 0 +BBX 5 10 -1 2 +BITMAP +08 +00 +10 +10 +10 +20 +20 +20 +20 +C0 +ENDCHAR +STARTCHAR uni02B3 +ENCODING 691 +SWIDTH 219 0 +DWIDTH 4 0 +BBX 4 6 1 4 +BITMAP +70 +C0 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni02B4 +ENCODING 692 +SWIDTH 219 0 +DWIDTH 4 0 +BBX 5 6 0 4 +BITMAP +08 +10 +10 +10 +30 +D0 +ENDCHAR +STARTCHAR uni02B5 +ENCODING 693 +SWIDTH 219 0 +DWIDTH 4 0 +BBX 5 8 0 2 +BITMAP +08 +10 +10 +10 +30 +D0 +20 +30 +ENDCHAR +STARTCHAR uni02B6 +ENCODING 694 +SWIDTH 326 0 +DWIDTH 6 0 +BBX 5 6 1 4 +BITMAP +48 +90 +F0 +88 +88 +F0 +ENDCHAR +STARTCHAR uni02B7 +ENCODING 695 +SWIDTH 509 0 +DWIDTH 9 0 +BBX 8 6 2 4 +BITMAP +91 +B2 +B2 +AC +CC +C8 +ENDCHAR +STARTCHAR uni02B8 +ENCODING 696 +SWIDTH 348 0 +DWIDTH 6 0 +BBX 6 8 1 2 +BITMAP +44 +48 +48 +50 +60 +20 +40 +C0 +ENDCHAR +STARTCHAR uni02B9 +ENCODING 697 +SWIDTH 190 0 +DWIDTH 3 0 +BBX 2 4 2 8 +BITMAP +40 +C0 +C0 +80 +ENDCHAR +STARTCHAR uni02BA +ENCODING 698 +SWIDTH 354 0 +DWIDTH 6 0 +BBX 5 4 2 8 +BITMAP +48 +D8 +D8 +90 +ENDCHAR +STARTCHAR uni02BB +ENCODING 699 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 4 2 8 +BITMAP +20 +40 +80 +C0 +ENDCHAR +STARTCHAR uni02BC +ENCODING 700 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 4 2 8 +BITMAP +60 +40 +40 +80 +ENDCHAR +STARTCHAR uni02BD +ENCODING 701 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 2 4 3 8 +BITMAP +C0 +80 +80 +80 +ENDCHAR +STARTCHAR uni02BE +ENCODING 702 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 1 4 4 8 +BITMAP +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni02BF +ENCODING 703 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 1 4 4 8 +BITMAP +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni02C0 +ENCODING 704 +SWIDTH 355 0 +DWIDTH 6 0 +BBX 5 8 2 4 +BITMAP +70 +88 +08 +18 +10 +60 +40 +40 +ENDCHAR +STARTCHAR uni02C1 +ENCODING 705 +SWIDTH 355 0 +DWIDTH 6 0 +BBX 5 8 2 4 +BITMAP +70 +C8 +80 +80 +80 +C0 +40 +40 +ENDCHAR +STARTCHAR uni02C2 +ENCODING 706 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 8 9 2 2 +BITMAP +01 +06 +18 +60 +80 +60 +18 +06 +01 +ENDCHAR +STARTCHAR uni02C3 +ENCODING 707 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 8 9 2 2 +BITMAP +80 +E0 +38 +0E +03 +0E +38 +E0 +80 +ENDCHAR +STARTCHAR uni02C4 +ENCODING 708 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 7 8 2 2 +BITMAP +10 +38 +28 +6C +44 +46 +C2 +82 +ENDCHAR +STARTCHAR uni02C5 +ENCODING 709 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 7 8 2 2 +BITMAP +82 +C2 +46 +44 +6C +28 +38 +10 +ENDCHAR +STARTCHAR circumflex +ENCODING 710 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 3 2 9 +BITMAP +30 +50 +D0 +ENDCHAR +STARTCHAR caron +ENCODING 711 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 3 2 9 +BITMAP +D8 +70 +60 +ENDCHAR +STARTCHAR uni02C8 +ENCODING 712 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 1 3 4 9 +BITMAP +80 +80 +80 +ENDCHAR +STARTCHAR uni02C9 +ENCODING 713 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 1 2 10 +BITMAP +F8 +ENDCHAR +STARTCHAR uni02CA +ENCODING 714 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 3 3 9 +BITMAP +60 +40 +80 +ENDCHAR +STARTCHAR uni02CB +ENCODING 715 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 3 3 9 +BITMAP +80 +C0 +40 +ENDCHAR +STARTCHAR uni02CC +ENCODING 716 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 1 3 2 -4 +BITMAP +80 +80 +80 +ENDCHAR +STARTCHAR uni02CD +ENCODING 717 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 1 -1 -2 +BITMAP +F8 +ENDCHAR +STARTCHAR uni02CE +ENCODING 718 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 2 1 -3 +BITMAP +C0 +40 +ENDCHAR +STARTCHAR uni02CF +ENCODING 719 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 2 0 -3 +BITMAP +60 +C0 +ENDCHAR +STARTCHAR uni02D0 +ENCODING 720 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 3 9 1 0 +BITMAP +20 +20 +00 +00 +00 +00 +00 +80 +C0 +ENDCHAR +STARTCHAR uni02D1 +ENCODING 721 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 1 2 3 7 +BITMAP +80 +80 +ENDCHAR +STARTCHAR uni02D2 +ENCODING 722 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 4 2 0 +BITMAP +80 +40 +40 +80 +ENDCHAR +STARTCHAR uni02D3 +ENCODING 723 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 4 2 0 +BITMAP +40 +80 +80 +40 +ENDCHAR +STARTCHAR uni02D4 +ENCODING 724 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 3 1 1 +BITMAP +40 +40 +E0 +ENDCHAR +STARTCHAR uni02D5 +ENCODING 725 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 3 1 1 +BITMAP +E0 +40 +40 +ENDCHAR +STARTCHAR uni02D6 +ENCODING 726 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 3 1 1 +BITMAP +40 +E0 +40 +ENDCHAR +STARTCHAR uni02D7 +ENCODING 727 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 1 0 2 +BITMAP +F8 +ENDCHAR +STARTCHAR breve +ENCODING 728 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 2 2 10 +BITMAP +98 +70 +ENDCHAR +STARTCHAR dotaccent +ENCODING 729 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 1 3 10 +BITMAP +C0 +ENDCHAR +STARTCHAR ring +ENCODING 730 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 4 3 8 +BITMAP +C0 +A0 +A0 +C0 +ENDCHAR +STARTCHAR ogonek +ENCODING 731 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 4 1 -4 +BITMAP +40 +80 +80 +C0 +ENDCHAR +STARTCHAR tilde +ENCODING 732 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 2 2 10 +BITMAP +E8 +B8 +ENDCHAR +STARTCHAR hungarumlaut +ENCODING 733 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 3 2 9 +BITMAP +68 +D8 +90 +ENDCHAR +STARTCHAR uni02DE +ENCODING 734 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 3 0 3 +BITMAP +C0 +C0 +70 +ENDCHAR +STARTCHAR uni02DF +ENCODING 735 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 6 2 6 +BITMAP +88 +D0 +60 +60 +D0 +88 +ENDCHAR +STARTCHAR uni02E0 +ENCODING 736 +SWIDTH 364 0 +DWIDTH 6 0 +BBX 5 8 2 2 +BITMAP +88 +90 +B0 +60 +40 +40 +C0 +C0 +ENDCHAR +STARTCHAR uni02E1 +ENCODING 737 +SWIDTH 92 0 +DWIDTH 2 0 +BBX 2 8 1 4 +BITMAP +40 +40 +40 +C0 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni02E2 +ENCODING 738 +SWIDTH 324 0 +DWIDTH 6 0 +BBX 5 6 1 4 +BITMAP +78 +48 +60 +10 +88 +F0 +ENDCHAR +STARTCHAR uni02E3 +ENCODING 739 +SWIDTH 336 0 +DWIDTH 6 0 +BBX 5 6 1 4 +BITMAP +48 +70 +30 +20 +50 +90 +ENDCHAR +STARTCHAR uni02E4 +ENCODING 740 +SWIDTH 355 0 +DWIDTH 6 0 +BBX 5 8 2 4 +BITMAP +70 +C8 +80 +80 +80 +C0 +40 +40 +ENDCHAR +STARTCHAR uni02E5 +ENCODING 741 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 4 12 1 0 +BITMAP +F0 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR uni02E6 +ENCODING 742 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 4 12 1 0 +BITMAP +10 +10 +10 +F0 +10 +10 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR uni02E7 +ENCODING 743 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 4 12 1 0 +BITMAP +10 +10 +10 +10 +10 +10 +F0 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR uni02E8 +ENCODING 744 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 4 12 1 0 +BITMAP +10 +10 +10 +10 +10 +10 +10 +10 +F0 +10 +10 +10 +ENDCHAR +STARTCHAR uni02E9 +ENCODING 745 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 4 12 1 0 +BITMAP +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +F0 +ENDCHAR +STARTCHAR uni02EA +ENCODING 746 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 7 1 0 +BITMAP +80 +80 +80 +80 +80 +80 +F0 +ENDCHAR +STARTCHAR uni02EB +ENCODING 747 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 7 1 0 +BITMAP +80 +80 +80 +F0 +80 +80 +80 +ENDCHAR +STARTCHAR uni02EC +ENCODING 748 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 2 0 -3 +BITMAP +B0 +E0 +ENDCHAR +STARTCHAR uni02ED +ENCODING 749 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 3 2 9 +BITMAP +F8 +00 +F8 +ENDCHAR +STARTCHAR uni02EE +ENCODING 750 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 4 2 8 +BITMAP +D8 +48 +50 +90 +ENDCHAR +STARTCHAR uni02EF +ENCODING 751 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 2 1 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR uni02F0 +ENCODING 752 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 2 1 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR uni02F1 +ENCODING 753 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 3 1 -3 +BITMAP +40 +80 +40 +ENDCHAR +STARTCHAR uni02F2 +ENCODING 754 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 3 1 -3 +BITMAP +80 +40 +80 +ENDCHAR +STARTCHAR uni02F3 +ENCODING 755 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 4 0 -5 +BITMAP +60 +A0 +A0 +60 +ENDCHAR +STARTCHAR uni02F4 +ENCODING 756 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 2 2 2 +BITMAP +80 +40 +ENDCHAR +STARTCHAR uni02F5 +ENCODING 757 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 2 0 2 +BITMAP +D8 +68 +ENDCHAR +STARTCHAR uni02F6 +ENCODING 758 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 2 0 2 +BITMAP +48 +90 +ENDCHAR +STARTCHAR uni02F7 +ENCODING 759 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 2 -1 -4 +BITMAP +E8 +98 +ENDCHAR +STARTCHAR uni02F8 +ENCODING 760 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 3 7 2 5 +BITMAP +60 +00 +00 +00 +00 +00 +80 +ENDCHAR +STARTCHAR uni02F9 +ENCODING 761 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 3 3 9 +BITMAP +E0 +80 +80 +ENDCHAR +STARTCHAR uni02FA +ENCODING 762 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 3 3 9 +BITMAP +E0 +20 +20 +ENDCHAR +STARTCHAR uni02FB +ENCODING 763 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 3 0 -3 +BITMAP +80 +80 +E0 +ENDCHAR +STARTCHAR uni02FC +ENCODING 764 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 3 0 -3 +BITMAP +20 +20 +E0 +ENDCHAR +STARTCHAR uni02FD +ENCODING 765 +SWIDTH 397 0 +DWIDTH 7 0 +BBX 7 3 -1 -3 +BITMAP +C6 +C6 +FE +ENDCHAR +STARTCHAR uni02FE +ENCODING 766 +SWIDTH 397 0 +DWIDTH 7 0 +BBX 7 3 -1 -3 +BITMAP +C0 +C0 +FE +ENDCHAR +STARTCHAR uni02FF +ENCODING 767 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 5 0 -3 +BITMAP +40 +80 +F0 +80 +40 +ENDCHAR +STARTCHAR gravecomb +ENCODING 768 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -2 14 +BITMAP +C0 +40 +ENDCHAR +STARTCHAR acutecomb +ENCODING 769 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -1 14 +BITMAP +40 +80 +ENDCHAR +STARTCHAR uni0302 +ENCODING 770 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -1 10 +BITMAP +30 +D8 +ENDCHAR +STARTCHAR tildecomb +ENCODING 771 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -5 14 +BITMAP +C8 +B0 +ENDCHAR +STARTCHAR uni0304 +ENCODING 772 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 1 -1 10 +BITMAP +F8 +ENDCHAR +STARTCHAR uni0305 +ENCODING 773 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 10 1 -3 13 +BITMAP +FFC0 +ENDCHAR +STARTCHAR uni0306 +ENCODING 774 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -1 10 +BITMAP +C8 +70 +ENDCHAR +STARTCHAR uni0307 +ENCODING 775 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 1 10 +BITMAP +C0 +ENDCHAR +STARTCHAR uni0308 +ENCODING 776 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 1 -1 10 +BITMAP +D8 +ENDCHAR +STARTCHAR hookabovecomb +ENCODING 777 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -2 13 +BITMAP +E0 +20 +40 +ENDCHAR +STARTCHAR uni030A +ENCODING 778 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 0 8 +BITMAP +60 +A0 +A0 +60 +ENDCHAR +STARTCHAR uni030B +ENCODING 779 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 0 10 +BITMAP +D8 +B0 +ENDCHAR +STARTCHAR uni030C +ENCODING 780 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 2 0 10 +BITMAP +B0 +E0 +ENDCHAR +STARTCHAR uni030D +ENCODING 781 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 3 1 9 +BITMAP +80 +80 +80 +ENDCHAR +STARTCHAR uni030E +ENCODING 782 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 0 9 +BITMAP +A0 +A0 +A0 +ENDCHAR +STARTCHAR uni030F +ENCODING 783 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -2 10 +BITMAP +D8 +68 +ENDCHAR +STARTCHAR uni0310 +ENCODING 784 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 3 -1 10 +BITMAP +30 +C8 +70 +ENDCHAR +STARTCHAR uni0311 +ENCODING 785 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 2 0 10 +BITMAP +F0 +90 +ENDCHAR +STARTCHAR uni0312 +ENCODING 786 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 0 8 +BITMAP +20 +40 +80 +C0 +ENDCHAR +STARTCHAR uni0313 +ENCODING 787 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 0 8 +BITMAP +60 +40 +40 +80 +ENDCHAR +STARTCHAR uni0314 +ENCODING 788 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 4 1 8 +BITMAP +C0 +80 +80 +80 +ENDCHAR +STARTCHAR uni0315 +ENCODING 789 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 2 8 +BITMAP +60 +40 +40 +80 +ENDCHAR +STARTCHAR uni0316 +ENCODING 790 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -2 -3 +BITMAP +C0 +40 +ENDCHAR +STARTCHAR uni0317 +ENCODING 791 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -2 -3 +BITMAP +C0 +80 +ENDCHAR +STARTCHAR uni0318 +ENCODING 792 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -2 -4 +BITMAP +20 +E0 +20 +ENDCHAR +STARTCHAR uni0319 +ENCODING 793 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -2 -4 +BITMAP +80 +E0 +80 +ENDCHAR +STARTCHAR uni031A +ENCODING 794 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 4 -1 10 +BITMAP +FC +04 +04 +04 +ENDCHAR +STARTCHAR uni031B +ENCODING 795 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 -1 8 +BITMAP +20 +20 +20 +C0 +ENDCHAR +STARTCHAR uni031C +ENCODING 796 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 4 -2 -4 +BITMAP +40 +80 +80 +40 +ENDCHAR +STARTCHAR uni031D +ENCODING 797 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -2 -4 +BITMAP +40 +40 +E0 +ENDCHAR +STARTCHAR uni031E +ENCODING 798 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -2 -3 +BITMAP +E0 +40 +40 +ENDCHAR +STARTCHAR uni031F +ENCODING 799 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -2 -4 +BITMAP +40 +E0 +40 +ENDCHAR +STARTCHAR uni0320 +ENCODING 800 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 1 -4 -2 +BITMAP +FC +ENDCHAR +STARTCHAR uni0321 +ENCODING 801 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 4 -4 -3 +BITMAP +10 +30 +30 +E0 +ENDCHAR +STARTCHAR uni0322 +ENCODING 802 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 5 -2 -3 +BITMAP +40 +40 +C0 +C0 +E0 +ENDCHAR +STARTCHAR dotbelowcomb +ENCODING 803 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -8 -2 +BITMAP +C0 +ENDCHAR +STARTCHAR uni0324 +ENCODING 804 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 1 -3 -3 +BITMAP +90 +ENDCHAR +STARTCHAR uni0325 +ENCODING 805 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 -3 -5 +BITMAP +60 +A0 +A0 +60 +ENDCHAR +STARTCHAR uni0326 +ENCODING 806 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 3 -2 -3 +BITMAP +C0 +40 +80 +ENDCHAR +STARTCHAR uni0327 +ENCODING 807 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -3 -3 +BITMAP +40 +30 +E0 +ENDCHAR +STARTCHAR uni0328 +ENCODING 808 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 4 -2 -4 +BITMAP +40 +80 +80 +C0 +ENDCHAR +STARTCHAR uni0329 +ENCODING 809 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 3 -1 -4 +BITMAP +80 +80 +80 +ENDCHAR +STARTCHAR uni032A +ENCODING 810 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 3 -4 -4 +BITMAP +FC +84 +84 +ENDCHAR +STARTCHAR uni032B +ENCODING 811 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -4 -3 +BITMAP +94 +78 +ENDCHAR +STARTCHAR uni032C +ENCODING 812 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 2 -3 -3 +BITMAP +B0 +E0 +ENDCHAR +STARTCHAR uni032D +ENCODING 813 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 2 -3 -3 +BITMAP +60 +B0 +ENDCHAR +STARTCHAR uni032E +ENCODING 814 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 2 -3 -3 +BITMAP +90 +E0 +ENDCHAR +STARTCHAR uni032F +ENCODING 815 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 2 -3 -3 +BITMAP +70 +90 +ENDCHAR +STARTCHAR uni0330 +ENCODING 816 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -4 -4 +BITMAP +68 +98 +ENDCHAR +STARTCHAR uni0331 +ENCODING 817 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 1 -4 -2 +BITMAP +FC +ENDCHAR +STARTCHAR uni0332 +ENCODING 818 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 10 1 -6 -3 +BITMAP +FFC0 +ENDCHAR +STARTCHAR uni0333 +ENCODING 819 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 3 -3 -5 +BITMAP +F8 +00 +F8 +ENDCHAR +STARTCHAR uni0334 +ENCODING 820 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -3 2 +BITMAP +6C +98 +ENDCHAR +STARTCHAR uni0335 +ENCODING 821 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 1 -3 2 +BITMAP +F8 +ENDCHAR +STARTCHAR uni0336 +ENCODING 822 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 10 1 -5 2 +BITMAP +FFC0 +ENDCHAR +STARTCHAR uni0337 +ENCODING 823 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 8 8 -4 0 +BITMAP +01 +02 +04 +08 +10 +20 +40 +80 +ENDCHAR +STARTCHAR uni0338 +ENCODING 824 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 7 12 -3 0 +BITMAP +02 +06 +04 +08 +08 +10 +10 +20 +60 +40 +C0 +80 +ENDCHAR +STARTCHAR uni0339 +ENCODING 825 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 4 -2 -4 +BITMAP +80 +40 +40 +80 +ENDCHAR +STARTCHAR uni033A +ENCODING 826 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 3 -4 -3 +BITMAP +84 +84 +FC +ENDCHAR +STARTCHAR uni033B +ENCODING 827 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 -2 -4 +BITMAP +E0 +A0 +A0 +E0 +ENDCHAR +STARTCHAR uni033C +ENCODING 828 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 3 -4 -4 +BITMAP +78 +B4 +20 +ENDCHAR +STARTCHAR uni033D +ENCODING 829 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 0 8 +BITMAP +A0 +E0 +E0 +A0 +ENDCHAR +STARTCHAR uni033E +ENCODING 830 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 5 1 8 +BITMAP +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni033F +ENCODING 831 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 10 3 -3 11 +BITMAP +FFC0 +0000 +FFC0 +ENDCHAR +STARTCHAR uni0340 +ENCODING 832 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 1 10 +BITMAP +80 +C0 +ENDCHAR +STARTCHAR uni0341 +ENCODING 833 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 2 0 10 +BITMAP +60 +C0 +ENDCHAR +STARTCHAR uni0342 +ENCODING 834 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -1 10 +BITMAP +E8 +98 +ENDCHAR +STARTCHAR uni0343 +ENCODING 835 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 0 8 +BITMAP +60 +40 +40 +80 +ENDCHAR +STARTCHAR uni0344 +ENCODING 836 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 3 -2 9 +BITMAP +18 +10 +A4 +ENDCHAR +STARTCHAR uni0345 +ENCODING 837 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 2 -2 -3 +BITMAP +80 +80 +ENDCHAR +STARTCHAR uni0346 +ENCODING 838 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 3 -2 10 +BITMAP +FC +84 +84 +ENDCHAR +STARTCHAR uni0347 +ENCODING 839 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 8 3 -5 -6 +BITMAP +FF +00 +FF +ENDCHAR +STARTCHAR uni0348 +ENCODING 840 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 3 -2 -4 +BITMAP +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni0349 +ENCODING 841 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -2 -3 +BITMAP +E0 +20 +20 +ENDCHAR +STARTCHAR uni034A +ENCODING 842 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 4 -1 9 +BITMAP +10 +E8 +B8 +40 +ENDCHAR +STARTCHAR uni034B +ENCODING 843 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 4 -1 9 +BITMAP +30 +E8 +98 +60 +ENDCHAR +STARTCHAR uni034C +ENCODING 844 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 4 -1 10 +BITMAP +64 +98 +E8 +98 +ENDCHAR +STARTCHAR uni034D +ENCODING 845 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -3 -4 +BITMAP +10 +F0 +10 +ENDCHAR +STARTCHAR uni034E +ENCODING 846 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 3 -2 -3 +BITMAP +C0 +80 +80 +ENDCHAR +STARTCHAR uni034F +ENCODING 847 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 12 13 -6 0 +BITMAP +E670 +8010 +8D10 +1080 +2040 +8010 +A050 +8010 +2040 +1080 +8D10 +8010 +E670 +ENDCHAR +STARTCHAR uni0350 +ENCODING 848 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 0 10 +BITMAP +80 +60 +C0 +ENDCHAR +STARTCHAR uni0351 +ENCODING 849 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 4 1 8 +BITMAP +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni0352 +ENCODING 850 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 3 -1 10 +BITMAP +70 +88 +20 +ENDCHAR +STARTCHAR uni0353 +ENCODING 851 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 -2 -4 +BITMAP +A0 +C0 +C0 +A0 +ENDCHAR +STARTCHAR uni0354 +ENCODING 852 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 3 -2 -3 +BITMAP +40 +80 +40 +ENDCHAR +STARTCHAR uni0355 +ENCODING 853 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 3 -2 -3 +BITMAP +80 +40 +80 +ENDCHAR +STARTCHAR uni0356 +ENCODING 854 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 3 -4 -3 +BITMAP +80 +68 +D4 +ENDCHAR +STARTCHAR uni0357 +ENCODING 855 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 4 1 8 +BITMAP +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni0358 +ENCODING 856 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 2 10 +BITMAP +C0 +ENDCHAR +STARTCHAR uni0359 +ENCODING 857 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 -2 -4 +BITMAP +40 +A0 +40 +C0 +ENDCHAR +STARTCHAR uni035A +ENCODING 858 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 4 -4 -4 +BITMAP +78 +94 +94 +78 +ENDCHAR +STARTCHAR uni035B +ENCODING 859 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 5 0 9 +BITMAP +40 +80 +E0 +20 +20 +ENDCHAR +STARTCHAR uni035C +ENCODING 860 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 12 3 -1 -3 +BITMAP +8010 +4060 +3F80 +ENDCHAR +STARTCHAR uni035D +ENCODING 861 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 13 3 -1 10 +BITMAP +8018 +6020 +1FC0 +ENDCHAR +STARTCHAR uni035E +ENCODING 862 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 9 1 -1 11 +BITMAP +FF80 +ENDCHAR +STARTCHAR uni035F +ENCODING 863 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 10 1 -3 -2 +BITMAP +FFC0 +ENDCHAR +STARTCHAR uni0360 +ENCODING 864 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 13 2 -1 10 +BITMAP +7C18 +83E0 +ENDCHAR +STARTCHAR uni0361 +ENCODING 865 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 12 3 -1 10 +BITMAP +1FC0 +6020 +8010 +ENDCHAR +STARTCHAR uni0362 +ENCODING 866 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 9 1 -1 -3 +BITMAP +FF80 +ENDCHAR +STARTCHAR uni0363 +ENCODING 867 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 6 -2 4 +BITMAP +78 +08 +78 +88 +98 +E8 +ENDCHAR +STARTCHAR uni0364 +ENCODING 868 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 6 -2 4 +BITMAP +78 +88 +F8 +80 +88 +70 +ENDCHAR +STARTCHAR uni0365 +ENCODING 869 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 8 0 4 +BITMAP +40 +00 +40 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni0366 +ENCODING 870 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 6 -2 4 +BITMAP +78 +C8 +88 +88 +88 +70 +ENDCHAR +STARTCHAR uni0367 +ENCODING 871 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 6 -2 4 +BITMAP +44 +48 +88 +88 +98 +E8 +ENDCHAR +STARTCHAR uni0368 +ENCODING 872 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 6 -2 4 +BITMAP +38 +48 +80 +80 +88 +70 +ENDCHAR +STARTCHAR uni0369 +ENCODING 873 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 8 -2 4 +BITMAP +04 +04 +74 +4C +88 +88 +88 +78 +ENDCHAR +STARTCHAR uni036A +ENCODING 874 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 8 -2 4 +BITMAP +40 +40 +78 +48 +88 +88 +88 +98 +ENDCHAR +STARTCHAR uni036B +ENCODING 875 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 9 6 -4 4 +BITMAP +5B80 +6C80 +4880 +4880 +8900 +8900 +ENDCHAR +STARTCHAR uni036C +ENCODING 876 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 6 -2 4 +BITMAP +58 +60 +40 +40 +40 +80 +ENDCHAR +STARTCHAR uni036D +ENCODING 877 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 8 0 4 +BITMAP +40 +40 +E0 +80 +80 +80 +80 +C0 +ENDCHAR +STARTCHAR uni036E +ENCODING 878 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 6 -1 4 +BITMAP +88 +90 +90 +A0 +C0 +C0 +ENDCHAR +STARTCHAR uni036F +ENCODING 879 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 6 -2 4 +BITMAP +48 +50 +30 +20 +50 +90 +ENDCHAR +STARTCHAR uni0370 +ENCODING 880 +SWIDTH 601 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +3000 +3000 +2000 +2000 +6000 +7F80 +4000 +4000 +C000 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni0371 +ENCODING 881 +SWIDTH 468 0 +DWIDTH 8 0 +BBX 7 9 1 0 +BITMAP +E0 +60 +60 +60 +7E +40 +40 +C0 +C0 +ENDCHAR +STARTCHAR uni0372 +ENCODING 882 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 11 12 1 0 +BITMAP +7FE0 +6660 +4440 +4440 +CCC0 +0C00 +0C00 +0800 +0800 +1800 +1800 +1800 +ENDCHAR +STARTCHAR uni0373 +ENCODING 883 +SWIDTH 458 0 +DWIDTH 8 0 +BBX 7 12 2 0 +BITMAP +FE +B6 +B6 +20 +20 +20 +60 +60 +40 +40 +40 +C0 +ENDCHAR +STARTCHAR uni0374 +ENCODING 884 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 3 3 9 +BITMAP +60 +40 +80 +ENDCHAR +STARTCHAR uni0375 +ENCODING 885 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 2 0 -3 +BITMAP +40 +C0 +ENDCHAR +STARTCHAR uni0376 +ENCODING 886 +SWIDTH 715 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +3030 +30E0 +20E0 +2160 +6260 +6460 +6440 +48C0 +D0C0 +E0C0 +C080 +C080 +ENDCHAR +STARTCHAR uni0377 +ENCODING 887 +SWIDTH 601 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +6180 +6380 +4780 +4D00 +D900 +D300 +E300 +C300 +8380 +ENDCHAR +STARTCHAR uni037A +ENCODING 890 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 1 2 1 -3 +BITMAP +80 +80 +ENDCHAR +STARTCHAR uni037B +ENCODING 891 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +3C +66 +C2 +02 +02 +06 +86 +8C +78 +ENDCHAR +STARTCHAR uni037C +ENCODING 892 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1C +62 +43 +C0 +D8 +80 +C6 +C4 +78 +ENDCHAR +STARTCHAR uni037D +ENCODING 893 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +3C +66 +C2 +02 +32 +06 +86 +8C +78 +ENDCHAR +STARTCHAR semicolon.dup3 +ENCODING 894 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 12 0 -3 +BITMAP +10 +00 +00 +00 +00 +00 +00 +00 +60 +20 +40 +80 +ENDCHAR +STARTCHAR uni037F +ENCODING 895 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +03 +03 +03 +02 +02 +06 +06 +04 +04 +8C +8C +F8 +ENDCHAR +STARTCHAR tonos +ENCODING 900 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 3 3 9 +BITMAP +60 +40 +C0 +ENDCHAR +STARTCHAR dieresistonos +ENCODING 901 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 3 1 9 +BITMAP +18 +10 +A4 +ENDCHAR +STARTCHAR Alphatonos +ENCODING 902 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 0 0 +BITMAP +1B80 +3380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR anoteleia +ENCODING 903 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 1 1 3 8 +BITMAP +80 +ENDCHAR +STARTCHAR Epsilontonos +ENCODING 904 +SWIDTH 788 0 +DWIDTH 13 0 +BBX 13 12 1 0 +BITMAP +6FF8 +CC00 +0800 +0800 +1800 +1FF0 +1800 +1000 +1000 +3000 +3000 +3FE0 +ENDCHAR +STARTCHAR Etatonos +ENCODING 905 +SWIDTH 846 0 +DWIDTH 14 0 +BBX 14 12 1 0 +BITMAP +6C0C +CC0C +0808 +0808 +1818 +1FF8 +1818 +1010 +1030 +3030 +3030 +3030 +ENDCHAR +STARTCHAR Iotatonos +ENCODING 906 +SWIDTH 388 0 +DWIDTH 7 0 +BBX 6 12 1 0 +BITMAP +6C +CC +08 +08 +18 +18 +18 +10 +10 +30 +30 +30 +ENDCHAR +STARTCHAR Omicrontonos +ENCODING 908 +SWIDTH 793 0 +DWIDTH 14 0 +BBX 12 12 1 0 +BITMAP +67C0 +D860 +3030 +6010 +6010 +4010 +4010 +4030 +6030 +6060 +30C0 +1F00 +ENDCHAR +STARTCHAR Upsilontonos +ENCODING 910 +SWIDTH 865 0 +DWIDTH 15 0 +BBX 15 12 1 0 +BITMAP +6406 +C60C +0218 +0318 +01B0 +01E0 +00C0 +00C0 +0080 +0080 +0180 +0180 +ENDCHAR +STARTCHAR Omegatonos +ENCODING 911 +SWIDTH 774 0 +DWIDTH 13 0 +BBX 13 12 0 0 +BITMAP +33C0 +6C30 +1810 +1018 +3018 +3018 +2018 +2018 +3010 +3030 +1860 +F8F8 +ENDCHAR +STARTCHAR iotadieresistonos +ENCODING 912 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 13 0 0 +BITMAP +18 +10 +A4 +00 +30 +30 +20 +20 +60 +60 +60 +40 +40 +ENDCHAR +STARTCHAR Alpha +ENCODING 913 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 0 0 +BITMAP +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR Beta +ENCODING 914 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +3F80 +30C0 +2040 +20C0 +6080 +7F00 +4080 +40C0 +C0C0 +C0C0 +C180 +FF00 +ENDCHAR +STARTCHAR Gamma +ENCODING 915 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +3FC0 +2000 +2000 +2000 +6000 +6000 +4000 +4000 +C000 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni0394 +ENCODING 916 +SWIDTH 670 0 +DWIDTH 11 0 +BBX 11 12 0 0 +BITMAP +0380 +0280 +0680 +0480 +0C80 +08C0 +18C0 +30C0 +30C0 +6040 +6040 +FFE0 +ENDCHAR +STARTCHAR Epsilon +ENCODING 917 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR Zeta +ENCODING 918 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 11 12 0 0 +BITMAP +3FE0 +00C0 +0180 +0180 +0300 +0600 +0C00 +1800 +1800 +3000 +6000 +FFC0 +ENDCHAR +STARTCHAR Eta +ENCODING 919 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +3030 +3020 +2020 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C0C0 +8080 +ENDCHAR +STARTCHAR Theta +ENCODING 920 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +1F00 +30C0 +6040 +C060 +C060 +8060 +9F60 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR Iota +ENCODING 921 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 12 1 0 +BITMAP +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR Kappa +ENCODING 922 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3060 +30C0 +2380 +2700 +6E00 +7C00 +7600 +6200 +C300 +C180 +C180 +80C0 +ENDCHAR +STARTCHAR Lambda +ENCODING 923 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 0 0 +BITMAP +0300 +0380 +0780 +0580 +0C80 +1880 +18C0 +30C0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR Mu +ENCODING 924 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 14 12 1 0 +BITMAP +300C +381C +3838 +2828 +6878 +6858 +4890 +4890 +CD30 +CD30 +C630 +8620 +ENDCHAR +STARTCHAR Nu +ENCODING 925 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +3030 +3830 +2820 +2820 +6460 +6460 +6640 +4240 +4240 +C1C0 +C1C0 +C080 +ENDCHAR +STARTCHAR Xi +ENCODING 926 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 12 12 0 0 +BITMAP +1FF0 +0000 +0000 +0000 +0000 +0000 +3FC0 +0000 +0000 +0000 +0000 +FFC0 +ENDCHAR +STARTCHAR Omicron +ENCODING 927 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR Pi +ENCODING 928 +SWIDTH 724 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +3FF0 +3030 +2020 +2060 +6060 +6060 +6040 +4040 +C0C0 +C0C0 +C0C0 +8080 +ENDCHAR +STARTCHAR Rho +ENCODING 929 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3FC0 +3060 +2060 +2060 +6060 +60C0 +7F80 +4000 +C000 +C000 +C000 +8000 +ENDCHAR +STARTCHAR Sigma +ENCODING 931 +SWIDTH 599 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +3FC0 +3000 +3000 +1800 +0C00 +0400 +0E00 +1C00 +3800 +7000 +C000 +FF00 +ENDCHAR +STARTCHAR Tau +ENCODING 932 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 12 2 0 +BITMAP +FFC0 +0C00 +0800 +0800 +1800 +1800 +1800 +1000 +1000 +3000 +3000 +3000 +ENDCHAR +STARTCHAR Upsilon +ENCODING 933 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 2 0 +BITMAP +C060 +60C0 +6180 +3300 +3300 +1600 +1C00 +0800 +0800 +1800 +1800 +1000 +ENDCHAR +STARTCHAR Phi +ENCODING 934 +SWIDTH 836 0 +DWIDTH 14 0 +BBX 12 12 2 0 +BITMAP +0300 +0300 +1FC0 +6260 +C630 +8630 +8430 +8420 +CCC0 +3F80 +0800 +0800 +ENDCHAR +STARTCHAR Chi +ENCODING 935 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 13 12 0 0 +BITMAP +3038 +1870 +18E0 +0CC0 +0D80 +0700 +0600 +0F00 +1980 +3180 +60C0 +C0C0 +ENDCHAR +STARTCHAR Psi +ENCODING 936 +SWIDTH 830 0 +DWIDTH 14 0 +BBX 13 12 2 0 +BITMAP +4318 +4218 +C210 +C610 +C630 +C630 +6460 +3F80 +0C00 +0C00 +0C00 +0800 +ENDCHAR +STARTCHAR uni03A9 +ENCODING 937 +SWIDTH 760 0 +DWIDTH 13 0 +BBX 13 12 0 0 +BITMAP +03C0 +0C20 +1810 +3018 +3018 +2018 +2018 +2018 +2030 +3030 +1860 +F9F0 +ENDCHAR +STARTCHAR Iotadieresis +ENCODING 938 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 14 1 0 +BITMAP +6C +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR Upsilondieresis +ENCODING 939 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 14 2 0 +BITMAP +1B00 +0000 +C060 +60C0 +6180 +3300 +3300 +1600 +1C00 +0800 +0800 +1800 +1800 +1000 +ENDCHAR +STARTCHAR alphatonos +ENCODING 940 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +0600 +0400 +0800 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR epsilontonos +ENCODING 941 +SWIDTH 439 0 +DWIDTH 7 0 +BBX 6 13 1 0 +BITMAP +0C +08 +10 +00 +3C +64 +40 +60 +70 +C0 +80 +88 +78 +ENDCHAR +STARTCHAR etatonos +ENCODING 942 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 8 16 1 -3 +BITMAP +06 +04 +08 +00 +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +06 +04 +04 +ENDCHAR +STARTCHAR iotatonos +ENCODING 943 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 4 13 1 0 +BITMAP +30 +20 +40 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR upsilondieresistonos +ENCODING 944 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +04 +29 +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR alpha +ENCODING 945 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR beta +ENCODING 946 +SWIDTH 571 0 +DWIDTH 10 0 +BBX 9 15 0 -3 +BITMAP +0F00 +1880 +1080 +3080 +3180 +2600 +2100 +6080 +6080 +6180 +7100 +5E00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR gamma +ENCODING 947 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +C1 +43 +42 +44 +4C +68 +78 +30 +30 +20 +60 +60 +ENDCHAR +STARTCHAR delta +ENCODING 948 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +3F80 +1000 +0800 +3C00 +6200 +4300 +C100 +8100 +8300 +8200 +C600 +7C00 +ENDCHAR +STARTCHAR epsilon +ENCODING 949 +SWIDTH 439 0 +DWIDTH 7 0 +BBX 6 9 1 0 +BITMAP +3C +64 +40 +60 +70 +C0 +80 +88 +78 +ENDCHAR +STARTCHAR zeta +ENCODING 950 +SWIDTH 463 0 +DWIDTH 8 0 +BBX 8 15 1 -3 +BITMAP +1F +06 +0C +18 +30 +60 +C0 +C0 +80 +80 +C0 +78 +0C +08 +30 +ENDCHAR +STARTCHAR eta +ENCODING 951 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +06 +04 +04 +ENDCHAR +STARTCHAR theta +ENCODING 952 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1E +33 +21 +61 +41 +C1 +FF +C3 +C3 +C2 +44 +38 +ENDCHAR +STARTCHAR iota +ENCODING 953 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 9 1 0 +BITMAP +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR kappa +ENCODING 954 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +63 +66 +4C +58 +F0 +F8 +C8 +8C +86 +ENDCHAR +STARTCHAR lambda +ENCODING 955 +SWIDTH 492 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +0C +0C +04 +0C +0C +1E +16 +36 +22 +62 +C2 +83 +ENDCHAR +STARTCHAR uni03BC +ENCODING 956 +SWIDTH 547 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3080 +3080 +2180 +2180 +6100 +6100 +6300 +6300 +5F00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR nu +ENCODING 957 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +C1 +43 +42 +46 +6C +68 +78 +30 +30 +ENDCHAR +STARTCHAR xi +ENCODING 958 +SWIDTH 446 0 +DWIDTH 8 0 +BBX 7 15 1 -3 +BITMAP +1E +30 +20 +30 +1C +30 +60 +C0 +C0 +C0 +C0 +78 +0C +0C +38 +ENDCHAR +STARTCHAR omicron +ENCODING 959 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR pi +ENCODING 960 +SWIDTH 669 0 +DWIDTH 11 0 +BBX 10 9 2 0 +BITMAP +FFC0 +6300 +6300 +4200 +4200 +C200 +C600 +C600 +8400 +ENDCHAR +STARTCHAR rho +ENCODING 961 +SWIDTH 572 0 +DWIDTH 10 0 +BBX 9 12 0 -3 +BITMAP +0F00 +1980 +3080 +2080 +6080 +6080 +6180 +6300 +5E00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR sigma1 +ENCODING 962 +SWIDTH 486 0 +DWIDTH 8 0 +BBX 8 12 1 -3 +BITMAP +1F +30 +40 +C0 +80 +80 +C0 +60 +18 +0C +08 +78 +ENDCHAR +STARTCHAR sigma +ENCODING 963 +SWIDTH 603 0 +DWIDTH 10 0 +BBX 10 9 1 0 +BITMAP +3FC0 +6300 +4100 +C100 +8100 +8300 +8200 +C600 +7C00 +ENDCHAR +STARTCHAR tau +ENCODING 964 +SWIDTH 374 0 +DWIDTH 6 0 +BBX 5 9 2 0 +BITMAP +F8 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR upsilon +ENCODING 965 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR phi +ENCODING 966 +SWIDTH 652 0 +DWIDTH 11 0 +BBX 10 12 1 -3 +BITMAP +1380 +6680 +44C0 +CCC0 +8CC0 +8CC0 +C980 +4B00 +3E00 +1800 +1000 +1000 +ENDCHAR +STARTCHAR chi +ENCODING 967 +SWIDTH 545 0 +DWIDTH 9 0 +BBX 11 12 -1 -3 +BITMAP +1060 +18C0 +1980 +0B00 +0E00 +0E00 +0E00 +1A00 +1200 +3300 +6300 +C100 +ENDCHAR +STARTCHAR psi +ENCODING 968 +SWIDTH 727 0 +DWIDTH 12 0 +BBX 11 12 1 -3 +BITMAP +6220 +6620 +4660 +4460 +C460 +C440 +CCC0 +4C80 +3F00 +0800 +1800 +1800 +ENDCHAR +STARTCHAR omega +ENCODING 969 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 9 1 0 +BITMAP +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +ENDCHAR +STARTCHAR iotadieresis +ENCODING 970 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 11 1 0 +BITMAP +D8 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR upsilondieresis +ENCODING 971 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1B +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR omicrontonos +ENCODING 972 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +04 +08 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR upsilontonos +ENCODING 973 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +04 +08 +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR omegatonos +ENCODING 974 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 13 1 0 +BITMAP +0180 +0100 +0200 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +ENDCHAR +STARTCHAR uni03CF +ENCODING 975 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 1 -4 +BITMAP +3060 +30C0 +2380 +2700 +6C00 +7C00 +7600 +6200 +C300 +C180 +C180 +80C0 +0100 +0200 +0C00 +0800 +ENDCHAR +STARTCHAR uni03D0 +ENCODING 976 +SWIDTH 504 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1E +33 +63 +7E +C0 +BC +C6 +C2 +82 +86 +CC +78 +ENDCHAR +STARTCHAR theta1 +ENCODING 977 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +0E00 +1100 +3180 +3180 +3900 +0F80 +E300 +6300 +4200 +C400 +CC00 +7000 +ENDCHAR +STARTCHAR Upsilon1 +ENCODING 978 +SWIDTH 715 0 +DWIDTH 12 0 +BBX 12 12 2 0 +BITMAP +C070 +40D0 +6180 +2100 +3300 +1600 +1C00 +0800 +1800 +1800 +1800 +1000 +ENDCHAR +STARTCHAR uni03D3 +ENCODING 979 +SWIDTH 881 0 +DWIDTH 15 0 +BBX 16 12 1 0 +BITMAP +6C07 +440D +8618 +0210 +0330 +0160 +01C0 +0080 +0180 +0180 +0180 +0100 +ENDCHAR +STARTCHAR uni03D4 +ENCODING 980 +SWIDTH 715 0 +DWIDTH 12 0 +BBX 12 14 2 0 +BITMAP +0D80 +0000 +C070 +40D0 +6180 +2100 +3300 +1600 +1C00 +0800 +1800 +1800 +1800 +1000 +ENDCHAR +STARTCHAR phi1 +ENCODING 981 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +04 +04 +0C +3E +6B +49 +D9 +99 +9B +93 +D6 +7C +30 +30 +20 +ENDCHAR +STARTCHAR omega1 +ENCODING 982 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 13 9 1 0 +BITMAP +7FF8 +6030 +4230 +C630 +8630 +8630 +8620 +CA60 +7380 +ENDCHAR +STARTCHAR uni03D7 +ENCODING 983 +SWIDTH 563 0 +DWIDTH 10 0 +BBX 10 12 0 -3 +BITMAP +30C0 +1180 +1300 +1700 +3F00 +3B00 +3200 +6200 +C380 +0100 +0300 +0E00 +ENDCHAR +STARTCHAR uni03D8 +ENCODING 984 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 15 2 -3 +BITMAP +1F00 +30C0 +6060 +C060 +C060 +8020 +8060 +8060 +8040 +C0C0 +6180 +3E00 +1800 +1800 +1000 +ENDCHAR +STARTCHAR uni03D9 +ENCODING 985 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +3E +63 +41 +C1 +81 +83 +83 +C6 +7C +30 +30 +20 +ENDCHAR +STARTCHAR uni03DA +ENCODING 986 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 2 0 +BITMAP +1F80 +30C0 +4060 +C000 +8000 +8000 +8000 +C000 +7800 +1800 +1800 +1800 +ENDCHAR +STARTCHAR uni03DB +ENCODING 987 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +3C +62 +43 +C0 +C0 +C0 +C0 +78 +0C +0C +0C +F0 +ENDCHAR +STARTCHAR uni03DC +ENCODING 988 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +3FC0 +3000 +2000 +2000 +6000 +7F00 +4300 +4300 +4000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR uni03DD +ENCODING 989 +SWIDTH 377 0 +DWIDTH 6 0 +BBX 7 12 0 -3 +BITMAP +3E +30 +20 +20 +7C +6C +40 +40 +40 +C0 +C0 +80 +ENDCHAR +STARTCHAR uni03DE +ENCODING 990 +SWIDTH 624 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +6000 +3000 +3000 +2080 +2380 +6F80 +7900 +E100 +8300 +0200 +0200 +0380 +ENDCHAR +STARTCHAR uni03DF +ENCODING 991 +SWIDTH 529 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +18 +10 +30 +20 +60 +C0 +FF +02 +06 +0C +08 +18 +ENDCHAR +STARTCHAR uni03E0 +ENCODING 992 +SWIDTH 756 0 +DWIDTH 13 0 +BBX 10 15 2 -3 +BITMAP +3E00 +7300 +9180 +90C0 +30C0 +31C0 +0640 +0440 +0440 +0C40 +08C0 +0880 +0180 +0300 +3C00 +ENDCHAR +STARTCHAR uni03E1 +ENCODING 993 +SWIDTH 576 0 +DWIDTH 10 0 +BBX 6 15 3 -3 +BITMAP +C0 +E0 +30 +18 +18 +7C +8C +0C +3C +4C +0C +08 +08 +18 +10 +ENDCHAR +STARTCHAR uni03E2 +ENCODING 994 +SWIDTH 846 0 +DWIDTH 14 0 +BBX 15 15 0 -3 +BITMAP +10C6 +10C6 +3086 +3084 +3184 +218C +218C +6108 +6308 +6318 +6738 +39D8 +0010 +0030 +FFE0 +ENDCHAR +STARTCHAR uni03E3 +ENCODING 995 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 14 12 0 -3 +BITMAP +3184 +218C +210C +2108 +6108 +6318 +4318 +4738 +79D0 +0010 +0030 +FFE0 +ENDCHAR +STARTCHAR uni03E4 +ENCODING 996 +SWIDTH 673 0 +DWIDTH 11 0 +BBX 10 12 2 0 +BITMAP +1EC0 +60C0 +C0C0 +C080 +8080 +C180 +C380 +7D00 +0100 +0300 +0300 +0300 +ENDCHAR +STARTCHAR uni03E5 +ENCODING 997 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 2 0 +BITMAP +73 +43 +C2 +C2 +86 +86 +86 +8C +F4 +0C +0C +08 +ENDCHAR +STARTCHAR uni03E6 +ENCODING 998 +SWIDTH 673 0 +DWIDTH 11 0 +BBX 10 15 1 -3 +BITMAP +3000 +3000 +3000 +2000 +2F80 +70C0 +60C0 +40C0 +40C0 +40C0 +C0C0 +C080 +0180 +0300 +FC00 +ENDCHAR +STARTCHAR uni03E7 +ENCODING 999 +SWIDTH 512 0 +DWIDTH 9 0 +BBX 9 10 0 0 +BITMAP +0080 +1F80 +2300 +6700 +3900 +0100 +0100 +0300 +E600 +BC00 +ENDCHAR +STARTCHAR uni03E8 +ENCODING 1000 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +0F80 +30C0 +20C0 +60C0 +0380 +0F00 +38C0 +60C0 +C0C0 +C080 +C300 +7E00 +ENDCHAR +STARTCHAR uni03E9 +ENCODING 1001 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +0F80 +30C0 +20C0 +60C0 +0180 +0F00 +3800 +6000 +C000 +C000 +C080 +7F00 +ENDCHAR +STARTCHAR uni03EA +ENCODING 1002 +SWIDTH 609 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +79C0 +5B40 +0A00 +0C00 +0C00 +0C00 +1C00 +1400 +2400 +6600 +4600 +FE00 +ENDCHAR +STARTCHAR uni03EB +ENCODING 1003 +SWIDTH 596 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +7380 +9E80 +1C00 +1C00 +0800 +1800 +3800 +2C00 +7C00 +ENDCHAR +STARTCHAR uni03EC +ENCODING 1004 +SWIDTH 745 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +0FE0 +3000 +6F80 +70C0 +C040 +C060 +8060 +8040 +80C0 +8080 +C300 +7E00 +ENDCHAR +STARTCHAR uni03ED +ENCODING 1005 +SWIDTH 553 0 +DWIDTH 9 0 +BBX 9 9 1 0 +BITMAP +0F80 +3000 +5E00 +C300 +8100 +8300 +8300 +C600 +7C00 +ENDCHAR +STARTCHAR uni03EE +ENCODING 1006 +SWIDTH 415 0 +DWIDTH 7 0 +BBX 8 12 0 0 +BITMAP +0C +0C +0C +3F +49 +D9 +18 +18 +10 +30 +30 +30 +ENDCHAR +STARTCHAR uni03EF +ENCODING 1007 +SWIDTH 358 0 +DWIDTH 6 0 +BBX 6 12 1 0 +BITMAP +18 +10 +10 +FC +B0 +20 +20 +20 +60 +60 +40 +40 +ENDCHAR +STARTCHAR uni03F0 +ENCODING 1008 +SWIDTH 563 0 +DWIDTH 10 0 +BBX 10 9 0 0 +BITMAP +30C0 +1180 +1300 +1700 +3F00 +3B00 +3200 +6200 +C380 +ENDCHAR +STARTCHAR uni03F1 +ENCODING 1009 +SWIDTH 579 0 +DWIDTH 10 0 +BBX 9 12 1 -3 +BITMAP +1E00 +2300 +6180 +4180 +C100 +C100 +C300 +C600 +BC00 +8000 +C000 +7E00 +ENDCHAR +STARTCHAR uni03F2 +ENCODING 1010 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1C +62 +43 +C0 +C0 +80 +C6 +C4 +78 +ENDCHAR +STARTCHAR uni03F3 +ENCODING 1011 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 15 -2 -3 +BITMAP +04 +00 +00 +0C +0C +08 +08 +18 +18 +10 +10 +10 +30 +30 +E0 +ENDCHAR +STARTCHAR uni03F4 +ENCODING 1012 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +1F00 +30C0 +6060 +C060 +C060 +8020 +FFE0 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni03F5 +ENCODING 1013 +SWIDTH 440 0 +DWIDTH 8 0 +BBX 7 9 1 0 +BITMAP +3E +60 +C0 +C0 +F0 +80 +80 +C0 +78 +ENDCHAR +STARTCHAR uni03F6 +ENCODING 1014 +SWIDTH 440 0 +DWIDTH 8 0 +BBX 7 9 0 0 +BITMAP +3C +06 +02 +02 +1E +06 +06 +0C +F8 +ENDCHAR +STARTCHAR uni03F7 +ENCODING 1015 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +3000 +3000 +3F80 +20C0 +6040 +6040 +6040 +40C0 +C180 +FF00 +C000 +8000 +ENDCHAR +STARTCHAR uni03F8 +ENCODING 1016 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 15 0 -3 +BITMAP +1000 +1000 +1000 +3F00 +3180 +3080 +2080 +6080 +6180 +6100 +6300 +5E00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni03F9 +ENCODING 1017 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 10 12 2 0 +BITMAP +1F00 +3080 +60C0 +C040 +C000 +8000 +8000 +8000 +80C0 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR uni03FA +ENCODING 1018 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 14 12 1 0 +BITMAP +381C +383C +2C68 +2CC8 +6798 +6318 +4010 +4010 +C030 +C030 +C030 +8020 +ENDCHAR +STARTCHAR uni03FB +ENCODING 1019 +SWIDTH 685 0 +DWIDTH 12 0 +BBX 12 12 0 -3 +BITMAP +3870 +3860 +28A0 +28A0 +6960 +6B60 +4A40 +4E40 +4CC0 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni03FC +ENCODING 1020 +SWIDTH 572 0 +DWIDTH 10 0 +BBX 10 12 -1 -3 +BITMAP +0780 +0CC0 +1840 +1040 +3040 +3040 +30C0 +3180 +2F00 +6000 +F800 +4000 +ENDCHAR +STARTCHAR uni03FD +ENCODING 1021 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +0F80 +30C0 +2060 +6060 +0020 +0020 +0060 +0060 +C040 +40C0 +6180 +1E00 +ENDCHAR +STARTCHAR uni03FE +ENCODING 1022 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 10 12 2 0 +BITMAP +1F00 +3080 +60C0 +C040 +C000 +8000 +8C00 +8000 +80C0 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR uni03FF +ENCODING 1023 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +0F80 +30C0 +2060 +6060 +0020 +0020 +0660 +0060 +C040 +40C0 +6180 +1E00 +ENDCHAR +STARTCHAR uni0400 +ENCODING 1024 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 1 0 +BITMAP +0400 +0600 +0200 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR uni0401 +ENCODING 1025 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 14 1 0 +BITMAP +0D80 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR uni0402 +ENCODING 1026 +SWIDTH 842 0 +DWIDTH 14 0 +BBX 12 12 2 0 +BITMAP +FFC0 +0800 +0800 +1800 +1FC0 +1820 +1030 +1030 +3030 +3030 +2060 +27C0 +ENDCHAR +STARTCHAR uni0403 +ENCODING 1027 +SWIDTH 543 0 +DWIDTH 9 0 +BBX 10 16 1 0 +BITMAP +0300 +0200 +0400 +0000 +3FC0 +3000 +2000 +2000 +6000 +6000 +4000 +4000 +C000 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni0404 +ENCODING 1028 +SWIDTH 707 0 +DWIDTH 12 0 +BBX 10 12 2 0 +BITMAP +1F00 +3080 +60C0 +C040 +C000 +C000 +FC00 +8000 +80C0 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR uni0405 +ENCODING 1029 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +1F80 +30C0 +2040 +2000 +3000 +1E00 +0780 +0180 +C0C0 +C080 +6180 +3E00 +ENDCHAR +STARTCHAR uni0406 +ENCODING 1030 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 12 1 0 +BITMAP +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni0407 +ENCODING 1031 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 14 1 0 +BITMAP +6C +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni0408 +ENCODING 1032 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +03 +03 +03 +02 +02 +06 +06 +04 +04 +8C +8C +F8 +ENDCHAR +STARTCHAR uni0409 +ENCODING 1033 +SWIDTH 1065 0 +DWIDTH 18 0 +BBX 18 12 0 0 +BITMAP +0FF000 +0C3000 +082000 +082000 +186000 +187F00 +106080 +1040C0 +30C0C0 +30C080 +20C180 +E0FE00 +ENDCHAR +STARTCHAR uni040A +ENCODING 1034 +SWIDTH 982 0 +DWIDTH 17 0 +BBX 15 12 1 0 +BITMAP +3080 +3080 +2180 +2180 +6180 +6180 +7FFC +4306 +C302 +C306 +C20C +87F8 +ENDCHAR +STARTCHAR uni040B +ENCODING 1035 +SWIDTH 844 0 +DWIDTH 14 0 +BBX 12 12 2 0 +BITMAP +FFC0 +0800 +0800 +1800 +1FC0 +1820 +1030 +1030 +3030 +3020 +2020 +2060 +ENDCHAR +STARTCHAR uni040C +ENCODING 1036 +SWIDTH 589 0 +DWIDTH 10 0 +BBX 10 16 1 0 +BITMAP +0300 +0200 +0400 +0000 +30C0 +3100 +2300 +2600 +6400 +7800 +4C00 +4600 +C600 +C200 +C300 +8300 +ENDCHAR +STARTCHAR uni040D +ENCODING 1037 +SWIDTH 715 0 +DWIDTH 12 0 +BBX 12 16 1 0 +BITMAP +0400 +0600 +0200 +0000 +3030 +30E0 +20E0 +2160 +6260 +6460 +6440 +48C0 +D0C0 +E0C0 +C080 +C080 +ENDCHAR +STARTCHAR uni040E +ENCODING 1038 +SWIDTH 639 0 +DWIDTH 11 0 +BBX 10 15 2 0 +BITMAP +1300 +0E00 +0000 +C040 +40C0 +4080 +6180 +2300 +3200 +3600 +1400 +1800 +1800 +3000 +E000 +ENDCHAR +STARTCHAR uni040F +ENCODING 1039 +SWIDTH 723 0 +DWIDTH 12 0 +BBX 12 15 1 -3 +BITMAP +3030 +3030 +2020 +2020 +6060 +6060 +6060 +4040 +C040 +C0C0 +C0C0 +FF80 +0800 +1800 +1800 +ENDCHAR +STARTCHAR uni0410 +ENCODING 1040 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 0 0 +BITMAP +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni0411 +ENCODING 1041 +SWIDTH 650 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +3FC0 +3000 +2000 +2000 +6000 +7F00 +4180 +40C0 +C0C0 +C080 +C180 +FE00 +ENDCHAR +STARTCHAR uni0412 +ENCODING 1042 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +3F80 +30C0 +2040 +20C0 +6080 +7F00 +4080 +40C0 +C0C0 +C0C0 +C180 +FF00 +ENDCHAR +STARTCHAR uni0413 +ENCODING 1043 +SWIDTH 543 0 +DWIDTH 9 0 +BBX 10 12 1 0 +BITMAP +3FC0 +3000 +2000 +2000 +6000 +6000 +4000 +4000 +C000 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni0414 +ENCODING 1044 +SWIDTH 704 0 +DWIDTH 12 0 +BBX 13 14 -1 -2 +BITMAP +07F8 +0618 +0418 +0418 +0C18 +0C10 +0830 +0830 +1830 +1020 +3020 +7FF0 +C030 +8030 +ENDCHAR +STARTCHAR uni0415 +ENCODING 1045 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR uni0416 +ENCODING 1046 +SWIDTH 916 0 +DWIDTH 16 0 +BBX 17 12 0 0 +BITMAP +384380 +084600 +08C400 +0CCC00 +0CD800 +07E000 +0D9800 +199800 +318C00 +610C00 +410400 +C30600 +ENDCHAR +STARTCHAR uni0417 +ENCODING 1047 +SWIDTH 613 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +0F00 +3180 +2080 +6080 +0180 +0E00 +0300 +0180 +8180 +C100 +4300 +3E00 +ENDCHAR +STARTCHAR uni0418 +ENCODING 1048 +SWIDTH 715 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +3030 +30E0 +20E0 +2160 +6260 +6460 +6440 +48C0 +D0C0 +E0C0 +C080 +C080 +ENDCHAR +STARTCHAR uni0419 +ENCODING 1049 +SWIDTH 715 0 +DWIDTH 12 0 +BBX 12 15 1 0 +BITMAP +04C0 +0380 +0000 +3030 +30E0 +20E0 +2160 +6260 +6460 +6440 +48C0 +D0C0 +E0C0 +C080 +C080 +ENDCHAR +STARTCHAR uni041A +ENCODING 1050 +SWIDTH 589 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +30C0 +3100 +2300 +2600 +6400 +7800 +4C00 +4600 +C600 +C200 +C300 +8300 +ENDCHAR +STARTCHAR uni041B +ENCODING 1051 +SWIDTH 685 0 +DWIDTH 12 0 +BBX 12 12 0 0 +BITMAP +0FF0 +0C30 +0830 +0830 +1820 +1860 +1060 +1060 +3040 +3040 +20C0 +E0C0 +ENDCHAR +STARTCHAR uni041C +ENCODING 1052 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 14 12 1 0 +BITMAP +300C +381C +3838 +2828 +6878 +6858 +4890 +4890 +CD30 +CD30 +C630 +8620 +ENDCHAR +STARTCHAR uni041D +ENCODING 1053 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +3030 +3020 +2020 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C0C0 +8080 +ENDCHAR +STARTCHAR uni041E +ENCODING 1054 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni041F +ENCODING 1055 +SWIDTH 724 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +3FF0 +3030 +2020 +2060 +6060 +6060 +6040 +4040 +C0C0 +C0C0 +C0C0 +8080 +ENDCHAR +STARTCHAR uni0420 +ENCODING 1056 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3FC0 +3060 +2060 +2060 +6060 +60C0 +7F80 +4000 +C000 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni0421 +ENCODING 1057 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 10 12 2 0 +BITMAP +1F00 +3080 +60C0 +C040 +C000 +8000 +8000 +8000 +80C0 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR uni0422 +ENCODING 1058 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 12 2 0 +BITMAP +FFC0 +0C00 +0800 +0800 +1800 +1800 +1800 +1000 +1000 +3000 +3000 +3000 +ENDCHAR +STARTCHAR uni0423 +ENCODING 1059 +SWIDTH 639 0 +DWIDTH 11 0 +BBX 10 12 2 0 +BITMAP +C040 +40C0 +4080 +6180 +2300 +3200 +3600 +1400 +1800 +1800 +3000 +E000 +ENDCHAR +STARTCHAR uni0424 +ENCODING 1060 +SWIDTH 794 0 +DWIDTH 14 0 +BBX 12 12 1 0 +BITMAP +0100 +0FC0 +3330 +6310 +6210 +4210 +C610 +C630 +4620 +6460 +1F80 +0C00 +ENDCHAR +STARTCHAR uni0425 +ENCODING 1061 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 13 12 0 0 +BITMAP +3038 +1870 +18E0 +0CC0 +0D80 +0700 +0600 +0F00 +1980 +3180 +60C0 +C0C0 +ENDCHAR +STARTCHAR uni0426 +ENCODING 1062 +SWIDTH 727 0 +DWIDTH 12 0 +BBX 12 14 1 -2 +BITMAP +3030 +3030 +2020 +2020 +6060 +6060 +6060 +4040 +C040 +C0C0 +C0C0 +FFE0 +0040 +0040 +ENDCHAR +STARTCHAR uni0427 +ENCODING 1063 +SWIDTH 673 0 +DWIDTH 11 0 +BBX 10 12 2 0 +BITMAP +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +C380 +7F00 +0100 +0300 +0300 +0300 +ENDCHAR +STARTCHAR uni0428 +ENCODING 1064 +SWIDTH 920 0 +DWIDTH 16 0 +BBX 15 12 1 0 +BITMAP +30C2 +3086 +2186 +2184 +6184 +610C +610C +430C +C308 +C308 +C218 +FFF8 +ENDCHAR +STARTCHAR uni0429 +ENCODING 1065 +SWIDTH 922 0 +DWIDTH 16 0 +BBX 15 14 1 -2 +BITMAP +30C2 +3086 +2186 +2186 +6184 +610C +610C +430C +C308 +C308 +C218 +FFFC +000C +0008 +ENDCHAR +STARTCHAR uni042A +ENCODING 1066 +SWIDTH 805 0 +DWIDTH 14 0 +BBX 11 12 2 0 +BITMAP +F800 +0800 +1800 +1800 +1800 +1FC0 +1060 +3020 +3020 +3060 +20C0 +7F80 +ENDCHAR +STARTCHAR uni042B +ENCODING 1067 +SWIDTH 886 0 +DWIDTH 15 0 +BBX 15 12 1 0 +BITMAP +3006 +3004 +2004 +200C +600C +6008 +7F08 +4098 +C0D8 +C098 +C190 +FF10 +ENDCHAR +STARTCHAR uni042C +ENCODING 1068 +SWIDTH 650 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +3000 +3000 +2000 +2000 +6000 +6000 +7F00 +4080 +C0C0 +C080 +C180 +FF00 +ENDCHAR +STARTCHAR uni042D +ENCODING 1069 +SWIDTH 693 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +0F00 +30C0 +6040 +4060 +0060 +07E0 +0060 +80C0 +C0C0 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR uni042E +ENCODING 1070 +SWIDTH 1022 0 +DWIDTH 17 0 +BBX 16 12 1 0 +BITMAP +307C +3086 +2103 +2303 +6201 +6601 +7E03 +4603 +C602 +C206 +C30C +81F0 +ENDCHAR +STARTCHAR uni042F +ENCODING 1071 +SWIDTH 681 0 +DWIDTH 12 0 +BBX 12 12 0 0 +BITMAP +0FF0 +1830 +3030 +3020 +3020 +1FE0 +0C60 +1860 +3040 +7040 +60C0 +C0C0 +ENDCHAR +STARTCHAR uni0430 +ENCODING 1072 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni0431 +ENCODING 1073 +SWIDTH 562 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +1F80 +2000 +2000 +5E00 +6300 +C100 +C100 +C100 +8300 +C300 +4600 +3C00 +ENDCHAR +STARTCHAR uni0432 +ENCODING 1074 +SWIDTH 521 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1E +63 +43 +C6 +FC +86 +82 +C6 +7C +ENDCHAR +STARTCHAR uni0433 +ENCODING 1075 +SWIDTH 493 0 +DWIDTH 8 0 +BBX 7 9 1 0 +BITMAP +3C +46 +02 +0E +38 +C0 +86 +C4 +78 +ENDCHAR +STARTCHAR uni0434 +ENCODING 1076 +SWIDTH 552 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1E +03 +01 +1D +63 +41 +C1 +81 +83 +82 +C6 +78 +ENDCHAR +STARTCHAR uni0435 +ENCODING 1077 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR uni0436 +ENCODING 1078 +SWIDTH 687 0 +DWIDTH 12 0 +BBX 12 9 0 0 +BITMAP +3330 +1360 +1240 +1AC0 +0F00 +3680 +26C0 +6440 +C460 +ENDCHAR +STARTCHAR uni0437 +ENCODING 1079 +SWIDTH 464 0 +DWIDTH 8 0 +BBX 8 9 0 0 +BITMAP +1E +23 +03 +02 +1C +06 +C2 +46 +3C +ENDCHAR +STARTCHAR uni0438 +ENCODING 1080 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uni0439 +ENCODING 1081 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +13 +0E +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uni043A +ENCODING 1082 +SWIDTH 472 0 +DWIDTH 8 0 +BBX 8 9 1 0 +BITMAP +63 +64 +4C +48 +F0 +D8 +C8 +8C +84 +ENDCHAR +STARTCHAR uni043B +ENCODING 1083 +SWIDTH 563 0 +DWIDTH 10 0 +BBX 10 9 0 0 +BITMAP +1FC0 +1080 +1080 +3180 +3180 +2180 +2100 +6100 +C300 +ENDCHAR +STARTCHAR uni043C +ENCODING 1084 +SWIDTH 685 0 +DWIDTH 12 0 +BBX 11 9 1 0 +BITMAP +70E0 +70C0 +5140 +5140 +D2C0 +D6C0 +D480 +9C80 +9980 +ENDCHAR +STARTCHAR uni043D +ENCODING 1085 +SWIDTH 550 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +61 +61 +43 +43 +FF +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR uni043E +ENCODING 1086 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni043F +ENCODING 1087 +SWIDTH 550 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +7F +61 +43 +43 +C3 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR uni0440 +ENCODING 1088 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3F00 +3180 +3080 +2080 +6080 +6180 +6100 +6300 +5E00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni0441 +ENCODING 1089 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1C +62 +43 +C0 +C0 +80 +C6 +C4 +78 +ENDCHAR +STARTCHAR uni0442 +ENCODING 1090 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +6E70 +7398 +6318 +4218 +C210 +C610 +C630 +8630 +8430 +ENDCHAR +STARTCHAR uni0443 +ENCODING 1091 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +2080 +2180 +2100 +3300 +3600 +3400 +1C00 +1800 +1800 +1000 +2000 +E000 +ENDCHAR +STARTCHAR uni0444 +ENCODING 1092 +SWIDTH 835 0 +DWIDTH 14 0 +BBX 13 15 1 -3 +BITMAP +0180 +0100 +0100 +3FF0 +6798 +4318 +C218 +8218 +8618 +8610 +CF30 +75E0 +0400 +0C00 +0C00 +ENDCHAR +STARTCHAR uni0445 +ENCODING 1093 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +2180 +3300 +1600 +1C00 +0800 +1C00 +3400 +6600 +C200 +ENDCHAR +STARTCHAR uni0446 +ENCODING 1094 +SWIDTH 571 0 +DWIDTH 10 0 +BBX 8 12 1 -3 +BITMAP +61 +61 +43 +43 +C3 +C2 +C6 +CE +73 +01 +01 +03 +ENDCHAR +STARTCHAR uni0447 +ENCODING 1095 +SWIDTH 517 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +43 +43 +C2 +C2 +C2 +7E +06 +04 +04 +ENDCHAR +STARTCHAR uni0448 +ENCODING 1096 +SWIDTH 830 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +6308 +6318 +4318 +4210 +C210 +C610 +C630 +CE70 +73A0 +ENDCHAR +STARTCHAR uni0449 +ENCODING 1097 +SWIDTH 851 0 +DWIDTH 14 0 +BBX 13 12 1 -3 +BITMAP +6308 +6318 +4318 +4210 +C210 +C610 +C630 +CE70 +73B8 +0008 +0018 +0018 +ENDCHAR +STARTCHAR uni044A +ENCODING 1098 +SWIDTH 621 0 +DWIDTH 11 0 +BBX 9 9 1 0 +BITMAP +F000 +1000 +3000 +3000 +3F00 +2180 +2180 +6180 +7F00 +ENDCHAR +STARTCHAR uni044B +ENCODING 1099 +SWIDTH 735 0 +DWIDTH 13 0 +BBX 12 9 1 0 +BITMAP +6030 +6020 +4020 +4060 +FE60 +C240 +C240 +8640 +FCC0 +ENDCHAR +STARTCHAR uni044C +ENCODING 1100 +SWIDTH 525 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +60 +60 +40 +40 +FE +C2 +C2 +86 +FC +ENDCHAR +STARTCHAR uni044D +ENCODING 1101 +SWIDTH 491 0 +DWIDTH 8 0 +BBX 8 9 0 0 +BITMAP +1E +33 +61 +01 +0F +03 +C2 +46 +3C +ENDCHAR +STARTCHAR uni044E +ENCODING 1102 +SWIDTH 751 0 +DWIDTH 13 0 +BBX 12 9 1 0 +BITMAP +63C0 +6660 +4C20 +4830 +F820 +C820 +C860 +8CC0 +8780 +ENDCHAR +STARTCHAR uni044F +ENCODING 1103 +SWIDTH 534 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +1F80 +2180 +6180 +2100 +3F00 +3300 +2300 +6300 +C200 +ENDCHAR +STARTCHAR uni0450 +ENCODING 1104 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +10 +18 +08 +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR uni0451 +ENCODING 1105 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1B +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR uni0452 +ENCODING 1106 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +30 +7C +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +86 +06 +04 +1C +ENDCHAR +STARTCHAR uni0453 +ENCODING 1107 +SWIDTH 377 0 +DWIDTH 6 0 +BBX 6 12 1 0 +BITMAP +08 +10 +00 +7C +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni0454 +ENCODING 1108 +SWIDTH 495 0 +DWIDTH 8 0 +BBX 7 9 1 0 +BITMAP +3C +62 +42 +C0 +F0 +80 +86 +CC +78 +ENDCHAR +STARTCHAR uni0455 +ENCODING 1109 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +3C +66 +42 +60 +3C +0E +86 +C6 +7C +ENDCHAR +STARTCHAR uni0456 +ENCODING 1110 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 12 1 0 +BITMAP +20 +00 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni0457 +ENCODING 1111 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 11 1 0 +BITMAP +D8 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni0458 +ENCODING 1112 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 15 -2 -3 +BITMAP +04 +00 +00 +0C +0C +08 +08 +18 +18 +10 +10 +10 +30 +30 +E0 +ENDCHAR +STARTCHAR uni0459 +ENCODING 1113 +SWIDTH 910 0 +DWIDTH 15 0 +BBX 15 9 0 0 +BITMAP +1FC0 +1040 +10C0 +10C0 +30FC +3086 +2086 +2186 +E1FC +ENDCHAR +STARTCHAR uni045A +ENCODING 1114 +SWIDTH 827 0 +DWIDTH 14 0 +BBX 12 9 1 0 +BITMAP +6300 +6300 +4300 +4200 +FFF0 +C610 +C610 +8630 +87E0 +ENDCHAR +STARTCHAR uni045B +ENCODING 1115 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +30 +7C +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR uni045C +ENCODING 1116 +SWIDTH 472 0 +DWIDTH 8 0 +BBX 8 13 1 0 +BITMAP +06 +04 +08 +00 +63 +64 +4C +48 +F0 +D8 +C8 +8C +84 +ENDCHAR +STARTCHAR uni045D +ENCODING 1117 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +08 +0C +04 +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uni045E +ENCODING 1118 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 15 0 -3 +BITMAP +1300 +0E00 +0000 +2080 +2180 +2100 +3300 +3600 +3400 +1C00 +1800 +1800 +1000 +2000 +E000 +ENDCHAR +STARTCHAR uni045F +ENCODING 1119 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +20 +60 +40 +ENDCHAR +STARTCHAR uni0460 +ENCODING 1120 +SWIDTH 1301 0 +DWIDTH 22 0 +BBX 20 12 2 0 +BITMAP +0F87C0 +308460 +600030 +C00030 +C00030 +800030 +800030 +80C060 +80C060 +C0C0C0 +61C180 +3E7E00 +ENDCHAR +STARTCHAR uni0461 +ENCODING 1121 +SWIDTH 594 0 +DWIDTH 10 0 +BBX 10 9 1 0 +BITMAP +C840 +88C0 +9880 +9980 +9900 +DB00 +EA00 +EE00 +4C00 +ENDCHAR +STARTCHAR uni0462 +ENCODING 1122 +SWIDTH 759 0 +DWIDTH 13 0 +BBX 11 12 1 0 +BITMAP +0C00 +0800 +FF80 +1800 +1800 +1FC0 +1060 +1020 +3020 +3060 +30E0 +3F80 +ENDCHAR +STARTCHAR uni0463 +ENCODING 1123 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 9 1 0 +BITMAP +6F00 +5100 +6300 +4200 +47E0 +C430 +C430 +8620 +83C0 +ENDCHAR +STARTCHAR uni0464 +ENCODING 1124 +SWIDTH 902 0 +DWIDTH 15 0 +BBX 15 12 1 0 +BITMAP +30F8 +230C +2204 +6606 +6400 +6C00 +7FC0 +4800 +CC0C +CC0C +C618 +83E0 +ENDCHAR +STARTCHAR uni0465 +ENCODING 1125 +SWIDTH 694 0 +DWIDTH 12 0 +BBX 11 9 1 0 +BITMAP +63C0 +6460 +4860 +4800 +FF00 +D800 +D840 +88C0 +8700 +ENDCHAR +STARTCHAR uni0466 +ENCODING 1126 +SWIDTH 667 0 +DWIDTH 11 0 +BBX 10 12 0 0 +BITMAP +0300 +0380 +0580 +0480 +0880 +1880 +1FC0 +26C0 +64C0 +44C0 +CC40 +8C40 +ENDCHAR +STARTCHAR uni0467 +ENCODING 1127 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 0 0 +BITMAP +04 +0E +1E +16 +32 +3E +5A +DB +93 +ENDCHAR +STARTCHAR uni0468 +ENCODING 1128 +SWIDTH 877 0 +DWIDTH 15 0 +BBX 13 12 1 0 +BITMAP +3060 +20E0 +20A0 +6130 +6330 +6230 +7FF0 +4490 +C998 +D998 +9198 +B118 +ENDCHAR +STARTCHAR uni0469 +ENCODING 1129 +SWIDTH 680 0 +DWIDTH 12 0 +BBX 10 9 1 0 +BITMAP +6180 +6380 +4280 +4680 +C480 +FFC0 +DAC0 +92C0 +B640 +ENDCHAR +STARTCHAR uni046A +ENCODING 1130 +SWIDTH 828 0 +DWIDTH 14 0 +BBX 14 12 0 0 +BITMAP +0FFC +0C18 +0630 +0660 +03C0 +0FE0 +3B30 +2318 +6318 +4318 +4218 +C210 +ENDCHAR +STARTCHAR uni046B +ENCODING 1131 +SWIDTH 685 0 +DWIDTH 12 0 +BBX 10 9 1 0 +BITMAP +1FC0 +1180 +1B00 +0A00 +3F80 +4C80 +CC80 +8880 +8880 +ENDCHAR +STARTCHAR uni046C +ENCODING 1132 +SWIDTH 1023 0 +DWIDTH 17 0 +BBX 17 12 1 0 +BITMAP +33FF80 +218600 +218C00 +60D800 +60F000 +7FFC00 +4E4E00 +4C4600 +D8C600 +D8C600 +90C600 +908600 +ENDCHAR +STARTCHAR uni046D +ENCODING 1133 +SWIDTH 855 0 +DWIDTH 15 0 +BBX 13 9 1 0 +BITMAP +67F8 +6230 +4360 +4140 +FFF0 +C990 +D910 +9110 +9110 +ENDCHAR +STARTCHAR uni046E +ENCODING 1134 +SWIDTH 613 0 +DWIDTH 10 0 +BBX 10 18 1 -3 +BITMAP +08C0 +0500 +0700 +0F00 +3180 +2080 +6080 +0180 +0E00 +0300 +0180 +0180 +0100 +0300 +7C00 +C000 +8E00 +F200 +ENDCHAR +STARTCHAR uni046F +ENCODING 1135 +SWIDTH 464 0 +DWIDTH 8 0 +BBX 9 15 0 -3 +BITMAP +1980 +0A00 +0E00 +1E00 +2300 +0300 +0200 +1C00 +0600 +0200 +0600 +7C00 +C000 +CE00 +F200 +ENDCHAR +STARTCHAR uni0470 +ENCODING 1136 +SWIDTH 830 0 +DWIDTH 14 0 +BBX 13 12 2 0 +BITMAP +C318 +4218 +6210 +6610 +6630 +2620 +3460 +1F80 +0C00 +0C00 +0C00 +0800 +ENDCHAR +STARTCHAR uni0471 +ENCODING 1137 +SWIDTH 727 0 +DWIDTH 12 0 +BBX 10 12 2 -3 +BITMAP +8440 +8C40 +8CC0 +C8C0 +C8C0 +C880 +D980 +5900 +7E00 +1000 +3000 +3000 +ENDCHAR +STARTCHAR uni0472 +ENCODING 1138 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +1F00 +30C0 +6060 +C060 +C060 +F860 +87E0 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni0473 +ENCODING 1139 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +3E +63 +43 +C1 +F1 +8F +82 +C6 +7C +ENDCHAR +STARTCHAR uni0474 +ENCODING 1140 +SWIDTH 759 0 +DWIDTH 13 0 +BBX 12 12 2 0 +BITMAP +C070 +C0D0 +4080 +4180 +6100 +6300 +6200 +2600 +2400 +2C00 +3800 +3000 +ENDCHAR +STARTCHAR uni0475 +ENCODING 1141 +SWIDTH 589 0 +DWIDTH 10 0 +BBX 10 9 1 0 +BITMAP +C1C0 +4340 +4200 +4400 +4400 +6800 +7800 +3000 +3000 +ENDCHAR +STARTCHAR uni0476 +ENCODING 1142 +SWIDTH 759 0 +DWIDTH 13 0 +BBX 12 15 2 0 +BITMAP +3600 +1A00 +0000 +C070 +C0D0 +4080 +4180 +6100 +6300 +6200 +2600 +2400 +2C00 +3800 +3000 +ENDCHAR +STARTCHAR uni0477 +ENCODING 1143 +SWIDTH 589 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +6C00 +3400 +0000 +C1C0 +4340 +4200 +4400 +4400 +6800 +7800 +3000 +3000 +ENDCHAR +STARTCHAR uni0478 +ENCODING 1144 +SWIDTH 1108 0 +DWIDTH 19 0 +BBX 18 15 2 -3 +BITMAP +1F0000 +318000 +618000 +41A0C0 +C1A180 +C1B100 +81B300 +813200 +831600 +821C00 +C61800 +781800 +001000 +002000 +00C000 +ENDCHAR +STARTCHAR uni0479 +ENCODING 1145 +SWIDTH 918 0 +DWIDTH 16 0 +BBX 15 12 1 -3 +BITMAP +3D82 +6486 +4484 +C48C +C4D8 +84D0 +8CF0 +D860 +7040 +0040 +0080 +0300 +ENDCHAR +STARTCHAR uni047A +ENCODING 1146 +SWIDTH 827 0 +DWIDTH 14 0 +BBX 14 14 1 -1 +BITMAP +0180 +0FE0 +19B8 +2018 +400C +C00C +C00C +8008 +8018 +8010 +C030 +6660 +3F80 +0C00 +ENDCHAR +STARTCHAR uni047B +ENCODING 1147 +SWIDTH 599 0 +DWIDTH 10 0 +BBX 10 11 0 -1 +BITMAP +0600 +1F80 +36C0 +6040 +4040 +C040 +C040 +C0C0 +6D80 +3E00 +1800 +ENDCHAR +STARTCHAR uni047C +ENCODING 1148 +SWIDTH 1282 0 +DWIDTH 22 0 +BBX 20 16 2 0 +BITMAP +003C00 +004600 +009180 +002000 +0F87C0 +308860 +600020 +C00030 +C00030 +800030 +800020 +800060 +8000C0 +C000C0 +61C300 +3E7E00 +ENDCHAR +STARTCHAR uni047D +ENCODING 1149 +SWIDTH 875 0 +DWIDTH 15 0 +BBX 14 14 1 0 +BITMAP +01E0 +0230 +048C +0100 +0000 +3018 +6008 +400C +C00C +8008 +8008 +8018 +C630 +7FE0 +ENDCHAR +STARTCHAR uni047E +ENCODING 1150 +SWIDTH 1301 0 +DWIDTH 22 0 +BBX 20 15 2 0 +BITMAP +00FE00 +009400 +000000 +0F87C0 +308460 +600030 +C00030 +C00030 +800030 +800030 +80C060 +80C060 +C0C0C0 +61C180 +3E7E00 +ENDCHAR +STARTCHAR uni047F +ENCODING 1151 +SWIDTH 594 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +3F80 +2500 +0000 +C840 +88C0 +9880 +9980 +9900 +DB00 +EA00 +EE00 +4C00 +ENDCHAR +STARTCHAR uni0480 +ENCODING 1152 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 10 15 2 -3 +BITMAP +1F00 +3080 +60C0 +C040 +C000 +8000 +8000 +8000 +8000 +C000 +6000 +3800 +1800 +1800 +1800 +ENDCHAR +STARTCHAR uni0481 +ENCODING 1153 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +1C +62 +43 +C0 +C0 +80 +C0 +C0 +70 +30 +30 +20 +ENDCHAR +STARTCHAR uni0482 +ENCODING 1154 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +01 +02 +62 +1C +0C +0B +D8 +30 +3C +22 +40 +40 +ENDCHAR +STARTCHAR uni0483 +ENCODING 1155 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 3 -1 10 +BITMAP +08 +F8 +80 +ENDCHAR +STARTCHAR uni0484 +ENCODING 1156 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -1 10 +BITMAP +38 +C8 +ENDCHAR +STARTCHAR uni0485 +ENCODING 1157 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 3 1 9 +BITMAP +C0 +80 +80 +ENDCHAR +STARTCHAR uni0486 +ENCODING 1158 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 3 1 9 +BITMAP +C0 +80 +80 +ENDCHAR +STARTCHAR uni0487 +ENCODING 1159 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 9 3 -3 11 +BITMAP +3C00 +4300 +8180 +ENDCHAR +STARTCHAR uni0488 +ENCODING 1160 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 16 15 -8 -3 +BITMAP +0180 +0240 +700E +5012 +0000 +0000 +E007 +A009 +0000 +0000 +0000 +700E +5012 +0180 +0240 +ENDCHAR +STARTCHAR uni0489 +ENCODING 1161 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 16 17 -8 -3 +BITMAP +0100 +0100 +2180 +2004 +3008 +1000 +0000 +0000 +A006 +6005 +0000 +0008 +100C +2004 +0184 +0100 +0100 +ENDCHAR +STARTCHAR uni048A +ENCODING 1162 +SWIDTH 715 0 +DWIDTH 12 0 +BBX 12 16 1 -2 +BITMAP +0440 +0380 +3030 +3060 +20E0 +21E0 +6360 +6660 +4C40 +5840 +D0C0 +F0C0 +E0C0 +C0C0 +00C0 +0180 +ENDCHAR +STARTCHAR uni048B +ENCODING 1163 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +11 +0E +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +77 +02 +06 +04 +ENDCHAR +STARTCHAR uni048C +ENCODING 1164 +SWIDTH 650 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +3000 +3000 +F800 +2000 +6000 +7F00 +4080 +40C0 +C0C0 +C080 +C180 +FE00 +ENDCHAR +STARTCHAR uni048D +ENCODING 1165 +SWIDTH 525 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +20 +70 +60 +60 +60 +40 +40 +FE +C2 +C2 +86 +FC +ENDCHAR +STARTCHAR uni048E +ENCODING 1166 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3FC0 +3060 +2060 +2060 +6140 +60C0 +7F40 +4000 +C000 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni048F +ENCODING 1167 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3700 +3980 +3180 +2080 +6080 +6180 +6300 +6300 +5D00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni0490 +ENCODING 1168 +SWIDTH 492 0 +DWIDTH 8 0 +BBX 10 14 1 0 +BITMAP +00C0 +0080 +3F80 +3000 +2000 +2000 +6000 +6000 +4000 +4000 +C000 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni0491 +ENCODING 1169 +SWIDTH 339 0 +DWIDTH 6 0 +BBX 6 11 1 0 +BITMAP +04 +04 +7C +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni0492 +ENCODING 1170 +SWIDTH 543 0 +DWIDTH 9 0 +BBX 10 12 1 0 +BITMAP +3FC0 +2000 +2000 +2000 +6000 +FC00 +4000 +4000 +C000 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni0493 +ENCODING 1171 +SWIDTH 377 0 +DWIDTH 6 0 +BBX 6 9 1 0 +BITMAP +7C +60 +40 +F0 +40 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni0494 +ENCODING 1172 +SWIDTH 644 0 +DWIDTH 11 0 +BBX 10 15 1 -3 +BITMAP +3FC0 +2000 +2000 +2000 +6F00 +7180 +40C0 +40C0 +C0C0 +C0C0 +C080 +8180 +0300 +C600 +7C00 +ENDCHAR +STARTCHAR uni0495 +ENCODING 1173 +SWIDTH 525 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +7E +60 +60 +40 +7C +C6 +C3 +83 +82 +06 +8C +F8 +ENDCHAR +STARTCHAR uni0496 +ENCODING 1174 +SWIDTH 916 0 +DWIDTH 16 0 +BBX 17 15 0 -3 +BITMAP +384380 +084600 +08C400 +0CCC00 +04D800 +03E000 +0D9000 +199800 +318800 +610C00 +410400 +C30600 +000600 +000600 +000400 +ENDCHAR +STARTCHAR uni0497 +ENCODING 1175 +SWIDTH 687 0 +DWIDTH 12 0 +BBX 12 12 0 -3 +BITMAP +3330 +1360 +1240 +1AC0 +0F00 +3680 +26C0 +6440 +C460 +0020 +0060 +0040 +ENDCHAR +STARTCHAR uni0498 +ENCODING 1176 +SWIDTH 613 0 +DWIDTH 10 0 +BBX 9 15 1 -3 +BITMAP +0F00 +3180 +2080 +6080 +0180 +0E00 +0300 +0180 +8180 +C100 +4300 +3E00 +0800 +1000 +7000 +ENDCHAR +STARTCHAR uni0499 +ENCODING 1177 +SWIDTH 464 0 +DWIDTH 8 0 +BBX 8 12 0 -3 +BITMAP +1E +23 +03 +02 +1C +06 +C2 +46 +3C +10 +10 +E0 +ENDCHAR +STARTCHAR uni049A +ENCODING 1178 +SWIDTH 589 0 +DWIDTH 10 0 +BBX 10 15 1 -3 +BITMAP +30C0 +3100 +2300 +2200 +6400 +7800 +4C00 +4400 +C600 +C200 +C300 +8300 +0100 +0300 +0300 +ENDCHAR +STARTCHAR uni049B +ENCODING 1179 +SWIDTH 472 0 +DWIDTH 8 0 +BBX 8 12 1 -3 +BITMAP +63 +64 +4C +48 +F0 +D8 +C8 +8C +84 +04 +04 +04 +ENDCHAR +STARTCHAR uni049C +ENCODING 1180 +SWIDTH 589 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +30C0 +3100 +2B00 +2A00 +6C00 +7800 +5C00 +5400 +D600 +D200 +C300 +8300 +ENDCHAR +STARTCHAR uni049D +ENCODING 1181 +SWIDTH 472 0 +DWIDTH 8 0 +BBX 8 9 1 0 +BITMAP +63 +74 +5C +58 +F0 +D8 +E8 +8C +84 +ENDCHAR +STARTCHAR uni049E +ENCODING 1182 +SWIDTH 589 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +30C0 +3100 +FB00 +2200 +6400 +7800 +4C00 +4400 +C600 +C200 +C300 +8300 +ENDCHAR +STARTCHAR uni049F +ENCODING 1183 +SWIDTH 472 0 +DWIDTH 8 0 +BBX 8 12 1 0 +BITMAP +30 +7C +20 +63 +64 +4C +48 +70 +D8 +C8 +8C +84 +ENDCHAR +STARTCHAR uni04A0 +ENCODING 1184 +SWIDTH 742 0 +DWIDTH 13 0 +BBX 12 12 2 0 +BITMAP +F870 +08C0 +1880 +1980 +1B00 +1C00 +3200 +3300 +3180 +2180 +2080 +60C0 +ENDCHAR +STARTCHAR uni04A1 +ENCODING 1185 +SWIDTH 567 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +F180 +1300 +3200 +3600 +3800 +2600 +2600 +6200 +6300 +ENDCHAR +STARTCHAR uni04A2 +ENCODING 1186 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 15 1 -3 +BITMAP +3030 +3030 +2020 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C0C0 +80E0 +0040 +0040 +00C0 +ENDCHAR +STARTCHAR uni04A3 +ENCODING 1187 +SWIDTH 550 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +61 +61 +41 +43 +FF +C2 +C2 +86 +87 +03 +02 +02 +ENDCHAR +STARTCHAR uni04A4 +ENCODING 1188 +SWIDTH 891 0 +DWIDTH 15 0 +BBX 16 12 1 0 +BITMAP +303F +3020 +2020 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C0C0 +8080 +ENDCHAR +STARTCHAR uni04A5 +ENCODING 1189 +SWIDTH 700 0 +DWIDTH 12 0 +BBX 12 9 1 0 +BITMAP +61F0 +6100 +4300 +4300 +FE00 +C200 +C200 +8600 +8600 +ENDCHAR +STARTCHAR uni04A6 +ENCODING 1190 +SWIDTH 1087 0 +DWIDTH 18 0 +BBX 18 15 1 -3 +BITMAP +3FF000 +303000 +202000 +206000 +606F00 +607180 +6040C0 +4040C0 +C0C0C0 +C0C0C0 +C0C180 +808180 +000300 +008600 +007C00 +ENDCHAR +STARTCHAR uni04A7 +ENCODING 1191 +SWIDTH 839 0 +DWIDTH 14 0 +BBX 13 12 1 -3 +BITMAP +7F00 +6100 +4300 +4300 +C3F0 +C218 +C218 +8618 +8618 +0010 +0620 +03C0 +ENDCHAR +STARTCHAR uni04A8 +ENCODING 1192 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +1F00 +31C0 +6360 +6220 +C620 +C620 +C660 +C660 +C640 +46C0 +6380 +3FE0 +ENDCHAR +STARTCHAR uni04A9 +ENCODING 1193 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +38 +6E +CA +9A +92 +92 +96 +DC +7E +ENDCHAR +STARTCHAR uni04AA +ENCODING 1194 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 10 15 2 -3 +BITMAP +1F00 +3080 +60C0 +C040 +C000 +8000 +8000 +8000 +80C0 +C180 +6300 +3E00 +0800 +0800 +7000 +ENDCHAR +STARTCHAR uni04AB +ENCODING 1195 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +1C +62 +43 +C0 +C0 +80 +C6 +C4 +78 +10 +10 +E0 +ENDCHAR +STARTCHAR uni04AC +ENCODING 1196 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 14 2 -2 +BITMAP +FFC0 +0C00 +0800 +0800 +1800 +1800 +1800 +1000 +1000 +3000 +3000 +3800 +1000 +1000 +ENDCHAR +STARTCHAR uni04AD +ENCODING 1197 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 12 1 -3 +BITMAP +6E70 +7398 +6318 +4218 +C210 +C610 +C630 +8630 +8438 +0010 +0010 +0010 +ENDCHAR +STARTCHAR uni04AE +ENCODING 1198 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 2 0 +BITMAP +C180 +C300 +4200 +6600 +2C00 +3800 +3000 +3000 +3000 +2000 +2000 +2000 +ENDCHAR +STARTCHAR uni04AF +ENCODING 1199 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +C1 +43 +42 +44 +64 +68 +78 +30 +30 +20 +60 +60 +ENDCHAR +STARTCHAR uni04B0 +ENCODING 1200 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 12 1 0 +BITMAP +60C0 +2180 +2100 +3300 +1600 +1C00 +FF80 +1800 +1800 +1000 +1000 +1000 +ENDCHAR +STARTCHAR uni04B1 +ENCODING 1201 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +6080 +2180 +2100 +2200 +3200 +3400 +3C00 +1800 +1800 +FE00 +3000 +3000 +ENDCHAR +STARTCHAR uni04B2 +ENCODING 1202 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 13 15 0 -3 +BITMAP +3038 +1070 +18E0 +0DC0 +0D80 +0700 +0600 +0F00 +1900 +3180 +6080 +C0E0 +0040 +0040 +0040 +ENDCHAR +STARTCHAR uni04B3 +ENCODING 1203 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3180 +3300 +1600 +1C00 +0C00 +1C00 +3400 +6600 +C300 +0300 +0200 +0200 +ENDCHAR +STARTCHAR uni04B4 +ENCODING 1204 +SWIDTH 897 0 +DWIDTH 15 0 +BBX 14 14 2 -2 +BITMAP +FFCC +0808 +0808 +1818 +1818 +1818 +1010 +1010 +3030 +3030 +3030 +3FF8 +0010 +0010 +ENDCHAR +STARTCHAR uni04B5 +ENCODING 1205 +SWIDTH 571 0 +DWIDTH 10 0 +BBX 8 14 1 -3 +BITMAP +1F +00 +61 +61 +43 +43 +C3 +C2 +C6 +CE +73 +01 +01 +03 +ENDCHAR +STARTCHAR uni04B6 +ENCODING 1206 +SWIDTH 673 0 +DWIDTH 11 0 +BBX 10 14 2 -2 +BITMAP +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +C380 +7D00 +0100 +0300 +0300 +0380 +0100 +0100 +ENDCHAR +STARTCHAR uni04B7 +ENCODING 1207 +SWIDTH 517 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +43 +43 +C2 +C2 +C2 +7E +06 +04 +06 +02 +06 +04 +ENDCHAR +STARTCHAR uni04B8 +ENCODING 1208 +SWIDTH 673 0 +DWIDTH 11 0 +BBX 10 12 2 0 +BITMAP +40C0 +C0C0 +C080 +C880 +8980 +8980 +CB80 +7D00 +1100 +1300 +0300 +0300 +ENDCHAR +STARTCHAR uni04B9 +ENCODING 1209 +SWIDTH 517 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +43 +C3 +D2 +D2 +D2 +7E +26 +24 +04 +ENDCHAR +STARTCHAR uni04BA +ENCODING 1210 +SWIDTH 673 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +3000 +3000 +3000 +2000 +2F80 +70C0 +6040 +40C0 +40C0 +40C0 +C0C0 +C080 +ENDCHAR +STARTCHAR uni04BB +ENCODING 1211 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +30 +20 +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR uni04BC +ENCODING 1212 +SWIDTH 850 0 +DWIDTH 14 0 +BBX 13 12 1 0 +BITMAP +03E0 +0C30 +1818 +B018 +B018 +FFF8 +2000 +3030 +3020 +3060 +18C0 +0F80 +ENDCHAR +STARTCHAR uni04BD +ENCODING 1213 +SWIDTH 634 0 +DWIDTH 11 0 +BBX 10 9 0 0 +BITMAP +0780 +08C0 +D840 +D040 +7FC0 +3000 +30C0 +1180 +0F00 +ENDCHAR +STARTCHAR uni04BE +ENCODING 1214 +SWIDTH 850 0 +DWIDTH 14 0 +BBX 13 14 1 -2 +BITMAP +03E0 +0C30 +1810 +1018 +B018 +B018 +FFF8 +2000 +3030 +3020 +1840 +0F80 +0200 +0200 +ENDCHAR +STARTCHAR uni04BF +ENCODING 1215 +SWIDTH 634 0 +DWIDTH 11 0 +BBX 10 11 0 -2 +BITMAP +0780 +08C0 +D840 +D040 +7FC0 +3000 +30C0 +1180 +0F00 +0400 +0400 +ENDCHAR +STARTCHAR uni04C0 +ENCODING 1216 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 12 1 0 +BITMAP +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni04C1 +ENCODING 1217 +SWIDTH 916 0 +DWIDTH 16 0 +BBX 17 15 0 0 +BITMAP +009800 +007000 +000000 +384380 +084600 +08C400 +0CCC00 +0CD800 +07E000 +0D9800 +199800 +318C00 +610C00 +410400 +C30600 +ENDCHAR +STARTCHAR uni04C2 +ENCODING 1218 +SWIDTH 687 0 +DWIDTH 12 0 +BBX 12 12 0 0 +BITMAP +04C0 +0380 +0000 +3330 +1360 +1240 +1AC0 +0F00 +3680 +26C0 +6440 +C460 +ENDCHAR +STARTCHAR uni04C3 +ENCODING 1219 +SWIDTH 626 0 +DWIDTH 11 0 +BBX 10 15 1 -3 +BITMAP +30C0 +3100 +2300 +2200 +6400 +7F00 +4180 +4080 +C080 +C080 +C180 +8180 +0300 +C600 +7C00 +ENDCHAR +STARTCHAR uni04C4 +ENCODING 1220 +SWIDTH 519 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3180 +3200 +2600 +2400 +7E00 +6300 +6100 +4100 +4100 +0300 +C600 +7C00 +ENDCHAR +STARTCHAR uni04C5 +ENCODING 1221 +SWIDTH 685 0 +DWIDTH 12 0 +BBX 12 14 0 -2 +BITMAP +0FF0 +0C30 +0830 +0830 +1820 +1860 +1060 +1060 +1040 +3040 +20C0 +E0E0 +0040 +0080 +ENDCHAR +STARTCHAR uni04C6 +ENCODING 1222 +SWIDTH 563 0 +DWIDTH 10 0 +BBX 10 12 0 -3 +BITMAP +1FC0 +1080 +1080 +3180 +3180 +2180 +2100 +6100 +C380 +0100 +0100 +0200 +ENDCHAR +STARTCHAR uni04C7 +ENCODING 1223 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 15 1 -3 +BITMAP +3030 +3020 +2020 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C080 +8080 +0100 +C300 +7C00 +ENDCHAR +STARTCHAR uni04C8 +ENCODING 1224 +SWIDTH 550 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3080 +3080 +2180 +2180 +7F00 +6100 +6100 +4300 +4300 +0200 +C600 +7800 +ENDCHAR +STARTCHAR uni04C9 +ENCODING 1225 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 14 1 -2 +BITMAP +3030 +3030 +2020 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C0C0 +80C0 +00C0 +0080 +ENDCHAR +STARTCHAR uni04CA +ENCODING 1226 +SWIDTH 550 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +61 +61 +43 +43 +FF +C2 +C2 +86 +87 +02 +06 +04 +ENDCHAR +STARTCHAR uni04CB +ENCODING 1227 +SWIDTH 673 0 +DWIDTH 11 0 +BBX 10 14 2 -2 +BITMAP +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +C380 +7D00 +0100 +0300 +0300 +0700 +0400 +0C00 +ENDCHAR +STARTCHAR uni04CC +ENCODING 1228 +SWIDTH 517 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +43 +43 +C2 +C2 +C2 +7E +06 +04 +0C +18 +18 +10 +ENDCHAR +STARTCHAR uni04CD +ENCODING 1229 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 14 14 1 -2 +BITMAP +300C +301C +3838 +2828 +6868 +6858 +4890 +4890 +CD10 +CF30 +C630 +8630 +0030 +0020 +ENDCHAR +STARTCHAR uni04CE +ENCODING 1230 +SWIDTH 685 0 +DWIDTH 12 0 +BBX 11 12 1 -3 +BITMAP +70E0 +70C0 +5140 +5140 +D2C0 +D6C0 +D480 +9C80 +99C0 +0080 +0080 +0100 +ENDCHAR +STARTCHAR uni04CF +ENCODING 1231 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 12 1 0 +BITMAP +20 +20 +60 +60 +60 +40 +40 +C0 +C0 +80 +80 +80 +ENDCHAR +STARTCHAR uni04D0 +ENCODING 1232 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 15 0 0 +BITMAP +0260 +01C0 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni04D1 +ENCODING 1233 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +13 +0E +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni04D2 +ENCODING 1234 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +06C0 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni04D3 +ENCODING 1235 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1B +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni04D4 +ENCODING 1236 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 18 12 0 0 +BITMAP +03FFC0 +026000 +066000 +046000 +0C4000 +187F80 +10C000 +3FC000 +60C000 +408000 +C18000 +81FF00 +ENDCHAR +STARTCHAR uni04D5 +ENCODING 1237 +SWIDTH 889 0 +DWIDTH 15 0 +BBX 14 9 1 0 +BITMAP +3EF0 +6388 +430C +030C +7FFC +C600 +8618 +CF10 +71E0 +ENDCHAR +STARTCHAR uni04D6 +ENCODING 1238 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 15 1 0 +BITMAP +04C0 +0380 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR uni04D7 +ENCODING 1239 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +13 +0E +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR uni018F.dup4 +ENCODING 1240 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +0F00 +30C0 +6040 +4040 +0060 +FFE0 +8060 +80C0 +80C0 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR uni0259.dup5 +ENCODING 1241 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1E +63 +43 +01 +FF +83 +C2 +46 +38 +ENDCHAR +STARTCHAR uni04DA +ENCODING 1242 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 14 2 0 +BITMAP +0D80 +0000 +0F00 +30C0 +6040 +4040 +0060 +FFE0 +8060 +80C0 +80C0 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR uni04DB +ENCODING 1243 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1B +00 +1E +63 +43 +01 +FF +83 +C2 +46 +38 +ENDCHAR +STARTCHAR uni04DC +ENCODING 1244 +SWIDTH 916 0 +DWIDTH 16 0 +BBX 17 14 0 0 +BITMAP +00D800 +000000 +384380 +084600 +08C400 +0CCC00 +0CD800 +07E000 +0D9800 +199800 +318C00 +610C00 +410400 +C30600 +ENDCHAR +STARTCHAR uni04DD +ENCODING 1245 +SWIDTH 687 0 +DWIDTH 12 0 +BBX 12 11 0 0 +BITMAP +06C0 +0000 +3330 +1360 +1240 +1AC0 +0F00 +3680 +26C0 +6440 +C460 +ENDCHAR +STARTCHAR uni04DE +ENCODING 1246 +SWIDTH 613 0 +DWIDTH 10 0 +BBX 9 14 1 0 +BITMAP +0D80 +0000 +0F00 +3180 +2080 +6080 +0180 +0E00 +0300 +0180 +8180 +C100 +4300 +3E00 +ENDCHAR +STARTCHAR uni04DF +ENCODING 1247 +SWIDTH 464 0 +DWIDTH 8 0 +BBX 8 11 0 0 +BITMAP +1B +00 +1E +23 +03 +02 +1C +06 +C2 +46 +3C +ENDCHAR +STARTCHAR uni04E0 +ENCODING 1248 +SWIDTH 613 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +7FC0 +0180 +0300 +0600 +0C00 +0E00 +0300 +0180 +8180 +C100 +4300 +3E00 +ENDCHAR +STARTCHAR uni04E1 +ENCODING 1249 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 10 12 -1 -3 +BITMAP +1FC0 +0180 +0300 +0200 +0600 +0E00 +0300 +0100 +0100 +C100 +4200 +3C00 +ENDCHAR +STARTCHAR uni04E2 +ENCODING 1250 +SWIDTH 715 0 +DWIDTH 12 0 +BBX 12 14 1 0 +BITMAP +07C0 +0000 +3030 +30E0 +20E0 +2160 +6260 +6460 +6440 +48C0 +D0C0 +E0C0 +C080 +C080 +ENDCHAR +STARTCHAR uni04E3 +ENCODING 1251 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1F +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uni04E4 +ENCODING 1252 +SWIDTH 715 0 +DWIDTH 12 0 +BBX 12 14 1 0 +BITMAP +06C0 +0000 +3030 +30E0 +20E0 +2160 +6260 +6460 +6440 +48C0 +D0C0 +E0C0 +C080 +C080 +ENDCHAR +STARTCHAR uni04E5 +ENCODING 1253 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1B +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uni04E6 +ENCODING 1254 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 14 2 0 +BITMAP +0D80 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni04E7 +ENCODING 1255 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1B +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni04E8 +ENCODING 1256 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +1F00 +30C0 +6060 +C060 +C060 +8020 +FFE0 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni04E9 +ENCODING 1257 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +3E +63 +43 +C1 +FF +83 +82 +C6 +78 +ENDCHAR +STARTCHAR uni04EA +ENCODING 1258 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 14 2 0 +BITMAP +0D80 +0000 +1F00 +30C0 +6060 +C060 +C060 +8020 +FFE0 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni04EB +ENCODING 1259 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1B +00 +3E +63 +43 +C1 +FF +83 +82 +C6 +78 +ENDCHAR +STARTCHAR uni04EC +ENCODING 1260 +SWIDTH 693 0 +DWIDTH 12 0 +BBX 11 14 1 0 +BITMAP +0D80 +0000 +0F00 +30C0 +6040 +4060 +0060 +07E0 +0060 +80C0 +C0C0 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR uni04ED +ENCODING 1261 +SWIDTH 491 0 +DWIDTH 8 0 +BBX 8 11 0 0 +BITMAP +1B +00 +1E +33 +61 +01 +0F +03 +C2 +46 +3C +ENDCHAR +STARTCHAR uni04EE +ENCODING 1262 +SWIDTH 639 0 +DWIDTH 11 0 +BBX 10 14 2 0 +BITMAP +1F00 +0000 +C040 +40C0 +4080 +6180 +2300 +3200 +3600 +1400 +1800 +1800 +3000 +E000 +ENDCHAR +STARTCHAR uni04EF +ENCODING 1263 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 14 0 -3 +BITMAP +0F80 +0000 +2080 +2180 +2100 +3300 +3600 +3400 +1C00 +1800 +1800 +1000 +2000 +E000 +ENDCHAR +STARTCHAR uni04F0 +ENCODING 1264 +SWIDTH 639 0 +DWIDTH 11 0 +BBX 10 14 2 0 +BITMAP +1B00 +0000 +C040 +40C0 +4080 +6180 +2300 +3200 +3600 +1400 +1800 +1800 +3000 +E000 +ENDCHAR +STARTCHAR uni04F1 +ENCODING 1265 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 14 0 -3 +BITMAP +0D80 +0000 +2080 +2180 +2100 +3300 +3600 +3400 +1C00 +1800 +1800 +1000 +2000 +E000 +ENDCHAR +STARTCHAR uni04F2 +ENCODING 1266 +SWIDTH 639 0 +DWIDTH 11 0 +BBX 10 16 2 0 +BITMAP +0D00 +1B00 +1200 +0000 +C040 +40C0 +4080 +6180 +2300 +3200 +3600 +1400 +1800 +1800 +3000 +E000 +ENDCHAR +STARTCHAR uni04F3 +ENCODING 1267 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0680 +0D80 +0900 +0000 +2080 +2180 +2100 +3300 +3600 +3400 +1C00 +1800 +1800 +1000 +2000 +E000 +ENDCHAR +STARTCHAR uni04F4 +ENCODING 1268 +SWIDTH 673 0 +DWIDTH 11 0 +BBX 10 14 2 0 +BITMAP +1B00 +0000 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +C380 +7F00 +0100 +0300 +0300 +0300 +ENDCHAR +STARTCHAR uni04F5 +ENCODING 1269 +SWIDTH 517 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +36 +00 +43 +43 +C2 +C2 +C2 +7E +06 +04 +04 +ENDCHAR +STARTCHAR uni04F6 +ENCODING 1270 +SWIDTH 543 0 +DWIDTH 9 0 +BBX 10 14 1 -2 +BITMAP +3FC0 +3000 +2000 +2000 +6000 +6000 +6000 +4000 +C000 +C000 +C000 +E000 +4000 +4000 +ENDCHAR +STARTCHAR uni04F7 +ENCODING 1271 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 11 1 -2 +BITMAP +3C +62 +42 +0E +38 +E0 +82 +86 +7E +04 +04 +ENDCHAR +STARTCHAR uni04F8 +ENCODING 1272 +SWIDTH 886 0 +DWIDTH 15 0 +BBX 15 14 1 0 +BITMAP +0360 +0000 +3006 +3004 +2004 +200C +600C +6008 +7F08 +4098 +C0D8 +C098 +C190 +FF10 +ENDCHAR +STARTCHAR uni04F9 +ENCODING 1273 +SWIDTH 735 0 +DWIDTH 13 0 +BBX 12 11 1 0 +BITMAP +0D80 +0000 +6030 +6020 +4020 +4060 +FE60 +C240 +C240 +8640 +FCC0 +ENDCHAR +STARTCHAR uni04FA +ENCODING 1274 +SWIDTH 543 0 +DWIDTH 9 0 +BBX 12 15 -1 -3 +BITMAP +0FF0 +0C00 +0800 +0800 +1800 +1800 +3F00 +1000 +1000 +3000 +3000 +3000 +3000 +3000 +E000 +ENDCHAR +STARTCHAR uni04FB +ENCODING 1275 +SWIDTH 377 0 +DWIDTH 6 0 +BBX 8 12 -1 -3 +BITMAP +1F +18 +10 +10 +3C +30 +30 +20 +30 +30 +20 +C0 +ENDCHAR +STARTCHAR uni04FC +ENCODING 1276 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 13 15 0 -3 +BITMAP +3038 +1830 +1860 +0CC0 +0D80 +0700 +0600 +0F00 +1980 +3180 +60C0 +C040 +0040 +0040 +0380 +ENDCHAR +STARTCHAR uni04FD +ENCODING 1277 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3180 +3300 +1E00 +1C00 +0C00 +1C00 +3400 +6600 +C200 +0300 +0200 +0E00 +ENDCHAR +STARTCHAR uni04FE +ENCODING 1278 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 13 12 0 0 +BITMAP +3038 +1030 +1860 +0CC0 +0D80 +0700 +3FC0 +0F00 +1900 +3180 +60C0 +C0C0 +ENDCHAR +STARTCHAR uni04FF +ENCODING 1279 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +3180 +3300 +1600 +1C00 +7F00 +1C00 +3400 +6600 +C200 +ENDCHAR +STARTCHAR uni0500 +ENCODING 1280 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +0060 +0040 +0040 +00C0 +00C0 +3FC0 +6080 +C080 +8180 +8180 +C180 +7F00 +ENDCHAR +STARTCHAR uni0501 +ENCODING 1281 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +0080 +0180 +0180 +3D00 +6500 +4300 +C300 +8300 +8200 +C600 +C600 +7E00 +ENDCHAR +STARTCHAR uni0502 +ENCODING 1282 +SWIDTH 951 0 +DWIDTH 16 0 +BBX 15 12 1 0 +BITMAP +0060 +0040 +0040 +00C0 +00C0 +3FC2 +6086 +C086 +8184 +8184 +C38C +7EF0 +ENDCHAR +STARTCHAR uni0503 +ENCODING 1283 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 12 1 0 +BITMAP +0080 +0180 +0180 +3D00 +6300 +4300 +C300 +8308 +8218 +C618 +C730 +79E0 +ENDCHAR +STARTCHAR uni0504 +ENCODING 1284 +SWIDTH 937 0 +DWIDTH 16 0 +BBX 14 12 2 0 +BITMAP +1E00 +6300 +4100 +C100 +0300 +1C0C +060C +0308 +0308 +0318 +0310 +01E0 +ENDCHAR +STARTCHAR uni0505 +ENCODING 1285 +SWIDTH 763 0 +DWIDTH 13 0 +BBX 11 9 2 0 +BITMAP +7800 +CC00 +8C00 +0800 +7060 +1860 +0840 +0CC0 +0780 +ENDCHAR +STARTCHAR uni0506 +ENCODING 1286 +SWIDTH 613 0 +DWIDTH 10 0 +BBX 8 14 2 -2 +BITMAP +1E +63 +41 +C1 +03 +1C +06 +03 +03 +03 +02 +07 +01 +03 +ENDCHAR +STARTCHAR uni0507 +ENCODING 1287 +SWIDTH 464 0 +DWIDTH 8 0 +BBX 6 12 2 -3 +BITMAP +78 +CC +8C +08 +70 +18 +08 +18 +1C +0C +08 +08 +ENDCHAR +STARTCHAR uni0508 +ENCODING 1288 +SWIDTH 980 0 +DWIDTH 17 0 +BBX 17 12 0 0 +BITMAP +0FF000 +0C3000 +083000 +083000 +182000 +186180 +106100 +106100 +104300 +304300 +206600 +E03C00 +ENDCHAR +STARTCHAR uni0509 +ENCODING 1289 +SWIDTH 845 0 +DWIDTH 14 0 +BBX 14 9 0 0 +BITMAP +1FC0 +1080 +1080 +3180 +3184 +2184 +210C +6188 +C0F0 +ENDCHAR +STARTCHAR uni050A +ENCODING 1290 +SWIDTH 1012 0 +DWIDTH 17 0 +BBX 16 12 1 0 +BITMAP +3030 +3020 +2020 +2060 +6060 +7FE1 +4043 +4043 +C0C3 +C0C2 +C046 +803C +ENDCHAR +STARTCHAR uni050B +ENCODING 1291 +SWIDTH 830 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +6100 +6100 +4300 +4300 +FF08 +C218 +C218 +8330 +81E0 +ENDCHAR +STARTCHAR uni050C +ENCODING 1292 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +0F80 +30C0 +6060 +4060 +C000 +8000 +87C0 +8040 +80C0 +C080 +6180 +3E00 +ENDCHAR +STARTCHAR uni050D +ENCODING 1293 +SWIDTH 550 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1E +61 +40 +C0 +8F +83 +82 +C6 +7C +ENDCHAR +STARTCHAR uni050E +ENCODING 1294 +SWIDTH 732 0 +DWIDTH 12 0 +BBX 10 12 2 0 +BITMAP +FFC0 +0C00 +0800 +0800 +1800 +1840 +1840 +1040 +10C0 +1080 +1180 +0F00 +ENDCHAR +STARTCHAR uni050F +ENCODING 1295 +SWIDTH 1114 0 +DWIDTH 19 0 +BBX 18 9 1 0 +BITMAP +6E7000 +739800 +631800 +421800 +C210C0 +C610C0 +C61080 +861180 +840F00 +ENDCHAR +STARTCHAR uni0510 +ENCODING 1296 +SWIDTH 613 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +0F00 +3080 +20C0 +20C0 +3000 +3C00 +6000 +C000 +C180 +C100 +C600 +7C00 +ENDCHAR +STARTCHAR uni0511 +ENCODING 1297 +SWIDTH 439 0 +DWIDTH 7 0 +BBX 6 9 1 0 +BITMAP +3C +64 +40 +60 +70 +C0 +80 +88 +78 +ENDCHAR +STARTCHAR uni0512 +ENCODING 1298 +SWIDTH 685 0 +DWIDTH 12 0 +BBX 12 15 0 -3 +BITMAP +0FF0 +0830 +0830 +0820 +1820 +1860 +1060 +1060 +3040 +3040 +20C0 +C0C0 +0080 +0080 +0300 +ENDCHAR +STARTCHAR uni0513 +ENCODING 1299 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 10 12 0 -3 +BITMAP +1FC0 +1080 +1080 +3180 +3180 +2180 +2100 +6100 +C300 +0300 +0200 +0C00 +ENDCHAR +STARTCHAR uni0514 +ENCODING 1300 +SWIDTH 965 0 +DWIDTH 16 0 +BBX 18 12 0 0 +BITMAP +0FC0C0 +0C4180 +086300 +082600 +083C00 +181800 +183800 +106800 +10CC00 +318400 +330600 +E60200 +ENDCHAR +STARTCHAR uni0515 +ENCODING 1301 +SWIDTH 753 0 +DWIDTH 13 0 +BBX 13 9 0 0 +BITMAP +1F18 +1130 +11A0 +30E0 +30C0 +21C0 +2360 +6220 +C630 +ENDCHAR +STARTCHAR uni0516 +ENCODING 1302 +SWIDTH 828 0 +DWIDTH 14 0 +BBX 14 12 1 0 +BITMAP +3F1C +31B8 +21E0 +21C0 +6180 +6300 +7D80 +4080 +C0C0 +C040 +C060 +8020 +ENDCHAR +STARTCHAR uni0517 +ENCODING 1303 +SWIDTH 716 0 +DWIDTH 12 0 +BBX 13 12 0 -3 +BITMAP +3718 +39B0 +30E0 +20C0 +60C0 +61C0 +6140 +6360 +5E20 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni0518 +ENCODING 1304 +SWIDTH 950 0 +DWIDTH 16 0 +BBX 17 12 0 0 +BITMAP +0FFF80 +186000 +306000 +306000 +304000 +1FFE00 +0CC000 +18C000 +308000 +708000 +618000 +C1FE00 +ENDCHAR +STARTCHAR uni0519 +ENCODING 1305 +SWIDTH 893 0 +DWIDTH 15 0 +BBX 15 9 0 0 +BITMAP +1FB8 +21C4 +6186 +2186 +3FFE +3100 +2104 +6188 +C0F0 +ENDCHAR +STARTCHAR uni051A +ENCODING 1306 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 13 2 -1 +BITMAP +1F00 +30C0 +6060 +C060 +C020 +8020 +8060 +8060 +8040 +C4C0 +6380 +3F80 +00C0 +ENDCHAR +STARTCHAR uni051B +ENCODING 1307 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +3D +67 +43 +C3 +82 +82 +86 +C6 +7E +04 +04 +0C +ENDCHAR +STARTCHAR uni051C +ENCODING 1308 +SWIDTH 943 0 +DWIDTH 16 0 +BBX 16 12 2 0 +BITMAP +C183 +C182 +C386 +C684 +C68C +CC88 +4898 +5890 +50B0 +70A0 +60E0 +60C0 +ENDCHAR +STARTCHAR uni051D +ENCODING 1309 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 9 1 0 +BITMAP +C630 +C620 +4E20 +4A60 +4A40 +52C0 +5280 +6280 +6300 +ENDCHAR +STARTCHAR uni051E +ENCODING 1310 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3260 +31C0 +2380 +2780 +6C40 +7C00 +7600 +6200 +C300 +C180 +C180 +80C0 +ENDCHAR +STARTCHAR uni051F +ENCODING 1311 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +6B +66 +5E +72 +F0 +D8 +CC +8C +86 +ENDCHAR +STARTCHAR uni0520 +ENCODING 1312 +SWIDTH 1068 0 +DWIDTH 18 0 +BBX 18 15 0 -3 +BITMAP +0FF000 +0C3000 +083000 +082000 +182F80 +1870C0 +106040 +106040 +1040C0 +3040C0 +20C0C0 +E0C080 +000080 +000180 +000700 +ENDCHAR +STARTCHAR uni0521 +ENCODING 1313 +SWIDTH 846 0 +DWIDTH 14 0 +BBX 14 12 0 -3 +BITMAP +1FC0 +1080 +1080 +31F8 +318C +210C +210C +610C +C308 +0008 +0018 +0070 +ENDCHAR +STARTCHAR uni0522 +ENCODING 1314 +SWIDTH 1100 0 +DWIDTH 19 0 +BBX 18 15 1 -3 +BITMAP +303000 +302000 +202000 +206000 +607F00 +7FE080 +4040C0 +4040C0 +C0C0C0 +C0C080 +C0C180 +808180 +000180 +000100 +000700 +ENDCHAR +STARTCHAR uni0523 +ENCODING 1315 +SWIDTH 830 0 +DWIDTH 14 0 +BBX 13 12 1 -3 +BITMAP +6100 +6100 +4300 +43F0 +FE18 +C218 +C210 +8610 +8610 +0030 +0020 +00E0 +ENDCHAR +STARTCHAR uni0524 +ENCODING 1316 +SWIDTH 724 0 +DWIDTH 12 0 +BBX 12 14 1 -2 +BITMAP +3FF0 +3030 +2020 +2060 +6060 +6060 +6040 +4040 +C0C0 +C0C0 +C0C0 +80E0 +0040 +0040 +ENDCHAR +STARTCHAR uni0525 +ENCODING 1317 +SWIDTH 550 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +7F +61 +43 +43 +C3 +C2 +C2 +86 +87 +02 +02 +02 +ENDCHAR +STARTCHAR uni0526 +ENCODING 1318 +SWIDTH 673 0 +DWIDTH 11 0 +BBX 10 14 1 -2 +BITMAP +3000 +3000 +2000 +2000 +6F80 +70C0 +40C0 +40C0 +C0C0 +C0C0 +C080 +81C0 +0040 +00C0 +ENDCHAR +STARTCHAR uni0527 +ENCODING 1319 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +30 +20 +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +87 +02 +02 +02 +ENDCHAR +STARTCHAR uni0528 +ENCODING 1320 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 15 15 -2 -3 +BITMAP +0606 +0604 +0404 +040C +0C0C +0FFC +0808 +0808 +1818 +1818 +1818 +1010 +1000 +3000 +E000 +ENDCHAR +STARTCHAR uni0529 +ENCODING 1321 +SWIDTH 550 0 +DWIDTH 9 0 +BBX 11 12 -2 -3 +BITMAP +0C20 +0C20 +0860 +0860 +1FE0 +1840 +1840 +10C0 +10C0 +3000 +3000 +E000 +ENDCHAR +STARTCHAR uni052A +ENCODING 1322 +SWIDTH 1284 0 +DWIDTH 22 0 +BBX 23 14 -1 -2 +BITMAP +07F106 +06130C +043318 +043330 +0C32C0 +0C3FE0 +082730 +086630 +186618 +106418 +30440C +7FEC0C +C06000 +806000 +ENDCHAR +STARTCHAR uni052B +ENCODING 1323 +SWIDTH 1016 0 +DWIDTH 17 0 +BBX 17 12 1 0 +BITMAP +1E0000 +030000 +010000 +1D1180 +633200 +413600 +C12400 +81F800 +832C00 +826600 +C66600 +7C4200 +ENDCHAR +STARTCHAR uni052C +ENCODING 1324 +SWIDTH 729 0 +DWIDTH 12 0 +BBX 14 14 -1 -2 +BITMAP +040C +0C1C +0C38 +0C68 +08D8 +0998 +0F38 +07D0 +0C10 +1830 +3030 +FFF8 +C010 +8010 +ENDCHAR +STARTCHAR uni052D +ENCODING 1325 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 12 -1 -3 +BITMAP +1840 +18C0 +1940 +12C0 +1CC0 +0F80 +1080 +2080 +FFC0 +80C0 +8080 +8080 +ENDCHAR +STARTCHAR uni052E +ENCODING 1326 +SWIDTH 685 0 +DWIDTH 12 0 +BBX 12 14 0 -2 +BITMAP +0FF0 +0C30 +0830 +0830 +1820 +1860 +1060 +1060 +1040 +3040 +20C0 +E0E0 +0060 +0040 +ENDCHAR +STARTCHAR uni052F +ENCODING 1327 +SWIDTH 563 0 +DWIDTH 10 0 +BBX 10 12 0 -3 +BITMAP +1FC0 +1080 +1080 +3180 +3180 +2180 +2100 +6100 +C380 +0180 +0180 +0100 +ENDCHAR +STARTCHAR uni0531 +ENCODING 1329 +SWIDTH 751 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +6060 +6060 +4040 +4040 +C0C0 +C0C0 +C0C0 +8080 +8480 +8780 +C380 +3C80 +ENDCHAR +STARTCHAR uni0532 +ENCODING 1330 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +0F80 +1840 +3060 +2060 +6060 +6060 +6000 +4000 +7FC0 +C000 +C000 +C000 +ENDCHAR +STARTCHAR uni0533 +ENCODING 1331 +SWIDTH 715 0 +DWIDTH 12 0 +BBX 10 12 2 0 +BITMAP +3E00 +6180 +C080 +C080 +8080 +8180 +8180 +C180 +7FC0 +0300 +0300 +0300 +ENDCHAR +STARTCHAR uni0534 +ENCODING 1332 +SWIDTH 704 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +1F00 +30C0 +60C0 +6040 +40C0 +C0C0 +00C0 +0080 +00E0 +0180 +0180 +0180 +ENDCHAR +STARTCHAR uni0535 +ENCODING 1333 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 10 12 2 0 +BITMAP +6000 +6000 +4000 +7FC0 +C000 +C000 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni0536 +ENCODING 1334 +SWIDTH 725 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +0F80 +18C0 +3060 +2060 +6060 +0060 +0040 +00C0 +0180 +C300 +CE00 +FF80 +ENDCHAR +STARTCHAR uni0537 +ENCODING 1335 +SWIDTH 634 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +3000 +3000 +2000 +3FC0 +6000 +6000 +6000 +4000 +4000 +C000 +C000 +FF00 +ENDCHAR +STARTCHAR uni0538 +ENCODING 1336 +SWIDTH 721 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +0F80 +1840 +3060 +2060 +6060 +6060 +6000 +4000 +4000 +C000 +C000 +FFC0 +ENDCHAR +STARTCHAR uni0539 +ENCODING 1337 +SWIDTH 807 0 +DWIDTH 14 0 +BBX 13 12 1 0 +BITMAP +07C0 +1860 +3030 +2030 +6030 +63F8 +6420 +4C20 +4C60 +CC60 +CC40 +C780 +ENDCHAR +STARTCHAR uni053A +ENCODING 1338 +SWIDTH 715 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +0060 +0060 +0060 +1FF0 +60C0 +40C0 +C0C0 +C0C0 +C080 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR uni053B +ENCODING 1339 +SWIDTH 660 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +3000 +3000 +3000 +2F00 +70C0 +60C0 +6040 +40C0 +40C0 +C000 +C000 +C000 +ENDCHAR +STARTCHAR uni053C +ENCODING 1340 +SWIDTH 527 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +30 +30 +20 +60 +60 +60 +60 +40 +C0 +C0 +C0 +FF +ENDCHAR +STARTCHAR uni053D +ENCODING 1341 +SWIDTH 916 0 +DWIDTH 16 0 +BBX 15 12 1 0 +BITMAP +3000 +3000 +2000 +3F06 +6204 +620C +660C +460C +4608 +C618 +C210 +C1E0 +ENDCHAR +STARTCHAR uni053E +ENCODING 1342 +SWIDTH 758 0 +DWIDTH 13 0 +BBX 12 12 2 0 +BITMAP +63F0 +6E00 +7F00 +6180 +40C0 +C0C0 +8040 +80C0 +80C0 +8180 +C300 +3E00 +ENDCHAR +STARTCHAR uni053F +ENCODING 1343 +SWIDTH 698 0 +DWIDTH 12 0 +BBX 10 12 2 0 +BITMAP +6000 +6000 +4000 +40C0 +C0C0 +C080 +C180 +4380 +3F80 +0180 +0100 +0100 +ENDCHAR +STARTCHAR uni0540 +ENCODING 1344 +SWIDTH 598 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +3F00 +0180 +0180 +0180 +0300 +FE00 +0300 +0100 +0300 +0300 +0300 +0200 +ENDCHAR +STARTCHAR uni0541 +ENCODING 1345 +SWIDTH 706 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +0F80 +18C0 +3060 +6060 +6060 +0060 +0040 +00C0 +7D80 +C700 +C780 +7980 +ENDCHAR +STARTCHAR uni0542 +ENCODING 1346 +SWIDTH 705 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +1F00 +30C0 +60C0 +6040 +40C0 +C0C0 +00C0 +0080 +0080 +0180 +0180 +01E0 +ENDCHAR +STARTCHAR uni0543 +ENCODING 1347 +SWIDTH 713 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +01F0 +0700 +3E00 +1B00 +3180 +20C0 +60C0 +60C0 +40C0 +C0C0 +C080 +FF80 +ENDCHAR +STARTCHAR uni0544 +ENCODING 1348 +SWIDTH 752 0 +DWIDTH 13 0 +BBX 13 12 2 0 +BITMAP +6078 +6040 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni0545 +ENCODING 1349 +SWIDTH 716 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +0F80 +18C0 +3060 +0060 +00C0 +7F80 +00C0 +0040 +C040 +C0C0 +6180 +3F00 +ENDCHAR +STARTCHAR uni0546 +ENCODING 1350 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 10 12 2 0 +BITMAP +E000 +2000 +6000 +6000 +6000 +4000 +C0C0 +C0C0 +C080 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR uni0547 +ENCODING 1351 +SWIDTH 692 0 +DWIDTH 12 0 +BBX 10 12 1 0 +BITMAP +3C00 +0700 +1FC0 +3000 +6000 +6000 +C000 +C0C0 +C0C0 +4080 +6180 +3E00 +ENDCHAR +STARTCHAR uni0548 +ENCODING 1352 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +0F80 +1840 +3060 +2060 +6060 +6060 +6040 +4040 +40C0 +C0C0 +C0C0 +C080 +ENDCHAR +STARTCHAR uni0549 +ENCODING 1353 +SWIDTH 699 0 +DWIDTH 12 0 +BBX 10 12 2 0 +BITMAP +1F00 +3180 +40C0 +C0C0 +C0C0 +0080 +0180 +0300 +CE00 +7800 +1C00 +0400 +ENDCHAR +STARTCHAR uni054A +ENCODING 1354 +SWIDTH 801 0 +DWIDTH 14 0 +BBX 11 12 2 0 +BITMAP +1F80 +6660 +C660 +8420 +8420 +0C60 +0C60 +0C60 +0040 +00C0 +00C0 +00C0 +ENDCHAR +STARTCHAR uni054B +ENCODING 1355 +SWIDTH 746 0 +DWIDTH 13 0 +BBX 11 12 1 0 +BITMAP +07C0 +1860 +3020 +2020 +6020 +6020 +7C60 +0640 +03C0 +0380 +CE00 +FFC0 +ENDCHAR +STARTCHAR uni054C +ENCODING 1356 +SWIDTH 761 0 +DWIDTH 13 0 +BBX 12 12 1 0 +BITMAP +0F80 +1840 +3060 +2060 +6060 +6060 +6060 +4040 +40F0 +C0C0 +C0C0 +C080 +ENDCHAR +STARTCHAR uni054D +ENCODING 1357 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 2 0 +BITMAP +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni054E +ENCODING 1358 +SWIDTH 688 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +0060 +0040 +0040 +40C0 +C0C0 +C0C0 +4180 +6380 +3F80 +0180 +0180 +01C0 +ENDCHAR +STARTCHAR uni054F +ENCODING 1359 +SWIDTH 659 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +1F80 +30C0 +2040 +2000 +3000 +1E00 +0780 +0180 +C0C0 +C080 +6180 +3E00 +ENDCHAR +STARTCHAR uni0550 +ENCODING 1360 +SWIDTH 675 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +0F80 +1840 +3060 +2060 +6060 +6060 +6000 +4000 +4000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR uni0551 +ENCODING 1361 +SWIDTH 677 0 +DWIDTH 12 0 +BBX 10 12 1 0 +BITMAP +0F80 +18C0 +3040 +3040 +30C0 +7F80 +00C0 +00C0 +C0C0 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni0552 +ENCODING 1362 +SWIDTH 515 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +3000 +3000 +2000 +3F80 +6000 +6000 +6000 +4000 +4000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR uni0553 +ENCODING 1363 +SWIDTH 761 0 +DWIDTH 13 0 +BBX 12 12 1 0 +BITMAP +0100 +0FC0 +3360 +6230 +4230 +C630 +C630 +4620 +66C0 +3F80 +0C00 +0C00 +ENDCHAR +STARTCHAR uni0554 +ENCODING 1364 +SWIDTH 686 0 +DWIDTH 12 0 +BBX 12 12 0 0 +BITMAP +07C0 +0C60 +1820 +1830 +1020 +3060 +38C0 +3F80 +2000 +2000 +FFC0 +6000 +ENDCHAR +STARTCHAR uni0555 +ENCODING 1365 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni0556 +ENCODING 1366 +SWIDTH 787 0 +DWIDTH 13 0 +BBX 12 12 1 0 +BITMAP +0F00 +1300 +1300 +1FC0 +0260 +0630 +0630 +C630 +C620 +C460 +64C0 +3F00 +ENDCHAR +STARTCHAR uni0559 +ENCODING 1369 +SWIDTH 273 0 +DWIDTH 5 0 +BBX 2 4 3 8 +BITMAP +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni055A +ENCODING 1370 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 4 2 8 +BITMAP +60 +40 +40 +80 +ENDCHAR +STARTCHAR uni055B +ENCODING 1371 +SWIDTH 183 0 +DWIDTH 3 0 +BBX 3 3 1 10 +BITMAP +60 +C0 +80 +ENDCHAR +STARTCHAR uni055C +ENCODING 1372 +SWIDTH 200 0 +DWIDTH 3 0 +BBX 3 3 1 10 +BITMAP +20 +E0 +80 +ENDCHAR +STARTCHAR uni055D +ENCODING 1373 +SWIDTH 265 0 +DWIDTH 5 0 +BBX 2 4 3 9 +BITMAP +80 +C0 +C0 +40 +ENDCHAR +STARTCHAR uni055E +ENCODING 1374 +SWIDTH 231 0 +DWIDTH 4 0 +BBX 4 3 1 10 +BITMAP +70 +A0 +80 +ENDCHAR +STARTCHAR uni055F +ENCODING 1375 +SWIDTH 513 0 +DWIDTH 9 0 +BBX 8 3 3 13 +BITMAP +80 +80 +FF +ENDCHAR +STARTCHAR uni0561 +ENCODING 1377 +SWIDTH 837 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +6308 +6318 +4318 +4218 +C210 +C610 +C630 +CE70 +73B0 +ENDCHAR +STARTCHAR uni0562 +ENCODING 1378 +SWIDTH 558 0 +DWIDTH 10 0 +BBX 9 12 0 -3 +BITMAP +3700 +3980 +3180 +2180 +6180 +6100 +6000 +4000 +7F00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni0563 +ENCODING 1379 +SWIDTH 579 0 +DWIDTH 10 0 +BBX 8 12 1 -3 +BITMAP +3D +63 +43 +C3 +83 +82 +86 +C6 +7F +04 +04 +0C +ENDCHAR +STARTCHAR uni0564 +ENCODING 1380 +SWIDTH 578 0 +DWIDTH 10 0 +BBX 8 12 1 -3 +BITMAP +6E +73 +63 +43 +C3 +C2 +C2 +86 +87 +06 +04 +04 +ENDCHAR +STARTCHAR uni0565 +ENCODING 1381 +SWIDTH 561 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +2000 +2000 +2000 +7F80 +6000 +4000 +4300 +C300 +C200 +C600 +CE00 +7600 +ENDCHAR +STARTCHAR uni0566 +ENCODING 1382 +SWIDTH 579 0 +DWIDTH 10 0 +BBX 8 12 1 -3 +BITMAP +3D +63 +43 +C3 +82 +82 +86 +C6 +7E +04 +04 +0F +ENDCHAR +STARTCHAR uni0567 +ENCODING 1383 +SWIDTH 515 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +3000 +2000 +2000 +7F80 +6000 +4000 +4000 +4000 +C000 +C000 +8000 +FC00 +ENDCHAR +STARTCHAR uni0568 +ENCODING 1384 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3700 +3980 +3180 +2180 +6180 +6100 +6100 +4300 +4300 +C000 +C000 +FE00 +ENDCHAR +STARTCHAR uni0569 +ENCODING 1385 +SWIDTH 696 0 +DWIDTH 12 0 +BBX 12 12 0 -3 +BITMAP +3780 +3840 +3060 +2060 +67F0 +6C40 +6C40 +4CC0 +4700 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni056A +ENCODING 1386 +SWIDTH 590 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +0080 +0180 +0180 +1FC0 +6100 +4100 +C300 +8300 +8200 +8600 +C400 +7800 +ENDCHAR +STARTCHAR uni056B +ENCODING 1387 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 15 0 -3 +BITMAP +1800 +1000 +1000 +3700 +3980 +3180 +2180 +6180 +6100 +6100 +4300 +4300 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni056C +ENCODING 1388 +SWIDTH 233 0 +DWIDTH 4 0 +BBX 4 12 0 -3 +BITMAP +30 +30 +20 +20 +60 +60 +60 +40 +40 +C0 +C0 +F0 +ENDCHAR +STARTCHAR uni056D +ENCODING 1389 +SWIDTH 839 0 +DWIDTH 14 0 +BBX 14 15 0 -3 +BITMAP +1800 +1000 +1000 +3704 +398C +318C +210C +6108 +6308 +6318 +4338 +41D8 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni056E +ENCODING 1390 +SWIDTH 562 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +1800 +3000 +1800 +1F80 +6200 +4300 +C300 +8300 +8200 +8600 +C400 +7800 +ENDCHAR +STARTCHAR uni056F +ENCODING 1391 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +30 +20 +20 +61 +61 +43 +43 +C3 +C2 +C6 +CE +76 +04 +04 +04 +ENDCHAR +STARTCHAR uni0570 +ENCODING 1392 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +30 +20 +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR uni0571 +ENCODING 1393 +SWIDTH 522 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +0C +18 +18 +0C +1C +26 +42 +C2 +82 +86 +8E +F4 +ENDCHAR +STARTCHAR uni0572 +ENCODING 1394 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +06 +04 +07 +ENDCHAR +STARTCHAR uni0573 +ENCODING 1395 +SWIDTH 547 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +0380 +0C00 +1800 +7800 +2600 +6200 +4300 +C300 +C200 +8600 +CA00 +7600 +ENDCHAR +STARTCHAR uni0574 +ENCODING 1396 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 11 12 1 0 +BITMAP +00E0 +0180 +0180 +6100 +6100 +4100 +4300 +C300 +C200 +C600 +CE00 +7600 +ENDCHAR +STARTCHAR uni0575 +ENCODING 1397 +SWIDTH 228 0 +DWIDTH 4 0 +BBX 6 12 -2 -3 +BITMAP +0C +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +E0 +ENDCHAR +STARTCHAR uni0576 +ENCODING 1398 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +F0 +20 +20 +61 +61 +43 +43 +C3 +C2 +C6 +CE +76 +ENDCHAR +STARTCHAR uni0577 +ENCODING 1399 +SWIDTH 481 0 +DWIDTH 8 0 +BBX 9 12 -1 -3 +BITMAP +0F00 +1180 +3080 +0180 +0180 +0300 +0600 +0C00 +3000 +6000 +C000 +7E00 +ENDCHAR +STARTCHAR uni0578 +ENCODING 1400 +SWIDTH 550 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR uni0579 +ENCODING 1401 +SWIDTH 351 0 +DWIDTH 6 0 +BBX 7 12 -1 -3 +BITMAP +10 +10 +30 +30 +18 +0E +0C +18 +30 +60 +C0 +78 +ENDCHAR +STARTCHAR uni057A +ENCODING 1402 +SWIDTH 837 0 +DWIDTH 14 0 +BBX 13 12 1 -3 +BITMAP +6308 +6318 +4318 +4218 +C210 +C610 +C630 +CE70 +73A0 +0020 +0020 +0060 +ENDCHAR +STARTCHAR uni057B +ENCODING 1403 +SWIDTH 522 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +1E00 +3100 +2180 +6180 +2100 +3300 +3600 +2800 +3000 +6000 +8000 +FE00 +ENDCHAR +STARTCHAR uni057C +ENCODING 1404 +SWIDTH 575 0 +DWIDTH 10 0 +BBX 8 9 1 0 +BITMAP +6E +73 +61 +43 +C3 +C2 +C6 +8C +8F +ENDCHAR +STARTCHAR uni057D +ENCODING 1405 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uni057E +ENCODING 1406 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 15 1 -3 +BITMAP +0080 +0180 +0180 +6100 +6100 +4100 +4300 +C300 +C200 +C600 +CE00 +7600 +0600 +0400 +0700 +ENDCHAR +STARTCHAR uni057F +ENCODING 1407 +SWIDTH 836 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +6370 +6398 +4318 +4218 +C210 +C610 +C630 +CE30 +7430 +ENDCHAR +STARTCHAR uni0580 +ENCODING 1408 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3700 +3980 +3180 +2180 +6180 +6100 +6100 +4300 +4300 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni0581 +ENCODING 1409 +SWIDTH 551 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +1E80 +3180 +2180 +6180 +4100 +4100 +4300 +6700 +3F00 +0200 +C600 +7C00 +ENDCHAR +STARTCHAR uni0582 +ENCODING 1410 +SWIDTH 391 0 +DWIDTH 7 0 +BBX 5 9 1 0 +BITMAP +60 +60 +40 +40 +C0 +C0 +C0 +80 +F8 +ENDCHAR +STARTCHAR uni0583 +ENCODING 1411 +SWIDTH 836 0 +DWIDTH 14 0 +BBX 13 15 1 -3 +BITMAP +0180 +0100 +0100 +6170 +6398 +4318 +4218 +C210 +C610 +C630 +CE30 +7430 +0400 +0C00 +0C00 +ENDCHAR +STARTCHAR uni0584 +ENCODING 1412 +SWIDTH 572 0 +DWIDTH 10 0 +BBX 10 12 -1 -3 +BITMAP +1F80 +18C0 +1840 +1040 +3040 +30C0 +3180 +2F00 +2000 +6000 +FF00 +6000 +ENDCHAR +STARTCHAR uni0585 +ENCODING 1413 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni0586 +ENCODING 1414 +SWIDTH 743 0 +DWIDTH 13 0 +BBX 11 15 1 -3 +BITMAP +0F00 +1300 +3200 +1FC0 +0660 +0620 +0420 +8420 +8460 +8C40 +CCC0 +3F00 +0800 +1800 +1800 +ENDCHAR +STARTCHAR uni0587 +ENCODING 1415 +SWIDTH 718 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +3000 +2000 +2000 +6100 +6100 +4300 +4300 +C300 +C200 +C600 +CE00 +77E0 +ENDCHAR +STARTCHAR uni0589 +ENCODING 1417 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 3 9 1 0 +BITMAP +20 +00 +00 +00 +00 +00 +00 +00 +C0 +ENDCHAR +STARTCHAR uni058A +ENCODING 1418 +SWIDTH 324 0 +DWIDTH 6 0 +BBX 5 2 1 3 +BITMAP +80 +F8 +ENDCHAR +STARTCHAR uni058D +ENCODING 1421 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 15 15 1 -3 +BITMAP +03C0 +1CF0 +2908 +5214 +52EC +4A82 +CBF2 +A7CA +9FA6 +8196 +6294 +5C94 +2198 +1F30 +07C0 +ENDCHAR +STARTCHAR uni058E +ENCODING 1422 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 15 15 1 -3 +BITMAP +03C0 +1E30 +2128 +4894 +7694 +4196 +9FA6 +A3CE +CFFA +4B02 +52C4 +523C +2908 +18F0 +07C0 +ENDCHAR +STARTCHAR uni058F +ENCODING 1423 +SWIDTH 726 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +1F00 +30C0 +60C0 +6040 +40C0 +C0C0 +00C0 +0FE0 +0080 +0FE0 +0180 +0180 +ENDCHAR +STARTCHAR uni0591 +ENCODING 1425 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 -3 -4 +BITMAP +20 +60 +A0 +A0 +ENDCHAR +STARTCHAR uni0592 +ENCODING 1426 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 0 9 +BITMAP +40 +A0 +A0 +ENDCHAR +STARTCHAR uni0593 +ENCODING 1427 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 0 9 +BITMAP +20 +60 +40 +80 +ENDCHAR +STARTCHAR uni0594 +ENCODING 1428 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 3 1 9 +BITMAP +80 +80 +80 +ENDCHAR +STARTCHAR uni0595 +ENCODING 1429 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 0 9 +BITMAP +60 +A0 +A0 +80 +ENDCHAR +STARTCHAR uni0596 +ENCODING 1430 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 4 -2 -4 +BITMAP +80 +80 +80 +40 +ENDCHAR +STARTCHAR uni0597 +ENCODING 1431 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 1 10 +BITMAP +C0 +80 +ENDCHAR +STARTCHAR uni0598 +ENCODING 1432 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 3 -1 10 +BITMAP +40 +A8 +18 +ENDCHAR +STARTCHAR uni0599 +ENCODING 1433 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 4 -1 9 +BITMAP +80 +40 +40 +40 +ENDCHAR +STARTCHAR uni059A +ENCODING 1434 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 0 -4 +BITMAP +60 +80 +80 +40 +ENDCHAR +STARTCHAR uni059B +ENCODING 1435 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 4 -3 -4 +BITMAP +50 +60 +20 +C0 +ENDCHAR +STARTCHAR uni059C +ENCODING 1436 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 0 9 +BITMAP +20 +40 +80 +80 +ENDCHAR +STARTCHAR uni059D +ENCODING 1437 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 4 2 9 +BITMAP +30 +40 +80 +80 +ENDCHAR +STARTCHAR uni059E +ENCODING 1438 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 4 -1 9 +BITMAP +28 +50 +A0 +A0 +ENDCHAR +STARTCHAR uni059F +ENCODING 1439 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 7 4 -2 9 +BITMAP +42 +AE +C6 +20 +ENDCHAR +STARTCHAR uni05A0 +ENCODING 1440 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 0 10 +BITMAP +20 +E0 +60 +ENDCHAR +STARTCHAR uni05A1 +ENCODING 1441 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 0 9 +BITMAP +40 +A0 +C0 +80 +ENDCHAR +STARTCHAR uni05A2 +ENCODING 1442 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 4 -3 -4 +BITMAP +50 +90 +60 +40 +ENDCHAR +STARTCHAR uni05A3 +ENCODING 1443 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -3 -4 +BITMAP +20 +20 +E0 +ENDCHAR +STARTCHAR uni05A4 +ENCODING 1444 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 4 -2 -4 +BITMAP +40 +80 +80 +40 +ENDCHAR +STARTCHAR uni05A5 +ENCODING 1445 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 4 -3 -4 +BITMAP +10 +20 +20 +C0 +ENDCHAR +STARTCHAR uni05A6 +ENCODING 1446 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 4 -3 -4 +BITMAP +10 +50 +50 +A0 +ENDCHAR +STARTCHAR uni05A7 +ENCODING 1447 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 3 -2 -4 +BITMAP +C0 +40 +80 +ENDCHAR +STARTCHAR uni05A8 +ENCODING 1448 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 4 1 9 +BITMAP +80 +40 +40 +40 +ENDCHAR +STARTCHAR uni05A9 +ENCODING 1449 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 0 9 +BITMAP +40 +A0 +C0 +20 +ENDCHAR +STARTCHAR uni05AA +ENCODING 1450 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 4 -3 -4 +BITMAP +50 +90 +60 +40 +ENDCHAR +STARTCHAR uni05AB +ENCODING 1451 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 4 1 9 +BITMAP +40 +80 +80 +40 +ENDCHAR +STARTCHAR uni05AC +ENCODING 1452 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 0 9 +BITMAP +20 +20 +20 +E0 +ENDCHAR +STARTCHAR uni05AD +ENCODING 1453 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 4 0 -4 +BITMAP +80 +80 +80 +40 +ENDCHAR +STARTCHAR uni05AE +ENCODING 1454 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 3 -3 10 +BITMAP +40 +A8 +98 +ENDCHAR +STARTCHAR uni05AF +ENCODING 1455 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 3 1 10 +BITMAP +40 +C0 +80 +ENDCHAR +STARTCHAR uni05B0 +ENCODING 1456 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 3 -1 -4 +BITMAP +80 +80 +80 +ENDCHAR +STARTCHAR uni05B1 +ENCODING 1457 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 4 -1 -4 +BITMAP +08 +A8 +48 +40 +ENDCHAR +STARTCHAR uni05B2 +ENCODING 1458 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 4 -1 -4 +BITMAP +E8 +08 +18 +10 +ENDCHAR +STARTCHAR uni05B3 +ENCODING 1459 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 4 -1 -4 +BITMAP +E8 +48 +58 +10 +ENDCHAR +STARTCHAR uni05B4 +ENCODING 1460 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 1 -1 -2 +BITMAP +80 +ENDCHAR +STARTCHAR uni05B5 +ENCODING 1461 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 1 -1 -2 +BITMAP +B0 +ENDCHAR +STARTCHAR uni05B6 +ENCODING 1462 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -1 -4 +BITMAP +B0 +40 +40 +ENDCHAR +STARTCHAR uni05B7 +ENCODING 1463 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 1 -1 -1 +BITMAP +F0 +ENDCHAR +STARTCHAR uni05B8 +ENCODING 1464 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -1 -3 +BITMAP +F0 +40 +40 +ENDCHAR +STARTCHAR uni05B9 +ENCODING 1465 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 2 1 9 +BITMAP +80 +80 +ENDCHAR +STARTCHAR uni05BA +ENCODING 1466 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 2 1 9 +BITMAP +80 +80 +ENDCHAR +STARTCHAR uni05BB +ENCODING 1467 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 3 -1 -4 +BITMAP +A0 +28 +08 +ENDCHAR +STARTCHAR uni05BC +ENCODING 1468 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 2 4 +BITMAP +C0 +ENDCHAR +STARTCHAR uni05BD +ENCODING 1469 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 4 -2 -4 +BITMAP +40 +80 +80 +80 +ENDCHAR +STARTCHAR uni05BE +ENCODING 1470 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 5 1 2 8 +BITMAP +F8 +ENDCHAR +STARTCHAR uni05BF +ENCODING 1471 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 1 0 9 +BITMAP +E0 +ENDCHAR +STARTCHAR uni05C0 +ENCODING 1472 +SWIDTH 274 0 +DWIDTH 5 0 +BBX 3 11 1 0 +BITMAP +20 +20 +20 +20 +60 +40 +40 +40 +40 +C0 +80 +ENDCHAR +STARTCHAR uni05C1 +ENCODING 1473 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 8 9 +BITMAP +C0 +ENDCHAR +STARTCHAR uni05C2 +ENCODING 1474 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 1 0 9 +BITMAP +80 +ENDCHAR +STARTCHAR uni05C3 +ENCODING 1475 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 3 9 1 0 +BITMAP +20 +00 +00 +00 +00 +00 +00 +00 +C0 +ENDCHAR +STARTCHAR uni05C4 +ENCODING 1476 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 1 1 10 +BITMAP +80 +ENDCHAR +STARTCHAR uni05C5 +ENCODING 1477 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -2 -2 +BITMAP +40 +C0 +ENDCHAR +STARTCHAR uni05C6 +ENCODING 1478 +SWIDTH 352 0 +DWIDTH 6 0 +BBX 6 9 0 0 +BITMAP +1C +30 +20 +60 +60 +60 +40 +40 +F8 +ENDCHAR +STARTCHAR uni05C7 +ENCODING 1479 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 4 -1 -4 +BITMAP +F0 +40 +40 +40 +ENDCHAR +STARTCHAR uni05D0 +ENCODING 1488 +SWIDTH 562 0 +DWIDTH 10 0 +BBX 10 9 0 0 +BITMAP +30C0 +1880 +1980 +1D80 +3F00 +6600 +6600 +4300 +C300 +ENDCHAR +STARTCHAR uni05D1 +ENCODING 1489 +SWIDTH 541 0 +DWIDTH 9 0 +BBX 8 9 0 0 +BITMAP +3E +03 +03 +03 +03 +03 +02 +02 +FF +ENDCHAR +STARTCHAR uni05D2 +ENCODING 1490 +SWIDTH 398 0 +DWIDTH 7 0 +BBX 6 9 0 0 +BITMAP +3C +0C +0C +0C +0C +0C +38 +68 +CC +ENDCHAR +STARTCHAR uni05D3 +ENCODING 1491 +SWIDTH 508 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +FF +06 +04 +04 +0C +0C +0C +08 +08 +ENDCHAR +STARTCHAR uni05D4 +ENCODING 1492 +SWIDTH 602 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +7E00 +0300 +0180 +0180 +4100 +C100 +C300 +C300 +8300 +ENDCHAR +STARTCHAR uni05D5 +ENCODING 1493 +SWIDTH 246 0 +DWIDTH 4 0 +BBX 3 9 1 0 +BITMAP +60 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR uni05D6 +ENCODING 1494 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 5 9 2 0 +BITMAP +F8 +60 +40 +C0 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni05D7 +ENCODING 1495 +SWIDTH 598 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +7E00 +6300 +6180 +4100 +4100 +C300 +C300 +C300 +8200 +ENDCHAR +STARTCHAR uni05D8 +ENCODING 1496 +SWIDTH 589 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +6700 +6180 +4180 +4180 +C100 +C300 +C300 +4600 +7C00 +ENDCHAR +STARTCHAR uni05D9 +ENCODING 1497 +SWIDTH 246 0 +DWIDTH 4 0 +BBX 2 5 2 4 +BITMAP +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni05DA +ENCODING 1498 +SWIDTH 509 0 +DWIDTH 9 0 +BBX 6 12 2 -3 +BITMAP +F8 +0C +0C +0C +0C +0C +08 +18 +18 +18 +10 +10 +ENDCHAR +STARTCHAR uni05DB +ENCODING 1499 +SWIDTH 460 0 +DWIDTH 8 0 +BBX 8 9 0 0 +BITMAP +3C +06 +02 +03 +02 +06 +06 +0C +F0 +ENDCHAR +STARTCHAR uni05DC +ENCODING 1500 +SWIDTH 462 0 +DWIDTH 8 0 +BBX 6 12 2 0 +BITMAP +C0 +C0 +80 +FC +0C +0C +08 +18 +30 +60 +60 +60 +ENDCHAR +STARTCHAR uni05DD +ENCODING 1501 +SWIDTH 598 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +7E00 +6300 +6180 +4100 +4100 +C100 +C300 +C300 +FE00 +ENDCHAR +STARTCHAR uni05DE +ENCODING 1502 +SWIDTH 601 0 +DWIDTH 10 0 +BBX 10 9 0 0 +BITMAP +3780 +3C80 +38C0 +3080 +3080 +2080 +6180 +4180 +CF80 +ENDCHAR +STARTCHAR uni05DF +ENCODING 1503 +SWIDTH 246 0 +DWIDTH 4 0 +BBX 4 12 0 -3 +BITMAP +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni05E0 +ENCODING 1504 +SWIDTH 352 0 +DWIDTH 6 0 +BBX 5 9 0 0 +BITMAP +38 +08 +08 +08 +18 +18 +18 +10 +F0 +ENDCHAR +STARTCHAR uni05E1 +ENCODING 1505 +SWIDTH 574 0 +DWIDTH 10 0 +BBX 8 9 1 0 +BITMAP +1E +23 +61 +C1 +C1 +C3 +C3 +C6 +78 +ENDCHAR +STARTCHAR uni05E2 +ENCODING 1506 +SWIDTH 529 0 +DWIDTH 9 0 +BBX 9 10 0 -1 +BITMAP +3180 +3180 +3180 +3100 +3300 +3300 +3200 +3400 +3800 +C000 +ENDCHAR +STARTCHAR uni05E3 +ENCODING 1507 +SWIDTH 566 0 +DWIDTH 10 0 +BBX 8 12 1 -3 +BITMAP +7E +43 +43 +C3 +C3 +62 +02 +06 +06 +06 +04 +04 +ENDCHAR +STARTCHAR uni05E4 +ENCODING 1508 +SWIDTH 546 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +3E00 +2380 +2180 +2180 +3980 +0180 +0300 +0600 +FC00 +ENDCHAR +STARTCHAR uni05E5 +ENCODING 1509 +SWIDTH 461 0 +DWIDTH 8 0 +BBX 6 12 2 -3 +BITMAP +84 +CC +CC +D8 +70 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni05E6 +ENCODING 1510 +SWIDTH 478 0 +DWIDTH 8 0 +BBX 8 9 0 0 +BITMAP +21 +33 +33 +1E +1C +08 +0C +0C +FC +ENDCHAR +STARTCHAR uni05E7 +ENCODING 1511 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 10 12 0 -3 +BITMAP +3FC0 +0080 +0080 +0180 +2300 +6600 +6600 +6400 +4C00 +4000 +C000 +C000 +ENDCHAR +STARTCHAR uni05E8 +ENCODING 1512 +SWIDTH 509 0 +DWIDTH 9 0 +BBX 6 9 2 0 +BITMAP +F8 +0C +0C +0C +0C +0C +08 +08 +18 +ENDCHAR +STARTCHAR uni05E9 +ENCODING 1513 +SWIDTH 694 0 +DWIDTH 12 0 +BBX 11 9 1 0 +BITMAP +6660 +4660 +4440 +4C40 +C8C0 +F080 +C180 +6300 +3C00 +ENDCHAR +STARTCHAR uni05EA +ENCODING 1514 +SWIDTH 642 0 +DWIDTH 11 0 +BBX 10 9 0 0 +BITMAP +3F80 +18C0 +1840 +1840 +10C0 +10C0 +30C0 +3080 +E080 +ENDCHAR +STARTCHAR uni05F0 +ENCODING 1520 +SWIDTH 493 0 +DWIDTH 8 0 +BBX 7 9 1 0 +BITMAP +62 +66 +66 +46 +44 +C4 +CC +CC +8C +ENDCHAR +STARTCHAR uni05F1 +ENCODING 1521 +SWIDTH 493 0 +DWIDTH 8 0 +BBX 6 9 2 0 +BITMAP +C4 +CC +CC +8C +88 +08 +18 +18 +18 +ENDCHAR +STARTCHAR uni05F2 +ENCODING 1522 +SWIDTH 493 0 +DWIDTH 8 0 +BBX 6 5 2 4 +BITMAP +C4 +CC +CC +8C +88 +ENDCHAR +STARTCHAR uni05F3 +ENCODING 1523 +SWIDTH 235 0 +DWIDTH 4 0 +BBX 2 3 2 6 +BITMAP +40 +80 +80 +ENDCHAR +STARTCHAR uni05F4 +ENCODING 1524 +SWIDTH 416 0 +DWIDTH 7 0 +BBX 5 3 2 6 +BITMAP +48 +90 +90 +ENDCHAR +STARTCHAR uni1D00 +ENCODING 7424 +SWIDTH 499 0 +DWIDTH 8 0 +BBX 8 9 0 0 +BITMAP +0C +0E +1E +12 +32 +3E +42 +C3 +83 +ENDCHAR +STARTCHAR uni1D01 +ENCODING 7425 +SWIDTH 716 0 +DWIDTH 12 0 +BBX 13 9 -1 0 +BITMAP +07F8 +0580 +0D80 +0980 +19F8 +3F00 +2300 +6300 +C3F0 +ENDCHAR +STARTCHAR uni1D02 +ENCODING 7426 +SWIDTH 889 0 +DWIDTH 15 0 +BBX 14 9 1 0 +BITMAP +3C78 +628C +C30C +0308 +FFF0 +8200 +8618 +CF30 +79E0 +ENDCHAR +STARTCHAR uni1D03 +ENCODING 7427 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +7C +62 +42 +46 +FF +C6 +C2 +86 +FC +ENDCHAR +STARTCHAR uni1D04 +ENCODING 7428 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1C +62 +43 +C0 +C0 +80 +C6 +C4 +78 +ENDCHAR +STARTCHAR uni1D05 +ENCODING 7429 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +7E +63 +41 +41 +C1 +C3 +C2 +86 +F8 +ENDCHAR +STARTCHAR uni1D06 +ENCODING 7430 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +3F00 +3180 +2080 +2080 +F880 +6180 +6100 +4300 +7C00 +ENDCHAR +STARTCHAR uni1D07 +ENCODING 7431 +SWIDTH 471 0 +DWIDTH 8 0 +BBX 7 9 1 0 +BITMAP +7E +60 +40 +40 +FC +C0 +C0 +80 +FC +ENDCHAR +STARTCHAR uni1D08 +ENCODING 7432 +SWIDTH 464 0 +DWIDTH 8 0 +BBX 8 9 0 0 +BITMAP +1E +23 +03 +02 +1C +06 +C2 +46 +3C +ENDCHAR +STARTCHAR uni1D09 +ENCODING 7433 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 4 12 0 -3 +BITMAP +30 +20 +20 +60 +60 +60 +40 +40 +C0 +00 +00 +80 +ENDCHAR +STARTCHAR uni1D0A +ENCODING 7434 +SWIDTH 414 0 +DWIDTH 7 0 +BBX 7 9 0 0 +BITMAP +06 +06 +06 +04 +04 +0C +CC +C8 +70 +ENDCHAR +STARTCHAR uni1D0B +ENCODING 7435 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +63 +66 +4C +58 +F0 +F8 +C8 +8C +86 +ENDCHAR +STARTCHAR uni1D0C +ENCODING 7436 +SWIDTH 447 0 +DWIDTH 8 0 +BBX 7 9 0 0 +BITMAP +30 +30 +28 +30 +60 +E0 +60 +40 +7E +ENDCHAR +STARTCHAR uni1D0D +ENCODING 7437 +SWIDTH 685 0 +DWIDTH 12 0 +BBX 11 9 1 0 +BITMAP +70E0 +70C0 +5140 +5140 +D2C0 +D6C0 +D480 +9C80 +9980 +ENDCHAR +STARTCHAR uni1D0E +ENCODING 7438 +SWIDTH 585 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +6180 +6380 +4780 +4D00 +C900 +D300 +E300 +C200 +8200 +ENDCHAR +STARTCHAR uni1D0F +ENCODING 7439 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1D10 +ENCODING 7440 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +3C +66 +C2 +02 +02 +06 +86 +8C +78 +ENDCHAR +STARTCHAR uni1D11 +ENCODING 7441 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 9 0 0 +BITMAP +3E00 +6300 +4180 +C080 +C0C0 +40C0 +6080 +3180 +1F00 +ENDCHAR +STARTCHAR uni1D12 +ENCODING 7442 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 7 0 1 +BITMAP +7C00 +C300 +8180 +8080 +4080 +2180 +0300 +ENDCHAR +STARTCHAR uni1D13 +ENCODING 7443 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 11 9 0 0 +BITMAP +FE00 +6180 +5080 +4840 +4440 +6240 +2140 +39C0 +0F60 +ENDCHAR +STARTCHAR uni1D14 +ENCODING 7444 +SWIDTH 943 0 +DWIDTH 16 0 +BBX 15 9 1 0 +BITMAP +1C38 +62C4 +4186 +0106 +FF06 +C304 +C30C +4598 +38F0 +ENDCHAR +STARTCHAR uni1D15 +ENCODING 7445 +SWIDTH 457 0 +DWIDTH 8 0 +BBX 7 9 1 0 +BITMAP +62 +64 +38 +4C +84 +84 +8C +88 +F0 +ENDCHAR +STARTCHAR uni1D16 +ENCODING 7446 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 4 1 5 +BITMAP +3E +63 +C1 +C1 +ENDCHAR +STARTCHAR uni1D17 +ENCODING 7447 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 4 1 0 +BITMAP +83 +83 +C6 +7C +ENDCHAR +STARTCHAR uni1D18 +ENCODING 7448 +SWIDTH 535 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +7E +61 +41 +43 +FE +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1D19 +ENCODING 7449 +SWIDTH 534 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +1F80 +2180 +6180 +2100 +3F00 +3300 +2300 +6300 +C200 +ENDCHAR +STARTCHAR uni1D1A +ENCODING 7450 +SWIDTH 534 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +61 +63 +23 +33 +7E +C2 +86 +86 +FE +ENDCHAR +STARTCHAR uni1D1B +ENCODING 7451 +SWIDTH 514 0 +DWIDTH 9 0 +BBX 7 9 2 0 +BITMAP +FE +30 +30 +30 +20 +20 +60 +60 +60 +ENDCHAR +STARTCHAR uni1D1C +ENCODING 7452 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1D1D +ENCODING 7453 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +E000 +1E00 +0380 +0100 +0080 +0080 +0080 +F080 +0F80 +ENDCHAR +STARTCHAR uni1D1E +ENCODING 7454 +SWIDTH 697 0 +DWIDTH 12 0 +BBX 12 9 0 0 +BITMAP +1800 +07C0 +C0E0 +0060 +0020 +C030 +0030 +1E30 +01E0 +ENDCHAR +STARTCHAR uni1D1F +ENCODING 7455 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 13 0 -2 +BITMAP +C000 +3E00 +0380 +0100 +0080 +0080 +F080 +0F80 +0100 +0080 +0080 +F080 +0F80 +ENDCHAR +STARTCHAR uni1D20 +ENCODING 7456 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +C1 +43 +42 +46 +6C +68 +78 +30 +30 +ENDCHAR +STARTCHAR uni1D21 +ENCODING 7457 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 9 1 0 +BITMAP +C630 +C620 +4E20 +4A60 +4A40 +52C0 +5280 +6280 +6300 +ENDCHAR +STARTCHAR uni1D22 +ENCODING 7458 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +3F80 +0300 +0600 +0C00 +0800 +1800 +3000 +6000 +FF00 +ENDCHAR +STARTCHAR uni1D23 +ENCODING 7459 +SWIDTH 464 0 +DWIDTH 8 0 +BBX 8 9 0 0 +BITMAP +3F +02 +04 +0C +1E +06 +C2 +46 +3C +ENDCHAR +STARTCHAR uni1D24 +ENCODING 7460 +SWIDTH 464 0 +DWIDTH 8 0 +BBX 7 9 1 0 +BITMAP +3C +46 +06 +06 +1C +70 +80 +8C +F8 +ENDCHAR +STARTCHAR uni1D25 +ENCODING 7461 +SWIDTH 606 0 +DWIDTH 10 0 +BBX 9 9 0 0 +BITMAP +0700 +1F80 +1F80 +1F80 +1F00 +0E00 +0C00 +9680 +E380 +ENDCHAR +STARTCHAR uni1D26 +ENCODING 7462 +SWIDTH 377 0 +DWIDTH 6 0 +BBX 6 9 1 0 +BITMAP +7C +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1D27 +ENCODING 7463 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 0 0 +BITMAP +0C +0E +1E +16 +32 +22 +62 +C3 +C3 +ENDCHAR +STARTCHAR uni1D28 +ENCODING 7464 +SWIDTH 550 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +7F +61 +43 +43 +C3 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR uni1D29 +ENCODING 7465 +SWIDTH 535 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +7E +61 +41 +43 +FE +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1D2A +ENCODING 7466 +SWIDTH 727 0 +DWIDTH 12 0 +BBX 10 9 2 0 +BITMAP +C440 +CC40 +8CC0 +88C0 +8880 +C980 +7E00 +1800 +1000 +ENDCHAR +STARTCHAR uni1D2B +ENCODING 7467 +SWIDTH 563 0 +DWIDTH 10 0 +BBX 10 9 0 0 +BITMAP +1FC0 +1080 +1080 +3180 +3180 +2180 +2100 +6100 +C300 +ENDCHAR +STARTCHAR uni1D2C +ENCODING 7468 +SWIDTH 491 0 +DWIDTH 8 0 +BBX 7 8 1 4 +BITMAP +0C +0C +14 +34 +24 +7E +42 +82 +ENDCHAR +STARTCHAR uni1D2D +ENCODING 7469 +SWIDTH 717 0 +DWIDTH 12 0 +BBX 12 8 1 4 +BITMAP +0FF0 +0A00 +1200 +33E0 +2200 +7E00 +4400 +87E0 +ENDCHAR +STARTCHAR uni1D2E +ENCODING 7470 +SWIDTH 453 0 +DWIDTH 8 0 +BBX 7 8 1 4 +BITMAP +3C +62 +42 +7C +42 +42 +86 +FC +ENDCHAR +STARTCHAR uni1D2F +ENCODING 7471 +SWIDTH 453 0 +DWIDTH 8 0 +BBX 7 8 1 4 +BITMAP +3C +62 +42 +FE +42 +42 +86 +FC +ENDCHAR +STARTCHAR uni1D30 +ENCODING 7472 +SWIDTH 476 0 +DWIDTH 8 0 +BBX 8 8 1 4 +BITMAP +3C +62 +41 +41 +43 +42 +86 +F8 +ENDCHAR +STARTCHAR uni1D31 +ENCODING 7473 +SWIDTH 451 0 +DWIDTH 8 0 +BBX 8 8 1 4 +BITMAP +3F +60 +40 +7E +40 +40 +80 +FC +ENDCHAR +STARTCHAR uni1D32 +ENCODING 7474 +SWIDTH 451 0 +DWIDTH 8 0 +BBX 8 8 1 4 +BITMAP +7F +02 +02 +02 +7E +04 +04 +FC +ENDCHAR +STARTCHAR uni1D33 +ENCODING 7475 +SWIDTH 489 0 +DWIDTH 8 0 +BBX 8 8 1 4 +BITMAP +1E +63 +41 +C0 +8F +C2 +42 +3C +ENDCHAR +STARTCHAR uni1D34 +ENCODING 7476 +SWIDTH 476 0 +DWIDTH 8 0 +BBX 8 8 1 4 +BITMAP +21 +41 +43 +7E +42 +42 +82 +86 +ENDCHAR +STARTCHAR uni1D35 +ENCODING 7477 +SWIDTH 160 0 +DWIDTH 3 0 +BBX 3 8 1 4 +BITMAP +20 +60 +40 +40 +40 +40 +80 +80 +ENDCHAR +STARTCHAR uni1D36 +ENCODING 7478 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 8 1 4 +BITMAP +04 +08 +08 +08 +08 +98 +90 +70 +ENDCHAR +STARTCHAR uni1D37 +ENCODING 7479 +SWIDTH 449 0 +DWIDTH 8 0 +BBX 7 8 1 4 +BITMAP +22 +64 +48 +70 +68 +4C +84 +86 +ENDCHAR +STARTCHAR uni1D38 +ENCODING 7480 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 5 8 1 4 +BITMAP +20 +60 +40 +40 +40 +40 +80 +F8 +ENDCHAR +STARTCHAR uni1D39 +ENCODING 7481 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 9 8 1 4 +BITMAP +2080 +6180 +6180 +5280 +5280 +5500 +9900 +9900 +ENDCHAR +STARTCHAR uni1D3A +ENCODING 7482 +SWIDTH 473 0 +DWIDTH 8 0 +BBX 8 8 1 4 +BITMAP +21 +61 +51 +52 +4A +4A +86 +86 +ENDCHAR +STARTCHAR uni1D3B +ENCODING 7483 +SWIDTH 474 0 +DWIDTH 8 0 +BBX 8 8 1 4 +BITMAP +21 +43 +45 +4A +52 +62 +C2 +C6 +ENDCHAR +STARTCHAR uni1D3C +ENCODING 7484 +SWIDTH 496 0 +DWIDTH 8 0 +BBX 8 8 1 4 +BITMAP +1E +63 +41 +C1 +81 +C3 +42 +3C +ENDCHAR +STARTCHAR uni1D3D +ENCODING 7485 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 7 8 1 4 +BITMAP +22 +24 +18 +64 +C4 +84 +88 +70 +ENDCHAR +STARTCHAR uni1D3E +ENCODING 7486 +SWIDTH 437 0 +DWIDTH 7 0 +BBX 8 8 1 4 +BITMAP +3E +62 +43 +42 +7C +40 +80 +80 +ENDCHAR +STARTCHAR uni1D3F +ENCODING 7487 +SWIDTH 456 0 +DWIDTH 8 0 +BBX 8 8 1 4 +BITMAP +3E +41 +43 +7E +4C +44 +86 +82 +ENDCHAR +STARTCHAR uni1D40 +ENCODING 7488 +SWIDTH 396 0 +DWIDTH 7 0 +BBX 6 8 2 4 +BITMAP +FC +30 +20 +20 +20 +20 +40 +40 +ENDCHAR +STARTCHAR uni1D41 +ENCODING 7489 +SWIDTH 443 0 +DWIDTH 8 0 +BBX 8 8 1 4 +BITMAP +61 +43 +42 +42 +42 +86 +44 +78 +ENDCHAR +STARTCHAR uni1D42 +ENCODING 7490 +SWIDTH 640 0 +DWIDTH 11 0 +BBX 10 8 2 4 +BITMAP +8440 +8C40 +9C80 +9480 +A500 +A500 +C600 +C600 +ENDCHAR +STARTCHAR uni1D43 +ENCODING 7491 +SWIDTH 358 0 +DWIDTH 6 0 +BBX 5 6 1 4 +BITMAP +78 +08 +78 +88 +98 +E8 +ENDCHAR +STARTCHAR uni1D44 +ENCODING 7492 +SWIDTH 358 0 +DWIDTH 6 0 +BBX 6 6 1 4 +BITMAP +78 +44 +78 +80 +88 +70 +ENDCHAR +STARTCHAR uni1D45 +ENCODING 7493 +SWIDTH 353 0 +DWIDTH 6 0 +BBX 6 6 1 4 +BITMAP +3C +4C +44 +88 +48 +78 +ENDCHAR +STARTCHAR uni1D46 +ENCODING 7494 +SWIDTH 592 0 +DWIDTH 10 0 +BBX 10 6 1 4 +BITMAP +3B80 +4C40 +0440 +FF80 +8800 +7780 +ENDCHAR +STARTCHAR uni1D47 +ENCODING 7495 +SWIDTH 311 0 +DWIDTH 5 0 +BBX 6 8 0 4 +BITMAP +20 +20 +3C +64 +44 +44 +4C +B8 +ENDCHAR +STARTCHAR uni1D48 +ENCODING 7496 +SWIDTH 396 0 +DWIDTH 7 0 +BBX 7 8 1 4 +BITMAP +02 +04 +3C +4C +44 +84 +48 +78 +ENDCHAR +STARTCHAR uni1D49 +ENCODING 7497 +SWIDTH 387 0 +DWIDTH 7 0 +BBX 6 6 1 4 +BITMAP +38 +44 +7C +80 +48 +70 +ENDCHAR +STARTCHAR uni1D4A +ENCODING 7498 +SWIDTH 387 0 +DWIDTH 7 0 +BBX 6 6 1 4 +BITMAP +38 +44 +04 +FC +88 +70 +ENDCHAR +STARTCHAR uni1D4B +ENCODING 7499 +SWIDTH 289 0 +DWIDTH 5 0 +BBX 5 6 1 4 +BITMAP +78 +40 +60 +80 +90 +60 +ENDCHAR +STARTCHAR uni1D4C +ENCODING 7500 +SWIDTH 289 0 +DWIDTH 5 0 +BBX 5 6 1 4 +BITMAP +78 +08 +30 +10 +90 +70 +ENDCHAR +STARTCHAR uni1D4D +ENCODING 7501 +SWIDTH 391 0 +DWIDTH 7 0 +BBX 6 8 1 2 +BITMAP +3C +4C +84 +C8 +78 +08 +88 +70 +ENDCHAR +STARTCHAR uni1D4E +ENCODING 7502 +SWIDTH 124 0 +DWIDTH 2 0 +BBX 3 8 0 2 +BITMAP +20 +20 +20 +40 +40 +40 +00 +80 +ENDCHAR +STARTCHAR uni1D4F +ENCODING 7503 +SWIDTH 315 0 +DWIDTH 5 0 +BBX 5 8 1 4 +BITMAP +40 +40 +48 +B0 +E0 +A0 +90 +90 +ENDCHAR +STARTCHAR uni1D50 +ENCODING 7504 +SWIDTH 499 0 +DWIDTH 8 0 +BBX 8 6 1 4 +BITMAP +7B +CD +89 +89 +91 +91 +ENDCHAR +STARTCHAR uni1D51 +ENCODING 7505 +SWIDTH 307 0 +DWIDTH 5 0 +BBX 5 8 1 2 +BITMAP +78 +C8 +88 +88 +88 +90 +10 +30 +ENDCHAR +STARTCHAR uni1D52 +ENCODING 7506 +SWIDTH 394 0 +DWIDTH 7 0 +BBX 6 6 1 4 +BITMAP +38 +44 +44 +84 +4C +78 +ENDCHAR +STARTCHAR uni1D53 +ENCODING 7507 +SWIDTH 354 0 +DWIDTH 6 0 +BBX 5 6 1 4 +BITMAP +38 +48 +08 +08 +88 +70 +ENDCHAR +STARTCHAR uni1D54 +ENCODING 7508 +SWIDTH 394 0 +DWIDTH 7 0 +BBX 6 3 1 7 +BITMAP +38 +44 +C4 +ENDCHAR +STARTCHAR uni1D55 +ENCODING 7509 +SWIDTH 394 0 +DWIDTH 7 0 +BBX 6 3 1 4 +BITMAP +84 +4C +78 +ENDCHAR +STARTCHAR uni1D56 +ENCODING 7510 +SWIDTH 366 0 +DWIDTH 6 0 +BBX 6 8 0 2 +BITMAP +3C +24 +44 +44 +44 +78 +80 +80 +ENDCHAR +STARTCHAR uni1D57 +ENCODING 7511 +SWIDTH 195 0 +DWIDTH 3 0 +BBX 3 8 1 4 +BITMAP +20 +60 +E0 +40 +40 +40 +80 +C0 +ENDCHAR +STARTCHAR uni1D58 +ENCODING 7512 +SWIDTH 353 0 +DWIDTH 6 0 +BBX 6 6 1 4 +BITMAP +44 +44 +48 +88 +98 +68 +ENDCHAR +STARTCHAR uni1D59 +ENCODING 7513 +SWIDTH 466 0 +DWIDTH 8 0 +BBX 6 6 2 4 +BITMAP +E0 +1C +08 +04 +C4 +38 +ENDCHAR +STARTCHAR uni1D5A +ENCODING 7514 +SWIDTH 525 0 +DWIDTH 9 0 +BBX 9 6 1 4 +BITMAP +4880 +4880 +8900 +8900 +9900 +EF00 +ENDCHAR +STARTCHAR uni1D5B +ENCODING 7515 +SWIDTH 357 0 +DWIDTH 6 0 +BBX 5 6 2 4 +BITMAP +88 +90 +90 +A0 +A0 +40 +ENDCHAR +STARTCHAR uni1D5C +ENCODING 7516 +SWIDTH 441 0 +DWIDTH 8 0 +BBX 6 6 1 4 +BITMAP +1C +3C +3C +18 +B4 +CC +ENDCHAR +STARTCHAR uni1D5D +ENCODING 7517 +SWIDTH 398 0 +DWIDTH 7 0 +BBX 7 10 0 2 +BITMAP +1C +32 +22 +2C +24 +42 +64 +5C +40 +80 +ENDCHAR +STARTCHAR uni1D5E +ENCODING 7518 +SWIDTH 367 0 +DWIDTH 6 0 +BBX 5 8 2 2 +BITMAP +88 +90 +90 +A0 +A0 +40 +40 +C0 +ENDCHAR +STARTCHAR uni1D5F +ENCODING 7519 +SWIDTH 380 0 +DWIDTH 6 0 +BBX 6 8 1 4 +BITMAP +3C +10 +38 +44 +C4 +84 +C8 +78 +ENDCHAR +STARTCHAR uni1D60 +ENCODING 7520 +SWIDTH 437 0 +DWIDTH 7 0 +BBX 7 8 1 2 +BITMAP +2C +4A +92 +92 +D4 +78 +20 +20 +ENDCHAR +STARTCHAR uni1D61 +ENCODING 7521 +SWIDTH 380 0 +DWIDTH 6 0 +BBX 7 8 0 2 +BITMAP +22 +34 +1C +18 +18 +28 +48 +C4 +ENDCHAR +STARTCHAR uni1D62 +ENCODING 7522 +SWIDTH 124 0 +DWIDTH 2 0 +BBX 2 8 0 -1 +BITMAP +40 +00 +40 +40 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni1D63 +ENCODING 7523 +SWIDTH 190 0 +DWIDTH 3 0 +BBX 5 6 -1 -1 +BITMAP +58 +60 +40 +40 +40 +80 +ENDCHAR +STARTCHAR uni1D64 +ENCODING 7524 +SWIDTH 353 0 +DWIDTH 6 0 +BBX 6 6 0 -1 +BITMAP +44 +48 +88 +88 +98 +E8 +ENDCHAR +STARTCHAR uni1D65 +ENCODING 7525 +SWIDTH 357 0 +DWIDTH 6 0 +BBX 5 6 1 -1 +BITMAP +88 +90 +90 +A0 +A0 +40 +ENDCHAR +STARTCHAR uni1D66 +ENCODING 7526 +SWIDTH 398 0 +DWIDTH 7 0 +BBX 6 10 0 -3 +BITMAP +38 +64 +44 +58 +48 +84 +C8 +B8 +80 +80 +ENDCHAR +STARTCHAR uni1D67 +ENCODING 7527 +SWIDTH 367 0 +DWIDTH 6 0 +BBX 5 8 1 -3 +BITMAP +88 +90 +90 +A0 +A0 +40 +40 +80 +ENDCHAR +STARTCHAR uni1D68 +ENCODING 7528 +SWIDTH 379 0 +DWIDTH 6 0 +BBX 6 8 0 -3 +BITMAP +38 +44 +C4 +84 +C8 +F0 +80 +F8 +ENDCHAR +STARTCHAR uni1D69 +ENCODING 7529 +SWIDTH 437 0 +DWIDTH 7 0 +BBX 7 8 0 -3 +BITMAP +2C +5A +92 +92 +D4 +78 +20 +20 +ENDCHAR +STARTCHAR uni1D6A +ENCODING 7530 +SWIDTH 380 0 +DWIDTH 6 0 +BBX 7 8 -1 -3 +BITMAP +22 +24 +18 +18 +10 +28 +48 +8C +ENDCHAR +STARTCHAR uni1D6B +ENCODING 7531 +SWIDTH 912 0 +DWIDTH 16 0 +BBX 14 9 1 0 +BITMAP +6178 +618C +4304 +4304 +C3FC +C200 +C708 +C918 +70E0 +ENDCHAR +STARTCHAR uni1D6C +ENCODING 7532 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +E8 +B8 +60 +6E +73 +61 +41 +C1 +C3 +C2 +C6 +BC +ENDCHAR +STARTCHAR uni1D6D +ENCODING 7533 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 11 12 1 0 +BITMAP +03A0 +05C0 +0180 +3D00 +6300 +4300 +C300 +8300 +8200 +C600 +C600 +7E00 +ENDCHAR +STARTCHAR uni1D6E +ENCODING 7534 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 7 12 0 0 +BITMAP +0E +18 +10 +7C +30 +30 +20 +E8 +B8 +60 +60 +40 +ENDCHAR +STARTCHAR uni1D6F +ENCODING 7535 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 15 9 0 0 +BITMAP +3738 +39CC +318C +210C +7F0E +E3F8 +6318 +4318 +4218 +ENDCHAR +STARTCHAR uni1D70 +ENCODING 7536 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 9 0 0 +BITMAP +3700 +2980 +3180 +2180 +79C0 +E780 +6100 +4300 +4300 +ENDCHAR +STARTCHAR uni1D71 +ENCODING 7537 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 11 12 -2 -3 +BITMAP +0DC0 +0E60 +0C60 +0820 +1820 +1860 +1840 +18C0 +3780 +7400 +B800 +2000 +ENDCHAR +STARTCHAR uni1D72 +ENCODING 7538 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 8 9 -1 0 +BITMAP +1B +1C +18 +10 +74 +B8 +20 +20 +20 +ENDCHAR +STARTCHAR uni1D73 +ENCODING 7539 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 8 9 -1 0 +BITMAP +07 +08 +10 +10 +74 +B8 +20 +20 +20 +ENDCHAR +STARTCHAR uni1D74 +ENCODING 7540 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +3E +62 +40 +E1 +9E +06 +86 +C6 +78 +ENDCHAR +STARTCHAR uni1D75 +ENCODING 7541 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 12 0 0 +BITMAP +08 +10 +10 +78 +30 +20 +E8 +F8 +60 +60 +60 +70 +ENDCHAR +STARTCHAR uni1D76 +ENCODING 7542 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +3F80 +0300 +0600 +3D00 +5F00 +3000 +2000 +6000 +FF00 +ENDCHAR +STARTCHAR uni1D77 +ENCODING 7543 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +0F00 +1180 +2180 +2000 +6E00 +7300 +6180 +4180 +4100 +C300 +E200 +9C00 +ENDCHAR +STARTCHAR uni1D78 +ENCODING 7544 +SWIDTH 380 0 +DWIDTH 6 0 +BBX 6 6 1 4 +BITMAP +44 +44 +7C +88 +88 +88 +ENDCHAR +STARTCHAR uni1D79 +ENCODING 7545 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +1F80 +0300 +0600 +0400 +1E00 +2300 +4100 +C180 +C100 +C300 +C600 +7C00 +ENDCHAR +STARTCHAR uni1D7A +ENCODING 7546 +SWIDTH 761 0 +DWIDTH 13 0 +BBX 13 13 0 -1 +BITMAP +0910 +1120 +1340 +7BF0 +3298 +2318 +2618 +2610 +7E10 +7430 +6430 +7C20 +8000 +ENDCHAR +STARTCHAR uni1D7B +ENCODING 7547 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 4 9 0 0 +BITMAP +30 +30 +20 +20 +F0 +60 +60 +40 +40 +ENDCHAR +STARTCHAR uni1D7C +ENCODING 7548 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 4 9 0 0 +BITMAP +30 +30 +20 +20 +F0 +60 +60 +40 +40 +ENDCHAR +STARTCHAR uni1D7D +ENCODING 7549 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 12 0 -3 +BITMAP +3700 +3980 +3180 +2080 +7FC0 +6180 +6100 +6300 +5E00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni1D7E +ENCODING 7550 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +61 +61 +43 +43 +FF +C2 +C2 +44 +78 +ENDCHAR +STARTCHAR uni1D7F +ENCODING 7551 +SWIDTH 562 0 +DWIDTH 10 0 +BBX 10 9 0 0 +BITMAP +7BC0 +3100 +2180 +6080 +FFC0 +4180 +4180 +6300 +3E00 +ENDCHAR +STARTCHAR uni1D80 +ENCODING 7552 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +30 +20 +20 +6E +73 +61 +41 +41 +C3 +C2 +C6 +BC +04 +0C +38 +ENDCHAR +STARTCHAR uni1D81 +ENCODING 7553 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 15 1 -3 +BITMAP +0080 +0180 +0180 +3D00 +6300 +4300 +C300 +8300 +8200 +C600 +C600 +7F00 +0200 +0600 +1C00 +ENDCHAR +STARTCHAR uni1D82 +ENCODING 7554 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 8 15 -1 -3 +BITMAP +07 +0C +08 +3E +18 +18 +10 +10 +30 +30 +30 +30 +30 +30 +E0 +ENDCHAR +STARTCHAR uni1D83 +ENCODING 7555 +SWIDTH 688 0 +DWIDTH 12 0 +BBX 12 12 0 -3 +BITMAP +1E80 +3180 +2180 +6180 +4180 +4180 +4100 +63F0 +3F20 +0360 +C6C0 +7C00 +ENDCHAR +STARTCHAR uni1D84 +ENCODING 7556 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +30 +20 +20 +63 +66 +4C +78 +68 +C8 +CC +84 +86 +02 +06 +1C +ENDCHAR +STARTCHAR uni1D85 +ENCODING 7557 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 15 -1 -3 +BITMAP +08 +08 +18 +18 +18 +10 +10 +30 +30 +30 +20 +30 +30 +20 +C0 +ENDCHAR +STARTCHAR uni1D86 +ENCODING 7558 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 12 1 -3 +BITMAP +6E70 +7398 +6318 +4218 +C210 +C610 +C630 +8630 +8430 +0010 +0030 +00E0 +ENDCHAR +STARTCHAR uni1D87 +ENCODING 7559 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +6E +53 +63 +43 +C3 +C2 +C2 +86 +87 +02 +06 +1C +ENDCHAR +STARTCHAR uni1D88 +ENCODING 7560 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3700 +3980 +3180 +2080 +6080 +6180 +6100 +6300 +5E00 +C200 +C600 +9C00 +ENDCHAR +STARTCHAR uni1D89 +ENCODING 7561 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 8 12 -1 -3 +BITMAP +1B +1C +18 +10 +30 +30 +30 +20 +30 +30 +20 +E0 +ENDCHAR +STARTCHAR uni1D8A +ENCODING 7562 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 12 1 -3 +BITMAP +3C +62 +42 +70 +1C +06 +86 +C6 +7C +04 +0C +38 +ENDCHAR +STARTCHAR uni1D8B +ENCODING 7563 +SWIDTH 386 0 +DWIDTH 7 0 +BBX 9 15 -2 -3 +BITMAP +0380 +0600 +0400 +0400 +0400 +0C00 +0C00 +0800 +0800 +1800 +1F00 +1900 +1300 +3E00 +E000 +ENDCHAR +STARTCHAR uni1D8C +ENCODING 7564 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +C1 +43 +42 +46 +44 +6C +78 +30 +3C +0C +08 +30 +ENDCHAR +STARTCHAR uni1D8D +ENCODING 7565 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +2180 +3300 +1600 +1C00 +0C00 +1C00 +3400 +6600 +C300 +0100 +0300 +0E00 +ENDCHAR +STARTCHAR uni1D8E +ENCODING 7566 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3F80 +0300 +0600 +0C00 +0800 +1800 +3000 +6000 +FF00 +0200 +0600 +1C00 +ENDCHAR +STARTCHAR uni1D8F +ENCODING 7567 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 -3 +BITMAP +3E00 +6300 +4300 +0300 +7F00 +C200 +8600 +C600 +7B00 +0300 +0200 +0380 +ENDCHAR +STARTCHAR uni1D90 +ENCODING 7568 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +3D +63 +43 +C3 +83 +82 +C6 +C6 +7F +02 +02 +03 +ENDCHAR +STARTCHAR uni1D91 +ENCODING 7569 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 11 15 1 -3 +BITMAP +00E0 +0180 +0180 +3D00 +6700 +4300 +C300 +8300 +8200 +C600 +C600 +7E00 +0400 +0400 +0700 +ENDCHAR +STARTCHAR uni1D92 +ENCODING 7570 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +1E +63 +43 +C1 +FF +80 +C2 +C6 +7A +06 +06 +07 +ENDCHAR +STARTCHAR uni1D93 +ENCODING 7571 +SWIDTH 439 0 +DWIDTH 7 0 +BBX 7 12 1 -3 +BITMAP +3C +64 +40 +60 +70 +C0 +80 +88 +7C +0C +08 +0E +ENDCHAR +STARTCHAR uni1D94 +ENCODING 7572 +SWIDTH 464 0 +DWIDTH 8 0 +BBX 9 12 -1 -3 +BITMAP +0F00 +1180 +0180 +0100 +0E00 +0300 +6100 +6300 +5E00 +4000 +C000 +6000 +ENDCHAR +STARTCHAR uni1D95 +ENCODING 7573 +SWIDTH 634 0 +DWIDTH 11 0 +BBX 10 12 1 -3 +BITMAP +1E00 +6300 +4300 +0100 +FFC0 +8380 +C280 +4780 +3980 +0180 +0100 +01C0 +ENDCHAR +STARTCHAR uni1D96 +ENCODING 7574 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 15 1 -3 +BITMAP +20 +00 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +C0 +C0 +80 +E0 +ENDCHAR +STARTCHAR uni1D97 +ENCODING 7575 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 0 -3 +BITMAP +1E +33 +61 +01 +01 +03 +C3 +C6 +FC +80 +80 +E0 +ENDCHAR +STARTCHAR uni1D98 +ENCODING 7576 +SWIDTH 290 0 +DWIDTH 5 0 +BBX 8 15 -1 -3 +BITMAP +07 +0C +08 +08 +08 +18 +18 +10 +10 +30 +30 +20 +E0 +80 +E0 +ENDCHAR +STARTCHAR uni1D99 +ENCODING 7577 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 -3 +BITMAP +6100 +6100 +4300 +4300 +C300 +C200 +C600 +CA00 +7700 +0200 +0200 +0380 +ENDCHAR +STARTCHAR uni1D9A +ENCODING 7578 +SWIDTH 544 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +1F80 +0100 +0600 +0C00 +0F00 +0300 +0180 +C100 +E300 +BC00 +8000 +E000 +ENDCHAR +STARTCHAR uni1D9B +ENCODING 7579 +SWIDTH 379 0 +DWIDTH 6 0 +BBX 6 6 1 4 +BITMAP +58 +64 +44 +44 +C8 +B0 +ENDCHAR +STARTCHAR uni1D9C +ENCODING 7580 +SWIDTH 356 0 +DWIDTH 6 0 +BBX 6 6 1 4 +BITMAP +38 +4C +40 +80 +C8 +70 +ENDCHAR +STARTCHAR uni1D9D +ENCODING 7581 +SWIDTH 356 0 +DWIDTH 6 0 +BBX 6 6 1 4 +BITMAP +38 +44 +40 +B8 +48 +F0 +ENDCHAR +STARTCHAR uni1D9E +ENCODING 7582 +SWIDTH 395 0 +DWIDTH 7 0 +BBX 6 8 1 4 +BITMAP +1C +08 +3C +44 +44 +84 +48 +78 +ENDCHAR +STARTCHAR uni1D9F +ENCODING 7583 +SWIDTH 289 0 +DWIDTH 5 0 +BBX 5 6 1 4 +BITMAP +78 +08 +30 +10 +90 +70 +ENDCHAR +STARTCHAR uni1DA0 +ENCODING 7584 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 8 1 4 +BITMAP +30 +20 +F0 +40 +40 +40 +40 +80 +ENDCHAR +STARTCHAR uni1DA1 +ENCODING 7585 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 8 0 2 +BITMAP +10 +10 +20 +20 +20 +70 +20 +C0 +ENDCHAR +STARTCHAR uni1DA2 +ENCODING 7586 +SWIDTH 391 0 +DWIDTH 7 0 +BBX 6 8 1 2 +BITMAP +3C +4C +84 +C8 +78 +08 +88 +70 +ENDCHAR +STARTCHAR uni1DA3 +ENCODING 7587 +SWIDTH 354 0 +DWIDTH 6 0 +BBX 5 8 2 4 +BITMAP +88 +88 +88 +90 +90 +F0 +10 +10 +ENDCHAR +STARTCHAR uni1DA4 +ENCODING 7588 +SWIDTH 124 0 +DWIDTH 2 0 +BBX 2 8 1 4 +BITMAP +40 +00 +40 +40 +C0 +80 +80 +80 +ENDCHAR +STARTCHAR uni1DA5 +ENCODING 7589 +SWIDTH 124 0 +DWIDTH 2 0 +BBX 2 6 1 4 +BITMAP +40 +40 +40 +80 +80 +80 +ENDCHAR +STARTCHAR uni1DA6 +ENCODING 7590 +SWIDTH 124 0 +DWIDTH 2 0 +BBX 2 6 1 4 +BITMAP +40 +40 +40 +80 +80 +80 +ENDCHAR +STARTCHAR uni1DA7 +ENCODING 7591 +SWIDTH 124 0 +DWIDTH 2 0 +BBX 2 6 1 4 +BITMAP +40 +40 +C0 +80 +80 +80 +ENDCHAR +STARTCHAR uni1DA8 +ENCODING 7592 +SWIDTH 234 0 +DWIDTH 4 0 +BBX 5 10 0 2 +BITMAP +08 +00 +08 +10 +10 +10 +10 +70 +A0 +E0 +ENDCHAR +STARTCHAR uni1DA9 +ENCODING 7593 +SWIDTH 124 0 +DWIDTH 2 0 +BBX 2 10 1 2 +BITMAP +40 +40 +40 +40 +80 +80 +80 +80 +80 +C0 +ENDCHAR +STARTCHAR uni1DAA +ENCODING 7594 +SWIDTH 124 0 +DWIDTH 2 0 +BBX 3 10 0 2 +BITMAP +20 +20 +20 +20 +20 +40 +40 +40 +40 +C0 +ENDCHAR +STARTCHAR uni1DAB +ENCODING 7595 +SWIDTH 303 0 +DWIDTH 5 0 +BBX 4 6 1 4 +BITMAP +40 +40 +40 +80 +80 +F0 +ENDCHAR +STARTCHAR uni1DAC +ENCODING 7596 +SWIDTH 499 0 +DWIDTH 8 0 +BBX 8 8 1 2 +BITMAP +7B +CD +89 +89 +91 +91 +02 +06 +ENDCHAR +STARTCHAR uni1DAD +ENCODING 7597 +SWIDTH 499 0 +DWIDTH 8 0 +BBX 9 8 1 2 +BITMAP +4880 +8900 +8900 +9100 +9300 +ED00 +0200 +0200 +ENDCHAR +STARTCHAR uni1DAE +ENCODING 7598 +SWIDTH 307 0 +DWIDTH 5 0 +BBX 7 8 -1 2 +BITMAP +1E +32 +22 +22 +22 +24 +40 +C0 +ENDCHAR +STARTCHAR uni1DAF +ENCODING 7599 +SWIDTH 307 0 +DWIDTH 5 0 +BBX 5 8 1 2 +BITMAP +78 +C8 +88 +88 +90 +90 +10 +18 +ENDCHAR +STARTCHAR uni1DB0 +ENCODING 7600 +SWIDTH 352 0 +DWIDTH 6 0 +BBX 6 6 1 4 +BITMAP +44 +64 +A4 +98 +98 +88 +ENDCHAR +STARTCHAR uni1DB1 +ENCODING 7601 +SWIDTH 394 0 +DWIDTH 7 0 +BBX 6 6 1 4 +BITMAP +38 +44 +7C +84 +4C +78 +ENDCHAR +STARTCHAR uni1DB2 +ENCODING 7602 +SWIDTH 394 0 +DWIDTH 7 0 +BBX 6 10 1 2 +BITMAP +08 +18 +38 +54 +54 +94 +E8 +78 +20 +20 +ENDCHAR +STARTCHAR uni1DB3 +ENCODING 7603 +SWIDTH 343 0 +DWIDTH 6 0 +BBX 5 8 1 2 +BITMAP +38 +48 +60 +18 +88 +F0 +80 +80 +ENDCHAR +STARTCHAR uni1DB4 +ENCODING 7604 +SWIDTH 190 0 +DWIDTH 3 0 +BBX 6 10 0 2 +BITMAP +1C +10 +10 +20 +20 +20 +20 +60 +40 +C0 +ENDCHAR +STARTCHAR uni1DB5 +ENCODING 7605 +SWIDTH 195 0 +DWIDTH 3 0 +BBX 3 10 1 2 +BITMAP +20 +20 +60 +40 +40 +40 +80 +C0 +40 +C0 +ENDCHAR +STARTCHAR uni1DB6 +ENCODING 7606 +SWIDTH 307 0 +DWIDTH 5 0 +BBX 5 6 1 4 +BITMAP +48 +88 +F8 +88 +98 +F0 +ENDCHAR +STARTCHAR uni1DB7 +ENCODING 7607 +SWIDTH 401 0 +DWIDTH 7 0 +BBX 7 6 1 4 +BITMAP +6E +44 +44 +84 +4C +78 +ENDCHAR +STARTCHAR uni1DB8 +ENCODING 7608 +SWIDTH 307 0 +DWIDTH 5 0 +BBX 5 6 1 4 +BITMAP +48 +88 +88 +88 +90 +70 +ENDCHAR +STARTCHAR uni1DB9 +ENCODING 7609 +SWIDTH 307 0 +DWIDTH 5 0 +BBX 5 6 1 4 +BITMAP +58 +88 +88 +88 +90 +E0 +ENDCHAR +STARTCHAR uni1DBA +ENCODING 7610 +SWIDTH 357 0 +DWIDTH 6 0 +BBX 5 6 1 4 +BITMAP +10 +30 +28 +48 +88 +88 +ENDCHAR +STARTCHAR uni1DBB +ENCODING 7611 +SWIDTH 327 0 +DWIDTH 6 0 +BBX 5 6 1 4 +BITMAP +78 +10 +30 +60 +C0 +F8 +ENDCHAR +STARTCHAR uni1DBC +ENCODING 7612 +SWIDTH 327 0 +DWIDTH 6 0 +BBX 5 9 1 1 +BITMAP +78 +10 +30 +60 +C0 +F8 +10 +10 +18 +ENDCHAR +STARTCHAR uni1DBD +ENCODING 7613 +SWIDTH 367 0 +DWIDTH 6 0 +BBX 6 7 1 3 +BITMAP +78 +10 +30 +78 +E4 +F8 +40 +ENDCHAR +STARTCHAR uni1DBE +ENCODING 7614 +SWIDTH 341 0 +DWIDTH 6 0 +BBX 7 8 0 2 +BITMAP +3E +04 +08 +18 +0C +04 +C8 +78 +ENDCHAR +STARTCHAR uni1DBF +ENCODING 7615 +SWIDTH 395 0 +DWIDTH 7 0 +BBX 5 8 2 4 +BITMAP +70 +48 +88 +F8 +88 +98 +90 +E0 +ENDCHAR +STARTCHAR uni1DC0 +ENCODING 7616 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -1 10 +BITMAP +2C +90 +ENDCHAR +STARTCHAR uni1DC1 +ENCODING 7617 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -1 10 +BITMAP +D0 +28 +ENDCHAR +STARTCHAR uni1DC2 +ENCODING 7618 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 4 -2 -4 +BITMAP +C0 +80 +80 +C0 +ENDCHAR +STARTCHAR uni1DC3 +ENCODING 7619 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -1 10 +BITMAP +9C +E0 +ENDCHAR +STARTCHAR uni1DC4 +ENCODING 7620 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 2 -1 10 +BITMAP +10 +F0 +ENDCHAR +STARTCHAR uni1DC5 +ENCODING 7621 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -1 10 +BITMAP +C0 +78 +ENDCHAR +STARTCHAR uni1DC6 +ENCODING 7622 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -1 10 +BITMAP +F0 +08 +ENDCHAR +STARTCHAR uni1DC7 +ENCODING 7623 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 0 10 +BITMAP +78 +80 +ENDCHAR +STARTCHAR uni1DC8 +ENCODING 7624 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 7 2 -2 10 +BITMAP +CC +72 +ENDCHAR +STARTCHAR uni1DC9 +ENCODING 7625 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 7 2 -2 10 +BITMAP +72 +CC +ENDCHAR +STARTCHAR uni1DCA +ENCODING 7626 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -2 -4 +BITMAP +E0 +80 +80 +ENDCHAR +STARTCHAR uni1DFE +ENCODING 7678 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 0 10 +BITMAP +20 +C0 +60 +ENDCHAR +STARTCHAR uni1DFF +ENCODING 7679 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 3 -4 -3 +BITMAP +80 +74 +C8 +ENDCHAR +STARTCHAR uni1E00 +ENCODING 7680 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 17 0 -5 +BITMAP +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +0000 +0C00 +1400 +1400 +0C00 +ENDCHAR +STARTCHAR uni1E01 +ENCODING 7681 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 -5 +BITMAP +1E +63 +43 +03 +7F +C2 +86 +CE +7A +00 +60 +A0 +A0 +60 +ENDCHAR +STARTCHAR uni1E02 +ENCODING 7682 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 14 1 0 +BITMAP +0600 +0000 +3F80 +30C0 +2040 +20C0 +6080 +7F00 +4080 +40C0 +C0C0 +C0C0 +C180 +FF00 +ENDCHAR +STARTCHAR uni1E03 +ENCODING 7683 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +2C +20 +20 +7E +63 +61 +41 +41 +C3 +C2 +C6 +BC +ENDCHAR +STARTCHAR uni1E04 +ENCODING 7684 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 14 1 -2 +BITMAP +3F80 +30C0 +2040 +20C0 +6080 +7F00 +4080 +40C0 +C0C0 +C0C0 +C180 +FF00 +0000 +3000 +ENDCHAR +STARTCHAR uni1E05 +ENCODING 7685 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +20 +20 +20 +7E +63 +61 +41 +41 +C3 +C2 +C6 +BC +00 +30 +ENDCHAR +STARTCHAR uni1E06 +ENCODING 7686 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 14 1 -2 +BITMAP +3F80 +30C0 +2040 +20C0 +6080 +7F00 +4080 +40C0 +C0C0 +C0C0 +C180 +FF00 +0000 +7E00 +ENDCHAR +STARTCHAR uni1E07 +ENCODING 7687 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +20 +20 +20 +7E +63 +61 +41 +41 +C3 +C2 +C6 +BC +00 +FC +ENDCHAR +STARTCHAR uni1E08 +ENCODING 7688 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 10 19 2 -3 +BITMAP +0300 +0200 +0400 +0000 +1F00 +3080 +60C0 +C040 +C000 +8000 +8000 +8000 +80C0 +C180 +6300 +3E00 +1000 +0C00 +3800 +ENDCHAR +STARTCHAR uni1E09 +ENCODING 7689 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 16 1 -3 +BITMAP +06 +04 +08 +00 +1C +62 +43 +C0 +C0 +80 +C6 +C4 +78 +20 +18 +70 +ENDCHAR +STARTCHAR uni1E0A +ENCODING 7690 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 14 1 0 +BITMAP +0600 +0000 +3F80 +30C0 +2060 +2060 +6060 +6060 +6060 +4060 +C040 +C0C0 +C180 +FE00 +ENDCHAR +STARTCHAR uni1E0B +ENCODING 7691 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +1880 +0180 +0180 +3D00 +6500 +4300 +C300 +8300 +8200 +C600 +C600 +7E00 +ENDCHAR +STARTCHAR uni1E0C +ENCODING 7692 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 14 1 -2 +BITMAP +3F80 +30C0 +2060 +2060 +6060 +6060 +6060 +4060 +C040 +C0C0 +C180 +FE00 +0000 +3000 +ENDCHAR +STARTCHAR uni1E0D +ENCODING 7693 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 14 1 -2 +BITMAP +0080 +0180 +0180 +3D00 +6500 +4300 +C300 +8300 +8200 +C600 +C600 +7E00 +0000 +6000 +ENDCHAR +STARTCHAR uni1E0E +ENCODING 7694 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 14 1 -2 +BITMAP +3F80 +30C0 +2060 +2060 +6060 +6060 +6060 +4060 +C040 +C0C0 +C180 +FE00 +0000 +7E00 +ENDCHAR +STARTCHAR uni1E0F +ENCODING 7695 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 14 1 -2 +BITMAP +0080 +0180 +0180 +3D00 +6500 +4300 +C300 +8300 +8200 +C600 +C600 +7E00 +0000 +FC00 +ENDCHAR +STARTCHAR uni1E10 +ENCODING 7696 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 15 1 -3 +BITMAP +3F80 +30C0 +2060 +2060 +6060 +6060 +6060 +4060 +C040 +C0C0 +C180 +FE00 +1800 +0800 +1000 +ENDCHAR +STARTCHAR uni1E11 +ENCODING 7697 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 15 1 -3 +BITMAP +0080 +0180 +0180 +3D00 +6500 +4300 +C300 +8300 +8200 +C600 +C600 +7E00 +6000 +2000 +4000 +ENDCHAR +STARTCHAR uni1E12 +ENCODING 7698 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 15 1 -3 +BITMAP +3F80 +30C0 +2060 +2060 +6060 +6060 +6060 +4060 +C040 +C0C0 +C180 +FE00 +0000 +1800 +2C00 +ENDCHAR +STARTCHAR uni1E13 +ENCODING 7699 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 15 1 -3 +BITMAP +0080 +0180 +0180 +3D00 +6500 +4300 +C300 +8300 +8200 +C600 +C600 +7E00 +0000 +3000 +5800 +ENDCHAR +STARTCHAR uni1E14 +ENCODING 7700 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 17 1 0 +BITMAP +0200 +0100 +0000 +0F80 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR uni1E15 +ENCODING 7701 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +08 +0C +04 +1F +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR uni1E16 +ENCODING 7702 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 17 1 0 +BITMAP +0180 +0300 +0000 +0F80 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR uni1E17 +ENCODING 7703 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +06 +04 +08 +1F +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR uni1E18 +ENCODING 7704 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 15 1 -3 +BITMAP +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +0000 +1800 +2C00 +ENDCHAR +STARTCHAR uni1E19 +ENCODING 7705 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +00 +30 +58 +ENDCHAR +STARTCHAR uni1E1A +ENCODING 7706 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 1 -4 +BITMAP +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +0000 +0000 +3400 +4C00 +ENDCHAR +STARTCHAR uni1E1B +ENCODING 7707 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 -4 +BITMAP +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +00 +00 +68 +98 +ENDCHAR +STARTCHAR uni1E1C +ENCODING 7708 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 18 1 -3 +BITMAP +04C0 +0380 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +0C00 +0400 +3C00 +ENDCHAR +STARTCHAR uni1E1D +ENCODING 7709 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +13 +0E +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +18 +08 +78 +ENDCHAR +STARTCHAR uni1E1E +ENCODING 7710 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 14 1 0 +BITMAP +0600 +0000 +3FC0 +3000 +2000 +2000 +6000 +6000 +7F80 +4000 +4000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR uni1E1F +ENCODING 7711 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 14 1 0 +BITMAP +18 +00 +1C +30 +20 +F8 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR uni1E20 +ENCODING 7712 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 14 2 0 +BITMAP +0F80 +0000 +0F80 +30C0 +6060 +4060 +C000 +8000 +87C0 +8040 +80C0 +C0C0 +61C0 +3F00 +ENDCHAR +STARTCHAR uni1E21 +ENCODING 7713 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 14 0 -3 +BITMAP +0F80 +0000 +1E80 +3180 +2180 +6180 +4180 +4100 +4100 +6300 +3F00 +0300 +C600 +7C00 +ENDCHAR +STARTCHAR uni1E22 +ENCODING 7714 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 14 1 0 +BITMAP +0300 +0000 +3030 +3020 +2020 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C0C0 +8080 +ENDCHAR +STARTCHAR uni1E23 +ENCODING 7715 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +0C +00 +30 +20 +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR uni1E24 +ENCODING 7716 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 14 1 -2 +BITMAP +3030 +3020 +2020 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C0C0 +8080 +0000 +1800 +ENDCHAR +STARTCHAR uni1E25 +ENCODING 7717 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +30 +20 +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +86 +00 +60 +ENDCHAR +STARTCHAR uni1E26 +ENCODING 7718 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 14 1 0 +BITMAP +06C0 +0000 +3030 +3020 +2020 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C0C0 +8080 +ENDCHAR +STARTCHAR uni1E27 +ENCODING 7719 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +1B +00 +30 +20 +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR uni1E28 +ENCODING 7720 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 13 15 0 -3 +BITMAP +1818 +1810 +1010 +1030 +3030 +3FF0 +2020 +2020 +6060 +6060 +6060 +4040 +4000 +3000 +E000 +ENDCHAR +STARTCHAR uni1E29 +ENCODING 7721 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 15 0 -3 +BITMAP +1800 +1000 +1000 +3700 +3980 +3180 +2180 +2180 +6100 +6100 +4300 +4300 +4000 +3000 +E000 +ENDCHAR +STARTCHAR uni1E2A +ENCODING 7722 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 15 1 -3 +BITMAP +3030 +3020 +2020 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C0C0 +8080 +0000 +2400 +3800 +ENDCHAR +STARTCHAR uni1E2B +ENCODING 7723 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +30 +20 +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +86 +00 +48 +70 +ENDCHAR +STARTCHAR uni1E2C +ENCODING 7724 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 7 16 -2 -4 +BITMAP +06 +06 +06 +04 +04 +0C +0C +0C +08 +18 +18 +18 +00 +00 +68 +98 +ENDCHAR +STARTCHAR uni1E2D +ENCODING 7725 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 16 -2 -4 +BITMAP +04 +00 +00 +0C +0C +08 +08 +18 +18 +18 +10 +10 +00 +00 +68 +98 +ENDCHAR +STARTCHAR uni1E2E +ENCODING 7726 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 16 1 0 +BITMAP +0C +18 +24 +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni1E2F +ENCODING 7727 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 14 1 0 +BITMAP +18 +10 +20 +6C +00 +20 +20 +60 +60 +40 +40 +40 +C0 +C0 +ENDCHAR +STARTCHAR uni1E30 +ENCODING 7728 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 1 0 +BITMAP +0180 +0100 +0200 +0000 +3060 +30C0 +2380 +2700 +6E00 +7C00 +7600 +6200 +C300 +C180 +C180 +80C0 +ENDCHAR +STARTCHAR uni1E31 +ENCODING 7729 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +06 +04 +08 +00 +30 +20 +20 +63 +66 +4C +58 +68 +CC +CC +84 +86 +ENDCHAR +STARTCHAR uni1E32 +ENCODING 7730 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 14 1 -2 +BITMAP +3060 +30C0 +2380 +2700 +6E00 +7C00 +7600 +6200 +C300 +C180 +C180 +80C0 +0000 +1800 +ENDCHAR +STARTCHAR uni1E33 +ENCODING 7731 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +30 +20 +20 +63 +66 +4C +58 +68 +CC +CC +84 +86 +00 +60 +ENDCHAR +STARTCHAR uni1E34 +ENCODING 7732 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 14 1 -2 +BITMAP +3060 +30C0 +2380 +2700 +6E00 +7C00 +7600 +6200 +C300 +C180 +C180 +80C0 +0000 +3F00 +ENDCHAR +STARTCHAR uni1E35 +ENCODING 7733 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +30 +20 +20 +63 +66 +4C +58 +68 +CC +CC +84 +86 +00 +FC +ENDCHAR +STARTCHAR uni1E36 +ENCODING 7734 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +30 +30 +20 +60 +60 +60 +60 +40 +C0 +C0 +C0 +FF +00 +30 +ENDCHAR +STARTCHAR uni1E37 +ENCODING 7735 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 14 -1 -2 +BITMAP +08 +08 +18 +18 +18 +10 +10 +30 +30 +20 +20 +20 +00 +C0 +ENDCHAR +STARTCHAR uni1E38 +ENCODING 7736 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 -2 +BITMAP +1F +00 +30 +30 +20 +60 +60 +60 +60 +40 +C0 +C0 +C0 +FF +00 +30 +ENDCHAR +STARTCHAR uni1E39 +ENCODING 7737 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 8 16 -1 -2 +BITMAP +1F +00 +08 +08 +18 +18 +18 +10 +10 +30 +30 +20 +20 +20 +00 +C0 +ENDCHAR +STARTCHAR uni1E3A +ENCODING 7738 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +30 +30 +20 +60 +60 +60 +60 +40 +C0 +C0 +C0 +FF +00 +FC +ENDCHAR +STARTCHAR uni1E3B +ENCODING 7739 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 14 -2 -2 +BITMAP +04 +04 +0C +0C +0C +08 +08 +18 +18 +10 +10 +10 +00 +FC +ENDCHAR +STARTCHAR uni1E3C +ENCODING 7740 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +30 +30 +20 +60 +60 +60 +60 +40 +C0 +C0 +C0 +FF +00 +30 +58 +ENDCHAR +STARTCHAR uni1E3D +ENCODING 7741 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 15 -1 -3 +BITMAP +08 +08 +18 +18 +18 +10 +10 +30 +30 +20 +20 +20 +00 +60 +B0 +ENDCHAR +STARTCHAR uni1E3E +ENCODING 7742 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 14 16 1 0 +BITMAP +00C0 +0080 +0100 +0000 +300C +381C +3838 +2828 +6878 +6858 +4890 +4890 +CD30 +CD30 +C630 +8620 +ENDCHAR +STARTCHAR uni1E3F +ENCODING 7743 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 13 1 0 +BITMAP +00C0 +0080 +0100 +0000 +6E70 +7398 +6318 +4218 +C210 +C610 +C630 +8630 +8430 +ENDCHAR +STARTCHAR uni1E40 +ENCODING 7744 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 14 14 1 0 +BITMAP +0180 +0000 +300C +381C +3838 +2828 +6878 +6858 +4890 +4890 +CD30 +CD30 +C630 +8620 +ENDCHAR +STARTCHAR uni1E41 +ENCODING 7745 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 11 1 0 +BITMAP +0300 +0000 +6E70 +7398 +6318 +4218 +C210 +C610 +C630 +8630 +8430 +ENDCHAR +STARTCHAR uni1E42 +ENCODING 7746 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 14 14 1 -2 +BITMAP +300C +381C +3838 +2828 +6878 +6858 +4890 +4890 +CD30 +CD30 +C630 +8620 +0000 +0C00 +ENDCHAR +STARTCHAR uni1E43 +ENCODING 7747 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 11 1 -2 +BITMAP +6E70 +7398 +6318 +4218 +C210 +C610 +C630 +8630 +8430 +0000 +0C00 +ENDCHAR +STARTCHAR uni1E44 +ENCODING 7748 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 14 1 0 +BITMAP +0300 +0000 +3030 +3830 +2820 +2820 +6460 +6460 +6640 +4240 +4240 +C1C0 +C1C0 +C080 +ENDCHAR +STARTCHAR uni1E45 +ENCODING 7749 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +0C +00 +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +ENDCHAR +STARTCHAR uni1E46 +ENCODING 7750 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 14 1 -2 +BITMAP +3030 +3830 +2820 +2820 +6460 +6460 +6640 +4240 +4240 +C1C0 +C1C0 +C080 +0000 +1800 +ENDCHAR +STARTCHAR uni1E47 +ENCODING 7751 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 -2 +BITMAP +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +00 +30 +ENDCHAR +STARTCHAR uni1E48 +ENCODING 7752 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 14 1 -2 +BITMAP +3030 +3830 +2820 +2820 +6460 +6460 +6640 +4240 +4240 +C1C0 +C1C0 +C080 +0000 +7E00 +ENDCHAR +STARTCHAR uni1E49 +ENCODING 7753 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 -2 +BITMAP +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +00 +FC +ENDCHAR +STARTCHAR uni1E4A +ENCODING 7754 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 15 1 -3 +BITMAP +3030 +3830 +2820 +2820 +6460 +6460 +6640 +4240 +4240 +C1C0 +C1C0 +C080 +0000 +1800 +2C00 +ENDCHAR +STARTCHAR uni1E4B +ENCODING 7755 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +00 +30 +58 +ENDCHAR +STARTCHAR uni1E4C +ENCODING 7756 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 17 2 0 +BITMAP +0180 +0300 +0680 +0980 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni1E4D +ENCODING 7757 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 0 +BITMAP +06 +04 +08 +3A +2E +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1E4E +ENCODING 7758 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 17 2 0 +BITMAP +0480 +0000 +0680 +0980 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni1E4F +ENCODING 7759 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +1B +00 +3A +2E +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1E50 +ENCODING 7760 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 17 2 0 +BITMAP +0400 +0200 +0000 +1F00 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni1E51 +ENCODING 7761 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +08 +0C +04 +3E +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1E52 +ENCODING 7762 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 17 2 0 +BITMAP +0300 +0600 +0000 +1F00 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni1E53 +ENCODING 7763 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +03 +02 +04 +1F +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1E54 +ENCODING 7764 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 1 0 +BITMAP +0300 +0200 +0400 +0000 +3FC0 +3060 +2060 +2060 +6060 +60C0 +7F80 +4000 +C000 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni1E55 +ENCODING 7765 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0300 +0200 +0400 +0000 +3F00 +3180 +3080 +2080 +6080 +6180 +6100 +6300 +5E00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni1E56 +ENCODING 7766 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 14 1 0 +BITMAP +0600 +0000 +3FC0 +3060 +2060 +2060 +6060 +60C0 +7F80 +4000 +C000 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni1E57 +ENCODING 7767 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 14 0 -3 +BITMAP +0600 +0000 +3F00 +3180 +3080 +2080 +6080 +6180 +6100 +6300 +5E00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni1E58 +ENCODING 7768 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 14 1 0 +BITMAP +0600 +0000 +3FC0 +3060 +2020 +2020 +6020 +6060 +7F80 +4300 +4180 +C080 +C0C0 +C0C0 +ENDCHAR +STARTCHAR uni1E59 +ENCODING 7769 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 11 1 0 +BITMAP +18 +00 +6C +70 +60 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1E5A +ENCODING 7770 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 14 1 -2 +BITMAP +3FC0 +3060 +2020 +2020 +6020 +6060 +7F80 +4300 +4180 +C080 +C0C0 +C0C0 +0000 +1800 +ENDCHAR +STARTCHAR uni1E5B +ENCODING 7771 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 7 11 0 -2 +BITMAP +36 +38 +30 +20 +60 +60 +60 +40 +40 +00 +C0 +ENDCHAR +STARTCHAR uni1E5C +ENCODING 7772 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 1 -2 +BITMAP +0F80 +0000 +3FC0 +3060 +2020 +2020 +6020 +6060 +7F80 +4300 +4180 +C080 +C0C0 +C0C0 +0000 +1800 +ENDCHAR +STARTCHAR uni1E5D +ENCODING 7773 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 8 13 0 -2 +BITMAP +1F +00 +36 +38 +30 +20 +60 +60 +60 +40 +40 +00 +C0 +ENDCHAR +STARTCHAR uni1E5E +ENCODING 7774 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 14 1 -2 +BITMAP +3FC0 +3060 +2020 +2020 +6020 +6060 +7F80 +4300 +4180 +C080 +C0C0 +C0C0 +0000 +3F00 +ENDCHAR +STARTCHAR uni1E5F +ENCODING 7775 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 9 11 -2 -2 +BITMAP +0D80 +0E00 +0C00 +0800 +1800 +1800 +1800 +1000 +1000 +0000 +FC00 +ENDCHAR +STARTCHAR uni1E60 +ENCODING 7776 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 14 1 0 +BITMAP +0600 +0000 +1F80 +30C0 +2040 +2000 +3000 +1E00 +0780 +0180 +C0C0 +C080 +6180 +3E00 +ENDCHAR +STARTCHAR uni1E61 +ENCODING 7777 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 11 1 0 +BITMAP +18 +00 +3C +66 +42 +60 +3C +0E +86 +C6 +7C +ENDCHAR +STARTCHAR uni1E62 +ENCODING 7778 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 14 1 -2 +BITMAP +1F80 +30C0 +2040 +2000 +3000 +1E00 +0780 +0180 +C0C0 +C080 +6180 +3E00 +0000 +1800 +ENDCHAR +STARTCHAR uni1E63 +ENCODING 7779 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 11 1 -2 +BITMAP +3C +66 +42 +60 +3C +0E +86 +C6 +7C +00 +30 +ENDCHAR +STARTCHAR uni1E64 +ENCODING 7780 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 17 1 0 +BITMAP +0300 +0000 +0300 +0200 +0000 +1F80 +30C0 +2040 +2000 +3000 +1E00 +0780 +0180 +C0C0 +C080 +6180 +3E00 +ENDCHAR +STARTCHAR uni1E65 +ENCODING 7781 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 15 1 0 +BITMAP +0C +00 +0C +08 +10 +00 +3C +66 +42 +60 +3C +0E +86 +C6 +7C +ENDCHAR +STARTCHAR uni1E66 +ENCODING 7782 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 17 1 0 +BITMAP +0300 +0000 +0500 +0300 +0000 +1F80 +30C0 +2040 +2000 +3000 +1E00 +0780 +0180 +C0C0 +C080 +6180 +3E00 +ENDCHAR +STARTCHAR uni1E67 +ENCODING 7783 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 15 1 0 +BITMAP +0C +00 +36 +1C +18 +00 +3C +66 +42 +60 +3C +0E +86 +C6 +7C +ENDCHAR +STARTCHAR uni1E68 +ENCODING 7784 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 1 -2 +BITMAP +0600 +0000 +1F80 +30C0 +2040 +2000 +3000 +1E00 +0780 +0180 +C0C0 +C080 +6180 +3E00 +0000 +1800 +ENDCHAR +STARTCHAR uni1E69 +ENCODING 7785 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 13 1 -2 +BITMAP +18 +00 +3C +66 +42 +60 +3C +0E +86 +C6 +7C +00 +30 +ENDCHAR +STARTCHAR uni1E6A +ENCODING 7786 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 14 2 0 +BITMAP +0C00 +0000 +FFC0 +0C00 +0800 +0800 +1800 +1800 +1800 +1000 +1000 +3000 +3000 +3000 +ENDCHAR +STARTCHAR uni1E6B +ENCODING 7787 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 14 1 0 +BITMAP +30 +00 +10 +20 +20 +F0 +60 +40 +40 +40 +C0 +C0 +C0 +E0 +ENDCHAR +STARTCHAR uni1E6C +ENCODING 7788 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 14 2 -2 +BITMAP +FFC0 +0C00 +0800 +0800 +1800 +1800 +1800 +1000 +1000 +3000 +3000 +3000 +0000 +6000 +ENDCHAR +STARTCHAR uni1E6D +ENCODING 7789 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 14 0 -2 +BITMAP +08 +10 +10 +78 +30 +20 +20 +20 +60 +60 +60 +70 +00 +C0 +ENDCHAR +STARTCHAR uni1E6E +ENCODING 7790 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 11 14 1 -2 +BITMAP +7FE0 +0600 +0400 +0400 +0C00 +0C00 +0C00 +0800 +0800 +1800 +1800 +1800 +0000 +FC00 +ENDCHAR +STARTCHAR uni1E6F +ENCODING 7791 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 14 -1 -2 +BITMAP +04 +08 +08 +3C +18 +10 +10 +10 +30 +30 +30 +38 +00 +FC +ENDCHAR +STARTCHAR uni1E70 +ENCODING 7792 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 15 2 -3 +BITMAP +FFC0 +0C00 +0800 +0800 +1800 +1800 +1800 +1000 +1000 +3000 +3000 +3000 +0000 +6000 +B000 +ENDCHAR +STARTCHAR uni1E71 +ENCODING 7793 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 15 0 -3 +BITMAP +08 +10 +10 +78 +30 +20 +20 +20 +60 +60 +60 +70 +00 +60 +B0 +ENDCHAR +STARTCHAR uni1E72 +ENCODING 7794 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 15 2 -3 +BITMAP +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +0000 +0000 +2400 +ENDCHAR +STARTCHAR uni1E73 +ENCODING 7795 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +00 +00 +48 +ENDCHAR +STARTCHAR uni1E74 +ENCODING 7796 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 2 -4 +BITMAP +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +0000 +0000 +3400 +4C00 +ENDCHAR +STARTCHAR uni1E75 +ENCODING 7797 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 -4 +BITMAP +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +00 +00 +68 +98 +ENDCHAR +STARTCHAR uni1E76 +ENCODING 7798 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 15 2 -3 +BITMAP +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +0000 +3000 +5800 +ENDCHAR +STARTCHAR uni1E77 +ENCODING 7799 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +00 +30 +58 +ENDCHAR +STARTCHAR uni1E78 +ENCODING 7800 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 17 2 0 +BITMAP +0180 +0300 +0680 +0980 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni1E79 +ENCODING 7801 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +03 +02 +04 +00 +1D +17 +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uni1E7A +ENCODING 7802 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 2 0 +BITMAP +0480 +0000 +0F80 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni1E7B +ENCODING 7803 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +1B +00 +00 +1F +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uni1E7C +ENCODING 7804 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 15 2 0 +BITMAP +1D00 +1700 +0000 +C060 +C0C0 +4080 +4180 +6100 +6300 +6200 +2600 +2C00 +3C00 +3800 +3000 +ENDCHAR +STARTCHAR uni1E7D +ENCODING 7805 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +3A +2E +00 +C1 +43 +42 +46 +6C +68 +78 +30 +30 +ENDCHAR +STARTCHAR uni1E7E +ENCODING 7806 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 14 2 -2 +BITMAP +C060 +C0C0 +4080 +4180 +6100 +6300 +6200 +2600 +2C00 +3C00 +3800 +3000 +0000 +3000 +ENDCHAR +STARTCHAR uni1E7F +ENCODING 7807 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 11 1 -2 +BITMAP +C1 +43 +42 +46 +6C +68 +78 +30 +30 +00 +60 +ENDCHAR +STARTCHAR Wgrave +ENCODING 7808 +SWIDTH 943 0 +DWIDTH 16 0 +BBX 16 16 2 0 +BITMAP +0100 +0180 +0080 +0000 +C183 +C182 +C386 +C684 +C68C +CC88 +4898 +5890 +50B0 +70A0 +60E0 +60C0 +ENDCHAR +STARTCHAR wgrave +ENCODING 7809 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 13 1 0 +BITMAP +0400 +0600 +0200 +0000 +C630 +C620 +4E20 +4A60 +4A40 +52C0 +5280 +6280 +6300 +ENDCHAR +STARTCHAR Wacute +ENCODING 7810 +SWIDTH 943 0 +DWIDTH 16 0 +BBX 16 16 2 0 +BITMAP +00C0 +0080 +0100 +0000 +C183 +C182 +C386 +C684 +C68C +CC88 +4898 +5890 +50B0 +70A0 +60E0 +60C0 +ENDCHAR +STARTCHAR wacute +ENCODING 7811 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 13 1 0 +BITMAP +0300 +0200 +0400 +0000 +C630 +C620 +4E20 +4A60 +4A40 +52C0 +5280 +6280 +6300 +ENDCHAR +STARTCHAR Wdieresis +ENCODING 7812 +SWIDTH 943 0 +DWIDTH 16 0 +BBX 16 14 2 0 +BITMAP +0360 +0000 +C183 +C182 +C386 +C684 +C68C +CC88 +4898 +5890 +50B0 +70A0 +60E0 +60C0 +ENDCHAR +STARTCHAR wdieresis +ENCODING 7813 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 11 1 0 +BITMAP +0D80 +0000 +C630 +C620 +4E20 +4A60 +4A40 +52C0 +5280 +6280 +6300 +ENDCHAR +STARTCHAR uni1E86 +ENCODING 7814 +SWIDTH 943 0 +DWIDTH 16 0 +BBX 16 14 2 0 +BITMAP +0180 +0000 +C183 +C182 +C386 +C684 +C68C +CC88 +4898 +5890 +50B0 +70A0 +60E0 +60C0 +ENDCHAR +STARTCHAR uni1E87 +ENCODING 7815 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 11 1 0 +BITMAP +0600 +0000 +C630 +C620 +4E20 +4A60 +4A40 +52C0 +5280 +6280 +6300 +ENDCHAR +STARTCHAR uni1E88 +ENCODING 7816 +SWIDTH 943 0 +DWIDTH 16 0 +BBX 16 14 2 -2 +BITMAP +C183 +C182 +C386 +C684 +C68C +CC88 +4898 +5890 +50B0 +70A0 +60E0 +60C0 +0000 +0C00 +ENDCHAR +STARTCHAR uni1E89 +ENCODING 7817 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 11 1 -2 +BITMAP +C630 +C620 +4E20 +4A60 +4A40 +52C0 +5280 +6280 +6300 +0000 +1800 +ENDCHAR +STARTCHAR uni1E8A +ENCODING 7818 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 13 14 0 0 +BITMAP +0300 +0000 +3038 +1870 +18E0 +0CC0 +0D80 +0700 +0600 +0F00 +1980 +3180 +60C0 +C0C0 +ENDCHAR +STARTCHAR uni1E8B +ENCODING 7819 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 11 0 0 +BITMAP +0C00 +0000 +2180 +3300 +1600 +1C00 +0800 +1C00 +3400 +6600 +C200 +ENDCHAR +STARTCHAR uni1E8C +ENCODING 7820 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 13 14 0 0 +BITMAP +06C0 +0000 +3038 +1870 +18E0 +0CC0 +0D80 +0700 +0600 +0F00 +1980 +3180 +60C0 +C0C0 +ENDCHAR +STARTCHAR uni1E8D +ENCODING 7821 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 11 0 0 +BITMAP +1B00 +0000 +2180 +3300 +1600 +1C00 +0800 +1C00 +3400 +6600 +C200 +ENDCHAR +STARTCHAR uni1E8E +ENCODING 7822 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 14 2 0 +BITMAP +0C00 +0000 +C060 +60C0 +6180 +3300 +3300 +1600 +1C00 +0800 +0800 +1800 +1800 +1000 +ENDCHAR +STARTCHAR uni1E8F +ENCODING 7823 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 14 0 -3 +BITMAP +0600 +0000 +2080 +2180 +2100 +3300 +3600 +3400 +1C00 +1800 +1800 +1000 +2000 +E000 +ENDCHAR +STARTCHAR uni1E90 +ENCODING 7824 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 11 16 0 0 +BITMAP +0180 +0280 +0680 +0000 +3FE0 +00C0 +0180 +0180 +0300 +0600 +0C00 +1800 +1800 +3000 +6000 +FFC0 +ENDCHAR +STARTCHAR uni1E91 +ENCODING 7825 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 13 0 0 +BITMAP +0600 +0A00 +1A00 +0000 +3F80 +0300 +0600 +0C00 +0800 +1800 +3000 +6000 +FF00 +ENDCHAR +STARTCHAR uni1E92 +ENCODING 7826 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 11 14 0 -2 +BITMAP +3FE0 +00C0 +0180 +0180 +0300 +0600 +0C00 +1800 +1800 +3000 +6000 +FFC0 +0000 +1800 +ENDCHAR +STARTCHAR uni1E93 +ENCODING 7827 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 11 0 -2 +BITMAP +3F80 +0300 +0600 +0C00 +0800 +1800 +3000 +6000 +FF00 +0000 +3000 +ENDCHAR +STARTCHAR uni1E94 +ENCODING 7828 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 11 14 0 -2 +BITMAP +3FE0 +00C0 +0180 +0180 +0300 +0600 +0C00 +1800 +1800 +3000 +6000 +FFC0 +0000 +3F00 +ENDCHAR +STARTCHAR uni1E95 +ENCODING 7829 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 11 0 -2 +BITMAP +3F80 +0300 +0600 +0C00 +0800 +1800 +3000 +6000 +FF00 +0000 +7E00 +ENDCHAR +STARTCHAR uni1E96 +ENCODING 7830 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +30 +20 +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +86 +00 +FC +ENDCHAR +STARTCHAR uni1E97 +ENCODING 7831 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 14 1 0 +BITMAP +6C +00 +10 +20 +20 +F0 +60 +40 +40 +40 +C0 +C0 +C0 +E0 +ENDCHAR +STARTCHAR uni1E98 +ENCODING 7832 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 14 1 0 +BITMAP +0600 +0900 +0900 +0600 +0000 +C630 +C620 +4E20 +4A60 +4A40 +52C0 +5280 +6280 +6300 +ENDCHAR +STARTCHAR uni1E99 +ENCODING 7833 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 17 0 -3 +BITMAP +0C00 +1200 +1200 +0C00 +0000 +2080 +2180 +2100 +3300 +3600 +3400 +1C00 +1800 +1800 +1000 +2000 +E000 +ENDCHAR +STARTCHAR uni1E9A +ENCODING 7834 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +04 +04 +04 +04 +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni1E9B +ENCODING 7835 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 14 1 0 +BITMAP +18 +00 +3C +20 +60 +60 +60 +40 +40 +C0 +C0 +80 +80 +80 +ENDCHAR +STARTCHAR uni1E9C +ENCODING 7836 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 7 12 0 0 +BITMAP +0E +18 +10 +70 +38 +30 +60 +A0 +20 +60 +60 +40 +ENDCHAR +STARTCHAR uni1E9D +ENCODING 7837 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 12 1 0 +BITMAP +1C +30 +F8 +20 +E0 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR uni1E9E +ENCODING 7838 +SWIDTH 672 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +0F80 +1040 +30E0 +2180 +6300 +6780 +40C0 +4040 +C040 +C0C0 +C180 +9F00 +ENDCHAR +STARTCHAR uni1E9F +ENCODING 7839 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1F +20 +30 +1C +23 +43 +C1 +81 +83 +82 +C6 +78 +ENDCHAR +STARTCHAR uni1EA0 +ENCODING 7840 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 14 0 -2 +BITMAP +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +0000 +1800 +ENDCHAR +STARTCHAR uni1EA1 +ENCODING 7841 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 -2 +BITMAP +1E +63 +43 +03 +7F +C2 +86 +CE +7A +00 +30 +ENDCHAR +STARTCHAR uni1EA2 +ENCODING 7842 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 0 0 +BITMAP +0380 +0080 +0100 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1EA3 +ENCODING 7843 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +0E +03 +06 +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni1EA4 +ENCODING 7844 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 0 0 +BITMAP +0180 +0100 +0300 +0680 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1EA5 +ENCODING 7845 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +02 +04 +00 +06 +0A +1A +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni1EA6 +ENCODING 7846 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 0 0 +BITMAP +0300 +0100 +0300 +0680 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1EA7 +ENCODING 7847 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +0C +04 +00 +06 +0A +1A +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni1EA8 +ENCODING 7848 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 0 0 +BITMAP +03C0 +0100 +0300 +0680 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1EA9 +ENCODING 7849 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +0E +02 +04 +06 +0A +1A +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni1EAA +ENCODING 7850 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 0 0 +BITMAP +0740 +0580 +0300 +0680 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1EAB +ENCODING 7851 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +19 +16 +00 +06 +0A +1A +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni1EAC +ENCODING 7852 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 17 0 -2 +BITMAP +0180 +0340 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +0000 +1800 +ENDCHAR +STARTCHAR uni1EAD +ENCODING 7853 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -2 +BITMAP +06 +0A +1A +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +00 +30 +ENDCHAR +STARTCHAR uni1EAE +ENCODING 7854 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 0 0 +BITMAP +0180 +0100 +0240 +01C0 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1EAF +ENCODING 7855 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +02 +04 +00 +00 +13 +0E +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni1EB0 +ENCODING 7856 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 0 0 +BITMAP +0300 +0100 +0240 +01C0 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1EB1 +ENCODING 7857 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +0C +04 +00 +00 +13 +0E +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni1EB2 +ENCODING 7858 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 0 0 +BITMAP +03C0 +0100 +0240 +01C0 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1EB3 +ENCODING 7859 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +0E +02 +04 +00 +13 +0E +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni1EB4 +ENCODING 7860 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 0 0 +BITMAP +03A0 +02C0 +0240 +01C0 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1EB5 +ENCODING 7861 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +19 +16 +00 +00 +13 +0E +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +ENDCHAR +STARTCHAR uni1EB6 +ENCODING 7862 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 17 0 -2 +BITMAP +0240 +01C0 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +0000 +1800 +ENDCHAR +STARTCHAR uni1EB7 +ENCODING 7863 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +13 +0E +00 +1E +63 +43 +03 +7F +C2 +86 +CE +7A +00 +30 +ENDCHAR +STARTCHAR uni1EB8 +ENCODING 7864 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 14 1 -2 +BITMAP +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +0000 +1800 +ENDCHAR +STARTCHAR uni1EB9 +ENCODING 7865 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 -2 +BITMAP +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +00 +30 +ENDCHAR +STARTCHAR uni1EBA +ENCODING 7866 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 1 0 +BITMAP +0700 +0100 +0200 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR uni1EBB +ENCODING 7867 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +1C +06 +0C +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR uni1EBC +ENCODING 7868 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 15 1 0 +BITMAP +0E80 +0B80 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR uni1EBD +ENCODING 7869 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1D +17 +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR uni1EBE +ENCODING 7870 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 1 0 +BITMAP +0180 +0100 +0300 +0680 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR uni1EBF +ENCODING 7871 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +02 +04 +00 +06 +0A +1A +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR uni1EC0 +ENCODING 7872 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 1 0 +BITMAP +0600 +0200 +0300 +0680 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR uni1EC1 +ENCODING 7873 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +06 +02 +00 +06 +0A +1A +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR uni1EC2 +ENCODING 7874 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 1 0 +BITMAP +0780 +0200 +0300 +0680 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR uni1EC3 +ENCODING 7875 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +0E +02 +04 +06 +0A +1A +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR uni1EC4 +ENCODING 7876 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 1 0 +BITMAP +0740 +0580 +0300 +0680 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +ENDCHAR +STARTCHAR uni1EC5 +ENCODING 7877 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +19 +16 +00 +06 +0A +1A +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +ENDCHAR +STARTCHAR uni1EC6 +ENCODING 7878 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 17 1 -2 +BITMAP +0300 +0680 +0000 +3FE0 +3000 +2000 +2000 +6000 +7FC0 +4000 +4000 +4000 +C000 +C000 +FF80 +0000 +1800 +ENDCHAR +STARTCHAR uni1EC7 +ENCODING 7879 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -2 +BITMAP +06 +0A +1A +00 +1E +63 +43 +C1 +FF +80 +C2 +C6 +78 +00 +30 +ENDCHAR +STARTCHAR uni1EC8 +ENCODING 7880 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 16 1 0 +BITMAP +38 +08 +10 +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni1EC9 +ENCODING 7881 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 13 1 0 +BITMAP +70 +18 +30 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1ECA +ENCODING 7882 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 14 0 -2 +BITMAP +18 +18 +18 +10 +10 +30 +30 +30 +20 +60 +60 +60 +00 +C0 +ENDCHAR +STARTCHAR uni1ECB +ENCODING 7883 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 14 -1 -2 +BITMAP +08 +00 +00 +18 +18 +10 +10 +30 +30 +30 +20 +20 +00 +C0 +ENDCHAR +STARTCHAR uni1ECC +ENCODING 7884 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 14 2 -2 +BITMAP +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +0000 +1800 +ENDCHAR +STARTCHAR uni1ECD +ENCODING 7885 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 -2 +BITMAP +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +00 +30 +ENDCHAR +STARTCHAR uni1ECE +ENCODING 7886 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0700 +0100 +0200 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni1ECF +ENCODING 7887 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +0E +03 +06 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1ED0 +ENCODING 7888 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0300 +0200 +0600 +0D00 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni1ED1 +ENCODING 7889 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +02 +04 +00 +06 +0A +1A +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1ED2 +ENCODING 7890 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0600 +0200 +0600 +0D00 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni1ED3 +ENCODING 7891 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +0C +04 +00 +06 +0A +1A +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1ED4 +ENCODING 7892 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0780 +0200 +0600 +0D00 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni1ED5 +ENCODING 7893 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +0E +02 +04 +06 +0A +1A +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1ED6 +ENCODING 7894 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0E80 +0B00 +0600 +0D00 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni1ED7 +ENCODING 7895 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +19 +16 +00 +06 +0A +1A +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1ED8 +ENCODING 7896 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 17 2 -2 +BITMAP +0600 +0D00 +0000 +1F00 +30C0 +6060 +C060 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +0000 +1800 +ENDCHAR +STARTCHAR uni1ED9 +ENCODING 7897 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -2 +BITMAP +06 +0A +1A +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +00 +30 +ENDCHAR +STARTCHAR uni1EDA +ENCODING 7898 +SWIDTH 811 0 +DWIDTH 14 0 +BBX 13 16 2 0 +BITMAP +0300 +0200 +0400 +0000 +1F18 +30C8 +6068 +C070 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni1EDB +ENCODING 7899 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 10 13 1 0 +BITMAP +0600 +0400 +0800 +0000 +3E40 +6340 +4140 +C180 +8100 +8300 +8200 +C600 +7800 +ENDCHAR +STARTCHAR uni1EDC +ENCODING 7900 +SWIDTH 811 0 +DWIDTH 14 0 +BBX 13 16 2 0 +BITMAP +0200 +0300 +0100 +0000 +1F18 +30C8 +6068 +C070 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni1EDD +ENCODING 7901 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 10 13 1 0 +BITMAP +0800 +0C00 +0400 +0000 +3E40 +6340 +4140 +C180 +8100 +8300 +8200 +C600 +7800 +ENDCHAR +STARTCHAR uni1EDE +ENCODING 7902 +SWIDTH 811 0 +DWIDTH 14 0 +BBX 13 16 2 0 +BITMAP +0700 +0100 +0200 +0000 +1F18 +30C8 +6068 +C070 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni1EDF +ENCODING 7903 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 10 13 1 0 +BITMAP +0E00 +0300 +0600 +0000 +3E40 +6340 +4140 +C180 +8100 +8300 +8200 +C600 +7800 +ENDCHAR +STARTCHAR uni1EE0 +ENCODING 7904 +SWIDTH 811 0 +DWIDTH 14 0 +BBX 13 15 2 0 +BITMAP +0E80 +0B80 +0000 +1F18 +30C8 +6068 +C070 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uni1EE1 +ENCODING 7905 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 10 12 1 0 +BITMAP +1D00 +1700 +0000 +3E40 +6340 +4140 +C180 +8100 +8300 +8200 +C600 +7800 +ENDCHAR +STARTCHAR uni1EE2 +ENCODING 7906 +SWIDTH 811 0 +DWIDTH 14 0 +BBX 13 14 2 -2 +BITMAP +1F18 +30C8 +6068 +C070 +C060 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +0000 +1800 +ENDCHAR +STARTCHAR uni1EE3 +ENCODING 7907 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 10 11 1 -2 +BITMAP +3E40 +6340 +4140 +C180 +8100 +8300 +8200 +C600 +7800 +0000 +3000 +ENDCHAR +STARTCHAR uni1EE4 +ENCODING 7908 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 14 2 -2 +BITMAP +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +0000 +3000 +ENDCHAR +STARTCHAR uni1EE5 +ENCODING 7909 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 -2 +BITMAP +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +00 +60 +ENDCHAR +STARTCHAR uni1EE6 +ENCODING 7910 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 16 2 0 +BITMAP +0700 +0100 +0200 +0000 +6060 +6060 +4040 +40C0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni1EE7 +ENCODING 7911 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +0E +03 +06 +00 +61 +61 +43 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uni1EE8 +ENCODING 7912 +SWIDTH 793 0 +DWIDTH 13 0 +BBX 14 16 2 0 +BITMAP +0300 +0200 +0400 +0000 +606C +6048 +4048 +40F0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni1EE9 +ENCODING 7913 +SWIDTH 633 0 +DWIDTH 11 0 +BBX 11 13 1 0 +BITMAP +0600 +0400 +0800 +0000 +6160 +6120 +4320 +43C0 +C200 +C200 +C600 +CA00 +7600 +ENDCHAR +STARTCHAR uni1EEA +ENCODING 7914 +SWIDTH 793 0 +DWIDTH 13 0 +BBX 14 16 2 0 +BITMAP +0400 +0600 +0200 +0000 +606C +6048 +4048 +40F0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni1EEB +ENCODING 7915 +SWIDTH 633 0 +DWIDTH 11 0 +BBX 11 13 1 0 +BITMAP +0800 +0C00 +0400 +0000 +6160 +6120 +4320 +43C0 +C200 +C200 +C600 +CA00 +7600 +ENDCHAR +STARTCHAR uni1EEC +ENCODING 7916 +SWIDTH 793 0 +DWIDTH 13 0 +BBX 14 16 2 0 +BITMAP +0700 +0100 +0200 +0000 +606C +6048 +4048 +40F0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni1EED +ENCODING 7917 +SWIDTH 633 0 +DWIDTH 11 0 +BBX 11 13 1 0 +BITMAP +0E00 +0300 +0600 +0000 +6160 +6120 +4320 +43C0 +C200 +C200 +C600 +CA00 +7600 +ENDCHAR +STARTCHAR uni1EEE +ENCODING 7918 +SWIDTH 793 0 +DWIDTH 13 0 +BBX 14 15 2 0 +BITMAP +0E80 +0B80 +0000 +606C +6048 +4048 +40F0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +ENDCHAR +STARTCHAR uni1EEF +ENCODING 7919 +SWIDTH 633 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +1D00 +1700 +0000 +6160 +6120 +4320 +43C0 +C200 +C200 +C600 +CA00 +7600 +ENDCHAR +STARTCHAR uni1EF0 +ENCODING 7920 +SWIDTH 793 0 +DWIDTH 13 0 +BBX 14 14 2 -2 +BITMAP +606C +6048 +4048 +40F0 +C0C0 +C0C0 +C080 +8080 +8180 +8100 +C300 +7C00 +0000 +3000 +ENDCHAR +STARTCHAR uni1EF1 +ENCODING 7921 +SWIDTH 633 0 +DWIDTH 11 0 +BBX 11 11 1 -2 +BITMAP +6160 +6120 +4320 +43C0 +C200 +C200 +C600 +CA00 +7600 +0000 +6000 +ENDCHAR +STARTCHAR Ygrave +ENCODING 7922 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 2 0 +BITMAP +0400 +0600 +0200 +0000 +C060 +60C0 +6180 +3300 +3300 +1600 +1C00 +0800 +0800 +1800 +1800 +1000 +ENDCHAR +STARTCHAR ygrave +ENCODING 7923 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0800 +0C00 +0400 +0000 +2080 +2180 +2100 +3300 +3600 +3400 +1C00 +1800 +1800 +1000 +2000 +E000 +ENDCHAR +STARTCHAR uni1EF4 +ENCODING 7924 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 14 2 -2 +BITMAP +C060 +60C0 +6180 +3300 +3300 +1600 +1C00 +0800 +0800 +1800 +1800 +1000 +0000 +3000 +ENDCHAR +STARTCHAR uni1EF5 +ENCODING 7925 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +2080 +2180 +2100 +3300 +3600 +3400 +1C00 +1800 +1800 +1000 +2600 +E000 +ENDCHAR +STARTCHAR uni1EF6 +ENCODING 7926 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 16 2 0 +BITMAP +0E00 +0200 +0400 +0000 +C060 +60C0 +6180 +3300 +3300 +1600 +1C00 +0800 +0800 +1800 +1800 +1000 +ENDCHAR +STARTCHAR uni1EF7 +ENCODING 7927 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0E00 +0300 +0600 +0000 +2080 +2180 +2100 +3300 +3600 +3400 +1C00 +1800 +1800 +1000 +2000 +E000 +ENDCHAR +STARTCHAR uni1EF8 +ENCODING 7928 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 15 2 0 +BITMAP +0E80 +0B80 +0000 +C060 +60C0 +6180 +3300 +3300 +1600 +1C00 +0800 +0800 +1800 +1800 +1000 +ENDCHAR +STARTCHAR uni1EF9 +ENCODING 7929 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 15 0 -3 +BITMAP +0E80 +0B80 +0000 +2080 +2180 +2100 +3300 +3600 +3400 +1C00 +1800 +1800 +1000 +2000 +E000 +ENDCHAR +STARTCHAR uni1EFA +ENCODING 7930 +SWIDTH 766 0 +DWIDTH 13 0 +BBX 11 12 1 0 +BITMAP +3200 +3600 +3600 +2600 +2600 +6400 +6C00 +6C00 +4C00 +C800 +C800 +DFE0 +ENDCHAR +STARTCHAR uni1EFB +ENCODING 7931 +SWIDTH 397 0 +DWIDTH 7 0 +BBX 7 12 1 0 +BITMAP +24 +7E +6C +6C +48 +48 +48 +D8 +D8 +90 +90 +90 +ENDCHAR +STARTCHAR uni1EFC +ENCODING 7932 +SWIDTH 611 0 +DWIDTH 10 0 +BBX 8 12 2 0 +BITMAP +06 +18 +30 +22 +63 +C3 +C1 +81 +83 +82 +C6 +78 +ENDCHAR +STARTCHAR uni1EFD +ENCODING 7933 +SWIDTH 561 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +06 +08 +10 +32 +63 +41 +C1 +C1 +83 +82 +C6 +78 +ENDCHAR +STARTCHAR uni1EFE +ENCODING 7934 +SWIDTH 695 0 +DWIDTH 12 0 +BBX 13 12 0 0 +BITMAP +1818 +0830 +0C30 +0460 +06C0 +0780 +0300 +0700 +7E00 +8C00 +9800 +F000 +ENDCHAR +STARTCHAR uni1EFF +ENCODING 7935 +SWIDTH 560 0 +DWIDTH 10 0 +BBX 12 12 -2 -3 +BITMAP +0C30 +0C20 +0460 +0640 +06C0 +0380 +0300 +0300 +7E00 +4400 +C800 +7000 +ENDCHAR +STARTCHAR uni1F00 +ENCODING 7936 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +0C00 +0400 +0800 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR uni1F01 +ENCODING 7937 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +0400 +0800 +0400 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR uni1F02 +ENCODING 7938 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +1A00 +1B00 +1000 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR uni1F03 +ENCODING 7939 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +1A00 +1300 +1000 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR uni1F04 +ENCODING 7940 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +1B00 +1E00 +1000 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR uni1F05 +ENCODING 7941 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +1B00 +1600 +1000 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR uni1F06 +ENCODING 7942 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 16 1 0 +BITMAP +1D00 +1300 +0000 +0C00 +0400 +0800 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR uni1F07 +ENCODING 7943 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 16 1 0 +BITMAP +1D00 +1300 +0000 +0400 +0800 +0400 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR uni1F08 +ENCODING 7944 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 0 0 +BITMAP +3380 +1380 +2780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1F09 +ENCODING 7945 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 0 0 +BITMAP +1380 +2380 +1780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1F0A +ENCODING 7946 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 10 12 2 0 +BITMAP +D380 +DB80 +8780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1F0B +ENCODING 7947 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 10 12 2 0 +BITMAP +D380 +9B80 +8780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1F0C +ENCODING 7948 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 10 12 2 0 +BITMAP +DB80 +F380 +8780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1F0D +ENCODING 7949 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 10 12 2 0 +BITMAP +DB80 +B380 +8780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1F0E +ENCODING 7950 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 10 15 2 0 +BITMAP +E800 +9800 +0000 +6380 +2380 +4780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1F0F +ENCODING 7951 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 10 15 2 0 +BITMAP +E800 +9800 +0000 +2380 +4380 +2780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1F10 +ENCODING 7952 +SWIDTH 439 0 +DWIDTH 7 0 +BBX 6 13 1 0 +BITMAP +0C +04 +08 +00 +3C +64 +40 +60 +70 +C0 +80 +88 +78 +ENDCHAR +STARTCHAR uni1F11 +ENCODING 7953 +SWIDTH 439 0 +DWIDTH 7 0 +BBX 6 13 1 0 +BITMAP +08 +10 +08 +00 +3C +64 +40 +60 +70 +C0 +80 +88 +78 +ENDCHAR +STARTCHAR uni1F12 +ENCODING 7954 +SWIDTH 439 0 +DWIDTH 7 0 +BBX 7 13 1 0 +BITMAP +34 +36 +20 +00 +3C +64 +40 +60 +70 +C0 +80 +88 +78 +ENDCHAR +STARTCHAR uni1F13 +ENCODING 7955 +SWIDTH 439 0 +DWIDTH 7 0 +BBX 7 13 1 0 +BITMAP +34 +26 +20 +00 +3C +64 +40 +60 +70 +C0 +80 +88 +78 +ENDCHAR +STARTCHAR uni1F14 +ENCODING 7956 +SWIDTH 439 0 +DWIDTH 7 0 +BBX 8 13 1 0 +BITMAP +1B +1E +10 +00 +3C +64 +40 +60 +70 +C0 +80 +88 +78 +ENDCHAR +STARTCHAR uni1F15 +ENCODING 7957 +SWIDTH 439 0 +DWIDTH 7 0 +BBX 8 13 1 0 +BITMAP +1B +16 +10 +00 +3C +64 +40 +60 +70 +C0 +80 +88 +78 +ENDCHAR +STARTCHAR uni1F18 +ENCODING 7960 +SWIDTH 764 0 +DWIDTH 13 0 +BBX 13 12 1 0 +BITMAP +CFF8 +4C00 +8800 +0800 +1800 +1FF0 +1000 +1000 +1000 +3000 +3000 +3FE0 +ENDCHAR +STARTCHAR uni1F19 +ENCODING 7961 +SWIDTH 764 0 +DWIDTH 13 0 +BBX 13 12 1 0 +BITMAP +4FF8 +8C00 +4800 +0800 +1800 +1FF0 +1000 +1000 +1000 +3000 +3000 +3FE0 +ENDCHAR +STARTCHAR uni1F1A +ENCODING 7962 +SWIDTH 959 0 +DWIDTH 16 0 +BBX 15 12 2 0 +BITMAP +D3FE +DB00 +8200 +0200 +0600 +07FC +0400 +0400 +0400 +0C00 +0C00 +0FF8 +ENDCHAR +STARTCHAR uni1F1B +ENCODING 7963 +SWIDTH 959 0 +DWIDTH 16 0 +BBX 15 12 2 0 +BITMAP +D3FE +9B00 +8200 +0200 +0600 +07FC +0400 +0400 +0400 +0C00 +0C00 +0FF8 +ENDCHAR +STARTCHAR uni1F1C +ENCODING 7964 +SWIDTH 959 0 +DWIDTH 16 0 +BBX 15 12 2 0 +BITMAP +DBFE +F300 +8200 +0200 +0600 +07FC +0400 +0400 +0400 +0C00 +0C00 +0FF8 +ENDCHAR +STARTCHAR uni1F1D +ENCODING 7965 +SWIDTH 959 0 +DWIDTH 16 0 +BBX 15 12 2 0 +BITMAP +DBFE +B300 +8200 +0200 +0600 +07FC +0400 +0400 +0400 +0C00 +0C00 +0FF8 +ENDCHAR +STARTCHAR uni1F20 +ENCODING 7968 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 8 16 1 -3 +BITMAP +0C +04 +08 +00 +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +06 +04 +04 +ENDCHAR +STARTCHAR uni1F21 +ENCODING 7969 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 8 16 1 -3 +BITMAP +04 +08 +04 +00 +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +06 +04 +04 +ENDCHAR +STARTCHAR uni1F22 +ENCODING 7970 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 8 16 1 -3 +BITMAP +1A +1B +10 +00 +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +06 +04 +04 +ENDCHAR +STARTCHAR uni1F23 +ENCODING 7971 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 8 16 1 -3 +BITMAP +1A +13 +10 +00 +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +06 +04 +04 +ENDCHAR +STARTCHAR uni1F24 +ENCODING 7972 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 16 1 -3 +BITMAP +0D80 +0F00 +0800 +0000 +6E00 +7300 +6300 +4300 +C300 +C200 +C200 +8600 +8600 +0600 +0400 +0400 +ENDCHAR +STARTCHAR uni1F25 +ENCODING 7973 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 16 1 -3 +BITMAP +0D80 +0B00 +0800 +0000 +6E00 +7300 +6300 +4300 +C300 +C200 +C200 +8600 +8600 +0600 +0400 +0400 +ENDCHAR +STARTCHAR uni1F26 +ENCODING 7974 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 8 19 1 -3 +BITMAP +1D +13 +00 +0C +04 +08 +00 +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +06 +04 +04 +ENDCHAR +STARTCHAR uni1F27 +ENCODING 7975 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 8 19 1 -3 +BITMAP +1D +13 +00 +04 +08 +04 +00 +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +06 +04 +04 +ENDCHAR +STARTCHAR uni1F28 +ENCODING 7976 +SWIDTH 819 0 +DWIDTH 14 0 +BBX 14 12 1 0 +BITMAP +CC0C +4C08 +8808 +0818 +1818 +1FF8 +1010 +1010 +3030 +3030 +3030 +2020 +ENDCHAR +STARTCHAR uni1F29 +ENCODING 7977 +SWIDTH 819 0 +DWIDTH 14 0 +BBX 14 12 1 0 +BITMAP +4C0C +8C08 +4808 +0818 +1818 +1FF8 +1010 +1010 +3030 +3030 +3030 +2020 +ENDCHAR +STARTCHAR uni1F2A +ENCODING 7978 +SWIDTH 1015 0 +DWIDTH 17 0 +BBX 16 12 2 0 +BITMAP +D303 +DB02 +8202 +0206 +0606 +07FE +0404 +0404 +0C0C +0C0C +0C0C +0808 +ENDCHAR +STARTCHAR uni1F2B +ENCODING 7979 +SWIDTH 1015 0 +DWIDTH 17 0 +BBX 16 12 2 0 +BITMAP +D303 +9B02 +8202 +0206 +0606 +07FE +0404 +0404 +0C0C +0C0C +0C0C +0808 +ENDCHAR +STARTCHAR uni1F2C +ENCODING 7980 +SWIDTH 1015 0 +DWIDTH 17 0 +BBX 16 12 2 0 +BITMAP +DB03 +F302 +8202 +0206 +0606 +07FE +0404 +0404 +0C0C +0C0C +0C0C +0808 +ENDCHAR +STARTCHAR uni1F2D +ENCODING 7981 +SWIDTH 1015 0 +DWIDTH 17 0 +BBX 16 12 2 0 +BITMAP +DB03 +B302 +8202 +0206 +0606 +07FE +0404 +0404 +0C0C +0C0C +0C0C +0808 +ENDCHAR +STARTCHAR uni1F2E +ENCODING 7982 +SWIDTH 1015 0 +DWIDTH 17 0 +BBX 16 15 2 0 +BITMAP +E800 +9800 +0000 +6303 +2302 +4202 +0206 +0606 +07FE +0404 +0404 +0C0C +0C0C +0C0C +0808 +ENDCHAR +STARTCHAR uni1F2F +ENCODING 7983 +SWIDTH 1015 0 +DWIDTH 17 0 +BBX 16 15 2 0 +BITMAP +E800 +9800 +0000 +2303 +4302 +2202 +0206 +0606 +07FE +0404 +0404 +0C0C +0C0C +0C0C +0808 +ENDCHAR +STARTCHAR uni1F30 +ENCODING 7984 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 4 13 1 0 +BITMAP +30 +10 +20 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1F31 +ENCODING 7985 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 13 1 0 +BITMAP +20 +40 +20 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1F32 +ENCODING 7986 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 13 1 0 +BITMAP +68 +6C +40 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1F33 +ENCODING 7987 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 13 1 0 +BITMAP +68 +4C +40 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1F34 +ENCODING 7988 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 13 1 0 +BITMAP +6C +78 +40 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1F35 +ENCODING 7989 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 13 1 0 +BITMAP +6C +58 +40 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1F36 +ENCODING 7990 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 16 1 0 +BITMAP +74 +4C +00 +30 +10 +20 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1F37 +ENCODING 7991 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 16 1 0 +BITMAP +74 +4C +00 +10 +20 +10 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1F38 +ENCODING 7992 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 6 12 1 0 +BITMAP +CC +4C +8C +08 +08 +18 +18 +18 +10 +30 +30 +30 +ENDCHAR +STARTCHAR uni1F39 +ENCODING 7993 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 6 12 1 0 +BITMAP +4C +8C +4C +08 +08 +18 +18 +18 +10 +30 +30 +30 +ENDCHAR +STARTCHAR uni1F3A +ENCODING 7994 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 8 12 2 0 +BITMAP +D3 +DB +83 +02 +02 +06 +06 +06 +04 +0C +0C +0C +ENDCHAR +STARTCHAR uni1F3B +ENCODING 7995 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 8 12 2 0 +BITMAP +D3 +9B +83 +02 +02 +06 +06 +06 +04 +0C +0C +0C +ENDCHAR +STARTCHAR uni1F3C +ENCODING 7996 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 8 12 2 0 +BITMAP +DB +F3 +83 +02 +02 +06 +06 +06 +04 +0C +0C +0C +ENDCHAR +STARTCHAR uni1F3D +ENCODING 7997 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 8 12 2 0 +BITMAP +DB +B3 +83 +02 +02 +06 +06 +06 +04 +0C +0C +0C +ENDCHAR +STARTCHAR uni1F3E +ENCODING 7998 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 8 15 2 0 +BITMAP +E8 +98 +00 +63 +23 +43 +02 +02 +06 +06 +06 +04 +0C +0C +0C +ENDCHAR +STARTCHAR uni1F3F +ENCODING 7999 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 8 15 2 0 +BITMAP +E8 +98 +00 +23 +43 +23 +02 +02 +06 +06 +06 +04 +0C +0C +0C +ENDCHAR +STARTCHAR uni1F40 +ENCODING 8000 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +0C +04 +08 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1F41 +ENCODING 8001 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +04 +08 +04 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1F42 +ENCODING 8002 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +1A +1B +10 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1F43 +ENCODING 8003 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +1A +13 +10 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1F44 +ENCODING 8004 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +1B +1E +10 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1F45 +ENCODING 8005 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +1B +16 +10 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1F48 +ENCODING 8008 +SWIDTH 826 0 +DWIDTH 14 0 +BBX 13 12 1 0 +BITMAP +C7C0 +4C30 +9818 +3018 +3018 +2018 +2018 +2018 +2010 +3030 +1860 +0F80 +ENDCHAR +STARTCHAR uni1F49 +ENCODING 8009 +SWIDTH 826 0 +DWIDTH 14 0 +BBX 13 12 1 0 +BITMAP +47C0 +8C30 +5818 +3018 +3018 +2018 +2018 +2018 +2010 +3030 +1860 +0F80 +ENDCHAR +STARTCHAR uni1F4A +ENCODING 8010 +SWIDTH 1021 0 +DWIDTH 17 0 +BBX 15 12 2 0 +BITMAP +D1F0 +DB0C +8606 +0C06 +0C06 +0806 +0806 +0806 +0804 +0C0C +0618 +03E0 +ENDCHAR +STARTCHAR uni1F4B +ENCODING 8011 +SWIDTH 1021 0 +DWIDTH 17 0 +BBX 15 12 2 0 +BITMAP +D1F0 +9B0C +8606 +0C06 +0C06 +0806 +0806 +0806 +0804 +0C0C +0618 +03E0 +ENDCHAR +STARTCHAR uni1F4C +ENCODING 8012 +SWIDTH 973 0 +DWIDTH 17 0 +BBX 14 12 2 0 +BITMAP +DBE0 +F618 +8C0C +180C +180C +100C +100C +100C +1008 +1818 +0C30 +07C0 +ENDCHAR +STARTCHAR uni1F4D +ENCODING 8013 +SWIDTH 973 0 +DWIDTH 17 0 +BBX 14 12 2 0 +BITMAP +DBE0 +B618 +8C0C +180C +180C +100C +100C +100C +1008 +1818 +0C30 +07C0 +ENDCHAR +STARTCHAR uni1F50 +ENCODING 8016 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +0C +04 +08 +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1F51 +ENCODING 8017 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +04 +08 +04 +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1F52 +ENCODING 8018 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +1A +1B +10 +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1F53 +ENCODING 8019 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +1A +13 +10 +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1F54 +ENCODING 8020 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +1B +1E +10 +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1F55 +ENCODING 8021 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +1B +16 +10 +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1F56 +ENCODING 8022 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +1D +13 +00 +0C +04 +08 +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1F57 +ENCODING 8023 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +1D +13 +00 +04 +08 +04 +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1F59 +ENCODING 8025 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 14 12 1 0 +BITMAP +580C +8C18 +4C30 +0660 +0660 +02C0 +0380 +0100 +0100 +0300 +0300 +0200 +ENDCHAR +STARTCHAR uni1F5B +ENCODING 8027 +SWIDTH 959 0 +DWIDTH 16 0 +BBX 16 12 2 0 +BITMAP +D603 +9B06 +830C +0198 +0198 +00B0 +00E0 +0040 +0040 +00C0 +00C0 +0080 +ENDCHAR +STARTCHAR uni1F5D +ENCODING 8029 +SWIDTH 1008 0 +DWIDTH 17 0 +BBX 17 12 2 0 +BITMAP +DB0180 +B18300 +818600 +00CC00 +00CC00 +005800 +007000 +002000 +002000 +006000 +006000 +004000 +ENDCHAR +STARTCHAR uni1F5F +ENCODING 8031 +SWIDTH 959 0 +DWIDTH 16 0 +BBX 16 15 2 0 +BITMAP +E800 +9800 +0000 +2603 +4306 +230C +0198 +0198 +00B0 +00E0 +0040 +0040 +00C0 +00C0 +0080 +ENDCHAR +STARTCHAR uni1F60 +ENCODING 8032 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 13 1 0 +BITMAP +0300 +0100 +0200 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +ENDCHAR +STARTCHAR uni1F61 +ENCODING 8033 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 13 1 0 +BITMAP +0100 +0200 +0100 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +ENDCHAR +STARTCHAR uni1F62 +ENCODING 8034 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 13 1 0 +BITMAP +0680 +06C0 +0400 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +ENDCHAR +STARTCHAR uni1F63 +ENCODING 8035 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 13 1 0 +BITMAP +0680 +04C0 +0400 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +ENDCHAR +STARTCHAR uni1F64 +ENCODING 8036 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 13 1 0 +BITMAP +06C0 +0780 +0400 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +ENDCHAR +STARTCHAR uni1F65 +ENCODING 8037 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 13 1 0 +BITMAP +06C0 +0580 +0400 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +ENDCHAR +STARTCHAR uni1F66 +ENCODING 8038 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 16 1 0 +BITMAP +0740 +04C0 +0000 +0300 +0100 +0200 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +ENDCHAR +STARTCHAR uni1F67 +ENCODING 8039 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 16 1 0 +BITMAP +0740 +04C0 +0000 +0100 +0200 +0100 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +ENDCHAR +STARTCHAR uni1F68 +ENCODING 8040 +SWIDTH 809 0 +DWIDTH 14 0 +BBX 13 12 1 0 +BITMAP +C3C0 +4C20 +9810 +3018 +3018 +2018 +2018 +2018 +2030 +3030 +1860 +F9F0 +ENDCHAR +STARTCHAR uni1F69 +ENCODING 8041 +SWIDTH 809 0 +DWIDTH 14 0 +BBX 13 12 1 0 +BITMAP +43C0 +8C20 +5810 +3018 +3018 +2018 +2018 +2018 +2030 +3030 +1860 +F9F0 +ENDCHAR +STARTCHAR uni1F6A +ENCODING 8042 +SWIDTH 1004 0 +DWIDTH 17 0 +BBX 15 12 2 0 +BITMAP +D0F0 +DB08 +8604 +0C06 +0C06 +0806 +0806 +0806 +080C +0C0C +0618 +3E7C +ENDCHAR +STARTCHAR uni1F6B +ENCODING 8043 +SWIDTH 1004 0 +DWIDTH 17 0 +BBX 15 12 2 0 +BITMAP +D0F0 +9B08 +8604 +0C06 +0C06 +0806 +0806 +0806 +080C +0C0C +0618 +3E7C +ENDCHAR +STARTCHAR uni1F6C +ENCODING 8044 +SWIDTH 956 0 +DWIDTH 16 0 +BBX 14 12 2 0 +BITMAP +D9E0 +F610 +8C08 +180C +180C +100C +100C +100C +1018 +1818 +0C30 +7CF8 +ENDCHAR +STARTCHAR uni1F6D +ENCODING 8045 +SWIDTH 956 0 +DWIDTH 16 0 +BBX 14 12 2 0 +BITMAP +D9E0 +B610 +8C08 +180C +180C +100C +100C +100C +1018 +1818 +0C30 +7CF8 +ENDCHAR +STARTCHAR uni1F6E +ENCODING 8046 +SWIDTH 956 0 +DWIDTH 16 0 +BBX 14 15 2 0 +BITMAP +E800 +9800 +0000 +61E0 +2610 +4C08 +180C +180C +100C +100C +100C +1018 +1818 +0C30 +7CF8 +ENDCHAR +STARTCHAR uni1F6F +ENCODING 8047 +SWIDTH 956 0 +DWIDTH 16 0 +BBX 14 15 2 0 +BITMAP +E800 +9800 +0000 +21E0 +4610 +2C08 +180C +180C +100C +100C +100C +1018 +1818 +0C30 +7CF8 +ENDCHAR +STARTCHAR uni1F70 +ENCODING 8048 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +1000 +1800 +0800 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR uni1F71 +ENCODING 8049 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +0600 +0400 +0800 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR uni1F72 +ENCODING 8050 +SWIDTH 439 0 +DWIDTH 7 0 +BBX 6 13 1 0 +BITMAP +10 +18 +08 +00 +3C +64 +40 +60 +70 +C0 +80 +88 +78 +ENDCHAR +STARTCHAR uni1F73 +ENCODING 8051 +SWIDTH 439 0 +DWIDTH 7 0 +BBX 6 13 1 0 +BITMAP +0C +08 +10 +00 +3C +64 +40 +60 +70 +C0 +80 +88 +78 +ENDCHAR +STARTCHAR uni1F74 +ENCODING 8052 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 8 16 1 -3 +BITMAP +08 +0C +04 +00 +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +06 +04 +04 +ENDCHAR +STARTCHAR uni1F75 +ENCODING 8053 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 8 16 1 -3 +BITMAP +03 +02 +04 +00 +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +06 +04 +04 +ENDCHAR +STARTCHAR uni1F76 +ENCODING 8054 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 13 1 0 +BITMAP +40 +60 +20 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1F77 +ENCODING 8055 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 4 13 1 0 +BITMAP +30 +20 +40 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1F78 +ENCODING 8056 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +10 +18 +08 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1F79 +ENCODING 8057 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +04 +08 +00 +3E +63 +41 +C1 +81 +83 +83 +C6 +78 +ENDCHAR +STARTCHAR uni1F7A +ENCODING 8058 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +08 +0C +04 +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1F7B +ENCODING 8059 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +04 +08 +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1F7C +ENCODING 8060 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 13 1 0 +BITMAP +0400 +0600 +0200 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +ENDCHAR +STARTCHAR uni1F7D +ENCODING 8061 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 13 1 0 +BITMAP +0180 +0100 +0200 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +ENDCHAR +STARTCHAR uni1F80 +ENCODING 8064 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 16 1 -3 +BITMAP +0C00 +0400 +0800 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +0000 +2000 +2000 +ENDCHAR +STARTCHAR uni1F81 +ENCODING 8065 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 16 1 -3 +BITMAP +0400 +0800 +0400 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +0000 +2000 +2000 +ENDCHAR +STARTCHAR uni1F82 +ENCODING 8066 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 16 1 -3 +BITMAP +1A00 +1B00 +1000 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +0000 +2000 +2000 +ENDCHAR +STARTCHAR uni1F83 +ENCODING 8067 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 16 1 -3 +BITMAP +1A00 +1300 +1000 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +0000 +2000 +2000 +ENDCHAR +STARTCHAR uni1F84 +ENCODING 8068 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 16 1 -3 +BITMAP +1B00 +1E00 +1000 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +0000 +2000 +2000 +ENDCHAR +STARTCHAR uni1F85 +ENCODING 8069 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 16 1 -3 +BITMAP +1B00 +1600 +1000 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +0000 +2000 +2000 +ENDCHAR +STARTCHAR uni1F86 +ENCODING 8070 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 19 1 -3 +BITMAP +1D00 +1300 +0000 +0C00 +0400 +0800 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +0000 +2000 +2000 +ENDCHAR +STARTCHAR uni1F87 +ENCODING 8071 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 19 1 -3 +BITMAP +1D00 +1300 +0000 +0400 +0800 +0400 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +0000 +2000 +2000 +ENDCHAR +STARTCHAR uni1F88 +ENCODING 8072 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 15 0 -3 +BITMAP +3380 +1380 +2780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +0000 +0800 +0800 +ENDCHAR +STARTCHAR uni1F89 +ENCODING 8073 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 15 0 -3 +BITMAP +1380 +2380 +1780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +0000 +0800 +0800 +ENDCHAR +STARTCHAR uni1F8A +ENCODING 8074 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 10 15 2 -3 +BITMAP +D380 +DB80 +8780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +0000 +0400 +0400 +ENDCHAR +STARTCHAR uni1F8B +ENCODING 8075 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 10 15 2 -3 +BITMAP +D380 +9B80 +8780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +0000 +0400 +0400 +ENDCHAR +STARTCHAR uni1F8C +ENCODING 8076 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 10 15 2 -3 +BITMAP +DB80 +F380 +8780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +0000 +0400 +0400 +ENDCHAR +STARTCHAR uni1F8D +ENCODING 8077 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 10 15 2 -3 +BITMAP +DB80 +B380 +8780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +0000 +0400 +0400 +ENDCHAR +STARTCHAR uni1F8E +ENCODING 8078 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 10 18 2 -3 +BITMAP +E800 +9800 +0000 +6380 +2380 +4780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +0000 +0400 +0400 +ENDCHAR +STARTCHAR uni1F8F +ENCODING 8079 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 10 18 2 -3 +BITMAP +E800 +9800 +0000 +2380 +4380 +2780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +0000 +0400 +0400 +ENDCHAR +STARTCHAR uni1F90 +ENCODING 8080 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0600 +0200 +0400 +0000 +3700 +3980 +3180 +2180 +6180 +6100 +6100 +4300 +4300 +0300 +8200 +8200 +ENDCHAR +STARTCHAR uni1F91 +ENCODING 8081 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0200 +0400 +0200 +0000 +3700 +3980 +3180 +2180 +6180 +6100 +6100 +4300 +4300 +0300 +8200 +8200 +ENDCHAR +STARTCHAR uni1F92 +ENCODING 8082 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0D00 +0D80 +0800 +0000 +3700 +3980 +3180 +2180 +6180 +6100 +6100 +4300 +4300 +0300 +8200 +8200 +ENDCHAR +STARTCHAR uni1F93 +ENCODING 8083 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0D00 +0980 +0800 +0000 +3700 +3980 +3180 +2180 +6180 +6100 +6100 +4300 +4300 +0300 +8200 +8200 +ENDCHAR +STARTCHAR uni1F94 +ENCODING 8084 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 10 16 0 -3 +BITMAP +06C0 +0780 +0400 +0000 +3700 +3980 +3180 +2180 +6180 +6100 +6100 +4300 +4300 +0300 +8200 +8200 +ENDCHAR +STARTCHAR uni1F95 +ENCODING 8085 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 10 16 0 -3 +BITMAP +06C0 +0580 +0400 +0000 +3700 +3980 +3180 +2180 +6180 +6100 +6100 +4300 +4300 +0300 +8200 +8200 +ENDCHAR +STARTCHAR uni1F96 +ENCODING 8086 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 19 0 -3 +BITMAP +0E80 +0980 +0000 +0600 +0200 +0400 +0000 +3700 +3980 +3180 +2180 +6180 +6100 +6100 +4300 +4300 +0300 +8200 +8200 +ENDCHAR +STARTCHAR uni1F97 +ENCODING 8087 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 19 0 -3 +BITMAP +0E80 +0980 +0000 +0200 +0400 +0200 +0000 +3700 +3980 +3180 +2180 +6180 +6100 +6100 +4300 +4300 +0300 +8200 +8200 +ENDCHAR +STARTCHAR uni1F98 +ENCODING 8088 +SWIDTH 819 0 +DWIDTH 14 0 +BBX 14 15 1 -3 +BITMAP +CC0C +4C08 +8808 +0818 +1818 +1FF8 +1010 +1010 +3030 +3030 +3030 +2020 +0000 +0400 +0400 +ENDCHAR +STARTCHAR uni1F99 +ENCODING 8089 +SWIDTH 819 0 +DWIDTH 14 0 +BBX 14 15 1 -3 +BITMAP +4C0C +8C08 +4808 +0818 +1818 +1FF8 +1010 +1010 +3030 +3030 +3030 +2020 +0000 +0400 +0400 +ENDCHAR +STARTCHAR uni1F9A +ENCODING 8090 +SWIDTH 1015 0 +DWIDTH 17 0 +BBX 16 15 2 -3 +BITMAP +D303 +DB02 +8202 +0206 +0606 +07FE +0404 +0404 +0C0C +0C0C +0C0C +0808 +0000 +0100 +0100 +ENDCHAR +STARTCHAR uni1F9B +ENCODING 8091 +SWIDTH 1015 0 +DWIDTH 17 0 +BBX 16 15 2 -3 +BITMAP +D303 +9B02 +8202 +0206 +0606 +07FE +0404 +0404 +0C0C +0C0C +0C0C +0808 +0000 +0100 +0100 +ENDCHAR +STARTCHAR uni1F9C +ENCODING 8092 +SWIDTH 1015 0 +DWIDTH 17 0 +BBX 16 15 2 -3 +BITMAP +DB03 +F302 +8202 +0206 +0606 +07FE +0404 +0404 +0C0C +0C0C +0C0C +0808 +0000 +0100 +0100 +ENDCHAR +STARTCHAR uni1F9D +ENCODING 8093 +SWIDTH 1015 0 +DWIDTH 17 0 +BBX 16 15 2 -3 +BITMAP +DB03 +B302 +8202 +0206 +0606 +07FE +0404 +0404 +0C0C +0C0C +0C0C +0808 +0000 +0100 +0100 +ENDCHAR +STARTCHAR uni1F9E +ENCODING 8094 +SWIDTH 1015 0 +DWIDTH 17 0 +BBX 16 18 2 -3 +BITMAP +E800 +9800 +0000 +6303 +2302 +4202 +0206 +0606 +07FE +0404 +0404 +0C0C +0C0C +0C0C +0808 +0000 +0100 +0100 +ENDCHAR +STARTCHAR uni1F9F +ENCODING 8095 +SWIDTH 1015 0 +DWIDTH 17 0 +BBX 16 18 2 -3 +BITMAP +E800 +9800 +0000 +2303 +4302 +2202 +0206 +0606 +07FE +0404 +0404 +0C0C +0C0C +0C0C +0808 +0000 +0100 +0100 +ENDCHAR +STARTCHAR uni1FA0 +ENCODING 8096 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 16 1 -3 +BITMAP +0300 +0100 +0200 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +0000 +0800 +0800 +ENDCHAR +STARTCHAR uni1FA1 +ENCODING 8097 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 16 1 -3 +BITMAP +0100 +0200 +0100 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +0000 +0800 +0800 +ENDCHAR +STARTCHAR uni1FA2 +ENCODING 8098 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 16 1 -3 +BITMAP +0680 +06C0 +0400 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +0000 +0800 +0800 +ENDCHAR +STARTCHAR uni1FA3 +ENCODING 8099 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 16 1 -3 +BITMAP +0680 +04C0 +0400 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +0000 +0800 +0800 +ENDCHAR +STARTCHAR uni1FA4 +ENCODING 8100 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 16 1 -3 +BITMAP +06C0 +0780 +0400 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +0000 +0800 +0800 +ENDCHAR +STARTCHAR uni1FA5 +ENCODING 8101 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 16 1 -3 +BITMAP +06C0 +0580 +0400 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +0000 +0800 +0800 +ENDCHAR +STARTCHAR uni1FA6 +ENCODING 8102 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 19 1 -3 +BITMAP +0740 +04C0 +0000 +0300 +0100 +0200 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +0000 +0800 +0800 +ENDCHAR +STARTCHAR uni1FA7 +ENCODING 8103 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 19 1 -3 +BITMAP +0740 +04C0 +0000 +0100 +0200 +0100 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +0000 +0800 +0800 +ENDCHAR +STARTCHAR uni1FA8 +ENCODING 8104 +SWIDTH 809 0 +DWIDTH 14 0 +BBX 13 15 1 -3 +BITMAP +C3C0 +4C20 +9810 +3018 +3018 +2018 +2018 +2018 +2030 +3030 +1860 +F9F0 +0000 +0400 +0400 +ENDCHAR +STARTCHAR uni1FA9 +ENCODING 8105 +SWIDTH 809 0 +DWIDTH 14 0 +BBX 13 15 1 -3 +BITMAP +43C0 +8C20 +5810 +3018 +3018 +2018 +2018 +2018 +2030 +3030 +1860 +F9F0 +0000 +0400 +0400 +ENDCHAR +STARTCHAR uni1FAA +ENCODING 8106 +SWIDTH 1004 0 +DWIDTH 17 0 +BBX 15 15 2 -3 +BITMAP +D0F0 +DB08 +8604 +0C06 +0C06 +0806 +0806 +0806 +080C +0C0C +0618 +3E7C +0000 +0100 +0100 +ENDCHAR +STARTCHAR uni1FAB +ENCODING 8107 +SWIDTH 1004 0 +DWIDTH 17 0 +BBX 15 15 2 -3 +BITMAP +D0F0 +9B08 +8604 +0C06 +0C06 +0806 +0806 +0806 +080C +0C0C +0618 +3E7C +0000 +0100 +0100 +ENDCHAR +STARTCHAR uni1FAC +ENCODING 8108 +SWIDTH 956 0 +DWIDTH 16 0 +BBX 14 15 2 -3 +BITMAP +D9E0 +F610 +8C08 +180C +180C +100C +100C +100C +1018 +1818 +0C30 +7CF8 +0000 +0100 +0100 +ENDCHAR +STARTCHAR uni1FAD +ENCODING 8109 +SWIDTH 956 0 +DWIDTH 16 0 +BBX 14 15 2 -3 +BITMAP +D9E0 +B610 +8C08 +180C +180C +100C +100C +100C +1018 +1818 +0C30 +7CF8 +0000 +0100 +0100 +ENDCHAR +STARTCHAR uni1FAE +ENCODING 8110 +SWIDTH 956 0 +DWIDTH 16 0 +BBX 14 18 2 -3 +BITMAP +E800 +9800 +0000 +61E0 +2610 +4C08 +180C +180C +100C +100C +100C +1018 +1818 +0C30 +7CF8 +0000 +0100 +0100 +ENDCHAR +STARTCHAR uni1FAF +ENCODING 8111 +SWIDTH 956 0 +DWIDTH 16 0 +BBX 14 18 2 -3 +BITMAP +E800 +9800 +0000 +21E0 +4610 +2C08 +180C +180C +100C +100C +100C +1018 +1818 +0C30 +7CF8 +0000 +0100 +0100 +ENDCHAR +STARTCHAR uni1FB0 +ENCODING 8112 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +1300 +0E00 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR uni1FB1 +ENCODING 8113 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 11 1 0 +BITMAP +1F00 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR uni1FB2 +ENCODING 8114 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 16 1 -3 +BITMAP +1000 +1800 +0800 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +0000 +2000 +2000 +ENDCHAR +STARTCHAR uni1FB3 +ENCODING 8115 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 12 1 -3 +BITMAP +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +0000 +2000 +2000 +ENDCHAR +STARTCHAR uni1FB4 +ENCODING 8116 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 16 1 -3 +BITMAP +0600 +0400 +0800 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +0000 +2000 +2000 +ENDCHAR +STARTCHAR uni1FB6 +ENCODING 8118 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +3A00 +2E00 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR uni1FB7 +ENCODING 8119 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 15 1 -3 +BITMAP +3A00 +2E00 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +0000 +2000 +2000 +ENDCHAR +STARTCHAR uni1FB8 +ENCODING 8120 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 15 0 0 +BITMAP +0260 +01C0 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1FB9 +ENCODING 8121 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +07C0 +0000 +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1FBA +ENCODING 8122 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 0 0 +BITMAP +2380 +3380 +1780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1FBB +ENCODING 8123 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 0 0 +BITMAP +3380 +2380 +4780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +ENDCHAR +STARTCHAR uni1FBC +ENCODING 8124 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 15 0 -3 +BITMAP +0380 +0380 +0780 +0480 +0C80 +1880 +10C0 +3FC0 +20C0 +6040 +4040 +C040 +0000 +0800 +0800 +ENDCHAR +STARTCHAR uni1FBD +ENCODING 8125 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 3 3 9 +BITMAP +C0 +40 +80 +ENDCHAR +STARTCHAR uni1FBE +ENCODING 8126 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 1 2 1 -3 +BITMAP +80 +80 +ENDCHAR +STARTCHAR uni1FBF +ENCODING 8127 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 3 3 9 +BITMAP +C0 +40 +80 +ENDCHAR +STARTCHAR uni1FC0 +ENCODING 8128 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 2 2 10 +BITMAP +E8 +B8 +ENDCHAR +STARTCHAR uni1FC1 +ENCODING 8129 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 4 2 11 +BITMAP +64 +98 +00 +D8 +ENDCHAR +STARTCHAR uni1FC2 +ENCODING 8130 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0400 +0600 +0200 +0000 +3700 +3980 +3180 +2180 +6180 +6100 +6100 +4300 +4300 +0300 +8200 +8200 +ENDCHAR +STARTCHAR uni1FC3 +ENCODING 8131 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3700 +3980 +3180 +2180 +6180 +6100 +6100 +4300 +4300 +0300 +8200 +8200 +ENDCHAR +STARTCHAR uni1FC4 +ENCODING 8132 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0180 +0100 +0200 +0000 +3700 +3980 +3180 +2180 +6180 +6100 +6100 +4300 +4300 +0300 +8200 +8200 +ENDCHAR +STARTCHAR uni1FC6 +ENCODING 8134 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +1D +17 +00 +6E +73 +63 +43 +C3 +C2 +C2 +86 +86 +06 +04 +04 +ENDCHAR +STARTCHAR uni1FC7 +ENCODING 8135 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 15 0 -3 +BITMAP +0E80 +0B80 +0000 +3700 +3980 +3180 +2180 +6180 +6100 +6100 +4300 +4300 +0300 +8200 +8200 +ENDCHAR +STARTCHAR uni1FC8 +ENCODING 8136 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 12 12 2 0 +BITMAP +9FF0 +D800 +5000 +1000 +3000 +3FE0 +2000 +2000 +2000 +6000 +6000 +7FC0 +ENDCHAR +STARTCHAR uni1FC9 +ENCODING 8137 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 13 12 1 0 +BITMAP +6FF8 +4C00 +8800 +0800 +1800 +1FF0 +1000 +1000 +1000 +3000 +3000 +3FE0 +ENDCHAR +STARTCHAR uni1FCA +ENCODING 8138 +SWIDTH 868 0 +DWIDTH 15 0 +BBX 13 12 2 0 +BITMAP +9818 +D810 +5010 +1030 +3030 +3FF0 +2020 +2020 +6060 +6060 +6060 +4040 +ENDCHAR +STARTCHAR uni1FCB +ENCODING 8139 +SWIDTH 868 0 +DWIDTH 15 0 +BBX 14 12 1 0 +BITMAP +6C0C +4C08 +8808 +0818 +1818 +1FF8 +1010 +1010 +3030 +3030 +3030 +2020 +ENDCHAR +STARTCHAR uni1FCC +ENCODING 8140 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 15 1 -3 +BITMAP +3030 +3020 +2020 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C0C0 +8080 +0000 +1000 +1000 +ENDCHAR +STARTCHAR uni1FCD +ENCODING 8141 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 3 2 9 +BITMAP +D0 +D8 +80 +ENDCHAR +STARTCHAR uni1FCE +ENCODING 8142 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 3 2 9 +BITMAP +D8 +F0 +80 +ENDCHAR +STARTCHAR uni1FCF +ENCODING 8143 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 6 2 9 +BITMAP +E8 +98 +00 +60 +20 +40 +ENDCHAR +STARTCHAR uni1FD0 +ENCODING 8144 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 12 1 0 +BITMAP +98 +70 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1FD1 +ENCODING 8145 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 11 1 0 +BITMAP +F8 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1FD2 +ENCODING 8146 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 15 1 0 +BITMAP +40 +60 +20 +00 +D8 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1FD3 +ENCODING 8147 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 15 1 0 +BITMAP +0C +08 +10 +00 +D8 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1FD6 +ENCODING 8150 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 12 1 0 +BITMAP +E8 +B8 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1FD7 +ENCODING 8151 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 15 1 0 +BITMAP +74 +5C +00 +00 +D8 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni1FD8 +ENCODING 8152 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 15 1 0 +BITMAP +4C +38 +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni1FD9 +ENCODING 8153 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 14 1 0 +BITMAP +7C +00 +30 +30 +30 +20 +20 +60 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uni1FDA +ENCODING 8154 +SWIDTH 424 0 +DWIDTH 7 0 +BBX 5 12 2 0 +BITMAP +98 +D8 +58 +10 +10 +30 +30 +30 +20 +60 +60 +60 +ENDCHAR +STARTCHAR uni1FDB +ENCODING 8155 +SWIDTH 424 0 +DWIDTH 7 0 +BBX 6 12 1 0 +BITMAP +6C +4C +8C +08 +08 +18 +18 +18 +10 +30 +30 +30 +ENDCHAR +STARTCHAR uni1FDD +ENCODING 8157 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 3 2 9 +BITMAP +D0 +98 +80 +ENDCHAR +STARTCHAR uni1FDE +ENCODING 8158 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 3 2 9 +BITMAP +D8 +B0 +80 +ENDCHAR +STARTCHAR uni1FDF +ENCODING 8159 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 6 2 9 +BITMAP +E8 +98 +00 +20 +40 +20 +ENDCHAR +STARTCHAR uni1FE0 +ENCODING 8160 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +13 +0E +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1FE1 +ENCODING 8161 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1F +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1FE2 +ENCODING 8162 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 15 1 0 +BITMAP +08 +0C +04 +00 +1B +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1FE3 +ENCODING 8163 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 15 1 0 +BITMAP +03 +02 +04 +00 +1B +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1FE4 +ENCODING 8164 +SWIDTH 572 0 +DWIDTH 10 0 +BBX 9 16 0 -3 +BITMAP +0600 +0200 +0400 +0000 +0F00 +1980 +3080 +2080 +6080 +6080 +6180 +6300 +5E00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni1FE5 +ENCODING 8165 +SWIDTH 572 0 +DWIDTH 10 0 +BBX 9 16 0 -3 +BITMAP +0200 +0400 +0200 +0000 +0F00 +1980 +3080 +2080 +6080 +6080 +6180 +6300 +5E00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni1FE6 +ENCODING 8166 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1D +17 +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1FE7 +ENCODING 8167 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 15 1 0 +BITMAP +1D +17 +00 +00 +1B +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR uni1FE8 +ENCODING 8168 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 15 2 0 +BITMAP +1300 +0E00 +0000 +C060 +60C0 +6180 +3300 +3300 +1600 +1C00 +0800 +0800 +1800 +1800 +1000 +ENDCHAR +STARTCHAR uni1FE9 +ENCODING 8169 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 14 2 0 +BITMAP +1F00 +0000 +C060 +60C0 +6180 +3300 +3300 +1600 +1C00 +0800 +0800 +1800 +1800 +1000 +ENDCHAR +STARTCHAR uni1FEA +ENCODING 8170 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 13 12 2 0 +BITMAP +B018 +D830 +5860 +0CC0 +0CC0 +0580 +0700 +0200 +0200 +0600 +0600 +0400 +ENDCHAR +STARTCHAR uni1FEB +ENCODING 8171 +SWIDTH 862 0 +DWIDTH 15 0 +BBX 15 12 1 0 +BITMAP +6C06 +460C +8618 +0330 +0330 +0160 +01C0 +0080 +0080 +0180 +0180 +0100 +ENDCHAR +STARTCHAR uni1FEC +ENCODING 8172 +SWIDTH 764 0 +DWIDTH 13 0 +BBX 13 12 1 0 +BITMAP +4FF0 +8C18 +4818 +0818 +1818 +1830 +1FE0 +1000 +3000 +3000 +3000 +2000 +ENDCHAR +STARTCHAR uni1FED +ENCODING 8173 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 2 1 10 +BITMAP +30 +94 +ENDCHAR +STARTCHAR uni1FEE +ENCODING 8174 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 2 1 10 +BITMAP +10 +A4 +ENDCHAR +STARTCHAR uni1FEF +ENCODING 8175 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 2 3 10 +BITMAP +C0 +40 +ENDCHAR +STARTCHAR uni1FF2 +ENCODING 8178 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 16 1 -3 +BITMAP +0400 +0600 +0200 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +0000 +0800 +0800 +ENDCHAR +STARTCHAR uni1FF3 +ENCODING 8179 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 12 1 -3 +BITMAP +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +0000 +0800 +0800 +ENDCHAR +STARTCHAR uni1FF4 +ENCODING 8180 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 16 1 -3 +BITMAP +0180 +0100 +0200 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +0000 +0800 +0800 +ENDCHAR +STARTCHAR uni1FF6 +ENCODING 8182 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 12 1 0 +BITMAP +0740 +05C0 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +ENDCHAR +STARTCHAR uni1FF7 +ENCODING 8183 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 15 1 -3 +BITMAP +0740 +05C0 +0000 +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +0000 +0800 +0800 +ENDCHAR +STARTCHAR uni1FF8 +ENCODING 8184 +SWIDTH 924 0 +DWIDTH 16 0 +BBX 13 12 2 0 +BITMAP +87C0 +CC30 +5818 +3018 +3018 +2018 +2018 +2018 +2010 +3030 +1860 +0F80 +ENDCHAR +STARTCHAR uni1FF9 +ENCODING 8185 +SWIDTH 826 0 +DWIDTH 14 0 +BBX 13 12 1 0 +BITMAP +67C0 +4C30 +9818 +3018 +3018 +2018 +2018 +2018 +2010 +3030 +1860 +0F80 +ENDCHAR +STARTCHAR uni1FFA +ENCODING 8186 +SWIDTH 907 0 +DWIDTH 15 0 +BBX 13 12 2 0 +BITMAP +83C0 +CC20 +5810 +3018 +3018 +2018 +2018 +2018 +2030 +3030 +1860 +F9F0 +ENDCHAR +STARTCHAR uni1FFB +ENCODING 8187 +SWIDTH 809 0 +DWIDTH 14 0 +BBX 13 12 1 0 +BITMAP +63C0 +4C20 +9810 +3018 +3018 +2018 +2018 +2018 +2030 +3030 +1860 +F9F0 +ENDCHAR +STARTCHAR uni1FFC +ENCODING 8188 +SWIDTH 760 0 +DWIDTH 13 0 +BBX 13 15 0 -3 +BITMAP +03C0 +0C20 +1810 +3018 +3018 +2018 +2018 +2018 +2030 +3030 +1860 +F9F0 +0000 +0400 +0400 +ENDCHAR +STARTCHAR uni1FFD +ENCODING 8189 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 2 3 10 +BITMAP +60 +C0 +ENDCHAR +STARTCHAR uni1FFE +ENCODING 8190 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 2 3 3 9 +BITMAP +40 +80 +40 +ENDCHAR +STARTCHAR uni2000 +ENCODING 8192 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2001 +ENCODING 8193 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2002 +ENCODING 8194 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2003 +ENCODING 8195 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2004 +ENCODING 8196 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2005 +ENCODING 8197 +SWIDTH 250 0 +DWIDTH 4 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2006 +ENCODING 8198 +SWIDTH 166 0 +DWIDTH 3 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2007 +ENCODING 8199 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2008 +ENCODING 8200 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni2009 +ENCODING 8201 +SWIDTH 200 0 +DWIDTH 3 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni200A +ENCODING 8202 +SWIDTH 83 0 +DWIDTH 1 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni200B +ENCODING 8203 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR uni200C +ENCODING 8204 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 13 -1 -2 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni200D +ENCODING 8205 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 13 -2 -2 +BITMAP +90 +60 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni200E +ENCODING 8206 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 14 0 -2 +BITMAP +40 +F0 +C0 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni200F +ENCODING 8207 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 14 -4 -2 +BITMAP +40 +F0 +50 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR figuredash +ENCODING 8210 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 1 0 4 +BITMAP +FF80 +ENDCHAR +STARTCHAR endash +ENCODING 8211 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 1 0 4 +BITMAP +FF80 +ENDCHAR +STARTCHAR emdash +ENCODING 8212 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 17 1 0 4 +BITMAP +FFFF80 +ENDCHAR +STARTCHAR uni2015 +ENCODING 8213 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 16 1 1 4 +BITMAP +FFFF +ENDCHAR +STARTCHAR uni01C1.dup6 +ENCODING 8214 +SWIDTH 413 0 +DWIDTH 7 0 +BBX 3 12 2 0 +BITMAP +A0 +A0 +A0 +A0 +A0 +A0 +A0 +A0 +A0 +A0 +A0 +A0 +ENDCHAR +STARTCHAR underscoredbl +ENCODING 8215 +SWIDTH 552 0 +DWIDTH 9 0 +BBX 10 3 -1 -6 +BITMAP +FFC0 +0000 +FFC0 +ENDCHAR +STARTCHAR quoteleft +ENCODING 8216 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 4 2 8 +BITMAP +20 +40 +80 +C0 +ENDCHAR +STARTCHAR quoteright +ENCODING 8217 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 4 2 8 +BITMAP +60 +40 +40 +80 +ENDCHAR +STARTCHAR quotesinglbase +ENCODING 8218 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 2 4 0 -3 +BITMAP +40 +40 +40 +80 +ENDCHAR +STARTCHAR quotereversed +ENCODING 8219 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 2 4 3 8 +BITMAP +C0 +80 +80 +80 +ENDCHAR +STARTCHAR quotedblleft +ENCODING 8220 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 4 2 8 +BITMAP +48 +D0 +90 +D0 +ENDCHAR +STARTCHAR quotedblright +ENCODING 8221 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 4 2 8 +BITMAP +D8 +48 +50 +90 +ENDCHAR +STARTCHAR quotedblbase +ENCODING 8222 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 4 0 -3 +BITMAP +D8 +48 +50 +A0 +ENDCHAR +STARTCHAR uni201F +ENCODING 8223 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 4 2 8 +BITMAP +D8 +A0 +A0 +90 +ENDCHAR +STARTCHAR dagger +ENCODING 8224 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 2 -3 +BITMAP +08 +08 +18 +18 +FF +10 +10 +30 +30 +20 +20 +60 +60 +60 +40 +ENDCHAR +STARTCHAR daggerdbl +ENCODING 8225 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 15 0 -3 +BITMAP +0200 +0200 +0600 +0600 +3FC0 +0400 +0400 +0C00 +0C00 +0800 +0800 +FF00 +1800 +1800 +1000 +ENDCHAR +STARTCHAR bullet +ENCODING 8226 +SWIDTH 350 0 +DWIDTH 6 0 +BBX 4 4 1 4 +BITMAP +60 +F0 +F0 +60 +ENDCHAR +STARTCHAR ellipsis +ENCODING 8230 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 13 1 3 0 +BITMAP +8618 +ENDCHAR +STARTCHAR uni202A +ENCODING 8234 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 12 0 -2 +BITMAP +F0 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR uni202B +ENCODING 8235 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 12 -4 -2 +BITMAP +F0 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR uni202C +ENCODING 8236 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 14 -2 -2 +BITMAP +F0 +F0 +F0 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni202D +ENCODING 8237 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 14 -2 -2 +BITMAP +F0 +80 +80 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni202E +ENCODING 8238 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 14 -2 -2 +BITMAP +F0 +10 +10 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni2009.dup7 +ENCODING 8239 +SWIDTH 200 0 +DWIDTH 3 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR perthousand +ENCODING 8240 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 16 12 1 0 +BITMAP +3880 +4880 +C900 +8B00 +9A00 +7400 +0DCE +0A49 +1651 +3451 +26D2 +438E +ENDCHAR +STARTCHAR minute +ENCODING 8242 +SWIDTH 187 0 +DWIDTH 3 0 +BBX 2 4 2 8 +BITMAP +40 +C0 +C0 +80 +ENDCHAR +STARTCHAR second +ENCODING 8243 +SWIDTH 354 0 +DWIDTH 6 0 +BBX 5 4 2 8 +BITMAP +48 +D8 +D8 +90 +ENDCHAR +STARTCHAR uni2034 +ENCODING 8244 +SWIDTH 354 0 +DWIDTH 6 0 +BBX 7 4 1 8 +BITMAP +52 +F6 +F6 +A4 +ENDCHAR +STARTCHAR guilsinglleft +ENCODING 8249 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 7 1 1 +BITMAP +10 +20 +40 +80 +C0 +40 +40 +ENDCHAR +STARTCHAR guilsinglright +ENCODING 8250 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 7 1 1 +BITMAP +40 +20 +20 +30 +60 +40 +80 +ENDCHAR +STARTCHAR exclamdbl +ENCODING 8252 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +33 +33 +33 +22 +22 +66 +66 +44 +44 +00 +00 +CC +ENDCHAR +STARTCHAR uni203D +ENCODING 8253 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 2 0 +BITMAP +3C +5A +DA +93 +32 +36 +3C +30 +20 +20 +00 +60 +ENDCHAR +STARTCHAR uni203E +ENCODING 8254 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 7 1 1 10 +BITMAP +FE +ENDCHAR +STARTCHAR fraction +ENCODING 8260 +SWIDTH 166 0 +DWIDTH 3 0 +BBX 12 13 -4 -1 +BITMAP +0010 +0020 +0040 +0080 +0180 +0300 +0600 +0C00 +0800 +1000 +2000 +4000 +8000 +ENDCHAR +STARTCHAR uni205E +ENCODING 8286 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 12 1 0 +BITMAP +30 +00 +00 +00 +20 +00 +00 +60 +00 +00 +00 +C0 +ENDCHAR +STARTCHAR uni206A +ENCODING 8298 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 14 -2 -2 +BITMAP +F0 +40 +40 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni206B +ENCODING 8299 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 14 -2 -2 +BITMAP +F0 +90 +90 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni206C +ENCODING 8300 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 14 -2 -2 +BITMAP +F0 +60 +60 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni206D +ENCODING 8301 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 13 -2 -2 +BITMAP +60 +60 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni206E +ENCODING 8302 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 15 -2 -2 +BITMAP +40 +60 +90 +60 +60 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni206F +ENCODING 8303 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 14 -2 -2 +BITMAP +C0 +40 +40 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR uni2070 +ENCODING 8304 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 6 1 6 +BITMAP +38 +4C +4C +C8 +C8 +70 +ENDCHAR +STARTCHAR uni2074 +ENCODING 8308 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 6 1 6 +BITMAP +0C +18 +28 +48 +FC +18 +ENDCHAR +STARTCHAR uni2075 +ENCODING 8309 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 6 1 6 +BITMAP +7C +40 +78 +08 +C8 +70 +ENDCHAR +STARTCHAR uni2076 +ENCODING 8310 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 6 1 6 +BITMAP +38 +40 +78 +C8 +C8 +70 +ENDCHAR +STARTCHAR uni2077 +ENCODING 8311 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 6 2 6 +BITMAP +F0 +10 +20 +40 +40 +80 +ENDCHAR +STARTCHAR uni2078 +ENCODING 8312 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 6 1 6 +BITMAP +38 +4C +30 +48 +C8 +78 +ENDCHAR +STARTCHAR uni2079 +ENCODING 8313 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 6 2 6 +BITMAP +70 +98 +98 +F0 +10 +E0 +ENDCHAR +STARTCHAR uni207F +ENCODING 8319 +SWIDTH 364 0 +DWIDTH 6 0 +BBX 6 6 1 4 +BITMAP +58 +64 +4C +48 +88 +88 +ENDCHAR +STARTCHAR uni2090 +ENCODING 8336 +SWIDTH 358 0 +DWIDTH 6 0 +BBX 6 6 0 -1 +BITMAP +78 +04 +78 +88 +88 +78 +ENDCHAR +STARTCHAR uni2091 +ENCODING 8337 +SWIDTH 387 0 +DWIDTH 7 0 +BBX 6 6 0 -1 +BITMAP +38 +44 +7C +80 +48 +70 +ENDCHAR +STARTCHAR uni2092 +ENCODING 8338 +SWIDTH 394 0 +DWIDTH 7 0 +BBX 6 6 0 -1 +BITMAP +38 +44 +44 +84 +4C +78 +ENDCHAR +STARTCHAR uni2093 +ENCODING 8339 +SWIDTH 380 0 +DWIDTH 6 0 +BBX 5 6 1 -1 +BITMAP +C8 +50 +60 +60 +F0 +90 +ENDCHAR +STARTCHAR uni2094 +ENCODING 8340 +SWIDTH 387 0 +DWIDTH 7 0 +BBX 6 6 0 -1 +BITMAP +38 +4C +04 +FC +88 +70 +ENDCHAR +STARTCHAR uni20A0 +ENCODING 8352 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +1E00 +6300 +4300 +C000 +8F80 +8800 +D800 +7F00 +1000 +1000 +1000 +3F00 +ENDCHAR +STARTCHAR colonmonetary +ENCODING 8353 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 14 1 -1 +BITMAP +01A0 +0FE0 +1A40 +32A0 +64A0 +6500 +4900 +4A00 +5200 +5460 +64C0 +7980 +5F00 +D000 +ENDCHAR +STARTCHAR uni20A2 +ENCODING 8354 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 10 12 2 0 +BITMAP +1F00 +3080 +60C0 +C040 +C000 +8980 +8E00 +8800 +98C0 +D980 +7300 +3E00 +ENDCHAR +STARTCHAR franc +ENCODING 8355 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 12 0 0 +BITMAP +1FC0 +1800 +1000 +1000 +3000 +3000 +3F80 +2000 +2000 +FC00 +6000 +6000 +ENDCHAR +STARTCHAR lira +ENCODING 8356 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +0F00 +1180 +3080 +2000 +2000 +7C00 +3000 +F800 +2000 +6000 +F100 +8E00 +ENDCHAR +STARTCHAR uni20A5 +ENCODING 8357 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 13 1 -2 +BITMAP +0020 +0040 +6EF0 +7398 +6318 +4218 +C210 +C610 +CE30 +8E30 +9430 +3000 +2000 +ENDCHAR +STARTCHAR uni20A6 +ENCODING 8358 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +3030 +3830 +2820 +2820 +FFF0 +6460 +4640 +FFE0 +C3C0 +C1C0 +C1C0 +C080 +ENDCHAR +STARTCHAR peseta +ENCODING 8359 +SWIDTH 1093 0 +DWIDTH 19 0 +BBX 18 12 0 0 +BITMAP +1F0000 +319000 +30B000 +30FF80 +20ACC0 +21AC40 +7F6600 +606380 +604080 +4050C0 +405880 +C07F00 +ENDCHAR +STARTCHAR uni20A8 +ENCODING 8360 +SWIDTH 1129 0 +DWIDTH 19 0 +BBX 18 12 1 0 +BITMAP +3FC000 +306000 +202000 +202780 +602CC0 +606840 +7F8C00 +430780 +4181C0 +C090C0 +C0D8C0 +C0CF80 +ENDCHAR +STARTCHAR uni20A9 +ENCODING 8361 +SWIDTH 943 0 +DWIDTH 16 0 +BBX 17 12 1 0 +BITMAP +60C180 +60C100 +614300 +614200 +FFFF00 +664400 +244C00 +FFFE00 +285000 +385000 +307000 +306000 +ENDCHAR +STARTCHAR uni20AA +ENCODING 8362 +SWIDTH 815 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +7F98 +6098 +4090 +4D90 +4990 +C930 +D820 +9820 +9FC0 +ENDCHAR +STARTCHAR dong +ENCODING 8363 +SWIDTH 513 0 +DWIDTH 9 0 +BBX 8 10 1 2 +BITMAP +0F +02 +1A +26 +44 +44 +44 +3C +00 +FC +ENDCHAR +STARTCHAR Euro +ENCODING 8364 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 12 1 0 +BITMAP +0780 +1840 +3000 +2000 +6000 +FF00 +4000 +FE00 +4000 +6000 +3100 +1E00 +ENDCHAR +STARTCHAR uni20AD +ENCODING 8365 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3060 +30C0 +2180 +2300 +6600 +6C00 +FFC0 +7600 +6300 +C180 +C180 +C0C0 +ENDCHAR +STARTCHAR uni20AE +ENCODING 8366 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 11 12 1 0 +BITMAP +7FE0 +0600 +0480 +0500 +0E00 +0D00 +3F00 +4C00 +1800 +7800 +9800 +1800 +ENDCHAR +STARTCHAR uni20AF +ENCODING 8367 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 16 17 0 -3 +BITMAP +0020 +0040 +07E0 +0910 +0318 +0618 +0618 +0C18 +0C10 +1837 +F029 +B071 +A8D3 +C73E +0020 +0060 +0040 +ENDCHAR +STARTCHAR uni20B0 +ENCODING 8368 +SWIDTH 520 0 +DWIDTH 9 0 +BBX 10 15 0 -3 +BITMAP +03C0 +06C0 +06C0 +0680 +0680 +0700 +0600 +0600 +2E00 +6A00 +F200 +A200 +0200 +0600 +1C00 +ENDCHAR +STARTCHAR uni20B1 +ENCODING 8369 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 12 12 1 0 +BITMAP +3FC0 +3060 +7FF0 +2060 +FFE0 +60C0 +7F80 +4000 +C000 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni20B2 +ENCODING 8370 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 15 2 -2 +BITMAP +00C0 +0F80 +31C0 +6160 +4260 +C600 +8400 +8FC0 +8840 +90C0 +D0C0 +61C0 +7F00 +4000 +C000 +ENDCHAR +STARTCHAR uni20B3 +ENCODING 8371 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 12 12 0 0 +BITMAP +0380 +0380 +0780 +0480 +7FF0 +1880 +10C0 +FFF0 +60C0 +6040 +C040 +C040 +ENDCHAR +STARTCHAR uni20B4 +ENCODING 8372 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +0F80 +30C0 +20C0 +00C0 +7FC0 +0F00 +3C00 +FFC0 +C000 +C080 +C380 +7E00 +ENDCHAR +STARTCHAR uni20B5 +ENCODING 8373 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 10 15 2 -2 +BITMAP +0200 +1F00 +3280 +64C0 +C440 +C400 +8400 +8800 +8800 +88C0 +C980 +6B00 +3E00 +1000 +1000 +ENDCHAR +STARTCHAR uni20B6 +ENCODING 8374 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 7 12 2 0 +BITMAP +12 +24 +24 +FE +6C +48 +48 +48 +D8 +D8 +98 +9C +ENDCHAR +STARTCHAR uni20B7 +ENCODING 8375 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 13 0 -1 +BITMAP +0FC0 +1860 +1020 +1000 +1C00 +0F00 +03C0 +00C0 +5E60 +AA40 +CBC0 +7F00 +5200 +ENDCHAR +STARTCHAR uni20B8 +ENCODING 8376 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 12 2 0 +BITMAP +FFC0 +0000 +FF80 +0800 +1800 +1800 +1800 +1000 +1000 +3000 +3000 +3000 +ENDCHAR +STARTCHAR uni20B9 +ENCODING 8377 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 2 0 +BITMAP +7F +0C +0C +FE +0C +18 +E0 +C0 +60 +60 +30 +18 +ENDCHAR +STARTCHAR uni20BA +ENCODING 8378 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +0800 +1B00 +3C00 +D800 +1E00 +F180 +3180 +3100 +3300 +2600 +6C00 +7000 +ENDCHAR +STARTCHAR uni20BB +ENCODING 8379 +SWIDTH 813 0 +DWIDTH 14 0 +BBX 13 12 1 0 +BITMAP +7800 +4C00 +CC00 +7FF0 +0818 +0C58 +1FD8 +7A60 +1800 +1800 +0860 +0780 +ENDCHAR +STARTCHAR uni20BC +ENCODING 8380 +SWIDTH 736 0 +DWIDTH 13 0 +BBX 12 10 0 0 +BITMAP +0100 +07C0 +0B60 +1320 +3330 +6230 +4230 +C630 +C630 +8430 +ENDCHAR +STARTCHAR uni20BD +ENCODING 8381 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 12 0 0 +BITMAP +1FC0 +10C0 +3040 +3040 +30C0 +7F00 +6000 +FF00 +6000 +4000 +4000 +C000 +ENDCHAR +STARTCHAR uni20BE +ENCODING 8382 +SWIDTH 807 0 +DWIDTH 14 0 +BBX 12 12 1 0 +BITMAP +0240 +07C0 +1EE0 +36B0 +2490 +6490 +6D90 +4000 +6000 +6000 +3000 +FFE0 +ENDCHAR +STARTCHAR uni20BF +ENCODING 8383 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 16 1 -2 +BITMAP +0900 +0900 +3F80 +30C0 +2040 +20C0 +6080 +7F00 +4080 +40C0 +C0C0 +C0C0 +C180 +FF00 +6800 +4800 +ENDCHAR +STARTCHAR uni20F0 +ENCODING 8432 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 5 -1 9 +BITMAP +20 +E8 +30 +50 +50 +ENDCHAR +STARTCHAR uni2105 +ENCODING 8453 +SWIDTH 885 0 +DWIDTH 15 0 +BBX 13 12 2 0 +BITMAP +7020 +8840 +8080 +9180 +9300 +E200 +0470 +0898 +1108 +3108 +6110 +40E0 +ENDCHAR +STARTCHAR uni2113 +ENCODING 8467 +SWIDTH 323 0 +DWIDTH 6 0 +BBX 7 12 0 0 +BITMAP +0E +1A +16 +14 +38 +30 +60 +E0 +60 +40 +50 +60 +ENDCHAR +STARTCHAR uni2116 +ENCODING 8470 +SWIDTH 1083 0 +DWIDTH 18 0 +BBX 17 12 1 0 +BITMAP +302000 +382000 +286700 +286C80 +6C4880 +645880 +445880 +42D980 +42CF00 +C28000 +C1BF00 +818000 +ENDCHAR +STARTCHAR uni2117 +ENCODING 8471 +SWIDTH 736 0 +DWIDTH 13 0 +BBX 12 12 1 0 +BITMAP +1F00 +30C0 +4020 +8F30 +8890 +8890 +8F10 +8810 +8830 +4020 +30C0 +1F00 +ENDCHAR +STARTCHAR trademark +ENCODING 8482 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 13 7 2 5 +BITMAP +FD18 +1198 +1198 +1198 +1168 +1168 +1168 +ENDCHAR +STARTCHAR Omega +ENCODING 8486 +SWIDTH 768 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +1F00 +6180 +40C0 +C0C0 +C040 +C060 +C060 +C040 +C0C0 +6080 +3100 +F3E0 +ENDCHAR +STARTCHAR estimated +ENCODING 8494 +SWIDTH 600 0 +DWIDTH 10 0 +BBX 8 9 1 0 +BITMAP +3C +43 +C1 +FF +C0 +C0 +C1 +42 +3C +ENDCHAR +STARTCHAR uni214D +ENCODING 8525 +SWIDTH 942 0 +DWIDTH 16 0 +BBX 15 12 1 0 +BITMAP +1804 +1808 +2810 +6820 +7840 +CCBC +8D66 +0260 +043C +0804 +10C4 +2078 +ENDCHAR +STARTCHAR uni214E +ENCODING 8526 +SWIDTH 489 0 +DWIDTH 8 0 +BBX 8 9 0 0 +BITMAP +01 +01 +01 +03 +3F +02 +02 +02 +FE +ENDCHAR +STARTCHAR onethird +ENCODING 8531 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 13 1 -1 +BITMAP +0818 +1830 +7060 +10C0 +1080 +1100 +0200 +0478 +0808 +1830 +3018 +6098 +C070 +ENDCHAR +STARTCHAR twothirds +ENCODING 8532 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 13 1 -1 +BITMAP +3818 +4C30 +0860 +30C0 +6080 +F900 +0200 +0478 +0808 +1830 +3018 +6098 +C070 +ENDCHAR +STARTCHAR oneeighth +ENCODING 8539 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 13 1 -1 +BITMAP +0818 +1830 +7060 +10C0 +1080 +1100 +0200 +0478 +08C8 +1870 +3098 +6098 +C0F0 +ENDCHAR +STARTCHAR threeeighths +ENCODING 8540 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 12 13 2 -1 +BITMAP +F030 +0860 +3040 +1080 +9100 +F200 +0400 +0CF0 +1990 +30E0 +6130 +4130 +81E0 +ENDCHAR +STARTCHAR fiveeighths +ENCODING 8541 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 12 13 2 -1 +BITMAP +7830 +8060 +F040 +1880 +9100 +F200 +0400 +0CF0 +1990 +30E0 +6130 +4130 +81E0 +ENDCHAR +STARTCHAR seveneighths +ENCODING 8542 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 13 1 -1 +BITMAP +7C10 +0830 +1060 +30C0 +2180 +2100 +0200 +0478 +08C8 +1070 +2098 +6098 +C0F0 +ENDCHAR +STARTCHAR uni2184 +ENCODING 8580 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +3C +66 +C2 +02 +02 +06 +86 +8C +78 +ENDCHAR +STARTCHAR arrowleft +ENCODING 8592 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 15 6 1 1 +BITMAP +2000 +6000 +FFFE +4000 +2000 +1000 +ENDCHAR +STARTCHAR arrowup +ENCODING 8593 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 6 15 1 -4 +BITMAP +10 +30 +78 +94 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR arrowright +ENCODING 8594 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 15 6 1 1 +BITMAP +0008 +000C +FFFE +0004 +0008 +0010 +ENDCHAR +STARTCHAR arrowdown +ENCODING 8595 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 5 14 2 -3 +BITMAP +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +B8 +70 +60 +ENDCHAR +STARTCHAR arrowboth +ENCODING 8596 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 15 6 1 1 +BITMAP +2008 +600C +FFFE +4004 +2008 +1010 +ENDCHAR +STARTCHAR arrowupdn +ENCODING 8597 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 6 15 1 -3 +BITMAP +10 +30 +78 +94 +10 +10 +10 +10 +10 +10 +10 +10 +5C +38 +30 +ENDCHAR +STARTCHAR arrowupdnbse +ENCODING 8616 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 6 17 1 -5 +BITMAP +10 +30 +78 +94 +10 +10 +10 +10 +10 +10 +10 +10 +5C +38 +30 +00 +FC +ENDCHAR +STARTCHAR partialdiff +ENCODING 8706 +SWIDTH 494 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +0E +11 +11 +01 +0F +31 +61 +41 +C2 +C2 +44 +78 +ENDCHAR +STARTCHAR Delta +ENCODING 8710 +SWIDTH 611 0 +DWIDTH 10 0 +BBX 10 11 0 0 +BITMAP +0400 +0400 +0E00 +1200 +1200 +2300 +2100 +4180 +4080 +80C0 +FFC0 +ENDCHAR +STARTCHAR product +ENCODING 8719 +SWIDTH 823 0 +DWIDTH 14 0 +BBX 11 15 2 -3 +BITMAP +FFE0 +C020 +C020 +C020 +C020 +C020 +C020 +C020 +C020 +C020 +C020 +C020 +C020 +C020 +C020 +ENDCHAR +STARTCHAR summation +ENCODING 8721 +SWIDTH 712 0 +DWIDTH 12 0 +BBX 11 15 1 -3 +BITMAP +FFC0 +6000 +6000 +3000 +1800 +0C00 +0E00 +0600 +0C00 +0C00 +1800 +3000 +6000 +C000 +FFE0 +ENDCHAR +STARTCHAR minus +ENCODING 8722 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 8 1 2 5 +BITMAP +FF +ENDCHAR +STARTCHAR fraction.dup8 +ENCODING 8725 +SWIDTH 166 0 +DWIDTH 3 0 +BBX 12 13 -4 -1 +BITMAP +0010 +0020 +0040 +0080 +0180 +0300 +0600 +0C00 +0800 +1000 +2000 +4000 +8000 +ENDCHAR +STARTCHAR uni2219 +ENCODING 8729 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 1 1 2 5 +BITMAP +80 +ENDCHAR +STARTCHAR radical +ENCODING 8730 +SWIDTH 548 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +01 +01 +01 +01 +01 +02 +02 +42 +A2 +22 +12 +12 +0C +0C +04 +04 +ENDCHAR +STARTCHAR infinity +ENCODING 8734 +SWIDTH 712 0 +DWIDTH 12 0 +BBX 10 5 1 4 +BITMAP +7380 +9440 +8C40 +9C40 +7380 +ENDCHAR +STARTCHAR orthogonal +ENCODING 8735 +SWIDTH 979 0 +DWIDTH 17 0 +BBX 11 11 3 0 +BITMAP +8000 +8000 +8000 +8000 +8000 +8000 +8000 +8000 +8000 +8000 +FFE0 +ENDCHAR +STARTCHAR intersection +ENCODING 8745 +SWIDTH 718 0 +DWIDTH 12 0 +BBX 10 12 2 0 +BITMAP +1E00 +6100 +4080 +8080 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +ENDCHAR +STARTCHAR integral +ENCODING 8747 +SWIDTH 273 0 +DWIDTH 5 0 +BBX 5 17 0 -1 +BITMAP +18 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +C0 +ENDCHAR +STARTCHAR approxequal +ENCODING 8776 +SWIDTH 548 0 +DWIDTH 9 0 +BBX 9 4 1 4 +BITMAP +7880 +8F00 +7880 +8F00 +ENDCHAR +STARTCHAR notequal +ENCODING 8800 +SWIDTH 548 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +02 +02 +04 +FF +08 +08 +10 +10 +FF +20 +60 +40 +ENDCHAR +STARTCHAR equivalence +ENCODING 8801 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 8 7 2 3 +BITMAP +FF +00 +00 +FF +00 +00 +FF +ENDCHAR +STARTCHAR lessequal +ENCODING 8804 +SWIDTH 548 0 +DWIDTH 9 0 +BBX 8 11 1 1 +BITMAP +01 +06 +18 +70 +C0 +70 +18 +06 +01 +00 +FF +ENDCHAR +STARTCHAR greaterequal +ENCODING 8805 +SWIDTH 548 0 +DWIDTH 9 0 +BBX 8 11 1 1 +BITMAP +80 +60 +18 +06 +03 +06 +18 +60 +80 +00 +FF +ENDCHAR +STARTCHAR house +ENCODING 8962 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 8 9 1 0 +BITMAP +18 +24 +42 +81 +81 +81 +81 +81 +FF +ENDCHAR +STARTCHAR revlogicalnot +ENCODING 8976 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 8 5 1 4 +BITMAP +FF +80 +80 +80 +80 +ENDCHAR +STARTCHAR integraltp +ENCODING 8992 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 3 18 5 -4 +BITMAP +E0 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR integralbt +ENCODING 8993 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 4 18 2 -4 +BITMAP +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +20 +E0 +ENDCHAR +STARTCHAR SF100000 +ENCODING 9472 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 2 0 4 +BITMAP +FFF0 +FFF0 +ENDCHAR +STARTCHAR SF110000 +ENCODING 9474 +SWIDTH 625 0 +DWIDTH 11 0 +BBX 1 20 4 -5 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR SF010000 +ENCODING 9484 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 7 11 5 -5 +BITMAP +FE +FE +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR SF030000 +ENCODING 9488 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 7 11 0 -5 +BITMAP +FE +FE +06 +06 +06 +06 +06 +06 +06 +06 +06 +ENDCHAR +STARTCHAR SF020000 +ENCODING 9492 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 7 11 5 4 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +FE +FE +ENDCHAR +STARTCHAR SF040000 +ENCODING 9496 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 7 11 0 4 +BITMAP +06 +06 +06 +06 +06 +06 +06 +06 +06 +FE +FE +ENDCHAR +STARTCHAR SF080000 +ENCODING 9500 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 7 20 5 -5 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +FE +FE +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR SF090000 +ENCODING 9508 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 7 20 0 -5 +BITMAP +06 +06 +06 +06 +06 +06 +06 +06 +06 +FE +FE +06 +06 +06 +06 +06 +06 +06 +06 +06 +ENDCHAR +STARTCHAR SF060000 +ENCODING 9516 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 11 0 -5 +BITMAP +FFF0 +FFF0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR SF070000 +ENCODING 9524 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 11 0 4 +BITMAP +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +FFF0 +FFF0 +ENDCHAR +STARTCHAR SF050000 +ENCODING 9532 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 20 0 -5 +BITMAP +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +FFF0 +FFF0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR SF430000 +ENCODING 9552 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 4 0 3 +BITMAP +FFF0 +0000 +0000 +FFF0 +ENDCHAR +STARTCHAR SF240000 +ENCODING 9553 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 4 20 4 -5 +BITMAP +90 +90 +90 +90 +90 +90 +90 +90 +90 +90 +90 +90 +90 +90 +90 +90 +90 +90 +90 +90 +ENDCHAR +STARTCHAR SF510000 +ENCODING 9554 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 7 12 5 -5 +BITMAP +FE +C0 +C0 +FE +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR SF520000 +ENCODING 9555 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 8 11 4 -5 +BITMAP +FF +FF +90 +90 +90 +90 +90 +90 +90 +90 +90 +ENDCHAR +STARTCHAR SF390000 +ENCODING 9556 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 8 12 4 -5 +BITMAP +FF +80 +80 +9F +90 +90 +90 +90 +90 +90 +90 +90 +ENDCHAR +STARTCHAR SF220000 +ENCODING 9557 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 7 12 0 -5 +BITMAP +FE +06 +06 +FE +06 +06 +06 +06 +06 +06 +06 +06 +ENDCHAR +STARTCHAR SF210000 +ENCODING 9558 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 8 11 0 -5 +BITMAP +FF +FF +09 +09 +09 +09 +09 +09 +09 +09 +09 +ENDCHAR +STARTCHAR SF250000 +ENCODING 9559 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 8 12 0 -5 +BITMAP +FF +01 +01 +F9 +09 +09 +09 +09 +09 +09 +09 +09 +ENDCHAR +STARTCHAR SF500000 +ENCODING 9560 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 7 12 5 3 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +FE +C0 +C0 +FE +ENDCHAR +STARTCHAR SF490000 +ENCODING 9561 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 8 11 4 4 +BITMAP +90 +90 +90 +90 +90 +90 +90 +90 +90 +FF +FF +ENDCHAR +STARTCHAR SF380000 +ENCODING 9562 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 8 12 4 3 +BITMAP +90 +90 +90 +90 +90 +90 +90 +90 +9F +80 +80 +FF +ENDCHAR +STARTCHAR SF280000 +ENCODING 9563 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 7 12 0 3 +BITMAP +06 +06 +06 +06 +06 +06 +06 +06 +FE +06 +06 +FE +ENDCHAR +STARTCHAR SF270000 +ENCODING 9564 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 8 11 0 4 +BITMAP +09 +09 +09 +09 +09 +09 +09 +09 +09 +FF +FF +ENDCHAR +STARTCHAR SF260000 +ENCODING 9565 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 8 12 0 3 +BITMAP +09 +09 +09 +09 +09 +09 +09 +09 +F9 +01 +01 +FF +ENDCHAR +STARTCHAR SF360000 +ENCODING 9566 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 7 20 5 -5 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +FE +C0 +C0 +FE +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR SF370000 +ENCODING 9567 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 8 20 4 -5 +BITMAP +90 +90 +90 +90 +90 +90 +90 +90 +90 +9F +9F +90 +90 +90 +90 +90 +90 +90 +90 +90 +ENDCHAR +STARTCHAR SF420000 +ENCODING 9568 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 8 20 4 -5 +BITMAP +90 +90 +90 +90 +90 +90 +90 +90 +9F +80 +80 +9F +90 +90 +90 +90 +90 +90 +90 +90 +ENDCHAR +STARTCHAR SF190000 +ENCODING 9569 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 7 20 0 -5 +BITMAP +06 +06 +06 +06 +06 +06 +06 +06 +FE +06 +06 +FE +06 +06 +06 +06 +06 +06 +06 +06 +ENDCHAR +STARTCHAR SF200000 +ENCODING 9570 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 8 20 0 -5 +BITMAP +09 +09 +09 +09 +09 +09 +09 +09 +09 +F9 +F9 +09 +09 +09 +09 +09 +09 +09 +09 +09 +ENDCHAR +STARTCHAR SF230000 +ENCODING 9571 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 8 20 0 -5 +BITMAP +09 +09 +09 +09 +09 +09 +09 +09 +F9 +01 +01 +F9 +09 +09 +09 +09 +09 +09 +09 +09 +ENDCHAR +STARTCHAR SF470000 +ENCODING 9572 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 12 0 -5 +BITMAP +FFF0 +0000 +0000 +FFF0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR SF480000 +ENCODING 9573 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 11 0 -5 +BITMAP +FFF0 +FFF0 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +ENDCHAR +STARTCHAR SF410000 +ENCODING 9574 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 12 0 -5 +BITMAP +FFF0 +0000 +0000 +F9F0 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +ENDCHAR +STARTCHAR SF450000 +ENCODING 9575 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 12 0 3 +BITMAP +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +FFF0 +0000 +0000 +FFF0 +ENDCHAR +STARTCHAR SF460000 +ENCODING 9576 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 11 0 4 +BITMAP +0900 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +FFF0 +FFF0 +ENDCHAR +STARTCHAR SF400000 +ENCODING 9577 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 12 0 3 +BITMAP +0900 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +F9F0 +0000 +0000 +FFF0 +ENDCHAR +STARTCHAR SF540000 +ENCODING 9578 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 20 0 -5 +BITMAP +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +FFF0 +0600 +0600 +FFF0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR SF530000 +ENCODING 9579 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 20 0 -5 +BITMAP +0900 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +FFF0 +FFF0 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +ENDCHAR +STARTCHAR SF440000 +ENCODING 9580 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 20 0 -5 +BITMAP +0900 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +F9F0 +0000 +0000 +F9F0 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +0900 +ENDCHAR +STARTCHAR upblock +ENCODING 9600 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 10 0 5 +BITMAP +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +ENDCHAR +STARTCHAR dnblock +ENCODING 9604 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 10 0 -5 +BITMAP +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +ENDCHAR +STARTCHAR block +ENCODING 9608 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 20 0 -5 +BITMAP +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +FFF0 +ENDCHAR +STARTCHAR lfblock +ENCODING 9612 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 6 20 0 -5 +BITMAP +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +ENDCHAR +STARTCHAR rtblock +ENCODING 9616 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 6 20 6 -5 +BITMAP +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +FC +ENDCHAR +STARTCHAR ltshade +ENCODING 9617 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 11 19 1 -4 +BITMAP +8880 +0000 +2220 +0000 +8880 +0000 +2220 +0000 +8880 +0000 +2220 +0000 +8880 +0000 +2220 +0000 +8880 +0000 +2220 +ENDCHAR +STARTCHAR shade +ENCODING 9618 +SWIDTH 708 0 +DWIDTH 12 0 +BBX 12 19 0 -4 +BITMAP +5550 +0000 +AAA0 +0000 +5550 +0000 +AAA0 +0000 +5550 +0000 +AAA0 +0000 +5550 +0000 +AAA0 +0000 +5550 +0000 +AAA0 +ENDCHAR +STARTCHAR dkshade +ENCODING 9619 +SWIDTH 729 0 +DWIDTH 12 0 +BBX 12 20 0 -5 +BITMAP +5550 +FFF0 +AAA0 +FFF0 +5550 +FFF0 +AAA0 +FFF0 +5550 +FFF0 +AAA0 +FFF0 +5550 +FFF0 +AAA0 +FFF0 +5550 +FFF0 +AAA0 +FFF0 +ENDCHAR +STARTCHAR filledbox +ENCODING 9632 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 8 8 1 0 +BITMAP +FF +FF +FF +FF +FF +FF +FF +FF +ENDCHAR +STARTCHAR H22073 +ENCODING 9633 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 8 8 1 0 +BITMAP +FF +81 +81 +81 +81 +81 +81 +FF +ENDCHAR +STARTCHAR H18543 +ENCODING 9642 +SWIDTH 354 0 +DWIDTH 6 0 +BBX 4 4 1 4 +BITMAP +F0 +F0 +F0 +F0 +ENDCHAR +STARTCHAR H18551 +ENCODING 9643 +SWIDTH 354 0 +DWIDTH 6 0 +BBX 4 4 1 4 +BITMAP +F0 +90 +90 +F0 +ENDCHAR +STARTCHAR filledrect +ENCODING 9644 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 17 3 0 3 +BITMAP +FFFF80 +FFFF80 +FFFF80 +ENDCHAR +STARTCHAR triagup +ENCODING 9650 +SWIDTH 989 0 +DWIDTH 17 0 +BBX 11 12 3 0 +BITMAP +0400 +0400 +0E00 +0E00 +1F00 +1F00 +3F80 +3F80 +7FC0 +7FC0 +FFE0 +FFE0 +ENDCHAR +STARTCHAR triagrt +ENCODING 9658 +SWIDTH 989 0 +DWIDTH 17 0 +BBX 12 12 2 0 +BITMAP +8000 +E000 +F800 +FE00 +FF80 +FFE0 +FFF0 +FFC0 +FF00 +FC00 +F000 +C000 +ENDCHAR +STARTCHAR triagdn +ENCODING 9660 +SWIDTH 989 0 +DWIDTH 17 0 +BBX 11 12 3 0 +BITMAP +FFE0 +FFE0 +7FC0 +7FC0 +3F80 +3F80 +1F00 +1F00 +0E00 +0E00 +0400 +0400 +ENDCHAR +STARTCHAR triaglf +ENCODING 9668 +SWIDTH 989 0 +DWIDTH 17 0 +BBX 11 11 3 0 +BITMAP +0060 +01E0 +07E0 +1FE0 +7FE0 +FFE0 +3FE0 +0FE0 +03E0 +00E0 +0020 +ENDCHAR +STARTCHAR lozenge +ENCODING 9674 +SWIDTH 494 0 +DWIDTH 8 0 +BBX 7 12 1 0 +BITMAP +10 +28 +24 +44 +42 +82 +82 +42 +44 +24 +28 +10 +ENDCHAR +STARTCHAR circle +ENCODING 9675 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 8 7 1 1 +BITMAP +3E +42 +81 +81 +81 +42 +3C +ENDCHAR +STARTCHAR uni25CC +ENCODING 9676 +SWIDTH 594 0 +DWIDTH 10 0 +BBX 8 9 1 1 +BITMAP +34 +42 +00 +81 +81 +81 +00 +42 +34 +ENDCHAR +STARTCHAR H18533 +ENCODING 9679 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 8 7 1 1 +BITMAP +3E +7E +7F +FF +7F +7E +1C +ENDCHAR +STARTCHAR invbullet +ENCODING 9688 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 8 8 1 0 +BITMAP +FF +FF +E7 +E3 +E3 +F7 +FF +FF +ENDCHAR +STARTCHAR invcircle +ENCODING 9689 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 10 10 0 0 +BITMAP +FFC0 +FFC0 +ECC0 +DFC0 +FF40 +BF40 +FF40 +DEC0 +F1C0 +FFC0 +ENDCHAR +STARTCHAR openbullet +ENCODING 9702 +SWIDTH 354 0 +DWIDTH 6 0 +BBX 4 4 1 4 +BITMAP +60 +90 +90 +F0 +ENDCHAR +STARTCHAR smileface +ENCODING 9786 +SWIDTH 1020 0 +DWIDTH 17 0 +BBX 11 11 3 -1 +BITMAP +0600 +3980 +4040 +4020 +9120 +8020 +8020 +5120 +4E40 +2080 +1F00 +ENDCHAR +STARTCHAR invsmileface +ENCODING 9787 +SWIDTH 1052 0 +DWIDTH 18 0 +BBX 10 11 4 -1 +BITMAP +0C00 +3F00 +7F80 +FFC0 +CCC0 +FFC0 +FFC0 +FFC0 +E380 +7F80 +1E00 +ENDCHAR +STARTCHAR sun +ENCODING 9788 +SWIDTH 916 0 +DWIDTH 16 0 +BBX 14 15 1 -2 +BITMAP +0200 +4208 +2310 +1CE0 +2020 +2020 +2010 +E01C +2020 +2020 +1060 +2F90 +4208 +0200 +0200 +ENDCHAR +STARTCHAR female +ENCODING 9792 +SWIDTH 750 0 +DWIDTH 13 0 +BBX 9 17 2 -4 +BITMAP +0800 +7600 +8100 +8080 +8080 +8080 +8100 +4100 +2200 +1C00 +0800 +0800 +0800 +7E00 +0800 +0800 +0800 +ENDCHAR +STARTCHAR male +ENCODING 9794 +SWIDTH 750 0 +DWIDTH 13 0 +BBX 11 15 1 -2 +BITMAP +01C0 +06C0 +0940 +0140 +0220 +0200 +0C00 +7200 +8100 +8100 +8080 +8080 +8100 +8100 +7E00 +ENDCHAR +STARTCHAR spade +ENCODING 9824 +SWIDTH 531 0 +DWIDTH 9 0 +BBX 8 10 1 0 +BITMAP +10 +10 +38 +7C +FE +FF +FE +D6 +10 +7C +ENDCHAR +STARTCHAR club +ENCODING 9827 +SWIDTH 656 0 +DWIDTH 11 0 +BBX 11 10 0 0 +BITMAP +0E00 +1F00 +1F00 +7FC0 +7FE0 +FFE0 +7FC0 +3580 +0400 +1F00 +ENDCHAR +STARTCHAR heart +ENCODING 9829 +SWIDTH 593 0 +DWIDTH 10 0 +BBX 9 9 1 1 +BITMAP +E700 +FF80 +FF80 +FF00 +7F00 +7E00 +3C00 +1800 +1800 +ENDCHAR +STARTCHAR diamond +ENCODING 9830 +SWIDTH 510 0 +DWIDTH 9 0 +BBX 7 10 1 0 +BITMAP +10 +30 +38 +7C +FE +FE +7C +38 +30 +10 +ENDCHAR +STARTCHAR musicalnote +ENCODING 9834 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 11 0 0 +BITMAP +0E +0F +09 +09 +08 +08 +08 +28 +78 +F8 +70 +ENDCHAR +STARTCHAR musicalnotedbl +ENCODING 9835 +SWIDTH 750 0 +DWIDTH 13 0 +BBX 10 13 1 -1 +BITMAP +03C0 +1FC0 +1E40 +1040 +1040 +1040 +1040 +1140 +13C0 +77C0 +F3C0 +F000 +E000 +ENDCHAR +STARTCHAR uni266F +ENCODING 9839 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 14 0 -2 +BITMAP +0100 +0100 +1180 +1700 +1A00 +6200 +2200 +2200 +2500 +2E00 +7400 +C400 +4000 +4000 +ENDCHAR +STARTCHAR uni2C60 +ENCODING 11360 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 0 +BITMAP +1800 +1800 +1000 +1000 +3000 +7E00 +3000 +FE00 +6000 +6000 +6000 +7F80 +ENDCHAR +STARTCHAR uni2C61 +ENCODING 11361 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 12 1 0 +BITMAP +20 +20 +20 +60 +60 +E0 +40 +E0 +C0 +80 +80 +80 +ENDCHAR +STARTCHAR uni2C62 +ENCODING 11362 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 0 +BITMAP +1800 +1800 +1000 +3000 +3000 +7400 +B800 +2000 +6000 +6000 +6000 +7F80 +ENDCHAR +STARTCHAR uni2C63 +ENCODING 11363 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3FC0 +3060 +2060 +FC60 +6060 +60C0 +7F80 +4000 +C000 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni2C64 +ENCODING 11364 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 15 0 -3 +BITMAP +1FE0 +1830 +1010 +1010 +3030 +3030 +3FC0 +2180 +60C0 +6040 +6060 +6060 +4000 +C000 +6000 +ENDCHAR +STARTCHAR uni2C65 +ENCODING 11365 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 15 0 -3 +BITMAP +0040 +0080 +0180 +1F00 +3380 +2380 +0580 +3F80 +6900 +5300 +7300 +3D00 +4000 +C000 +8000 +ENDCHAR +STARTCHAR uni2C66 +ENCODING 11366 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 10 15 -1 -3 +BITMAP +04C0 +0880 +0980 +3F00 +1A00 +1600 +1400 +1800 +3800 +3000 +3000 +3800 +4000 +C000 +8000 +ENDCHAR +STARTCHAR uni2C67 +ENCODING 11367 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 15 1 -3 +BITMAP +3030 +3030 +2020 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C0C0 +80E0 +0040 +0040 +00C0 +ENDCHAR +STARTCHAR uni2C68 +ENCODING 11368 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +30 +20 +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +87 +03 +02 +02 +ENDCHAR +STARTCHAR uni2C69 +ENCODING 11369 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 15 1 -3 +BITMAP +3060 +30C0 +2180 +2700 +6E00 +7C00 +7600 +6200 +C300 +C100 +C180 +80C0 +0040 +00C0 +00C0 +ENDCHAR +STARTCHAR uni2C6A +ENCODING 11370 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +30 +20 +20 +63 +66 +4C +58 +78 +C8 +CC +84 +86 +02 +06 +06 +ENDCHAR +STARTCHAR uni2C6B +ENCODING 11371 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 15 1 -3 +BITMAP +7FC0 +0180 +0300 +0300 +0600 +0C00 +1800 +3000 +3000 +6000 +C000 +FF80 +0100 +0100 +0300 +ENDCHAR +STARTCHAR uni2C6C +ENCODING 11372 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3F80 +0300 +0600 +0C00 +0800 +1800 +3000 +6000 +FF00 +0200 +0200 +0200 +ENDCHAR +STARTCHAR uni2C6D +ENCODING 11373 +SWIDTH 754 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +0FE0 +1860 +6060 +4060 +C040 +8040 +80C0 +80C0 +80C0 +C080 +6180 +3F80 +ENDCHAR +STARTCHAR uni2C6E +ENCODING 11374 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 14 15 1 -3 +BITMAP +300C +3818 +3838 +3828 +6878 +6858 +48D0 +4990 +CD30 +CF30 +C630 +8620 +0020 +0060 +01C0 +ENDCHAR +STARTCHAR uni2C6F +ENCODING 11375 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 2 0 +BITMAP +C060 +C0C0 +C080 +4180 +7F00 +4300 +6600 +6600 +6C00 +2800 +3800 +3000 +ENDCHAR +STARTCHAR uni2C70 +ENCODING 11376 +SWIDTH 754 0 +DWIDTH 13 0 +BBX 12 12 1 0 +BITMAP +3F80 +30E0 +2060 +2020 +6030 +6020 +6020 +4060 +C040 +C0C0 +C180 +FE00 +ENDCHAR +STARTCHAR uni2C71 +ENCODING 11377 +SWIDTH 601 0 +DWIDTH 10 0 +BBX 10 9 1 0 +BITMAP +C1C0 +4340 +4200 +4400 +4400 +6800 +7800 +3000 +3000 +ENDCHAR +STARTCHAR uni2C72 +ENCODING 11378 +SWIDTH 1037 0 +DWIDTH 18 0 +BBX 17 12 2 0 +BITMAP +C18380 +C18680 +C28400 +C28400 +C48800 +CC8800 +489800 +589000 +50B000 +70E000 +60E000 +60C000 +ENDCHAR +STARTCHAR uni2C73 +ENCODING 11379 +SWIDTH 840 0 +DWIDTH 14 0 +BBX 14 9 1 0 +BITMAP +C61C +C634 +4E20 +4A60 +5A40 +52C0 +5280 +6380 +6300 +ENDCHAR +STARTCHAR uni2C74 +ENCODING 11380 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +71 +5B +52 +76 +C4 +68 +78 +30 +30 +ENDCHAR +STARTCHAR uni2C75 +ENCODING 11381 +SWIDTH 601 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +3000 +3000 +2000 +2000 +6000 +7F80 +4000 +4000 +C000 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni2C76 +ENCODING 11382 +SWIDTH 438 0 +DWIDTH 7 0 +BBX 6 9 1 0 +BITMAP +60 +60 +40 +40 +FC +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uni2C77 +ENCODING 11383 +SWIDTH 652 0 +DWIDTH 11 0 +BBX 10 9 1 0 +BITMAP +1380 +6480 +44C0 +CCC0 +8CC0 +8C80 +C980 +4B00 +3E00 +ENDCHAR +STARTCHAR uni2C78 +ENCODING 11384 +SWIDTH 676 0 +DWIDTH 12 0 +BBX 10 9 1 0 +BITMAP +1E00 +6200 +4300 +C100 +FF00 +8000 +C240 +C740 +7980 +ENDCHAR +STARTCHAR uni2C79 +ENCODING 11385 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 7 12 -1 0 +BITMAP +0E +02 +02 +06 +06 +04 +04 +04 +0C +0C +18 +E8 +ENDCHAR +STARTCHAR uni2C7A +ENCODING 11386 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +3E +63 +41 +C1 +81 +93 +AB +EE +78 +ENDCHAR +STARTCHAR uni2C7B +ENCODING 11387 +SWIDTH 489 0 +DWIDTH 8 0 +BBX 8 9 0 0 +BITMAP +3F +01 +03 +03 +7F +02 +02 +06 +FE +ENDCHAR +STARTCHAR uni2C7C +ENCODING 11388 +SWIDTH 122 0 +DWIDTH 2 0 +BBX 4 10 -2 -3 +BITMAP +10 +00 +10 +10 +20 +20 +20 +20 +60 +C0 +ENDCHAR +STARTCHAR uni2C7D +ENCODING 11389 +SWIDTH 357 0 +DWIDTH 6 0 +BBX 5 6 2 6 +BITMAP +88 +88 +90 +50 +60 +40 +ENDCHAR +STARTCHAR uni2C7E +ENCODING 11390 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 15 1 -3 +BITMAP +1F00 +30C0 +2040 +2040 +3000 +1C00 +0300 +0180 +C0C0 +C080 +6180 +3E00 +1000 +1800 +0E00 +ENDCHAR +STARTCHAR uni2C7F +ENCODING 11391 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 15 1 -3 +BITMAP +7FC0 +0180 +0300 +0300 +0600 +0C00 +1800 +3000 +3000 +6000 +C000 +E000 +3800 +0C80 +0780 +ENDCHAR +STARTCHAR uni2E17 +ENCODING 11799 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 6 0 2 +BITMAP +04 +38 +40 +08 +30 +C0 +ENDCHAR +STARTCHAR uniA717 +ENCODING 42775 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 5 0 7 +BITMAP +20 +20 +A0 +20 +20 +ENDCHAR +STARTCHAR uniA718 +ENCODING 42776 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 4 0 8 +BITMAP +90 +20 +40 +80 +ENDCHAR +STARTCHAR uniA719 +ENCODING 42777 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 0 9 +BITMAP +40 +00 +F0 +ENDCHAR +STARTCHAR uniA71A +ENCODING 42778 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 3 -1 9 +BITMAP +08 +08 +F8 +ENDCHAR +STARTCHAR uniA71B +ENCODING 42779 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 6 7 1 8 +BITMAP +10 +78 +FC +10 +10 +10 +10 +ENDCHAR +STARTCHAR uniA71C +ENCODING 42780 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 6 7 1 9 +BITMAP +10 +10 +10 +10 +FC +78 +10 +ENDCHAR +STARTCHAR uniA71D +ENCODING 42781 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 3 8 3 9 +BITMAP +60 +60 +40 +40 +40 +C0 +00 +80 +ENDCHAR +STARTCHAR uniA71E +ENCODING 42782 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 3 8 3 8 +BITMAP +60 +00 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR uniA71F +ENCODING 42783 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 3 8 2 4 +BITMAP +60 +00 +40 +40 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uniA720 +ENCODING 42784 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 3 -1 9 +BITMAP +FC +90 +90 +ENDCHAR +STARTCHAR uniA721 +ENCODING 42785 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 3 -2 0 +BITMAP +A0 +A0 +F8 +ENDCHAR +STARTCHAR uniA722 +ENCODING 42786 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 12 0 0 +BITMAP +10 +08 +08 +18 +30 +00 +60 +30 +30 +30 +20 +C0 +ENDCHAR +STARTCHAR uniA723 +ENCODING 42787 +SWIDTH 208 0 +DWIDTH 4 0 +BBX 3 9 1 3 +BITMAP +20 +20 +20 +40 +00 +40 +40 +40 +80 +ENDCHAR +STARTCHAR uniA724 +ENCODING 42788 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 6 2 6 +BITMAP +30 +40 +C0 +80 +C0 +60 +ENDCHAR +STARTCHAR uniA725 +ENCODING 42789 +SWIDTH 208 0 +DWIDTH 4 0 +BBX 3 4 2 8 +BITMAP +60 +80 +80 +C0 +ENDCHAR +STARTCHAR uniA726 +ENCODING 42790 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 15 1 -3 +BITMAP +3030 +3020 +2020 +2060 +6060 +7FE0 +4040 +4040 +C0C0 +C0C0 +C0C0 +8080 +0180 +0100 +0E00 +ENDCHAR +STARTCHAR uniA727 +ENCODING 42791 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +30 +20 +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +86 +04 +04 +18 +ENDCHAR +STARTCHAR uniA728 +ENCODING 42792 +SWIDTH 829 0 +DWIDTH 14 0 +BBX 12 15 2 -3 +BITMAP +FFC0 +0C00 +0800 +0FF0 +1860 +18C0 +1980 +13C0 +1060 +3060 +3060 +3060 +0040 +18C0 +0F00 +ENDCHAR +STARTCHAR uniA729 +ENCODING 42793 +SWIDTH 627 0 +DWIDTH 11 0 +BBX 10 15 1 -3 +BITMAP +1000 +2000 +2000 +FFC0 +6180 +4300 +4400 +4E00 +C300 +C180 +C180 +E180 +0300 +4600 +3C00 +ENDCHAR +STARTCHAR uniA72A +ENCODING 42794 +SWIDTH 552 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +0780 +1800 +3000 +1800 +0C00 +1E00 +6000 +C000 +8000 +8000 +C000 +7E00 +ENDCHAR +STARTCHAR uniA72B +ENCODING 42795 +SWIDTH 552 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +0780 +1800 +3000 +1800 +0C00 +1E00 +6000 +C000 +8000 +8000 +C000 +7E00 +ENDCHAR +STARTCHAR uniA72C +ENCODING 42796 +SWIDTH 516 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +01 +03 +07 +0B +12 +32 +66 +C6 +FC +04 +0C +38 +ENDCHAR +STARTCHAR uniA72D +ENCODING 42797 +SWIDTH 516 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +01 +03 +07 +0B +12 +32 +66 +C6 +FC +04 +0C +38 +ENDCHAR +STARTCHAR uniA72E +ENCODING 42798 +SWIDTH 586 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +01 +03 +07 +0B +12 +32 +66 +C6 +FF +04 +0D +3A +ENDCHAR +STARTCHAR uniA72F +ENCODING 42799 +SWIDTH 586 0 +DWIDTH 10 0 +BBX 8 12 1 -3 +BITMAP +01 +03 +07 +0B +12 +32 +66 +C6 +FF +04 +0D +3A +ENDCHAR +STARTCHAR uniA730 +ENCODING 42800 +SWIDTH 503 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +3F +60 +60 +40 +7E +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR uniA731 +ENCODING 42801 +SWIDTH 553 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +1F00 +3180 +2180 +3000 +1E00 +0100 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR uniA732 +ENCODING 42802 +SWIDTH 1155 0 +DWIDTH 20 0 +BBX 19 12 0 0 +BITMAP +038180 +038380 +078680 +058680 +0C8CC0 +188CC0 +18D8C0 +30D8C0 +3FFFC0 +60E040 +406060 +C04060 +ENDCHAR +STARTCHAR uniA733 +ENCODING 42803 +SWIDTH 902 0 +DWIDTH 15 0 +BBX 14 9 1 0 +BITMAP +3EF8 +638C +430C +030C +7FF8 +C308 +8618 +C638 +79F8 +ENDCHAR +STARTCHAR uniA734 +ENCODING 42804 +SWIDTH 1167 0 +DWIDTH 20 0 +BBX 20 12 0 0 +BITMAP +038F80 +0398C0 +07A060 +05E030 +0CC030 +18C030 +18C030 +30C020 +3FC060 +606040 +407180 +C01F00 +ENDCHAR +STARTCHAR uniA735 +ENCODING 42805 +SWIDTH 921 0 +DWIDTH 16 0 +BBX 14 9 1 0 +BITMAP +3E78 +638C +4304 +0304 +7F04 +C304 +870C +C518 +78F0 +ENDCHAR +STARTCHAR uniA736 +ENCODING 42806 +SWIDTH 1020 0 +DWIDTH 17 0 +BBX 18 12 0 0 +BITMAP +0380C0 +0380C0 +078080 +058080 +0C8180 +188180 +18C100 +30C100 +3FC300 +60C300 +404600 +C07800 +ENDCHAR +STARTCHAR uniA737 +ENCODING 42807 +SWIDTH 885 0 +DWIDTH 15 0 +BBX 14 9 1 0 +BITMAP +3E0C +630C +430C +0308 +7F08 +C218 +8618 +C638 +7BD0 +ENDCHAR +STARTCHAR uniA738 +ENCODING 42808 +SWIDTH 942 0 +DWIDTH 16 0 +BBX 17 12 0 0 +BITMAP +038080 +038180 +078300 +058300 +0C8600 +188400 +18CC00 +30C800 +3FD800 +60D000 +407000 +C06000 +ENDCHAR +STARTCHAR uniA739 +ENCODING 42809 +SWIDTH 734 0 +DWIDTH 12 0 +BBX 12 9 1 0 +BITMAP +3E10 +6330 +4320 +0360 +7FC0 +C280 +8780 +C700 +7B00 +ENDCHAR +STARTCHAR uniA73A +ENCODING 42810 +SWIDTH 942 0 +DWIDTH 16 0 +BBX 17 12 0 0 +BITMAP +038080 +038180 +078100 +048300 +0C8600 +188600 +1FFF00 +30C800 +20D800 +60D000 +407000 +C06000 +ENDCHAR +STARTCHAR uniA73B +ENCODING 42811 +SWIDTH 734 0 +DWIDTH 12 0 +BBX 12 9 1 0 +BITMAP +3E10 +6330 +4320 +0360 +7FE0 +C2C0 +8780 +C700 +7B00 +ENDCHAR +STARTCHAR uniA73C +ENCODING 42812 +SWIDTH 942 0 +DWIDTH 16 0 +BBX 17 15 0 -3 +BITMAP +038080 +038180 +078300 +058300 +0C8600 +188400 +18CC00 +30C800 +3FD800 +60D000 +406000 +C06000 +004000 +008000 +070000 +ENDCHAR +STARTCHAR uniA73D +ENCODING 42813 +SWIDTH 734 0 +DWIDTH 12 0 +BBX 12 12 1 -3 +BITMAP +3E10 +6330 +4320 +0340 +7FC0 +C280 +8780 +C700 +7A00 +0600 +0400 +1800 +ENDCHAR +STARTCHAR uniA73E +ENCODING 42814 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +0F80 +30C0 +6060 +0020 +0020 +0620 +0460 +0060 +8040 +C0C0 +6380 +3E00 +ENDCHAR +STARTCHAR uniA73F +ENCODING 42815 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 0 0 +BITMAP +1E +63 +01 +09 +19 +C3 +C3 +46 +3C +ENDCHAR +STARTCHAR uniA740 +ENCODING 42816 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3060 +7CC0 +2380 +6600 +6C00 +7C00 +7600 +6300 +C300 +C180 +C180 +80C0 +ENDCHAR +STARTCHAR uniA741 +ENCODING 42817 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +30 +7C +20 +63 +66 +4C +58 +68 +CC +CC +84 +86 +ENDCHAR +STARTCHAR uniA742 +ENCODING 42818 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3060 +30C0 +2380 +2700 +6C00 +7C80 +7780 +6300 +CF00 +C980 +C180 +80C0 +ENDCHAR +STARTCHAR uniA743 +ENCODING 42819 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +30 +20 +20 +63 +66 +4C +58 +7A +EC +DC +94 +86 +ENDCHAR +STARTCHAR uniA744 +ENCODING 42820 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3060 +7CC0 +2380 +6600 +6C00 +7C80 +7780 +6300 +CF00 +C980 +C180 +80C0 +ENDCHAR +STARTCHAR uniA745 +ENCODING 42821 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +30 +7C +20 +63 +66 +4C +58 +7A +EC +DC +94 +86 +ENDCHAR +STARTCHAR uniA746 +ENCODING 42822 +SWIDTH 650 0 +DWIDTH 11 0 +BBX 8 12 2 0 +BITMAP +60 +40 +40 +C0 +C0 +C0 +E0 +60 +60 +40 +40 +FF +ENDCHAR +STARTCHAR uniA747 +ENCODING 42823 +SWIDTH 310 0 +DWIDTH 5 0 +BBX 3 12 2 0 +BITMAP +40 +40 +C0 +C0 +C0 +80 +60 +40 +40 +C0 +C0 +C0 +ENDCHAR +STARTCHAR uniA748 +ENCODING 42824 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +30 +7C +20 +60 +60 +60 +40 +40 +C0 +C0 +C0 +FF +ENDCHAR +STARTCHAR uniA749 +ENCODING 42825 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 4 12 1 0 +BITMAP +20 +70 +60 +60 +40 +40 +40 +C0 +C0 +80 +80 +80 +ENDCHAR +STARTCHAR uniA74A +ENCODING 42826 +SWIDTH 802 0 +DWIDTH 14 0 +BBX 13 12 1 0 +BITMAP +0780 +1860 +3020 +2030 +6030 +4010 +FFF8 +4030 +4020 +6060 +30C0 +1F00 +ENDCHAR +STARTCHAR uniA74B +ENCODING 42827 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 11 9 0 0 +BITMAP +0F00 +1980 +3080 +20C0 +FFE0 +6080 +6180 +3300 +1E00 +ENDCHAR +STARTCHAR uniA74C +ENCODING 42828 +SWIDTH 877 0 +DWIDTH 15 0 +BBX 14 12 2 0 +BITMAP +1F38 +30EC +606C +C068 +C070 +8020 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uniA74D +ENCODING 42829 +SWIDTH 651 0 +DWIDTH 11 0 +BBX 10 9 1 0 +BITMAP +1FC0 +6340 +4140 +C140 +8180 +8300 +8300 +C600 +7C00 +ENDCHAR +STARTCHAR uniA74E +ENCODING 42830 +SWIDTH 1333 0 +DWIDTH 23 0 +BBX 22 12 1 0 +BITMAP +0F83E0 +184630 +302818 +60380C +40300C +C0300C +C0300C +C03008 +407018 +605810 +318C60 +1F07C0 +ENDCHAR +STARTCHAR uniA74F +ENCODING 42831 +SWIDTH 952 0 +DWIDTH 16 0 +BBX 15 9 1 0 +BITMAP +1E78 +63C4 +4186 +C106 +8106 +8306 +8304 +C78C +78F0 +ENDCHAR +STARTCHAR uniA750 +ENCODING 42832 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 12 12 0 0 +BITMAP +1FE0 +1830 +1030 +1030 +3030 +3060 +3FC0 +2000 +6000 +F800 +6000 +4000 +ENDCHAR +STARTCHAR uniA751 +ENCODING 42833 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 12 -1 -3 +BITMAP +1B80 +1CC0 +18C0 +1040 +3040 +30C0 +3080 +3180 +2E00 +6000 +F800 +4000 +ENDCHAR +STARTCHAR uniA752 +ENCODING 42834 +SWIDTH 823 0 +DWIDTH 14 0 +BBX 15 12 0 0 +BITMAP +03F8 +020C +0606 +0604 +060C +040C +3FF0 +4C00 +CC00 +CC00 +0800 +1800 +ENDCHAR +STARTCHAR uniA753 +ENCODING 42835 +SWIDTH 697 0 +DWIDTH 12 0 +BBX 12 12 -1 -3 +BITMAP +02E0 +0730 +0610 +0610 +0410 +0410 +0C30 +0C60 +3FC0 +4800 +8800 +1800 +ENDCHAR +STARTCHAR uniA754 +ENCODING 42836 +SWIDTH 930 0 +DWIDTH 16 0 +BBX 14 12 2 0 +BITMAP +E3F8 +360C +3604 +2604 +240C +2418 +3FF0 +0C00 +0C00 +0800 +0800 +1800 +ENDCHAR +STARTCHAR uniA755 +ENCODING 42837 +SWIDTH 805 0 +DWIDTH 14 0 +BBX 12 13 1 -3 +BITMAP +E000 +22E0 +2730 +2610 +6610 +6410 +6410 +4C30 +4C60 +7FC0 +0800 +1800 +1800 +ENDCHAR +STARTCHAR uniA756 +ENCODING 42838 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 14 2 -2 +BITMAP +1F00 +30C0 +6060 +C060 +C020 +8020 +8060 +8060 +8040 +C4C0 +63A0 +3FC0 +01C0 +0200 +ENDCHAR +STARTCHAR uniA757 +ENCODING 42839 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +3D +63 +43 +C3 +82 +82 +86 +C6 +7E +04 +3E +0C +ENDCHAR +STARTCHAR uniA758 +ENCODING 42840 +SWIDTH 979 0 +DWIDTH 17 0 +BBX 15 15 2 -3 +BITMAP +1F00 +30C0 +6060 +C06E +C022 +8022 +8066 +806C +8058 +C4F0 +63E0 +3FC0 +01C0 +0300 +0600 +ENDCHAR +STARTCHAR uniA759 +ENCODING 42841 +SWIDTH 747 0 +DWIDTH 13 0 +BBX 12 12 1 -3 +BITMAP +3D70 +6310 +4310 +C330 +8260 +82C0 +8780 +C700 +7E00 +0C00 +1C00 +3C00 +ENDCHAR +STARTCHAR uniA75A +ENCODING 42842 +SWIDTH 581 0 +DWIDTH 10 0 +BBX 8 12 2 0 +BITMAP +3E +C3 +83 +03 +03 +06 +38 +30 +18 +18 +0C +06 +ENDCHAR +STARTCHAR uniA75B +ENCODING 42843 +SWIDTH 410 0 +DWIDTH 7 0 +BBX 6 9 1 0 +BITMAP +78 +C4 +04 +0C +1C +70 +60 +30 +18 +ENDCHAR +STARTCHAR uniA75C +ENCODING 42844 +SWIDTH 581 0 +DWIDTH 10 0 +BBX 9 12 0 0 +BITMAP +1E00 +0200 +0600 +0400 +0D80 +1980 +3100 +2100 +4300 +FF80 +0200 +0200 +ENDCHAR +STARTCHAR uniA75D +ENCODING 42845 +SWIDTH 581 0 +DWIDTH 10 0 +BBX 9 12 -1 -3 +BITMAP +1E00 +0200 +0600 +0400 +0D80 +1980 +3100 +2100 +4300 +FF80 +0200 +0200 +ENDCHAR +STARTCHAR uniA75E +ENCODING 42846 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 12 12 1 0 +BITMAP +6130 +6260 +2640 +24C0 +3C80 +3980 +3100 +3300 +3600 +5600 +5C00 +9800 +ENDCHAR +STARTCHAR uniA75F +ENCODING 42847 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 10 13 -1 -2 +BITMAP +0180 +0100 +3240 +16C0 +1480 +1D80 +1B00 +1A00 +1E00 +2C00 +6C00 +4000 +8000 +ENDCHAR +STARTCHAR uniA760 +ENCODING 42848 +SWIDTH 943 0 +DWIDTH 16 0 +BBX 16 15 2 -3 +BITMAP +C183 +C182 +C386 +C684 +C68C +CC88 +4C98 +5890 +50B0 +70A0 +60C0 +60C0 +0080 +0180 +0600 +ENDCHAR +STARTCHAR uniA761 +ENCODING 42849 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 12 1 -3 +BITMAP +C630 +C620 +4E20 +4A40 +5A40 +5280 +5280 +6300 +6300 +0200 +0600 +1C00 +ENDCHAR +STARTCHAR uniA762 +ENCODING 42850 +SWIDTH 548 0 +DWIDTH 9 0 +BBX 9 15 0 -3 +BITMAP +1E00 +3100 +2000 +3000 +1F80 +0100 +0600 +0C00 +0E00 +0300 +0100 +0100 +0300 +C600 +7C00 +ENDCHAR +STARTCHAR uniA763 +ENCODING 42851 +SWIDTH 493 0 +DWIDTH 8 0 +BBX 8 14 0 -3 +BITMAP +1E +22 +20 +20 +3F +02 +0C +18 +1C +06 +02 +06 +86 +78 +ENDCHAR +STARTCHAR uniA764 +ENCODING 42852 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +3000 +7C00 +2000 +3F80 +60C0 +6040 +40C0 +4180 +FF00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uniA765 +ENCODING 42853 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 15 0 -3 +BITMAP +1000 +3E00 +3000 +3700 +3980 +3180 +2080 +6080 +6180 +6100 +6300 +5C00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uniA766 +ENCODING 42854 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 0 0 +BITMAP +1800 +1800 +1FC0 +1060 +3020 +3020 +3060 +20C0 +7F80 +6000 +F800 +4000 +ENDCHAR +STARTCHAR uniA767 +ENCODING 42855 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 15 -1 -3 +BITMAP +0800 +0800 +0800 +1B80 +1CC0 +18C0 +1040 +3040 +30C0 +3080 +3180 +2E00 +6000 +F800 +4000 +ENDCHAR +STARTCHAR uniA768 +ENCODING 42856 +SWIDTH 509 0 +DWIDTH 9 0 +BBX 10 15 0 -3 +BITMAP +18C0 +1880 +1980 +1300 +1200 +3600 +3400 +2800 +3800 +7000 +6000 +6000 +4000 +4000 +C000 +ENDCHAR +STARTCHAR uniA769 +ENCODING 42857 +SWIDTH 408 0 +DWIDTH 7 0 +BBX 8 12 0 -3 +BITMAP +33 +26 +24 +2C +78 +70 +60 +60 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR uniA76A +ENCODING 42858 +SWIDTH 445 0 +DWIDTH 8 0 +BBX 7 12 0 0 +BITMAP +1C +02 +02 +02 +06 +18 +04 +06 +06 +06 +0C +F8 +ENDCHAR +STARTCHAR uniA76B +ENCODING 42859 +SWIDTH 445 0 +DWIDTH 8 0 +BBX 7 12 0 -3 +BITMAP +1C +02 +02 +02 +06 +18 +04 +06 +06 +06 +0C +F8 +ENDCHAR +STARTCHAR uniA76C +ENCODING 42860 +SWIDTH 501 0 +DWIDTH 9 0 +BBX 10 12 0 0 +BITMAP +0380 +04C0 +0C80 +3F80 +0C00 +0800 +0800 +1800 +1800 +1000 +3000 +E000 +ENDCHAR +STARTCHAR uniA76D +ENCODING 42861 +SWIDTH 501 0 +DWIDTH 9 0 +BBX 11 15 -1 -3 +BITMAP +01C0 +0260 +0640 +1F80 +0600 +0400 +0400 +0C00 +0C00 +0800 +0800 +1800 +1800 +1000 +E000 +ENDCHAR +STARTCHAR uniA76E +ENCODING 42862 +SWIDTH 561 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +1E00 +3300 +6100 +4180 +4180 +6180 +3900 +0100 +0300 +0600 +0C00 +F800 +ENDCHAR +STARTCHAR uniA76F +ENCODING 42863 +SWIDTH 561 0 +DWIDTH 10 0 +BBX 9 12 0 -3 +BITMAP +1E00 +3300 +6100 +4180 +4180 +6180 +3900 +0100 +0300 +0600 +0C00 +F800 +ENDCHAR +STARTCHAR uniA770 +ENCODING 42864 +SWIDTH 326 0 +DWIDTH 6 0 +BBX 4 6 2 6 +BITMAP +70 +90 +90 +D0 +30 +E0 +ENDCHAR +STARTCHAR uniA771 +ENCODING 42865 +SWIDTH 676 0 +DWIDTH 12 0 +BBX 10 14 1 -2 +BITMAP +0080 +0180 +0180 +3D00 +6300 +4300 +C300 +8300 +8200 +C6C0 +C680 +7FC0 +0100 +0200 +ENDCHAR +STARTCHAR uniA772 +ENCODING 42866 +SWIDTH 344 0 +DWIDTH 6 0 +BBX 4 14 1 -2 +BITMAP +20 +20 +60 +60 +60 +40 +40 +C0 +C0 +90 +B0 +F0 +40 +C0 +ENDCHAR +STARTCHAR uniA773 +ENCODING 42867 +SWIDTH 961 0 +DWIDTH 16 0 +BBX 15 11 1 -2 +BITMAP +6E70 +7398 +6318 +4218 +C210 +C610 +C636 +8634 +843E +0018 +0010 +ENDCHAR +STARTCHAR uniA774 +ENCODING 42868 +SWIDTH 680 0 +DWIDTH 12 0 +BBX 10 11 1 -2 +BITMAP +6E00 +5300 +6300 +4300 +C300 +C200 +C240 +8680 +87C0 +0100 +0200 +ENDCHAR +STARTCHAR uniA775 +ENCODING 42869 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 10 1 0 +BITMAP +04 +6C +78 +78 +40 +C0 +C0 +80 +80 +80 +ENDCHAR +STARTCHAR uniA776 +ENCODING 42870 +SWIDTH 750 0 +DWIDTH 13 0 +BBX 11 11 1 -2 +BITMAP +3F00 +6180 +6080 +4180 +7E00 +C600 +C220 +C360 +81E0 +0080 +0180 +ENDCHAR +STARTCHAR uniA777 +ENCODING 42871 +SWIDTH 672 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +10E0 +2120 +2320 +FFC0 +6200 +4200 +4600 +4600 +C600 +C400 +C400 +EC00 +ENDCHAR +STARTCHAR uniA778 +ENCODING 42872 +SWIDTH 475 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +0E +1B +1B +1A +0E +0E +0B +13 +33 +22 +06 +FC +ENDCHAR +STARTCHAR uniA779 +ENCODING 42873 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +FF00 +30C0 +6060 +C060 +C020 +8060 +8060 +8060 +8040 +C0C0 +6180 +3E00 +ENDCHAR +STARTCHAR uniA77A +ENCODING 42874 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +04 +02 +03 +3D +63 +41 +C1 +81 +83 +C2 +C6 +7C +ENDCHAR +STARTCHAR uniA77B +ENCODING 42875 +SWIDTH 404 0 +DWIDTH 7 0 +BBX 8 15 0 -3 +BITMAP +1B +1C +18 +10 +10 +30 +30 +30 +20 +60 +60 +78 +40 +40 +C0 +ENDCHAR +STARTCHAR uniA77C +ENCODING 42876 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 7 12 0 -3 +BITMAP +3E +30 +20 +20 +60 +60 +40 +40 +F8 +C0 +C0 +80 +ENDCHAR +STARTCHAR uniA77D +ENCODING 42877 +SWIDTH 589 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +3F80 +0600 +0C00 +0C00 +1E00 +3700 +6300 +C100 +8100 +8300 +C600 +7C00 +ENDCHAR +STARTCHAR uniA77E +ENCODING 42878 +SWIDTH 589 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +1F00 +3180 +6080 +4080 +4180 +6380 +7700 +1C00 +1800 +1800 +3000 +FE00 +ENDCHAR +STARTCHAR uniA77F +ENCODING 42879 +SWIDTH 589 0 +DWIDTH 10 0 +BBX 9 12 1 -3 +BITMAP +1F00 +3180 +6080 +4080 +4180 +6380 +7700 +1C00 +1800 +1800 +3000 +FE00 +ENDCHAR +STARTCHAR uniA780 +ENCODING 42880 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 2 0 +BITMAP +FF +03 +03 +02 +06 +06 +06 +06 +04 +0C +0C +0C +ENDCHAR +STARTCHAR uniA781 +ENCODING 42881 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 12 1 0 +BITMAP +20 +20 +60 +60 +60 +40 +40 +C0 +C0 +80 +80 +80 +ENDCHAR +STARTCHAR uniA782 +ENCODING 42882 +SWIDTH 799 0 +DWIDTH 14 0 +BBX 13 15 0 -3 +BITMAP +1BE0 +1C30 +1810 +1010 +3030 +3030 +3030 +2030 +6020 +6060 +6060 +4038 +4000 +C000 +C000 +ENDCHAR +STARTCHAR uniA783 +ENCODING 42883 +SWIDTH 598 0 +DWIDTH 10 0 +BBX 9 12 0 -3 +BITMAP +3700 +3980 +3180 +2180 +6180 +6100 +6100 +4100 +4180 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uniA784 +ENCODING 42884 +SWIDTH 404 0 +DWIDTH 7 0 +BBX 8 15 0 -3 +BITMAP +1B +1C +18 +10 +10 +30 +30 +20 +20 +60 +60 +60 +40 +40 +C0 +ENDCHAR +STARTCHAR uniA785 +ENCODING 42885 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 7 12 0 -3 +BITMAP +3E +30 +20 +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR uniA786 +ENCODING 42886 +SWIDTH 643 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3FE0 +1800 +3000 +6000 +6000 +C000 +C000 +C000 +C000 +C000 +6100 +3F00 +ENDCHAR +STARTCHAR uniA787 +ENCODING 42887 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +7F +20 +40 +C0 +80 +80 +80 +C0 +7C +ENDCHAR +STARTCHAR uniA788 +ENCODING 42888 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 2 0 -3 +BITMAP +60 +B0 +ENDCHAR +STARTCHAR uniA789 +ENCODING 42889 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 3 6 1 3 +BITMAP +20 +00 +00 +00 +00 +C0 +ENDCHAR +STARTCHAR uniA78A +ENCODING 42890 +SWIDTH 437 0 +DWIDTH 7 0 +BBX 5 4 2 4 +BITMAP +F8 +00 +00 +F8 +ENDCHAR +STARTCHAR uniA78B +ENCODING 42891 +SWIDTH 190 0 +DWIDTH 3 0 +BBX 2 7 2 5 +BITMAP +40 +C0 +C0 +C0 +80 +80 +80 +ENDCHAR +STARTCHAR uniA78C +ENCODING 42892 +SWIDTH 190 0 +DWIDTH 3 0 +BBX 2 5 2 7 +BITMAP +40 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR uniA78D +ENCODING 42893 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 2 0 +BITMAP +6060 +6040 +4040 +C0C0 +C0C0 +FFC0 +0080 +0080 +0180 +0180 +0180 +0100 +ENDCHAR +STARTCHAR uniA78E +ENCODING 42894 +SWIDTH 444 0 +DWIDTH 8 0 +BBX 7 15 1 -3 +BITMAP +0C +0C +78 +D8 +DE +78 +10 +10 +30 +30 +30 +20 +20 +20 +38 +ENDCHAR +STARTCHAR periodcentered.dup9 +ENCODING 42895 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 1 1 3 5 +BITMAP +80 +ENDCHAR +STARTCHAR uniA790 +ENCODING 42896 +SWIDTH 767 0 +DWIDTH 13 0 +BBX 12 15 1 -3 +BITMAP +3030 +3830 +2820 +2C20 +6C60 +6460 +6660 +4240 +4340 +C1C0 +C1C0 +C1E0 +0020 +0060 +0060 +ENDCHAR +STARTCHAR uniA791 +ENCODING 42897 +SWIDTH 601 0 +DWIDTH 10 0 +BBX 8 12 1 -3 +BITMAP +6E +53 +63 +43 +C3 +C2 +C2 +86 +87 +01 +01 +03 +ENDCHAR +STARTCHAR uniA792 +ENCODING 42898 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +0F80 +1840 +3060 +6020 +6000 +4000 +F800 +4000 +4060 +60C0 +3180 +1F00 +ENDCHAR +STARTCHAR uniA793 +ENCODING 42899 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +0E00 +3100 +2180 +6000 +F800 +4000 +6300 +6200 +3C00 +ENDCHAR +STARTCHAR uniA794 +ENCODING 42900 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +1C +62 +43 +C0 +C0 +80 +C6 +C6 +7E +04 +04 +18 +ENDCHAR +STARTCHAR uniA795 +ENCODING 42901 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 15 1 -3 +BITMAP +30 +20 +20 +6E +73 +63 +43 +43 +C2 +C2 +86 +87 +02 +06 +1C +ENDCHAR +STARTCHAR uniA796 +ENCODING 42902 +SWIDTH 789 0 +DWIDTH 13 0 +BBX 13 12 0 0 +BITMAP +07F0 +0618 +0408 +0408 +0C18 +3FE0 +4C10 +C818 +D818 +1818 +1830 +1FE0 +ENDCHAR +STARTCHAR uniA797 +ENCODING 42903 +SWIDTH 678 0 +DWIDTH 12 0 +BBX 11 14 0 -2 +BITMAP +0600 +0400 +0400 +0FC0 +1C60 +3820 +6820 +4820 +D860 +9860 +9CC0 +9780 +C000 +7800 +ENDCHAR +STARTCHAR uniA798 +ENCODING 42904 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 13 15 -1 -3 +BITMAP +07F8 +0400 +0C00 +0C00 +0C00 +3F80 +1800 +1800 +1800 +1000 +1000 +3000 +3000 +3000 +E000 +ENDCHAR +STARTCHAR uniA799 +ENCODING 42905 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 12 1 0 +BITMAP +1C +30 +20 +F8 +60 +F0 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR uniA79A +ENCODING 42906 +SWIDTH 668 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +1F60 +30E0 +6040 +6040 +30C0 +18C0 +60C0 +C080 +C080 +C180 +C380 +7D80 +ENDCHAR +STARTCHAR uniA79B +ENCODING 42907 +SWIDTH 524 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +1E80 +3180 +2180 +2100 +1900 +6300 +C300 +C300 +7E00 +ENDCHAR +STARTCHAR uniA79C +ENCODING 42908 +SWIDTH 714 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +1F80 +30C0 +6060 +6060 +3020 +1820 +6060 +C060 +C040 +C0C0 +C380 +3E00 +ENDCHAR +STARTCHAR uniA79D +ENCODING 42909 +SWIDTH 548 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +1F00 +3180 +2180 +2080 +1880 +6180 +C100 +4300 +3C00 +ENDCHAR +STARTCHAR uniA79E +ENCODING 42910 +SWIDTH 668 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3060 +2060 +2040 +6040 +20C0 +18C0 +60C0 +C080 +C080 +C180 +C380 +7D80 +ENDCHAR +STARTCHAR uniA79F +ENCODING 42911 +SWIDTH 524 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +3180 +2180 +2180 +2100 +1900 +6300 +C300 +C300 +7E00 +ENDCHAR +STARTCHAR uniA7A0 +ENCODING 42912 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 14 12 0 0 +BITMAP +03E0 +0C30 +1818 +1000 +300C +2070 +27F0 +3810 +E030 +3030 +1870 +0FC0 +ENDCHAR +STARTCHAR uniA7A1 +ENCODING 42913 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 12 0 -3 +BITMAP +1EC0 +3380 +2180 +61C0 +4780 +7980 +E100 +6300 +3F00 +0300 +C600 +7C00 +ENDCHAR +STARTCHAR uniA7A2 +ENCODING 42914 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 12 12 0 0 +BITMAP +1830 +1860 +11C0 +1380 +3600 +3E00 +3B40 +3780 +7980 +E0C0 +60C0 +4060 +ENDCHAR +STARTCHAR uniA7A3 +ENCODING 42915 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 9 12 0 0 +BITMAP +1800 +1000 +1000 +3180 +3300 +2600 +2C00 +3D80 +6E00 +7600 +C200 +4300 +ENDCHAR +STARTCHAR uniA7A4 +ENCODING 42916 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 13 12 0 0 +BITMAP +1818 +1C18 +1410 +1410 +3638 +32F0 +3730 +3920 +E1A0 +60E0 +60E0 +60C0 +ENDCHAR +STARTCHAR uniA7A5 +ENCODING 42917 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 10 9 0 0 +BITMAP +3700 +2980 +31C0 +2180 +2F00 +7100 +E100 +4300 +4300 +ENDCHAR +STARTCHAR uniA7A6 +ENCODING 42918 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 12 1 0 +BITMAP +3FC0 +3070 +23E0 +7C20 +E060 +7F80 +4300 +4180 +C180 +C0C0 +C0C0 +C0C0 +ENDCHAR +STARTCHAR uniA7A7 +ENCODING 42919 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 7 9 0 0 +BITMAP +36 +28 +30 +20 +2C +70 +C0 +40 +40 +ENDCHAR +STARTCHAR uniA7A8 +ENCODING 42920 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +0F80 +30C0 +2040 +2000 +3040 +1F80 +3F00 +C180 +00C0 +C080 +6180 +3E00 +ENDCHAR +STARTCHAR uniA7A9 +ENCODING 42921 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +3E +62 +40 +63 +3C +CE +06 +86 +78 +ENDCHAR +STARTCHAR uniA7AA +ENCODING 42922 +SWIDTH 787 0 +DWIDTH 13 0 +BBX 13 12 1 0 +BITMAP +7818 +D818 +9010 +1010 +3030 +3FF0 +3030 +2020 +2060 +6060 +6060 +6040 +ENDCHAR +STARTCHAR uniA7AB +ENCODING 42923 +SWIDTH 613 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +0F00 +3180 +2080 +6080 +0180 +0E00 +0300 +0180 +8180 +C100 +4300 +3E00 +ENDCHAR +STARTCHAR uniA7AC +ENCODING 42924 +SWIDTH 754 0 +DWIDTH 13 0 +BBX 11 15 2 -3 +BITMAP +0FE0 +1860 +6060 +4060 +C040 +8040 +80C0 +80C0 +80C0 +C080 +6180 +3F80 +0100 +0300 +FC00 +ENDCHAR +STARTCHAR uniA7AD +ENCODING 42925 +SWIDTH 684 0 +DWIDTH 12 0 +BBX 10 12 1 0 +BITMAP +0C00 +0C00 +0800 +0800 +7800 +9800 +9C00 +F800 +1000 +3000 +3000 +3FC0 +ENDCHAR +STARTCHAR uniA7AE +ENCODING 42926 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 12 12 0 0 +BITMAP +3FF0 +0300 +0200 +0200 +0600 +0600 +0600 +0400 +0400 +0C00 +0C00 +FFC0 +ENDCHAR +STARTCHAR uniA7B0 +ENCODING 42928 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +6020 +3060 +3060 +1860 +08C0 +0DC0 +07C0 +06C0 +0CC0 +3880 +7080 +C180 +ENDCHAR +STARTCHAR uniA7B1 +ENCODING 42929 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 10 12 0 0 +BITMAP +0300 +0300 +0200 +0200 +0600 +0600 +0600 +0400 +0400 +0C00 +0C00 +FFC0 +ENDCHAR +STARTCHAR uniA7B2 +ENCODING 42930 +SWIDTH 523 0 +DWIDTH 9 0 +BBX 9 13 0 -1 +BITMAP +0180 +0180 +0180 +0100 +0100 +0300 +0300 +0300 +7A00 +CE00 +C600 +7A00 +0200 +ENDCHAR +STARTCHAR uniA7B3 +ENCODING 42931 +SWIDTH 735 0 +DWIDTH 13 0 +BBX 13 15 0 -3 +BITMAP +1808 +1818 +0830 +0C60 +0CC0 +0780 +0700 +0200 +0700 +0F00 +1980 +3180 +6080 +40C0 +C0C0 +ENDCHAR +STARTCHAR uniA7B4 +ENCODING 42932 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 11 15 0 -3 +BITMAP +1FC0 +1860 +1020 +1060 +3040 +3F80 +2040 +2060 +6060 +6060 +60C0 +7F80 +4000 +C000 +C000 +ENDCHAR +STARTCHAR uniA7B5 +ENCODING 42933 +SWIDTH 571 0 +DWIDTH 10 0 +BBX 9 15 0 -3 +BITMAP +0F00 +1880 +1080 +3080 +3180 +2600 +2100 +6080 +6080 +6180 +7100 +5E00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uniA7B6 +ENCODING 42934 +SWIDTH 1002 0 +DWIDTH 17 0 +BBX 16 12 1 0 +BITMAP +1803 +3003 +3003 +6003 +6083 +4083 +C183 +C182 +C186 +C384 +678C +3CF0 +ENDCHAR +STARTCHAR uniA7B7 +ENCODING 42935 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 12 9 1 0 +BITMAP +2030 +6030 +4230 +C630 +C630 +8630 +8620 +CA60 +7380 +ENDCHAR +STARTCHAR uniA7F7 +ENCODING 42999 +SWIDTH 769 0 +DWIDTH 13 0 +BBX 12 1 1 5 +BITMAP +FFF0 +ENDCHAR +STARTCHAR uniA7F8 +ENCODING 43000 +SWIDTH 448 0 +DWIDTH 8 0 +BBX 7 7 2 5 +BITMAP +44 +FE +C4 +FC +8C +88 +88 +ENDCHAR +STARTCHAR uniA7F9 +ENCODING 43001 +SWIDTH 639 0 +DWIDTH 11 0 +BBX 10 6 1 4 +BITMAP +3BC0 +4440 +87C0 +8400 +CC40 +7380 +ENDCHAR +STARTCHAR uniA7FA +ENCODING 43002 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +6318 +4318 +4218 +C210 +C610 +C630 +8630 +8E70 +F3A0 +ENDCHAR +STARTCHAR uniA7FB +ENCODING 43003 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 9 12 2 0 +BITMAP +7F80 +0180 +0100 +0300 +0300 +FF00 +0300 +0200 +0600 +0600 +0600 +0400 +ENDCHAR +STARTCHAR uniA7FC +ENCODING 43004 +SWIDTH 666 0 +DWIDTH 11 0 +BBX 10 12 2 0 +BITMAP +3FC0 +E0C0 +C080 +8180 +C180 +7F80 +0180 +0100 +0300 +0300 +0300 +0200 +ENDCHAR +STARTCHAR uniA7FD +ENCODING 43005 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 14 12 1 0 +BITMAP +318C +2388 +2288 +6698 +6498 +6C98 +48D0 +58D0 +F070 +E070 +E070 +C060 +ENDCHAR +STARTCHAR uniA7FE +ENCODING 43006 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 5 15 0 -3 +BITMAP +18 +18 +18 +10 +10 +30 +30 +20 +20 +60 +60 +60 +40 +40 +C0 +ENDCHAR +STARTCHAR uniA7FF +ENCODING 43007 +SWIDTH 1185 0 +DWIDTH 20 0 +BBX 22 12 0 0 +BITMAP +03060C +070E08 +0F0A18 +0B1A10 +1B1230 +113220 +312360 +216340 +6143C0 +41C380 +C18380 +818300 +ENDCHAR +STARTCHAR uniAB30 +ENCODING 43824 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 10 9 0 0 +BITMAP +1EC0 +33C0 +2180 +6180 +FFC0 +4100 +4300 +6700 +3D00 +ENDCHAR +STARTCHAR uniAB31 +ENCODING 43825 +SWIDTH 895 0 +DWIDTH 15 0 +BBX 14 9 1 0 +BITMAP +3E78 +638C +430C +0300 +7FFC +C20C +8708 +CF18 +71E0 +ENDCHAR +STARTCHAR uniAB32 +ENCODING 43826 +SWIDTH 478 0 +DWIDTH 8 0 +BBX 7 9 1 0 +BITMAP +0C +3C +66 +C4 +D8 +E0 +C4 +F8 +70 +ENDCHAR +STARTCHAR uniAB33 +ENCODING 43827 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +0E00 +3100 +2180 +6080 +7F80 +4000 +FF80 +6300 +3E00 +ENDCHAR +STARTCHAR uniAB34 +ENCODING 43828 +SWIDTH 667 0 +DWIDTH 11 0 +BBX 11 9 0 0 +BITMAP +0780 +0C40 +0860 +1820 +7FE0 +D000 +9040 +18C0 +0F00 +ENDCHAR +STARTCHAR uniAB35 +ENCODING 43829 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 6 12 1 0 +BITMAP +1C +30 +20 +F8 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR uniAB36 +ENCODING 43830 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +3D +63 +C3 +C3 +83 +82 +C6 +7E +06 +7C +8C +FA +ENDCHAR +STARTCHAR uniAB37 +ENCODING 43831 +SWIDTH 368 0 +DWIDTH 6 0 +BBX 6 12 1 0 +BITMAP +18 +18 +10 +14 +34 +F4 +B8 +A0 +A0 +60 +60 +40 +ENDCHAR +STARTCHAR uniAB38 +ENCODING 43832 +SWIDTH 346 0 +DWIDTH 6 0 +BBX 6 12 1 0 +BITMAP +10 +10 +30 +74 +7C +20 +E8 +F8 +60 +40 +40 +40 +ENDCHAR +STARTCHAR uniAB39 +ENCODING 43833 +SWIDTH 242 0 +DWIDTH 4 0 +BBX 4 12 1 0 +BITMAP +30 +20 +20 +20 +F0 +F0 +D0 +E0 +40 +C0 +80 +80 +ENDCHAR +STARTCHAR uniAB3A +ENCODING 43834 +SWIDTH 851 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +6E70 +7398 +6318 +4218 +C210 +C6F8 +C7B0 +87B0 +84E0 +ENDCHAR +STARTCHAR uniAB3B +ENCODING 43835 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +6E +53 +63 +43 +C3 +CF +D2 +96 +9C +ENDCHAR +STARTCHAR uniAB3C +ENCODING 43836 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +6E +53 +63 +43 +C3 +C2 +C2 +86 +86 +7C +8C +FA +ENDCHAR +STARTCHAR uniAB3D +ENCODING 43837 +SWIDTH 547 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +0300 +1F00 +3300 +3380 +3180 +6300 +7200 +FC00 +1800 +ENDCHAR +STARTCHAR uniAB3E +ENCODING 43838 +SWIDTH 547 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +0380 +1F00 +3300 +3780 +3980 +7300 +7200 +FC00 +D800 +ENDCHAR +STARTCHAR uniAB3F +ENCODING 43839 +SWIDTH 610 0 +DWIDTH 10 0 +BBX 9 10 1 -1 +BITMAP +1F80 +2300 +4300 +0580 +0980 +1100 +F300 +6600 +7C00 +8000 +ENDCHAR +STARTCHAR uniAB40 +ENCODING 43840 +SWIDTH 943 0 +DWIDTH 16 0 +BBX 15 9 1 0 +BITMAP +1E78 +63C4 +4186 +C100 +81FE +8306 +830C +C788 +78F0 +ENDCHAR +STARTCHAR uniAB41 +ENCODING 43841 +SWIDTH 943 0 +DWIDTH 16 0 +BBX 15 10 1 -1 +BITMAP +1E7E +62CC +438C +0116 +FF24 +8344 +C3CC +4798 +39F0 +0200 +ENDCHAR +STARTCHAR uniAB42 +ENCODING 43842 +SWIDTH 943 0 +DWIDTH 16 0 +BBX 15 9 1 0 +BITMAP +1E78 +62CC +4384 +0106 +FFFC +8304 +C30C +4798 +38F0 +ENDCHAR +STARTCHAR uniAB43 +ENCODING 43843 +SWIDTH 952 0 +DWIDTH 16 0 +BBX 15 9 1 0 +BITMAP +1C78 +60C4 +4186 +C106 +8106 +8306 +8304 +C78C +78F0 +ENDCHAR +STARTCHAR uniAB44 +ENCODING 43844 +SWIDTH 952 0 +DWIDTH 16 0 +BBX 15 10 1 -1 +BITMAP +1C7A +60C4 +418E +C116 +8136 +8326 +8344 +C78C +79F0 +0200 +ENDCHAR +STARTCHAR uniAB45 +ENCODING 43845 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 9 0 0 +BITMAP +06 +04 +04 +0C +1E +63 +41 +C1 +C1 +ENDCHAR +STARTCHAR uniAB46 +ENCODING 43846 +SWIDTH 606 0 +DWIDTH 10 0 +BBX 9 12 1 -3 +BITMAP +3F00 +6180 +6080 +4180 +7E00 +C200 +C200 +C200 +8600 +0600 +0600 +0380 +ENDCHAR +STARTCHAR uniAB47 +ENCODING 43847 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 9 1 0 +BITMAP +78 +60 +40 +40 +C0 +C0 +80 +80 +80 +ENDCHAR +STARTCHAR uniAB48 +ENCODING 43848 +SWIDTH 502 0 +DWIDTH 9 0 +BBX 9 9 1 0 +BITMAP +7F80 +6000 +4000 +4000 +C000 +C000 +8000 +8000 +8000 +ENDCHAR +STARTCHAR uniAB49 +ENCODING 43849 +SWIDTH 449 0 +DWIDTH 8 0 +BBX 9 9 0 0 +BITMAP +0D80 +0A00 +0C00 +0800 +1800 +7C00 +D800 +9000 +E000 +ENDCHAR +STARTCHAR uniAB4A +ENCODING 43850 +SWIDTH 627 0 +DWIDTH 11 0 +BBX 12 9 0 0 +BITMAP +0FF0 +0C00 +0C00 +0800 +1800 +7C00 +D800 +9000 +E000 +ENDCHAR +STARTCHAR uniAB4B +ENCODING 43851 +SWIDTH 474 0 +DWIDTH 8 0 +BBX 7 9 1 0 +BITMAP +46 +FE +86 +04 +04 +0C +0C +0C +08 +ENDCHAR +STARTCHAR uniAB4C +ENCODING 43852 +SWIDTH 699 0 +DWIDTH 12 0 +BBX 10 9 1 0 +BITMAP +4600 +FE00 +8400 +07C0 +0440 +0C40 +0C40 +0CC0 +0780 +ENDCHAR +STARTCHAR uniAB4D +ENCODING 43853 +SWIDTH 290 0 +DWIDTH 5 0 +BBX 9 15 -2 -3 +BITMAP +0380 +0600 +0400 +0400 +0400 +0C00 +0C00 +0800 +0800 +1800 +1800 +1000 +1000 +3000 +E000 +ENDCHAR +STARTCHAR uniAB4E +ENCODING 43854 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +60 +60 +40 +43 +C3 +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uniAB4F +ENCODING 43855 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +60 +60 +40 +43 +FF +C2 +C6 +CA +76 +ENDCHAR +STARTCHAR uniAB50 +ENCODING 43856 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +6318 +4318 +4018 +C010 +C210 +C630 +8630 +8E70 +F3A0 +ENDCHAR +STARTCHAR uniAB51 +ENCODING 43857 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +6E70 +7398 +6318 +4218 +C210 +C010 +C030 +8630 +8430 +ENDCHAR +STARTCHAR uniAB52 +ENCODING 43858 +SWIDTH 612 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +E080 +2080 +2180 +2180 +6100 +6100 +4300 +6300 +3F00 +ENDCHAR +STARTCHAR uniAB53 +ENCODING 43859 +SWIDTH 545 0 +DWIDTH 9 0 +BBX 11 12 -1 -3 +BITMAP +1060 +18C0 +1980 +0B00 +0E00 +0E00 +0E00 +1A00 +1200 +3300 +6300 +C100 +ENDCHAR +STARTCHAR uniAB54 +ENCODING 43860 +SWIDTH 613 0 +DWIDTH 10 0 +BBX 11 12 -1 -3 +BITMAP +3860 +18C0 +0880 +0D00 +0E00 +0600 +0E00 +0A00 +13E0 +3320 +6120 +C0C0 +ENDCHAR +STARTCHAR uniAB55 +ENCODING 43861 +SWIDTH 593 0 +DWIDTH 10 0 +BBX 12 12 -1 -3 +BITMAP +1870 +0840 +0880 +0D80 +0700 +0600 +0600 +0A00 +1300 +3300 +2100 +C180 +ENDCHAR +STARTCHAR uniAB56 +ENCODING 43862 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 9 9 0 0 +BITMAP +3180 +3300 +1600 +1C00 +0C00 +1D80 +3680 +6680 +C380 +ENDCHAR +STARTCHAR uniAB57 +ENCODING 43863 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 12 12 -3 -3 +BITMAP +0630 +0660 +03C0 +0380 +0380 +0780 +04C0 +0CC0 +1840 +3000 +6000 +C000 +ENDCHAR +STARTCHAR uniAB58 +ENCODING 43864 +SWIDTH 604 0 +DWIDTH 10 0 +BBX 11 12 -2 -3 +BITMAP +0C60 +0CC0 +0580 +0700 +0300 +0760 +0DA0 +19A0 +30E0 +6000 +C000 +8000 +ENDCHAR +STARTCHAR uniAB59 +ENCODING 43865 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 13 12 -4 -3 +BITMAP +0318 +0330 +01E0 +01C0 +01C0 +01C0 +0260 +0660 +0C20 +1800 +3000 +E000 +ENDCHAR +STARTCHAR uniAB5A +ENCODING 43866 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 7 12 0 -3 +BITMAP +20 +20 +20 +32 +36 +34 +1C +18 +18 +10 +20 +E0 +ENDCHAR +STARTCHAR uniAB5B +ENCODING 43867 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 5 1 7 +BITMAP +44 +38 +00 +70 +C8 +ENDCHAR +STARTCHAR uniAB5C +ENCODING 43868 +SWIDTH 383 0 +DWIDTH 7 0 +BBX 6 9 1 3 +BITMAP +20 +40 +5C +64 +44 +48 +88 +88 +10 +ENDCHAR +STARTCHAR uniAB5D +ENCODING 43869 +SWIDTH 273 0 +DWIDTH 5 0 +BBX 5 8 1 4 +BITMAP +10 +28 +68 +B0 +A0 +20 +40 +40 +ENDCHAR +STARTCHAR uniAB5E +ENCODING 43870 +SWIDTH 247 0 +DWIDTH 4 0 +BBX 4 8 1 4 +BITMAP +20 +70 +B0 +20 +70 +B0 +40 +40 +ENDCHAR +STARTCHAR uniAB5F +ENCODING 43871 +SWIDTH 415 0 +DWIDTH 7 0 +BBX 6 6 2 4 +BITMAP +84 +48 +88 +88 +98 +F0 +ENDCHAR +STARTCHAR uniAB60 +ENCODING 43872 +SWIDTH 720 0 +DWIDTH 12 0 +BBX 11 9 1 0 +BITMAP +6400 +6C00 +4C00 +4C00 +CFC0 +C860 +9860 +9840 +9F80 +ENDCHAR +STARTCHAR uniAB61 +ENCODING 43873 +SWIDTH 764 0 +DWIDTH 13 0 +BBX 12 9 1 0 +BITMAP +63C0 +6660 +4C20 +4830 +FFF0 +D800 +C860 +8CC0 +8780 +ENDCHAR +STARTCHAR uniAB62 +ENCODING 43874 +SWIDTH 943 0 +DWIDTH 16 0 +BBX 15 9 1 0 +BITMAP +1E78 +63CC +4184 +0186 +01FE +0300 +C30C +4798 +3CF0 +ENDCHAR +STARTCHAR uniAB63 +ENCODING 43875 +SWIDTH 921 0 +DWIDTH 16 0 +BBX 14 9 1 0 +BITMAP +6178 +618C +4304 +4304 +C304 +C304 +C70C +CD18 +78F0 +ENDCHAR +STARTCHAR uniAB64 +ENCODING 43876 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +3D +65 +C3 +C3 +82 +82 +86 +CE +76 +ENDCHAR +STARTCHAR uniAB65 +ENCODING 43877 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 11 9 0 0 +BITMAP +0F80 +18C0 +3060 +2060 +6060 +6060 +20C0 +3180 +FBC0 +ENDCHAR +STARTCHAR uniF301 +ENCODING 62209 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -2 -2 +BITMAP +40 +C0 +ENDCHAR +STARTCHAR uniFB00 +ENCODING 64256 +SWIDTH 530 0 +DWIDTH 9 0 +BBX 10 12 1 0 +BITMAP +1DC0 +2300 +2300 +FF80 +6200 +6600 +4600 +4400 +C400 +C400 +CC00 +8C00 +ENDCHAR +STARTCHAR uniFB01 +ENCODING 64257 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1D +30 +20 +FA +62 +62 +66 +46 +44 +C4 +C4 +CC +ENDCHAR +STARTCHAR uniFB02 +ENCODING 64258 +SWIDTH 500 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1D +33 +23 +FB +62 +62 +66 +46 +44 +C4 +C4 +CC +ENDCHAR +STARTCHAR uniFB03 +ENCODING 64259 +SWIDTH 743 0 +DWIDTH 13 0 +BBX 12 12 1 0 +BITMAP +1DD0 +2310 +2300 +FFB0 +6220 +6620 +4620 +4460 +C460 +C440 +CC40 +8CC0 +ENDCHAR +STARTCHAR uniFB04 +ENCODING 64260 +SWIDTH 747 0 +DWIDTH 13 0 +BBX 12 12 1 0 +BITMAP +1DD0 +2310 +2330 +FFB0 +6220 +6620 +4620 +4460 +C460 +C440 +CC40 +8CC0 +ENDCHAR +STARTCHAR uniFB05 +ENCODING 64261 +SWIDTH 538 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +1D00 +2300 +2300 +FF80 +6200 +6600 +4600 +4400 +C400 +C400 +CC00 +8600 +ENDCHAR +STARTCHAR uniFB06 +ENCODING 64262 +SWIDTH 765 0 +DWIDTH 13 0 +BBX 13 12 1 0 +BITMAP +00F0 +0130 +0220 +3EF8 +6260 +4060 +7060 +1C40 +0640 +86C0 +C6C0 +7860 +ENDCHAR +STARTCHAR uniFB13 +ENCODING 64275 +SWIDTH 1110 0 +DWIDTH 19 0 +BBX 18 12 1 0 +BITMAP +00F800 +019800 +019800 +6110C0 +6110C0 +413080 +433080 +C32080 +C22180 +C62180 +CE2300 +763D00 +ENDCHAR +STARTCHAR uniFB14 +ENCODING 64276 +SWIDTH 1110 0 +DWIDTH 19 0 +BBX 18 12 1 0 +BITMAP +00F800 +019800 +019000 +611FC0 +611000 +413000 +433080 +C32180 +C22180 +C62180 +CE2300 +763D00 +ENDCHAR +STARTCHAR uniFB15 +ENCODING 64277 +SWIDTH 1110 0 +DWIDTH 19 0 +BBX 17 15 1 -3 +BITMAP +00F800 +019800 +019000 +611780 +611880 +413080 +433080 +C32080 +C22180 +C66180 +CE6100 +766100 +004000 +004000 +00C000 +ENDCHAR +STARTCHAR uniFB16 +ENCODING 64278 +SWIDTH 1110 0 +DWIDTH 19 0 +BBX 18 15 1 -3 +BITMAP +00B800 +019800 +019800 +6110C0 +6110C0 +413080 +433080 +C32080 +C22180 +C62180 +CE2300 +763D00 +060000 +040000 +070000 +ENDCHAR +STARTCHAR uniFB17 +ENCODING 64279 +SWIDTH 1333 0 +DWIDTH 23 0 +BBX 22 15 1 -3 +BITMAP +01D000 +01B000 +013000 +612F0C +43310C +436108 +C36308 +C26318 +C24318 +864218 +8EC230 +74C3D0 +008000 +008000 +008000 +ENDCHAR +STARTCHAR uniFB1D +ENCODING 64285 +SWIDTH 246 0 +DWIDTH 4 0 +BBX 3 7 1 2 +BITMAP +60 +60 +60 +40 +40 +00 +C0 +ENDCHAR +STARTCHAR uniFB1E +ENCODING 64286 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -1 9 +BITMAP +C8 +70 +ENDCHAR +STARTCHAR uniFB1F +ENCODING 64287 +SWIDTH 493 0 +DWIDTH 8 0 +BBX 7 7 1 2 +BITMAP +62 +66 +66 +46 +44 +00 +FC +ENDCHAR +STARTCHAR uniFB20 +ENCODING 64288 +SWIDTH 535 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +3080 +3180 +3180 +3100 +3100 +3300 +3200 +3400 +F800 +ENDCHAR +STARTCHAR uniFB21 +ENCODING 64289 +SWIDTH 709 0 +DWIDTH 12 0 +BBX 12 9 0 0 +BITMAP +1830 +1830 +0C20 +1E60 +3780 +6300 +6180 +40C0 +C0E0 +ENDCHAR +STARTCHAR uniFB22 +ENCODING 64290 +SWIDTH 654 0 +DWIDTH 11 0 +BBX 11 9 1 0 +BITMAP +FFE0 +0080 +0180 +0180 +0180 +0100 +0100 +0300 +0300 +ENDCHAR +STARTCHAR uniFB23 +ENCODING 64291 +SWIDTH 748 0 +DWIDTH 13 0 +BBX 11 9 1 0 +BITMAP +7F80 +00E0 +0060 +0060 +4060 +C060 +C040 +C040 +80C0 +ENDCHAR +STARTCHAR uniFB24 +ENCODING 64292 +SWIDTH 607 0 +DWIDTH 10 0 +BBX 10 9 0 0 +BITMAP +3F00 +0180 +00C0 +00C0 +00C0 +00C0 +0180 +0300 +FC00 +ENDCHAR +STARTCHAR uniFB25 +ENCODING 64293 +SWIDTH 609 0 +DWIDTH 10 0 +BBX 9 12 2 0 +BITMAP +C000 +C000 +8000 +FF80 +0100 +0100 +0300 +0600 +0C00 +0C00 +0800 +1800 +ENDCHAR +STARTCHAR uniFB26 +ENCODING 64294 +SWIDTH 745 0 +DWIDTH 13 0 +BBX 11 9 1 0 +BITMAP +7F80 +6060 +6060 +4060 +4060 +C060 +C040 +C040 +FFC0 +ENDCHAR +STARTCHAR uniFB27 +ENCODING 64295 +SWIDTH 655 0 +DWIDTH 11 0 +BBX 8 9 2 0 +BITMAP +FE +03 +01 +01 +01 +03 +03 +03 +02 +ENDCHAR +STARTCHAR uniFB28 +ENCODING 64296 +SWIDTH 789 0 +DWIDTH 13 0 +BBX 13 9 0 0 +BITMAP +3FE0 +1830 +1818 +1818 +1018 +1010 +3030 +3030 +E030 +ENDCHAR +STARTCHAR uniFB29 +ENCODING 64297 +SWIDTH 583 0 +DWIDTH 10 0 +BBX 8 4 1 3 +BITMAP +08 +08 +08 +FF +ENDCHAR +STARTCHAR uniFB2A +ENCODING 64298 +SWIDTH 694 0 +DWIDTH 12 0 +BBX 12 10 1 0 +BITMAP +0030 +6660 +4660 +4440 +4C40 +C8C0 +F080 +C180 +6300 +3C00 +ENDCHAR +STARTCHAR uniFB2B +ENCODING 64299 +SWIDTH 694 0 +DWIDTH 12 0 +BBX 11 10 1 0 +BITMAP +2000 +6660 +4660 +4440 +4C40 +C8C0 +F080 +C180 +6300 +3C00 +ENDCHAR +STARTCHAR uniFB2C +ENCODING 64300 +SWIDTH 694 0 +DWIDTH 12 0 +BBX 12 10 1 0 +BITMAP +0030 +6660 +4660 +4440 +4C40 +C8C0 +F680 +C180 +6300 +3C00 +ENDCHAR +STARTCHAR uniFB2D +ENCODING 64301 +SWIDTH 694 0 +DWIDTH 12 0 +BBX 11 10 1 0 +BITMAP +2000 +6660 +4660 +4440 +4C40 +C8C0 +F680 +C180 +6300 +3C00 +ENDCHAR +STARTCHAR uniFB2E +ENCODING 64302 +SWIDTH 562 0 +DWIDTH 10 0 +BBX 10 10 0 -1 +BITMAP +30C0 +1880 +1980 +1D80 +3F00 +6600 +6600 +4300 +C300 +3C00 +ENDCHAR +STARTCHAR uniFB2F +ENCODING 64303 +SWIDTH 562 0 +DWIDTH 10 0 +BBX 10 12 0 -3 +BITMAP +30C0 +1880 +1980 +1D80 +3F00 +6600 +6600 +4300 +C300 +3C00 +1000 +1000 +ENDCHAR +STARTCHAR uniFB30 +ENCODING 64304 +SWIDTH 562 0 +DWIDTH 10 0 +BBX 10 9 0 0 +BITMAP +30C0 +1880 +1980 +1D80 +3F00 +6600 +6600 +5B00 +C300 +ENDCHAR +STARTCHAR uniFB31 +ENCODING 64305 +SWIDTH 541 0 +DWIDTH 9 0 +BBX 8 9 0 0 +BITMAP +3E +03 +03 +03 +33 +03 +02 +02 +FF +ENDCHAR +STARTCHAR uniFB32 +ENCODING 64306 +SWIDTH 398 0 +DWIDTH 7 0 +BBX 6 9 0 0 +BITMAP +3C +0C +0C +3C +0C +0C +38 +68 +CC +ENDCHAR +STARTCHAR uniFB33 +ENCODING 64307 +SWIDTH 508 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +FF +06 +04 +04 +3C +0C +0C +08 +08 +ENDCHAR +STARTCHAR uniFB34 +ENCODING 64308 +SWIDTH 602 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +7E00 +0300 +0180 +0180 +4100 +D900 +C300 +C300 +8300 +ENDCHAR +STARTCHAR uniFB35 +ENCODING 64309 +SWIDTH 286 0 +DWIDTH 5 0 +BBX 5 9 0 0 +BITMAP +18 +18 +18 +10 +D0 +30 +30 +30 +20 +ENDCHAR +STARTCHAR uniFB36 +ENCODING 64310 +SWIDTH 411 0 +DWIDTH 7 0 +BBX 8 9 0 0 +BITMAP +1F +0C +08 +18 +D8 +18 +18 +10 +10 +ENDCHAR +STARTCHAR uniFB38 +ENCODING 64312 +SWIDTH 589 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +6700 +6180 +4180 +4180 +D900 +C300 +C300 +4600 +7C00 +ENDCHAR +STARTCHAR uniFB39 +ENCODING 64313 +SWIDTH 286 0 +DWIDTH 5 0 +BBX 5 5 0 4 +BITMAP +18 +18 +18 +D0 +10 +ENDCHAR +STARTCHAR uniFB3A +ENCODING 64314 +SWIDTH 509 0 +DWIDTH 9 0 +BBX 6 12 2 -3 +BITMAP +F8 +0C +0C +0C +0C +CC +08 +18 +18 +18 +10 +10 +ENDCHAR +STARTCHAR uniFB3B +ENCODING 64315 +SWIDTH 460 0 +DWIDTH 8 0 +BBX 8 9 0 0 +BITMAP +3C +06 +02 +03 +32 +06 +06 +0C +F0 +ENDCHAR +STARTCHAR uniFB3C +ENCODING 64316 +SWIDTH 462 0 +DWIDTH 8 0 +BBX 6 12 2 0 +BITMAP +C0 +C0 +80 +FC +0C +0C +08 +D8 +30 +60 +60 +60 +ENDCHAR +STARTCHAR uniFB3E +ENCODING 64318 +SWIDTH 601 0 +DWIDTH 10 0 +BBX 10 9 0 0 +BITMAP +3780 +3C80 +38C0 +3080 +3080 +2680 +6180 +4180 +CF80 +ENDCHAR +STARTCHAR uniFB40 +ENCODING 64320 +SWIDTH 352 0 +DWIDTH 6 0 +BBX 5 9 0 0 +BITMAP +38 +08 +08 +08 +78 +18 +18 +10 +F0 +ENDCHAR +STARTCHAR uniFB41 +ENCODING 64321 +SWIDTH 574 0 +DWIDTH 10 0 +BBX 8 9 1 0 +BITMAP +1E +23 +61 +C1 +D9 +C3 +C3 +C6 +78 +ENDCHAR +STARTCHAR uniFB43 +ENCODING 64323 +SWIDTH 566 0 +DWIDTH 10 0 +BBX 8 12 1 -3 +BITMAP +7E +43 +43 +C3 +C3 +6A +02 +06 +06 +06 +04 +04 +ENDCHAR +STARTCHAR uniFB44 +ENCODING 64324 +SWIDTH 546 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +3E00 +2380 +2180 +2180 +3580 +0180 +0300 +0600 +FC00 +ENDCHAR +STARTCHAR uniFB46 +ENCODING 64326 +SWIDTH 478 0 +DWIDTH 8 0 +BBX 8 9 0 0 +BITMAP +21 +33 +33 +1E +1C +68 +0C +0C +FC +ENDCHAR +STARTCHAR uniFB47 +ENCODING 64327 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 10 12 0 -3 +BITMAP +3FC0 +0080 +0080 +0180 +2F00 +6600 +6600 +6400 +4C00 +4000 +C000 +C000 +ENDCHAR +STARTCHAR uniFB48 +ENCODING 64328 +SWIDTH 509 0 +DWIDTH 9 0 +BBX 6 9 2 0 +BITMAP +F8 +0C +0C +0C +0C +CC +08 +08 +18 +ENDCHAR +STARTCHAR uniFB49 +ENCODING 64329 +SWIDTH 694 0 +DWIDTH 12 0 +BBX 11 9 1 0 +BITMAP +6660 +4660 +4440 +4C40 +C8C0 +F680 +C180 +6300 +3C00 +ENDCHAR +STARTCHAR uniFB4A +ENCODING 64330 +SWIDTH 642 0 +DWIDTH 11 0 +BBX 10 9 0 0 +BITMAP +3F80 +18C0 +1840 +1840 +10C0 +16C0 +30C0 +3080 +E080 +ENDCHAR +STARTCHAR uniFB4B +ENCODING 64331 +SWIDTH 246 0 +DWIDTH 4 0 +BBX 4 11 1 0 +BITMAP +10 +10 +60 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR uniFB4C +ENCODING 64332 +SWIDTH 541 0 +DWIDTH 9 0 +BBX 8 10 0 0 +BITMAP +1C +3E +03 +03 +03 +03 +03 +02 +02 +FF +ENDCHAR +STARTCHAR uniFB4D +ENCODING 64333 +SWIDTH 460 0 +DWIDTH 8 0 +BBX 8 10 0 0 +BITMAP +1C +3C +06 +02 +03 +02 +06 +06 +0C +F0 +ENDCHAR +STARTCHAR uniFB4E +ENCODING 64334 +SWIDTH 546 0 +DWIDTH 9 0 +BBX 9 10 0 0 +BITMAP +0E00 +3E00 +2380 +2180 +2180 +3980 +0180 +0300 +0600 +FC00 +ENDCHAR +STARTCHAR uniFB4F +ENCODING 64335 +SWIDTH 575 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +6000 +6000 +4000 +7180 +3180 +1100 +3B00 +6E00 +4C00 +C400 +C600 +8600 +ENDCHAR +STARTCHAR uniFE20 +ENCODING 65056 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 3 -1 10 +BITMAP +1C +60 +80 +ENDCHAR +STARTCHAR uniFE21 +ENCODING 65057 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 3 -1 10 +BITMAP +E0 +18 +0C +ENDCHAR +STARTCHAR uniFE22 +ENCODING 65058 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -1 10 +BITMAP +78 +84 +ENDCHAR +STARTCHAR uniFE23 +ENCODING 65059 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -1 10 +BITMAP +84 +78 +ENDCHAR +STARTCHAR uniFFFC +ENCODING 65532 +SWIDTH 1000 0 +DWIDTH 17 0 +BBX 17 12 0 0 +BITMAP +E63380 +800080 +800080 +1CE200 +229200 +A2E280 +A29280 +229200 +1CEC00 +800080 +800080 +E63380 +ENDCHAR +STARTCHAR .notdef +ENCODING -1 +SWIDTH 750 0 +DWIDTH 13 0 +BBX 9 11 2 0 +BITMAP +FF80 +8080 +8080 +8080 +8080 +8080 +8080 +8080 +8080 +8080 +FF80 +ENDCHAR +STARTCHAR glyph1 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR glyph2 +ENCODING -1 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR +STARTCHAR glyph155 +ENCODING -1 +SWIDTH 548 0 +DWIDTH 9 0 +BBX 10 9 0 0 +BITMAP +7FC0 +3180 +3100 +2300 +6300 +6300 +4200 +C600 +C600 +ENDCHAR +STARTCHAR glyph493 +ENCODING -1 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 4 0 -5 +BITMAP +60 +20 +40 +80 +ENDCHAR +STARTCHAR glyph494 +ENCODING -1 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 3 0 -4 +BITMAP +70 +10 +E0 +ENDCHAR +STARTCHAR glyph705 +ENCODING -1 +SWIDTH 246 0 +DWIDTH 4 0 +BBX 3 11 2 0 +BITMAP +80 +80 +60 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR uni05DA_uni05B0.ccmp +ENCODING -1 +SWIDTH 509 0 +DWIDTH 9 0 +BBX 6 12 2 -3 +BITMAP +F8 +0C +0C +0C +0C +0C +88 +98 +98 +18 +10 +10 +ENDCHAR +STARTCHAR uni05DA_uni05B8.ccmp +ENCODING -1 +SWIDTH 509 0 +DWIDTH 9 0 +BBX 7 12 1 -3 +BITMAP +7C +06 +06 +06 +06 +F6 +44 +4C +0C +0C +08 +08 +ENDCHAR +STARTCHAR glyph708 +ENCODING -1 +SWIDTH 462 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +30 +B0 +A0 +3F +03 +03 +02 +06 +0C +18 +18 +18 +ENDCHAR +STARTCHAR glyph709 +ENCODING -1 +SWIDTH 462 0 +DWIDTH 8 0 +BBX 8 12 0 0 +BITMAP +30 +B0 +A0 +3F +03 +03 +02 +36 +0C +18 +18 +18 +ENDCHAR +STARTCHAR glyph759 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 19 -1 -4 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +00 +00 +00 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR glyph760 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 19 -2 -4 +BITMAP +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +F0 +ENDCHAR +STARTCHAR glyph761 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 19 0 -4 +BITMAP +80 +C0 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR glyph762 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 19 -2 -4 +BITMAP +40 +C0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR glyph763 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 19 0 -4 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +C0 +ENDCHAR +STARTCHAR glyph770 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -2 14 +BITMAP +C0 +40 +ENDCHAR +STARTCHAR glyph771 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -5 14 +BITMAP +80 +40 +ENDCHAR +STARTCHAR glyph772 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -4 14 +BITMAP +80 +C0 +ENDCHAR +STARTCHAR glyph773 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -1 14 +BITMAP +C0 +80 +ENDCHAR +STARTCHAR glyph774 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -4 14 +BITMAP +C0 +80 +ENDCHAR +STARTCHAR glyph775 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -3 14 +BITMAP +C0 +80 +ENDCHAR +STARTCHAR glyph777 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 2 -2 14 +BITMAP +F0 +40 +ENDCHAR +STARTCHAR glyph778 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -4 13 +BITMAP +E0 +20 +C0 +ENDCHAR +STARTCHAR glyph779 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 2 -5 14 +BITMAP +E0 +80 +ENDCHAR +STARTCHAR glyph780 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -3 14 +BITMAP +64 +98 +ENDCHAR +STARTCHAR glyph781 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -6 14 +BITMAP +E8 +B0 +ENDCHAR +STARTCHAR glyph783 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 2 0 12 +BITMAP +90 +70 +ENDCHAR +STARTCHAR glyph784 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 2 0 12 +BITMAP +60 +D0 +ENDCHAR +STARTCHAR glyph785 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -4 -2 +BITMAP +C0 +ENDCHAR +STARTCHAR glyph789 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 2 -1 11 +BITMAP +60 +C0 +ENDCHAR +STARTCHAR glyph790 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -4 11 +BITMAP +C0 +80 +ENDCHAR +STARTCHAR glyph791 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -2 11 +BITMAP +80 +40 +ENDCHAR +STARTCHAR glyph792 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -4 11 +BITMAP +80 +C0 +ENDCHAR +STARTCHAR glyph793 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -2 11 +BITMAP +E0 +30 +60 +ENDCHAR +STARTCHAR glyph794 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -5 10 +BITMAP +E0 +30 +60 +ENDCHAR +STARTCHAR glyph795 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -6 14 +BITMAP +C8 +B0 +ENDCHAR +STARTCHAR glyph796 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -8 14 +BITMAP +E8 +B8 +ENDCHAR +STARTCHAR glyph797 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -8 14 +BITMAP +E8 +B8 +ENDCHAR +STARTCHAR glyph798 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -6 10 +BITMAP +E8 +98 +ENDCHAR +STARTCHAR glyph799 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -7 10 +BITMAP +E8 +98 +ENDCHAR +STARTCHAR glyph800 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -7 10 +BITMAP +E8 +B8 +ENDCHAR +STARTCHAR glyph801 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -8 -2 +BITMAP +C0 +ENDCHAR +STARTCHAR glyph802 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -8 -2 +BITMAP +C0 +ENDCHAR +STARTCHAR glyph803 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -9 -2 +BITMAP +C0 +ENDCHAR +STARTCHAR glyph804 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -8 -2 +BITMAP +C0 +ENDCHAR +STARTCHAR glyph805 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -9 -2 +BITMAP +C0 +ENDCHAR +STARTCHAR glyph808 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -3 10 +BITMAP +E8 +98 +ENDCHAR +STARTCHAR glyph810 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -8 -2 +BITMAP +C0 +ENDCHAR +STARTCHAR glyph811 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -5 -2 +BITMAP +C0 +ENDCHAR +STARTCHAR glyph812 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -4 -2 +BITMAP +C0 +ENDCHAR +STARTCHAR glyph813 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -8 -2 +BITMAP +C0 +ENDCHAR +STARTCHAR glyph814 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -7 -2 +BITMAP +C0 +ENDCHAR +STARTCHAR glyph815 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -7 -2 +BITMAP +C0 +ENDCHAR +STARTCHAR glyph816 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -7 -2 +BITMAP +C0 +ENDCHAR +STARTCHAR glyph817 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -8 -2 +BITMAP +C0 +ENDCHAR +STARTCHAR glyph818 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -9 -2 +BITMAP +C0 +ENDCHAR +STARTCHAR glyph819 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -6 14 +BITMAP +68 +B8 +ENDCHAR +STARTCHAR glyph820 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -6 14 +BITMAP +64 +98 +ENDCHAR +STARTCHAR glyph821 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 2 -7 14 +BITMAP +C8 +B0 +ENDCHAR +STARTCHAR glyph822 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -8 14 +BITMAP +64 +D8 +ENDCHAR +STARTCHAR glyph823 +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 9 1 0 +BITMAP +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR glyph928 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 1 13 +BITMAP +F0 +00 +90 +ENDCHAR +STARTCHAR glyph929 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 1 13 +BITMAP +30 +60 +90 +ENDCHAR +STARTCHAR glyph930 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 1 13 +BITMAP +F0 +60 +90 +ENDCHAR +STARTCHAR glyph931 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 1 13 +BITMAP +C0 +40 +90 +ENDCHAR +STARTCHAR glyph958 +ENCODING -1 +SWIDTH 341 0 +DWIDTH 6 0 +BBX 6 1 0 2 +BITMAP +FC +ENDCHAR +STARTCHAR glyph1034 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 0 13 +BITMAP +F0 +00 +60 +ENDCHAR +STARTCHAR glyph1104 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 3 0 12 +BITMAP +78 +68 +90 +ENDCHAR +STARTCHAR uni02E5_uni02E5_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +F2 +12 +0A +06 +02 +02 +02 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E5_uni02E5_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +F2 +12 +0A +0A +06 +06 +06 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E5_uni02E5_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +F2 +12 +12 +0A +0A +0A +06 +06 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E5_uni02E5_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +F2 +12 +12 +12 +0A +0A +0A +0A +06 +06 +06 +02 +ENDCHAR +STARTCHAR uni02E5_uni02E6_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +86 +CE +7A +22 +02 +02 +02 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E5_uni02E6_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +82 +C2 +62 +3E +02 +02 +02 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E5_uni02E6_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +82 +C2 +62 +32 +1A +0E +06 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E5_uni02E6_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +82 +C2 +62 +12 +12 +0A +0A +06 +06 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E5_uni02E6_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +82 +C2 +62 +32 +12 +1A +0A +0A +0E +06 +06 +02 +ENDCHAR +STARTCHAR uni02E5_uni02E6.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 4 12 1 0 +BITMAP +90 +D0 +50 +30 +10 +10 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR uni02E5_uni02E7_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +83 +43 +45 +25 +29 +19 +11 +01 +01 +01 +01 +01 +ENDCHAR +STARTCHAR uni02E5_uni02E7_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +82 +82 +C2 +46 +2A +32 +22 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E5_uni02E7_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +82 +82 +C2 +42 +22 +22 +1E +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E5_uni02E7_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +82 +82 +42 +42 +22 +22 +12 +0E +06 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E5_uni02E7_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +82 +82 +C2 +42 +22 +22 +12 +12 +0A +0A +06 +06 +ENDCHAR +STARTCHAR uni02E5_uni02E7.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 5 12 0 0 +BITMAP +88 +48 +48 +28 +28 +18 +08 +08 +08 +08 +08 +08 +ENDCHAR +STARTCHAR uni02E5_uni02E8_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +83 +43 +43 +25 +25 +29 +19 +19 +01 +01 +01 +01 +ENDCHAR +STARTCHAR uni02E5_uni02E8_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +81 +41 +43 +23 +25 +25 +19 +19 +01 +01 +01 +01 +ENDCHAR +STARTCHAR uni02E5_uni02E8_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +81 +41 +41 +21 +21 +21 +13 +15 +09 +01 +01 +01 +ENDCHAR +STARTCHAR uni02E5_uni02E8_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +81 +41 +41 +21 +21 +31 +11 +11 +0F +01 +01 +01 +ENDCHAR +STARTCHAR uni02E5_uni02E8_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +81 +41 +41 +21 +21 +31 +11 +11 +09 +0D +07 +03 +ENDCHAR +STARTCHAR uni02E5_uni02E8.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 5 12 0 0 +BITMAP +88 +48 +48 +28 +28 +18 +18 +18 +08 +08 +08 +08 +ENDCHAR +STARTCHAR uni02E5_uni02E9_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +81 +43 +43 +43 +25 +25 +25 +29 +19 +19 +11 +01 +ENDCHAR +STARTCHAR uni02E5_uni02E9_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +81 +41 +43 +43 +23 +25 +25 +19 +19 +19 +11 +01 +ENDCHAR +STARTCHAR uni02E5_uni02E9_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +81 +41 +41 +41 +21 +23 +23 +15 +15 +19 +19 +01 +ENDCHAR +STARTCHAR uni02E5_uni02E9_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +81 +41 +41 +41 +21 +21 +21 +11 +13 +15 +19 +11 +ENDCHAR +STARTCHAR uni02E5_uni02E9_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +81 +41 +41 +41 +21 +21 +21 +11 +11 +11 +19 +0F +ENDCHAR +STARTCHAR uni02E5_uni02E9.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 5 12 0 0 +BITMAP +88 +48 +48 +48 +28 +28 +28 +18 +18 +18 +18 +08 +ENDCHAR +STARTCHAR uni02E6_uni02E5_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +3E +62 +C2 +82 +02 +02 +02 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E5_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +22 +7A +CE +86 +02 +02 +02 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E5_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +22 +72 +D2 +8A +0A +06 +06 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E5_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +22 +72 +D2 +92 +0A +0A +06 +06 +06 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E5_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +22 +62 +D2 +92 +12 +0A +0A +0A +06 +06 +06 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E5.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 4 12 1 0 +BITMAP +30 +70 +D0 +90 +10 +10 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR uni02E6_uni02E6_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +06 +0E +1A +F2 +02 +02 +02 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E6_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +F2 +1A +0E +06 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E6_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +F2 +1A +0A +0E +06 +06 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E6_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +F2 +12 +1A +0A +0A +0E +06 +06 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E7_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +06 +06 +8A +8A +52 +32 +22 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E7_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +86 +4A +32 +22 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E7_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +82 +42 +22 +3E +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E7_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +82 +C2 +62 +32 +1A +0E +06 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E7_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +82 +42 +62 +32 +1A +0A +0E +06 +06 +ENDCHAR +STARTCHAR uni02E6_uni02E7.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 4 12 1 0 +BITMAP +10 +10 +10 +90 +50 +30 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR uni02E6_uni02E8_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +06 +06 +86 +8A +4A +5A +32 +32 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E8_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +86 +86 +4A +4A +32 +32 +22 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E8_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +82 +82 +42 +42 +2E +3A +12 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E8_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +82 +82 +42 +42 +22 +22 +1E +02 +02 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E8_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +82 +82 +42 +42 +22 +22 +12 +1A +0E +06 +ENDCHAR +STARTCHAR uni02E6_uni02E8.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 4 12 1 0 +BITMAP +10 +10 +90 +90 +50 +50 +30 +30 +10 +10 +10 +10 +ENDCHAR +STARTCHAR uni02E6_uni02E9_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +86 +86 +86 +4A +4A +4A +52 +32 +32 +22 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E9_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +82 +86 +86 +4E +4A +4A +52 +32 +32 +22 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E9_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +82 +82 +82 +42 +46 +46 +6A +3A +32 +32 +02 +ENDCHAR +STARTCHAR uni02E6_uni02E9_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +82 +82 +82 +42 +42 +42 +62 +26 +2A +32 +22 +ENDCHAR +STARTCHAR uni02E6_uni02E9_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +82 +82 +82 +42 +42 +42 +62 +22 +22 +32 +1E +ENDCHAR +STARTCHAR uni02E6_uni02E9.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 5 12 0 0 +BITMAP +08 +88 +48 +48 +48 +28 +28 +28 +18 +18 +18 +08 +ENDCHAR +STARTCHAR uni02E7_uni02E5_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +1F +11 +21 +21 +41 +41 +81 +01 +01 +01 +01 +01 +ENDCHAR +STARTCHAR uni02E7_uni02E5_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +09 +1D +17 +23 +61 +41 +81 +01 +01 +01 +01 +01 +ENDCHAR +STARTCHAR uni02E7_uni02E5_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +11 +19 +19 +25 +65 +43 +83 +01 +01 +01 +01 +01 +ENDCHAR +STARTCHAR uni02E7_uni02E5_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +11 +19 +19 +29 +65 +45 +83 +03 +03 +01 +01 +01 +ENDCHAR +STARTCHAR uni02E7_uni02E5_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +01 +11 +19 +29 +69 +45 +85 +05 +03 +03 +03 +01 +ENDCHAR +STARTCHAR uni02E7_uni02E5.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 5 12 0 0 +BITMAP +08 +18 +18 +28 +68 +48 +88 +08 +08 +08 +08 +08 +ENDCHAR +STARTCHAR uni02E7_uni02E6_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +06 +0E +1A +32 +62 +C2 +82 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E7_uni02E6_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +3E +62 +C2 +82 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E7_uni02E6_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +32 +7A +CE +86 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E7_uni02E6_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +32 +D2 +8A +0A +06 +06 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E7_uni02E6_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +22 +72 +D2 +92 +0A +0A +0A +06 +06 +06 +ENDCHAR +STARTCHAR uni02E7_uni02E6.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 4 12 1 0 +BITMAP +10 +10 +10 +30 +50 +90 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR uni02E7_uni02E7_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +06 +06 +06 +0A +0A +12 +F2 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E7_uni02E7_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +06 +0A +12 +F2 +02 +02 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E7_uni02E7_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +02 +F2 +0A +06 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E7_uni02E7_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +02 +F2 +1A +0A +0E +06 +06 +ENDCHAR +STARTCHAR uni02E7_uni02E8_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +06 +06 +06 +0A +0A +92 +D2 +72 +22 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E7_uni02E8_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +06 +06 +0A +8A +D2 +72 +22 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E7_uni02E8_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +82 +CE +7A +32 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E7_uni02E8_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +82 +C2 +42 +3E +02 +02 +02 +ENDCHAR +STARTCHAR uni02E7_uni02E8_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +82 +C2 +62 +32 +1A +0E +06 +ENDCHAR +STARTCHAR uni02E7_uni02E8.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 4 12 1 0 +BITMAP +10 +10 +10 +10 +10 +10 +D0 +70 +30 +10 +10 +10 +ENDCHAR +STARTCHAR uni02E7_uni02E9_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +06 +06 +06 +0A +8A +8A +52 +52 +32 +22 +02 +ENDCHAR +STARTCHAR uni02E7_uni02E9_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +06 +06 +0E +8A +8A +52 +52 +32 +22 +02 +ENDCHAR +STARTCHAR uni02E7_uni02E9_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +86 +86 +4A +4A +32 +32 +22 +ENDCHAR +STARTCHAR uni02E7_uni02E9_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +82 +82 +46 +46 +2A +32 +22 +ENDCHAR +STARTCHAR uni02E7_uni02E9_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +82 +82 +42 +42 +22 +22 +1E +ENDCHAR +STARTCHAR uni02E7_uni02E9.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 4 12 1 0 +BITMAP +10 +10 +10 +10 +10 +90 +90 +50 +50 +30 +30 +10 +ENDCHAR +STARTCHAR uni02E8_uni02E5_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +0F +11 +11 +31 +21 +21 +41 +41 +81 +01 +01 +01 +ENDCHAR +STARTCHAR uni02E8_uni02E5_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +09 +1D +17 +33 +21 +21 +41 +41 +81 +01 +01 +01 +ENDCHAR +STARTCHAR uni02E8_uni02E5_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +11 +19 +19 +35 +27 +23 +43 +41 +81 +01 +01 +01 +ENDCHAR +STARTCHAR uni02E8_uni02E5_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +01 +19 +19 +39 +25 +25 +43 +43 +83 +01 +01 +01 +ENDCHAR +STARTCHAR uni02E8_uni02E5_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +01 +11 +19 +39 +29 +25 +45 +45 +83 +03 +03 +01 +ENDCHAR +STARTCHAR uni02E8_uni02E5.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 5 12 0 0 +BITMAP +08 +18 +18 +38 +28 +28 +48 +48 +88 +08 +08 +08 +ENDCHAR +STARTCHAR uni02E8_uni02E6_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +06 +0E +1A +12 +22 +62 +42 +82 +82 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E8_uni02E6_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +1E +22 +42 +42 +82 +82 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E8_uni02E6_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +01 +01 +01 +19 +15 +27 +23 +41 +C1 +01 +01 +01 +ENDCHAR +STARTCHAR uni02E8_uni02E6_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +01 +01 +11 +19 +19 +25 +65 +43 +C3 +01 +01 +01 +ENDCHAR +STARTCHAR uni02E8_uni02E6_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +01 +01 +11 +19 +39 +29 +65 +45 +C7 +03 +03 +01 +ENDCHAR +STARTCHAR uni02E8_uni02E6.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 5 12 0 0 +BITMAP +08 +08 +18 +18 +38 +28 +68 +48 +C8 +08 +08 +08 +ENDCHAR +STARTCHAR uni02E8_uni02E7_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +06 +06 +0E +0A +0A +12 +32 +62 +82 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E8_uni02E7_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +06 +1A +32 +62 +C2 +82 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E8_uni02E7_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +02 +3E +42 +82 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E8_uni02E7_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +02 +32 +CE +86 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E8_uni02E7_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +02 +32 +D2 +8A +0A +06 +06 +ENDCHAR +STARTCHAR uni02E8_uni02E7.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 4 12 1 0 +BITMAP +10 +10 +10 +10 +10 +10 +30 +50 +90 +10 +10 +10 +ENDCHAR +STARTCHAR uni02E8_uni02E8_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +06 +06 +0E +0A +0A +1A +12 +F2 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E8_uni02E8_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +06 +06 +0A +0A +0A +12 +F2 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E8_uni02E8_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +02 +06 +1A +F2 +02 +02 +02 +ENDCHAR +STARTCHAR uni02E8_uni02E8_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +02 +02 +02 +F2 +1A +0E +06 +ENDCHAR +STARTCHAR uni02E8_uni02E9_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +06 +06 +06 +0A +0A +0A +12 +92 +D2 +62 +22 +ENDCHAR +STARTCHAR uni02E8_uni02E9_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +06 +06 +0E +0A +0A +12 +92 +D2 +62 +22 +ENDCHAR +STARTCHAR uni02E8_uni02E9_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +06 +06 +0A +8A +D2 +72 +22 +ENDCHAR +STARTCHAR uni02E8_uni02E9_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +02 +02 +02 +86 +CA +72 +22 +ENDCHAR +STARTCHAR uni02E8_uni02E9_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +02 +02 +02 +82 +C2 +42 +3E +ENDCHAR +STARTCHAR uni02E8_uni02E9.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 4 12 1 0 +BITMAP +10 +10 +10 +10 +10 +10 +10 +10 +90 +D0 +70 +30 +ENDCHAR +STARTCHAR uni02E9_uni02E5_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +0F +19 +11 +11 +11 +21 +21 +21 +41 +41 +41 +81 +ENDCHAR +STARTCHAR uni02E9_uni02E5_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +09 +1D +17 +13 +11 +21 +21 +21 +41 +41 +41 +81 +ENDCHAR +STARTCHAR uni02E9_uni02E5_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +01 +19 +19 +15 +27 +23 +23 +21 +41 +41 +41 +81 +ENDCHAR +STARTCHAR uni02E9_uni02E5_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +01 +19 +19 +19 +15 +25 +23 +23 +43 +41 +41 +81 +ENDCHAR +STARTCHAR uni02E9_uni02E5_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +01 +11 +19 +19 +19 +25 +25 +25 +43 +43 +43 +81 +ENDCHAR +STARTCHAR uni02E9_uni02E5.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 5 12 0 0 +BITMAP +08 +18 +18 +18 +18 +28 +28 +28 +48 +48 +48 +88 +ENDCHAR +STARTCHAR uni02E9_uni02E6_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +03 +07 +05 +09 +19 +11 +11 +21 +21 +41 +41 +81 +ENDCHAR +STARTCHAR uni02E9_uni02E6_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +01 +01 +01 +0F +11 +11 +31 +21 +21 +41 +41 +81 +ENDCHAR +STARTCHAR uni02E9_uni02E6_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +01 +01 +11 +19 +15 +13 +23 +21 +61 +41 +41 +81 +ENDCHAR +STARTCHAR uni02E9_uni02E6_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +01 +01 +09 +19 +1D +35 +27 +23 +63 +41 +41 +81 +ENDCHAR +STARTCHAR uni02E9_uni02E6_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 8 12 0 0 +BITMAP +01 +01 +09 +19 +19 +35 +25 +25 +63 +43 +43 +81 +ENDCHAR +STARTCHAR uni02E9_uni02E6.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 5 12 0 0 +BITMAP +08 +08 +18 +18 +18 +28 +28 +28 +48 +48 +48 +88 +ENDCHAR +STARTCHAR uni02E9_uni02E7_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +06 +06 +0E +0A +12 +12 +22 +22 +42 +C2 +82 +82 +ENDCHAR +STARTCHAR uni02E9_uni02E7_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +06 +0A +1A +12 +22 +62 +42 +82 +82 +ENDCHAR +STARTCHAR uni02E9_uni02E7_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +02 +1E +22 +42 +42 +82 +82 +ENDCHAR +STARTCHAR uni02E9_uni02E7_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +12 +3A +2E +46 +42 +82 +82 +ENDCHAR +STARTCHAR uni02E9_uni02E7_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +12 +32 +3A +4A +CE +86 +86 +ENDCHAR +STARTCHAR uni02E9_uni02E7.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 4 12 1 0 +BITMAP +10 +10 +10 +10 +10 +10 +30 +70 +50 +D0 +90 +90 +ENDCHAR +STARTCHAR uni02E9_uni02E8_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +06 +06 +06 +0A +0A +0A +12 +12 +62 +C2 +82 +ENDCHAR +STARTCHAR uni02E9_uni02E8_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +06 +06 +0A +0A +0A +12 +12 +62 +C2 +82 +ENDCHAR +STARTCHAR uni02E9_uni02E8_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +02 +06 +1A +32 +62 +C2 +82 +ENDCHAR +STARTCHAR uni02E9_uni02E8_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +02 +02 +02 +3E +62 +C2 +82 +ENDCHAR +STARTCHAR uni02E9_uni02E8_uni02E9.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +02 +02 +02 +32 +6A +CE +86 +ENDCHAR +STARTCHAR uni02E9_uni02E8.ccmp +ENCODING -1 +SWIDTH 382 0 +DWIDTH 7 0 +BBX 4 12 1 0 +BITMAP +10 +10 +10 +10 +10 +10 +10 +10 +30 +70 +D0 +90 +ENDCHAR +STARTCHAR uni02E9_uni02E9_uni02E5.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +06 +06 +06 +06 +0A +0A +0A +0A +12 +12 +F2 +ENDCHAR +STARTCHAR uni02E9_uni02E9_uni02E6.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +06 +06 +06 +06 +0A +0A +0A +12 +12 +12 +F2 +ENDCHAR +STARTCHAR uni02E9_uni02E9_uni02E7.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +06 +06 +06 +0A +0A +0A +12 +F2 +ENDCHAR +STARTCHAR uni02E9_uni02E9_uni02E8.ccmp +ENCODING -1 +SWIDTH 542 0 +DWIDTH 9 0 +BBX 7 12 1 0 +BITMAP +02 +02 +02 +02 +02 +02 +02 +02 +06 +0A +12 +F2 +ENDCHAR +STARTCHAR glyph1567 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 7 2 -2 9 +BITMAP +FE +94 +ENDCHAR +STARTCHAR glyph1626 +ENCODING -1 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 2 2 10 +BITMAP +98 +70 +ENDCHAR +STARTCHAR glyph1710 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 4 0 12 +BITMAP +20 +10 +00 +F8 +ENDCHAR +STARTCHAR glyph1711 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 4 0 12 +BITMAP +18 +30 +00 +F8 +ENDCHAR +STARTCHAR glyph1712 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 4 0 12 +BITMAP +18 +30 +68 +98 +ENDCHAR +STARTCHAR glyph1713 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 4 0 12 +BITMAP +48 +00 +68 +98 +ENDCHAR +STARTCHAR glyph1714 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 4 2 12 +BITMAP +C0 +00 +C0 +80 +ENDCHAR +STARTCHAR glyph1715 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 4 1 12 +BITMAP +60 +00 +A0 +60 +ENDCHAR +STARTCHAR glyph1716 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 3 0 12 +BITMAP +48 +00 +F8 +ENDCHAR +STARTCHAR glyph2116 +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 4 9 0 0 +BITMAP +30 +30 +20 +20 +F0 +60 +60 +40 +40 +ENDCHAR +STARTCHAR uni05B1_uni05BD.ccmp +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 7 4 -1 -4 +BITMAP +D2 +AA +4A +4A +ENDCHAR +STARTCHAR uni05B2_uni05BD.ccmp +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 7 4 -1 -4 +BITMAP +EA +14 +14 +14 +ENDCHAR +STARTCHAR uni05B3_uni05BD.ccmp +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 7 4 -1 -4 +BITMAP +EA +54 +14 +14 +ENDCHAR +STARTCHAR alpha_uni0304_uni0313_gravecomb.ccmp +ENCODING -1 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 15 1 0 +BITMAP +1A00 +1B00 +1000 +0000 +3E00 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR alpha_uni0304_uni0313_acutecomb.ccmp +ENCODING -1 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 15 1 0 +BITMAP +1B00 +1E00 +1000 +0000 +3E00 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR alpha_uni0304_uni0314_gravecomb.ccmp +ENCODING -1 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 15 1 0 +BITMAP +1A00 +1300 +1000 +0000 +3E00 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR alpha_uni0304_uni0314_acutecomb.ccmp +ENCODING -1 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 15 1 0 +BITMAP +1B00 +1600 +1000 +0000 +3E00 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR alpha_uni0306_uni0313_gravecomb.ccmp +ENCODING -1 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 15 1 0 +BITMAP +1A00 +1B00 +1000 +2600 +1C00 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR alpha_uni0306_uni0313_acutecomb.ccmp +ENCODING -1 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 15 1 0 +BITMAP +1B00 +1E00 +1000 +2600 +1C00 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR alpha_uni0306_uni0314_gravecomb.ccmp +ENCODING -1 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 15 1 0 +BITMAP +1A00 +1300 +1000 +2600 +1C00 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR alpha_uni0306_uni0314_acutecomb.ccmp +ENCODING -1 +SWIDTH 570 0 +DWIDTH 10 0 +BBX 9 15 1 0 +BITMAP +1B00 +1600 +1000 +2600 +1C00 +0000 +3D80 +6300 +4300 +C200 +8200 +8200 +8600 +CA00 +7200 +ENDCHAR +STARTCHAR iota_uni0304_uni0313_gravecomb.ccmp +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 15 1 0 +BITMAP +68 +6C +40 +00 +F8 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR iota_uni0304_uni0313_acutecomb.ccmp +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 15 1 0 +BITMAP +6C +78 +40 +00 +F8 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR iota_uni0304_uni0314_gravecomb.ccmp +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 15 1 0 +BITMAP +68 +4C +40 +00 +F8 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR iota_uni0304_uni0314_acutecomb.ccmp +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 15 1 0 +BITMAP +6C +58 +40 +00 +F8 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR iota_uni0306_uni0313_gravecomb.ccmp +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 15 1 0 +BITMAP +68 +6C +40 +98 +70 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR iota_uni0306_uni0313_acutecomb.ccmp +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 15 1 0 +BITMAP +6C +78 +40 +98 +70 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR iota_uni0306_uni0314_gravecomb.ccmp +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 15 1 0 +BITMAP +68 +4C +40 +98 +70 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR iota_uni0306_uni0314_acutecomb.ccmp +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 15 1 0 +BITMAP +6C +58 +40 +98 +70 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR upsilon_uni0304_uni0313_gravecomb.ccmp +ENCODING -1 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 15 1 0 +BITMAP +1A +1B +10 +00 +1F +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR upsilon_uni0304_uni0313_acutecomb.ccmp +ENCODING -1 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 9 15 1 0 +BITMAP +0D80 +0F00 +0800 +0000 +1F00 +0000 +6100 +6100 +4300 +4300 +C300 +C200 +C600 +4400 +7800 +ENDCHAR +STARTCHAR upsilon_uni0304_uni0314_gravecomb.ccmp +ENCODING -1 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 15 1 0 +BITMAP +1A +13 +10 +00 +1F +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR upsilon_uni0304_uni0314_acutecomb.ccmp +ENCODING -1 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 15 1 0 +BITMAP +1B +16 +10 +00 +1F +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR upsilon_uni0306_uni0313_gravecomb.ccmp +ENCODING -1 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 15 1 0 +BITMAP +1A +1B +10 +13 +0E +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR upsilon_uni0306_uni0313_acutecomb.ccmp +ENCODING -1 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 15 1 0 +BITMAP +1B +1E +10 +13 +0E +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR upsilon_uni0306_uni0314_gravecomb.ccmp +ENCODING -1 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 15 1 0 +BITMAP +1A +13 +10 +13 +0E +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR upsilon_uni0306_uni0314_acutecomb.ccmp +ENCODING -1 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 15 1 0 +BITMAP +1B +16 +10 +13 +0E +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR iota_uni0308_uni0304_gravecomb.ccmp +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 16 1 0 +BITMAP +20 +30 +10 +7C +D8 +00 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR iota_uni0308_uni0304_acutecomb.ccmp +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 16 1 0 +BITMAP +18 +10 +20 +7C +D8 +00 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR iota_uni0308_uni0306_gravecomb.ccmp +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 16 1 0 +BITMAP +20 +30 +5C +38 +00 +D8 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR iota_uni0308_uni0306_acutecomb.ccmp +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 6 16 1 0 +BITMAP +18 +10 +6C +38 +00 +D8 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR upsilon_uni0308_uni0304_gravecomb.ccmp +ENCODING -1 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +08 +0C +04 +1F +1B +00 +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR upsilon_uni0308_uni0304_acutecomb.ccmp +ENCODING -1 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +03 +02 +04 +1F +1B +00 +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR upsilon_uni0308_uni0306_gravecomb.ccmp +ENCODING -1 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +08 +0C +17 +0E +00 +1B +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR upsilon_uni0308_uni0306_acutecomb.ccmp +ENCODING -1 +SWIDTH 549 0 +DWIDTH 9 0 +BBX 8 16 1 0 +BITMAP +03 +02 +17 +0E +00 +1B +00 +61 +61 +43 +43 +C3 +C2 +C6 +44 +78 +ENDCHAR +STARTCHAR glyph2515 +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 16 1 0 +BITMAP +18 +10 +20 +00 +20 +00 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR glyph2516 +ENCODING -1 +SWIDTH 723 0 +DWIDTH 12 0 +BBX 11 15 1 -3 +BITMAP +37C0 +3860 +3060 +2020 +6020 +6020 +6060 +4060 +C040 +C040 +C0C0 +8080 +0180 +0100 +1E00 +ENDCHAR +STARTCHAR glyph2517 +ENCODING -1 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 12 15 1 -3 +BITMAP +3030 +3830 +3820 +2C20 +6C60 +6660 +6660 +4340 +4340 +C1C0 +C1C0 +80C0 +0080 +0180 +0700 +ENDCHAR +STARTCHAR glyph2518 +ENCODING -1 +SWIDTH 723 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +37C0 +3860 +3020 +6020 +6020 +6060 +0060 +0060 +C040 +40C0 +6180 +3E00 +ENDCHAR +STARTCHAR glyph2519 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 6 -3 1 +BITMAP +38 +4C +4C +C8 +C8 +70 +ENDCHAR +STARTCHAR glyph2520 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 6 -2 1 +BITMAP +10 +70 +E0 +20 +20 +60 +ENDCHAR +STARTCHAR glyph2521 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 6 -3 1 +BITMAP +38 +4C +0C +30 +60 +F8 +ENDCHAR +STARTCHAR glyph2522 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 6 -3 1 +BITMAP +78 +0C +10 +08 +C8 +78 +ENDCHAR +STARTCHAR glyph2523 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 6 -3 1 +BITMAP +0C +18 +28 +48 +FC +18 +ENDCHAR +STARTCHAR glyph2524 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 6 -3 1 +BITMAP +7C +40 +78 +08 +C8 +70 +ENDCHAR +STARTCHAR glyph2525 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 6 -3 1 +BITMAP +38 +40 +78 +C8 +C8 +70 +ENDCHAR +STARTCHAR glyph2526 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 6 -2 1 +BITMAP +F0 +10 +20 +40 +40 +80 +ENDCHAR +STARTCHAR glyph2527 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 6 -3 1 +BITMAP +38 +4C +30 +48 +C8 +78 +ENDCHAR +STARTCHAR glyph2528 +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 5 6 -2 1 +BITMAP +70 +98 +98 +F0 +10 +E0 +ENDCHAR +STARTCHAR zero.oldstyle +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +1E +63 +41 +C1 +C1 +C3 +C3 +C6 +7C +ENDCHAR +STARTCHAR one.oldstyle +ENCODING -1 +SWIDTH 383 0 +DWIDTH 7 0 +BBX 5 9 1 0 +BITMAP +18 +38 +D0 +10 +30 +30 +30 +20 +20 +ENDCHAR +STARTCHAR two.oldstyle +ENCODING -1 +SWIDTH 539 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +1F00 +3180 +2180 +0180 +0300 +0C00 +3000 +6000 +FF00 +ENDCHAR +STARTCHAR three.oldstyle +ENCODING -1 +SWIDTH 534 0 +DWIDTH 9 0 +BBX 8 12 0 -3 +BITMAP +1E +33 +61 +01 +03 +0E +02 +03 +03 +C3 +C6 +3C +ENDCHAR +STARTCHAR four.oldstyle +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +0180 +0300 +0700 +0D00 +0B00 +1300 +2200 +6200 +FF80 +0600 +0600 +0400 +ENDCHAR +STARTCHAR five.oldstyle +ENCODING -1 +SWIDTH 539 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +1F80 +3000 +2000 +3E00 +6300 +6100 +0100 +0100 +C300 +C300 +6600 +3C00 +ENDCHAR +STARTCHAR six.oldstyle +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +0E00 +1100 +2180 +6000 +7E00 +6300 +4100 +C100 +C100 +4300 +6600 +3C00 +ENDCHAR +STARTCHAR seven.oldstyle +ENCODING -1 +SWIDTH 519 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +FF +02 +04 +0C +18 +10 +30 +20 +60 +60 +40 +40 +ENDCHAR +STARTCHAR eight.oldstyle +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +1E00 +3100 +2180 +6180 +2300 +3E00 +6300 +C300 +C300 +C300 +4600 +3C00 +ENDCHAR +STARTCHAR nine.oldstyle +ENCODING -1 +SWIDTH 559 0 +DWIDTH 10 0 +BBX 8 12 1 -3 +BITMAP +1E +33 +61 +41 +41 +43 +63 +3F +02 +C6 +44 +78 +ENDCHAR +STARTCHAR zero.pnum +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +0E00 +3100 +2100 +6180 +4180 +4100 +C100 +C100 +C300 +C200 +4400 +3800 +ENDCHAR +STARTCHAR one.pnum +ENCODING -1 +SWIDTH 387 0 +DWIDTH 7 0 +BBX 5 12 2 0 +BITMAP +08 +18 +78 +90 +10 +30 +30 +30 +20 +20 +60 +60 +ENDCHAR +STARTCHAR two.pnum +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +1E00 +3300 +6100 +2180 +0100 +0300 +0600 +0C00 +3000 +6000 +4000 +FE00 +ENDCHAR +STARTCHAR three.pnum +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1E +33 +61 +01 +03 +0E +02 +03 +03 +C3 +C6 +3C +ENDCHAR +STARTCHAR four.pnum +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +03 +03 +07 +0A +1A +36 +66 +C6 +FF +04 +0C +0C +ENDCHAR +STARTCHAR five.pnum +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +1F80 +3000 +2000 +3E00 +6300 +6100 +0100 +0100 +C300 +C300 +6600 +3C00 +ENDCHAR +STARTCHAR six.pnum +ENCODING -1 +SWIDTH 561 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +0E00 +1100 +2180 +6000 +7E00 +6300 +4100 +C100 +C100 +4300 +6600 +3C00 +ENDCHAR +STARTCHAR seven.pnum +ENCODING -1 +SWIDTH 522 0 +DWIDTH 9 0 +BBX 8 12 2 0 +BITMAP +FF +02 +04 +0C +18 +10 +30 +20 +60 +60 +40 +40 +ENDCHAR +STARTCHAR eight.pnum +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +1E00 +3100 +2180 +6180 +2300 +3E00 +6300 +C300 +C300 +C300 +4600 +3C00 +ENDCHAR +STARTCHAR nine.pnum +ENCODING -1 +SWIDTH 560 0 +DWIDTH 10 0 +BBX 8 12 1 0 +BITMAP +1E +33 +61 +41 +41 +43 +63 +3F +02 +C6 +44 +78 +ENDCHAR +STARTCHAR A.unic +ENCODING -1 +SWIDTH 721 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +0FC0 +3060 +2060 +0060 +00E0 +1F60 +6040 +C040 +C0C0 +C0C0 +C3C0 +7CC0 +ENDCHAR +STARTCHAR E.unic +ENCODING -1 +SWIDTH 755 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +0F80 +30C0 +6040 +C060 +C060 +FFC0 +8000 +8000 +80C0 +C080 +6300 +3E00 +ENDCHAR +STARTCHAR N.unic +ENCODING -1 +SWIDTH 746 0 +DWIDTH 13 0 +BBX 11 12 1 0 +BITMAP +37C0 +3860 +3020 +2020 +6020 +6060 +4060 +4060 +C040 +C040 +C0C0 +80C0 +ENDCHAR +STARTCHAR M.unic +ENCODING -1 +SWIDTH 1166 0 +DWIDTH 20 0 +BBX 19 12 1 0 +BITMAP +37C780 +3848C0 +307040 +206060 +606040 +604040 +4040C0 +40C0C0 +C0C0C0 +C0C080 +C08080 +808180 +ENDCHAR +STARTCHAR U.unic +ENCODING -1 +SWIDTH 746 0 +DWIDTH 13 0 +BBX 12 12 1 0 +BITMAP +3030 +3030 +2030 +6020 +6020 +6060 +4060 +4060 +C040 +40C0 +61C0 +3EC0 +ENDCHAR +STARTCHAR I.ss03 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 12 0 0 +BITMAP +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR K.ss03 +ENCODING -1 +SWIDTH 656 0 +DWIDTH 11 0 +BBX 11 12 1 0 +BITMAP +3060 +30C0 +2180 +2300 +6E00 +7800 +7800 +4C00 +C600 +C300 +C300 +8180 +ENDCHAR +STARTCHAR Q.ss03 +ENCODING -1 +SWIDTH 777 0 +DWIDTH 13 0 +BBX 11 13 2 -1 +BITMAP +1F00 +30C0 +6040 +C060 +C060 +8020 +8060 +8060 +8640 +C2C0 +6380 +3F80 +00C0 +ENDCHAR +STARTCHAR a.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +3D +63 +43 +C3 +83 +82 +C6 +C6 +7E +ENDCHAR +STARTCHAR j.ss03 +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 4 16 0 -3 +BITMAP +10 +10 +00 +00 +30 +30 +20 +20 +60 +60 +40 +40 +40 +C0 +C0 +80 +ENDCHAR +STARTCHAR k.ss03 +ENCODING -1 +SWIDTH 496 0 +DWIDTH 8 0 +BBX 8 12 1 0 +BITMAP +30 +20 +20 +63 +66 +4C +58 +70 +D0 +D8 +8C +86 +ENDCHAR +STARTCHAR l.ss03 +ENCODING -1 +SWIDTH 254 0 +DWIDTH 4 0 +BBX 3 12 1 0 +BITMAP +20 +20 +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +E0 +ENDCHAR +STARTCHAR q.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 -3 +BITMAP +3D +67 +43 +C3 +82 +82 +86 +C6 +7E +04 +04 +07 +ENDCHAR +STARTCHAR t.ss03 +ENCODING -1 +SWIDTH 289 0 +DWIDTH 5 0 +BBX 5 11 1 0 +BITMAP +30 +30 +F8 +20 +60 +60 +40 +40 +40 +C0 +C0 +ENDCHAR +STARTCHAR y.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +3080 +3080 +2180 +2180 +6100 +6100 +6300 +6500 +3B00 +0200 +C600 +7C00 +ENDCHAR +STARTCHAR six.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +03 +06 +1C +38 +30 +7E +E3 +C1 +C1 +C3 +C6 +7C +ENDCHAR +STARTCHAR nine.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 2 0 +BITMAP +3C +62 +C3 +83 +83 +C6 +7E +0C +18 +30 +60 +C0 +ENDCHAR +STARTCHAR I.ss01 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 12 0 0 +BITMAP +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR l.ss01 +ENCODING -1 +SWIDTH 254 0 +DWIDTH 4 0 +BBX 3 12 1 0 +BITMAP +20 +20 +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +E0 +ENDCHAR +STARTCHAR i.locl +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 3 12 1 0 +BITMAP +20 +00 +00 +60 +60 +40 +40 +C0 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR A.c2sc +ENCODING -1 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +0600 +0E00 +0A00 +1300 +3300 +3F00 +4100 +C180 +8180 +ENDCHAR +STARTCHAR B.c2sc +ENCODING -1 +SWIDTH 566 0 +DWIDTH 10 0 +BBX 8 9 1 0 +BITMAP +3E +61 +61 +43 +7C +C3 +C3 +C3 +FC +ENDCHAR +STARTCHAR C.c2sc +ENCODING -1 +SWIDTH 595 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +1F00 +3180 +6080 +C000 +C000 +C000 +C100 +4300 +3C00 +ENDCHAR +STARTCHAR D.c2sc +ENCODING -1 +SWIDTH 612 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +3E00 +6180 +6180 +4080 +4080 +C180 +C180 +C300 +FC00 +ENDCHAR +STARTCHAR E.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 9 9 1 0 +BITMAP +3F80 +6000 +6000 +4000 +7F00 +C000 +C000 +C000 +FE00 +ENDCHAR +STARTCHAR F.c2sc +ENCODING -1 +SWIDTH 503 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +3F +60 +60 +40 +7E +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR G.c2sc +ENCODING -1 +SWIDTH 647 0 +DWIDTH 11 0 +BBX 10 9 1 0 +BITMAP +1F80 +30C0 +6000 +C000 +C780 +C080 +C180 +6180 +3E00 +ENDCHAR +STARTCHAR H.c2sc +ENCODING -1 +SWIDTH 617 0 +DWIDTH 11 0 +BBX 9 9 1 0 +BITMAP +2080 +6080 +6080 +4180 +7F80 +C100 +C100 +C300 +8300 +ENDCHAR +STARTCHAR I.c2sc +ENCODING -1 +SWIDTH 239 0 +DWIDTH 4 0 +BBX 3 9 1 0 +BITMAP +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR J.c2sc +ENCODING -1 +SWIDTH 431 0 +DWIDTH 7 0 +BBX 8 9 0 0 +BITMAP +03 +02 +02 +06 +06 +04 +C4 +CC +78 +ENDCHAR +STARTCHAR K.c2sc +ENCODING -1 +SWIDTH 566 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +2180 +6300 +6C00 +5800 +7800 +CC00 +C600 +C600 +8300 +ENDCHAR +STARTCHAR L.c2sc +ENCODING -1 +SWIDTH 466 0 +DWIDTH 8 0 +BBX 6 9 1 0 +BITMAP +20 +60 +60 +40 +40 +C0 +C0 +C0 +FC +ENDCHAR +STARTCHAR M.c2sc +ENCODING -1 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 9 1 0 +BITMAP +3060 +70E0 +70E0 +5160 +5140 +DA40 +CE40 +8CC0 +88C0 +ENDCHAR +STARTCHAR N.c2sc +ENCODING -1 +SWIDTH 615 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +2080 +7080 +7080 +5980 +4980 +CD00 +C500 +8700 +8300 +ENDCHAR +STARTCHAR O.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 10 9 1 0 +BITMAP +1F00 +3180 +60C0 +C0C0 +C0C0 +C080 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR P.c2sc +ENCODING -1 +SWIDTH 553 0 +DWIDTH 9 0 +BBX 9 9 1 0 +BITMAP +3E00 +6100 +6180 +4180 +4300 +FE00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR Q.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 10 10 1 -1 +BITMAP +1F00 +3180 +60C0 +C0C0 +C0C0 +C080 +C580 +6700 +3F80 +0080 +ENDCHAR +STARTCHAR R.c2sc +ENCODING -1 +SWIDTH 606 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +3F00 +6180 +6080 +4180 +7E00 +C600 +C200 +C300 +8100 +ENDCHAR +STARTCHAR S.c2sc +ENCODING -1 +SWIDTH 553 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +1F00 +3180 +2180 +3000 +1E00 +0100 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR T.c2sc +ENCODING -1 +SWIDTH 507 0 +DWIDTH 9 0 +BBX 8 9 2 0 +BITMAP +FF +10 +30 +30 +20 +20 +60 +60 +60 +ENDCHAR +STARTCHAR U.c2sc +ENCODING -1 +SWIDTH 607 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +6080 +6180 +4180 +4100 +C100 +C100 +C300 +C600 +7C00 +ENDCHAR +STARTCHAR V.c2sc +ENCODING -1 +SWIDTH 550 0 +DWIDTH 9 0 +BBX 9 9 1 0 +BITMAP +C180 +C100 +4300 +4600 +4400 +6C00 +6800 +3000 +3000 +ENDCHAR +STARTCHAR W.c2sc +ENCODING -1 +SWIDTH 793 0 +DWIDTH 13 0 +BBX 13 9 1 0 +BITMAP +C308 +C518 +C510 +4930 +5920 +5160 +7140 +61C0 +6180 +ENDCHAR +STARTCHAR X.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 10 9 0 0 +BITMAP +30C0 +3180 +1B00 +0E00 +0C00 +1C00 +3600 +4300 +8300 +ENDCHAR +STARTCHAR Y.c2sc +ENCODING -1 +SWIDTH 552 0 +DWIDTH 9 0 +BBX 9 9 1 0 +BITMAP +C180 +6300 +6600 +3C00 +3800 +1000 +1000 +3000 +3000 +ENDCHAR +STARTCHAR Z.c2sc +ENCODING -1 +SWIDTH 506 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +3F80 +0100 +0200 +0400 +0800 +1000 +6000 +C000 +FF00 +ENDCHAR +STARTCHAR AE.c2sc +ENCODING -1 +SWIDTH 820 0 +DWIDTH 14 0 +BBX 14 9 0 0 +BITMAP +03FC +0480 +0D80 +0980 +11F8 +3F00 +6100 +C300 +83F8 +ENDCHAR +STARTCHAR OE.c2sc +ENCODING -1 +SWIDTH 833 0 +DWIDTH 14 0 +BBX 14 9 1 0 +BITMAP +1EFC +2180 +4180 +C180 +C1F0 +C100 +C300 +C700 +7BF0 +ENDCHAR +STARTCHAR Lslash.c2sc +ENCODING -1 +SWIDTH 466 0 +DWIDTH 8 0 +BBX 6 9 1 0 +BITMAP +20 +60 +60 +48 +70 +C0 +C0 +C0 +FC +ENDCHAR +STARTCHAR Oslash.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 11 9 0 0 +BITMAP +0FA0 +18E0 +30E0 +6360 +6660 +6860 +70C0 +7180 +9F00 +ENDCHAR +STARTCHAR Thorn.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +20 +60 +7E +43 +41 +C3 +FE +80 +80 +ENDCHAR +STARTCHAR Eth.c2sc +ENCODING -1 +SWIDTH 612 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +3E00 +6180 +6180 +4080 +F880 +C180 +C180 +C300 +FC00 +ENDCHAR +STARTCHAR uni1E9E.c2sc +ENCODING -1 +SWIDTH 595 0 +DWIDTH 10 0 +BBX 8 9 1 0 +BITMAP +1E +21 +63 +46 +CE +C3 +C1 +83 +BE +ENDCHAR +STARTCHAR Agrave.c2sc +ENCODING -1 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 13 0 0 +BITMAP +0400 +0600 +0200 +0000 +0600 +0E00 +0A00 +1300 +3300 +3F00 +4100 +C180 +8180 +ENDCHAR +STARTCHAR Aacute.c2sc +ENCODING -1 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 13 0 0 +BITMAP +0300 +0200 +0400 +0000 +0600 +0E00 +0A00 +1300 +3300 +3F00 +4100 +C180 +8180 +ENDCHAR +STARTCHAR Acircumflex.c2sc +ENCODING -1 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 13 0 0 +BITMAP +0300 +0500 +0D00 +0000 +0600 +0E00 +0A00 +1300 +3300 +3F00 +4100 +C180 +8180 +ENDCHAR +STARTCHAR Atilde.c2sc +ENCODING -1 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 12 0 0 +BITMAP +0E80 +0B80 +0000 +0600 +0E00 +0A00 +1300 +3300 +3F00 +4100 +C180 +8180 +ENDCHAR +STARTCHAR Adieresis.c2sc +ENCODING -1 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 11 0 0 +BITMAP +0D80 +0000 +0600 +0E00 +0A00 +1300 +3300 +3F00 +4100 +C180 +8180 +ENDCHAR +STARTCHAR Aring.c2sc +ENCODING -1 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 12 0 0 +BITMAP +0600 +0900 +0900 +0600 +0E00 +0A00 +1300 +3300 +3F00 +4100 +C180 +8180 +ENDCHAR +STARTCHAR Ccedilla.c2sc +ENCODING -1 +SWIDTH 595 0 +DWIDTH 10 0 +BBX 9 12 1 -3 +BITMAP +1F00 +3180 +6080 +C000 +C000 +C000 +C100 +4300 +3C00 +1000 +0C00 +3800 +ENDCHAR +STARTCHAR Egrave.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 9 13 1 0 +BITMAP +0800 +0C00 +0400 +0000 +3F80 +6000 +6000 +4000 +7F00 +C000 +C000 +C000 +FE00 +ENDCHAR +STARTCHAR Eacute.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 9 13 1 0 +BITMAP +0300 +0200 +0400 +0000 +3F80 +6000 +6000 +4000 +7F00 +C000 +C000 +C000 +FE00 +ENDCHAR +STARTCHAR Ecircumflex.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 9 13 1 0 +BITMAP +0600 +0A00 +1A00 +0000 +3F80 +6000 +6000 +4000 +7F00 +C000 +C000 +C000 +FE00 +ENDCHAR +STARTCHAR Edieresis.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 9 11 1 0 +BITMAP +1B00 +0000 +3F80 +6000 +6000 +4000 +7F00 +C000 +C000 +C000 +FE00 +ENDCHAR +STARTCHAR Igrave.c2sc +ENCODING -1 +SWIDTH 239 0 +DWIDTH 4 0 +BBX 3 13 1 0 +BITMAP +40 +60 +20 +00 +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR Iacute.c2sc +ENCODING -1 +SWIDTH 239 0 +DWIDTH 4 0 +BBX 5 13 1 0 +BITMAP +18 +10 +20 +00 +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR Icircumflex.c2sc +ENCODING -1 +SWIDTH 239 0 +DWIDTH 4 0 +BBX 4 13 1 0 +BITMAP +30 +50 +D0 +00 +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR Idieresis.c2sc +ENCODING -1 +SWIDTH 239 0 +DWIDTH 4 0 +BBX 5 11 1 0 +BITMAP +D8 +00 +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR Ntilde.c2sc +ENCODING -1 +SWIDTH 615 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +0E80 +0B80 +0000 +2080 +7080 +7080 +5980 +4980 +CD00 +C500 +8700 +8300 +ENDCHAR +STARTCHAR Ograve.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 10 13 1 0 +BITMAP +0800 +0C00 +0400 +0000 +1F00 +3180 +60C0 +C0C0 +C0C0 +C080 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR Oacute.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 10 13 1 0 +BITMAP +0300 +0200 +0400 +0000 +1F00 +3180 +60C0 +C0C0 +C0C0 +C080 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR Ocircumflex.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 10 13 1 0 +BITMAP +0300 +0500 +0D00 +0000 +1F00 +3180 +60C0 +C0C0 +C0C0 +C080 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR Otilde.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +0E80 +0B80 +0000 +1F00 +3180 +60C0 +C0C0 +C0C0 +C080 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR Odieresis.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 10 11 1 0 +BITMAP +1B00 +0000 +1F00 +3180 +60C0 +C0C0 +C0C0 +C080 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR Ugrave.c2sc +ENCODING -1 +SWIDTH 607 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +0800 +0C00 +0400 +0000 +6080 +6180 +4180 +4100 +C100 +C100 +C300 +C600 +7C00 +ENDCHAR +STARTCHAR Uacute.c2sc +ENCODING -1 +SWIDTH 607 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +0600 +0400 +0800 +0000 +6080 +6180 +4180 +4100 +C100 +C100 +C300 +C600 +7C00 +ENDCHAR +STARTCHAR Ucircumflex.c2sc +ENCODING -1 +SWIDTH 607 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +0600 +0A00 +1A00 +0000 +6080 +6180 +4180 +4100 +C100 +C100 +C300 +C600 +7C00 +ENDCHAR +STARTCHAR Udieresis.c2sc +ENCODING -1 +SWIDTH 607 0 +DWIDTH 10 0 +BBX 9 11 1 0 +BITMAP +1B00 +0000 +6080 +6180 +4180 +4100 +C100 +C100 +C300 +C600 +7C00 +ENDCHAR +STARTCHAR Yacute.c2sc +ENCODING -1 +SWIDTH 552 0 +DWIDTH 9 0 +BBX 9 13 1 0 +BITMAP +0600 +0400 +0800 +0000 +C180 +6300 +6600 +3C00 +3800 +1000 +1000 +3000 +3000 +ENDCHAR +STARTCHAR Amacron.c2sc +ENCODING -1 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 11 0 0 +BITMAP +0F80 +0000 +0600 +0E00 +0A00 +1300 +3300 +3F00 +4100 +C180 +8180 +ENDCHAR +STARTCHAR Abreve.c2sc +ENCODING -1 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 12 0 0 +BITMAP +0980 +0700 +0000 +0600 +0E00 +0A00 +1300 +3300 +3F00 +4100 +C180 +8180 +ENDCHAR +STARTCHAR Aogonek.c2sc +ENCODING -1 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 13 0 -4 +BITMAP +0600 +0E00 +0A00 +1300 +3300 +3F00 +4100 +C180 +8180 +0100 +0200 +0200 +0300 +ENDCHAR +STARTCHAR Cacute.c2sc +ENCODING -1 +SWIDTH 595 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +0300 +0200 +0400 +0000 +1F00 +3180 +6080 +C000 +C000 +C000 +C100 +4300 +3C00 +ENDCHAR +STARTCHAR Ccaron.c2sc +ENCODING -1 +SWIDTH 595 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +0D80 +0700 +0600 +0000 +1F00 +3180 +6080 +C000 +C000 +C000 +C100 +4300 +3C00 +ENDCHAR +STARTCHAR Ccircumflex.c2sc +ENCODING -1 +SWIDTH 595 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +0300 +0500 +0D00 +0000 +1F00 +3180 +6080 +C000 +C000 +C000 +C100 +4300 +3C00 +ENDCHAR +STARTCHAR Cdotaccent.c2sc +ENCODING -1 +SWIDTH 595 0 +DWIDTH 10 0 +BBX 9 11 1 0 +BITMAP +0600 +0000 +1F00 +3180 +6080 +C000 +C000 +C000 +C100 +4300 +3C00 +ENDCHAR +STARTCHAR Dcaron.c2sc +ENCODING -1 +SWIDTH 612 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +1B00 +0E00 +0C00 +0000 +3E00 +6180 +6180 +4080 +4080 +C180 +C180 +C300 +FC00 +ENDCHAR +STARTCHAR Dcroat.c2sc +ENCODING -1 +SWIDTH 612 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +3E00 +6180 +6180 +4080 +F880 +C180 +C180 +C300 +FC00 +ENDCHAR +STARTCHAR Emacron.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 9 11 1 0 +BITMAP +1F00 +0000 +3F80 +6000 +6000 +4000 +7F00 +C000 +C000 +C000 +FE00 +ENDCHAR +STARTCHAR Ebreve.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +1300 +0E00 +0000 +3F80 +6000 +6000 +4000 +7F00 +C000 +C000 +C000 +FE00 +ENDCHAR +STARTCHAR Edotaccent.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 9 11 1 0 +BITMAP +0C00 +0000 +3F80 +6000 +6000 +4000 +7F00 +C000 +C000 +C000 +FE00 +ENDCHAR +STARTCHAR Eogonek.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 9 13 1 -4 +BITMAP +3F80 +6000 +6000 +4000 +7F00 +C000 +C000 +C000 +FE00 +0400 +0800 +0800 +0C00 +ENDCHAR +STARTCHAR Ecaron.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 9 13 1 0 +BITMAP +1B00 +0E00 +0C00 +0000 +3F80 +6000 +6000 +4000 +7F00 +C000 +C000 +C000 +FE00 +ENDCHAR +STARTCHAR Gbreve.c2sc +ENCODING -1 +SWIDTH 647 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +0980 +0700 +0000 +1F80 +30C0 +6000 +C000 +C780 +C080 +C180 +6180 +3E00 +ENDCHAR +STARTCHAR Gcircumflex.c2sc +ENCODING -1 +SWIDTH 647 0 +DWIDTH 11 0 +BBX 10 13 1 0 +BITMAP +0300 +0500 +0D00 +0000 +1F80 +30C0 +6000 +C000 +C780 +C080 +C180 +6180 +3E00 +ENDCHAR +STARTCHAR uni0122.c2sc +ENCODING -1 +SWIDTH 647 0 +DWIDTH 11 0 +BBX 10 13 1 -4 +BITMAP +1F80 +30C0 +6000 +C000 +C780 +C080 +C180 +6180 +3E00 +0000 +1C00 +0400 +3800 +ENDCHAR +STARTCHAR Gdotaccent.c2sc +ENCODING -1 +SWIDTH 647 0 +DWIDTH 11 0 +BBX 10 11 1 0 +BITMAP +0600 +0000 +1F80 +30C0 +6000 +C000 +C780 +C080 +C180 +6180 +3E00 +ENDCHAR +STARTCHAR Hcircumflex.c2sc +ENCODING -1 +SWIDTH 617 0 +DWIDTH 11 0 +BBX 9 13 1 0 +BITMAP +0300 +0500 +0D00 +0000 +2080 +6080 +6080 +4180 +7F80 +C100 +C100 +C300 +8300 +ENDCHAR +STARTCHAR Hbar.c2sc +ENCODING -1 +SWIDTH 618 0 +DWIDTH 11 0 +BBX 10 9 1 0 +BITMAP +20C0 +6080 +FFC0 +6180 +7F80 +C100 +C100 +C300 +8300 +ENDCHAR +STARTCHAR Itilde.c2sc +ENCODING -1 +SWIDTH 239 0 +DWIDTH 4 0 +BBX 5 12 1 0 +BITMAP +E8 +B8 +00 +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR Imacron.c2sc +ENCODING -1 +SWIDTH 239 0 +DWIDTH 4 0 +BBX 5 11 1 0 +BITMAP +F8 +00 +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR Ibreve.c2sc +ENCODING -1 +SWIDTH 239 0 +DWIDTH 4 0 +BBX 6 12 1 0 +BITMAP +4C +38 +00 +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR Iogonek.c2sc +ENCODING -1 +SWIDTH 239 0 +DWIDTH 4 0 +BBX 4 13 0 -4 +BITMAP +10 +30 +30 +20 +20 +60 +60 +60 +40 +40 +80 +80 +C0 +ENDCHAR +STARTCHAR Idotaccent.c2sc +ENCODING -1 +SWIDTH 239 0 +DWIDTH 4 0 +BBX 3 11 1 0 +BITMAP +60 +00 +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR IJ.c2sc +ENCODING -1 +SWIDTH 657 0 +DWIDTH 11 0 +BBX 11 9 1 0 +BITMAP +2060 +6040 +6040 +40C0 +40C0 +C080 +D880 +D980 +8F00 +ENDCHAR +STARTCHAR Jcircumflex.c2sc +ENCODING -1 +SWIDTH 431 0 +DWIDTH 7 0 +BBX 9 13 0 0 +BITMAP +0180 +0280 +0680 +0000 +0300 +0200 +0200 +0600 +0600 +0400 +C400 +CC00 +7800 +ENDCHAR +STARTCHAR uni0136.c2sc +ENCODING -1 +SWIDTH 566 0 +DWIDTH 10 0 +BBX 9 13 1 -4 +BITMAP +2180 +6300 +6C00 +5800 +7800 +CC00 +C600 +C600 +8300 +0000 +3800 +0800 +7000 +ENDCHAR +STARTCHAR Lacute.c2sc +ENCODING -1 +SWIDTH 466 0 +DWIDTH 8 0 +BBX 6 13 1 0 +BITMAP +18 +10 +20 +00 +20 +60 +60 +40 +40 +C0 +C0 +C0 +FC +ENDCHAR +STARTCHAR uni013B.c2sc +ENCODING -1 +SWIDTH 466 0 +DWIDTH 8 0 +BBX 6 13 1 -4 +BITMAP +20 +60 +60 +40 +40 +C0 +C0 +C0 +FC +00 +70 +10 +E0 +ENDCHAR +STARTCHAR Lcaron.c2sc +ENCODING -1 +SWIDTH 466 0 +DWIDTH 8 0 +BBX 7 9 1 0 +BITMAP +26 +62 +64 +48 +40 +C0 +C0 +C0 +FC +ENDCHAR +STARTCHAR Ldot.c2sc +ENCODING -1 +SWIDTH 466 0 +DWIDTH 8 0 +BBX 6 9 1 0 +BITMAP +20 +60 +60 +40 +4C +C0 +C0 +C0 +FC +ENDCHAR +STARTCHAR Nacute.c2sc +ENCODING -1 +SWIDTH 615 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +0300 +0200 +0400 +0000 +2080 +7080 +7080 +5980 +4980 +CD00 +C500 +8700 +8300 +ENDCHAR +STARTCHAR uni0145.c2sc +ENCODING -1 +SWIDTH 615 0 +DWIDTH 10 0 +BBX 9 13 1 -4 +BITMAP +2080 +7080 +7080 +5980 +4980 +CD00 +C500 +8700 +8300 +0000 +3800 +0800 +7000 +ENDCHAR +STARTCHAR Ncaron.c2sc +ENCODING -1 +SWIDTH 615 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +0D80 +0700 +0600 +0000 +2080 +7080 +7080 +5980 +4980 +CD00 +C500 +8700 +8300 +ENDCHAR +STARTCHAR Eng.c2sc +ENCODING -1 +SWIDTH 619 0 +DWIDTH 11 0 +BBX 9 9 1 0 +BITMAP +2F00 +7180 +6180 +4080 +4180 +C180 +C100 +C300 +9E00 +ENDCHAR +STARTCHAR Omacron.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 10 11 1 0 +BITMAP +0F80 +0000 +1F00 +3180 +60C0 +C0C0 +C0C0 +C080 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR Obreve.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 10 12 1 0 +BITMAP +0980 +0700 +0000 +1F00 +3180 +60C0 +C0C0 +C0C0 +C080 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR Ohungarumlaut.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 10 13 1 0 +BITMAP +0680 +0D80 +0900 +0000 +1F00 +3180 +60C0 +C0C0 +C0C0 +C080 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR Racute.c2sc +ENCODING -1 +SWIDTH 606 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +0300 +0200 +0400 +0000 +3F00 +6180 +6080 +4180 +7E00 +C600 +C200 +C300 +8100 +ENDCHAR +STARTCHAR uni0156.c2sc +ENCODING -1 +SWIDTH 606 0 +DWIDTH 10 0 +BBX 9 13 1 -4 +BITMAP +3F00 +6180 +6080 +4180 +7E00 +C600 +C200 +C300 +8100 +0000 +1C00 +0400 +3800 +ENDCHAR +STARTCHAR Rcaron.c2sc +ENCODING -1 +SWIDTH 606 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +1B00 +0E00 +0C00 +0000 +3F00 +6180 +6080 +4180 +7E00 +C600 +C200 +C300 +8100 +ENDCHAR +STARTCHAR Sacute.c2sc +ENCODING -1 +SWIDTH 553 0 +DWIDTH 9 0 +BBX 9 13 0 0 +BITMAP +0300 +0200 +0400 +0000 +1F00 +3180 +2180 +3000 +1E00 +0100 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR Scircumflex.c2sc +ENCODING -1 +SWIDTH 553 0 +DWIDTH 9 0 +BBX 9 13 0 0 +BITMAP +0300 +0500 +0D00 +0000 +1F00 +3180 +2180 +3000 +1E00 +0100 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR Scedilla.c2sc +ENCODING -1 +SWIDTH 553 0 +DWIDTH 9 0 +BBX 9 12 0 -3 +BITMAP +1F00 +3180 +2180 +3000 +1E00 +0100 +C180 +6300 +3E00 +1000 +0C00 +3800 +ENDCHAR +STARTCHAR Scaron.c2sc +ENCODING -1 +SWIDTH 553 0 +DWIDTH 9 0 +BBX 9 13 0 0 +BITMAP +0D80 +0700 +0600 +0000 +1F00 +3180 +2180 +3000 +1E00 +0100 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR uni0218.c2sc +ENCODING -1 +SWIDTH 553 0 +DWIDTH 9 0 +BBX 9 14 0 -5 +BITMAP +1F00 +3180 +2180 +3000 +1E00 +0100 +C180 +6300 +3E00 +0000 +1800 +0800 +1000 +2000 +ENDCHAR +STARTCHAR uni0162.c2sc +ENCODING -1 +SWIDTH 507 0 +DWIDTH 9 0 +BBX 8 12 2 -3 +BITMAP +FF +10 +30 +30 +20 +20 +60 +60 +60 +40 +30 +E0 +ENDCHAR +STARTCHAR glyph2699 +ENCODING -1 +SWIDTH 507 0 +DWIDTH 9 0 +BBX 9 14 1 -5 +BITMAP +7F80 +0800 +1800 +1800 +1000 +1000 +3000 +3000 +3000 +0000 +6000 +2000 +4000 +8000 +ENDCHAR +STARTCHAR Tcaron.c2sc +ENCODING -1 +SWIDTH 507 0 +DWIDTH 9 0 +BBX 8 13 2 0 +BITMAP +36 +1C +18 +00 +FF +10 +30 +30 +20 +20 +60 +60 +60 +ENDCHAR +STARTCHAR Tbar.c2sc +ENCODING -1 +SWIDTH 506 0 +DWIDTH 9 0 +BBX 8 9 2 0 +BITMAP +FF +30 +30 +30 +FC +20 +60 +60 +60 +ENDCHAR +STARTCHAR Utilde.c2sc +ENCODING -1 +SWIDTH 607 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +1D00 +1700 +0000 +6080 +6180 +4180 +4100 +C100 +C100 +C300 +C600 +7C00 +ENDCHAR +STARTCHAR Umacron.c2sc +ENCODING -1 +SWIDTH 607 0 +DWIDTH 10 0 +BBX 9 11 1 0 +BITMAP +1F00 +0000 +6080 +6180 +4180 +4100 +C100 +C100 +C300 +C600 +7C00 +ENDCHAR +STARTCHAR Ubreve.c2sc +ENCODING -1 +SWIDTH 607 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +1300 +0E00 +0000 +6080 +6180 +4180 +4100 +C100 +C100 +C300 +C600 +7C00 +ENDCHAR +STARTCHAR Uring.c2sc +ENCODING -1 +SWIDTH 607 0 +DWIDTH 10 0 +BBX 9 14 1 0 +BITMAP +0C00 +1200 +1200 +0C00 +0000 +6080 +6180 +4180 +4100 +C100 +C100 +C300 +C600 +7C00 +ENDCHAR +STARTCHAR Uhungarumlaut.c2sc +ENCODING -1 +SWIDTH 607 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +0680 +0D80 +0900 +0000 +6080 +6180 +4180 +4100 +C100 +C100 +C300 +C600 +7C00 +ENDCHAR +STARTCHAR Uogonek.c2sc +ENCODING -1 +SWIDTH 607 0 +DWIDTH 10 0 +BBX 9 13 1 -4 +BITMAP +6080 +6180 +4180 +4100 +C100 +C100 +C300 +C600 +7C00 +1000 +2000 +2000 +3000 +ENDCHAR +STARTCHAR Wcircumflex.c2sc +ENCODING -1 +SWIDTH 793 0 +DWIDTH 13 0 +BBX 13 13 1 0 +BITMAP +0180 +0280 +0680 +0000 +C308 +C518 +C510 +4930 +5920 +5160 +7140 +61C0 +6180 +ENDCHAR +STARTCHAR Wgrave.c2sc +ENCODING -1 +SWIDTH 793 0 +DWIDTH 13 0 +BBX 13 13 1 0 +BITMAP +0200 +0300 +0100 +0000 +C308 +C518 +C510 +4930 +5920 +5160 +7140 +61C0 +6180 +ENDCHAR +STARTCHAR Wacute.c2sc +ENCODING -1 +SWIDTH 793 0 +DWIDTH 13 0 +BBX 13 13 1 0 +BITMAP +0180 +0100 +0200 +0000 +C308 +C518 +C510 +4930 +5920 +5160 +7140 +61C0 +6180 +ENDCHAR +STARTCHAR Wdieresis.c2sc +ENCODING -1 +SWIDTH 793 0 +DWIDTH 13 0 +BBX 13 11 1 0 +BITMAP +06C0 +0000 +C308 +C518 +C510 +4930 +5920 +5160 +7140 +61C0 +6180 +ENDCHAR +STARTCHAR Ycircumflex.c2sc +ENCODING -1 +SWIDTH 552 0 +DWIDTH 9 0 +BBX 9 13 1 0 +BITMAP +0600 +0A00 +1A00 +0000 +C180 +6300 +6600 +3C00 +3800 +1000 +1000 +3000 +3000 +ENDCHAR +STARTCHAR Ydieresis.c2sc +ENCODING -1 +SWIDTH 552 0 +DWIDTH 9 0 +BBX 9 11 1 0 +BITMAP +1B00 +0000 +C180 +6300 +6600 +3C00 +3800 +1000 +1000 +3000 +3000 +ENDCHAR +STARTCHAR Ygrave.c2sc +ENCODING -1 +SWIDTH 552 0 +DWIDTH 9 0 +BBX 9 13 1 0 +BITMAP +1000 +1800 +0800 +0000 +C180 +6300 +6600 +3C00 +3800 +1000 +1000 +3000 +3000 +ENDCHAR +STARTCHAR Zacute.c2sc +ENCODING -1 +SWIDTH 506 0 +DWIDTH 9 0 +BBX 9 13 0 0 +BITMAP +0300 +0200 +0400 +0000 +3F80 +0100 +0200 +0400 +0800 +1000 +6000 +C000 +FF00 +ENDCHAR +STARTCHAR Zdotaccent.c2sc +ENCODING -1 +SWIDTH 506 0 +DWIDTH 9 0 +BBX 9 11 0 0 +BITMAP +0600 +0000 +3F80 +0100 +0200 +0400 +0800 +1000 +6000 +C000 +FF00 +ENDCHAR +STARTCHAR Zcaron.c2sc +ENCODING -1 +SWIDTH 506 0 +DWIDTH 9 0 +BBX 9 13 0 0 +BITMAP +0D80 +0700 +0600 +0000 +3F80 +0100 +0200 +0400 +0800 +1000 +6000 +C000 +FF00 +ENDCHAR +STARTCHAR Aringacute.c2sc +ENCODING -1 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 14 0 0 +BITMAP +0300 +0200 +0600 +0900 +0900 +0600 +0E00 +0A00 +1300 +3300 +3F00 +4100 +C180 +8180 +ENDCHAR +STARTCHAR AEacute.c2sc +ENCODING -1 +SWIDTH 820 0 +DWIDTH 14 0 +BBX 14 13 0 0 +BITMAP +0030 +0020 +0040 +0000 +03FC +0480 +0D80 +0980 +11F8 +3F00 +6100 +C300 +83F8 +ENDCHAR +STARTCHAR Oslashacute.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 11 13 0 0 +BITMAP +0180 +0100 +0200 +0000 +0FA0 +18E0 +30E0 +6360 +6660 +6860 +70C0 +7180 +9F00 +ENDCHAR +STARTCHAR Alpha.c2sc +ENCODING -1 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +0600 +0E00 +0A00 +1300 +3300 +3F00 +4100 +C180 +8180 +ENDCHAR +STARTCHAR Beta.c2sc +ENCODING -1 +SWIDTH 566 0 +DWIDTH 10 0 +BBX 8 9 1 0 +BITMAP +3E +61 +61 +43 +7C +C3 +C3 +C3 +FC +ENDCHAR +STARTCHAR Gamma.c2sc +ENCODING -1 +SWIDTH 459 0 +DWIDTH 8 0 +BBX 8 9 1 0 +BITMAP +3F +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR uni0394.c2sc +ENCODING -1 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +0600 +0E00 +0A00 +1B00 +3300 +2300 +6100 +C180 +FF80 +ENDCHAR +STARTCHAR Epsilon.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 9 9 1 0 +BITMAP +3F80 +6000 +6000 +4000 +7F00 +C000 +C000 +C000 +FE00 +ENDCHAR +STARTCHAR Zeta.c2sc +ENCODING -1 +SWIDTH 506 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +3F80 +0100 +0200 +0400 +0800 +1000 +6000 +C000 +FF00 +ENDCHAR +STARTCHAR Eta.c2sc +ENCODING -1 +SWIDTH 617 0 +DWIDTH 11 0 +BBX 9 9 1 0 +BITMAP +2080 +6080 +6080 +4180 +7F80 +C100 +C100 +C300 +8300 +ENDCHAR +STARTCHAR Theta.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 10 9 1 0 +BITMAP +1F00 +3180 +60C0 +C0C0 +DEC0 +C080 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR Iota.c2sc +ENCODING -1 +SWIDTH 239 0 +DWIDTH 4 0 +BBX 3 9 1 0 +BITMAP +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR Kappa.c2sc +ENCODING -1 +SWIDTH 566 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +2180 +6300 +6C00 +5800 +7800 +CC00 +C600 +C600 +8300 +ENDCHAR +STARTCHAR Lambda.c2sc +ENCODING -1 +SWIDTH 543 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +0600 +0E00 +0A00 +1B00 +3300 +2300 +6100 +C100 +8180 +ENDCHAR +STARTCHAR Mu.c2sc +ENCODING -1 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 9 1 0 +BITMAP +3060 +70E0 +70E0 +5160 +5140 +DA40 +CE40 +8CC0 +88C0 +ENDCHAR +STARTCHAR Nu.c2sc +ENCODING -1 +SWIDTH 615 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +2080 +7080 +7080 +5980 +4980 +CD00 +C500 +8700 +8300 +ENDCHAR +STARTCHAR Xi.c2sc +ENCODING -1 +SWIDTH 522 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +3F80 +0000 +0000 +0000 +3F00 +0000 +0000 +0000 +FF00 +ENDCHAR +STARTCHAR Omicron.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 10 9 1 0 +BITMAP +1F00 +3180 +60C0 +C0C0 +C0C0 +C080 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR Pi.c2sc +ENCODING -1 +SWIDTH 612 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +3F80 +6080 +6180 +4180 +4180 +C100 +C100 +8300 +8300 +ENDCHAR +STARTCHAR Rho.c2sc +ENCODING -1 +SWIDTH 553 0 +DWIDTH 9 0 +BBX 9 9 1 0 +BITMAP +3E00 +6100 +6180 +4180 +4300 +FE00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR Sigma.c2sc +ENCODING -1 +SWIDTH 518 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +7F +60 +30 +18 +18 +10 +20 +40 +FE +ENDCHAR +STARTCHAR Tau.c2sc +ENCODING -1 +SWIDTH 507 0 +DWIDTH 9 0 +BBX 8 9 2 0 +BITMAP +FF +10 +30 +30 +20 +20 +60 +60 +60 +ENDCHAR +STARTCHAR Upsilon.c2sc +ENCODING -1 +SWIDTH 552 0 +DWIDTH 9 0 +BBX 9 9 1 0 +BITMAP +C180 +6300 +6600 +3C00 +3800 +1000 +1000 +3000 +3000 +ENDCHAR +STARTCHAR Phi.c2sc +ENCODING -1 +SWIDTH 659 0 +DWIDTH 11 0 +BBX 10 9 1 0 +BITMAP +0400 +3F00 +6C80 +CCC0 +88C0 +8880 +C980 +7E00 +1800 +ENDCHAR +STARTCHAR Chi.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 10 9 0 0 +BITMAP +30C0 +3180 +1B00 +0E00 +0C00 +1C00 +3600 +4300 +8300 +ENDCHAR +STARTCHAR Psi.c2sc +ENCODING -1 +SWIDTH 657 0 +DWIDTH 11 0 +BBX 11 9 1 0 +BITMAP +4460 +C440 +CC40 +CCC0 +C980 +7F00 +1800 +1800 +1800 +ENDCHAR +STARTCHAR uni03A9.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 11 9 0 0 +BITMAP +0F80 +18C0 +3060 +2060 +6060 +6060 +20C0 +3180 +FBC0 +ENDCHAR +STARTCHAR Alphatonos.c2sc +ENCODING -1 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 13 0 0 +BITMAP +0300 +0200 +0400 +0000 +0600 +0E00 +0A00 +1300 +3300 +3F00 +4100 +C180 +8180 +ENDCHAR +STARTCHAR Epsilontonos.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 9 13 1 0 +BITMAP +0300 +0200 +0400 +0000 +3F80 +6000 +6000 +4000 +7F00 +C000 +C000 +C000 +FE00 +ENDCHAR +STARTCHAR Etatonos.c2sc +ENCODING -1 +SWIDTH 617 0 +DWIDTH 11 0 +BBX 9 13 1 0 +BITMAP +0300 +0200 +0400 +0000 +2080 +6080 +6080 +4180 +7F80 +C100 +C100 +C300 +8300 +ENDCHAR +STARTCHAR Iotatonos.c2sc +ENCODING -1 +SWIDTH 239 0 +DWIDTH 4 0 +BBX 5 13 1 0 +BITMAP +18 +10 +20 +00 +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR Omicrontonos.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 10 13 1 0 +BITMAP +0300 +0200 +0400 +0000 +1F00 +3180 +60C0 +C0C0 +C0C0 +C080 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR Upsilontonos.c2sc +ENCODING -1 +SWIDTH 552 0 +DWIDTH 9 0 +BBX 9 13 1 0 +BITMAP +0600 +0400 +0800 +0000 +C180 +6300 +6600 +3C00 +3800 +1000 +1000 +3000 +3000 +ENDCHAR +STARTCHAR Omegatonos.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 11 13 0 0 +BITMAP +0180 +0100 +0200 +0000 +0F80 +18C0 +3060 +2060 +6060 +6060 +20C0 +3180 +FBC0 +ENDCHAR +STARTCHAR Iotadieresis.c2sc +ENCODING -1 +SWIDTH 239 0 +DWIDTH 4 0 +BBX 5 11 1 0 +BITMAP +D8 +00 +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR Upsilondieresis.c2sc +ENCODING -1 +SWIDTH 552 0 +DWIDTH 9 0 +BBX 9 11 1 0 +BITMAP +1B00 +0000 +C180 +6300 +6600 +3C00 +3800 +1000 +1000 +3000 +3000 +ENDCHAR +STARTCHAR uni0401.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 9 11 1 0 +BITMAP +1B00 +0000 +3F80 +6000 +6000 +4000 +7F00 +C000 +C000 +C000 +FE00 +ENDCHAR +STARTCHAR uni0402.c2sc +ENCODING -1 +SWIDTH 710 0 +DWIDTH 12 0 +BBX 9 9 2 0 +BITMAP +FF00 +1000 +3000 +3F00 +3180 +2080 +6080 +6180 +6F00 +ENDCHAR +STARTCHAR uni0403.c2sc +ENCODING -1 +SWIDTH 459 0 +DWIDTH 8 0 +BBX 8 13 1 0 +BITMAP +06 +04 +08 +00 +3F +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR uni0404.c2sc +ENCODING -1 +SWIDTH 597 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +1F00 +3180 +6080 +C000 +F800 +C000 +C100 +4300 +3C00 +ENDCHAR +STARTCHAR uni0405.c2sc +ENCODING -1 +SWIDTH 553 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +1F00 +3180 +2180 +3000 +1E00 +0100 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR uni0406.c2sc +ENCODING -1 +SWIDTH 239 0 +DWIDTH 4 0 +BBX 3 9 1 0 +BITMAP +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR uni0407.c2sc +ENCODING -1 +SWIDTH 239 0 +DWIDTH 4 0 +BBX 5 11 1 0 +BITMAP +D8 +00 +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR uni0408.c2sc +ENCODING -1 +SWIDTH 431 0 +DWIDTH 7 0 +BBX 8 9 0 0 +BITMAP +03 +02 +02 +06 +06 +04 +C4 +CC +78 +ENDCHAR +STARTCHAR uni0409.c2sc +ENCODING -1 +SWIDTH 869 0 +DWIDTH 15 0 +BBX 14 9 0 0 +BITMAP +1FC0 +1880 +1080 +1180 +31F8 +3184 +2104 +210C +C3F8 +ENDCHAR +STARTCHAR uni040A.c2sc +ENCODING -1 +SWIDTH 838 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +2100 +6300 +6300 +4300 +7FF0 +C618 +C618 +C618 +87F0 +ENDCHAR +STARTCHAR uni040B.c2sc +ENCODING -1 +SWIDTH 731 0 +DWIDTH 12 0 +BBX 10 9 2 0 +BITMAP +FF00 +1800 +1800 +1F80 +10C0 +30C0 +30C0 +20C0 +2080 +ENDCHAR +STARTCHAR uni040C.c2sc +ENCODING -1 +SWIDTH 510 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +04 +08 +00 +23 +66 +6C +48 +70 +D8 +CC +CC +86 +ENDCHAR +STARTCHAR uni040E.c2sc +ENCODING -1 +SWIDTH 548 0 +DWIDTH 9 0 +BBX 9 12 1 0 +BITMAP +1300 +0E00 +0000 +4180 +6100 +2300 +2600 +3400 +1800 +1800 +3000 +E000 +ENDCHAR +STARTCHAR uni040F.c2sc +ENCODING -1 +SWIDTH 612 0 +DWIDTH 10 0 +BBX 9 12 1 -3 +BITMAP +2080 +6080 +6180 +4180 +4180 +C100 +C100 +C300 +FF00 +1000 +1000 +3000 +ENDCHAR +STARTCHAR uni0410.c2sc +ENCODING -1 +SWIDTH 555 0 +DWIDTH 9 0 +BBX 9 9 0 0 +BITMAP +0600 +0E00 +0A00 +1300 +3300 +3F00 +4100 +C180 +8180 +ENDCHAR +STARTCHAR uni0411.c2sc +ENCODING -1 +SWIDTH 565 0 +DWIDTH 10 0 +BBX 8 9 1 0 +BITMAP +3F +60 +60 +40 +7E +C3 +C3 +C3 +FE +ENDCHAR +STARTCHAR uni0412.c2sc +ENCODING -1 +SWIDTH 566 0 +DWIDTH 10 0 +BBX 8 9 1 0 +BITMAP +3E +61 +61 +43 +7C +C3 +C3 +C3 +FC +ENDCHAR +STARTCHAR uni0413.c2sc +ENCODING -1 +SWIDTH 459 0 +DWIDTH 8 0 +BBX 8 9 1 0 +BITMAP +3F +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR uni0414.c2sc +ENCODING -1 +SWIDTH 551 0 +DWIDTH 9 0 +BBX 11 11 -1 -2 +BITMAP +0FE0 +0C40 +08C0 +08C0 +18C0 +1080 +1080 +3180 +7FC0 +C080 +C080 +ENDCHAR +STARTCHAR uni0415.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 9 9 1 0 +BITMAP +3F80 +6000 +6000 +4000 +7F00 +C000 +C000 +C000 +FE00 +ENDCHAR +STARTCHAR uni0416.c2sc +ENCODING -1 +SWIDTH 791 0 +DWIDTH 13 0 +BBX 14 9 0 0 +BITMAP +318C +1990 +1930 +0960 +0FC0 +1B60 +3220 +6230 +C630 +ENDCHAR +STARTCHAR uni0417.c2sc +ENCODING -1 +SWIDTH 515 0 +DWIDTH 9 0 +BBX 7 9 1 0 +BITMAP +3E +62 +42 +06 +1C +06 +86 +C6 +7C +ENDCHAR +STARTCHAR uni0418.c2sc +ENCODING -1 +SWIDTH 611 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +2080 +6180 +4380 +4580 +4980 +D100 +E100 +E300 +C300 +ENDCHAR +STARTCHAR uni0419.c2sc +ENCODING -1 +SWIDTH 611 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +0980 +0700 +0000 +2080 +6180 +4380 +4580 +4980 +D100 +E100 +E300 +C300 +ENDCHAR +STARTCHAR uni041A.c2sc +ENCODING -1 +SWIDTH 510 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +23 +66 +6C +48 +70 +D8 +CC +CC +86 +ENDCHAR +STARTCHAR uni041B.c2sc +ENCODING -1 +SWIDTH 566 0 +DWIDTH 10 0 +BBX 10 9 0 0 +BITMAP +1FC0 +1880 +1080 +1180 +3180 +3180 +2100 +2100 +C300 +ENDCHAR +STARTCHAR uni041C.c2sc +ENCODING -1 +SWIDTH 722 0 +DWIDTH 12 0 +BBX 11 9 1 0 +BITMAP +3060 +70E0 +70E0 +5160 +5140 +DA40 +CE40 +8CC0 +88C0 +ENDCHAR +STARTCHAR uni041D.c2sc +ENCODING -1 +SWIDTH 617 0 +DWIDTH 11 0 +BBX 9 9 1 0 +BITMAP +2080 +6080 +6080 +4180 +7F80 +C100 +C100 +C300 +8300 +ENDCHAR +STARTCHAR uni041E.c2sc +ENCODING -1 +SWIDTH 648 0 +DWIDTH 11 0 +BBX 10 9 1 0 +BITMAP +1F00 +3180 +60C0 +C0C0 +C0C0 +C080 +C180 +6300 +3E00 +ENDCHAR +STARTCHAR uni041F.c2sc +ENCODING -1 +SWIDTH 612 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +3F80 +6080 +6180 +4180 +4180 +C100 +C100 +8300 +8300 +ENDCHAR +STARTCHAR uni0420.c2sc +ENCODING -1 +SWIDTH 553 0 +DWIDTH 9 0 +BBX 9 9 1 0 +BITMAP +3E00 +6100 +6180 +4180 +4300 +FE00 +C000 +C000 +8000 +ENDCHAR +STARTCHAR uni0421.c2sc +ENCODING -1 +SWIDTH 595 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +1F00 +3180 +6080 +C000 +C000 +C000 +C100 +4300 +3C00 +ENDCHAR +STARTCHAR uni0422.c2sc +ENCODING -1 +SWIDTH 507 0 +DWIDTH 9 0 +BBX 8 9 2 0 +BITMAP +FF +10 +30 +30 +20 +20 +60 +60 +60 +ENDCHAR +STARTCHAR uni0423.c2sc +ENCODING -1 +SWIDTH 548 0 +DWIDTH 9 0 +BBX 9 9 1 0 +BITMAP +4180 +6100 +2300 +2600 +3400 +1800 +1800 +3000 +E000 +ENDCHAR +STARTCHAR uni0424.c2sc +ENCODING -1 +SWIDTH 631 0 +DWIDTH 11 0 +BBX 10 9 1 0 +BITMAP +0400 +3F00 +6D80 +CC80 +C8C0 +C880 +C980 +7E00 +1800 +ENDCHAR +STARTCHAR uni0425.c2sc +ENCODING -1 +SWIDTH 554 0 +DWIDTH 9 0 +BBX 10 9 0 0 +BITMAP +30C0 +3180 +1B00 +0E00 +0C00 +1C00 +3600 +4300 +8300 +ENDCHAR +STARTCHAR uni0426.c2sc +ENCODING -1 +SWIDTH 607 0 +DWIDTH 10 0 +BBX 9 12 1 -3 +BITMAP +2080 +6080 +6180 +4180 +4180 +C100 +C100 +C300 +FF80 +0100 +0100 +0100 +ENDCHAR +STARTCHAR uni0427.c2sc +ENCODING -1 +SWIDTH 561 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +4180 +4100 +C100 +C300 +C300 +7E00 +0200 +0600 +0600 +ENDCHAR +STARTCHAR uni0428.c2sc +ENCODING -1 +SWIDTH 769 0 +DWIDTH 13 0 +BBX 12 9 1 0 +BITMAP +2310 +6230 +6230 +4620 +4620 +C460 +C460 +C460 +FFC0 +ENDCHAR +STARTCHAR uni0429.c2sc +ENCODING -1 +SWIDTH 764 0 +DWIDTH 13 0 +BBX 12 12 1 -3 +BITMAP +2310 +6230 +6230 +4620 +4620 +C460 +C460 +C460 +FFE0 +0020 +0060 +0060 +ENDCHAR +STARTCHAR uni042A.c2sc +ENCODING -1 +SWIDTH 676 0 +DWIDTH 12 0 +BBX 9 9 2 0 +BITMAP +F000 +1000 +3000 +3000 +3F00 +2180 +6180 +6180 +7F00 +ENDCHAR +STARTCHAR uni042B.c2sc +ENCODING -1 +SWIDTH 737 0 +DWIDTH 13 0 +BBX 12 9 1 0 +BITMAP +2030 +6020 +6020 +4060 +7E60 +C340 +C340 +C240 +FCC0 +ENDCHAR +STARTCHAR uni042C.c2sc +ENCODING -1 +SWIDTH 541 0 +DWIDTH 9 0 +BBX 8 9 1 0 +BITMAP +20 +60 +60 +40 +7E +C3 +C3 +C3 +FC +ENDCHAR +STARTCHAR uni042D.c2sc +ENCODING -1 +SWIDTH 596 0 +DWIDTH 10 0 +BBX 9 9 1 0 +BITMAP +1E00 +6100 +4180 +0180 +0F80 +0180 +8300 +C600 +7C00 +ENDCHAR +STARTCHAR uni042E.c2sc +ENCODING -1 +SWIDTH 835 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +21E0 +6610 +6C18 +4C18 +7818 +C818 +C830 +8C60 +83C0 +ENDCHAR +STARTCHAR uni042F.c2sc +ENCODING -1 +SWIDTH 606 0 +DWIDTH 10 0 +BBX 10 9 0 0 +BITMAP +1FC0 +3040 +20C0 +30C0 +1F80 +1880 +3180 +6180 +C180 +ENDCHAR +STARTCHAR uni0490.c2sc +ENCODING -1 +SWIDTH 392 0 +DWIDTH 7 0 +BBX 8 12 1 0 +BITMAP +03 +02 +02 +3E +60 +60 +40 +40 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR zero.dnom +ENCODING -1 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 6 0 0 +BITMAP +38 +4C +4C +C8 +C8 +70 +ENDCHAR +STARTCHAR one.dnom +ENCODING -1 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 6 1 0 +BITMAP +10 +30 +E0 +20 +20 +20 +ENDCHAR +STARTCHAR two.dnom +ENCODING -1 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 6 0 0 +BITMAP +38 +44 +0C +30 +60 +F8 +ENDCHAR +STARTCHAR three.dnom +ENCODING -1 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 6 1 0 +BITMAP +70 +C8 +30 +10 +90 +F0 +ENDCHAR +STARTCHAR four.dnom +ENCODING -1 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 6 0 0 +BITMAP +0C +18 +28 +48 +FC +18 +ENDCHAR +STARTCHAR five.dnom +ENCODING -1 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 6 0 0 +BITMAP +7C +40 +78 +08 +C8 +70 +ENDCHAR +STARTCHAR six.dnom +ENCODING -1 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 6 0 0 +BITMAP +38 +40 +78 +C8 +C8 +70 +ENDCHAR +STARTCHAR seven.dnom +ENCODING -1 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 6 1 0 +BITMAP +F0 +10 +20 +40 +40 +80 +ENDCHAR +STARTCHAR eight.dnom +ENCODING -1 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 6 0 0 +BITMAP +38 +4C +30 +48 +C8 +78 +ENDCHAR +STARTCHAR nine.dnom +ENCODING -1 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 6 1 0 +BITMAP +70 +98 +98 +F0 +10 +E0 +ENDCHAR +STARTCHAR agrave.unic +ENCODING -1 +SWIDTH 721 0 +DWIDTH 12 0 +BBX 11 16 1 0 +BITMAP +0200 +0300 +0100 +0000 +0FC0 +3060 +2060 +0060 +00E0 +1F60 +6040 +C040 +C0C0 +C0C0 +C3C0 +7CC0 +ENDCHAR +STARTCHAR aacute.unic +ENCODING -1 +SWIDTH 721 0 +DWIDTH 12 0 +BBX 11 16 1 0 +BITMAP +00C0 +0080 +0100 +0000 +0FC0 +3060 +2060 +0060 +00E0 +1F60 +6040 +C040 +C0C0 +C0C0 +C3C0 +7CC0 +ENDCHAR +STARTCHAR acircumflex.unic +ENCODING -1 +SWIDTH 721 0 +DWIDTH 12 0 +BBX 11 16 1 0 +BITMAP +0180 +0280 +0680 +0000 +0FC0 +3060 +2060 +0060 +00E0 +1F60 +6040 +C040 +C0C0 +C0C0 +C3C0 +7CC0 +ENDCHAR +STARTCHAR atilde.unic +ENCODING -1 +SWIDTH 721 0 +DWIDTH 12 0 +BBX 11 15 1 0 +BITMAP +0740 +05C0 +0000 +0FC0 +3060 +2060 +0060 +00E0 +1F60 +6040 +C040 +C0C0 +C0C0 +C3C0 +7CC0 +ENDCHAR +STARTCHAR Adieresis.unic +ENCODING -1 +SWIDTH 721 0 +DWIDTH 12 0 +BBX 11 14 1 0 +BITMAP +06C0 +0000 +0FC0 +3060 +2060 +0060 +00E0 +1F60 +6040 +C040 +C0C0 +C0C0 +C3C0 +7CC0 +ENDCHAR +STARTCHAR Aring.unic +ENCODING -1 +SWIDTH 721 0 +DWIDTH 12 0 +BBX 11 17 1 0 +BITMAP +0300 +0480 +0480 +0300 +0000 +0FC0 +3060 +2060 +0060 +00E0 +1F60 +6040 +C040 +C0C0 +C0C0 +C3C0 +7CC0 +ENDCHAR +STARTCHAR Amacron.unic +ENCODING -1 +SWIDTH 721 0 +DWIDTH 12 0 +BBX 11 14 1 0 +BITMAP +07C0 +0000 +0FC0 +3060 +2060 +0060 +00E0 +1F60 +6040 +C040 +C0C0 +C0C0 +C3C0 +7CC0 +ENDCHAR +STARTCHAR Abreve.unic +ENCODING -1 +SWIDTH 721 0 +DWIDTH 12 0 +BBX 11 15 1 0 +BITMAP +04C0 +0380 +0000 +0FC0 +3060 +2060 +0060 +00E0 +1F60 +6040 +C040 +C0C0 +C0C0 +C3C0 +7CC0 +ENDCHAR +STARTCHAR Aogonek.unic +ENCODING -1 +SWIDTH 721 0 +DWIDTH 12 0 +BBX 11 16 1 -4 +BITMAP +0FC0 +3060 +2060 +0060 +00E0 +1F60 +6040 +C040 +C0C0 +C0C0 +C3C0 +7CC0 +0080 +0100 +0100 +0180 +ENDCHAR +STARTCHAR Aringacute.unic +ENCODING -1 +SWIDTH 721 0 +DWIDTH 12 0 +BBX 11 17 1 0 +BITMAP +00C0 +0080 +0300 +0480 +0480 +0FC0 +3060 +2060 +0060 +00E0 +1F60 +6040 +C040 +C0C0 +C0C0 +C3C0 +7CC0 +ENDCHAR +STARTCHAR glyph2824 +ENCODING -1 +SWIDTH 721 0 +DWIDTH 12 0 +BBX 11 12 1 0 +BITMAP +0FC0 +3060 +2060 +0060 +00E0 +1F60 +6040 +C040 +C0C0 +C0C0 +C3C0 +7CC0 +ENDCHAR +STARTCHAR egrave.unic +ENCODING -1 +SWIDTH 755 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0400 +0600 +0200 +0000 +0F80 +30C0 +6040 +C060 +C060 +FFC0 +8000 +8000 +80C0 +C080 +6300 +3E00 +ENDCHAR +STARTCHAR Eacute.unic +ENCODING -1 +SWIDTH 755 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0180 +0100 +0200 +0000 +0F80 +30C0 +6040 +C060 +C060 +FFC0 +8000 +8000 +80C0 +C080 +6300 +3E00 +ENDCHAR +STARTCHAR ecircumflex.unic +ENCODING -1 +SWIDTH 755 0 +DWIDTH 13 0 +BBX 11 16 2 0 +BITMAP +0300 +0500 +0D00 +0000 +0F80 +30C0 +6040 +C060 +C060 +FFC0 +8000 +8000 +80C0 +C080 +6300 +3E00 +ENDCHAR +STARTCHAR edieresis.unic +ENCODING -1 +SWIDTH 755 0 +DWIDTH 13 0 +BBX 11 14 2 0 +BITMAP +0D80 +0000 +0F80 +30C0 +6040 +C060 +C060 +FFC0 +8000 +8000 +80C0 +C080 +6300 +3E00 +ENDCHAR +STARTCHAR Emacron.unic +ENCODING -1 +SWIDTH 755 0 +DWIDTH 13 0 +BBX 11 14 2 0 +BITMAP +0F80 +0000 +0F80 +30C0 +6040 +C060 +C060 +FFC0 +8000 +8000 +80C0 +C080 +6300 +3E00 +ENDCHAR +STARTCHAR Ebreve.unic +ENCODING -1 +SWIDTH 755 0 +DWIDTH 13 0 +BBX 11 15 2 0 +BITMAP +0980 +0700 +0000 +0F80 +30C0 +6040 +C060 +C060 +FFC0 +8000 +8000 +80C0 +C080 +6300 +3E00 +ENDCHAR +STARTCHAR Edotaccent.unic +ENCODING -1 +SWIDTH 755 0 +DWIDTH 13 0 +BBX 11 14 2 0 +BITMAP +0600 +0000 +0F80 +30C0 +6040 +C060 +C060 +FFC0 +8000 +8000 +80C0 +C080 +6300 +3E00 +ENDCHAR +STARTCHAR Eogonek.unic +ENCODING -1 +SWIDTH 755 0 +DWIDTH 13 0 +BBX 11 16 2 -4 +BITMAP +0F80 +30C0 +6040 +C060 +C060 +FFC0 +8000 +8000 +80C0 +C080 +6300 +3E00 +0400 +0800 +0800 +0C00 +ENDCHAR +STARTCHAR Ecaron.unic +ENCODING -1 +SWIDTH 755 0 +DWIDTH 13 0 +BBX 11 15 2 0 +BITMAP +0980 +0700 +0000 +0F80 +30C0 +6040 +C060 +C060 +FFC0 +8000 +8000 +80C0 +C080 +6300 +3E00 +ENDCHAR +STARTCHAR glyph2834 +ENCODING -1 +SWIDTH 755 0 +DWIDTH 13 0 +BBX 11 12 2 0 +BITMAP +0F80 +30C0 +6040 +C060 +C060 +FFC0 +8000 +8000 +80C0 +C080 +6300 +3E00 +ENDCHAR +STARTCHAR glyph2835 +ENCODING -1 +SWIDTH 755 0 +DWIDTH 13 0 +BBX 11 14 2 0 +BITMAP +0D80 +0000 +0F80 +30C0 +6040 +C060 +C060 +FFC0 +8000 +8000 +80C0 +C080 +6300 +3E00 +ENDCHAR +STARTCHAR Ntilde.unic +ENCODING -1 +SWIDTH 746 0 +DWIDTH 13 0 +BBX 11 15 1 0 +BITMAP +0740 +05C0 +0000 +37C0 +3860 +3020 +2020 +6020 +6060 +4060 +4060 +C040 +C040 +C0C0 +80C0 +ENDCHAR +STARTCHAR Nacute.unic +ENCODING -1 +SWIDTH 746 0 +DWIDTH 13 0 +BBX 11 16 1 0 +BITMAP +00C0 +0080 +0100 +0000 +37C0 +3860 +3020 +2020 +6020 +6060 +4060 +4060 +C040 +C040 +C0C0 +80C0 +ENDCHAR +STARTCHAR uni0145.unic +ENCODING -1 +SWIDTH 746 0 +DWIDTH 13 0 +BBX 11 16 1 -4 +BITMAP +37C0 +3860 +3020 +2020 +6020 +6060 +4060 +4060 +C040 +C040 +C0C0 +80C0 +0000 +1C00 +0400 +3800 +ENDCHAR +STARTCHAR Ncaron.unic +ENCODING -1 +SWIDTH 746 0 +DWIDTH 13 0 +BBX 11 16 1 0 +BITMAP +0360 +01C0 +0180 +0000 +37C0 +3860 +3020 +2020 +6020 +6060 +4060 +4060 +C040 +C040 +C0C0 +80C0 +ENDCHAR +STARTCHAR ugrave.unic +ENCODING -1 +SWIDTH 746 0 +DWIDTH 13 0 +BBX 12 16 1 0 +BITMAP +0200 +0300 +0100 +0000 +3030 +3030 +2030 +6020 +6020 +6060 +4060 +4060 +C040 +40C0 +61C0 +3EC0 +ENDCHAR +STARTCHAR uacute.unic +ENCODING -1 +SWIDTH 746 0 +DWIDTH 13 0 +BBX 12 16 1 0 +BITMAP +00C0 +0080 +0100 +0000 +3030 +3030 +2030 +6020 +6020 +6060 +4060 +4060 +C040 +40C0 +61C0 +3EC0 +ENDCHAR +STARTCHAR Udieresis.unic +ENCODING -1 +SWIDTH 746 0 +DWIDTH 13 0 +BBX 12 14 1 0 +BITMAP +06C0 +0000 +3030 +3030 +2030 +6020 +6020 +6060 +4060 +4060 +C040 +40C0 +61C0 +3EC0 +ENDCHAR +STARTCHAR Utilde.unic +ENCODING -1 +SWIDTH 746 0 +DWIDTH 13 0 +BBX 12 15 1 0 +BITMAP +0740 +05C0 +0000 +3030 +3030 +2030 +6020 +6020 +6060 +4060 +4060 +C040 +40C0 +61C0 +3EC0 +ENDCHAR +STARTCHAR Umacron.unic +ENCODING -1 +SWIDTH 746 0 +DWIDTH 13 0 +BBX 12 14 1 0 +BITMAP +07C0 +0000 +3030 +3030 +2030 +6020 +6020 +6060 +4060 +4060 +C040 +40C0 +61C0 +3EC0 +ENDCHAR +STARTCHAR Ubreve.unic +ENCODING -1 +SWIDTH 746 0 +DWIDTH 13 0 +BBX 12 15 1 0 +BITMAP +04C0 +0380 +0000 +3030 +3030 +2030 +6020 +6020 +6060 +4060 +4060 +C040 +40C0 +61C0 +3EC0 +ENDCHAR +STARTCHAR Uring.unic +ENCODING -1 +SWIDTH 746 0 +DWIDTH 13 0 +BBX 12 17 1 0 +BITMAP +0300 +0480 +0480 +0300 +0000 +3030 +3030 +2030 +6020 +6020 +6060 +4060 +4060 +C040 +40C0 +61C0 +3EC0 +ENDCHAR +STARTCHAR Uhungarumlaut.unic +ENCODING -1 +SWIDTH 746 0 +DWIDTH 13 0 +BBX 12 16 1 0 +BITMAP +0340 +06C0 +0480 +0000 +3030 +3030 +2030 +6020 +6020 +6060 +4060 +4060 +C040 +40C0 +61C0 +3EC0 +ENDCHAR +STARTCHAR Uogonek.unic +ENCODING -1 +SWIDTH 746 0 +DWIDTH 13 0 +BBX 12 16 1 -4 +BITMAP +3030 +3030 +2030 +6020 +6020 +6060 +4060 +4060 +C040 +40C0 +61C0 +3EC0 +0080 +0100 +0100 +0180 +ENDCHAR +STARTCHAR Igrave.ss01 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 16 0 0 +BITMAP +08 +0C +04 +00 +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR Iacute.ss01 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 16 0 0 +BITMAP +06 +04 +08 +00 +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR Icircumflex.ss01 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 16 0 0 +BITMAP +06 +0A +1A +00 +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR Idieresis.ss01 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 14 0 0 +BITMAP +1B +00 +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR Itilde.ss01 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 15 0 0 +BITMAP +1D +17 +00 +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR Ibreve.ss01 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 15 0 0 +BITMAP +13 +0E +00 +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR Iogonek.ss01 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 16 0 -4 +BITMAP +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +20 +40 +40 +60 +ENDCHAR +STARTCHAR Idotaccent.ss01 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 14 0 0 +BITMAP +0C +00 +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR Iota.ss01 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 12 0 0 +BITMAP +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR Iotatonos.ss01 +ENCODING -1 +SWIDTH 481 0 +DWIDTH 8 0 +BBX 10 12 0 0 +BITMAP +6FC0 +4300 +8200 +0200 +0600 +0600 +0600 +0400 +0400 +0C00 +0C00 +3E00 +ENDCHAR +STARTCHAR Iotadieresis.ss01 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 14 0 0 +BITMAP +1B +00 +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR uni0406.ss01 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 12 0 0 +BITMAP +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR uni0407.ss01 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 14 0 0 +BITMAP +1B +00 +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR lacute.ss01 +ENCODING -1 +SWIDTH 254 0 +DWIDTH 4 0 +BBX 5 16 1 0 +BITMAP +18 +10 +20 +00 +20 +20 +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +E0 +ENDCHAR +STARTCHAR uni013C.ss01 +ENCODING -1 +SWIDTH 254 0 +DWIDTH 4 0 +BBX 4 16 0 -4 +BITMAP +10 +10 +10 +30 +30 +20 +20 +60 +60 +60 +40 +70 +00 +70 +10 +E0 +ENDCHAR +STARTCHAR lcaron.ss01 +ENCODING -1 +SWIDTH 292 0 +DWIDTH 5 0 +BBX 6 12 1 0 +BITMAP +2C +28 +28 +70 +60 +40 +40 +C0 +C0 +C0 +80 +E0 +ENDCHAR +STARTCHAR ldot.ss01 +ENCODING -1 +SWIDTH 330 0 +DWIDTH 6 0 +BBX 5 12 1 0 +BITMAP +20 +20 +20 +60 +60 +40 +40 +D8 +C0 +C0 +80 +E0 +ENDCHAR +STARTCHAR lslash.ss01 +ENCODING -1 +SWIDTH 254 0 +DWIDTH 4 0 +BBX 5 12 0 0 +BITMAP +10 +10 +10 +30 +38 +30 +60 +E0 +60 +60 +40 +70 +ENDCHAR +STARTCHAR Igrave.ss03 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 16 0 0 +BITMAP +08 +0C +04 +00 +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR Iacute.ss03 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 16 0 0 +BITMAP +06 +04 +08 +00 +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR Icircumflex.ss03 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 16 0 0 +BITMAP +06 +0A +1A +00 +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR Idieresis.ss03 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 14 0 0 +BITMAP +1B +00 +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR Itilde.ss03 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 15 0 0 +BITMAP +1D +17 +00 +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR Ibreve.ss03 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 15 0 0 +BITMAP +13 +0E +00 +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR Iogonek.ss03 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 16 0 -4 +BITMAP +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +20 +40 +40 +60 +ENDCHAR +STARTCHAR Idotaccent.ss03 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 14 0 0 +BITMAP +0C +00 +3F +0C +08 +08 +18 +18 +18 +10 +10 +30 +30 +F8 +ENDCHAR +STARTCHAR uni0136.ss03 +ENCODING -1 +SWIDTH 656 0 +DWIDTH 11 0 +BBX 11 16 1 -4 +BITMAP +3060 +30C0 +2180 +2300 +6E00 +7800 +7800 +4C00 +C600 +C300 +C300 +8180 +0000 +1C00 +0400 +3800 +ENDCHAR +STARTCHAR agrave.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +08 +0C +04 +00 +3D +63 +43 +C3 +83 +82 +C6 +C6 +7E +ENDCHAR +STARTCHAR aacute.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +04 +08 +00 +3D +63 +43 +C3 +83 +82 +C6 +C6 +7E +ENDCHAR +STARTCHAR acircumflex.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 0 +BITMAP +06 +0A +1A +00 +3D +63 +43 +C3 +83 +82 +C6 +C6 +7E +ENDCHAR +STARTCHAR atilde.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +1D +17 +00 +3D +63 +43 +C3 +83 +82 +C6 +C6 +7E +ENDCHAR +STARTCHAR adieresis.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1B +00 +3D +63 +43 +C3 +83 +82 +C6 +C6 +7E +ENDCHAR +STARTCHAR aring.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +0C +12 +12 +0C +00 +3D +63 +43 +C3 +83 +82 +C6 +C6 +7E +ENDCHAR +STARTCHAR amacron.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 11 1 0 +BITMAP +1F +00 +3D +63 +43 +C3 +83 +82 +C6 +C6 +7E +ENDCHAR +STARTCHAR abreve.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 12 1 0 +BITMAP +13 +0E +00 +3D +63 +43 +C3 +83 +82 +C6 +C6 +7E +ENDCHAR +STARTCHAR aogonek.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 8 13 1 -4 +BITMAP +3D +63 +43 +C3 +83 +82 +C6 +C6 +7E +04 +08 +08 +0C +ENDCHAR +STARTCHAR jcircumflex.ss03 +ENCODING -1 +SWIDTH 222 0 +DWIDTH 4 0 +BBX 5 15 0 -3 +BITMAP +38 +68 +00 +30 +30 +20 +20 +60 +60 +40 +40 +40 +C0 +C0 +80 +ENDCHAR +STARTCHAR uni0137.ss03 +ENCODING -1 +SWIDTH 496 0 +DWIDTH 8 0 +BBX 8 16 1 -4 +BITMAP +30 +20 +20 +63 +66 +4C +58 +70 +D0 +D8 +8C +86 +00 +38 +08 +70 +ENDCHAR +STARTCHAR lacute.ss03 +ENCODING -1 +SWIDTH 254 0 +DWIDTH 4 0 +BBX 5 16 1 0 +BITMAP +18 +10 +20 +00 +20 +20 +20 +60 +60 +40 +40 +C0 +C0 +C0 +80 +E0 +ENDCHAR +STARTCHAR uni013C.ss03 +ENCODING -1 +SWIDTH 254 0 +DWIDTH 4 0 +BBX 4 16 0 -4 +BITMAP +10 +10 +10 +30 +30 +20 +20 +60 +60 +60 +40 +70 +00 +70 +10 +E0 +ENDCHAR +STARTCHAR lcaron.ss03 +ENCODING -1 +SWIDTH 301 0 +DWIDTH 5 0 +BBX 6 12 1 0 +BITMAP +2C +28 +28 +70 +60 +40 +40 +C0 +C0 +C0 +80 +E0 +ENDCHAR +STARTCHAR ldot.ss03 +ENCODING -1 +SWIDTH 330 0 +DWIDTH 6 0 +BBX 5 12 1 0 +BITMAP +20 +20 +20 +60 +60 +40 +40 +D8 +C0 +C0 +80 +E0 +ENDCHAR +STARTCHAR lslash.ss03 +ENCODING -1 +SWIDTH 254 0 +DWIDTH 4 0 +BBX 5 12 0 0 +BITMAP +10 +10 +10 +30 +38 +30 +60 +E0 +60 +60 +40 +70 +ENDCHAR +STARTCHAR uni0163.ss03 +ENCODING -1 +SWIDTH 289 0 +DWIDTH 5 0 +BBX 6 14 0 -3 +BITMAP +18 +18 +7C +10 +30 +30 +20 +20 +20 +60 +60 +40 +30 +E0 +ENDCHAR +STARTCHAR uni021B.ss03 +ENCODING -1 +SWIDTH 289 0 +DWIDTH 5 0 +BBX 7 15 -1 -4 +BITMAP +0C +0C +3E +08 +18 +18 +10 +10 +10 +30 +30 +00 +70 +10 +E0 +ENDCHAR +STARTCHAR tcaron.ss03 +ENCODING -1 +SWIDTH 375 0 +DWIDTH 6 0 +BBX 8 13 1 0 +BITMAP +03 +02 +32 +34 +F8 +20 +60 +60 +40 +40 +40 +C0 +C0 +ENDCHAR +STARTCHAR tbar.ss03 +ENCODING -1 +SWIDTH 289 0 +DWIDTH 5 0 +BBX 5 11 1 0 +BITMAP +30 +30 +F8 +20 +60 +60 +F0 +40 +40 +C0 +C0 +ENDCHAR +STARTCHAR yacute.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0300 +0200 +0400 +0000 +3080 +3080 +2180 +2180 +6100 +6100 +6300 +6500 +3B00 +0200 +C600 +7C00 +ENDCHAR +STARTCHAR ycircumflex.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0300 +0500 +0D00 +0000 +3080 +3080 +2180 +2180 +6100 +6100 +6300 +6500 +3B00 +0200 +C600 +7C00 +ENDCHAR +STARTCHAR ydieresis.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 14 0 -3 +BITMAP +0D80 +0000 +3080 +3080 +2180 +2180 +6100 +6100 +6300 +6500 +3B00 +0200 +C600 +7C00 +ENDCHAR +STARTCHAR ygrave.ss03 +ENCODING -1 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 16 0 -3 +BITMAP +0800 +0C00 +0400 +0000 +3080 +3080 +2180 +2180 +6100 +6100 +6300 +6500 +3B00 +0200 +C600 +7C00 +ENDCHAR +STARTCHAR ampersand.c2sc +ENCODING -1 +SWIDTH 578 0 +DWIDTH 10 0 +BBX 8 9 1 0 +BITMAP +1E +32 +26 +3C +38 +C9 +8E +8E +FB +ENDCHAR +STARTCHAR glyph2951 +ENCODING -1 +SWIDTH 277 0 +DWIDTH 5 0 +BBX 4 13 0 -4 +BITMAP +10 +10 +30 +30 +20 +20 +20 +60 +60 +40 +80 +80 +C0 +ENDCHAR +STARTCHAR uni05D2_uni05BF.ccmp +ENCODING -1 +SWIDTH 398 0 +DWIDTH 7 0 +BBX 6 10 0 0 +BITMAP +1C +3C +0C +0C +0C +0C +0C +38 +68 +CC +ENDCHAR +STARTCHAR uni05D3_uni05BF.ccmp +ENCODING -1 +SWIDTH 508 0 +DWIDTH 9 0 +BBX 8 10 1 0 +BITMAP +1C +FF +06 +04 +04 +0C +0C +0C +08 +08 +ENDCHAR +STARTCHAR uni05D4_uni05BF.ccmp +ENCODING -1 +SWIDTH 602 0 +DWIDTH 10 0 +BBX 9 10 1 0 +BITMAP +0E00 +7E00 +0300 +0180 +0180 +4100 +C100 +C300 +C300 +8300 +ENDCHAR +STARTCHAR uni05EA_uni05BF.ccmp +ENCODING -1 +SWIDTH 642 0 +DWIDTH 11 0 +BBX 10 10 0 0 +BITMAP +0700 +3F80 +18C0 +1840 +1840 +10C0 +10C0 +30C0 +3080 +E080 +ENDCHAR +STARTCHAR uni0307.ccmp +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 2 1 9 +BITMAP +80 +80 +ENDCHAR +STARTCHAR uni0307_uni0307.ccmp +ENCODING -1 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 2 0 9 +BITMAP +A0 +A0 +ENDCHAR +ENDFONT diff --git a/Fruit_Jam/Fruit_Jam_Quotes/quote_background.bmp b/Fruit_Jam/Fruit_Jam_Quotes/quote_background.bmp new file mode 100644 index 000000000..7715e9f23 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Quotes/quote_background.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/aws_polly.py b/Fruit_Jam/Fruit_Jam_Spell_Jam/aws_polly.py new file mode 100644 index 000000000..d86901aa0 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Spell_Jam/aws_polly.py @@ -0,0 +1,295 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +import hmac +import json + +from adafruit_datetime import datetime +import adafruit_hashlib as hashlib + + +def url_encode(string, safe=""): + """ + Minimal URL encoding function to replace urllib.parse.quote + + Args: + string (str): String to encode + safe (str): Characters that should not be encoded + + Returns: + str: URL encoded string + """ + # Characters that need to be encoded (RFC 3986) + unreserved = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~" + + # Add safe characters to unreserved set + allowed = unreserved + safe + + encoded = "" + for char in string: + if char in allowed: + encoded += char + else: + # Convert to percent-encoded format + encoded += f"%{ord(char):02X}" + + return encoded + + +def _zero_pad(num, count=2): + padded = str(num) + while len(padded) < count: + padded = "0" + padded + return padded + + +class PollyHTTPClient: + # pylint: disable=no-self-use + def __init__(self, requests_instance, access_key, secret_key, region="us-east-1"): + self._requests = requests_instance + self.access_key = access_key + self.secret_key = secret_key + self.region = region + self.service = "polly" + self.host = f"polly.{region}.amazonaws.com" + self.endpoint = f"https://{self.host}" + + def _sign(self, key, msg): + """Helper function for AWS signature""" + return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest() + + def _get_signature_key(self, date_stamp): + """Generate AWS signature key""" + k_date = self._sign(("AWS4" + self.secret_key).encode("utf-8"), date_stamp) + k_region = self._sign(k_date, self.region) + k_service = self._sign(k_region, self.service) + k_signing = self._sign(k_service, "aws4_request") + return k_signing + + def _create_canonical_request(self, method, uri, query_string, headers, payload): + """Create canonical request for AWS Signature V4""" + canonical_uri = url_encode(uri, safe="/") + canonical_querystring = query_string + + # Create canonical headers + canonical_headers = "" + signed_headers = "" + header_names = sorted(headers.keys()) + for name in header_names: + canonical_headers += f"{name.lower()}:{headers[name].strip()}\n" + signed_headers += f"{name.lower()};" + signed_headers = signed_headers[:-1] # Remove trailing semicolon + + # Create payload hash + payload_hash = hashlib.sha256(payload.encode("utf-8")).hexdigest() + + # Create canonical request + canonical_request = (f"{method}\n{canonical_uri}\n{canonical_querystring}\n" + f"{canonical_headers}\n{signed_headers}\n{payload_hash}") + + return canonical_request, signed_headers + + def _create_string_to_sign(self, timestamp, credential_scope, canonical_request): + """Create string to sign for AWS Signature V4""" + algorithm = "AWS4-HMAC-SHA256" + canonical_request_hash = hashlib.sha256( + canonical_request.encode("utf-8") + ).hexdigest() + string_to_sign = ( + f"{algorithm}\n{timestamp}\n{credential_scope}\n{canonical_request_hash}" + ) + return string_to_sign + + def synthesize_speech( # pylint: disable=too-many-locals + self, + text, + voice_id="Joanna", + output_format="mp3", + engine="standard", + text_type="text", + ): + """ + Synthesize speech using Amazon Polly via direct HTTP request + + Args: + text (str): Text to convert to speech + voice_id (str): Voice to use (e.g., 'Joanna', 'Matthew', 'Amy') + output_format (str): Audio format ('mp3', 'ogg_vorbis', 'pcm') + engine (str): Engine type ('standard' or 'neural') + text_type (str): 'text' or 'ssml' + + Returns: + bytes: Audio data if successful, None if failed + """ + + # Prepare request + method = "POST" + uri = "/v1/speech" + + # Create request body + request_body = { + "Text": text, + "OutputFormat": output_format, + "VoiceId": voice_id, + "Engine": engine, + "TextType": text_type, + } + payload = json.dumps(request_body) + + # Get current time + now = datetime.now() + # amzdate = now.strftime('%Y%m%dT%H%M%SZ') + amzdate = (f"{now.year}{_zero_pad(now.month)}{_zero_pad(now.day)}" + f"T{_zero_pad(now.hour)}{_zero_pad(now.minute)}{_zero_pad(now.second)}Z") + # datestamp = now.strftime('%Y%m%d') + datestamp = f"{now.year}{_zero_pad(now.month)}{_zero_pad(now.day)}" + + # Create headers + headers = { + "Content-Type": "application/x-amz-json-1.0", + "Host": self.host, + "X-Amz-Date": amzdate, + "X-Amz-Target": "AWSPollyService.SynthesizeSpeech", + } + + # Create canonical request + canonical_request, signed_headers = self._create_canonical_request( + method, uri, "", headers, payload + ) + + # Create string to sign + credential_scope = f"{datestamp}/{self.region}/{self.service}/aws4_request" + string_to_sign = self._create_string_to_sign( + amzdate, credential_scope, canonical_request + ) + + # Create signature + signing_key = self._get_signature_key(datestamp) + signature = hmac.new( + signing_key, string_to_sign.encode("utf-8"), hashlib.sha256 + ).hexdigest() + + # Add authorization header + authorization_header = ( + f"AWS4-HMAC-SHA256 " + f"Credential={self.access_key}/{credential_scope}, " + f"SignedHeaders={signed_headers}, " + f"Signature={signature}" + ) + headers["Authorization"] = authorization_header + + # Make request + try: + url = f"{self.endpoint}{uri}" + response = self._requests.post(url, headers=headers, data=payload) + + if response.status_code == 200: + return response.content + else: + print(f"Error: HTTP {response.status_code}") + print(f"Response: {response.text}") + return None + + except Exception as e: # pylint: disable=broad-except + print(f"Request failed: {e}") + return None + + +def text_to_speech_polly_http( + requests_instance, + text, + access_key, + secret_key, + output_file="/saves/tts_output.mp3", + voice_id="Joanna", + region="us-east-1", + output_format="mp3", +): + """ + Simple function to convert text to speech using Polly HTTP API + + Args: + text (str): Text to convert + access_key (str): AWS Access Key ID + secret_key (str): AWS Secret Access Key + output_file (str): Output file path + voice_id (str): Polly voice ID + region (str): AWS region + output_format (str): Audio format + + Returns: + bool: True if successful, False otherwise + """ + + # Create Polly client + client = PollyHTTPClient(requests_instance, access_key, secret_key, region) + + # Synthesize speech + audio_data = client.synthesize_speech( + text=text, voice_id=voice_id, output_format=output_format + ) + + if audio_data: + # Save to file + try: + with open(output_file, "wb") as f: + f.write(audio_data) + print(f"Audio saved to: {output_file}") + return True + except Exception as e: # pylint: disable=broad-except + print(f"Failed to save file: {e}") + return False + else: + print("Failed to synthesize speech") + return False + + +def text_to_speech_with_ssml( + requests_instance, + text, + access_key, + secret_key, + speech_rate="medium", + output_file="output.mp3", +): + """ + Example with SSML for speech rate control + """ + # Wrap text in SSML + ssml_text = f'{text}' + + client = PollyHTTPClient(requests_instance, access_key, secret_key) + audio_data = client.synthesize_speech( + text=ssml_text, voice_id="Joanna", text_type="ssml" + ) + + if audio_data: + with open(output_file, "wb") as f: + f.write(audio_data) + print(f"SSML audio saved to: {output_file}") + return True + return False + + +# Example usage +# if __name__ == "__main__": +# # Replace with your actual AWS credentials +# AWS_ACCESS_KEY = os.getenv('AWS_ACCESS_KEY') +# AWS_SECRET_KEY = os.getenv('AWS_SECRET_KEY') +# +# # Basic usage +# success = text_to_speech_polly_http( +# text="Hello from CircuitPython! This is Amazon Polly speaking.", +# access_key=AWS_ACCESS_KEY, +# secret_key=AWS_SECRET_KEY, +# voice_id="Joanna" +# ) + +# SSML example +# if success: +# text_to_speech_with_ssml( +# text="This speech has a custom rate using SSML markup.", +# access_key=AWS_ACCESS_KEY, +# secret_key=AWS_SECRET_KEY, +# speech_rate="slow", +# output_file="ssml_example.mp3" +# ) diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/code.py b/Fruit_Jam/Fruit_Jam_Spell_Jam/code.py new file mode 100644 index 000000000..5ba543abe --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Spell_Jam/code.py @@ -0,0 +1,125 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT + +import sys +import time +import supervisor + +from adafruit_fruitjam import FruitJam +from adafruit_fruitjam.peripherals import request_display_config +from displayio import OnDiskBitmap, TileGrid, Group +from adafruit_bitmap_font import bitmap_font +from adafruit_display_text.bitmap_label import Label + +from launcher_config import LauncherConfig + +# comment out one of these imports depending on which TTS engine you want to use +from tts_aws import WordFetcherTTS +# from tts_local import WordFetcherTTS + +# read the user settings +launcher_config = LauncherConfig() + +# constants +LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +# local variables +curword = "" +lastword = "" +sayword = False + +# setup display +request_display_config(320, 240) +display = supervisor.runtime.display + +# setup background image +main_group = Group() +background = OnDiskBitmap("spell_jam_assets/background.bmp") +background_tg = TileGrid(background, pixel_shader=background.pixel_shader) +main_group.append(background_tg) + +# setup 14-segment label used to display words +font = bitmap_font.load_font("spell_jam_assets/14segment_16.bdf") +screen_lbl = Label(text="Type a word", font=font, color=0x00FF00) +screen_lbl.anchor_point = (0.5, 0) +screen_lbl.anchored_position = (display.width // 2, 100) +main_group.append(screen_lbl) + +# initialize Fruit Jam built-in hardware +fj = FruitJam() + +if "audio" in launcher_config.data and "volume" in launcher_config.data["audio"]: + volume_level = launcher_config.audio_volume +else: + volume_level = 0.5 + +fj.peripherals.audio_output = launcher_config.audio_output +fj.peripherals.safe_volume_limit = launcher_config.audio_volume_override_danger + +fj.peripherals.volume = volume_level +vol_int = round(volume_level * 100) + +fj.neopixels.brightness = 0.1 + +word_fetcher = WordFetcherTTS(fj, launcher_config) + +def say_and_spell_lastword(): + """ + Say the last word, then spell it out one letter at a time, finally say it once more. + """ + if sayword: + if word_fetcher.output_path[-4:] == ".mp3": + fj.play_mp3_file(word_fetcher.output_path) + elif word_fetcher.output_path[-4:] == ".wav": + fj.play_file(word_fetcher.output_path) + time.sleep(0.2) + for letter in lastword: + fj.play_mp3_file(f"spell_jam_assets/letter_mp3s/{letter.upper()}.mp3") + time.sleep(0.2) + if sayword: + if word_fetcher.output_path[-4:] == ".mp3": + fj.play_mp3_file(word_fetcher.output_path) + elif word_fetcher.output_path[-4:] == ".wav": + fj.play_file(word_fetcher.output_path) + fj.neopixels.fill(0x000000) + + +display.root_group = main_group +while True: + # check how many bytes are available + available = supervisor.runtime.serial_bytes_available + + # if there are some bytes available + if available: + # read data from the keyboard input + c = sys.stdin.read(available) + # print the data that was read + print(c, end="") + + if c in LETTERS: + curword += c + screen_lbl.text = curword + elif c in {"\x7f", "\x08"}: # backspace + curword = curword[:-1] + screen_lbl.text = curword + elif c == "\n": + if curword: + lastword = curword + sayword = word_fetcher.fetch_word(lastword) + say_and_spell_lastword() + curword = "" + else: + # repeat last word + say_and_spell_lastword() + elif c.encode("utf-8") == b"\x1b[B": + # down arrow + vol_int = max(0, vol_int - 5) + fj.peripherals.volume = vol_int / 100 + print(f"Volume: {fj.peripherals.volume}") + elif c.encode("utf-8") == b"\x1b[A": + # up arrow + vol_int = min(fj.peripherals.safe_volume_limit * 100, vol_int + 5) + fj.peripherals.volume = vol_int / 100 + print(f"Volume: {fj.peripherals.volume}") + else: + print(f"unused key: {c.encode('utf-8')}") diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/hmac.py b/Fruit_Jam/Fruit_Jam_Spell_Jam/hmac.py new file mode 100644 index 000000000..d1516d9a4 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Spell_Jam/hmac.py @@ -0,0 +1,93 @@ +# SPDX-FileCopyrightText: 2015 Paul Sokolovsky +# SPDX-License-Identifier: MIT +# https://github.com/micropython/micropython-lib +# https://github.com/micropython/micropython-lib/blob/master/LICENSE + +# Implements the hmac module from the Python standard library. + + +class HMAC: + # pylint: disable=protected-access, import-outside-toplevel + def __init__(self, key, msg=None, digestmod=None): + if not isinstance(key, (bytes, bytearray)): + raise TypeError("key: expected bytes/bytearray") + + import adafruit_hashlib as hashlib + + if digestmod is None: + # TODO: Default hash algorithm is now deprecated. + digestmod = hashlib.md5 + + if callable(digestmod): + # A hashlib constructor returning a new hash object. + make_hash = digestmod # A + elif isinstance(digestmod, str): + # A hash name suitable for hashlib.new(). + make_hash = lambda d=b"": getattr(hashlib, digestmod)(d) + else: + # A module supporting PEP 247. + make_hash = digestmod.new # C + + self._outer = make_hash() + self._inner = make_hash() + + self.digest_size = getattr(self._inner, "digest_size", None) + # If the provided hash doesn't support block_size (e.g. built-in + # hashlib), 64 is the correct default for all built-in hash + # functions (md5, sha1, sha256). + self.block_size = getattr(self._inner, "block_size", 64) + + # Truncate to digest_size if greater than block_size. + if len(key) > self.block_size: + key = make_hash(key).digest() + + # Pad to block size. + key = key + bytes(self.block_size - len(key)) + + self._outer.update(bytes(x ^ 0x5C for x in key)) + self._inner.update(bytes(x ^ 0x36 for x in key)) + + if msg is not None: + self.update(msg) + + @property + def name(self): + return "hmac-" + getattr(self._inner, "name", type(self._inner).__name__) + + def update(self, msg): + self._inner.update(msg) + + def copy(self): + if not hasattr(self._inner, "copy"): + # Not supported for built-in hash functions. + raise NotImplementedError() + # Call __new__ directly to avoid the expensive __init__. + other = self.__class__.__new__(self.__class__) + other.block_size = self.block_size + other.digest_size = self.digest_size + other._inner = self._inner.copy() + other._outer = self._outer.copy() + return other + + def _current(self): + h = self._outer + if hasattr(h, "copy"): + # built-in hash functions don't support this, and as a result, + # digest() will finalise the hmac and further calls to + # update/digest will fail. + h = h.copy() + h.update(self._inner.digest()) + return h + + def digest(self): + h = self._current() + return h.digest() + + def hexdigest(self): + import binascii + + return str(binascii.hexlify(self.digest()), "utf-8") + + +def new(key, msg=None, digestmod=None): + return HMAC(key, msg, digestmod) diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/icon.bmp b/Fruit_Jam/Fruit_Jam_Spell_Jam/icon.bmp new file mode 100644 index 000000000..91b42534f Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/icon.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/metadata.json b/Fruit_Jam/Fruit_Jam_Spell_Jam/metadata.json new file mode 100644 index 000000000..2a14fabb9 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Spell_Jam/metadata.json @@ -0,0 +1,4 @@ +{ + "title": "Spell Jam", + "icon": "icon.bmp" +} diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/14segment_16.bdf b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/14segment_16.bdf new file mode 100644 index 000000000..e17ac7935 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/14segment_16.bdf @@ -0,0 +1,2432 @@ +STARTFONT 2.1 +COMMENT +COMMENT Converted from OpenType font "DSEG14Modern-Regular.ttf" by "otf2bdf 3.0". +COMMENT +FONT -FreeType-DSEG14 Modern-Medium-R-Normal--22-160-100-100-P-120-ISO10646-1 +SIZE 16 100 100 +FONTBOUNDINGBOX 17 22 -1 0 +STARTPROPERTIES 19 +FOUNDRY "FreeType" +FAMILY_NAME "DSEG14 Modern" +WEIGHT_NAME "Medium" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 22 +POINT_SIZE 160 +RESOLUTION_X 100 +RESOLUTION_Y 100 +SPACING "P" +AVERAGE_WIDTH 120 +CHARSET_REGISTRY "ISO10646" +CHARSET_ENCODING "1" +FONT_ASCENT 22 +FONT_DESCENT 0 +COPYRIGHT "Created by Keshikan with FontForge 2.0 (http://fontforge.sf.net)" +_OTF_FONTFILE "DSEG14Modern-Regular.ttf" +_OTF_PSNAME "DSEG14Modern-Regular" +ENDPROPERTIES +CHARS 93 +STARTCHAR 0020 +ENCODING 32 +SWIDTH 180 0 +DWIDTH 4 0 +BBX 0 0 0 0 +BITMAP +ENDCHAR +STARTCHAR 0021 +ENCODING 33 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 0 0 0 0 +BITMAP +ENDCHAR +STARTCHAR 0022 +ENCODING 34 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 8 10 2 10 +BITMAP +80 +C3 +C3 +C3 +C3 +C3 +C3 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0024 +ENCODING 36 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFF8 +BFF0 +C300 +C300 +C300 +C300 +C300 +C300 +C000 +C000 +FCF0 +3CFC +000C +000C +030C +030C +030C +030C +030C +030C +3FF4 +7FFC +ENDCHAR +STARTCHAR 0025 +ENCODING 37 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 20 2 1 +BITMAP +8000 +C000 +D020 +D020 +D860 +DCE0 +CCC0 +CCC0 +C480 +FCF0 +3CFC +048C +0CCC +0CCC +1CEC +186C +102C +102C +000C +0004 +ENDCHAR +STARTCHAR 0026 +ENCODING 38 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFF8 +3FF0 +0000 +1020 +1020 +1860 +1CE0 +0CC0 +0CC0 +0480 +0000 +000C +048C +0CCC +0CCC +1CEC +186C +102C +102C +000C +3FF4 +7FFC +ENDCHAR +STARTCHAR 0027 +ENCODING 39 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 2 6 8 12 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0028 +ENCODING 40 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 3 16 10 3 +BITMAP +20 +20 +60 +E0 +C0 +C0 +80 +00 +00 +80 +C0 +C0 +E0 +60 +20 +20 +ENDCHAR +STARTCHAR 0029 +ENCODING 41 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 3 16 5 3 +BITMAP +80 +80 +C0 +E0 +60 +60 +20 +00 +00 +20 +60 +60 +E0 +C0 +80 +80 +ENDCHAR +STARTCHAR 002A +ENCODING 42 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 10 18 4 2 +BITMAP +0C00 +4C80 +4C80 +6D80 +7F80 +3F00 +3300 +1200 +F3C0 +F3C0 +1200 +3300 +3F00 +7F80 +6D80 +4C80 +4C80 +0C00 +ENDCHAR +STARTCHAR 002B +ENCODING 43 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 10 18 4 2 +BITMAP +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +0000 +0000 +F3C0 +F3C0 +0000 +0000 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 002C +ENCODING 44 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 3 7 5 3 +BITMAP +20 +60 +60 +E0 +C0 +80 +80 +ENDCHAR +STARTCHAR 002D +ENCODING 45 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 10 2 4 10 +BITMAP +F3C0 +F3C0 +ENDCHAR +STARTCHAR 002E +ENCODING 46 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 3 -1 0 +BITMAP +C0 +C0 +C0 +ENDCHAR +STARTCHAR 002F +ENCODING 47 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 8 16 5 3 +BITMAP +01 +01 +03 +07 +06 +06 +04 +00 +00 +20 +60 +60 +E0 +C0 +80 +80 +ENDCHAR +STARTCHAR 0030 +ENCODING 48 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +BFF4 +C00C +C02C +C02C +C06C +C0EC +C0CC +C0CC +C08C +C000 +000C +C40C +CC0C +CC0C +DC0C +D80C +D00C +D00C +C00C +BFF4 +FFFC +ENDCHAR +STARTCHAR 0031 +ENCODING 49 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 2 21 14 1 +BITMAP +40 +40 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +40 +ENDCHAR +STARTCHAR 0032 +ENCODING 50 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +3FF4 +000C +000C +000C +000C +000C +000C +000C +000C +3CF0 +3CF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +BFF0 +FFFC +ENDCHAR +STARTCHAR 0033 +ENCODING 51 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +3FF4 +000C +000C +000C +000C +000C +000C +000C +000C +3CF0 +3CFC +000C +000C +000C +000C +000C +000C +000C +000C +3FF4 +7FFC +ENDCHAR +STARTCHAR 0034 +ENCODING 52 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 21 2 1 +BITMAP +0004 +8004 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +FCF0 +3CFC +000C +000C +000C +000C +000C +000C +000C +000C +0004 +ENDCHAR +STARTCHAR 0035 +ENCODING 53 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFF8 +BFF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FCF0 +3CFC +000C +000C +000C +000C +000C +000C +000C +000C +3FF4 +7FFC +ENDCHAR +STARTCHAR 0036 +ENCODING 54 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFF8 +BFF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FCF0 +3CFC +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +BFF4 +FFFC +ENDCHAR +STARTCHAR 0037 +ENCODING 55 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 21 2 1 +BITMAP +FFFC +BFF4 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C000 +000C +000C +000C +000C +000C +000C +000C +000C +000C +0004 +ENDCHAR +STARTCHAR 0038 +ENCODING 56 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +BFF4 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +FCF0 +3CFC +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +BFF4 +FFFC +ENDCHAR +STARTCHAR 0039 +ENCODING 57 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +BFF4 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +FCF0 +3CFC +000C +000C +000C +000C +000C +000C +000C +000C +3FF4 +7FFC +ENDCHAR +STARTCHAR 003A +ENCODING 58 +SWIDTH 180 0 +DWIDTH 4 0 +BBX 3 12 1 5 +BITMAP +40 +E0 +C0 +00 +00 +00 +00 +00 +00 +40 +E0 +C0 +ENDCHAR +STARTCHAR 003C +ENCODING 60 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 13 19 3 1 +BITMAP +0040 +0040 +00C0 +01C0 +0180 +0180 +0100 +0000 +0000 +0800 +1800 +1800 +3800 +3000 +2000 +2000 +0000 +7FE0 +FFF8 +ENDCHAR +STARTCHAR 003D +ENCODING 61 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 13 12 3 0 +BITMAP +79E0 +79E0 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +7FE0 +FFF8 +ENDCHAR +STARTCHAR 003E +ENCODING 62 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 13 19 3 1 +BITMAP +2000 +2000 +3000 +3800 +1800 +1800 +0800 +0000 +0000 +0100 +0180 +0180 +01C0 +00C0 +0040 +0040 +0000 +7FE0 +FFF8 +ENDCHAR +STARTCHAR 003F +ENCODING 63 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 20 2 2 +BITMAP +FFFC +BFF4 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C0F0 +00F0 +0000 +0000 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 0040 +ENCODING 64 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +BFF4 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C0F0 +00FC +C00C +C00C +C30C +C30C +C30C +C30C +C30C +C30C +BFF4 +FFFC +ENDCHAR +STARTCHAR 0041 +ENCODING 65 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +BFF4 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +FCF0 +3CFC +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +8004 +8000 +ENDCHAR +STARTCHAR 0042 +ENCODING 66 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +3FF4 +030C +030C +030C +030C +030C +030C +000C +000C +00F0 +00FC +000C +000C +030C +030C +030C +030C +030C +030C +3FF4 +7FFC +ENDCHAR +STARTCHAR 0043 +ENCODING 67 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFF8 +BFF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +0000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +BFF0 +FFFC +ENDCHAR +STARTCHAR 0044 +ENCODING 68 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +3FF4 +030C +030C +030C +030C +030C +030C +000C +000C +0000 +000C +000C +000C +030C +030C +030C +030C +030C +030C +3FF4 +7FFC +ENDCHAR +STARTCHAR 0045 +ENCODING 69 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFF8 +BFF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FCF0 +3CF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +BFF0 +FFFC +ENDCHAR +STARTCHAR 0046 +ENCODING 70 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 13 22 2 0 +BITMAP +FFF8 +BFF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FCF0 +3CF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +8000 +8000 +ENDCHAR +STARTCHAR 0047 +ENCODING 71 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFF8 +BFF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C0F0 +00FC +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +BFF4 +FFFC +ENDCHAR +STARTCHAR 0048 +ENCODING 72 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +0004 +8004 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +FCF0 +3CFC +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +8004 +8000 +ENDCHAR +STARTCHAR 0049 +ENCODING 73 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFF8 +3FF0 +0300 +0300 +0300 +0300 +0300 +0300 +0000 +0000 +0000 +0000 +0000 +0000 +0300 +0300 +0300 +0300 +0300 +0300 +3FF0 +7FFC +ENDCHAR +STARTCHAR 004A +ENCODING 74 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +0004 +0004 +000C +000C +000C +000C +000C +000C +000C +000C +0000 +000C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +BFF4 +FFFC +ENDCHAR +STARTCHAR 004B +ENCODING 75 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 11 21 2 0 +BITMAP +8000 +C000 +C020 +C020 +C060 +C0E0 +C0C0 +C0C0 +C080 +FC00 +3C00 +C080 +C0C0 +C0C0 +C0E0 +C060 +C020 +C020 +C000 +8000 +8000 +ENDCHAR +STARTCHAR 004C +ENCODING 76 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 21 2 0 +BITMAP +8000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +0000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +BFF0 +FFFC +ENDCHAR +STARTCHAR 004D +ENCODING 77 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +0004 +8004 +C00C +D02C +D02C +D86C +DCEC +CCCC +CCCC +C48C +C000 +000C +C00C +C00C +C30C +C30C +C30C +C30C +C30C +C30C +8004 +8000 +ENDCHAR +STARTCHAR 004E +ENCODING 78 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +0004 +8004 +C00C +D00C +D00C +D80C +DC0C +CC0C +CC0C +C40C +C000 +000C +C08C +C0CC +C0CC +C0EC +C06C +C02C +C02C +C00C +8004 +8000 +ENDCHAR +STARTCHAR 004F +ENCODING 79 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +BFF4 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C000 +000C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +BFF4 +FFFC +ENDCHAR +STARTCHAR 0050 +ENCODING 80 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +BFF4 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +FCF0 +3CF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +8000 +8000 +ENDCHAR +STARTCHAR 0051 +ENCODING 81 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +BFF4 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C000 +000C +C08C +C0CC +C0CC +C0EC +C06C +C02C +C02C +C00C +BFF4 +FFFC +ENDCHAR +STARTCHAR 0052 +ENCODING 82 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +BFF4 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +FCF0 +3CF0 +C080 +C0C0 +C0C0 +C0E0 +C060 +C020 +C020 +C000 +8000 +8000 +ENDCHAR +STARTCHAR 0053 +ENCODING 83 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFF8 +BFF0 +C000 +D000 +D000 +D800 +DC00 +CC00 +CC00 +C400 +FCF0 +3CFC +008C +00CC +00CC +00EC +006C +002C +002C +000C +3FF4 +7FFC +ENDCHAR +STARTCHAR 0054 +ENCODING 84 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 13 20 2 2 +BITMAP +FFF8 +3FF0 +0300 +0300 +0300 +0300 +0300 +0300 +0000 +0000 +0000 +0000 +0000 +0000 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 0055 +ENCODING 85 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +0004 +8004 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C000 +000C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +BFF4 +FFFC +ENDCHAR +STARTCHAR 0056 +ENCODING 86 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 11 21 2 0 +BITMAP +8000 +C000 +C020 +C020 +C060 +C0E0 +C0C0 +C0C0 +C080 +C000 +0000 +C400 +CC00 +CC00 +DC00 +D800 +D000 +D000 +C000 +8000 +8000 +ENDCHAR +STARTCHAR 0057 +ENCODING 87 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +0004 +8004 +C30C +C30C +C30C +C30C +C30C +C30C +C00C +C00C +C000 +000C +C48C +CCCC +CCCC +DCEC +D86C +D02C +D02C +C00C +8004 +8000 +ENDCHAR +STARTCHAR 0058 +ENCODING 88 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 8 16 5 3 +BITMAP +81 +81 +C3 +E7 +66 +66 +24 +00 +00 +24 +66 +66 +E7 +C3 +81 +81 +ENDCHAR +STARTCHAR 0059 +ENCODING 89 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 8 17 5 3 +BITMAP +81 +81 +C3 +E7 +66 +66 +24 +00 +00 +00 +00 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 005A +ENCODING 90 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFF8 +3FF0 +0000 +0020 +0020 +0060 +00E0 +00C0 +00C0 +0080 +0000 +0000 +0400 +0C00 +0C00 +1C00 +1800 +1000 +1000 +0000 +3FF0 +7FFC +ENDCHAR +STARTCHAR 005C +ENCODING 92 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 8 16 5 3 +BITMAP +80 +80 +C0 +E0 +60 +60 +20 +00 +00 +04 +06 +06 +07 +03 +01 +01 +ENDCHAR +STARTCHAR 005E +ENCODING 94 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 6 10 2 10 +BITMAP +80 +C0 +D0 +D0 +D8 +DC +CC +CC +C4 +C0 +ENDCHAR +STARTCHAR 005F +ENCODING 95 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 13 2 3 0 +BITMAP +7FE0 +FFF8 +ENDCHAR +STARTCHAR 0060 +ENCODING 96 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 3 7 5 12 +BITMAP +80 +80 +C0 +E0 +60 +60 +20 +ENDCHAR +STARTCHAR 0061 +ENCODING 97 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +BFF4 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +FCF0 +3CFC +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +8004 +8000 +ENDCHAR +STARTCHAR 0062 +ENCODING 98 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +3FF4 +030C +030C +030C +030C +030C +030C +000C +000C +00F0 +00FC +000C +000C +030C +030C +030C +030C +030C +030C +3FF4 +7FFC +ENDCHAR +STARTCHAR 0063 +ENCODING 99 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFF8 +BFF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +0000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +BFF0 +FFFC +ENDCHAR +STARTCHAR 0064 +ENCODING 100 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +3FF4 +030C +030C +030C +030C +030C +030C +000C +000C +0000 +000C +000C +000C +030C +030C +030C +030C +030C +030C +3FF4 +7FFC +ENDCHAR +STARTCHAR 0065 +ENCODING 101 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFF8 +BFF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FCF0 +3CF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +BFF0 +FFFC +ENDCHAR +STARTCHAR 0066 +ENCODING 102 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 13 22 2 0 +BITMAP +FFF8 +BFF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FCF0 +3CF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +8000 +8000 +ENDCHAR +STARTCHAR 0067 +ENCODING 103 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFF8 +BFF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C0F0 +00FC +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +BFF4 +FFFC +ENDCHAR +STARTCHAR 0068 +ENCODING 104 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +0004 +8004 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +FCF0 +3CFC +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +8004 +8000 +ENDCHAR +STARTCHAR 0069 +ENCODING 105 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFF8 +3FF0 +0300 +0300 +0300 +0300 +0300 +0300 +0000 +0000 +0000 +0000 +0000 +0000 +0300 +0300 +0300 +0300 +0300 +0300 +3FF0 +7FFC +ENDCHAR +STARTCHAR 006A +ENCODING 106 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +0004 +0004 +000C +000C +000C +000C +000C +000C +000C +000C +0000 +000C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +BFF4 +FFFC +ENDCHAR +STARTCHAR 006B +ENCODING 107 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 11 21 2 0 +BITMAP +8000 +C000 +C020 +C020 +C060 +C0E0 +C0C0 +C0C0 +C080 +FC00 +3C00 +C080 +C0C0 +C0C0 +C0E0 +C060 +C020 +C020 +C000 +8000 +8000 +ENDCHAR +STARTCHAR 006C +ENCODING 108 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 21 2 0 +BITMAP +8000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +0000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +BFF0 +FFFC +ENDCHAR +STARTCHAR 006D +ENCODING 109 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +0004 +8004 +C00C +D02C +D02C +D86C +DCEC +CCCC +CCCC +C48C +C000 +000C +C00C +C00C +C30C +C30C +C30C +C30C +C30C +C30C +8004 +8000 +ENDCHAR +STARTCHAR 006E +ENCODING 110 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +0004 +8004 +C00C +D00C +D00C +D80C +DC0C +CC0C +CC0C +C40C +C000 +000C +C08C +C0CC +C0CC +C0EC +C06C +C02C +C02C +C00C +8004 +8000 +ENDCHAR +STARTCHAR 006F +ENCODING 111 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +BFF4 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C000 +000C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +BFF4 +FFFC +ENDCHAR +STARTCHAR 0070 +ENCODING 112 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +BFF4 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +FCF0 +3CF0 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +8000 +8000 +ENDCHAR +STARTCHAR 0071 +ENCODING 113 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +BFF4 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C000 +000C +C08C +C0CC +C0CC +C0EC +C06C +C02C +C02C +C00C +BFF4 +FFFC +ENDCHAR +STARTCHAR 0072 +ENCODING 114 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +BFF4 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +FCF0 +3CF0 +C080 +C0C0 +C0C0 +C0E0 +C060 +C020 +C020 +C000 +8000 +8000 +ENDCHAR +STARTCHAR 0073 +ENCODING 115 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFF8 +BFF0 +C000 +D000 +D000 +D800 +DC00 +CC00 +CC00 +C400 +FCF0 +3CFC +008C +00CC +00CC +00EC +006C +002C +002C +000C +3FF4 +7FFC +ENDCHAR +STARTCHAR 0074 +ENCODING 116 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 13 20 2 2 +BITMAP +FFF8 +3FF0 +0300 +0300 +0300 +0300 +0300 +0300 +0000 +0000 +0000 +0000 +0000 +0000 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 0075 +ENCODING 117 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +0004 +8004 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C000 +000C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +BFF4 +FFFC +ENDCHAR +STARTCHAR 0076 +ENCODING 118 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 11 21 2 0 +BITMAP +8000 +C000 +C020 +C020 +C060 +C0E0 +C0C0 +C0C0 +C080 +C000 +0000 +C400 +CC00 +CC00 +DC00 +D800 +D000 +D000 +C000 +8000 +8000 +ENDCHAR +STARTCHAR 0077 +ENCODING 119 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +0004 +8004 +C30C +C30C +C30C +C30C +C30C +C30C +C00C +C00C +C000 +000C +C48C +CCCC +CCCC +DCEC +D86C +D02C +D02C +C00C +8004 +8000 +ENDCHAR +STARTCHAR 0078 +ENCODING 120 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 8 16 5 3 +BITMAP +81 +81 +C3 +E7 +66 +66 +24 +00 +00 +24 +66 +66 +E7 +C3 +81 +81 +ENDCHAR +STARTCHAR 0079 +ENCODING 121 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 8 17 5 3 +BITMAP +81 +81 +C3 +E7 +66 +66 +24 +00 +00 +00 +00 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 007A +ENCODING 122 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFF8 +3FF0 +0000 +0020 +0020 +0060 +00E0 +00C0 +00C0 +0080 +0000 +0000 +0400 +0C00 +0C00 +1C00 +1800 +1000 +1000 +0000 +3FF0 +7FFC +ENDCHAR +STARTCHAR 007C +ENCODING 124 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 2 18 8 2 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +00 +00 +00 +00 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 007E +ENCODING 126 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 22 2 0 +BITMAP +FFFC +BFF4 +C30C +D32C +D32C +DB6C +DFEC +CFCC +CCCC +C48C +FCF0 +3CFC +C48C +CCCC +CFCC +DFEC +DB6C +D32C +D32C +C30C +BFF4 +FFFC +ENDCHAR +STARTCHAR 00A5 +ENCODING 165 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 10 17 4 3 +BITMAP +4080 +4080 +6180 +7380 +3300 +3300 +1200 +F3C0 +F3C0 +0000 +0000 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 00A6 +ENCODING 166 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 2 18 8 2 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +00 +00 +00 +00 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00B0 +ENCODING 176 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 14 12 2 10 +BITMAP +FFFC +BFF4 +C00C +C00C +C00C +C00C +C00C +C00C +C00C +C00C +FCF0 +3CF0 +ENDCHAR +STARTCHAR 00B1 +ENCODING 177 +SWIDTH 810 0 +DWIDTH 18 0 +BBX 13 20 3 0 +BITMAP +0600 +0600 +0600 +0600 +0600 +0600 +0000 +0000 +79E0 +79E0 +0000 +0000 +0600 +0600 +0600 +0600 +0600 +0600 +7FE0 +FFF8 +ENDCHAR +ENDFONT diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/14segment_16.bdf.license b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/14segment_16.bdf.license new file mode 100644 index 000000000..9232f592f --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/14segment_16.bdf.license @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: Copyright (c) 2020, keshikan (https://www.keshikan.net), with Reserved Font Name "DSEG". + +# SPDX-License-Identifier: OFL-1.1-RFN + +# This Font Software is licensed under the SIL Open Font License, Version 1.1. +# This license is copied below, and is also available with a FAQ at: +# http://scripts.sil.org/OFL + diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/background.bmp b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/background.bmp new file mode 100644 index 000000000..6151b7c45 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/background.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/background.bmp.license b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/background.bmp.license new file mode 100644 index 000000000..39cb00c04 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/background.bmp.license @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025, Tim Cocks for Adafruit Industries + +# SPDX-License-Identifier: MIT \ No newline at end of file diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/A.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/A.mp3 new file mode 100644 index 000000000..f281ab896 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/A.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/B.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/B.mp3 new file mode 100644 index 000000000..30d3d593a Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/B.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/C.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/C.mp3 new file mode 100644 index 000000000..ce7b23a8a Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/C.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/D.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/D.mp3 new file mode 100644 index 000000000..2397eabc3 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/D.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/E.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/E.mp3 new file mode 100644 index 000000000..1b70a9dee Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/E.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/F.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/F.mp3 new file mode 100644 index 000000000..5ac0905b9 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/F.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/G.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/G.mp3 new file mode 100644 index 000000000..c687fca09 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/G.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/H.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/H.mp3 new file mode 100644 index 000000000..44ad2dba7 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/H.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/I.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/I.mp3 new file mode 100644 index 000000000..ef568e288 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/I.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/J.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/J.mp3 new file mode 100644 index 000000000..08b708145 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/J.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/K.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/K.mp3 new file mode 100644 index 000000000..69ae3e3b6 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/K.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/L.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/L.mp3 new file mode 100644 index 000000000..5fb69a7ce Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/L.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/M.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/M.mp3 new file mode 100644 index 000000000..521e6d272 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/M.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/N.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/N.mp3 new file mode 100644 index 000000000..b10d92f92 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/N.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/O.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/O.mp3 new file mode 100644 index 000000000..edf62590c Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/O.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/P.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/P.mp3 new file mode 100644 index 000000000..635952f6c Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/P.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/Q.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/Q.mp3 new file mode 100644 index 000000000..9c6b6c725 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/Q.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/R.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/R.mp3 new file mode 100644 index 000000000..b5386fabe Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/R.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/S.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/S.mp3 new file mode 100644 index 000000000..10c399dc9 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/S.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/T.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/T.mp3 new file mode 100644 index 000000000..e01ac6947 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/T.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/U.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/U.mp3 new file mode 100644 index 000000000..2521c9650 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/U.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/V.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/V.mp3 new file mode 100644 index 000000000..922738aea Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/V.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/W.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/W.mp3 new file mode 100644 index 000000000..d210b316e Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/W.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/X.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/X.mp3 new file mode 100644 index 000000000..576910ea3 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/X.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/Y.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/Y.mp3 new file mode 100644 index 000000000..ef11d65a6 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/Y.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/Z.mp3 b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/Z.mp3 new file mode 100644 index 000000000..e3e95aa7f Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Spell_Jam/spell_jam_assets/letter_mp3s/Z.mp3 differ diff --git a/Fruit_Jam/Fruit_Jam_Spell_Jam/tts_aws.py b/Fruit_Jam/Fruit_Jam_Spell_Jam/tts_aws.py new file mode 100644 index 000000000..6994cf164 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Spell_Jam/tts_aws.py @@ -0,0 +1,48 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT + +# tts_aws.py +import os +import adafruit_connection_manager +import adafruit_requests +from aws_polly import text_to_speech_polly_http + +class WordFetcherTTS(): + def __init__(self, fj=None, launcher_config=None, output_path="/saves/tts_output.mp3"): + + self.output_path = output_path + self.fj = fj + self.launcher_config = launcher_config + + # AWS auth requires us to have accurate date/time + fj.sync_time() + + # setup adafruit_requests session + pool = adafruit_connection_manager.get_radio_socketpool(fj.network._wifi.esp) + ssl_context = adafruit_connection_manager.get_radio_ssl_context(fj.network._wifi.esp) + self.requests = adafruit_requests.Session(pool, ssl_context) + self.AWS_ACCESS_KEY = os.getenv("AWS_ACCESS_KEY") + self.AWS_SECRET_KEY = os.getenv("AWS_SECRET_KEY") + + def fetch_word(self, word: str, voice: str = "Joanna") -> bool: + if not self.AWS_ACCESS_KEY or not self.AWS_SECRET_KEY: + print("Missing AWS credentials.") + return False + + if self.fj: + self.fj.neopixels.fill(0xFFFF00) + + success = text_to_speech_polly_http( + self.requests, + text=word, + access_key=self.AWS_ACCESS_KEY, + secret_key=self.AWS_SECRET_KEY, + output_file=self.output_path, + voice_id=voice, + region="us-east-1", + output_format="mp3", + ) + + if self.fj: + self.fj.neopixels.fill(0x00FF00) + return success diff --git a/Fruit_Jam/Fruit_Jam_Startups/GameBoy_Startup/code.py b/Fruit_Jam/Fruit_Jam_Startups/GameBoy_Startup/code.py new file mode 100644 index 000000000..dceaffe83 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Startups/GameBoy_Startup/code.py @@ -0,0 +1,88 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +import time +from audiocore import WaveFile +import audiobusio +import board +from displayio import Group, TileGrid, Bitmap, Palette +import supervisor +import adafruit_imageload +import adafruit_tlv320 +from adafruit_fruitjam.peripherals import request_display_config + + +# how long between animation frames +ANIMATE_INTERVAL = 1 / 45 + +background_color = 0xE1F7CE + +i2c = board.I2C() +dac = adafruit_tlv320.TLV320DAC3100(i2c) +dac.configure_clocks(sample_rate=44100, bit_depth=16) +# for headphone jack ouput +dac.headphone_output = True +dac.headphone_volume = -15 # dB +# for speaker JST output +# dac.speaker_output = True +# dac.speaker_volume = -15 # dB + +wave_file = open("gameboy_startup/gameboy_pling.wav", "rb") +wave = WaveFile(wave_file) +audio = audiobusio.I2SOut(board.I2S_BCLK, board.I2S_WS, board.I2S_DIN) + +# display setup +request_display_config(320, 240) +display = supervisor.runtime.display + +# group to hold all visual elements +main_group = Group() + +# Bitmap for background color +bg_bmp = Bitmap(display.width // 20, display.height // 20, 1) +bg_palette = Palette(1) +bg_palette[0] = background_color +bg_tg = TileGrid(bg_bmp, pixel_shader=bg_palette) + +# group to scale the background bitmap up to display size +bg_group = Group(scale=20) +bg_group.append(bg_tg) +main_group.append(bg_group) + +# Bitmap for logo +logo, palette = adafruit_imageload.load("gameboy_startup/gameboy_logo.bmp") +logo_tg = TileGrid(logo, pixel_shader=palette) +main_group.append(logo_tg) + +# place it in the center horizontally and above the top of the display +logo_tg.x = display.width // 2 - logo_tg.tile_width // 2 +logo_tg.y = -logo_tg.tile_height + +# y pixel location to stop logo at +STOP_Y = display.height * 0.4 - logo_tg.tile_height // 2 + + +display.root_group = main_group +time.sleep(1.5) +last_animate_time = time.monotonic() +played_audio = False +display.auto_refresh = False +while True: + now = time.monotonic() + + # if it's time to animate and the logo isn't to the + # stopping position yet + if last_animate_time + ANIMATE_INTERVAL <= now and logo_tg.y < STOP_Y: + + # update the timestamp + last_animate_time = now + # move the logo down by a pixel + logo_tg.y += 1 + display.refresh() + + # if the logo has reached the stop position + if logo_tg.y >= STOP_Y and not played_audio: + played_audio = True + # play the audio pling + audio.play(wave) + while audio.playing: + pass diff --git a/Fruit_Jam/Fruit_Jam_Startups/GameBoy_Startup/gameboy_startup/gameboy_logo.bmp b/Fruit_Jam/Fruit_Jam_Startups/GameBoy_Startup/gameboy_startup/gameboy_logo.bmp new file mode 100644 index 000000000..79ce257b7 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Startups/GameBoy_Startup/gameboy_startup/gameboy_logo.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_Startups/GameBoy_Startup/gameboy_startup/gameboy_pling.wav b/Fruit_Jam/Fruit_Jam_Startups/GameBoy_Startup/gameboy_startup/gameboy_pling.wav new file mode 100644 index 000000000..50484cf42 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Startups/GameBoy_Startup/gameboy_startup/gameboy_pling.wav differ diff --git a/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/code.py b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/code.py new file mode 100644 index 000000000..33be58018 --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/code.py @@ -0,0 +1,107 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +import time +from audiocore import WaveFile +import audiobusio +import board +import supervisor +from displayio import Group, TileGrid, OnDiskBitmap +import adafruit_tlv320 +from adafruit_fruitjam.peripherals import request_display_config +from adafruit_progressbar.horizontalprogressbar import ( + HorizontalFillDirection, + HorizontalProgressBar, +) + +# DAC setup +i2c = board.I2C() +dac = adafruit_tlv320.TLV320DAC3100(i2c) +dac.configure_clocks(sample_rate=44100, bit_depth=16) + +# for headphone jack ouput +dac.headphone_output = True +dac.headphone_volume = -15 # dB +# for speaker JST output +# dac.speaker_output = True +# dac.speaker_volume = -15 # dB + +# Chime audio setup +wave_file = open("mac_startup/mac_chime.wav", "rb") +wave = WaveFile(wave_file) +audio = audiobusio.I2SOut(board.I2S_BCLK, board.I2S_WS, board.I2S_DIN) + +# Display setup +request_display_config(640, 480) +display = supervisor.runtime.display +display.auto_refresh = False + +# group to hold visual all elements +main_group = Group() +display.root_group = main_group +display.refresh() + +# background image +bg_bmp = OnDiskBitmap("mac_startup/mac_startup_bg.bmp") +bg_tg = TileGrid(bg_bmp, pixel_shader=bg_bmp.pixel_shader) +main_group.append(bg_tg) + +# Icons for bottom left +icons = [] +for i in range(6): + odb = OnDiskBitmap("mac_startup/mac_startup_icon{0}.bmp".format(i)) + tg = TileGrid(odb, pixel_shader=odb.pixel_shader) + icons.append( + { + "bmp": odb, + "tg": tg, + } + ) + tg.x = 10 + ((33 + 8) * i) + tg.y = display.height - tg.tile_height - 10 + tg.hidden = True + if i < 5: + odb.pixel_shader.make_transparent(0) + main_group.append(tg) + +# progress bar in the welcome box +progress_bar = HorizontalProgressBar( + (147, 138), + (346, 7), + direction=HorizontalFillDirection.LEFT_TO_RIGHT, + min_value=0, + max_value=800, + fill_color=0xC7BEFD, + outline_color=0x000000, + bar_color=0x3F3F3F, + margin_size=0, +) +main_group.append(progress_bar) + +# play the chime sound +audio.play(wave) +while audio.playing: + pass + +# start drawing the visual elements +display.auto_refresh = True +time.sleep(1) +start_time = time.monotonic() + +while True: + elapsed = time.monotonic() - start_time + + # if we haven't reached the end yet + if elapsed * 100 <= 800: + # update the progress bar + progress_bar.value = elapsed * 100 + + else: # reached the end animation + # set progress bar to max value + progress_bar.value = 800 + + # loop over all icons + for index, icon in enumerate(icons): + # if it's time for the current icon to show, and it's still hidden + if (elapsed - 1) > index and icon["tg"].hidden: + # make the current icon visible + icon["tg"].hidden = False diff --git a/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_chime.wav b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_chime.wav new file mode 100644 index 000000000..17e55ed95 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_chime.wav differ diff --git a/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_bg.bmp b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_bg.bmp new file mode 100644 index 000000000..6ebaf37f9 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_bg.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon0.bmp b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon0.bmp new file mode 100644 index 000000000..837f319b1 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon0.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon1.bmp b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon1.bmp new file mode 100644 index 000000000..73247cc49 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon1.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon2.bmp b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon2.bmp new file mode 100644 index 000000000..ee63e2014 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon2.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon3.bmp b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon3.bmp new file mode 100644 index 000000000..c9c249645 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon3.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon4.bmp b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon4.bmp new file mode 100644 index 000000000..af6a75567 Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon4.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon5.bmp b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon5.bmp new file mode 100644 index 000000000..b84e94a8c Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Startups/Mac_Startup/mac_startup/mac_startup_icon5.bmp differ diff --git a/Fruit_Jam/Fruit_Jam_Video_Music/code.py b/Fruit_Jam/Fruit_Jam_Video_Music/code.py new file mode 100644 index 000000000..3bbf3ab1e --- /dev/null +++ b/Fruit_Jam/Fruit_Jam_Video_Music/code.py @@ -0,0 +1,1023 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# FFT calculations based on Phil B.'s Audio Spectrum Light Show Code +# https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/ +# Feather_Sense_Audio_Visualizer_13x9_RGB_LED_Matrix/audio_spectrum_lightshow/code.py + +from array import array +from math import cos, log, sin, pi +from random import randint, choice +import board +import keypad +from audiobusio import PDMIn +import displayio +import picodvi +import framebufferio +import vectorio +import adafruit_imageload +from analogio import AnalogIn +from adafruit_display_shapes.polygon import Polygon +from digitalio import DigitalInOut, Direction +import simpleio +from ulab import numpy as np +try: + from ulab.utils import spectrogram +except ImportError: + from ulab.scipy.signal import spectrogram + +# ------ PICODVI SETUP ------ +displayio.release_displays() +fb = picodvi.Framebuffer(320, 240, clk_dp=board.CKP, clk_dn=board.CKN, + red_dp=board.D0P, red_dn=board.D0N, + green_dp=board.D1P, green_dn=board.D1N, + blue_dp=board.D2P, blue_dn=board.D2N, + color_depth=8) +display = framebufferio.FramebufferDisplay(fb, auto_refresh=False) + +# ------ SHARED VARIABLES ------ +fft_size = 512 +low_bin = 15 +high_bin = 75 +low_band = (15, 75) +mid_band = (100, 120) +spectrum_size = fft_size // 2 +spectrum_bits = log(spectrum_size, 2) +mode = 0 +new_mode = True +states = {} + +# ------ PDM MIC ------ +mic = PDMIn(board.D6, board.D7, sample_rate=44100, bit_depth=16) +rec_buf = array("H", [0] * fft_size) + +# ------ POTENTIOMETER SETUP ------ +pot1 = AnalogIn(board.A0) +read_pots = True +# ------ POTENTIOMETER MODE VALUES ------ +mode0_values = [0, 0, 0] +mode1_values = [0, 0, 0] +mode2_values = [0, 0, 0] +mode_vals = [0, 0, 0] +# ------ POTENTIOMETER READ FUNCTION ------ +def val(pin): + return pin.value + +# ------ SWITCH SETUP ------ +keys = keypad.Keys((board.A1, board.A3), value_when_pressed=False, pull=True) + +# ------ LED SETUP ------ +led_0 = DigitalInOut(board.A2) +led_0.direction = Direction.OUTPUT +led_1 = DigitalInOut(board.A4) +led_1.direction = Direction.OUTPUT + +leds = [led_0, led_1] + +# pylint: disable=too-many-locals, global-statement, too-many-statements, global-variable-not-assigned +# pylint: disable=too-many-nested-blocks, too-many-branches, too-many-lines + +def initialize_party(freq): + global states + spectrum_group = displayio.Group() + display.root_group = spectrum_group + + low_frac = log(low_bin, 2) / spectrum_bits + frac_range = log(high_bin, 2) / spectrum_bits - low_frac + num_columns = freq + column_table = [] + moving_avg_buffer = [0] * num_columns + smoothing_factor = 0.3 + dynamic_level = 10 + noise_floor = 3.1 + + # Threshold for triggering frame advance (0-1 range, adjust as needed) + trigger_threshold = 0.1 + # Frames to advance when triggered + frames_per_trigger = 1 + # Cooldown frames between advances + frame_cooldown = 1 + + # Load the bitmap + bitmap, palette = adafruit_imageload.load( + "/partyParrotsXtraSmol.bmp", + bitmap=displayio.Bitmap, + palette=displayio.Palette + ) + + # Create 16 parrot grids arranged in a 4x4 layout + parrot_grids = [] + grid_size = 32 # Tile size + grid_cols = int(freq ** 0.5) + grid_rows = int(freq ** 0.5) + + # Calculate spacing to center the grid + total_width = grid_cols * grid_size + total_height = grid_rows * grid_size + start_x = (display.width - total_width) // 2 + start_y = (display.height - total_height) // 2 + + for i in range(num_columns): + row = i // grid_cols + col = i % grid_cols + + parrot_grid = displayio.TileGrid( + bitmap, + width=1, + height=1, + pixel_shader=palette, + tile_height=grid_size, + tile_width=grid_size, + x=start_x + col * grid_size, + y=start_y + row * grid_size + ) + parrot_grids.append(parrot_grid) + spectrum_group.append(parrot_grid) + + # Initialize frame tracking for each bitmap + frame_indices = [0] * num_columns + frame_cooldowns = [0] * num_columns + + # Build frequency mapping table (same as original) + for column in range(num_columns): + lower = low_frac + frac_range * (column / num_columns * 0.95) + upper = low_frac + frac_range * ((column + 1) / num_columns) + mid = (lower + upper) * 0.5 + half_width = (upper - lower) * 0.5 + first_bin = int(2 ** (spectrum_bits * lower) + 1e-4) + last_bin = int(2 ** (spectrum_bits * upper) + 1e-4) + bin_weights = [] + for bin_index in range(first_bin, last_bin + 1): + bin_center = log(bin_index + 0.5, 2) / spectrum_bits + dist = abs(bin_center - mid) / half_width + if dist < 1.0: + dist = 1.0 - dist + bin_weights.append(((3.0 - (dist * 2.0)) * dist) * dist) + total = sum(bin_weights) + bin_weights = [ + (weight / total) * (0.8 + idx / num_columns * 1.4) + for idx, weight in enumerate(bin_weights) + ] + column_table.append([first_bin - low_bin, bin_weights]) + + states = { + "spectrum_group": spectrum_group, + "parrot_grids": parrot_grids, + "frame_indices": frame_indices, + "frame_cooldowns": frame_cooldowns, + "column_table": column_table, + "moving_avg_buffer": moving_avg_buffer, + "smoothing_factor": smoothing_factor, + "dynamic_level": dynamic_level, + "noise_floor": noise_floor, + "num_columns": num_columns, + "trigger_threshold": trigger_threshold, + "frames_per_trigger": frames_per_trigger, + "frame_cooldown": frame_cooldown, + "total_frames": 10, + "bounce_counter": 0, + "bounce_phase": 0, + "bounce_amplitude": 8, + "bounce_speed": 0.1, + "start_x": start_x, + "start_y": start_y, + "grid_size": 32, + "grid_cols": grid_cols, + "grid_rows": grid_rows, + } + +# ------ BITMAP ANIMATION ------ +def party(pos, read): + global states + if read: + # Optionally adjust parameters based on knob positions + states["noise_floor"] = pos + + parrot_grids = states["parrot_grids"] + frame_indices = states["frame_indices"] + frame_cooldowns = states["frame_cooldowns"] + column_table = states["column_table"] + moving_avg_buffer = states["moving_avg_buffer"] + smoothing_factor = states["smoothing_factor"] + dynamic_level = states["dynamic_level"] + noise_floor = states["noise_floor"] + num_columns = states["num_columns"] + trigger_threshold = states["trigger_threshold"] + frames_per_trigger = states["frames_per_trigger"] + frame_cooldown = states["frame_cooldown"] + total_frames = states["total_frames"] + # Update bounce animation + bounce_counter = states["bounce_counter"] + bounce_phase = states["bounce_phase"] + bounce_amplitude = states["bounce_amplitude"] + bounce_speed = states["bounce_speed"] + start_x = states["start_x"] + start_y = states["start_y"] + grid_size = states["grid_size"] + grid_cols = states["grid_cols"] + + # Record and analyze audio + mic.record(rec_buf, fft_size) + samples = np.array(rec_buf) + + spectrum = spectrogram(samples)[low_bin : high_bin + 1] + spectrum = np.log(spectrum + 1e-7) + spectrum = np.maximum(spectrum - noise_floor, 0) + lower = max(np.min(spectrum), 4) + upper = min(max(np.max(spectrum), lower + 12), 20) + + # Dynamic level adjustment + if upper > dynamic_level: + dynamic_level = upper * 0.7 + dynamic_level * 0.3 + else: + dynamic_level = dynamic_level * 0.5 + lower * 0.5 + states["dynamic_level"] = dynamic_level + + # Normalize spectrum data + data = (spectrum - lower) / (dynamic_level - lower) + + # Process each frequency band + for column in range(num_columns): + element = column_table[column] + first_bin = element[0] + bin_weights = element[1] + + # Calculate weighted intensity for this frequency band + intensity = 0 + for bin_offset, weight in enumerate(bin_weights): + if first_bin + bin_offset < len(data): + intensity += data[first_bin + bin_offset] * weight + + # Apply smoothing + moving_avg_buffer[column] = ( + moving_avg_buffer[column] * (1 - smoothing_factor) + + intensity * smoothing_factor + ) + smoothed_intensity = moving_avg_buffer[column] + + # Update cooldown + if frame_cooldowns[column] > 0: + frame_cooldowns[column] -= 1 + + # Check if we should advance the frame + if smoothed_intensity > trigger_threshold and frame_cooldowns[column] == 0: + # Advance frame + frame_indices[column] = (frame_indices[column] + frames_per_trigger) % total_frames + parrot_grids[column][0] = frame_indices[column] + # Set cooldown + frame_cooldowns[column] = frame_cooldown + + # Calculate bounce offset using sine wave + bounce_offset = int(sin(bounce_counter) * bounce_amplitude) + + # Update positions based on phase + for i, parrot in enumerate(parrot_grids): + row = i // grid_cols + col = i % grid_cols + base_x = start_x + col * grid_size + base_y = start_y + row * grid_size + + if bounce_phase == 0: # Rows bounce horizontally + # Even rows go right, odd rows go left + if row % 2 == 0: + parrot.x = base_x + bounce_offset + else: + parrot.x = base_x - bounce_offset + parrot.y = base_y + else: # Columns bounce vertically + # Even columns go up, odd columns go down + if col % 2 == 0: + parrot.y = base_y - bounce_offset + else: + parrot.y = base_y + bounce_offset + parrot.x = base_x + + # Update counter + bounce_counter += bounce_speed + states["bounce_counter"] = bounce_counter + + # Check if we've completed a full bounce cycle + if bounce_counter >= pi * 2: + bounce_counter = 0 + states["bounce_counter"] = 0 + # Switch phase + states["bounce_phase"] = 1 - bounce_phase + + display.refresh() + +# ------ DIAMOND PATTERN INIT ------ +def initialize_diamond(dia_count): + global states + + spectrum_group = displayio.Group() + display.root_group = spectrum_group + + # Create palette with colors + palette = displayio.Palette(8) + palette[0] = 0x000000 # Black background + palette[1] = 0xFF0000 # Red + palette[2] = 0xFF7F00 # Orange + palette[3] = 0xFFFF00 # Yellow + palette[4] = 0x00FF00 # Green + palette[5] = 0x0000FF # Blue + palette[6] = 0xFF00FF # Magenta + palette[7] = 0xFFFFFF # White + + # Create background + background = displayio.Bitmap(display.width, display.height, 8) + background.fill(0) + bg_sprite = displayio.TileGrid(background, pixel_shader=palette) + spectrum_group.append(bg_sprite) + + # Diamond parameters + center_x = display.width // 2 + center_y = display.height // 2 + base_width = 30 + base_height = 50 + + # Side diamonds are half the size + side_base_width = base_width // 2 + side_base_height = base_height // 2 + orbit_radius = 85 # Distance from center + + # Create center diamond + center_initial_points = [ + (center_x, center_y - base_height), # Top + (center_x + base_width, center_y), # Right + (center_x, center_y + base_height), # Bottom + (center_x - base_width, center_y), # Left + ] + + center_diamond = Polygon( + points=center_initial_points, + outline=palette[3], # Yellow outline + stroke=2 + ) + spectrum_group.append(center_diamond) + + # Initialize with 2 side diamonds + num_side_diamonds = dia_count + + # Create new side diamonds + new_diamonds = [] + # Initialize color indices for new diamonds + new_color_indices = [] + for i in range(num_side_diamonds): + angle = (2 * pi * i) / num_side_diamonds # Start from right (0 radians) + x = center_x + int(cos(angle) * orbit_radius) + y = center_y + int(sin(angle) * orbit_radius) + + points = [ + (x, y - side_base_height), # Top + (x + side_base_width, y), # Right + (x, y + side_base_height), # Bottom + (x - side_base_width, y), # Left + ] + + # Determine color based on position/angle + # Normalize angle to 0-360 degrees for easier logic + angle_deg = (angle * 180 / pi) % 360 + + # Right (0°) and Left (180°) - original pair + if abs(angle_deg - 0) < 10 or abs(angle_deg - 180) < 10: + initial_color = 5 # Blue for left/right + # Bottom (90°) and Top (270°) - second pair + elif abs(angle_deg - 90) < 10 or abs(angle_deg - 270) < 10: + initial_color = 2 # Orange for top/bottom + # Diagonals (45°, 135°, 225°, 315°) - third group + else: + initial_color = 6 # Magenta for diagonals + + new_color_indices.append(initial_color) + + diamond = Polygon( + points=points, + outline=palette[initial_color], + stroke=2 + ) + new_diamonds.append(diamond) + spectrum_group.append(diamond) + + states["side_diamonds"] = new_diamonds + states["side_color_indices"] = new_color_indices + print(f"Side diamonds: {num_side_diamonds}") + + states = { + "spectrum_group": spectrum_group, + "center_diamond": center_diamond, + "side_diamonds": new_diamonds, + "palette": palette, + "center_x": center_x, + "center_y": center_y, + "orbit_radius": orbit_radius, + "base_width": base_width, + "base_height": base_height, + "side_base_width": side_base_width, + "side_base_height": side_base_height, + "current_width": base_width, + "current_height": base_height, + "side_current_width": side_base_width, + "side_current_height": side_base_height, + "center_color_index": 3, # Start with yellow + "side_color_indices": new_color_indices, # Individual color for each side diamond + "color_change_counter": 0, # Track which group should change next + "orbit_angle_offset": 0, # For rotating diamonds around center + "orbit_speed": 0.02, # Speed of rotation (radians per frame) + "smoothing_factor": 0.15, # Lower = faster response + "dynamic_level": 10, + "noise_floor": 2.5, # Lower = more sensitive + "frame_count": 0, + "color_timer": 0, + "num_side_diamonds": num_side_diamonds + } + +# ------ DIAMOND PATTERN ANIMATION ------ +def diamonds(pos, read): + global states + + if read: + # Handle both list and single value inputs + if isinstance(pos, (list, tuple)): + states["noise_floor"] = pos[0] + else: + # Single value - use for noise floor only + states["noise_floor"] = pos + + center_diamond = states["center_diamond"] + side_diamonds = states["side_diamonds"] + palette = states["palette"] + center_x = states["center_x"] + center_y = states["center_y"] + orbit_radius = states["orbit_radius"] + base_width = states["base_width"] + base_height = states["base_height"] + side_base_width = states["side_base_width"] + side_base_height = states["side_base_height"] + current_width = states["current_width"] + current_height = states["current_height"] + side_current_width = states["side_current_width"] + side_current_height = states["side_current_height"] + center_color_index = states["center_color_index"] + side_color_indices = states.get("side_color_indices", + [5] * len(side_diamonds)) + smoothing_factor = states["smoothing_factor"] + dynamic_level = states["dynamic_level"] + noise_floor = states["noise_floor"] + color_timer = states["color_timer"] + num_side_diamonds = states["num_side_diamonds"] + orbit_angle_offset = states.get("orbit_angle_offset", 0) + + # Record audio + mic.record(rec_buf, fft_size) + samples = np.array(rec_buf) + + # Get spectrum - same as bars() function + spectrum = spectrogram(samples)[low_bin : high_bin + 1] + spectrum = np.log(spectrum + 1e-7) + spectrum = np.maximum(spectrum - noise_floor, 0) + + # Get min/max for normalization + lower = max(np.min(spectrum), 4) + upper = min(max(np.max(spectrum), lower + 12), 20) + + # Update dynamic level - more aggressive adaptation + if upper > dynamic_level: + dynamic_level = upper * 0.8 + dynamic_level * 0.2 # Faster rise + else: + dynamic_level = dynamic_level * 0.7 + lower * 0.3 # Faster fall + states["dynamic_level"] = dynamic_level + + # Normalize data + if dynamic_level > lower: + data = (spectrum - lower) / (dynamic_level - lower) + else: + data = spectrum * 0 + + # Split spectrum for width and height control + spectrum_len = len(data) + mid_point = spectrum_len // 2 + + # Low frequencies affect height (vertical stretch) + low_level = np.mean(data[0:mid_point]) if mid_point > 0 else 0 + # High frequencies affect width (horizontal stretch) + high_level = np.mean(data[mid_point:]) if mid_point < spectrum_len else 0 + + # Overall level for color changes + overall_level = np.mean(data) + + # Calculate target dimensions for center diamond + target_height = base_height + int(low_level * 120) + target_width = base_width + int(high_level * 60) + + # Smooth the changes - faster response + current_height = int(current_height * (1 - smoothing_factor * 2) + + target_height * smoothing_factor * 2) + current_width = int(current_width * (1 - smoothing_factor * 2) + + target_width * smoothing_factor * 2) + + # Clamp dimensions + current_height = max(20, min(current_height, display.height // 2 - 10)) + current_width = max(10, min(current_width, display.width // 2 - 10)) + + states["current_width"] = current_width + states["current_height"] = current_height + + # Calculate target dimensions for side diamonds (half the scaling) + side_target_height = side_base_height + int(low_level * 60) # Half the scaling + side_target_width = side_base_width + int(high_level * 30) # Half the scaling + + # Smooth the side diamond changes + side_current_height = int(side_current_height * (1 - smoothing_factor * 2) + + side_target_height * smoothing_factor * 2) + side_current_width = int(side_current_width * (1 - smoothing_factor * 2) + + side_target_width * smoothing_factor * 2) + + # Clamp side dimensions + side_current_height = max(10, min(side_current_height, display.height // 4 - 5)) + side_current_width = max(5, min(side_current_width, display.width // 4 - 5)) + + states["side_current_width"] = side_current_width + states["side_current_height"] = side_current_height + + # Update center diamond points + center_new_points = [ + (center_x, center_y - current_height), # Top + (center_x + current_width, center_y), # Right + (center_x, center_y + current_height), # Bottom + (center_x - current_width, center_y), # Left + ] + center_diamond.points = center_new_points + + # Update orbit angle for rotation - speed up with audio + # Base speed plus audio-reactive component + base_speed = 0.02 + audio_speed_boost = overall_level * 0.08 # Speed boost based on audio level + current_orbit_speed = base_speed + audio_speed_boost + + orbit_angle_offset += current_orbit_speed + if orbit_angle_offset >= 2 * pi: + orbit_angle_offset -= 2 * pi + states["orbit_angle_offset"] = orbit_angle_offset + + # Update side diamonds points with rotation + for i, diamond in enumerate(side_diamonds): + # Calculate angle with rotation offset + base_angle = (2 * pi * i) / num_side_diamonds # Original position + angle = base_angle + orbit_angle_offset # Add rotation + x = center_x + int(cos(angle) * orbit_radius) + y = center_y + int(sin(angle) * orbit_radius) + + new_points = [ + (x, y - side_current_height), # Top + (x + side_current_width, y), # Right + (x, y + side_current_height), # Bottom + (x - side_current_width, y), # Left + ] + diamond.points = new_points + + # Color cycling based on threshold + # Calculate threshold based on noise floor + color_threshold = 0.05 + (noise_floor - 2.0) * 0.02 + color_threshold = max(0.0, min(color_threshold, 0.15)) # Clamp between 0.0 and 0.15 + + color_timer += 1 + # Change colors when we hit the threshold OR after timeout + if overall_level > color_threshold or color_timer > 60: + # Center diamond ALWAYS goes forward through colors + center_color_index = (center_color_index % 7) + 1 + states["center_color_index"] = center_color_index + center_diamond.outline = palette[center_color_index] + + # Get or initialize color change counter + color_change_counter = states.get("color_change_counter", 0) + + # Side diamonds alternate which group changes + new_side_indices = [] + + # Track unique colors for each group + blue_idx = None + orange_idx = None + magenta_idx = None + + for i, diamond in enumerate(side_diamonds): + current_color = side_color_indices[i] + + # Determine which color group this diamond belongs to (based on ORIGINAL position) + base_angle = (2 * pi * i) / num_side_diamonds + angle_deg = (base_angle * 180 / pi) % 360 + + # Determine if this diamond should change based on the pattern + should_change = False + + if num_side_diamonds == 2: + # With 2 diamonds: always change (all are left/right) + should_change = True + elif num_side_diamonds == 4: + # With 4 diamonds: alternate between left/right and top/bottom + if color_change_counter % 2 == 0: + # Change left/right + if abs(angle_deg - 0) < 10 or abs(angle_deg - 180) < 10: + should_change = True + else: + # Change top/bottom + if abs(angle_deg - 90) < 10 or abs(angle_deg - 270) < 10: + should_change = True + else: # 8 diamonds + # Pattern: left/right -> diagonals -> top/bottom -> diagonals -> repeat + pattern_position = color_change_counter % 4 + if pattern_position == 0: + # Change left/right + if abs(angle_deg - 0) < 10 or abs(angle_deg - 180) < 10: + should_change = True + elif pattern_position in (1, 3): + # Change diagonals + if not (abs(angle_deg - 0) < 10 or abs(angle_deg - 180) < 10 or + abs(angle_deg - 90) < 10 or abs(angle_deg - 270) < 10): + should_change = True + else: # pattern_position == 2 + # Change top/bottom + if abs(angle_deg - 90) < 10 or abs(angle_deg - 270) < 10: + should_change = True + + # Apply color change or keep current color + if should_change: + # Right (0°) and Left (180°) - blue group + if abs(angle_deg - 0) < 10 or abs(angle_deg - 180) < 10: + if blue_idx is None: + blue_idx = current_color - 1 + if blue_idx < 1: + blue_idx = 7 + color_idx = blue_idx + # Bottom (90°) and Top (270°) - orange group + elif abs(angle_deg - 90) < 10 or abs(angle_deg - 270) < 10: + if orange_idx is None: + orange_idx = current_color - 1 + if orange_idx < 1: + orange_idx = 7 + color_idx = orange_idx + # Diagonals - magenta group + else: + if magenta_idx is None: + magenta_idx = current_color - 1 + if magenta_idx < 1: + magenta_idx = 7 + color_idx = magenta_idx + else: + # Keep current color + color_idx = current_color + + new_side_indices.append(color_idx) + diamond.outline = palette[color_idx] + + states["side_color_indices"] = new_side_indices + states["color_change_counter"] = color_change_counter + 1 + + color_timer = 0 + + states["color_timer"] = color_timer + states["frame_count"] += 1 + + display.refresh() + +# ------ LINES PATTERN INIT ------ +def initialize_lines(num_lines=8): + global states + + spectrum_group = displayio.Group() + display.root_group = spectrum_group + + # Create palette with colors + palette = displayio.Palette(8) + palette[0] = 0x000000 # Black background + palette[1] = 0xFF0000 # Red + palette[2] = 0xFF7F00 # Orange + palette[3] = 0xFFFF00 # Yellow + palette[4] = 0x00FF00 # Green + palette[5] = 0x0000FF # Blue + palette[6] = 0xFF00FF # Magenta + palette[7] = 0xFFFFFF # White + + # Create background + background = displayio.Bitmap(display.width, display.height, 8) + background.fill(0) + bg_sprite = displayio.TileGrid(background, pixel_shader=palette) + spectrum_group.append(bg_sprite) + + # Create lines - split evenly between vertical and horizontal + lines = [] + line_data = [] # Store line properties for animation + num_vertical = num_lines // 2 + num_horizontal = num_lines - num_vertical + + # Create vertical lines (full height) + for i in range(num_vertical): + x = randint(20, display.width - 20) + thickness = randint(2, 5) # Random thickness between 2 and 5 + color_idx = (i % 7) + 1 # Cycle through colors 1-7 + + # Create a thin vertical rectangle + line = vectorio.Rectangle( + pixel_shader=palette, + width=thickness, + height=display.height, + x=x, + y=0, + color_index=color_idx + ) + lines.append(line) + spectrum_group.append(line) + + # Store line data for animation + line_data.append({ + 'type': 'vertical', + 'base_x': x, + 'current_x': x, + 'jitter_amount': 0, + 'color_index': color_idx, + 'thickness': thickness + }) + + # Create horizontal lines (full width) + for i in range(num_horizontal): + y = randint(20, display.height - 20) + thickness = randint(2, 5) # Random thickness between 2 and 5 + color_idx = ((i + num_vertical) % 7) + 1 # Continue color cycle + + # Create a thin horizontal rectangle + line = vectorio.Rectangle( + pixel_shader=palette, + width=display.width, + height=thickness, + x=0, + y=y, + color_index=color_idx + ) + lines.append(line) + spectrum_group.append(line) + + # Store line data for animation + line_data.append({ + 'type': 'horizontal', + 'base_y': y, + 'current_y': y, + 'jitter_amount': 0, + 'color_index': color_idx, + 'thickness': thickness + }) + + states = { + "spectrum_group": spectrum_group, + "lines": lines, + "line_data": line_data, + "palette": palette, + "smoothing_factor": 0.15, + "dynamic_level": 10, + "noise_floor": 2.5, + "color_timer": 0, + "jitter_decay": 0.9, # How quickly jitter settles (higher = smoother) + "max_jitter": 20, # Maximum jitter distance + "num_lines": num_lines, + "color_change_threshold": 0.3, + "trigger_threshold": 0.15, # Lower threshold for more sensitivity + } + +# ------ LINES PATTERN ANIMATION ------ +def lines_pattern(pos, read): + global states + + if read: + if isinstance(pos, (list, tuple)): + states["noise_floor"] = pos[0] + else: + states["noise_floor"] = pos + + lines = states["lines"] + line_data = states["line_data"] + dynamic_level = states["dynamic_level"] + noise_floor = states["noise_floor"] + color_timer = states["color_timer"] + jitter_decay = states["jitter_decay"] + max_jitter = states["max_jitter"] + num_lines = states["num_lines"] + color_change_threshold = states["color_change_threshold"] + trigger_threshold = states["trigger_threshold"] + + # Record audio + mic.record(rec_buf, fft_size) + samples = np.array(rec_buf) + + # Get spectrum + spectrum = spectrogram(samples)[low_bin : high_bin + 1] + spectrum = np.log(spectrum + 1e-7) + spectrum = np.maximum(spectrum - noise_floor, 0) + + # Get min/max for normalization + lower = max(np.min(spectrum), 4) + upper = min(max(np.max(spectrum), lower + 12), 20) + + # Update dynamic level + if upper > dynamic_level: + dynamic_level = upper * 0.8 + dynamic_level * 0.2 + else: + dynamic_level = dynamic_level * 0.7 + lower * 0.3 + states["dynamic_level"] = dynamic_level + + # Normalize data + if dynamic_level > lower: + data = (spectrum - lower) / (dynamic_level - lower) + else: + data = spectrum * 0 + + # Split spectrum into bands for each line + spectrum_len = len(data) + num_lines = states["num_lines"] + band_size = max(1, spectrum_len // num_lines) # Ensure at least 1 + + # Update each line based on its frequency band + for i, (line, line_info) in enumerate(zip(lines, line_data)): + # Get the frequency band for this line + band_start = i * band_size + band_end = min(band_start + band_size, spectrum_len) + + if band_end > band_start: + band_level = np.mean(data[band_start:band_end]) + else: + band_level = 0 + + # Apply jitter based on band level + if band_level > trigger_threshold: # Threshold for triggering jitter + # Add new jitter based on intensity + new_jitter = band_level * max_jitter * choice([-1, 1]) + line_info['jitter_amount'] = line_info['jitter_amount'] * 0.7 + new_jitter * 0.3 + else: + # Decay existing jitter + line_info['jitter_amount'] *= jitter_decay + + # Clamp jitter + line_info['jitter_amount'] = max(-max_jitter, min(max_jitter, line_info['jitter_amount'])) + + # Apply jitter to line position + if line_info['type'] == 'vertical': + # Vertical lines jitter left/right + new_x = int(line_info['base_x'] + line_info['jitter_amount']) + # Clamp to screen bounds (accounting for thickness) + new_x = max(0, min(display.width - line_info['thickness'], new_x)) + line_info['current_x'] = new_x + + # Update rectangle position + line.x = new_x + else: + # Horizontal lines jitter up/down + new_y = int(line_info['base_y'] + line_info['jitter_amount']) + # Clamp to screen bounds (accounting for thickness) + new_y = max(0, min(display.height - line_info['thickness'], new_y)) + line_info['current_y'] = new_y + + # Update rectangle position + line.y = new_y + + # Color changes based on intensity + if band_level > color_change_threshold: + # Cycle to next color (skip black at index 0) + line_info['color_index'] = (line_info['color_index'] % 7) + 1 + line.color_index = line_info['color_index'] + + color_timer += 1 + states["color_timer"] = color_timer + + display.refresh() + +# Add these variables at the top of your main loop +mode = 0 +new_mode = True +diamond_count_index = 0 +diamond_count_options = [2, 4, 8] +update_diamonds = False +party_count_index = 0 +party_count_options = [1, 4, 9, 16] +update_party = False +lines_count_index = 0 +lines_count_options = [8, 12, 16, 20] +update_lines = False + +# Auto-cycle mode variables +auto_cycle_active = False +cycle_frame_counter = 0 +cycle_current_mode = 0 +FRAMES_PER_MODE = 60 + +# Main loop +while True: + event = keys.events.get() + if event: + if event.pressed: + leds[event.key_number].value = True + if event.key_number == 0: + # Cycle through modes: 0=diamond, 1=bars, 2=lines, 3=auto-cycle + mode = (mode + 1) % 4 + new_mode = True + + # Handle auto-cycle mode LED + if mode == 3: + auto_cycle_active = True + # Keep LED on for auto-cycle mode + leds[0].value = True + else: + auto_cycle_active = False + # LED will turn off on button release for normal modes + + elif event.key_number == 1 and not auto_cycle_active: + # Button 2 only works when not in auto-cycle mode + if mode == 0: + diamond_count_index = (diamond_count_index + 1) % 3 + update_diamonds = True + elif mode == 1: + party_count_index = (party_count_index + 1) % 4 + update_party = True + elif mode == 2: + lines_count_index = (lines_count_index + 1) % 4 + update_lines = True + else: + # Only turn off LED if not in auto-cycle mode + if event.key_number == 0 and not auto_cycle_active: + leds[0].value = False + elif event.key_number == 1: + leds[1].value = False + print(event) + + # Initialize new mode + if new_mode: + if mode == 0: + initialize_diamond(diamond_count_options[diamond_count_index]) + elif mode == 1: + initialize_party(party_count_options[party_count_index]) + elif mode == 2: + initialize_lines(lines_count_options[lines_count_index]) + elif mode == 3: + + # Randomize starting counts + diamond_count_index = randint(0, (len(diamond_count_options) - 1)) + party_count_index = randint(0, (len(party_count_options) - 1)) + lines_count_index = randint(0, (len(lines_count_options) - 1)) + + # Start with a random animation + cycle_current_mode = randint(0, 2) + cycle_frame_counter = 0 + + # Initialize the first random animation + if cycle_current_mode == 0: + initialize_diamond(diamond_count_options[diamond_count_index]) + elif cycle_current_mode == 1: + initialize_party(party_count_options[party_count_index]) + elif cycle_current_mode == 2: + initialize_lines(lines_count_options[lines_count_index]) + new_mode = False + + # Handle manual count updates + if update_diamonds and mode == 0: + initialize_diamond(diamond_count_options[diamond_count_index]) + update_diamonds = False + if update_party and mode == 1: + initialize_party(party_count_options[party_count_index]) + update_party = False + if update_lines and mode == 2: + initialize_lines(lines_count_options[lines_count_index]) + update_lines = False + + # Run animations + noise = simpleio.map_range(val(pot1), 0, 65535, 3.5, 1.5) + + if mode == 0: + diamonds(noise, read_pots) + elif mode == 1: + party(noise, read_pots) + elif mode == 2: + lines_pattern(noise, read_pots) + elif mode == 3: + # Auto-cycle mode + cycle_frame_counter += 1 + + # Check if it's time to switch animations + if cycle_frame_counter >= FRAMES_PER_MODE: + cycle_frame_counter = 0 + cycle_current_mode = randint(0, 2) + + # Initialize the next animation with random count + if cycle_current_mode == 0: + diamond_count_index = randint(0, (len(diamond_count_options) - 1)) + initialize_diamond(diamond_count_options[diamond_count_index]) + elif cycle_current_mode == 1: + party_count_index = randint(0, (len(party_count_options) - 1)) + initialize_party(party_count_options[party_count_index]) + elif cycle_current_mode == 2: + lines_count_index = randint(0, (len(lines_count_options) - 1)) + initialize_lines(lines_count_options[lines_count_index]) + + # Run the current animation + if cycle_current_mode == 0: + diamonds(noise, read_pots) + elif cycle_current_mode == 1: + party(noise, read_pots) + elif cycle_current_mode == 2: + lines_pattern(noise, read_pots) diff --git a/Fruit_Jam/Fruit_Jam_Video_Music/partyParrotsXtraSmol.bmp b/Fruit_Jam/Fruit_Jam_Video_Music/partyParrotsXtraSmol.bmp new file mode 100644 index 000000000..945282f8a Binary files /dev/null and b/Fruit_Jam/Fruit_Jam_Video_Music/partyParrotsXtraSmol.bmp differ diff --git a/Fruit_Jam/Larsio_Paint_Music/code.py b/Fruit_Jam/Larsio_Paint_Music/code.py new file mode 100755 index 000000000..7f449e14d --- /dev/null +++ b/Fruit_Jam/Larsio_Paint_Music/code.py @@ -0,0 +1,104 @@ +# SPDX-FileCopyrightText: 2025 John Park and Claude AI for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +Larsio Paint Music +Fruit Jam w mouse, HDMI, audio out +or Metro RP2350 with EYESPI DVI breakout and TLV320DAC3100 breakout on STEMMA_I2C, +pin D7 reset, 9/10/11 = BCLC/WSEL/DIN +""" +# pylint: disable=invalid-name,too-few-public-methods,broad-except,redefined-outer-name + +# Main application file for Larsio Paint Music + +import time +import gc +from sound_manager import SoundManager +from note_manager import NoteManager +from ui_manager import UIManager + +# Configuration +AUDIO_OUTPUT = "i2s" # Options: "pwm" or "i2s" + +class MusicStaffApp: + """Main application class that ties everything together""" + + def __init__(self, audio_output="pwm"): + # Initialize the sound manager with selected audio output + # Calculate tempo parameters + BPM = 120 # Beats per minute + SECONDS_PER_BEAT = 60 / BPM + SECONDS_PER_EIGHTH = SECONDS_PER_BEAT / 2 + + # Initialize components in a specific order + # First, force garbage collection to free memory + gc.collect() + + # Initialize the sound manager + print("Initializing sound manager...") + self.sound_manager = SoundManager( + audio_output=audio_output, + seconds_per_eighth=SECONDS_PER_EIGHTH + ) + + # Give hardware time to stabilize + time.sleep(0.5) + gc.collect() + + # Initialize the note manager + print("Initializing note manager...") + self.note_manager = NoteManager( + start_margin=25, # START_MARGIN + staff_y_start=int(240 * 0.1), # STAFF_Y_START + line_spacing=int((240 - int(240 * 0.1) - int(240 * 0.2)) * 0.95) // 8 # LINE_SPACING + ) + + gc.collect() + + # Initialize the UI manager + print("Initializing UI manager...") + self.ui_manager = UIManager(self.sound_manager, self.note_manager) + + def run(self): + """Set up and run the application""" + # Setup the display and UI + print("Setting up display...") + self.ui_manager.setup_display() + + # Give hardware time to stabilize + time.sleep(0.5) + gc.collect() + + # Try to find the mouse + if self.ui_manager.find_mouse(): + print("Mouse found successfully!") + else: + print("WARNING: Mouse not found.") + print("The application will run, but mouse control may be limited.") + + # Enter the main loop + self.ui_manager.main_loop() + + +# Create and run the application +if __name__ == "__main__": + # Start with garbage collection + gc.collect() + print("Starting Music Staff Application...") + + try: + app = MusicStaffApp(audio_output=AUDIO_OUTPUT) + app.run() + except Exception as e: # pylint: disable=broad-except + print(f"Error with I2S audio: {e}") + + # Force garbage collection + gc.collect() + time.sleep(1) + + # Fallback to PWM + try: + app = MusicStaffApp(audio_output="pwm") + app.run() + except Exception as e2: # pylint: disable=broad-except + print(f"Fatal error: {e2}") diff --git a/Fruit_Jam/Larsio_Paint_Music/control_panel.py b/Fruit_Jam/Larsio_Paint_Music/control_panel.py new file mode 100755 index 000000000..e49ef1e11 --- /dev/null +++ b/Fruit_Jam/Larsio_Paint_Music/control_panel.py @@ -0,0 +1,353 @@ +# SPDX-FileCopyrightText: 2025 John Park and Claude AI for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +# control_panel.py: CircuitPython Music Staff Application component +""" + +# pylint: disable=import-error +from displayio import Group, Bitmap, Palette, TileGrid +from adafruit_display_text.bitmap_label import Label +import terminalio + + +# pylint: disable=invalid-name,no-member,too-many-instance-attributes,too-many-arguments +# pylint: disable=too-many-branches,too-many-statements, trailing-whitespace +class ControlPanel: + """Manages transport controls and channel selectors""" + + def __init__(self, screen_width, screen_height): + self.SCREEN_WIDTH = screen_width + self.SCREEN_HEIGHT = screen_height + + # Button dimensions + self.BUTTON_WIDTH = 64 # Updated for bitmap buttons + self.BUTTON_HEIGHT = 48 # Updated for bitmap buttons + self.BUTTON_SPACING = 10 + + # Channel button dimensions + self.CHANNEL_BUTTON_SIZE = 20 + self.CHANNEL_BUTTON_SPACING = 5 + self.CHANNEL_BUTTON_Y = 5 + + # Transport area + self.TRANSPORT_AREA_Y = (int(screen_height * 0.1) + + int((screen_height - int(screen_height * 0.1) - + int(screen_height * 0.2)) * 0.95) + 10) + + # State + self.is_playing = False + self.loop_enabled = False + + # Channel colors (reduced from 8 to 6) + self.CHANNEL_COLORS = [ + 0x000000, # Channel 1: Black (default) + 0xFF0000, # Channel 2: Red + 0x00FF00, # Channel 3: Green + 0x0000FF, # Channel 4: Blue + 0xFF00FF, # Channel 5: Magenta + 0xFFAA00, # Channel 6: Orange + ] + self.current_channel = 0 + + # UI elements + self.play_button = None + self.stop_button = None + self.loop_button = None + self.clear_button = None + self.play_button_bitmap = None + self.stop_button_bitmap = None + self.loop_button_bitmap = None + self.clear_button_bitmap = None + self.channel_selector = None + + # For bitmap buttons + self.button_sprites = None + + # Center points for fallback play/loop buttons + self.play_center_x = self.BUTTON_WIDTH // 2 + self.play_center_y = self.BUTTON_HEIGHT // 2 + self.play_size = 10 + self.loop_center_x = self.BUTTON_WIDTH // 2 + self.loop_center_y = self.BUTTON_HEIGHT // 2 + self.loop_radius = 6 + + def create_channel_buttons(self): + """Create channel selector buttons at the top of the screen using sprites""" + channel_group = Group() + + # Add a highlight indicator for the selected channel (yellow outline only) + # Create bitmap for channel selector with appropriate dimensions + btn_size = self.CHANNEL_BUTTON_SIZE + channel_select_bitmap = Bitmap(btn_size + 6, btn_size + 6, 2) + channel_select_palette = Palette(2) + channel_select_palette[0] = 0x444444 # Same as background color (dark gray) + channel_select_palette[1] = 0xFFFF00 # Yellow highlight + channel_select_palette.make_transparent(0) # Make background transparent + + # Draw just the outline (no filled background) + bitmap_size = btn_size + 6 + for x in range(bitmap_size): + for y in range(bitmap_size): + # Draw only the border pixels + if (x == 0 or x == bitmap_size - 1 or + y == 0 or y == bitmap_size - 1): + channel_select_bitmap[x, y] = 1 # Yellow outline + else: + channel_select_bitmap[x, y] = 0 # Transparent background + + self.channel_selector = TileGrid( + channel_select_bitmap, + pixel_shader=channel_select_palette, + x=7, + y=self.CHANNEL_BUTTON_Y - 3 + ) + channel_group.append(self.channel_selector) + + return channel_group, self.channel_selector + + def create_transport_controls(self, sprite_manager): + """Create transport controls using bitmap buttons""" + transport_group = Group() + + # Check if button sprites were successfully loaded + if (sprite_manager.play_up is None or sprite_manager.stop_up is None or + sprite_manager.loop_up is None or sprite_manager.clear_up is None): + print("Warning: Button sprites not loaded, using fallback buttons") + return self._create_fallback_transport_controls() + + # Button spacing based on the new size (64x48) + button_spacing = 10 + button_y = self.SCREEN_HEIGHT - 50 # Allow some margin at bottom + + # Create TileGrids for each button using the "up" state initially + self.stop_button = TileGrid( + sprite_manager.stop_up, + pixel_shader=sprite_manager.stop_up_palette, + x=10, + y=button_y + ) + + self.play_button = TileGrid( + sprite_manager.play_up, + pixel_shader=sprite_manager.play_up_palette, + x=10 + 64 + button_spacing, + y=button_y + ) + + self.loop_button = TileGrid( + sprite_manager.loop_up, + pixel_shader=sprite_manager.loop_up_palette, + x=10 + 2 * (64 + button_spacing), + y=button_y + ) + + self.clear_button = TileGrid( + sprite_manager.clear_up, + pixel_shader=sprite_manager.clear_up_palette, + x=10 + 3 * (64 + button_spacing), + y=button_y + ) + + # Store references to the button bitmaps and palettes + self.button_sprites = { + 'play': { + 'up': (sprite_manager.play_up, sprite_manager.play_up_palette), + 'down': (sprite_manager.play_down, sprite_manager.play_down_palette) + }, + 'stop': { + 'up': (sprite_manager.stop_up, sprite_manager.stop_up_palette), + 'down': (sprite_manager.stop_down, sprite_manager.stop_down_palette) + }, + 'loop': { + 'up': (sprite_manager.loop_up, sprite_manager.loop_up_palette), + 'down': (sprite_manager.loop_down, sprite_manager.loop_down_palette) + }, + 'clear': { + 'up': (sprite_manager.clear_up, sprite_manager.clear_up_palette), + 'down': (sprite_manager.clear_down, sprite_manager.clear_down_palette) + } + } + + # Save the button dimensions + self.BUTTON_WIDTH = 64 + self.BUTTON_HEIGHT = 48 + + # Add buttons to the group + transport_group.append(self.stop_button) + transport_group.append(self.play_button) + transport_group.append(self.loop_button) + transport_group.append(self.clear_button) + + return (transport_group, self.play_button, self.stop_button, + self.loop_button, self.clear_button) + + # pylint: disable=too-many-locals + def _create_fallback_transport_controls(self): + """Create fallback transport controls using drawn buttons (original implementation)""" + transport_group = Group() + + # Create button bitmaps + self.play_button_bitmap = Bitmap(self.BUTTON_WIDTH, self.BUTTON_HEIGHT, 3) + self.stop_button_bitmap = Bitmap(self.BUTTON_WIDTH, self.BUTTON_HEIGHT, 3) + self.loop_button_bitmap = Bitmap(self.BUTTON_WIDTH, self.BUTTON_HEIGHT, 3) + self.clear_button_bitmap = Bitmap(self.BUTTON_WIDTH, self.BUTTON_HEIGHT, 3) + + # Button palettes with custom colors + play_button_palette = Palette(3) + play_button_palette[0] = 0x444444 # Dark gray background + play_button_palette[1] = 0x000000 # Black text/border + play_button_palette[2] = 0xFFD700 # Golden yellow for active state + + stop_button_palette = Palette(3) + stop_button_palette[0] = 0x444444 # Dark gray background + stop_button_palette[1] = 0x000000 # Black text/border + stop_button_palette[2] = 0xFF00FF # Magenta for active state + + loop_button_palette = Palette(3) + loop_button_palette[0] = 0x444444 # Dark gray background + loop_button_palette[1] = 0x000000 # Black text/border + loop_button_palette[2] = 0xFFD700 # Golden yellow for active state + + clear_button_palette = Palette(3) + clear_button_palette[0] = 0x444444 # Dark gray background + clear_button_palette[1] = 0x000000 # Black text/border + clear_button_palette[2] = 0xFF0000 # Red for pressed state + + # Create Stop button + for x in range(self.BUTTON_WIDTH): + for y in range(self.BUTTON_HEIGHT): + # Draw border + if (x == 0 or x == self.BUTTON_WIDTH - 1 or + y == 0 or y == self.BUTTON_HEIGHT - 1): + self.stop_button_bitmap[x, y] = 1 + # Fill with magenta (active state) + else: + self.stop_button_bitmap[x, y] = 2 + + # Create Play button + for x in range(self.BUTTON_WIDTH): + for y in range(self.BUTTON_HEIGHT): + # Draw border + if (x == 0 or x == self.BUTTON_WIDTH - 1 or + y == 0 or y == self.BUTTON_HEIGHT - 1): + self.play_button_bitmap[x, y] = 1 + # Fill with gray (inactive state) + else: + self.play_button_bitmap[x, y] = 0 + + # Draw play symbol (triangle) + for y in range( + self.play_center_y - self.play_size//2, + self.play_center_y + self.play_size//2 + ): + width = (y - (self.play_center_y - self.play_size//2)) // 2 + for x in range( + self.play_center_x - self.play_size//4, + self.play_center_x - self.play_size//4 + width + ): + if 0 <= x < self.BUTTON_WIDTH and 0 <= y < self.BUTTON_HEIGHT: + self.play_button_bitmap[x, y] = 1 + + # Create Loop button + for x in range(self.BUTTON_WIDTH): + for y in range(self.BUTTON_HEIGHT): + # Draw border + if (x == 0 or x == self.BUTTON_WIDTH - 1 or + y == 0 or y == self.BUTTON_HEIGHT - 1): + self.loop_button_bitmap[x, y] = 1 + # Fill with gray (inactive state) + else: + self.loop_button_bitmap[x, y] = 0 + + # Draw loop symbol (circle with arrow) + for x in range(self.BUTTON_WIDTH): + for y in range(self.BUTTON_HEIGHT): + dx = x - self.loop_center_x + dy = y - self.loop_center_y + # Draw circle outline + if self.loop_radius - 1 <= (dx*dx + dy*dy)**0.5 <= self.loop_radius + 1: + if 0 <= x < self.BUTTON_WIDTH and 0 <= y < self.BUTTON_HEIGHT: + self.loop_button_bitmap[x, y] = 1 + + # Add arrow to loop symbol + for i in range(4): + x = self.loop_center_x + int(self.loop_radius * 0.7) - i + y = self.loop_center_y - self.loop_radius - 1 + i + if 0 <= x < self.BUTTON_WIDTH and 0 <= y < self.BUTTON_HEIGHT: + self.loop_button_bitmap[x, y] = 1 + + x = self.loop_center_x + int(self.loop_radius * 0.7) - i + y = self.loop_center_y - self.loop_radius - 1 - i + 2 + if 0 <= x < self.BUTTON_WIDTH and 0 <= y < self.BUTTON_HEIGHT: + self.loop_button_bitmap[x, y] = 1 + + # Create Clear button + for x in range(self.BUTTON_WIDTH): + for y in range(self.BUTTON_HEIGHT): + # Draw border + if (x == 0 or x == self.BUTTON_WIDTH - 1 or + y == 0 or y == self.BUTTON_HEIGHT - 1): + self.clear_button_bitmap[x, y] = 1 + # Fill with gray background + else: + self.clear_button_bitmap[x, y] = 0 + + # Create button TileGrids + x_offset = 10 + y_pos = self.SCREEN_HEIGHT - 40 + + self.stop_button = TileGrid( + self.stop_button_bitmap, + pixel_shader=stop_button_palette, + x=x_offset, + y=y_pos + ) + + x_offset += self.BUTTON_WIDTH + self.BUTTON_SPACING + self.play_button = TileGrid( + self.play_button_bitmap, + pixel_shader=play_button_palette, + x=x_offset, + y=y_pos + ) + + x_offset += self.BUTTON_WIDTH + self.BUTTON_SPACING + self.loop_button = TileGrid( + self.loop_button_bitmap, + pixel_shader=loop_button_palette, + x=x_offset, + y=y_pos + ) + + x_offset += self.BUTTON_WIDTH + self.BUTTON_SPACING + self.clear_button = TileGrid( + self.clear_button_bitmap, + pixel_shader=clear_button_palette, + x=x_offset, + y=y_pos + ) + + # Add buttons to group + transport_group.append(self.stop_button) + transport_group.append(self.play_button) + transport_group.append(self.loop_button) + transport_group.append(self.clear_button) + + # Add "CLEAR" text to clear button + text_color = 0x000000 # Black text + label_x = self.clear_button.x + self.BUTTON_WIDTH // 2 + label_y = self.clear_button.y + self.BUTTON_HEIGHT // 2 + + clear_label = Label( + terminalio.FONT, + text="CLEAR", + color=text_color, + scale=1 + ) + clear_label.anchor_point = (0.5, 0.5) # Center the text + clear_label.anchored_position = (label_x, label_y) + transport_group.append(clear_label) + + return (transport_group, self.play_button, self.stop_button, + self.loop_button, self.clear_button) diff --git a/Fruit_Jam/Larsio_Paint_Music/cursor_manager.py b/Fruit_Jam/Larsio_Paint_Music/cursor_manager.py new file mode 100755 index 000000000..995824ed4 --- /dev/null +++ b/Fruit_Jam/Larsio_Paint_Music/cursor_manager.py @@ -0,0 +1,85 @@ +# SPDX-FileCopyrightText: 2025 John Park and Claude AI for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +# cursor_manager.py: CircuitPython Music Staff Application component +""" + +# pylint: disable=import-error +from displayio import Bitmap, Palette, TileGrid + + +# pylint: disable=invalid-name,no-member,too-many-instance-attributes +# pylint: disable=too-many-arguments,too-many-branches,too-many-statements +class CursorManager: + """Manages cursor appearance and position""" + + def __init__(self, bg_color=0x8AAD8A): + self.bg_color = bg_color + + # Cursors + self.crosshair_cursor = None + self.triangle_cursor = None + self.current_cursor = None + + self.create_cursors() + + def create_cursors(self): + """Create custom cursor bitmaps for different areas""" + # Regular crosshair cursor for staff area + crosshair_cursor_bitmap = Bitmap(8, 8, 2) + crosshair_cursor_palette = Palette(2) + crosshair_cursor_palette[0] = self.bg_color # Background color (sage green) + crosshair_cursor_palette[1] = 0x000000 # Cursor color (black) + crosshair_cursor_palette.make_transparent(0) # Make background transparent + + for i in range(8): + crosshair_cursor_bitmap[i, 3] = 1 + crosshair_cursor_bitmap[i, 4] = 1 + crosshair_cursor_bitmap[3, i] = 1 + crosshair_cursor_bitmap[4, i] = 1 + + # Triangle cursor for controls area + triangle_cursor_bitmap = Bitmap(12, 12, 2) + triangle_cursor_palette = Palette(2) + triangle_cursor_palette[0] = 0x000000 # Background color + triangle_cursor_palette[1] = 0x000000 # Cursor color (black) + triangle_cursor_palette.make_transparent(0) # Make background transparent + + # Draw a triangle cursor + for y in range(12): + width = y // 2 + 1 # Triangle gets wider as y increases + for x in range(width): + triangle_cursor_bitmap[x, y] = 1 + + # Create a TileGrid for each cursor type + self.crosshair_cursor = TileGrid( + crosshair_cursor_bitmap, + pixel_shader=crosshair_cursor_palette + ) + self.triangle_cursor = TileGrid( + triangle_cursor_bitmap, + pixel_shader=triangle_cursor_palette + ) + + # Initially use crosshair cursor + self.current_cursor = self.crosshair_cursor + self.triangle_cursor.hidden = True + + return self.crosshair_cursor, self.triangle_cursor + + def set_cursor_position(self, x, y): + """Set the position of the current cursor""" + self.current_cursor.x = x + self.current_cursor.y = y + + def switch_cursor(self, use_triangle=False): + """Switch between crosshair and triangle cursor""" + if use_triangle and self.current_cursor != self.triangle_cursor: + self.crosshair_cursor.hidden = True + self.triangle_cursor.hidden = False + self.current_cursor = self.triangle_cursor + elif not use_triangle and self.current_cursor != self.crosshair_cursor: + self.triangle_cursor.hidden = True + self.crosshair_cursor.hidden = False + self.current_cursor = self.crosshair_cursor diff --git a/Fruit_Jam/Larsio_Paint_Music/display_manager.py b/Fruit_Jam/Larsio_Paint_Music/display_manager.py new file mode 100755 index 000000000..ede7e296a --- /dev/null +++ b/Fruit_Jam/Larsio_Paint_Music/display_manager.py @@ -0,0 +1,57 @@ +# SPDX-FileCopyrightText: 2025 John Park and Claude AI for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +# display_manager.py: CircuitPython Music Staff Application component +""" +# pylint: disable=import-error,invalid-name,no-member,too-many-instance-attributes,too-many-arguments,too-many-branches,too-many-statements + +import supervisor +import displayio +from adafruit_fruitjam.peripherals import request_display_config + + + +class DisplayManager: + """Manages the display initialization and basic display operations""" + + + def __init__(self, width=320, height=240): + self.SCREEN_WIDTH = width + self.SCREEN_HEIGHT = height + self.display = None + self.main_group = None + + def initialize_display(self): + """Initialize the DVI display""" + # Use the Fruit Jam library to set up display, that way on DAC fallback + # the display doesn't attempt to be re-initialized + + request_display_config(self.SCREEN_WIDTH, self.SCREEN_HEIGHT,color_depth=16) + + # Create the display + self.display = supervisor.runtime.display + + # Create main group + self.main_group = displayio.Group() + + # Set the display's root group + self.display.root_group = self.main_group + + return self.main_group, self.display + + def create_background(self, color=0x888888): + """Create a background with the given color""" + bg_bitmap = displayio.Bitmap(self.SCREEN_WIDTH, self.SCREEN_HEIGHT, 1) + bg_palette = displayio.Palette(1) + bg_palette[0] = color + + # Fill the bitmap with the background color + for x in range(self.SCREEN_WIDTH): + for y in range(self.SCREEN_HEIGHT): + bg_bitmap[x, y] = 0 + + # Create a TileGrid with the background bitmap + bg_grid = displayio.TileGrid(bg_bitmap, pixel_shader=bg_palette, x=0, y=0) + + return bg_grid diff --git a/Fruit_Jam/Larsio_Paint_Music/input_handler.py b/Fruit_Jam/Larsio_Paint_Music/input_handler.py new file mode 100755 index 000000000..23e7d3151 --- /dev/null +++ b/Fruit_Jam/Larsio_Paint_Music/input_handler.py @@ -0,0 +1,90 @@ +# SPDX-FileCopyrightText: 2025 John Park and Claude AI for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +# input_handler.py: CircuitPython Music Staff Application component +""" + +from adafruit_usb_host_mouse import find_and_init_boot_mouse + +# pylint: disable=invalid-name,no-member,too-many-instance-attributes,too-many-arguments +# pylint: disable=too-many-branches,too-many-statements,broad-except +# pylint: disable=too-many-nested-blocks,too-many-locals,no-self-use +class InputHandler: + """Handles user input through mouse and interactions with UI elements""" + + def __init__(self, screen_width, screen_height, staff_y_start, staff_height): + self.SCREEN_WIDTH = screen_width + self.SCREEN_HEIGHT = screen_height + self.STAFF_Y_START = staff_y_start + self.STAFF_HEIGHT = staff_height + + # Mouse state + self.last_left_button_state = 0 + self.last_right_button_state = 0 + self.left_button_pressed = False + self.right_button_pressed = False + self.mouse = None + self.buf = None + self.in_endpoint = None + + # Mouse position + self.mouse_x = screen_width // 2 + self.mouse_y = screen_height // 2 + + def find_mouse(self): + self.mouse = find_and_init_boot_mouse(cursor_image=None) + if self.mouse is None: + print("Failed to find a working mouse after multiple attempts") + return False + + # Change the mouse resolution so it's not too sensitive + self.mouse.sensitivity = 4 + + return True + + def process_mouse_input(self): + """Process mouse input - simplified version without wheel support""" + buttons = self.mouse.update() + + # Extract button states + if buttons is None: + current_left_button_state = 0 + current_right_button_state = 0 + else: + current_left_button_state = 1 if 'left' in buttons else 0 + current_right_button_state = 1 if 'right' in buttons else 0 + + # Detect button presses + if current_left_button_state == 1 and self.last_left_button_state == 0: + self.left_button_pressed = True + else: + self.left_button_pressed = False + + if current_right_button_state == 1 and self.last_right_button_state == 0: + self.right_button_pressed = True + else: + self.right_button_pressed = False + + # Update button states + self.last_left_button_state = current_left_button_state + self.last_right_button_state = current_right_button_state + + # Update position + self.mouse_x = self.mouse.x + self.mouse_y = self.mouse.y + + # Ensure position stays within bounds + self.mouse_x = max(0, min(self.SCREEN_WIDTH - 1, self.mouse_x)) + self.mouse_y = max(0, min(self.SCREEN_HEIGHT - 1, self.mouse_y)) + + return True + + def point_in_rect(self, x, y, rect_x, rect_y, rect_width, rect_height): + """Check if a point is inside a rectangle""" + return (rect_x <= x < rect_x + rect_width and + rect_y <= y < rect_y + rect_height) + + def is_over_staff(self, y): + """Check if mouse is over the staff area""" + return self.STAFF_Y_START <= y <= self.STAFF_Y_START + self.STAFF_HEIGHT diff --git a/Fruit_Jam/Larsio_Paint_Music/lpm_icon.bmp b/Fruit_Jam/Larsio_Paint_Music/lpm_icon.bmp new file mode 100644 index 000000000..864c33fa0 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/lpm_icon.bmp differ diff --git a/Fruit_Jam/Larsio_Paint_Music/metadata.json b/Fruit_Jam/Larsio_Paint_Music/metadata.json new file mode 100644 index 000000000..338fedaba --- /dev/null +++ b/Fruit_Jam/Larsio_Paint_Music/metadata.json @@ -0,0 +1,4 @@ +{ + "title": "LarsioPant", + "icon": "lpm_icon.bmp" +} diff --git a/Fruit_Jam/Larsio_Paint_Music/note_manager.py b/Fruit_Jam/Larsio_Paint_Music/note_manager.py new file mode 100755 index 000000000..9a6a9dad3 --- /dev/null +++ b/Fruit_Jam/Larsio_Paint_Music/note_manager.py @@ -0,0 +1,425 @@ +# SPDX-FileCopyrightText: 2025 John Park and Claude AI for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +# note_manager.py: CircuitPython Music Staff Application component +""" + +# pylint: disable=import-error +from displayio import Group, Bitmap, Palette, TileGrid + + +# pylint: disable=invalid-name,no-member,too-many-instance-attributes,too-many-arguments +# pylint: disable=too-many-branches,too-many-statements,protected-access,too-many-locals +# pylint: disable=trailing-whitespace +class NoteManager: + """Manages notes, their positions, and related data""" + + def __init__(self, start_margin, staff_y_start, line_spacing): + self.note_data = [] # List of (x_position, y_position, midi_note, midi_channel) + self.notes_group = Group() + self.ledger_lines_group = Group() + self.note_to_ledger = {} # Mapping from note indices to ledger line indices + + # Key staff parameters + self.START_MARGIN = start_margin + self.STAFF_Y_START = staff_y_start + self.LINE_SPACING = line_spacing + + # Note positions and their MIDI values + self.note_positions = self._create_note_positions() + self.x_positions = [] # Will be populated by the UI manager + + # Create note bitmaps + self.NOTE_WIDTH = (line_spacing // 2) - 2 + self.NOTE_HEIGHT = (line_spacing // 2) - 2 + self.note_bitmap = self._create_note_bitmap() + + # Create ledger line bitmap + self.ledger_line_width = 14 + self.ledger_line_height = 2 + self.ledger_bitmap = Bitmap(self.ledger_line_width, self.ledger_line_height, 2) + for x in range(self.ledger_line_width): + for y in range(self.ledger_line_height): + self.ledger_bitmap[x, y] = 1 + + self.ledger_palette = Palette(2) + self.ledger_palette[0] = 0x8AAD8A # Transparent (sage green background) + self.ledger_palette[1] = 0x000000 # Black for ledger lines + + # MIDI note mapping for each position + self.midi_notes = { + 0: 59, # B3 + 1: 60, # C4 (middle C) + 2: 62, # D4 + 3: 64, # E4 + 4: 65, # F4 + 5: 67, # G4 + 6: 69, # A4 + 7: 71, # B4 + 8: 72, # C5 + 9: 74, # D5 + 10: 76, # E5 + 11: 77, # F5 + 12: 79 # G5 + } + + # Map of positions to note names (for treble clef) + self.note_names = { + 0: "B3", # B below middle C (ledger line) + 1: "C4", # Middle C (ledger line below staff) + 2: "D4", # Space below staff + 3: "E4", # Bottom line + 4: "F4", # First space + 5: "G4", # Second line + 6: "A4", # Second space + 7: "B4", # Middle line + 8: "C5", # Third space + 9: "D5", # Fourth line + 10: "E5", # Fourth space + 11: "F5", # Top line + 12: "G5" # Space above staff + } + + def _create_note_positions(self): + """Create the vertical positions for notes on the staff""" + note_positions = [] + + # Calculate positions from the bottom up + bottom_line_y = self.STAFF_Y_START + 5 * self.LINE_SPACING # Bottom staff line (E) + + # B3 (ledger line below staff) + note_positions.append(bottom_line_y + self.LINE_SPACING + self.LINE_SPACING // 2) + + # Middle C4 (ledger line below staff) + note_positions.append(bottom_line_y + self.LINE_SPACING) + + # D4 (space below staff) + note_positions.append(bottom_line_y + self.LINE_SPACING // 2) + + # E4 (bottom line) + note_positions.append(bottom_line_y) + + # F4 (first space) + note_positions.append(bottom_line_y - self.LINE_SPACING // 2) + + # G4 (second line) + note_positions.append(bottom_line_y - self.LINE_SPACING) + + # A4 (second space) + note_positions.append(bottom_line_y - self.LINE_SPACING - self.LINE_SPACING // 2) + + # B4 (middle line) + note_positions.append(bottom_line_y - 2 * self.LINE_SPACING) + + # C5 (third space) + note_positions.append(bottom_line_y - 2 * self.LINE_SPACING - self.LINE_SPACING // 2) + + # D5 (fourth line) + note_positions.append(bottom_line_y - 3 * self.LINE_SPACING) + + # E5 (fourth space) + note_positions.append(bottom_line_y - 3 * self.LINE_SPACING - self.LINE_SPACING // 2) + + # F5 (top line) + note_positions.append(bottom_line_y - 4 * self.LINE_SPACING) + + # G5 (space above staff) + note_positions.append(bottom_line_y - 4 * self.LINE_SPACING - self.LINE_SPACING // 2) + + return note_positions + + def _create_note_bitmap(self): + """Create a bitmap for a quarter note (circular shape)""" + note_bitmap = Bitmap(self.NOTE_WIDTH, self.NOTE_HEIGHT, 2) + + # Draw a circular shape for the note head + cx = self.NOTE_WIDTH // 2 + cy = self.NOTE_HEIGHT // 2 + radius = self.NOTE_WIDTH // 2 + + for y in range(self.NOTE_HEIGHT): + for x in range(self.NOTE_WIDTH): + # Use the circle equation (x-cx)² + (y-cy)² ≤ r² to determine if pixel is in circle + if ((x - cx) ** 2 + (y - cy) ** 2) <= (radius ** 2): + note_bitmap[x, y] = 1 + + return note_bitmap + + def find_closest_position(self, y): + """Find the closest valid note position to a given y-coordinate""" + closest_pos = 0 + min_distance = abs(y - self.note_positions[0]) + + for i, pos in enumerate(self.note_positions): + distance = abs(y - pos) + if distance < min_distance: + min_distance = distance + closest_pos = i + + return closest_pos + + def find_closest_x_position(self, x): + """Find the closest valid horizontal position""" + # Only allow positions after the double bar at beginning + if x < self.START_MARGIN: + return self.x_positions[0] # Return first valid position + + closest_x = self.x_positions[0] + min_distance = abs(x - closest_x) + + for pos in self.x_positions: + distance = abs(x - pos) + if distance < min_distance: + min_distance = distance + closest_x = pos + + return closest_x + + def note_exists_at_position(self, x_pos, y_pos, mario_head, mario_palette): + """Check if a note exists at the exact position (for adding new notes)""" + # Only check for exact overlap, not proximity + for note_tg in self.notes_group: + # Check if this is a Mario head note or a regular note + is_mario = (hasattr(note_tg.pixel_shader, "_palette") and + len(note_tg.pixel_shader._palette) > 1 and + note_tg.pixel_shader._palette[0] == mario_palette[0]) + + if is_mario: + note_width = mario_head.width + note_height = mario_head.height + else: + note_width = self.NOTE_WIDTH + note_height = self.NOTE_HEIGHT + + note_x = note_tg.x + note_width // 2 + note_y = note_tg.y + note_height // 2 + + # Only prevent notes from being in the exact same position (with a tiny tolerance) + if abs(note_x - x_pos) < 2 and abs(note_y - y_pos) < 2: + return True + return False + + def find_note_at(self, x, y, mario_head, mario_palette): + """Check if a note already exists at a position and return its index""" + for i, note_tg in enumerate(self.notes_group): + # Check if this is a Mario head note or a regular note + is_mario = (hasattr(note_tg.pixel_shader, "_palette") and + len(note_tg.pixel_shader._palette) > 1 and + note_tg.pixel_shader._palette[0] == mario_palette[0]) + + if is_mario: + note_width = mario_head.width + note_height = mario_head.height + else: + note_width = self.NOTE_WIDTH + note_height = self.NOTE_HEIGHT + + # Check if the note's center is within a reasonable distance of the cursor + note_center_x = note_tg.x + note_width // 2 + note_center_y = note_tg.y + note_height // 2 + + # Use a slightly larger hit box for easier clicking + hit_box_width = max(self.NOTE_WIDTH, note_width) + hit_box_height = max(self.NOTE_HEIGHT, note_height) + + if (abs(x-note_center_x) < hit_box_width) and (abs(y - note_center_y) < hit_box_height): + return i + return None + + def add_note( + self, + x, + y, + current_channel, + note_palettes, + mario_head, + mario_palette, + heart_note, + heart_palette, + sound_manager + ): + """Add a note at the specified position""" + # Enforce the minimum x position (after the double bar at beginning) + if x < self.START_MARGIN: + return (False, "Notes must be after the double bar") + + # Find the closest valid position + position_index = self.find_closest_position(y) + y_position = self.note_positions[position_index] + + # Find the closest valid horizontal position + x_position = self.find_closest_x_position(x) + + # Check if a note already exists at this exact position + if self.note_exists_at_position(x_position, y_position, mario_head, mario_palette): + return (False, "Note already exists here") + + # Get the corresponding MIDI note number + midi_note = self.midi_notes[position_index] + + # Create a TileGrid for the note based on channel + if current_channel == 0: # Channel 1 (index 0) uses Mario head + note_tg = TileGrid(mario_head, pixel_shader=mario_palette) + # Adjust position offset based on the size of mario_head bitmap + note_width = mario_head.width + note_height = mario_head.height + note_tg.x = x_position - note_width // 2 + note_tg.y = y_position - note_height // 2 + elif current_channel == 1: # Channel 2 uses Heart note + note_tg = TileGrid(heart_note, pixel_shader=heart_palette) + # Adjust position offset based on the size of heart_note bitmap + note_width = heart_note.width + note_height = heart_note.height + note_tg.x = x_position - note_width // 2 + note_tg.y = y_position - note_height // 2 + elif current_channel == 2: # Channel 3 uses Drum note + note_tg = TileGrid(mario_head, pixel_shader=mario_palette) + # Adjust position offset based on the size + note_width = mario_head.width + note_height = mario_head.height + note_tg.x = x_position - note_width // 2 + note_tg.y = y_position - note_height // 2 + elif current_channel in (3, 4, 5): # Channels 4-6 use custom sprites + # We'll pass appropriate sprites in ui_manager + note_tg = TileGrid(mario_head, pixel_shader=mario_palette) + note_width = mario_head.width + note_height = mario_head.height + note_tg.x = x_position - note_width // 2 + note_tg.y = y_position - note_height // 2 + else: # Other channels use the colored circle + note_tg = TileGrid(self.note_bitmap, pixel_shader=note_palettes[current_channel]) + note_tg.x = x_position - self.NOTE_WIDTH // 2 + note_tg.y = y_position - self.NOTE_HEIGHT // 2 + + # Play the appropriate sound + sound_manager.play_note(midi_note, current_channel) + + # Add the note to the notes group + note_index = len(self.notes_group) + self.notes_group.append(note_tg) + + # Store the note data for playback with channel information + self.note_data.append((x_position, y_position, midi_note, current_channel)) + + # Add a ledger line if it's the B3 or C4 below staff + if position_index <= 1: # B3 or C4 + ledger_tg = TileGrid(self.ledger_bitmap, pixel_shader=self.ledger_palette) + ledger_tg.x = x_position - self.ledger_line_width // 2 + ledger_tg.y = y_position + ledger_index = len(self.ledger_lines_group) + self.ledger_lines_group.append(ledger_tg) + + # Track association between note and its ledger line + self.note_to_ledger[note_index] = ledger_index + + note_name = self.note_names[position_index] + return (True, f"Added: Ch{current_channel+1} {note_name}") + + def erase_note(self, x, y, mario_head, mario_palette, sound_manager=None): + """Erase a note at the clicked position""" + # Try to find a note at the click position + note_index = self.find_note_at(x, y, mario_head, mario_palette) + + if note_index is not None: + # Get the position of the note + note_tg = self.notes_group[note_index] + + # Check if this is a Mario head note or a regular note + is_mario = (hasattr(note_tg.pixel_shader, "_palette") and + len(note_tg.pixel_shader._palette) > 1 and + note_tg.pixel_shader._palette[0] == mario_palette[0]) + + if is_mario: + note_width = mario_head.width + note_height = mario_head.height + else: + note_width = self.NOTE_WIDTH + note_height = self.NOTE_HEIGHT + + note_x = note_tg.x + note_width // 2 + note_y = note_tg.y + note_height // 2 + + # Find the corresponding note data + found_data_index = None + # found_channel = None # Unused variable + + for i, (x_pos, y_pos, _midi_note, _channel) in enumerate(self.note_data): + # Increased tolerance for position matching + if abs(x_pos - note_x) < 5 and abs(y_pos - note_y) < 5: + found_data_index = i + break + + # If we found the note data and have a sound manager reference + if found_data_index is not None and sound_manager is not None: + # Extract note data + x_pos, y_pos, _midi_note, channel = self.note_data[found_data_index] + + # If this is a sample-based note (channels 0, 1, or 2), stop it + if channel in [0, 1, 2]: + sound_manager.stop_sample_at_position(x_pos, y_pos, channel) + + # Remove the note data + self.note_data.pop(found_data_index) + print(f"Erased note at position ({x_pos}, {y_pos}) ch {channel+1}") + else: + # Still remove the note data if found (for backward compatibility) + if found_data_index is not None: + self.note_data.pop(found_data_index) + + # Check if this note has an associated ledger line + if note_index in self.note_to_ledger: + ledger_index = self.note_to_ledger[note_index] + + # Remove the ledger line + self.ledger_lines_group.pop(ledger_index) + + # Update ledger line mappings after removing a ledger line + new_note_to_ledger = {} + + # Process each mapping + for n_idx, l_idx in self.note_to_ledger.items(): + # Skip the note we're removing + if n_idx != note_index: + # Adjust indices for ledger lines after the removed one + if l_idx > ledger_index: + new_note_to_ledger[n_idx] = l_idx - 1 + else: + new_note_to_ledger[n_idx] = l_idx + + self.note_to_ledger = new_note_to_ledger + + # Remove the note + self.notes_group.pop(note_index) + + # Update mappings for notes with higher indices + new_note_to_ledger = {} + for n_idx, l_idx in self.note_to_ledger.items(): + if n_idx > note_index: + new_note_to_ledger[n_idx - 1] = l_idx + else: + new_note_to_ledger[n_idx] = l_idx + + self.note_to_ledger = new_note_to_ledger + + return (True, "Note erased") + + return (False, "No note found at this position") + + def clear_all_notes(self, sound_manager=None): + """Clear all notes from the staff""" + # Stop all sample playback if we have a sound manager + if sound_manager is not None: + sound_manager.stop_all_notes() + + # Remove all notes + while len(self.notes_group) > 0: + self.notes_group.pop() + + # Remove all ledger lines + while len(self.ledger_lines_group) > 0: + self.ledger_lines_group.pop() + + # Clear note data and ledger line mappings + self.note_data = [] + self.note_to_ledger = {} diff --git a/Fruit_Jam/Larsio_Paint_Music/playback_controller.py b/Fruit_Jam/Larsio_Paint_Music/playback_controller.py new file mode 100755 index 000000000..f6810ae3e --- /dev/null +++ b/Fruit_Jam/Larsio_Paint_Music/playback_controller.py @@ -0,0 +1,143 @@ +# SPDX-FileCopyrightText: 2025 John Park and Claude AI for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +Playback controller for CircuitPython Music Staff Application. +Manages the playback state, button displays, and sound triggering. +""" + +import time + +# pylint: disable=trailing-whitespace, too-many-instance-attributes +class PlaybackController: + """Manages playback state and controls""" + + def __init__(self, sound_manager, note_manager, seconds_per_eighth=0.25): + """Initialize the playback controller with sound and note managers""" + self.sound_manager = sound_manager + self.note_manager = note_manager + self.seconds_per_eighth = seconds_per_eighth + + # Playback state + self.is_playing = False + self.playhead_position = -1 + self.last_playhead_time = 0 + self.loop_enabled = False + + # UI elements (to be set externally) + self.playhead = None + self.play_button = None + self.play_button_bitmap = None + self.stop_button = None + self.stop_button_bitmap = None + + # Button sprites (will be set in set_ui_elements) + self.button_sprites = None + + def set_ui_elements(self, playhead, play_button, stop_button, button_sprites=None): + """Set references to UI elements needed for playback control""" + self.playhead = playhead + self.play_button = play_button + self.stop_button = stop_button + self.button_sprites = button_sprites + + def start_playback(self, start_margin=25): + """Start playback""" + self.is_playing = True + self.playhead_position = -1 # Start at -1 so first note plays immediately + self.last_playhead_time = time.monotonic() + + # Set playhead position to just before the first note + self.playhead.x = start_margin - 5 + + # Update button states using bitmaps + if hasattr(self, 'button_sprites') and self.button_sprites is not None: + # Update play button to "down" state + self.play_button.bitmap = self.button_sprites['play']['down'][0] + self.play_button.pixel_shader = self.button_sprites['play']['down'][1] + + # Update stop button to "up" state + self.stop_button.bitmap = self.button_sprites['stop']['up'][0] + self.stop_button.pixel_shader = self.button_sprites['stop']['up'][1] + else: + # Fallback implementation for drawn buttons + # Note: This section is for backward compatibility but has issues + # Ideally, button_sprites should always be provided + print("Warning: Using fallback button display (not fully supported)") + # The fallback code is intentionally omitted as it has errors + # and requires refactoring of the bitmap handling + + print("Playback started") + + def stop_playback(self): + """Stop playback""" + self.sound_manager.stop_all_notes() + self.is_playing = False + self.playhead.x = -10 # Move off-screen + + # Update button states using bitmaps + if hasattr(self, 'button_sprites') and self.button_sprites is not None: + # Update play button to "up" state + self.play_button.bitmap = self.button_sprites['play']['up'][0] + self.play_button.pixel_shader = self.button_sprites['play']['up'][1] + + # Update stop button to "down" state + self.stop_button.bitmap = self.button_sprites['stop']['down'][0] + self.stop_button.pixel_shader = self.button_sprites['stop']['down'][1] + else: + # Fallback implementation for drawn buttons + # Note: This section is for backward compatibility but has issues + # Ideally, button_sprites should always be provided + print("Warning: Using fallback button display (not fully supported)") + # The fallback code is intentionally omitted as it has errors + # and requires refactoring of the bitmap handling + + print("Playback stopped") + + def set_tempo(self, seconds_per_eighth): + """Update the playback tempo""" + self.seconds_per_eighth = seconds_per_eighth + print(f"Playback tempo updated: {60 / (seconds_per_eighth * 2)} BPM") + + def update_playback(self, x_positions): + """Update playback state and play notes at current position""" + if not self.is_playing: + return + + current_time = time.monotonic() + elapsed = current_time - self.last_playhead_time + + # Move at tempo rate + if elapsed >= self.seconds_per_eighth: + # Stop all current active notes + self.sound_manager.stop_all_notes() + + # Move playhead to next eighth note position + self.playhead_position += 1 + self.last_playhead_time = current_time + + # Check if we've reached the end + if self.playhead_position >= len(x_positions): + if self.loop_enabled: + # Loop back to the beginning + self.playhead_position = 0 + self.playhead.x = x_positions[0] - 1 + else: + # Stop playback if not looping + self.stop_playback() + return + + # Update playhead position + self.playhead.x = x_positions[self.playhead_position] - 1 + + # Find all notes at current playhead position + current_x = x_positions[self.playhead_position] + notes_at_position = [] + + for x_pos, y_pos, midi_note, channel in self.note_manager.note_data: + if abs(x_pos - current_x) < 2: # Note is at current position + notes_at_position.append((x_pos, y_pos, midi_note, channel)) + + # Play all notes at the current position + if notes_at_position: + self.sound_manager.play_notes_at_position(notes_at_position) diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/chat_01.wav b/Fruit_Jam/Larsio_Paint_Music/samples/chat_01.wav new file mode 100755 index 000000000..f4606c333 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/chat_01.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/crash_01.wav b/Fruit_Jam/Larsio_Paint_Music/samples/crash_01.wav new file mode 100755 index 000000000..3d0c64acb Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/crash_01.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/kick_01.wav b/Fruit_Jam/Larsio_Paint_Music/samples/kick_01.wav new file mode 100755 index 000000000..f404cf804 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/kick_01.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/larso_A4.wav b/Fruit_Jam/Larsio_Paint_Music/samples/larso_A4.wav new file mode 100755 index 000000000..0e8f56621 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/larso_A4.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/larso_B3.wav b/Fruit_Jam/Larsio_Paint_Music/samples/larso_B3.wav new file mode 100755 index 000000000..92331cc65 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/larso_B3.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/larso_B4.wav b/Fruit_Jam/Larsio_Paint_Music/samples/larso_B4.wav new file mode 100755 index 000000000..b71c7f80e Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/larso_B4.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/larso_C4.wav b/Fruit_Jam/Larsio_Paint_Music/samples/larso_C4.wav new file mode 100755 index 000000000..f0ca34ec1 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/larso_C4.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/larso_C5.wav b/Fruit_Jam/Larsio_Paint_Music/samples/larso_C5.wav new file mode 100755 index 000000000..da435ddc6 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/larso_C5.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/larso_D4.wav b/Fruit_Jam/Larsio_Paint_Music/samples/larso_D4.wav new file mode 100755 index 000000000..e9120da70 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/larso_D4.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/larso_D5.wav b/Fruit_Jam/Larsio_Paint_Music/samples/larso_D5.wav new file mode 100755 index 000000000..872406794 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/larso_D5.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/larso_E4.wav b/Fruit_Jam/Larsio_Paint_Music/samples/larso_E4.wav new file mode 100755 index 000000000..151a141ed Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/larso_E4.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/larso_E5.wav b/Fruit_Jam/Larsio_Paint_Music/samples/larso_E5.wav new file mode 100755 index 000000000..8d8c45c19 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/larso_E5.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/larso_F4.wav b/Fruit_Jam/Larsio_Paint_Music/samples/larso_F4.wav new file mode 100755 index 000000000..419c8e4bb Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/larso_F4.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/larso_F5.wav b/Fruit_Jam/Larsio_Paint_Music/samples/larso_F5.wav new file mode 100755 index 000000000..7fd14ff10 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/larso_F5.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/larso_G4.wav b/Fruit_Jam/Larsio_Paint_Music/samples/larso_G4.wav new file mode 100755 index 000000000..eab079aa1 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/larso_G4.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/larso_G5.wav b/Fruit_Jam/Larsio_Paint_Music/samples/larso_G5.wav new file mode 100755 index 000000000..22cdae793 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/larso_G5.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_A4.wav b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_A4.wav new file mode 100755 index 000000000..4173e55c4 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_A4.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_B3.wav b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_B3.wav new file mode 100755 index 000000000..da6d8f84d Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_B3.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_B4.wav b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_B4.wav new file mode 100755 index 000000000..7a2ea264a Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_B4.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_C4.wav b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_C4.wav new file mode 100755 index 000000000..b870ac3c4 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_C4.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_C5.wav b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_C5.wav new file mode 100755 index 000000000..50febe988 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_C5.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_D4.wav b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_D4.wav new file mode 100755 index 000000000..843ada638 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_D4.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_D5.wav b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_D5.wav new file mode 100755 index 000000000..f43f9a1e3 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_D5.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_E4.wav b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_E4.wav new file mode 100755 index 000000000..609095e70 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_E4.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_E5.wav b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_E5.wav new file mode 100755 index 000000000..561b45931 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_E5.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_F4.wav b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_F4.wav new file mode 100755 index 000000000..081be3cb2 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_F4.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_F5.wav b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_F5.wav new file mode 100755 index 000000000..96b4b6640 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_F5.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_G4.wav b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_G4.wav new file mode 100755 index 000000000..31f19a0e1 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_G4.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_G5.wav b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_G5.wav new file mode 100755 index 000000000..7a0b5fd8c Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/musicnote16_G5.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/ohat_01.wav b/Fruit_Jam/Larsio_Paint_Music/samples/ohat_01.wav new file mode 100755 index 000000000..3c41e6a3a Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/ohat_01.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/samples/snare_01.wav b/Fruit_Jam/Larsio_Paint_Music/samples/snare_01.wav new file mode 100755 index 000000000..004be30a8 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/samples/snare_01.wav differ diff --git a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py new file mode 100755 index 000000000..259ea4ae4 --- /dev/null +++ b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py @@ -0,0 +1,628 @@ +# SPDX-FileCopyrightText: 2025 John Park and Claude AI for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +# sound_manager.py: CircuitPython Music Staff Application component +""" +# pylint: disable=import-error, trailing-whitespace +# +import math +import time +import array +import json +import gc +import os +import digitalio + +import adafruit_midi +import audiobusio +import audiocore +import audiopwmio +import audiomixer +import synthio +import board +import adafruit_pathlib as pathlib +import adafruit_fruitjam +from adafruit_midi.note_on import NoteOn +from adafruit_midi.note_off import NoteOff +import usb_midi + + +# pylint: disable=invalid-name,no-member,too-many-instance-attributes,too-many-arguments +# pylint: disable=too-many-branches,too-many-statements,too-many-locals,broad-except +# pylint: disable=cell-var-from-loop,undefined-loop-variable +class SoundManager: + """Handles playback of both MIDI notes and WAV samples, and synthio for channels 3-5""" + + def __init__(self, audio_output="pwm", seconds_per_eighth=0.25): + """ + Initialize the sound manager + + Parameters: + audio_output (str): The type of audio output to use - "pwm" or "i2s" + seconds_per_eighth (float): Duration of an eighth note in seconds + """ + # Initialize USB MIDI + self.midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=0) + self.active_notes = {} # {note_number: channel} + + # Store timing information + self.seconds_per_eighth = seconds_per_eighth + + # Initialize audio output based on selected type + self.audio_output_type = audio_output + self.tlv = None + + if self.audio_output_type == "pwm": + # Setup PWM audio output on D10 + self.audio = audiopwmio.PWMAudioOut(board.D10) + else: # i2s + # optional configuration file for speaker/headphone setting + launcher_config = {} + for directory in ("/", "/sd/", "/saves/"): + launcher_config_path = directory + "launcher.conf.json" + if pathlib.Path(launcher_config_path).exists(): + with open(launcher_config_path, "r") as f: + launcher_config = launcher_config | json.load(f) + if "audio" not in launcher_config: + launcher_config["audio"] = {} + + try: + # Import libraries needed for I2S + #check for Metro RP2350 vs. Fruit Jam + board_type = os.uname().machine + + if 'Metro RP2350' in board_type: + print("Metro setup") + reset_pin = digitalio.DigitalInOut(board.D7) + reset_pin.direction = digitalio.Direction.OUTPUT + reset_pin.value = False # Set low to reset + time.sleep(0.1) # Pause 100ms + reset_pin.value = True # Set high to release from reset + + # Initialize TLV320 + fjPeriphs = adafruit_fruitjam.Peripherals( + audio_output=launcher_config["audio"].get("output", "headphone"), + safe_volume_limit= + launcher_config["audio"].get("volume_override_danger",.75), + sample_rate=11025, + bit_depth=16, + i2c=board.STEMMA_I2C() + ) + + self.tlv = fjPeriphs.dac + fjPeriphs.audio = audiobusio.I2SOut(board.D9, board.D10, board.D11) + + elif 'Fruit Jam' in board_type: + print("Fruit Jam setup") + reset_pin = digitalio.DigitalInOut(board.PERIPH_RESET) + reset_pin.direction = digitalio.Direction.OUTPUT + reset_pin.value = False + time.sleep(0.1) + reset_pin.value = True + + # Initialize TLV320 + fjPeriphs = adafruit_fruitjam.Peripherals( + audio_output=launcher_config["audio"].get("output", "headphone"), + safe_volume_limit= + launcher_config["audio"].get("volume_override_danger",.75), + sample_rate=11025, + bit_depth=16, + i2c=board.I2C() + ) + + self.tlv = fjPeriphs.dac + + # If volume was specified use it, otherwise use the fruitjam library default + if "volume" in launcher_config["audio"]: + fjPeriphs.volume = launcher_config["audio"]["volume"] # FruitJam vol 0.0-1.0 + + # Setup I2S audio output - important to do this AFTER configuring the DAC + # Fruitjam library actually does this before we modify the configuration + # but after the initial default configuration is performed + self.audio = fjPeriphs.audio + + print("TLV320 I2S DAC initialized successfully") + except Exception as e: + print(f"Error initializing TLV320 DAC: {e}") + print("Falling back to PWM audio output") + fjPeriphs.deinit() + # Fallback to PWM if I2S initialization fails + self.audio = audiopwmio.PWMAudioOut(board.D10) + + # Create an audio mixer with multiple voices + self.mixer = audiomixer.Mixer( + voice_count=6, + sample_rate=11025, + channel_count=1, + bits_per_sample=16, + samples_signed=True + ) + self.audio.play(self.mixer) + + # Track which voices are being used for samples + # First 3 for regular samples, next 3 for playback-only + self.active_voices = [False, False, False, False, False, False] + + # Track which note position corresponds to which voice + # This will help us stop samples when notes are erased + self.position_to_voice = {} # {(x_pos, y_pos): voice_index} + + # Track which voice is used for which channel during playback + self.playback_voice_mapping = {} # {(x_pos, y_pos, channel): voice_index} + + # Load multiple WAV samples at different pitches + try: + # Channel 1 samples + self.samples = { + 59: audiocore.WaveFile("samples/larso_B3.wav"), # B3 + 60: audiocore.WaveFile("samples/larso_C4.wav"), # C4 + 62: audiocore.WaveFile("samples/larso_D4.wav"), # D4 + 64: audiocore.WaveFile("samples/larso_E4.wav"), # E4 + 65: audiocore.WaveFile("samples/larso_F4.wav"), # F4 + 67: audiocore.WaveFile("samples/larso_G4.wav"), # G4 + 69: audiocore.WaveFile("samples/larso_A4.wav"), # A4 + 71: audiocore.WaveFile("samples/larso_B4.wav"), # B4 + 72: audiocore.WaveFile("samples/larso_C5.wav"), # C5 + 74: audiocore.WaveFile("samples/larso_D5.wav"), # D5 + 76: audiocore.WaveFile("samples/larso_E5.wav"), # E5 + 77: audiocore.WaveFile("samples/larso_F5.wav"), # F5 + 79: audiocore.WaveFile("samples/larso_G5.wav"), # G5 + } + print("Loaded channel 1 WAV samples") + + # Load samples for channel 2 + self.heart_samples = { + 59: audiocore.WaveFile("samples/musicnote16_B3.wav"), # B3 + 60: audiocore.WaveFile("samples/musicnote16_C4.wav"), # C4 + 62: audiocore.WaveFile("samples/musicnote16_D4.wav"), # D4 + 64: audiocore.WaveFile("samples/musicnote16_E4.wav"), # E4 + 65: audiocore.WaveFile("samples/musicnote16_F4.wav"), # F4 + 67: audiocore.WaveFile("samples/musicnote16_G4.wav"), # G4 + 69: audiocore.WaveFile("samples/musicnote16_A4.wav"), # A4 + 71: audiocore.WaveFile("samples/musicnote16_B4.wav"), # B4 + 72: audiocore.WaveFile("samples/musicnote16_C5.wav"), # C5 + 74: audiocore.WaveFile("samples/musicnote16_D5.wav"), # D5 + 76: audiocore.WaveFile("samples/musicnote16_E5.wav"), # E5 + 77: audiocore.WaveFile("samples/musicnote16_F5.wav"), # F5 + 79: audiocore.WaveFile("samples/musicnote16_G5.wav"), # G5 + } + print("Loaded channel 2 WAV samples") + + # Load samples for channel 3 (drum samples) + self.drum_samples = {} + try: + self.drum_samples = { + 59: audiocore.WaveFile("samples/kick_01.wav"), + 60: audiocore.WaveFile("samples/kick_01.wav"), + 62: audiocore.WaveFile("samples/kick_01.wav"), + 64: audiocore.WaveFile("samples/snare_01.wav"), + 65: audiocore.WaveFile("samples/snare_01.wav"), + 67: audiocore.WaveFile("samples/snare_01.wav"), + 69: audiocore.WaveFile("samples/chat_01.wav"), + 71: audiocore.WaveFile("samples/chat_01.wav"), + 72: audiocore.WaveFile("samples/chat_01.wav"), + 74: audiocore.WaveFile("samples/ohat_01.wav"), + 76: audiocore.WaveFile("samples/ohat_01.wav"), + 77: audiocore.WaveFile("samples/crash_01.wav"), + 79: audiocore.WaveFile("samples/crash_01.wav"), + } + print("Loaded channel 3 WAV samples (drums)") + except Exception as e: + print(f"Error loading drum samples: {e}") + # Fallback - use the same samples as channel 1 + self.drum_samples = self.samples + print("Using fallback samples for channel 3") + + except Exception as e: + print(f"Error loading WAV samples: {e}") + # Fallback to basic samples if there's an error + self.samples = { + 65: audiocore.WaveFile("samples/musicnote01.wav"), # Default sample + } + self.heart_samples = self.samples # Use same samples as fallback + self.drum_samples = self.samples # Use same samples as fallback + + # Initialize synthio for channels 4-6 + self.synth = synthio.Synthesizer(sample_rate=11025) + # Use the last voice for synthio + self.mixer.voice[5].play(self.synth) + + # Set lower volume for synthio channel + self.mixer.voice[5].level = 0.3 + + # Create waveforms for different synthio channels + SAMPLE_SIZE = 512 + SAMPLE_VOLUME = 30000 # Slightly lower to avoid overflow + half_period = SAMPLE_SIZE // 2 + + # Sine wave for channel 4 + self.wave_sine = array.array("h", [0] * SAMPLE_SIZE) + for i in range(SAMPLE_SIZE): + # Use max() and min() to ensure we stay within bounds + value = int(math.sin(math.pi * 2 * (i/2) / SAMPLE_SIZE) * SAMPLE_VOLUME) + self.wave_sine[i] = max(-32768, min(32767, value)) + + # Triangle wave for channel 5 + self.wave_tri = array.array("h", [0] * SAMPLE_SIZE) + for i in range(SAMPLE_SIZE): + if i < half_period: + value = int(((i / (half_period)) * 2 - 1) * SAMPLE_VOLUME) + else: + value = int(((2 - (i / (half_period)) * 2)) * SAMPLE_VOLUME) + self.wave_tri[i] = max(-32768, min(32767, value)) + + # Sawtooth wave for channel 6 + self.wave_saw = array.array("h", [0] * SAMPLE_SIZE) + for i in range(SAMPLE_SIZE): + value = int(((i / SAMPLE_SIZE) * 2 - 1) * SAMPLE_VOLUME) + self.wave_saw[i] = max(-32768, min(32767, value)) + + # Map channels to waveforms + self.channel_waveforms = { + 3: self.wave_sine, # Channel 4: Sine wave (soft, pure tone) + 4: self.wave_tri, # Channel 5: Triangle wave (mellow, soft) + 5: self.wave_saw, # Channel 6: Sawtooth wave (brassy, sharp) + } + + # Set different amplitudes for each waveform to balance volumes + self.channel_amplitudes = { + 3: 1.0, # Sine wave - normal volume + 4: 0.8, # Triangle wave - slightly quieter + 5: 0.3, # Sawtooth wave - much quieter (harmonically rich) + } + + # Track active synth notes by channel and note + self.active_synth_notes = { + 3: [], # Channel 4 + 4: [], # Channel 5 + 5: [], # Channel 6 + } + + # Variables for timed release of preview notes + self.note_release_time = 0 + self.note_to_release = None + self.note_to_release_channel = None + self.preview_mode = False + + def play_note(self, midi_note, channel): + """Play a note using either MIDI, WAV, or synthio based on channel""" + if channel == 0: # Channel 1 uses WAV samples + self.play_multi_sample(midi_note, channel) + elif channel == 1: # Channel 2 uses Heart note WAV samples + self.play_multi_sample(midi_note, channel) + elif channel == 2: # Channel 3 uses Drum WAV samples + self.play_multi_sample(midi_note, channel) + elif channel in [3, 4, 5]: # Channels 4-6 use synthio with different waveforms + self.preview_mode = True + self.play_synth_note(midi_note, channel) + # Schedule note release + self.note_release_time = time.monotonic() + self.seconds_per_eighth + self.note_to_release_channel = channel + else: + # Send note on the correct MIDI channel (channels are 0-based in adafruit_midi) + self.midi.send(NoteOn(midi_note, 100), channel=channel) + # Store note with its channel for proper Note Off later + self.active_notes[midi_note] = channel + # print(f"Playing note: {midi_note} on channel {channel + 1}") + + def play_notes_at_position(self, notes_data): + """Play all notes at a specific position simultaneously""" + # Stop all sample voices first + for i in range(5): # Use first 5 voices for WAV samples (0-4) + self.mixer.voice[i].stop() + self.active_voices[i] = False + + # Clear the position to voice mapping + self.position_to_voice = {} + self.playback_voice_mapping = {} + + # Group notes by channel type + sample_notes = { + 0: [], # Channel 1 (Lars WAV samples) + 1: [], # Channel 2 (Heart WAV samples) + 2: [] # Channel 3 (Drum WAV samples) + } + + # Synthio channels (4-6) + synth_notes = { + 3: [], # Channel 4 (Sine wave) + 4: [], # Channel 5 (Triangle wave) + 5: [], # Channel 6 (Sawtooth wave) + } + + midi_notes = {} # Other channels (MIDI) + + for x_pos, y_pos, note_val, channel in notes_data: + if channel in [0, 1, 2]: # Sample-based channels + sample_notes[channel].append((x_pos, y_pos, note_val)) + elif channel in [3, 4, 5]: # Synthio channels + synth_notes[channel].append(note_val) + else: # Other channels (MIDI) + midi_notes[note_val] = channel + + # Voice allocation - we have 5 voices to distribute among sample notes + remaining_voices = 5 + voice_index = 0 + + # Play sample notes for channels 1-3 + for channel, notes in sample_notes.items(): + for x_pos, y_pos, midi_note in notes: + if remaining_voices <= 0: + print(f"Warning: No more voices available for channel {channel+1}") + break + + # Get the appropriate sample set + sample_set = None + if channel == 0: + sample_set = self.samples + elif channel == 1: + sample_set = self.heart_samples + elif channel == 2: + sample_set = self.drum_samples + + # Find the closest sample + closest_note = min(sample_set.keys(), key=lambda x: abs(x - midi_note)) + sample = sample_set[closest_note] + + # Play the sample + self.mixer.voice[voice_index].play(sample, loop=False) + self.active_voices[voice_index] = True + + # Store the position to voice mapping + position_key = (x_pos, y_pos) + self.position_to_voice[position_key] = voice_index + self.playback_voice_mapping[(x_pos, y_pos, channel)] = voice_index + + # Adjust volume + total_notes = sum(len(notes) for notes in sample_notes.values()) + volume_factor = 0.9 if total_notes <= 3 else 0.7 if total_notes <= 6 else 0.5 + self.mixer.voice[voice_index].level = 0.7 * volume_factor + + voice_index += 1 + remaining_voices -= 1 + + # Log what we're playing + # Channel names commented out as it was unused + # channel_names = ["Lars", "Heart", "Drum"] + # print(f"Playing {channel_names[channel]} sample {closest_note} for note {midi_note}") + + # Play synth notes for each channel (4-6) + self.preview_mode = False + for channel, notes in synth_notes.items(): + for note in notes: + self.play_synth_note(note, channel) + + # Play MIDI notes + for midi_note, channel in midi_notes.items(): + self.midi.send(NoteOn(midi_note, 100), channel=channel) + self.active_notes[midi_note] = channel + + def play_multi_sample(self, midi_note, channel=0): + """Play the most appropriate sample for the given MIDI note""" + try: + # Find an available voice (use first 3 voices for interactive play) + voice_index = -1 + for i in range(3): # Only use the first 3 voices for interactive playback + if not self.active_voices[i]: + voice_index = i + break + + # If all voices are active, use the first one + if voice_index == -1: + voice_index = 0 + + # Stop any currently playing sample in this voice + self.mixer.voice[voice_index].stop() + + # Select the appropriate sample set based on channel + if channel == 1: # Heart samples + sample_set = self.heart_samples + elif channel == 2: # Drum samples + sample_set = self.drum_samples + else: # Default to channel 1 samples + sample_set = self.samples + + # Find the closest sample + closest_note = min(sample_set.keys(), key=lambda x: abs(x - midi_note)) + + # Get the sample + sample = sample_set[closest_note] + + # Play the sample + self.mixer.voice[voice_index].play(sample, loop=False) + self.active_voices[voice_index] = True + + # Adjust volume based on which sample we're using + if closest_note == 65: # F4 + self.mixer.voice[voice_index].level = 0.8 + elif closest_note == 69: # A4 + self.mixer.voice[voice_index].level = 0.7 + elif closest_note == 72: # C5 + self.mixer.voice[voice_index].level = 0.6 + else: + self.mixer.voice[voice_index].level = 0.7 + + except Exception as e: + print(f"Error playing multi-sample: {e}") + # Try to play any available sample as a fallback + if len(self.samples) > 0: + first_sample = next(iter(self.samples.values())) + self.mixer.voice[0].play(first_sample, loop=False) + + def play_synth_note(self, midi_note, channel): + """Play a note using synthio with different waveforms per channel""" + try: + # Convert MIDI note to frequency + frequency = 440 * math.pow(2, (midi_note - 69) / 12) + + # Get the appropriate waveform for this channel + waveform = self.channel_waveforms.get(channel, self.wave_sine) + + # Get the appropriate amplitude for this channel + amplitude = self.channel_amplitudes.get(channel, 1.0) + + # Create synthio note with the specific waveform and amplitude + note = synthio.Note( + frequency, + waveform=waveform, + amplitude=amplitude + ) + + # Add to synth + self.synth.press(note) + + # If we have an existing preview note to release, release it first + if self.preview_mode and self.note_to_release and self.note_to_release_channel==channel: + try: + self.synth.release(self.note_to_release) + except Exception as e: + print(f"Error releasing previous note: {e}") + + # Store the new note for scheduled release if in preview mode + if self.preview_mode: + self.note_to_release = note + self.note_to_release_channel = channel + else: + self.active_synth_notes[channel].append(note) + + except Exception as e: + print(f"Error playing synthio note: {e}") + # If there's an error with custom waveforms, fall back to default note + try: + frequency = 440 * math.pow(2, (midi_note - 69) / 12) + note = synthio.Note(frequency) + self.synth.press(note) + + # Store for later release + if self.preview_mode: + self.note_to_release = note + self.note_to_release_channel = channel + else: + self.active_synth_notes[channel].append(note) + + except Exception as e2: + print(f"Fallback note error: {e2}") + + def stop_sample_at_position(self, x_pos, y_pos, channel): + """Stop a sample that's playing at the given position for a specific channel""" + position_key = (x_pos, y_pos, channel) + if position_key in self.playback_voice_mapping: + voice_index = self.playback_voice_mapping[position_key] + + # Stop the sample + self.mixer.voice[voice_index].stop() + self.active_voices[voice_index] = False + + # Remove from mappings + del self.playback_voice_mapping[position_key] + return True + + # Also check the simple position mapping + simple_key = (x_pos, y_pos) + if simple_key in self.position_to_voice: + voice_index = self.position_to_voice[simple_key] + + # Stop the sample + self.mixer.voice[voice_index].stop() + self.active_voices[voice_index] = False + + # Remove from mapping + del self.position_to_voice[simple_key] + return True + + return False + + def update(self): + """Update function to handle timed note releases""" + # Check if we need to release a preview note + if self.note_to_release and time.monotonic() >= self.note_release_time: + try: + self.synth.release(self.note_to_release) + self.note_to_release = None + self.note_to_release_channel = None + except Exception as e: + print(f"Error releasing preview note: {e}") + self.note_to_release = None + self.note_to_release_channel = None + + def stop_all_notes(self): + """Stop all currently playing notes""" + # Stop all MIDI notes + for note_number, channel in self.active_notes.items(): + self.midi.send(NoteOff(note_number, 0), channel=channel) + self.active_notes = {} + + # Stop all WAV samples + for i in range(5): # Use first 5 voices for WAV samples + self.mixer.voice[i].stop() + self.active_voices[i] = False + + # Clear position mappings + self.position_to_voice = {} + self.playback_voice_mapping = {} + + # Stop all synth notes + try: + # Release notes from all channels + for channel, notes in self.active_synth_notes.items(): + for note in notes: + self.synth.release(note) + self.active_synth_notes[channel] = [] + + # Also release preview note if there is one + if self.note_to_release: + self.synth.release(self.note_to_release) + self.note_to_release = None + self.note_to_release_channel = None + + except Exception as e: + print(f"Error releasing synth notes: {e}") + # Reinitialize the synth as a fallback + try: + self.synth.deinit() + self.synth = synthio.Synthesizer(sample_rate=11025) + self.mixer.voice[5].play(self.synth) + + # Reset all active notes + self.active_synth_notes = { + 3: [], # Channel 4 + 4: [], # Channel 5 + 5: [], # Channel 6 + } + except Exception as e2: + print(f"Error reinitializing synth: {e2}") + + def deinit(self): + """Clean up resources when shutting down""" + # Stop all sounds + self.stop_all_notes() + + # Clean up audio resources + try: + self.audio.deinit() + except Exception: + pass + + # Power down the TLV320 if applicable + if self.tlv: + try: + # For TLV320DAC3100, headphone_output = False will power down the output + self.tlv.headphone_output = False + self.tlv.speaker_output = False + except Exception: + pass + + # Clean up synth + try: + self.synth.deinit() + except Exception: + pass + + # Force garbage collection + gc.collect() + + def set_tempo(self, seconds_per_eighth): + """Update the playback tempo""" + self.seconds_per_eighth = seconds_per_eighth + print(f"Playback tempo updated: {60 / (seconds_per_eighth * 2)} BPM") diff --git a/Fruit_Jam/Larsio_Paint_Music/sprite_manager.py b/Fruit_Jam/Larsio_Paint_Music/sprite_manager.py new file mode 100755 index 000000000..644a77ca5 --- /dev/null +++ b/Fruit_Jam/Larsio_Paint_Music/sprite_manager.py @@ -0,0 +1,219 @@ +# SPDX-FileCopyrightText: 2025 John Park and Claude AI for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +Sprite manager for CircuitPython Music Staff Application. +Handles loading and managing sprite images and palettes. +""" + +# pylint: disable=import-error, trailing-whitespace +import adafruit_imageload +from displayio import Palette, TileGrid + + +# pylint: disable=too-many-instance-attributes,invalid-name,broad-except +class SpriteManager: + """Manages sprites and palettes for note display""" + + def __init__(self, bg_color=0x8AAD8A): + """Initialize the sprite manager""" + self.bg_color = bg_color + + # Initialize palettes as empty lists first + self.note_palettes = [] + self.preview_palettes = [] + + # Sprites + self.mario_head = None + self.mario_palette = None + self.heart_note = None + self.heart_palette = None + self.drum_note = None + self.drum_palette = None + # Add new sprite variables + self.meatball_note = None + self.meatball_palette = None + self.star_note = None + self.star_palette = None + self.bot_note = None + self.bot_palette = None + + # Channel colors (still need these for palette management) + self.channel_colors = [ + 0x000000, # Channel 1: Black (default) + 0xFF0000, # Channel 2: Red + 0x00FF00, # Channel 3: Green + 0x0000FF, # Channel 4: Blue + 0xFF00FF, # Channel 5: Magenta + 0xFFAA00, # Channel 6: Orange + ] + + # Add button sprites + self.play_up = None + self.play_up_palette = None + self.play_down = None + self.play_down_palette = None + self.stop_up = None + self.stop_up_palette = None + self.stop_down = None + self.stop_down_palette = None + self.loop_up = None + self.loop_up_palette = None + self.loop_down = None + self.loop_down_palette = None + self.clear_up = None + self.clear_up_palette = None + self.clear_down = None + self.clear_down_palette = None + + # Load sprites + self.load_sprites() + + # Load button sprites + self.load_button_sprites() + + # Create palettes + self.create_palettes() + + def load_sprites(self): + """Load sprite images""" + try: + # Load the Lars note bitmap for channel 1 notes + self.mario_head, self.mario_palette = adafruit_imageload.load( + "sprites/lars_note.bmp" + ) + # Make the background color transparent (not just the same color) + self.mario_palette.make_transparent(0) + + # Load the Heart note bitmap for channel 2 notes + self.heart_note, self.heart_palette = adafruit_imageload.load( + "sprites/heart_note.bmp" + ) + # Make the background color transparent + self.heart_palette.make_transparent(0) + + # Load the Drum note bitmap for channel 3 notes + self.drum_note, self.drum_palette = adafruit_imageload.load( + "sprites/drum_note.bmp" + ) + # Make the background color transparent + self.drum_palette.make_transparent(0) + + # Load the new sprites for channels 4, 5, and 6 + # Meatball for channel 4 + self.meatball_note, self.meatball_palette = adafruit_imageload.load( + "sprites/meatball.bmp" + ) + self.meatball_palette.make_transparent(0) + + # Star for channel 5 + self.star_note, self.star_palette = adafruit_imageload.load( + "sprites/star.bmp" + ) + self.star_palette.make_transparent(0) + + # Bot for channel 6 + self.bot_note, self.bot_palette = adafruit_imageload.load("sprites/bot.bmp") + self.bot_palette.make_transparent(0) + + except Exception as e: + print(f"Error loading sprites: {e}") + + def create_palettes(self): + """Create palettes for notes and preview""" + # Create a palette for music notes with multiple colors + for channel_color in self.channel_colors: + palette = Palette(2) + palette[0] = self.bg_color # Transparent (sage green background) + palette[1] = channel_color # Note color for this channel + self.note_palettes.append(palette) + + # Create a preview palette with multiple colors + for channel_color in self.channel_colors: + palette = Palette(2) + palette[0] = self.bg_color # Transparent (sage green background) + # For preview, use a lighter version of the channel color + r = ((channel_color >> 16) & 0xFF) // 2 + 0x40 + g = ((channel_color >> 8) & 0xFF) // 2 + 0x40 + b = (channel_color & 0xFF) // 2 + 0x40 + preview_color = (r << 16) | (g << 8) | b + palette[1] = preview_color + self.preview_palettes.append(palette) + + def create_preview_note(self, current_channel, note_bitmap): + """Create preview note based on channel""" + if current_channel == 0: # Channel 1 uses Lars note + preview_tg = TileGrid(self.mario_head, pixel_shader=self.mario_palette) + elif current_channel == 1: # Channel 2 uses Heart note + preview_tg = TileGrid(self.heart_note, pixel_shader=self.heart_palette) + elif current_channel == 2: # Channel 3 uses Drum note + preview_tg = TileGrid(self.drum_note, pixel_shader=self.drum_palette) + elif current_channel == 3: # Channel 4 uses Meatball + preview_tg = TileGrid(self.meatball_note, pixel_shader=self.meatball_palette) + elif current_channel == 4: # Channel 5 uses Star + preview_tg = TileGrid(self.star_note, pixel_shader=self.star_palette) + elif current_channel == 5: # Channel 6 uses Bot + preview_tg = TileGrid(self.bot_note, pixel_shader=self.bot_palette) + else: # Fallback to colored circle + preview_tg = TileGrid( + note_bitmap, + pixel_shader=self.preview_palettes[current_channel] + ) + + preview_tg.x = 0 + preview_tg.y = 0 + preview_tg.hidden = True # Start with preview hidden + + return preview_tg + + def load_button_sprites(self): + """Load button sprites for transport controls""" + try: + # Load play button images + self.play_up, self.play_up_palette = adafruit_imageload.load( + "sprites/play_up.bmp" + ) + self.play_up_palette.make_transparent(0) + + self.play_down, self.play_down_palette = adafruit_imageload.load( + "sprites/play_down.bmp" + ) + self.play_down_palette.make_transparent(0) + + # Load stop button images + self.stop_up, self.stop_up_palette = adafruit_imageload.load( + "sprites/stop_up.bmp" + ) + self.stop_up_palette.make_transparent(0) + + self.stop_down, self.stop_down_palette = adafruit_imageload.load( + "sprites/stop_down.bmp" + ) + self.stop_down_palette.make_transparent(0) + + # Load loop button images + self.loop_up, self.loop_up_palette = adafruit_imageload.load( + "sprites/loop_up.bmp" + ) + self.loop_up_palette.make_transparent(0) + + self.loop_down, self.loop_down_palette = adafruit_imageload.load( + "sprites/loop_down.bmp" + ) + self.loop_down_palette.make_transparent(0) + + # Load clear button images + self.clear_up, self.clear_up_palette = adafruit_imageload.load( + "sprites/clear_up.bmp" + ) + self.clear_up_palette.make_transparent(0) + + self.clear_down, self.clear_down_palette = adafruit_imageload.load( + "sprites/clear_down.bmp" + ) + self.clear_down_palette.make_transparent(0) + + return True + except Exception as e: + print(f"Error loading button sprites: {e}") + return False diff --git a/Fruit_Jam/Larsio_Paint_Music/sprites/bot.bmp b/Fruit_Jam/Larsio_Paint_Music/sprites/bot.bmp new file mode 100755 index 000000000..d409f1fa2 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/sprites/bot.bmp differ diff --git a/Fruit_Jam/Larsio_Paint_Music/sprites/clear_down.bmp b/Fruit_Jam/Larsio_Paint_Music/sprites/clear_down.bmp new file mode 100755 index 000000000..248c261e5 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/sprites/clear_down.bmp differ diff --git a/Fruit_Jam/Larsio_Paint_Music/sprites/clear_up.bmp b/Fruit_Jam/Larsio_Paint_Music/sprites/clear_up.bmp new file mode 100755 index 000000000..70fdb13c6 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/sprites/clear_up.bmp differ diff --git a/Fruit_Jam/Larsio_Paint_Music/sprites/drum_note.bmp b/Fruit_Jam/Larsio_Paint_Music/sprites/drum_note.bmp new file mode 100755 index 000000000..a01c582e2 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/sprites/drum_note.bmp differ diff --git a/Fruit_Jam/Larsio_Paint_Music/sprites/heart_note.bmp b/Fruit_Jam/Larsio_Paint_Music/sprites/heart_note.bmp new file mode 100755 index 000000000..c3c460cd7 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/sprites/heart_note.bmp differ diff --git a/Fruit_Jam/Larsio_Paint_Music/sprites/lars_note.bmp b/Fruit_Jam/Larsio_Paint_Music/sprites/lars_note.bmp new file mode 100755 index 000000000..0c1f3e873 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/sprites/lars_note.bmp differ diff --git a/Fruit_Jam/Larsio_Paint_Music/sprites/loop_down.bmp b/Fruit_Jam/Larsio_Paint_Music/sprites/loop_down.bmp new file mode 100755 index 000000000..297786d09 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/sprites/loop_down.bmp differ diff --git a/Fruit_Jam/Larsio_Paint_Music/sprites/loop_up.bmp b/Fruit_Jam/Larsio_Paint_Music/sprites/loop_up.bmp new file mode 100755 index 000000000..2d1a0aa86 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/sprites/loop_up.bmp differ diff --git a/Fruit_Jam/Larsio_Paint_Music/sprites/meatball.bmp b/Fruit_Jam/Larsio_Paint_Music/sprites/meatball.bmp new file mode 100755 index 000000000..6d93e0dd6 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/sprites/meatball.bmp differ diff --git a/Fruit_Jam/Larsio_Paint_Music/sprites/play_down.bmp b/Fruit_Jam/Larsio_Paint_Music/sprites/play_down.bmp new file mode 100755 index 000000000..077c05552 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/sprites/play_down.bmp differ diff --git a/Fruit_Jam/Larsio_Paint_Music/sprites/play_up.bmp b/Fruit_Jam/Larsio_Paint_Music/sprites/play_up.bmp new file mode 100755 index 000000000..d9e3e53a3 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/sprites/play_up.bmp differ diff --git a/Fruit_Jam/Larsio_Paint_Music/sprites/star.bmp b/Fruit_Jam/Larsio_Paint_Music/sprites/star.bmp new file mode 100755 index 000000000..18247a132 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/sprites/star.bmp differ diff --git a/Fruit_Jam/Larsio_Paint_Music/sprites/stop_down.bmp b/Fruit_Jam/Larsio_Paint_Music/sprites/stop_down.bmp new file mode 100755 index 000000000..44cf026ae Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/sprites/stop_down.bmp differ diff --git a/Fruit_Jam/Larsio_Paint_Music/sprites/stop_up.bmp b/Fruit_Jam/Larsio_Paint_Music/sprites/stop_up.bmp new file mode 100755 index 000000000..28b07b908 Binary files /dev/null and b/Fruit_Jam/Larsio_Paint_Music/sprites/stop_up.bmp differ diff --git a/Fruit_Jam/Larsio_Paint_Music/staff_view.py b/Fruit_Jam/Larsio_Paint_Music/staff_view.py new file mode 100755 index 000000000..75ea89388 --- /dev/null +++ b/Fruit_Jam/Larsio_Paint_Music/staff_view.py @@ -0,0 +1,220 @@ +# SPDX-FileCopyrightText: 2025 John Park and Claude AI for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +# staff_view.py: Larsio Paint Music component +""" + +# pylint: disable=import-error, trailing-whitespace +from displayio import Group, Bitmap, Palette, TileGrid + + +# pylint: disable=invalid-name,no-member,too-many-instance-attributes,too-many-arguments +# pylint: disable=too-many-branches,too-many-statements,too-many-locals,too-many-nested-blocks +class StaffView: + """Manages the music staff display and related elements""" + + def __init__(self, screen_width, screen_height, note_manager): + self.SCREEN_WIDTH = screen_width + self.SCREEN_HEIGHT = screen_height + self.note_manager = note_manager + + # Staff dimensions + self.TOP_MARGIN = int(self.SCREEN_HEIGHT * 0.1) + self.BOTTOM_MARGIN = int(self.SCREEN_HEIGHT * 0.2) + self.STAFF_HEIGHT = int((self.SCREEN_HEIGHT - self.TOP_MARGIN - self.BOTTOM_MARGIN) * 0.95) + self.STAFF_Y_START = self.TOP_MARGIN + self.LINE_SPACING = self.STAFF_HEIGHT // 8 + + # Margins and spacing + self.START_MARGIN = 25 # Pixels from left edge for the double bar + + # Note spacing + self.EIGHTH_NOTE_SPACING = self.SCREEN_WIDTH // 40 + self.QUARTER_NOTE_SPACING = self.EIGHTH_NOTE_SPACING * 2 + + # Measure settings + self.NOTES_PER_MEASURE = 4 + self.MEASURE_WIDTH = self.QUARTER_NOTE_SPACING * self.NOTES_PER_MEASURE + self.MEASURES_PER_LINE = 4 + + # Playback elements + self.playhead = None + self.highlight_grid = None + + # X positions for notes + self.x_positions = [] + self._generate_x_positions() + + def _generate_x_positions(self): + """Generate horizontal positions for notes""" + self.x_positions = [] + for measure in range(self.MEASURES_PER_LINE): + measure_start = self.START_MARGIN + (measure * self.MEASURE_WIDTH) + for eighth_pos in range(8): + x_pos = (measure_start + (eighth_pos * self.EIGHTH_NOTE_SPACING) + + self.EIGHTH_NOTE_SPACING // 2) + if x_pos < self.SCREEN_WIDTH: + self.x_positions.append(x_pos) + + # Share positions with note manager + self.note_manager.x_positions = self.x_positions + + def create_staff(self): + """Create the staff with lines and background""" + staff_group = Group() + + # Create staff background + staff_bg_bitmap = Bitmap(self.SCREEN_WIDTH, self.STAFF_HEIGHT, 2) + staff_bg_palette = Palette(2) + staff_bg_palette[0] = 0xF5F5DC # Light beige (transparent) + staff_bg_palette[1] = 0x657c95 # 8AAD8A + + # Fill staff background with sage green + for x in range(self.SCREEN_WIDTH): + for y in range(self.STAFF_HEIGHT): + staff_bg_bitmap[x, y] = 1 + + # Create a TileGrid for staff background + staff_bg_grid = TileGrid( + staff_bg_bitmap, + pixel_shader=staff_bg_palette, + x=0, + y=self.STAFF_Y_START + ) + staff_group.append(staff_bg_grid) + + # Create staff lines + staff_bitmap = Bitmap(self.SCREEN_WIDTH, self.STAFF_HEIGHT, 4) + staff_palette = Palette(4) + staff_palette[0] = 0x657c95 # + staff_palette[1] = 0x000000 # Black for horizontal staff lines + staff_palette[2] = 0x888888 # Medium gray for measure bar lines + staff_palette[3] = 0xAAAAAA # Lighter gray for quarter note dividers + + # Draw 5 horizontal staff lines + for i in range(5): + y_pos = (i + 1) * self.LINE_SPACING + for x in range(self.SCREEN_WIDTH): + staff_bitmap[x, y_pos] = 1 + + # Add double bar at the beginning + for x in range(self.START_MARGIN - 5, self.START_MARGIN - 2): + for y in range(self.STAFF_HEIGHT): + if self.LINE_SPACING <= y <= 5 * self.LINE_SPACING: + staff_bitmap[x, y] = 1 + + for x in range(self.START_MARGIN - 1, self.START_MARGIN + 2): + for y in range(self.STAFF_HEIGHT): + if self.LINE_SPACING <= y <= 5 * self.LINE_SPACING: + staff_bitmap[x, y] = 1 + + # Add measure bar lines (thicker, darker) + bar_line_width = 2 + + # For each measure (except after the last one) + for i in range(1, self.MEASURES_PER_LINE): + # Calculate measure bar position + measure_bar_x = self.START_MARGIN + (i * self.MEASURE_WIDTH) + + if measure_bar_x < self.SCREEN_WIDTH: + # Draw the measure bar line + for y in range(self.STAFF_HEIGHT): + if self.LINE_SPACING <= y <= 5 * self.LINE_SPACING: + for thickness in range(bar_line_width): + if measure_bar_x + thickness < self.SCREEN_WIDTH: + staff_bitmap[measure_bar_x + thickness, y] = 2 + + # Add quarter note divider lines within each measure + for measure in range(self.MEASURES_PER_LINE): + measure_start_x = self.START_MARGIN + (measure * self.MEASURE_WIDTH) + + # Calculate quarter note positions (divide measure into 4 equal parts) + quarter_width = self.MEASURE_WIDTH // 4 + + # Draw lines at the first, second, and third quarter positions + for q in range(1, 4): # Draw at positions 1, 2, and 3 (not at 0 or 4) + quarter_x = measure_start_x + (q * quarter_width) + + if quarter_x < self.SCREEN_WIDTH: + for y in range(self.STAFF_HEIGHT): + if self.LINE_SPACING <= y <= 5 * self.LINE_SPACING: + staff_bitmap[quarter_x, y] = 3 # Use color 3 (light gray) + + # Add double bar line at the end + double_bar_width = 5 + double_bar_x = self.START_MARGIN + (self.MEASURES_PER_LINE * self.MEASURE_WIDTH) + 5 + if double_bar_x + double_bar_width < self.SCREEN_WIDTH: + # First thick line + for x in range(3): + for y in range(self.STAFF_HEIGHT): + if self.LINE_SPACING <= y <= 5 * self.LINE_SPACING: + staff_bitmap[double_bar_x + x, y] = 1 + + # Second thick line (with gap) + for x in range(3): + for y in range(self.STAFF_HEIGHT): + if self.LINE_SPACING <= y <= 5 * self.LINE_SPACING: + staff_bitmap[double_bar_x + x + 4, y] = 1 + + # Create a TileGrid with the staff bitmap + staff_grid = TileGrid( + staff_bitmap, + pixel_shader=staff_palette, + x=0, + y=self.STAFF_Y_START + ) + staff_group.append(staff_grid) + + return staff_group + + def create_grid_lines(self): + """Add vertical grid lines to show note spacing""" + grid_bitmap = Bitmap(self.SCREEN_WIDTH, self.STAFF_HEIGHT, 2) + grid_palette = Palette(2) + grid_palette[0] = 0x657c95 # Transparent + grid_palette[1] = 0xAAAAAA # Faint grid lines (light gray) + + # Draw vertical grid lines at each eighth note position + for x_pos in self.x_positions: + for y in range(self.STAFF_HEIGHT): + if self.LINE_SPACING <= y <= 5 * self.LINE_SPACING: + grid_bitmap[x_pos, y] = 1 + + return TileGrid(grid_bitmap, pixel_shader=grid_palette, x=0, y=self.STAFF_Y_START) + + def create_playhead(self): + """Create a playhead indicator""" + playhead_bitmap = Bitmap(2, self.STAFF_HEIGHT, 2) + playhead_palette = Palette(2) + playhead_palette[0] = 0x657c95 # Transparent + playhead_palette[1] = 0xFF0000 # Red playhead line + + for y in range(self.STAFF_HEIGHT): + playhead_bitmap[0, y] = 1 + playhead_bitmap[1, y] = 1 + + self.playhead = TileGrid( + playhead_bitmap, + pixel_shader=playhead_palette, + x=0, + y=self.STAFF_Y_START + ) + self.playhead.x = -10 # Start off-screen + + return self.playhead + + def create_highlight(self): + """Create a highlight marker for the closest valid note position""" + highlight_bitmap = Bitmap(self.SCREEN_WIDTH, 3, 2) + highlight_palette = Palette(2) + highlight_palette[0] = 0x657c95 # Transparent + highlight_palette[1] = 0x007700 # Highlight color (green) + + for x in range(self.SCREEN_WIDTH): + highlight_bitmap[x, 1] = 1 + + self.highlight_grid = TileGrid(highlight_bitmap, pixel_shader=highlight_palette) + self.highlight_grid.y = self.note_manager.note_positions[0] # Start at first position + + return self.highlight_grid diff --git a/Fruit_Jam/Larsio_Paint_Music/ui_manager.py b/Fruit_Jam/Larsio_Paint_Music/ui_manager.py new file mode 100755 index 000000000..00c953945 --- /dev/null +++ b/Fruit_Jam/Larsio_Paint_Music/ui_manager.py @@ -0,0 +1,644 @@ +# SPDX-FileCopyrightText: 2025 John Park and Claude AI for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +# ui_manager.py: CircuitPython Music Staff Application component +""" + +import time +import gc + +# pylint: disable=import-error, trailing-whitespace, line-too-long, superfluous-parens +from adafruit_display_text.bitmap_label import Label +import terminalio +from displayio import TileGrid + +from display_manager import DisplayManager +from staff_view import StaffView +from control_panel import ControlPanel +from input_handler import InputHandler +from sprite_manager import SpriteManager +from cursor_manager import CursorManager +from playback_controller import PlaybackController + + +# pylint: disable=invalid-name,no-member,too-many-instance-attributes,too-many-arguments +# pylint: disable=too-many-branches,too-many-statements,too-many-public-methods +# pylint: disable=too-many-locals,attribute-defined-outside-init +# pylint: disable=consider-using-in,too-many-return-statements,no-else-return +class UIManager: + """Manages the UI elements, input, and user interaction""" + + def __init__(self, sound_manager, note_manager): + """Initialize the UI manager with sound and note managers""" + self.sound_manager = sound_manager + self.note_manager = note_manager + + # Screen dimensions + self.SCREEN_WIDTH = 320 + self.SCREEN_HEIGHT = 240 + + # Staff dimensions + self.TOP_MARGIN = int(self.SCREEN_HEIGHT * 0.1) + self.BOTTOM_MARGIN = int(self.SCREEN_HEIGHT * 0.2) + self.STAFF_HEIGHT = int((self.SCREEN_HEIGHT - self.TOP_MARGIN - self.BOTTOM_MARGIN) * 0.95) + self.STAFF_Y_START = self.TOP_MARGIN + self.LINE_SPACING = self.STAFF_HEIGHT // 8 + + # Start margin + self.START_MARGIN = 25 + + # Tempo and timing + self.BPM = 120 + self.SECONDS_PER_BEAT = 60 / self.BPM + self.SECONDS_PER_EIGHTH = self.SECONDS_PER_BEAT / 2 + + # Initialize components + self.display_manager = DisplayManager(self.SCREEN_WIDTH, self.SCREEN_HEIGHT) + self.staff_view = StaffView(self.SCREEN_WIDTH, self.SCREEN_HEIGHT, self.note_manager) + self.control_panel = ControlPanel(self.SCREEN_WIDTH, self.SCREEN_HEIGHT) + self.input_handler = InputHandler(self.SCREEN_WIDTH, self.SCREEN_HEIGHT, + self.STAFF_Y_START, self.STAFF_HEIGHT) + self.sprite_manager = SpriteManager() + self.cursor_manager = CursorManager() + self.playback_controller = PlaybackController(self.sound_manager, self.note_manager, + self.SECONDS_PER_EIGHTH) + + # UI elements + self.main_group = None + self.note_name_label = None + self.tempo_label = None + self.preview_tg = None + self.highlight_grid = None + self.playhead = None + self.channel_buttons = [] + self.channel_selector = None + + # Initialize attributes that will be defined later + self.display = None + self.play_button = None + self.stop_button = None + self.loop_button = None + self.clear_button = None + self.crosshair_cursor = None + self.triangle_cursor = None + self.tempo_minus_label = None + self.tempo_plus_label = None + + # Channel setting + self.current_channel = 0 + + def setup_display(self): + """Initialize the display and create visual elements""" + # Initialize display + self.main_group, self.display = self.display_manager.initialize_display() + + # Create background + bg_grid = self.display_manager.create_background() + self.main_group.append(bg_grid) + + # Create staff + staff_group = self.staff_view.create_staff() + self.main_group.append(staff_group) + + # Create grid lines + grid_tg = self.staff_view.create_grid_lines() + self.main_group.insert(1, grid_tg) # Insert before staff so it appears behind + + # Create channel buttons using sprites + self._create_sprite_channel_buttons() + + # Create transport controls + transport_group, self.play_button, self.stop_button, self.loop_button, self.clear_button = \ + self.control_panel.create_transport_controls(self.sprite_manager) + self.main_group.append(transport_group) + + # Create cursors + self.crosshair_cursor, self.triangle_cursor = self.cursor_manager.create_cursors() + self.main_group.append(self.crosshair_cursor) + self.main_group.append(self.triangle_cursor) + + # Create note name label + self._create_note_name_label() + + # Create tempo display + self._create_tempo_display() + + # Create highlight + self.highlight_grid = self.staff_view.create_highlight() + self.main_group.append(self.highlight_grid) + + # Create playhead + self.playhead = self.staff_view.create_playhead() + self.main_group.append(self.playhead) + + # Set playback controller elements + self.playback_controller.set_ui_elements( + self.playhead, + self.play_button, + self.stop_button, + self.control_panel.button_sprites + ) + + # Create preview note + self.preview_tg = self.sprite_manager.create_preview_note( + self.current_channel, self.note_manager.note_bitmap) + self.main_group.append(self.preview_tg) + + # Add note groups to main group + self.main_group.append(self.note_manager.notes_group) + self.main_group.append(self.note_manager.ledger_lines_group) + + def _create_sprite_channel_buttons(self): + """Create channel buttons using sprites instead of numbered boxes""" + # Get a reference to the channel selector from control panel + channel_group, self.channel_selector = self.control_panel.create_channel_buttons() + + # Add sprite-based channel buttons + button_sprites = [ + (self.sprite_manager.mario_head, self.sprite_manager.mario_palette), + (self.sprite_manager.heart_note, self.sprite_manager.heart_palette), + (self.sprite_manager.drum_note, self.sprite_manager.drum_palette), + (self.sprite_manager.meatball_note, self.sprite_manager.meatball_palette), + (self.sprite_manager.star_note, self.sprite_manager.star_palette), + (self.sprite_manager.bot_note, self.sprite_manager.bot_palette) + ] + + # Create and position the sprite buttons + self.channel_buttons = [] + + for i, (sprite, palette) in enumerate(button_sprites): + button_x = 10 + i * (self.control_panel.CHANNEL_BUTTON_SIZE + + self.control_panel.CHANNEL_BUTTON_SPACING) + + # Create TileGrid for the sprite + button_tg = TileGrid( + sprite, + pixel_shader=palette, + x=button_x, + y=self.control_panel.CHANNEL_BUTTON_Y + ) + + # Center the sprite if it's not exactly the button size + if sprite.width != self.control_panel.CHANNEL_BUTTON_SIZE: + offset_x = (self.control_panel.CHANNEL_BUTTON_SIZE - sprite.width) // 2 + button_tg.x += offset_x + + if sprite.height != self.control_panel.CHANNEL_BUTTON_SIZE: + offset_y = (self.control_panel.CHANNEL_BUTTON_SIZE - sprite.height) // 2 + button_tg.y += offset_y + + self.channel_buttons.append(button_tg) + channel_group.append(button_tg) + + # Add the channel_group to main_group + self.main_group.append(channel_group) + + def _create_note_name_label(self): + """Create a label to show the current note name""" + self.note_name_label = Label( + terminalio.FONT, + text="", + color=0x000000, # Black text for beige background + scale=1 + ) + self.note_name_label.anchor_point = (0, 0) + self.note_name_label.anchored_position = (10, self.SCREEN_HEIGHT - 70) + self.main_group.append(self.note_name_label) + + def _create_tempo_display(self): + """Create a label for the tempo display with + and - buttons""" + gc.collect() # Force garbage collection before creating the label + + # Create plus and minus buttons for tempo adjustment + self.tempo_minus_label = Label( + terminalio.FONT, + text="-", + color=0xaaaaaa, # White text + background_color=0x444444, # Dark gray background + scale=1 + ) + self.tempo_minus_label.anchor_point = (0.5, 0.5) + self.tempo_minus_label.anchored_position = (self.SCREEN_WIDTH - 24, 10) + self.main_group.append(self.tempo_minus_label) + + self.tempo_plus_label = Label( + terminalio.FONT, + text="+", + color=0xaaaaaa, # gray text + background_color=0x444444, # Dark gray background + scale=1 + ) + self.tempo_plus_label.anchor_point = (0.5, 0.5) + self.tempo_plus_label.anchored_position = (self.SCREEN_WIDTH - 7, 10) + self.main_group.append(self.tempo_plus_label) + + # Create the tempo display label + self.tempo_label = Label( + terminalio.FONT, + text=f"Tempo~ {self.BPM} BPM", + color=0x222222, # gray text + scale=1 + ) + self.tempo_label.anchor_point = (0, 0.5) + self.tempo_label.anchored_position = (self.SCREEN_WIDTH - 114, 10) + self.main_group.append(self.tempo_label) + + print(f"Created tempo display: {self.tempo_label.text}") + + def find_mouse(self): + """Find the mouse device""" + return self.input_handler.find_mouse() + + def change_channel(self, channel_idx): + """Change the current MIDI channel""" + if 0 <= channel_idx < 6: # Ensure valid channel index + self.current_channel = channel_idx + + # Update channel selector position + channel_offset = (self.control_panel.CHANNEL_BUTTON_SIZE + + self.control_panel.CHANNEL_BUTTON_SPACING) + self.channel_selector.x = 7 + channel_idx * channel_offset + + # Update preview note color/image based on channel + self.main_group.remove(self.preview_tg) + self.preview_tg = self.sprite_manager.create_preview_note( + self.current_channel, self.note_manager.note_bitmap) + self.main_group.append(self.preview_tg) + + # Update status text + channel_names = ["Lars", "Heart", "Drum", "Meatball", "Star", "Bot"] + channel_text = f"Channel {self.current_channel + 1}: {channel_names[self.current_channel]}" + self.note_name_label.text = f"{channel_text} selected" + + print(f"Changed to MIDI channel {self.current_channel + 1}") + + def toggle_loop(self): + """Toggle loop button state""" + self.playback_controller.loop_enabled = not self.playback_controller.loop_enabled + self.control_panel.loop_enabled = self.playback_controller.loop_enabled + + # Update loop button appearance using bitmap if button_sprites are available + if hasattr(self.control_panel, 'button_sprites') and self.control_panel.button_sprites is not None: + state = 'down' if self.playback_controller.loop_enabled else 'up' + loop_bitmap, loop_palette = self.control_panel.button_sprites['loop'][state] + self.loop_button.bitmap = loop_bitmap + self.loop_button.pixel_shader = loop_palette + else: + # Fallback to original implementation + for x in range(1, self.control_panel.BUTTON_WIDTH - 1): + for y in range(1, self.control_panel.BUTTON_HEIGHT - 1): + skip_corners = (x, y) in [ + (0, 0), + (0, self.control_panel.BUTTON_HEIGHT-1), + (self.control_panel.BUTTON_WIDTH-1, 0), + (self.control_panel.BUTTON_WIDTH-1, self.control_panel.BUTTON_HEIGHT-1) + ] + + if not skip_corners: + # Skip pixels that are part of the loop symbol + dx = x - self.control_panel.BUTTON_WIDTH // 2 + dy = y - self.control_panel.BUTTON_HEIGHT // 2 + # Is pixel on the circle outline? + is_on_circle = (self.control_panel.loop_radius - 1 <= + (dx*dx + dy*dy)**0.5 <= + self.control_panel.loop_radius + 1) + + # Calculate arrow point positions + arrow_y1 = (self.control_panel.BUTTON_HEIGHT // 2 - + self.control_panel.loop_radius - 1) + arrow_y2 = arrow_y1 + 2 + + # Is pixel part of the arrow? + arrow_x = (self.control_panel.BUTTON_WIDTH // 2 + + int(self.control_panel.loop_radius * 0.7)) + is_arrow = x == arrow_x and (y == arrow_y1 or y == arrow_y2) + + if not (is_on_circle or is_arrow): + # Fill with active color if loop enabled, else inactive + val = 2 if self.playback_controller.loop_enabled else 0 + self.control_panel.loop_button_bitmap[x, y] = val + + self.note_name_label.text = "Loop: " + ("ON" if self.playback_controller.loop_enabled else "OFF") + + def press_clear_button(self): + """Handle clear button pressing effect""" + # Show pressed state + if hasattr(self.control_panel, 'button_sprites') and self.control_panel.button_sprites is not None: + self.clear_button.bitmap = self.control_panel.button_sprites['clear']['down'][0] + self.clear_button.pixel_shader = self.control_panel.button_sprites['clear']['down'][1] + else: + # Fallback to original implementation + for x in range(1, self.control_panel.BUTTON_WIDTH - 1): + for y in range(1, self.control_panel.BUTTON_HEIGHT - 1): + self.control_panel.clear_button_bitmap[x, y] = 2 # Red + + # Small delay for visual feedback + time.sleep(0.1) + + # Return to up state + if hasattr(self.control_panel, 'button_sprites') and self.control_panel.button_sprites is not None: + self.clear_button.bitmap = self.control_panel.button_sprites['clear']['up'][0] + self.clear_button.pixel_shader = self.control_panel.button_sprites['clear']['up'][1] + else: + # Fallback to original implementation + for x in range(1, self.control_panel.BUTTON_WIDTH - 1): + for y in range(1, self.control_panel.BUTTON_HEIGHT - 1): + self.control_panel.clear_button_bitmap[x, y] = 0 # Gray + + def clear_all_notes(self): + """Clear all notes""" + # Stop playback if it's running + if self.playback_controller.is_playing: + self.playback_controller.stop_playback() + + # Visual feedback for button press + self.press_clear_button() + + # Clear notes using note manager + self.note_manager.clear_all_notes(self.sound_manager) + + self.note_name_label.text = "All notes cleared" + + def adjust_tempo(self, direction): + """Adjust the tempo based on button press""" + # direction should be +1 for increase, -1 for decrease + + # Adjust BPM + new_bpm = self.BPM + (direction * 5) # Change by 5 BPM increments + + # Constrain to valid range + new_bpm = max(40, min(280, new_bpm)) + + # Only update if changed + if new_bpm != self.BPM: + self.BPM = new_bpm + self.SECONDS_PER_BEAT = 60 / self.BPM + self.SECONDS_PER_EIGHTH = self.SECONDS_PER_BEAT / 2 + + # Update playback controller with new tempo + self.playback_controller.set_tempo(self.SECONDS_PER_EIGHTH) + + # Update display + self.tempo_label.text = f"Tempo~ {self.BPM} BPM" + + print(f"Tempo adjusted to {self.BPM} BPM") + + def handle_mouse_position(self): + """Handle mouse movement and cursor updates""" + mouse_x = self.input_handler.mouse_x + mouse_y = self.input_handler.mouse_y + + # Check if mouse is over channel buttons area + is_over_channel_buttons = ( + self.control_panel.CHANNEL_BUTTON_Y <= mouse_y <= + self.control_panel.CHANNEL_BUTTON_Y + self.control_panel.CHANNEL_BUTTON_SIZE + ) + + # Check if we're over the staff area or transport controls area + is_over_staff = self.input_handler.is_over_staff(mouse_y) + is_over_transport = (mouse_y >= self.control_panel.TRANSPORT_AREA_Y) + + # Switch cursor based on area + self.cursor_manager.switch_cursor(use_triangle=(is_over_transport or is_over_channel_buttons)) + self.cursor_manager.set_cursor_position(mouse_x, mouse_y) + + # Handle staff area differently from other areas + if not is_over_staff: + # Hide highlight and preview when not over staff + self.highlight_grid.hidden = True + self.preview_tg.hidden = True + + # Show channel info if over channel buttons + if is_over_channel_buttons: + self._update_channel_button_info(mouse_x, mouse_y) + return + + # Process staff area interactions + # Find closest position and update highlight + closest_pos = self.note_manager.find_closest_position(mouse_y) + y_position = self.note_manager.note_positions[closest_pos] + self.highlight_grid.y = y_position - 1 # Center the highlight + self.highlight_grid.hidden = False + + # Find closest horizontal position (enforce minimum x position) + x_position = self.note_manager.find_closest_x_position(mouse_x) + + # Define sprite dimensions for each channel + sprite_width, sprite_height = self._get_sprite_dimensions(self.current_channel) + + # Update preview note position + self.preview_tg.x = x_position - sprite_width // 2 + self.preview_tg.y = y_position - sprite_height // 2 + self.preview_tg.hidden = False + + # Update note name label + if x_position < self.START_MARGIN: + self.note_name_label.text = "Invalid position - after double bar only" + else: + channel_names = ["Lars", "Heart", "Drum", "Meatball", "Star", "Bot"] + channel_text = f"Ch{self.current_channel+1} ({channel_names[self.current_channel]})" + note_text = self.note_manager.note_names[closest_pos] + self.note_name_label.text = f"{channel_text}: {note_text}" + + def _update_channel_button_info(self, mouse_x, mouse_y): + """Update the note name label based on which channel button the mouse is over""" + # Calculate which channel button we're over (if any) + for i in range(6): + button_x = 10 + i * (self.control_panel.CHANNEL_BUTTON_SIZE + + self.control_panel.CHANNEL_BUTTON_SPACING) + + # Get sprite dimensions for hit testing + sprite_width, sprite_height = self._get_sprite_dimensions(i) + + # Calculate the centered position of the sprite + offset_x = (self.control_panel.CHANNEL_BUTTON_SIZE - sprite_width) // 2 + offset_y = (self.control_panel.CHANNEL_BUTTON_SIZE - sprite_height) // 2 + sprite_x = button_x + offset_x + sprite_y = self.control_panel.CHANNEL_BUTTON_Y + offset_y + + # Check if mouse is over the sprite + rect_check = self.input_handler.point_in_rect( + mouse_x, mouse_y, sprite_x, sprite_y, + sprite_width, sprite_height) + + if rect_check: + channel_names = ["Lars", "Heart", "Drum", "Meatball", "Star", "Bot"] + self.note_name_label.text = f"Channel {i+1}: {channel_names[i]}" + break + + def _get_sprite_dimensions(self, channel_idx): + """Get the width and height of a sprite based on channel index""" + if channel_idx == 0: + return self.sprite_manager.mario_head.width, self.sprite_manager.mario_head.height + if channel_idx == 1: + return self.sprite_manager.heart_note.width, self.sprite_manager.heart_note.height + if channel_idx == 2: + return self.sprite_manager.drum_note.width, self.sprite_manager.drum_note.height + if channel_idx == 3: + return self.sprite_manager.meatball_note.width, self.sprite_manager.meatball_note.height + if channel_idx == 4: + return self.sprite_manager.star_note.width, self.sprite_manager.star_note.height + if channel_idx == 5: + return self.sprite_manager.bot_note.width, self.sprite_manager.bot_note.height + # Default fallback if channel_idx is out of range + return self.note_manager.NOTE_WIDTH, self.note_manager.NOTE_HEIGHT + + def handle_mouse_buttons(self): + """Handle mouse button presses""" + mouse_x = self.input_handler.mouse_x + mouse_y = self.input_handler.mouse_y + + # Check for staff area + is_over_staff = self.input_handler.is_over_staff(mouse_y) + + if self.input_handler.left_button_pressed: + # Check for tempo button clicks + minus_button_x, minus_button_y = self.tempo_minus_label.anchored_position + plus_button_x, plus_button_y = self.tempo_plus_label.anchored_position + button_radius = 8 # Allow a bit of space around the button for easier clicking + + if ((mouse_x - minus_button_x)**2 + (mouse_y - minus_button_y)**2) < button_radius**2: + # Clicked minus button - decrease tempo + self.adjust_tempo(-1) + return + + if ((mouse_x - plus_button_x)**2 + (mouse_y - plus_button_y)**2) < button_radius**2: + # Clicked plus button - increase tempo + self.adjust_tempo(1) + return + + # Check if a channel button was clicked + channel_clicked = False + for i in range(6): + button_x = 10 + i * (self.control_panel.CHANNEL_BUTTON_SIZE + + self.control_panel.CHANNEL_BUTTON_SPACING) + + # Get sprite dimensions for hit testing + sprite_width, sprite_height = self._get_sprite_dimensions(i) + + # Calculate the centered position of the sprite + offset_x = (self.control_panel.CHANNEL_BUTTON_SIZE - sprite_width) // 2 + offset_y = (self.control_panel.CHANNEL_BUTTON_SIZE - sprite_height) // 2 + sprite_x = button_x + offset_x + sprite_y = self.control_panel.CHANNEL_BUTTON_Y + offset_y + + # Check if click is within the sprite area + if self.input_handler.point_in_rect( + mouse_x, mouse_y, sprite_x, sprite_y, + sprite_width, sprite_height): + self.change_channel(i) + channel_clicked = True + break + + if not channel_clicked: + # Handle play/stop button clicks + if self.input_handler.point_in_rect( + mouse_x, mouse_y, self.play_button.x, self.play_button.y, + self.control_panel.BUTTON_WIDTH, self.control_panel.BUTTON_HEIGHT): + if not self.playback_controller.is_playing: + self.playback_controller.start_playback(self.START_MARGIN) + else: + self.playback_controller.stop_playback() + elif self.input_handler.point_in_rect( + mouse_x, mouse_y, self.stop_button.x, self.stop_button.y, + self.control_panel.BUTTON_WIDTH, self.control_panel.BUTTON_HEIGHT): + self.playback_controller.stop_playback() + elif self.input_handler.point_in_rect( + mouse_x, mouse_y, self.loop_button.x, self.loop_button.y, + self.control_panel.BUTTON_WIDTH, self.control_panel.BUTTON_HEIGHT): + self.toggle_loop() + elif self.input_handler.point_in_rect( + mouse_x, mouse_y, self.clear_button.x, self.clear_button.y, + self.control_panel.BUTTON_WIDTH, self.control_panel.BUTTON_HEIGHT): + self.clear_all_notes() + # Handle staff area clicks - left button adds notes only + elif is_over_staff: + self._add_note_based_on_channel(mouse_x, mouse_y) + + # Handle right mouse button for note deletion + elif self.input_handler.right_button_pressed and is_over_staff: + _, message = self.note_manager.erase_note( + mouse_x, mouse_y, + self.sprite_manager.mario_head, self.sprite_manager.mario_palette, + self.sound_manager + ) + self.note_name_label.text = message + + def _add_note_based_on_channel(self, x, y): + """Add a note based on the current channel""" + if self.current_channel == 0: + _, message = self.note_manager.add_note( + x, y, self.current_channel, + self.sprite_manager.note_palettes, + self.sprite_manager.mario_head, self.sprite_manager.mario_palette, + self.sprite_manager.heart_note, self.sprite_manager.heart_palette, + self.sound_manager + ) + elif self.current_channel == 1: + _, message = self.note_manager.add_note( + x, y, self.current_channel, + self.sprite_manager.note_palettes, + self.sprite_manager.heart_note, self.sprite_manager.heart_palette, + self.sprite_manager.heart_note, self.sprite_manager.heart_palette, + self.sound_manager + ) + elif self.current_channel == 2: + _, message = self.note_manager.add_note( + x, y, self.current_channel, + self.sprite_manager.note_palettes, + self.sprite_manager.drum_note, self.sprite_manager.drum_palette, + self.sprite_manager.heart_note, self.sprite_manager.heart_palette, + self.sound_manager + ) + elif self.current_channel == 3: + _, message = self.note_manager.add_note( + x, y, self.current_channel, + self.sprite_manager.note_palettes, + self.sprite_manager.meatball_note, self.sprite_manager.meatball_palette, + self.sprite_manager.heart_note, self.sprite_manager.heart_palette, + self.sound_manager + ) + elif self.current_channel == 4: + _, message = self.note_manager.add_note( + x, y, self.current_channel, + self.sprite_manager.note_palettes, + self.sprite_manager.star_note, self.sprite_manager.star_palette, + self.sprite_manager.heart_note, self.sprite_manager.heart_palette, + self.sound_manager + ) + elif self.current_channel == 5: + _, message = self.note_manager.add_note( + x, y, self.current_channel, + self.sprite_manager.note_palettes, + self.sprite_manager.bot_note, self.sprite_manager.bot_palette, + self.sprite_manager.heart_note, self.sprite_manager.heart_palette, + self.sound_manager + ) + else: + _, message = self.note_manager.add_note( + x, y, self.current_channel, + self.sprite_manager.note_palettes, + self.sprite_manager.mario_head, self.sprite_manager.mario_palette, + self.sprite_manager.heart_note, self.sprite_manager.heart_palette, + self.sound_manager + ) + self.note_name_label.text = message + + def main_loop(self): + """Main application loop""" + while True: + # Update playback if active + if self.playback_controller.is_playing: + self.playback_controller.update_playback(self.staff_view.x_positions) + + # Update sound manager for timed releases + self.sound_manager.update() + + # Process mouse input - simplified version without wheel tracking + if self.input_handler.process_mouse_input(): + # Handle mouse position and update cursor + self.handle_mouse_position() + + # Handle mouse button presses + self.handle_mouse_buttons() diff --git a/FunHouse_Fume_Extractor/code.py b/FunHouse_Fume_Extractor/code.py index e05999784..f1c62d468 100644 --- a/FunHouse_Fume_Extractor/code.py +++ b/FunHouse_Fume_Extractor/code.py @@ -56,7 +56,7 @@ group = displayio.Group() # adding start-up bitmap to group group.append(tile_grid) -funhouse.splash.append(group) +funhouse.graphics.root_group.append(group) # text for fume data fume_text = funhouse.add_text( text=" ", @@ -74,7 +74,7 @@ text_font="fonts/Arial-Bold-24.pcf", ) # showing graphics -funhouse.display.root_group = funhouse.splash +funhouse.display.root_group = funhouse.graphics.root_group # state machines run = False # state if main code is running diff --git a/FunHouse_HA_Companion/code.py b/FunHouse_HA_Companion/code.py index ed55a3bb0..699ff8e64 100755 --- a/FunHouse_HA_Companion/code.py +++ b/FunHouse_HA_Companion/code.py @@ -65,10 +65,10 @@ ) # Now display the splash to draw all labels at once -funhouse.display.root_group = funhouse.splash +funhouse.display.root_group = funhouse.graphics.root_group status = Circle(229, 10, 10, fill=0xFF0000, outline=0x880000) -funhouse.splash.append(status) +funhouse.graphics.root_group.append(status) def connected(client, _userdata, _result, _payload): status.fill = 0x00FF00 diff --git a/FunHouse_IOT_Hub/battery_peripheral/code.py b/FunHouse_IOT_Hub/battery_peripheral/code.py index 5dc93605e..6f633493d 100644 --- a/FunHouse_IOT_Hub/battery_peripheral/code.py +++ b/FunHouse_IOT_Hub/battery_peripheral/code.py @@ -12,6 +12,7 @@ Either the Feather or the Airlift Featherwing should have stacking headers for the display. """ +from os import getenv import time import board from adafruit_lc709203f import LC709203F @@ -25,22 +26,30 @@ from adafruit_io.adafruit_io import IO_MQTT import displayio +import i2cdisplaybus import terminalio from adafruit_display_text import label import adafruit_displayio_ssd1306 +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + displayio.release_displays() ### WiFi ### -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise - - # If you are using a board with pre-defined ESP32 Pins: esp32_cs = DigitalInOut(board.D13) esp32_ready = DigitalInOut(board.D11) @@ -49,10 +58,10 @@ spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) """Use below for Most Boards""" -status_light = neopixel.NeoPixel( +status_pixel = neopixel.NeoPixel( board.NEOPIXEL, 1, brightness=0.2 ) # Uncomment for Most Boards -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Define callback functions which will be called when certain events happen. # pylint: disable=unused-argument @@ -80,8 +89,8 @@ def message(client, feed_id, payload): # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", - username=secrets["aio_username"], - password=secrets["aio_key"], + username=aio_username, + password=aio_key, socket_pool=pool, ssl_context=ssl_context, ) @@ -101,7 +110,7 @@ def message(client, feed_id, payload): i2c = board.I2C() # uses board.SCL and board.SDA # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller -display_bus = displayio.I2CDisplay(i2c, device_address=0x3C) +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3C) WIDTH = 128 HEIGHT = 32 diff --git a/FunHouse_IOT_Hub/door_peripheral/code.py b/FunHouse_IOT_Hub/door_peripheral/code.py index ae8854f95..e11c2e9a8 100644 --- a/FunHouse_IOT_Hub/door_peripheral/code.py +++ b/FunHouse_IOT_Hub/door_peripheral/code.py @@ -14,6 +14,7 @@ either the Feather or the AirLift Featherwing has stacking headers. """ +from os import getenv import board import busio import adafruit_connection_manager @@ -25,14 +26,22 @@ from digitalio import DigitalInOut, Direction, Pull from adafruit_debouncer import Debouncer -### WiFi ### +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +### WiFi ### switch_pin = DigitalInOut(board.D10) switch_pin.direction = Direction.INPUT @@ -47,10 +56,10 @@ spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) """Use below for Most Boards""" -status_light = neopixel.NeoPixel( +status_pixel = neopixel.NeoPixel( board.NEOPIXEL, 1, brightness=0.2 ) # Uncomment for Most Boards -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Connect to WiFi print("Connecting to WiFi...") @@ -63,8 +72,8 @@ # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", - username=secrets["aio_username"], - password=secrets["aio_key"], + username=aio_username, + password=aio_key, socket_pool=pool, ssl_context=ssl_context, ) diff --git a/FunHouse_IOT_Hub/iot_hub/code.py b/FunHouse_IOT_Hub/iot_hub/code.py index c09c11844..a13efe80b 100644 --- a/FunHouse_IOT_Hub/iot_hub/code.py +++ b/FunHouse_IOT_Hub/iot_hub/code.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2021 Eva Herrada for Adafruit Industries # SPDX-License-Identifier: MIT +from os import getenv import time import ssl import displayio @@ -15,6 +16,21 @@ from adafruit_io.adafruit_io import IO_MQTT from adafruit_dash_display import Hub +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + # Set up navigation buttons up = DigitalInOut(board.BUTTON_UP) up.direction = Direction.INPUT @@ -31,14 +47,6 @@ back = touchio.TouchIn(board.CAP7) submit = touchio.TouchIn(board.CAP8) -# Check for secrets.py. Note: for this project, your secrets.py needs an adafruit io api key as -# well as the wifi information -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise - # Make the rgb group for setting rgb hex values for NeoPixels rgb_group = displayio.Group() R_label = Label( @@ -174,15 +182,9 @@ def pub_lamp(lamp): display = board.DISPLAY -# Set your Adafruit IO Username and Key in secrets.py -# (visit io.adafruit.com if you need to create an account, -# or if you need your Adafruit IO key.) -aio_username = secrets["aio_username"] -aio_key = secrets["aio_key"] - -print("Connecting to %s" % secrets["ssid"]) -wifi.radio.connect(secrets["ssid"], secrets["password"]) -print("Connected to %s!" % secrets["ssid"]) +print(f"Connecting to {ssid}") +wifi.radio.connect(ssid, password) +print(f"Connected to {ssid}!") # Create a socket pool pool = socketpool.SocketPool(wifi.radio) @@ -190,8 +192,8 @@ def pub_lamp(lamp): # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", - username=secrets["aio_username"], - password=secrets["aio_key"], + username=aio_username, + password=aio_key, socket_pool=pool, ssl_context=ssl.create_default_context(), ) diff --git a/FunHouse_IOT_Hub/neopixel_remote/code.py b/FunHouse_IOT_Hub/neopixel_remote/code.py index 685a7bdae..7e30ed84b 100644 --- a/FunHouse_IOT_Hub/neopixel_remote/code.py +++ b/FunHouse_IOT_Hub/neopixel_remote/code.py @@ -7,6 +7,7 @@ Colors used are taken from Adafruit_CircuitPython_LED_Animation library """ +from os import getenv import time import math import board @@ -26,6 +27,21 @@ # Import Adafruit IO HTTP Client from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + ts = adafruit_touchscreen.Touchscreen( board.TOUCH_XL, board.TOUCH_XR, @@ -92,30 +108,17 @@ group.append(rect) print(len(group)) -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise - # PyPortal ESP32 Setup esp32_cs = DigitalInOut(board.ESP_CS) esp32_ready = DigitalInOut(board.ESP_BUSY) esp32_reset = DigitalInOut(board.ESP_RESET) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) -status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) - -# Set your Adafruit IO Username and Key in secrets.py -# (visit io.adafruit.com if you need to create an account, -# or if you need your Adafruit IO key.) -ADAFRUIT_IO_USER = secrets["aio_username"] -ADAFRUIT_IO_KEY = secrets["aio_key"] +status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Create an instance of the Adafruit IO HTTP client -io = IO_HTTP(ADAFRUIT_IO_USER, ADAFRUIT_IO_KEY, wifi) +io = IO_HTTP(aio_username, aio_key, wifi) try: # Get the 'temperature' feed from Adafruit IO diff --git a/FunHouse_IOT_Hub/neopixel_remote/feather_code/code.py b/FunHouse_IOT_Hub/neopixel_remote/feather_code/code.py index 30f3d960a..76fd255a6 100644 --- a/FunHouse_IOT_Hub/neopixel_remote/feather_code/code.py +++ b/FunHouse_IOT_Hub/neopixel_remote/feather_code/code.py @@ -15,6 +15,7 @@ But if it doesn't, use stacking headers on either the Feather or the AirLift FeatherWing """ +from os import getenv import board import busio import adafruit_connection_manager @@ -25,14 +26,22 @@ from adafruit_io.adafruit_io import IO_MQTT from digitalio import DigitalInOut -### WiFi ### +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +### WiFi ### # Change the first number to the pin the data line is plugged in to and the second number # to the number of pixels @@ -46,10 +55,10 @@ spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) """Use below for Most Boards""" -status_light = neopixel.NeoPixel( +status_pixel = neopixel.NeoPixel( board.NEOPIXEL, 1, brightness=0.2 ) # Uncomment for Most Boards -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Define callback functions which will be called when certain events happen. # pylint: disable=unused-argument @@ -82,8 +91,8 @@ def on_neopixel(client, topic, message): # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", - username=secrets["aio_username"], - password=secrets["aio_key"], + username=aio_username, + password=aio_key, socket_pool=pool, ssl_context=ssl_context, ) diff --git a/FunHouse_IOT_Hub/relay_heatindex_peripheral/code.py b/FunHouse_IOT_Hub/relay_heatindex_peripheral/code.py index ca4882707..8f58e09b5 100644 --- a/FunHouse_IOT_Hub/relay_heatindex_peripheral/code.py +++ b/FunHouse_IOT_Hub/relay_heatindex_peripheral/code.py @@ -17,6 +17,7 @@ a box fan connected to it. """ +from os import getenv import board import busio import adafruit_connection_manager @@ -27,14 +28,22 @@ from adafruit_io.adafruit_io import IO_MQTT from digitalio import DigitalInOut, Direction -### WiFi ### +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +### WiFi ### RELAY = DigitalInOut(board.D10) RELAY.direction = Direction.OUTPUT @@ -47,10 +56,10 @@ spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) """Use below for Most Boards""" -status_light = neopixel.NeoPixel( +status_pixel = neopixel.NeoPixel( board.NEOPIXEL, 1, brightness=0.2 ) # Uncomment for Most Boards -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Define callback functions which will be called when certain events happen. # pylint: disable=unused-argument @@ -81,8 +90,8 @@ def on_hi(client, topic, message): # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", - username=secrets["aio_username"], - password=secrets["aio_key"], + username=aio_username, + password=aio_key, socket_pool=pool, ssl_context=ssl_context, ) diff --git a/FunHouse_IOT_Hub/relay_peripheral/code.py b/FunHouse_IOT_Hub/relay_peripheral/code.py index 0f2dbfae4..cdb8f0d22 100644 --- a/FunHouse_IOT_Hub/relay_peripheral/code.py +++ b/FunHouse_IOT_Hub/relay_peripheral/code.py @@ -12,6 +12,8 @@ OR * https://www.adafruit.com/product/2935 """ + +from os import getenv import board import busio import adafruit_connection_manager @@ -22,14 +24,22 @@ from adafruit_io.adafruit_io import IO_MQTT from digitalio import DigitalInOut, Direction -### WiFi ### +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +### WiFi ### # If you are using a Relay FeatherWing, make sure this pin corresponds to the pin shorted on the # bottom of the Relay FeatherWing @@ -44,10 +54,10 @@ spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) """Use below for Most Boards""" -status_light = neopixel.NeoPixel( +status_pixel = neopixel.NeoPixel( board.NEOPIXEL, 1, brightness=0.2 ) # Uncomment for Most Boards -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Define callback functions which will be called when certain events happen. # pylint: disable=unused-argument @@ -75,8 +85,8 @@ def on_lamp(client, topic, message): # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", - username=secrets["aio_username"], - password=secrets["aio_key"], + username=aio_username, + password=aio_key, socket_pool=pool, ssl_context=ssl_context, ) diff --git a/FunHouse_IOT_Hub/temp_humid_peripheral/code.py b/FunHouse_IOT_Hub/temp_humid_peripheral/code.py index b744a0faa..fa80c67ea 100644 --- a/FunHouse_IOT_Hub/temp_humid_peripheral/code.py +++ b/FunHouse_IOT_Hub/temp_humid_peripheral/code.py @@ -14,6 +14,7 @@ * https://www.adafruit.com/product/4399 """ +from os import getenv import ssl import socketpool import wifi @@ -25,33 +26,30 @@ import board import adafruit_sht4x -### WiFi ### +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) -# Add a secrets.py to your filesystem that has a dictionary called secrets with "ssid" and -# "password" keys with your WiFi credentials. DO NOT share that file or commit it into Git or other -# source control. -# pylint: disable=no-name-in-module,wrong-import-order +### WiFi ### magtag = MagTag() -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise - -# Set your Adafruit IO Username and Key in secrets.py -# (visit io.adafruit.com if you need to create an account, -# or if you need your Adafruit IO key.) -aio_username = secrets["aio_username"] -aio_key = secrets["aio_key"] - - connected = False try: - print("Connecting to %s" % secrets["ssid"]) - wifi.radio.connect(secrets["ssid"], secrets["password"]) - print("Connected to %s!" % secrets["ssid"]) + print(f"Connecting to {ssid}") + wifi.radio.connect(ssid, password) + print(f"Connected to {ssid}!") # Create a socket pool pool = socketpool.SocketPool(wifi.radio) @@ -59,8 +57,8 @@ # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", - username=secrets["aio_username"], - password=secrets["aio_key"], + username=aio_username, + password=aio_key, socket_pool=pool, ssl_context=ssl.create_default_context(), ) diff --git a/FunHouse_LIFX/.circuitpython.skip b/FunHouse_LIFX/.circuitpython.skip deleted file mode 100644 index 69a38db93..000000000 --- a/FunHouse_LIFX/.circuitpython.skip +++ /dev/null @@ -1,2 +0,0 @@ -FunHouse_LIFX/code.py 117: Comparison to literal (literal-comparison) -FunHouse_LIFX/code.py 136: Comparison to literal (literal-comparison) diff --git a/FunHouse_LIFX/code.py b/FunHouse_LIFX/code.py index 2cb211075..3aaadd1d0 100644 --- a/FunHouse_LIFX/code.py +++ b/FunHouse_LIFX/code.py @@ -1,21 +1,28 @@ # SPDX-FileCopyrightText: 2021 John Park for Adafruit Industries # SPDX-License-Identifier: MIT # FunHouse PIR Motion Sensor for LIFX light bulbs + +from os import getenv import time import ssl import socketpool import wifi import adafruit_requests -from adafruit_funhouse import FunHouse from displayio import CIRCUITPYTHON_TERMINAL import adafruit_lifx +from adafruit_funhouse import FunHouse + +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi and API secrets are kept in secrets.py, please add them there!") - raise +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # choose colors here. Note formatting differences. default_bulb_color = "#002010" @@ -24,13 +31,13 @@ tripped_led_color = 0x440044 # Set up ESP32-S2 and adafruit_requests session -wifi.radio.connect(ssid=secrets["ssid"], password=secrets["password"]) +wifi.radio.connect(ssid, password) pool = socketpool.SocketPool(wifi.radio) http_session = adafruit_requests.Session(pool, ssl.create_default_context()) -# Add your LIFX Personal Access token to secrets.py +# Add your LIFX Personal Access token to settings.toml # (to obtain a token, visit: https://cloud.lifx.com/settings) -lifx_token = secrets["lifx_token"] +lifx_token = getenv("lifx_token") # Set this to your LIFX light separator label # https://api.developer.lifx.com/docs/selectors @@ -70,7 +77,7 @@ def set_label_color(conditional, index, on_color): text=trip_time, text_scale=2, text_position=(30, 25), text_color=0x606060 ) -funhouse.display.root_group = funhouse.splash +funhouse.display.root_group = funhouse.graphics.root_group # Turn on the light print("Turning on light...") @@ -115,7 +122,7 @@ def set_label_color(conditional, index, on_color): time.sleep(0.5) # when sensor is tripped, set the color x amount of time - if running_state is True and funhouse.peripherals.pir_sensor and pir_state is 0: + if running_state is True and funhouse.peripherals.pir_sensor and pir_state == 0: funhouse.peripherals.dotstars.fill(tripped_led_color) funhouse.set_text("tripped", running_label) lifx.set_color( @@ -134,7 +141,7 @@ def set_label_color(conditional, index, on_color): # return to default color elif ( - running_state is True and not funhouse.peripherals.pir_sensor and pir_state is 1 + running_state is True and not funhouse.peripherals.pir_sensor and pir_state == 1 ): funhouse.peripherals.dotstars.fill(default_led_color) funhouse.set_text("sensing...", running_label) diff --git a/FunHouse_Mailslot/code.py b/FunHouse_Mailslot/code.py index 37b5bc662..13fbf32f1 100644 --- a/FunHouse_Mailslot/code.py +++ b/FunHouse_Mailslot/code.py @@ -31,7 +31,7 @@ ) reset_label = funhouse.add_text(text="reset", text_position=(3, 70), text_color=GRAY) -funhouse.display.root_group = funhouse.splash +funhouse.display.root_group = funhouse.graphics.root_group def send_io_data(mail_value): diff --git a/FunHouse_Motion_Outlet/code.py b/FunHouse_Motion_Outlet/code.py index fb48c215d..19fcbc2ef 100755 --- a/FunHouse_Motion_Outlet/code.py +++ b/FunHouse_Motion_Outlet/code.py @@ -82,10 +82,10 @@ def timeleft(): text_color=0xFFFF00, text_font="fonts/Arial-Bold-24.pcf", ) -funhouse.display.root_group = funhouse.splash +funhouse.display.root_group = funhouse.graphics.root_group status = Circle(229, 10, 10, fill=0xFF0000, outline=0x880000) -funhouse.splash.append(status) +funhouse.graphics.root_group.append(status) # Initialize a new MQTT Client object if USE_MQTT: diff --git a/FunHouse_Pet_Bowl_Sensor/code.py b/FunHouse_Pet_Bowl_Sensor/code.py index ead6fef18..4cd7d20b9 100755 --- a/FunHouse_Pet_Bowl_Sensor/code.py +++ b/FunHouse_Pet_Bowl_Sensor/code.py @@ -77,10 +77,10 @@ def bowl_level_display(level): text_color=0xFFFF00, text_font="fonts/Arial-Bold-24.pcf", ) -funhouse.display.root_group = funhouse.splash +funhouse.display.root_group = funhouse.graphics.root_group status = Circle(229, 10, 10, fill=0xFF0000, outline=0x880000) -funhouse.splash.append(status) +funhouse.graphics.root_group.append(status) # Initialize a new MQTT Client object funhouse.network.init_mqtt( diff --git a/GemmaM0_Band_Jacket/DiscoBandCamp/DiscoBandCamp.ino b/GemmaM0_Band_Jacket/DiscoBandCamp/DiscoBandCamp.ino index 828d99035..055b3498a 100644 --- a/GemmaM0_Band_Jacket/DiscoBandCamp/DiscoBandCamp.ino +++ b/GemmaM0_Band_Jacket/DiscoBandCamp/DiscoBandCamp.ino @@ -43,6 +43,10 @@ #include "effects.h" #include "buttons.h" +#if defined(FASTLED_VERSION) && FASTLED_VERSION > 3010001 + #error "FastLED 3.10.2 has known compile issues with SAMD boards. Please downgrade to FastLED 3.10.1" +#endif + // list of Functions: functionList effectList[] = {SolidRed, //all pixels solid red swirly, //glittery swirly patterns diff --git a/GemmaM0_Headband/code.py b/GemmaM0_Headband/code.py index 25dda30d8..d87a61757 100644 --- a/GemmaM0_Headband/code.py +++ b/GemmaM0_Headband/code.py @@ -23,7 +23,7 @@ # For the Gemma M0 onboard DotStar LED dotstar = adafruit_dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1) -def deg_f(deg_c): # Convert Celcius to Fahrenheit +def deg_f(deg_c): # Convert celsius to Fahrenheit return(deg_c * 9 / 5) + 32.0 while True: diff --git a/Gemma_M0_NeoPixel_Dress/Gemma_M0_NeoPixel_Dress.ino b/Gemma_M0_NeoPixel_Dress/Gemma_M0_NeoPixel_Dress.ino index 0af54c1ed..dc27bc591 100644 --- a/Gemma_M0_NeoPixel_Dress/Gemma_M0_NeoPixel_Dress.ino +++ b/Gemma_M0_NeoPixel_Dress/Gemma_M0_NeoPixel_Dress.ino @@ -6,6 +6,10 @@ #include #include "Adafruit_TCS34725.h" +#if defined(FASTLED_VERSION) && FASTLED_VERSION > 3010001 + #error "FastLED 3.10.2 has known compile issues with SAMD boards. Please downgrade to FastLED 3.10.1" +#endif + #define DATA_PIN 1 #define LED_TYPE WS2812B #define COLOR_ORDER GRB diff --git a/Glowing_Beehive_Hairdo_Wig/Glowing_Beehive_Hairdo_Wig.ino b/Glowing_Beehive_Hairdo_Wig/Glowing_Beehive_Hairdo_Wig.ino index 9a140bd36..e7fb92ad1 100644 --- a/Glowing_Beehive_Hairdo_Wig/Glowing_Beehive_Hairdo_Wig.ino +++ b/Glowing_Beehive_Hairdo_Wig/Glowing_Beehive_Hairdo_Wig.ino @@ -8,6 +8,10 @@ #include // add this before the FastLED library to avoid issues #include +#if defined(FASTLED_VERSION) && FASTLED_VERSION > 3010001 + #error "FastLED 3.10.2 has known compile issues with SAMD boards. Please downgrade to FastLED 3.10.1" +#endif + #define LED_PIN 6 //led strand is soldered to pin 6 #define CP_PIN 17 //circuit playground's neopixels live on pin 17 #define NUM_LEDS 12 // number of LEDs in my strand diff --git a/Glowing_Mirror_Mask/Glowing_Mirror_Mask/Glowing_Mirror_Mask.ino b/Glowing_Mirror_Mask/Glowing_Mirror_Mask/Glowing_Mirror_Mask.ino index ac48d20f9..b328e851d 100644 --- a/Glowing_Mirror_Mask/Glowing_Mirror_Mask/Glowing_Mirror_Mask.ino +++ b/Glowing_Mirror_Mask/Glowing_Mirror_Mask/Glowing_Mirror_Mask.ino @@ -12,6 +12,10 @@ #include #include +#if defined(FASTLED_VERSION) && FASTLED_VERSION > 3010001 + #error "FastLED 3.10.2 has known compile issues with SAMD boards. Please downgrade to FastLED 3.10.1" +#endif + // Enable ONE of these lines to select an animation, // others MUST be commented out! diff --git a/Gravity_Falls_Memory_Gun/code.py b/Gravity_Falls_Memory_Gun/code.py index aeecbbe91..6e4b7e378 100644 --- a/Gravity_Falls_Memory_Gun/code.py +++ b/Gravity_Falls_Memory_Gun/code.py @@ -8,6 +8,7 @@ import audiobusio from digitalio import DigitalInOut, Direction import displayio +import i2cdisplaybus from adafruit_bitmap_font import bitmap_font from adafruit_display_text import label import adafruit_displayio_ssd1306 @@ -31,7 +32,7 @@ # oled oled_reset = board.D9 -display_bus = displayio.I2CDisplay(i2c, device_address=0x3D, reset=oled_reset) +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3D, reset=oled_reset) WIDTH = 128 HEIGHT = 64 display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=WIDTH, height=HEIGHT) diff --git a/HalloWing_Cat_Toy/code.py b/HalloWing_Cat_Toy/code.py index dbfe90429..caa9c7034 100644 --- a/HalloWing_Cat_Toy/code.py +++ b/HalloWing_Cat_Toy/code.py @@ -75,17 +75,8 @@ def play_wave(filename): # Display an image on the HalloWing TFT screen def show_image(filename): - # CircuitPython 6 & 7 compatible - image_file = open(filename, "rb") - odb = displayio.OnDiskBitmap(image_file) - face = displayio.TileGrid( - odb, - pixel_shader=getattr(odb, 'pixel_shader', displayio.ColorConverter()) - ) - - # # CircuitPython 7+ compatible - # odb = displayio.OnDiskBitmap(filename) - # face = displayio.TileGrid(odb, pixel_shader=odb.pixel_shader) + odb = displayio.OnDiskBitmap(filename) + face = displayio.TileGrid(odb, pixel_shader=odb.pixel_shader) backlight.value = False splash.append(face) diff --git a/HalloWing_Jump_Scare_Trap/code.py b/HalloWing_Jump_Scare_Trap/code.py index 05092c79b..caa6bf4d3 100644 --- a/HalloWing_Jump_Scare_Trap/code.py +++ b/HalloWing_Jump_Scare_Trap/code.py @@ -98,17 +98,9 @@ def blink(count, speed): "trap_set.bmp"] # Function for displaying images on HalloWing TFT screen def show_image(filename): - # CircuitPython 6 & 7 compatible - image_file = open(filename, "rb") - odb = displayio.OnDiskBitmap(image_file) - face = displayio.TileGrid( - odb, - pixel_shader=getattr(odb, 'pixel_shader', displayio.ColorConverter()) - ) - - # # CircuitPython 7+ compatible - # odb = displayio.OnDiskBitmap(filename) - # face = displayio.TileGrid(odb, pixel_shader=odb.pixel_shader) + + odb = displayio.OnDiskBitmap(filename) + face = displayio.TileGrid(odb, pixel_shader=odb.pixel_shader) backlight.duty_cycle = 0 splash.append(face) diff --git a/HalloWing_Tour_Guide/code.py b/HalloWing_Tour_Guide/code.py index e4856591b..0a4026aeb 100644 --- a/HalloWing_Tour_Guide/code.py +++ b/HalloWing_Tour_Guide/code.py @@ -64,23 +64,12 @@ def play_wave(filename): pass def show_image(filename): - # CircuitPython 6 & 7 compatible + try: - image_file = open(filename, "rb") - except OSError: - image_file = open("missing.bmp", "rb") - odb = displayio.OnDiskBitmap(image_file) - face = displayio.TileGrid( - odb, - pixel_shader=getattr(odb, 'pixel_shader', displayio.ColorConverter()) - ) - - # # CircuitPython 7+ compatible - # try: - # odb = displayio.OnDiskBitmap(filename) - # except (OSError, ValueError): - # odb = displayio.OnDiskBitmap("missing.bmp") - # face = displayio.TileGrid(odb, pixel_shader=odb.pixel_shader) + odb = displayio.OnDiskBitmap(filename) + except (OSError, ValueError): + odb = displayio.OnDiskBitmap("missing.bmp") + face = displayio.TileGrid(odb, pixel_shader=odb.pixel_shader) backlight.value = False splash.append(face) diff --git a/Hallowing_Jump_Sound/jump-sound/code.py b/Hallowing_Jump_Sound/jump-sound/code.py index e68911e84..7f60501d6 100755 --- a/Hallowing_Jump_Sound/jump-sound/code.py +++ b/Hallowing_Jump_Sound/jump-sound/code.py @@ -102,7 +102,6 @@ def play_wav(wav): SCREEN = displayio.Group() board.DISPLAY.root_group = SCREEN - # CircuitPython 7+ compatible BITMAP = displayio.OnDiskBitmap(IMAGEFILE) TILEGRID = displayio.TileGrid(BITMAP, pixel_shader=BITMAP.pixel_shader) diff --git a/Hallowing_Jump_Sound/stomp-and-roar/code.py b/Hallowing_Jump_Sound/stomp-and-roar/code.py index 96895e438..541472658 100755 --- a/Hallowing_Jump_Sound/stomp-and-roar/code.py +++ b/Hallowing_Jump_Sound/stomp-and-roar/code.py @@ -98,7 +98,6 @@ def load_wav(name): SCREEN = displayio.Group() board.DISPLAY.root_group = SCREEN - # CircuitPython 7+ compatible BITMAP = displayio.OnDiskBitmap(IMAGEFILE) TILEGRID = displayio.TileGrid(BITMAP, pixel_shader=BITMAP.pixel_shader) diff --git a/I_Voted_Pin/code.py b/I_Voted_Pin/code.py index ff13ba3d8..ca65ebdc3 100755 --- a/I_Voted_Pin/code.py +++ b/I_Voted_Pin/code.py @@ -6,6 +6,7 @@ from adafruit_debouncer import Debouncer import digitalio import displayio +import i2cdisplaybus from adafruit_display_text import label import adafruit_displayio_ssd1306 from adafruit_bitmap_font import bitmap_font @@ -35,7 +36,7 @@ # Set up display & add group i2c = board.I2C() # uses board.SCL and board.SDA # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller -display_bus = displayio.I2CDisplay(i2c, device_address=0x3C) +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3C) display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32) group = displayio.Group() display.root_group = group diff --git a/Ideal_Diode_Examples/Arduino_Ideal_Diode_Monitor/.uno.test.only b/Ideal_Diode_Examples/Arduino_Ideal_Diode_Monitor/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Ideal_Diode_Examples/Arduino_Ideal_Diode_Monitor/Arduino_Ideal_Diode_Monitor.ino b/Ideal_Diode_Examples/Arduino_Ideal_Diode_Monitor/Arduino_Ideal_Diode_Monitor.ino new file mode 100644 index 000000000..a4ad0e162 --- /dev/null +++ b/Ideal_Diode_Examples/Arduino_Ideal_Diode_Monitor/Arduino_Ideal_Diode_Monitor.ino @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// LM73100 IMON Current Monitoring + +const int IMON_PIN = A0; // IMON connected to analog pin A0 +const float RIMON = 1500.0; // RIMON resistor value in ohms (1.5kΩ) +const float GIMON = 2.5; // GIMON typical value in μA/A (from datasheet, typical is 2.5) +const float VREF = 5.0; // Arduino reference voltage (5V for most Arduinos) +const int ADC_RESOLUTION = 1024; + +void setup() { + Serial.begin(9600); + pinMode(IMON_PIN, INPUT); + + Serial.println("LM73100 Current Monitor Started"); + Serial.println("================================"); + Serial.print("RIMON: "); + Serial.print(RIMON); + Serial.println(" ohms"); + Serial.print("GIMON: "); + Serial.print(GIMON); + Serial.println(" μA/A"); + Serial.println("================================\n"); +} + +void loop() { + int adcValue = analogRead(IMON_PIN); + float vimon = (adcValue * VREF) / ADC_RESOLUTION; + float iout_A = vimon / (RIMON * GIMON); + float iout_mA = iout_A * 1000.0; + + Serial.print("ADC Value: "); + Serial.print(adcValue); + Serial.print(" | VIMON: "); + Serial.print(vimon, 3); + Serial.print(" V | Output Current: "); + Serial.print(iout_mA, 2); + Serial.print(" mA ("); + Serial.print(iout_A, 3); + Serial.println(" A)"); + + delay(500); // Read every 500ms +} diff --git a/Ideal_Diode_Examples/CircuitPython_Ideal_Diode_Monitor/code.py b/Ideal_Diode_Examples/CircuitPython_Ideal_Diode_Monitor/code.py new file mode 100644 index 000000000..d9c98cce9 --- /dev/null +++ b/Ideal_Diode_Examples/CircuitPython_Ideal_Diode_Monitor/code.py @@ -0,0 +1,33 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# LM73100 IMON Current Monitoring + +import time +import board +from analogio import AnalogIn + +RIMON = 1500.0 # 1.5kΩ +GIMON = 2.5 # μA/A +analog_in = AnalogIn(board.A0) + +def get_voltage(pin): + return (pin.value * 3.3) / 65536 + +print("LM73100 Current Monitor Started") +print("================================") +print(f"RIMON: {RIMON} ohms") +print(f"GIMON: {GIMON} μA/A") +print("================================\n") + +while True: + # Read voltage from IMON pin + vimon = get_voltage(analog_in) + + # Calculate output current + iout_A = vimon / (RIMON * GIMON) + iout_mA = iout_A * 1000.0 + + print(f"ADC: {analog_in.value} | VIMON: {vimon:.3f}V | Current: {iout_mA:.2f} mA") + + time.sleep(0.5) diff --git a/IoT_Environment_Sensor/.circuitpython.skip b/IoT_Environment_Sensor/.circuitpython.skip deleted file mode 100644 index 117ae2f31..000000000 --- a/IoT_Environment_Sensor/.circuitpython.skip +++ /dev/null @@ -1,5 +0,0 @@ -IoT_Environment_Sensor/gps.py 22: Class 'Gps' inherits from object, can be safely removed from bases in python3 (useless-object-inheritance) -IoT_Environment_Sensor/air_quality.py 24: Class 'AirQualitySensor' inherits from object, can be safely removed from bases in python3 (useless-object-inheritance) -IoT_Environment_Sensor/aio.py 41: Class 'AIO' inherits from object, can be safely removed from bases in python3 (useless-object-inheritance) -IoT_Environment_Sensor/aio.py 120: Consider explicitly re-raising using the 'from' keyword (raise-missing-from) -IoT_Environment_Sensor/aio.py 142: Consider explicitly re-raising using the 'from' keyword (raise-missing-from) diff --git a/IoT_Environment_Sensor/aio.py b/IoT_Environment_Sensor/aio.py index fd4e74519..b3b178c3a 100644 --- a/IoT_Environment_Sensor/aio.py +++ b/IoT_Environment_Sensor/aio.py @@ -16,6 +16,7 @@ All text above must be included in any redistribution. """ +from os import getenv import time import gc import board @@ -37,14 +38,22 @@ -# Get wifi details and more from a settings.py file -try: - from secrets import secrets -except ImportError: - logger.critical('WiFi settings are kept in settings.py, please add them there!') - raise +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") -class AIO(object): +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + +class AIO: def __init__(self): try: @@ -76,16 +85,16 @@ def connect(self): logger.debug("Connecting...") while not self._esp.is_connected: try: - self._esp.connect_AP(secrets['ssid'], secrets['password']) + self._esp.connect_AP(ssid, password) except RuntimeError as e: logger.error("could not connect to AP, retrying: %s", e) continue def post(self, feed, payload): - api_url = 'https://io.adafruit.com/api/v2/{0}/feeds/{1}/data'.format(secrets['aio_username'], feed)# pylint: disable=line-too-long + api_url = f'https://io.adafruit.com/api/v2/{aio_username}/feeds/{feed}/data' logger.info('POSTing to %s', api_url) logger.info('payload: %s', str(payload)) - auth_header = {'X-AIO-KEY':secrets['aio_key']} + auth_header = {'X-AIO-KEY': aio_key} self.connect() r = None tries = 0 @@ -119,13 +128,8 @@ def refresh_local_time(self): """ # pylint: enable=line-too-long api_url = None - try: - aio_username = secrets['aio_username'] - aio_key = secrets['aio_key'] - except KeyError: - raise KeyError("\n\nOur time service requires a login/password to rate-limit. Please register for a free adafruit.io account and place the user/key in your secrets file under 'aio_username' and 'aio_key'")# pylint: disable=line-too-long - location = secrets['timezone'] + location = getenv('timezone') if location: logger.debug('Getting time for timezone %s', location) api_url = (TIME_SERVICE + "&tz=%s") % (aio_username, aio_key, location) @@ -144,8 +148,8 @@ def refresh_local_time(self): year_day = int(times[2]) week_day = int(times[3]) is_dst = None # no way to know yet - except KeyError: - raise KeyError("Was unable to lookup the time, try setting secrets['timezone'] according to http://worldtimeapi.org/timezones") # pylint: disable=line-too-long + except KeyError as exc: + raise KeyError("Was unable to lookup the time, try setting timezone in your settings.toml according to http://worldtimeapi.org/timezones") from exc # pylint: disable=line-too-long year, month, mday = [int(x) for x in the_date.split('-')] the_time = the_time.split('.')[0] hours, minutes, seconds = [int(x) for x in the_time.split(':')] diff --git a/IoT_Environment_Sensor/air_quality.py b/IoT_Environment_Sensor/air_quality.py index bb392cc2e..a2fff82fa 100644 --- a/IoT_Environment_Sensor/air_quality.py +++ b/IoT_Environment_Sensor/air_quality.py @@ -27,7 +27,7 @@ if not logger.hasHandlers(): logger.addHandler(logging.StreamHandler()) -class AirQualitySensor (object): +class AirQualitySensor: def __init__(self, uart): self._uart = uart diff --git a/IoT_Environment_Sensor/code.py b/IoT_Environment_Sensor/code.py index 5ff2970cf..2ffe9397f 100644 --- a/IoT_Environment_Sensor/code.py +++ b/IoT_Environment_Sensor/code.py @@ -21,9 +21,9 @@ import busio import air_quality import gps -import adafruit_bme280 import aio import adafruit_logging as logging +import adafruit_bme280 logger = logging.getLogger('main') if not logger.hasHandlers(): diff --git a/IoT_Environment_Sensor/gps.py b/IoT_Environment_Sensor/gps.py index 9839350c1..5b8014422 100644 --- a/IoT_Environment_Sensor/gps.py +++ b/IoT_Environment_Sensor/gps.py @@ -25,7 +25,7 @@ if not logger.hasHandlers(): logger.addHandler(logging.StreamHandler()) -class Gps(object): +class Gps: def __init__(self, uart): self._gps = adafruit_gps.GPS(uart, debug=False) diff --git a/IoT_Environment_Sensor/secrets.py b/IoT_Environment_Sensor/secrets.py deleted file mode 100644 index f55951b18..000000000 --- a/IoT_Environment_Sensor/secrets.py +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-FileCopyrightText: 2019 Dave Astels for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -# This file is where you keep secret settings, passwords, and tokens! -# If you put them in the code you risk committing that info or sharing it - -secrets = { - "ssid": b"My_SSID", - "password": b"My_WIFI_Password", - "timezone": "Area/City", - "aio_username": "my_username", - "aio_key": "my_key", -} diff --git a/IoT_Environment_Sensor/settings.toml b/IoT_Environment_Sensor/settings.toml new file mode 100644 index 000000000..c6b66bd33 --- /dev/null +++ b/IoT_Environment_Sensor/settings.toml @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: 2019 Dave Astels for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# This file is where you keep private settings, passwords, and tokens! +# If you put them in the code you risk committing that info or sharing it + +CIRCUITPY_WIFI_SSID="your-wifi-ssid" +CIRCUITPY_WIFI_PASSWORD="your-wifi-password" +ADAFRUIT_AIO_USERNAME="my_username" +ADAFRUIT_AIO_KEY="my_key" +timezone="America/New_York" # http://worldtimeapi.org/timezones diff --git a/IoT_NeoPixel_Sign/.circuitpython.skip b/IoT_NeoPixel_Sign/.circuitpython.skip deleted file mode 100644 index e6f96e785..000000000 --- a/IoT_NeoPixel_Sign/.circuitpython.skip +++ /dev/null @@ -1 +0,0 @@ -IoT_NeoPixel_Sign/code.py 47: Using the global statement (global-statement) diff --git a/IoT_NeoPixel_Sign/code.py b/IoT_NeoPixel_Sign/code.py index 3c0130464..2e35fbbcd 100644 --- a/IoT_NeoPixel_Sign/code.py +++ b/IoT_NeoPixel_Sign/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import ssl import board import neopixel @@ -12,20 +13,26 @@ from adafruit_pixel_framebuf import PixelFramebuffer # adafruit_circuitpython_adafruitio usage with native wifi networking +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + # Neopixel matrix configuration PIXEL_PIN = board.IO6 PIXEL_WIDTH = 12 PIXEL_HEIGHT = 12 -# secrets.py has SSID/password and adafruit.io -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise -AIO_USERNAME = secrets["aio_username"] -AIO_KEY = secrets["aio_key"] - # LED matrix creation PIXELS = neopixel.NeoPixel( PIXEL_PIN, PIXEL_WIDTH * PIXEL_HEIGHT, brightness=0.5, auto_write=False, @@ -48,7 +55,7 @@ # Helper function to get updated data from Adafruit.io def update_data(): - global CURRENT_TEXT, CURRENT_COLOR + global CURRENT_TEXT, CURRENT_COLOR # pylint: disable=global-statement print("Updating data from Adafruit IO") try: quote_feed = IO.get_feed(QUOTE_FEED) @@ -63,15 +70,15 @@ def update_data(): # Connect to WiFi -print("Connecting to %s" % secrets["ssid"]) -wifi.radio.connect(secrets["ssid"], secrets["password"]) -print("Connected to %s!" % secrets["ssid"]) +print(f"Connecting to {ssid}") +wifi.radio.connect(ssid, password) +print(f"Connected to {ssid}!") # Setup Adafruit IO connection -POOL = socketpool.SocketPool(wifi.radio) -REQUESTS = adafruit_requests.Session(POOL, ssl.create_default_context()) +pool = socketpool.SocketPool(wifi.radio) +requests = adafruit_requests.Session(pool, ssl.create_default_context()) # Initialize an Adafruit IO HTTP API object -IO = IO_HTTP(AIO_USERNAME, AIO_KEY, REQUESTS) +IO = IO_HTTP(aio_username, aio_key, requests) while True: diff --git a/IoT_Party_Parrot/code.py b/IoT_Party_Parrot/code.py index a4486ee23..55b24a76e 100644 --- a/IoT_Party_Parrot/code.py +++ b/IoT_Party_Parrot/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import board import displayio @@ -9,17 +10,22 @@ from adafruit_matrixportal.matrix import Matrix import adafruit_imageload -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise - print("Party Parrot Twitter Matrix") +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) + # import your bearer token -bear = secrets['bearer_token'] +bear = getenv('bearer_token') # query URL for tweets. looking for hashtag partyparrot sent to a specific username DATA_SOURCE = 'https://api.twitter.com/2/tweets/search/recent?query=#partyparrot to:blitzcitydiy' diff --git a/IoT_Party_Parrot/secrets.py b/IoT_Party_Parrot/secrets.py deleted file mode 100644 index 39bdad947..000000000 --- a/IoT_Party_Parrot/secrets.py +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Liz Clark for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -# This file is where you keep secret settings, passwords, and tokens! -# If you put them in the code you risk committing that info or sharing it - -secrets = { - 'ssid' : 'insert your network name here', - 'password' : 'insert your network password here', - 'timezone' : "America/New_York", # http://worldtimeapi.org/timezones - 'twitter_api_key' : 'insert your twitter api key here', - 'twitter_secret_key' : 'insert your twitter secret key here', - 'bearer_token' : 'insert your bearer token here' - } diff --git a/IoT_Party_Parrot/settings.toml b/IoT_Party_Parrot/settings.toml new file mode 100644 index 000000000..4b4d629e3 --- /dev/null +++ b/IoT_Party_Parrot/settings.toml @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2020 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# This file is where you keep private settings, passwords, and tokens! +# If you put them in the code you risk committing that info or sharing it + +CIRCUITPY_WIFI_SSID="your-wifi-ssid" +CIRCUITPY_WIFI_PASSWORD="your-wifi-password" +timezone="America/New_York" # http://worldtimeapi.org/timezones +twitter_api_key="insert your twitter api key here" +twitter_secret_key="insert your twitter secret key here" +bearer_token="insert your bearer token here" diff --git a/Jack_O_LED_trix/Jack_O_LED_trix.ino b/Jack_O_LED_trix/Jack_O_LED_trix.ino index b0619b1d9..662d3de18 100644 --- a/Jack_O_LED_trix/Jack_O_LED_trix.ino +++ b/Jack_O_LED_trix/Jack_O_LED_trix.ino @@ -29,6 +29,10 @@ #include "colorutils.h" #include "colorpalettes.h" +#if defined(FASTLED_VERSION) && FASTLED_VERSION > 3010001 + #error "FastLED 3.10.2 has known compile issues with SAMD boards. Please downgrade to FastLED 3.10.1" +#endif + #define BRIGHTNESS 128 //Define the type of pixels you are using on the next line here. diff --git a/Keyset_MIDI_Controller/code.py b/Keyset_MIDI_Controller/code.py new file mode 100644 index 000000000..7dabc7ca2 --- /dev/null +++ b/Keyset_MIDI_Controller/code.py @@ -0,0 +1,517 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark and Noe Ruiz for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import board +import simpleio +import displayio +import i2cdisplaybus +import adafruit_imageload +import rotaryio +import digitalio +import terminalio +import keypad +from digitalio import DigitalInOut, Direction +from adafruit_display_text import label +from adafruit_display_shapes.rect import Rect +import adafruit_displayio_ssd1306 +import usb_midi +import adafruit_midi +from adafruit_midi.note_on import NoteOn +from adafruit_midi.note_off import NoteOff +from adafruit_midi.control_change import ControlChange +from analogio import AnalogIn +from adafruit_debouncer import Button + +# midi note names +MIDI_NOTE_NAMES = [ + "C-2", "C#-2", "D-2", "D#-2", "E-2", "F-2", "F#-2", "G-2", "G#-2", "A-2", "A#-2", "B-2", + "C-1", "C#-1", "D-1", "D#-1", "E-1", "F-1", "F#-1", "G-1", "G#-1", "A-1", "A#-1", "B-1", + "C0", "C#0", "D0", "D#0", "E0", "F0", "F#0", "G0", "G#0", "A0", "A#0", "B0", + "C1", "C#1", "D1", "D#1", "E1", "F1", "F#1", "G1", "G#1", "A1", "A#1", "B1", + "C2", "C#2", "D2", "D#2", "E2", "F2", "F#2", "G2", "G#2", "A2", "A#2", "B2", + "C3", "C#3", "D3", "D#3", "E3", "F3", "F#3", "G3", "G#3", "A3", "A#3", "B3", + "C4", "C#4", "D4", "D#4", "E4", "F4", "F#4", "G4", "G#4", "A4", "A#4", "B4", + "C5", "C#5", "D5", "D#5", "E5", "F5", "F#5", "G5", "G#5", "A5", "A#5", "B5", + "C6", "C#6", "D6", "D#6", "E6", "F6", "F#6", "G6", "G#6", "A6", "A#6", "B6", + "C7", "C#7", "D7", "D#7", "E7", "F7", "F#7", "G7", "G#7", "A7", "A#7", "B7", + "C8", "C#8", "D8", "D#8", "E8", "F8", "F#8", "G8", "G#8", "A8", "A#8", "B8", + "C9", "C#9", "D9", "D#9", "E9", "F9", "F#9", "G9", "G#9", "A9", "A#9", "B9" + ] + + +# Data structure to store all control settings +control_settings = { + 'pots': [ + {'cc_num': 1, 'range_min': 0, 'range_max': 127, 'channel': 0, 'current_val': 0}, # Pot A + {'cc_num': 10, 'range_min': 0, 'range_max': 127, 'channel': 0, 'current_val': 0}, # Pot B + {'cc_num': 11, 'range_min': 0, 'range_max': 127, 'channel': 0, 'current_val': 0}, # Pot C + ], + 'keys': [ + {'note': 61, 'velocity': 120, 'channel': 0}, # Key 1 + {'note': 64, 'velocity': 120, 'channel': 0}, # Key 2 + {'note': 66, 'velocity': 120, 'channel': 0}, # Key 3 + {'note': 68, 'velocity': 120, 'channel': 0}, # Key 4 + {'note': 73, 'velocity': 120, 'channel': 0}, # Key 5 + ] +} + +# midi note numbers (will be replaced by control_settings) +midi_notes = [key['note'] for key in control_settings['keys']] + + +#rotary encoder and button +encoder = rotaryio.IncrementalEncoder(board.D3, board.D2) +last_position = 0 + +# midi setup +midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=0) + +# Create keypad object with the pins (removed encoder button) +keys = keypad.Keys( + pins=(board.D4, board.D5, board.D6, board.D7, board.D8), + value_when_pressed=False, # Buttons pull to ground when pressed + pull=True # Enable internal pull-up resistors +) + +# Set up encoder button with debouncer +encoder_button_pin = DigitalInOut(board.A3) +encoder_button_pin.direction = Direction.INPUT +encoder_button_pin.pull = digitalio.Pull.UP +encoder_button = Button(encoder_button_pin, value_when_pressed=False, long_duration_ms=500) + +# potentiometer setup +pot_A = AnalogIn(board.A2) +pot_B = AnalogIn(board.A1) +pot_C = AnalogIn(board.A0) + +#display setup +i2c = board.STEMMA_I2C() +displayio.release_displays() + +# oled +oled_reset = board.D9 +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3D, reset=oled_reset) +WIDTH = 128 +HEIGHT = 64 +display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=WIDTH, height=HEIGHT) + +bitmap, palette = adafruit_imageload.load("/main.bmp", + bitmap=displayio.Bitmap, + palette=displayio.Palette) + +# Create a TileGrid to hold the bitmap +bitmap_grid = displayio.TileGrid(bitmap, pixel_shader=palette) + +# Create main page +maingroup = displayio.Group() + +#dictionary for rectangle highlights +rect_dict = [ + {'pos': (0, 0), 'dim': (42, 32)}, + {'pos': (42, 0), 'dim': (42, 32)}, + {'pos': (84, 0), 'dim': (42, 32)}, + {'pos': (1, 32), 'dim': (25, 32)}, + {'pos': (26, 32), 'dim': (25, 32)}, + {'pos': (51, 32), 'dim': (25, 32)}, + {'pos': (76, 32), 'dim': (25, 32)}, + {'pos': (101, 32), 'dim': (25, 32)}, +] + +current_index = 0 +rect_info = rect_dict[current_index] +x, y = rect_info['pos'] +w, h = rect_info['dim'] + +# Create the rectangle (outline only, no fill) +rectangle = Rect(x, y, w, h, fill=None, outline=0xFFFFFF) + +# Add rectangles to the Group +maingroup.append(bitmap_grid) +maingroup.append(rectangle) + +#text container +keynote_maingroup = displayio.Group() +font = terminalio.FONT +color = 0x000000 + +keynotes = [ + {'num': control_settings['keys'][0]['note'], 'pos': (14, 42)}, + {'num': control_settings['keys'][1]['note'], 'pos': (39, 42)}, + {'num': control_settings['keys'][2]['note'], 'pos': (64, 42)}, + {'num': control_settings['keys'][3]['note'], 'pos': (89, 42)}, + {'num': control_settings['keys'][4]['note'], 'pos': (114, 42)}, +] +keynote_labels = [] +for keynote in keynotes: + keynote_area = label.Label(terminalio.FONT, + text=MIDI_NOTE_NAMES[keynote['num']], + color=0x000000) + keynote_area.anchor_point = (0.5, 0.0) + keynote_area.anchored_position = (keynote['pos'][0], keynote['pos'][1]) + keynote_labels.append(keynote_area) + keynote_maingroup.append(keynote_area) +maingroup.append(keynote_maingroup) + +# labels for potentiometers + +potval_maingroup = displayio.Group() +potvals = [ + {'num': "0", 'pos': (22, 10)}, + {'num': "0", 'pos': (64, 10)}, + {'num': "0", 'pos': (106, 10)}, +] +potvals_labels = [] + +for potval in potvals: + potval_area = label.Label( + terminalio.FONT, + text=potval['num'], + color=0x000000, + ) + potval_area.anchor_point = (0.5, 0.0) + potval_area.anchored_position = (potval['pos'][0], potval['pos'][1]) + potvals_labels.append(potval_area) + potval_maingroup.append(potval_area) +maingroup.append(potval_maingroup) + +# Create edit page +editgroup = displayio.Group() + +# Labels for Edit Page +header_area = label.Label( + terminalio.FONT, + text="", + color=0x000000, + x=0, y=10, + background_color=0xFFFFFF, + padding_left=34, + padding_right=34, + padding_top=2, + padding_bottom=2, + ) +header_area.anchor_point = (0.5, 0.0) +header_area.anchored_position = (64, 2) + +item1_area = label.Label(terminalio.FONT, text="", color=0xFFFFFF, x=4, y=25,) +item2_area = label.Label(terminalio.FONT, text="", color=0xFFFFFF, x=4, y=38,) +item3_area = label.Label(terminalio.FONT, text="", color=0xFFFFFF, x=4, y=52,) + +# Create separate labels for range min and max +range_label = label.Label(terminalio.FONT, text="Range:", color=0xFFFFFF, x=4, y=38,) +range_min_label = label.Label(terminalio.FONT, text="", color=0xFFFFFF, x=65, y=38,) +range_dash_label = label.Label(terminalio.FONT, text="-", color=0xFFFFFF, x=85, y=38,) +range_max_label = label.Label(terminalio.FONT, text="", color=0xFFFFFF, x=95, y=38,) + +item_areas = [item1_area, item2_area, item3_area] +edit_rectangle = Rect(0, 0, 128, 14, fill=None, outline=0xFFFFFF) +range_rectangle = Rect(0, 0, 20, 14, fill=0x000000, outline=0xFFFFFF) + +editgroup.append(edit_rectangle) +editgroup.append(header_area) +editgroup.append(item1_area) +editgroup.append(item2_area) +editgroup.append(item3_area) +editgroup.append(range_rectangle) +range_rectangle.hidden = True + +# Add the Group to the Display +display.root_group = maingroup + +# function to read analog input +def val(pin): + return pin.value + +# Function to update edit mode display +def update_edit_display(index): + # First, remove the range components if they exist in editgroup + if range_label in editgroup: + editgroup.remove(range_label) + editgroup.remove(range_min_label) + editgroup.remove(range_dash_label) + editgroup.remove(range_max_label) + if index < 3: # Potentiometer + p = control_settings['pots'][index] + header_area.text = f"EDIT POT {'ABC'[index]}" + item1_area.text = f"CC Number: {p['cc_num']}" + # Clear item2_area text since we'll use separate labels + item2_area.text = "" + # Add range components + editgroup.append(range_label) + editgroup.append(range_min_label) + editgroup.append(range_dash_label) + editgroup.append(range_max_label) + range_min_label.text = str(p['range_min']) + range_max_label.text = str(p['range_max']) + item3_area.text = f"MIDI Channel: {p['channel'] + 1}" + else: # Button + k = index - 3 + s = control_settings['keys'][k] + note_name = MIDI_NOTE_NAMES[s['note']] + header_area.text = f"EDIT KEY {k + 1}" + item1_area.text = f"MIDI Note: {note_name}" + item2_area.text = f"Velocity: {s['velocity']}" + item3_area.text = f"MIDI Channel: {s['channel'] + 1}" + +# variables for last read value +pot_A_val2 = 0 +pot_B_val2 = 0 +pot_C_val2 = 0 + +edit_mode = False +edit_current_index = 0 +edit_active = False # Whether we're actively editing a value +range_edit_selection = 0 # 0 for min, 1 for max +range_edit_active = False # New variable to track if we're actively editing a range value + +while True: + # Update encoder button state + encoder_button.update() + + # Handle encoder button presses + if encoder_button.short_count == 1: + if not edit_mode: + # Short press enters edit mode + update_edit_display(current_index) + edit_current_index = 0 + edit_rectangle.x = 0 + edit_rectangle.y = item_areas[edit_current_index].y - 7 + edit_active = False + range_rectangle.hidden = True + display.root_group = editgroup + edit_mode = True + elif edit_mode and edit_active and current_index < 3 and edit_current_index == 1: + # In range editing mode, short press switches between min/max + range_edit_selection = 1 - range_edit_selection # Toggle between 0 and 1 + if range_edit_selection == 0: + range_rectangle.x = range_min_label.x - 2 + else: + range_rectangle.x = range_max_label.x - 2 + else: + # Short press exits edit mode + display.root_group = maingroup + edit_mode = False + edit_active = False + range_edit_active = False + edit_rectangle.fill = None + item_areas[edit_current_index].color = 0xFFFFFF + if current_index < 3 and edit_current_index == 1: + range_min_label.color = 0xFFFFFF + range_max_label.color = 0xFFFFFF + range_label.color = 0xFFFFFF + range_dash_label.color = 0xFFFFFF + range_rectangle.hidden = True + if encoder_button.short_count == 2: + # send midi panic + panic = ControlChange(123, 120) + # send CC message + midi.send(panic) + + # Handle long press in edit mode + if edit_mode and encoder_button.long_press: + if current_index < 3 and edit_current_index == 1: + # We're on the Range line + if not edit_active: + # Not in range edit mode yet, enter it + edit_active = True + range_edit_active = False + edit_rectangle.fill = 0xFFFFFF + # Show the range rectangle + range_rectangle.hidden = False + range_rectangle.fill = None + range_rectangle.outline = 0x000000 + range_edit_selection = 0 # Start with min + # Position range rectangle over the min value + range_rectangle.x = range_min_label.x - 2 + range_rectangle.y = range_min_label.y - 7 + range_label.color = 0x000000 + range_dash_label.color = 0x000000 + range_max_label.color = 0x000000 + range_min_label.color = 0x000000 + elif edit_active and not range_edit_active: + # In selection mode, enter value editing mode + range_edit_active = True + range_rectangle.fill = 0x000000 + range_min_label.color = 0xFFFFFF + range_max_label.color = 0xFFFFFF + elif edit_active and range_edit_active: + # In value editing mode, exit range editing completely + edit_active = False + range_edit_active = False + edit_rectangle.fill = None + # Hide range rectangle and restore colors + range_rectangle.hidden = True + range_label.color = 0xFFFFFF + range_dash_label.color = 0xFFFFFF + range_min_label.color = 0xFFFFFF + range_max_label.color = 0xFFFFFF + else: + # Non-range items - simple toggle + edit_active = not edit_active + range_edit_active = False # Reset range edit active state + + # Change rectangle color to indicate active editing + if edit_active: + edit_rectangle.fill = 0xFFFFFF + # Make text black on white background for other items + item_areas[edit_current_index].color = 0x000000 + else: + edit_rectangle.fill = None + # Make text white + item_areas[edit_current_index].color = 0xFFFFFF + + event = keys.events.get() + + if event: + # event.key_number gives you the index (0-4) of which button + key_index = event.key_number + + if event.pressed: + # Button was pressed - send NoteOn using settings + key_settings = control_settings['keys'][key_index] + midi.send(NoteOn(key_settings['note'], key_settings['velocity'])) + + if event.released: + # Button was released - send NoteOff using settings + key_settings = control_settings['keys'][key_index] + midi.send(NoteOff(key_settings['note'], key_settings['velocity'])) + + position = encoder.position + + # Check if encoder moved + if position != last_position: + if not edit_mode: + # Main menu navigation + if position > last_position: + current_index = (current_index + 1) % len(rect_dict) + else: + current_index = (current_index - 1) % len(rect_dict) + + rect_info = rect_dict[current_index] + x, y = rect_info['pos'] + w, h = rect_info['dim'] + + # Remove old rectangle and create new one with updated dimensions + maingroup.remove(rectangle) + rectangle = Rect(x, y, w, h, fill=None, outline=0xFFFFFF) + maingroup.append(rectangle) + last_position = position + + elif edit_mode and not edit_active: + # Edit mode navigation - cycle through editable items + # First restore previous item colors + item_areas[edit_current_index].color = 0xFFFFFF + + if position > last_position: + edit_current_index = (edit_current_index + 1) % len(item_areas) + else: + edit_current_index = (edit_current_index - 1) % len(item_areas) + + # Update rectangle position to highlight current item + edit_rectangle.x = 0 + edit_rectangle.y = item_areas[edit_current_index].y - 7 + last_position = position + + elif edit_mode and edit_active: + # Actively editing a value + direction = 1 if position > last_position else -1 + + if current_index < 3: # Editing potentiometer + pot_settings = control_settings['pots'][current_index] + + if edit_current_index == 0: # CC Number + pot_settings['cc_num'] = (pot_settings['cc_num'] + direction) % 128 + item1_area.text = f"CC Number: {pot_settings['cc_num']}" + elif edit_current_index == 1: # Range editing + if range_edit_active: + # Actually edit the value + if range_edit_selection == 0: # Editing min + pot_settings['range_min'] = (pot_settings['range_min'] + + direction) % 128 + range_min_label.text = f"{pot_settings['range_min']}" + else: # Editing max + pot_settings['range_max'] = (pot_settings['range_max'] + + direction) % 128 + range_max_label.text = f"{pot_settings['range_max']}" + else: + # Special handling for range - switch between min and max + if direction > 0 and range_edit_selection == 0: + # Moving right from min, switch to max + range_edit_selection = 1 + range_rectangle.x = range_max_label.x - 2 + elif direction < 0 and range_edit_selection == 1: + # Moving left from max, switch to min + range_edit_selection = 0 + range_rectangle.x = range_min_label.x - 2 + elif edit_current_index == 2: # MIDI Channel + pot_settings['channel'] = (pot_settings['channel'] + direction) % 16 + item3_area.text = f"MIDI Channel: {pot_settings['channel'] + 1}" + + else: # Editing key + key_index = current_index - 3 + key_settings = control_settings['keys'][key_index] + + if edit_current_index == 0: # MIDI Note + key_settings['note'] = (key_settings['note'] + direction) % len(MIDI_NOTE_NAMES) + key_note_name = MIDI_NOTE_NAMES[key_settings['note']] + item1_area.text = f"MIDI Note: {key_note_name}" + # Update the main screen label too + keynote_labels[key_index].text = key_note_name + elif edit_current_index == 1: # Velocity + key_settings['velocity'] = (key_settings['velocity'] + direction) % 127 + item2_area.text = f"Velocity: {key_settings['velocity']}" + elif edit_current_index == 2: # MIDI Channel + key_settings['channel'] = (key_settings['channel'] + direction) % 16 + item3_area.text = f"MIDI Channel: {key_settings['channel'] + 1}" + + last_position = position + + pot_A_val1 = round(simpleio.map_range(val(pot_A), 65535, 0, + control_settings['pots'][0]['range_min'], + control_settings['pots'][0]['range_max'])) + pot_B_val1 = round(simpleio.map_range(val(pot_B), 65535, 0, + control_settings['pots'][1]['range_min'], + control_settings['pots'][1]['range_max'])) + pot_C_val1 = round(simpleio.map_range(val(pot_C), 65535, 0, + control_settings['pots'][2]['range_min'], + control_settings['pots'][2]['range_max'])) + + # if modulation value is updated... + if abs(pot_A_val1 - pot_A_val2) > 1: + # update pot_A_val2 + pot_A_val2 = pot_A_val1 + # create integer + modulation = int(pot_A_val2) + control_settings['pots'][0]['current_val'] = modulation + potvals_labels[0].text = str(modulation) + # create CC message + pot_settings = control_settings['pots'][0] + modWheel = ControlChange(pot_settings['cc_num'], modulation) + # send CC message + midi.send(modWheel) + + if abs(pot_B_val1 - pot_B_val2) > 1: + # update pot_B_val2 + pot_B_val2 = pot_B_val1 + # create integer + ControllerB = int(pot_B_val2) + control_settings['pots'][1]['current_val'] = ControllerB + potvals_labels[1].text = str(ControllerB) + # create CC message + pot_settings = control_settings['pots'][1] + ControlB = ControlChange(pot_settings['cc_num'], ControllerB) + # send CC message + midi.send(ControlB) + + if abs(pot_C_val1 - pot_C_val2) > 1: + # update pot_c_val2 + pot_C_val2 = pot_C_val1 + # create integer + ControllerC = int(pot_C_val2) + control_settings['pots'][2]['current_val'] = ControllerC + potvals_labels[2].text = str(ControllerC) + # create CC message + pot_settings = control_settings['pots'][2] + ControlC = ControlChange(pot_settings['cc_num'], ControllerC) + # send CC message + midi.send(ControlC) diff --git a/Keyset_MIDI_Controller/main.bmp b/Keyset_MIDI_Controller/main.bmp new file mode 100644 index 000000000..9d2a077cc Binary files /dev/null and b/Keyset_MIDI_Controller/main.bmp differ diff --git a/Kitty_Paw_Keypad/code.py b/Kitty_Paw_Keypad/code.py index c3d9ad70b..05b53dde0 100644 --- a/Kitty_Paw_Keypad/code.py +++ b/Kitty_Paw_Keypad/code.py @@ -4,6 +4,7 @@ import board import displayio +import fourwire import keypad from adafruit_st7789 import ST7789 import adafruit_imageload @@ -50,7 +51,7 @@ tft_cs = board.D7 tft_dc = board.D5 -display_bus = displayio.FourWire( +display_bus = fourwire.FourWire( spi, command=tft_dc, chip_select=tft_cs, reset=board.D6 ) diff --git a/Knobby_Sequencer/code.py b/Knobby_Sequencer/code.py new file mode 100644 index 000000000..ff9afceb3 --- /dev/null +++ b/Knobby_Sequencer/code.py @@ -0,0 +1,975 @@ +# SPDX-FileCopyrightText: John Park for Adafruit 2025 Knobby MIDI Step Sequencer +# SPDX-License-Identifier: MIT +""" +MIDI Step Sequencer for QT Py RP2040 with NeoRotary 4 encoder seesaw boards +Configurable 4/8/12/16-step sequencer: +- Each encoder controls one step's note pitch +- Encoder buttons toggle steps on/off +- DOUBLE-CLICK first knob to enter settings mode +- In settings mode: control playback, tempo, scales, velocity, randomization +- External NeoPixel strip shows step status and current playback position +- Sends MIDI notes via USB +- I2C reads only after each board's 4 steps for performance +- Uses bulk digital reads for better I2C performance +""" + +import time +import random +import busio +import board +import digitalio +import usb_midi + +import adafruit_seesaw.digitalio +import adafruit_seesaw.rotaryio +import adafruit_seesaw.seesaw +import neopixel + +from scales import get_scale, list_scales, get_scale_info + +# USER CONFIGURATION +SCALE_MODE = "major" # Options: see scales.py for all available scales +STEPS = 16 # Options: 4, 8, 12, or 16 steps +BPM = 90 # Beats per minute + +# I2C addresses for encoder boards (add/remove as needed) +I2C_ADDRESSES = [0x49, 0x4A, 0x4B, 0x4C] # Up to 4 boards for 16 steps + +# Calculate number of NeoPixels based on steps +NEOPIXEL_COUNT = {4: 12, 8: 24, 12: 36, 16: 48} +NUM_NEOPIXELS = NEOPIXEL_COUNT.get(STEPS, 24) + +# Validate configuration +if STEPS not in [4, 8, 12, 16]: + raise ValueError("STEPS must be 4, 8, 12, or 16") + +REQUIRED_BOARDS = (STEPS + 3) // 4 # Round up division +if len(I2C_ADDRESSES) < REQUIRED_BOARDS: + raise ValueError(f"Need at least {REQUIRED_BOARDS} I2C addresses for {STEPS} steps") + +STEP_TIME = 60.0 / BPM / 4 # 16th note timing + +# Button pin mappings for bulk reads +BUTTON_PINS_BOARD = [12, 14, 17, 9] # Pin numbers for board buttons +BUTTON_MASK_BOARD = sum(1 << pin for pin in BUTTON_PINS_BOARD) # Bitmask + +# Timing constants +DOUBLE_CLICK_TIME = 0.5 # seconds +NOTE_LENGTH_RATIO = 0.25 # Note duration as ratio of step time + +# Parameter limits +MIN_BPM, MAX_BPM = 60, 200 +MIN_OCTAVE, MAX_OCTAVE = -2, 2 +MIN_SEMITONE, MAX_SEMITONE = 0, 12 +MIN_VELOCITY, MAX_VELOCITY = 20, 127 +MIN_VEL_RANDOM, MAX_VEL_RANDOM = 0, 50 + +# Colors for settings indicators +COLORS = { + 'off': 0x000000, # Black - step off + 'playing_off': 0x220000, # Dim red - current position but step off + 'play_stop': 0x00FF00, # Green - play/stop control + 'bpm': 0x800080, # Purple - BPM control + 'octave': 0xFF8000, # Orange - octave control + 'semitone': 0xFFFF00, # Yellow - semitone control + 'scale_inactive': 0x404040, # Dim white - inactive scale categories + 'scale_active': 0x008080, # Cyan - active scale category + 'velocity': 0xFF0080, # Hot pink - velocity control + 'vel_random': 0x80FF80, # Light green - velocity randomization + 'randomize': 0xFF8080, # Light red - randomize all +} + +# External NeoPixel strip setup +external_strip = neopixel.NeoPixel(board.MOSI, NUM_NEOPIXELS, brightness=0.06, auto_write=False) +external_strip.fill(0x000000) +external_strip.show() + +# Startup animation +for i in range(NUM_NEOPIXELS): + external_strip[i] = 0x201500 + time.sleep(0.02) + external_strip.show() + +# RAW MIDI Setup - using direct USB MIDI port +midi_out = usb_midi.ports[1] + + +def midi_panic(): + """Send MIDI panic - All Notes Off and All Sound Off on all channels""" + print("Sending MIDI panic...") + try: + # Send on all 16 MIDI channels (0-15) + for channel in range(16): + # All Notes Off (CC 123): 0xB0 + channel, 123, 0 + midi_out.write(bytes([0xB0 + channel, 123, 0])) + # All Sound Off (CC 120): 0xB0 + channel, 120, 0 + midi_out.write(bytes([0xB0 + channel, 120, 0])) + + # Small delay to ensure messages are sent + time.sleep(0.1) + print("MIDI panic complete") + except OSError as e: + print(f"MIDI panic error: {e}") + + +# Send MIDI panic on startup to clear any stuck notes +midi_panic() + +external_strip.fill(0x000000) +external_strip.show() + +# I2C and Seesaw setup +i2c = busio.I2C(board.SCL1, board.SDA1, frequency=400000) + +# Initialize seesaw boards based on required count +seesaw_boards = [] +encoders_per_board = [] +switches_per_board = [] + +for board_idx in range(REQUIRED_BOARDS): + try: + board_addr = I2C_ADDRESSES[board_idx] + seesaw_board = adafruit_seesaw.seesaw.Seesaw(i2c, board_addr) + seesaw_boards.append(seesaw_board) + + # Setup encoders and switches for this board + board_encoders = [ + adafruit_seesaw.rotaryio.IncrementalEncoder(seesaw_board, n) + for n in range(4) + ] + board_switches = [ + adafruit_seesaw.digitalio.DigitalIO(seesaw_board, pin) + for pin in (12, 14, 17, 9) + ] + + for switch in board_switches: + switch.switch_to_input(digitalio.Pull.UP) + + encoders_per_board.append(board_encoders) + switches_per_board.append(board_switches) + + print(f"Initialized board {board_idx+1} at address 0x{board_addr:02X}") + + except OSError as e: + print( + f"Failed to initialize board {board_idx+1} " + f"at address 0x{I2C_ADDRESSES[board_idx]:02X}: {e}" + ) + raise + +# Flatten lists for easier access (only up to STEPS count) +encoders = [] +switches = [] +for board_encoders, board_switches in zip(encoders_per_board, switches_per_board): + encoders.extend(board_encoders) + switches.extend(board_switches) + +# Trim to exact step count +encoders = encoders[:STEPS] +switches = switches[:STEPS] + + +# Step-to-external pixel mapping based on step count +def generate_step_to_pixel_mapping(num_steps, num_pixels): + """Generate step to pixel mapping based on configuration""" + if num_steps == 4: + return [1, 4, 7, 10] + elif num_steps == 8: + return [1, 4, 7, 10, 13, 16, 19, 22] + elif num_steps == 12: + return [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34] + elif num_steps == 16: + return [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46] + else: + # Fallback: evenly distribute + step_spacing = num_pixels // num_steps + return [idx * step_spacing + 1 for idx in range(num_steps)] + + +STEP_TO_PIXEL = generate_step_to_pixel_mapping(STEPS, NUM_NEOPIXELS) + +# Get available scales organized by category +SCALE_CATEGORIES = get_scale_info() +AVAILABLE_SCALES = list_scales() +current_scale_index = 0 + +# Scale category management +SCALE_CATEGORY_NAMES = list(SCALE_CATEGORIES.keys()) +current_scale_categories = {} # Track current scale index for each category + +# Initialize each category's current scale index +for category in SCALE_CATEGORY_NAMES: + current_scale_categories[category] = 0 + +# Find the index of the current scale mode +try: + current_scale_index = AVAILABLE_SCALES.index(SCALE_MODE) +except ValueError: + current_scale_index = 0 + SCALE_MODE = AVAILABLE_SCALES[0] + +# Get the selected scale +SCALE = get_scale(SCALE_MODE) + + +# Step data - each step has a note and on/off state +class Step: + """Represents a single step in the sequence""" + def __init__(self, note=60, active=False): + self.note = note # MIDI note number + self.active = active # Whether step plays or not + + +# Initialize steps with notes from the selected scale +def initialize_steps_from_scale(scale, num_steps): + """Initialize steps with notes from the selected scale""" + step_list = [] + scale_len = len(scale) + + # Use notes from the middle of the scale (around the 4th octave) + start_index = scale_len // 3 # Start roughly 1/3 through the scale + + # Create the first 8 ascending notes from the scale + first_eight_notes = [] + for note_idx in range(8): + # Cycle through scale notes, wrapping around if needed + scale_index = (start_index + note_idx) % scale_len + note = scale[scale_index] + first_eight_notes.append(note) + + # Initialize steps based on the pattern + for sequence_step in range(num_steps): + if sequence_step < 8: + # First 8 steps: use ascending notes + note = first_eight_notes[sequence_step] + else: + # Steps 9-16: repeat the first 8 notes + note = first_eight_notes[sequence_step - 8] + + active = True # All steps start active + step_list.append(Step(note=note, active=active)) + + return step_list + + +# Initialize steps using the selected scale +steps = initialize_steps_from_scale(SCALE, STEPS) + +# Sequencer state +current_step = 0 +last_step_time = time.monotonic() +expected_step_time = time.monotonic() # When step should have happened +last_positions = [0] * STEPS # Track encoder positions +last_switch_states = [True] * STEPS # Track switch states +currently_playing_note = None # keep track of which note is currently playing +note_off_time = 0 # When to send note off +note_length = STEP_TIME * NOTE_LENGTH_RATIO # Note duration +display_needs_update = False # Flag to update display + +# Global sequencer settings +is_playing = True # Play/stop state +current_octave = 0 # Octave offset for entire sequence (-2 to +2) +semitone_transpose = 0 # Semitone offset (0 to 12) +velocity_baseline = 100 # Base MIDI velocity (20-127) +velocity_randomization = 0 # Amount of velocity randomization (0-50) + +# Settings mode state +settings_mode = False +first_knob_click_time = 0 +first_knob_click_count = 0 + + +def get_current_scale_category(): + """Get the category name of the currently active scale""" + for category_name, scales in SCALE_CATEGORIES.items(): + if SCALE_MODE in scales: + return category_name + return None + + +def get_note_color(note_value): + """Get color based on note pitch - yellow for low notes, green for high notes""" + # Using extended range: C1 (24) to B6 (95) + min_note = 24 # C1 + max_note = 95 # B6 + + # Clamp note to range + note_value = max(min_note, min(max_note, note_value)) + + # Calculate ratio (0.0 = lowest note, 1.0 = highest note) + ratio = (note_value - min_note) / (max_note - min_note) + + # Interpolate from yellow (0xFFFF00) to green (0x00FF00) + red = int(255 * (1 - ratio)) # 255 -> 0 + green = 255 # Always 255 + blue = 0 # Always 0 + + return (red << 16) | (green << 8) | blue + + +# pylint: disable=global-statement +# Global statements are necessary for CircuitPython embedded programming +# to modify module-level sequencer state variables + +def update_step_timing(): + """Update step timing when BPM changes""" + global STEP_TIME, note_length, expected_step_time + STEP_TIME = 60.0 / BPM / 4 # 16th note timing + note_length = STEP_TIME * NOTE_LENGTH_RATIO # Note duration + # Adjust next expected step time + expected_step_time = time.monotonic() + STEP_TIME + + +def update_scale_by_category(category_name, direction): + """Update scale within a specific category - preserve notes and mutes""" + global SCALE, SCALE_MODE, steps, display_needs_update, current_scale_categories + + if category_name not in SCALE_CATEGORIES: + return + + category_scales = SCALE_CATEGORIES[category_name] + current_idx = current_scale_categories[category_name] + + # Update index with wrapping + new_idx = (current_idx + direction) % len(category_scales) + current_scale_categories[category_name] = new_idx + + # Get new scale name + new_scale_name = category_scales[new_idx] + + # Update the scale + old_scale = SCALE_MODE + SCALE_MODE = new_scale_name + SCALE = get_scale(SCALE_MODE) + + # Adjust existing notes to fit new scale (preserve mute states) + for step in steps: + if step.note not in SCALE: + # Find the nearest higher note in the new scale + nearest_note = None + for scale_note in sorted(SCALE): + if scale_note >= step.note: + nearest_note = scale_note + break + + # If no higher note found, use the highest note in scale + if nearest_note is None: + nearest_note = max(SCALE) + + step.note = nearest_note + + print(f"Scale changed ({category_name}): {old_scale} → {SCALE_MODE}") + print("Adjusted out-of-scale notes to fit new scale") + display_needs_update = True + + +def randomize_all_steps(): + """Randomize all step notes within current octave range and mute states""" + global steps, display_needs_update + + # Calculate the current octave range based on existing notes + current_notes = [step.note for step in steps] + min_current = min(current_notes) + max_current = max(current_notes) + + # Find the octave that contains most of our current notes + base_octave = (min_current // 12) * 12 + octave_range = [note for note in SCALE if base_octave <= note <= base_octave + 24] + + # If we don't have enough notes in that range, expand to include current range + if not octave_range or max(octave_range) < max_current: + octave_range = [ + note for note in SCALE + if min_current <= note <= max_current + 12 + ] + + # Fallback: use a reasonable default range if still empty + if not octave_range: + # C3 to C5 range + octave_range = [note for note in SCALE if 48 <= note <= 72] + + for step in steps: + # Randomize note within the current octave range + if octave_range: + random_note = random.choice(octave_range) + step.note = random_note + + # Randomize mute state (70% chance to be active) + step.active = random.random() > 0.3 + + print(f"Randomized notes w/in range {min(octave_range)}-{max(octave_range)} and mute states") + display_needs_update = True + + +def calculate_velocity(): + """Calculate velocity with randomization""" + if velocity_randomization == 0: + return velocity_baseline + + # Add random variation + variation = random.randint(-velocity_randomization, velocity_randomization) + final_velocity = velocity_baseline + variation + + # Clamp to valid MIDI range + return max(1, min(127, final_velocity)) + + +# Initialize external strip with step indicators +print("Setting up external strip...") +for display_step_idx in range(STEPS): + display_pixel_idx = STEP_TO_PIXEL[display_step_idx] + + if steps[display_step_idx].active: + if display_step_idx == current_step: + display_color = 0xFF0000 # Red for currently playing + else: + display_color = get_note_color(steps[display_step_idx].note) + else: + display_color = COLORS['off'] + + external_strip[display_pixel_idx] = display_color + +external_strip.show() +print("External strip setup complete") + + +def update_display(): + """Update only external strip for speed""" + # Clear all pixels first + external_strip.fill(0x000000) + + # Special handling for settings mode + if settings_mode: + # Set settings mode indicators based on knob positions + external_strip[0] = COLORS['play_stop'] # Pixel 0: Play/Stop (knob 1) + external_strip[3] = COLORS['bpm'] # Pixel 3: BPM (knob 2) + external_strip[6] = COLORS['octave'] # Pixel 6: Octave (knob 3) + external_strip[9] = COLORS['semitone'] # Pixel 9: Semitone (knob 4) + + # Get current scale category for scale indicators + current_category = get_current_scale_category() + + # Scale category indicators - active one is cyan, others dim white + if STEPS >= 8: + # Western scales (knob 5) + western_color = ( + COLORS['scale_active'] if current_category == "Western" + else COLORS['scale_inactive'] + ) + external_strip[12] = western_color + + # Middle Eastern scales (knob 6) + me_color = ( + COLORS['scale_active'] if current_category == "Middle Eastern" + else COLORS['scale_inactive'] + ) + external_strip[15] = me_color + + if STEPS >= 12: + # Indonesian scales (knob 7) + indonesian_color = ( + COLORS['scale_active'] if current_category == "Indonesian" + else COLORS['scale_inactive'] + ) + external_strip[18] = indonesian_color + + # Japanese scales (knob 8) + japanese_color = ( + COLORS['scale_active'] if current_category == "Japanese" + else COLORS['scale_inactive'] + ) + external_strip[21] = japanese_color + + # Indian scales (knob 9) + indian_color = ( + COLORS['scale_active'] if current_category == "Indian" + else COLORS['scale_inactive'] + ) + external_strip[24] = indian_color + + if STEPS >= 16: + # Chinese scales (knob 10) + chinese_color = ( + COLORS['scale_active'] if current_category == "Chinese" + else COLORS['scale_inactive'] + ) + external_strip[27] = chinese_color + + # African scales (knob 11) + african_color = ( + COLORS['scale_active'] if current_category == "African" + else COLORS['scale_inactive'] + ) + external_strip[30] = african_color + + # Eastern European scales (knob 12) + ee_color = ( + COLORS['scale_active'] if current_category == "Eastern European" + else COLORS['scale_inactive'] + ) + external_strip[33] = ee_color + + # Celtic scales (knob 13) + celtic_color = ( + COLORS['scale_active'] if current_category == "Celtic" + else COLORS['scale_inactive'] + ) + external_strip[36] = celtic_color + + # Velocity baseline (knob 14) + external_strip[39] = COLORS['velocity'] + + # Velocity randomization (knob 15) + external_strip[42] = COLORS['vel_random'] + + # Randomize all (knob 16) + external_strip[45] = COLORS['randomize'] + + # Update step indicators (normal step pixels remain unchanged) + for main_step_idx in range(STEPS): + main_pixel_idx = STEP_TO_PIXEL[main_step_idx] + if main_step_idx == current_step and is_playing: + # Current step is always red when playing + main_color = ( + 0xFF0000 if steps[main_step_idx].active + else COLORS['playing_off'] + ) + elif main_step_idx == current_step and not is_playing: + # Current step is dim when stopped + main_color = ( + 0x440000 if steps[main_step_idx].active + else 0x220000 + ) + else: + # Non-current steps use pitch-based color when active + final_note = ( + steps[main_step_idx].note + current_octave * 12 + + semitone_transpose + ) + main_color = ( + get_note_color(final_note) if steps[main_step_idx].active + else COLORS['off'] + ) + external_strip[main_pixel_idx] = main_color + + external_strip.show() + + +def handle_basic_settings(step_id, change): + """Handle basic settings controls (play/stop, BPM, octave, semitones)""" + global BPM, current_octave, semitone_transpose, is_playing + + if step_id == 0: + # Knob 1: Play/Stop + if change != 0: + is_playing = not is_playing + playback_status = 'PLAYING' if is_playing else 'STOPPED' + print(f"Playback: {playback_status}") + + elif step_id == 1: + # Knob 2: BPM + new_bpm = BPM + change + BPM = max(MIN_BPM, min(MAX_BPM, new_bpm)) + update_step_timing() + print(f"BPM: {BPM}") + + elif step_id == 2: + # Knob 3: Octave + new_octave = current_octave + change + current_octave = max(MIN_OCTAVE, min(MAX_OCTAVE, new_octave)) + print(f"Octave: {current_octave:+d}") + + elif step_id == 3: + # Knob 4: Semitones + new_semitone = semitone_transpose + change + semitone_transpose = max(MIN_SEMITONE, min(MAX_SEMITONE, new_semitone)) + print(f"Semitones: +{semitone_transpose}") + + +def handle_scale_settings(step_id, change): + """Handle scale category controls""" + scale_categories = { + 4: "Western", 5: "Middle Eastern", 6: "Indonesian", 7: "Japanese", + 8: "Indian", 9: "Chinese", 10: "African", 11: "Eastern European", + 12: "Celtic" + } + if step_id in scale_categories: + update_scale_by_category(scale_categories[step_id], change) + + +def handle_velocity_settings(step_id, change): + """Handle velocity and randomization controls""" + global velocity_baseline, velocity_randomization + + if step_id == 13: + # Knob 14: Velocity baseline + new_velocity = velocity_baseline + change * 5 # Increment by 5 + velocity_baseline = max(MIN_VELOCITY, min(MAX_VELOCITY, new_velocity)) + print(f"Velocity baseline: {velocity_baseline}") + + elif step_id == 14: + # Knob 15: Velocity randomization + new_vel_random = velocity_randomization + change + velocity_randomization = max( + MIN_VEL_RANDOM, min(MAX_VEL_RANDOM, new_vel_random) + ) + print(f"Velocity randomization: ±{velocity_randomization}") + + elif step_id == 15: + # Knob 16: Randomize all + if change != 0: + randomize_all_steps() + + +def handle_settings_mode_encoder(): + """Handle encoder input for settings mode with all 16 controls""" + global last_positions, display_needs_update + + # Check all available encoders for settings + for settings_board_idx, settings_board_encoders in enumerate(encoders_per_board): + for encoder_idx, encoder in enumerate(settings_board_encoders): + step_id = settings_board_idx * 4 + encoder_idx + + if step_id >= STEPS: + continue + + current_pos = encoder.position + + if current_pos != last_positions[step_id]: + change = current_pos - last_positions[step_id] + + # Handle different setting categories + if step_id <= 3: + handle_basic_settings(step_id, change) + elif 4 <= step_id <= 12: + handle_scale_settings(step_id, change) + elif 13 <= step_id <= 15: + handle_velocity_settings(step_id, change) + + last_positions[step_id] = current_pos + display_needs_update = True + + +def handle_encoder_input_board(board_index): + """Handle rotary encoder input for a specific board""" + global last_positions, display_needs_update + + if board_index >= len(encoders_per_board): + return + + encoder_board_encoders = encoders_per_board[board_index] + positions = [encoder.position for encoder in encoder_board_encoders] + + for encoder_idx, pos in enumerate(positions): + step_id = board_index * 4 + encoder_idx + + # Only process if this step exists in our configuration + if step_id >= STEPS: + continue + + # Skip all encoders in settings mode (they're handled separately) + if settings_mode: + continue + + if pos != last_positions[step_id]: + # Calculate note change + note_change = pos - last_positions[step_id] + + # Find current note in scale + try: + current_index = SCALE.index(steps[step_id].note) + except ValueError: + # If note not in scale, find closest + current_index = 0 + for scale_idx, note in enumerate(SCALE): + if note >= steps[step_id].note: + current_index = scale_idx + break + + # Apply change and constrain + new_index = current_index + note_change + new_index = max(0, min(len(SCALE) - 1, new_index)) + + steps[step_id].note = SCALE[new_index] + + # Calculate final note with octave and semitone transpose + final_note = ( + steps[step_id].note + current_octave * 12 + semitone_transpose + ) + print( + f"Step {step_id + 1}: Note {steps[step_id].note} " + f"(final: {final_note})" + ) + last_positions[step_id] = pos + display_needs_update = True + + +def handle_switch_input_board(board_index): + """Handle encoder button presses for a specific board using bulk read""" + global last_switch_states, display_needs_update + + if board_index >= len(seesaw_boards): + return + + switch_seesaw_board = seesaw_boards[board_index] + + # Bulk read all digital pins from this board + try: + digital_bulk = switch_seesaw_board.digital_read_bulk(BUTTON_MASK_BOARD) + + # Process each button on this board + for encoder_idx, pin in enumerate(BUTTON_PINS_BOARD): + step_id = board_index * 4 + encoder_idx + + # Only process if this step exists in our configuration + if step_id >= STEPS: + continue + + # Skip first knob (step 0) - it's handled separately for double-click + if step_id == 0: + continue + + # In settings mode, skip ALL settings control knobs for button presses + if settings_mode: + # Still need to update the switch state to prevent false triggers + current_state = bool(digital_bulk & (1 << pin)) + last_switch_states[step_id] = current_state + continue + + current_state = bool(digital_bulk & (1 << pin)) + + # Detect button press (transition from high to low) + if not current_state and last_switch_states[step_id]: + # Normal step toggle (only when not in settings mode) + steps[step_id].active = not steps[step_id].active + step_status = 'ON' if steps[step_id].active else 'OFF' + print(f"Step {step_id + 1}: {step_status}") + display_needs_update = True + + last_switch_states[step_id] = current_state + + except OSError as e: + print(f"Bulk read error board {board_index + 1}: {e}") + # Fallback to individual reads if bulk read fails + switch_board_switches = switches_per_board[board_index] + for encoder_idx, board_switch in enumerate(switch_board_switches): + step_id = board_index * 4 + encoder_idx + + if step_id >= STEPS: + continue + + # Skip first knob and all settings knobs in settings mode + if step_id == 0: + continue + + current_state = board_switch.value + + # In settings mode, skip all control knobs for button presses + if settings_mode: + last_switch_states[step_id] = current_state + continue + + if not current_state and last_switch_states[step_id]: + steps[step_id].active = not steps[step_id].active + step_status = 'ON' if steps[step_id].active else 'OFF' + print(f"Step {step_id + 1}: {step_status}") + display_needs_update = True + last_switch_states[step_id] = current_state + + +def check_first_knob_button(): + """Check first knob button state more frequently for double-click detection""" + global last_switch_states, settings_mode, first_knob_click_time + global first_knob_click_count, display_needs_update + + if len(seesaw_boards) == 0: + return + + try: + # Read just the first button (pin 12 on first board) + first_button_state = seesaw_boards[0].digital_read(12) + + # Detect button press (transition from high to low) + if not first_button_state and last_switch_states[0]: + button_time = time.monotonic() + + if first_knob_click_count == 0: + # First click + first_knob_click_time = button_time + first_knob_click_count = 1 + print("First knob clicked once") + elif first_knob_click_count == 1: + # Check if this is a double-click + time_diff = button_time - first_knob_click_time + print(f"Second click detected, time diff: {time_diff:.3f}s") + if time_diff <= DOUBLE_CLICK_TIME: + # Double-click detected - toggle settings mode + settings_mode = not settings_mode + mode_status = 'ON' if settings_mode else 'OFF' + print(f"DOUBLE-CLICK! Settings mode: {mode_status}") + if settings_mode: + print("Settings mode controls available") + display_needs_update = True + first_knob_click_count = 0 + else: + # Too slow, treat as new first click + print("Too slow for double-click, treating as new first click") + first_knob_click_time = button_time + first_knob_click_count = 1 + + last_switch_states[0] = first_button_state + + except OSError as e: + print(f"Error reading first knob button: {e}") + + +def check_double_click_timeout(): + """Check for double-click timeout in main loop""" + global first_knob_click_count, first_knob_click_time + global settings_mode, display_needs_update + + if first_knob_click_count > 0: + if time.monotonic() - first_knob_click_time > DOUBLE_CLICK_TIME: + # Timeout - treat first click as single step toggle (if not in settings mode) + print("Double-click timeout - treating as single click") + if not settings_mode: + steps[0].active = not steps[0].active + step_status = 'ON' if steps[0].active else 'OFF' + print(f"Step 1: {step_status}") + display_needs_update = True + first_knob_click_count = 0 + + +def play_current_step(): + """Play the current step if it's active using raw MIDI""" + global currently_playing_note, note_off_time + + # First, turn off any currently playing note + if currently_playing_note is not None: + # Raw MIDI Note Off: 0x80 (channel 1), note, velocity 0 + midi_out.write(bytes([0x80, currently_playing_note, 0])) + currently_playing_note = None + + # Then play the new note if this step is active and we're playing + if steps[current_step].active and is_playing: + # Apply octave and semitone transpose to the note + final_note = steps[current_step].note + current_octave * 12 + semitone_transpose + + # Clamp to valid MIDI range (0-127) + final_note = max(0, min(127, final_note)) + + # Calculate velocity with randomization + velocity = calculate_velocity() + + # Raw MIDI Note On: 0x90 (channel 1), note, velocity + midi_out.write(bytes([0x90, final_note, velocity])) + currently_playing_note = final_note + note_off_time = time.monotonic() + note_length + + # Determine which board to check based on current step + # Check I2C inputs only after each board's last step (every 4th step) + board_to_check = current_step // 4 + step_in_board = current_step % 4 + + if step_in_board == 3: # Last step of a board (0,1,2,3 -> check at 3) + if board_to_check < len(seesaw_boards): + # Handle settings mode encoder separately + if settings_mode: + handle_settings_mode_encoder() + + # Always handle normal encoder input + handle_encoder_input_board(board_to_check) + handle_switch_input_board(board_to_check) + + +def handle_note_off(): + """Handle note off after specified duration using raw MIDI""" + global currently_playing_note, note_off_time + + if (currently_playing_note is not None and + time.monotonic() >= note_off_time): + # Raw MIDI Note Off: 0x80 (channel 1), note, velocity 0 + midi_out.write(bytes([0x80, currently_playing_note, 0])) + currently_playing_note = None + note_off_time = 0 + + +def advance_step(): + """Advance to the next step in the sequence with timing compensation""" + global current_step, last_step_time, expected_step_time, display_needs_update + + # Only advance if we're playing + if not is_playing: + return + + step_time = time.monotonic() + + # Calculate timing error (how late were we?) + timing_error = step_time - expected_step_time + + # Advance step + current_step = (current_step + 1) % STEPS + last_step_time = step_time + + # Set next expected time, compensating for any drift + expected_step_time += STEP_TIME + + # If we're way behind (more than one step), reset to current time + if timing_error > STEP_TIME: + expected_step_time = step_time + STEP_TIME + print(f"Timing reset - was {timing_error*1000:.1f}ms late") + + # Always update display when step changes (for current step indicator) + update_display() + + +# Initialize timing +last_step_time = time.monotonic() +expected_step_time = last_step_time + STEP_TIME + +# Initialize display +update_display() +print("MIDI Step Sequencer Started - COMPREHENSIVE SETTINGS MODE") +print(f"{STEPS} steps, single track ({REQUIRED_BOARDS} NeoRotary boards)") +for board_idx, addr in enumerate(I2C_ADDRESSES[:REQUIRED_BOARDS]): + steps_start = board_idx * 4 + 1 + steps_end = min((board_idx + 1) * 4, STEPS) + print(f"Board {board_idx+1} (0x{addr:02X}): Steps {steps_start}-{steps_end}") +print("Encoder rotation: Change note pitch for each step") +print("Encoder press: Toggle step on/off") +print("DOUBLE-CLICK first knob: Enter settings mode") +print("Settings mode controls:") +print(" 1. Play/Stop 2. BPM 3. Octave 4. Semitones") +print(" 5. Western 6. Middle Eastern 7. Indonesian 8. Japanese") +print(" 9. Indian 10. Chinese 11. African 12. Eastern European") +print(" 13. Celtic 14. Velocity 15. Vel Random 16. Randomize All") +print(f"BPM: {BPM}") +print(f"Octave: {current_octave:+d}") +print(f"Semitones: +{semitone_transpose}") +print(f"Scale: {SCALE_MODE}") +print(f"Velocity: {velocity_baseline} ±{velocity_randomization}") +print(f"Playing: {is_playing}") +print(f"NeoPixels: {NUM_NEOPIXELS}") + +# Main loop - MINIMAL for maximum timing precision with compensation +while True: + current_time = time.monotonic() + + # Handle note off timing (critical timing) + handle_note_off() + + # Check first knob button frequently for double-click detection + check_first_knob_button() + + # Check for double-click timeout in main loop (more frequent than I2C reads) + check_double_click_timeout() + + # Check if it's time for the next step (use expected time for compensation) + if current_time >= expected_step_time: + advance_step() + play_current_step() # This will handle I2C reads only after each board's 4th step + + # Update display only when needed and only after board transitions + if display_needs_update and (current_step % 4 == 3): + update_display() + display_needs_update = False diff --git a/Knobby_Sequencer/scales.py b/Knobby_Sequencer/scales.py new file mode 100644 index 000000000..ee73cd60d --- /dev/null +++ b/Knobby_Sequencer/scales.py @@ -0,0 +1,165 @@ +# SPDX-FileCopyrightText: John Park for Adafruit 2025 Scales for Knobby MIDI Step Sequencer +# SPDX-License-Identifier: MIT +""" +Optimized Musical Scales Library for MIDI Step Sequencer +Contains single-octave scale patterns that can be expanded across any range +All base scales start from C (MIDI note 0 relative) +""" + +# Base scale patterns - single octave starting from C (relative to 0) +BASE_SCALES = { + # Western scales + "pentatonic_major": [0, 2, 4, 7, 9], # C, D, E, G, A + "pentatonic_minor": [0, 3, 5, 7, 10], # C, Eb, F, G, Bb + "major": [0, 2, 4, 5, 7, 9, 11], # C, D, E, F, G, A, B (Ionian) + "dorian": [0, 2, 3, 5, 7, 9, 10], # C, D, Eb, F, G, A, Bb + "phrygian": [0, 1, 3, 5, 7, 8, 10], # C, Db, Eb, F, G, Ab, Bb + "lydian": [0, 2, 4, 6, 7, 9, 11], # C, D, E, F#, G, A, B + "mixolydian": [0, 2, 4, 5, 7, 9, 10], # C, D, E, F, G, A, Bb + "minor": [0, 2, 3, 5, 7, 8, 10], # C, D, Eb, F, G, Ab, Bb (Aeolian) + "locrian": [0, 1, 3, 5, 6, 8, 10], # C, Db, Eb, F, Gb, Ab, Bb + "harmonic_minor": [0, 2, 3, 5, 7, 8, 11], # C, D, Eb, F, G, Ab, B + "melodic_minor": [0, 2, 3, 5, 7, 9, 11], # C, D, Eb, F, G, A, B + "blues": [0, 3, 5, 6, 7, 10], # C, Eb, F, Gb, G, Bb + "chromatic": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], # All 12 notes + + # Middle Eastern Maqams (approximated in 12-TET) + "maqam_rast": [0, 2, 4, 5, 7, 9, 10, 11], # C, D, E, F, G, A, Bb, B + "maqam_hijaz": [0, 1, 4, 5, 7, 8, 10], # C, Db, E, F, G, Ab, Bb + "maqam_bayati": [0, 1, 3, 5, 7, 8, 10], # C, Db, Eb, F, G, Ab, Bb + "maqam_saba": [0, 1, 2, 5, 7, 8, 10], # C, Db, D, F, G, Ab, Bb + "maqam_kurd": [0, 1, 3, 5, 7, 8, 10], # C, Db, Eb, F, G, Ab, Bb + + # Indonesian Gamelan (approximated in 12-TET) + "slendro": [0, 2, 5, 7, 10], # C, D, F, G, Bb + "pelog_lima": [0, 1, 4, 7, 10], # C, Db, E, G, Bb + "pelog_tujuh": [0, 1, 3, 6, 7, 10, 11], # C, Db, Eb, F#, G, Bb, B + + # Japanese Scales + "hirajoshi": [0, 2, 3, 7, 8], # C, D, Eb, G, Ab + "in_scale": [0, 1, 5, 7, 8], # C, Db, F, G, Ab + "yo_scale": [0, 2, 5, 7, 9], # C, D, F, G, A + + # Indian Ragas (simplified 12-TET approximations) + "raga_bhairav": [0, 1, 4, 5, 7, 8, 11], # C, Db, E, F, G, Ab, B + "raga_yaman": [0, 2, 4, 6, 7, 9, 11], # C, D, E, F#, G, A, B + "raga_kafi": [0, 2, 3, 5, 7, 9, 10], # C, D, Eb, F, G, A, Bb + + # Chinese Scales + "chinese_pentatonic": [0, 2, 4, 7, 9], # C, D, E, G, A + + # African-influenced scales + "african_pentatonic": [0, 3, 5, 7, 10], # C, Eb, F, G, Bb + + # Eastern European + "ee_scale": [0, 2, 3, 6, 7, 8, 11], # C, D, Eb, F#, G, Ab, B (Hungarian/Romani) + + # Celtic + "irish_scale": [0, 2, 4, 5, 7, 9, 10] # C, D, E, F, G, A, Bb +} + +def generate_scale(scale_name, start_note=24, end_note=95): + """ + Generate a full-range scale from a base pattern + + Args: + scale_name (str): Name of the scale to generate + start_note (int): Starting MIDI note (default 24 = C1) + end_note (int): Ending MIDI note (default 95 = B6) + + Returns: + list: List of MIDI note numbers, or None if scale not found + """ + if scale_name not in BASE_SCALES: + return None + + pattern = BASE_SCALES[scale_name] + notes = [] + + # Start from the octave that contains or is below start_note + start_octave = (start_note // 12) * 12 + + # Generate notes across all octaves in range + octave = start_octave + while octave <= end_note: + for interval in pattern: + note = octave + interval + if start_note <= note <= end_note: + notes.append(note) + octave += 12 + + return notes + +def get_scale(scale_name, start_note=24, end_note=95): + """ + Get a scale by name with specified range + + Args: + scale_name (str): Name of the scale to retrieve + start_note (int): Starting MIDI note (default 24 = C1) + end_note (int): Ending MIDI note (default 95 = B6) + + Returns: + list: List of MIDI note numbers, or None if scale not found + """ + return generate_scale(scale_name, start_note, end_note) + +def list_scales(): + """ + Get a list of all available scale names + + Returns: + list: List of scale names + """ + return sorted(BASE_SCALES.keys()) + +def get_scale_pattern(scale_name): + """ + Get the base pattern for a scale (single octave, relative to 0) + + Args: + scale_name (str): Name of the scale + + Returns: + list: Base pattern or None if not found + """ + return BASE_SCALES.get(scale_name) + +def get_scale_info(): + """ + Get information about all scales organized by category + + Returns: + dict: Dictionary with scale categories and descriptions + """ + return { + "Western": [ + "pentatonic_major", "pentatonic_minor", "major", "dorian", "phrygian", + "lydian", "mixolydian", "minor", "locrian", "harmonic_minor", + "melodic_minor", "blues", "chromatic" + ], + "Middle Eastern": [ + "maqam_rast", "maqam_hijaz", "maqam_bayati", "maqam_saba", "maqam_kurd" + ], + "Indonesian": [ + "slendro", "pelog_lima", "pelog_tujuh" + ], + "Japanese": [ + "hirajoshi", "in_scale", "yo_scale" + ], + "Indian": [ + "raga_bhairav", "raga_yaman", "raga_kafi" + ], + "Chinese": [ + "chinese_pentatonic" + ], + "African": [ + "african_pentatonic" + ], + "Eastern European": [ + "ee_scale" + ], + "Celtic": [ + "irish_scale" + ] + } diff --git a/LED_Harness_Bra/LED_Harness_Bra.ino b/LED_Harness_Bra/LED_Harness_Bra.ino index ab75e49f9..57177934b 100644 --- a/LED_Harness_Bra/LED_Harness_Bra.ino +++ b/LED_Harness_Bra/LED_Harness_Bra.ino @@ -16,6 +16,10 @@ Summary: #include #include +#if defined(FASTLED_VERSION) && FASTLED_VERSION > 3010001 + #error "FastLED 3.10.2 has known compile issues with SAMD boards. Please downgrade to FastLED 3.10.1" +#endif + // Circuit Playground Setup---------------------------------------------------- #define CP_PIN 8 //CPX neopixels live on pin 8, CP live on pin 17 #define NUM_CP 10 //number of neopixels on the CP diff --git a/LED_Matrix_Clock/code.py b/LED_Matrix_Clock/code.py new file mode 100644 index 000000000..3244383fe --- /dev/null +++ b/LED_Matrix_Clock/code.py @@ -0,0 +1,468 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# SPDX-License-Identifier: MIT + +'''LED Matrix Alarm Clock with Scrolling Wake Up Text and Winking Eyes''' +import os +import ssl +import time +import random +import wifi +import socketpool +import microcontroller +import board +import audiocore +import audiobusio +import audiomixer +import adafruit_is31fl3741 +from adafruit_is31fl3741.adafruit_rgbmatrixqt import Adafruit_RGBMatrixQT +import adafruit_ntp +from adafruit_ticks import ticks_ms, ticks_add, ticks_diff +from rainbowio import colorwheel +from adafruit_seesaw import digitalio, rotaryio, seesaw +from adafruit_debouncer import Button + +# Configuration +timezone = -4 +alarm_hour = 11 +alarm_min = 36 +alarm_volume = .2 +hour_12 = True +no_alarm_plz = False +BRIGHTNESS_DAY = 200 +BRIGHTNESS_NIGHT = 50 + +# I2S pins for Audio BFF +DATA = board.A0 +LRCLK = board.A1 +BCLK = board.A2 + +# Connect to WIFI +wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD")) +print(f"Connected to {os.getenv('CIRCUITPY_WIFI_SSID')}") + +context = ssl.create_default_context() +pool = socketpool.SocketPool(wifi.radio) +ntp = adafruit_ntp.NTP(pool, tz_offset=timezone, cache_seconds=3600) + +# Initialize I2C and displays +i2c = board.STEMMA_I2C() +matrix1 = Adafruit_RGBMatrixQT(i2c, address=0x30, allocate=adafruit_is31fl3741.PREFER_BUFFER) +matrix2 = Adafruit_RGBMatrixQT(i2c, address=0x31, allocate=adafruit_is31fl3741.PREFER_BUFFER) + +# Configure displays +for m in [matrix1, matrix2]: + m.global_current = 0x05 + m.set_led_scaling(BRIGHTNESS_DAY) + m.enable = True + m.fill(0x000000) + m.show() + +# Audio setup +audio = audiobusio.I2SOut(BCLK, LRCLK, DATA) +wavs = ["/"+f for f in os.listdir('/') if f.lower().endswith('.wav') and not f.startswith('.')] +mixer = audiomixer.Mixer(voice_count=1, sample_rate=22050, channel_count=1, + bits_per_sample=16, samples_signed=True, buffer_size=32768) +mixer.voice[0].level = alarm_volume +audio.play(mixer) + +def open_audio(): + """Open a random WAV file""" + filename = random.choice(wavs) + return audiocore.WaveFile(open(filename, "rb")) + +def update_brightness(hour_24): + """Update LED brightness based on time of day""" + brightness = BRIGHTNESS_NIGHT if (hour_24 >= 20 or hour_24 < 7) else BRIGHTNESS_DAY + matrix1.set_led_scaling(brightness) + matrix2.set_led_scaling(brightness) + return brightness + +# Seesaw setup for encoder and button +seesaw = seesaw.Seesaw(i2c, addr=0x36) +seesaw.pin_mode(24, seesaw.INPUT_PULLUP) +button = Button(digitalio.DigitalIO(seesaw, 24), long_duration_ms=1000) +encoder = rotaryio.IncrementalEncoder(seesaw) +last_position = 0 + +# Font definitions +FONT_5X7 = { + '0': [0b01110, 0b10001, 0b10011, 0b10101, 0b11001, 0b10001, 0b01110], + '1': [0b00100, 0b01100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110], + '2': [0b01110, 0b10001, 0b00001, 0b00010, 0b00100, 0b01000, 0b11111], + '3': [0b11111, 0b00010, 0b00100, 0b00010, 0b00001, 0b10001, 0b01110], + '4': [0b00010, 0b00110, 0b01010, 0b10010, 0b11111, 0b00010, 0b00010], + '5': [0b11111, 0b10000, 0b11110, 0b00001, 0b00001, 0b10001, 0b01110], + '6': [0b00110, 0b01000, 0b10000, 0b11110, 0b10001, 0b10001, 0b01110], + '7': [0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b01000, 0b01000], + '8': [0b01110, 0b10001, 0b10001, 0b01110, 0b10001, 0b10001, 0b01110], + '9': [0b01110, 0b10001, 0b10001, 0b01111, 0b00001, 0b00010, 0b01100], + ' ': [0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000], + 'W': [0b10001, 0b10001, 0b10001, 0b10101, 0b10101, 0b11011, 0b10001], + 'A': [0b01110, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001], + 'K': [0b10001, 0b10010, 0b10100, 0b11000, 0b10100, 0b10010, 0b10001], + 'E': [0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b11111], + 'U': [0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110], + 'P': [0b11110, 0b10001, 0b10001, 0b11110, 0b10000, 0b10000, 0b10000], + 'O': [0b01110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110], + 'N': [0b10001, 0b11001, 0b10101, 0b10101, 0b10011, 0b10001, 0b10001], + 'F': [0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b10000] +} + +# Eye patterns +EYE_OPEN = [0b10101, 0b01110, 0b10001, 0b10101, 0b10001, 0b01110, 0b00000] +EYE_CLOSED = [0b00000, 0b00000, 0b00000, 0b11111, 0b00000, 0b00000, 0b00000] + +class Display: + """Handle all display operations""" + def __init__(self, m1, m2): + self.matrix1 = m1 + self.matrix2 = m2 + + def clear(self): + """Clear both displays""" + self.matrix1.fill(0x000000) + self.matrix2.fill(0x000000) + + def show(self): + """Update both displays""" + self.matrix1.show() + self.matrix2.show() + + def pixel(self, matrix, x, y, color): # pylint: disable=no-self-use + """Draw a pixel with 180-degree rotation""" + fx, fy = 12 - x, 8 - y + if 0 <= fx < 13 and 0 <= fy < 9: + matrix.pixel(fx, fy, color) + + def draw_char(self, matrix, char, x, y, color): + """Draw a character at position x,y""" + if char.upper() in FONT_5X7: + bitmap = FONT_5X7[char.upper()] + for row in range(7): + for col in range(5): + if bitmap[row] & (1 << (4 - col)): + self.pixel(matrix, x + col, y + row, color) + + def draw_colon(self, y, color, is_pm=False): + """Draw colon split between displays with optional PM indicator""" + # Two dots for the colon + for dy in [(1, 2), (4, 5)]: + for offset in dy: + self.pixel(self.matrix1, 12, y + offset, color) + self.pixel(self.matrix2, 0, y + offset, color) + # PM indicator dot + if is_pm: + self.pixel(self.matrix1, 12, y + 6, color) + self.pixel(self.matrix2, 0, y + 6, color) + + def draw_time(self, time_str, color, is_pm=False): + """Draw time display across both matrices""" + self.clear() + y = 1 + # Draw digits + if len(time_str) >= 5: + self.draw_char(self.matrix1, time_str[0], 0, y, color) + self.draw_char(self.matrix1, time_str[1], 6, y, color) + self.draw_colon(y, color, is_pm) + self.draw_char(self.matrix2, time_str[3], 2, y, color) + self.draw_char(self.matrix2, time_str[4], 8, y, color) + self.show() + + def draw_scrolling_text(self, text, offset, color): + """Draw scrolling text across both matrices""" + self.clear() + char_width = 6 + total_width = 26 + # Calculate position for smooth scrolling + y = 1 + for i, char in enumerate(text): + # Start from right edge and move left + char_x = total_width - offset + (i * char_width) + # Draw character if any part is visible + if -6 < char_x < total_width: + if char_x < 13: # On matrix1 + self.draw_char(self.matrix1, char, char_x, y, color) + else: # On matrix2 + self.draw_char(self.matrix2, char, char_x - 13, y, color) + self.show() + + def draw_eye(self, matrix, pattern, color): + """Draw eye pattern centered on matrix""" + x, y = 4, 1 # Center position + for row in range(7): + for col in range(5): + if pattern[row] & (1 << (4 - col)): + self.pixel(matrix, x + col, y + row, color) + + def wink_animation(self, color): + """Perform winking animation""" + # Sequence: open -> left wink -> open -> right wink -> open + sequences = [ + (EYE_OPEN, EYE_OPEN), + (EYE_CLOSED, EYE_OPEN), + (EYE_OPEN, EYE_OPEN), + (EYE_OPEN, EYE_CLOSED), + (EYE_OPEN, EYE_OPEN) + ] + for left_eye, right_eye in sequences: + self.clear() + self.draw_eye(self.matrix1, left_eye, color) + self.draw_eye(self.matrix2, right_eye, color) + self.show() + time.sleep(0.3) + + def blink_time(self, time_str, color, is_pm=False, count=3): + """Blink time display for mode changes""" + for _ in range(count): + self.clear() + self.show() + time.sleep(0.2) + self.draw_time(time_str, color, is_pm) + time.sleep(0.2) + +# Initialize display handler +display = Display(matrix1, matrix2) + +# State variables +class State: + """Track all state variables""" + def __init__(self): + self.color_value = 0 + self.color = colorwheel(0) + self.is_pm = False + self.alarm_is_pm = False + self.time_str = "00:00" + self.set_alarm = 0 + self.active_alarm = False + self.alarm_str = f"{alarm_hour:02}:{alarm_min:02}" + self.current_brightness = BRIGHTNESS_DAY + # Timers + self.refresh_timer = Timer(3600000) # 1 hour + self.clock_timer = Timer(1000) # 1 second + self.wink_timer = Timer(30000) # 30 seconds + self.scroll_timer = Timer(80) # Scroll speed + self.blink_timer = Timer(500) # Blink speed + self.alarm_status_timer = Timer(100) # Status scroll + # Display state + self.scroll_offset = 0 + self.blink_state = True + self.showing_status = False + self.status_start_time = 0 + self.alarm_start_time = 0 + # Time tracking + self.first_run = True + self.seconds = 0 + self.mins = 0 + self.am_pm_hour = 0 + +class Timer: + """Simple timer helper""" + def __init__(self, interval): + self.interval = interval + self.last_tick = ticks_ms() + + def check(self): + """Check if timer has elapsed""" + if ticks_diff(ticks_ms(), self.last_tick) >= self.interval: + self.last_tick = ticks_add(self.last_tick, self.interval) + return True + return False + + def reset(self): + """Reset timer""" + self.last_tick = ticks_ms() + +# Initialize state +state = State() + +def format_time_display(hour_24, minute, use_12hr=True): + """Format time for display with AM/PM detection""" + if use_12hr: + hour = hour_24 % 12 + if hour == 0: + hour = 12 + is_pm = hour_24 >= 12 + else: + hour = hour_24 + is_pm = False + return f"{hour:02}:{minute:02}", is_pm + +def sync_time(): + """Sync with NTP server""" + try: + print("Getting time from internet!") + now = ntp.datetime + state.am_pm_hour = now.tm_hour + state.mins = now.tm_min + state.seconds = now.tm_sec + state.time_str, state.is_pm = format_time_display(state.am_pm_hour, state.mins, hour_12) + update_brightness(state.am_pm_hour) + if not state.active_alarm and not state.showing_status: + display.draw_time(state.time_str, state.color, state.is_pm) + print(f"Time: {state.time_str}") + state.first_run = False + return True + except Exception as e: # pylint: disable=broad-except + print(f"Error syncing time: {e}") + return False + +# Main loop +while True: + button.update() + + # Handle button presses + if button.long_press: + if state.set_alarm == 0 and not state.active_alarm: + # Enter alarm setting mode + state.blink_timer.reset() + state.set_alarm = 1 + state.alarm_is_pm = alarm_hour >= 12 if hour_12 else False + hour_str, _ = format_time_display(alarm_hour, 0, hour_12) + display.blink_time(hour_str[:2] + ": ", state.color, state.alarm_is_pm) + # Draw the alarm hour after blinking to keep it displayed + display.draw_time(hour_str[:2] + ": ", state.color, state.alarm_is_pm) + elif state.active_alarm: + # Stop alarm + mixer.voice[0].stop() + state.active_alarm = False + update_brightness(state.am_pm_hour) + state.scroll_offset = 0 + # Immediately redraw the current time + display.draw_time(state.time_str, state.color, state.is_pm) + print("Alarm silenced") + + if button.short_count == 1: # Changed from == 1 to >= 1 for better detection + # Cycle through alarm setting modes + state.set_alarm = (state.set_alarm + 1) % 3 + if state.set_alarm == 0: + # Exiting alarm setting mode - redraw current time + state.wink_timer.reset() + display.draw_time(state.time_str, state.color, state.is_pm) + elif state.set_alarm == 1: + # Entering hour setting + hour_str, _ = format_time_display(alarm_hour, 0, hour_12) + display.draw_time(hour_str[:2] + ": ", state.color, state.alarm_is_pm) + # Reset timer to prevent immediate blinking + elif state.set_alarm == 2: + # Entering minute setting + display.blink_time(f" :{alarm_min:02}", state.color, state.alarm_is_pm) + # Draw the minutes after blinking to keep them displayed + display.draw_time(f" :{alarm_min:02}", state.color, state.alarm_is_pm) + # Reset timer to prevent immediate blinking + + if button.short_count == 3: # Changed for better detection + # Toggle alarm on/off + no_alarm_plz = not no_alarm_plz + print(f"Alarm disabled: {no_alarm_plz}") + state.showing_status = True + state.status_start_time = ticks_ms() + state.scroll_offset = 0 + + # Handle encoder (your existing code) + position = -encoder.position + if position != last_position: + delta = 1 if position > last_position else -1 + if state.set_alarm == 0: + # Change color + state.color_value = (state.color_value + delta * 5) % 255 + state.color = colorwheel(state.color_value) + display.draw_time(state.time_str, state.color, state.is_pm) + elif state.set_alarm == 1: + # Change hour + alarm_hour = (alarm_hour + delta) % 24 + state.alarm_is_pm = alarm_hour >= 12 if hour_12 else False + hour_str, _ = format_time_display(alarm_hour, 0, hour_12) + display.draw_time(hour_str[:2] + ": ", state.color, state.alarm_is_pm) + elif state.set_alarm == 2: + # Change minute + alarm_min = (alarm_min + delta) % 60 + display.draw_time(f" :{alarm_min:02}", state.color, state.alarm_is_pm) + state.alarm_str = f"{alarm_hour:02}:{alarm_min:02}" + last_position = position + + # Handle alarm status display + if state.showing_status: + if state.alarm_status_timer.check(): + status_text = "OFF " if no_alarm_plz else "ON " + display.draw_scrolling_text(status_text, state.scroll_offset, state.color) + text_width = 4*6 if no_alarm_plz else 3*6 + state.scroll_offset += 1 + # Reset when text has completely scrolled off + if state.scroll_offset > text_width + 18: + state.scroll_offset = 0 + state.showing_status = False + if state.set_alarm == 0 and not state.active_alarm: + display.draw_time(state.time_str, state.color, state.is_pm) + + # Handle active alarm scrolling + if state.active_alarm: + # Auto-silence alarm after 1 minute + if ticks_diff(ticks_ms(), state.alarm_start_time) >= 60000: + mixer.voice[0].stop() + state.active_alarm = False + update_brightness(state.am_pm_hour) + state.scroll_offset = 0 + display.draw_time(state.time_str, state.color, state.is_pm) + print("Alarm auto-silenced") + elif state.scroll_timer.check(): + display.draw_scrolling_text("WAKE UP ", state.scroll_offset, state.color) + text_width = 8 * 6 # "WAKE UP " is 8 characters + state.scroll_offset += 1 + # Reset when text has completely scrolled off + if state.scroll_offset > text_width + 26: + state.scroll_offset = 0 + + # Handle alarm setting mode blinking + elif state.set_alarm > 0: + # Only blink if enough time has passed since mode change + if state.blink_timer.check(): + state.blink_state = not state.blink_state + if state.blink_state: + # Redraw during the "on" part of blink + if state.set_alarm == 1: + hour_str, _ = format_time_display(alarm_hour, 0, hour_12) + display.draw_time(hour_str[:2] + ": ", state.color, state.alarm_is_pm) + else: + display.draw_time(f" :{alarm_min:02}", state.color, state.alarm_is_pm) + else: + # Only clear display during the "off" part of blink + display.clear() + display.show() + + # Normal mode operations + else: # state.set_alarm == 0 + # Winking animation + if not state.active_alarm and not state.showing_status and state.wink_timer.check(): + print("Winking!") + display.wink_animation(state.color) + display.draw_time(state.time_str, state.color, state.is_pm) + + # Time sync + if state.refresh_timer.check() or state.first_run: + if not sync_time(): + time.sleep(10) + microcontroller.reset() + + # Local timekeeping + if state.clock_timer.check(): + state.seconds += 1 + if state.seconds > 59: + state.seconds = 0 + state.mins += 1 + if state.mins > 59: + state.mins = 0 + state.am_pm_hour = (state.am_pm_hour + 1) % 24 + update_brightness(state.am_pm_hour) + # Update display + state.time_str, state.is_pm = format_time_display(state.am_pm_hour, + state.mins, hour_12) + if not state.active_alarm and not state.showing_status: + display.draw_time(state.time_str, state.color, state.is_pm) + # Check alarm + if f"{state.am_pm_hour:02}:{state.mins:02}" == state.alarm_str and not no_alarm_plz: + print("ALARM!") + wave = open_audio() + mixer.voice[0].play(wave, loop=True) + state.active_alarm = True + state.alarm_start_time = ticks_ms() + state.scroll_offset = 0 diff --git a/LED_Matrix_Clock/nice-alarm.wav b/LED_Matrix_Clock/nice-alarm.wav new file mode 100644 index 000000000..50718c738 Binary files /dev/null and b/LED_Matrix_Clock/nice-alarm.wav differ diff --git a/LED_Matrix_Clock/square-alarm.wav b/LED_Matrix_Clock/square-alarm.wav new file mode 100644 index 000000000..92a54e503 Binary files /dev/null and b/LED_Matrix_Clock/square-alarm.wav differ diff --git a/MEMENTO/Memento_Face_Detect_Recognize/memento_platformio_camera/lib/Adafruit_PyCamera/Adafruit_PyCamera.cpp b/MEMENTO/Memento_Face_Detect_Recognize/memento_platformio_camera/lib/Adafruit_PyCamera/Adafruit_PyCamera.cpp index df87bc6f9..8b9bf28ef 100644 --- a/MEMENTO/Memento_Face_Detect_Recognize/memento_platformio_camera/lib/Adafruit_PyCamera/Adafruit_PyCamera.cpp +++ b/MEMENTO/Memento_Face_Detect_Recognize/memento_platformio_camera/lib/Adafruit_PyCamera/Adafruit_PyCamera.cpp @@ -172,7 +172,7 @@ bool Adafruit_PyCamera::initSD(void) { } Serial.println("Card successfully initialized"); - uint32_t size = sd.card()->cardSize(); + uint32_t size = sd.card()->sectorCount(); if (size == 0) { Serial.println("Can't determine the card size"); } else { @@ -497,7 +497,7 @@ bool Adafruit_PyCamera::takePhoto(const char *filename_base, return false; } - if (!sd.card() || (sd.card()->cardSize() == 0)) { + if (!sd.card() || (sd.card()->sectorCount() == 0)) { Serial.println("No SD card found"); // try to initialize? if (!initSD()) diff --git a/MEMENTO/Memento_Face_Detect_Recognize/memento_platformio_camera/lib/Adafruit_PyCamera/Adafruit_PyCamera.h b/MEMENTO/Memento_Face_Detect_Recognize/memento_platformio_camera/lib/Adafruit_PyCamera/Adafruit_PyCamera.h index 00863c10b..932d2bea1 100644 --- a/MEMENTO/Memento_Face_Detect_Recognize/memento_platformio_camera/lib/Adafruit_PyCamera/Adafruit_PyCamera.h +++ b/MEMENTO/Memento_Face_Detect_Recognize/memento_platformio_camera/lib/Adafruit_PyCamera/Adafruit_PyCamera.h @@ -6,7 +6,7 @@ #include #include #include // Hardware-specific library for ST7789 -#include +#include #ifndef TAG #define TAG "PYCAM" diff --git a/MEMENTO/Memento_Shoulder_Robot/platformio_memento_shoulder_camera/lib/Adafruit_PyCamera/Adafruit_PyCamera.cpp b/MEMENTO/Memento_Shoulder_Robot/platformio_memento_shoulder_camera/lib/Adafruit_PyCamera/Adafruit_PyCamera.cpp index df87bc6f9..8b9bf28ef 100644 --- a/MEMENTO/Memento_Shoulder_Robot/platformio_memento_shoulder_camera/lib/Adafruit_PyCamera/Adafruit_PyCamera.cpp +++ b/MEMENTO/Memento_Shoulder_Robot/platformio_memento_shoulder_camera/lib/Adafruit_PyCamera/Adafruit_PyCamera.cpp @@ -172,7 +172,7 @@ bool Adafruit_PyCamera::initSD(void) { } Serial.println("Card successfully initialized"); - uint32_t size = sd.card()->cardSize(); + uint32_t size = sd.card()->sectorCount(); if (size == 0) { Serial.println("Can't determine the card size"); } else { @@ -497,7 +497,7 @@ bool Adafruit_PyCamera::takePhoto(const char *filename_base, return false; } - if (!sd.card() || (sd.card()->cardSize() == 0)) { + if (!sd.card() || (sd.card()->sectorCount() == 0)) { Serial.println("No SD card found"); // try to initialize? if (!initSD()) diff --git a/MIDI_Melody_Maker/code.py b/MIDI_Melody_Maker/code.py index b10454e2e..125825167 100644 --- a/MIDI_Melody_Maker/code.py +++ b/MIDI_Melody_Maker/code.py @@ -12,6 +12,7 @@ from digitalio import DigitalInOut, Direction, Pull from analogio import AnalogIn import displayio +import i2cdisplaybus import adafruit_imageload from adafruit_display_text import label import adafruit_displayio_ssd1306 @@ -34,7 +35,7 @@ # Use for I2C for STEMMA OLED i2c = board.I2C() # uses board.SCL and board.SDA # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller -display_bus = displayio.I2CDisplay(i2c, device_address=0x3D, reset=oled_reset) +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3D, reset=oled_reset) # STEMMA OLED dimensions. can have height of 64, but 32 makes text larger WIDTH = 128 diff --git a/MIDI_for_Makers/Receive_and_Display_MIDI_Messages/code.py b/MIDI_for_Makers/Receive_and_Display_MIDI_Messages/code.py index 22f5089b5..1638d195a 100644 --- a/MIDI_for_Makers/Receive_and_Display_MIDI_Messages/code.py +++ b/MIDI_for_Makers/Receive_and_Display_MIDI_Messages/code.py @@ -6,6 +6,7 @@ import usb_midi import adafruit_midi import displayio +import i2cdisplaybus import terminalio from adafruit_display_text import label import adafruit_displayio_ssd1306 @@ -26,7 +27,7 @@ # STEMMA I2C setup for CP 7.2+ # i2c = board.STEMMA_I2C() -display_bus = displayio.I2CDisplay(i2c, device_address=0x3D, reset=oled_reset) +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3D, reset=oled_reset) # midi setup print(usb_midi.ports) diff --git a/MacroPad_Scramble_Lock/code.py b/MacroPad_Scramble_Lock/code.py index ef21dfc3b..49026ed31 100644 --- a/MacroPad_Scramble_Lock/code.py +++ b/MacroPad_Scramble_Lock/code.py @@ -22,7 +22,7 @@ # CONFIGURABLES ------------------------ # Password information -# For higher security, place password in a separate file like secrets.py +# For higher security, place password in a separate file like settings.toml PASSWORD = "2468" PASSWORD_LENGTH = len(PASSWORD) diff --git a/Macropad_2FA_TOTP/.circuitpython.skip b/Macropad_2FA_TOTP/.circuitpython.skip deleted file mode 100644 index d5b0018ba..000000000 --- a/Macropad_2FA_TOTP/.circuitpython.skip +++ /dev/null @@ -1,6 +0,0 @@ -Macropad_2FA_TOTP/secrets.py 19: Final newline missing (missing-final-newline) -Macropad_2FA_TOTP/secrets.py 19: Unexpected line ending format. There is 'CRLF' while it should be 'LF'. (unexpected-line-ending-format) -Macropad_2FA_TOTP/rtc_setter.py 35: Final newline missing (missing-final-newline) -Macropad_2FA_TOTP/rtc_setter.py 35: Unexpected line ending format. There is 'CRLF' while it should be 'LF'. (unexpected-line-ending-format) -Macropad_2FA_TOTP/macropad_totp.py 77: Line too long (103/100) (line-too-long) -Macropad_2FA_TOTP/macropad_totp.py 169: Redefining name 'code' from outer scope (line 65) (redefined-outer-name) diff --git a/Macropad_2FA_TOTP/code.py b/Macropad_2FA_TOTP/code.py index 4e7546371..64da6b25f 100755 --- a/Macropad_2FA_TOTP/code.py +++ b/Macropad_2FA_TOTP/code.py @@ -31,15 +31,11 @@ DISPLAY_RATE = 1 # screen refresh rate #------------------------------------------------------------------------- -# Get secrets from a secrets.py file +# Get totp_keys from a totp_keys.py file try: - from secrets import secrets - totp_keys = secrets["totp_keys"] + from totp_keys import totp_keys except ImportError: - print("Secrets are kept in secrets.py, please add them there!") - raise -except KeyError: - print("TOTP info not found in secrets.py.") + print("TOTP info not found in totp_keys.py, please add them there!") raise # set board to use PCF8523 as its RTC @@ -80,7 +76,9 @@ rtc_time.anchor_point = (0.0, 0.5) rtc_time.anchored_position = (0, 59) -progress_bar = HorizontalProgressBar((68, 46), (55, 17), bar_color=0xFFFFFF, min_value=0, max_value=30) +progress_bar = HorizontalProgressBar( + (68, 46), (55, 17), bar_color=0xFFFFFF, min_value=0, max_value=30 +) splash = displayio.Group() splash.append(name) @@ -172,15 +170,15 @@ def generate_otp(int_input, secret_key, digits=6): int_to_bytestring(int_input)).digest() ) offset = hmac_hash[-1] & 0xf - code = ((hmac_hash[offset] & 0x7f) << 24 | - (hmac_hash[offset + 1] & 0xff) << 16 | - (hmac_hash[offset + 2] & 0xff) << 8 | - (hmac_hash[offset + 3] & 0xff)) - str_code = str(code % 10 ** digits) - while len(str_code) < digits: - str_code = '0' + str_code + otp_code = ((hmac_hash[offset] & 0x7f) << 24 | + (hmac_hash[offset + 1] & 0xff) << 16 | + (hmac_hash[offset + 2] & 0xff) << 8 | + (hmac_hash[offset + 3] & 0xff)) + str_otp_code = str(otp_code % 10 ** digits) + while len(str_otp_code) < digits: + str_otp_code = '0' + str_otp_code - return str_code + return str_otp_code #------------------------------------------------------------------------- # M A C R O P A D S E T U P diff --git a/Macropad_2FA_TOTP/secrets.py b/Macropad_2FA_TOTP/secrets.py deleted file mode 100755 index 0ed9c2961..000000000 --- a/Macropad_2FA_TOTP/secrets.py +++ /dev/null @@ -1,23 +0,0 @@ -# SPDX-FileCopyrightText: 2021 Carter Nelson for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -# This file is where you keep secret settings, passwords, and tokens! -# If you put them in the code you risk committing that info or sharing it - -secrets = { - # tuples of name, sekret key, color - 'totp_keys' : [("Github", "JBSWY3DPEHPK3PXP", 0x8732A8), - ("Discord", "JBSWY3DPEHPK3PXQ", 0x32A89E), - ("Slack", "JBSWY5DZEHPK3PXR", 0xFC861E), - ("Basecamp", "JBSWY6DZEHPK3PXS", 0x55C24C), - ("Gmail", "JBSWY7DZEHPK3PXT", 0x3029FF), - None, - None, # must have 12 entires - None, # set None for unused keys - None, - ("Hello Kitty", "JBSWY7DZEHPK3PXU", 0xED164F), - None, - None, - ] - } \ No newline at end of file diff --git a/Macropad_2FA_TOTP/totp_keys.py b/Macropad_2FA_TOTP/totp_keys.py new file mode 100644 index 000000000..6e9b5babe --- /dev/null +++ b/Macropad_2FA_TOTP/totp_keys.py @@ -0,0 +1,22 @@ +# SPDX-FileCopyrightText: 2021 Carter Nelson for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# This file contains totp codes! +# If you put them in the code you risk committing that info or sharing it + +# tuples of name, key, color +totp_keys = [ + ("Github", "JBSWY3DPEHPK3PXP", 0x8732A8), + ("Discord", "JBSWY3DPEHPK3PXQ", 0x32A89E), + ("Slack", "JBSWY5DZEHPK3PXR", 0xFC861E), + ("Basecamp", "JBSWY6DZEHPK3PXS", 0x55C24C), + ("Gmail", "JBSWY7DZEHPK3PXT", 0x3029FF), + None, + None, # must have 12 entires + None, # set None for unused keys + None, + ("Hello Kitty", "JBSWY7DZEHPK3PXU", 0xED164F), + None, + None, +] diff --git a/MagTag/MagTag_Arduino_Demos/shipping_demo/shipping_demo.ino b/MagTag/MagTag_Arduino_Demos/shipping_demo/shipping_demo.ino index f8c9e4992..2c8303f16 100644 --- a/MagTag/MagTag_Arduino_Demos/shipping_demo/shipping_demo.ino +++ b/MagTag/MagTag_Arduino_Demos/shipping_demo/shipping_demo.ino @@ -10,7 +10,12 @@ #include "magtaglogo.h" Adafruit_NeoPixel intneo = Adafruit_NeoPixel(4, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); -ThinkInk_290_Grayscale4_T5 display(EPD_DC, EPD_RESET, EPD_CS, -1, -1); + +// older pre-2025 magtag +//ThinkInk_290_Grayscale4_T5 display(EPD_DC, EPD_RESET, EPD_CS, -1, -1); +// magtag with SSD1680Z chipset +ThinkInk_290_Grayscale4_EAAMFGN display(EPD_DC, EPD_RESET, EPD_CS, -1, -1); + Adafruit_LIS3DH lis = Adafruit_LIS3DH(); uint8_t j = 0; @@ -18,7 +23,7 @@ void setup() { Serial.begin(115200); //while (!Serial) { delay(10); } delay(100); - Serial.println("Adafruit EPD Portal demo"); + Serial.println("Adafruit MagTag 2.9\" demo"); intneo.begin(); intneo.setBrightness(50); diff --git a/MagTag/MagTag_Christmas_Countdown/code.py b/MagTag/MagTag_Christmas_Countdown/code.py index de08e7b51..3b4b9f7a1 100644 --- a/MagTag/MagTag_Christmas_Countdown/code.py +++ b/MagTag/MagTag_Christmas_Countdown/code.py @@ -25,16 +25,8 @@ # import tree bitmap filename = "/atree.bmp" - -# CircuitPython 6 & 7 compatible -tree = displayio.OnDiskBitmap(open(filename, "rb")) -tree_grid = displayio.TileGrid( - tree, pixel_shader=getattr(tree, 'pixel_shader', displayio.ColorConverter()) -) - -# # CircuitPython 7+ compatible -# tree = displayio.OnDiskBitmap(filename) -# tree_grid = displayio.TileGrid(tree, pixel_shader=tree.pixel_shader) +tree = displayio.OnDiskBitmap(filename) +tree_grid = displayio.TileGrid(tree, pixel_shader=tree.pixel_shader) # add bitmap to its group tree_group.append(tree_grid) diff --git a/MagTag/MagTag_Covid_Vaccination/code.py b/MagTag/MagTag_Covid_Vaccination/code.py index ca97d20df..ecec54738 100644 --- a/MagTag/MagTag_Covid_Vaccination/code.py +++ b/MagTag/MagTag_Covid_Vaccination/code.py @@ -65,8 +65,8 @@ BAR_X, 95, BAR_WIDTH, BAR_HEIGHT, 1.0, bar_color=0x999999, outline_color=0x000000 ) -magtag.graphics.splash.append(progress_bar) -magtag.graphics.splash.append(progress_bar_1) +magtag.graphics.root_group.append(progress_bar) +magtag.graphics.root_group.append(progress_bar_1) magtag.graphics.set_background("/bmps/background.bmp") diff --git a/MagTag/MagTag_Dishwasher_Status/wake_on_button/code.py b/MagTag/MagTag_Dishwasher_Status/wake_on_button/code.py index 6a5065104..01850a76c 100755 --- a/MagTag/MagTag_Dishwasher_Status/wake_on_button/code.py +++ b/MagTag/MagTag_Dishwasher_Status/wake_on_button/code.py @@ -22,31 +22,15 @@ bmp_file = "/images/clean.bmp" if alarm.sleep_memory[0] else "/images/dirty.bmp" # show bitmap - -# CircuitPython 6 & 7 compatible -with open(bmp_file, "rb") as fp: - bitmap = displayio.OnDiskBitmap(fp) - tile_grid = displayio.TileGrid( - bitmap, pixel_shader=getattr(bitmap, 'pixel_shader', displayio.ColorConverter()) - ) - group = displayio.Group() - group.append(tile_grid) - epd.root_group = group - time.sleep(epd.time_to_refresh + 0.01) - epd.refresh() - while epd.busy: - pass - -# # CircuitPython 7+ compatible -# bitmap = displayio.OnDiskBitmap(bmp_file) -# tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader) -# group = displayio.Group() -# group.append(tile_grid) -# epd.root_group = group -# time.sleep(epd.time_to_refresh + 0.01) -# epd.refresh() -# while epd.busy: -# pass +bitmap = displayio.OnDiskBitmap(bmp_file) +tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader) +group = displayio.Group() +group.append(tile_grid) +epd.root_group = group +time.sleep(epd.time_to_refresh + 0.01) +epd.refresh() +while epd.busy: + pass # go to sleep alarm.exit_and_deep_sleep_until_alarms(*pin_alarms) diff --git a/MagTag/MagTag_Dishwasher_Status/wake_on_flip/code.py b/MagTag/MagTag_Dishwasher_Status/wake_on_flip/code.py index 3b86f8cfe..af1e00f9a 100755 --- a/MagTag/MagTag_Dishwasher_Status/wake_on_flip/code.py +++ b/MagTag/MagTag_Dishwasher_Status/wake_on_flip/code.py @@ -51,31 +51,15 @@ epd.rotation = rotation # show bitmap - -# CircuitPython 6 & 7 compatible -with open(bmp_file, "rb") as fp: - bitmap = displayio.OnDiskBitmap(fp) - tile_grid = displayio.TileGrid( - bitmap, pixel_shader=getattr(bitmap, 'pixel_shader', displayio.ColorConverter()) - ) - group = displayio.Group() - group.append(tile_grid) - epd.root_group = group - time.sleep(epd.time_to_refresh + 0.01) - epd.refresh() - while epd.busy: - pass - -# # CircuitPython 7+ compatible -# bitmap = displayio.OnDiskBitmap(bmp_file) -# tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader) -# group = displayio.Group() -# group.append(tile_grid) -# epd.root_group = group -# time.sleep(epd.time_to_refresh + 0.01) -# epd.refresh() -# while epd.busy: -# pass +bitmap = displayio.OnDiskBitmap(bmp_file) +tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader) +group = displayio.Group() +group.append(tile_grid) +epd.root_group = group +time.sleep(epd.time_to_refresh + 0.01) +epd.refresh() +while epd.busy: + pass # config accelo irq diff --git a/MagTag/MagTag_Flashcards/chapters/code.py b/MagTag/MagTag_Flashcards/chapters/code.py index de2f62a56..da1370fd9 100644 --- a/MagTag/MagTag_Flashcards/chapters/code.py +++ b/MagTag/MagTag_Flashcards/chapters/code.py @@ -40,7 +40,7 @@ # Add button labels at the bottom of the screen BUTTON_TEXT_IDX = list_len -magtag.graphics.splash.append(Rect(0, magtag.graphics.display.height - 14, +magtag.graphics.root_group.append(Rect(0, magtag.graphics.display.height - 14, magtag.graphics.display.width, magtag.graphics.display.height, fill=0x0)) magtag.add_text( diff --git a/MagTag/MagTag_Google_Calendar/authenticator.py b/MagTag/MagTag_Google_Calendar/authenticator.py index b008b2da2..fe4b5b8b9 100755 --- a/MagTag/MagTag_Google_Calendar/authenticator.py +++ b/MagTag/MagTag_Google_Calendar/authenticator.py @@ -1,21 +1,25 @@ # SPDX-FileCopyrightText: 2021 Brent Rubell, written for Adafruit Industries # # SPDX-License-Identifier: Unlicense + +from os import getenv from adafruit_oauth2 import OAuth2 from adafruit_display_text.label import Label from adafruit_bitmap_font import bitmap_font from adafruit_magtag.magtag import Graphics, Network from adafruit_display_shapes.rect import Rect -# Add a secrets.py to your filesystem that has a dictionary called secrets with "ssid" and -# "password" keys with your WiFi credentials. DO NOT share that file or commit it into Git or other -# source control. -# pylint: disable=no-name-in-module,wrong-import-order -try: - from secrets import secrets -except ImportError: - print("Credentials and tokens are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) network = Network() network.connect() @@ -28,7 +32,7 @@ display = graphics.display background = Rect(0, 0, 296, 128, fill=0xFFFFFF) -graphics.splash.append(background) +graphics.root_group.append(background) label_overview_text = Label( font_large, @@ -38,18 +42,18 @@ color=0x000000, text="Authorize this device with Google:", ) -graphics.splash.append(label_overview_text) +graphics.root_group.append(label_overview_text) label_verification_url = Label(font_small, x=0, y=40, line_spacing=0.75, color=0x000000) -graphics.splash.append(label_verification_url) +graphics.root_group.append(label_verification_url) label_user_code = Label(font_small, x=0, y=80, color=0x000000, line_spacing=0.75) -graphics.splash.append(label_user_code) +graphics.root_group.append(label_user_code) label_qr_code = Label( font_small, x=0, y=100, color=0x000000, text="Or scan the QR code:" ) -graphics.splash.append(label_qr_code) +graphics.root_group.append(label_qr_code) # Set scope(s) of access required by the API you're using scopes = ["https://www.googleapis.com/auth/calendar.readonly"] @@ -57,8 +61,8 @@ # Initialize an OAuth2 object google_auth = OAuth2( network.requests, - secrets["google_client_id"], - secrets["google_client_secret"], + getenv("google_client_id"), + getenv("google_client_secret"), scopes, ) @@ -81,7 +85,7 @@ label_user_code.text = "2. Enter code: %s" % google_auth.user_code graphics.qrcode(google_auth.verification_url.encode(), qr_size=2, x=240, y=70) -graphics.display.root_group = graphics.splash +graphics.display.root_group = graphics.root_group display.refresh() # Poll Google's authorization server @@ -90,16 +94,16 @@ raise RuntimeError("Timed out waiting for browser response!") print("Successfully Authenticated with Google!") -print("Add the following lines to your secrets.py file:") -print("\t'google_access_token' " + ":" + " '%s'," % google_auth.access_token) -print("\t'google_refresh_token' " + ":" + " '%s'" % google_auth.refresh_token) +print("Add the following lines to your settings.toml file:") +print(f'google_access_token="{google_auth.access_token}"') +print(f'google_refresh_token="{google_auth.refresh_token}"') -graphics.splash.pop() -graphics.splash.pop() -graphics.splash.pop() +graphics.root_group.pop() +graphics.root_group.pop() +graphics.root_group.pop() label_overview_text.text = "Successfully Authenticated!" label_verification_url.text = ( - "Check the REPL for tokens to add\n\tto your secrets.py file" + "Check the REPL for tokens to add\n\tto your settings.toml file" ) display.refresh() diff --git a/MagTag/MagTag_Google_Calendar/code.py b/MagTag/MagTag_Google_Calendar/code.py index 83447e954..74e969430 100755 --- a/MagTag/MagTag_Google_Calendar/code.py +++ b/MagTag/MagTag_Google_Calendar/code.py @@ -1,12 +1,26 @@ # SPDX-FileCopyrightText: 2021 Brent Rubell, written for Adafruit Industries # # SPDX-License-Identifier: Unlicense + +from os import getenv import time import rtc from adafruit_oauth2 import OAuth2 from adafruit_display_shapes.line import Line from adafruit_magtag.magtag import MagTag +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) + # Calendar ID CALENDAR_ID = "YOUR_CALENDAR_ID" @@ -42,15 +56,6 @@ 6: "Sunday", } -# Add a secrets.py to your filesystem that has a dictionary called secrets with "ssid" and -# "password" keys with your WiFi credentials. DO NOT share that file or commit it into Git or other -# source control. -# pylint: disable=no-name-in-module,wrong-import-order -try: - from secrets import secrets -except ImportError: - print("Credentials and tokens are kept in secrets.py, please add them there!") - raise # Create a new MagTag object magtag = MagTag() @@ -62,18 +67,18 @@ scopes = ["https://www.googleapis.com/auth/calendar.readonly"] google_auth = OAuth2( magtag.network.requests, - secrets["google_client_id"], - secrets["google_client_secret"], + getenv("google_client_id"), + getenv("google_client_secret"), scopes, - secrets["google_access_token"], - secrets["google_refresh_token"], + getenv("google_access_token"), + getenv("google_refresh_token"), ) def get_current_time(time_max=False): """Gets local time from Adafruit IO and converts to RFC3339 timestamp.""" # Get local time from Adafruit IO - magtag.get_local_time(secrets["timezone"]) + magtag.get_local_time(getenv("timezone")) # Format as RFC339 timestamp cur_time = r.datetime if time_max: # maximum time to fetch events is midnight (4:59:59UTC) @@ -200,7 +205,7 @@ def display_calendar_events(resp_events): # Add the header line_header = Line(0, 30, 320, 30, color=0x000000) -magtag.splash.append(line_header) +magtag.graphics.root_group.append(line_header) label_header = magtag.add_text( text_font="fonts/Arial-18.pcf", diff --git a/MagTag/MagTag_Google_Sheets/naughty_nice/code.py b/MagTag/MagTag_Google_Sheets/naughty_nice/code.py index 3510ca889..5908b5859 100755 --- a/MagTag/MagTag_Google_Sheets/naughty_nice/code.py +++ b/MagTag/MagTag_Google_Sheets/naughty_nice/code.py @@ -60,7 +60,7 @@ def hh_mm(time_struct, twelve_hour=True): # Add 14-pixel-tall black bar at bottom of display. It's a distinct layer # (not just background) to appear on top of name list if it runs long. -MAGTAG.graphics.splash.append(Rect(0, MAGTAG.graphics.display.height - 14, +MAGTAG.graphics.root_group.append(Rect(0, MAGTAG.graphics.display.height - 14, MAGTAG.graphics.display.width, MAGTAG.graphics.display.height, fill=0x0)) diff --git a/MagTag/MagTag_Google_Sheets/weekly_planner/code.py b/MagTag/MagTag_Google_Sheets/weekly_planner/code.py index 0e4f30834..52eac313c 100755 --- a/MagTag/MagTag_Google_Sheets/weekly_planner/code.py +++ b/MagTag/MagTag_Google_Sheets/weekly_planner/code.py @@ -69,7 +69,7 @@ def hh_mm(time_struct, twelve_hour=True): # Add 14-pixel-tall black bar at bottom of display. It's a distinct layer # (not just background) to appear on top of task list if it runs long. -MAGTAG.graphics.splash.append(Rect(0, MAGTAG.graphics.display.height - 14, +MAGTAG.graphics.root_group.append(Rect(0, MAGTAG.graphics.display.height - 14, MAGTAG.graphics.display.width, MAGTAG.graphics.display.height, fill=0x0)) diff --git a/MagTag/MagTag_NextBus/code.py b/MagTag/MagTag_NextBus/code.py index 1b719fc9f..f7b157fc5 100644 --- a/MagTag/MagTag_NextBus/code.py +++ b/MagTag/MagTag_NextBus/code.py @@ -11,9 +11,10 @@ """ # pylint: disable=import-error + +from os import getenv import gc import time -from secrets import secrets import displayio from rtc import RTC from adafruit_magtag.magtag import Graphics @@ -23,6 +24,17 @@ from adafruit_display_text.label import Label from nextbus import NextBus +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # CONFIGURABLE SETTINGS ---------------------------------------------------- @@ -54,15 +66,12 @@ # not a big problem if this drifts a bit due to infrequent synchronizations. # 6 hour default. CLOCK_SYNC_INTERVAL = 6 * 60 * 60 -# Load time zone string from secrets.py, else IP geolocation is used +# Load time zone string from settings.toml, else IP geolocation is used # (http://worldtimeapi.org/api/timezone for list). Again, this is only # used for the 'Last checked' display, not predictions, so it's not # especially disruptive if missing. # pylint: disable=bare-except -try: - TIME_ZONE = secrets['timezone'] # e.g. 'America/New_York' -except: - TIME_ZONE = None # Use IP geolocation +TIME_ZONE = getenv('timezone') # e.g. 'America/New_York' # SOME UTILITY FUNCTIONS --------------------------------------------------- diff --git a/MagTag/MagTag_Progress_Displays/weblate_translated_percent/code.py b/MagTag/MagTag_Progress_Displays/weblate_translated_percent/code.py index 6f2ac5a8c..34dd9b4b2 100644 --- a/MagTag/MagTag_Progress_Displays/weblate_translated_percent/code.py +++ b/MagTag/MagTag_Progress_Displays/weblate_translated_percent/code.py @@ -75,7 +75,7 @@ def texturl_transform(val): BAR_X, BAR_Y, BAR_WIDTH, BAR_HEIGHT, 1.0, bar_color=0x999999, outline_color=0x000000 ) -magtag.graphics.splash.append(progress_bar) +magtag.graphics.root_group.append(progress_bar) timestamp = None diff --git a/MagTag/MagTag_Progress_Displays/year_progress_percent/code.py b/MagTag/MagTag_Progress_Displays/year_progress_percent/code.py index 2570f0075..ee249da83 100644 --- a/MagTag/MagTag_Progress_Displays/year_progress_percent/code.py +++ b/MagTag/MagTag_Progress_Displays/year_progress_percent/code.py @@ -53,7 +53,7 @@ def days_in_year(date_obj): BAR_X, BAR_Y, BAR_WIDTH, BAR_HEIGHT, 1.0, bar_color=0x999999, outline_color=0x000000 ) -magtag.graphics.splash.append(progress_bar) +magtag.graphics.root_group.append(progress_bar) try: diff --git a/MagTag/MagTag_Project_Selector/secrets.py b/MagTag/MagTag_Project_Selector/secrets.py deleted file mode 100644 index 0f8010a57..000000000 --- a/MagTag/MagTag_Project_Selector/secrets.py +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Eva Herrada for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -# This file is where you keep secret settings, passwords, and tokens! -# If you put them in the code you risk committing that info or sharing it - -secrets = { - "ssid": "wifi_network", - "password": "wifi_password", - "timezone": "America/New_York", # http://worldtimeapi.org/timezones - "openweather_token": "my_openweather_token", - "openweather_location": "New York City, US", - "aio_username": "my_adafruit_io_username", - "aio_key": "my_adafruit_io_key", -} diff --git a/MagTag/MagTag_Project_Selector/settings.toml b/MagTag/MagTag_Project_Selector/settings.toml new file mode 100644 index 000000000..a01a196a7 --- /dev/null +++ b/MagTag/MagTag_Project_Selector/settings.toml @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2020 Eva Herrada for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# This file is where you keep private settings, passwords, and tokens! +# If you put them in the code you risk committing that info or sharing it + +CIRCUITPY_WIFI_SSID="your-wifi-ssid" +CIRCUITPY_WIFI_PASSWORD="your-wifi-password" +ADAFRUIT_AIO_USERNAME="my_username" +ADAFRUIT_AIO_KEY="my_key" +timezone="America/New_York" # http://worldtimeapi.org/timezones +openweather_token="my_openweather_token" +openweather_location="New York City, US" diff --git a/MagTag/MagTag_Quote_Board/code.py b/MagTag/MagTag_Quote_Board/code.py index 125312c58..da0df4526 100644 --- a/MagTag/MagTag_Quote_Board/code.py +++ b/MagTag/MagTag_Quote_Board/code.py @@ -4,11 +4,24 @@ # MagTag Quote Board # Displays Quotes from the Adafruit quotes server -# Be sure to put WiFi access point info in secrets.py file to connect +# Be sure to put WiFi access point info in settings.toml file to connect +from os import getenv import time from adafruit_magtag.magtag import MagTag +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) + # Set up where we'll be fetching data from DATA_SOURCE = "https://www.adafruit.com/api/quotes.php" QUOTE_LOCATION = [0, "text"] diff --git a/MagTag/MagTag_Seasonal_Produce/code.py b/MagTag/MagTag_Seasonal_Produce/code.py index 7253e5da9..c50ec834f 100755 --- a/MagTag/MagTag_Seasonal_Produce/code.py +++ b/MagTag/MagTag_Seasonal_Produce/code.py @@ -9,14 +9,27 @@ """ # pylint: disable=import-error, line-too-long + +from os import getenv import time -from secrets import secrets import rtc from adafruit_display_shapes.rect import Rect from adafruit_magtag.magtag import MagTag from produce import Produce +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) + # CONFIGURABLE SETTINGS and ONE-TIME INITIALIZATION ------------------------ TWELVE_HOUR = True # If set, show 12-hour vs 24-hour (e.g. 3:00 vs 15:00) @@ -24,9 +37,9 @@ # Location of produce data (file:// or http:// or https://): JSON_URL = 'https://raw.githubusercontent.com/adafruit/Adafruit_Learning_System_Guides/master/MagTag_Seasonal_Produce/produce.json' -# Location is configured in secrets.py. If location is not contained there, +# Location is configured in settings.toml. If location is not contained there, # default value below will be used. -LOCATION = secrets.get('location', 'NY') # default to 'NY' +LOCATION = getenv('location', 'NY') # default to 'NY' PRODUCE = Produce(JSON_URL, LOCATION) MAGTAG = MagTag(rotation=0) # Portrait (vertical) display @@ -65,7 +78,7 @@ def hh_mm(time_struct, twelve_hour=True): # Add 14-pixel-tall black bar at bottom of display. It's a distinct layer # (not just background) to appear on top of produce list if it runs long. -MAGTAG.graphics.splash.append(Rect(0, MAGTAG.graphics.display.height - 14, +MAGTAG.graphics.root_group.append(Rect(0, MAGTAG.graphics.display.height - 14, MAGTAG.graphics.display.width, MAGTAG.graphics.display.height, fill=0x0)) diff --git a/MagTag/MagTag_Showerthoughts/code.py b/MagTag/MagTag_Showerthoughts/code.py index 3632c4810..99ba6d909 100644 --- a/MagTag/MagTag_Showerthoughts/code.py +++ b/MagTag/MagTag_Showerthoughts/code.py @@ -3,12 +3,24 @@ # SPDX-License-Identifier: MIT # MagTag Shower Thoughts -# Be sure to put WiFi access point info in secrets.py file to connect +# Be sure to put WiFi access point info in settings.toml file to connect +from os import getenv import time import random from adafruit_magtag.magtag import MagTag +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Set up where we'll be fetching data from DATA_SOURCE = "https://www.reddit.com/r/showerthoughts/hot.json?limit=10" diff --git a/MagTag/MagTag_Showtimes/code.py b/MagTag/MagTag_Showtimes/code.py index 4f8acce4f..c7e9e9376 100644 --- a/MagTag/MagTag_Showtimes/code.py +++ b/MagTag/MagTag_Showtimes/code.py @@ -4,13 +4,26 @@ # MagTag Showtimes Event Viewer # Uses the events.json file to display next or current event -# Be sure to put WiFi access point info in secrets.py file to connect +# Be sure to put WiFi access point info in settings.toml file to connect +from os import getenv import time import json import re from adafruit_magtag.magtag import MagTag +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) + # You can test by setting a time.struct here, to pretend its a different day # (tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst) FAKETIME = False # time.struct_time(2020, 12, 11, 15, 01, 00, 4, 346, -1) diff --git a/MagTag/MagTag_SimpleClock/code.py b/MagTag/MagTag_SimpleClock/code.py index 33c2e8e12..1b6bedcdc 100644 --- a/MagTag/MagTag_SimpleClock/code.py +++ b/MagTag/MagTag_SimpleClock/code.py @@ -31,7 +31,6 @@ if HOUR_MODE_24: timestr = "%d:%02d" % (hour, minute) else: - is_pm = (hour >= 12) hour %= 12 if hour == 0: hour = 12 diff --git a/MagTag/MagTag_Sports_Schedule/code.py b/MagTag/MagTag_Sports_Schedule/code.py index af1707d51..a7365ecc9 100644 --- a/MagTag/MagTag_Sports_Schedule/code.py +++ b/MagTag/MagTag_Sports_Schedule/code.py @@ -2,19 +2,31 @@ # SPDX-License-Identifier: MIT # MagTag Sports Schedule Viewer -# Be sure to add your wifi credentials to the secrets.py file +# Be sure to add your wifi credentials to the settings.toml file # Press D to advance to next game # Press C to go back one game # Press B to refresh the schedule (this takes a minute) # Press A to advance to next sport (this takes a minute) - +from os import getenv import time import json from adafruit_datetime import datetime, timedelta from adafruit_magtag.magtag import MagTag +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) + USE_24HR_TIME = False TIME_ZONE_OFFSET = -8 # hours ahead or behind Zulu time, e.g. Pacific is -8 TIME_ZONE_NAME = "PST" @@ -186,7 +198,7 @@ def update_labels(): def fetch_sports_data(reset_game_number=True): # Fetches and parses data for all games for the current sport # pylint: disable=global-statement - global sports_data, current_game, current_sport + global current_game magtag.url = SPORTS[current_sport]["url"] sports_data.clear() raw_data = json.loads(magtag.fetch(auto_refresh=False)) diff --git a/MagTag/MagTag_Tides/code.py b/MagTag/MagTag_Tides/code.py index 95acaa7c3..b03609510 100755 --- a/MagTag/MagTag_Tides/code.py +++ b/MagTag/MagTag_Tides/code.py @@ -130,12 +130,12 @@ # ---------------------------- # Add all the graphic layers # ---------------------------- -magtag.splash.append(tide_tg) -magtag.splash.append(grid_overlay) -magtag.splash.append(plot_y_labels) -magtag.splash.append(tide_info) -magtag.splash.append(date_label) -magtag.splash.append(station_info) +magtag.graphics.root_group.append(tide_tg) +magtag.graphics.root_group.append(grid_overlay) +magtag.graphics.root_group.append(plot_y_labels) +magtag.graphics.root_group.append(tide_info) +magtag.graphics.root_group.append(date_label) +magtag.graphics.root_group.append(station_info) # ///////////////////////////////////////////////////////////////////////// diff --git a/MagTag/MagTag_Twitter/code.py b/MagTag/MagTag_Twitter/code.py index 92e02285e..09a4cf8a2 100755 --- a/MagTag/MagTag_Twitter/code.py +++ b/MagTag/MagTag_Twitter/code.py @@ -2,17 +2,22 @@ # SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries. # # SPDX-License-Identifier: Unlicense + +from os import getenv import time from adafruit_magtag.magtag import MagTag -try: - from secrets import secrets -except ImportError: - print( - """WiFi settings are kept in secrets.py, please add them there! -the secrets dictionary must contain 'ssid' and 'password' at a minimum""" +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." ) - raise # Set to the twitter username you'd like to fetch tweets from TWITTER_USERNAME = "adafruit" @@ -31,7 +36,7 @@ magtag = MagTag(url=DATA_SOURCE, json_path=(TWEET_FULL_NAME, TWEET_HANDLE, TWEET_TEXT)) # Set Twitter OAuth2.0 Bearer Token -bearer_token = secrets["twitter_bearer_token"] +bearer_token = getenv("twitter_bearer_token") magtag.set_headers({"Authorization": "Bearer " + bearer_token}) # Display setup diff --git a/MagTag/MagTag_Weather/.circuitpython.skip b/MagTag/MagTag_Weather/.circuitpython.skip deleted file mode 100644 index 465e39b2c..000000000 --- a/MagTag/MagTag_Weather/.circuitpython.skip +++ /dev/null @@ -1,2 +0,0 @@ -MagTag_Weather/magtag_weather.py 269: Trailing newlines (trailing-newlines) -MagTag_Weather/magtag_weather.py 7: standard import "from secrets import secrets" should be placed before "import terminalio" (wrong-import-order) diff --git a/MagTag/MagTag_Weather/forecast/code.py b/MagTag/MagTag_Weather/forecast/code.py index a52eabaab..1ce5f6184 100755 --- a/MagTag/MagTag_Weather/forecast/code.py +++ b/MagTag/MagTag_Weather/forecast/code.py @@ -3,13 +3,25 @@ # SPDX-License-Identifier: MIT # pylint: disable=redefined-outer-name, eval-used, wrong-import-order +from os import getenv import time import terminalio import displayio import adafruit_imageload from adafruit_display_text import label from adafruit_magtag.magtag import MagTag -from secrets import secrets + +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # --| USER CONFIG |-------------------------- METRIC = False # set to True for metric units @@ -74,7 +86,7 @@ def get_data_source_url(api="forecast", location=None): URL += "&lon={}".format(location[1]) else: raise ValueError("Unknown API type: " + api) - return URL + "&appid=" + secrets["openweather_token"] + return URL + "&appid=" + getenv("openweather_token") def get_latlon(city_name): @@ -245,18 +257,20 @@ def go_to_sleep(current_time): # =========== # Location # =========== -if isinstance(secrets["openweather_location"], str): +openweather_location = getenv("openweather_location") +is_lat_long = "," in openweather_location +if openweather_location and not is_lat_long: # Get lat/lon using city name - city = secrets["openweather_location"] + city = openweather_location print("Getting lat/lon for city:", city) latlon = get_latlon(city) -elif isinstance(secrets["openweather_location"], tuple): +elif openweather_location: # Get city name using lat/lon - latlon = secrets["openweather_location"] + latlon = openweather_location.split(",") print("Getting city name for lat/lon:", latlon) city = get_city(latlon) else: - raise ValueError("Unknown location:", secrets["openweather_location"]) + raise ValueError(f"Unknown location:{openweather_location}") print("City =", city) print("Lat/Lon = ", latlon) @@ -330,9 +344,9 @@ def go_to_sleep(current_time): make_banner(x=210, y=81), ] -magtag.splash.append(today_banner) +magtag.graphics.root_group.append(today_banner) for future_banner in future_banners: - magtag.splash.append(future_banner) + magtag.graphics.root_group.append(future_banner) # =========== # M A I N diff --git a/MagTag/MagTag_Weather/onecall/code.py b/MagTag/MagTag_Weather/onecall/code.py index fb188d2a0..0a90743aa 100644 --- a/MagTag/MagTag_Weather/onecall/code.py +++ b/MagTag/MagTag_Weather/onecall/code.py @@ -3,13 +3,25 @@ # SPDX-License-Identifier: MIT # pylint: disable=redefined-outer-name, eval-used, wrong-import-order +from os import getenv import time import terminalio import displayio import adafruit_imageload from adafruit_display_text import label from adafruit_magtag.magtag import MagTag -from secrets import secrets + +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # --| USER CONFIG |-------------------------- METRIC = False # set to True for metric units @@ -68,7 +80,7 @@ def get_data_source_url(api="onecall", location=None): URL += "&lon={}".format(location[1]) else: raise ValueError("Unknown API type: " + api) - return URL + "&appid=" + secrets["openweather_token"] + return URL + "&appid=" + getenv("openweather_token") def get_latlon(city_name): @@ -183,18 +195,20 @@ def go_to_sleep(current_time): # =========== # Location # =========== -if isinstance(secrets["openweather_location"], str): +openweather_location = getenv("openweather_location") +is_lat_long = "," in openweather_location +if openweather_location and not is_lat_long: # Get lat/lon using city name - city = secrets["openweather_location"] + city = openweather_location print("Getting lat/lon for city:", city) latlon = get_latlon(city) -elif isinstance(secrets["openweather_location"], tuple): +elif openweather_location: # Get city name using lat/lon - latlon = secrets["openweather_location"] + latlon = openweather_location.split(",") print("Getting city name for lat/lon:", latlon) city = get_city(latlon) else: - raise ValueError("Unknown location:", secrets["openweather_location"]) + raise ValueError(f"Unknown location:{openweather_location}") print("City =", city) print("Lat/Lon = ", latlon) @@ -269,9 +283,9 @@ def go_to_sleep(current_time): make_banner(x=210, y=102), ] -magtag.splash.append(today_banner) +magtag.graphics.root_group.append(today_banner) for future_banner in future_banners: - magtag.splash.append(future_banner) + magtag.graphics.root_group.append(future_banner) # =========== # M A I N diff --git a/MagTag/MagTag_Weather/openmeteo/code.py b/MagTag/MagTag_Weather/openmeteo/code.py index 932f90124..fc4d41f64 100644 --- a/MagTag/MagTag_Weather/openmeteo/code.py +++ b/MagTag/MagTag_Weather/openmeteo/code.py @@ -280,9 +280,9 @@ def go_to_sleep(current_time_secs): make_banner(x=210, y=102), ] -magtag.splash.append(today_banner) +magtag.graphics.root_group.append(today_banner) for future_banner in future_banners: - magtag.splash.append(future_banner) + magtag.graphics.root_group.append(future_banner) # =========== # M A I N diff --git a/MagTag/MagTag_Webb_Telescope_Status/code.py b/MagTag/MagTag_Webb_Telescope_Status/code.py index a590beeae..4a66b23a0 100644 --- a/MagTag/MagTag_Webb_Telescope_Status/code.py +++ b/MagTag/MagTag_Webb_Telescope_Status/code.py @@ -4,6 +4,8 @@ """ MagTag status display for James Webb Telescope """ + +from os import getenv import time import json import ssl @@ -18,11 +20,17 @@ import alarm import adafruit_requests -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Update once per hour SLEEP_TIME = 60 * 60 # seconds @@ -66,7 +74,7 @@ def try_refresh(): print("Connecting to AP...") try: # wifi connect - wifi.radio.connect(secrets["ssid"], secrets["password"]) + wifi.radio.connect(ssid, password) # Create Socket, initialize requests socket = socketpool.SocketPool(wifi.radio) diff --git a/MagTag/MagTag_Webb_Telescope_Status/deprecated_original_version/code.py b/MagTag/MagTag_Webb_Telescope_Status/deprecated_original_version/code.py index 3a2c19409..ae5176661 100644 --- a/MagTag/MagTag_Webb_Telescope_Status/deprecated_original_version/code.py +++ b/MagTag/MagTag_Webb_Telescope_Status/deprecated_original_version/code.py @@ -4,6 +4,8 @@ """ MagTag status display for James Webb Telescope """ + +from os import getenv import time import json import ssl @@ -18,11 +20,17 @@ import alarm import adafruit_requests -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Update once per hour SLEEP_TIME = 60 * 60 # seconds @@ -64,7 +72,7 @@ def try_refresh(): print("Connecting to AP...") try: # wifi connect - wifi.radio.connect(secrets["ssid"], secrets["password"]) + wifi.radio.connect(ssid, password) # Create Socket, initialize requests socket = socketpool.SocketPool(wifi.radio) diff --git a/Magic_Nine_Ball/code.py b/Magic_Nine_Ball/code.py index fe1a5f63b..8091a8e68 100644 --- a/Magic_Nine_Ball/code.py +++ b/Magic_Nine_Ball/code.py @@ -33,24 +33,13 @@ shaken = False print("Image load {}".format(images[i])) - # CircuitPython 6 & 7 compatible try: - f = open(images[i], "rb") - odb = displayio.OnDiskBitmap(f) + odb = displayio.OnDiskBitmap(images[i]) except ValueError: print("Image unsupported {}".format(images[i])) del images[i] continue - face = displayio.TileGrid(odb, pixel_shader=getattr(odb, 'pixel_shader', displayio.ColorConverter())) - - # # CircuitPython 7+ compatible - # try: - # odb = displayio.OnDiskBitmap(images[i]) - # except ValueError: - # print("Image unsupported {}".format(images[i])) - # del images[i] - # continue - # face = displayio.TileGrid(odb, pixel_shader=odb.pixel_shader) + face = displayio.TileGrid(odb, pixel_shader=odb.pixel_shader) splash.append(face) # Wait for the image to load. diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/code.py b/MatrixPortal_S3_Flight_Proximity_Tracker/code.py deleted file mode 100755 index b3dc39f96..000000000 --- a/MatrixPortal_S3_Flight_Proximity_Tracker/code.py +++ /dev/null @@ -1,332 +0,0 @@ -# SPDX-FileCopyrightText: 2023 Trevor Beaton for Adafruit Industries -# -# SPDX-License-Identifier: MIT -import os -import ssl -import time -import board -import wifi -import terminalio -import socketpool -import adafruit_requests -import displayio -import rgbmatrix -import framebufferio -import adafruit_display_text.label -from displayio import OnDiskBitmap, TileGrid, Group - -# Release any existing displays -displayio.release_displays() - -# --- Matrix Properties --- -DISPLAY_WIDTH = 128 -DISPLAY_HEIGHT = 64 - -# 432 Minutes - 7.2 Hours -NETWORK_CALL_INTERVAL = 25920 - -# --- Icon Properties --- -ICON_WIDTH = 26 # Width of the icons -ICON_HEIGHT = 26 # Height of the icons -# Calculate the gap between icons -gap_between_icons = 5 - -GAP_BETWEEN_ICONS = 15 # Gap between the icons -NUMBER_OF_ICONS = 2 # Number of icons to display -PLACEHOLDER_ICON_PATH = "/airline_logos/placeholder.bmp" - -# --- Text Properties --- -TEXT_START_X = ICON_WIDTH + 4 -TEXT_RESET_X = 170 -FONT = terminalio.FONT -TEXT_COLOR = 0x22FF00 # e.g., Green - -# Initialize the main display group -main_group = Group() - -# Initialize the icon group (this remains static on the display) -static_icon_group = Group() - -# Sample Bounding Box -bounding_box = { - "min_latitude": 40.633013, # Southernmost latitude - "max_latitude": 44.953469, # Northernmost latitude - "min_longitude": -111.045360, # Westernmost longitude - "max_longitude": -104.046570, # Easternmost longitude -} - -# --- Matrix setup --- -BIT_DEPTH = 2 -matrix = rgbmatrix.RGBMatrix( - width=DISPLAY_WIDTH, - height=DISPLAY_HEIGHT, - bit_depth=BIT_DEPTH, - rgb_pins=[ - board.MTX_B1, - board.MTX_G1, - board.MTX_R1, - board.MTX_B2, - board.MTX_G2, - board.MTX_R2, - ], - addr_pins=[ - board.MTX_ADDRA, - board.MTX_ADDRB, - board.MTX_ADDRC, - board.MTX_ADDRD, - board.MTX_ADDRE, - ], - clock_pin=board.MTX_CLK, - latch_pin=board.MTX_LAT, - output_enable_pin=board.MTX_OE, - tile=1, - serpentine=True, - doublebuffer=True, -) - -display = framebufferio.FramebufferDisplay(matrix, auto_refresh=True) - -# --- Wi-Fi setup --- -wifi.radio.connect( - os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD") -) -print(f"Connected to {os.getenv('CIRCUITPY_WIFI_SSID')}") - -# --- Networking setup --- -context = ssl.create_default_context() - -with open("/ssl.com-root.pem", "rb") as certfile: - context.load_verify_locations(cadata=certfile.read()) - -pool = socketpool.SocketPool(wifi.radio) -requests = adafruit_requests.Session(pool, context) - -# --- Icon Positioning --- -total_icons_height = (ICON_HEIGHT * NUMBER_OF_ICONS) + ( - GAP_BETWEEN_ICONS * (NUMBER_OF_ICONS - 1) -) - -# Function to scroll objects -def scroll_text_labels(text_labels): - for label in text_labels: - label.x -= 1 # Move label left. - if label.x < -300: # If label has moved off screen. - label.x = TEXT_RESET_X - - -def construct_query_string(params): - return "&".join(f"{key}={value}" for key, value in params.items()) - -def fetch_flight_data(): - print("Running fetch_flight_data") - - base_url = "https://aeroapi.flightaware.com/aeroapi/flights/search" - query_prefix = "-latlong+\"" - query_suffix = ( - str(bounding_box['min_latitude']) + "+" + - str(bounding_box['min_longitude']) + "+" + - str(bounding_box['max_latitude']) + "+" + - str(bounding_box['max_longitude']) + "\"") - query = query_prefix + query_suffix - - params = { - "query": query, - "max_pages": "1",} - - - headers = { - "Accept": "application/json; charset=UTF-8", - "x-apikey": os.getenv("AERO_API_KEY"), # Replace with your actual API key - } - full_url = f"{base_url}?{construct_query_string(params)}" - response = requests.get(full_url, headers=headers) - - if response.status_code == 200: - json_response = response.json() # Parse JSON only once - return process_flight_data(json_response) # Process flights and return - else: - print(f"Request failed with status code {response.status_code}") - if response.content: - print(f"Response content: {response.content}") - return [] - -def process_flight_data(json_data): - # Initialize an empty list to hold processed flight data - processed_flights = [] - - for flight in json_data.get("flights", []): - # Use 'get' with default values to avoid KeyError - flight_info = { - "ident": flight.get("ident", "N/A"), - "ident_icao": flight.get("ident_icao", "N/A"), - "fa_flight_id": flight.get("fa_flight_id", "N/A"), - "actual_off": flight.get("actual_off", "N/A"), - "actual_on": flight.get("actual_on", "N/A"), - "origin_code": flight.get("origin", {}).get("code", "UnknownA"), - "origin_city": flight.get("origin", {}).get("city", "UnknownB"), - "origin_country": flight.get("origin", {}).get("country", "UnknownC"), - "destination_code": flight.get("destination", {}).get("code", "UnknownD") - if flight.get("destination") - else "UnknownE", - "destination_city": flight.get("destination", {}).get("city", "UnknownH") - if flight.get("destination") - else "Unknown Destination", - "destination_country": flight.get("destination", {}).get( - "country", "UnknownZ" - ) - if flight.get("destination") - else "UnknownG", - "altitude": flight.get("last_position", {}).get("altitude", "N/A"), - "groundspeed": flight.get("last_position", {}).get("groundspeed", "N/A"), - "heading": flight.get("last_position", {}).get("heading", "N/A"), - "latitude": flight.get("last_position", {}).get("latitude", "N/A"), - "longitude": flight.get("last_position", {}).get("longitude", "N/A"), - "timestamp": flight.get("last_position", {}).get("timestamp", "N/A"), - "aircraft_type": flight.get("aircraft_type", "N/A"), - } - # Only add flight_info if the 'ident_icao' is present and not 'N/A' - if flight_info["ident_icao"] != "N/A": - processed_flights.append(flight_info) - - return processed_flights - - -def create_text_labels(flight_data, Ypositions): - local_text_labels = [] - for i, flight in enumerate(flight_data): - y_position = Ypositions[i] + GAP_BETWEEN_ICONS - - # Since 'country' is not present, use 'origin_city' and 'destination_city' instead - origin_city = flight.get("origin_city", "Unknown City") - destination_city = flight.get("destination_city", "Unknown City") - - # Construct the display text for each flight - single_line_text = ( - f"{flight['ident']} | From: {origin_city} To: {destination_city}" - ) - - text_label = adafruit_display_text.label.Label( - FONT, color=TEXT_COLOR, x=TEXT_START_X, y=y_position, text=single_line_text - ) - local_text_labels.append(text_label) - return local_text_labels - - - -def create_icon_tilegrid(ident): - airline_code = ident[:3].upper() # Use the first three characters of 'ident' - icon_path = f"/airline_logos/{airline_code}.bmp" - - try: - file = open(icon_path, "rb") - icon_bitmap = OnDiskBitmap(file) - except OSError: - print(f"Icon for {airline_code} not found. Using placeholder.") - file = open(PLACEHOLDER_ICON_PATH, "rb") - icon_bitmap = OnDiskBitmap(file) - - icon_tilegrid = TileGrid(icon_bitmap, pixel_shader=icon_bitmap.pixel_shader, x=0, y=0) - return icon_tilegrid - - -def update_display_with_flight_data(flight_data, icon_group, display_group): - # Clear previous display items - while len(display_group): - display_group.pop() - - # Clear previous icon items - while len(icon_group): - icon_group.pop() - - # Limit flight data to the adjusted number of icons - flight_data = flight_data[:NUMBER_OF_ICONS] - - # Calculate the y position for each icon - y_positions = [ - gap_between_icons + (ICON_HEIGHT + gap_between_icons) * i - for i in range(NUMBER_OF_ICONS) - ] - - # Create text labels for up to NUMBER_OF_ICONS flights - text_labels = create_text_labels(flight_data, y_positions) - - # Add text labels to the display group first so they are behind icons - for label in text_labels: - display_group.append(label) - - # Load icons and create icon tilegrids for up to NUMBER_OF_ICONS flights - for i, flight in enumerate(flight_data): - # Calculate the y position for each icon - y_position = y_positions[i] - - # Load the icon dynamically - icon_tilegrid = create_icon_tilegrid(flight["ident"]) - if icon_tilegrid: - icon_tilegrid.y = y_position - icon_group.append(icon_tilegrid) - - # Add the icon group to the main display group after text labels - display_group.append(icon_group) - - # Show the updated group on the display - display.root_group = display_group - display.refresh() - return text_labels - - - -def display_no_flights(): - # Clear the previous group content - while len(main_group): - main_group.pop() - - # Create a label for "Looking for flights..." - looking_label = adafruit_display_text.label.Label( - FONT, color=TEXT_COLOR, text="LOOKING FOR FLIGHTS", x=8, y=DISPLAY_HEIGHT // 2 - ) - main_group.append(looking_label) - - # Update the display with the new group - display.root_group = main_group - display.refresh() - - -display_no_flights() - -flight_json_response = fetch_flight_data() - -# Check if we received any flight data -if flight_json_response: - flight_data_labels = update_display_with_flight_data( - flight_json_response, static_icon_group, main_group - ) - -last_network_call_time = time.monotonic() - - -while True: - # Scroll the text labels - scroll_text_labels(flight_data_labels) - # Refresh the display - display.refresh(minimum_frames_per_second=0) - current_time = time.monotonic() - - # Check if NETWORK_CALL_INTERVAL seconds have passed - if (current_time - last_network_call_time) >= NETWORK_CALL_INTERVAL: - print("Fetching new flight data...") - new_flight_data = fetch_flight_data() - - if new_flight_data: - # If flight data is found, update the display with it - new_text_labels = update_display_with_flight_data( - new_flight_data, static_icon_group, main_group - ) - else: - # If no flight data is found, display the "Looking for flights..." message - display_no_flights() - - # Reset the last network call time - last_network_call_time = current_time - - # Sleep for a short period to prevent maxing out your CPU - time.sleep(1) # Sleep for 1 second diff --git a/Matrix_On_Air/code.py b/Matrix_On_Air/code.py index 05657136d..b323e4d2f 100644 --- a/Matrix_On_Air/code.py +++ b/Matrix_On_Air/code.py @@ -5,6 +5,7 @@ # ON AIR sign for YouTube livestreaming # Runs on Airlift Metro M4 with 64x32 RGB Matrix display & shield +from os import getenv import time import board import displayio @@ -15,12 +16,17 @@ from adafruit_matrixportal.network import Network from adafruit_matrixportal.matrix import Matrix -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Set up where we'll be fetching data from # Adafruit YouTube channel: @@ -32,7 +38,7 @@ "https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=" + CHANNEL_ID + "&type=video&eventType=live&key=" - + secrets["youtube_token"] + + getenv("youtube_token") ) DATA_LOCATION1 = ["items"] diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AAA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AAA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AAA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AAA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AAH.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AAH.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AAH.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AAH.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AAL.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AAL.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AAL.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AAL.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AAR.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AAR.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AAR.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AAR.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ACA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ACA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ACA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ACA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AFL.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AFL.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AFL.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AFL.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AFR.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AFR.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AFR.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AFR.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AIC.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AIC.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AIC.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AIC.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AJM.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AJM.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AJM.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AJM.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ALK.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ALK.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ALK.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ALK.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AMC.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AMC.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AMC.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AMC.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AMU.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AMU.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AMU.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AMU.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AMX.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AMX.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AMX.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AMX.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ANA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ANA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ANA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ANA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ANZ.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ANZ.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ANZ.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ANZ.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ASA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ASA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ASA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ASA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ATC.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ATC.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ATC.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ATC.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AUA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AUA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AUA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AUA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AVA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AVA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AVA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AVA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AWE.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AWE.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AWE.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AWE.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AZA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AZA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AZA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AZA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AZU.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AZU.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AZU.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/AZU.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BEE.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BEE.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BEE.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BEE.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BER.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BER.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BER.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BER.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BMA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BMA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BMA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BMA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BOE.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BOE.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BOE.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BOE.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BTA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BTA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BTA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BTA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BWA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BWA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BWA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/BWA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CAL.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CAL.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CAL.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CAL.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CCA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CCA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CCA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CCA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CES.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CES.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CES.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CES.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CHH.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CHH.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CHH.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CHH.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CJT.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CJT.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CJT.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CJT.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CLH.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CLH.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CLH.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CLH.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CLX.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CLX.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CLX.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CLX.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CMP.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CMP.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CMP.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CMP.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/COA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/COA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/COA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/COA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CPA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CPA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CPA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CPA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CSA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CSA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CSA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CSA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CSC.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CSC.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CSC.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CSC.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CSN.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CSN.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CSN.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CSN.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CSZ.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CSZ.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CSZ.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CSZ.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CXA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CXA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CXA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/CXA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/DAL.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/DAL.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/DAL.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/DAL.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/DLH.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/DLH.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/DLH.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/DLH.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EAL.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EAL.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EAL.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EAL.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EDV.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EDV.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EDV.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EDV.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EGF.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EGF.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EGF.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EGF.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EIN.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EIN.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EIN.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EIN.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ENY.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ENY.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ENY.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ENY.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ETD.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ETD.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ETD.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ETD.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ETH.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ETH.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ETH.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ETH.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EVA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EVA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EVA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EVA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EWG.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EWG.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EWG.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/EWG.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FDX.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FDX.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FDX.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FDX.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FFT.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FFT.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FFT.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FFT.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FIN.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FIN.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FIN.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FIN.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FJI.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FJI.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FJI.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FJI.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FLG.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FLG.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FLG.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/FLG.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GEC.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GEC.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GEC.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GEC.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GFA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GFA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GFA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GFA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GIA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GIA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GIA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GIA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GLO.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GLO.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GLO.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GLO.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GTI.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GTI.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GTI.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/GTI.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/HAL.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/HAL.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/HAL.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/HAL.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/HTL.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/HTL.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/HTL.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/HTL.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/IBE.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/IBE.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/IBE.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/IBE.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ICE.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ICE.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ICE.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ICE.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JAL.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JAL.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JAL.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JAL.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JAT.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JAT.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JAT.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JAT.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JBU.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JBU.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JBU.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JBU.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JKK.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JKK.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JKK.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JKK.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JMC.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JMC.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JMC.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JMC.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JSX.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JSX.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JSX.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JSX.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JZA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JZA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JZA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/JZA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/KAL.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/KAL.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/KAL.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/KAL.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/KLM.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/KLM.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/KLM.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/KLM.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LAL.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LAL.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LAL.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LAL.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LAN.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LAN.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LAN.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LAN.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LDA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LDA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LDA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LDA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LGL.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LGL.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LGL.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LGL.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LNI.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LNI.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LNI.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LNI.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LOF.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LOF.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LOF.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LOF.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LOT.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LOT.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LOT.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LOT.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LTD.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LTD.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LTD.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LTD.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LTG.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LTG.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LTG.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/LTG.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MAS.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MAS.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MAS.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MAS.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MEP.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MEP.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MEP.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MEP.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MGL.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MGL.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MGL.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MGL.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MPG.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MPG.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MPG.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MPG.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MPH.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MPH.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MPH.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MPH.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MSR.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MSR.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MSR.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MSR.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MXA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MXA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MXA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/MXA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/NGE.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/NGE.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/NGE.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/NGE.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/NMB.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/NMB.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/NMB.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/NMB.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/NRL.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/NRL.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/NRL.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/NRL.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/NWA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/NWA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/NWA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/NWA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/OAL.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/OAL.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/OAL.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/OAL.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PAC.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PAC.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PAC.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PAC.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PAL.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PAL.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PAL.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PAL.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PGA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PGA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PGA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PGA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PIA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PIA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PIA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PIA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/POE.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/POE.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/POE.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/POE.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PWD.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PWD.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PWD.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/PWD.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/QFA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/QFA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/QFA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/QFA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/QTR.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/QTR.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/QTR.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/QTR.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ROU.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ROU.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ROU.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/ROU.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/RSP.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/RSP.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/RSP.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/RSP.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/RVF.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/RVF.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/RVF.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/RVF.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/RYR.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/RYR.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/RYR.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/RYR.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SAA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SAA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SAA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SAA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SAS.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SAS.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SAS.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SAS.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SCX.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SCX.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SCX.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SCX.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SIA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SIA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SIA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SIA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SKW.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SKW.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SKW.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SKW.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SLI.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SLI.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SLI.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SLI.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SLM.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SLM.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SLM.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SLM.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SVA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SVA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SVA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SVA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SWA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SWA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SWA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SWA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SWG.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SWG.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SWG.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SWG.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SWR.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SWR.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SWR.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/SWR.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/TAI.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/TAI.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/TAI.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/TAI.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/TAM.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/TAM.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/TAM.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/TAM.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/TAP.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/TAP.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/TAP.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/TAP.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/THA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/THA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/THA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/THA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/THY.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/THY.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/THY.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/THY.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/TRS.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/TRS.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/TRS.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/TRS.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/UAE.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/UAE.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/UAE.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/UAE.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/UAL.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/UAL.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/UAL.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/UAL.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/USA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/USA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/USA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/USA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/VIR.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/VIR.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/VIR.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/VIR.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/VOZ.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/VOZ.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/VOZ.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/VOZ.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/VRD.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/VRD.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/VRD.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/VRD.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/VRG.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/VRG.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/VRG.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/VRG.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/WJA.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/WJA.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/WJA.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/WJA.bmp diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/placeholder.bmp b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/placeholder.bmp old mode 100755 new mode 100644 similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/placeholder.bmp rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/airline_logos/placeholder.bmp diff --git a/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/code.py b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/code.py new file mode 100644 index 000000000..72295f6b1 --- /dev/null +++ b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/code.py @@ -0,0 +1,330 @@ +# SPDX-FileCopyrightText: 2023 Trevor Beaton for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import os +import ssl +import time +import board +import wifi +import terminalio +import socketpool +import adafruit_requests +import displayio +import rgbmatrix +import framebufferio +import adafruit_display_text.label +from displayio import OnDiskBitmap, TileGrid, Group + +# Release any existing displays +displayio.release_displays() + +# --- Matrix Properties --- +DISPLAY_WIDTH = 128 +DISPLAY_HEIGHT = 64 + +# 432 Minutes - 7.2 Hours +NETWORK_CALL_INTERVAL = 25920 + +# --- Icon Properties --- +ICON_WIDTH = 26 # Width of the icons +ICON_HEIGHT = 26 # Height of the icons +# Calculate the gap between icons +gap_between_icons = 5 + +GAP_BETWEEN_ICONS = 15 # Gap between the icons +NUMBER_OF_ICONS = 2 # Number of icons to display +PLACEHOLDER_ICON_PATH = "/airline_logos/placeholder.bmp" + +# --- Text Properties --- +TEXT_START_X = ICON_WIDTH + 4 +TEXT_RESET_X = 170 +FONT = terminalio.FONT +TEXT_COLOR = 0x22FF00 # e.g., Green + +# Initialize the main display group +main_group = Group() + +# Initialize the icon group (this remains static on the display) +static_icon_group = Group() + +# Sample Bounding Box +bounding_box = { + "min_latitude": 40.633013, # Southernmost latitude + "max_latitude": 44.953469, # Northernmost latitude + "min_longitude": -111.045360, # Westernmost longitude + "max_longitude": -104.046570, # Easternmost longitude +} + +# --- Matrix setup --- +BIT_DEPTH = 2 +matrix = rgbmatrix.RGBMatrix( + width=DISPLAY_WIDTH, + height=DISPLAY_HEIGHT, + bit_depth=BIT_DEPTH, + rgb_pins=[ + board.MTX_B1, + board.MTX_G1, + board.MTX_R1, + board.MTX_B2, + board.MTX_G2, + board.MTX_R2, + ], + addr_pins=[ + board.MTX_ADDRA, + board.MTX_ADDRB, + board.MTX_ADDRC, + board.MTX_ADDRD, + board.MTX_ADDRE, + ], + clock_pin=board.MTX_CLK, + latch_pin=board.MTX_LAT, + output_enable_pin=board.MTX_OE, + tile=1, + serpentine=True, + doublebuffer=True, +) + +display = framebufferio.FramebufferDisplay(matrix, auto_refresh=True) + +# --- Wi-Fi setup --- +wifi.radio.connect( + os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD") +) +print(f"Connected to {os.getenv('CIRCUITPY_WIFI_SSID')}") + +# --- Networking setup --- +context = ssl.create_default_context() + +with open("/ssl.com-root.pem", "rb") as certfile: + context.load_verify_locations(cadata=certfile.read()) + +pool = socketpool.SocketPool(wifi.radio) +requests = adafruit_requests.Session(pool, context) + +# --- Icon Positioning --- +total_icons_height = (ICON_HEIGHT * NUMBER_OF_ICONS) + ( + GAP_BETWEEN_ICONS * (NUMBER_OF_ICONS - 1) +) + +# Function to scroll objects +def scroll_text_labels(text_labels): + for label in text_labels: + label.x -= 1 # Move label left. + if label.x < -300: # If label has moved off screen. + label.x = TEXT_RESET_X + + +def construct_query_string(params): + return "&".join(f"{key}={value}" for key, value in params.items()) + +def fetch_flight_data(): + print("Running fetch_flight_data") + + base_url = "https://aeroapi.flightaware.com/aeroapi/flights/search" + query_prefix = "-latlong+\"" + query_suffix = ( + str(bounding_box['min_latitude']) + "+" + + str(bounding_box['min_longitude']) + "+" + + str(bounding_box['max_latitude']) + "+" + + str(bounding_box['max_longitude']) + "\"") + query = query_prefix + query_suffix + + params = { + "query": query, + "max_pages": "1",} + + + headers = { + "Accept": "application/json; charset=UTF-8", + "x-apikey": os.getenv("AERO_API_KEY"), # Replace with your actual API key + } + full_url = f"{base_url}?{construct_query_string(params)}" + response = requests.get(full_url, headers=headers) + + if response.status_code == 200: + json_response = response.json() # Parse JSON only once + return process_flight_data(json_response) # Process flights and return + else: + print(f"Request failed with status code {response.status_code}") + if response.content: + print(f"Response content: {response.content}") + return [] + +def process_flight_data(json_data): + # Initialize an empty list to hold processed flight data + processed_flights = [] + + for flight in json_data.get("flights", []): + # Use 'get' with default values to avoid KeyError + flight_info = { + "ident": flight.get("ident", "N/A"), + "ident_icao": flight.get("ident_icao", "N/A"), + "fa_flight_id": flight.get("fa_flight_id", "N/A"), + "actual_off": flight.get("actual_off", "N/A"), + "actual_on": flight.get("actual_on", "N/A"), + "origin_code": flight.get("origin", {}).get("code", "UnknownA"), + "origin_city": flight.get("origin", {}).get("city", "UnknownB"), + "origin_country": flight.get("origin", {}).get("country", "UnknownC"), + "destination_code": flight.get("destination", {}).get("code", "UnknownD") + if flight.get("destination") + else "UnknownE", + "destination_city": flight.get("destination", {}).get("city", "UnknownH") + if flight.get("destination") + else "Unknown Destination", + "destination_country": flight.get("destination", {}).get( + "country", "UnknownZ" + ) + if flight.get("destination") + else "UnknownG", + "altitude": flight.get("last_position", {}).get("altitude", "N/A"), + "groundspeed": flight.get("last_position", {}).get("groundspeed", "N/A"), + "heading": flight.get("last_position", {}).get("heading", "N/A"), + "latitude": flight.get("last_position", {}).get("latitude", "N/A"), + "longitude": flight.get("last_position", {}).get("longitude", "N/A"), + "timestamp": flight.get("last_position", {}).get("timestamp", "N/A"), + "aircraft_type": flight.get("aircraft_type", "N/A"), + } + # Only add flight_info if the 'ident_icao' is present and not 'N/A' + if flight_info["ident_icao"] != "N/A": + processed_flights.append(flight_info) + + return processed_flights + + +def create_text_labels(flight_data, Ypositions): + local_text_labels = [] + for i, flight in enumerate(flight_data): + y_position = Ypositions[i] + GAP_BETWEEN_ICONS + + # Since 'country' is not present, use 'origin_city' and 'destination_city' instead + origin_city = flight.get("origin_city", "Unknown City") + destination_city = flight.get("destination_city", "Unknown City") + + # Construct the display text for each flight + single_line_text = ( + f"{flight['ident']} | From: {origin_city} To: {destination_city}" + ) + + text_label = adafruit_display_text.label.Label( + FONT, color=TEXT_COLOR, x=TEXT_START_X, y=y_position, text=single_line_text + ) + local_text_labels.append(text_label) + return local_text_labels + + + +def create_icon_tilegrid(ident): + airline_code = ident[:3].upper() # Use the first three characters of 'ident' + icon_path = f"/airline_logos/{airline_code}.bmp" + + try: + icon_bitmap = OnDiskBitmap(icon_path) + except OSError: + print(f"Icon for {airline_code} not found. Using placeholder.") + icon_bitmap = OnDiskBitmap(PLACEHOLDER_ICON_PATH) + + icon_tilegrid = TileGrid(icon_bitmap, pixel_shader=icon_bitmap.pixel_shader, x=0, y=0) + return icon_tilegrid + + +def update_display_with_flight_data(flight_data, icon_group, display_group): + # Clear previous display items + while len(display_group): + display_group.pop() + + # Clear previous icon items + while len(icon_group): + icon_group.pop() + + # Limit flight data to the adjusted number of icons + flight_data = flight_data[:NUMBER_OF_ICONS] + + # Calculate the y position for each icon + y_positions = [ + gap_between_icons + (ICON_HEIGHT + gap_between_icons) * i + for i in range(NUMBER_OF_ICONS) + ] + + # Create text labels for up to NUMBER_OF_ICONS flights + text_labels = create_text_labels(flight_data, y_positions) + + # Add text labels to the display group first so they are behind icons + for label in text_labels: + display_group.append(label) + + # Load icons and create icon tilegrids for up to NUMBER_OF_ICONS flights + for i, flight in enumerate(flight_data): + # Calculate the y position for each icon + y_position = y_positions[i] + + # Load the icon dynamically + icon_tilegrid = create_icon_tilegrid(flight["ident"]) + if icon_tilegrid: + icon_tilegrid.y = y_position + icon_group.append(icon_tilegrid) + + # Add the icon group to the main display group after text labels + display_group.append(icon_group) + + # Show the updated group on the display + display.root_group = display_group + display.refresh() + return text_labels + + + +def display_no_flights(): + # Clear the previous group content + while len(main_group): + main_group.pop() + + # Create a label for "Looking for flights..." + looking_label = adafruit_display_text.label.Label( + FONT, color=TEXT_COLOR, text="LOOKING FOR FLIGHTS", x=8, y=DISPLAY_HEIGHT // 2 + ) + main_group.append(looking_label) + + # Update the display with the new group + display.root_group = main_group + display.refresh() + + +display_no_flights() + +flight_json_response = fetch_flight_data() + +# Check if we received any flight data +if flight_json_response: + flight_data_labels = update_display_with_flight_data( + flight_json_response, static_icon_group, main_group + ) + +last_network_call_time = time.monotonic() + + +while True: + # Scroll the text labels + scroll_text_labels(flight_data_labels) + # Refresh the display + display.refresh(minimum_frames_per_second=0) + current_time = time.monotonic() + + # Check if NETWORK_CALL_INTERVAL seconds have passed + if (current_time - last_network_call_time) >= NETWORK_CALL_INTERVAL: + print("Fetching new flight data...") + new_flight_data = fetch_flight_data() + + if new_flight_data: + # If flight data is found, update the display with it + new_text_labels = update_display_with_flight_data( + new_flight_data, static_icon_group, main_group + ) + else: + # If no flight data is found, display the "Looking for flights..." message + display_no_flights() + + # Reset the last network call time + last_network_call_time = current_time + + # Sleep for a short period to prevent maxing out your CPU + time.sleep(1) # Sleep for 1 second diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/get_airline_logos.py b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/get_airline_logos.py similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/get_airline_logos.py rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/get_airline_logos.py diff --git a/MatrixPortal_S3_Flight_Proximity_Tracker/ssl.com-root.pem b/Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/ssl.com-root.pem similarity index 100% rename from MatrixPortal_S3_Flight_Proximity_Tracker/ssl.com-root.pem rename to Matrix_Portal/MatrixPortal_S3_Flight_Proximity_Tracker/ssl.com-root.pem diff --git a/Matrix_Portal_CO2_Monitor/.circuitpython.skip b/Matrix_Portal/Matrix_Portal_CO2_Monitor/.circuitpython.skip similarity index 100% rename from Matrix_Portal_CO2_Monitor/.circuitpython.skip rename to Matrix_Portal/Matrix_Portal_CO2_Monitor/.circuitpython.skip diff --git a/Matrix_Portal_CO2_Monitor/bmps/digits.bmp b/Matrix_Portal/Matrix_Portal_CO2_Monitor/bmps/digits.bmp similarity index 100% rename from Matrix_Portal_CO2_Monitor/bmps/digits.bmp rename to Matrix_Portal/Matrix_Portal_CO2_Monitor/bmps/digits.bmp diff --git a/Matrix_Portal_CO2_Monitor/bmps/smileys.bmp b/Matrix_Portal/Matrix_Portal_CO2_Monitor/bmps/smileys.bmp similarity index 100% rename from Matrix_Portal_CO2_Monitor/bmps/smileys.bmp rename to Matrix_Portal/Matrix_Portal_CO2_Monitor/bmps/smileys.bmp diff --git a/Matrix_Portal_CO2_Monitor/bmps/tags.bmp b/Matrix_Portal/Matrix_Portal_CO2_Monitor/bmps/tags.bmp similarity index 100% rename from Matrix_Portal_CO2_Monitor/bmps/tags.bmp rename to Matrix_Portal/Matrix_Portal_CO2_Monitor/bmps/tags.bmp diff --git a/Matrix_Portal_CO2_Monitor/code.py b/Matrix_Portal/Matrix_Portal_CO2_Monitor/code.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_CO2_Monitor/code.py rename to Matrix_Portal/Matrix_Portal_CO2_Monitor/code.py diff --git a/Matrix_Portal_ExpressivePixels/AnimeEyes.epx b/Matrix_Portal/Matrix_Portal_ExpressivePixels/AnimeEyes.epx similarity index 100% rename from Matrix_Portal_ExpressivePixels/AnimeEyes.epx rename to Matrix_Portal/Matrix_Portal_ExpressivePixels/AnimeEyes.epx diff --git a/Matrix_Portal_ExpressivePixels/ColorPortal.epx b/Matrix_Portal/Matrix_Portal_ExpressivePixels/ColorPortal.epx similarity index 100% rename from Matrix_Portal_ExpressivePixels/ColorPortal.epx rename to Matrix_Portal/Matrix_Portal_ExpressivePixels/ColorPortal.epx diff --git a/Matrix_Portal_ExpressivePixels/ExpressivePixels-MatrixPortal-16-32.uf2 b/Matrix_Portal/Matrix_Portal_ExpressivePixels/ExpressivePixels-MatrixPortal-16-32.uf2 old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_ExpressivePixels/ExpressivePixels-MatrixPortal-16-32.uf2 rename to Matrix_Portal/Matrix_Portal_ExpressivePixels/ExpressivePixels-MatrixPortal-16-32.uf2 diff --git a/Matrix_Portal_ExpressivePixels/ExpressivePixels-MatrixPortal-32-32.uf2 b/Matrix_Portal/Matrix_Portal_ExpressivePixels/ExpressivePixels-MatrixPortal-32-32.uf2 old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_ExpressivePixels/ExpressivePixels-MatrixPortal-32-32.uf2 rename to Matrix_Portal/Matrix_Portal_ExpressivePixels/ExpressivePixels-MatrixPortal-32-32.uf2 diff --git a/Matrix_Portal_ExpressivePixels/ExpressivePixels-MatrixPortal-64-32.uf2 b/Matrix_Portal/Matrix_Portal_ExpressivePixels/ExpressivePixels-MatrixPortal-64-32.uf2 old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_ExpressivePixels/ExpressivePixels-MatrixPortal-64-32.uf2 rename to Matrix_Portal/Matrix_Portal_ExpressivePixels/ExpressivePixels-MatrixPortal-64-32.uf2 diff --git a/Matrix_Portal_ExpressivePixels/Eyeball.epx b/Matrix_Portal/Matrix_Portal_ExpressivePixels/Eyeball.epx similarity index 100% rename from Matrix_Portal_ExpressivePixels/Eyeball.epx rename to Matrix_Portal/Matrix_Portal_ExpressivePixels/Eyeball.epx diff --git a/Matrix_Portal_ExpressivePixels/Fire.epx b/Matrix_Portal/Matrix_Portal_ExpressivePixels/Fire.epx similarity index 100% rename from Matrix_Portal_ExpressivePixels/Fire.epx rename to Matrix_Portal/Matrix_Portal_ExpressivePixels/Fire.epx diff --git a/Matrix_Portal_ExpressivePixels/Flag.epx b/Matrix_Portal/Matrix_Portal_ExpressivePixels/Flag.epx similarity index 100% rename from Matrix_Portal_ExpressivePixels/Flag.epx rename to Matrix_Portal/Matrix_Portal_ExpressivePixels/Flag.epx diff --git a/Matrix_Portal_ExpressivePixels/Fruits.epx b/Matrix_Portal/Matrix_Portal_ExpressivePixels/Fruits.epx similarity index 100% rename from Matrix_Portal_ExpressivePixels/Fruits.epx rename to Matrix_Portal/Matrix_Portal_ExpressivePixels/Fruits.epx diff --git a/Matrix_Portal_ExpressivePixels/PacmanGhosts.epx b/Matrix_Portal/Matrix_Portal_ExpressivePixels/PacmanGhosts.epx similarity index 100% rename from Matrix_Portal_ExpressivePixels/PacmanGhosts.epx rename to Matrix_Portal/Matrix_Portal_ExpressivePixels/PacmanGhosts.epx diff --git a/Matrix_Portal_ExpressivePixels/RoboMan.epx b/Matrix_Portal/Matrix_Portal_ExpressivePixels/RoboMan.epx similarity index 100% rename from Matrix_Portal_ExpressivePixels/RoboMan.epx rename to Matrix_Portal/Matrix_Portal_ExpressivePixels/RoboMan.epx diff --git a/Matrix_Portal_Eyes/.circuitpython.skip b/Matrix_Portal/Matrix_Portal_Eyes/.circuitpython.skip similarity index 100% rename from Matrix_Portal_Eyes/.circuitpython.skip rename to Matrix_Portal/Matrix_Portal_Eyes/.circuitpython.skip diff --git a/Matrix_Portal_Eyes/code.py b/Matrix_Portal/Matrix_Portal_Eyes/code.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/code.py rename to Matrix_Portal/Matrix_Portal_Eyes/code.py diff --git a/Matrix_Portal_Eyes/eyes/adabot/adabot-eyes.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/adabot/adabot-eyes.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/adabot/adabot-eyes.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/adabot/adabot-eyes.bmp diff --git a/Matrix_Portal_Eyes/eyes/adabot/adabot-lower-lids.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/adabot/adabot-lower-lids.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/adabot/adabot-lower-lids.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/adabot/adabot-lower-lids.bmp diff --git a/Matrix_Portal_Eyes/eyes/adabot/adabot-stencil.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/adabot/adabot-stencil.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/adabot/adabot-stencil.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/adabot/adabot-stencil.bmp diff --git a/Matrix_Portal_Eyes/eyes/adabot/adabot-upper-lids.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/adabot/adabot-upper-lids.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/adabot/adabot-upper-lids.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/adabot/adabot-upper-lids.bmp diff --git a/Matrix_Portal_Eyes/eyes/adabot/data.py b/Matrix_Portal/Matrix_Portal_Eyes/eyes/adabot/data.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/adabot/data.py rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/adabot/data.py diff --git a/Matrix_Portal_Eyes/eyes/cyclops/cyclops-eye.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/cyclops/cyclops-eye.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/cyclops/cyclops-eye.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/cyclops/cyclops-eye.bmp diff --git a/Matrix_Portal_Eyes/eyes/cyclops/cyclops-lower-lid.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/cyclops/cyclops-lower-lid.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/cyclops/cyclops-lower-lid.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/cyclops/cyclops-lower-lid.bmp diff --git a/Matrix_Portal_Eyes/eyes/cyclops/cyclops-stencil.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/cyclops/cyclops-stencil.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/cyclops/cyclops-stencil.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/cyclops/cyclops-stencil.bmp diff --git a/Matrix_Portal_Eyes/eyes/cyclops/cyclops-upper-lid.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/cyclops/cyclops-upper-lid.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/cyclops/cyclops-upper-lid.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/cyclops/cyclops-upper-lid.bmp diff --git a/Matrix_Portal_Eyes/eyes/cyclops/data.py b/Matrix_Portal/Matrix_Portal_Eyes/eyes/cyclops/data.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/cyclops/data.py rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/cyclops/data.py diff --git a/Matrix_Portal_Eyes/eyes/kobold/data.py b/Matrix_Portal/Matrix_Portal_Eyes/eyes/kobold/data.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/kobold/data.py rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/kobold/data.py diff --git a/Matrix_Portal_Eyes/eyes/kobold/kobold-eyes.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/kobold/kobold-eyes.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/kobold/kobold-eyes.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/kobold/kobold-eyes.bmp diff --git a/Matrix_Portal_Eyes/eyes/kobold/kobold-lower-lids.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/kobold/kobold-lower-lids.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/kobold/kobold-lower-lids.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/kobold/kobold-lower-lids.bmp diff --git a/Matrix_Portal_Eyes/eyes/kobold/kobold-stencil.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/kobold/kobold-stencil.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/kobold/kobold-stencil.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/kobold/kobold-stencil.bmp diff --git a/Matrix_Portal_Eyes/eyes/kobold/kobold-upper-lids.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/kobold/kobold-upper-lids.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/kobold/kobold-upper-lids.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/kobold/kobold-upper-lids.bmp diff --git a/Matrix_Portal_Eyes/eyes/skull/data.py b/Matrix_Portal/Matrix_Portal_Eyes/eyes/skull/data.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/skull/data.py rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/skull/data.py diff --git a/Matrix_Portal_Eyes/eyes/skull/skull-eyes.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/skull/skull-eyes.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/skull/skull-eyes.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/skull/skull-eyes.bmp diff --git a/Matrix_Portal_Eyes/eyes/skull/skull-lower-lids.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/skull/skull-lower-lids.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/skull/skull-lower-lids.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/skull/skull-lower-lids.bmp diff --git a/Matrix_Portal_Eyes/eyes/skull/skull-stencil.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/skull/skull-stencil.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/skull/skull-stencil.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/skull/skull-stencil.bmp diff --git a/Matrix_Portal_Eyes/eyes/skull/skull-upper-lids.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/skull/skull-upper-lids.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/skull/skull-upper-lids.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/skull/skull-upper-lids.bmp diff --git a/Matrix_Portal_Eyes/eyes/werewolf/data.py b/Matrix_Portal/Matrix_Portal_Eyes/eyes/werewolf/data.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/werewolf/data.py rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/werewolf/data.py diff --git a/Matrix_Portal_Eyes/eyes/werewolf/werewolf-eyes.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/werewolf/werewolf-eyes.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/werewolf/werewolf-eyes.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/werewolf/werewolf-eyes.bmp diff --git a/Matrix_Portal_Eyes/eyes/werewolf/werewolf-lower-lids.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/werewolf/werewolf-lower-lids.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/werewolf/werewolf-lower-lids.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/werewolf/werewolf-lower-lids.bmp diff --git a/Matrix_Portal_Eyes/eyes/werewolf/werewolf-stencil.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/werewolf/werewolf-stencil.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/werewolf/werewolf-stencil.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/werewolf/werewolf-stencil.bmp diff --git a/Matrix_Portal_Eyes/eyes/werewolf/werewolf-upper-lids.bmp b/Matrix_Portal/Matrix_Portal_Eyes/eyes/werewolf/werewolf-upper-lids.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Eyes/eyes/werewolf/werewolf-upper-lids.bmp rename to Matrix_Portal/Matrix_Portal_Eyes/eyes/werewolf/werewolf-upper-lids.bmp diff --git a/Matrix_Portal_Flow_Viewer/.circuitpython.skip b/Matrix_Portal/Matrix_Portal_Flow_Viewer/.circuitpython.skip similarity index 100% rename from Matrix_Portal_Flow_Viewer/.circuitpython.skip rename to Matrix_Portal/Matrix_Portal_Flow_Viewer/.circuitpython.skip diff --git a/Matrix_Portal_Flow_Viewer/flow/code.py b/Matrix_Portal/Matrix_Portal_Flow_Viewer/flow/code.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Flow_Viewer/flow/code.py rename to Matrix_Portal/Matrix_Portal_Flow_Viewer/flow/code.py diff --git a/Matrix_Portal_Flow_Viewer/flow_runner.py b/Matrix_Portal/Matrix_Portal_Flow_Viewer/flow_runner.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Flow_Viewer/flow_runner.py rename to Matrix_Portal/Matrix_Portal_Flow_Viewer/flow_runner.py diff --git a/Matrix_Portal_Flow_Viewer/flow_viewer/code.py b/Matrix_Portal/Matrix_Portal_Flow_Viewer/flow_viewer/code.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Flow_Viewer/flow_viewer/code.py rename to Matrix_Portal/Matrix_Portal_Flow_Viewer/flow_viewer/code.py diff --git a/Matrix_Portal_Handbag/.circuitpython.skip b/Matrix_Portal/Matrix_Portal_Handbag/.circuitpython.skip similarity index 100% rename from Matrix_Portal_Handbag/.circuitpython.skip rename to Matrix_Portal/Matrix_Portal_Handbag/.circuitpython.skip diff --git a/Matrix_Portal_Handbag/bmps/00_v.bmp b/Matrix_Portal/Matrix_Portal_Handbag/bmps/00_v.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Handbag/bmps/00_v.bmp rename to Matrix_Portal/Matrix_Portal_Handbag/bmps/00_v.bmp diff --git a/Matrix_Portal_Handbag/bmps/01_vo.bmp b/Matrix_Portal/Matrix_Portal_Handbag/bmps/01_vo.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Handbag/bmps/01_vo.bmp rename to Matrix_Portal/Matrix_Portal_Handbag/bmps/01_vo.bmp diff --git a/Matrix_Portal_Handbag/bmps/02_vot.bmp b/Matrix_Portal/Matrix_Portal_Handbag/bmps/02_vot.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Handbag/bmps/02_vot.bmp rename to Matrix_Portal/Matrix_Portal_Handbag/bmps/02_vot.bmp diff --git a/Matrix_Portal_Handbag/bmps/03_vote.bmp b/Matrix_Portal/Matrix_Portal_Handbag/bmps/03_vote.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Handbag/bmps/03_vote.bmp rename to Matrix_Portal/Matrix_Portal_Handbag/bmps/03_vote.bmp diff --git a/Matrix_Portal_Handbag/bmps2/00_nyancat.bmp b/Matrix_Portal/Matrix_Portal_Handbag/bmps2/00_nyancat.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Handbag/bmps2/00_nyancat.bmp rename to Matrix_Portal/Matrix_Portal_Handbag/bmps2/00_nyancat.bmp diff --git a/Matrix_Portal_Handbag/bmps2/01_nyancat.bmp b/Matrix_Portal/Matrix_Portal_Handbag/bmps2/01_nyancat.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Handbag/bmps2/01_nyancat.bmp rename to Matrix_Portal/Matrix_Portal_Handbag/bmps2/01_nyancat.bmp diff --git a/Matrix_Portal_Handbag/bmps2/02_nyancat.bmp b/Matrix_Portal/Matrix_Portal_Handbag/bmps2/02_nyancat.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Handbag/bmps2/02_nyancat.bmp rename to Matrix_Portal/Matrix_Portal_Handbag/bmps2/02_nyancat.bmp diff --git a/Matrix_Portal_Handbag/bmps2/03_nyancat.bmp b/Matrix_Portal/Matrix_Portal_Handbag/bmps2/03_nyancat.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Handbag/bmps2/03_nyancat.bmp rename to Matrix_Portal/Matrix_Portal_Handbag/bmps2/03_nyancat.bmp diff --git a/Matrix_Portal_Handbag/bmps3/00_mermaidglimmer.bmp b/Matrix_Portal/Matrix_Portal_Handbag/bmps3/00_mermaidglimmer.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Handbag/bmps3/00_mermaidglimmer.bmp rename to Matrix_Portal/Matrix_Portal_Handbag/bmps3/00_mermaidglimmer.bmp diff --git a/Matrix_Portal_Handbag/bmps3/01_mermaid.bmp b/Matrix_Portal/Matrix_Portal_Handbag/bmps3/01_mermaid.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Handbag/bmps3/01_mermaid.bmp rename to Matrix_Portal/Matrix_Portal_Handbag/bmps3/01_mermaid.bmp diff --git a/Matrix_Portal_Handbag/bmps3/02_mermaid.bmp b/Matrix_Portal/Matrix_Portal_Handbag/bmps3/02_mermaid.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Handbag/bmps3/02_mermaid.bmp rename to Matrix_Portal/Matrix_Portal_Handbag/bmps3/02_mermaid.bmp diff --git a/Matrix_Portal_Handbag/bmps3/03_mermaid.bmp b/Matrix_Portal/Matrix_Portal_Handbag/bmps3/03_mermaid.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Handbag/bmps3/03_mermaid.bmp rename to Matrix_Portal/Matrix_Portal_Handbag/bmps3/03_mermaid.bmp diff --git a/Matrix_Portal_Handbag/bmps3/04_mermaid.bmp b/Matrix_Portal/Matrix_Portal_Handbag/bmps3/04_mermaid.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Handbag/bmps3/04_mermaid.bmp rename to Matrix_Portal/Matrix_Portal_Handbag/bmps3/04_mermaid.bmp diff --git a/Matrix_Portal_Handbag/code.py b/Matrix_Portal/Matrix_Portal_Handbag/code.py similarity index 100% rename from Matrix_Portal_Handbag/code.py rename to Matrix_Portal/Matrix_Portal_Handbag/code.py diff --git a/Matrix_Portal_Learn_Stats/IBMPlexMono-Medium-24_jep.bdf.zip b/Matrix_Portal/Matrix_Portal_Learn_Stats/IBMPlexMono-Medium-24_jep.bdf.zip similarity index 100% rename from Matrix_Portal_Learn_Stats/IBMPlexMono-Medium-24_jep.bdf.zip rename to Matrix_Portal/Matrix_Portal_Learn_Stats/IBMPlexMono-Medium-24_jep.bdf.zip diff --git a/Matrix_Portal/Matrix_Portal_Learn_Stats/code.py b/Matrix_Portal/Matrix_Portal_Learn_Stats/code.py new file mode 100644 index 000000000..af185fb3d --- /dev/null +++ b/Matrix_Portal/Matrix_Portal_Learn_Stats/code.py @@ -0,0 +1,115 @@ +# SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import time +from random import randrange +import board +import terminalio +from adafruit_matrixportal.matrixportal import MatrixPortal + +# --- Data Setup --- # +# Number of guides to fetch and display from the Adafruit Learning System +DISPLAY_NUM_GUIDES = 5 +# Data source URL +DATA_SOURCE = ( + "https://learn.adafruit.com/api/guides.json?count=%d" % DISPLAY_NUM_GUIDES +) +TITLE_DATA_LOCATION = ["guides"] + +matrixportal = MatrixPortal( + url=DATA_SOURCE, + json_path=TITLE_DATA_LOCATION, + status_neopixel=board.NEOPIXEL, +) + +# --- Display Setup --- # + +# Colors for guide name +colors = [0xFFA500, 0xFFFF00, 0x008000, 0x0000FF, 0x4B0082, 0xEE82EE] + +# Delay for scrolling the text +SCROLL_DELAY = 0.03 + +FONT = "/IBMPlexMono-Medium-24_jep.bdf" + +# Learn guide count (ID = 0) +matrixportal.add_text( + text_font=FONT, + text_position=( + (matrixportal.graphics.display.width // 12) - 1, + (matrixportal.graphics.display.height // 2) - 8, + ), + text_color=0x800000, +) +matrixportal.preload_font("0123456789") + +# Learn guide title (ID = 1) +matrixportal.add_text( + text_font=terminalio.FONT, + text_position=(2, 25), + text_color=0x000080, + scrolling=True, +) + + +def get_guide_info(index): + """Parses JSON data returned by the DATA_SOURCE + to obtain the ALS guide title and number of guides and + sets the text labels. + :param int index: Guide index to display + + """ + if index > DISPLAY_NUM_GUIDES: + raise RuntimeError("Provided index may not be larger than DISPLAY_NUM_GUIDES.") + print("Obtaining guide info for guide %d..." % index) + + # Traverse JSON data for title + guide_count = matrixportal.network.json_traverse(als_data.json(), ["guides_total_count"]) + + # Set guide count + matrixportal.set_text(guide_count, 0) + + guides = matrixportal.network.json_traverse(als_data.json(), TITLE_DATA_LOCATION) + guide_title = guides[index]["guide"]["title"] + print("Guide Title", guide_title) + + # Select color for title text + color_index = randrange(0, len(colors)) + + # Set the title text color + matrixportal.set_text_color(colors[color_index], 1) + + # Set the title text + matrixportal.set_text(guide_title, 1) + + +refresh_time = None +guide_idx = 0 +prv_hour = 0 +while True: + if (not refresh_time) or (time.monotonic() - refresh_time) > 900: + try: + print("obtaining time from adafruit.io server...") + matrixportal.get_local_time() + refresh_time = time.monotonic() + except RuntimeError as e: + print("Unable to obtain time from Adafruit IO, retrying - ", e) + continue + + if time.localtime()[3] != prv_hour: + print("New Hour, fetching new data...") + # Fetch and store guide info response + als_data = matrixportal.network.fetch(DATA_SOURCE) + prv_hour = time.localtime()[3] + + # Cycle through guides retrieved + if guide_idx < DISPLAY_NUM_GUIDES: + get_guide_info(guide_idx) + + # Scroll the scrollable text block + matrixportal.scroll_text(SCROLL_DELAY) + guide_idx += 1 + else: + guide_idx = 0 + time.sleep(0.05) diff --git a/Matrix_Portal_M4_Boxing_Interval_Timer/code.py b/Matrix_Portal/Matrix_Portal_M4_Boxing_Interval_Timer/code.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_M4_Boxing_Interval_Timer/code.py rename to Matrix_Portal/Matrix_Portal_M4_Boxing_Interval_Timer/code.py diff --git a/Matrix_Portal/Matrix_Portal_Moon_Clock/code.py b/Matrix_Portal/Matrix_Portal_Moon_Clock/code.py new file mode 100644 index 000000000..8eb75b610 --- /dev/null +++ b/Matrix_Portal/Matrix_Portal_Moon_Clock/code.py @@ -0,0 +1,475 @@ +# SPDX-FileCopyrightText: 2020 Phillip Burgess for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +MOON PHASE CLOCK for Adafruit Matrix Portal: displays current time, lunar +phase and time of next moonrise or moonset. Requires WiFi internet access +and Adafruit IO user account (basic account is free, just needs registration). + +Written by Phil 'PaintYourDragon' Burgess for Adafruit Industries. +MIT license, all text above must be included in any redistribution. + +BDF fonts from the X.Org project. Startup 'splash' images should not be +included in derivative projects, thanks. Tall splash images licensed from +123RF.com, wide splash images used with permission of artist Lew Lashmit +(viergacht@gmail.com). Rawr! +""" + +# pylint: disable=import-error + +from os import getenv +import gc +import time +import math +import board +import busio +import displayio +from rtc import RTC +from adafruit_matrixportal.network import Network +from adafruit_matrixportal.matrix import Matrix +from adafruit_bitmap_font import bitmap_font +import adafruit_display_text.label +import adafruit_lis3dh + +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) + +# CONFIGURABLE SETTINGS ---------------------------------------------------- + +TWELVE_HOUR = True # If set, use 12-hour time vs 24-hour (e.g. 3:00 vs 15:00) +COUNTDOWN = False # If set, show time to (vs time of) next rise/set event +MONTH_DAY = True # If set, use MM/DD vs DD/MM (e.g. 31/12 vs 12/31) +BITPLANES = 6 # Ideally 6, but can set lower if RAM is tight + +# Moon API requres valid User-Agent header. Only maintainer should edit this. +HEADERS = { "User-Agent" : "AdafruitMoonClock/1.1 support@adafruit.com" } + +# SOME UTILITY FUNCTIONS AND CLASSES --------------------------------------- + +# Notes to Future Self on timekeeping: times are expressed in so many +# formats throughout this code, a variable naming system is used: local +# times (i.e. in clock's present geographic time zone) will have _local +# in their variable name, while UTC times (aka Greenwich or Zulu time) +# will have _utc. Types are also explicitly stated: strings (e.g. +# "2023-07-20T08:37-07:00") will have _string in the variable name, +# struct_time objects will have _struct, and integer "UNIX time" epoch +# seconds will have _seconds. Conversions (offset is signed, e.g. -700): +# Convert UTC to local time: add UTC offset; local = utc + offset +# Convert local to UTC time: subtract UTC offset; utc = local - offset + +def update_system_time(): + """ Update system clock date/time from Adafruit IO. Credentials and time + zone are in settings.toml. See http://worldtimeapi.org/api/timezone for + list of time zones. If missing, will attempt using IP geolocation. + Returns present local (not UTC) time as a struct_time and UTC offset + as string "sHH:MM". This may throw an exception on get_local_time(), + it is NOT CAUGHT HERE, should be handled in the calling code because + different behaviors may be needed for some situations (e.g. + reschedule later). + """ + local_time_string = NETWORK.get_local_time() # Sets RTC() time, but also + elements = local_time_string.split(" ") # returns server response + utc_offset = int(elements[-2]) # Format shHMM, e.g. -700 = -7 hr, 0 min + # Pad UTC format shHMM to sHH:MM as needed for moon API 3.0 + utc_offset_string = "{:+03d}:{:02d}".format(utc_offset // 100, # Hours + abs(utc_offset) % 100) # Mins + return RTC().datetime, utc_offset_string + + +def hh_mm(time_struct): + """ Used for clock display elements, not for delta-time calculations. + Given a struct_time, return a string as H:MM or HH:MM, either 12- + or 24-hour style depending on global TWELVE_HOUR setting. This is + ONLY for 'clock time,' NOT for countdown time, which is handled + separately in the one spot where it's needed. + """ + if TWELVE_HOUR: + if time_struct.tm_hour > 12: + hour_string = str(time_struct.tm_hour - 12) # 13-23 -> 1-11 (pm) + elif time_struct.tm_hour > 0: + hour_string = str(time_struct.tm_hour) # 1-12 + else: + hour_string = '12' # 0 -> 12 (am) + else: + hour_string = '{0:0>2}'.format(time_struct.tm_hour) + return hour_string + ':' + '{0:0>2}'.format(time_struct.tm_min) + + +def parse_time_to_utc_seconds(time_local_string): + """ Given a string of YYYY-MM-DDTHH:MMsHH:MM or YYYY-MM-DDTHH:MM:SSZ + return equivalent UTC epoch seconds. + """ + # This could be UTC or local time, don't know yet, so no tag in var name + date_time = time_local_string.split('T') # Separate into date and time + date_str = date_time[0].split('-') # Separate date into Y/M/D + time_str = date_time[1] + # Moon API always puts 00 seconds for interval, while rise/set times + # include no seconds value. Thus, only first two values are referenced: + hour = int(time_str[0:2]) # HH:MM as encoded in string, + minute = int(time_str[3:5]) # still could be UTC or local... + if time_str[-1] != 'Z': # If not "Zulu time" (UTC), is local, so: + hour -= int(time_str[-6:-3]) # convert local to UTC + minute -= int(time_str[-2:]) + return time.mktime(time.struct_time((int(date_str[0]), + int(date_str[1]), + int(date_str[2]), + hour, + minute, + 0, -1, -1, False))) + + +# pylint: disable=too-few-public-methods +class MoonData(): + """ Class holding lunar data for a given 24-hour period. App uses two + of these -- one for the current day, and one for the following day, + then some interpolations and such can be made. Elements include: + age : Moon phase 'age' at start of period, expressed + from 0.0 (new moon) through 0.5 (full moon) to + 1.0 (next new moon). + start_utc_seconds : Epoch time at start of period, UTC + end_utc_seconds : Epoch time at end of period, " + rise_utc_seconds : Epoch time of moon rise within this 24-hour period + set_utc_seconds : Epoch time of moon set within this 24-hour period + """ + def __init__(self, datetime_local_struct, days_ahead, utc_offset_string): + """ Initialize MoonData elements (see above) given a struct_time, + days to skip ahead (typically 0 or 1), and a UTC offset (as a + string) and a query to the MET Norway Sunrise API (also provides + lunar data), documented at: + https://docs.api.met.no/doc/sunrise/celestial.html + """ + if days_ahead > 0: + # Can't change attributes in struct_time, need to create a new + # one which will roll the date ahead as needed. Convert to local + # epoch seconds and back for the offset to work. :/ + datetime_local_struct = time.localtime( + time.mktime(time.struct_time(( + datetime_local_struct.tm_year, + datetime_local_struct.tm_mon, + datetime_local_struct.tm_mday + days_ahead, + datetime_local_struct.tm_hour, + datetime_local_struct.tm_min, + datetime_local_struct.tm_sec, + -1, -1, -1)))) + # URL does not contain local or UTC time, only date. strftime() is + # not available in CircuitPython, manual conversion to time string + # is needed. Response is moon data for a 24-hour period, based on + # longitude and requested date. Some values within are UTC time, + # others are local. Anything we parse out of this will be converted + # to UTC epoch seconds, period. + url = ('https://api.met.no/weatherapi/sunrise/3.0/moon?lat=' + + str(LATITUDE) + '&lon=' + str(LONGITUDE) + + '&date=' + str(datetime_local_struct.tm_year) + '-' + + '{0:0>2}'.format(datetime_local_struct.tm_mon) + '-' + + '{0:0>2}'.format(datetime_local_struct.tm_mday) + + '&offset=' + utc_offset_string) + print('Fetching moon data via', url) + # pylint: disable=bare-except + for _ in range(5): # Retries + try: + moon_data = NETWORK.fetch_data(url, + json_path=[], + headers = HEADERS) + properties = moon_data['properties'] + # 0 = new moon, 90 = Q1, 180 = full moon, 270 = LQ + self.age = float(properties['moonphase']) / 360 + interval = moon_data['when']['interval'] + self.start_utc_seconds = parse_time_to_utc_seconds(interval[0]) + self.end_utc_seconds = parse_time_to_utc_seconds(interval[1]) + # Thx user sandorcourane for the properties fixes! + if properties['moonrise']['time'] is not None: + self.rise_utc_seconds = parse_time_to_utc_seconds( + properties['moonrise']['time']) + else: + self.rise_utc_seconds = None + if properties['moonset']['time'] is not None: + self.set_utc_seconds = parse_time_to_utc_seconds( + properties['moonset']['time']) + else: + self.set_utc_seconds = None + return # Success! + except: + # Moon server error (maybe), try again after 15 seconds. + # (Might be a memory error, that should be handled different) + time.sleep(15) + + +# ONE-TIME INITIALIZATION -------------------------------------------------- + +MATRIX = Matrix(bit_depth=BITPLANES) +DISPLAY = MATRIX.display +ACCEL = adafruit_lis3dh.LIS3DH_I2C(busio.I2C(board.SCL, board.SDA), + address=0x19) +_ = ACCEL.acceleration # Dummy reading to blow out any startup residue +time.sleep(0.1) +DISPLAY.rotation = (int(((math.atan2(-ACCEL.acceleration.y, + -ACCEL.acceleration.x) + math.pi) / + (math.pi * 2) + 0.875) * 4) % 4) * 90 + +LARGE_FONT = bitmap_font.load_font('/fonts/helvB12.bdf') +SMALL_FONT = bitmap_font.load_font('/fonts/helvR10.bdf') +SYMBOL_FONT = bitmap_font.load_font('/fonts/6x10.bdf') +LARGE_FONT.load_glyphs('0123456789:') +SMALL_FONT.load_glyphs('0123456789:/.%') +SYMBOL_FONT.load_glyphs('\u21A5\u21A7') + +# Display group is set up once, then we just shuffle items around later. +# Order of creation here determines their stacking order. +GROUP = displayio.Group() + +# Element 0 is a stand-in item, later replaced with the moon phase bitmap +# pylint: disable=bare-except +try: + FILENAME = 'moon/splash-' + str(DISPLAY.rotation) + '.bmp' + + BITMAP = displayio.OnDiskBitmap(FILENAME) + TILE_GRID = displayio.TileGrid(BITMAP, pixel_shader=BITMAP.pixel_shader) + + GROUP.append(TILE_GRID) +except: + GROUP.append(adafruit_display_text.label.Label(SMALL_FONT, color=0xFF0000, + text='AWOO')) + GROUP[0].x = (DISPLAY.width - GROUP[0].bounding_box[2] + 1) // 2 + GROUP[0].y = DISPLAY.height // 2 - 1 + +# Elements 1-4 are an outline around the moon percentage -- text labels +# offset by 1 pixel up/down/left/right. Initial position is off the matrix, +# updated on first refresh. Initial text value must be long enough for +# longest anticipated string later. +for i in range(4): + GROUP.append(adafruit_display_text.label.Label(SMALL_FONT, color=0, + text='99.9%', y=-99)) +# Element 5 is the moon percentage (on top of the outline labels) +GROUP.append(adafruit_display_text.label.Label(SMALL_FONT, color=0xFFFF00, + text='99.9%', y=-99)) +# Element 6 is the current time +GROUP.append(adafruit_display_text.label.Label(LARGE_FONT, color=0x808080, + text='12:00', y=-99)) +# Element 7 is the current date +GROUP.append(adafruit_display_text.label.Label(SMALL_FONT, color=0x808080, + text='12/31', y=-99)) +# Element 8 is a symbol indicating next rise or set +GROUP.append(adafruit_display_text.label.Label(SYMBOL_FONT, color=0x00FF00, + text='x', y=-99)) +# Element 9 is the time of (or time to) next rise/set event +GROUP.append(adafruit_display_text.label.Label(SMALL_FONT, color=0x00FF00, + text='12:00', y=-99)) +DISPLAY.root_group = GROUP + +NETWORK = Network(status_neopixel=board.NEOPIXEL, debug=False) +NETWORK.connect() + +# LATITUDE, LONGITUDE, TIMEZONE are set up once, constant over app lifetime + +# Fetch latitude/longitude from settings.toml. If not present, use +# IP geolocation. This only needs to be done once, at startup! +try: + LATITUDE = getenv('latitude') + LONGITUDE = getenv('longitude') + print('Using stored geolocation: ', LATITUDE, LONGITUDE) +except KeyError: + LATITUDE, LONGITUDE = ( + NETWORK.fetch_data('http://www.geoplugin.net/json.gp', + json_path=[['geoplugin_latitude'], + ['geoplugin_longitude']])) + print('Using IP geolocation: ', LATITUDE, LONGITUDE) + +# Set initial clock time, also fetch initial UTC offset while +# here (NOT stored in settings.toml as it may change with DST). +# pylint: disable=bare-except +try: + DATETIME_LOCAL_STRUCT, UTC_OFFSET_STRING = update_system_time() +except: + DATETIME_LOCAL_STRUCT, UTC_OFFSET_STRING = time.localtime(), '+00:00' +LAST_SYNC_LOCAL_SECONDS = time.mktime(DATETIME_LOCAL_STRUCT) + +# Poll server for moon data for current 24-hour period and +24 ahead +PERIOD = [] +for DAY in range(2): # Today, tomorrow + PERIOD.append(MoonData(DATETIME_LOCAL_STRUCT, DAY, UTC_OFFSET_STRING)) +# PERIOD[0] is a current 24-hour time period we're in. PERIOD[1] is the +# 24 hours following that. Start/end time thresholds vary by longitude. +# Any values within the object are expressed in UTC seconds. Data is +# shifted down and new data fetched as days expire. Thought we might need a +# PERIOD[2] for certain circumstances but it appears not, that's changed +# easily enough if needed. + + +# MAIN LOOP ---------------------------------------------------------------- + +while True: + gc.collect() + NOW_LOCAL_SECONDS = time.time() # Current local epoch time in seconds + + # Sync with time server every ~3 hours + if NOW_LOCAL_SECONDS - LAST_SYNC_LOCAL_SECONDS > 3 * 60 * 60: + try: + DATETIME_LOCAL_STRUCT, UTC_OFFSET_STRING = update_system_time() + LAST_SYNC_LOCAL_SECONDS = time.mktime(DATETIME_LOCAL_STRUCT) + continue # Time may have changed; refresh NOW_LOCAL_SECONDS value + except: + # update_system_time() can throw an exception if time server doesn't + # respond. That's OK, keep running with our current time, and + # push sync time ahead to retry in 30 minutes (don't overwhelm + # the server with repeated queries). + LAST_SYNC_LOCAL_SECONDS += 30 * 60 # 30 minutes -> seconds + + # NOW_LOCAL_SECONDS and DATETIME_LOCAL_STRUCT are local time, while all + # moon properties are UTC. Convert 'now' to UTC seconds... + # UTC_OFFSET_STRING is a string, like +HH:MM. Convert to integer seconds: + hhmm = UTC_OFFSET_STRING.split(':') + utc_offset_seconds = (int(hhmm[0]) * 60 + int(hhmm[1])) * 60 + NOW_UTC_SECONDS = NOW_LOCAL_SECONDS - utc_offset_seconds + + # If PERIOD has expired, move data down and fetch new +24-hour data + if NOW_UTC_SECONDS >= PERIOD[0].end_utc_seconds: + PERIOD[0] = PERIOD[1] + PERIOD[1] = MoonData(time.localtime(), 1, UTC_OFFSET_STRING) + + # Determine weighting of tomorrow's phase vs today's, using current time + RATIO = ((NOW_UTC_SECONDS - PERIOD[0].start_utc_seconds) / + (PERIOD[1].start_utc_seconds - PERIOD[0].start_utc_seconds)) + # Determine moon phase 'age' + # 0.0 = new moon + # 0.25 = first quarter + # 0.5 = full moon + # 0.75 = last quarter + # 1.0 = new moon + if PERIOD[0].age < PERIOD[1].age: + AGE = (PERIOD[0].age + + (PERIOD[1].age - PERIOD[0].age) * RATIO) % 1.0 + else: # Handle age wraparound (1.0 -> 0.0) + # If tomorrow's age is less than today's, it indicates a new moon + # crossover. Add 1 to tomorrow's age when computing age delta. + AGE = (PERIOD[0].age + + (PERIOD[1].age + 1 - PERIOD[0].age) * RATIO) % 1.0 + + # AGE can be used for direct lookup to moon bitmap (0 to 99) -- these + # images are pre-rendered for a linear timescale (solar terminator moves + # nonlinearly across sphere). + FRAME = int(AGE * 100) % 100 # Bitmap 0 to 99 + + # Then use some trig to get percentage lit + if AGE <= 0.5: # New -> first quarter -> full + PERCENT = (1 - math.cos(AGE * 2 * math.pi)) * 50 + else: # Full -> last quarter -> new + PERCENT = (1 + math.cos((AGE - 0.5) * 2 * math.pi)) * 50 + + # Find next rise/set event, complicated by the fact that some 24-hour + # periods might not have one or the other (but usually do) due to the + # Moon rising ~50 mins later each day. This uses a brute force approach, + # working through the time periods to locate rise/set events that + # A) exist in that 24-hour period (are not None), B) are still in + # the future, and C) are closer than the last guess. What's left at the + # end is the next rise or set time, and a flag whether the moon's + # currently risen or not. + NEXT_EVENT_UTC_SECONDS = NOW_UTC_SECONDS + 300000 # Way future + for DAY in PERIOD: + if (DAY.rise_utc_seconds and + NOW_UTC_SECONDS < DAY.rise_utc_seconds < NEXT_EVENT_UTC_SECONDS): + NEXT_EVENT_UTC_SECONDS = DAY.rise_utc_seconds + RISEN = False # Current moon state; next event is inverse + if (DAY.set_utc_seconds and + NOW_UTC_SECONDS < DAY.set_utc_seconds < NEXT_EVENT_UTC_SECONDS): + NEXT_EVENT_UTC_SECONDS = DAY.set_utc_seconds + RISEN = True + + if DISPLAY.rotation in (0, 180): # Horizontal 'landscape' orientation + CENTER_X = 48 # Text along right + MOON_Y = 0 # Moon at left + TIME_Y = 6 # Time at top right + EVENT_Y = 26 # Rise/set at bottom right + else: # Vertical 'portrait' orientation + CENTER_X = 16 # Text down center + if RISEN: + MOON_Y = 0 # Moon at top + EVENT_Y = 38 # Rise/set in middle + TIME_Y = 49 # Time/date at bottom + else: + TIME_Y = 6 # Time/date at top + EVENT_Y = 26 # Rise/set in middle + MOON_Y = 32 # Moon at bottom + + print() + + # Update moon image (GROUP[0]) + FILENAME = 'moon/moon' + '{0:0>2}'.format(FRAME) + '.bmp' + + BITMAP = displayio.OnDiskBitmap(FILENAME) + TILE_GRID = displayio.TileGrid(BITMAP, pixel_shader=BITMAP.pixel_shader) + + TILE_GRID.x = 0 + TILE_GRID.y = MOON_Y + GROUP[0] = TILE_GRID + + # Update percent value (5 labels: GROUP[1-4] for outline, [5] for text) + if PERCENT >= 99.95: + STRING = '100%' + else: + STRING = '{:.1f}'.format(PERCENT + 0.05) + '%' + print(NOW_UTC_SECONDS, STRING, 'full') + # Set element 5 first, use its size and position for setting others + GROUP[5].text = STRING + GROUP[5].x = 16 - GROUP[5].bounding_box[2] // 2 + GROUP[5].y = MOON_Y + 16 + for _ in range(1, 5): + GROUP[_].text = GROUP[5].text + GROUP[1].x, GROUP[1].y = GROUP[5].x, GROUP[5].y - 1 # Up 1 pixel + GROUP[2].x, GROUP[2].y = GROUP[5].x - 1, GROUP[5].y # Left + GROUP[3].x, GROUP[3].y = GROUP[5].x + 1, GROUP[5].y # Right + GROUP[4].x, GROUP[4].y = GROUP[5].x, GROUP[5].y + 1 # Down + + # Update next-event time (GROUP[8] and [9]) + NEXT_EVENT_LOCAL_STRUCT = time.localtime(NEXT_EVENT_UTC_SECONDS + + utc_offset_seconds) # Need later + if COUNTDOWN: # Show NEXT_EVENT_UTC_SECONDS as countdown to event + MINUTES = (NEXT_EVENT_UTC_SECONDS - NOW_UTC_SECONDS) // 60 + STRING = str(MINUTES // 60) + ':' + '{0:0>2}'.format(MINUTES % 60) + else: # Show NEXT_EVENT_UTC_SECONDS in clock time + STRING = hh_mm(NEXT_EVENT_LOCAL_STRUCT) + GROUP[9].text = STRING + XPOS = CENTER_X - (GROUP[9].bounding_box[2] + 6) // 2 + GROUP[8].x = XPOS + if RISEN: # Next event is SET + GROUP[8].text = '\u21A7' # Downwards arrow from bar + GROUP[8].y = EVENT_Y - 2 + print('Sets:', STRING) + else: # Next event is RISE + GROUP[8].text = '\u21A5' # Upwards arrow from bar + GROUP[8].y = EVENT_Y - 1 + print('Rises:', STRING) + GROUP[9].x = XPOS + 6 + GROUP[9].y = EVENT_Y + # Show event time in green if a.m., amber if p.m. + GROUP[8].color = GROUP[9].color = (0x00FF00 if + NEXT_EVENT_LOCAL_STRUCT.tm_hour < 12 + else 0xC04000) + + # Update time (GROUP[6]) and date (GROUP[7]) + NOW_LOCAL_STRUCT = time.localtime() + STRING = hh_mm(NOW_LOCAL_STRUCT) + GROUP[6].text = STRING + GROUP[6].x = CENTER_X - GROUP[6].bounding_box[2] // 2 + GROUP[6].y = TIME_Y + if MONTH_DAY: + STRING = (str(NOW_LOCAL_STRUCT.tm_mon) + '/' + + str(NOW_LOCAL_STRUCT.tm_mday)) + else: + STRING = (str(NOW_LOCAL_STRUCT.tm_mday) + '/' + + str(NOW_LOCAL_STRUCT.tm_mon)) + GROUP[7].text = STRING + GROUP[7].x = CENTER_X - GROUP[7].bounding_box[2] // 2 + GROUP[7].y = TIME_Y + 10 + + DISPLAY.refresh() # Force full repaint (splash screen sometimes sticks) + time.sleep(5) diff --git a/Matrix_Portal_Moon_Clock/fonts/6x10.bdf b/Matrix_Portal/Matrix_Portal_Moon_Clock/fonts/6x10.bdf old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/fonts/6x10.bdf rename to Matrix_Portal/Matrix_Portal_Moon_Clock/fonts/6x10.bdf diff --git a/Matrix_Portal_Moon_Clock/fonts/helvB12.bdf b/Matrix_Portal/Matrix_Portal_Moon_Clock/fonts/helvB12.bdf old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/fonts/helvB12.bdf rename to Matrix_Portal/Matrix_Portal_Moon_Clock/fonts/helvB12.bdf diff --git a/Matrix_Portal_Moon_Clock/fonts/helvR10.bdf b/Matrix_Portal/Matrix_Portal_Moon_Clock/fonts/helvR10.bdf old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/fonts/helvR10.bdf rename to Matrix_Portal/Matrix_Portal_Moon_Clock/fonts/helvR10.bdf diff --git a/Matrix_Portal_Moon_Clock/moon/moon00.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon00.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon00.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon00.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon01.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon01.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon01.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon01.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon02.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon02.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon02.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon02.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon03.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon03.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon03.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon03.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon04.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon04.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon04.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon04.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon05.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon05.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon05.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon05.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon06.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon06.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon06.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon06.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon07.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon07.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon07.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon07.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon08.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon08.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon08.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon08.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon09.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon09.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon09.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon09.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon10.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon10.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon10.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon10.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon11.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon11.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon11.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon11.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon12.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon12.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon12.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon12.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon13.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon13.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon13.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon13.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon14.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon14.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon14.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon14.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon15.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon15.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon15.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon15.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon16.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon16.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon16.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon16.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon17.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon17.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon17.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon17.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon18.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon18.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon18.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon18.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon19.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon19.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon19.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon19.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon20.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon20.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon20.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon20.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon21.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon21.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon21.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon21.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon22.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon22.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon22.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon22.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon23.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon23.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon23.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon23.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon24.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon24.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon24.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon24.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon25.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon25.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon25.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon25.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon26.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon26.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon26.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon26.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon27.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon27.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon27.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon27.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon28.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon28.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon28.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon28.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon29.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon29.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon29.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon29.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon30.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon30.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon30.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon30.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon31.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon31.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon31.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon31.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon32.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon32.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon32.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon32.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon33.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon33.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon33.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon33.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon34.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon34.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon34.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon34.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon35.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon35.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon35.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon35.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon36.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon36.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon36.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon36.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon37.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon37.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon37.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon37.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon38.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon38.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon38.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon38.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon39.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon39.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon39.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon39.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon40.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon40.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon40.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon40.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon41.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon41.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon41.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon41.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon42.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon42.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon42.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon42.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon43.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon43.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon43.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon43.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon44.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon44.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon44.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon44.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon45.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon45.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon45.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon45.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon46.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon46.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon46.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon46.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon47.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon47.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon47.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon47.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon48.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon48.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon48.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon48.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon49.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon49.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon49.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon49.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon50.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon50.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon50.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon50.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon51.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon51.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon51.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon51.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon52.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon52.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon52.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon52.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon53.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon53.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon53.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon53.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon54.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon54.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon54.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon54.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon55.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon55.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon55.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon55.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon56.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon56.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon56.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon56.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon57.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon57.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon57.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon57.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon58.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon58.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon58.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon58.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon59.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon59.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon59.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon59.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon60.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon60.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon60.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon60.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon61.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon61.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon61.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon61.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon62.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon62.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon62.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon62.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon63.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon63.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon63.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon63.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon64.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon64.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon64.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon64.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon65.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon65.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon65.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon65.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon66.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon66.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon66.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon66.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon67.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon67.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon67.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon67.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon68.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon68.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon68.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon68.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon69.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon69.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon69.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon69.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon70.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon70.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon70.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon70.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon71.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon71.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon71.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon71.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon72.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon72.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon72.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon72.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon73.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon73.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon73.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon73.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon74.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon74.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon74.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon74.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon75.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon75.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon75.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon75.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon76.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon76.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon76.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon76.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon77.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon77.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon77.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon77.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon78.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon78.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon78.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon78.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon79.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon79.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon79.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon79.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon80.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon80.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon80.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon80.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon81.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon81.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon81.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon81.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon82.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon82.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon82.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon82.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon83.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon83.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon83.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon83.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon84.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon84.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon84.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon84.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon85.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon85.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon85.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon85.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon86.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon86.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon86.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon86.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon87.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon87.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon87.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon87.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon88.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon88.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon88.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon88.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon89.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon89.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon89.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon89.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon90.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon90.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon90.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon90.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon91.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon91.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon91.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon91.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon92.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon92.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon92.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon92.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon93.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon93.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon93.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon93.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon94.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon94.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon94.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon94.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon95.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon95.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon95.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon95.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon96.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon96.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon96.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon96.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon97.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon97.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon97.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon97.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon98.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon98.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon98.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon98.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/moon99.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon99.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/moon99.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/moon99.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/splash-0.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/splash-0.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/splash-0.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/splash-0.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/splash-180.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/splash-180.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/splash-180.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/splash-180.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/splash-270.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/splash-270.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/splash-270.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/splash-270.bmp diff --git a/Matrix_Portal_Moon_Clock/moon/splash-90.bmp b/Matrix_Portal/Matrix_Portal_Moon_Clock/moon/splash-90.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_Moon_Clock/moon/splash-90.bmp rename to Matrix_Portal/Matrix_Portal_Moon_Clock/moon/splash-90.bmp diff --git a/Matrix_Portal_S3_ESPN_API/CircuitPython/code.py b/Matrix_Portal/Matrix_Portal_S3_ESPN_API/CircuitPython/code.py similarity index 100% rename from Matrix_Portal_S3_ESPN_API/CircuitPython/code.py rename to Matrix_Portal/Matrix_Portal_S3_ESPN_API/CircuitPython/code.py diff --git a/Matrix_Portal_S3_ESPN_API/get_team_logos.py b/Matrix_Portal/Matrix_Portal_S3_ESPN_API/get_team_logos.py similarity index 100% rename from Matrix_Portal_S3_ESPN_API/get_team_logos.py rename to Matrix_Portal/Matrix_Portal_S3_ESPN_API/get_team_logos.py diff --git a/Matrix_Portal_S3_Message_Board/Enclosure/3MF_Files.zip b/Matrix_Portal/Matrix_Portal_S3_Message_Board/Enclosure/3MF_Files.zip similarity index 100% rename from Matrix_Portal_S3_Message_Board/Enclosure/3MF_Files.zip rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/Enclosure/3MF_Files.zip diff --git a/Matrix_Portal_S3_Message_Board/Enclosure/CAD_Files.zip b/Matrix_Portal/Matrix_Portal_S3_Message_Board/Enclosure/CAD_Files.zip similarity index 100% rename from Matrix_Portal_S3_Message_Board/Enclosure/CAD_Files.zip rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/Enclosure/CAD_Files.zip diff --git a/Matrix_Portal_S3_Message_Board/Enclosure/STL_Files.zip b/Matrix_Portal/Matrix_Portal_S3_Message_Board/Enclosure/STL_Files.zip similarity index 100% rename from Matrix_Portal_S3_Message_Board/Enclosure/STL_Files.zip rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/Enclosure/STL_Files.zip diff --git a/Matrix_Portal_S3_Message_Board/code.py b/Matrix_Portal/Matrix_Portal_S3_Message_Board/code.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/code.py rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/code.py diff --git a/Matrix_Portal_S3_Message_Board/demo.py b/Matrix_Portal/Matrix_Portal_S3_Message_Board/demo.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/demo.py rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/demo.py diff --git a/Matrix_Portal_S3_Message_Board/fonts/Arial-10.pcf b/Matrix_Portal/Matrix_Portal_S3_Message_Board/fonts/Arial-10.pcf old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/fonts/Arial-10.pcf rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/fonts/Arial-10.pcf diff --git a/Matrix_Portal_S3_Message_Board/fonts/Comic-10.pcf b/Matrix_Portal/Matrix_Portal_S3_Message_Board/fonts/Comic-10.pcf old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/fonts/Comic-10.pcf rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/fonts/Comic-10.pcf diff --git a/Matrix_Portal_S3_Message_Board/fonts/DejaVuSans-10.pcf b/Matrix_Portal/Matrix_Portal_S3_Message_Board/fonts/DejaVuSans-10.pcf old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/fonts/DejaVuSans-10.pcf rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/fonts/DejaVuSans-10.pcf diff --git a/Matrix_Portal_S3_Message_Board/images/adafruit_star.bmp b/Matrix_Portal/Matrix_Portal_S3_Message_Board/images/adafruit_star.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/images/adafruit_star.bmp rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/images/adafruit_star.bmp diff --git a/Matrix_Portal_S3_Message_Board/images/background.bmp b/Matrix_Portal/Matrix_Portal_S3_Message_Board/images/background.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/images/background.bmp rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/images/background.bmp diff --git a/Matrix_Portal_S3_Message_Board/images/logo.bmp b/Matrix_Portal/Matrix_Portal_S3_Message_Board/images/logo.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/images/logo.bmp rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/images/logo.bmp diff --git a/Matrix_Portal_S3_Message_Board/images/maskedblinka.bmp b/Matrix_Portal/Matrix_Portal_S3_Message_Board/images/maskedblinka.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/images/maskedblinka.bmp rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/images/maskedblinka.bmp diff --git a/Matrix_Portal_S3_Message_Board/images/maskedstar.bmp b/Matrix_Portal/Matrix_Portal_S3_Message_Board/images/maskedstar.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/images/maskedstar.bmp rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/images/maskedstar.bmp diff --git a/Matrix_Portal_S3_Message_Board/lib/messageboard/__init__.py b/Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/lib/messageboard/__init__.py rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/__init__.py diff --git a/Matrix_Portal_S3_Message_Board/lib/messageboard/animations/__init__.py b/Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/animations/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/lib/messageboard/animations/__init__.py rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/animations/__init__.py diff --git a/Matrix_Portal_S3_Message_Board/lib/messageboard/animations/loop.py b/Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/animations/loop.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/lib/messageboard/animations/loop.py rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/animations/loop.py diff --git a/Matrix_Portal_S3_Message_Board/lib/messageboard/animations/scroll.py b/Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/animations/scroll.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/lib/messageboard/animations/scroll.py rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/animations/scroll.py diff --git a/Matrix_Portal_S3_Message_Board/lib/messageboard/animations/split.py b/Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/animations/split.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/lib/messageboard/animations/split.py rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/animations/split.py diff --git a/Matrix_Portal_S3_Message_Board/lib/messageboard/animations/static.py b/Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/animations/static.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/lib/messageboard/animations/static.py rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/animations/static.py diff --git a/Matrix_Portal_S3_Message_Board/lib/messageboard/doublebuffer.py b/Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/doublebuffer.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/lib/messageboard/doublebuffer.py rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/doublebuffer.py diff --git a/Matrix_Portal_S3_Message_Board/lib/messageboard/fontpool.py b/Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/fontpool.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/lib/messageboard/fontpool.py rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/fontpool.py diff --git a/Matrix_Portal_S3_Message_Board/lib/messageboard/message.py b/Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/message.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_Message_Board/lib/messageboard/message.py rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/lib/messageboard/message.py diff --git a/Matrix_Portal_S3_Message_Board/settings.toml b/Matrix_Portal/Matrix_Portal_S3_Message_Board/settings.toml similarity index 100% rename from Matrix_Portal_S3_Message_Board/settings.toml rename to Matrix_Portal/Matrix_Portal_S3_Message_Board/settings.toml diff --git a/Matrix_Portal_S3_SMS_Scroller/Matrix Portal SMS Fonts.zip b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/Matrix Portal SMS Fonts.zip similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/Matrix Portal SMS Fonts.zip rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/Matrix Portal SMS Fonts.zip diff --git a/Matrix_Portal_S3_SMS_Scroller/code.py b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/code.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/code.py rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/code.py diff --git a/Matrix_Portal_S3_SMS_Scroller/fonts/Arial-10.pcf b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/fonts/Arial-10.pcf old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/fonts/Arial-10.pcf rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/fonts/Arial-10.pcf diff --git a/Matrix_Portal_S3_SMS_Scroller/fonts/Arial-15.pcf b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/fonts/Arial-15.pcf old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/fonts/Arial-15.pcf rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/fonts/Arial-15.pcf diff --git a/Matrix_Portal_S3_SMS_Scroller/fonts/Comic-10.pcf b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/fonts/Comic-10.pcf old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/fonts/Comic-10.pcf rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/fonts/Comic-10.pcf diff --git a/Matrix_Portal_S3_SMS_Scroller/fonts/DejaVuSans-10.pcf b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/fonts/DejaVuSans-10.pcf old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/fonts/DejaVuSans-10.pcf rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/fonts/DejaVuSans-10.pcf diff --git a/Matrix_Portal_S3_SMS_Scroller/fonts/Sofia-Regular-15.pcf b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/fonts/Sofia-Regular-15.pcf old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/fonts/Sofia-Regular-15.pcf rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/fonts/Sofia-Regular-15.pcf diff --git a/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/__init__.py b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/lib/messageboard/__init__.py rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/__init__.py diff --git a/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/__init__.py b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/__init__.py rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/__init__.py diff --git a/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/loop.py b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/loop.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/loop.py rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/loop.py diff --git a/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/scroll.py b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/scroll.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/scroll.py rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/scroll.py diff --git a/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/scroll.py.sb-9f345cee-oxZXpM b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/scroll.py.sb-9f345cee-oxZXpM old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/scroll.py.sb-9f345cee-oxZXpM rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/scroll.py.sb-9f345cee-oxZXpM diff --git a/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/split.py b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/split.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/split.py rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/split.py diff --git a/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/static.py b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/static.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/static.py rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/animations/static.py diff --git a/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/doublebuffer.py b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/doublebuffer.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/lib/messageboard/doublebuffer.py rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/doublebuffer.py diff --git a/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/fontpool.py b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/fontpool.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/lib/messageboard/fontpool.py rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/fontpool.py diff --git a/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/message.py b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/message.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/lib/messageboard/message.py rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/lib/messageboard/message.py diff --git a/Matrix_Portal_S3_SMS_Scroller/settings.toml b/Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/settings.toml old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_SMS_Scroller/settings.toml rename to Matrix_Portal/Matrix_Portal_S3_SMS_Scroller/settings.toml diff --git a/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/cloudy.bmp b/Matrix_Portal/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/cloudy.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/cloudy.bmp rename to Matrix_Portal/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/cloudy.bmp diff --git a/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/moon.bmp b/Matrix_Portal/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/moon.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/moon.bmp rename to Matrix_Portal/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/moon.bmp diff --git a/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/rain.bmp b/Matrix_Portal/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/rain.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/rain.bmp rename to Matrix_Portal/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/rain.bmp diff --git a/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/snowy.bmp b/Matrix_Portal/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/snowy.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/snowy.bmp rename to Matrix_Portal/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/snowy.bmp diff --git a/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/sunny.bmp b/Matrix_Portal/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/sunny.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/sunny.bmp rename to Matrix_Portal/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/sunny.bmp diff --git a/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/thunder.bmp b/Matrix_Portal/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/thunder.bmp old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/thunder.bmp rename to Matrix_Portal/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/Images/thunder.bmp diff --git a/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/code.py b/Matrix_Portal/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/code.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/code.py rename to Matrix_Portal/Matrix_Portal_S3_itsaSNAP_Daily_Forecast_Display/code.py diff --git a/Matrix_Portal_Scoreboard/code.py b/Matrix_Portal/Matrix_Portal_Scoreboard/code.py similarity index 100% rename from Matrix_Portal_Scoreboard/code.py rename to Matrix_Portal/Matrix_Portal_Scoreboard/code.py diff --git a/Matrix_Portal_Tip_Jar/bmps.zip b/Matrix_Portal/Matrix_Portal_Tip_Jar/bmps.zip similarity index 100% rename from Matrix_Portal_Tip_Jar/bmps.zip rename to Matrix_Portal/Matrix_Portal_Tip_Jar/bmps.zip diff --git a/Matrix_Portal/Matrix_Portal_Tip_Jar/code.py b/Matrix_Portal/Matrix_Portal_Tip_Jar/code.py new file mode 100644 index 000000000..3547b999f --- /dev/null +++ b/Matrix_Portal/Matrix_Portal_Tip_Jar/code.py @@ -0,0 +1,140 @@ +# SPDX-FileCopyrightText: 2020 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-FileCopyrightText: 2020 Erin St Blaine for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +Motion-sensing Animation Example using the Matrix Portal and 64 x 32 LED matrix display +Written by Melissa LeBlanc-Williams and Erin St Blaine for Adafruit Industries +A VL6180X sensor causes a sprite sheet animation to play +""" + +import time +import os +import board +import busio +import displayio +from digitalio import DigitalInOut, Pull +from adafruit_matrixportal.matrix import Matrix +from adafruit_debouncer import Debouncer +import adafruit_vl6180x +# pylint: disable=global-statement +# Create I2C bus. +i2c = busio.I2C(board.SCL, board.SDA) + +# Create sensor instance. +sensor = adafruit_vl6180x.VL6180X(i2c) + +SPRITESHEET_FOLDER = "/bmps" +DEFAULT_FRAME_DURATION = 0.1 # 100ms +ANIMATION_DURATION = 5 +AUTO_ADVANCE_LOOPS = 1 +THRESHOLD = 20 + +# --- Display setup --- +matrix = Matrix(bit_depth=4) +sprite_group = displayio.Group() +matrix.display.root_group = sprite_group + +# --- Button setup --- +pin_down = DigitalInOut(board.BUTTON_DOWN) +pin_down.switch_to_input(pull=Pull.UP) +button_down = Debouncer(pin_down) +pin_up = DigitalInOut(board.BUTTON_UP) +pin_up.switch_to_input(pull=Pull.UP) +button_up = Debouncer(pin_up) + +AUTO_ADVANCE = True + +file_list = sorted( + [ + f + for f in os.listdir(SPRITESHEET_FOLDER) + if (f.endswith(".bmp") and not f.startswith(".")) + ] +) + +if len(file_list) == 0: + raise RuntimeError("No images found") + +CURRENT_IMAGE = None +CURRENT_FRAME = 0 +CURRENT_LOOP = 0 +FRAME_COUNT = 0 +FRAME_DURATION = DEFAULT_FRAME_DURATION + + +def load_image(): + """ + Load an image as a sprite + """ + # pylint: disable=global-statement + global CURRENT_FRAME, CURRENT_LOOP, FRAME_COUNT, FRAME_DURATION + while sprite_group: + sprite_group.pop() + + filename = SPRITESHEET_FOLDER + "/" + file_list[CURRENT_IMAGE] + + bitmap = displayio.OnDiskBitmap(filename) + sprite = displayio.TileGrid( + bitmap, + pixel_shader=bitmap.pixel_shader, + tile_width=bitmap.width, + tile_height=matrix.display.height, + ) + + sprite_group.append(sprite) + + FRAME_COUNT = int(bitmap.height / matrix.display.height) + FRAME_DURATION = DEFAULT_FRAME_DURATION + CURRENT_FRAME = 0 + CURRENT_LOOP = 0 + + +def advance_image(): + """ + Advance to the next image in the list and loop back at the end + """ + # pylint: disable=global-statement + global CURRENT_IMAGE + if CURRENT_IMAGE is not None: + CURRENT_IMAGE += 1 + if CURRENT_IMAGE is None or CURRENT_IMAGE >= len(file_list): + CURRENT_IMAGE = 0 + load_image() + +def advance_frame(): + """Advance the frame""" + # pylint: disable=global-statement + global CURRENT_FRAME, CURRENT_LOOP + CURRENT_FRAME = CURRENT_FRAME + 1 + if CURRENT_FRAME >= FRAME_COUNT: + CURRENT_FRAME = 0 + CURRENT_LOOP = CURRENT_LOOP + 1 + sprite_group[0][0] = CURRENT_FRAME + +def load_list_image(item): + """Load the list item""" + global CURRENT_IMAGE + CURRENT_IMAGE = item + load_image() + +def load_tipsy(): + """Load the .bmp image""" + load_list_image(1) + +def play_thankyou(): + """load the thank you image""" + load_list_image(0) + while CURRENT_LOOP <= AUTO_ADVANCE_LOOPS: + advance_frame() + time.sleep(FRAME_DURATION) + + +advance_image() + +while True: + if sensor.range < THRESHOLD: + play_thankyou() + else: + load_tipsy() diff --git a/Matrix_Portal_itsaSNAP_Apple_Health_Display/code.py b/Matrix_Portal/Matrix_Portal_itsaSNAP_Apple_Health_Display/code.py old mode 100755 new mode 100644 similarity index 100% rename from Matrix_Portal_itsaSNAP_Apple_Health_Display/code.py rename to Matrix_Portal/Matrix_Portal_itsaSNAP_Apple_Health_Display/code.py diff --git a/Matrix_Portal/README.md b/Matrix_Portal/README.md new file mode 100644 index 000000000..c5b017b23 --- /dev/null +++ b/Matrix_Portal/README.md @@ -0,0 +1,6 @@ +## Matrix Portal Project Subdirectory + +Adafruit Learning System Guides relating to the the Matrix Portal should be +placed in this folder (rather than the top level Learning System repo). + +Please support Open Source software from Adafruit by buying Adafruit hardware \ No newline at end of file diff --git a/Matrix_Portal_Learn_Stats/code.py b/Matrix_Portal_Learn_Stats/code.py deleted file mode 100755 index d8f694f8c..000000000 --- a/Matrix_Portal_Learn_Stats/code.py +++ /dev/null @@ -1,115 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -import time -from random import randrange -import board -import terminalio -from adafruit_matrixportal.matrixportal import MatrixPortal - -# --- Data Setup --- # -# Number of guides to fetch and display from the Adafruit Learning System -DISPLAY_NUM_GUIDES = 5 -# Data source URL -DATA_SOURCE = ( - "https://learn.adafruit.com/api/guides/new.json?count=%d" % DISPLAY_NUM_GUIDES -) -TITLE_DATA_LOCATION = ["guides"] - -matrixportal = MatrixPortal( - url=DATA_SOURCE, - json_path=TITLE_DATA_LOCATION, - status_neopixel=board.NEOPIXEL, -) - -# --- Display Setup --- # - -# Colors for guide name -colors = [0xFFA500, 0xFFFF00, 0x008000, 0x0000FF, 0x4B0082, 0xEE82EE] - -# Delay for scrolling the text -SCROLL_DELAY = 0.03 - -FONT = "/IBMPlexMono-Medium-24_jep.bdf" - -# Learn guide count (ID = 0) -matrixportal.add_text( - text_font=FONT, - text_position=( - (matrixportal.graphics.display.width // 12) - 1, - (matrixportal.graphics.display.height // 2) - 8, - ), - text_color=0x800000, -) -matrixportal.preload_font("0123456789") - -# Learn guide title (ID = 1) -matrixportal.add_text( - text_font=terminalio.FONT, - text_position=(2, 25), - text_color=0x000080, - scrolling=True, -) - - -def get_guide_info(index): - """Parses JSON data returned by the DATA_SOURCE - to obtain the ALS guide title and number of guides and - sets the text labels. - :param int index: Guide index to display - - """ - if index > DISPLAY_NUM_GUIDES: - raise RuntimeError("Provided index may not be larger than DISPLAY_NUM_GUIDES.") - print("Obtaining guide info for guide %d..." % index) - - # Traverse JSON data for title - guide_count = matrixportal.network.json_traverse(als_data.json(), ["guide_count"]) - - # Set guide count - matrixportal.set_text(guide_count, 0) - - guides = matrixportal.network.json_traverse(als_data.json(), TITLE_DATA_LOCATION) - guide_title = guides[index]["guide"]["title"] - print("Guide Title", guide_title) - - # Select color for title text - color_index = randrange(0, len(colors)) - - # Set the title text color - matrixportal.set_text_color(colors[color_index], 1) - - # Set the title text - matrixportal.set_text(guide_title, 1) - - -refresh_time = None -guide_idx = 0 -prv_hour = 0 -while True: - if (not refresh_time) or (time.monotonic() - refresh_time) > 900: - try: - print("obtaining time from adafruit.io server...") - matrixportal.get_local_time() - refresh_time = time.monotonic() - except RuntimeError as e: - print("Unable to obtain time from Adafruit IO, retrying - ", e) - continue - - if time.localtime()[3] != prv_hour: - print("New Hour, fetching new data...") - # Fetch and store guide info response - als_data = matrixportal.network.fetch(DATA_SOURCE) - prv_hour = time.localtime()[3] - - # Cycle through guides retrieved - if guide_idx < DISPLAY_NUM_GUIDES: - get_guide_info(guide_idx) - - # Scroll the scrollable text block - matrixportal.scroll_text(SCROLL_DELAY) - guide_idx += 1 - else: - guide_idx = 0 - time.sleep(0.05) diff --git a/Matrix_Portal_Moon_Clock/code.py b/Matrix_Portal_Moon_Clock/code.py deleted file mode 100755 index 415e98152..000000000 --- a/Matrix_Portal_Moon_Clock/code.py +++ /dev/null @@ -1,484 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Phillip Burgess for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -""" -MOON PHASE CLOCK for Adafruit Matrix Portal: displays current time, lunar -phase and time of next moonrise or moonset. Requires WiFi internet access -and Adafruit IO user account (basic account is free, just needs registration). - -Written by Phil 'PaintYourDragon' Burgess for Adafruit Industries. -MIT license, all text above must be included in any redistribution. - -BDF fonts from the X.Org project. Startup 'splash' images should not be -included in derivative projects, thanks. Tall splash images licensed from -123RF.com, wide splash images used with permission of artist Lew Lashmit -(viergacht@gmail.com). Rawr! -""" - -# pylint: disable=import-error -import gc -import time -import math -import board -import busio -import displayio -from rtc import RTC -from adafruit_matrixportal.network import Network -from adafruit_matrixportal.matrix import Matrix -from adafruit_bitmap_font import bitmap_font -import adafruit_display_text.label -import adafruit_lis3dh - -try: - from secrets import secrets -except ImportError: - print('WiFi secrets are kept in secrets.py, please add them there!') - raise - -# CONFIGURABLE SETTINGS ---------------------------------------------------- - -TWELVE_HOUR = True # If set, use 12-hour time vs 24-hour (e.g. 3:00 vs 15:00) -COUNTDOWN = False # If set, show time to (vs time of) next rise/set event -MONTH_DAY = True # If set, use MM/DD vs DD/MM (e.g. 31/12 vs 12/31) -BITPLANES = 6 # Ideally 6, but can set lower if RAM is tight - -# Moon API requres valid User-Agent header. Only maintainer should edit this. -HEADERS = { "User-Agent" : "AdafruitMoonClock/1.1 support@adafruit.com" } - -# SOME UTILITY FUNCTIONS AND CLASSES --------------------------------------- - -# Notes to Future Self on timekeeping: times are expressed in so many -# formats throughout this code, a variable naming system is used: local -# times (i.e. in clock's present geographic time zone) will have _local -# in their variable name, while UTC times (aka Greenwich or Zulu time) -# will have _utc. Types are also explicitly stated: strings (e.g. -# "2023-07-20T08:37-07:00") will have _string in the variable name, -# struct_time objects will have _struct, and integer "UNIX time" epoch -# seconds will have _seconds. Conversions (offset is signed, e.g. -700): -# Convert UTC to local time: add UTC offset; local = utc + offset -# Convert local to UTC time: subtract UTC offset; utc = local - offset - -def update_system_time(): - """ Update system clock date/time from Adafruit IO. Credentials and time - zone are in secrets.py. See http://worldtimeapi.org/api/timezone for - list of time zones. If missing, will attempt using IP geolocation. - Returns present local (not UTC) time as a struct_time and UTC offset - as string "sHH:MM". This may throw an exception on get_local_time(), - it is NOT CAUGHT HERE, should be handled in the calling code because - different behaviors may be needed for some situations (e.g. - reschedule later). - """ - local_time_string = NETWORK.get_local_time() # Sets RTC() time, but also - elements = local_time_string.split(" ") # returns server response - utc_offset = int(elements[-2]) # Format shHMM, e.g. -700 = -7 hr, 0 min - # Pad UTC format shHMM to sHH:MM as needed for moon API 3.0 - utc_offset_string = "{:+03d}:{:02d}".format(utc_offset // 100, # Hours - abs(utc_offset) % 100) # Mins - return RTC().datetime, utc_offset_string - - -def hh_mm(time_struct): - """ Used for clock display elements, not for delta-time calculations. - Given a struct_time, return a string as H:MM or HH:MM, either 12- - or 24-hour style depending on global TWELVE_HOUR setting. This is - ONLY for 'clock time,' NOT for countdown time, which is handled - separately in the one spot where it's needed. - """ - if TWELVE_HOUR: - if time_struct.tm_hour > 12: - hour_string = str(time_struct.tm_hour - 12) # 13-23 -> 1-11 (pm) - elif time_struct.tm_hour > 0: - hour_string = str(time_struct.tm_hour) # 1-12 - else: - hour_string = '12' # 0 -> 12 (am) - else: - hour_string = '{0:0>2}'.format(time_struct.tm_hour) - return hour_string + ':' + '{0:0>2}'.format(time_struct.tm_min) - - -def parse_time_to_utc_seconds(time_local_string): - """ Given a string of YYYY-MM-DDTHH:MMsHH:MM or YYYY-MM-DDTHH:MM:SSZ - return equivalent UTC epoch seconds. - """ - # This could be UTC or local time, don't know yet, so no tag in var name - date_time = time_local_string.split('T') # Separate into date and time - date_str = date_time[0].split('-') # Separate date into Y/M/D - time_str = date_time[1] - # Moon API always puts 00 seconds for interval, while rise/set times - # include no seconds value. Thus, only first two values are referenced: - hour = int(time_str[0:2]) # HH:MM as encoded in string, - minute = int(time_str[3:5]) # still could be UTC or local... - if time_str[-1] != 'Z': # If not "Zulu time" (UTC), is local, so: - hour -= int(time_str[-6:-3]) # convert local to UTC - minute -= int(time_str[-2:]) - return time.mktime(time.struct_time((int(date_str[0]), - int(date_str[1]), - int(date_str[2]), - hour, - minute, - 0, -1, -1, False))) - - -# pylint: disable=too-few-public-methods -class MoonData(): - """ Class holding lunar data for a given 24-hour period. App uses two - of these -- one for the current day, and one for the following day, - then some interpolations and such can be made. Elements include: - age : Moon phase 'age' at start of period, expressed - from 0.0 (new moon) through 0.5 (full moon) to - 1.0 (next new moon). - start_utc_seconds : Epoch time at start of period, UTC - end_utc_seconds : Epoch time at end of period, " - rise_utc_seconds : Epoch time of moon rise within this 24-hour period - set_utc_seconds : Epoch time of moon set within this 24-hour period - """ - def __init__(self, datetime_local_struct, days_ahead, utc_offset_string): - """ Initialize MoonData elements (see above) given a struct_time, - days to skip ahead (typically 0 or 1), and a UTC offset (as a - string) and a query to the MET Norway Sunrise API (also provides - lunar data), documented at: - https://docs.api.met.no/doc/sunrise/celestial.html - """ - if days_ahead > 0: - # Can't change attributes in struct_time, need to create a new - # one which will roll the date ahead as needed. Convert to local - # epoch seconds and back for the offset to work. :/ - datetime_local_struct = time.localtime( - time.mktime(time.struct_time(( - datetime_local_struct.tm_year, - datetime_local_struct.tm_mon, - datetime_local_struct.tm_mday + days_ahead, - datetime_local_struct.tm_hour, - datetime_local_struct.tm_min, - datetime_local_struct.tm_sec, - -1, -1, -1)))) - # URL does not contain local or UTC time, only date. strftime() is - # not available in CircuitPython, manual conversion to time string - # is needed. Response is moon data for a 24-hour period, based on - # longitude and requested date. Some values within are UTC time, - # others are local. Anything we parse out of this will be converted - # to UTC epoch seconds, period. - url = ('https://api.met.no/weatherapi/sunrise/3.0/moon?lat=' + - str(LATITUDE) + '&lon=' + str(LONGITUDE) + - '&date=' + str(datetime_local_struct.tm_year) + '-' + - '{0:0>2}'.format(datetime_local_struct.tm_mon) + '-' + - '{0:0>2}'.format(datetime_local_struct.tm_mday) + - '&offset=' + utc_offset_string) - print('Fetching moon data via', url) - # pylint: disable=bare-except - for _ in range(5): # Retries - try: - moon_data = NETWORK.fetch_data(url, - json_path=[], - headers = HEADERS) - properties = moon_data['properties'] - # 0 = new moon, 90 = Q1, 180 = full moon, 270 = LQ - self.age = float(properties['moonphase']) / 360 - interval = moon_data['when']['interval'] - self.start_utc_seconds = parse_time_to_utc_seconds(interval[0]) - self.end_utc_seconds = parse_time_to_utc_seconds(interval[1]) - # Thx user sandorcourane for the properties fixes! - if properties['moonrise']['time'] is not None: - self.rise_utc_seconds = parse_time_to_utc_seconds( - properties['moonrise']['time']) - else: - self.rise_utc_seconds = None - if properties['moonset']['time'] is not None: - self.set_utc_seconds = parse_time_to_utc_seconds( - properties['moonset']['time']) - else: - self.set_utc_seconds = None - return # Success! - except: - # Moon server error (maybe), try again after 15 seconds. - # (Might be a memory error, that should be handled different) - time.sleep(15) - - -# ONE-TIME INITIALIZATION -------------------------------------------------- - -MATRIX = Matrix(bit_depth=BITPLANES) -DISPLAY = MATRIX.display -ACCEL = adafruit_lis3dh.LIS3DH_I2C(busio.I2C(board.SCL, board.SDA), - address=0x19) -_ = ACCEL.acceleration # Dummy reading to blow out any startup residue -time.sleep(0.1) -DISPLAY.rotation = (int(((math.atan2(-ACCEL.acceleration.y, - -ACCEL.acceleration.x) + math.pi) / - (math.pi * 2) + 0.875) * 4) % 4) * 90 - -LARGE_FONT = bitmap_font.load_font('/fonts/helvB12.bdf') -SMALL_FONT = bitmap_font.load_font('/fonts/helvR10.bdf') -SYMBOL_FONT = bitmap_font.load_font('/fonts/6x10.bdf') -LARGE_FONT.load_glyphs('0123456789:') -SMALL_FONT.load_glyphs('0123456789:/.%') -SYMBOL_FONT.load_glyphs('\u21A5\u21A7') - -# Display group is set up once, then we just shuffle items around later. -# Order of creation here determines their stacking order. -GROUP = displayio.Group() - -# Element 0 is a stand-in item, later replaced with the moon phase bitmap -# pylint: disable=bare-except -try: - FILENAME = 'moon/splash-' + str(DISPLAY.rotation) + '.bmp' - - # CircuitPython 6 & 7 compatible - BITMAP = displayio.OnDiskBitmap(open(FILENAME, 'rb')) - TILE_GRID = displayio.TileGrid( - BITMAP, - pixel_shader=getattr(BITMAP, 'pixel_shader', displayio.ColorConverter()) - ) - - # # CircuitPython 7+ compatible - # BITMAP = displayio.OnDiskBitmap(FILENAME) - # TILE_GRID = displayio.TileGrid(BITMAP, pixel_shader=BITMAP.pixel_shader) - - GROUP.append(TILE_GRID) -except: - GROUP.append(adafruit_display_text.label.Label(SMALL_FONT, color=0xFF0000, - text='AWOO')) - GROUP[0].x = (DISPLAY.width - GROUP[0].bounding_box[2] + 1) // 2 - GROUP[0].y = DISPLAY.height // 2 - 1 - -# Elements 1-4 are an outline around the moon percentage -- text labels -# offset by 1 pixel up/down/left/right. Initial position is off the matrix, -# updated on first refresh. Initial text value must be long enough for -# longest anticipated string later. -for i in range(4): - GROUP.append(adafruit_display_text.label.Label(SMALL_FONT, color=0, - text='99.9%', y=-99)) -# Element 5 is the moon percentage (on top of the outline labels) -GROUP.append(adafruit_display_text.label.Label(SMALL_FONT, color=0xFFFF00, - text='99.9%', y=-99)) -# Element 6 is the current time -GROUP.append(adafruit_display_text.label.Label(LARGE_FONT, color=0x808080, - text='12:00', y=-99)) -# Element 7 is the current date -GROUP.append(adafruit_display_text.label.Label(SMALL_FONT, color=0x808080, - text='12/31', y=-99)) -# Element 8 is a symbol indicating next rise or set -GROUP.append(adafruit_display_text.label.Label(SYMBOL_FONT, color=0x00FF00, - text='x', y=-99)) -# Element 9 is the time of (or time to) next rise/set event -GROUP.append(adafruit_display_text.label.Label(SMALL_FONT, color=0x00FF00, - text='12:00', y=-99)) -DISPLAY.root_group = GROUP - -NETWORK = Network(status_neopixel=board.NEOPIXEL, debug=False) -NETWORK.connect() - -# LATITUDE, LONGITUDE, TIMEZONE are set up once, constant over app lifetime - -# Fetch latitude/longitude from secrets.py. If not present, use -# IP geolocation. This only needs to be done once, at startup! -try: - LATITUDE = secrets['latitude'] - LONGITUDE = secrets['longitude'] - print('Using stored geolocation: ', LATITUDE, LONGITUDE) -except KeyError: - LATITUDE, LONGITUDE = ( - NETWORK.fetch_data('http://www.geoplugin.net/json.gp', - json_path=[['geoplugin_latitude'], - ['geoplugin_longitude']])) - print('Using IP geolocation: ', LATITUDE, LONGITUDE) - -# Set initial clock time, also fetch initial UTC offset while -# here (NOT stored in secrets.py as it may change with DST). -# pylint: disable=bare-except -try: - DATETIME_LOCAL_STRUCT, UTC_OFFSET_STRING = update_system_time() -except: - DATETIME_LOCAL_STRUCT, UTC_OFFSET_STRING = time.localtime(), '+00:00' -LAST_SYNC_LOCAL_SECONDS = time.mktime(DATETIME_LOCAL_STRUCT) - -# Poll server for moon data for current 24-hour period and +24 ahead -PERIOD = [] -for DAY in range(2): # Today, tomorrow - PERIOD.append(MoonData(DATETIME_LOCAL_STRUCT, DAY, UTC_OFFSET_STRING)) -# PERIOD[0] is a current 24-hour time period we're in. PERIOD[1] is the -# 24 hours following that. Start/end time thresholds vary by longitude. -# Any values within the object are expressed in UTC seconds. Data is -# shifted down and new data fetched as days expire. Thought we might need a -# PERIOD[2] for certain circumstances but it appears not, that's changed -# easily enough if needed. - - -# MAIN LOOP ---------------------------------------------------------------- - -while True: - gc.collect() - NOW_LOCAL_SECONDS = time.time() # Current local epoch time in seconds - - # Sync with time server every ~3 hours - if NOW_LOCAL_SECONDS - LAST_SYNC_LOCAL_SECONDS > 3 * 60 * 60: - try: - DATETIME_LOCAL_STRUCT, UTC_OFFSET_STRING = update_system_time() - LAST_SYNC_LOCAL_SECONDS = time.mktime(DATETIME_LOCAL_STRUCT) - continue # Time may have changed; refresh NOW_LOCAL_SECONDS value - except: - # update_system_time() can throw an exception if time server doesn't - # respond. That's OK, keep running with our current time, and - # push sync time ahead to retry in 30 minutes (don't overwhelm - # the server with repeated queries). - LAST_SYNC_LOCAL_SECONDS += 30 * 60 # 30 minutes -> seconds - - # NOW_LOCAL_SECONDS and DATETIME_LOCAL_STRUCT are local time, while all - # moon properties are UTC. Convert 'now' to UTC seconds... - # UTC_OFFSET_STRING is a string, like +HH:MM. Convert to integer seconds: - hhmm = UTC_OFFSET_STRING.split(':') - utc_offset_seconds = ((int(hhmm[0]) * 60 + int(hhmm[1])) * 60) - NOW_UTC_SECONDS = NOW_LOCAL_SECONDS - utc_offset_seconds - - # If PERIOD has expired, move data down and fetch new +24-hour data - if NOW_UTC_SECONDS >= PERIOD[0].end_utc_seconds: - PERIOD[0] = PERIOD[1] - PERIOD[1] = MoonData(time.localtime(), 1, UTC_OFFSET_STRING) - - # Determine weighting of tomorrow's phase vs today's, using current time - RATIO = ((NOW_UTC_SECONDS - PERIOD[0].start_utc_seconds) / - (PERIOD[1].start_utc_seconds - PERIOD[0].start_utc_seconds)) - # Determine moon phase 'age' - # 0.0 = new moon - # 0.25 = first quarter - # 0.5 = full moon - # 0.75 = last quarter - # 1.0 = new moon - if PERIOD[0].age < PERIOD[1].age: - AGE = (PERIOD[0].age + - (PERIOD[1].age - PERIOD[0].age) * RATIO) % 1.0 - else: # Handle age wraparound (1.0 -> 0.0) - # If tomorrow's age is less than today's, it indicates a new moon - # crossover. Add 1 to tomorrow's age when computing age delta. - AGE = (PERIOD[0].age + - (PERIOD[1].age + 1 - PERIOD[0].age) * RATIO) % 1.0 - - # AGE can be used for direct lookup to moon bitmap (0 to 99) -- these - # images are pre-rendered for a linear timescale (solar terminator moves - # nonlinearly across sphere). - FRAME = int(AGE * 100) % 100 # Bitmap 0 to 99 - - # Then use some trig to get percentage lit - if AGE <= 0.5: # New -> first quarter -> full - PERCENT = (1 - math.cos(AGE * 2 * math.pi)) * 50 - else: # Full -> last quarter -> new - PERCENT = (1 + math.cos((AGE - 0.5) * 2 * math.pi)) * 50 - - # Find next rise/set event, complicated by the fact that some 24-hour - # periods might not have one or the other (but usually do) due to the - # Moon rising ~50 mins later each day. This uses a brute force approach, - # working through the time periods to locate rise/set events that - # A) exist in that 24-hour period (are not None), B) are still in - # the future, and C) are closer than the last guess. What's left at the - # end is the next rise or set time, and a flag whether the moon's - # currently risen or not. - NEXT_EVENT_UTC_SECONDS = NOW_UTC_SECONDS + 300000 # Way future - for DAY in PERIOD: - if (DAY.rise_utc_seconds and - NOW_UTC_SECONDS < DAY.rise_utc_seconds < NEXT_EVENT_UTC_SECONDS): - NEXT_EVENT_UTC_SECONDS = DAY.rise_utc_seconds - RISEN = False # Current moon state; next event is inverse - if (DAY.set_utc_seconds and - NOW_UTC_SECONDS < DAY.set_utc_seconds < NEXT_EVENT_UTC_SECONDS): - NEXT_EVENT_UTC_SECONDS = DAY.set_utc_seconds - RISEN = True - - if DISPLAY.rotation in (0, 180): # Horizontal 'landscape' orientation - CENTER_X = 48 # Text along right - MOON_Y = 0 # Moon at left - TIME_Y = 6 # Time at top right - EVENT_Y = 26 # Rise/set at bottom right - else: # Vertical 'portrait' orientation - CENTER_X = 16 # Text down center - if RISEN: - MOON_Y = 0 # Moon at top - EVENT_Y = 38 # Rise/set in middle - TIME_Y = 49 # Time/date at bottom - else: - TIME_Y = 6 # Time/date at top - EVENT_Y = 26 # Rise/set in middle - MOON_Y = 32 # Moon at bottom - - print() - - # Update moon image (GROUP[0]) - FILENAME = 'moon/moon' + '{0:0>2}'.format(FRAME) + '.bmp' - - # CircuitPython 6 & 7 compatible - # BITMAP = displayio.OnDiskBitmap(open(FILENAME, 'rb')) - # TILE_GRID = displayio.TileGrid( - # BITMAP, - # pixel_shader=getattr(BITMAP, 'pixel_shader', - # displayio.ColorConverter()) - # ) - - # CircuitPython 7+ compatible - BITMAP = displayio.OnDiskBitmap(FILENAME) - TILE_GRID = displayio.TileGrid(BITMAP, pixel_shader=BITMAP.pixel_shader) - - TILE_GRID.x = 0 - TILE_GRID.y = MOON_Y - GROUP[0] = TILE_GRID - - # Update percent value (5 labels: GROUP[1-4] for outline, [5] for text) - if PERCENT >= 99.95: - STRING = '100%' - else: - STRING = '{:.1f}'.format(PERCENT + 0.05) + '%' - print(NOW_UTC_SECONDS, STRING, 'full') - # Set element 5 first, use its size and position for setting others - GROUP[5].text = STRING - GROUP[5].x = 16 - GROUP[5].bounding_box[2] // 2 - GROUP[5].y = MOON_Y + 16 - for _ in range(1, 5): - GROUP[_].text = GROUP[5].text - GROUP[1].x, GROUP[1].y = GROUP[5].x, GROUP[5].y - 1 # Up 1 pixel - GROUP[2].x, GROUP[2].y = GROUP[5].x - 1, GROUP[5].y # Left - GROUP[3].x, GROUP[3].y = GROUP[5].x + 1, GROUP[5].y # Right - GROUP[4].x, GROUP[4].y = GROUP[5].x, GROUP[5].y + 1 # Down - - # Update next-event time (GROUP[8] and [9]) - NEXT_EVENT_LOCAL_STRUCT = time.localtime(NEXT_EVENT_UTC_SECONDS + - utc_offset_seconds) # Need later - if COUNTDOWN: # Show NEXT_EVENT_UTC_SECONDS as countdown to event - MINUTES = (NEXT_EVENT_UTC_SECONDS - NOW_UTC_SECONDS) // 60 - STRING = str(MINUTES // 60) + ':' + '{0:0>2}'.format(MINUTES % 60) - else: # Show NEXT_EVENT_UTC_SECONDS in clock time - STRING = hh_mm(NEXT_EVENT_LOCAL_STRUCT) - GROUP[9].text = STRING - XPOS = CENTER_X - (GROUP[9].bounding_box[2] + 6) // 2 - GROUP[8].x = XPOS - if RISEN: # Next event is SET - GROUP[8].text = '\u21A7' # Downwards arrow from bar - GROUP[8].y = EVENT_Y - 2 - print('Sets:', STRING) - else: # Next event is RISE - GROUP[8].text = '\u21A5' # Upwards arrow from bar - GROUP[8].y = EVENT_Y - 1 - print('Rises:', STRING) - GROUP[9].x = XPOS + 6 - GROUP[9].y = EVENT_Y - # Show event time in green if a.m., amber if p.m. - GROUP[8].color = GROUP[9].color = (0x00FF00 if - NEXT_EVENT_LOCAL_STRUCT.tm_hour < 12 - else 0xC04000) - - # Update time (GROUP[6]) and date (GROUP[7]) - NOW_LOCAL_STRUCT = time.localtime() - STRING = hh_mm(NOW_LOCAL_STRUCT) - GROUP[6].text = STRING - GROUP[6].x = CENTER_X - GROUP[6].bounding_box[2] // 2 - GROUP[6].y = TIME_Y - if MONTH_DAY: - STRING = (str(NOW_LOCAL_STRUCT.tm_mon) + '/' + - str(NOW_LOCAL_STRUCT.tm_mday)) - else: - STRING = (str(NOW_LOCAL_STRUCT.tm_mday) + '/' + - str(NOW_LOCAL_STRUCT.tm_mon)) - GROUP[7].text = STRING - GROUP[7].x = CENTER_X - GROUP[7].bounding_box[2] // 2 - GROUP[7].y = TIME_Y + 10 - - DISPLAY.refresh() # Force full repaint (splash screen sometimes sticks) - time.sleep(5) diff --git a/Matrix_Portal_Tip_Jar/code.py b/Matrix_Portal_Tip_Jar/code.py deleted file mode 100644 index 609148fbb..000000000 --- a/Matrix_Portal_Tip_Jar/code.py +++ /dev/null @@ -1,150 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Melissa LeBlanc-Williams for Adafruit Industries -# SPDX-FileCopyrightText: 2020 Erin St Blaine for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -""" -Motion-sensing Animation Example using the Matrix Portal and 64 x 32 LED matrix display -Written by Melissa LeBlanc-Williams and Erin St Blaine for Adafruit Industries -A VL6180X sensor causes a sprite sheet animation to play -""" - -import time -import os -import board -import busio -import displayio -from digitalio import DigitalInOut, Pull -from adafruit_matrixportal.matrix import Matrix -from adafruit_debouncer import Debouncer -import adafruit_vl6180x -# pylint: disable=global-statement -# Create I2C bus. -i2c = busio.I2C(board.SCL, board.SDA) - -# Create sensor instance. -sensor = adafruit_vl6180x.VL6180X(i2c) - -SPRITESHEET_FOLDER = "/bmps" -DEFAULT_FRAME_DURATION = 0.1 # 100ms -ANIMATION_DURATION = 5 -AUTO_ADVANCE_LOOPS = 1 -THRESHOLD = 20 - -# --- Display setup --- -matrix = Matrix(bit_depth=4) -sprite_group = displayio.Group() -matrix.display.root_group = sprite_group - -# --- Button setup --- -pin_down = DigitalInOut(board.BUTTON_DOWN) -pin_down.switch_to_input(pull=Pull.UP) -button_down = Debouncer(pin_down) -pin_up = DigitalInOut(board.BUTTON_UP) -pin_up.switch_to_input(pull=Pull.UP) -button_up = Debouncer(pin_up) - -AUTO_ADVANCE = True - -file_list = sorted( - [ - f - for f in os.listdir(SPRITESHEET_FOLDER) - if (f.endswith(".bmp") and not f.startswith(".")) - ] -) - -if len(file_list) == 0: - raise RuntimeError("No images found") - -CURRENT_IMAGE = None -CURRENT_FRAME = 0 -CURRENT_LOOP = 0 -FRAME_COUNT = 0 -FRAME_DURATION = DEFAULT_FRAME_DURATION - - -def load_image(): - """ - Load an image as a sprite - """ - # pylint: disable=global-statement - global CURRENT_FRAME, CURRENT_LOOP, FRAME_COUNT, FRAME_DURATION - while sprite_group: - sprite_group.pop() - - filename = SPRITESHEET_FOLDER + "/" + file_list[CURRENT_IMAGE] - - # CircuitPython 6 & 7 compatible - bitmap = displayio.OnDiskBitmap(open(filename, "rb")) - sprite = displayio.TileGrid( - bitmap, - pixel_shader=getattr(bitmap, 'pixel_shader', displayio.ColorConverter()), - tile_width=bitmap.width, - tile_height=matrix.display.height, - ) - - # # CircuitPython 7+ compatible - # bitmap = displayio.OnDiskBitmap(filename) - # sprite = displayio.TileGrid( - # bitmap, - # pixel_shader=bitmap.pixel_shader, - # tile_width=bitmap.width, - # tile_height=matrix.display.height, - # ) - - sprite_group.append(sprite) - - FRAME_COUNT = int(bitmap.height / matrix.display.height) - FRAME_DURATION = DEFAULT_FRAME_DURATION - CURRENT_FRAME = 0 - CURRENT_LOOP = 0 - - -def advance_image(): - """ - Advance to the next image in the list and loop back at the end - """ - # pylint: disable=global-statement - global CURRENT_IMAGE - if CURRENT_IMAGE is not None: - CURRENT_IMAGE += 1 - if CURRENT_IMAGE is None or CURRENT_IMAGE >= len(file_list): - CURRENT_IMAGE = 0 - load_image() - -def advance_frame(): - """Advance the frame""" - # pylint: disable=global-statement - global CURRENT_FRAME, CURRENT_LOOP - CURRENT_FRAME = CURRENT_FRAME + 1 - if CURRENT_FRAME >= FRAME_COUNT: - CURRENT_FRAME = 0 - CURRENT_LOOP = CURRENT_LOOP + 1 - sprite_group[0][0] = CURRENT_FRAME - -def load_list_image(item): - """Load the list item""" - global CURRENT_IMAGE - CURRENT_IMAGE = item - load_image() - -def load_tipsy(): - """Load the .bmp image""" - load_list_image(1) - -def play_thankyou(): - """load the thank you image""" - load_list_image(0) - while CURRENT_LOOP <= AUTO_ADVANCE_LOOPS: - advance_frame() - time.sleep(FRAME_DURATION) - - -advance_image() - -while True: - if sensor.range < THRESHOLD: - play_thankyou() - else: - load_tipsy() diff --git a/Matrix_Sprite_Animation_Player/code.py b/Matrix_Sprite_Animation_Player/code.py index a2258c40f..7e0f7d85a 100644 --- a/Matrix_Sprite_Animation_Player/code.py +++ b/Matrix_Sprite_Animation_Player/code.py @@ -62,25 +62,14 @@ def load_image(): sprite_group.pop() filename = SPRITESHEET_FOLDER + "/" + file_list[current_image] - - # CircuitPython 6 & 7 compatible - bitmap = displayio.OnDiskBitmap(open(filename, "rb")) + bitmap = displayio.OnDiskBitmap(filename) sprite = displayio.TileGrid( bitmap, - pixel_shader=getattr(bitmap, 'pixel_shader', displayio.ColorConverter()), + pixel_shader=bitmap.pixel_shader, tile_width=bitmap.width, tile_height=matrix.display.height, ) - # # CircuitPython 7+ compatible - # bitmap = displayio.OnDiskBitmap(filename) - # sprite = displayio.TileGrid( - # bitmap, - # pixel_shader=bitmap.pixel_shader, - # tile_width=bitmap.width, - # tile_height=matrix.display.height, - # ) - sprite_group.append(sprite) current_frame = 0 diff --git a/Metro/Metro_HSTX_Matrix/.none.test.only b/Metro/Metro_HSTX_Matrix/.none.test.only new file mode 100644 index 000000000..8d1c8b69c --- /dev/null +++ b/Metro/Metro_HSTX_Matrix/.none.test.only @@ -0,0 +1 @@ + diff --git a/Metro/Metro_HSTX_Matrix/Metro_HSTX_Matrix.ino b/Metro/Metro_HSTX_Matrix/Metro_HSTX_Matrix.ino new file mode 100644 index 000000000..68e2be41e --- /dev/null +++ b/Metro/Metro_HSTX_Matrix/Metro_HSTX_Matrix.ino @@ -0,0 +1,182 @@ +// SPDX-FileCopyrightText: 2021 Anne Barela for Adafruit Industries +// +// SPDX-License-Identifier: MIT +// +// Based on Adafruit-DVI-HSTX library code written by Jeff Epler +// and use of Claude 3.7 Sonnet on 3/2/2025 +// https://claude.site/artifacts/cf022b66-50c3-43eb-b334-17fbf0ed791c + +#include + +// Display configuration for text mode in Adafruit-DVI-HSTX +const int SCREEN_WIDTH = 91; +const int SCREEN_HEIGHT = 30; + +// Animation speed (lower = faster) +// Adjust this value to change the speed of the animation +const int ANIMATION_SPEED = 70; // milliseconds between updates + +// Initialize display for Adafruit Metro RP2350 +DVHSTXText display({14, 18, 16, 12}); // Adafruit Metro HSTX Pinout + +// Define structures for character streams +struct CharStream { + int x; // X position + int y; // Y position (head of the stream) + int length; // Length of the stream + int speed; // How many frames to wait before moving + int countdown; // Counter for movement + bool active; // Whether this stream is currently active + char chars[30]; // Characters in the stream +}; + +// Array of character streams - increased for higher density +// To fill 60-75% of the screen width (91 chars), we need around 55-68 active streams +CharStream streams[250]; // Allow for decent density + +// Stream creation rate (higher = more frequent new streams) +const int STREAM_CREATION_CHANCE = 65; // % chance per frame to create new stream + +// Initial streams to create at startup +const int INITIAL_STREAMS = 30; + +// Random characters that appear in the streams +const char matrixChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+[]{}|;:,.<>?/\\"; +const int numMatrixChars = sizeof(matrixChars) - 1; + +// Function declarations +void initStreams(); +void updateStreams(); +void drawStream(CharStream &stream); +void createNewStream(); +char getRandomChar(); + +void setup() { + // Initialize the display + display.begin(); + display.clear(); + + // Seed the random number generator + randomSeed(analogRead(A0)); + + // Initialize all streams + initStreams(); +} + +void loop() { + // Update and draw all streams + updateStreams(); + + // Randomly create new streams at a higher rate + if (random(100) < STREAM_CREATION_CHANCE) { + createNewStream(); + } + + // Control animation speed + delay(ANIMATION_SPEED); +} + +void initStreams() { + // Initialize all streams as inactive + for (int i = 0; i < sizeof(streams) / sizeof(streams[0]); i++) { + streams[i].active = false; + } + + // Create more initial streams for immediate visual impact + for (int i = 0; i < INITIAL_STREAMS; i++) { + createNewStream(); + } +} + +void createNewStream() { + // Find an inactive stream + for (int i = 0; i < sizeof(streams) / sizeof(streams[0]); i++) { + if (!streams[i].active) { + // Initialize the stream + streams[i].x = random(SCREEN_WIDTH); + streams[i].y = random(5) - 5; // Start above the screen + streams[i].length = random(5, 20); + streams[i].speed = random(1, 4); + streams[i].countdown = streams[i].speed; + streams[i].active = true; + + // Fill with random characters + for (int j = 0; j < streams[i].length; j++) { + streams[i].chars[j] = getRandomChar(); + } + + return; + } + } +} + +void updateStreams() { + display.clear(); + + // Count active streams (for debugging if needed) + int activeCount = 0; + + for (int i = 0; i < sizeof(streams) / sizeof(streams[0]); i++) { + if (streams[i].active) { + activeCount++; + streams[i].countdown--; + + // Time to move the stream down + if (streams[i].countdown <= 0) { + streams[i].y++; + streams[i].countdown = streams[i].speed; + + // Change a random character in the stream + int randomIndex = random(streams[i].length); + streams[i].chars[randomIndex] = getRandomChar(); + } + + // Draw the stream + drawStream(streams[i]); + + // Check if the stream has moved completely off the screen + if (streams[i].y - streams[i].length > SCREEN_HEIGHT) { + streams[i].active = false; + } + } + } +} + +void drawStream(CharStream &stream) { + for (int i = 0; i < stream.length; i++) { + int y = stream.y - i; + + // Only draw if the character is on screen + if (y >= 0 && y < SCREEN_HEIGHT) { + display.setCursor(stream.x, y); + + // Set different colors/intensities based on position in the stream + if (i == 0) { + // Head of the stream is white (brightest) + display.setColor(TextColor::TEXT_WHITE, TextColor::BG_BLACK, TextColor::ATTR_NORMAL_INTEN); + } else if (i < 3) { + // First few characters are bright green + display.setColor(TextColor::TEXT_GREEN, TextColor::BG_BLACK, TextColor::ATTR_NORMAL_INTEN); + } else if (i < 6) { + // Next few are medium green + display.setColor(TextColor::TEXT_GREEN, TextColor::BG_BLACK, TextColor::ATTR_LOW_INTEN); + } else { + // The rest are dim green + display.setColor(TextColor::TEXT_GREEN, TextColor::BG_BLACK, TextColor::ATTR_V_LOW_INTEN); + } + + // Draw the character + display.write(stream.chars[i]); + } + } + + // Occasionally change a character in the stream + if (random(100) < 25) { // 25% chance + int idx = random(stream.length); + stream.chars[idx] = getRandomChar(); + } +} + +char getRandomChar() { + return matrixChars[random(numMatrixChars)]; +} diff --git a/Metro/Metro_RP2350_Breakout/code.py b/Metro/Metro_RP2350_Breakout/code.py new file mode 100644 index 000000000..beaafd4c9 --- /dev/null +++ b/Metro/Metro_RP2350_Breakout/code.py @@ -0,0 +1,532 @@ +# SPDX-FileCopyrightText: 2025 Anne Barela for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# +# Breakout +# Original https://github.com/davepl/Grok3-Breakout by Grok3 +# Converted to CircuitPython by GitHub Copilot 2/20/2025 +# Further improved with keyboard controls via serial input, sound +# with Claude Sonnet 3.7 + +import sys +import time +import random +import board +import displayio +import supervisor +from adafruit_display_shapes.rect import Rect +from adafruit_display_shapes.circle import Circle +from adafruit_display_text import label +import terminalio +import picodvi +import framebufferio +import neopixel +import pwmio + +displayio.release_displays() # Ensure there are no active displays + +# Initialize status LED +leds = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.4) +leds.fill((0, 40, 0)) # Initial status: green + +# Initialize piezo speaker, connect piezo D23 to ground +try: + piezo = pwmio.PWMOut(board.D23, frequency=440, duty_cycle=0, + variable_frequency=True) +except Exception as e: # pylint: disable=broad-except + print("Piezo initialization error:", e) + piezo = None + +# Sound effect functions +def play_tone(frequency, duration): + """Play a tone at the specified frequency for the specified duration""" + if piezo is None: + return + + piezo.frequency = frequency + piezo.duty_cycle = 32767 # 50% duty cycle + time.sleep(duration) + piezo.duty_cycle = 0 + +def play_paddle_hit(): + """Sound for ball hitting paddle""" + if piezo is None: + return + + play_tone(440, 0.05) # A4, short duration + +def play_wall_hit(): + """Sound for ball hitting wall""" + if piezo is None: + return + + play_tone(330, 0.03) # E4, very short + +def play_brick_hit(): + """Sound for ball hitting brick""" + if piezo is None: + return + + play_tone(660, 0.05) # E5, short + +def play_game_over(): + """Sound for game over""" + if piezo is None: + return + + # Descending tone + for i in range(5): + play_tone(330 - i*30, 0.1) + +def play_level_win(): + """Sound for winning the level""" + if piezo is None: + return + + # Victory fanfare + sequence = [440, 440, 440, 587, 440, 587, 659] + durations = [0.1, 0.1, 0.1, 0.3, 0.1, 0.1, 0.4] + + for freq, dur in zip(sequence, durations): + play_tone(freq, dur) + time.sleep(0.01) # Small gap between notes + +def play_life_lost(): + """Sound for losing a life""" + if piezo is None: + return + + play_tone(220, 0.1) + time.sleep(0.05) + play_tone(196, 0.2) + +def play_game_start(): + """Sound for game start""" + if piezo is None: + return + + play_tone(440, 0.1) + time.sleep(0.05) + play_tone(554, 0.1) + time.sleep(0.05) + play_tone(659, 0.2) + +# Initialize display +try: + fb = picodvi.Framebuffer( + 320, 240, + clk_dp=board.CKP, clk_dn=board.CKN, + red_dp=board.D0P, red_dn=board.D0N, + green_dp=board.D1P, green_dn=board.D1N, + blue_dp=board.D2P, blue_dn=board.D2N, + color_depth=8 + ) +except ValueError as e: + print("Error: ", e) + # Per picodvi/Framebuffer_RP2350.c only 320x240 at 8 & 16 bits work + leds.fill((255, 0, 0)) # Error status: red + sys.exit(e) +display = framebufferio.FramebufferDisplay(fb) + +# Game constants +PADDLE_WIDTH = 40 +PADDLE_HEIGHT = 5 +BALL_RADIUS = 2 +BRICK_ROWS = 5 +BRICK_COLS = 10 +BRICK_WIDTH = 30 +BRICK_HEIGHT = 10 +BRICK_GAP = 2 +PADDLE_SPEED = 6.0 # Change to make paddle speed up or slow down +BALL_SPEED_INITIAL = 2.75 # Change initial ball speed +BRICK_COLORS = [0xFF4136, 0xFF851B, 0xFFDC00, 0x2ECC40, 0x0074D9] +DISPLAY_LINE = 20 # Score is on the bottom of the display 20 px tall + +# Game state +game_active = False +game_over = False +brick_count = BRICK_ROWS * BRICK_COLS + +# Keyboard input state +key_left_pressed = False +key_right_pressed = False +key_space_pressed = False +space_key_released = True # Track space key release to prevent multiple actions + +# Track paddle position with float for smoother movement +paddle_pos_x = 0.0 + +def check_keys(): + """ + Check for keyboard input via supervisor.runtime.serial_bytes_available + Returns tuple of (left_pressed, right_pressed, space_pressed, any_input) + """ + l_pressed = False + r_pressed = False + s_pressed = False + any_key = False + + # Check if serial data is available + if supervisor.runtime.serial_bytes_available: + any_key = True + try: + key = sys.stdin.read(1) + if key in ('a', 'A'): # Left movement + l_pressed = True + elif key in ('d', 'D'): # Right movement + r_pressed = True + elif key == ' ': # Space for start/launch + s_pressed = True + elif key in ('q', 'Q') or ord(key) == 27: # q, Q, or ESC is quit + sys.exit(0) # We're out of here + except Exception as e: # pylint: disable=broad-except + print("Input error:", e) + + return (l_pressed, r_pressed, s_pressed, any_key) + +# pylint: disable=redefined-outer-name +def create_game_elements(): + """Create and return all game display elements""" + game_group = displayio.Group() + + # Paddle + paddle = Rect( + (display.width - PADDLE_WIDTH) // 2, + display.height - PADDLE_HEIGHT - DISPLAY_LINE, + PADDLE_WIDTH, + PADDLE_HEIGHT, + fill=0x00FFFF + ) + game_group.append(paddle) + + # Ball + ball = Circle( + display.width // 2, + display.height - PADDLE_HEIGHT - DISPLAY_LINE - BALL_RADIUS * 3, + BALL_RADIUS, + fill=0xFFFFFF + ) + game_group.append(ball) + + # Bricks + bricks = [] + for row in range(BRICK_ROWS): + for col in range(BRICK_COLS): + # Calculate brick position with appropriate spacing + brick_x = col * (BRICK_WIDTH + BRICK_GAP) + \ + (display.width - (BRICK_COLS * (BRICK_WIDTH + BRICK_GAP) + - BRICK_GAP)) // 2 + brick_y = row * (BRICK_HEIGHT + BRICK_GAP) + 30 # Start a bit down from top + + brick = Rect( + brick_x, + brick_y, + BRICK_WIDTH, + BRICK_HEIGHT, + fill=BRICK_COLORS[row % len(BRICK_COLORS)] + ) + bricks.append(brick) + game_group.append(brick) + + # Score and lives + score_label = label.Label( + terminalio.FONT, + text="Score: 0", + color=0xFFFFFF, + x=5, + y=display.height - 10 + ) + lives_label = label.Label( + terminalio.FONT, + text="Lives: 3", + color=0xFFFFFF, + x=display.width - 60, + y=display.height - 10 + ) + game_group.append(score_label) + game_group.append(lives_label) + + # Controls info + controls_label = label.Label( + terminalio.FONT, + text="A: Left D: Right", + color=0xFFFFFF, + x=10, + y=display.height - 30 + ) + game_group.append(controls_label) + + # Start/game over message + message_label = label.Label( + terminalio.FONT, + text="Press SPACE to begin", + color=0xFFFFFF, + x=(display.width - 130) // 2, + y=display.height // 2 + ) + game_group.append(message_label) + + return (game_group, paddle, ball, bricks, score_label, + lives_label, message_label, controls_label) + +# Create initial game elements +main_group, paddle, ball, bricks, score_label, lives_label, message_label, \ + controls_label = create_game_elements() +display.root_group = main_group + +# Game variables +score = 0 +lives = 3 +ball_dx = 0.0 +ball_dy = 0.0 +ball_speed = BALL_SPEED_INITIAL +last_hit_brick = None + +# Track actual ball position with floats +ball_pos_x = float(ball.x) +ball_pos_y = float(ball.y) + +# Initialize paddle position tracking +paddle_pos_x = float((display.width - PADDLE_WIDTH) // 2) + +def reset_ball(): + """Reset the ball position and set it initially stationary""" + global ball_dx, ball_dy, ball_pos_x, ball_pos_y # pylint: disable=global-statement + ball_pos_x = float(display.width // 2) + ball_pos_y = float(display.height - PADDLE_HEIGHT - DISPLAY_LINE - BALL_RADIUS * 3) + ball.x = int(ball_pos_x) + ball.y = int(ball_pos_y) + ball_dx = 0 + ball_dy = 0 + +def launch_ball(): + """Launch the ball in a random upward direction""" + global ball_dx, ball_dy, ball_speed # pylint: disable=global-statement + ball_speed = BALL_SPEED_INITIAL + angle = random.uniform(0.5, 0.8) # Launch at angle between 45-65 degrees + ball_dx = ball_speed * random.choice([-angle, angle]) + # Ensure consistent speed + ball_dy = -ball_speed * (1 - abs(ball_dx/ball_speed)) + controls_label.hidden = True + +def update_message(text): + """Update the message text""" + message_label.text = text + # Center text (approximate width) + message_label.x = (display.width - len(text) * 6) // 2 + +# Game loop +reset_ball() + +# Track last collision for sound effect throttling +last_wall_hit_time = 0 +sound_cooldown = 0.05 # Minimum time between similar sound effects + +# Play startup sound +play_game_start() + +while True: + current_time = time.monotonic() + + # Check keyboard input + left_pressed, right_pressed, space_pressed, any_input = check_keys() + + # Apply paddle movement ONLY if keys are currently pressed + if left_pressed and paddle_pos_x > 0: + paddle_pos_x -= PADDLE_SPEED + # Ensure paddle doesn't go offscreen + if paddle_pos_x < 0: + paddle_pos_x = 0 + + if right_pressed and paddle_pos_x < display.width - PADDLE_WIDTH: + paddle_pos_x += PADDLE_SPEED + # Ensure paddle doesn't go offscreen + if paddle_pos_x > display.width - PADDLE_WIDTH: + paddle_pos_x = display.width - PADDLE_WIDTH + + # Update paddle position with integer conversion + paddle.x = int(paddle_pos_x) + + # Handle space bar for start/launch with debouncing + if space_pressed and space_key_released: + space_key_released = False # Prevent multiple triggers until released + + if game_over: + # Reset everything for a new game + (main_group, paddle, ball, bricks, score_label, + lives_label, message_label, controls_label) = create_game_elements() + display.root_group = main_group + score = 0 + lives = 3 + brick_count = BRICK_ROWS * BRICK_COLS + game_over = False + reset_ball() + update_message("") + # Reset paddle position tracker + paddle_pos_x = float((display.width - PADDLE_WIDTH) // 2) + + # Play restart sound + play_game_start() + + if not game_active and not game_over: + game_active = True + launch_ball() + update_message("") + + # Play ball launch sound + play_tone(587, 0.1) # D5, short + + # Reset space key released state if no key is pressed + if not space_pressed: + space_key_released = True + + # Handle game logic when active + if game_active and not game_over: + # Update ball position (using float variables first) + ball_pos_x += ball_dx + ball_pos_y += ball_dy + # Update the actual ball object with integer positions + ball.x = int(ball_pos_x) + ball.y = int(ball_pos_y) + + # Ball collision with walls with sound + wall_hit = False + + if ball_pos_x - BALL_RADIUS <= 0: + ball_pos_x = BALL_RADIUS + 1 # Prevent sticking to wall + ball_dx = abs(ball_dx) # Move right + wall_hit = True + elif ball_pos_x + BALL_RADIUS >= display.width: + ball_pos_x = display.width - BALL_RADIUS - 1 # Prevent sticking to wall + ball_dx = -abs(ball_dx) # Move left + wall_hit = True + + if ball_pos_y - BALL_RADIUS <= 0: + ball_pos_y = BALL_RADIUS + 1 # Prevent sticking to wall + ball_dy = abs(ball_dy) # Move down + wall_hit = True + + # Play wall hit sound with cooldown to prevent sound overlap + if wall_hit and current_time - last_wall_hit_time > sound_cooldown: + play_wall_hit() + last_wall_hit_time = current_time + + # Ball fell below paddle + if ball_pos_y + BALL_RADIUS > display.height - DISPLAY_LINE: + lives -= 1 + lives_label.text = f"Lives: {lives}" + + # Play life lost sound + play_life_lost() + + if lives <= 0: + game_active = False + game_over = True + update_message("GAME OVER - Press SPACE to play again, Q to quit") + + # Play game over sound + play_game_over() + else: + reset_ball() + game_active = False + update_message("Press SPACE to continue") + + # Ball collision with paddle + paddle_collision = ( + ball_pos_y + BALL_RADIUS >= paddle.y and + ball_pos_y - BALL_RADIUS <= paddle.y + PADDLE_HEIGHT and + ball_pos_x + BALL_RADIUS >= paddle.x and + ball_pos_x - BALL_RADIUS <= paddle.x + PADDLE_WIDTH + ) + + if paddle_collision: + # Determine bounce angle based on where ball hit paddle + # Center of paddle gives straight bounce, edges give angled bounce + hit_position = (ball_pos_x - paddle.x) / PADDLE_WIDTH + angle_factor = 2 * (hit_position - 0.5) # -1 to 1 based on position + + # Set new ball direction with slight speed increase + ball_speed = min(ball_speed * 1.05, 4.5) # Speed up slightly, max at 4.5 + ball_dx = ball_speed * angle_factor + # Ensure upward movement + ball_dy = -ball_speed * (1 - 0.8 * abs(angle_factor)) + + # Ensure ball is above paddle (prevent sticking) + ball_pos_y = paddle.y - BALL_RADIUS - 1 + ball.y = int(ball_pos_y) + + # Play paddle hit sound + play_paddle_hit() + + # Ball collision with bricks + for brick in bricks: + brick_collision = ( + brick in main_group and + brick.x <= ball_pos_x + BALL_RADIUS and + brick.x + BRICK_WIDTH >= ball_pos_x - BALL_RADIUS and + brick.y <= ball_pos_y + BALL_RADIUS and + brick.y + BRICK_HEIGHT >= ball_pos_y - BALL_RADIUS + ) + + if brick_collision: + # Skip if this is the same brick we just hit (prevent double hits) + if brick == last_hit_brick: + continue + + last_hit_brick = brick + main_group.remove(brick) + brick_count -= 1 + + # Determine which side of the brick was hit + dx1 = ball_pos_x - brick.x # Distance from left edge + dx2 = brick.x + BRICK_WIDTH - ball_pos_x # Distance from right edge + dy1 = ball_pos_y - brick.y # Distance from top edge + dy2 = brick.y + BRICK_HEIGHT - ball_pos_y # Distance from bottom edge + + # Find the minimum distance + min_dist = min(dx1, dx2, dy1, dy2) + + # Bounce based on which side was hit + if min_dist in (dy1, dy2): # Top or bottom hit + ball_dy = -ball_dy + else: # Left or right hit + ball_dx = -ball_dx + + # Update score + score += 10 + score_label.text = f"Score: {score}" + + # Play brick hit sound + play_brick_hit() + + # Check win condition + if brick_count <= 0: + game_active = False + game_over = True + update_message("YOU WIN! Press SPACE to play again") + + # Play victory sound + play_level_win() + + # Only process one brick collision per frame + break + + # Reset last_hit_brick if we're not touching it anymore + if last_hit_brick: + still_touching = ( + last_hit_brick.x <= ball_pos_x + BALL_RADIUS and + last_hit_brick.x + BRICK_WIDTH >= ball_pos_x - BALL_RADIUS and + last_hit_brick.y <= ball_pos_y + BALL_RADIUS and + last_hit_brick.y + BRICK_HEIGHT >= ball_pos_y - BALL_RADIUS + ) + if not still_touching: + last_hit_brick = None + + elif not game_active and not game_over: + # Ball sticks to paddle when not active + ball.x = paddle.x + PADDLE_WIDTH // 2 + ball_pos_x = float(ball.x) + + # Refresh display + display.refresh() + time.sleep(0.016) # ~60fps diff --git a/Metro/Metro_RP2350_Breakout/icon.bmp b/Metro/Metro_RP2350_Breakout/icon.bmp new file mode 100644 index 000000000..d78c04e66 Binary files /dev/null and b/Metro/Metro_RP2350_Breakout/icon.bmp differ diff --git a/Metro/Metro_RP2350_Breakout/metadata.json b/Metro/Metro_RP2350_Breakout/metadata.json new file mode 100644 index 000000000..cbfe8bfdf --- /dev/null +++ b/Metro/Metro_RP2350_Breakout/metadata.json @@ -0,0 +1,4 @@ +{ + "title": "Breakout", + "icon": "icon.bmp" +} diff --git a/Metro/Metro_RP2350_Chips_Challenge/CHIPS.DAT b/Metro/Metro_RP2350_Chips_Challenge/CHIPS.DAT new file mode 100755 index 000000000..db68c1238 Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/CHIPS.DAT differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/audio.py b/Metro/Metro_RP2350_Chips_Challenge/audio.py new file mode 100755 index 000000000..d8ea59029 --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/audio.py @@ -0,0 +1,28 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +import audiocore +from definitions import PLAY_SOUNDS + +class Audio: + def __init__(self, audio_bus, sounds): + self._audio = audio_bus + self._wav_files = {} + for sound_name, file in sounds.items(): + self._add_sound(sound_name, file) + # Play the first sound in the list to initialize the audio system + self.play(tuple(self._wav_files.keys())[0], wait=True) + + def play(self, sound_name, wait=False): + if not PLAY_SOUNDS or self._audio is None: + return + if sound_name in self._wav_files: + with open(self._wav_files[sound_name], "rb") as wave_file: + wav = audiocore.WaveFile(wave_file) + self._audio.play(wav) + if wait: + while self._audio.playing: + pass + + def _add_sound(self, sound_name, file): + self._wav_files[sound_name] = file diff --git a/Metro/Metro_RP2350_Chips_Challenge/bitmaps/background.bmp b/Metro/Metro_RP2350_Chips_Challenge/bitmaps/background.bmp new file mode 100755 index 000000000..823b06d46 Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/bitmaps/background.bmp differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/bitmaps/chipend.bmp b/Metro/Metro_RP2350_Chips_Challenge/bitmaps/chipend.bmp new file mode 100755 index 000000000..3c1a56ec2 Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/bitmaps/chipend.bmp differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/bitmaps/digits.bmp b/Metro/Metro_RP2350_Chips_Challenge/bitmaps/digits.bmp new file mode 100755 index 000000000..5100fa2d1 Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/bitmaps/digits.bmp differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/bitmaps/info.bmp b/Metro/Metro_RP2350_Chips_Challenge/bitmaps/info.bmp new file mode 100755 index 000000000..4310ee541 Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/bitmaps/info.bmp differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/bitmaps/spritesheet_24_keyed.bmp b/Metro/Metro_RP2350_Chips_Challenge/bitmaps/spritesheet_24_keyed.bmp new file mode 100755 index 000000000..7820db71d Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/bitmaps/spritesheet_24_keyed.bmp differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/code.py b/Metro/Metro_RP2350_Chips_Challenge/code.py new file mode 100755 index 000000000..04a2d3d64 --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/code.py @@ -0,0 +1,80 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT + +import json +import time +import board +import supervisor +import audiobusio +from audio import Audio +import adafruit_pathlib as pathlib +import adafruit_fruitjam.Peripherals +from game import Game +from definitions import SECOND_LENGTH, TICKS_PER_SECOND + +# Disable auto-reload to prevent the game from restarting +#import supervisor +#supervisor.runtime.autoreload = False + +# Change this to use a different data file +DATA_FILE = "CHIPS.DAT" + +SOUND_EFFECTS = { + "BUTTON_PUSHED": "sounds/pop2.wav", + "DOOR_OPENED": "sounds/door.wav", + "ITEM_COLLECTED": "sounds/blip2.wav", + "BOOTS_STOLEN": "sounds/strike.wav", + "WATER_SPLASH": "sounds/water2.wav", + "TELEPORT": "sounds/teleport.wav", + "CANT_MOVE": "sounds/oof3.wav", + "CHIP_LOSES": "sounds/bummer.wav", + "LEVEL_COMPLETE": "sounds/ditty1.wav", + "IC_COLLECTED": "sounds/click3.wav", + "BOMB_EXPLOSION": "sounds/hit3.wav", + "SOCKET_SOUND": "sounds/chimes.wav", + "TIME_LOW_TICK": "sounds/click1.wav", + "TIME_UP": "sounds/bell.wav" +} + +# optional configuration file for speaker/headphone setting +launcher_config = {} +for directory in ("/", "/sd/", "/saves/"): + launcher_config_path = directory + "launcher.conf.json" + if pathlib.Path(launcher_config_path).exists(): + with open(launcher_config_path, "r") as f: + launcher_config = launcher_config | json.load(f) +if "audio" not in launcher_config: + launcher_config["audio"] = {} + + +fjPeriphs = adafruit_fruitjam.Peripherals.Peripherals( + audio_output=launcher_config["audio"].get("output", "headphone"), + safe_volume_limit=launcher_config["audio"].get("volume_override_danger",.75), + sample_rate=44100, + bit_depth=16, + i2c=board.I2C() +) +if not hasattr(board, "I2S_BCLK") and \ + hasattr(board, "D9") and hasattr(board, "D10") and hasattr(board, "D11"): + + fjPeriphs.audio = audiobusio.I2SOut(board.D9, board.D10, board.D11) + +# If volume was specified use it, otherwise use the fruitjam library default +if "volume" in launcher_config["audio"]: + fjPeriphs.volume = launcher_config["audio"]["volume"] # FruitJam vol 0.0-1.0 + +if fjPeriphs.audio is not None: + audio = Audio(fjPeriphs.audio, SOUND_EFFECTS) +else: + audio = None + +adafruit_fruitjam.Peripherals.request_display_config(320, 240, 8) + +game = Game(supervisor.runtime.display, DATA_FILE, audio) +tick_length = SECOND_LENGTH / 1000 / TICKS_PER_SECOND +while True: + start = time.monotonic() + game.tick() + while time.monotonic() - start < tick_length: + pass diff --git a/Metro/Metro_RP2350_Chips_Challenge/creature.py b/Metro/Metro_RP2350_Chips_Challenge/creature.py new file mode 100755 index 000000000..ba23b5155 --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/creature.py @@ -0,0 +1,132 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +from point import Point +from definitions import NONE, TYPE_BLOCK, TYPE_CHIP, NORTH, SOUTH, WEST, EAST + +DIR_UP = 0 +DIR_LEFT = 1 +DIR_DOWN = 2 +DIR_RIGHT = 3 + +# creatures should move based on chip, tiles near them, and their own AI +# creatures should be able to move in any direction assuming they are not blocked + +# Abstract class +class Creature: + def __init__(self, *, position=None, direction=NONE, creature_type=NONE): + self.cur_pos = position or Point(0, 0) + self.type = creature_type or TYPE_BLOCK + self.direction = direction + self.state = 0x00 + self.hidden = False + self.on_slip_list = False + self.to_direction = NONE + + def move(self, destination): + if destination.y < self.cur_pos.y: + self.direction = NORTH + elif destination.x < self.cur_pos.x: + self.direction = WEST + elif destination.y > self.cur_pos.y: + self.direction = SOUTH + elif destination.x > self.cur_pos.x: + self.direction = EAST + else: + self.direction = NONE + self.cur_pos = destination + + def image_number(self): + tile_index = 0 + if self.type == TYPE_CHIP: + tile_index = 0x6C + elif self.type == TYPE_BLOCK: + tile_index = 0x0A + else: + tile_index = 0x40 + ((self.type - 1) * 4) + + if self.direction == WEST: + tile_index += DIR_LEFT + elif self.direction == EAST: + tile_index += DIR_RIGHT + elif self.direction == NORTH: + tile_index += DIR_UP + elif self.direction in (SOUTH, NONE): + tile_index += DIR_DOWN + return tile_index + + def get_tile_in_dir(self, direction): + pt_dir = Point(self.cur_pos.x, self.cur_pos.y) + if direction == WEST: + pt_dir.x -= 1 + elif direction == EAST: + pt_dir.x += 1 + elif direction == NORTH: + pt_dir.y -= 1 + elif direction == SOUTH: + pt_dir.y += 1 + return pt_dir + + def left(self): + # return the point to the left of the creature + pt_dest = Point(self.cur_pos.x, self.cur_pos.y) + if self.direction == NORTH: + pt_dest.x -= 1 + elif self.direction == WEST: + pt_dest.y += 1 + elif self.direction == SOUTH: + pt_dest.x += 1 + elif self.direction == EAST: + pt_dest.y -= 1 + return pt_dest + + def right(self): + # Return point to the right of the creature + pt_dest = Point(self.cur_pos.x, self.cur_pos.y) + if self.direction == NORTH: + pt_dest.x += 1 + elif self.direction == WEST: + pt_dest.y -= 1 + elif self.direction == SOUTH: + pt_dest.x -= 1 + elif self.direction == EAST: + pt_dest.y += 1 + return pt_dest + + def back(self): + # Return point behind the creature + pt_dest = Point(self.cur_pos.x, self.cur_pos.y) + if self.direction == NORTH: + pt_dest.y += 1 + elif self.direction == WEST: + pt_dest.x += 1 + elif self.direction == SOUTH: + pt_dest.y -= 1 + elif self.direction == EAST: + pt_dest.x -= 1 + return pt_dest + + def front(self): + # Return point in front of the creature + pt_dest = Point(self.cur_pos.x, self.cur_pos.y) + if self.direction == NORTH: + pt_dest.y -= 1 + elif self.direction == WEST: + pt_dest.x -= 1 + elif self.direction == SOUTH: + pt_dest.y += 1 + elif self.direction == EAST: + pt_dest.x += 1 + return pt_dest + + def reverse(self): + if self.direction == NORTH: + return SOUTH + elif self.direction == SOUTH: + return NORTH + elif self.direction == WEST: + return EAST + elif self.direction == EAST: + return WEST + else: + return self.direction diff --git a/Metro/Metro_RP2350_Chips_Challenge/databuffer.py b/Metro/Metro_RP2350_Chips_Challenge/databuffer.py new file mode 100755 index 000000000..69a264099 --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/databuffer.py @@ -0,0 +1,43 @@ +# SPDX-FileCopyrightText: 2023 Melissa LeBlanc-Williams for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +class DataBuffer: + def __init__(self): + self._dataset = {} + self._default_data = {} + + def set_data_structure(self, data_structure): + self._default_data = data_structure + self.reset() + + def reset(self, field=None): + # Copy the default data to the dataset + if field is not None: + if not isinstance(field, (tuple, list)): + field = [field] + for item in field: + self._dataset[item] = self.deepcopy(self._default_data[item]) + else: + self._dataset = self.deepcopy(self._default_data) + + def deepcopy(self, data): + # Iterate through the data and copy each element + new_data = {} + if isinstance(data, (dict)): + for key, value in data.items(): + if isinstance(value, (dict, list)): + new_data[key] = self.deepcopy(value) + else: + new_data[key] = value + elif isinstance(data, (list)): + for idx, item in enumerate(data): + if isinstance(item, (dict, list)): + new_data[idx] = self.deepcopy(item) + else: + new_data[idx] = item + return new_data + + @property + def dataset(self): + return self._dataset diff --git a/Metro/Metro_RP2350_Chips_Challenge/definitions.py b/Metro/Metro_RP2350_Chips_Challenge/definitions.py new file mode 100755 index 000000000..df53dc158 --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/definitions.py @@ -0,0 +1,336 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +from micropython import const + +# Settings +PLAY_SOUNDS = True + +# Timing Constants +TICKS_PER_SECOND = const(20) +SECOND_LENGTH = const(1000) + +# Tile Constants +TYPE_NOTILE = const(-1) +TYPE_EMPTY = const(0x00) +TYPE_WALL = const(0x01) +TYPE_ICCHIP = const(0x02) +TYPE_WATER = const(0x03) +TYPE_FIRE = const(0x04) +TYPE_HIDDENWALL_PERM = const(0x05) +TYPE_WALL_NORTH = const(0x06) +TYPE_WALL_WEST = const(0x07) +TYPE_WALL_SOUTH = const(0x08) +TYPE_WALL_EAST = const(0x09) +TYPE_BLOCK_STATIC = const(0x0a) +TYPE_DIRT = const(0x0b) +TYPE_ICE = const(0x0c) +TYPE_SLIDE_SOUTH = const(0x0d) +TYPE_SLIDE_NORTH = const(0x12) +TYPE_SLIDE_EAST = const(0x13) +TYPE_SLIDE_WEST = const(0x14) +TYPE_EXIT = const(0x15) +TYPE_DOOR_BLUE = const(0x16) +TYPE_DOOR_RED = const(0x17) +TYPE_DOOR_GREEN = const(0x18) +TYPE_DOOR_YELLOW = const(0x19) +TYPE_ICEWALL_SOUTHEAST = const(0x1a) +TYPE_ICEWALL_SOUTHWEST = const(0x1b) +TYPE_ICEWALL_NORTHWEST = const(0x1c) +TYPE_ICEWALL_NORTHEAST = const(0x1d) +TYPE_BLUEWALL_FAKE = const(0x1e) +TYPE_BLUEWALL_REAL = const(0x1f) + +TYPE_THIEF = const(0x21) +TYPE_SOCKET = const(0x22) +TYPE_BUTTON_GREEN = const(0x23) +TYPE_BUTTON_RED = const(0x24) +TYPE_SWITCHWALL_CLOSED = const(0x25) +TYPE_SWITCHWALL_OPEN = const(0x26) +TYPE_BUTTON_BROWN = const(0x27) +TYPE_BUTTON_BLUE = const(0x28) +TYPE_TELEPORT = const(0x29) +TYPE_BOMB = const(0x2a) +TYPE_BEARTRAP = const(0x2b) +TYPE_HIDDENWALL_TEMP = const(0x2c) +TYPE_GRAVEL = const(0x2d) +TYPE_POPUPWALL = const(0x2e) +TYPE_HINTBUTTON = const(0x2f) +TYPE_WALL_SOUTHEAST = const(0x30) +TYPE_CLONEMACHINE = const(0x31) +TYPE_SLIDE_RANDOM = const(0x32) + +TYPE_CHIP_DROWNED = const(0x33) +TYPE_CHIP_BURNED = const(0x34) +TYPE_CHIP_BOMBED = const(0x35) + +TYPE_EXITED_CHIP = const(0x39) +TYPE_EXIT_EXTRA_1 = const(0x3a) +TYPE_EXIT_EXTRA_2 = const(0x3b) + +TYPE_BLOCK = const(0xd0) +TYPE_CHIP_SWIMMING = const(0x3c) +TYPE_BUG = const(0x40) +TYPE_FIREBALL = const(0x44) +TYPE_BALL = const(0x48) +TYPE_TANK = const(0x4c) +TYPE_GLIDER = const(0x50) +TYPE_TEETH = const(0x54) +TYPE_WALKER = const(0x58) +TYPE_BLOB = const(0x5c) +TYPE_PARAMECIUM = const(0x60) + +TYPE_KEY_BLUE = const(0x64) +TYPE_KEY_RED = const(0x65) +TYPE_KEY_GREEN = const(0x66) +TYPE_KEY_YELLOW = const(0x67) + +TYPE_BOOTS_WATER = const(0x68) +TYPE_BOOTS_FIRE = const(0x69) +TYPE_BOOTS_ICE = const(0x6a) +TYPE_BOOTS_SLIDE = const(0x6b) + +TYPE_CHIP = const(0x6c) +TYPE_NOTHING = const(0xff) + +# Map Directional Constants +NONE = const(-1) +NORTH = const(1) +WEST = const(2) +SOUTH = const(4) +EAST = const(8) +NWSE = const(NORTH | WEST | SOUTH | EAST) + +# Command Constants +UP = const(0) +LEFT = const(1) +DOWN = const(2) +RIGHT = const(3) +NEXT_LEVEL = const(4) +PREVIOUS_LEVEL = const(5) +RESTART_LEVEL = const(6) +GOTO_LEVEL = const(7) +PAUSE = const(8) +QUIT = const(9) +OK = const(10) +CANCEL = const(11) +CHANGE_FIELDS = const(12) +DELCHAR = const(13) + +# Keycode Constants +UP_ARROW = const("\x1b[A") +DOWN_ARROW = const("\x1b[B") +RIGHT_ARROW = const("\x1b[C") +LEFT_ARROW = const("\x1b[D") +SPACE = const(" ") +CTRL_G = const("\x07") # Ctrl+G +CTRL_N = const("\x0E") # Ctrl+N +CTRL_P = const("\x10") # Ctrl+P +CTRL_Q = const("\x11") # Ctrl+Q +CTRL_R = const("\x12") # Ctrl+R +BACKSPACE = const("\x08") +TAB = const("\x09") +ENTER = const("\n") +ESC = const("\x1b") + +# Mapping Buttons to Commands for different modes +GAMEPLAY_COMMANDS = { + UP_ARROW: UP, + LEFT_ARROW: LEFT, + DOWN_ARROW: DOWN, + RIGHT_ARROW: RIGHT, + SPACE: PAUSE, + CTRL_G: GOTO_LEVEL, + CTRL_N: NEXT_LEVEL, + CTRL_P: PREVIOUS_LEVEL, + CTRL_Q: QUIT, + CTRL_R: RESTART_LEVEL, +} + +MESSAGE_COMMANDS = { + ENTER: OK, + SPACE: OK, +} + +# Password commands include only letters, enter, tab, and backspace +PASSWORD_COMMANDS = { + ESC: CANCEL, + TAB: CHANGE_FIELDS, + ENTER: OK, + BACKSPACE: DELCHAR, +} + +# The rest are input characters +for i in range(65, 91): + PASSWORD_COMMANDS[chr(i)] = chr(i) +for i in range(97, 123): + PASSWORD_COMMANDS[chr(i)] = chr(i) +for i in range(48, 58): + PASSWORD_COMMANDS[chr(i)] = chr(i) + +# Can Make Move Constants +CMM_NOLEAVECHECK = const(0x0001) +CMM_NOEXPOSEWALLS = const(0x0002) +CMM_CLONECANTBLOCK = const(0x0004) +CMM_NOPUSHING = const(0x0008) +CMM_TELEPORTPUSH = const(0x0010) +CMM_NOFIRECHECK = const(0x0020) +CMM_NODEFERBUTTONS = const(0x0040) + +# Creature States +CS_RELEASED = const(0x01) +CS_CLONING = const(0x02) +CS_HASMOVED = const(0x04) +CS_TURNING = const(0x08) +CS_SLIP = const(0x10) +CS_SLIDE = const(0x20) +CS_DEFERPUSH = const(0x40) +CS_MUTANT = const(0x80) + +#Floor State Constants +FS_BUTTONDOWN = const(0x01) +FS_CLONING = const(0x02) +FS_BROKEN = const(0x04) +FS_HASMUTANT = const(0x08) +FS_MARKER = const(0x10) + +# Status Flag Constants +SF_CHIPWAITMASK = const(0x0007) +SF_CHIPOKAY = const(0x0000) +SF_CHIPBURNED = const(0x0010) +SF_CHIPBOMBED = const(0x0020) +SF_CHIPDROWNED = const(0x0030) +SF_CHIPHIT = const(0x0040) +SF_CHIPTIMEUP = const(0x0050) +SF_CHIPBLOCKHIT = const(0x0060) +SF_CHIPNOTOKAY = const(0x0070) +SF_CHIPSTATUSMASK = const(0x0070) +SF_DEFERBUTTONS = const(0x0080) +SF_COMPLETED = const(0x0100) +SF_SHOWHINT = const(0x10000000) + +# Game Mode Constants +GM_NONE = const(0) # No mode (not sure if this should be a mode) +GM_PAUSED = const(1) # Paused +GM_CHIPDEAD = const(2) # Chip is dead +GM_GAMEWON = const(3) # Game is won +GM_LEVELWON = const(4) # Level is won +GM_LOADING = const(5) # Not sure +GM_MESSAGE = const(6) # Message is displayed +GM_NEWGAME = const(7) # Not sure +GM_NORMAL = const(8) # Normal gameplay + +# Key Constants +RED_KEY = const(0) +BLUE_KEY = const(1) +YELLOW_KEY = const(2) +GREEN_KEY = const(3) + +# Boot Constants +ICE_BOOTS = const(0) +SUCTION_BOOTS = const(1) +FIRE_BOOTS = const(2) +WATER_BOOTS = const(3) + +death_messages = { + SF_CHIPHIT: "Ooops! Look out for creatures!", + SF_CHIPDROWNED: "Ooops! Chip can't swim without flippers!", + SF_CHIPBURNED: "Ooops! Don't step in the fire without fire boots!", + SF_CHIPBOMBED: "Ooops! Don't touch the bombs!", + SF_CHIPTIMEUP: "Ooops! Out of time!", + SF_CHIPBLOCKHIT: "Ooops! Watch out for moving blocks!", +} + +decade_messages = { + 10: ("After warming up on the first levels of the challenge, " + "Chip is raring to go! 'This isn't so hard,' he thinks."), + 20: ("But the challenge turns out to be harder than Chip thought. " + "The Bit Busters want it that way -- to keep out lobotomy heads."), + 30: ("Chip's thick-soled shoes and pop-bottle glasses speed him through " + "the mazes while his calculator watch keeps track of time."), + 40: "Chip reads the clues so he won't lose.", + 50: ("Picking up chips is what the challenge is all about. But on ice, " + "Chip gets chapped and feels like a chump instead of a champ."), + 60: ("Chip hits the ice and decides to chill out. Then he runs into a " + "fake wall and turns the maze into a thrash-a-thon!"), + 70: ("Chip is halfway through the world's hardest puzzle. If he suceeds, " + "maybe the kids will stop calling him computer breath!"), + 80: ("Chip used to spend his time programming computer games and making " + "models. But that was just practice for this brain-buster!"), + 90: ("'I can do it! I know I can!' Chip thinks as the going gets tougher. " + "Besides, Melinda the Mental Marvel waits at the end."), + 100: ("Besides being an angel on earth, Melinda is the top scorer in the " + "Challenge--and the president of the Bit Busters."), + 110: ("Chip can't wait to join the Bit Busters! The club's already figured " + "out the school's password and accessed everyone's grades!"), + 120: ("If Chip's grades aren't as good as Melinda's, maybe she'll come " + "over to his house and help him study!"), + 130: ("'I've made it this far,' Chip thinks. 'Totally fair, with my " + "mega-brain.' Then he starts the next maze. 'Totally unfair!' he yelps."), + 140: "Groov-u-loids! Chip makes it almost to the end. He's stoked!", + 144: ("Melinda herself offers Chip membership in the exclusive Bit Busters " + "computer club, and gives him access to the club's computer system. " + "Chip is in heaven!"), + 149: ("Melinda herself offers Chip membership in the exclusive Bit Busters " + "computer club, and gives him access to the club's computer system. " + "Chip is in heaven!"), +} + +victory_messages = { + 0: "Yowser! First Try!", + 2: "Go Bit Buster!", + 4: "Finished! Good Work!", + 5: "At last! You did it!", +} + +winning_message = ( + "You completed {completed_levels} levels, and your total score for the " + "challenge is {total_score} points.\n\n" + "You can still improve your score, by completing levels that you skipped, " + "and getting better times on each level. When you replay a level, if your " + "new score is better than your old, your score will be adjusted by the " + "difference. Select Best Times from the Game menu to see your scores for " + "each level." +) + +# This will show the game won sequence for any of these levels +# -1 represents the last level +final_levels = [144, -1] + +def left(direction): + return ((direction << 1) | (direction >> 3)) & 15 + +def back(direction): + return ((direction << 2) | (direction >> 2)) & 15 + +def right(direction): + return ((direction << 3) | (direction >> 1)) & 15 + +def creature_id(tile_id): + return tile_id & ~3 + +def idx_dir(index): + return 1 << (index & 3) + +def dir_idx(direction): + return (0x30210 >> (direction * 2)) & 3 + +def creature_dir_id(tile_id): + return idx_dir(tile_id & 3) + +def cr_tile(tile_id, direction): + return tile_id | dir_idx(direction) + +def is_key(tile): + return TYPE_KEY_BLUE <= tile <= TYPE_KEY_YELLOW + +def is_boots(tile): + return TYPE_BOOTS_WATER <= tile <= TYPE_BOOTS_SLIDE + +def is_creature(tile): + return ((0x40 <= tile <= 0x63) or (TYPE_BLOCK <= tile <= TYPE_BLOCK + 3) or + (TYPE_CHIP_SWIMMING <= tile <= TYPE_CHIP_SWIMMING + 3) or + (TYPE_CHIP <= tile <= TYPE_CHIP + 3)) + +def is_door(tile): + return TYPE_DOOR_BLUE <= tile <= TYPE_DOOR_YELLOW diff --git a/Metro/Metro_RP2350_Chips_Challenge/device.py b/Metro/Metro_RP2350_Chips_Challenge/device.py new file mode 100755 index 000000000..d016f8090 --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/device.py @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +from point import Point + +class Device: + def __init__(self, button=None, device=None): + self.button = button if button else Point(0, 0) + self.device = device if device else Point(0, 0) diff --git a/Metro/Metro_RP2350_Chips_Challenge/dialog.py b/Metro/Metro_RP2350_Chips_Challenge/dialog.py new file mode 100755 index 000000000..0d3fe008d --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/dialog.py @@ -0,0 +1,532 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +from micropython import const +import displayio +import bitmaptools +from adafruit_display_text import bitmap_label +from adafruit_display_text.text_box import TextBox + +BORDER_STYLE_INSET = 0 +BORDER_STYLE_OUTSET = 1 +BORDER_STYLE_FLAT = 2 +BORDER_STYLE_LIGHT_OUTLINE = 3 +BORDER_STYLE_DARK_OUTLINE = 4 + +def add_border(bitmap, border_color_ul, border_color_br): + if border_color_ul is not None: + for x in range(bitmap.width): + bitmap[x, 0] = border_color_ul + for y in range(bitmap.height): + bitmap[0, y] = border_color_ul + if border_color_br is not None: + for x in range(bitmap.width): + bitmap[x, bitmap.height - 1] = border_color_br + for y in range(bitmap.height): + bitmap[bitmap.width - 1, y] = border_color_br + return bitmap + +def convert_padding(padding): + if isinstance(padding, int): # Top, Right, Bottom Left (same as CSS) + padding = { + "top": padding // 2, + "right": padding // 2, + "bottom": padding // 2, + "left": padding // 2 + } + elif isinstance(padding, (tuple, list)) and len(padding) == 2: # Top/Bottom, Left/Right + padding = { + "top": padding[0], + "right": padding[1], + "bottom": padding[0], + "left": padding[1] + } + elif isinstance(padding, (tuple, list)) and len(padding) == 4: # Top, Right, Bottom, Left + padding = { + "top": padding[0], + "right": padding[1], + "bottom": padding[2], + "left": padding[3] + } + return padding + +def text_bounding_box(text, font, line_spacing=0.75): + temp_label = bitmap_label.Label( + font, + text=text, + line_spacing=line_spacing, + background_tight=True + ) + return temp_label.bounding_box + +class InputFields: + + ALPHANUMERIC = const(0) + ALPHA = const(1) + NUMERIC = const(2) + + """Class to keep track of input fields in a dialog""" + def __init__(self): + self._input_fields = [] + self._active_field = 0 + + def add(self, label, field_type=ALPHANUMERIC, value=""): + value_type = int if isinstance(value, int) else str + if value in ("", 0): + value = " " + if value_type not in (str, int): + raise ValueError("value_type must be str or int") + key = label.lower().replace(" ", "_") + focused = len(self._input_fields) == 0 + self._input_fields.append({ + "key": key, + "label": label, + "font": None, + "value": str(value), + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "color_index": None, + "bgcolor_index": None, + "padding": 10, + "redraw": True, # This is to keep track of whether to redraw the field or not + "max_length": None, + "type": field_type, + "buffer": None, + "focused": focused, + "value_type": value_type, + }) + + def redraw_all(self): + for field in self._input_fields: + field["redraw"] = True + + def clear(self): + self._active_field = 0 + self._input_fields = [] + + def get_field(self, key): + for field in self._input_fields: + if field["key"] == key: + return field + return None + + def next_field(self): + self._input_fields[self._active_field]["focused"] = False + self._input_fields[self._active_field]["redraw"] = True + self._active_field = (self._active_field + 1) % len(self._input_fields) + self._input_fields[self._active_field]["focused"] = True + self._input_fields[self._active_field]["redraw"] = True + + def get_value(self, key): + field = self.get_field(key) + if field is None: + return None + value = field["value"] + if value == " ": + return "" if field["value_type"] == str else 0 + return field["value_type"](value) + + @property + def active_field(self): + return self._input_fields[self._active_field] + + @property + def active_field_value(self): + if self.active_field["value"] == " ": + return "" + return self.active_field["value"] + + @active_field_value.setter + def active_field_value(self, value): + if value == "": + value = " " + self.active_field["value"] = value + self.active_field["redraw"] = True + + @property + def fields(self): + return self._input_fields + +class Dialog: + def __init__(self, color_index, shader): + self._color_index = color_index + self.shader = shader + + def _reassign_indices(self, bitmap, foreground_color_index, background_color_index): + # This will reassign the indices in the bitmap to match the palette + new_bitmap = displayio.Bitmap(bitmap.width, bitmap.height, len(self.shader)) + if background_color_index is not None: + for x in range(bitmap.width): + for y in range(bitmap.height): + if bitmap[(x, y)] == 0: + new_bitmap[(x, y)] = background_color_index + if foreground_color_index is not None: + for x in range(bitmap.width): + for y in range(bitmap.height): + if bitmap[(x, y)] == 1: + new_bitmap[(x, y)] = foreground_color_index + return new_bitmap + + def _draw_button(self, buffer, text, font, x_position, y_position, + width=None, height=None, center_button=True, **kwargs): + del kwargs["center_dialog_vertically"] + del kwargs["center_dialog_horizontally"] + if "padding" not in kwargs: + kwargs["padding"] = 10 + return self.display_simple( + text, + font, + width, + height, + x_position, + y_position, + buffer, + border_dark_index=self._color_index["dark_gray"], + background_color_index=self._color_index["light_gray"], + center_dialog_horizontally=center_button, + center_dialog_vertically=False, + **kwargs) + + def _draw_background( + self, + x_position, + y_position, + width, + height, + buffer, + *, + border_style=BORDER_STYLE_OUTSET, + background_color_index=None, + border_light_index=None, + border_dark_index=None, + ): + # Draw a background for the dialog + # This will be a simple rectangle with a border + + if border_light_index is None: + # The index of the light border color in the palette + border_light_index = self._color_index["bounding_box_light"] + if border_dark_index is None: + # The index of the dark border color in the palette + border_dark_index = self._color_index["bounding_box_dark"] + if background_color_index is None: + background_color_index = self._color_index["dialog_background"] + + if border_style == BORDER_STYLE_OUTSET: + (border_color_ul, border_color_br) = (border_light_index, border_dark_index) + elif border_style == BORDER_STYLE_INSET: + border_color_ul, border_color_br = border_dark_index, border_light_index + elif border_style == BORDER_STYLE_DARK_OUTLINE: + border_color_ul, border_color_br = border_dark_index, border_dark_index + elif border_style == BORDER_STYLE_LIGHT_OUTLINE: + border_color_ul, border_color_br = border_light_index, border_light_index + else: + border_color_ul, border_color_br = None, None + + background_bitmap = displayio.Bitmap(width, height, len(self.shader)) + background_bitmap.fill(background_color_index) + background_bitmap = add_border(background_bitmap, border_color_ul, border_color_br) + bitmaptools.blit(buffer, background_bitmap, x_position, y_position) + + def display_simple( + self, + text, # the text to display in the dialog + font, # the font to use for the dialog + width, # the width of the dialog + height, # the height of the dialog + x_position, # the x coordinate the dialog should be centered on in the buffer + y_position, # the y coordinate the dialog should be centered on in the buffer + buffer, + *, + center_dialog_horizontally=False, # x position in center of the dialog + center_dialog_vertically=False, # y position in center of the dialog + horizontal_text_alignment=TextBox.ALIGN_CENTER, # The alignment of the text + center_text_vertically=True, # whether the text should be centered vertically + background_color_index=None, # the index of the background color in the palette + font_color_index=None, # the index of the font color in the palette + padding=10, # the padding around the text + border_light_index=None, + border_dark_index=None, + line_spacing=0.75, # Space between each line of text in pixels + border_style=BORDER_STYLE_OUTSET, # The style of the border + ): + #pylint: disable=too-many-locals, too-many-branches + + border_width = 1 + if horizontal_text_alignment is None: + horizontal_text_alignment = TextBox.ALIGN_CENTER + if font_color_index is None: + font_color_index = self._color_index["default_dialog_text_color"] + if background_color_index is None: + background_color_index = self._color_index["dialog_background"] + + padding = convert_padding(padding) + + if text is not None: + text_area_padding = (0, 0) + if width is None: + # Create a regular bitmap label with the text to get the width + text_width = text_bounding_box(text, font, line_spacing=line_spacing)[2] + text_area_padding = (-padding["left"], -padding["right"]) + else: + text_width = width - padding["right"] - padding["left"] - border_width * 2 + # Colors don't matter for bitmap fonts + text_area = TextBox( + font, + text_width, + TextBox.DYNAMIC_HEIGHT, + align=horizontal_text_alignment, + text=text, + background_tight=True, + line_spacing=line_spacing, + padding_left=text_area_padding[0], + padding_right=text_area_padding[1], + ) + + text_bmp = self._reassign_indices( + text_area.bitmap, font_color_index, background_color_index + ) + if width is None: + width = text_bmp.width + padding["right"] + padding["left"] + border_width * 2 + if height is None: + height = text_bmp.height + padding["top"] + padding["bottom"] + border_width * 2 + + text_bitmap_position = [padding["left"] + border_width, padding["top"] + border_width] + if center_text_vertically: + text_bitmap_position[1] = (height - text_bmp.height) // 2 + else: + text_bmp = None + if width is None: + width = padding["right"] + padding["left"] + border_width * 2 + if height is None: + height = padding["top"] + padding["bottom"] + border_width * 2 + + if x_position is None: + x_position = (buffer.width - width) // 2 + elif center_dialog_horizontally and x_position is not None: + x_position = x_position - width // 2 + + if y_position is None: + y_position = (buffer.height - height) // 2 + elif center_dialog_vertically and y_position is not None: + y_position = y_position - height // 2 + + # Draw the background + self._draw_background( + x_position, + y_position, + width, + height, + border_style=border_style, + background_color_index=background_color_index, + border_light_index=border_light_index, + border_dark_index=border_dark_index, + buffer=buffer, + ) + if text_bmp: + bitmaptools.blit( + buffer, text_bmp, x_position + text_bitmap_position[0], + y_position + text_bitmap_position[1] + ) + + # return the width and height of the dialog in a tuple + return width, height, text_bmp.height if text_bmp else 0 + + def display_message(self, text, font, width, height, x_position, y_position, buffer, **kwargs): + #pylint: disable=too-many-locals + button_font = font + button_text = "OK" + if "button_font" in kwargs: + button_font = kwargs.pop("button_font") + if "button_text" in kwargs: + button_text = kwargs.pop("button_text") + padding = convert_padding(kwargs.get("padding", 5)) + control_spacing = 5 + button_height = button_font.get_bounding_box()[1] + control_spacing + padding["bottom"] + + # Draw dialog and text + dialog_width, dialog_height, _ = self.display_simple( + text, + font, + width, + height, + x_position, + y_position, + buffer, + padding=( + padding["top"], padding["right"], + button_height + padding["bottom"], padding["left"] + ), + center_text_vertically=False, + border_light_index=self._color_index["light_gray"], + border_dark_index=self._color_index["black"], + **kwargs + ) + + if x_position is None: + if kwargs.get("center_dialog_horizontally", True): + x_position = buffer.width // 2 + else: + x_position = (buffer.width - dialog_width) // 2 + + # Draw a button + if y_position is None: + y_position = (buffer.height - dialog_height) // 2 + y_position += dialog_height - button_height + self._draw_button(buffer, button_text, button_font, x_position, y_position, **kwargs) + + def draw_field(self, field, first_draw=False): + # Draw a singular field + # A field should draw a label and a box to enter text + # The label should be on the left of the coordinates + # The box should be on the right of the coordinates + # The width and height should be the size of the box + # The font should be the font to use for the label and the text box + if isinstance(field["padding"], int): + field["padding"] = convert_padding(field["padding"]) + + if first_draw: + # draw the label + label = TextBox( + field["font"], + text_bounding_box(field["label"], field["font"])[2], + TextBox.DYNAMIC_HEIGHT, + align=TextBox.ALIGN_RIGHT, + text=field["label"], + background_tight=True, + line_spacing=0.75, + padding_left=-field["padding"]["left"], + padding_right=-field["padding"]["right"], + ) + label_bmp = self._reassign_indices( + label.bitmap, + field["color_index"], + field["bgcolor_index"], + ) + bitmaptools.blit( + field["buffer"], label_bmp, field["x"] - label_bmp.width - 3, field["y"] + ) + if field["redraw"]: + # draw the text box + # This will draw a border around the text box + textbox = TextBox( + field["font"], + field["width"], + TextBox.DYNAMIC_HEIGHT, + align=TextBox.ALIGN_LEFT, + text=field["value"], + line_spacing=0.75, + padding_left=field["padding"]["left"], + padding_right=field["padding"]["right"], + padding_top=-7, + padding_bottom=-1, + ) + textbox_bmp = self._reassign_indices( + textbox.bitmap, + field["color_index"], + field["bgcolor_index"], + ) + col_index = self._color_index + if field["focused"]: + border_color_ul, border_color_br = col_index["black"], col_index["black"] + else: + border_color_ul, border_color_br = col_index["light_gray"], col_index["light_gray"] + textbox_bmp = add_border(textbox_bmp, border_color_ul, border_color_br) + bitmaptools.blit(field["buffer"], textbox_bmp, field["x"], field["y"] - 2) + field["redraw"] = False + + def display_input(self, text, font, fields, buttons, width, + height, x_position, y_position, buffer, **kwargs): + #pylint: disable=too-many-locals + button_font = font + padding = 10 + if "button_font" in kwargs: + button_font = kwargs.pop("button_font") + padding = convert_padding(kwargs.get("padding", 10)) + control_spacing = 8 + button_height = button_font.get_bounding_box()[1] + control_spacing + padding["bottom"] + + # Calculate total field height + field_height = text_bounding_box(fields[0]["label"], font, line_spacing=0.75)[3] + field_area_height = (field_height + control_spacing )* len(fields) + + # Draw dialog (and text if present) + dialog_width, dialog_height, message_height = self.display_simple( + text, + font, + width, + height, + x_position, + y_position, + buffer, + padding=( + padding["top"], padding["right"], + field_area_height + button_height + padding["bottom"], padding["left"] + ), + center_text_vertically=False, + border_light_index=self._color_index["light_gray"], + border_dark_index=self._color_index["black"], + **kwargs + ) + + max_field_label_width = 0 + for field in fields: + max_field_label_width = max( + max_field_label_width, + text_bounding_box( + field["label"], font)[2] + padding["right"] + padding["left"] + ) + + if x_position is None: + if kwargs.get("center_dialog_horizontally", True): + x_position = buffer.width // 2 + else: + x_position = (buffer.width - dialog_width) // 2 + + if y_position is None: + y_position = buffer.height // 2 + if kwargs.get("center_dialog_vertically", True): + y_position -= dialog_height // 2 + + y_position += padding["top"] + message_height + + # Add field parameters and draw + field_width = 100 + y_position += control_spacing + field_x_position = (x_position + ( + max_field_label_width - (field_width + padding["right"] + padding["left"]) + ) // 2) + for field in fields: + field["font"] = font + field["width"] = field_width + field["height"] = field_height + field["y"] = y_position + field["x"] = field_x_position + field["color_index"] = self._color_index["default_dialog_text_color"] + field["bgcolor_index"] = self._color_index["dialog_background"] + field["padding"] = padding + field["max_length"] = 9 + field["buffer"] = buffer + y_position += field_height + control_spacing + self.draw_field(field, True) + + # Draw buttons + # Figure out the maximum width of the buttons by checking the bounding box of their text + total_button_width = 0 + for button_text in buttons: + total_button_width += text_bounding_box( + button_text, button_font)[2] + padding["right"] + padding["left"] + 2 + + button_spacing = (dialog_width - total_button_width) // (len(buttons) + 1) + if kwargs.get("center_dialog_horizontally", True): + x_position -= dialog_width // 2 + x_position += button_spacing + for button_text in buttons: + # Calculate X-position so that the buttons are spaced evenly apart and within the width + button_width, _, _ = self._draw_button( + buffer, button_text, button_font, x_position, + y_position, None, None, False, **kwargs + ) + x_position += button_spacing + button_width diff --git a/Metro/Metro_RP2350_Chips_Challenge/element.py b/Metro/Metro_RP2350_Chips_Challenge/element.py new file mode 100755 index 000000000..b472629bf --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/element.py @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +class Element: + def __init__(self, walkable=(0, 0, 0)): + self.chip_walk = walkable[0] + self.block_move = walkable[1] + self.creature_walk = walkable[2] + + def set_walk(self, chip_walk, block_move, creature_walk): + self.chip_walk = chip_walk + self.block_move = block_move + self.creature_walk = creature_walk diff --git a/Metro/Metro_RP2350_Chips_Challenge/fonts/Arial-8.pcf b/Metro/Metro_RP2350_Chips_Challenge/fonts/Arial-8.pcf new file mode 100755 index 000000000..bdc475829 Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/fonts/Arial-8.pcf differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/fonts/Arial-Bold-10.pcf b/Metro/Metro_RP2350_Chips_Challenge/fonts/Arial-Bold-10.pcf new file mode 100755 index 000000000..ea6a221ab Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/fonts/Arial-Bold-10.pcf differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/game.py b/Metro/Metro_RP2350_Chips_Challenge/game.py new file mode 100755 index 000000000..4d4c646a9 --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/game.py @@ -0,0 +1,855 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT + +from random import randint, random +from time import sleep +import sys +import math +import bitmaptools +import adafruit_imageload +import displayio +from databuffer import DataBuffer +from gamelogic import GameLogic +from point import Point +from definitions import victory_messages, winning_message, final_levels +from definitions import GM_NEWGAME, GM_NORMAL, GM_PAUSED, GM_LEVELWON, GM_CHIPDEAD, GM_GAMEWON +from definitions import GAMEPLAY_COMMANDS, MESSAGE_COMMANDS, PASSWORD_COMMANDS +from definitions import NONE, QUIT, NEXT_LEVEL, PREVIOUS_LEVEL, RESTART_LEVEL, GOTO_LEVEL +from definitions import PAUSE, OK, CANCEL, CHANGE_FIELDS, DELCHAR, SF_SHOWHINT +from definitions import TYPE_EMPTY, TYPE_EXIT, TYPE_EXITED_CHIP, TYPE_CHIP +from definitions import TYPE_EXIT_EXTRA_1, TYPE_EXIT_EXTRA_2, DOWN, TICKS_PER_SECOND +from keyboard import KeyboardBuffer +from adafruit_bitmap_font import bitmap_font +from dialog import Dialog, InputFields +from savestate import SaveState +from microcontroller import nvm + +# Colors must be colors in palette +LARGE_FONT = bitmap_font.load_font("fonts/Arial-Bold-10.pcf") +SMALL_FONT = bitmap_font.load_font("fonts/Arial-8.pcf") + +colors = { + "key_color": 0xAAFF00, # Light Green + "title_text_color": 0xFFFF00, # Yellow + "hint_text_color": 0x00FFFF, # Cyan + "default_dialog_text_color": 0x000000, # Black + "paused_text_color": 0xFF0000, # Red + "dialog_background": 0xFFFFFF, # Black + "bounding_box_light": 0xFFFFFF, # White + "bounding_box_dark": 0x808080, # Dark Gray + "tile_bg_color": 0xAABFAA, # Light Gray + "light_gray": 0xAABFAA, # Light Gray + "dark_gray": 0x808080, # Dark Gray + "black": 0x000000, # Black + "white": 0xFFFFFF, # White + "purple": 0xAA00ff # Purple +} + +# Image Files +SPRITESHEET_FILE = "bitmaps/spritesheet_24_keyed.bmp" +BACKGROUND_FILE = "bitmaps/background.bmp" +INFO_FILE = "bitmaps/info.bmp" +DIGITS_FILE = "bitmaps/digits.bmp" +CHIPEND_FILE = "bitmaps/chipend.bmp" + +# Layout Offsets +VIEWPORT_OFFSET = (1, 10) +INFO_OFFSET = (219, 10) +LEVEL_DIGITS_OFFSET = (INFO_OFFSET[0] + 26, INFO_OFFSET[1] + 23) +TIME_DIGITS_OFFSET = (INFO_OFFSET[0] + 26, INFO_OFFSET[1] + 69) +CHIPS_DIGITS_OFFSET = (INFO_OFFSET[0] + 26, INFO_OFFSET[1] + 123) +ITEMS_OFFSET = (INFO_OFFSET[0] + 2, INFO_OFFSET[1] + 153) +HINT_OFFSET = (INFO_OFFSET[0], INFO_OFFSET[1] + 96) + +def get_victory_message(deaths): + # go through victory message in reverse order + for i in range(5, -1, -1): + if deaths >= i: + return victory_messages.get(i, "Something went wrong!") + return None + +class Game: + def __init__(self, display, data_file, audio): + self._display = display + self._images = {} + self._buffers = {} + self._message_group = displayio.Group() + self._loading_group = displayio.Group() + self._tile_size = 24 # Default tile size (length and width) + self._digit_dims = (0, 0) + self._gamelogic = GameLogic(data_file, audio) # pylint: disable=too-many-function-args + self._databuffer = DataBuffer() + self._color_index = {} + self._init_display() + self._databuffer.set_data_structure({ + "info_drawn": False, + "title_visible": False, + "level": -1, + "time_left": 0, + "chips_needed": -1, + "keys": [False, False, False, False], + "boots": [False, False, False, False], + "viewport_tiles_top": [[-1]*9 for _ in range(9)], + "viewport_tiles_bottom": [[-1]*9 for _ in range(9)], + "hint_visible": False, + "pause_visible": False, + "message_shown": False, + }) + self.dialog = Dialog(self._color_index, self._shader) + self._input_fields = InputFields() + self._show_loading() + self._savestate = SaveState() + self._current_command_set = GAMEPLAY_COMMANDS + self._keyboard = KeyboardBuffer(self._current_command_set.keys()) + self._deaths = 0 + self._pw_request_level = None + + def _init_display(self): + # Set up the Shader and Color Index + self._shader = self._load_images() + self.extract_color_indices() + self._shader.make_transparent(self._color_index["key_color"]) + + # Create the Buffers and add key color for transparency + buffer_group = displayio.Group() + self._buffers["main"] = displayio.Bitmap(self._display.width, self._display.height, 256) + self._buffers["main"].fill(self._color_index["key_color"]) + self._buffers["loading"] = displayio.Bitmap(self._display.width, self._display.height, 256) + self._buffers["loading"].fill(self._color_index["key_color"]) + + buffer_group.append( + displayio.TileGrid( + self._images["background"], + pixel_shader=self._shader, + width=2, + height=2, + ) + ) + buffer_group.append( + displayio.TileGrid( + self._buffers["main"], + pixel_shader=self._shader, + ) + ) + buffer_group.append(self._message_group) + buffer_group.append(self._loading_group) + + self._display.root_group = buffer_group + + def _load_images(self): + self._images["spritesheet"], shader = adafruit_imageload.load(SPRITESHEET_FILE) + self._images["background"], _ = adafruit_imageload.load(BACKGROUND_FILE) + self._tile_size = self._images["spritesheet"].height // 16 + self._images["info"], _ = adafruit_imageload.load(INFO_FILE) + self._images["digits"], _ = adafruit_imageload.load(DIGITS_FILE) + self._images["chipend"], _ = adafruit_imageload.load(CHIPEND_FILE) + self._digit_dims = (self._images["digits"].width, self._images["digits"].height // 24) + return shader + + def extract_color_indices(self): + for key, color in colors.items(): + self._color_index[key] = self.get_color_index(color) + + def get_color_index(self, color, shader=None): + if shader is None: + shader = self._shader + for index, palette_color in enumerate(shader): + if palette_color == color: + return index + return None + + def reset_level(self, reset_deaths=True): + self._show_loading() + if reset_deaths: + self._deaths = 0 + self._gamelogic.reset() + self._remove_all_message_layers() + self._databuffer.reset(( + "viewport_tiles_top", + "level", + "time_left", + "chips_needed", + "keys", + "boots", + "viewport_tiles_top", + "title_visible", + "message_shown", + "pause_visible", + )) + self._databuffer.reset() + self._keyboard.clear() + self._pw_request_level = None + + def change_input_commands(self, commands): + previous_commands = self._current_command_set + self._current_command_set = commands + self._keyboard.set_valid_sequences(commands.keys()) + return previous_commands + + def input(self): + key = self._keyboard.get_key() + if key: + return self._current_command_set[key] + return NONE + + def wait_for_valid_input(self): + # Wait for a valid input (useful for dialogs) + while True: + key = self._keyboard.get_key() + if key: + return self._current_command_set[key] + + def save_level(self): + self._savestate.add_level_password( + self._gamelogic.current_level_number, + self._gamelogic.current_level.password + ) + + def tick(self): + """ + This is the main game function. It will be responsible for handling game states + and handling keyboard input. + """ + game_mode = self._gamelogic.get_game_mode() + if game_mode == GM_NEWGAME: + self._draw_frame() + self.reset_level() + level = nvm[0] + level_password = self._gamelogic.current_level.password + save_password = "" + for byte, _ in enumerate(level_password): + save_password += chr(nvm[1 + byte]) + if level_password != save_password: + level = 1 + self._gamelogic.set_level(level) + self.save_level() + + command = self._handle_commands() + + # Handle Game Modes + if game_mode == GM_NORMAL: + if command == PAUSE: + self._gamelogic.set_game_mode(GM_PAUSED) + self._draw_pause_screen() + self._gamelogic.advance_game(command) + elif game_mode == GM_CHIPDEAD: + self.show_message(self._gamelogic.get_death_message()) + self.reset_level(False) + self._gamelogic.set_level(self._gamelogic.current_level_number) + elif game_mode == GM_PAUSED: + if command == PAUSE: + self._draw_pause_screen(False) + self._gamelogic.revert_game_mode() + elif game_mode == GM_LEVELWON: + self.handle_win() + + # Draw every other tick to increase responsiveness + if not self._gamelogic.get_tick() or self._gamelogic.get_tick() & 1: + self._draw_frame() + + def _handle_commands(self): + command = self.input() + self._keyboard.clear() + # Handle Commands + if command == QUIT: + sys.exit() + elif command == NEXT_LEVEL: + if self._gamelogic.current_level_number < self._gamelogic.last_level: + if self._savestate.is_level_unlocked(self._gamelogic.current_level_number + 1): + self.reset_level() + self._gamelogic.inc_level() + self.save_level() + else: + self._input_fields.clear() + self._input_fields.add("Password", InputFields.ALPHANUMERIC) + self._databuffer.dataset["message_shown"] = False + self._pw_request_level = self._gamelogic.current_level_number + 1 + self.request_password() + elif command == PREVIOUS_LEVEL: + if self._gamelogic.current_level_number > 1: + if (self._gamelogic.current_level_number - 1 == 1 or + self._savestate.is_level_unlocked(self._gamelogic.current_level_number - 1)): + self.reset_level() + self._gamelogic.dec_level() + self.save_level() + else: + # If not, load the password dialog + self._input_fields.clear() + self._input_fields.add("Password", InputFields.ALPHANUMERIC) + self._databuffer.dataset["message_shown"] = False + self._pw_request_level = self._gamelogic.current_level_number - 1 + self.request_password() + elif command == RESTART_LEVEL: + self.reset_level() + self._gamelogic.set_level(self._gamelogic.current_level_number) + elif command == GOTO_LEVEL: + # We need to establish fields to keep track of where we are typing and the values + self._input_fields.clear() + self._input_fields.add("Level number", InputFields.NUMERIC, 0) + self._input_fields.add("Password", InputFields.ALPHANUMERIC) + self.request_password() + return command + + def show_score_tally(self): + time_left = (self._gamelogic.current_level.time_limit - + math.ceil(self._gamelogic.get_tick() / TICKS_PER_SECOND)) + time_left = max(time_left, 0) + level = self._gamelogic.current_level_number + score = self._savestate.calculate_score(level, time_left, self._deaths) + previous_score = self._savestate.level_score(self._gamelogic.current_level_number) + best_score = self._savestate.set_level_score(level, score[2], time_left) + score_message = "" + if previous_score[0] == 0: + score_message = "\n\nYou have established a time record for this level!" + elif best_score[1] < previous_score[1]: + difference = previous_score[1] - best_score[1] + score_message = ( + f"\n\nYou beat the previous time record by {difference} seconds!" + ) + elif best_score[0] > previous_score[0]: + difference = best_score[0] - previous_score[0] + score_message = ( + f"\n\nYou increased your score on this level by {difference} points!" + ) + # Update the score (with new total score) + score = self._savestate.calculate_score(level, time_left, self._deaths) + + message = f"""Level {self._gamelogic.current_level_number} Complete! +{get_victory_message(self._deaths)} + +Time Bonus: {score[0]} +Level Bonus: {score[1]} +Level Score: {score[2]} +Total Score: {score[3]}""" + message += score_message + self.show_message(message, button_text="Onward") + + def handle_win(self): + self._draw_frame() + # Show the level score tally + self.show_score_tally() + + # Check if we are at the last level and set game mode appropriately + level_check = self._gamelogic.current_level_number + if self._gamelogic.current_level_number == self._gamelogic.last_level: + level_check = -1 + if level_check in final_levels: + self._show_winning_sequence() + + # check for decade message + decade_message = self._gamelogic.get_decade_message() + if decade_message: + self.show_message(decade_message) + + if self._gamelogic.get_game_mode() == GM_GAMEWON: + # Show winning message + self.show_message(winning_message.format( + completed_levels=self._savestate.total_completed_levels, + total_score=self._savestate.total_score, + ), width=200) + self.change_input_commands(GAMEPLAY_COMMANDS) + else: + # Go to the next level + self.reset_level() + self._gamelogic.inc_level() + self.save_level() + + def show_message(self, message, *, button_text="OK", width=150): + buffer = self._add_message_layer() + self.dialog.display_message( + message, + SMALL_FONT, + width, + None, + None, + None, + buffer, + center_dialog_horizontally=True, + center_dialog_vertically=True, + button_text=button_text, + ) + current_commands = self.change_input_commands(MESSAGE_COMMANDS) + # Await input + self.wait_for_valid_input() + # Clear message + self._remove_message_layer() + # Set input commands to previous + self.change_input_commands(current_commands) + # Maybe remove item from sequence later + + def request_password(self): + #pylint: disable=too-many-branches + current_commands = self.change_input_commands(PASSWORD_COMMANDS) + self._draw_pause_screen() + while True: + command = NONE + while command not in (OK, CANCEL): + self._draw_password_dialog() + command = self.wait_for_valid_input() + if command == CHANGE_FIELDS: + self._input_fields.next_field() + elif command == DELCHAR: + self._input_fields.active_field_value = ( + self._input_fields.active_field_value[:-1] + ) + elif isinstance(command, str): + command = command.upper() + active_field = self._input_fields.active_field + if (active_field["max_length"] is None or + 0 <= len(active_field["value"]) < active_field["max_length"]): + if active_field["type"] == InputFields.NUMERIC and command.isdigit(): + self._input_fields.active_field_value += command + elif active_field["type"] == InputFields.ALPHA and command.isalpha(): + self._input_fields.active_field_value += command + elif active_field["type"] == InputFields.ALPHANUMERIC: + self._input_fields.active_field_value += command + if command == OK: + level = self._input_fields.get_value("level_number") + if level is None and self._pw_request_level is not None: + level = self._pw_request_level + password = self._input_fields.get_value("password") + if level == 0 and self._savestate.find_unlocked_level(password) is not None: + level = self._savestate.find_unlocked_level(password) + if not 0 < level <= self._gamelogic.last_level: + self.show_message("That is not a valid level number.") + elif (level > 1 and password and + self._gamelogic.current_level.passwords[level] != password): + self.show_message("You must enter a valid password.") + elif (level != 1 and self._savestate.is_level_unlocked(level) and + self._savestate.find_unlocked_level(level) is None + and self._savestate.find_unlocked_level(password) is None): + self.show_message("You must enter a valid password.") + else: + self._remove_all_message_layers() + self.change_input_commands(current_commands) + self.reset_level() + self._gamelogic.set_level(level) + self.save_level() + return + elif command == CANCEL: + self._remove_all_message_layers() + self.change_input_commands(current_commands) + return + + def _draw_number(self, value, offset, yellow_condition = None): + yellow = False + if yellow_condition is not None: + yellow = yellow_condition(value) + + buffer = self._buffers["main"] + + if value < 0: + # All digits are hyphens + for slot in range(3): + bitmaptools.blit( + buffer, + self._images["digits"], + offset[0] + slot * self._digit_dims[0], + offset[1], + 0, + 0, self._digit_dims[0], + self._digit_dims[1] + ) + return + + color_offset = 0 if yellow else self._digit_dims[1] * 12 + + calc_value = value + for slot in range(3): + if (value < 100 and slot == 0) or (value < 10 and slot == 1): + tile_offset = self._digit_dims[1] # a space + else: + tile_offset = (11 - (calc_value // (10 ** (2 - slot)))) * self._digit_dims[1] + calc_value -= (calc_value // (10 ** (2 - slot)) * (10 ** (2 - slot))) + bitmaptools.blit( + buffer, + self._images["digits"], + offset[0] + slot * self._digit_dims[0], + offset[1], + 0, + tile_offset + color_offset, self._digit_dims[0], + tile_offset + self._digit_dims[1] + color_offset + ) + + def _add_message_layer(self): + # Add the message layer to the display group + # Erase any existing stuff + + buffer = displayio.Bitmap(self._display.width, self._display.height, 256) + buffer.fill(self._color_index["key_color"]) + + self._message_group.append( + displayio.TileGrid( + buffer, + pixel_shader=self._shader, + ) + ) + + return buffer + + def _remove_message_layer(self): + # Remove the message layer from the display group + if len(self._message_group) == 0: + return + self._message_group.pop() + + def _remove_all_message_layers(self): + # Remove all message layers from the display group + while len(self._message_group) > 0: + self._message_group.pop() + + def _show_loading(self): + while len(self._loading_group) > 0: + self._loading_group.pop() + self.dialog.display_simple( + "Loading...", + LARGE_FONT, + None, + None, + None, + None, + self._buffers["loading"], + center_dialog_horizontally=True, + background_color_index=self._color_index["white"], + font_color_index=self._color_index["purple"], + padding=10, + ) + self._loading_group.append( + displayio.TileGrid( + self._buffers["loading"], + pixel_shader=self._shader, + ) + ) + + def _show_winning_sequence(self): + #pylint: disable=too-many-locals + self._gamelogic.set_game_mode(GM_GAMEWON) + + def get_frame_image(frame): + # Create a tile sized bitmap + tile_buffer = displayio.Bitmap(self._tile_size, self._tile_size, 256) + self._draw_tile(tile_buffer, 0, 0, frame[0], frame[1]) + return tile_buffer + + # Get chips coordinates + chip = self._gamelogic.get_chip_coords_in_viewport() + viewport_size = self._tile_size * 9 + + # Get centered screen coordinates of chip + chip_position = Point( + VIEWPORT_OFFSET[0] + chip.x * self._tile_size + self._tile_size // 2, + VIEWPORT_OFFSET[1] + chip.y * self._tile_size + self._tile_size // 2 + ) + + viewport_center = Point( + VIEWPORT_OFFSET[0] + viewport_size // 2 - 1, + VIEWPORT_OFFSET[1] + viewport_size // 2 - 1 + ) + + # Chip Frames + frames = { + "cheering": (TYPE_EXITED_CHIP, TYPE_EMPTY), + "standing_1": (TYPE_CHIP + DOWN, TYPE_EXIT), + "standing_2": (TYPE_CHIP + DOWN, TYPE_EXIT_EXTRA_1), + "standing_3": (TYPE_CHIP + DOWN, TYPE_EXIT_EXTRA_2), + } + + # Chip Sequences + zoom_sequence = ( + get_frame_image(frames["standing_1"]), + get_frame_image(frames["standing_2"]), + get_frame_image(frames["standing_3"]), + ) + + cheer_sequence = ( + get_frame_image(frames["cheering"]), + get_frame_image(frames["standing_1"]), + ) + + viewport_upper_left = Point( + VIEWPORT_OFFSET[0], + VIEWPORT_OFFSET[1] + ) + viewport_lower_right = Point( + VIEWPORT_OFFSET[0] + viewport_size, + VIEWPORT_OFFSET[1] + viewport_size + ) + + for i in range(32): + source_bmp = zoom_sequence[i % len(zoom_sequence)] + scale = 1 + ((i + 1) / 32) * 8 + scaled_tile_size = math.ceil(self._tile_size * scale) + x = chip_position.x + y = chip_position.y + + # Make sure the scaled tile is within the viewport + scaled_tile_upper_left = Point( + x - scaled_tile_size // 2, + y - scaled_tile_size // 2 + ) + scaled_tile_lower_right = Point( + x + scaled_tile_size // 2, + y + scaled_tile_size // 2 + ) + if scaled_tile_upper_left.y < viewport_upper_left.y: + y += viewport_upper_left.y - scaled_tile_upper_left.y + elif scaled_tile_lower_right.y > viewport_lower_right.y: + y -= scaled_tile_lower_right.y - viewport_lower_right.y + if scaled_tile_upper_left.x < viewport_upper_left.x: + x += viewport_upper_left.x - scaled_tile_upper_left.x + elif scaled_tile_lower_right.x > viewport_lower_right.x: + x -= scaled_tile_lower_right.x - viewport_lower_right.x + + bitmaptools.rotozoom(self._buffers["main"], source_bmp, ox=x, oy=y, scale=scale) + sleep(0.1) + + for i in range(randint(16, 20)): + source_bmp = cheer_sequence[i % len(cheer_sequence)] + bitmaptools.rotozoom( + self._buffers["main"], + source_bmp, + ox=viewport_center.x, + oy=viewport_center.y, + scale=9 + ) + sleep(random() * 0.5 + 0.25) # Sleep for a random time between 0.25 and 0.75 seconds + + bitmaptools.blit( + self._buffers["main"], + self._images["chipend"], + VIEWPORT_OFFSET[0], + VIEWPORT_OFFSET[1], + ) + self.show_message("Great Job Chip! You did it! You finished the challenge!") + + def _hide_loading(self): + while len(self._loading_group) > 0: + self._loading_group.pop() + self._buffers["loading"].fill(self._color_index["key_color"]) + + def _draw_title_dialog(self): + if self._gamelogic.get_game_mode() != GM_NORMAL: + return + + data = self._databuffer.dataset + if self._gamelogic.get_tick() > 0: + if data["title_visible"]: + data["title_visible"] = False + self._remove_message_layer() + return + + if not data["title_visible"]: + data["title_visible"] = True + text = ( + self._gamelogic.current_level.title + + "\nPassword: " + + self._gamelogic.current_level.password + ) + buffer = self._add_message_layer() + self.dialog.display_simple( + text, + LARGE_FONT, + None, + None, + VIEWPORT_OFFSET[0] + 108, + 160, + buffer, + center_dialog_horizontally=True, + background_color_index=self._color_index["black"], + font_color_index=self._color_index["title_text_color"], + padding=10, + ) + self._hide_loading() + + def _draw_password_dialog(self): + data = self._databuffer.dataset + message = None + if not data["message_shown"]: + data["message_shown"] = True + buttons = ("OK", "Cancel") + if self._pw_request_level is not None: + message = f"Enter a password\nfor level {self._pw_request_level}." + else: + message = "Enter a level number\n and/or password." + buffer = self._add_message_layer() + self.dialog.display_input( + message, + SMALL_FONT, + self._input_fields.fields, + buttons, + 200, + None, + None, + None, + buffer, + center_dialog_horizontally=True, + center_dialog_vertically=True, + ) + + # Update fields if needed + for field in self._input_fields.fields: + if field["redraw"]: + self.dialog.draw_field(field) + + def _draw_hint(self): + data = self._databuffer.dataset + if not self._gamelogic.status & SF_SHOWHINT: + if data["hint_visible"]: + data["hint_visible"] = False + self._remove_message_layer() + return + + if not data["hint_visible"]: + data["hint_visible"] = True + buffer = self._add_message_layer() + self.dialog.display_simple( + "Hint: " + self._gamelogic.current_level.hint, + SMALL_FONT, + 100, + 120, + HINT_OFFSET[0], + HINT_OFFSET[1], + buffer, + center_text_vertically=False, + font_color_index=self._color_index["hint_text_color"], + background_color_index=self._color_index["black"], + padding=10, + line_spacing=0.75, + ) + + def _draw_pause_screen(self, show=True): + data = self._databuffer.dataset + if show: + if not data["pause_visible"]: + data["pause_visible"] = True + buffer = self._add_message_layer() + self.dialog.display_simple( + "Paused", + LARGE_FONT, + 216, + 216, + VIEWPORT_OFFSET[0], + VIEWPORT_OFFSET[1], + buffer, + font_color_index=self._color_index["paused_text_color"], + background_color_index=self._color_index["black"], + padding=10, + line_spacing=5, + ) + return + + if data["pause_visible"]: + data["pause_visible"] = False + self._remove_message_layer() + + def _draw_tile(self, buffer, x, y, top_tile, bottom_tile): + # Create a bitmap of the tile size + tile_size = self._tile_size + if 0xD0 <= top_tile <= 0xD3: + top_tile -= 0xC2 + + # Bottom Layer + if top_tile > 0x40 and bottom_tile != TYPE_EMPTY: # Bottom Tile not visible + if 0xD0 <= bottom_tile <= 0xD3: + bottom_tile -= 0xC2 + top_tile += 48 # Make top tile transparent + x_src = (bottom_tile // 16) * tile_size + y_src = (bottom_tile % 16) * tile_size + bitmaptools.blit( + buffer, self._images["spritesheet"], x, y, x_src, y_src, + x_src + tile_size, y_src + tile_size + ) + + # Top Layer + x_src = (top_tile // 16) * tile_size + y_src = (top_tile % 16) * tile_size + bitmaptools.blit( + buffer, self._images["spritesheet"], x, y, x_src, y_src, + x_src + tile_size, y_src + tile_size, + skip_source_index=self._color_index["key_color"] + ) + + def _draw_frame(self): + """ + This will be responsible for drawing everything to the buffer. + """ + #pylint: disable=too-many-locals, too-many-branches + game_mode = self._gamelogic.get_game_mode() + buffer = self._buffers["main"] + data = self._databuffer.dataset + + if game_mode in (GM_NORMAL, GM_LEVELWON, GM_CHIPDEAD, GM_PAUSED): + # Draw Info Window + if not data["info_drawn"]: + data["info_drawn"] = True + bitmaptools.blit(buffer, self._images["info"], INFO_OFFSET[0], INFO_OFFSET[1]) + + # Draw Level Number + if self._gamelogic.current_level_number != data["level"]: + data["level"] = self._gamelogic.current_level_number + self._draw_number(self._gamelogic.current_level_number, LEVEL_DIGITS_OFFSET) + + # Draw Time Left + time_elapsed = math.ceil(self._gamelogic.get_tick() / TICKS_PER_SECOND) + time_left = self._gamelogic.current_level.time_limit - time_elapsed + if self._gamelogic.current_level.time_limit == 0: + time_left = -1 + if time_left != data["time_left"]: + data["time_left"] = time_left + self._draw_number( + time_left, + TIME_DIGITS_OFFSET, + lambda x: x <= 15, + ) + + # Draw Chips Needed + if self._gamelogic.get_chips_needed() != data["chips_needed"]: + data["chips_needed"] = self._gamelogic.get_chips_needed() + self._draw_number( + self._gamelogic.get_chips_needed(), + CHIPS_DIGITS_OFFSET, lambda x: x < 1 + ) + + # Draw Keys Collected + keys_images = (0x65, 0x64, 0x67, 0x66) + for i in range(4): + if self._gamelogic.keys[i] != data["keys"][i]: + data["keys"][i] = self._gamelogic.keys[i] + tile_id = keys_images[i] if self._gamelogic.keys[i] else TYPE_EMPTY + self._draw_tile( + buffer, ITEMS_OFFSET[0] + i * self._tile_size, + ITEMS_OFFSET[1], tile_id, 0 + ) + + # Draw Boots Collected + boot_images = (0x6A, 0x6B, 0x69, 0x68) + for i in range(4): + if self._gamelogic.boots[i] != data["boots"][i]: + data["boots"][i] = self._gamelogic.boots[i] + tile_id = boot_images[i] if self._gamelogic.boots[i] else TYPE_EMPTY + self._draw_tile( + buffer, ITEMS_OFFSET[0] + i * self._tile_size, + ITEMS_OFFSET[1] + self._tile_size, tile_id, 0 + ) + + if game_mode in (GM_NORMAL, GM_LEVELWON): + view_port = self._gamelogic.get_view_port() + for x_pos, x in enumerate(range(view_port.x - 4, view_port.x + 5)): + for y_pos, y in enumerate(range(view_port.y - 4, view_port.y + 5)): + tile_position = Point(x, y) + cell = self._gamelogic.current_level.get_cell(tile_position) + top_tile = cell.top.id + bottom_tile = cell.bottom.id + if (data["viewport_tiles_top"][x_pos][y_pos] != top_tile or + (top_tile >= 0x40 and + data["viewport_tiles_bottom"][x_pos][y_pos] != bottom_tile)): + data["viewport_tiles_top"][x_pos][y_pos] = top_tile + data["viewport_tiles_bottom"][x_pos][y_pos] = bottom_tile + self._draw_tile( + buffer, x_pos * self._tile_size + VIEWPORT_OFFSET[0], + y_pos * self._tile_size + VIEWPORT_OFFSET[1], top_tile, bottom_tile + ) + + self._draw_title_dialog() + self._draw_hint() diff --git a/Metro/Metro_RP2350_Chips_Challenge/gamelogic.py b/Metro/Metro_RP2350_Chips_Challenge/gamelogic.py new file mode 100755 index 000000000..e62ff21dc --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/gamelogic.py @@ -0,0 +1,1350 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +# SPDX-License-Identifier: GPL-1.0-or-later +# Based on Pocket Chip's Challenge (https://github.com/makermelissa/PocketChipsChallenge) +# and Tile World 1.3.2 (https://www.muppetlabs.com/~breadbox/software/tworld/) +# +# pylint: disable=too-many-lines, wildcard-import, unused-wildcard-import +import random +from definitions import * +from creature import Creature +from element import Element +from level import Level, Tile +from point import Point +from slip import Slip + +def is_ice(tile): + return tile == TYPE_ICE or TYPE_ICEWALL_SOUTHEAST <= tile <= TYPE_ICEWALL_NORTHEAST + +def is_slide(tile): + return (tile in (TYPE_SLIDE_SOUTH, TYPE_SLIDE_RANDOM) or + TYPE_SLIDE_NORTH <= tile <= TYPE_SLIDE_WEST) + +def get_slide_dir(floor): + if floor == TYPE_SLIDE_NORTH: + return NORTH + elif floor == TYPE_SLIDE_WEST: + return WEST + elif floor == TYPE_SLIDE_SOUTH: + return SOUTH + elif floor == TYPE_SLIDE_EAST: + return EAST + elif floor == TYPE_SLIDE_RANDOM: + return 1 << random.randint(0, 3) + return NONE + +def ice_wall_turn(floor, direction): + if floor == TYPE_ICEWALL_NORTHEAST: + return EAST if direction == SOUTH else NORTH if direction == WEST else direction + elif floor == TYPE_ICEWALL_SOUTHWEST: + return WEST if direction == NORTH else SOUTH if direction == EAST else direction + elif floor == TYPE_ICEWALL_NORTHWEST: + return WEST if direction == SOUTH else NORTH if direction == EAST else direction + elif floor == TYPE_ICEWALL_SOUTHEAST: + return EAST if direction == NORTH else SOUTH if direction == WEST else direction + return direction + +def random_p(array, level): + for index in range(5 - level, level + 1): + number = random.randint(0, index - 1) + array[number], array[index - 1] = array[index - 1], array[number] + +class GameLogic: + """ + A class to represent the state of the game as well as + control all the game movements and actions. + """ + def __init__(self, data_file, audio): + self._audio = audio + self._tileset = [Element() for _ in range(0x70)] + self._chip = Creature() + self._create_tileset() + self._game_mode = [GM_NEWGAME] + self.last_level = 149 + self._chip.type = 0 + self._sliplist = [] + self._creature_pool = [] + self._block_pool = [] + self.current_level = Level(data_file) + self._current_input = NONE + self._chips_needed = 0 + self._moving = False + self.dead_creatures = 0 + self.dead_blocks = 0 + self.keys = [0] * 4 + self.boots = [False] * 4 + self.status = SF_CHIPOKAY + self.current_level_number = 2 + self._current_time = 0 + self._last_slip_dir = NONE + self._controller_dir = NONE + self._time_limit = 0 + + def dec_level(self): + if self.current_level_number > 1: + self.set_level(self.current_level_number - 1) + + def inc_level(self): + if self.current_level_number < self.last_level: + self.set_level(self.current_level_number + 1) + + def set_level(self, level): + self.set_game_mode(GM_LOADING) + if not 1 <= level <= self.last_level: + level = 1 + self.reset() + self.current_level_number = level + self.current_level.load(level) + self.last_level = self.current_level.last_level + self._time_limit = int(self.current_level.time_limit * + TICKS_PER_SECOND * (1000 / SECOND_LENGTH)) + self._chips_needed = self.current_level.chips_required + self._extract_creatures() + self.set_game_mode(GM_NORMAL) + + def _possesion(self, key): + return { + TYPE_KEY_BLUE: self.keys[BLUE_KEY], + TYPE_KEY_RED: self.keys[RED_KEY], + TYPE_KEY_YELLOW: self.keys[YELLOW_KEY], + TYPE_KEY_GREEN: self.keys[GREEN_KEY], + TYPE_DOOR_BLUE: self.keys[BLUE_KEY], + TYPE_DOOR_RED: self.keys[RED_KEY], + TYPE_DOOR_YELLOW: self.keys[YELLOW_KEY], + TYPE_DOOR_GREEN: self.keys[GREEN_KEY], + TYPE_BOOTS_WATER: self.boots[WATER_BOOTS], + TYPE_BOOTS_FIRE: self.boots[FIRE_BOOTS], + TYPE_BOOTS_ICE: self.boots[ICE_BOOTS], + TYPE_BOOTS_SLIDE: self.boots[SUCTION_BOOTS], + TYPE_ICE: self.boots[ICE_BOOTS], + TYPE_ICEWALL_NORTHWEST: self.boots[ICE_BOOTS], + TYPE_ICEWALL_NORTHEAST: self.boots[ICE_BOOTS], + TYPE_ICEWALL_SOUTHWEST: self.boots[ICE_BOOTS], + TYPE_ICEWALL_SOUTHEAST: self.boots[ICE_BOOTS], + TYPE_SLIDE_NORTH: self.boots[SUCTION_BOOTS], + TYPE_SLIDE_WEST: self.boots[SUCTION_BOOTS], + TYPE_SLIDE_SOUTH: self.boots[SUCTION_BOOTS], + TYPE_SLIDE_EAST: self.boots[SUCTION_BOOTS], + TYPE_SLIDE_RANDOM: self.boots[SUCTION_BOOTS], + TYPE_FIRE: self.boots[FIRE_BOOTS], + TYPE_WATER: self.boots[WATER_BOOTS] + }.get(key, False) + + def _collect(self, key): + def add_key(key): + self.keys[key] += 1 + + def set_boots(boot): + self.boots[boot] = True + + functions = { + TYPE_KEY_BLUE: lambda: add_key(BLUE_KEY), + TYPE_KEY_RED: lambda: add_key(RED_KEY), + TYPE_KEY_YELLOW: lambda: add_key(YELLOW_KEY), + TYPE_KEY_GREEN: lambda: add_key(GREEN_KEY), + TYPE_DOOR_BLUE: lambda: add_key(BLUE_KEY), + TYPE_DOOR_RED: lambda: add_key(RED_KEY), + TYPE_DOOR_YELLOW: lambda: add_key(YELLOW_KEY), + TYPE_DOOR_GREEN: lambda: add_key(GREEN_KEY), + TYPE_BOOTS_WATER: lambda: set_boots(WATER_BOOTS), + TYPE_BOOTS_FIRE: lambda: set_boots(FIRE_BOOTS), + TYPE_BOOTS_ICE: lambda: set_boots(ICE_BOOTS), + TYPE_BOOTS_SLIDE: lambda: set_boots(SUCTION_BOOTS), + TYPE_ICE: lambda: set_boots(ICE_BOOTS), + TYPE_ICEWALL_NORTHWEST: lambda: set_boots(ICE_BOOTS), + TYPE_ICEWALL_NORTHEAST: lambda: set_boots(ICE_BOOTS), + TYPE_ICEWALL_SOUTHWEST: lambda: set_boots(ICE_BOOTS), + TYPE_ICEWALL_SOUTHEAST: lambda: set_boots(ICE_BOOTS), + TYPE_SLIDE_NORTH: lambda: set_boots(SUCTION_BOOTS), + TYPE_SLIDE_WEST: lambda: set_boots(SUCTION_BOOTS), + TYPE_SLIDE_SOUTH: lambda: set_boots(SUCTION_BOOTS), + TYPE_SLIDE_EAST: lambda: set_boots(SUCTION_BOOTS), + TYPE_SLIDE_RANDOM: lambda: set_boots(SUCTION_BOOTS), + TYPE_FIRE: lambda: set_boots(FIRE_BOOTS), + TYPE_WATER: lambda: set_boots(WATER_BOOTS) + } + if key in functions: + functions[key]() + + def _discard(self, key): + def rem_key(key): + self.keys[key] -= 1 + + def unset_boots(boot): + self.boots[boot] = False + + functions = { + TYPE_KEY_BLUE: lambda: rem_key(BLUE_KEY), + TYPE_KEY_RED: lambda: rem_key(RED_KEY), + TYPE_KEY_YELLOW: lambda: rem_key(YELLOW_KEY), + TYPE_DOOR_BLUE: lambda: rem_key(BLUE_KEY), + TYPE_DOOR_RED: lambda: rem_key(RED_KEY), + TYPE_DOOR_YELLOW: lambda: rem_key(YELLOW_KEY), + TYPE_BOOTS_WATER: lambda: unset_boots(WATER_BOOTS), + TYPE_BOOTS_FIRE: lambda: unset_boots(FIRE_BOOTS), + TYPE_BOOTS_ICE: lambda: unset_boots(ICE_BOOTS), + TYPE_BOOTS_SLIDE: lambda: unset_boots(SUCTION_BOOTS), + TYPE_ICE: lambda: unset_boots(ICE_BOOTS), + TYPE_ICEWALL_NORTHWEST: lambda: unset_boots(ICE_BOOTS), + TYPE_ICEWALL_NORTHEAST: lambda: unset_boots(ICE_BOOTS), + TYPE_ICEWALL_SOUTHWEST: lambda: unset_boots(ICE_BOOTS), + TYPE_ICEWALL_SOUTHEAST: lambda: unset_boots(ICE_BOOTS), + TYPE_SLIDE_NORTH: lambda: unset_boots(SUCTION_BOOTS), + TYPE_SLIDE_WEST: lambda: unset_boots(SUCTION_BOOTS), + TYPE_SLIDE_SOUTH: lambda: unset_boots(SUCTION_BOOTS), + TYPE_SLIDE_EAST: lambda: unset_boots(SUCTION_BOOTS), + TYPE_SLIDE_RANDOM: lambda: unset_boots(SUCTION_BOOTS), + TYPE_FIRE: lambda: unset_boots(FIRE_BOOTS), + TYPE_WATER: lambda: unset_boots(WATER_BOOTS) + } + if key in functions: + functions[key]() + + def get_view_port(self): + """ + This function lines up the edge of the map to the edge of the screen + """ + ptTile = Point(self._chip.cur_pos.x, self._chip.cur_pos.y) + if ptTile.x <= 4: + ptTile.x = 4 + elif ptTile.x >= 27: + ptTile.x = 27 + if ptTile.y <= 4: + ptTile.y = 4 + elif ptTile.y >= 27: + ptTile.y = 27 + return ptTile + + def get_chip_coords_in_viewport(self): + chip = Point(self._chip.cur_pos.x, self._chip.cur_pos.y) + viewport = self.get_view_port() + x_pos = 4 + y_pos = 4 + if chip.x < viewport.x: + x_pos = chip.x + elif chip.x > viewport.x: + x_pos = chip.x - viewport.x + 4 + if chip.y < viewport.y: + y_pos = chip.y + elif chip.y > viewport.y: + y_pos = chip.y - viewport.y + 4 + return Point(x_pos, y_pos) + + def _can_make_move(self, creature, direction, flags): + #pylint: disable=too-many-branches, too-many-return-statements + ptTo = creature.get_tile_in_dir(direction) + if not (0 <= ptTo.x < 32 and 0 <= ptTo.y < 32): + return False + + if not flags & CMM_NOLEAVECHECK: + nBottomTile = self.current_level.get_cell(creature.cur_pos).bottom.id + if nBottomTile == TYPE_WALL_NORTH and direction == NORTH: + return False + elif nBottomTile == TYPE_WALL_WEST and direction == WEST: + return False + elif nBottomTile == TYPE_WALL_SOUTH and direction == SOUTH: + return False + elif nBottomTile == TYPE_WALL_EAST and direction == EAST: + return False + elif nBottomTile == TYPE_WALL_SOUTHEAST and direction in (SOUTH, EAST): + return False + elif nBottomTile == TYPE_BEARTRAP and not creature.state & CS_RELEASED: + return False + + if creature.type == TYPE_CHIP: + floor = self._floor_at(ptTo) + if not self._tileset[floor].chip_walk & direction: + return False + if (floor == TYPE_SOCKET and self._chips_needed > 0): + return False + if (is_door(floor) and not self._possesion(floor)): + return False + if is_creature(self.current_level.get_cell(ptTo).top.id): + tile_id = creature_id(self.current_level.get_cell(ptTo).top.id) + if tile_id in (TYPE_CHIP, TYPE_CHIP_SWIMMING, TYPE_BLOCK): + return False + if floor in (TYPE_HIDDENWALL_TEMP, TYPE_BLUEWALL_REAL): + if not flags & CMM_NOEXPOSEWALLS: + self._set_floor_at(ptTo, TYPE_WALL) + return False + if floor == TYPE_BLOCK_STATIC: + if not self._push_block(ptTo, direction, flags): + return False + elif flags & CMM_NOPUSHING: + return False + if ((flags & CMM_TELEPORTPUSH) and self._floor_at(ptTo) == TYPE_BLOCK_STATIC and + self.current_level.get_cell(ptTo).bottom.id == TYPE_EMPTY): + return True + return self._can_make_move(creature, direction, flags | CMM_NOPUSHING) + elif creature.type == TYPE_BLOCK: + floor = self.current_level.get_cell(ptTo).top.id + if is_creature(floor): + tile_id = creature_id(floor) + return tile_id in (TYPE_CHIP, TYPE_CHIP_SWIMMING) + if not self._tileset[floor].block_move & direction: + return False + else: + floor = self.current_level.get_cell(ptTo).top.id + if is_creature(floor): + tile_id = creature_id(floor) + if tile_id in (TYPE_CHIP, TYPE_CHIP_SWIMMING): + floor = self.current_level.get_cell(ptTo).bottom.id + if is_creature(floor): + tile_id = creature_id(floor) + return tile_id in (TYPE_CHIP, TYPE_CHIP_SWIMMING) + if is_creature(floor): + if ((flags & CMM_CLONECANTBLOCK) and + floor == cr_tile(creature.type, creature.direction)): + return True + return False + if not self._tileset[floor].creature_walk & direction: + return False + if floor == TYPE_FIRE and (type in (TYPE_BUG, TYPE_WALKER)): + if not flags & CMM_NOFIRECHECK: + return False + + if self.current_level.get_cell(ptTo).bottom.id == TYPE_CLONEMACHINE: + return False + + return True + + def _push_block(self, ptPos, direction, flags): + creature = self._get_block(ptPos) + if creature is None: + return False + if creature.state & (CS_SLIP | CS_SLIDE): + slip_dir = self._get_slip_dir(creature) + if direction == slip_dir or direction == back(slip_dir): + if not flags & CMM_TELEPORTPUSH: + return False + return False + if (not (flags & CMM_TELEPORTPUSH) and + self.current_level.get_cell(ptPos).bottom.id == TYPE_BLOCK_STATIC): + self.current_level.get_cell(ptPos).bottom.id = TYPE_EMPTY + if not flags & CMM_NODEFERBUTTONS: + creature.state |= CS_DEFERPUSH + result = self._advance_creature(creature, direction) + if not flags & CMM_NODEFERBUTTONS: + creature.state &= ~CS_DEFERPUSH + if not result: + creature.state &= ~(CS_SLIP | CS_SLIDE) + return result + + def _update_creature(self, creature): + if creature.hidden: + return + tile = self.current_level.get_cell(creature.cur_pos).top + creature_type = creature.type + if creature_type == TYPE_BLOCK: + tile.id = TYPE_BLOCK_STATIC + return + elif creature_type == TYPE_CHIP: + if self._get_chip_status(): + if self._get_chip_status() == SF_CHIPBURNED: + tile.id = TYPE_CHIP_BURNED + return + elif self._get_chip_status() == SF_CHIPDROWNED: + tile.id = TYPE_CHIP_DROWNED + return + elif self._get_chip_status() == SF_CHIPBOMBED: + tile.id = TYPE_CHIP_BOMBED + return + elif self.current_level.get_cell(creature.cur_pos).bottom.id == TYPE_WATER: + creature_type = TYPE_CHIP_SWIMMING + + direction = creature.direction + if creature.state & CS_TURNING: + direction = right(direction) + tile.id = cr_tile(creature_type, direction) + tile.state = 0 + + def re_set_buttons(self): + for x in range(32): + for y in range(32): + self.current_level.get_cell(Point(x, y)).top.state &= ~FS_BUTTONDOWN + self.current_level.get_cell(Point(x, y)).bottom.state &= ~FS_BUTTONDOWN + + def handle_buttons(self): + for x in range(32): + for y in range(32): + top = self.current_level.get_cell(Point(x, y)).top + bottom = self.current_level.get_cell(Point(x, y)).bottom + if top.state & FS_BUTTONDOWN: + top.state &= ~FS_BUTTONDOWN + tile_id = top.id + elif bottom.state & FS_BUTTONDOWN: + bottom.state &= ~FS_BUTTONDOWN + tile_id = bottom.id + else: + continue + if tile_id == TYPE_BUTTON_BLUE: + self._toggle_tanks(None) + self._audio.play("BUTTON_PUSHED") + elif tile_id == TYPE_BUTTON_GREEN: + self.current_level.toggle_blocks() + elif tile_id == TYPE_BUTTON_RED: + self._activate_cloner(Point(x, y)) + self._audio.play("BUTTON_PUSHED") + elif tile_id == TYPE_BUTTON_BROWN: + self._spring_trap(Point(x, y)) + self._audio.play("BUTTON_PUSHED") + + def _start_floor_movement(self, creature, floor): + creature.state &= ~(CS_SLIP | CS_SLIDE) + + if is_ice(floor): + direction = ice_wall_turn(floor, creature.direction) + elif is_slide(floor): + direction = get_slide_dir(floor) + elif floor == TYPE_TELEPORT: + direction = creature.direction + elif floor == TYPE_BEARTRAP and creature.type == TYPE_BLOCK: + direction = creature.direction + else: + return + + if creature.type == TYPE_CHIP: + creature.state |= (CS_SLIDE if is_slide(floor) else CS_SLIP) + self._prepend_to_slip_list(creature, direction) + creature.direction = direction + self._update_creature(creature) + else: + creature.state |= CS_SLIP + self._append_to_slip_list(creature, direction) + + def _end_floor_movement(self, creature): + creature.state &= ~(CS_SLIP | CS_SLIDE) + self._remove_from_slip_list(creature) + + def _update_slip_list(self): + for slip in reversed(self._sliplist): + if not slip.creature.state & (CS_SLIP | CS_SLIDE): + self._end_floor_movement(slip.creature) + + def _floor_movements(self): + #pylint: disable=too-many-branches + slip_count = len(self._sliplist) + for n in range(slip_count): + saved_count = len(self._sliplist) + slip = self._sliplist[n] + creature = slip.creature + if not creature.state & (CS_SLIP | CS_SLIDE): + continue + slip_direction = slip.dir + if slip_direction == NONE: + continue + if creature.type == TYPE_CHIP: + self._last_slip_dir = slip_direction + if self._advance_creature(creature, slip_direction): + if creature.type == TYPE_CHIP: + creature.state &= ~CS_HASMOVED + else: + floor = self.current_level.get_cell(creature.cur_pos).bottom.id + if is_slide(floor): + if creature.type == TYPE_CHIP: + creature.state &= ~CS_HASMOVED + elif is_ice(floor): + # Go back + slip_direction = ice_wall_turn(floor, back(slip_direction)) + if creature.type == TYPE_CHIP: + self._last_slip_dir = slip_direction + if self._advance_creature(creature, slip_direction): + if creature.type == TYPE_CHIP: + creature.state &= ~CS_HASMOVED + elif creature.type == TYPE_CHIP: + if floor in (TYPE_TELEPORT, TYPE_BLOCK_STATIC): + self._last_slip_dir = slip_direction = back(slip_direction) + if self._advance_creature(creature, slip_direction): + creature.state &= ~CS_HASMOVED + if creature.state & (CS_SLIP | CS_SLIDE): + self._end_floor_movement(creature) + self._start_floor_movement( + creature, + self.current_level.get_cell(creature.cur_pos).bottom.id + ) + if self._check_for_ending(): + return + # If creature is not slipping or sliding and the creature is not + # chip and the slip list is one less than the saved count + if (not (creature.state & (CS_SLIP | CS_SLIDE)) and + creature.type != TYPE_CHIP and len(self._sliplist) == saved_count + 1): + n += 1 + + def get_death_message(self): + # To be shown after dying + for status, message in death_messages.items(): + if self._get_chip_status() == status: + return message + return None + + def get_decade_message(self): + # To be shown after beating a level + if self.current_level_number in decade_messages: + return decade_messages[self.current_level_number] + return None + + def _advance_creature(self, creature, direction): + if direction == NONE: + return True + if creature.type == TYPE_CHIP: + self._reset_chip_wait() + if not self._start_movement(creature, direction): + if creature.type == TYPE_CHIP: + self._audio.play("CANT_MOVE") + self.re_set_buttons() + return False + self._end_movement(creature) + if creature.type == TYPE_CHIP: + self.handle_buttons() + + return True + + def _start_movement(self, creature, direction): + floor = self.current_level.get_cell(creature.cur_pos).bottom.id + if not self._can_make_move(creature, direction, 0): + if (creature.type == TYPE_CHIP or + (floor != TYPE_BEARTRAP and floor != TYPE_CLONEMACHINE + and not creature.state & CS_SLIP)): + creature.direction = direction + self._update_creature(creature) + return False + + creature.state &= ~CS_RELEASED + creature.direction = direction + return True + + def _end_movement(self, creature): + #pylint: disable=too-many-branches, too-many-statements + dead = False + old_pos = creature.cur_pos + new_pos = creature.front() + cell = self.current_level.get_cell(new_pos) + tile = cell.top + floor = tile.id + + if creature.type == TYPE_CHIP: + if floor in (TYPE_EMPTY, TYPE_DIRT, TYPE_BLUEWALL_FAKE): + self.current_level.pop_tile(new_pos) + elif floor == TYPE_WATER: + if not self._possesion(TYPE_BOOTS_WATER): + self._set_chip_status(SF_CHIPDROWNED) + elif floor == TYPE_FIRE: + if not self._possesion(TYPE_BOOTS_FIRE): + self._set_chip_status(SF_CHIPBURNED) + elif floor == TYPE_POPUPWALL: + tile.id = TYPE_WALL + elif floor in (TYPE_DOOR_RED, TYPE_DOOR_BLUE, TYPE_DOOR_YELLOW, TYPE_DOOR_GREEN): + self._discard(floor) + self.current_level.pop_tile(new_pos) + self._audio.play("DOOR_OPENED") + elif floor in (TYPE_KEY_RED, TYPE_KEY_BLUE, TYPE_KEY_YELLOW, TYPE_KEY_GREEN, + TYPE_BOOTS_ICE, TYPE_BOOTS_SLIDE, TYPE_BOOTS_FIRE, TYPE_BOOTS_WATER): + if is_creature(cell.bottom.id): + self._set_chip_status(SF_CHIPHIT) + self._collect(floor) + self.current_level.pop_tile(new_pos) + self._audio.play("ITEM_COLLECTED") + elif floor == TYPE_THIEF: + for item in range(4): + self.boots[item] = False + self._audio.play("BOOTS_STOLEN") + elif floor == TYPE_ICCHIP: + self._chips_needed -= 1 + self.current_level.pop_tile(new_pos) + self._audio.play("IC_COLLECTED") + elif floor == TYPE_SOCKET: + if self._chips_needed == 0: + self.current_level.pop_tile(new_pos) + elif floor == TYPE_BOMB: + self._set_chip_status(SF_CHIPBOMBED) + self._audio.play("BOMB_EXPLOSION") + else: + if is_creature(floor): + self._set_chip_status(SF_CHIPHIT) + elif creature.type == TYPE_BLOCK: + if floor == TYPE_EMPTY: + self.current_level.pop_tile(new_pos) + elif floor == TYPE_WATER: + tile.id = TYPE_DIRT + dead = True + self._audio.play("WATER_SPLASH") + elif floor == TYPE_BOMB: + tile.id = TYPE_EMPTY + dead = True + self._audio.play("BOMB_EXPLOSION") + elif floor == TYPE_TELEPORT: + if not tile.state & FS_BROKEN: + new_pos = self._teleport_creature(creature, new_pos) + else: + if is_creature(floor): + tile = cell.bottom + floor = tile.id + if floor == TYPE_WATER: + if creature.type != TYPE_GLIDER: + dead = True + elif floor == TYPE_FIRE: + if creature.type != TYPE_FIREBALL: + dead = True + elif floor == TYPE_BOMB: + tile.id = TYPE_EMPTY + dead = True + self._audio.play("BOMB_EXPLOSION") + elif floor == TYPE_TELEPORT: + if not tile.state & FS_BROKEN: + new_pos = self._teleport_creature(creature, new_pos) + + if (self.current_level.get_cell(old_pos).bottom.id != TYPE_CLONEMACHINE or + creature.type == TYPE_CHIP): + self.current_level.pop_tile(old_pos) + + if dead: + self._remove_creature(creature) + if self.current_level.get_cell(old_pos).bottom.id == TYPE_CLONEMACHINE: + self.current_level.get_cell(old_pos).bottom.state &= ~FS_CLONING + return + + if creature.type == TYPE_CHIP and floor == TYPE_TELEPORT and not tile.state & FS_BROKEN: + pos = new_pos + new_pos = self._teleport_creature(creature, new_pos) + if pos != new_pos: + self._audio.play("TELEPORT") + if self._floor_at(new_pos) == TYPE_BLOCK_STATIC: + if self._last_slip_dir == NONE: + creature.direction = NORTH + self.current_level.get_cell(new_pos).top.id = cr_tile(TYPE_CHIP, NORTH) + floor = TYPE_EMPTY + else: + creature.direction = self._last_slip_dir + + + creature.cur_pos = new_pos + self._add_creature_to_map(creature) + creature.cur_pos = old_pos + + tile = cell.bottom + if floor == TYPE_BUTTON_BLUE: + if creature.state & CS_DEFERPUSH: + tile.state |= FS_BUTTONDOWN + else: + self._toggle_tanks(creature) + self._audio.play("BUTTON_PUSHED") + elif floor == TYPE_BUTTON_GREEN: + if creature.state & CS_DEFERPUSH: + tile.state |= FS_BUTTONDOWN + else: + self.current_level.toggle_blocks() + elif floor == TYPE_BUTTON_RED: + if creature.state & CS_DEFERPUSH: + tile.state |= FS_BUTTONDOWN + else: + self._activate_cloner(new_pos) + self._audio.play("BUTTON_PUSHED") + elif floor == TYPE_BUTTON_BROWN: + if creature.state & CS_DEFERPUSH: + tile.state |= FS_BUTTONDOWN + else: + self._spring_trap(new_pos) + self._audio.play("BUTTON_PUSHED") + + creature.cur_pos = new_pos + + if self.current_level.get_cell(old_pos).bottom.id == TYPE_CLONEMACHINE: + self.current_level.get_cell(old_pos).bottom.state &= ~FS_CLONING + + if floor == TYPE_BEARTRAP: + if self._is_trap_openr(new_pos, old_pos): + tile.state |= CS_RELEASED + elif self.current_level.get_cell(new_pos).bottom.id == TYPE_BEARTRAP: + for trap in self.current_level.traps: + if trap.device == new_pos: + creature.state |= CS_RELEASED + break + + if creature.type == TYPE_CHIP: + if self._get_chip_status() != SF_CHIPOKAY: + return + if cell.bottom.id == TYPE_EXIT: + self.status |= SF_COMPLETED + return + else: + if is_creature(cell.bottom.id): + if (creature_id(cell.bottom.id) == TYPE_CHIP or + creature_id(cell.bottom.id) == TYPE_CHIP_SWIMMING): + self._set_chip_status(SF_CHIPHIT) + return + + was_slipping = creature.state & (CS_SLIP | CS_SLIDE) + + if floor == TYPE_TELEPORT: + self._start_floor_movement(creature, floor) + elif (is_ice(floor) and + (creature.type != TYPE_CHIP or not self._possesion(TYPE_BOOTS_ICE))): + self._start_floor_movement(creature, floor) + elif (is_slide(floor) and + (creature.type != TYPE_CHIP or not self._possesion(TYPE_BOOTS_SLIDE))): + self._start_floor_movement(creature, floor) + elif floor == TYPE_BEARTRAP and creature.type == TYPE_BLOCK and was_slipping: + self._start_floor_movement(creature, floor) + else: + creature.state &= ~(CS_SLIP | CS_SLIDE) + + if (not was_slipping and (creature.state & (CS_SLIP | CS_SLIDE)) and + creature.type != TYPE_CHIP): + self._controller_dir = self._get_slip_dir(creature) + + def _add_creature_to_map(self, creature): + if creature.hidden: + return + self.current_level.push_tile(creature.cur_pos, Tile(TYPE_EMPTY, 0)) + self._update_creature(creature) + + def _cloner_from_button(self, pos): + for cloner in self.current_level.cloners: + if cloner.button == pos: + return cloner.device + return Point(-1, -1) + + def _is_trap_openr(self, pos, skip_pos): + for trap in self.current_level.traps: + if (trap.device == pos and trap.button != skip_pos and + self._is_trap_button_down(trap.button)): + return True + return False + + def _trap_from_button(self, pos): + for trap in self.current_level.traps: + if trap.button == pos: + return trap.device + return Point(-1, -1) + + def _activate_cloner(self, button_pos): + cloner_position = self._cloner_from_button(button_pos) + if not 0 <= cloner_position.x < 32 or not 0 <= cloner_position.y < 32: + return + tile_to_clone = self.current_level.get_cell(cloner_position).top.id + if not is_creature(tile_to_clone) or creature_id(tile_to_clone) == TYPE_CHIP: + return + if creature_id(tile_to_clone) == TYPE_BLOCK: + creature = self._get_block(cloner_position) + if creature.direction != NONE: + self._advance_creature(creature, creature.direction) + else: + if self.current_level.get_cell(cloner_position).bottom.state & FS_CLONING: + return + dummy_creature = Creature( + position=cloner_position, + direction=creature_dir_id(tile_to_clone), + creature_type=creature_id(tile_to_clone) + ) + if not self._can_make_move( + dummy_creature, dummy_creature.direction, CMM_CLONECANTBLOCK): + return + creature = self._awaken_creature(cloner_position) + if not creature: + return + creature.state |= CS_CLONING + if self.current_level.get_cell(cloner_position).bottom.id == TYPE_CLONEMACHINE: + self.current_level.get_cell(cloner_position).bottom.state |= FS_CLONING + + def _awaken_creature(self, pos): + tile = self.current_level.get_cell(pos).top.id + if not is_creature(tile) or creature_id(tile) == TYPE_CHIP: + return None + add_function = self._add_block if creature_id(tile) == TYPE_BLOCK else self._add_creature + return add_function(pos, creature_dir_id(tile), creature_id(tile)) + + def _spring_trap(self, button_position): + trap_position = self._trap_from_button(button_position) + if not 0 <= trap_position.x < 32 or not 0 <= trap_position.y < 32: + return + tile = self.current_level.get_cell(trap_position).top.id + if (tile == TYPE_BLOCK_STATIC or + self.current_level.get_cell(trap_position).bottom.state & FS_HASMUTANT): + creature = self._get_block(trap_position) + if creature: + creature.state |= CS_RELEASED + elif is_creature(tile): + creature = self._get_creature(trap_position, True) + if creature: + creature.state |= CS_RELEASED + + def _teleport_creature(self, creature, start_position): + orig_pos = creature.cur_pos + dest = Point(start_position.x, start_position.y) + while True: + dest.x -= 1 + if dest.x < 0: + dest.y -= 1 + dest.x = 31 + if dest.y < 0: + dest.y = 31 + if dest == start_position: + break + tile = self.current_level.get_cell(dest).top + if tile.id != TYPE_TELEPORT or (tile.state & FS_BROKEN): + continue + creature.cur_pos = dest + can_move = self._can_make_move( + creature, + creature.direction, + CMM_NOLEAVECHECK | CMM_NOEXPOSEWALLS | CMM_NODEFERBUTTONS | + CMM_NOFIRECHECK | CMM_TELEPORTPUSH) + creature.cur_pos = orig_pos + if can_move: + break + return dest + + # We may remove this as I believe it has to do with path finding based on mouse clicks + def _get_chip_walk_cmd(self): + choices = [0, 0] + pt_tile = self._chip.destination + x = pt_tile.x - self._chip.cur_pos.x + y = pt_tile.y - self._chip.cur_pos.y + n = NORTH if y < 0 else SOUTH if y > 0 else NONE + if y < 0: + y = -y + m = WEST if x < 0 else EAST if x > 0 else NONE + if x < 0: + x = -x + if x > y: + choices[0] = m + choices[1] = n + else: + choices[0] = n + choices[1] = m + index = 0 + while index < 2: + if choices[index] != NONE and self._can_make_move(self._chip, choices[index], 0): + return dir_idx(choices[index]) + index += 1 + self._chip.walking = False + return NONE + + def reset(self): + self.set_game_mode(GM_NORMAL) + self._moving = False + self._current_time = 0 + self.keys = [0] * 4 + self.boots = [False] * 4 + self.status = SF_CHIPOKAY + self._chip.walking = False + self._chip.state = 0 + self._creature_pool = [] + self._block_pool = [] + self._set_button(NONE) + self.dead_creatures = 0 + self.dead_blocks = 0 + + def _extract_creatures(self): + for creature_position in self.current_level.creatures: + tile = self.current_level.get_cell(creature_position).top.id + if is_creature(tile): + self._add_creature(creature_position, creature_dir_id(tile), creature_id(tile)) + for x in range(32): + for y in range(32): + tile2 = self.current_level.get_cell(Point(x, y)).top.id + if creature_id(tile2) == TYPE_CHIP: + self._chip.cur_pos = Point(x, y) + self._chip.type = TYPE_CHIP + self._chip.direction = creature_dir_id(tile2) + + def _append_to_slip_list(self, creature, direction): + # Append the given creature to the end of the slip list + for slip in self._sliplist: + if slip.creature == creature: + slip.dir = direction + return creature + + slip = Slip() + slip.creature = creature + slip.dir = direction + self._sliplist.append(slip) + return creature + + def _prepend_to_slip_list(self, creature, direction): + # Prepend the given creature to the start of the slip list + if len(self._sliplist) > 0 and self._sliplist[0].creature == creature: + self._sliplist[0].dir = direction + return creature + + slip = Slip() + slip.creature = creature + slip.dir = direction + self._sliplist.insert(0, slip) + return creature + + def _remove_from_slip_list(self, creature): + if len(self._sliplist) == 0: + return + + for slip in self._sliplist: + if slip.creature == creature: + self._sliplist.remove(slip) + break + + def _get_slip_dir(self, creature): + for slip in self._sliplist: + if slip.creature == creature: + return slip.dir + return NONE + + def _add_creature(self, tile_pos, direction, creature_type): + new_creature = Creature( + position=tile_pos, + direction=direction, + creature_type=creature_type + ) + self._creature_pool.append(new_creature) + return new_creature + + def _remove_creature(self, creature): + if creature.type == TYPE_BLOCK: + self.dead_blocks += 1 + else: + self.dead_creatures += 1 + creature.state &= ~(CS_SLIP | CS_SLIDE) + if creature.type == TYPE_CHIP: + if self.status == SF_CHIPOKAY: + self.status = SF_CHIPNOTOKAY + creature.hidden = True + + def _remove_dead_creatures(self): + for creature in self._creature_pool: + if creature.hidden and not creature.on_slip_list: + self._remove_creature(creature) + self.dead_creatures -= 1 + + def _get_creature(self, pos, include_chip): + for creature in self._creature_pool: + if creature.cur_pos == pos: + return creature + if include_chip and self._chip.cur_pos == pos: + return self._chip + return None + + def _add_block(self, tile_pos, direction, creature_type): + new_block = Creature() + new_block.cur_pos = tile_pos + new_block.direction = direction + new_block.type = creature_type + self._block_pool.append(new_block) + return new_block + + def _remove_dead_blocks(self): + for block in self._block_pool: + if block.hidden and not block.on_slip_list: + self._block_pool.remove(block) + self.dead_blocks -= 1 + + def _get_block(self, pos): + for block in self._block_pool: + if block.cur_pos == pos and not block.hidden: + return block + tile = self.current_level.get_cell(pos).top.id + if creature_id(tile) == TYPE_BLOCK: + creature_dir = creature_dir_id(tile) + elif tile == TYPE_BLOCK_STATIC: + creature_dir = NONE + else: + return None + + new_block = self._add_block(pos, creature_dir, TYPE_BLOCK) + if self.current_level.get_cell(pos).bottom.id == TYPE_BEARTRAP: + for trap in self.current_level.traps: + if trap.device == new_block.cur_pos: + new_block.state |= CS_RELEASED + break + return new_block + + def _toggle_tanks(self, mid_move): + for creature in self._creature_pool: + if creature.hidden or creature.type != TYPE_TANK: + continue + creature.direction = back(creature.direction) + if not creature.state & CS_TURNING: + creature.state |= CS_TURNING | CS_HASMOVED + if creature != mid_move: + if creature_id(self.current_level.get_cell(creature.cur_pos).top.id) == TYPE_TANK: + self._update_creature(creature) + else: + if creature.state & CS_TURNING: + creature.state &= ~CS_TURNING + self._update_creature(creature) + creature.state |= CS_TURNING + creature.direction = back(creature.direction) + + def set_game_mode(self, mode, push=True): + game_mode = self.get_game_mode() + if game_mode != mode: + if not push and len(self._game_mode) > 0: + self._game_mode.pop() + self._game_mode.append(mode) + # Housekeeping + while len(self._game_mode) > 4: + self._game_mode.pop(0) + + def revert_game_mode(self): + self._game_mode.pop() + + def get_game_mode(self): + last = len(self._game_mode) - 1 + if last < 0: + return None + return self._game_mode[last] + + def _choose_chip_move(self, creature, _discard): + creature.to_direction = NONE + if creature.hidden: + return + if not self.get_tick() & 3: + creature.state &= ~CS_HASMOVED + if creature.state & CS_HASMOVED: + return + direction = self._current_input + self._set_button(NONE) + + if not NORTH <= direction <= EAST: + direction = NONE + if _discard or ((creature.state & CS_SLIDE) and direction == creature.direction): + return + creature.to_direction = direction + + def _choose_move(self, creature): + if creature.type == TYPE_CHIP: + self._choose_chip_move(creature, creature.state & CS_SLIP) + else: + if creature.state & CS_SLIP: + creature.to_dir = NONE + else: + self._choose_creature_move(creature) + + def _choose_creature_move(self, creature): + #pylint: disable=too-many-branches, too-many-statements, too-many-return-statements + choices = [NONE, NONE, NONE, NONE] + creature.to_direction = NONE + creature_type = creature.type + if creature.hidden: + return + if creature_type == TYPE_BLOCK: + return + if self.get_tick() & 2: + return + if creature_type in (TYPE_TEETH, TYPE_BLOB): + if self.get_tick() & 4: + return + if creature.state & CS_TURNING: + creature.state &= ~(CS_TURNING | CS_HASMOVED) + self._update_creature(creature) + if creature.state & CS_HASMOVED: + self._controller_dir = NONE + return + if creature.state & (CS_SLIP | CS_SLIDE): + return + floor = self._floor_at(creature.cur_pos) + next_direction = current_direction = creature.direction + if floor in (TYPE_CLONEMACHINE, TYPE_BEARTRAP): + if creature_type in (TYPE_TANK, TYPE_BALL, TYPE_GLIDER, TYPE_FIREBALL, TYPE_WALKER): + choices[0] = current_direction + elif creature_type == TYPE_BLOB: + choices[0] = current_direction + choices[1] = left(current_direction) + choices[2] = back(current_direction) + choices[3] = right(current_direction) + random_p(choices, 4) + elif creature_type in (TYPE_BUG, TYPE_PARAMECIUM, TYPE_TEETH): + choices[0] = self._controller_dir + creature.to_direction = self._controller_dir + return + else: + raise ValueError("Invalid creature type") + else: + if creature_type == TYPE_TANK: + choices[0] = current_direction + elif creature_type == TYPE_BALL: + choices[0] = current_direction + choices[1] = back(current_direction) + elif creature_type == TYPE_GLIDER: + choices[0] = current_direction + choices[1] = left(current_direction) + choices[2] = right(current_direction) + choices[3] = back(current_direction) + elif creature_type == TYPE_FIREBALL: + choices[0] = current_direction + choices[1] = right(current_direction) + choices[2] = left(current_direction) + choices[3] = back(current_direction) + elif creature_type == TYPE_WALKER: + choices[0] = current_direction + choices[1] = left(current_direction) + choices[2] = back(current_direction) + choices[3] = right(current_direction) + random_p(choices[1:], 3) + elif creature_type == TYPE_BLOB: + choices[0] = current_direction + choices[1] = left(current_direction) + choices[2] = back(current_direction) + choices[3] = right(current_direction) + random_p(choices, 4) + elif creature_type == TYPE_BUG: + choices[0] = left(current_direction) + choices[1] = current_direction + choices[2] = right(current_direction) + choices[3] = back(current_direction) + elif creature_type == TYPE_PARAMECIUM: + choices[0] = right(current_direction) + choices[1] = current_direction + choices[2] = left(current_direction) + choices[3] = back(current_direction) + elif creature_type == TYPE_TEETH: + x = self._chip.cur_pos.x - creature.cur_pos.x + y = self._chip.cur_pos.y - creature.cur_pos.y + n = NORTH if y < 0 else SOUTH if y > 0 else NONE + if y < 0: + y = -y + m = WEST if x < 0 else EAST if x > 0 else NONE + if x < 0: + x = -x + if x > y: + choices[0] = m + choices[1] = n + else: + choices[0] = n + choices[1] = m + next_direction = choices[0] + else: + raise ValueError("Invalid creature type") + for n in range(4): + creature.to_direction = choices[n] + self._controller_dir = creature.to_direction + if self._can_make_move(creature, choices[n], 0): + return + if creature_type == TYPE_TANK: + if ((creature.state & CS_RELEASED) or floor not in (TYPE_BEARTRAP, TYPE_CLONEMACHINE)): + creature.state |= CS_HASMOVED + creature.to_direction = next_direction + + def _prepare(self): + if not self.get_tick() & 3: + for creature in self._creature_pool: + if creature.state & CS_TURNING: + creature.state &= ~(CS_TURNING | CS_HASMOVED) + self._update_creature(creature) + self.status = (self.status & ~SF_CHIPWAITMASK) | ((self.status & SF_CHIPWAITMASK) + 1) + if self.status & SF_CHIPWAITMASK > 3: + self._reset_chip_wait() + self._chip.direction = SOUTH + self._update_creature(self._chip) + + def advance_game(self, input_command): + #pylint: disable=too-many-branches + dir_cmd = NONE + if input_command == NONE: + # Check if chip is autopathing + if self._chip.walking: + dir_cmd = self._get_chip_walk_cmd() + if dir_cmd != NONE: + input_command = dir_cmd + else: + self._chip.walking = False + + # Don't start level until we have movement + if self.get_tick() or (UP <= input_command <= RIGHT): + self._current_time += 1 + + if UP <= input_command <= RIGHT: + self._set_button(idx_dir(input_command)) + else: + self._set_button(NONE) + + self._prepare() + + if self.get_tick() and not self.get_tick() & 1: + self._controller_dir = NONE + for creature in self._creature_pool: + if creature.hidden or (creature.state & CS_CLONING) or creature.type == TYPE_CHIP: + continue + self._choose_move(creature) + if creature.to_direction != NONE: + self._advance_creature(creature, creature.to_direction) + if self._check_for_ending(): + self._finalize() + return + if self.get_tick() and not self.get_tick() & 1: + self._floor_movements() + if self._check_for_ending(): + self._finalize() + return + + self._update_slip_list() + + if self._time_limit: + if self.get_tick() >= self._time_limit: + if self.status == SF_CHIPOKAY: + self.status = SF_CHIPNOTOKAY + self._set_chip_status(SF_CHIPTIMEUP) + self.set_game_mode(GM_CHIPDEAD) + self._audio.play("TIME_UP") + return + elif (self._time_limit - self.get_tick() <= 15 * TICKS_PER_SECOND and + self.get_tick() % TICKS_PER_SECOND == 0): + self._audio.play("TIME_LOW_TICK") + self._choose_move(self._chip) + if self._chip.to_direction != NONE: + if self._advance_creature(self._chip, self._chip.to_direction): + if self._check_for_ending(): + self._finalize() + return + self._chip.state |= CS_HASMOVED + self._update_slip_list() + self._create_clones() + self._finalize() + + def _create_clones(self): + for creature in self._creature_pool: + if creature.state & CS_CLONING: + creature.state &= ~CS_CLONING + + def _finalize(self): + if self.dead_creatures: + self._remove_dead_creatures() + if self.dead_blocks: + self._remove_dead_blocks() + if self.current_level.get_cell(self._chip.cur_pos).bottom.id == TYPE_HINTBUTTON: + self.status |= SF_SHOWHINT + else: + self.status &= ~SF_SHOWHINT + + def _check_for_ending(self): + if self.status & SF_COMPLETED: + self._audio.play("CHIP_WINS") + self.set_game_mode(GM_LEVELWON) + return True + if self.status & SF_CHIPNOTOKAY: + self._audio.play("CHIP_LOSES") + self.set_game_mode(GM_CHIPDEAD) + return True + return False + + def _create_tileset(self): + #pylint: disable=too-many-statements + # Chip, Block, Creature + self._tileset[TYPE_EMPTY].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_WALL].set_walk(0, 0, 0) + self._tileset[TYPE_ICCHIP].set_walk(NWSE, 0, 0) + self._tileset[TYPE_WATER].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_FIRE].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_WALL_NORTH].set_walk( + WEST | NORTH | EAST, + WEST | NORTH | EAST, + WEST | NORTH | EAST + ) + self._tileset[TYPE_WALL_WEST].set_walk( + NORTH | SOUTH | WEST, + NORTH | SOUTH | WEST, + NORTH | SOUTH | WEST + ) + self._tileset[TYPE_WALL_SOUTH].set_walk( + SOUTH | WEST | EAST, + SOUTH | WEST | EAST, + SOUTH | WEST | EAST + ) + self._tileset[TYPE_WALL_EAST].set_walk( + NORTH | EAST | SOUTH, + NORTH | EAST | SOUTH, + NORTH | EAST | SOUTH + ) + self._tileset[TYPE_WALL_SOUTHEAST].set_walk(SOUTH | EAST, SOUTH | EAST, SOUTH | EAST) + self._tileset[TYPE_BLOCK_STATIC].set_walk(NWSE, 0, 0) + self._tileset[TYPE_DIRT].set_walk(NWSE, 0, 0) + self._tileset[TYPE_ICE].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_SLIDE_SOUTH].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_SLIDE_NORTH].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_SLIDE_EAST].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_SLIDE_WEST].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_EXIT].set_walk(NWSE, NWSE, 0) + self._tileset[TYPE_DOOR_BLUE].set_walk(NWSE, 0, 0) + self._tileset[TYPE_DOOR_RED].set_walk(NWSE, 0, 0) + self._tileset[TYPE_DOOR_GREEN].set_walk(NWSE, 0, 0) + self._tileset[TYPE_DOOR_YELLOW].set_walk(NWSE, 0, 0) + self._tileset[TYPE_ICEWALL_NORTHWEST].set_walk(SOUTH | EAST, SOUTH | EAST, SOUTH | EAST) + self._tileset[TYPE_ICEWALL_NORTHEAST].set_walk(SOUTH | WEST, SOUTH | WEST, SOUTH | WEST) + self._tileset[TYPE_ICEWALL_SOUTHWEST].set_walk(NORTH | EAST, NORTH | EAST, NORTH | EAST) + self._tileset[TYPE_ICEWALL_SOUTHEAST].set_walk(NORTH | WEST, NORTH | WEST, NORTH | WEST) + self._tileset[TYPE_BLUEWALL_FAKE].set_walk(NWSE, 0, 0) + self._tileset[TYPE_BLUEWALL_REAL].set_walk(NWSE, 0, 0) + self._tileset[TYPE_THIEF].set_walk(NWSE, 0, 0) + self._tileset[TYPE_SOCKET].set_walk(NWSE, 0, 0) + self._tileset[TYPE_BUTTON_GREEN].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BUTTON_RED].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_SWITCHWALL_CLOSED].set_walk(0, 0, 0) + self._tileset[TYPE_SWITCHWALL_OPEN].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BUTTON_BROWN].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BUTTON_BLUE].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_TELEPORT].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BOMB].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BEARTRAP].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_HIDDENWALL_PERM].set_walk(0, 0, 0) + self._tileset[TYPE_HIDDENWALL_TEMP].set_walk(NWSE, 0, 0) + self._tileset[TYPE_GRAVEL].set_walk(NWSE, NWSE, 0) + self._tileset[TYPE_POPUPWALL].set_walk(NWSE, 0, 0) + self._tileset[TYPE_HINTBUTTON].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_CLONEMACHINE].set_walk(0, 0, 0) + self._tileset[TYPE_SLIDE_RANDOM].set_walk(NWSE, NWSE, 0) + self._tileset[TYPE_KEY_BLUE].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_KEY_RED].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_KEY_GREEN].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_KEY_YELLOW].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BOOTS_WATER].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BOOTS_FIRE].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BOOTS_ICE].set_walk(NWSE, NWSE, NWSE) + self._tileset[TYPE_BOOTS_SLIDE].set_walk(NWSE, NWSE, NWSE) + self._tileset[0x0E].set_walk(0, 0, 0) + self._tileset[0x0F].set_walk(0, 0, 0) + self._tileset[0x10].set_walk(0, 0, 0) + self._tileset[0x11].set_walk(0, 0, 0) + for index in range(0x40, 0x64): + self._tileset[index].set_walk(NWSE, 0, 0) + for index in range(0x64, 0x70): + self._tileset[index].set_walk(0, NWSE, 0) + + def _set_floor_at(self, tile_coords, tile): + test_tile = self.current_level.get_cell(tile_coords).top.id + if not is_key(test_tile) and not is_boots(test_tile) and not is_creature(test_tile): + self.current_level.get_cell(tile_coords).top.id = tile + return + else: + self.current_level.get_cell(tile_coords).bottom.id = tile + + def _floor_at(self, tile_coords): + tile = self.current_level.get_cell(tile_coords).top.id + if not is_key(tile) and not is_boots(tile) and not is_creature(tile): + return tile + tile = self.current_level.get_cell(tile_coords).bottom.id + if not is_key(tile) and not is_boots(tile) and not is_creature(tile): + return tile + return TYPE_EMPTY + + def _is_trap_button_down(self, coords): + return (0 <= coords.x < 32 and 0 <= coords.y < 32 and + self.current_level.get_cell(coords).top.id == TYPE_BUTTON_BROWN) + + def get_tick(self): + return self._current_time + + def _set_chip_status(self, status): + self.status = (self.status & ~SF_CHIPSTATUSMASK) | status + + def _get_chip_status(self): + return self.status & SF_CHIPSTATUSMASK + + def _reset_chip_wait(self): + self.status &= ~SF_CHIPWAITMASK + + def _set_button(self, button): + self._current_input = button + + def get_chips_needed(self): + if self._chips_needed < 0: + return 0 + return self._chips_needed diff --git a/Metro/Metro_RP2350_Chips_Challenge/icon.bmp b/Metro/Metro_RP2350_Chips_Challenge/icon.bmp new file mode 100644 index 000000000..57b921b93 Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/icon.bmp differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/keyboard.py b/Metro/Metro_RP2350_Chips_Challenge/keyboard.py new file mode 100755 index 000000000..42dd6dd9b --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/keyboard.py @@ -0,0 +1,42 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +import sys +import supervisor + +class KeyboardBuffer: + def __init__(self, valid_sequences): + self.key_buffer = "" + self._valid_sequences = valid_sequences + + def update(self): + while supervisor.runtime.serial_bytes_available: + self.key_buffer += sys.stdin.read(1) + + def print(self): + print("buffer", end=": ") + for key in self.key_buffer: + print(hex(ord(key)), end=" ") + + def set_valid_sequences(self, valid_sequences): + self._valid_sequences = valid_sequences + + def clear(self): + self.key_buffer = "" + + def get_key(self): + """ + Check for keyboard input and return the first valid key sequence. + """ + # Check if serial data is available + self.update() + if self.key_buffer: + for sequence in self._valid_sequences: + if self.key_buffer.startswith(sequence): + key = sequence + self.key_buffer = self.key_buffer[len(sequence):] + return key + # Remove first character + self.key_buffer = self.key_buffer[1:] + + return None diff --git a/Metro/Metro_RP2350_Chips_Challenge/level.py b/Metro/Metro_RP2350_Chips_Challenge/level.py new file mode 100755 index 000000000..ba40c7323 --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/level.py @@ -0,0 +1,245 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +# SPDX-License-Identifier: GPL-1.0-or-later +# Based on Pocket Chip's Challenge (https://github.com/makermelissa/PocketChipsChallenge) +# +# pylint: disable=too-many-lines, wildcard-import, unused-wildcard-import + +from point import Point +from device import Device +from definitions import TYPE_EMPTY, TYPE_SWITCHWALL_OPEN, TYPE_SWITCHWALL_CLOSED + +COMPRESSED = 0 +UNCOMPRESSED = 1 + +# These are the used optional field types +FIELD_TITLE = 3 +FIELD_BEAR_TRAPS = 4 +FIELD_CLONING_MACHINES = 5 +FIELD_PASSWORD = 6 +FIELD_HINT = 7 +FIELD_MOVING_CREATURES = 10 + +class Tile: + def __init__(self, tile_id=0, state=0): + self.id = tile_id + self.state = state + +class Cell: + def __init__(self): + self.top = Tile() + self.bottom = Tile() + + def __repr__(self): + return f"Top: {hex(self.top.id)} Bottom: {hex(self.bottom.id)}" + +def read_int(file, byte_count): + return int.from_bytes(file.read(byte_count), "little") + + +def position_to_coords(position): + return Point(position % 32, position // 32) + +class Level: + def __init__(self, data_file): + # Initialize any variables + self._data_file = data_file + self.level_number = 0 + self.last_level = 0 + self.time_limit = 0 + self.best_time = 0 + self.chips_required = 0 + self.password = "" + self.hint = "" + self.title = "" + self.level_map = [Cell() for _ in range(1024)] + self.traps = [] + self.cloners = [] + self.creatures = [] + self.passwords = {} + + def _reset_data(self): + self.level_map = [Cell() for _ in range(1024)] + self.traps = [] + self.cloners = [] + self.creatures = [] + + def get_cell(self, coords): + if isinstance(coords, int): + coords = position_to_coords(coords) + return self.level_map[coords.y * 32 + coords.x] + + def _update_cell_id(self, coords, tile_id, layer): + getattr(self.get_cell(coords), layer).id = tile_id + + def _get_map_representation(self, layer): + level_map = f"{layer} layer\n" + for y in range(32): + for x in range(32): + level_map += f"{hex(getattr(self.get_cell(Point(x, y)), layer).id)} " + level_map += "\n" + return level_map + + + def _process_map_data(self, map_data, layer): + """ + Store RLE mapdata in uncompressed form + """ + current_byte = 0 + current_position = 0 + while current_byte < len(map_data): + if map_data[current_byte] == 0xFF: + tile_id = map_data[current_byte + 2] + if 0x0E <= tile_id <= 0x11: + tile_id += 0xC2 + for _ in range(map_data[current_byte + 1]): + coords = position_to_coords(current_position) + self._update_cell_id(coords, tile_id, layer) + current_position += 1 + current_byte += 3 + else: + tile_id = map_data[current_byte] + if 0x0E <= tile_id <= 0x11: + tile_id += 0xC2 + coords = position_to_coords(current_position) + self._update_cell_id(coords, tile_id, layer) + current_position += 1 + current_byte += 1 + + def load(self, level_number): + #pylint: disable=too-many-branches, too-many-locals + # Reset the data prior to loading + self._reset_data() + # Read the file and fill in the variables + with open(self._data_file, "rb") as file: + # Read the first 4 bytes in little endian format + if read_int(file, 4) not in (0x0002AAAC, 0x0102AAAC): + raise ValueError("Not a CHIP file") + self.last_level = read_int(file, 2) + if not 0 < level_number <= self.last_level: + raise ValueError("Invalid level number") + self.level_number = level_number + # Seek to the start of the level data for the specified level + while True: + level_bytes = read_int(file, 2) + if read_int(file, 2) == level_number: + break + # Go to next level + file.seek(level_bytes - 2, 1) + + # Read the level data + self.time_limit = read_int(file, 2) + self.chips_required = read_int(file, 2) + compression = read_int(file, 2) + if compression == COMPRESSED: + raise ValueError("Compressed levels not supported") + + # Process the top map data + layer_bytes = read_int(file, 2) + map_data = file.read(layer_bytes) + self._process_map_data(map_data, "top") + + # Process the bottom map data + layer_bytes = read_int(file, 2) + map_data = file.read(layer_bytes) + self._process_map_data(map_data, "bottom") + + remaining_bytes = read_int(file, 2) + while remaining_bytes > 0: + field_type = read_int(file, 1) + field_size = read_int(file, 1) + remaining_bytes -= (2 + field_size) + if field_type == FIELD_TITLE: + self.title = file.read(field_size).decode("utf-8").replace("\x00", "") + elif field_type == FIELD_HINT: + self.hint = file.read(field_size).decode("utf-8").replace("\x00", "") + elif field_type == FIELD_PASSWORD: + self.password = ( + "".join([chr(c ^ 0x99) for c in file.read(field_size)]).replace("\x99", "") + ) + elif field_type == FIELD_BEAR_TRAPS: + trap_count = field_size // 10 + for _ in range(trap_count): + button = Point(read_int(file, 2), read_int(file, 2)) + device = Point(read_int(file, 2), read_int(file, 2)) + self.traps.append(Device(button, device)) + file.seek(2, 1) + elif field_type == FIELD_CLONING_MACHINES: + cloner_count = field_size // 8 + for _ in range(cloner_count): + button = Point(read_int(file, 2), read_int(file, 2)) + device = Point(read_int(file, 2), read_int(file, 2)) + self.cloners.append(Device(button, device)) + elif field_type == FIELD_MOVING_CREATURES: + creature_count = field_size // 2 + for _ in range(creature_count): + self.creatures.append(Point( + read_int(file, 1), + read_int(file, 1) + )) + + # Load passwords if not already loaded + if len(self.passwords) == 0: + self._load_passwords(file) + + def _load_passwords(self, file): + file.seek(6) # Skip the file header + while True: + file.seek(2, 1) + level_number = read_int(file, 2) + file.seek(6, 1) + layer_bytes = read_int(file, 2) # Number of bytes in the top layer + file.seek(layer_bytes, 1) # Skip top layer + layer_bytes = read_int(file, 2) # Number of bytes in the top layer + file.seek(layer_bytes, 1) # Skip bottom layer + remaining_bytes = read_int(file, 2) + while remaining_bytes > 0: + field_type = read_int(file, 1) + field_size = read_int(file, 1) + remaining_bytes -= (2 + field_size) + if field_type == FIELD_PASSWORD: + password = file.read(field_size) + self.passwords[level_number] = ( + "".join([chr(c ^ 0x99) for c in password]).replace("\x99", "") + ) + file.seek(remaining_bytes, 1) + break + file.seek(field_size, 1) + if len(self.passwords) == self.last_level: + break + + def toggle_blocks(self): + for cell in self.level_map: + if cell.top.id == TYPE_SWITCHWALL_OPEN: + cell.top.id = TYPE_SWITCHWALL_CLOSED + elif cell.top.id == TYPE_SWITCHWALL_CLOSED: + cell.top.id = TYPE_SWITCHWALL_OPEN + + if cell.bottom.id == TYPE_SWITCHWALL_OPEN: + cell.bottom.id = TYPE_SWITCHWALL_CLOSED + elif cell.bottom.id == TYPE_SWITCHWALL_CLOSED: + cell.bottom.id = TYPE_SWITCHWALL_OPEN + + def pop_tile(self, coords): + tile = Tile() + cell = self.get_cell(coords) + tile.id = cell.top.id + tile.state = cell.top.state + cell.top.id = cell.bottom.id + cell.top.state = cell.bottom.state + cell.bottom.id = TYPE_EMPTY + cell.bottom.state = 0 + + return tile + + def push_tile(self, coords, tile): + cell = self.get_cell(coords) + cell.bottom.id = cell.top.id + cell.bottom.state = cell.top.state + cell.top.id = tile.id + cell.top.state = tile.state + + def __str__(self): + # print the map ids from the level + return self._get_map_representation("top") + "\n" + self._get_map_representation("bottom") diff --git a/Metro/Metro_RP2350_Chips_Challenge/metadata.json b/Metro/Metro_RP2350_Chips_Challenge/metadata.json new file mode 100644 index 000000000..571444e9f --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/metadata.json @@ -0,0 +1,4 @@ +{ + "title": "Chip'sChall", + "icon": "icon.bmp" +} diff --git a/Metro/Metro_RP2350_Chips_Challenge/point.py b/Metro/Metro_RP2350_Chips_Challenge/point.py new file mode 100755 index 000000000..30dcd2d6f --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/point.py @@ -0,0 +1,83 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +import math + +class Point: + def __init__(self, x, y): + self.x = x + self.y = y + + def __str__(self): + return f'({self.x}, {self.y})' + + def __repr__(self): + return f'({self.x}, {self.y})' + + def __add__(self, other): + return Point(self.x + other.x, self.y + other.y) + + def __sub__(self, other): + return Point(self.x - other.x, self.y - other.y) + + def __mul__(self, other): + return Point(self.x * other.x, self.y * other.y) + + def __truediv__(self, other): + return Point(self.x / other.x, self.y / other.y) + + def __eq__(self, other): + return self.x == other.x and self.y == other.y + + def __ne__(self, other): + return not self.__eq__(other) + + def __lt__(self, other): + return self.x < other.x and self.y < other.y + + def __le__(self, other): + return self.x <= other.x and self.y <= other.y + + def __gt__(self, other): + return self.x > other.x and self.y > other.y + + def __ge__(self, other): + return self.x >= other.x and self.y >= other.y + + def __neg__(self): + return Point(-self.x, -self.y) + + def __pos__(self): + return Point(+self.x, +self.y) + + def __abs__(self): + return Point(abs(self.x), abs(self.y)) + + def __invert__(self): + return Point(~self.x, ~self.y) + + def __round__(self, n=0): + return Point(round(self.x, n), round(self.y, n)) + + def __floor__(self): + return Point(math.floor(self.x), math.floor(self.y)) + + def __ceil__(self): + return Point(math.ceil(self.x), math.ceil(self.y)) + + def __trunc__(self): + return Point(math.trunc(self.x), math.trunc(self.y)) + + def __hash__(self): + return hash((self.x, self.y)) + + def __len__(self): + return 2 + + def __getitem__(self, index): + if index == 0: + return self.x + elif index == 1: + return self.y + else: + raise IndexError diff --git a/Metro/Metro_RP2350_Chips_Challenge/savestate.py b/Metro/Metro_RP2350_Chips_Challenge/savestate.py new file mode 100755 index 000000000..15f54e75d --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/savestate.py @@ -0,0 +1,165 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +from math import floor +import json +import board +from microcontroller import nvm +from digitalio import DigitalInOut, Pull +import busio +import sdcardio +import storage + +SAVESTATE_FILE = "chips.json" + +class SaveState: + def __init__(self): + self._levels = {} + self._has_sdcard = self._mount_sd_card() + if self._has_sdcard: + print("SD Card detected") + else: + print("SD Card not detected. Level data will NOT be saved.") + self.load() + self._sdcard = None + + def _mount_sd_card(self): + + # Check if the SD card is already mounted + try: + storage.getmount("/sd") + return True + except OSError: + pass + + try: + self._card_detect = DigitalInOut(board.SD_CARD_DETECT) + except ValueError: + return False + self._card_detect.switch_to_input(pull=Pull.UP) + if self._card_detect.value: + return False + + # Attempt to unmount the SD card + try: + storage.umount("/sd") + except OSError: + pass + + spi = busio.SPI(board.SD_SCK, MOSI=board.SD_MOSI, MISO=board.SD_MISO) + + try: + sdcard = sdcardio.SDCard(spi, board.SD_CS, baudrate=20_000_000) + vfs = storage.VfsFat(sdcard) + storage.mount(vfs, "/sd") + except OSError: + return False + + return True + + def save(self): + if not self._has_sdcard: + return + with open("/sd/" + SAVESTATE_FILE, "w") as f: + json.dump({"levels": self._levels}, f) + + def load(self): + if not self._has_sdcard: + return + # Use try in case the file doesn't exist + try: + with open("/sd/" + SAVESTATE_FILE, "r") as f: + data = json.load(f) + self._levels = data["levels"] + except (OSError, ValueError): + pass + + def set_level_score(self, level, score, time_left): + level_key = f"level{level}" + new_high_score = False + lower_time = False + if level_key not in self._levels: + self._levels[level_key] = {} + if score > self._levels[level_key].get("score", 0): + new_high_score = True + self._levels[level_key]["score"] = score + if time_left > self._levels[level_key].get("time_left", 0): + lower_time = True + self._levels[level_key]["time_left"] = time_left + + self.save() + return new_high_score, lower_time + + def add_level_password(self, level, password): + nvm[0] = level + for byte, char in enumerate(password): + nvm[1 + byte] = ord(char) + level_key = f"level{level}" + if level_key not in self._levels: + self._levels[level_key] = {} + self._levels[level_key]["password"] = password.upper() + self.save() + + def find_unlocked_level(self, level_or_password): + if isinstance(level_or_password, int): + level_key = f"level{level_or_password}" + password = None + else: + level_key = None + password = level_or_password + + # Look for level by number + if level_key in self._levels: + return level_or_password + + for key, data in self._levels.items(): + if "password" in data and data["password"] == password: + return int(key[5:]) + + return None + + def calculate_score(self, level, time_left, deaths): + time_bonus = time_left * 10 + level_bonus = floor(level * 500 * 0.8**deaths) + level_score = time_bonus + level_bonus + total_score = self.total_score + return time_bonus, level_bonus, level_score, total_score + + def has_password(self, level, password): + level_key = f"level{level}" + if level_key in self._levels: + return self._levels[level_key]["password"] == password.upper() + return False + + def level_score(self, level): + level_key = f"level{level}" + if (level_key in self._levels and "score" in self._levels[level_key] and + "time_left" in self._levels[level_key]): + return self._levels[level_key]["score"], self._levels[level_key]["time_left"] + return 0, 0 + + def is_level_unlocked(self, level): + level_key = f"level{level}" + if level_key in self._levels and "password" in self._levels[level_key]: + return True + return False + + @property + def has_sdcard(self): + return self._has_sdcard + + @property + def total_score(self): + total_score = 0 + for data in self._levels.values(): + if "score" in data: + total_score += data["score"] + return total_score + + @property + def total_completed_levels(self): + completed_levels = 0 + for data in self._levels.values(): + if "score" in data: + completed_levels += 1 + return completed_levels diff --git a/Metro/Metro_RP2350_Chips_Challenge/settings.toml b/Metro/Metro_RP2350_Chips_Challenge/settings.toml new file mode 100755 index 000000000..86420f0ed --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/settings.toml @@ -0,0 +1 @@ +CIRCUITPY_PYSTACK_SIZE = 2400 \ No newline at end of file diff --git a/Metro/Metro_RP2350_Chips_Challenge/slip.py b/Metro/Metro_RP2350_Chips_Challenge/slip.py new file mode 100755 index 000000000..aba7e92d5 --- /dev/null +++ b/Metro/Metro_RP2350_Chips_Challenge/slip.py @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams +# +# SPDX-License-Identifier: MIT +class Slip: + def __init__(self): + self.creature = None + self.dir = None + + def __repr__(self): + return f"Creature: {self.creature} | Slip Direction: {self.dir}" diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/bell.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/bell.wav new file mode 100755 index 000000000..d4d3d21ae Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/sounds/bell.wav differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/blip2.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/blip2.wav new file mode 100755 index 000000000..f6969da18 Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/sounds/blip2.wav differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/bummer.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/bummer.wav new file mode 100755 index 000000000..bec81048b Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/sounds/bummer.wav differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/chimes.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/chimes.wav new file mode 100755 index 000000000..83e872d44 Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/sounds/chimes.wav differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/click1.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/click1.wav new file mode 100755 index 000000000..37e7ceb12 Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/sounds/click1.wav differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/click3.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/click3.wav new file mode 100755 index 000000000..7332a4684 Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/sounds/click3.wav differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/ditty1.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/ditty1.wav new file mode 100755 index 000000000..2ae39e85b Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/sounds/ditty1.wav differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/door.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/door.wav new file mode 100755 index 000000000..1bc817f7a Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/sounds/door.wav differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/hit3.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/hit3.wav new file mode 100755 index 000000000..9f9c72c34 Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/sounds/hit3.wav differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/oof3.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/oof3.wav new file mode 100755 index 000000000..982d86e36 Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/sounds/oof3.wav differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/pop2.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/pop2.wav new file mode 100755 index 000000000..32c65f01c Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/sounds/pop2.wav differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/strike.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/strike.wav new file mode 100755 index 000000000..e8cbacf4f Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/sounds/strike.wav differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/teleport.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/teleport.wav new file mode 100755 index 000000000..54ddc5f13 Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/sounds/teleport.wav differ diff --git a/Metro/Metro_RP2350_Chips_Challenge/sounds/water2.wav b/Metro/Metro_RP2350_Chips_Challenge/sounds/water2.wav new file mode 100755 index 000000000..864624657 Binary files /dev/null and b/Metro/Metro_RP2350_Chips_Challenge/sounds/water2.wav differ diff --git a/Metro/Metro_RP2350_CircuitPython_Matrix/code.py b/Metro/Metro_RP2350_CircuitPython_Matrix/code.py new file mode 100644 index 000000000..3e45bfe48 --- /dev/null +++ b/Metro/Metro_RP2350_CircuitPython_Matrix/code.py @@ -0,0 +1,234 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +Matrix rain visual effect + +Largely ported from Arduino version in Metro_HSTX_Matrix to +CircuitPython by claude with some additional tweaking to the +colors and refresh functionality. +""" +import sys +import random +import time +import displayio +import supervisor +from displayio import Group, TileGrid +from tilepalettemapper import TilePaletteMapper +from adafruit_fruitjam.peripherals import request_display_config +import adafruit_imageload + + +# use the built-in HSTX display +request_display_config(320, 240) +display = supervisor.runtime.display + +# screen size in tiles, tiles are 16x16 +SCREEN_WIDTH = display.width // 16 +SCREEN_HEIGHT = display.height // 16 + +# disable auto_refresh, we'll call refresh() after each frame +display.auto_refresh = False + +# group to hold visual elements +main_group = Group() + +# show the group on the display +display.root_group = main_group + +# Color gradient list from white to dark green +COLORS = [ + 0xFFFFFF, + 0x88FF88, + 0x00FF00, + 0x00DD00, + 0x00BB00, + 0x009900, + 0x007700, + 0x006600, + 0x005500, + 0x005500, + 0x003300, + 0x003300, + 0x002200, + 0x002200, + 0x001100, + 0x001100, +] + +# Palette to use with the mapper. Has 1 extra color +# so it can have black at index 0 +shader_palette = displayio.Palette(len(COLORS) + 1) +# set black at index 0 +shader_palette[0] = 0x000000 + +# set the colors from the gradient above in the +# remaining indexes +for i in range(0, len(COLORS)): + shader_palette[i + 1] = COLORS[i] + +# mapper to change colors of tiles within the grid +if sys.implementation.version[0] == 9: + grid_color_shader = TilePaletteMapper( + shader_palette, 2, SCREEN_WIDTH, SCREEN_HEIGHT + ) +elif sys.implementation.version[0] >= 10: + grid_color_shader = TilePaletteMapper(shader_palette, 2) + +# load the spritesheet +katakana_bmp, katakana_pixelshader = adafruit_imageload.load("matrix_characters.bmp") + +# how many characters are in the sprite sheet +char_count = katakana_bmp.width // 16 + +# grid to display characters within +display_text_grid = TileGrid( + bitmap=katakana_bmp, + width=SCREEN_WIDTH, + height=SCREEN_HEIGHT, + tile_height=16, + tile_width=16, + pixel_shader=grid_color_shader, +) + +# flip x to get backwards characters +display_text_grid.flip_x = True + +# add the text grid to main_group, so it will be visible on the display +main_group.append(display_text_grid) + + +# Define structures for character streams +class CharStream: + def __init__(self): + self.x = 0 # X position + self.y = 0 # Y position (head of the stream) + self.length = 0 # Length of the stream + self.speed = 0 # How many frames to wait before moving + self.countdown = 0 # Counter for movement + self.active = False # Whether this stream is currently active + self.chars = [" "] * 30 # Characters in the stream + + +# Array of character streams +streams = [CharStream() for _ in range(250)] + +# Stream creation rate (higher = more frequent new streams) +STREAM_CREATION_CHANCE = 65 # % chance per frame to create new stream + +# Initial streams to create at startup +INITIAL_STREAMS = 30 + + +def init_streams(): + """Initialize all streams as inactive""" + for _ in range(len(streams)): + streams[_].active = False + + # Create initial streams for immediate visual impact + for _ in range(INITIAL_STREAMS): + create_new_stream() + + +def create_new_stream(): + """Create a new active stream""" + # Find an inactive stream + for _ in range(len(streams)): + if not streams[_].active: + # Initialize the stream + streams[_].x = random.randint(0, SCREEN_WIDTH - 1) + streams[_].y = random.randint(-5, -1) # Start above the screen + streams[_].length = random.randint(5, 20) + streams[_].speed = random.randint(0, 3) + streams[_].countdown = streams[_].speed + streams[_].active = True + + # Fill with random characters + for j in range(streams[_].length): + # streams[i].chars[j] = get_random_char() + streams[_].chars[j] = random.randrange(0, char_count) + return + + +def update_streams(): + """Update and draw all streams""" + # Clear the display (we'll implement this by looping through display grid) + for x in range(SCREEN_WIDTH): + for y in range(SCREEN_HEIGHT): + display_text_grid[x, y] = 0 # Clear character + + # Count active streams (for debugging if needed) + active_count = 0 + + for _ in range(len(streams)): + if streams[_].active: + active_count += 1 + streams[_].countdown -= 1 + + # Time to move the stream down + if streams[_].countdown <= 0: + streams[_].y += 1 + streams[_].countdown = streams[_].speed + + # Change a random character in the stream + random_index = random.randint(0, streams[_].length - 1) + # streams[i].chars[random_index] = get_random_char() + streams[_].chars[random_index] = random.randrange(0, char_count) + + # Draw the stream + draw_stream(streams[_]) + + # Check if the stream has moved completely off the screen + if streams[_].y - streams[_].length > SCREEN_HEIGHT: + streams[_].active = False + + +def draw_stream(stream): + """Draw a single character stream""" + for _ in range(stream.length): + y = stream.y - _ + + # Only draw if the character is on screen + if 0 <= y < SCREEN_HEIGHT and 0 <= stream.x < SCREEN_WIDTH: + # Set the character + display_text_grid[stream.x, y] = stream.chars[_] + + if _ + 1 < len(COLORS): + grid_color_shader[stream.x, y] = [0, _ + 1] + else: + grid_color_shader[stream.x, y] = [0, len(COLORS) - 1] + # Occasionally change a character in the stream + if random.randint(0, 99) < 25: # 25% chance + idx = random.randint(0, stream.length - 1) + stream.chars[idx] = random.randrange(0, 112) + + +def setup(): + """Initialize the system""" + # Seed the random number generator + random.seed(int(time.monotonic() * 1000)) + + # Initialize all streams + init_streams() + + +def loop(): + """Main program loop""" + # Update and draw all streams + update_streams() + + # Randomly create new streams at a higher rate + if random.randint(0, 99) < STREAM_CREATION_CHANCE: + create_new_stream() + + display.refresh() + available = supervisor.runtime.serial_bytes_available + if available: + c = sys.stdin.read(available) + if c.lower() == "q": + supervisor.reload() + + +# Main program +setup() +while True: + loop() diff --git a/Metro/Metro_RP2350_CircuitPython_Matrix/icon.bmp b/Metro/Metro_RP2350_CircuitPython_Matrix/icon.bmp new file mode 100644 index 000000000..06e1ec0e1 Binary files /dev/null and b/Metro/Metro_RP2350_CircuitPython_Matrix/icon.bmp differ diff --git a/Metro/Metro_RP2350_CircuitPython_Matrix/matrix_characters.bmp b/Metro/Metro_RP2350_CircuitPython_Matrix/matrix_characters.bmp new file mode 100644 index 000000000..4264fd97f Binary files /dev/null and b/Metro/Metro_RP2350_CircuitPython_Matrix/matrix_characters.bmp differ diff --git a/Metro/Metro_RP2350_CircuitPython_Matrix/metadata.json b/Metro/Metro_RP2350_CircuitPython_Matrix/metadata.json new file mode 100644 index 000000000..46ce5585a --- /dev/null +++ b/Metro/Metro_RP2350_CircuitPython_Matrix/metadata.json @@ -0,0 +1,4 @@ +{ + "title": "Matrix", + "icon": "icon.bmp" +} diff --git a/Metro/Metro_RP2350_FlappyNyanCat/code.py b/Metro/Metro_RP2350_FlappyNyanCat/code.py new file mode 100644 index 000000000..39454cd23 --- /dev/null +++ b/Metro/Metro_RP2350_FlappyNyanCat/code.py @@ -0,0 +1,601 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +A game featuring Nyan cat inspired by flappy bird. +Learn Guide: https://learn.adafruit.com/flappy-nyan-cat-game-on-metro-rp2350 + +Controls: + Spacebar: Jump + S: Switch Trails + P: Play again after game over + Q: Quit after game over +""" +import random +import sys +import terminalio +from displayio import Group, TileGrid, Bitmap, Palette +import supervisor +import bitmaptools +from adafruit_display_text.bitmap_label import Label +from micropython import const +import adafruit_imageload +from adafruit_fruitjam.peripherals import request_display_config +from adafruit_pathlib import Path + +# how strong the gravity is +FALL_SPEED = 1 + +# how powerful the jump is +JUMP_SPEED = 5 + +# maximum gravity speed +TERMINAL_VELOCITY = 7 + +# make "close calls" more likely by fudging the collision check +# in favor of the player a bit +COLLIDE_FUDGE_FACTOR = 8 + +# how many scaled pixels wide the trail will be +TRAIL_LENGTH = 20 + +# current score +score = 0 + +request_display_config(320,240) +display = supervisor.runtime.display + +# initialize groups to hold visual elements +main_group = Group() + +# any elements in this Group will be scaled up 2x +scaled_group = Group(scale=2) +main_group.append(scaled_group) + + +class Post(Group): + # gap location constants + GAP_TOP = const(0) + GAP_MID = const(1) + GAP_BOTTOM = const(2) + + def __init__(self, spritesheet, gap_location=GAP_MID): + """ + A pair of scratching posts, aligned vertically. This class + holds the visual elements, and provides collision checking. + + :param Union[Bitmap,OnDiskBitmap] spritesheet: The Bitmap containing the post sprite sheet. + :param gap_location: Where the gap should be. Must be one of GAP_TOP, GAP_MID, GAP_BOTTOM. + """ + super().__init__() + # start out not visible + self.hidden = True + + # hold a reference to the spritesheet Bitmap + self.sprites = spritesheet + + # check which gap location was specified and + # set the post heights accordingly + if gap_location == Post.GAP_MID: + top_height = 4 + bottom_height = 4 + elif gap_location == Post.GAP_BOTTOM: + top_height = 7 + bottom_height = 1 + elif gap_location == Post.GAP_TOP: + top_height = 1 + bottom_height = 7 + else: + raise ValueError("Invalid gap_location") + + # initialize top post TileGrid + self.top_post = TileGrid( + post_sprites, + pixel_shader=post_sprites_pixel_shader, + height=top_height, + width=1, + tile_width=16, + tile_height=16, + default_tile=3, + ) + + # set the tiles for the top post. + # Normal double ended post tiles with + # the bottom cap tile below them. + for i in range(top_height): + if i == top_height - 1: + self.top_post[0, i] = 2 + else: + self.top_post[0, i] = 1 + + # initialize bottom post TileGrid + self.bottom_post = TileGrid( + post_sprites, + pixel_shader=post_sprites_pixel_shader, + height=bottom_height, + width=1, + tile_width=16, + tile_height=16, + default_tile=3, + ) + + # set the tiles for the bottom post. + # Normal double ended post tiles + # with the top cap tile above them + for i in range(bottom_height): + if i == 0: + self.bottom_post[0, i] = 0 + else: + self.bottom_post[0, i] = 1 + + # move the bottom post to the bottom of the display + self.bottom_post.y = 240 - bottom_height * 16 + + # append both post TileGrids to super class Group instance + self.append(self.top_post) + self.append(self.bottom_post) + + def check_collision(self, sprite): + """ + Check if either of our top or bottom posts are colliding with the given sprite + :param sprite: The sprite to check collision against. + :return: True if sprite is colliding with a post, false otherwise. + """ + # if the sprite is horizontally aligned with the posts + if ( + (sprite.x * 2) - self.top_post.tile_width + <= self.x + <= (sprite.x * 2) + (sprite.tile_width * 2) + ): + + # if the sprite is within the vertical range for either top or bottom post + if ( + sprite.y * 2 + ) + COLLIDE_FUDGE_FACTOR <= self.top_post.tile_height * self.top_post.height or ( + sprite.y * 2 + ) - COLLIDE_FUDGE_FACTOR >= self.bottom_post.y - ( + sprite.tile_height * 2 + ): + return True + + return False # no collision + + +class PostPool: + def __init__(self): + """ + A pool of Post objects to pull from and recycle back into. + """ + + # list to store the Posts in + self.pool = [] + + # start with 2 of each gap location + self.pool.append(Post(post_sprites, Post.GAP_MID)) + self.pool.append(Post(post_sprites, Post.GAP_MID)) + self.pool.append(Post(post_sprites, Post.GAP_BOTTOM)) + self.pool.append(Post(post_sprites, Post.GAP_BOTTOM)) + self.pool.append(Post(post_sprites, Post.GAP_TOP)) + self.pool.append(Post(post_sprites, Post.GAP_TOP)) + + def get_post(self, index=None): + """ + Get an available Post from the pool. + + :param index: The index of the post to return. + Default is None, which means random. + + :return: An available Post object. + """ + # if index is none, generate a random index + if index is None: + rnd_idx = random.randint(0, len(self.pool) - 1) + + else: # index not None + # use the provided index. + rnd_idx = index + + # select a Post and remove it from the pool + next_post = self.pool.pop(rnd_idx) + + # make the post visible + next_post.hidden = False + + # return the post + return next_post + + def recycle_post(self, post): + """ + Recycle a Post back into the pool + + :param Post post: The post to recycle. + + :return: None + """ + # set the post to not visible + post.hidden = True + + # add the post to the pool + self.pool.append(post) + + +class GameOverException(Exception): + """ + Exception that will be raised when the player loses the game. + """ + + def __init__(self, msg): + self.msg = msg + super().__init__(self.msg) + + +# palette of colors for the trail +trail_palette = Palette(10) +# rainbow colors +trail_palette[0] = 0x000000 +trail_palette[1] = 0xE71C1F +trail_palette[2] = 0xF39816 +trail_palette[3] = 0xF1E610 +trail_palette[4] = 0x6DB52F +trail_palette[5] = 0x428CCB +trail_palette[6] = 0x4B4C9C + +# trans flag colors +trail_palette[7] = 0xF5ABB9 +trail_palette[8] = 0x5BCFFA +trail_palette[9] = 0xFFFFFF + +# setup color index 0 for transparency +trail_palette.make_transparent(0) + +# Bitmap that holds 1 pixel width of the trail +trail_bmp = Bitmap(1, 6, 7) + +# initialize the Bitmap pixels to the rainbow colors +trail_bmp[0, 0] = 1 +trail_bmp[0, 1] = 2 +trail_bmp[0, 2] = 3 +trail_bmp[0, 3] = 4 +trail_bmp[0, 4] = 5 +trail_bmp[0, 5] = 6 + +# Bitmap for the background, 1/10 of 160x120 which is the +# of the display area accounting for the 2x from the scaled_group +bg_bmp = Bitmap(16, 12, 1) + +# palette for the background +bg_palette = Palette(1) +bg_palette[0] = 0x00014F # dark blue +bg_tilegrid = TileGrid(bg_bmp, pixel_shader=bg_palette) + +# Group for the background scaled to 10x +bg_group = Group(scale=10) + +# add the background to it's group and add that to the scaled_group +bg_group.append(bg_tilegrid) +scaled_group.append(bg_group) + +# load the sprite sheet for the posts +post_sprites, post_sprites_pixel_shader = adafruit_imageload.load( + "scratch_post_sprites.bmp" +) + +# set up color index 0 for transparency +post_sprites_pixel_shader.make_transparent(0) + +# initialize a PostPool() which will start with 2 posts +# of each gap location +post_pool = PostPool() + +# add all posts to the main_group. Note, not the scaled_group. +# posts are displayed at 1x size. +for _post in post_pool.pool: + main_group.append(_post) + +# get the first_post out of the pool +first_post = post_pool.get_post() + +# move it to the right edge +first_post.x = 320 - 16 + +# second post starts near the cat, so we want it to be +# middle gap to start with always. middle gap starts in index 0. +second_post = post_pool.get_post(0) + +# move it to the center +second_post.x = 160 + +# Group with an additional 2x scaling to hold the rainbow trail +canvas_group = Group(scale=2) + +# Bitmap for the trail canvas 1/4 display size for 2x from scaled_group +# and 2x from canvas_group +trail_canvas_bmp = Bitmap(display.width // 4, display.height // 4, 10) + +# TileGrid for the trail canvas +trail_canvas_tg = TileGrid(trail_canvas_bmp, pixel_shader=trail_palette) + +# add the canvas tilegrid to it's group, and add that to the scaled_group +canvas_group.append(trail_canvas_tg) +scaled_group.append(canvas_group) + +# load nyan cat Bitmap +nyan_bmp, nyan_bmp_pixel_shader = adafruit_imageload.load("nyancat_16x12.bmp") +# set color index 0 transparent +nyan_bmp_pixel_shader.make_transparent(0) +# TileGrid for cat +nyan_tg = TileGrid(bitmap=nyan_bmp, pixel_shader=nyan_bmp_pixel_shader) +# add cat to scaled_group +scaled_group.append(nyan_tg) + +# move cat near the center +nyan_tg.x = 80 +nyan_tg.y = 50 + +# text label for the current score +score_lbl = Label(terminalio.FONT, text="Spacebar", color=0xFFFFFF, scale=2) +# move it to the bottom left corner +score_lbl.anchor_point = (0, 1) +score_lbl.anchored_position = (2, display.height - 2) + +# add it to the main_group +main_group.append(score_lbl) + +game_over_label = Label( + terminalio.FONT, + text="", + color=0xFFFFFF, + background_color=0x000000, + padding_top=10, + padding_bottom=10, + padding_left=10, + padding_right=10, +) +game_over_label.anchor_point = (0.5, 0.5) +game_over_label.anchored_position = (display.width // 2, display.height // 2) +game_over_label.hidden = True + +main_group.append(game_over_label) + +# set the main_group to show on the display +display.root_group = main_group + +# disable auto_refresh +display.auto_refresh = False + +# list to store coordinates of each horizontal pixel of the trail +trail_coords = [] + +# cat_speed variable holds pixels per tick to move downward for gravity +cat_speed = FALL_SPEED + +# print(f"memfree: {gc.mem_free()}") + + +def swap_trail(): + """ + Swap the trail graphic between rainbow and trans flag colored. + """ + # if the top pixel is red + if trail_bmp[0, 0] == 1: + # change to the trans flag colors + trail_bmp[0, 0] = 0 + trail_bmp[0, 1] = 8 + trail_bmp[0, 2] = 7 + trail_bmp[0, 3] = 9 + trail_bmp[0, 4] = 7 + trail_bmp[0, 5] = 8 + else: + # change to rainbow colors + trail_bmp[0, 0] = 1 + trail_bmp[0, 1] = 2 + trail_bmp[0, 2] = 3 + trail_bmp[0, 3] = 4 + trail_bmp[0, 4] = 5 + trail_bmp[0, 5] = 6 + + +def draw_trail(): + """ + draw the trail in its current location + """ + # loop over the coordinates of the horizontal pixels + for coord in trail_coords: + # blit a copy of the trail Bitmap into the canvas + # Bitmap at the current coordinate + bitmaptools.blit(trail_canvas_bmp, trail_bmp, coord[0], coord[1]) + + +def erase_trail(): + """ + Erase the trail in its current location + """ + # loop over the coordinates of the horizontal pixels + for coord in trail_coords: + # fill a region the size of trail Bitmap with color_index 0 + # to make it transprent + bitmaptools.fill_region( + trail_canvas_bmp, coord[0], coord[1], coord[0] + 1, coord[1] + 6, 0 + ) + + +def shift_trail(): + """ + shift the coordinates of the trail to the left one pixel + """ + # loop over indexes within the trail coordinates list + for _ in range(len(trail_coords)): + # update the x value of the current coordinate by -1 + trail_coords[_][0] -= 1 + + +def shift_post(post): + """ + shift the coordinates of a post to the left + :param Post post: The Post to shift + :return: The shifted Post instance, or the new Post if the old one + went off the left edge + """ + # global score variable so we can update it + global score # pylint: disable=global-statement + + # if the post is at the left edge + if post.x <= 0: + # add bonus points for each post that makes it to the left edge + score += 10 + + # recycle the Post object back into the pool + post_pool.recycle_post(post) + + # get another Post out of the pool + new_post = post_pool.get_post() + + # move it to the right edge + new_post.x = 320 - 16 + + # return the new post + return new_post + + else: # post is not at the left edge + # move it left, getting faster for every 100 score points + # maxing out at 8 pixels per shift + post.x -= min((3 + score // 100), 8) + + # return the shifted post + return post + + +# initial display refresh +display.refresh(target_frames_per_second=30) +print("Press space to jump") + +# boolean to have the game paused to start and wait for the player to begin +playing = False + +while True: + try: + # if the player hasn't started yet + if not playing: + while True: + # check if any keys were pressed + available = supervisor.runtime.serial_bytes_available + + # if one or more keys was pressed + if available: + # read the value + cur_btn_val = sys.stdin.read(available) + else: + cur_btn_val = None + + # if spacebar was pressed + if cur_btn_val == " ": + # do the first jump + cat_speed = -JUMP_SPEED + + # set playing to true and breakout of the pause loop + playing = True + break + + # check if the cat is touching the first post + if first_post.check_collision(nyan_tg): + raise GameOverException( + f"Kitty got distracted by the scratchers post.\nScore: {score}" + ) + + # check if the cat is touching the second post + if second_post.check_collision(nyan_tg): + raise GameOverException( + f"Kitty got distracted by the scratchers post.\nScore: {score}" + ) + + # check if any keyboard data is available + available = supervisor.runtime.serial_bytes_available + if available: + # read the data if there is some available + cur_btn_val = sys.stdin.read(available) + else: + cur_btn_val = None + + # apply gravity to the cat, maxing out at terminal velocity + cat_speed = min(cat_speed + FALL_SPEED, TERMINAL_VELOCITY) + + # if there is keyboard data and spacebar was pressed + if cur_btn_val is not None and " " in cur_btn_val: + cat_speed = -JUMP_SPEED + + # award a point for each jump + score += 1 + elif cur_btn_val is not None and "s" in cur_btn_val: + swap_trail() + # award a point for swapping the trail + score += 1 + + # move the cat down by cat_speed amount of pixels + nyan_tg.y += cat_speed + + # if the cat has touched the top or bottom edge + if nyan_tg.y > display.height // 2 or nyan_tg.y < 0: + raise GameOverException(f"Kitty wandered away.\nScore: {score}") + + # current coordinates of the cat + draw_coords = [nyan_tg.x // 2, nyan_tg.y // 2] + + try: + # erase the trail + erase_trail() + except ValueError as exc: + raise GameOverException(f"Kitty wandered away.\nScore: {score}") from exc + + # shift the trail coordinates over + shift_trail() + + # add new coordinates to the trail at the cats current location + trail_coords.append(draw_coords) + + # if the trail is at its maximum length + if len(trail_coords) > TRAIL_LENGTH: + # remove the oldest coordinate from the trail coordinates list. + trail_coords.pop(0) + + # draw the trail + draw_trail() + + # shift the posts over + first_post = shift_post(first_post) + second_post = shift_post(second_post) + + # update the score label + score_lbl.text = str(score) + + # refresh the display + display.refresh(target_frames_per_second=30) + + except GameOverException as e: + # update the game over message + game_over_label.text = str(f"{e.msg}\nPress P to play again\nPress Q to quit") + # make the game over message visible + game_over_label.hidden = False + + # refresh display so the message shows + display.refresh() + break + +# wait for the player to press a key +while True: + # check if any keys were pressed + available = supervisor.runtime.serial_bytes_available + + # if one or more keys was pressed + if available: + # read the value + cur_btn_val = sys.stdin.read(available) + + # if player pressed p + if "p" in cur_btn_val: + supervisor.set_next_code_file(__file__, + working_directory=Path(__file__).parent.absolute()) + supervisor.reload() + + # if player pressed q + elif "q" in cur_btn_val: + print("exiting") + supervisor.reload() diff --git a/Metro/Metro_RP2350_FlappyNyanCat/icon.bmp b/Metro/Metro_RP2350_FlappyNyanCat/icon.bmp new file mode 100644 index 000000000..1868cace8 Binary files /dev/null and b/Metro/Metro_RP2350_FlappyNyanCat/icon.bmp differ diff --git a/Metro/Metro_RP2350_FlappyNyanCat/metadata.json b/Metro/Metro_RP2350_FlappyNyanCat/metadata.json new file mode 100644 index 000000000..f3f5a9dc3 --- /dev/null +++ b/Metro/Metro_RP2350_FlappyNyanCat/metadata.json @@ -0,0 +1,4 @@ +{ + "title": "FlapyNyan🐱", + "icon": "icon.bmp" +} diff --git a/Metro/Metro_RP2350_FlappyNyanCat/nyancat_16x12.bmp b/Metro/Metro_RP2350_FlappyNyanCat/nyancat_16x12.bmp new file mode 100644 index 000000000..9c10acb0f Binary files /dev/null and b/Metro/Metro_RP2350_FlappyNyanCat/nyancat_16x12.bmp differ diff --git a/Metro/Metro_RP2350_FlappyNyanCat/scratch_post_sprites.bmp b/Metro/Metro_RP2350_FlappyNyanCat/scratch_post_sprites.bmp new file mode 100644 index 000000000..e38e79d74 Binary files /dev/null and b/Metro/Metro_RP2350_FlappyNyanCat/scratch_post_sprites.bmp differ diff --git a/Metro/Metro_RP2350_Match3/autosave_resume_demo/code.py b/Metro/Metro_RP2350_Match3/autosave_resume_demo/code.py new file mode 100644 index 000000000..4f508dbac --- /dev/null +++ b/Metro/Metro_RP2350_Match3/autosave_resume_demo/code.py @@ -0,0 +1,251 @@ +# SPDX-FileCopyrightText: 2024 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +This example demonstrates basic autosave and resume functionality. There are two buttons +that can be clicked to increment respective counters. The number of clicks is stored +in a game_state dictionary and saved to a data file on the SDCard. When the code first +launches it will read the data file and load the game_state from it. +""" +import array +from io import BytesIO +import os + +import board +import busio +import digitalio +import displayio +import msgpack +import storage +import supervisor +import terminalio +import usb + +import adafruit_sdcard +from adafruit_display_text.bitmap_label import Label +from adafruit_button import Button + +# use the default built-in display +display = supervisor.runtime.display + +# button configuration +BUTTON_WIDTH = 100 +BUTTON_HEIGHT = 30 +BUTTON_STYLE = Button.ROUNDRECT + +# game state object will get loaded from SDCard +# or a new one initialized as a dictionary +game_state = None + +save_to = None + +# boolean variables for possible SDCard states +sd_pins_in_use = False + +# The SD_CS pin is the chip select line. +SD_CS = board.SD_CS + +# try to Connect to the sdcard card and mount the filesystem. +try: + # initialze CS pin + cs = digitalio.DigitalInOut(SD_CS) +except ValueError: + # likely the SDCard was auto-initialized by the core + sd_pins_in_use = True + +try: + # if sd CS pin was not in use + if not sd_pins_in_use: + # try to initialize and mount the SDCard + sdcard = adafruit_sdcard.SDCard( + busio.SPI(board.SD_SCK, board.SD_MOSI, board.SD_MISO), cs + ) + vfs = storage.VfsFat(sdcard) + storage.mount(vfs, "/sd") + + # check for the autosave data file + if "autosave_demo.dat" in os.listdir("/sd/"): + # if the file is found read data from it into a BytesIO buffer + buffer = BytesIO() + with open("/sd/autosave_demo.dat", "rb") as f: + buffer.write(f.read()) + buffer.seek(0) + + # unpack the game_state object from the read data in the buffer + game_state = msgpack.unpack(buffer) + print(game_state) + + # if placeholder.txt file does not exist + if "placeholder.txt" not in os.listdir("/sd/"): + # if we made it to here then /sd/ exists and has a card + # so use it for save data + save_to = "/sd/autosave_demo.dat" +except OSError as e: + # sdcard init or mounting failed + raise OSError( + "This demo requires an SDCard. Please power off the device " + + "insert an SDCard and then plug it back in." + ) from e + +# if no saved game_state was loaded +if game_state is None: + # create a new game state dictionary + game_state = {"pink_count": 0, "blue_count": 0} + +# Make the display context +main_group = displayio.Group() +display.root_group = main_group + +# make buttons +blue_button = Button( + x=30, + y=40, + width=BUTTON_WIDTH, + height=BUTTON_HEIGHT, + style=BUTTON_STYLE, + fill_color=0x0000FF, + outline_color=0xFFFFFF, + label="BLUE", + label_font=terminalio.FONT, + label_color=0xFFFFFF, +) + +pink_button = Button( + x=30, + y=80, + width=BUTTON_WIDTH, + height=BUTTON_HEIGHT, + style=BUTTON_STYLE, + fill_color=0xFF00FF, + outline_color=0xFFFFFF, + label="PINK", + label_font=terminalio.FONT, + label_color=0x000000, +) + +# add them to a list for easy iteration +all_buttons = [blue_button, pink_button] + +# Add buttons to the display context +main_group.append(blue_button) +main_group.append(pink_button) + +# make labels for each button +blue_lbl = Label( + terminalio.FONT, text=f"Blue: {game_state['blue_count']}", color=0x3F3FFF +) +blue_lbl.anchor_point = (0, 0) +blue_lbl.anchored_position = (4, 4) +pink_lbl = Label( + terminalio.FONT, text=f"Pink: {game_state['pink_count']}", color=0xFF00FF +) +pink_lbl.anchor_point = (0, 0) +pink_lbl.anchored_position = (4, 4 + 14) +main_group.append(blue_lbl) +main_group.append(pink_lbl) + +# load the mouse cursor bitmap +mouse_bmp = displayio.OnDiskBitmap("mouse_cursor.bmp") + +# make the background pink pixels transparent +mouse_bmp.pixel_shader.make_transparent(0) + +# create a TileGrid for the mouse, using its bitmap and pixel_shader +mouse_tg = displayio.TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader) + +# move it to the center of the display +mouse_tg.x = display.width // 2 +mouse_tg.y = display.height // 2 + +# add the mouse tilegrid to main_group +main_group.append(mouse_tg) + +# scan for connected USB device and loop over any found +for device in usb.core.find(find_all=True): + # print device info + print(f"{device.idVendor:04x}:{device.idProduct:04x}") + print(device.manufacturer, device.product) + print(device.serial_number) + # assume the device is the mouse + mouse = device + +# detach the kernel driver if needed +if mouse.is_kernel_driver_active(0): + mouse.detach_kernel_driver(0) + +# set configuration on the mouse so we can use it +mouse.set_configuration() + +# buffer to hold mouse data +# Boot mice have 4 byte reports +buf = array.array("b", [0] * 4) + + +def save_game_state(): + """ + msgpack the game_state and save it to the autosave data file + :return: + """ + b = BytesIO() + msgpack.pack(game_state, b) + b.seek(0) + with open(save_to, "wb") as savefile: + savefile.write(b.read()) + + +# main loop +while True: + try: + # attempt to read data from the mouse + # 10ms timeout, so we don't block long if there + # is no data + count = mouse.read(0x81, buf, timeout=10) + except usb.core.USBTimeoutError: + # skip the rest of the loop if there is no data + continue + + # update the mouse tilegrid x and y coordinates + # based on the delta values read from the mouse + mouse_tg.x = max(0, min(display.width - 1, mouse_tg.x + buf[1])) + mouse_tg.y = max(0, min(display.height - 1, mouse_tg.y + buf[2])) + + # if left click is pressed + if buf[0] & (1 << 0) != 0: + # get the current cursor coordinates + coords = (mouse_tg.x, mouse_tg.y, 0) + + # loop over the buttons + for button in all_buttons: + # if the current button contains the mouse coords + if button.contains(coords): + # if the button isn't already in the selected state + if not button.selected: + # enter selected state + button.selected = True + + # if it is the pink button + if button == pink_button: + # increment pink count + game_state["pink_count"] += 1 + # update the label + pink_lbl.text = f"Pink: {game_state['pink_count']}" + + # if it is the blue button + elif button == blue_button: + # increment blue count + game_state["blue_count"] += 1 + # update the label + blue_lbl.text = f"Blue: {game_state['blue_count']}" + + # save the new game state + save_game_state() + + # if the click is not on the current button + else: + # set this button as not selected + button.selected = False + + # left click is not pressed + else: + # set all buttons as not selected + for button in all_buttons: + button.selected = False diff --git a/Metro/Metro_RP2350_Match3/autosave_resume_demo/mouse_cursor.bmp b/Metro/Metro_RP2350_Match3/autosave_resume_demo/mouse_cursor.bmp new file mode 100644 index 000000000..94ec32889 Binary files /dev/null and b/Metro/Metro_RP2350_Match3/autosave_resume_demo/mouse_cursor.bmp differ diff --git a/Metro/Metro_RP2350_Match3/match3_game/btn_exit.bmp b/Metro/Metro_RP2350_Match3/match3_game/btn_exit.bmp new file mode 100644 index 000000000..2c3347e6b Binary files /dev/null and b/Metro/Metro_RP2350_Match3/match3_game/btn_exit.bmp differ diff --git a/Metro/Metro_RP2350_Match3/match3_game/btn_no_set.bmp b/Metro/Metro_RP2350_Match3/match3_game/btn_no_set.bmp new file mode 100644 index 000000000..eb23afbda Binary files /dev/null and b/Metro/Metro_RP2350_Match3/match3_game/btn_no_set.bmp differ diff --git a/Metro/Metro_RP2350_Match3/match3_game/btn_play_again.bmp b/Metro/Metro_RP2350_Match3/match3_game/btn_play_again.bmp new file mode 100644 index 000000000..ce4b8fed9 Binary files /dev/null and b/Metro/Metro_RP2350_Match3/match3_game/btn_play_again.bmp differ diff --git a/Metro/Metro_RP2350_Match3/match3_game/code.py b/Metro/Metro_RP2350_Match3/match3_game/code.py new file mode 100644 index 000000000..2a1fb4692 --- /dev/null +++ b/Metro/Metro_RP2350_Match3/match3_game/code.py @@ -0,0 +1,464 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +Match3 game inspired by the Set card game. Two players compete +to find sets of cards that share matching or mis-matching traits. +""" +import array +import atexit +import io +import os +import sys +import time + +import board +import busio +import digitalio +import supervisor +import terminalio +import usb +from tilepalettemapper import TilePaletteMapper +from displayio import TileGrid, Group, Palette, OnDiskBitmap, Bitmap +from adafruit_display_text.text_box import TextBox +import adafruit_usb_host_descriptors +from adafruit_debouncer import Debouncer +import adafruit_sdcard +import msgpack +import storage +from match3_game_helpers import ( + Match3Game, + STATE_GAMEOVER, + STATE_PLAYING_SETCALLED, + GameOverException, +) + +original_autoreload_val = supervisor.runtime.autoreload +supervisor.runtime.autoreload = False + +AUTOSAVE_FILENAME = "match3_game_autosave.dat" + +main_group = Group() +display = supervisor.runtime.display + +# set up scale factor of 2 for larger display resolution +scale_factor = 1 +if display.width > 360: + scale_factor = 2 + main_group.scale = scale_factor + +save_to = None +game_state = None +try: + # check for autosave file on CPSAVES drive + if AUTOSAVE_FILENAME in os.listdir("/saves/"): + savegame_buffer = io.BytesIO() + with open(f"/saves/{AUTOSAVE_FILENAME}", "rb") as f: + savegame_buffer.write(f.read()) + savegame_buffer.seek(0) + game_state = msgpack.unpack(savegame_buffer) + print(game_state) + + # if we made it to here then /saves/ exist so use it for + # save data + save_to = f"/saves/{AUTOSAVE_FILENAME}" +except OSError as e: + # no /saves/ dir likely means no CPSAVES + pass + +sd_pins_in_use = False + +if game_state is None: + # try to use sdcard for saves + # The SD_CS pin is the chip select line. + SD_CS = board.SD_CS + + # Connect to the card and mount the filesystem. + try: + cs = digitalio.DigitalInOut(SD_CS) + except ValueError: + sd_pins_in_use = True + + print(f"sd pins in use: {sd_pins_in_use}") + try: + if not sd_pins_in_use: + sdcard = adafruit_sdcard.SDCard( + busio.SPI(board.SD_SCK, board.SD_MOSI, board.SD_MISO), cs + ) + vfs = storage.VfsFat(sdcard) + storage.mount(vfs, "/sd") + + if "set_game_autosave.dat" in os.listdir("/sd/"): + savegame_buffer = io.BytesIO() + with open("/sd/set_game_autosave.dat", "rb") as f: + savegame_buffer.write(f.read()) + savegame_buffer.seek(0) + game_state = msgpack.unpack(savegame_buffer) + print(game_state) + + if "placeholder.txt" not in os.listdir("/sd/"): + # if we made it to here then /sd/ exists and has a card + # so use it for save data + save_to = "/sd/set_game_autosave.dat" + except OSError: + # no SDcard + pass + +# background color +bg_bmp = Bitmap( + display.width // scale_factor // 10, display.height // scale_factor // 10, 1 +) +bg_palette = Palette(1) +bg_palette[0] = 0x888888 +bg_tg = TileGrid(bg_bmp, pixel_shader=bg_palette) +bg_group = Group(scale=10) +bg_group.append(bg_tg) +main_group.append(bg_group) + +# create Game helper object +match3_game = Match3Game( + game_state=game_state, + display_size=(display.width // scale_factor, display.height // scale_factor), + save_location=save_to, +) +main_group.append(match3_game) + +# create a group to hold the game over elements +game_over_group = Group() + +# create a TextBox to hold the game over message +game_over_label = TextBox( + terminalio.FONT, + text="", + color=0xFFFFFF, + background_color=0x111111, + width=display.width // scale_factor // 2, + height=110, + align=TextBox.ALIGN_CENTER, +) +# move it to the center top of the display +game_over_label.anchor_point = (0, 0) +game_over_label.anchored_position = ( + display.width // scale_factor // 2 - (game_over_label.width) // 2, + 40, +) + +# make it hidden, we'll show it when the game is over. +game_over_group.hidden = True + +# add the game over lable to the game over group +game_over_group.append(game_over_label) + +# load the play again, and exit button bitmaps +play_again_btn_bmp = OnDiskBitmap("btn_play_again.bmp") +exit_btn_bmp = OnDiskBitmap("btn_exit.bmp") + +# create TileGrid for the play again button +play_again_btn = TileGrid( + bitmap=play_again_btn_bmp, pixel_shader=play_again_btn_bmp.pixel_shader +) + +# transparent pixels in the corners for the rounded corner effect +play_again_btn_bmp.pixel_shader.make_transparent(0) + +# centered within the display, offset to the left +play_again_btn.x = ( + display.width // scale_factor // 2 - (play_again_btn_bmp.width) // 2 - 30 +) + +# inside the bounds of the game over label, so it looks like a dialog visually +play_again_btn.y = 100 + +# create TileGrid for the exit button +exit_btn = TileGrid(bitmap=exit_btn_bmp, pixel_shader=exit_btn_bmp.pixel_shader) + +# transparent pixels in the corners for the rounded corner effect +exit_btn_bmp.pixel_shader.make_transparent(0) + +# centered within the display, offset to the right +exit_btn.x = display.width // scale_factor // 2 - (exit_btn_bmp.width) // 2 + 30 + +# inside the bounds of the game over label, so it looks like a dialog visually +exit_btn.y = 100 + +# add the play again and exit buttons to the game over group +game_over_group.append(play_again_btn) +game_over_group.append(exit_btn) +main_group.append(game_over_group) + +# wait a second for USB devices to be ready +time.sleep(1) + +# load the mouse bitmap +mouse_bmp = OnDiskBitmap("mouse_cursor.bmp") + +# make the background pink pixels transparent +mouse_bmp.pixel_shader.make_transparent(0) + +# list for mouse tilegrids +mouse_tgs = [] +# list for palette mappers, one for each mouse +palette_mappers = [] +# list for mouse colors +colors = [0x2244FF, 0xFFFF00] + +# remap palette will have the 3 colors from mouse bitmap +# and the two colors from the mouse colors list +remap_palette = Palette(3 + len(colors)) +# index 0 is transparent +remap_palette.make_transparent(0) + +# copy the 3 colors from the mouse bitmap palette +for i in range(3): + remap_palette[i] = mouse_bmp.pixel_shader[i] + +# copy the 2 colors from the mouse colors list +for i in range(2): + remap_palette[i + 3] = colors[i] + +# create tile palette mappers +for i in range(2): + if sys.implementation.version[0] == 9: + palette_mapper = TilePaletteMapper(remap_palette, 3, 1, 1) + elif sys.implementation.version[0] >= 10: + palette_mapper = TilePaletteMapper(remap_palette, 3) + + palette_mappers.append(palette_mapper) + + # create tilegrid for each mouse + mouse_tg = TileGrid(mouse_bmp, pixel_shader=palette_mapper) + mouse_tg.x = display.width // scale_factor // 2 - (i * 12) + mouse_tg.y = display.height // scale_factor // 2 + mouse_tgs.append(mouse_tg) + + # remap index 2 to each of the colors in mouse colors list + palette_mapper[0] = [0, 1, i + 3] + +# USB info lists +mouse_interface_indexes = [] +mouse_endpoint_addresses = [] +kernel_driver_active_flags = [] +# USB device object instance list +mice = [] +# buffers list for mouse packet data +mouse_bufs = [] +# debouncers list for debouncing mouse left clicks +mouse_debouncers = [] + +# scan for connected USB devices +for device in usb.core.find(find_all=True): + # check if current device is has a boot mouse endpoint + mouse_interface_index, mouse_endpoint_address = ( + adafruit_usb_host_descriptors.find_boot_mouse_endpoint(device) + ) + if mouse_interface_index is not None and mouse_endpoint_address is not None: + # if it does have a boot mouse endpoint then add information to the + # usb info lists + mouse_interface_indexes.append(mouse_interface_index) + mouse_endpoint_addresses.append(mouse_endpoint_address) + + # add the mouse device instance to list + mice.append(device) + print( + f"mouse interface: {mouse_interface_index} " + + f"endpoint_address: {hex(mouse_endpoint_address)}" + ) + + # detach kernel driver if needed + kernel_driver_active_flags.append(device.is_kernel_driver_active(0)) + if device.is_kernel_driver_active(0): + device.detach_kernel_driver(0) + + # set the mouse configuration so it can be used + device.set_configuration() + + +def is_mouse1_left_clicked(): + """ + Check if mouse 1 left click is pressed + :return: True if mouse 1 left click is pressed + """ + return is_left_mouse_clicked(mouse_bufs[0]) + + +def is_mouse2_left_clicked(): + """ + Check if mouse 2 left click is pressed + :return: True if mouse 2 left click is pressed + """ + return is_left_mouse_clicked(mouse_bufs[1]) + + +def is_left_mouse_clicked(buf): + """ + Check if a mouse is pressed given its packet buffer + filled with read data + :param buf: the buffer containing the packet data + :return: True if mouse left click is pressed + """ + val = buf[0] & (1 << 0) != 0 + return val + + +def is_right_mouse_clicked(buf): + """ + check if a mouse right click is pressed given its packet buffer + :param buf: the buffer containing the packet data + :return: True if mouse right click is pressed + """ + val = buf[0] & (1 << 1) != 0 + return val + + +# print(f"addresses: {mouse_endpoint_addresses}") +# print(f"indexes: {mouse_interface_indexes}") + +for mouse_tg in mouse_tgs: + # add the mouse to the main group + main_group.append(mouse_tg) + + # Buffer to hold data read from the mouse + # Boot mice have 4 byte reports + mouse_bufs.append(array.array("b", [0] * 8)) + +# create debouncer objects for left click functions +mouse_debouncers.append(Debouncer(is_mouse1_left_clicked)) +mouse_debouncers.append(Debouncer(is_mouse2_left_clicked)) + +# set main_group as root_group, so it is visible on the display +display.root_group = main_group + +# variable to hold winning player +winner = None + + +def get_mouse_deltas(buffer, read_count): + """ + Given a mouse packet buffer and a read count of number of bytes read, + return the delta x and y values of the mouse. + :param buffer: the buffer containing the packet data + :param read_count: the number of bytes read from the mouse + :return: tuple containing x and y delta values + """ + if read_count == 4: + delta_x = buffer[1] + delta_y = buffer[2] + elif read_count == 8: + delta_x = buffer[2] + delta_y = buffer[4] + else: + raise ValueError(f"Unsupported mouse packet size: {read_count}, must be 4 or 8") + return delta_x, delta_y + + +def atexit_callback(): + """ + re-attach USB devices to kernel if needed, and set + autoreload back to the original state. + :return: + """ + for _i, _mouse in enumerate(mice): + if kernel_driver_active_flags[_i]: + if not _mouse.is_kernel_driver_active(0): + _mouse.attach_kernel_driver(0) + supervisor.runtime.autoreload = original_autoreload_val + + +atexit.register(atexit_callback) + +# main loop +while True: + + # if set has been called + if match3_game.cur_state == STATE_PLAYING_SETCALLED: + # update the progress bar ticking down + match3_game.update_active_turn_progress() + + # loop over the mice objects + for i, mouse in enumerate(mice): + mouse_tg = mouse_tgs[i] + # attempt mouse read + try: + # read data from the mouse, small timeout so we move on + # quickly if there is no data + data_len = mouse.read( + mouse_endpoint_addresses[i], mouse_bufs[i], timeout=10 + ) + mouse_deltas = get_mouse_deltas(mouse_bufs[i], data_len) + # if we got data, then update the mouse cursor on the display + # using min and max to keep it within the bounds of the display + mouse_tg.x = max( + 0, + min( + display.width // scale_factor - 1, mouse_tg.x + mouse_deltas[0] // 2 + ), + ) + mouse_tg.y = max( + 0, + min( + display.height // scale_factor - 1, + mouse_tg.y + mouse_deltas[1] // 2, + ), + ) + + # timeout error is raised if no data was read within the allotted timeout + except usb.core.USBTimeoutError: + pass + + # update the mouse debouncers + mouse_debouncers[i].update() + + try: + # if the current mouse is right-clicking + if is_right_mouse_clicked(mouse_bufs[i]): + # let the game object handle the right-click + match3_game.handle_right_click(i) + + # if the current mouse left-clicked + if mouse_debouncers[i].rose: + # get the current mouse coordinates + coords = (mouse_tg.x, mouse_tg.y, 0) + + # if the current state is GAMEOVER + if match3_game.cur_state != STATE_GAMEOVER: + # let the game object handle the click event + match3_game.handle_left_click(i, coords) + else: + # if the mouse point is within the play again + # button bounding box + if play_again_btn.contains(coords): + # set next code file to this one + supervisor.set_next_code_file(__file__) + # reload + supervisor.reload() + + # if the mouse point is within the exit + # button bounding box + if exit_btn.contains(coords): + supervisor.reload() + + # if the game is over + except GameOverException: + # check for a winner + winner = None + if match3_game.scores[0] > match3_game.scores[1]: + winner = 0 + elif match3_game.scores[0] < match3_game.scores[1]: + winner = 1 + + # if there was a winner + if winner is not None: + # show a message with the winning player + message = f"\nGame Over\nPlayer{winner + 1} Wins!" + game_over_label.color = colors[winner] + game_over_label.text = message + + else: # there wasn't a winner + # show a tie game message + message = "\nGame Over\nTie Game Everyone Wins!" + + # make the gameover group visible + game_over_group.hidden = False + + # delete the autosave file. + os.remove(save_to) diff --git a/Metro/Metro_RP2350_Match3/match3_game/icon.bmp b/Metro/Metro_RP2350_Match3/match3_game/icon.bmp new file mode 100644 index 000000000..941271e0d Binary files /dev/null and b/Metro/Metro_RP2350_Match3/match3_game/icon.bmp differ diff --git a/Metro/Metro_RP2350_Match3/match3_game/match3_cards_spritesheet.bmp b/Metro/Metro_RP2350_Match3/match3_game/match3_cards_spritesheet.bmp new file mode 100644 index 000000000..78e34c0af Binary files /dev/null and b/Metro/Metro_RP2350_Match3/match3_game/match3_cards_spritesheet.bmp differ diff --git a/Metro/Metro_RP2350_Match3/match3_game/match3_game_helpers.py b/Metro/Metro_RP2350_Match3/match3_game/match3_game_helpers.py new file mode 100644 index 000000000..bbd5b9dbb --- /dev/null +++ b/Metro/Metro_RP2350_Match3/match3_game/match3_game_helpers.py @@ -0,0 +1,786 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import os +import random +import sys +import time +from io import BytesIO + +import terminalio + +import adafruit_imageload +from displayio import Group, TileGrid, OnDiskBitmap, Palette, Bitmap +import bitmaptools +import msgpack +from tilepalettemapper import TilePaletteMapper +import ulab.numpy as np + +from adafruit_display_text.bitmap_label import Label +from adafruit_displayio_layout.layouts.grid_layout import GridLayout +from adafruit_button import Button +from adafruit_progressbar.horizontalprogressbar import ( + HorizontalProgressBar, + HorizontalFillDirection, +) + +# pylint: disable=too-many-locals, too-many-nested-blocks, too-many-branches, too-many-statements +colors = [0x2244FF, 0xFFFF00] +STATE_TITLE = 0 +STATE_PLAYING_OPEN = 1 +STATE_PLAYING_SETCALLED = 2 +STATE_GAMEOVER = 3 + +ACTIVE_TURN_TIME_LIMIT = 10.0 + + +def random_selection(lst, count): + """ + Select items randomly from a list of items. + + returns a list of length count containing the selected items. + """ + if len(lst) < count: + raise ValueError("Count must be less than or equal to length of list") + selection = [] + while len(selection) < count: + selection.append(lst.pop(random.randrange(len(lst)))) + return selection + + +def validate_set(card_1, card_2, card_3): + """ + Check if a set of 3 cards is valid + :param card_1: the first card + :param card_2: the second card + :param card_3: the third card + :return: True if they are a valid set, False otherwise + """ + matrix_sums = card_1.tuple + card_2.tuple + card_3.tuple + for val in matrix_sums: + if val % 3 != 0: + return False + return True + + +class Match3Card(Group): + """ + Class representing a Match3 Card. Keeps track of shape, count, color, and fill. + + tuple value mappings: + + color, shape, fill, count + 0 , 1 , 2 , 1 + + colors + purple: 0 + red: 1 + green: 2 + + shapes + rectangle: 0 + triangle: 1 + circle: 2 + + fill + outline: 0 + filled: 1 + striped: 2 + + count + one: 0 + two: 1 + three: 2 + """ + + TUPLE_VALUE_TO_TILE_INDEX_LUT = { + # rectangle filled + (0, 1, 0): 0, + (0, 1, 1): 1, + (0, 1, 2): 2, + # triangle filled + (1, 1, 0): 3, + (1, 1, 1): 4, + (1, 1, 2): 5, + # circle filled + (2, 1, 0): 6, + (2, 1, 1): 13, + (2, 1, 2): 20, + # rectangle outline + (0, 0, 0): 7, + (0, 0, 1): 8, + (0, 0, 2): 9, + # triangle outline + (1, 0, 0): 10, + (1, 0, 1): 11, + (1, 0, 2): 12, + # circle outline + (2, 0, 0): 21, + (2, 0, 1): 22, + (2, 0, 2): 23, + # rectangle striped + (0, 2, 0): 14, + (0, 2, 1): 15, + (0, 2, 2): 16, + # triangle striped + (1, 2, 0): 17, + (1, 2, 1): 18, + (1, 2, 2): 19, + # circle striped + (2, 2, 0): 24, + (2, 2, 1): 25, + (2, 2, 2): 26, + } + + def __init__(self, card_tuple, **kwargs): + # tile palette mapper to color the card + if sys.implementation.version[0] == 9: + self._mapper = TilePaletteMapper(kwargs["pixel_shader"], 5, 1, 1) + elif sys.implementation.version[0] >= 10: + self._mapper = TilePaletteMapper(kwargs["pixel_shader"], 5) + kwargs["pixel_shader"] = self._mapper + # tile grid to for the visible sprite + self._tilegrid = TileGrid(**kwargs) + self._tilegrid.x = 4 + self._tilegrid.y = 4 + # initialize super class Group + super().__init__() + # add tilegrid to self instance Group + self.append(self._tilegrid) + # numpy array of the card tuple values + self._tuple = np.array(list(card_tuple), dtype=np.uint8) + # set the sprite and color based on card attributes + self._update_card_attributes() + + def _update_card_attributes(self): + """ + set the sprite and color based on card attributes + :return: None + """ + # set color + color_tuple_val = self._tuple[0] + self._mapper[0] = [0, color_tuple_val + 2, 2, 3, 4] + + # set tile + self._tilegrid[0] = Match3Card.TUPLE_VALUE_TO_TILE_INDEX_LUT[ + (self._tuple[1], self._tuple[2], self._tuple[3]) + ] + + def __str__(self): + return self.tuple + + def __repr__(self): + return self.tuple + + @property + def tuple(self): + """ + The tuple containing attributes values for this card. + """ + return self._tuple + + def contains(self, coordinates): + """ + Check if the cards bounding box contains the given coordinates. + :param coordinates: the coordinates to check + :return: True if the bounding box contains the given coordinates, False otherwise + """ + return ( + self.x <= coordinates[0] <= self.x + self._tilegrid.tile_width + and self.y <= coordinates[1] <= self.y + self._tilegrid.tile_height + ) + + +class Match3Game(Group): + """ + Match3 Game helper class + + Holds visual elements, manages state machine. + """ + + def __init__(self, game_state=None, display_size=None, save_location=None): + # initialize super Group instance + super().__init__() + self.game_state = game_state + self.display_size = display_size + + # list of Match3Card instances representing the current deck + self.play_deck = [] + + # load the spritesheet + self.card_spritesheet, self.card_palette = adafruit_imageload.load( + "match3_cards_spritesheet.bmp" + ) + + # start in the TITLE state + self.cur_state = STATE_TITLE + + # create a grid layout to help place cards neatly + # into a grid on the display + grid_size = (6, 3) + self.card_grid = GridLayout( + x=10, y=10, width=260, height=200, grid_size=grid_size + ) + + # no set button in the bottom right + self.no_set_btn_bmp = OnDiskBitmap("btn_no_set.bmp") + self.no_set_btn_bmp.pixel_shader.make_transparent(0) + self.no_set_btn = TileGrid( + bitmap=self.no_set_btn_bmp, pixel_shader=self.no_set_btn_bmp.pixel_shader + ) + self.no_set_btn.x = display_size[0] - self.no_set_btn.tile_width + self.no_set_btn.y = display_size[1] - self.no_set_btn.tile_height + self.append(self.no_set_btn) + + # list to hold score labels, one for each player + self.score_lbls = [] + + # player scores start at 0 + self.scores = [0, 0] + + self.save_location = save_location + + # initialize and position the score labels + for i in range(2): + score_lbl = Label(terminalio.FONT, text=f"P{i + 1}: 0", color=colors[i]) + self.score_lbls.append(score_lbl) + score_lbl.anchor_point = (1.0, 0.0) + score_lbl.anchored_position = (display_size[0] - 2, 2 + i * 12) + self.append(score_lbl) + + # deck count label in the bottom left + self.deck_count_lbl = Label( + terminalio.FONT, text=f"Deck: {len(self.play_deck)}" + ) + self.deck_count_lbl.anchor_point = (0.0, 1.0) + self.deck_count_lbl.anchored_position = (2, display_size[1] - 2) + self.append(self.deck_count_lbl) + + # will hold active player index + self.active_player = None + + # list of player index who have called no set + self.no_set_called_player_indexes = [] + + # active turn countdown progress bar + # below the score labels + self.active_turn_countdown = HorizontalProgressBar( + (display_size[0] - 64, 30), + (60, 6), + direction=HorizontalFillDirection.LEFT_TO_RIGHT, + min_value=0, + max_value=ACTIVE_TURN_TIME_LIMIT * 10, + ) + self.active_turn_countdown.hidden = True + self.append(self.active_turn_countdown) + + # will hold the timestamp when active turn began + self.active_turn_start_time = None + + # add the card grid to self instance Group + self.append(self.card_grid) + + # list of card objects that have been clicked + self.clicked_cards = [] + + # list of coordinates that have been clicked + self.clicked_coordinates = [] + + # initialize title screen + self.title_screen = Match3TitleScreen(display_size) + self.append(self.title_screen) + + # set up the clicked card indicator borders + self.clicked_card_indicator_palette = Palette(2) + self.clicked_card_indicator_palette[0] = 0x000000 + self.clicked_card_indicator_palette.make_transparent(0) + self.clicked_card_indicator_palette[1] = colors[0] + self.clicked_card_indicator_bmp = Bitmap(24 + 8, 32 + 8, 2) + self.clicked_card_indicator_bmp.fill(1) + bitmaptools.fill_region( + self.clicked_card_indicator_bmp, + 2, + 2, + self.clicked_card_indicator_bmp.width - 2, + self.clicked_card_indicator_bmp.height - 2, + value=0, + ) + self.clicked_card_indicators = [] + for _ in range(3): + self.clicked_card_indicators.append( + TileGrid( + bitmap=self.clicked_card_indicator_bmp, + pixel_shader=self.clicked_card_indicator_palette, + ) + ) + + def update_scores(self): + """ + Update the score labels to reflect the current player scores + :return: None + """ + for player_index in range(2): + prefix = "" + if player_index == self.active_player: + prefix = ">" + if player_index in self.no_set_called_player_indexes: + prefix = "*" + self.score_lbls[player_index].text = ( + f"{prefix}P{player_index + 1}: {self.scores[player_index]}" + ) + + def save_game_state(self): + """ + Save the game state to a file + :return: None + """ + # if there is a valid save location + if self.save_location is not None: + # create a dictionary object to store the game state + game_state = {"scores": self.scores, "board": {}, "deck": []} + # read the current board state into the dictionary object + for _y in range(3): + for _x in range(6): + try: + content = self.card_grid.get_content((_x, _y)) + game_state["board"][f"{_x},{_y}"] = tuple(content.tuple) + except KeyError: + pass + # read the current deck state into the dictionary object + for card in self.play_deck: + game_state["deck"].append(tuple(card.tuple)) + + # msgpack the object and write it to a file + b = BytesIO() + msgpack.pack(game_state, b) + b.seek(0) + with open(self.save_location, "wb") as f: + f.write(b.read()) + + def load_from_game_state(self, game_state): + """ + Load game state from a dictionary. + :param game_state: The dictionary of game state to load + :return: None + """ + # loop over cards in the deck + for card_tuple in game_state["deck"]: + # create a card instance and add it to the deck + self.play_deck.append( + Match3Card( + card_tuple, + bitmap=self.card_spritesheet, + pixel_shader=self.card_palette, + tile_width=24, + tile_height=32, + ) + ) + + # loop over grid cells + for y in range(3): + for x in range(6): + # if the current cell is in the board state of the save game + if f"{x},{y}" in game_state["board"]: + # create a card instance and put it in the grid here + card_tuple = game_state["board"][f"{x},{y}"] + self.card_grid.add_content( + Match3Card( + card_tuple, + bitmap=self.card_spritesheet, + pixel_shader=self.card_palette, + tile_width=24, + tile_height=32, + ), + (x, y), + (1, 1), + ) + # set the scores from the game state + self.scores = game_state["scores"] + # update the visible score labels + self.update_scores() + # update the deck count label + self.deck_count_lbl.text = f"Deck: {len(self.play_deck)}" + + def init_new_game(self): + """ + Initialize a new game state. + :return: None + """ + self.play_deck = [] + # loop over the 3 possibilities in each of the 4 attributes + for _color in range(0, 3): + for _shape in range(0, 3): + for _fill in range(0, 3): + for _count in range(0, 3): + # create a card instance with the current attributes + self.play_deck.append( + Match3Card( + (_color, _shape, _fill, _count), + bitmap=self.card_spritesheet, + pixel_shader=self.card_palette, + tile_width=24, + tile_height=32, + ) + ) + + # draw the starting cards at random + starting_pool = random_selection(self.play_deck, 12) + + # put the starting cards into the grid layout + for y in range(3): + for x in range(4): + self.card_grid.add_content(starting_pool[y * 4 + x], (x, y), (1, 1)) + + # update the deck count label + self.deck_count_lbl.text = f"Deck: {len(self.play_deck)}" + + def handle_right_click(self, player_index): + """ + Handle right click event + :param player_index: the index of the player who clicked + :return: None + """ + # if the current state is open play + if self.cur_state == STATE_PLAYING_OPEN: + # if there is no active player + if self.active_player is None: + # if the player who right clicked is in the no set called list + if player_index in self.no_set_called_player_indexes: + # remove them from the no set called list + self.no_set_called_player_indexes.remove(player_index) + # set the active player to the player that clicked + self.active_player = player_index + # set the clicked card indicators to the active player's color + self.clicked_card_indicator_palette[1] = colors[player_index] + # set the current state to the set called state + self.cur_state = STATE_PLAYING_SETCALLED + # store timestamp of when the active turn began + self.active_turn_start_time = time.monotonic() + # make the countdown progress bar visible + self.active_turn_countdown.hidden = False + # set the value to the maximum of the progress bar + self.active_turn_countdown.value = 60 + # update the score labels to show the active player indicator + self.update_scores() + + def handle_left_click(self, player_index, coords): + """ + Handle left click events + :param player_index: the index of the player who clicked + :param coords: the coordinates where the mouse clicked + :return: None + """ + # if the current state is open playing + if self.cur_state == STATE_PLAYING_OPEN: + # if the click is on the no set button + if self.no_set_btn.contains(coords): + # if the player that clicked is not in the net set called list + if player_index not in self.no_set_called_player_indexes: + # add them to the no set called list + self.no_set_called_player_indexes.append(player_index) + + # if both players have called no set + if len(self.no_set_called_player_indexes) == 2: + # if there are no cards left in the deck + if len(self.play_deck) == 0: + # set the state to game over + self.cur_state = STATE_GAMEOVER + raise GameOverException() + + # empty the no set called list + self.no_set_called_player_indexes = [] + + # find the empty cells in the card grid + empty_cells = self.find_empty_cells() + # if there are more than 3 empty cells + if len(empty_cells) >= 3: + # draw 3 new cards + _new_cards = random_selection(self.play_deck, 3) + # place them in 3 of the empty cells + for i, _new_card in enumerate(_new_cards): + self.card_grid.add_content( + _new_card, empty_cells[i], (1, 1) + ) + + else: # there are no 3 empty cells + # redraw the original grid with 12 new cards + + # remove existing cards from the grid and + # return them to the deck. + for _y in range(3): + for _x in range(6): + try: + _remove_card = self.card_grid.pop_content( + (_x, _y) + ) + print(f"remove_card: {_remove_card}") + self.play_deck.append(_remove_card) + + except KeyError: + continue + + # draw 12 new cards from the deck + starting_pool = random_selection(self.play_deck, 12) + # place them into the grid + for y in range(3): + for x in range(4): + self.card_grid.add_content( + starting_pool[y * 4 + x], (x + 1, y), (1, 1) + ) + + # update the deck count label + self.deck_count_lbl.text = f"Deck: {len(self.play_deck)}" + # save the game state + self.save_game_state() + + # update the score labels to show the no set called indicator(s) + self.update_scores() + + # if the current state is set called + elif self.cur_state == STATE_PLAYING_SETCALLED: + # if the player that clicked is the active player + if player_index == self.active_player: + # get the coordinates that were clicked adjusting for the card_grid position + adjusted_coords = ( + coords[0] - self.card_grid.x, + coords[1] - self.card_grid.y, + 0, + ) + # check which cell contains the clicked coordinates + clicked_grid_cell_coordinates = self.card_grid.which_cell_contains( + coords + ) + # print(clicked_grid_cell_coordinates) + + # if a cell in the grid was clicked + if clicked_grid_cell_coordinates is not None: + # try to get the content of the clicked cell, a Card instance potentially + try: + clicked_cell_content = self.card_grid.get_content( + clicked_grid_cell_coordinates + ) + except KeyError: + # if no content is in the cell just return + return + + # check if the Card instance was clicked, and if the card + # isn't already in the list of clicked cards + if ( + clicked_cell_content.contains(adjusted_coords) + and clicked_cell_content not in self.clicked_cards + ): + + clicked_card = clicked_cell_content + # show the clicked card indicator in this cell + clicked_cell_content.insert( + 0, self.clicked_card_indicators[len(self.clicked_cards)] + ) + # add the card instance to the clicked cards list + self.clicked_cards.append(clicked_card) + + # add the coordinates to the clicked coordinates list + self.clicked_coordinates.append(clicked_grid_cell_coordinates) + + # if 3 cards have been clicked + if len(self.clicked_cards) == 3: + # check if the 3 cards make a valid set + valid_set = validate_set( + self.clicked_cards[0], + self.clicked_cards[1], + self.clicked_cards[2], + ) + + # if they are a valid set + if valid_set: + # award a point to the active player + self.scores[self.active_player] += 1 + + # loop over the clicked coordinates + for coord in self.clicked_coordinates: + # remove the old card from this cell + _remove_card = self.card_grid.pop_content(coord) + # remove border from Match3Card group + _remove_card.pop(0) + + # find empty cells in the grid + empty_cells = self.find_empty_cells() + + # if there are at least 3 cards in the deck and + # at least 6 empty cells in the grid + if len(self.play_deck) >= 3 and len(empty_cells) > 6: + # deal 3 new cards to empty spots in the grid + for i in range(3): + _new_card = random_selection(self.play_deck, 1)[ + 0 + ] + self.card_grid.add_content( + _new_card, empty_cells[i], (1, 1) + ) + # update the deck count label + self.deck_count_lbl.text = ( + f"Deck: {len(self.play_deck)}" + ) + + # there are not at least 3 cards in the deck + # and at least 6 empty cells + else: + # if there are no empty cells + if len(self.find_empty_cells()) == 0: + # set the current state to game over + self.cur_state = STATE_GAMEOVER + raise GameOverException() + + else: # the 3 clicked cards are not a valid set + + # remove the clicked card indicators + for _ in range(3): + coords = self.clicked_coordinates.pop() + self.card_grid.get_content(coords).pop(0) + + # subtract a point from the active player + self.scores[self.active_player] -= 1 + + # save the game state + self.save_game_state() + # reset the clicked cards and coordinates lists + self.clicked_cards = [] + self.clicked_coordinates = [] + + # set the current state to open play + self.cur_state = STATE_PLAYING_OPEN + # set active player and active turn vars + self.active_player = None + self.active_turn_start_time = None + self.active_turn_countdown.hidden = True + # update the score labels + self.update_scores() + + # if the current state is title state + elif self.cur_state == STATE_TITLE: + # if the resume button is visible and was clicked + if ( + not self.title_screen.resume_btn.hidden + and self.title_screen.resume_btn.contains(coords) + ): + + # load the game from the given game state + self.load_from_game_state(self.game_state) + # hide the title screen + self.title_screen.hidden = True + # set the current state to open play + self.cur_state = STATE_PLAYING_OPEN + + # if the new game button was clicked + elif self.title_screen.new_game_btn.contains(coords): + self.game_state = None + # delete the autosave file + try: + os.remove(self.save_location) + print("removed old game save file") + except OSError: + pass + # initialize a new game + self.init_new_game() + # hide the title screen + self.title_screen.hidden = True + # set the current state to open play + self.cur_state = STATE_PLAYING_OPEN + + def find_empty_cells(self): + """ + find the cells within the card grid that are empty + :return: list of empty cell coordinate tuples. + """ + empty_cells = [] + for x in range(6): + for y in range(3): + try: + _content = self.card_grid.get_content((x, y)) + except KeyError: + empty_cells.append((x, y)) + return empty_cells + + def update_active_turn_progress(self): + """ + update the active turn progress bar countdown + :return: + """ + if self.cur_state == STATE_PLAYING_SETCALLED: + time_diff = time.monotonic() - self.active_turn_start_time + if time_diff > ACTIVE_TURN_TIME_LIMIT: + self.scores[self.active_player] -= 1 + self.active_player = None + self.update_scores() + self.cur_state = STATE_PLAYING_OPEN + self.active_turn_countdown.hidden = True + else: + self.active_turn_countdown.value = int( + (ACTIVE_TURN_TIME_LIMIT - time_diff) * 10 + ) + + +class GameOverException(Exception): + """ + Exception that indicates the game is over. + Message will contain the reason. + """ + + +class Match3TitleScreen(Group): + """ + Title screen for the Match3 game. + """ + + def __init__(self, display_size): + super().__init__() + self.hidden = False + self.display_size = display_size + # background bitmap color + bg_bmp = Bitmap(display_size[0] // 10, display_size[1] // 10, 1) + bg_palette = Palette(1) + bg_palette[0] = 0xFFFFFF + bg_tg = TileGrid(bg_bmp, pixel_shader=bg_palette) + bg_group = Group(scale=10) + bg_group.append(bg_tg) + self.append(bg_group) + + # load title card bitmap + title_card_bmp = OnDiskBitmap("title_card_match3.bmp") + title_card_tg = TileGrid( + title_card_bmp, pixel_shader=title_card_bmp.pixel_shader + ) + title_card_tg.x = 2 + if display_size[1] > 200: + title_card_tg.y = 20 + self.append(title_card_tg) + + # make resume and new game buttons + BUTTON_X = display_size[0] - 90 + BUTTON_WIDTH = 70 + BUTTON_HEIGHT = 20 + self.resume_btn = Button( + x=BUTTON_X, + y=40, + width=BUTTON_WIDTH, + height=BUTTON_HEIGHT, + style=Button.ROUNDRECT, + fill_color=0x6D2EDC, + outline_color=0x888888, + label="Resume", + label_font=terminalio.FONT, + label_color=0xFFFFFF, + ) + self.append(self.resume_btn) + self.new_game_btn = Button( + x=BUTTON_X, + y=40 + BUTTON_HEIGHT + 10, + width=BUTTON_WIDTH, + height=BUTTON_HEIGHT, + style=Button.RECT, + fill_color=0x0C9F0C, + outline_color=0x111111, + label="New Game", + label_font=terminalio.FONT, + label_color=0xFFFFFF, + ) + self.append(self.new_game_btn) diff --git a/Metro/Metro_RP2350_Match3/match3_game/metadata.json b/Metro/Metro_RP2350_Match3/match3_game/metadata.json new file mode 100644 index 000000000..b6cb9040d --- /dev/null +++ b/Metro/Metro_RP2350_Match3/match3_game/metadata.json @@ -0,0 +1,4 @@ +{ + "title": "Match3", + "icon": "icon.bmp" +} diff --git a/Metro/Metro_RP2350_Match3/match3_game/mouse_cursor.bmp b/Metro/Metro_RP2350_Match3/match3_game/mouse_cursor.bmp new file mode 100644 index 000000000..94ec32889 Binary files /dev/null and b/Metro/Metro_RP2350_Match3/match3_game/mouse_cursor.bmp differ diff --git a/Metro/Metro_RP2350_Match3/match3_game/title_card_match3.bmp b/Metro/Metro_RP2350_Match3/match3_game/title_card_match3.bmp new file mode 100644 index 000000000..66f040fb0 Binary files /dev/null and b/Metro/Metro_RP2350_Match3/match3_game/title_card_match3.bmp differ diff --git a/Metro/Metro_RP2350_Match3/tilepalettemapper_demo/code.py b/Metro/Metro_RP2350_Match3/tilepalettemapper_demo/code.py new file mode 100644 index 000000000..d8c9571a0 --- /dev/null +++ b/Metro/Metro_RP2350_Match3/tilepalettemapper_demo/code.py @@ -0,0 +1,63 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import sys + +import supervisor +from displayio import Group, OnDiskBitmap, TileGrid +from tilepalettemapper import TilePaletteMapper + +# use the default built-in display, +# the HSTX / PicoDVI display for the Metro RP2350 +display = supervisor.runtime.display + +# a group to hold all other visual elements +main_group = Group(scale=4, x=30, y=30) + +# set the main group to show on the display +display.root_group = main_group + +# load the sprite sheet bitmap +spritesheet_bmp = OnDiskBitmap("match3_cards_spritesheet.bmp") + +# create a TilePaletteMapper +if sys.implementation.version[0] == 9: + tile_palette_mapper = TilePaletteMapper( + spritesheet_bmp.pixel_shader, # input pixel_shader + 5, # input color count + 3, # grid width + 1, # grid height + ) +elif sys.implementation.version[0] >= 10: + tile_palette_mapper = TilePaletteMapper( + spritesheet_bmp.pixel_shader, # input pixel_shader + 5, # input color count + ) + +# create a TileGrid to show some cards +cards_tilegrid = TileGrid( + spritesheet_bmp, + pixel_shader=tile_palette_mapper, + width=3, + height=1, + tile_width=24, + tile_height=32, +) + +# set each tile in the grid to a different sprite index +cards_tilegrid[0, 0] = 10 +cards_tilegrid[1, 0] = 25 +cards_tilegrid[2, 0] = 2 + +# re-map each tile in the grid to use a different color for index 1 +# all other indexes remain their default values +tile_palette_mapper[0, 0] = [0, 2, 2, 3, 4] +tile_palette_mapper[1, 0] = [0, 3, 2, 3, 4] +tile_palette_mapper[2, 0] = [0, 4, 2, 3, 4] + +# add the tilegrid to the main group +main_group.append(cards_tilegrid) + +# wait forever so it remains visible on the display +while True: + pass diff --git a/Metro/Metro_RP2350_Match3/tilepalettemapper_demo/match3_cards_spritesheet.bmp b/Metro/Metro_RP2350_Match3/tilepalettemapper_demo/match3_cards_spritesheet.bmp new file mode 100644 index 000000000..78e34c0af Binary files /dev/null and b/Metro/Metro_RP2350_Match3/tilepalettemapper_demo/match3_cards_spritesheet.bmp differ diff --git a/Metro/Metro_RP2350_Match3/two_mice_demo/code.py b/Metro/Metro_RP2350_Match3/two_mice_demo/code.py new file mode 100644 index 000000000..93f51a511 --- /dev/null +++ b/Metro/Metro_RP2350_Match3/two_mice_demo/code.py @@ -0,0 +1,184 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import array +import supervisor +import terminalio +import usb.core +from adafruit_display_text.bitmap_label import Label +from displayio import Group, OnDiskBitmap, TileGrid, Palette + +import adafruit_usb_host_descriptors + +# use the default built-in display, +# the HSTX / PicoDVI display for the Metro RP2350 +display = supervisor.runtime.display + +# a group to hold all other visual elements +main_group = Group() + +# set the main group to show on the display +display.root_group = main_group + +# load the cursor bitmap file +mouse_bmp = OnDiskBitmap("mouse_cursor.bmp") + +# lists for labels, mouse tilegrids, and palettes. +# each mouse will get 1 of each item. All lists +# will end up with length 2. +output_lbls = [] +mouse_tgs = [] +palettes = [] + +# the different colors to use for each mouse cursor +# and labels +colors = [0xFF00FF, 0x00FF00] + +for i in range(2): + # create a palette for this mouse + mouse_palette = Palette(3) + # index zero is used for transparency + mouse_palette.make_transparent(0) + # add the palette to the list of palettes + palettes.append(mouse_palette) + + # copy the first two colors from mouse palette + for palette_color_index in range(2): + mouse_palette[palette_color_index] = mouse_bmp.pixel_shader[palette_color_index] + + # replace the last color with different color for each mouse + mouse_palette[2] = colors[i] + + # create a TileGrid for this mouse cursor. + # use the palette created above + mouse_tg = TileGrid(mouse_bmp, pixel_shader=mouse_palette) + + # move the mouse tilegrid to near the center of the display + mouse_tg.x = display.width // 2 - (i * 12) + mouse_tg.y = display.height // 2 + + # add this mouse tilegrid to the list of mouse tilegrids + mouse_tgs.append(mouse_tg) + + # add this mouse tilegrid to the main group so it will show + # on the display + main_group.append(mouse_tg) + + # create a label for this mouse + output_lbl = Label(terminalio.FONT, text=f"{mouse_tg.x},{mouse_tg.y}", color=colors[i], scale=1) + # anchored to the top left corner of the label + output_lbl.anchor_point = (0, 0) + + # move to op left corner of the display, moving + # down by a static amount to static the two labels + # one below the other + output_lbl.anchored_position = (1, 1 + i * 13) + + # add the label to the list of labels + output_lbls.append(output_lbl) + + # add the label to the main group so it will show + # on the display + main_group.append(output_lbl) + +# lists for mouse interface indexes, endpoint addresses, and USB Device instances +# each of these will end up with length 2 once we find both mice +mouse_interface_indexes = [] +mouse_endpoint_addresses = [] +mice = [] + +# scan for connected USB devices +for device in usb.core.find(find_all=True): + # check for boot mouse endpoints on this device + mouse_interface_index, mouse_endpoint_address = ( + adafruit_usb_host_descriptors.find_boot_mouse_endpoint(device) + ) + # if a boot mouse interface index and endpoint address were found + if mouse_interface_index is not None and mouse_endpoint_address is not None: + # add the interface index to the list of indexes + mouse_interface_indexes.append(mouse_interface_index) + # add the endpoint address to the list of addresses + mouse_endpoint_addresses.append(mouse_endpoint_address) + # add the device instance to the list of mice + mice.append(device) + + # print details to the console + print(f"mouse interface: {mouse_interface_index} ", end="") + print(f"endpoint_address: {hex(mouse_endpoint_address)}") + + # detach device from kernel if needed + if device.is_kernel_driver_active(0): + device.detach_kernel_driver(0) + + # set the mouse configuration so it can be used + device.set_configuration() + +# This is ordered by bit position. +BUTTONS = ["left", "right", "middle"] + +# list of buffers, will hold one buffer for each mouse +mouse_bufs = [] +for i in range(2): + # Buffer to hold data read from the mouse + mouse_bufs.append(array.array("b", [0] * 8)) + + +def get_mouse_deltas(buffer, read_count): + """ + Given a buffer and read_count return the x and y delta values + :param buffer: A buffer containing data read from the mouse + :param read_count: How many bytes of data were read from the mouse + :return: tuple x,y delta values + """ + if read_count == 4: + delta_x = buffer[1] + delta_y = buffer[2] + elif read_count == 8: + delta_x = buffer[2] + delta_y = buffer[4] + else: + raise ValueError(f"Unsupported mouse packet size: {read_count}, must be 4 or 8") + return delta_x, delta_y + +# main loop +while True: + # for each mouse instance + for mouse_index, mouse in enumerate(mice): + # try to read data from the mouse + try: + count = mouse.read( + mouse_endpoint_addresses[mouse_index], mouse_bufs[mouse_index], timeout=10 + ) + + # if there is no data it will raise USBTimeoutError + except usb.core.USBTimeoutError: + # Nothing to do if there is no data for this mouse + continue + + # there was mouse data, so get the delta x and y values from it + mouse_deltas = get_mouse_deltas(mouse_bufs[mouse_index], count) + + # update the x position of this mouse cursor using the delta value + # clamped to the display size + mouse_tgs[mouse_index].x = max( + 0, min(display.width - 1, mouse_tgs[mouse_index].x + mouse_deltas[0]) + ) + # update the y position of this mouse cursor using the delta value + # clamped to the display size + mouse_tgs[mouse_index].y = max( + 0, min(display.height - 1, mouse_tgs[mouse_index].y + mouse_deltas[1]) + ) + + # output string with the new cursor position + out_str = f"{mouse_tgs[mouse_index].x},{mouse_tgs[mouse_index].y}" + + # loop over possible button bit indexes + for i, button in enumerate(BUTTONS): + # check each bit index to determin if the button was pressed + if mouse_bufs[mouse_index][0] & (1 << i) != 0: + # if it was pressed, add the button to the output string + out_str += f" {button}" + + # set the output string into text of the label + # to show it on the display + output_lbls[mouse_index].text = out_str diff --git a/Metro/Metro_RP2350_Match3/two_mice_demo/mouse_cursor.bmp b/Metro/Metro_RP2350_Match3/two_mice_demo/mouse_cursor.bmp new file mode 100644 index 000000000..94ec32889 Binary files /dev/null and b/Metro/Metro_RP2350_Match3/two_mice_demo/mouse_cursor.bmp differ diff --git a/Metro/Metro_RP2350_Matching_Game/bitmaps/foreground.bmp b/Metro/Metro_RP2350_Matching_Game/bitmaps/foreground.bmp new file mode 100755 index 000000000..a546be7af Binary files /dev/null and b/Metro/Metro_RP2350_Matching_Game/bitmaps/foreground.bmp differ diff --git a/Metro/Metro_RP2350_Matching_Game/bitmaps/game_sprites.bmp b/Metro/Metro_RP2350_Matching_Game/bitmaps/game_sprites.bmp new file mode 100755 index 000000000..89ac3effb Binary files /dev/null and b/Metro/Metro_RP2350_Matching_Game/bitmaps/game_sprites.bmp differ diff --git a/Metro/Metro_RP2350_Matching_Game/bitmaps/mouse_cursor.bmp b/Metro/Metro_RP2350_Matching_Game/bitmaps/mouse_cursor.bmp new file mode 100755 index 000000000..f941ad29b Binary files /dev/null and b/Metro/Metro_RP2350_Matching_Game/bitmaps/mouse_cursor.bmp differ diff --git a/Metro/Metro_RP2350_Matching_Game/code.py b/Metro/Metro_RP2350_Matching_Game/code.py new file mode 100755 index 000000000..f6c903489 --- /dev/null +++ b/Metro/Metro_RP2350_Matching_Game/code.py @@ -0,0 +1,264 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +An implementation of a match3 jewel swap game. The idea is to move one character at a time +to line up at least 3 characters. +""" +import time +from displayio import Group, OnDiskBitmap, TileGrid, Bitmap, Palette +from adafruit_display_text.bitmap_label import Label +from adafruit_display_text.text_box import TextBox +from eventbutton import EventButton +import supervisor +import terminalio +from adafruit_usb_host_mouse import find_and_init_boot_mouse +from gamelogic import GameLogic, SELECTOR_SPRITE, EMPTY_SPRITE, GAMEBOARD_POSITION + +GAMEBOARD_SIZE = (8, 7) +HINT_TIMEOUT = 10 # seconds before hint is shown +GAME_PIECES = 7 # Number of different game pieces (set between 3 and 8) + +# pylint: disable=ungrouped-imports +if hasattr(supervisor.runtime, "display") and supervisor.runtime.display is not None: + # use the built-in HSTX display for Metro RP2350 + display = supervisor.runtime.display +else: + # pylint: disable=ungrouped-imports + from displayio import release_displays + import picodvi + import board + import framebufferio + + # initialize display + release_displays() + + fb = picodvi.Framebuffer( + 320, + 240, + clk_dp=board.CKP, + clk_dn=board.CKN, + red_dp=board.D0P, + red_dn=board.D0N, + green_dp=board.D1P, + green_dn=board.D1N, + blue_dp=board.D2P, + blue_dn=board.D2N, + color_depth=16, + ) + display = framebufferio.FramebufferDisplay(fb) + +def get_color_index(color, shader=None): + for index, palette_color in enumerate(shader): + if palette_color == color: + return index + return None + +# Load the spritesheet +sprite_sheet = OnDiskBitmap("/bitmaps/game_sprites.bmp") +sprite_sheet.pixel_shader.make_transparent( + get_color_index(0x00ff00, sprite_sheet.pixel_shader) +) + +# Main group will hold all the visual layers +main_group = Group() +display.root_group = main_group + +# Add Background to the Main Group +background = Bitmap(display.width, display.height, 1) +bg_color = Palette(1) +bg_color[0] = 0x333333 +main_group.append(TileGrid( + background, + pixel_shader=bg_color +)) + +# Add Game grid, which holds the game board, to the main group +game_grid = TileGrid( + sprite_sheet, + pixel_shader=sprite_sheet.pixel_shader, + width=GAMEBOARD_SIZE[0], + height=GAMEBOARD_SIZE[1], + tile_width=32, + tile_height=32, + x=GAMEBOARD_POSITION[0], + y=GAMEBOARD_POSITION[1], + default_tile=EMPTY_SPRITE, +) +main_group.append(game_grid) + +# Add a special selection groupd to highlight the selected piece and allow animation +selected_piece_group = Group() +selected_piece = TileGrid( + sprite_sheet, + pixel_shader=sprite_sheet.pixel_shader, + width=1, + height=1, + tile_width=32, + tile_height=32, + x=0, + y=0, + default_tile=EMPTY_SPRITE, +) +selected_piece_group.append(selected_piece) +selector = TileGrid( + sprite_sheet, + pixel_shader=sprite_sheet.pixel_shader, + width=1, + height=1, + tile_width=32, + tile_height=32, + x=0, + y=0, + default_tile=SELECTOR_SPRITE, +) +selected_piece_group.append(selector) +selected_piece_group.hidden = True +main_group.append(selected_piece_group) + +# Add a group for the swap piece to help with animation +swap_piece = TileGrid( + sprite_sheet, + pixel_shader=sprite_sheet.pixel_shader, + width=1, + height=1, + tile_width=32, + tile_height=32, + x=0, + y=0, + default_tile=EMPTY_SPRITE, +) +swap_piece.hidden = True +main_group.append(swap_piece) + +# Add foreground +foreground_bmp = OnDiskBitmap("/bitmaps/foreground.bmp") +foreground_bmp.pixel_shader.make_transparent(0) +foreground_tg = TileGrid(foreground_bmp, pixel_shader=foreground_bmp.pixel_shader) +foreground_tg.x = 0 +foreground_tg.y = 0 +main_group.append(foreground_tg) + +# Add a group for the UI Elements +ui_group = Group() +main_group.append(ui_group) + +# Create the mouse graphics and add to the main group +time.sleep(1) # Allow time for USB host to initialize +mouse = find_and_init_boot_mouse("/bitmaps/mouse_cursor.bmp") +if mouse is None: + raise RuntimeError("No mouse found connected to USB Host") +main_group.append(mouse.tilegrid) + +# Create the game logic object +# pylint: disable=no-value-for-parameter, too-many-function-args +game_logic = GameLogic( + display, + mouse, + game_grid, + swap_piece, + selected_piece_group, + GAME_PIECES, + HINT_TIMEOUT +) + +def update_ui(): + # Update the UI elements with the current game state + score_label.text = f"Score:\n{game_logic.score}" + +waiting_for_release = False +game_over_shown = False + +# Create the UI Elements +# Label for the Score +score_label = Label( + terminalio.FONT, + color=0xffff00, + x=5, + y=10, +) +ui_group.append(score_label) + +message_dialog = Group() +message_dialog.hidden = True + +def reset(): + global game_over_shown # pylint: disable=global-statement + # Reset the game logic + game_logic.reset() + message_dialog.hidden = True + game_over_shown = False + +def hide_group(group): + group.hidden = True + +reset() + +reset_button = EventButton( + reset, + label="Reset", + width=40, + height=16, + x=5, + y=50, + style=EventButton.RECT, +) +ui_group.append(reset_button) + +message_label = TextBox( + terminalio.FONT, + text="", + color=0x333333, + background_color=0xEEEEEE, + width=display.width // 3, + height=90, + align=TextBox.ALIGN_CENTER, + padding_top=5, +) +message_label.anchor_point = (0, 0) +message_label.anchored_position = ( + display.width // 2 - message_label.width // 2, + display.height // 2 - message_label.height // 2, +) +message_dialog.append(message_label) +message_button = EventButton( + (hide_group, message_dialog), + label="OK", + width=40, + height=16, + x=display.width // 2 - 20, + y=display.height // 2 - message_label.height // 2 + 60, + style=EventButton.RECT, +) +message_dialog.append(message_button) +ui_group.append(message_dialog) + +# main loop +while True: + update_ui() + # update mouse + game_logic.update_mouse() + + if not message_dialog.hidden: + if message_button.handle_mouse( + (mouse.x, mouse.y), + game_logic.pressed_btns and "left" in game_logic.pressed_btns, + waiting_for_release + ): + game_logic.waiting_for_release = True + continue + + if reset_button.handle_mouse( + (mouse.x, mouse.y), + game_logic.pressed_btns is not None and "left" in game_logic.pressed_btns, + game_logic.waiting_for_release + ): + game_logic.waiting_for_release = True + + # process gameboard click if no menu + game_logic.update() + game_over = game_logic.check_for_game_over() + if game_over and not game_over_shown: + message_label.text = ("No more moves available. your final score is:\n" + + str(game_logic.score)) + message_dialog.hidden = False + game_over_shown = True diff --git a/Metro/Metro_RP2350_Matching_Game/eventbutton.py b/Metro/Metro_RP2350_Matching_Game/eventbutton.py new file mode 100755 index 000000000..766cd9605 --- /dev/null +++ b/Metro/Metro_RP2350_Matching_Game/eventbutton.py @@ -0,0 +1,41 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +from adafruit_button import Button + +class EventButton(Button): + """A button that can be used to trigger a callback when clicked. + + :param callback: The callback function to call when the button is clicked. + A tuple can be passed with an argument that will be passed to the + callback function. The first element of the tuple should be the + callback function, and the remaining elements will be passed as + arguments to the callback function. + """ + def __init__(self, callback, *args, **kwargs): + super().__init__(*args, **kwargs) + self.args = [] + self.selected = False + if isinstance(callback, tuple): + self.callback = callback[0] + self.args = callback[1:] + else: + self.callback = callback + + def click(self): + """Call the function when the button is pressed.""" + self.callback(*self.args) + + def handle_mouse(self, point, clicked, waiting_for_release): + if waiting_for_release: + return False + + # Handle mouse events for the button + if self.contains(point): + self.selected = True + if clicked: + self.click() + return True + else: + self.selected = False + return False diff --git a/Metro/Metro_RP2350_Matching_Game/gamelogic.py b/Metro/Metro_RP2350_Matching_Game/gamelogic.py new file mode 100755 index 000000000..d89f47ea9 --- /dev/null +++ b/Metro/Metro_RP2350_Matching_Game/gamelogic.py @@ -0,0 +1,525 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +import random +import time +from adafruit_ticks import ticks_ms + +GAMEBOARD_POSITION = (55, 8) + +SELECTOR_SPRITE = 9 +EMPTY_SPRITE = 10 +DEBOUNCE_TIME = 0.2 # seconds for debouncing mouse clicks + +class GameBoard: + "Contains the game board" + def __init__(self, game_grid, swap_piece, selected_piece_group): + self.x = GAMEBOARD_POSITION[0] + self.y = GAMEBOARD_POSITION[1] + self._game_grid = game_grid + self._selected_coords = None + self._selected_piece = selected_piece_group[0] + self._selector = selected_piece_group[1] + self._swap_piece = swap_piece + self.selected_piece_group = selected_piece_group + + def add_game_piece(self, column, row, piece_type): + if 0 <= column < self.columns and 0 <= row < self.rows: + if self._game_grid[(column, row)] != EMPTY_SPRITE: + raise ValueError("Position already occupied") + self._game_grid[(column, row)] = piece_type + else: + raise IndexError("Position out of bounds") + + def remove_game_piece(self, column, row): + if 0 <= column < self.columns and 0 <= row < self.rows: + self._game_grid[(column, row)] = EMPTY_SPRITE + else: + raise IndexError("Position out of bounds") + + def reset(self): + for column in range(self.columns): + for row in range(self.rows): + if self._game_grid[(column, row)] != EMPTY_SPRITE: + self.remove_game_piece(column, row) + # Hide the animation TileGrids + self._selector.hidden = True + self._swap_piece.hidden = True + self.selected_piece_group.hidden = True + + def move_game_piece(self, old_x, old_y, new_x, new_y): + if 0 <= old_x < self.columns and 0 <= old_y < self.rows: + if 0 <= new_x < self.columns and 0 <= new_y < self.rows: + if self._game_grid[(new_x, new_y)] == EMPTY_SPRITE: + self._game_grid[(new_x, new_y)] = self._game_grid[(old_x, old_y)] + self._game_grid[(old_x, old_y)] = EMPTY_SPRITE + else: + raise ValueError("New position already occupied") + else: + raise IndexError("New position out of bounds") + else: + raise IndexError("Old position out of bounds") + + @property + def columns(self): + return self._game_grid.width + + @property + def rows(self): + return self._game_grid.height + + @property + def selected_piece(self): + if self._selected_coords is not None and self._selected_piece[0] != EMPTY_SPRITE: + return self._selected_piece[0] + return None + + @property + def swap_piece(self): + return self._swap_piece + + def set_swap_piece(self, column, row): + # Set the swap piece to the piece at the specified coordinates + piece = self.get_piece(column, row) + if self._swap_piece[0] is None and self._swap_piece[0] == EMPTY_SPRITE: + raise ValueError("Can't swap an empty piece") + if self._swap_piece.hidden: + self._swap_piece[0] = piece + self._swap_piece.x = column * 32 + self.x + self._swap_piece.y = row * 32 + self.y + self._swap_piece.hidden = False + self._game_grid[(column, row)] = EMPTY_SPRITE + else: + self._game_grid[(column, row)] = self._swap_piece[0] + self._swap_piece[0] = EMPTY_SPRITE + self._swap_piece.hidden = True + + @property + def selected_coords(self): + if self._selected_coords is not None: + return self._selected_coords + return None + + @property + def selector_hidden(self): + return self._selector.hidden + + @selector_hidden.setter + def selector_hidden(self, value): + # Set the visibility of the selector + self._selector.hidden = value + + def set_selected_coords(self, column, row): + # Set the selected coordinates to the specified column and row + if 0 <= column < self.columns and 0 <= row < self.rows: + self._selected_coords = (column, row) + self.selected_piece_group.x = column * 32 + self.x + self.selected_piece_group.y = row * 32 + self.y + else: + raise IndexError("Selected coordinates out of bounds") + + def select_piece(self, column, row, show_selector=True): + # Take care of selecting a piece + piece = self.get_piece(column, row) + if self.selected_piece is None and piece == EMPTY_SPRITE: + # If no piece is selected and the clicked piece is empty, do nothing + return + + if (self.selected_piece is not None and + (self._selected_coords[0] != column or self._selected_coords[1] != row)): + # If a piece is already selected and the coordinates don't match, do nothing + return + + if self.selected_piece is None: + # No piece selected, so select the specified piece + self._selected_piece[0] = self.get_piece(column, row) + self._selected_coords = (column, row) + self.selected_piece_group.x = column * 32 + self.x + self.selected_piece_group.y = row * 32 + self.y + self.selected_piece_group.hidden = False + self.selector_hidden = not show_selector + self._game_grid[(column, row)] = EMPTY_SPRITE + else: + self._game_grid[(column, row)] = self._selected_piece[0] + self._selected_piece[0] = EMPTY_SPRITE + self.selected_piece_group.hidden = True + self._selected_coords = None + + def get_piece(self, column, row): + if 0 <= column < self.columns and 0 <= row < self.rows: + return self._game_grid[(column, row)] + return None + + @property + def game_grid_copy(self): + # Return a copy of the game grid as a 2D list + return [[self._game_grid[(x, y)] for x in range(self.columns)] for y in range(self.rows)] + +class GameLogic: + "Contains the Logic to examine the game board and determine if a move is valid." + def __init__(self, display, mouse, game_grid, swap_piece, + selected_piece_group, game_pieces, hint_timeout): + self._display = display + self._mouse = mouse + self.game_board = GameBoard(game_grid, swap_piece, selected_piece_group) + self._score = 0 + self._available_moves = [] + if not 3 <= game_pieces <= 8: + raise ValueError("game_pieces must be between 3 and 8") + self._game_pieces = game_pieces # Number of different game pieces + self._hint_timeout = hint_timeout + self._last_update_time = ticks_ms() # For hint timing + self._last_click_time = ticks_ms() # For debouncing mouse clicks + self.pressed_btns = None + self.waiting_for_release = False + + def update_mouse(self): + self.pressed_btns = self._mouse.update() + if self.waiting_for_release and not self.pressed_btns: + # If both buttons are released, we can process the next click + self.waiting_for_release = False + + def update(self): + gb = self.game_board + if (gb.x <= self._mouse.x <= gb.x + gb.columns * 32 and + gb.y <= self._mouse.y <= gb.y + gb.rows * 32 and + not self.waiting_for_release): + piece_coords = ((self._mouse.x - gb.x) // 32, (self._mouse.y - gb.y) // 32) + if self.pressed_btns and "left" in self.pressed_btns: + self._piece_clicked(piece_coords) + self.waiting_for_release = True + if self.time_since_last_update > self._hint_timeout: + self.show_hint() + + def _piece_clicked(self, coords): + """ Handle a piece click event. """ + if ticks_ms() <= self._last_click_time: + self._last_click_time -= 2**29 # ticks_ms() wraps around after 2**29 ms + + if ticks_ms() <= self._last_click_time + (DEBOUNCE_TIME * 1000): + print("Debouncing click, too soon after last click.") + return + self._last_click_time = ticks_ms() # Update last click time + + column, row = coords + self._last_update_time = ticks_ms() + # Check if the clicked piece is valid + if not 0 <= column < self.game_board.columns or not 0 <= row < self.game_board.rows: + print(f"Clicked coordinates ({column}, {row}) are out of bounds.") + return + + # If clicked piece is empty and no piece is selected, do nothing + if (self.game_board.get_piece(column, row) == EMPTY_SPRITE and + self.game_board.selected_piece is None): + print(f"No piece at ({column}, {row}) and no piece selected.") + return + + if self.game_board.selected_piece is None: + # If no piece is selected, select the piece at the clicked coordinates + self.game_board.select_piece(column, row) + return + + if (self.game_board.selected_coords is not None and + (self.game_board.selected_coords[0] == column and + self.game_board.selected_coords[1] == row)): + # If the clicked piece is already selected, deselect it + self.game_board.select_piece(column, row) + return + + # If piece is selected and the new coordinates are 1 position + # away horizontally or vertically, swap the pieces + if self.game_board.selected_coords is not None: + previous_x, previous_y = self.game_board.selected_coords + if ((abs(previous_x - column) == 1 and previous_y == row) or + (previous_x == column and abs(previous_y - row) == 1)): + # Swap the pieces + self._swap_selected_piece(column, row) + + def show_hint(self): + """ Show a hint by selecting a random available + move and swapping the pieces back and forth. """ + if self._available_moves: + move = random.choice(self._available_moves) + from_coords = move['from'] + to_coords = move['to'] + self.game_board.select_piece(from_coords[0], from_coords[1]) + self._animate_swap(to_coords[0], to_coords[1]) + self.game_board.select_piece(from_coords[0], from_coords[1]) + self._animate_swap(to_coords[0], to_coords[1]) + self._last_update_time = ticks_ms() # Reset hint timer + + def _swap_selected_piece(self, column, row): + """ Swap the selected piece with the piece at the specified column and row. + If the swap is not valid, revert to the previous selection. """ + old_coords = self.game_board.selected_coords + self._animate_swap(column, row) + if not self._update_board(): + self.game_board.select_piece(column, row, show_selector=False) + self._animate_swap(old_coords[0], old_coords[1]) + + def _animate_swap(self, column, row): + """ Copy the pieces to separate tilegrids, animate the swap, and update the game board. """ + if 0 <= column < self.game_board.columns and 0 <= row < self.game_board.rows: + selected_coords = self.game_board.selected_coords + if selected_coords is None: + print("No piece selected to swap.") + return + + # Set the swap piece value to the column, row value + self.game_board.set_swap_piece(column, row) + self.game_board.selector_hidden = True + + # Calculate the steps for animation to move the pieces in the correct direction + selected_piece_steps = ( + (self.game_board.swap_piece.x - self.game_board.selected_piece_group.x) // 32, + (self.game_board.swap_piece.y - self.game_board.selected_piece_group.y) // 32 + ) + swap_piece_steps = ( + (self.game_board.selected_piece_group.x - self.game_board.swap_piece.x) // 32, + (self.game_board.selected_piece_group.y - self.game_board.swap_piece.y) // 32 + ) + + # Move the tilegrids in small steps to create an animation effect + for _ in range(32): + # Move the selected piece tilegrid to the swap piece position + self.game_board.selected_piece_group.x += selected_piece_steps[0] + self.game_board.selected_piece_group.y += selected_piece_steps[1] + # Move the swap piece tilegrid to the selected piece position + self.game_board.swap_piece.x += swap_piece_steps[0] + self.game_board.swap_piece.y += swap_piece_steps[1] + time.sleep(0.002) + + # Set the existing selected piece coords to the swap piece value + self.game_board.set_swap_piece(selected_coords[0], selected_coords[1]) + + # Update the selected piece coordinates to the new column, row + self.game_board.set_selected_coords(column, row) + + # Deselect the selected piece (which sets the value) + self.game_board.select_piece(column, row) + + def _apply_gravity(self): + """ Go through each column from the bottom up and move pieces down + continue until there are no more pieces to move """ + # pylint:disable=too-many-nested-blocks + while True: + self.pressed_btns = self._mouse.update() + moved = False + for x in range(self.game_board.columns): + for y in range(self.game_board.rows - 1, -1, -1): + piece = self.game_board.get_piece(x, y) + if piece != EMPTY_SPRITE: + # Check if the piece can fall + for new_y in range(y + 1, self.game_board.rows): + if self.game_board.get_piece(x, new_y) == EMPTY_SPRITE: + # Move the piece down + self.game_board.move_game_piece(x, y, x, new_y) + moved = True + break + # If the piece was in the top slot before falling, add a new piece + if y == 0 and self.game_board.get_piece(x, 0) == EMPTY_SPRITE: + self.game_board.add_game_piece(x, 0, random.randint(0, self._game_pieces)) + moved = True + if not moved: + break + + def _check_for_matches(self): + """ Scan the game board for matches of 3 or more in a row or column """ + matches = [] + for x in range(self.game_board.columns): + for y in range(self.game_board.rows): + piece = self.game_board.get_piece(x, y) + if piece != EMPTY_SPRITE: + # Check horizontal matches + horizontal_match = [(x, y)] + for dx in range(1, 3): + if (x + dx < self.game_board.columns and + self.game_board.get_piece(x + dx, y) == piece): + horizontal_match.append((x + dx, y)) + else: + break + if len(horizontal_match) >= 3: + matches.append(horizontal_match) + + # Check vertical matches + vertical_match = [(x, y)] + for dy in range(1, 3): + if (y + dy < self.game_board.rows and + self.game_board.get_piece(x, y + dy) == piece): + vertical_match.append((x, y + dy)) + else: + break + if len(vertical_match) >= 3: + matches.append(vertical_match) + return matches + + def _update_board(self): + """ Update the game logic, check for matches, and apply gravity. """ + matches_found = False + multiplier = 1 + matches = self._check_for_matches() + while matches: + if matches: + for match in matches: + for x, y in match: + self.game_board.remove_game_piece(x, y) + self._score += 10 * multiplier * len(matches) * (len(match) - 2) + time.sleep(0.5) # Pause to show the match removal + self._apply_gravity() + matches_found = True + matches = self._check_for_matches() + multiplier += 1 + self._available_moves = self._find_all_possible_matches() + print(f"{len(self._available_moves)} available moves found.") + return matches_found + + def reset(self): + """ Reset the game board and score. """ + print("Reset started") + self.game_board.reset() + self._score = 0 + self._last_update_time = ticks_ms() + self._apply_gravity() + self._update_board() + print("Reset completed") + + def _check_match_after_move(self, row, column, direction, move_type='horizontal'): + """ Move the piece in a copy of the board to see if it creates a match.""" + if move_type == 'horizontal': + new_row, new_column = row, column + direction + else: # vertical + new_row, new_column = row + direction, column + + # Check if move is within bounds + if (new_row < 0 or new_row >= self.game_board.rows or + new_column < 0 or new_column >= self.game_board.columns): + return False, False + + # Create a copy of the grid with the moved piece + new_grid = self.game_board.game_grid_copy + piece = new_grid[row][column] + new_grid[row][column], new_grid[new_row][new_column] = new_grid[new_row][new_column], piece + + # Check for horizontal matches at the new position + horizontal_match = self._check_horizontal_match(new_grid, new_row, new_column, piece) + + # Check for vertical matches at the new position + vertical_match = self._check_vertical_match(new_grid, new_row, new_column, piece) + + # Also check the original position for matches after the swap + original_piece = new_grid[row][column] + horizontal_match_orig = self._check_horizontal_match(new_grid, row, column, original_piece) + vertical_match_orig = self._check_vertical_match(new_grid, row, column, original_piece) + + all_matches = (horizontal_match + vertical_match + + horizontal_match_orig + vertical_match_orig) + + return True, len(all_matches) > 0 + + @staticmethod + def _check_horizontal_match(grid, row, column, piece): + """Check for horizontal 3-in-a-row matches centered + around or including the given position.""" + matches = [] + columns = len(grid[0]) + + # Check all possible 3-piece horizontal combinations that include this position + for start_column in range(max(0, column - 2), min(columns - 2, column + 1)): + if (start_column + 2 < columns and + grid[row][start_column] == piece and + grid[row][start_column + 1] == piece and + grid[row][start_column + 2] == piece): + matches.append([(row, start_column), + (row, start_column + 1), + (row, start_column + 2)]) + + return matches + + @staticmethod + def _check_vertical_match(grid, row, column, piece): + """Check for vertical 3-in-a-row matches centered around or including the given position.""" + matches = [] + rows = len(grid) + + # Check all possible 3-piece vertical combinations that include this position + for start_row in range(max(0, row - 2), min(rows - 2, row + 1)): + if (start_row + 2 < rows and + grid[start_row][column] == piece and + grid[start_row + 1][column] == piece and + grid[start_row + 2][column] == piece): + matches.append([(start_row, column), + (start_row + 1, column), + (start_row + 2, column)]) + + return matches + + def check_for_game_over(self): + """ Check if there are no available moves left on the game board. """ + if not self._available_moves: + return True + return False + + def _find_all_possible_matches(self): + """ + Scan the entire game board to find all possible moves that would create a 3-in-a-row match. + """ + possible_moves = [] + + for row in range(self.game_board.rows): + for column in range(self.game_board.columns): + # Check move right + can_move, creates_match = self._check_match_after_move( + row, column, 1, 'horizontal') + if can_move and creates_match: + possible_moves.append({ + 'from': (column, row), + 'to': (column + 1, row), + }) + + # Check move left + can_move, creates_match = self._check_match_after_move( + row, column, -1, 'horizontal') + if can_move and creates_match: + possible_moves.append({ + 'from': (column, row), + 'to': (column - 1, row), + }) + + # Check move down + can_move, creates_match = self._check_match_after_move( + row, column, 1, 'vertical') + if can_move and creates_match: + possible_moves.append({ + 'from': (column, row), + 'to': (column, row + 1), + }) + + # Check move up + can_move, creates_match = self._check_match_after_move( + row, column, -1, 'vertical') + if can_move and creates_match: + possible_moves.append({ + 'from': (column, row), + 'to': (column, row - 1), + }) + + # Remove duplicates because from and to can be reversed + unique_moves = set() + for move in possible_moves: + from_coords = tuple(move['from']) + to_coords = tuple(move['to']) + if from_coords > to_coords: + unique_moves.add((to_coords, from_coords)) + else: + unique_moves.add((from_coords, to_coords)) + possible_moves = [{'from': move[0], 'to': move[1]} for move in unique_moves] + + return possible_moves + + @property + def score(self): + return self._score + + @property + def time_since_last_update(self): + return (ticks_ms() - self._last_update_time) / 1000.0 diff --git a/Metro/Metro_RP2350_Memory/memory_game/btn_exit.bmp b/Metro/Metro_RP2350_Memory/memory_game/btn_exit.bmp new file mode 100644 index 000000000..2c3347e6b Binary files /dev/null and b/Metro/Metro_RP2350_Memory/memory_game/btn_exit.bmp differ diff --git a/Metro/Metro_RP2350_Memory/memory_game/btn_play_again.bmp b/Metro/Metro_RP2350_Memory/memory_game/btn_play_again.bmp new file mode 100644 index 000000000..ce4b8fed9 Binary files /dev/null and b/Metro/Metro_RP2350_Memory/memory_game/btn_play_again.bmp differ diff --git a/Metro/Metro_RP2350_Memory/memory_game/code.py b/Metro/Metro_RP2350_Memory/memory_game/code.py new file mode 100644 index 000000000..4e2b38a0a --- /dev/null +++ b/Metro/Metro_RP2350_Memory/memory_game/code.py @@ -0,0 +1,514 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +An implementation of the card game memory. Players take turns flipping +over two cards trying to find pairs. After the turn any non-pairs are +flipped face down so the players must try to remember where they are. + +Players trade off using the USB mouse to play their turns. +""" +import array +import random +import time +import atexit +from displayio import Group, OnDiskBitmap, TileGrid +from adafruit_display_text.bitmap_label import Label +from adafruit_display_text.text_box import TextBox +from adafruit_displayio_layout.layouts.grid_layout import GridLayout +from adafruit_ticks import ticks_ms +import supervisor +import terminalio +import usb.core +from adafruit_fruitjam.peripherals import request_display_config +import adafruit_usb_host_descriptors +from adafruit_pathlib import Path + + +def random_selection(lst, count): + """ + Select items randomly from a list of items. + + returns a list of length count containing the selected items. + """ + if len(lst) <= count: + raise ValueError("Count must be less than or equal to length of list") + iter_copy = list(lst) + selection = set() + while len(selection) < count: + selection.add(iter_copy.pop(random.randrange(len(iter_copy)))) + return list(selection) + + +def update_score_text(): + """ + Update the score text on the display for each player + """ + for _ in range(2): + out_str = f"p{_ + 1} score: {player_scores[_]}" + score_lbls[_].text = out_str + + +# state machine constants + +# title state, shows title screen waits for click +STATE_TITLE = 0 + +# playing state alternates players flipping cards to play the game +STATE_PLAYING = 1 + +# shows the game over message and waits for a button to be clicked +STATE_GAMEOVER = 2 + +# initial state is title screen +CUR_STATE = STATE_TITLE + +request_display_config(320, 240) +display = supervisor.runtime.display + +# main group will hold all the visual elements +main_group = Group() + +# make main group visible on the display +display.root_group = main_group + +# list of Label instances for player scores +score_lbls = [] + +# list of colors, one representing each player +colors = [0xFF00FF, 0x00FF00] + +# randomly choose the first player +current_turn_index = random.randrange(0, 2) + +# list that holds up to 2 cards that have been flipped over +# on the current turn +cards_flipped_this_turn = [] + +# list that holds the scores of each player +player_scores = [0, 0] + +# size of the grid of cards to layout +grid_size = (6, 4) + +# create a grid layout to help place cards neatly +# into a grid on the display +card_grid = GridLayout(x=10, y=10, width=260, height=200, grid_size=grid_size) + +# these indexes within the spritesheet contain the +# card front sprites, there are 8 different cards total. +CARD_FRONT_SPRITE_INDEXES = {1, 2, 3, 4, 5, 6, 7, 9} + +# pool of cards to deal them onto the board from +# starts with 2 copies of each of 8 different cards +pool = list(CARD_FRONT_SPRITE_INDEXES) + list(CARD_FRONT_SPRITE_INDEXES) + +# select 4 cards at random that will be duplicated +duplicates = random_selection(CARD_FRONT_SPRITE_INDEXES, 4) + +# add 2 copies each of the 4 selected duplicate cards +# this brings the pool to 24 cards total +pool += duplicates + duplicates + +# list that represents the order the cards are randomly +# dealt out into. The board is a two-dimensional grid, +# but this list is one dimension where +# index in the list = y * width + x in the grid. +card_locations = [] + +# load the spritesheet for the cards +sprites = OnDiskBitmap("memory_game_sprites.bmp") + +# list to hold TileGrid instances for each card +card_tgs = [] + +# loop over 4 rows +for y in range(4): + # loop over 6 columns + for x in range(6): + # i = y * 6 + x + + # create a TileGrid + new_tg = TileGrid( + bitmap=sprites, + default_tile=10, + tile_height=32, + tile_width=32, + height=1, + width=1, + pixel_shader=sprites.pixel_shader, + ) + + # add it to the list of card tilegrids + card_tgs.append(new_tg) + + # add it to the grid layout at the current x,y position + card_grid.add_content(new_tg, grid_position=(x, y), cell_size=(1, 1)) + + # choose a random index of a card in the pool + random_choice = random.randrange(0, len(pool) - 1) if len(pool) > 1 else 0 + + # remove the chosen card from the pool, and add it + # to the card locations list at the current location + card_locations.append(pool.pop(random_choice)) + +# center the card grid layout horizontally +card_grid.x = display.width // 2 - card_grid.width // 2 + +# move the card grid layout towards the bottom of the screen +card_grid.y = display.height - card_grid.height + +# add the card grid to the main group +main_group.append(card_grid) + +# create a group to hold the game over elements +game_over_group = Group() + +# create a TextBox to hold the game over message +game_over_label = TextBox( + terminalio.FONT, + text="", + color=0xFFFFFF, + background_color=0x222222, + width=display.width // 2, + height=80, + align=TextBox.ALIGN_CENTER, +) +# move it to the center top of the display +game_over_label.anchor_point = (0, 0) +game_over_label.anchored_position = ( + display.width // 2 - game_over_label.width // 2, + 40, +) + +# make it hidden, it will show it when the game is over. +game_over_group.hidden = True + +# add the game over lable to the game over group +game_over_group.append(game_over_label) + +# load the play again, and exit button bitmaps +play_again_btn_bmp = OnDiskBitmap("btn_play_again.bmp") +exit_btn_bmp = OnDiskBitmap("btn_exit.bmp") + +# create TileGrid for the play again button +play_again_btn = TileGrid( + bitmap=play_again_btn_bmp, pixel_shader=play_again_btn_bmp.pixel_shader +) + +# transparent pixels in the corners for the rounded corner effect +play_again_btn_bmp.pixel_shader.make_transparent(0) + +# centered within the display, offset to the left +play_again_btn.x = display.width // 2 - play_again_btn_bmp.width // 2 - 30 + +# inside the bounds of the game over label, so it looks like a dialog visually +play_again_btn.y = 80 + +# create TileGrid for the exit button +exit_btn = TileGrid(bitmap=exit_btn_bmp, pixel_shader=exit_btn_bmp.pixel_shader) + +# transparent pixels in the corners for the rounded corner effect +exit_btn_bmp.pixel_shader.make_transparent(0) + +# centered within the display, offset to the right +exit_btn.x = display.width // 2 - exit_btn_bmp.width // 2 + 30 + +# inside the bounds of the game over label, so it looks like a dialog visually +exit_btn.y = 80 + +# add the play again and exit buttons to the game over group +game_over_group.append(play_again_btn) +game_over_group.append(exit_btn) + +# add the game over group to the main group +main_group.append(game_over_group) + +# create score label for each player +for i in range(2): + # create a new label to hold score + score_lbl = Label(terminalio.FONT, text="", color=colors[i], scale=1) + if i == 0: + # if it's player 1 put it in the top left + score_lbl.anchor_point = (0, 0) + score_lbl.anchored_position = (4, 1) + else: + # if it's player 2 put it tin the top right + score_lbl.anchor_point = (1.0, 0) + score_lbl.anchored_position = (display.width - 4, 1) + + # add the label to list of score labels + score_lbls.append(score_lbl) + + # add the label to the main group + main_group.append(score_lbl) + +# initialize the text in the score labels to show 0 +update_score_text() + +# create a label to indicate which player's turn it is +current_player_lbl = Label( + terminalio.FONT, text="Current Player", color=colors[current_turn_index], scale=1 +) + +# place it centered horizontally at the top of the screen +current_player_lbl.anchor_point = (0.5, 0) +current_player_lbl.anchored_position = (display.width // 2, 1) + +# add the score label to the main group +main_group.append(current_player_lbl) + +# load the title screen bitmap +title_screen_bmp = OnDiskBitmap("memory_title.bmp") + +# create a TileGrid for the title screen +title_screen_tg = TileGrid( + bitmap=title_screen_bmp, pixel_shader=title_screen_bmp.pixel_shader +) + +# add it to the main group +main_group.append(title_screen_tg) + +# load the mouse bitmap +mouse_bmp = OnDiskBitmap("mouse_cursor.bmp") + +# make the background pink pixels transparent +mouse_bmp.pixel_shader.make_transparent(0) + +# create a TileGrid for the mouse +mouse_tg = TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader) + +# place it in the center of the display +mouse_tg.x = display.width // 2 +mouse_tg.y = display.height // 2 + +# add the mouse to the main group +main_group.append(mouse_tg) + +# variable for the mouse USB device instance +mouse = None + +# wait a second for USB devices to be ready +time.sleep(1) + +mouse_interface_index, mouse_endpoint_address = None, None +mouse = None + +# scan for connected USB devices +for device in usb.core.find(find_all=True): + # print information about the found devices + print(f"{device.idVendor:04x}:{device.idProduct:04x}") + print(device.manufacturer, device.product) + print(device.serial_number) + + config_descriptor = adafruit_usb_host_descriptors.get_configuration_descriptor( + device, 0 + ) + + _possible_interface_index, _possible_endpoint_address = ( + adafruit_usb_host_descriptors.find_boot_mouse_endpoint(device)) + + if _possible_interface_index is not None and _possible_endpoint_address is not None: + mouse = device + mouse_interface_index = _possible_interface_index + mouse_endpoint_address = _possible_endpoint_address + print(f"mouse interface: {mouse_interface_index}", end="") + print(f"endpoint_address: {hex(mouse_endpoint_address)}") + +mouse_was_attached = None +if mouse is not None: + # detach the kernel driver if needed + if mouse.is_kernel_driver_active(0): + mouse_was_attached = True + mouse.detach_kernel_driver(0) + else: + mouse_was_attached = False + + # set configuration on the mouse so we can use it + mouse.set_configuration() + + +def atexit_callback(): + """ + re-attach USB devices to kernel if needed. + :return: + """ + print("inside atexit callback") + if mouse_was_attached and not mouse.is_kernel_driver_active(0): + mouse.attach_kernel_driver(0) + + +atexit.register(atexit_callback) + +# Buffer to hold data read from the mouse +# Boot mice have 4 byte reports +buf = array.array("b", [0] * 4) + +# timestamp in the future to wait until before +# awarding points for a pair, or flipping cards +# back over and changing turns +WAIT_UNTIL = 0 + +# bool indicating whether the code is waiting to reset flipped +# cards and change turns or award points and remove +# cards. Will be True if the code is waiting to take action, +# False otherwise. +waiting_to_reset = False + +# main loop +while True: + # timestamp of the current time + now = ticks_ms() + + # attempt mouse read + try: + # try to read data from the mouse, small timeout so the code will move on + # quickly if there is no data + data_len = mouse.read(mouse_endpoint_address, buf, timeout=20) + + # if there was data, then update the mouse cursor on the display + # using min and max to keep it within the bounds of the display + mouse_tg.x = max(0, min(display.width - 1, mouse_tg.x + buf[1] // 2)) + mouse_tg.y = max(0, min(display.height - 1, mouse_tg.y + buf[2] // 2)) + + # timeout error is raised if no data was read within the allotted timeout + except usb.core.USBTimeoutError: + # no problem, just go on + pass + + # if the current state is title screen + if CUR_STATE == STATE_TITLE: + # if the left mouse button was clicked + if buf[0] & (1 << 0) != 0: + # change the current state to playing + CUR_STATE = STATE_PLAYING + # hide the title screen + title_screen_tg.hidden = True + # change the mouse cursor color to match the current player + mouse_bmp.pixel_shader[2] = colors[current_turn_index] + + # if the current state is playing + elif CUR_STATE == STATE_PLAYING: + + # if the code is waiting to reset, and it's time to take action + if waiting_to_reset and now >= WAIT_UNTIL: + # this means that there are already 2 cards flipped face up. + # The code needs to either award points, or flip the cards + # back over and change to the next players turn. + + # change variable to indicate the code is no longer waiting to take action + waiting_to_reset = False + + # if both cards were the same i.e. they found a match + if ( + card_tgs[cards_flipped_this_turn[0]][0] + == card_tgs[cards_flipped_this_turn[1]][0] + ): + + # set the cards tile index to show a blank spot instead of a card + card_tgs[cards_flipped_this_turn[0]][0] = 8 + card_tgs[cards_flipped_this_turn[1]][0] = 8 + + # award a point to the player + player_scores[current_turn_index] += 1 + + # refresh the score texts to show the new score + update_score_text() + + # if the total of both players scores is equal to half the amount + # of cards then the code knows the game is over because each pair is worth 1 + # point + if ( + player_scores[0] + player_scores[1] + >= (grid_size[0] * grid_size[1]) // 2 + ): + + # if the player's scores are equal + if player_scores[0] == player_scores[1]: + # set the game over message to tie game + game_over_label.text = "Game Over\nTie Game" + + else: # player scores are not equal + + # if player 2 score is larger than player 1 + if player_scores[0] < player_scores[1]: + # set the game over message to indicate player 2 victory + game_over_label.text = "Game Over\nPlayer 2 Wins" + game_over_label.color = colors[1] + + else: # player 1 score is larger than player 2 + # set the game over message to indicate player 1 victory + game_over_label.text = "Game Over\nPlayer 1 Wins" + game_over_label.color = colors[0] + + # set the game over group to visible + game_over_group.hidden = False + + # change the state to gameover + CUR_STATE = STATE_GAMEOVER + + else: # the two cards were different i.e. they did not find a match + # set both cards tile index to the card back sprite to flip it back over + card_tgs[cards_flipped_this_turn[0]][0] = 10 + card_tgs[cards_flipped_this_turn[1]][0] = 10 + + # go to the next players turn + current_turn_index = (current_turn_index + 1) % 2 + + # update the color of the current player indicator + current_player_lbl.color = colors[current_turn_index] + + # update the color of the mouse cursor + mouse_bmp.pixel_shader[2] = colors[current_turn_index] + + # empty out the cards flipped this turn list + cards_flipped_this_turn = [] + + # ignore any clicks while the code is waiting to take reset cards + if now >= WAIT_UNTIL: + # left btn pressed + if buf[0] & (1 << 0) != 0: + + # loop over all cards + for card_index, card in enumerate(card_tgs): + # coordinates of the mouse taking into account + # the offset from the card_grid position + coords = (mouse_tg.x - card_grid.x, mouse_tg.y - card_grid.y, 0) + + # if this is a face down card, and the mouse coordinates + # are within its bounding box + if card[0] == 10 and card.contains(coords): + # flip the card face up by setting its tile index + # to the appropriate value from the card_locations list + card[0] = card_locations[card_tgs.index(card)] + + # add this card index to the cards flipped this turn list + cards_flipped_this_turn.append(card_index) + + # if 2 cards have been flipped this turn + if len(cards_flipped_this_turn) == 2: + # set the wait until time to a little bit in the future + WAIT_UNTIL = ticks_ms() + 1500 + # set the waiting to reset flag to True + waiting_to_reset = True + + # if the current state is gameover + elif CUR_STATE == STATE_GAMEOVER: + # left btn pressed + if buf[0] & (1 << 0) != 0: + # get the coordinates of the mouse cursor point + coords = (mouse_tg.x, mouse_tg.y, 0) + + # if the mouse point is within the play again + # button bounding box + if play_again_btn.contains(coords): + # set next code file to this one + supervisor.set_next_code_file(__file__, + working_directory=Path(__file__).parent.absolute()) + # reload + supervisor.reload() + + # if the mouse point is within the exit + # button bounding box + if exit_btn.contains(coords): + # restart back to code.py + supervisor.reload() diff --git a/Metro/Metro_RP2350_Memory/memory_game/icon.bmp b/Metro/Metro_RP2350_Memory/memory_game/icon.bmp new file mode 100644 index 000000000..c268a6b33 Binary files /dev/null and b/Metro/Metro_RP2350_Memory/memory_game/icon.bmp differ diff --git a/Metro/Metro_RP2350_Memory/memory_game/memory_game_sprites.bmp b/Metro/Metro_RP2350_Memory/memory_game/memory_game_sprites.bmp new file mode 100644 index 000000000..939717fcd Binary files /dev/null and b/Metro/Metro_RP2350_Memory/memory_game/memory_game_sprites.bmp differ diff --git a/Metro/Metro_RP2350_Memory/memory_game/memory_title.bmp b/Metro/Metro_RP2350_Memory/memory_game/memory_title.bmp new file mode 100644 index 000000000..54ae2b30f Binary files /dev/null and b/Metro/Metro_RP2350_Memory/memory_game/memory_title.bmp differ diff --git a/Metro/Metro_RP2350_Memory/memory_game/metadata.json b/Metro/Metro_RP2350_Memory/memory_game/metadata.json new file mode 100644 index 000000000..cbf41d7da --- /dev/null +++ b/Metro/Metro_RP2350_Memory/memory_game/metadata.json @@ -0,0 +1,4 @@ +{ + "title": "Memory", + "icon": "icon.bmp" +} diff --git a/Metro/Metro_RP2350_Memory/memory_game/mouse_cursor.bmp b/Metro/Metro_RP2350_Memory/memory_game/mouse_cursor.bmp new file mode 100644 index 000000000..94ec32889 Binary files /dev/null and b/Metro/Metro_RP2350_Memory/memory_game/mouse_cursor.bmp differ diff --git a/Metro/Metro_RP2350_Memory/mouse_demo/code.py b/Metro/Metro_RP2350_Memory/mouse_demo/code.py new file mode 100644 index 000000000..4518e8efa --- /dev/null +++ b/Metro/Metro_RP2350_Memory/mouse_demo/code.py @@ -0,0 +1,134 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +This example is made for a basic Microsoft optical mouse with +two buttons and a wheel that can be pressed. + +It assumes there is a single mouse connected to USB Host, +and no other devices connected. +""" +import array +from displayio import Group, OnDiskBitmap, TileGrid +from adafruit_display_text.bitmap_label import Label +import supervisor +import terminalio +import usb.core + +# pylint: disable=ungrouped-imports +if hasattr(supervisor.runtime, "display") and supervisor.runtime.display is not None: + # use the built-in HSTX display for Metro RP2350 + display = supervisor.runtime.display +else: + # pylint: disable=ungrouped-imports + from displayio import release_displays + import picodvi + import board + import framebufferio + + # initialize display + release_displays() + + fb = picodvi.Framebuffer( + 320, + 240, + clk_dp=board.CKP, + clk_dn=board.CKN, + red_dp=board.D0P, + red_dn=board.D0N, + green_dp=board.D1P, + green_dn=board.D1N, + blue_dp=board.D2P, + blue_dn=board.D2N, + color_depth=16, + ) + display = framebufferio.FramebufferDisplay(fb) + +# group to hold visual elements +main_group = Group() + +# make the group visible on the display +display.root_group = main_group + +# load the mouse cursor bitmap +mouse_bmp = OnDiskBitmap("mouse_cursor.bmp") + +# make the background pink pixels transparent +mouse_bmp.pixel_shader.make_transparent(0) + +# create a TileGrid for the mouse, using its bitmap and pixel_shader +mouse_tg = TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader) + +# move it to the center of the display +mouse_tg.x = display.width // 2 +mouse_tg.y = display.height // 2 + +# text label to show the x, y coordinates on the screen +output_lbl = Label( + terminalio.FONT, text=f"{mouse_tg.x},{mouse_tg.y}", color=0xFFFFFF, scale=1 +) + +# move it to the upper left corner +output_lbl.anchor_point = (0, 0) +output_lbl.anchored_position = (1, 1) + +# add it to the main group +main_group.append(output_lbl) + +# add the mouse tile grid to the main group +main_group.append(mouse_tg) + +# button names +# This is ordered by bit position. +BUTTONS = ["left", "right", "middle"] + +# scan for connected USB device and loop over any found +for device in usb.core.find(find_all=True): + # print device info + print(f"{device.idVendor:04x}:{device.idProduct:04x}") + print(device.manufacturer, device.product) + print(device.serial_number) + # assume the device is the mouse + mouse = device + +# detach the kernel driver if needed +if mouse.is_kernel_driver_active(0): + mouse.detach_kernel_driver(0) + +# set configuration on the mouse so we can use it +mouse.set_configuration() + +# buffer to hold mouse data +# Boot mice have 4 byte reports +buf = array.array("b", [0] * 4) + +# main loop +while True: + try: + # attempt to read data from the mouse + # 10ms timeout, so we don't block long if there + # is no data + count = mouse.read(0x81, buf, timeout=10) + except usb.core.USBTimeoutError: + # skip the rest of the loop if there is no data + continue + + # update the mouse tilegrid x and y coordinates + # based on the delta values read from the mouse + mouse_tg.x = max(0, min(display.width - 1, mouse_tg.x + buf[1])) + mouse_tg.y = max(0, min(display.height - 1, mouse_tg.y + buf[2])) + + # string with updated coordinates for the text label + out_str = f"{mouse_tg.x},{mouse_tg.y}" + + # loop over the button names + for i, button in enumerate(BUTTONS): + # check if each button is pressed using bitwise AND shifted + # to the appropriate index for this button + if buf[0] & (1 << i) != 0: + # append the button name to the string to show if + # it is being clicked. + out_str += f" {button}" + + # update the text label with the new coordinates + # and buttons being pressed + output_lbl.text = out_str diff --git a/Metro/Metro_RP2350_Memory/mouse_demo/mouse_cursor.bmp b/Metro/Metro_RP2350_Memory/mouse_demo/mouse_cursor.bmp new file mode 100644 index 000000000..94ec32889 Binary files /dev/null and b/Metro/Metro_RP2350_Memory/mouse_demo/mouse_cursor.bmp differ diff --git a/Metro/Metro_RP2350_Memory/tictactoe_demo/code.py b/Metro/Metro_RP2350_Memory/tictactoe_demo/code.py new file mode 100644 index 000000000..886b896c9 --- /dev/null +++ b/Metro/Metro_RP2350_Memory/tictactoe_demo/code.py @@ -0,0 +1,253 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +This example is made for a basic Microsoft optical mouse with +two buttons and a wheel that can be pressed. + +It assumes there is a single mouse connected to USB Host, +and no other devices connected. + +It illustrates multi-player turn based logic with a very +basic implementation of tic-tac-toe. +""" +import array +import random +from displayio import Group, OnDiskBitmap, TileGrid +from adafruit_display_text.bitmap_label import Label +from adafruit_displayio_layout.layouts.grid_layout import GridLayout +import supervisor +import terminalio +import usb.core + +# pylint: disable=ungrouped-imports +if hasattr(supervisor.runtime, "display") and supervisor.runtime.display is not None: + # use the built-in HSTX display for Metro RP2350 + display = supervisor.runtime.display +else: + from displayio import release_displays + import picodvi + import board + import framebufferio + + # initialize display + release_displays() + + fb = picodvi.Framebuffer( + 320, + 240, + clk_dp=board.CKP, + clk_dn=board.CKN, + red_dp=board.D0P, + red_dn=board.D0N, + green_dp=board.D1P, + green_dn=board.D1N, + blue_dp=board.D2P, + blue_dn=board.D2N, + color_depth=16, + ) + display = framebufferio.FramebufferDisplay(fb) + +# group to hold visual elements +main_group = Group() + +# make the group visible on the display +display.root_group = main_group + +# load the mouse cursor bitmap +mouse_bmp = OnDiskBitmap("mouse_cursor.bmp") + +# make the background pink pixels transparent +mouse_bmp.pixel_shader.make_transparent(0) + +# create a TileGrid for the mouse, using its bitmap and pixel_shader +mouse_tg = TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader) + +# move it to the center of the display +mouse_tg.x = display.width // 2 +mouse_tg.y = display.height // 2 + +# text label to show the x, y coordinates on the screen +output_lbl = Label(terminalio.FONT, text="", color=0xFFFFFF, scale=1) + +# move it to the right side of the screen +output_lbl.anchor_point = (0, 0) +output_lbl.anchored_position = (180, 40) + +# add it to the main group +main_group.append(output_lbl) + +# scan for connected USB device and loop over any found +for device in usb.core.find(find_all=True): + # print device info + print(f"{device.idVendor:04x}:{device.idProduct:04x}") + print(device.manufacturer, device.product) + print(device.serial_number) + # assume the device is the mouse + mouse = device + +# detach the kernel driver if needed +if mouse.is_kernel_driver_active(0): + mouse.detach_kernel_driver(0) + +# set configuration on the mouse so we can use it +mouse.set_configuration() + +# buffer to hold mouse data +# Boot mice have 4 byte reports +buf = array.array("b", [0] * 4) + +# set up a 3x3 grid for the tic-tac-toe board +board_grid = GridLayout(x=40, y=40, width=128, height=128, grid_size=(3, 3)) + +# load the tic-tac-toe spritesheet +tictactoe_spritesheet = OnDiskBitmap("tictactoe_spritesheet.bmp") + +# X is index 1 in the spritesheet, O is index 2 in the spritesheet +player_icon_indexes = [1, 2] + +# current player variable. +# When this equlas 0 its X's turn, +# when it equals 1 it is O's turn. +current_player_index = random.randint(0, 1) # randomize the initial player + +# loop over rows +for y in range(3): + # loop over columns + for x in range(3): + # create a TileGrid for this cell + new_tg = TileGrid( + bitmap=tictactoe_spritesheet, + default_tile=0, + tile_height=32, + tile_width=32, + height=1, + width=1, + pixel_shader=tictactoe_spritesheet.pixel_shader, + ) + + # add the new TileGrid to the board grid at the current position + board_grid.add_content(new_tg, grid_position=(x, y), cell_size=(1, 1)) + +# add the board grid to the main group +main_group.append(board_grid) + +# add the mouse tile grid to the main group +main_group.append(mouse_tg) + + +def check_for_winner(): + """ + check if a player has won + + :return: the player icon index of the winning player, + None if no winner and game continues, -1 if game ended in a tie. + """ + found_empty = False + + # check rows + for row_idx in range(3): + # if the 3 cells in this row match + if ( + board_grid[0 + (row_idx * 3)][0] != 0 + and board_grid[0 + (row_idx * 3)][0] + == board_grid[1 + (row_idx * 3)][0] + == board_grid[2 + (row_idx * 3)][0] + ): + return board_grid[0 + (row_idx * 3)][0] + + # if any of the cells in this row are empty + if 0 in ( + board_grid[0 + (row_idx * 3)][0], + board_grid[1 + (row_idx * 3)][0], + board_grid[2 + (row_idx * 3)][0], + ): + found_empty = True + + # check columns + for col_idx in range(3): + # if the 3 cells in this column match + if ( + board_grid[0 + col_idx][0] != 0 + and board_grid[0 + col_idx][0] + == board_grid[3 + col_idx][0] + == board_grid[6 + col_idx][0] + ): + return board_grid[0 + col_idx][0] + + # if any of the cells in this column are empty + if 0 in ( + board_grid[0 + col_idx][0], + board_grid[3 + col_idx][0], + board_grid[6 + col_idx][0], + ): + found_empty = True + + # check diagonals + if ( + board_grid[0][0] != 0 + and board_grid[0][0] == board_grid[4][0] == board_grid[8][0] + ): + return board_grid[0][0] + + if ( + board_grid[2][0] != 0 + and board_grid[2][0] == board_grid[4][0] == board_grid[6][0] + ): + return board_grid[2][0] + + if found_empty: + # return None if there is no winner and the game continues + return None + else: + # return -1 if it's a tie game with no winner + return -1 + + +# main loop +while True: + try: + # attempt to read data from the mouse + # 10ms timeout, so we don't block long if there + # is no data + count = mouse.read(0x81, buf, timeout=10) + except usb.core.USBTimeoutError: + # skip the rest of the loop if there is no data + continue + + # update the mouse tilegrid x and y coordinates + # based on the delta values read from the mouse + mouse_tg.x = max(0, min(display.width - 1, mouse_tg.x + buf[1])) + mouse_tg.y = max(0, min(display.height - 1, mouse_tg.y + buf[2])) + + # if left button clicked + if buf[0] & (1 << 0) != 0: + # get the mouse pointer coordinates accounting for the offset of + # the board grid location + coords = (mouse_tg.x - board_grid.x, mouse_tg.y - board_grid.y, 0) + + # loop over all cells in the board + for cell_tg in board_grid: + + # if the current cell is blank, and contains the clicked coordinates + if cell_tg[0] == 0 and cell_tg.contains(coords): + # set the current cell tile index to the current player's icon + cell_tg[0] = player_icon_indexes[current_player_index] + + # change to the next player + current_player_index = (current_player_index + 1) % 2 + + # print out which player's turn it is + print(f"It is now {'X' if current_player_index == 0 else 'O'}'s turn") + + # check for a winner + result = check_for_winner() + + # if Xs or Os have won + if result == 1: + output_lbl.text = "X is the winner!" + elif result == 2: + output_lbl.text = "O is the winner!" + + # if it was a tie game + elif result == -1: + output_lbl.text = "Tie game, no winner." diff --git a/Metro/Metro_RP2350_Memory/tictactoe_demo/mouse_cursor.bmp b/Metro/Metro_RP2350_Memory/tictactoe_demo/mouse_cursor.bmp new file mode 100644 index 000000000..94ec32889 Binary files /dev/null and b/Metro/Metro_RP2350_Memory/tictactoe_demo/mouse_cursor.bmp differ diff --git a/Metro/Metro_RP2350_Memory/tictactoe_demo/tictactoe_spritesheet.bmp b/Metro/Metro_RP2350_Memory/tictactoe_demo/tictactoe_spritesheet.bmp new file mode 100644 index 000000000..a210c9ab2 Binary files /dev/null and b/Metro/Metro_RP2350_Memory/tictactoe_demo/tictactoe_spritesheet.bmp differ diff --git a/Metro/Metro_RP2350_Minesweeper/bitmaps/game_sprites.bmp b/Metro/Metro_RP2350_Minesweeper/bitmaps/game_sprites.bmp new file mode 100755 index 000000000..57f286254 Binary files /dev/null and b/Metro/Metro_RP2350_Minesweeper/bitmaps/game_sprites.bmp differ diff --git a/Metro/Metro_RP2350_Minesweeper/bitmaps/icon.bmp b/Metro/Metro_RP2350_Minesweeper/bitmaps/icon.bmp new file mode 100644 index 000000000..3b1a4296a Binary files /dev/null and b/Metro/Metro_RP2350_Minesweeper/bitmaps/icon.bmp differ diff --git a/Metro/Metro_RP2350_Minesweeper/bitmaps/mouse_cursor.bmp b/Metro/Metro_RP2350_Minesweeper/bitmaps/mouse_cursor.bmp new file mode 100755 index 000000000..f941ad29b Binary files /dev/null and b/Metro/Metro_RP2350_Minesweeper/bitmaps/mouse_cursor.bmp differ diff --git a/Metro/Metro_RP2350_Minesweeper/code.py b/Metro/Metro_RP2350_Minesweeper/code.py new file mode 100644 index 000000000..62fb4288b --- /dev/null +++ b/Metro/Metro_RP2350_Minesweeper/code.py @@ -0,0 +1,296 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +An implementation of minesweeper. The logic game where the player +correctly identifies the locations of mines on a grid by clicking on squares +and revealing the number of mines in adjacent squares. + +The player can also flag squares they suspect contain mines. The game ends when +the player successfully reveals all squares without mines or clicks on a mine. +""" +import array +from displayio import Group, OnDiskBitmap, TileGrid, Bitmap, Palette +from adafruit_display_text.bitmap_label import Label +from adafruit_display_text.text_box import TextBox +from eventbutton import EventButton +import supervisor +import terminalio +from adafruit_usb_host_mouse import find_and_init_boot_mouse +from gamelogic import GameLogic, BLANK, INFO_BAR_HEIGHT, DIFFICULTIES +from menu import Menu, SubMenu + +# pylint: disable=ungrouped-imports +if hasattr(supervisor.runtime, "display") and supervisor.runtime.display is not None: + # use the built-in HSTX display for Metro RP2350 + display = supervisor.runtime.display +else: + # pylint: disable=ungrouped-imports + from displayio import release_displays + import picodvi + import board + import framebufferio + + # initialize display + release_displays() + + fb = picodvi.Framebuffer( + 320, + 240, + clk_dp=board.CKP, + clk_dn=board.CKN, + red_dp=board.D0P, + red_dn=board.D0N, + green_dp=board.D1P, + green_dn=board.D1N, + blue_dp=board.D2P, + blue_dn=board.D2N, + color_depth=16, + ) + display = framebufferio.FramebufferDisplay(fb) + supervisor.runtime.display = display + +game_logic = GameLogic(display) # pylint: disable=no-value-for-parameter + +# Load the spritesheet +sprite_sheet = OnDiskBitmap("bitmaps/game_sprites.bmp") + +# Main group will hold all the visual layers +main_group = Group() +display.root_group = main_group + +# Add Background to the Main Group +background = Bitmap(display.width, display.height, 1) +bg_color = Palette(1) +bg_color[0] = 0xaaaaaa +main_group.append(TileGrid( + background, + pixel_shader=bg_color +)) + +# Add Game group, which holds the game board, to the main group +game_group = Group() +main_group.append(game_group) + +# Add a group for the UI Elements +ui_group = Group() +main_group.append(ui_group) + +MENU_ITEM_HEIGHT = INFO_BAR_HEIGHT + +def create_game_board(): + # Remove the old game board + if len(game_group) > 0: + game_group.pop() + + x = display.width // 2 - (game_logic.grid_width * 16) // 2 + y = ((display.height - INFO_BAR_HEIGHT) // 2 - + (game_logic.grid_height * 16) // 2 + INFO_BAR_HEIGHT) + + # Create a new game board + game_board = TileGrid( + sprite_sheet, + pixel_shader=sprite_sheet.pixel_shader, + width=game_logic.grid_width, + height=game_logic.grid_height, + tile_height=16, + tile_width=16, + x=x, + y=y, + default_tile=BLANK, + ) + + game_group.append(game_board) + return game_board + +def update_ui(): + # Update the UI elements with the current game state + mines_left_label.text = f"Mines: {game_logic.mines_left}" + elapsed_time_label.text = f"Time: {game_logic.elapsed_time}" + + +# variable for the mouse USB device instance +mouse = find_and_init_boot_mouse(cursor_image="bitmaps/mouse_cursor.bmp") +if mouse is None: + raise RuntimeError("No mouse found. Please connect a USB mouse.") + +mouse.sensitivity = 4 # Slow the mouse down a bit +mouse_tg = mouse.tilegrid +mouse_tg.x = display.width // 2 +mouse_tg.y = display.height // 2 + +# add mouse graphic to main_group +main_group.append(mouse_tg) + +buf = array.array("b", [0] * 4) +waiting_for_release = False +chord_selected = False +left_button = right_button = False +mouse_coords = (display.width // 2, display.height // 2) + +# Create the UI Elements (Ideally fit into 320x16 area) +# Label for the Mines Left (Left of Center) +mines_left_label = Label( + terminalio.FONT, + color=0x000000, + x=5, + y=0, +) +mines_left_label.anchor_point = (0, 0) +mines_left_label.anchored_position = (5, 2) +ui_group.append(mines_left_label) +# Label for the Elapsed Time (Right of Center) +elapsed_time_label = Label( + terminalio.FONT, + color=0x000000, + x=display.width - 50, + y=0, +) +elapsed_time_label.anchor_point = (1, 0) +elapsed_time_label.anchored_position = (display.width - 5, 2) +ui_group.append(elapsed_time_label) + +# Menu button to change difficulty +difficulty_menu = SubMenu( + "Difficulty", + 70, + 80, + display.width // 2 - 70, + 0 +) + +reset_menu = SubMenu( + "Reset", + 50, + 40, + display.width // 2 + 15, + 0 +) + +message_dialog = Group() +message_dialog.hidden = True + +def reset(): + # Reset the game logic + game_logic.reset() + + # Create a new game board and assign it into the game logic + game_logic.game_board = create_game_board() + + message_dialog.hidden = True + +def set_difficulty(diff): + game_logic.difficulty = diff + reset() + difficulty_menu.select_item(DIFFICULTIES[diff]['label'].lower().replace(" ", "_")) + +def hide_group(group): + group.hidden = True + +for i, difficulty in enumerate(DIFFICULTIES): + # Create a button for each difficulty + selected = i == game_logic.difficulty + difficulty_menu.add_item((set_difficulty, i), difficulty['label'], selected) + +reset_menu.add_item(reset, "OK") + +menu = Menu() +menu.append(difficulty_menu) +menu.append(reset_menu) +ui_group.append(menu) + +reset() + +message_label = TextBox( + terminalio.FONT, + text="", + color=0x333333, + background_color=0xEEEEEE, + width=display.width // 4, + height=50, + align=TextBox.ALIGN_CENTER, + padding_top=5, +) +message_label.anchor_point = (0, 0) +message_label.anchored_position = ( + display.width // 2 - message_label.width // 2, + display.height // 2 - message_label.height // 2, +) +message_dialog.append(message_label) +message_button = EventButton( + (hide_group, message_dialog), + label="OK", + width=40, + height=16, + x=display.width // 2 - 20, + y=display.height // 2 - message_label.height // 2 + 20, + style=EventButton.RECT, +) +message_dialog.append(message_button) +ui_group.append(message_dialog) + +# Popup message for game over/win + +menus = (reset_menu, difficulty_menu) + +# main loop +while True: + update_ui() + # update cursor position, and check for clicks + mouse.update() + buttons = mouse.pressed_btns + + # Extract button states + if buttons is None or buttons == (): + left_button = 0 + right_button = 0 + else: + left_button = 1 if 'left' in buttons else 0 + right_button = 1 if 'right' in buttons else 0 + + mouse_coords = (mouse_tg.x, mouse_tg.y) + + if waiting_for_release and not left_button and not right_button: + # If both buttons are released, we can process the next click + waiting_for_release = False + + if not message_dialog.hidden: + if message_button.handle_mouse(mouse_coords, left_button, waiting_for_release): + waiting_for_release = True + continue + + if menu.handle_mouse(mouse_coords, left_button, waiting_for_release): + waiting_for_release = True + else: + # process gameboard click if no menu + ms_board = game_logic.game_board + + if left_button and right_button and not chord_selected: + chord_coords = ((mouse_tg.x - ms_board.x) // 16, (mouse_tg.y - ms_board.y) // 16) + chord_selected = game_logic.square_chord_highlight(chord_coords) + if chord_selected: + waiting_for_release = True + + if (ms_board.x <= mouse_tg.x <= ms_board.x + game_logic.grid_width * 16 and + ms_board.y <= mouse_tg.y <= ms_board.y + game_logic.grid_height * 16 and + not waiting_for_release): + + coords = ((mouse_tg.x - ms_board.x) // 16, (mouse_tg.y - ms_board.y) // 16) + if chord_selected: + chord_selected = False + game_logic.square_chord_highlight(chord_coords, False) + game_logic.square_chorded(chord_coords) + elif right_button: + game_logic.square_flagged(coords) + elif left_button: + if not game_logic.square_clicked(coords): + message_label.text = "Game Over" + message_dialog.hidden = False + if left_button or right_button: + waiting_for_release = True + status = game_logic.check_for_win() + if status: + message_label.text = "You win!" + message_dialog.hidden = False + # Display message + if status is None: + continue diff --git a/Metro/Metro_RP2350_Minesweeper/eventbutton.py b/Metro/Metro_RP2350_Minesweeper/eventbutton.py new file mode 100755 index 000000000..0aa910e40 --- /dev/null +++ b/Metro/Metro_RP2350_Minesweeper/eventbutton.py @@ -0,0 +1,41 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +from adafruit_button import Button + +class EventButton(Button): + """A button that can be used to trigger a callback when clicked. + + :param callback: The callback function to call when the button is clicked. + A tuple can be passed with an argument that will be passed to the + callback function. The first element of the tuple should be the + callback function, and the remaining elements will be passed as + arguments to the callback function. + """ + def __init__(self, callback, *args, **kwargs): + super().__init__(*args, **kwargs) + self.args = [] + if isinstance(callback, tuple): + self.callback = callback[0] + self.args = callback[1:] + else: + self.callback = callback + + def click(self): + """Call the function when the button is pressed.""" + self.callback(*self.args) + + def handle_mouse(self, point, clicked, waiting_for_release): + # pylint: disable=attribute-defined-outside-init + if waiting_for_release: + return False + + # Handle mouse events for the button + if self.contains(point): + self.selected = True + if clicked: + self.click() + return True + else: + self.selected = False + return False diff --git a/Metro/Metro_RP2350_Minesweeper/gamelogic.py b/Metro/Metro_RP2350_Minesweeper/gamelogic.py new file mode 100755 index 000000000..dba3bcbd8 --- /dev/null +++ b/Metro/Metro_RP2350_Minesweeper/gamelogic.py @@ -0,0 +1,343 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +import random +from microcontroller import nvm +from adafruit_ticks import ticks_ms +from displayio import TileGrid + +# Mine Densities are about the same as the original +DIFFICULTIES = ( + { + 'label': "Beginner", + 'grid_size': (8,8), + 'mines': 10, + }, + { + 'label': "Intermediate", + 'grid_size': (14, 14), + 'mines': 30, + }, + { + 'label': "Expert", + 'grid_size': (20, 14), + 'mines': 58, + }, +) + +INFO_BAR_HEIGHT = 16 + +OPEN = 0 +OPEN1 = 1 +OPEN2 = 2 +OPEN3 = 3 +OPEN4 = 4 +OPEN5 = 5 +OPEN6 = 6 +OPEN7 = 7 +OPEN8 = 8 + +BLANK = 9 +FLAG = 10 +MINE_CLICKED = 11 +MINE_FLAGGED_WRONG = 12 +MINE = 13 +MINE_QUESTION = 14 +MINE_QUESTION_OPEN = 15 + +STATUS_NEWGAME = 0 +STATUS_PLAYING = 1 +STATUS_WON = 2 +STATUS_LOST = 3 + +class GameLogic: + def __init__(self, display): + self._board_data = bytearray() + self.game_board = None + self._difficulty = nvm[0] + if self._difficulty not in DIFFICULTIES: + self._difficulty = 0 + self._display = display + self._start_time = None + self._end_time = None + self._mine_count = 0 + self._status = STATUS_NEWGAME + self.reset() + + def reset(self): + if (self.grid_width * 16 > self._display.width or + self.grid_height * 16 > self._display.height - INFO_BAR_HEIGHT): + raise ValueError("Grid size exceeds display size") + self._mine_count = DIFFICULTIES[self._difficulty]['mines'] + if self._mine_count > (self.grid_width - 1) * (self.grid_height - 1): + raise ValueError("Too many mines for grid size") + if self._mine_count < 10: + raise ValueError("There must be at least 10 mines") + self._board_data = bytearray(self.grid_width * self.grid_height) + self._status = STATUS_NEWGAME + self._start_time = None + self._end_time = None + + def _seed_mines(self, coords): + for _ in range(DIFFICULTIES[self._difficulty]['mines']): + while True: + mine_x = random.randint(0, self.grid_width - 1) + mine_y = random.randint(0, self.grid_height - 1) + if self._get_data(mine_x, mine_y) == 0 and (mine_x, mine_y) != coords: + self._set_data(mine_x, mine_y, MINE) + break + self._compute_counts() + + def _set_data(self, x, y, value): + self._board_data[y * self.grid_width + x] = value + + def _get_data(self, x, y): + if x < 0 or x >= self.grid_width or y < 0 or y >= self.grid_height: + return None # out of bounds, do nothing + return self._board_data[y * self.grid_width + x] + + def _set_board(self, x, y, value): + if not isinstance(self.game_board, TileGrid): + raise ValueError("Game board not initialized") + self.game_board[x, y] = value # pylint: disable=unsupported-assignment-operation + + def _get_board(self, x, y): + if not isinstance(self.game_board, TileGrid): + raise ValueError("Game board not initialized") + if x < 0 or x >= self.grid_width or y < 0 or y >= self.grid_height: + return None # out of bounds, do nothing + return self.game_board[x, y] # pylint: disable=unsubscriptable-object + + def _compute_counts(self): + """For each mine, increment the count in each non-mine square around it""" + for y in range(self.grid_height): + for x in range(self.grid_width): + if self._get_data(x, y) != MINE: + continue # keep looking for mines + for dx in (-1, 0, 1): + if x + dx < 0 or x + dx >= self.grid_width: + continue # off screen + for dy in (-1, 0, 1): + if y + dy < 0 or y + dy >= self.grid_height: + continue # off screen + grid_value = self._get_data(x + dx, y + dy) + if grid_value == MINE: + continue # don't process mines + self._set_data(x + dx, y + dy, grid_value + 1) + + def _flag_count(self): + flags = 0 + for x in range(self.grid_width): + for y in range(self.grid_height): + if self._get_board(x, y) == FLAG: + flags += 1 + return flags + + def expand_uncovered(self, start_x, start_y): + # pylint: disable=too-many-nested-blocks + number_uncovered = 1 + stack = [(start_x, start_y)] + while len(stack) > 0: + x, y = stack.pop() + if self._get_board(x, y) == BLANK: + under_the_tile = self._get_data(x, y) + if under_the_tile <= OPEN8: + self._set_board(x, y, under_the_tile) + number_uncovered += 1 + if under_the_tile == OPEN: + for dx in (-1, 0, 1): + if x + dx < 0 or x + dx >= self.grid_width: + continue # off screen + for dy in (-1, 0, 1): + if y + dy < 0 or y + dy >= self.grid_height: + continue # off screen + if dx == 0 and dy == 0: + continue # don't process where the mine + stack.append((x + dx, y + dy)) + return number_uncovered + + def square_flagged(self, coords): + if self._status in (STATUS_WON, STATUS_LOST): + return False + + x, y = coords + TOGGLE_STATES = (BLANK, FLAG, MINE_QUESTION) + for state in TOGGLE_STATES: + if self._get_board(x, y) == state: + self._set_board(x, y, + TOGGLE_STATES[(TOGGLE_STATES.index(state) + 1) % len(TOGGLE_STATES)]) + break + return True + + def square_chorded(self, coords): + if self._status in (STATUS_WON, STATUS_LOST): + return False + + x, y = coords + if x < 0 or x >= self.grid_width or y < 0 or y >= self.grid_height: + return True # out of bounds, do nothing + + value = self._get_board(x, y) + + if value not in (OPEN1, OPEN2, OPEN3, OPEN4, OPEN5, OPEN6, OPEN7, OPEN8): + return True # Nothing to do if not an open numbered square + + # Pre-compute valid neighbors + neighbors = [ + (nx, ny) + for nx in range(x - 1, x + 2) + for ny in range(y - 1, y + 2) + if (0 <= nx < self.grid_width + and 0 <= ny < self.grid_height + and not (nx == x and ny == y)) + ] + + # Count flagged neighbors + flags = sum(1 for nx, ny in neighbors if self._get_board(nx, ny) == FLAG) + + if flags != value: + return True # not enough flags, do nothing + + # Uncover all non-flagged neighbors + for nx, ny in neighbors: + if self._get_board(nx, ny) != FLAG: + if not self.square_clicked((nx, ny)): + return False # lost + + return True + + def square_chord_highlight(self, coords, highlight=True): + if self._status in (STATUS_WON, STATUS_LOST): + return False + + x, y = coords + if x < 0 or x >= self.grid_width or y < 0 or y >= self.grid_height: + return False # out of bounds, do nothing + + value = self._get_board(x, y) + + if value not in (OPEN1, OPEN2, OPEN3, OPEN4, OPEN5, OPEN6, OPEN7, OPEN8): + return False # Nothing to do if not an open numbered square + + # Pre-compute valid neighbors + neighbors = [ + (nx, ny) + for nx in range(x - 1, x + 2) + for ny in range(y - 1, y + 2) + if (0 <= nx < self.grid_width + and 0 <= ny < self.grid_height + and not (nx == x and ny == y)) + ] + + # Highlight all non-flagged squares around here + for nx, ny in neighbors: + if highlight: + if self._get_board(nx, ny) == BLANK: + self._set_board(nx, ny,MINE_QUESTION_OPEN) + else: + if self._get_board(nx, ny) == MINE_QUESTION_OPEN: + self._set_board(nx, ny, BLANK) + + return True + + def square_clicked(self, coords): + x, y = coords + + if self._status in (STATUS_WON, STATUS_LOST): + return False + + # First click is never a mine, so start the game + if self._status == STATUS_NEWGAME: + self._seed_mines(coords) + self._status = STATUS_PLAYING + if self._start_time is None: + self._start_time = ticks_ms() + + if self._get_board(x, y) not in (FLAG, None): + under_the_tile = self._get_data(x, y) + if under_the_tile == MINE: + self._set_data(x, y, MINE_CLICKED) + self._set_board(x, y, MINE_CLICKED) + self._status = STATUS_LOST + self.reveal_board() + if self._end_time is None: + self._end_time = ticks_ms() + return False #lost + elif OPEN1 <= under_the_tile <= OPEN8: + self._set_board(x, y, under_the_tile) + elif under_the_tile == OPEN: + self._set_board(x, y, BLANK) + self.expand_uncovered(x, y) + else: + raise ValueError(f'Unexpected value {under_the_tile} on board') + return True + + def reveal_board(self): + for x in range(self.grid_width): + for y in range(self.grid_height): + if self._get_board(x, y) == FLAG and self._get_data(x, y) != MINE: + self._set_board(x, y, MINE_FLAGGED_WRONG) + else: + self._set_board(x, y, self._get_data(x, y)) + + def check_for_win(self): + """Check for a complete, winning game. That's one with all squares uncovered + and all bombs correctly flagged, with no non-bomb squares flaged. + """ + if self._status in (STATUS_WON, STATUS_LOST): + return None + + # first make sure everything has been explored and decided + for x in range(self.grid_width): + for y in range(self.grid_height): + if self._get_board(x, y) == BLANK or \ + self._get_board(x, y) == MINE_QUESTION or \ + self._get_board(x, y) == MINE_QUESTION_OPEN: + return None # still ignored or question squares + # then check for mistagged bombs + for x in range(self.grid_width): + for y in range(self.grid_height): + if self._get_board(x, y) == FLAG and self._get_data(x, y) != MINE: + return False # misflagged bombs, not done + self._status = STATUS_WON + if self._end_time is None: + self._end_time = ticks_ms() + return True # nothing unexplored, and no misflagged bombs + + @property + def grid_width(self): + return DIFFICULTIES[self._difficulty]['grid_size'][0] + + @property + def grid_height(self): + return DIFFICULTIES[self._difficulty]['grid_size'][1] + + @property + def status(self): + return self._status + + @property + def elapsed_time(self): + """Elapsed time in seconds since the game started with a maximum of 999 seconds""" + if self._start_time is None: + return 0 + if self._end_time is None: + return min(999, (ticks_ms() - self._start_time) // 1000) + return min(999, (self._end_time - self._start_time) // 1000) + + @property + def mines_left(self): + # This number can be negative + return self._mine_count - self._flag_count() + + @property + def difficulty(self): + return self._difficulty + + @difficulty.setter + def difficulty(self, value): + if not 0 <= value < len(DIFFICULTIES): + raise ValueError("Invalid difficulty option") + self._difficulty = value + nvm[0] = value + self.reset() diff --git a/Metro/Metro_RP2350_Minesweeper/menu.py b/Metro/Metro_RP2350_Minesweeper/menu.py new file mode 100755 index 000000000..1b1dc3109 --- /dev/null +++ b/Metro/Metro_RP2350_Minesweeper/menu.py @@ -0,0 +1,171 @@ +# SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT + +from displayio import Group +from adafruit_display_shapes.rect import Rect +from eventbutton import EventButton + +MENU_ITEM_HEIGHT = 16 + +class Menu(Group): + def handle_mouse(self, point, clicked, waiting_for_release): + if waiting_for_release: + return False + # Check if the point is in the menu items group + handled_submenu = None + for submenu in self: + if isinstance(submenu, SubMenu): + if submenu.handle_mouse(point, clicked): + handled_submenu = submenu + if clicked: + # Hide any visible menus + for submenu in self: + if isinstance(submenu, SubMenu) and submenu != handled_submenu: + submenu.hide() + return handled_submenu is not None + +class SubMenu(Group): + def __init__(self, label, button_width, menu_width, x, y): + super().__init__() + self._label = label + self._button_width = button_width + self._menu_width = menu_width + self._menu_items_group = None + self._xpos = x + self._ypos = y + self._menu_items = [] + self._root_button = None + + def add_item(self, function, label, selected=False): + key = label.lower().replace(" ", "_") + self._menu_items.append( + { + "key": key, + "function": function, + "label": label, + "selected": selected, + } + ) + self._render() + + def select_item(self, key): + for item in self._menu_items: + if item["key"] == key: + item["selected"] = True + else: + item["selected"] = False + self._render() + + @staticmethod + def _create_button(callback, label, width, x, y=0, border=True, selected=False): + if border: + outline_color = 0x000000 + selected_outline = 0x333333 + else: + outline_color = 0xEEEEEE + selected_outline = 0xBBBBBB + + if selected: + selected_label = label_color = 0x008800 + else: + selected_label = label_color = 0x333333 + + button = EventButton( + callback, + x=x, + y=y, + width=width, + height=MENU_ITEM_HEIGHT, + label=label, + style=EventButton.RECT, + fill_color=0xEEEEEE, + outline_color=outline_color, + label_color=label_color, + selected_fill=0xBBBBBB, + selected_label=selected_label, + selected_outline=selected_outline, + ) + return button + + + def _toggle_submenu(self): + self._menu_items_group.hidden = not self._menu_items_group.hidden + + def _render(self): + # Redraw the menu + # Remove all existing elements contained inside of this class + while len(self) > 0: + self.pop() + + # create a new root button + self._root_button = self._create_button( + self._toggle_submenu, + self._label, + self._button_width, + self._xpos, + self._ypos, + True, + ) + self.append(self._root_button) + + # Create the menu items group + self._menu_items_group = Group() + self._menu_items_group.hidden = True + self.append(self._menu_items_group) + + # Add the background rectangle to the menu items group + self._menu_items_group.append( + Rect(self._xpos, self._ypos + self._root_button.height - 1, self._menu_width, + len(self._menu_items) * MENU_ITEM_HEIGHT + 2, + fill=0xEEEEEE, + outline=0x333333 + ) + ) + + # Add the menu items to the menu items group + for index, item in enumerate(self._menu_items): + button = self._create_button( + item["function"], + item["label"], + self._menu_width - 2, + self._xpos + 1, + self._ypos + index * MENU_ITEM_HEIGHT + self._root_button.height, + False, + item["selected"], + ) + self._menu_items_group.append(button) + + def hide(self): + self._menu_items_group.hidden = True + + def handle_mouse(self, point, clicked): + # Check if the point is in the root button + if self._menu_items_group.hidden: + if self._root_button.contains(point): + self._root_button.selected = True + if clicked: + self._root_button.click() + return True + else: + self._root_button.selected = False + else: + # Check if the point is in the menu items group + for button in self._menu_items_group: + if isinstance(button, EventButton): + if button.contains(point): + button.selected = True + if clicked: + button.click() + self._menu_items_group.hidden = True + return True + else: + button.selected = False + return False + + @property + def visible(self): + return not self._menu_items_group.hidden + + @property + def items_group(self): + return self._menu_items_group diff --git a/Metro/Metro_RP2350_Minesweeper/metadata.json b/Metro/Metro_RP2350_Minesweeper/metadata.json new file mode 100644 index 000000000..ccdc149e5 --- /dev/null +++ b/Metro/Metro_RP2350_Minesweeper/metadata.json @@ -0,0 +1,4 @@ +{ + "title": "Minesweeper", + "icon": "bitmaps/icon.bmp" +} diff --git a/Metro/Metro_RP2350_Snake/code.py b/Metro/Metro_RP2350_Snake/code.py new file mode 100644 index 000000000..065496d6e --- /dev/null +++ b/Metro/Metro_RP2350_Snake/code.py @@ -0,0 +1,247 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +import sys +import time +from micropython import const +import supervisor +import displayio +import terminalio +from adafruit_display_text.text_box import TextBox +from adafruit_fruitjam.peripherals import request_display_config +from snake_helpers import World, Snake, GameOverException, SpeedAdjuster + +# state machine constant +STATE_TITLE = const(0) +STATE_PLAYING = const(1) +STATE_PAUSED = const(2) +STATE_GAME_OVER = const(3) + +# begin in the title state +CURRENT_STATE = STATE_TITLE + +# movement key bindings, change to different letters if you want. +KEY_UP = "w" +KEY_LEFT = "a" +KEY_DOWN = "s" +KEY_RIGHT = "d" +KEY_PAUSE = "t" + +# how many segments the snake will start with +INITIAL_SNAKE_LEN = 3 + +# variable for the players score +score = 0 + +request_display_config(320,240) +display = supervisor.runtime.display + +# load title splash screen bitmap +title_bmp = displayio.OnDiskBitmap("snake_splash.bmp") +# create a tilegrid for the title splash screen +title_tg = displayio.TileGrid(bitmap=title_bmp, pixel_shader=title_bmp.pixel_shader) + +instructions_txt = TextBox( + terminalio.FONT, + text=f"Move: {KEY_UP}{KEY_LEFT}{KEY_DOWN}{KEY_RIGHT} Pause: {KEY_PAUSE}".upper(), + width=title_bmp.width, + height=16, + align=TextBox.ALIGN_CENTER, +) +instructions_txt.anchor_point = (0, 0) +instructions_txt.anchored_position = (0, title_bmp.height + 1) + +# create a group for the title splash screen and put it in the center of the display +title_group = displayio.Group() +title_group.append(title_tg) +title_group.append(instructions_txt) +title_group.x = display.width // 2 - title_bmp.width // 2 +title_group.y = display.height // 2 - title_bmp.height // 2 + +# initialize SpeedAdjuster to control how fast the snake is moving +speed_adjuster = SpeedAdjuster(12) + +# initialize the world with enough room unused at the top for the score bar +world = World(height=28, width=40) +# move the world down to make room for the score bar +world.y = 16 + +# initialize a Snake instance and grow it to the appropriate size +snake = Snake(starting_location=[10, 10]) +for i in range(INITIAL_SNAKE_LEN - 1): + snake.grow() + +# add one of each type of apple to the world +world.add_apple(snake=snake, apple_sprite_index=World.APPLE_RED_SPRITE_INDEX) +world.add_apple(snake=snake, apple_sprite_index=World.APPLE_GREEN_SPRITE_INDEX) + +# create a group to hold everything for the game +game_group = displayio.Group() + +# add the world to the game group +game_group.append(world) + +# create TextBox to hold the score in a bar at the top of the display +score_txt = TextBox( + terminalio.FONT, text=f"Score: {score}", color=0xFFFFFF, width=320, height=16 +) +score_txt.anchor_point = (0, 0) +score_txt.anchored_position = (0, 2) + +# add the score text to the game group +game_group.append(score_txt) + +# create a TextBox to hold the game over message +game_over_label = TextBox( + terminalio.FONT, + text="", + color=0xFFFFFF, + background_color=0x000000, + width=display.width // 2, + height=80, + align=TextBox.ALIGN_CENTER, +) +# move it to the center of the display +game_over_label.anchor_point = (0, 0) +game_over_label.anchored_position = ( + display.width // 2 - game_over_label.width // 2, + 40, +) + +# make it hidden, we'll show it when the game is over. +game_over_label.hidden = True + +# add it to the game group +game_group.append(game_over_label) + +# set the title group to show on the display +display.root_group = title_group + +# draw the snake in it's starting location +world.draw_snake(snake) + +# timpstamp of the game step render +prev_step_time = time.monotonic() + +# variable to hold string read from the keyboard to get button presses +cur_btn_val = None + +while True: + # current timestamp + now = time.monotonic() + + # check if there is any keyboard input + available = supervisor.runtime.serial_bytes_available + + # if there is some keyboard input + if available: + # read it into cur_btn_val + cur_btn_val = sys.stdin.read(available) + + # change to lower-case before comparison + # so that it's case-insensitive. + cur_btn_val = cur_btn_val.lower() + + else: # no keyboard input + # set to None to clear out previous value + cur_btn_val = None + + # if the current state is title screen + if CURRENT_STATE == STATE_TITLE: + # if any button was pressed + if cur_btn_val is not None: + # set the visible group on the display to the game group + display.root_group = game_group + # update the current state to playing + CURRENT_STATE = STATE_PLAYING + + # if game is being played + elif CURRENT_STATE == STATE_PLAYING: + # if up button was pressed + if cur_btn_val == KEY_UP.lower(): + # if the snake is not already moving up or down + if snake.direction not in (snake.DIRECTION_DOWN, snake.DIRECTION_UP): + # change the direction to up + snake.direction = snake.DIRECTION_UP + # if down button was pressed + if cur_btn_val == KEY_DOWN.lower(): + # if the snake is not already moving up or down + if snake.direction not in (snake.DIRECTION_DOWN, snake.DIRECTION_UP): + # change the direction to down + snake.direction = snake.DIRECTION_DOWN + # if right button was pressed + if cur_btn_val == KEY_RIGHT.lower(): + # if the snake is not already moving left or right + if snake.direction not in (snake.DIRECTION_LEFT, snake.DIRECTION_RIGHT): + # change the direction to right + snake.direction = snake.DIRECTION_RIGHT + # if left button was pressed + if cur_btn_val == KEY_LEFT.lower(): + # if the snake is not already moving left or right + if snake.direction not in (snake.DIRECTION_LEFT, snake.DIRECTION_RIGHT): + # change direction to left + snake.direction = snake.DIRECTION_LEFT + # if the pause button was pressed + if cur_btn_val == KEY_PAUSE.lower(): + # change the state to paused + CURRENT_STATE = STATE_PAUSED + + # if it's time to render a step of the game + if now >= prev_step_time + speed_adjuster.delay: + try: + # move the snake in the direction it's going + result = world.move_snake(snake) + + # if a red apple was eaten + if result == World.APPLE_RED_SPRITE_INDEX: + # decrease the speed to slow down movement + speed_adjuster.decrease_speed() + # award score based on current speed and snake size + score += ((20 - speed_adjuster.speed) // 3) + snake.size + # update the score text in the top bar + score_txt.text = f"Score: {score}" + + # if a green apple was eaten + elif result == World.APPLE_GREEN_SPRITE_INDEX: + # increase the speed to speed up movement + speed_adjuster.increase_speed() + # award score based on current speed and snake + # size plus bonus points for green apple + score += ((20 - speed_adjuster.speed) // 3) + 3 + snake.size + # update the score text in the top bar + score_txt.text = f"Score: {score}" + + # if the game is over due to snake running into the edge or itself + except GameOverException as e: + # update the game over message with the score + output_str = ( + f"Game Over\nScore: {score}\nPress P to play again\nPress Q to quit" + ) + # set the message into the game over label + game_over_label.text = output_str + # make the game over label visible + game_over_label.hidden = False + # update the state to game over + CURRENT_STATE = STATE_GAME_OVER + + # store the timestamp to compare with next iteration + prev_step_time = now + + # if the game is paused + elif CURRENT_STATE == STATE_PAUSED: + # if the pause button was pressed + if cur_btn_val == KEY_PAUSE.lower(): + # change the state to playing so the game resumes + CURRENT_STATE = STATE_PLAYING + + # if the current state is game over + elif CURRENT_STATE == STATE_GAME_OVER: + # if the p button is pressed for play again + if cur_btn_val in {"p", "P"}: + # set next code file to this one + supervisor.set_next_code_file(__file__) + # reload + supervisor.reload() + # if the q button is pressed for exit + if cur_btn_val in {"q", "Q"}: + # reload to go back to code.py + supervisor.reload() diff --git a/Metro/Metro_RP2350_Snake/icon.bmp b/Metro/Metro_RP2350_Snake/icon.bmp new file mode 100644 index 000000000..3bc712748 Binary files /dev/null and b/Metro/Metro_RP2350_Snake/icon.bmp differ diff --git a/Metro/Metro_RP2350_Snake/metadata.json b/Metro/Metro_RP2350_Snake/metadata.json new file mode 100644 index 000000000..e94aba03e --- /dev/null +++ b/Metro/Metro_RP2350_Snake/metadata.json @@ -0,0 +1,4 @@ +{ + "title": "🐍 Snake 🐍", + "icon": "icon.bmp" +} diff --git a/Metro/Metro_RP2350_Snake/snake_helpers.py b/Metro/Metro_RP2350_Snake/snake_helpers.py new file mode 100644 index 000000000..40b90c9eb --- /dev/null +++ b/Metro/Metro_RP2350_Snake/snake_helpers.py @@ -0,0 +1,350 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +import random +import adafruit_imageload +from displayio import TileGrid + +X = 0 +Y = 1 + + +class Snake: + """ + Snake helper class keeps track of the current direction of the snake + and the x,y coordinates of all segments within the snake. + """ + + # direction constants + DIRECTION_UP = 0 + DIRECTION_DOWN = 1 + DIRECTION_RIGHT = 2 + DIRECTION_LEFT = 3 + + def __init__(self, starting_location=(10, 10)): + + # this list will hold locations of all segments + # we have only 1 segment when first initialized + self.locations = [list(starting_location)] + + # start in a random direction + self.direction = random.randint(0, 3) + + def grow(self): + """ + Grow the snake by 1 segment + """ + # check which direction we're currently going + if self.direction == self.DIRECTION_UP: + # new segment below the tail + new_segment = [self.tail[X], self.tail[Y] + 1] + elif self.direction == self.DIRECTION_DOWN: + # new segment above the tail + new_segment = [self.tail[X], self.tail[Y] - 1] + elif self.direction == self.DIRECTION_LEFT: + # new segment to the right of the tail + new_segment = [self.tail[X] + 1, self.tail[Y]] + elif self.direction == self.DIRECTION_RIGHT: + # new segment to the left of the tail + new_segment = [self.tail[X] - 1, self.tail[Y]] + else: + raise RuntimeError("Invalid Direction") + # add the new segment to our list + self.locations.append(new_segment) + + @property + def size(self): + """ + Length of the snake in segments + """ + return len(self.locations) + + def __len__(self): + """ + Length of the snake in segments + """ + return len(self.locations) + + @property + def head(self): + """ + The x,y coordinates of the head segment of the snake + """ + return self.locations[0] + + @property + def tail(self): + """ + The x,y coordinates of the tail segment of the snake + """ + return self.locations[-1] + + +class World(TileGrid): + """ + World helper class draws the world as a TileGrid and plots + apples and snakes within it. + """ + + # sprite tile indexes within the spritesheet + EMPTY_SPRITE_INDEX = 0 + SNAKE_SPRITE_INDEX = 1 + APPLE_RED_SPRITE_INDEX = 2 + APPLE_GREEN_SPRITE_INDEX = 3 + + def __init__(self, width=20, height=16): + + # load the spritesheet + self.spritesheet_bmp, self.spritesheet_palette = adafruit_imageload.load( + "snake_spritesheet.bmp" + ) + + # initialize the superclass TileGrid + super().__init__( + bitmap=self.spritesheet_bmp, + pixel_shader=self.spritesheet_palette, + width=width, + height=height, + tile_width=8, + tile_height=8, + default_tile=0, + ) + + def draw_snake(self, snake): + """ + Set the snake segments into the TileGrid at their current locations. + """ + # loop over all segment location x,y pairs + for location in snake.locations: + # update the TileGrid to show the snake sprite at this location + self[location] = self.SNAKE_SPRITE_INDEX + + def move_snake(self, snake): + # pylint: disable=too-many-branches + """ + Move the snake one step in its current direction + """ + # variable to hold what we will return + return_val = None + + # store the previous head location + prev_loc = tuple(snake.head) + + # variable for the next loc, starts on prev_loc and will be modified below + next_loc = [prev_loc[X], prev_loc[Y]] + + # if the snake is going up + if snake.direction == snake.DIRECTION_UP: + # if the snake is not at the top edge + if snake.head[Y] > 0: + # move the next_loc Y value north by 1 + next_loc[Y] -= 1 + + else: # snake is at top edge + raise GameOverException("Game Over - OOB Top") + + # if the snake is going down + if snake.direction == snake.DIRECTION_DOWN: + # if the snake is not at the bottom edge + if snake.head[Y] < self.height - 1: + # move the next_loc Y value south by 1 + next_loc[Y] += 1 + + else: # snake is at bottom edge + raise GameOverException("Game Over - OOB Bottom") + + # if the snake is going left + if snake.direction == snake.DIRECTION_LEFT: + # if the snake is not at the left edge + if snake.head[X] > 0: + # move the next_loc Y value west by 1 + next_loc[X] -= 1 + + else: # snake is at left edge + raise GameOverException("Game Over - OOB Left") + + # if snake is going right + if snake.direction == snake.DIRECTION_RIGHT: + # if snake is not at the right edge + if snake.head[X] < self.width - 1: + # move the next_loc Y value east by 1 + next_loc[X] += 1 + + else: # snake is at right edge + raise GameOverException("Game Over - OOB Right") + + # Check if there is an apple at the next_loc + if self[tuple(next_loc)] in ( + self.APPLE_RED_SPRITE_INDEX, + self.APPLE_GREEN_SPRITE_INDEX, + ): + # add the next_loc as a new segment to the snake + # it goes at the beginning of the list, making + # it the new head segment + snake.locations.insert(0, next_loc) + + # if it's a red apple + if self[tuple(next_loc)] == self.APPLE_RED_SPRITE_INDEX: + # add a new red apple to replace it + self.add_apple( + snake=snake, apple_sprite_index=self.APPLE_RED_SPRITE_INDEX + ) + # update the return_val to indicate red apple was eaten + return_val = self.APPLE_RED_SPRITE_INDEX + + # if it's a green apple + elif self[tuple(next_loc)] == self.APPLE_GREEN_SPRITE_INDEX: + # add a new green apple to replace it + self.add_apple( + snake=snake, apple_sprite_index=self.APPLE_GREEN_SPRITE_INDEX + ) + # update the return_val to indicate green apple was eaten + return_val = self.APPLE_GREEN_SPRITE_INDEX + + # check if a snake segment is at the next_loc + elif self[tuple(next_loc)] == self.SNAKE_SPRITE_INDEX: + # snake ran into itself + raise GameOverException("Game Over - Ran Into Self") + + # there is nothing at the next_loc + else: + # change the head segment location to next_loc + snake.locations[0] = next_loc + + # loop over all segments in the snake + for i, location in enumerate(snake.locations): + # skip the head segment, it's already been handled + if i != 0: + # temp var with this segment location + _tmp = tuple(location) + # update the X value of this segment to the X from prev_loc + snake.locations[i][X] = prev_loc[X] + # update the Y value of this segment to the Y from prev_loc + snake.locations[i][Y] = prev_loc[Y] + + # update prev_loc to the temp var + prev_loc = _tmp + + # if this is the tail segment + if i == len(snake.locations) - 1: # tail + # set this location to an empty tile + # it's now the empty tile behind the snake + self[prev_loc] = self.EMPTY_SPRITE_INDEX + + # draw the snake at the new location + self.draw_snake(snake) + + # return the apple that was eaten or None + return return_val + + def add_apple( + self, location=None, snake=None, apple_sprite_index=APPLE_RED_SPRITE_INDEX + ): + """ + Add a new apple to the world + """ + # check if snake was passed in + if snake is None: + # we need the snake so that we avoid putting an apple + # in the same spot as any of its segments. + raise AttributeError("Must pass snake") + + # loop until the location contains an empty tile + while location is None or self[location] != self.EMPTY_SPRITE_INDEX: + + # select a random location in the world + location = [ + random.randint(0, self.width - 1), + random.randint(0, self.height - 1), + ] + + # set the tile at the lcoation to the appropriate apple sprite tile index + self[tuple(location)] = apple_sprite_index + + +class SpeedAdjuster: + """ + SpeedAdjuster helper class keeps track of the speed of the snake + and provides easy to use increase and decrease speed functions. + + Speed is controlled by altering the delay time between + game steps. + """ + + # min and max delay values in seconds + MIN = 0.05 + MAX = 0.4 + + def __init__(self, speed): + """ + :param speed: speed as a value 0-20, lower is faster. + """ + # limit speed to the range 0-20 + if speed < 0 or speed > 20: + raise ValueError("Speed must be between 0 and 20") + + # store speed value on self + self.speed = speed + + # map the speed value to a delay value between the min and max + self.delay = SpeedAdjuster.map_range( + self.speed, 0, 20, SpeedAdjuster.MIN, SpeedAdjuster.MAX + ) + + def increase_speed(self): + """ + Speed up by 1 speed value + """ + + # if we aren't at max speed already + if self.speed > 0: + # speed value goes down by one because lower is faster + self.speed -= 1 + # update the delay with the new speed value mapped between min and max + self.delay = SpeedAdjuster.map_range( + self.speed, 0, 20, SpeedAdjuster.MIN, SpeedAdjuster.MAX + ) + + def decrease_speed(self): + """ + Slow down by 1 speed value + """ + # if we aren't at min speed already + if self.speed < 20: + # speed value goes up by one because higher is slower + self.speed += 1 + # update the delay with the new speed value mapped between min and max + self.delay = SpeedAdjuster.map_range( + self.speed, 0, 20, SpeedAdjuster.MIN, SpeedAdjuster.MAX + ) + + @staticmethod + def map_range(x, in_min, in_max, out_min, out_max): + """ + Maps a number from one range to another. + Note: This implementation handles values < in_min + differently than arduino's map function does. + Copied from circuitpython simpleio + + :return: Returns value mapped to new range + :rtype: float + """ + in_range = in_max - in_min + in_delta = x - in_min + if in_range != 0: + mapped = in_delta / in_range + elif in_delta != 0: + mapped = in_delta + else: + mapped = 0.5 + mapped *= out_max - out_min + mapped += out_min + if out_min <= out_max: + return max(min(mapped, out_max), out_min) + return min(max(mapped, out_max), out_min) + + +class GameOverException(Exception): + """ + Exception that indicates the game is over. + Message will contain the reason. + """ diff --git a/Metro/Metro_RP2350_Snake/snake_splash.bmp b/Metro/Metro_RP2350_Snake/snake_splash.bmp new file mode 100644 index 000000000..d90fddb67 Binary files /dev/null and b/Metro/Metro_RP2350_Snake/snake_splash.bmp differ diff --git a/Metro/Metro_RP2350_Snake/snake_spritesheet.bmp b/Metro/Metro_RP2350_Snake/snake_spritesheet.bmp new file mode 100644 index 000000000..fb52f4efd Binary files /dev/null and b/Metro/Metro_RP2350_Snake/snake_spritesheet.bmp differ diff --git a/Metro_Matrix_Clock/code.py b/Metro_Matrix_Clock/code.py index acb389a55..5773448c0 100644 --- a/Metro_Matrix_Clock/code.py +++ b/Metro_Matrix_Clock/code.py @@ -5,6 +5,7 @@ # Metro Matrix Clock # Runs on Airlift Metro M4 with 64x32 RGB Matrix display & shield +from os import getenv import time import board import displayio @@ -17,14 +18,20 @@ BLINK = True DEBUG = False -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) + print(" Metro Minimal Clock") -print("Time will be set for {}".format(secrets["timezone"])) +print("Time will be set for {}".format(getenv("timezone"))) # --- Display setup --- matrix = Matrix() diff --git a/Metro_RP2350_Examples/Arduino_RP2350_microSD/.metro_rp2350.test.only b/Metro_RP2350_Examples/Arduino_RP2350_microSD/.metro_rp2350.test.only new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/Metro_RP2350_Examples/Arduino_RP2350_microSD/.metro_rp2350.test.only @@ -0,0 +1 @@ + diff --git a/Metro_RP2350_Examples/Arduino_RP2350_microSD/Arduino_RP2350_microSD.ino b/Metro_RP2350_Examples/Arduino_RP2350_microSD/Arduino_RP2350_microSD.ino new file mode 100644 index 000000000..47cfa02f2 --- /dev/null +++ b/Metro_RP2350_Examples/Arduino_RP2350_microSD/Arduino_RP2350_microSD.ino @@ -0,0 +1,91 @@ +// SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +// +// SPDX-License-Identifier: MIT +/* + SD card read/write + + This example shows how to read and write data to and from an SD card file + The circuit: + * SD card attached to SPI bus as follows: + ** MOSI - pin 35 + ** MISO - pin 36 + ** CLK - pin 34 + + created Nov 2010 + by David A. Mellis + modified 9 Apr 2012 + by Tom Igoe + modified 14 Feb 2023 + by Liz Clark + modified 25 Aug 2023 + by Kattni Rembor + modified 18 Feb 2025 + by Tim Cocks + + + + This example code is in the public domain. + + */ + +#include +#include "SdFat.h" + +#define SD_CS_PIN 39 + +SdFat SD; +FsFile myFile; +SdSpiConfig config(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(16), &SPI1); + +void setup() { + // Open serial communications and wait for port to open: + Serial.begin(115200); + while (!Serial) { yield(); delay(10); } // wait till serial port is opened + delay(100); // RP2040 delay is not a bad idea + + Serial.print("Initializing SD card..."); + + // Retry mechanism for SD card initialization + while (!SD.begin(config)) { + Serial.println("initialization failed! Retrying..."); + delay(1000); // Wait for a second before retrying + } + Serial.println("initialization done."); + + // open the file. note that only one file can be open at a time, + // so you have to close this one before opening another. + myFile = SD.open("test.txt", FILE_WRITE); + + // if the file opened okay, write to it: + if (myFile) { + Serial.print("Writing to test.txt..."); + myFile.println("testing 1, 2, 3."); + myFile.println("hello world!"); + // close the file: + myFile.close(); + Serial.println("done."); + } else { + // if the file didn't open, print an error: + Serial.println("error opening test.txt"); + } + + // re-open the file for reading: + myFile = SD.open("test.txt"); + if (myFile) { + Serial.println("test.txt:"); + + // read from the file until there's nothing else in it: + while (myFile.available()) { + Serial.write(myFile.read()); + } + // close the file: + myFile.close(); + } else { + // if the file didn't open, print an error: + Serial.println("error opening test.txt"); + } +} + +void loop() { + // nothing happens after setup +} diff --git a/Metro_RP2350_Examples/CircuitPython_HSTX_Display/code.py b/Metro_RP2350_Examples/CircuitPython_HSTX_Display/code.py new file mode 100644 index 000000000..7893647ff --- /dev/null +++ b/Metro_RP2350_Examples/CircuitPython_HSTX_Display/code.py @@ -0,0 +1,32 @@ +# SPDX-FileCopyrightText: 2024 Scott Shawcroft for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import board +import picodvi +import framebufferio +import displayio + +displayio.release_displays() + +fb = picodvi.Framebuffer(320, 240, clk_dp=board.CKP, clk_dn=board.CKN, + red_dp=board.D0P, red_dn=board.D0N, + green_dp=board.D1P, green_dn=board.D1N, + blue_dp=board.D2P, blue_dn=board.D2N, + color_depth=16) +display = framebufferio.FramebufferDisplay(fb) + +# Initialize the display in the display variable +ruler = displayio.OnDiskBitmap("/display-ruler-rgb-720p.bmp") + +t = displayio.TileGrid(ruler, pixel_shader=ruler.pixel_shader) + +g = displayio.Group() +g.append(t) + +display.root_group = g + +display.refresh() + +while True: + pass diff --git a/Metro_RP2350_Examples/CircuitPython_HSTX_Display/display-ruler-rgb-720p.bmp b/Metro_RP2350_Examples/CircuitPython_HSTX_Display/display-ruler-rgb-720p.bmp new file mode 100644 index 000000000..f73b1c3c2 Binary files /dev/null and b/Metro_RP2350_Examples/CircuitPython_HSTX_Display/display-ruler-rgb-720p.bmp differ diff --git a/Metro_RP2350_Examples/CircuitPython_I2S_Tone/code.py b/Metro_RP2350_Examples/CircuitPython_I2S_Tone/code.py new file mode 100644 index 000000000..2c874b9fb --- /dev/null +++ b/Metro_RP2350_Examples/CircuitPython_I2S_Tone/code.py @@ -0,0 +1,30 @@ +# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +CircuitPython I2S Tone playback example. +Plays a tone for one second on, one +second off, in a loop. + +""" +import time +import array +import math +import audiocore +import board +import audiobusio + +audio = audiobusio.I2SOut(board.A0, board.A1, board.A2) + +tone_volume = 0.1 # Increase this to increase the volume of the tone. +frequency = 440 # Set this to the Hz of the tone you want to generate. +length = 8000 // frequency +sine_wave = array.array("h", [0] * length) +for i in range(length): + sine_wave[i] = int((math.sin(math.pi * 2 * i / length)) * tone_volume * (2 ** 15 - 1)) +sine_wave_sample = audiocore.RawSample(sine_wave) + +while True: + audio.play(sine_wave_sample, loop=True) + time.sleep(1) + audio.stop() + time.sleep(1) diff --git a/Metro_RP2350_Examples/CircuitPython_I2S_Wav/StreetChicken.wav b/Metro_RP2350_Examples/CircuitPython_I2S_Wav/StreetChicken.wav new file mode 100644 index 000000000..55d4eb0f2 Binary files /dev/null and b/Metro_RP2350_Examples/CircuitPython_I2S_Wav/StreetChicken.wav differ diff --git a/Metro_RP2350_Examples/CircuitPython_I2S_Wav/code.py b/Metro_RP2350_Examples/CircuitPython_I2S_Wav/code.py new file mode 100644 index 000000000..1061ca78b --- /dev/null +++ b/Metro_RP2350_Examples/CircuitPython_I2S_Wav/code.py @@ -0,0 +1,22 @@ +# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +CircuitPython I2S WAV file playback. +Plays a WAV file once. + +""" +import audiocore +import board +import audiobusio + +audio = audiobusio.I2SOut(board.A0, board.A1, board.A2) + +with open("StreetChicken.wav", "rb") as wave_file: + wav = audiocore.WaveFile(wave_file) + + print("Playing wav file!") + audio.play(wav) + while audio.playing: + pass + +print("Done!") diff --git a/Metro_RP2350_Examples/CircuitPython_PSRAM/code.py b/Metro_RP2350_Examples/CircuitPython_PSRAM/code.py new file mode 100644 index 000000000..50f7b2e09 --- /dev/null +++ b/Metro_RP2350_Examples/CircuitPython_PSRAM/code.py @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries +# SPDX-License-Identifier: MIT +import gc + +print(gc.mem_free()) diff --git a/Metro_RP2350_Examples/CircuitPython_PWM_Audio_Multi_MP3/code.py b/Metro_RP2350_Examples/CircuitPython_PWM_Audio_Multi_MP3/code.py new file mode 100644 index 000000000..fc60fbc45 --- /dev/null +++ b/Metro_RP2350_Examples/CircuitPython_PWM_Audio_Multi_MP3/code.py @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +CircuitPython multiple MP3 playback example. +Plays two MP3 files consecutively, once time each. +""" + +import board +import audiomp3 +import audiopwmio + +audio = audiopwmio.PWMAudioOut(board.A0) + +mp3files = ["slow.mp3", "happy.mp3"] + +with open(mp3files[0], "rb") as mp3: + decoder = audiomp3.MP3Decoder(mp3) + + for filename in mp3files: + with open(filename, "rb") as decoder.file: + audio.play(decoder) + print("Playing:", filename) + while audio.playing: + pass + +print("Done playing!") diff --git a/Metro_RP2350_Examples/CircuitPython_PWM_Audio_Multi_MP3/happy.mp3 b/Metro_RP2350_Examples/CircuitPython_PWM_Audio_Multi_MP3/happy.mp3 new file mode 100755 index 000000000..58fd59724 Binary files /dev/null and b/Metro_RP2350_Examples/CircuitPython_PWM_Audio_Multi_MP3/happy.mp3 differ diff --git a/Metro_RP2350_Examples/CircuitPython_PWM_Audio_Multi_MP3/slow.mp3 b/Metro_RP2350_Examples/CircuitPython_PWM_Audio_Multi_MP3/slow.mp3 new file mode 100755 index 000000000..39ceecdf6 Binary files /dev/null and b/Metro_RP2350_Examples/CircuitPython_PWM_Audio_Multi_MP3/slow.mp3 differ diff --git a/Metro_RP2350_Examples/CircuitPython_PWM_Audio_Single_MP3/code.py b/Metro_RP2350_Examples/CircuitPython_PWM_Audio_Single_MP3/code.py new file mode 100644 index 000000000..db70b9a6c --- /dev/null +++ b/Metro_RP2350_Examples/CircuitPython_PWM_Audio_Single_MP3/code.py @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +CircuitPython single MP3 playback example. +Plays a single MP3 once. +""" +import board +import audiomp3 +import audiopwmio + +audio = audiopwmio.PWMAudioOut(board.A0) + +with open("slow.mp3", "rb") as mp3_file: + decoder = audiomp3.MP3Decoder(mp3_file) + + audio.play(decoder) + while audio.playing: + pass + +print("Done playing!") diff --git a/Metro_RP2350_Examples/CircuitPython_PWM_Audio_Single_MP3/slow.mp3 b/Metro_RP2350_Examples/CircuitPython_PWM_Audio_Single_MP3/slow.mp3 new file mode 100755 index 000000000..39ceecdf6 Binary files /dev/null and b/Metro_RP2350_Examples/CircuitPython_PWM_Audio_Single_MP3/slow.mp3 differ diff --git a/Metro_RP2350_Examples/CircuitPython_SDCard_ListFiles/code.py b/Metro_RP2350_Examples/CircuitPython_SDCard_ListFiles/code.py new file mode 100644 index 000000000..392426831 --- /dev/null +++ b/Metro_RP2350_Examples/CircuitPython_SDCard_ListFiles/code.py @@ -0,0 +1,69 @@ +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT + +""" +CircuitPython Essentials SD Card Read Demo +""" + +import os +import digitalio +import busio +import board +import storage +import adafruit_sdcard + +# The SD_CS pin is the chip select line. +SD_CS = board.SD_CS + +# For CircuitPython 9.x we must initialize and mount the SD card manually. +# On CircuitPython 10.x the core will automatically initialize and mount the SD. +# This try/except block can be removed with 10.x has a stable release. +try: + # Initialize the Chip Select pin for the SD card + cs = digitalio.DigitalInOut(SD_CS) + # Initialize the SD card + sdcard = adafruit_sdcard.SDCard( + busio.SPI(board.SD_SCK, board.SD_MOSI, board.SD_MISO), cs + ) + # Mount the SD card + vfs = storage.VfsFat(sdcard) + storage.mount(vfs, "/sd") +except ValueError: + # "ValueError SD_CS in use" error happen on CircuitPython 10.x + # because the core initialized the SD automatically. The error + # can be ignored on 10.x. + pass + +# Use the filesystem as normal! Our files are under /sd + + +# This helper function will print the contents of the SD +def print_directory(path, tabs=0): + for file in os.listdir(path): + stats = os.stat(path + "/" + file) + filesize = stats[6] + isdir = stats[0] & 0x4000 + + if filesize < 1000: + sizestr = str(filesize) + " bytes" + elif filesize < 1000000: + sizestr = "%0.1f KB" % (filesize / 1000) + else: + sizestr = "%0.1f MB" % (filesize / 1000000) + + prettyprintname = "" + for _ in range(tabs): + prettyprintname += " " + prettyprintname += file + if isdir: + prettyprintname += "/" + print("{0:<40} Size: {1:>10}".format(prettyprintname, sizestr)) + + # recursively print directory contents + if isdir: + print_directory(path + "/" + file, tabs + 1) + + +print("Files on filesystem:") +print("====================") +print_directory("/sd") diff --git a/Metro_RP2350_Examples/CircuitPython_SDCard_Write/code.py b/Metro_RP2350_Examples/CircuitPython_SDCard_Write/code.py new file mode 100644 index 000000000..5100c8aa0 --- /dev/null +++ b/Metro_RP2350_Examples/CircuitPython_SDCard_Write/code.py @@ -0,0 +1,51 @@ +# SPDX-FileCopyrightText: 2017 Limor Fried for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +CircuitPython Essentials SD Card Write Demo +""" + +import time +import adafruit_sdcard +import board +import busio +import digitalio +import microcontroller +import storage + +# The SD_CS pin is the chip select line. +SD_CS = board.SD_CS + + +# For CircuitPython 9.x we must initialize and mount the SD card manually. +# On CircuitPython 10.x the core will automatically initialize and mount the SD. +# This try/except block can be removed with 10.x has a stable release. +try: + # Initialize the Chip Select pin for the SD card + cs = digitalio.DigitalInOut(SD_CS) + # Initialize the SD card + sdcard = adafruit_sdcard.SDCard( + busio.SPI(board.SD_SCK, board.SD_MOSI, board.SD_MISO), cs + ) + # Mount the SD card + vfs = storage.VfsFat(sdcard) + storage.mount(vfs, "/sd") +except ValueError: + # "ValueError SD_CS in use" error happen on CircuitPython 10.x + # because the core initialized the SD automatically. The error + # can be ignored on 10.x. + pass + +# Use the filesystem as normal! Our files are under /sd + +print("Logging temperature to filesystem") +# append to the file! +while True: + # open file for append + with open("/sd/temperature.txt", "a") as f: + t = microcontroller.cpu.temperature + print("Temperature = %0.1f" % t) + f.write("%0.1f\n" % t) + # file is saved + time.sleep(1) diff --git a/Minesweep/.circuitpython.skip b/Minesweep/.circuitpython.skip deleted file mode 100644 index 353ad158a..000000000 --- a/Minesweep/.circuitpython.skip +++ /dev/null @@ -1 +0,0 @@ -Minesweep/code.py 200: Simplify chained comparison between the operands (chained-comparison) diff --git a/Minesweep/code.py b/Minesweep/code.py deleted file mode 100644 index 409686310..000000000 --- a/Minesweep/code.py +++ /dev/null @@ -1,268 +0,0 @@ -# SPDX-FileCopyrightText: 2019 Dave Astels for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -""" -PyPortal MineSweeper - -Adafruit invests time and resources providing this open source code. -Please support Adafruit and open source hardware by purchasing -products from Adafruit! - -Written by Dave Astels for Adafruit Industries -Copyright (c) 2019 Adafruit Industries -Licensed under the MIT license. - -All text above must be included in any redistribution. -""" - -import time -from random import seed, randint -import board -import digitalio -import displayio -import audioio -try: - from audioio import WaveFile -except ImportError: - from audiocore import WaveFile - -import adafruit_imageload -import adafruit_touchscreen - -seed(int(time.monotonic())) - -# Set up audio -speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE) -speaker_enable.switch_to_output(False) -if hasattr(board, 'AUDIO_OUT'): - audio = audioio.AudioOut(board.AUDIO_OUT) -elif hasattr(board, 'SPEAKER'): - audio = audioio.AudioOut(board.SPEAKER) -else: - raise AttributeError('Board does not have a builtin speaker!') - - -NUMBER_OF_BOMBS = 15 - -# Board pieces - -OPEN0 = 0 -OPEN1 = 1 -OPEN2 = 2 -OPEN3 = 3 -OPEN4 = 4 -OPEN5 = 5 -OPEN6 = 6 -OPEN7 = 7 -OPEN8 = 8 -BLANK = 9 -BOMBDEATH = 10 -BOMBFLAGGED = 11 -BOMBMISFLAGGED = 12 -BOMBQUESTION = 13 -BOMB = 14 - -sprite_sheet, palette = adafruit_imageload.load("/SpriteSheet.bmp", - bitmap=displayio.Bitmap, - palette=displayio.Palette) - -display = board.DISPLAY -group = displayio.Group() -touchscreen = adafruit_touchscreen.Touchscreen(board.TOUCH_XL, board.TOUCH_XR, - board.TOUCH_YD, board.TOUCH_YU, - calibration=((9000, 59000), - (8000, 57000)), - size=(display.width, display.height)) -tilegrid = displayio.TileGrid(sprite_sheet, pixel_shader=palette, - width=20, height=15, - tile_height=16, tile_width=16, - default_tile=BLANK) -group.append(tilegrid) - - - -display.root_group = group - -board_data = bytearray(b'\x00' * 300) - -#pylint:disable=redefined-outer-name -def get_data(x, y): - return board_data[y * 20 + x] - -def set_data(x, y, value): - board_data[y * 20 + x] = value -#pylint:disable=redefined-outer-name - -def seed_bombs(how_many): - for _ in range(how_many): - while True: - bomb_x = randint(0, 19) - bomb_y = randint(0, 14) - if get_data(bomb_x, bomb_y) == 0: - set_data(bomb_x, bomb_y, 14) - break - -def compute_counts(): - """For each bomb, increment the count in each non-bomb square around it""" - for y in range(15): - for x in range(20): - if get_data(x, y) != 14: - continue # keep looking for bombs - for dx in (-1, 0, 1): - if x + dx < 0 or x + dx >= 20: - continue # off screen - for dy in (-1, 0, 1): - if y + dy < 0 or y + dy >= 15: - continue # off screen - count = get_data(x + dx, y + dy) - if count == 14: - continue # don't process bombs - set_data(x + dx, y + dy, count + 1) - -def reveal(): - for x in range(20): - for y in range(15): - if tilegrid[x, y] == BOMBFLAGGED and get_data(x, y) != BOMB: - tilegrid[x, y] = BOMBMISFLAGGED - else: - tilegrid[x, y] = get_data(x, y) - -#pylint:disable=too-many-nested-blocks -def expand_uncovered(start_x, start_y): - number_uncovered = 1 - stack = [(start_x, start_y)] - while len(stack) > 0: - x, y = stack.pop() - if tilegrid[x, y] == BLANK: - under_the_tile = get_data(x, y) - if under_the_tile <= OPEN8: - tilegrid[x, y] = under_the_tile - number_uncovered += 1 - if under_the_tile == OPEN0: - for dx in (-1, 0, 1): - if x + dx < 0 or x + dx >= 20: - continue # off screen - for dy in (-1, 0, 1): - if y + dy < 0 or y + dy >= 15: - continue # off screen - if dx == 0 and dy == 0: - continue # don't process where the bomb - stack.append((x + dx, y + dy)) - return number_uncovered -#pylint:enable=too-many-nested-blocks - -def check_for_win(): - """Check for a complete, winning game. That's one with all squares uncovered - and all bombs correctly flagged, with no non-bomb squares flaged. - """ - # first make sure everything has been explored and decided - for x in range(20): - for y in range(15): - if tilegrid[x, y] == BLANK or tilegrid[x, y] == BOMBQUESTION: - return None #still ignored or question squares - # then check for mistagged bombs - for x in range(20): - for y in range(15): - if tilegrid[x, y] == BOMBFLAGGED and get_data(x, y) != BOMB: - return False #misflagged bombs, not done - return True #nothing unexplored, and no misflagged bombs - -#pylint:disable=too-many-branches -# This could be broken apart but I think it's more understandable -# with it all in one place -def play_a_game(): - number_uncovered = 0 - touch_x = -1 - touch_y = -1 - touch_time = 0 - wait_for_release = False - while True: - now = time.monotonic() - if now >= touch_time: - touch_time = now + 0.2 - # process touch - touch_at = touchscreen.touch_point - if touch_at is None: - wait_for_release = False - else: - if wait_for_release: - continue - wait_for_release = True - touch_x = max(min([touch_at[0] // 16, 19]), 0) - touch_y = max(min([touch_at[1] // 16, 14]), 0) - if tilegrid[touch_x, touch_y] == BLANK: - tilegrid[touch_x, touch_y] = BOMBQUESTION - elif tilegrid[touch_x, touch_y] == BOMBQUESTION: - tilegrid[touch_x, touch_y] = BOMBFLAGGED - elif tilegrid[touch_x, touch_y] == BOMBFLAGGED: - under_the_tile = get_data(touch_x, touch_y) - if under_the_tile == 14: - set_data(touch_x, touch_y, BOMBDEATH) #reveal a red bomb - tilegrid[touch_x, touch_y] = BOMBDEATH - return False #lost - elif under_the_tile > OPEN0 and under_the_tile <= OPEN8: - tilegrid[touch_x, touch_y] = under_the_tile - elif under_the_tile == OPEN0: - tilegrid[touch_x, touch_y] = BLANK - number_uncovered += expand_uncovered(touch_x, touch_y) - else: #something bad happened - raise ValueError('Unexpected value on board') - status = check_for_win() - if status is None: - continue - return status -#pylint:enable=too-many-branches - -def reset_board(): - for x in range(20): - for y in range(15): - tilegrid[x, y] = BLANK - set_data(x, y, 0) - seed_bombs(NUMBER_OF_BOMBS) - compute_counts() - -def play_sound(file_name): - try: - board.DISPLAY.refresh(target_frames_per_second=60) - except AttributeError: - board.DISPLAY.wait_for_frame() - wavfile = open(file_name, "rb") - wavedata = WaveFile(wavfile) - speaker_enable.value = True - audio.play(wavedata) - return wavfile - -def wait_for_sound_and_cleanup(wavfile): - while audio.playing: - pass - wavfile.close() - speaker_enable.value = False - -def win(): - print('You won') - wait_for_sound_and_cleanup(play_sound('win.wav')) - -def lose(): - print('You lost') - wavfile = play_sound('lose.wav') - for _ in range(10): - tilegrid.x = randint(-2, 2) - tilegrid.y = randint(-2, 2) - try: - board.DISPLAY.refresh(target_frames_per_second=60) - except AttributeError: - board.DISPLAY.refresh_soon() - board.DISPLAY.wait_for_frame() - tilegrid.x = 0 - tilegrid.y = 0 - wait_for_sound_and_cleanup(wavfile) - -while True: - reset_board() - if play_a_game(): - win() - else: - reveal() - lose() - time.sleep(5.0) diff --git a/Mother_Of_All_Demos_Keyset/code.py b/Mother_Of_All_Demos_Keyset/code.py new file mode 100644 index 000000000..35a596e36 --- /dev/null +++ b/Mother_Of_All_Demos_Keyset/code.py @@ -0,0 +1,151 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import time +import board +import keypad +import supervisor +import usb_hid +from adafruit_hid.keyboard import Keyboard +from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS + +# Dictionary of macros for single keys and combinations +macros = { + # Single key macros + (0,): "good", + (1,): "great", + (2,): "nice", + (3,): "awesome", + (4,): "cool", + + # Combination macros + (0, 2, 4): "looks good to me", + (0, 2): "be right back", + (2, 4): "see you soon", + (1, 3): "sounds good", +} + +KEY_PINS = ( + board.A1, + board.A2, + board.A3, + board.MISO, + board.MOSI, +) + +keys = keypad.Keys( + KEY_PINS, + value_when_pressed=False, + pull=True, + interval=0.01, + max_events=64, + debounce_threshold=3 +) + +keyboard = Keyboard(usb_hid.devices) +keyboard_layout = KeyboardLayoutUS(keyboard) + +# need to wait longer for 3 key combos +LARGER_COMBOS = { + (0, 2): (0, 2, 4), + (2, 4): (0, 2, 4), +} + +# How long to wait for possible additional keys in a combo (ms) +COMBO_WAIT_TIME = 150 # Wait 150ms to see if more keys are coming + +# How long to wait for a single key before executing (ms) +SINGLE_KEY_TIMEOUT_MS = 80 + +# Minimum time between macro executions (ms) +MACRO_COOLDOWN_MS = 300 + +# Store the current state of all keys +key_states = {i: False for i in range(len(KEY_PINS))} + +# Create a reusable Event object to avoid memory allocations +reusable_event = keypad.Event() + +# Track timing and state +last_macro_time = 0 +key_combo_start_time = 0 +waiting_for_combo = False +last_executed_combo = None + +while True: + # Process all events in the queue + keys_changed = False + + while keys.events: + if keys.events.get_into(reusable_event): + # Check if key state actually changed + old_state = key_states[reusable_event.key_number] + key_states[reusable_event.key_number] = reusable_event.pressed + + if old_state != reusable_event.pressed: + print(f"Key {reusable_event.key_number} " + + f"{'pressed' if reusable_event.pressed else 'released'}") + keys_changed = True + + # Get currently pressed keys as a sorted tuple + current_pressed_keys = tuple(sorted(k for k, v in key_states.items() if v)) + current_time = supervisor.ticks_ms() + + # When all keys are released, reset tracking + if not current_pressed_keys: + waiting_for_combo = False + last_executed_combo = None + time.sleep(0.01) + continue + + # If this is a new key pattern or we just started + if keys_changed: + # If we weren't tracking before, start now + if not waiting_for_combo: + key_combo_start_time = current_time + waiting_for_combo = True + + # If the pressed keys have changed, update the timer + if current_pressed_keys != last_executed_combo: + key_combo_start_time = current_time + + # Skip if we've already executed this exact combination + if current_pressed_keys == last_executed_combo: + time.sleep(0.01) + continue + + # Determine if we should execute a macro now + should_execute = False + wait_more = False + + # If this is a potential part of a larger combo, wait longer + if current_pressed_keys in LARGER_COMBOS: + # Only wait if we've been waiting less than the combo wait time + if (current_time - key_combo_start_time) < COMBO_WAIT_TIME: + wait_more = True + else: + # We've waited long enough, go ahead and execute + should_execute = True + # Immediate execution for multi-key combinations that aren't potential parts of larger combos + elif len(current_pressed_keys) > 1: + should_execute = True + # Execute single key after timeout + elif waiting_for_combo and (current_time - key_combo_start_time) >= SINGLE_KEY_TIMEOUT_MS: + should_execute = True + + # If we need to wait more, skip to the next iteration + if wait_more: + time.sleep(0.01) + continue + + # Execute the macro if conditions are met + if should_execute and current_pressed_keys in macros: + # Only execute if cooldown period has passed + if current_time - last_macro_time >= MACRO_COOLDOWN_MS: + print(f"MACRO: {macros[current_pressed_keys]}") + keyboard_layout.write(macros[current_pressed_keys]) + last_macro_time = current_time + last_executed_combo = current_pressed_keys + + time.sleep(0.01) diff --git a/Neopixel_Aquarium/Neopixel_Aquarium.ino b/Neopixel_Aquarium/Neopixel_Aquarium.ino index 8b56ee13c..807ae944a 100644 --- a/Neopixel_Aquarium/Neopixel_Aquarium.ino +++ b/Neopixel_Aquarium/Neopixel_Aquarium.ino @@ -9,6 +9,10 @@ #include "Adafruit_FreeTouch.h" #include "FastLED.h" +#if defined(FASTLED_VERSION) && FASTLED_VERSION > 3010001 + #error "FastLED 3.10.2 has known compile issues with SAMD boards. Please downgrade to FastLED 3.10.1" +#endif + #define CAPTOUCH_PIN A2 //A2 capacitive touch pin #define CAPTOUCH_PIN2 A3 //A3 capacitive touch pin #define NEOPIXEL_PIN A1 //A1 neopixel pin diff --git a/Newxie_TFT_Examples/Newxie_CircuitPython/code.py b/Newxie_TFT_Examples/Newxie_CircuitPython/code.py index 17f510e31..8c09de128 100644 --- a/Newxie_TFT_Examples/Newxie_CircuitPython/code.py +++ b/Newxie_TFT_Examples/Newxie_CircuitPython/code.py @@ -10,6 +10,7 @@ from random import randint import time import displayio +import fourwire import board import vectorio import terminalio @@ -29,7 +30,7 @@ tft_cs = board.D5 tft_dc = board.D6 -display_bus = displayio.FourWire( +display_bus = fourwire.FourWire( spi, command=tft_dc, chip_select=tft_cs, reset=None ) diff --git a/Not_A_Typewriter/Desktop_Not_A_Typewriter/CircuitPython_Serial_Typewriter/boot.py b/Not_A_Typewriter/Desktop_Not_A_Typewriter/CircuitPython_Serial_Typewriter/boot.py new file mode 100644 index 000000000..ff9f9e96e --- /dev/null +++ b/Not_A_Typewriter/Desktop_Not_A_Typewriter/CircuitPython_Serial_Typewriter/boot.py @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import usb_cdc + +# Enable USB CDC (serial) communication +usb_cdc.enable(console=True, data=True) diff --git a/Not_A_Typewriter/Desktop_Not_A_Typewriter/CircuitPython_Serial_Typewriter/code.py b/Not_A_Typewriter/Desktop_Not_A_Typewriter/CircuitPython_Serial_Typewriter/code.py new file mode 100644 index 000000000..06f3bb68d --- /dev/null +++ b/Not_A_Typewriter/Desktop_Not_A_Typewriter/CircuitPython_Serial_Typewriter/code.py @@ -0,0 +1,190 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +USB Typewriter Feather-side Script +Converts incoming keystrokes to solenoid clicks +""" + +import time +import struct +import usb_cdc +import board +from adafruit_mcp230xx.mcp23017 import MCP23017 + +# Typewriter configuration +KEYSTROKE_BELL_INTERVAL = 25 # Ring bell every 25 keystrokes +SOLENOID_STRIKE_TIME = 0.03 # Duration in seconds for solenoid activation +ENTER_KEY_CODE = 0x28 # HID code for Enter key +ESCAPE_KEY_CODE = 0x29 # HID code for Escape key +BACKSPACE_KEY_CODE = 0x2A # HID code for Backspace key +TAB_KEY_CODE = 0x2B # HID code for Tab key + +# Key name mapping for debug output +key_names = { + 0x04: "A", 0x05: "B", 0x06: "C", 0x07: "D", + 0x08: "E", 0x09: "F", 0x0A: "G", 0x0B: "H", + 0x0C: "I", 0x0D: "J", 0x0E: "K", 0x0F: "L", + 0x10: "M", 0x11: "N", 0x12: "O", 0x13: "P", + 0x14: "Q", 0x15: "R", 0x16: "S", 0x17: "T", + 0x18: "U", 0x19: "V", 0x1A: "W", 0x1B: "X", + 0x1C: "Y", 0x1D: "Z", + 0x1E: "1", 0x1F: "2", 0x20: "3", 0x21: "4", + 0x22: "5", 0x23: "6", 0x24: "7", 0x25: "8", + 0x26: "9", 0x27: "0", + 0x28: "ENTER", 0x29: "ESC", 0x2A: "BACKSPACE", + 0x2B: "TAB", 0x2C: "SPACE", 0x2D: "MINUS", + 0x2E: "EQUAL", 0x2F: "LBRACKET", 0x30: "RBRACKET", + 0x31: "BACKSLASH", 0x33: "SEMICOLON", 0x34: "QUOTE", + 0x35: "GRAVE", 0x36: "COMMA", 0x37: "PERIOD", + 0x38: "SLASH", 0x39: "CAPS_LOCK", + 0x4F: "RIGHT", 0x50: "LEFT", 0x51: "DOWN", 0x52: "UP", +} + +# Add F1-F12 keys +for i in range(12): + key_names[0x3A + i] = f"F{i + 1}" + +# Set up I2C and MCP23017 +i2c = board.STEMMA_I2C() +mcp = MCP23017(i2c) + +# Configure solenoid pins +noid_1 = mcp.get_pin(0) # Bell solenoid +noid_2 = mcp.get_pin(1) # Key strike solenoid +noid_1.switch_to_output(value=False) +noid_2.switch_to_output(value=False) + +# Typewriter state tracking +keystroke_count = 0 +current_keys = set() # Track currently pressed keys + +# Check if USB CDC data is available +if usb_cdc.data is None: + print("ERROR: USB CDC data not enabled!") + print("Please create a boot.py file with:") + print(" import usb_cdc") + print(" usb_cdc.enable(console=True, data=True)") + print("\nThen reset the board.") + while True: + time.sleep(1) + +serial = usb_cdc.data + +def strike_key_solenoid(): + """Activate the key strike solenoid briefly""" + noid_2.value = True + time.sleep(SOLENOID_STRIKE_TIME) + noid_2.value = False + +def ring_bell_solenoid(): + """Activate the bell solenoid briefly""" + noid_1.value = True + time.sleep(SOLENOID_STRIKE_TIME) + noid_1.value = False + +def process_key_event(mod, code, p): # pylint: disable=too-many-branches + """Process a key event from the computer""" + global keystroke_count # pylint: disable=global-statement + + # Debug output + key_name = key_names.get(code, f"0x{code:02X}") + action = "pressed" if p else "released" + + # Handle modifier display + if mod > 0: + mod_str = [] + if mod & 0x01: + mod_str.append("L_CTRL") + if mod & 0x02: + mod_str.append("L_SHIFT") + if mod & 0x04: + mod_str.append("L_ALT") + if mod & 0x08: + mod_str.append("L_GUI") + if mod & 0x10: + mod_str.append("R_CTRL") + if mod & 0x20: + mod_str.append("R_SHIFT") + if mod & 0x40: + mod_str.append("R_ALT") + if mod & 0x80: + mod_str.append("R_GUI") + print(f"[{'+'.join(mod_str)}] {key_name} {action}") + else: + print(f"{key_name} {action}") + + # Only process key presses (not releases) for solenoid activation + if p and code > 0: # key_code 0 means modifier-only update + # Check if this is a new key press + if code not in current_keys: + current_keys.add(code) + + # Increment keystroke counter + keystroke_count += 1 + + # Strike the key solenoid + strike_key_solenoid() + + # Check for special keys + if code == ENTER_KEY_CODE: + ring_bell_solenoid() + keystroke_count = 0 # Reset counter for new line + elif code == ESCAPE_KEY_CODE: + ring_bell_solenoid() + keystroke_count = 0 # Reset counter + elif code == TAB_KEY_CODE: + ring_bell_solenoid() + keystroke_count = 0 # Reset counter + elif code == BACKSPACE_KEY_CODE: + keystroke_count = 0 # Reset counter but no bell + elif keystroke_count % KEYSTROKE_BELL_INTERVAL == 0: + print(f"\n*** DING! ({keystroke_count} keystrokes) ***\n") + ring_bell_solenoid() + + print(f"Total keystrokes: {keystroke_count}") + + elif not p and code > 0: + # Remove key from pressed set when released + current_keys.discard(code) + +print("USB Typewriter Receiver starting...") +print(f"Bell will ring every {KEYSTROKE_BELL_INTERVAL} keystrokes or on special keys") +print("Waiting for key events from computer...") +print("-" * 40) + +# Buffer for incoming data +buffer = bytearray(4) +buffer_pos = 0 + +while True: + # Check for incoming serial data + if serial.in_waiting > 0: + # Read available bytes + data = serial.read(serial.in_waiting) + + for byte in data: + # Look for start marker + if buffer_pos == 0: + if byte == 0xAA: + buffer[0] = byte + buffer_pos = 1 + else: + # Fill buffer + buffer[buffer_pos] = byte + buffer_pos += 1 + + # Process complete message + if buffer_pos >= 4: + # Unpack the message + _, modifier, key_code, pressed = struct.unpack('BBBB', buffer) + + # Process the key event + process_key_event(modifier, key_code, pressed) + + # Reset buffer + buffer_pos = 0 + + # Small delay to prevent busy-waiting + time.sleep(0.001) diff --git a/Not_A_Typewriter/Desktop_Not_A_Typewriter/keyboard_sender.py b/Not_A_Typewriter/Desktop_Not_A_Typewriter/keyboard_sender.py new file mode 100644 index 000000000..f8f3ab543 --- /dev/null +++ b/Not_A_Typewriter/Desktop_Not_A_Typewriter/keyboard_sender.py @@ -0,0 +1,223 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +#!/usr/bin/env python3 +""" +USB Typewriter Computer-side Script +Captures keyboard input and sends it to the Feather via serial +""" + +import struct +import time +import threading +import queue +import sys +import serial +import serial.tools.list_ports +from pynput import keyboard + +class TypewriterSender: + def __init__(self): + self.serial_port = None + self.key_queue = queue.Queue() + self.running = True + self.modifier_state = 0 + + # Map pynput keys to HID keycodes + self.key_to_hid = { + # Letters + 'a': 0x04, 'b': 0x05, 'c': 0x06, 'd': 0x07, + 'e': 0x08, 'f': 0x09, 'g': 0x0A, 'h': 0x0B, + 'i': 0x0C, 'j': 0x0D, 'k': 0x0E, 'l': 0x0F, + 'm': 0x10, 'n': 0x11, 'o': 0x12, 'p': 0x13, + 'q': 0x14, 'r': 0x15, 's': 0x16, 't': 0x17, + 'u': 0x18, 'v': 0x19, 'w': 0x1A, 'x': 0x1B, + 'y': 0x1C, 'z': 0x1D, + # Numbers + '1': 0x1E, '2': 0x1F, '3': 0x20, '4': 0x21, + '5': 0x22, '6': 0x23, '7': 0x24, '8': 0x25, + '9': 0x26, '0': 0x27, + # Special keys + keyboard.Key.enter: 0x28, + keyboard.Key.esc: 0x29, + keyboard.Key.backspace: 0x2A, + keyboard.Key.tab: 0x2B, + keyboard.Key.space: 0x2C, + '-': 0x2D, '=': 0x2E, '[': 0x2F, ']': 0x30, + '\\': 0x31, ';': 0x33, "'": 0x34, '`': 0x35, + ',': 0x36, '.': 0x37, '/': 0x38, + keyboard.Key.caps_lock: 0x39, + # Arrow keys + keyboard.Key.right: 0x4F, + keyboard.Key.left: 0x50, + keyboard.Key.down: 0x51, + keyboard.Key.up: 0x52, + } + + # Add function keys + for i in range(1, 13): + self.key_to_hid[getattr(keyboard.Key, f'f{i}')] = 0x3A + i - 1 + + # Modifier bits + self.modifier_bits = { + keyboard.Key.ctrl_l: 0x01, + keyboard.Key.shift_l: 0x02, + keyboard.Key.alt_l: 0x04, + keyboard.Key.cmd_l: 0x08, # Windows/Command key + keyboard.Key.ctrl_r: 0x10, + keyboard.Key.shift_r: 0x20, + keyboard.Key.alt_r: 0x40, + keyboard.Key.cmd_r: 0x80, + } + + @staticmethod + def find_feather_port(): + """Find the Feather's serial port""" + ports = serial.tools.list_ports.comports() + + print("Available serial ports:") + for i, port in enumerate(ports): + print(f"{i}: {port.device} - {port.description}") + feather_port = None + + if not feather_port: + # Manual selection + try: + choice = int(input("\nSelect port number: ")) + if 0 <= choice < len(ports): + feather_port = ports[choice].device + else: + print("Invalid selection") + return None + except (ValueError, IndexError): + print("Invalid input") + return None + + return feather_port + + def connect(self): + """Connect to the Feather via serial""" + port = self.find_feather_port() + if not port: + return False + + try: + self.serial_port = serial.Serial(port, 115200, timeout=0.1) + time.sleep(2) # Wait for connection to stabilize + print(f"Connected to {port}") + return True + except Exception as e: # pylint: disable=broad-except + print(f"Failed to connect: {e}") + return False + + def send_key_event(self, hid_code, pressed): + """Send a key event to the Feather""" + if self.serial_port and self.serial_port.is_open: + try: + # Protocol: [0xAA][modifier_byte][key_code][pressed] + # 0xAA is a start marker + data = struct.pack('BBBB', 0xAA, self.modifier_state, hid_code, 1 if pressed else 0) + self.serial_port.write(data) + self.serial_port.flush() + except Exception as e: # pylint: disable=broad-except + print(f"Error sending data: {e}") + + def on_press(self, key): + """Handle key press events""" + # Check for modifier keys + if key in self.modifier_bits: + self.modifier_state |= self.modifier_bits[key] + self.send_key_event(0, True) # Send modifier update + return + + # Get HID code for the key + hid_code = None + + # Check if it's a special key + if hasattr(key, 'value') and key in self.key_to_hid: + hid_code = self.key_to_hid[key] + # Check if it's a regular character + elif hasattr(key, 'char') and key.char: + hid_code = self.key_to_hid.get(key.char.lower()) + + if hid_code: + self.key_queue.put((hid_code, True)) + + def on_release(self, key): + """Handle key release events""" + # Check for modifier keys + if key in self.modifier_bits: + self.modifier_state &= ~self.modifier_bits[key] + self.send_key_event(0, False) # Send modifier update + return None + + # Get HID code for the key + hid_code = None + + # Check if it's a special key + if hasattr(key, 'value') and key in self.key_to_hid: + hid_code = self.key_to_hid[key] + # Check if it's a regular character + elif hasattr(key, 'char') and key.char: + hid_code = self.key_to_hid.get(key.char.lower()) + + if hid_code: + self.key_queue.put((hid_code, False)) + + # Check for escape to quit + if key == keyboard.Key.esc: + print("\nESC pressed - exiting...") + self.running = False + return False + + return None + + def process_queue(self): + """Process queued key events""" + while self.running: + try: + hid_code, pressed = self.key_queue.get(timeout=0.1) + self.send_key_event(hid_code, pressed) + + # Debug output + action = "pressed" if pressed else "released" + print(f"Key {action}: 0x{hid_code:02X}") + + except queue.Empty: + continue + + def run(self): + """Main run loop""" + if not self.connect(): + print("Failed to connect to Feather") + return + + print("\nNot A Typewriter") + print("Press keys to send to typewriter") + print("Press ESC to exit") + print("-" * 30) + + # Start queue processor thread + queue_thread = threading.Thread(target=self.process_queue) + queue_thread.daemon = True + queue_thread.start() + + # Start keyboard listener + with keyboard.Listener( + on_press=self.on_press, + on_release=self.on_release) as listener: + listener.join() + + # Cleanup + if self.serial_port: + self.serial_port.close() + print("Disconnected") + +if __name__ == "__main__": + try: + sender = TypewriterSender() + sender.run() + except KeyboardInterrupt: + print("\nInterrupted") + sys.exit(0) diff --git a/Not_A_Typewriter/USB_Host_Not_A_Typewriter/code.py b/Not_A_Typewriter/USB_Host_Not_A_Typewriter/code.py new file mode 100644 index 000000000..9ea2b36fc --- /dev/null +++ b/Not_A_Typewriter/USB_Host_Not_A_Typewriter/code.py @@ -0,0 +1,387 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import array +import time +import board +from adafruit_mcp230xx.mcp23017 import MCP23017 + +import usb +import adafruit_usb_host_descriptors +import usb_hid +from adafruit_hid.keyboard import Keyboard +from adafruit_hid.keycode import Keycode + +# Typewriter configuration +KEYSTROKE_BELL_INTERVAL = 25 # Ring bell every 25 keystrokes +SOLENOID_STRIKE_TIME = 0.03 # Duration in seconds for solenoid activation (reduced) +SOLENOID_DELAY = 0.01 # Small delay between solenoid operations (reduced) +ENTER_KEY_CODE = 0x28 # HID code for Enter key +ESCAPE_KEY_CODE = 0x29 # HID code for Escape key +BACKSPACE_KEY_CODE = 0x2A # HID code for Backspace key +TAB_KEY_CODE = 0x2B # HID code for Tab key +bell_keys = {ENTER_KEY_CODE, ESCAPE_KEY_CODE, TAB_KEY_CODE} + +# Set up USB HID keyboard +hid_keyboard = Keyboard(usb_hid.devices) + +# HID to Keycode mapping dictionary +hid_to_keycode = { + 0x04: Keycode.A, + 0x05: Keycode.B, + 0x06: Keycode.C, + 0x07: Keycode.D, + 0x08: Keycode.E, + 0x09: Keycode.F, + 0x0A: Keycode.G, + 0x0B: Keycode.H, + 0x0C: Keycode.I, + 0x0D: Keycode.J, + 0x0E: Keycode.K, + 0x0F: Keycode.L, + 0x10: Keycode.M, + 0x11: Keycode.N, + 0x12: Keycode.O, + 0x13: Keycode.P, + 0x14: Keycode.Q, + 0x15: Keycode.R, + 0x16: Keycode.S, + 0x17: Keycode.T, + 0x18: Keycode.U, + 0x19: Keycode.V, + 0x1A: Keycode.W, + 0x1B: Keycode.X, + 0x1C: Keycode.Y, + 0x1D: Keycode.Z, + 0x1E: Keycode.ONE, + 0x1F: Keycode.TWO, + 0x20: Keycode.THREE, + 0x21: Keycode.FOUR, + 0x22: Keycode.FIVE, + 0x23: Keycode.SIX, + 0x24: Keycode.SEVEN, + 0x25: Keycode.EIGHT, + 0x26: Keycode.NINE, + 0x27: Keycode.ZERO, + 0x28: Keycode.ENTER, + 0x29: Keycode.ESCAPE, + 0x2A: Keycode.BACKSPACE, + 0x2B: Keycode.TAB, + 0x2C: Keycode.SPACE, + 0x2D: Keycode.MINUS, + 0x2E: Keycode.EQUALS, + 0x2F: Keycode.LEFT_BRACKET, + 0x30: Keycode.RIGHT_BRACKET, + 0x31: Keycode.BACKSLASH, + 0x33: Keycode.SEMICOLON, + 0x34: Keycode.QUOTE, + 0x35: Keycode.GRAVE_ACCENT, + 0x36: Keycode.COMMA, + 0x37: Keycode.PERIOD, + 0x38: Keycode.FORWARD_SLASH, + 0x39: Keycode.CAPS_LOCK, + 0x3A: Keycode.F1, + 0x3B: Keycode.F2, + 0x3C: Keycode.F3, + 0x3D: Keycode.F4, + 0x3E: Keycode.F5, + 0x3F: Keycode.F6, + 0x40: Keycode.F7, + 0x41: Keycode.F8, + 0x42: Keycode.F9, + 0x43: Keycode.F10, + 0x44: Keycode.F11, + 0x45: Keycode.F12, + 0x4F: Keycode.RIGHT_ARROW, + 0x50: Keycode.LEFT_ARROW, + 0x51: Keycode.DOWN_ARROW, + 0x52: Keycode.UP_ARROW, +} + +# Modifier mapping +modifier_to_keycode = { + 0x01: Keycode.LEFT_CONTROL, + 0x02: Keycode.LEFT_SHIFT, + 0x04: Keycode.LEFT_ALT, + 0x08: Keycode.LEFT_GUI, + 0x10: Keycode.RIGHT_CONTROL, + 0x20: Keycode.RIGHT_SHIFT, + 0x40: Keycode.RIGHT_ALT, + 0x80: Keycode.RIGHT_GUI, +} + +#interface index, and endpoint addresses for USB Device instance +kbd_interface_index = None +kbd_endpoint_address = None +keyboard = None + +i2c = board.STEMMA_I2C() + +mcp = MCP23017(i2c) + +noid_2 = mcp.get_pin(0) # Key strike solenoid +noid_1 = mcp.get_pin(1) # Bell solenoid +noid_1.switch_to_output(value=False) +noid_2.switch_to_output(value=False) + +# Typewriter state tracking +keystroke_count = 0 +previous_keys = set() # Track previously pressed keys to detect new presses +previous_modifiers = 0 # Track modifier state + +#interface index, and endpoint addresses for USB Device instance +kbd_interface_index = None +kbd_endpoint_address = None +keyboard = None + +# scan for connected USB devices +for device in usb.core.find(find_all=True): + # check for boot keyboard endpoints on this device + kbd_interface_index, kbd_endpoint_address = ( + adafruit_usb_host_descriptors.find_boot_keyboard_endpoint(device) + ) + # if a boot keyboard interface index and endpoint address were found + if kbd_interface_index is not None and kbd_interface_index is not None: + keyboard = device + + # detach device from kernel if needed + if keyboard.is_kernel_driver_active(0): + keyboard.detach_kernel_driver(0) + + # set the configuration so it can be used + keyboard.set_configuration() + +if keyboard is None: + raise RuntimeError("No boot keyboard endpoint found") + +buf = array.array("b", [0] * 8) + +def strike_key_solenoid(): + """Activate the key strike solenoid briefly""" + noid_1.value = True + time.sleep(SOLENOID_STRIKE_TIME) + noid_1.value = False + +def ring_bell_solenoid(): + """Activate the bell solenoid briefly""" + noid_2.value = True + time.sleep(SOLENOID_STRIKE_TIME) + noid_2.value = False + +def get_pressed_keys(report_data): + """Extract currently pressed keys from HID report""" + pressed_keys = set() + + # Check bytes 2-7 for key codes (up to 6 simultaneous keys) + for i in range(2, 8): + k = report_data[i] + # Skip if no key (0) or error rollover (1) + if k > 1: + pressed_keys.add(k) + + return pressed_keys + +def print_keyboard_report(report_data): + # Dictionary for modifier keys (first byte) + modifier_dict = { + 0x01: "LEFT_CTRL", + 0x02: "LEFT_SHIFT", + 0x04: "LEFT_ALT", + 0x08: "LEFT_GUI", + 0x10: "RIGHT_CTRL", + 0x20: "RIGHT_SHIFT", + 0x40: "RIGHT_ALT", + 0x80: "RIGHT_GUI", + } + + # Dictionary for key codes (main keys) + key_dict = { + 0x04: "A", + 0x05: "B", + 0x06: "C", + 0x07: "D", + 0x08: "E", + 0x09: "F", + 0x0A: "G", + 0x0B: "H", + 0x0C: "I", + 0x0D: "J", + 0x0E: "K", + 0x0F: "L", + 0x10: "M", + 0x11: "N", + 0x12: "O", + 0x13: "P", + 0x14: "Q", + 0x15: "R", + 0x16: "S", + 0x17: "T", + 0x18: "U", + 0x19: "V", + 0x1A: "W", + 0x1B: "X", + 0x1C: "Y", + 0x1D: "Z", + 0x1E: "1", + 0x1F: "2", + 0x20: "3", + 0x21: "4", + 0x22: "5", + 0x23: "6", + 0x24: "7", + 0x25: "8", + 0x26: "9", + 0x27: "0", + 0x28: "ENTER", + 0x29: "ESC", + 0x2A: "BACKSPACE", + 0x2B: "TAB", + 0x2C: "SPACE", + 0x2D: "MINUS", + 0x2E: "EQUAL", + 0x2F: "LBRACKET", + 0x30: "RBRACKET", + 0x31: "BACKSLASH", + 0x33: "SEMICOLON", + 0x34: "QUOTE", + 0x35: "GRAVE", + 0x36: "COMMA", + 0x37: "PERIOD", + 0x38: "SLASH", + 0x39: "CAPS_LOCK", + 0x4F: "RIGHT_ARROW", + 0x50: "LEFT_ARROW", + 0x51: "DOWN_ARROW", + 0x52: "UP_ARROW", + } + + # Add F1-F12 keys to the dictionary + for i in range(12): + key_dict[0x3A + i] = f"F{i + 1}" + + # First byte contains modifier keys + modifiers = report_data[0] + + # Print modifier keys if pressed + if modifiers > 0: + print("Modifiers:", end=" ") + + # Check each bit for modifiers and print if pressed + for b, name in modifier_dict.items(): + if modifiers & b: + print(name, end=" ") + + print() + + # Bytes 2-7 contain up to 6 key codes (byte 1 is reserved) + keys_pressed = False + + for i in range(2, 8): + k = report_data[i] + + # Skip if no key or error rollover + if k in {0, 1}: + continue + + if not keys_pressed: + print("Keys:", end=" ") + keys_pressed = True + + # Print key name based on dictionary lookup + if k in key_dict: + print(key_dict[k], end=" ") + else: + # For keys not in the dictionary, print the HID code + print(f"0x{k:02X}", end=" ") + + if keys_pressed: + print() + elif modifiers == 0: + print("No keys pressed") + + +print("USB Typewriter starting...") +print(f"Bell will ring every {KEYSTROKE_BELL_INTERVAL} keystrokes or when Enter is pressed") + +while True: + # try to read data from the keyboard + try: + count = keyboard.read(kbd_endpoint_address, buf, timeout=10) + + # if there is no data it will raise USBTimeoutError + except usb.core.USBTimeoutError: + # Nothing to do if there is no data for this keyboard + continue + + # Get currently pressed keys and modifiers + current_keys = get_pressed_keys(buf) + current_modifiers = buf[0] + + # Find newly pressed keys (not in previous scan) + new_keys = current_keys - previous_keys + + # Find released keys for HID pass-through + released_keys = previous_keys - current_keys + + # Handle modifier changes + if current_modifiers != previous_modifiers: + # Build list of modifier keycodes to press/release + for bit, keycode in modifier_to_keycode.items(): + if current_modifiers & bit and not previous_modifiers & bit: + # Modifier newly pressed + hid_keyboard.press(keycode) + elif not (current_modifiers & bit) and (previous_modifiers & bit): + # Modifier released + hid_keyboard.release(keycode) + + # Release any keys that were let go + for key in released_keys: + if key in hid_to_keycode: + hid_keyboard.release(hid_to_keycode[key]) + + # Process each newly pressed key + for key in new_keys: + # Increment keystroke counter + keystroke_count += 1 + # Strike the key solenoid for typewriter effect + strike_key_solenoid() + # Pass through the key press via USB HID + if key in hid_to_keycode: + hid_keyboard.press(hid_to_keycode[key]) + + # Check if special keys were pressed + if key == ENTER_KEY_CODE: + ring_bell_solenoid() + keystroke_count = 0 # Reset counter for new line + elif key == ESCAPE_KEY_CODE: + ring_bell_solenoid() + keystroke_count = 0 # Reset counter + elif key == TAB_KEY_CODE: + ring_bell_solenoid() + keystroke_count = 0 # Reset counter + elif key == BACKSPACE_KEY_CODE: + keystroke_count = 0 # Reset counter but no bell + elif keystroke_count % KEYSTROKE_BELL_INTERVAL == 0: + print(f"\n*** DING! ({keystroke_count} keystrokes) ***\n") + ring_bell_solenoid() + # Special handling for bell keys that are still held + # check if they were released and re-pressed + # This handles rapid double-taps where the key might not fully release + + for key in bell_keys: + if key in current_keys and key in previous_keys and key not in new_keys: + # Key is being held, check if it was briefly released by looking at the raw state + # For held keys, we'll check if this is a repeat event + if len(current_keys) != len(previous_keys) or current_keys != previous_keys: + # Something changed, might be a repeat + continue + + # Update previous keys and modifiers for next scan + previous_keys = current_keys + previous_modifiers = current_modifiers + + # Still print the keyboard report for debugging + if new_keys: # Only print if there are new key presses + print_keyboard_report(buf) + print(f"Total keystrokes: {keystroke_count}") diff --git a/OV5640_Breakout/CircuitPython_Kaluga-jpeg/code.py b/OV5640_Breakout/CircuitPython_Kaluga-jpeg/code.py index 946e8761f..4353465bf 100644 --- a/OV5640_Breakout/CircuitPython_Kaluga-jpeg/code.py +++ b/OV5640_Breakout/CircuitPython_Kaluga-jpeg/code.py @@ -25,6 +25,8 @@ import board import busio import displayio +import busdisplay +import fourwire import espcamera import espidf import keypad @@ -34,7 +36,7 @@ print("Initializing display") displayio.release_displays() spi = busio.SPI(MOSI=board.LCD_MOSI, clock=board.LCD_CLK) -display_bus = displayio.FourWire( +display_bus = fourwire.FourWire( spi, command=board.LCD_D_C, chip_select=board.LCD_CS, @@ -67,7 +69,7 @@ b"\x29\x80\x78" # Display on then delay 0x78 (120ms) ) -display = displayio.Display(display_bus, _INIT_SEQUENCE, width=320, height=240) +display = busdisplay.BusDisplay(display_bus, _INIT_SEQUENCE, width=320, height=240) if espidf.get_reserved_psram() < 1047586: print("""Place the following line in CIRCUITPY/settings.toml, then hard-reset the board: diff --git a/OV5640_Breakout/CircuitPython_Kaluga-lcd-mirror/code.py b/OV5640_Breakout/CircuitPython_Kaluga-lcd-mirror/code.py index ad9d09b60..0ff64067e 100644 --- a/OV5640_Breakout/CircuitPython_Kaluga-lcd-mirror/code.py +++ b/OV5640_Breakout/CircuitPython_Kaluga-lcd-mirror/code.py @@ -19,13 +19,15 @@ import busio import keypad import displayio +import busdisplay +import fourwire import espcamera import espidf print("Initializing display") displayio.release_displays() spi = busio.SPI(MOSI=board.LCD_MOSI, clock=board.LCD_CLK) -display_bus = displayio.FourWire( +display_bus = fourwire.FourWire( spi, command=board.LCD_D_C, chip_select=board.LCD_CS, @@ -58,7 +60,7 @@ b"\x29\x80\x78" # Display on then delay 0x78 (120ms) ) -display = displayio.Display(display_bus, _INIT_SEQUENCE, width=320, height=240) +display = busdisplay.BusDisplay(display_bus, _INIT_SEQUENCE, width=320, height=240) if espidf.get_reserved_psram() < 1047586: print("""Place the following line in CIRCUITPY/settings.toml, then hard-reset the board: diff --git a/OV5640_Breakout/CircuitPython_Pico-lcd-mirror/code.py b/OV5640_Breakout/CircuitPython_Pico-lcd-mirror/code.py index 24b6d8c43..c652a28bb 100644 --- a/OV5640_Breakout/CircuitPython_Pico-lcd-mirror/code.py +++ b/OV5640_Breakout/CircuitPython_Pico-lcd-mirror/code.py @@ -13,11 +13,12 @@ import adafruit_ov5640 import adafruit_st7789 import displayio +import fourwire # Set up the display (You must customize this block for your display!) displayio.release_displays() spi = busio.SPI(clock=board.GP2, MOSI=board.GP3) -display_bus = displayio.FourWire(spi, command=board.GP0, chip_select=board.GP1, reset=None) +display_bus = fourwire.FourWire(spi, command=board.GP0, chip_select=board.GP1, reset=None) display = adafruit_st7789.ST7789(display_bus, width=240, height=240, rowstart=80, rotation=0) print("construct bus") diff --git a/PCM510x_Examples/Arduino_Audio_Playback/.feather_rp2040.test.only b/PCM510x_Examples/Arduino_Audio_Playback/.feather_rp2040.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/PCM510x_Examples/Arduino_Audio_Playback/Arduino_Audio_Playback.ino b/PCM510x_Examples/Arduino_Audio_Playback/Arduino_Audio_Playback.ino new file mode 100644 index 000000000..463b0f6ab --- /dev/null +++ b/PCM510x_Examples/Arduino_Audio_Playback/Arduino_Audio_Playback.ino @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2023 Ladyada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/* + This example plays a 'raw' PCM file from memory to I2S +*/ + +#include + +#include "startup.h" // audio file in flash + +// Create the I2S port using a PIO state machine +I2S i2s(OUTPUT); + +// GPIO pin numbers on Feather RP2040 +#define pBCLK D9 // BITCLOCK +#define pWS D10 // LRCLOCK +#define pDOUT D11 // DATA + +void setup() { + Serial.begin(115200); + while (!Serial) delay(10); + Serial.println("I2S playback demo"); +} + +void loop() { +} + +void setup1() { + i2s.setBCLK(pBCLK); + i2s.setDATA(pDOUT); + i2s.setBitsPerSample(16); +} + +void loop1() { + // the main loop will tell us when it wants us to play! + play_i2s(startupAudioData, sizeof(startupAudioData), startupSampleRate); + delay(1000); +} + +void play_i2s(const uint8_t *data, uint32_t len, uint32_t rate) { + // start I2S at the sample rate with 16-bits per sample + if (!i2s.begin(rate)) { + Serial.println("Failed to initialize I2S!"); + delay(500); + i2s.end(); + return; + } + + for(uint32_t i=0; i + + + bool setBCLK(pin_size_t pin); + - This assigns two adjacent pins - the pin after this one (one greater) + is the WS (word select) signal, which toggles before the sample for + each channel is sent + + bool setDATA(pin_size_t pin); + - Sets the DOUT pin, can be any valid GPIO pin +*/ + +#include + +// Create the I2S port using a PIO state machine +I2S i2s(OUTPUT); + +// GPIO pin numbers on Feather RP2040 +#define pBCLK D9 // BITCLOCK +#define pWS D10 // LRCLOCK +#define pDOUT D11 // DATA + +const int frequency = 440; // frequency of square wave in Hz +const int amplitude = 500; // amplitude of square wave +const int sampleRate = 16000; // 16 KHz is a good quality + +const int halfWavelength = (sampleRate / frequency); // half wavelength of square wave + +int16_t sample = amplitude; // current sample value +int count = 0; + +void setup() { + Serial.begin(115200); + while (!Serial) delay(10); + Serial.println("I2S simple tone"); + + i2s.setBCLK(pBCLK); + i2s.setDATA(pDOUT); + i2s.setBitsPerSample(16); + + // start I2S at the sample rate with 16-bits per sample + if (!i2s.begin(sampleRate)) { + Serial.println("Failed to initialize I2S!"); + while (1); // do nothing + } + +} + +void loop() { + if (count % halfWavelength == 0) { + // invert the sample every half wavelength count multiple to generate square wave + sample = -1 * sample; + } + + // write the same sample twice, once for left and once for the right channel + i2s.write(sample); + i2s.write(sample); + + // increment the counter for the next sample + count++; +} diff --git a/PCM510x_Examples/CircuitPython_Tone/code.py b/PCM510x_Examples/CircuitPython_Tone/code.py new file mode 100644 index 000000000..0c9047d1e --- /dev/null +++ b/PCM510x_Examples/CircuitPython_Tone/code.py @@ -0,0 +1,29 @@ +# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +CircuitPython I2S Tone playback example. +Plays a tone for one second on, one +second off, in a loop. +""" +import time +import array +import math +import audiocore +import board +import audiobusio + +audio = audiobusio.I2SOut(board.D9, board.D10, board.D11) + +tone_volume = 0.1 # Increase this to increase the volume of the tone. +frequency = 440 # Set this to the Hz of the tone you want to generate. +length = 8000 // frequency +sine_wave = array.array("h", [0] * length) +for i in range(length): + sine_wave[i] = int((math.sin(math.pi * 2 * i / length)) * tone_volume * (2 ** 15 - 1)) +sine_wave_sample = audiocore.RawSample(sine_wave) + +while True: + audio.play(sine_wave_sample, loop=True) + time.sleep(1) + audio.stop() + time.sleep(1) diff --git a/PCM510x_Examples/CircuitPython_WAV/StreetChicken.wav b/PCM510x_Examples/CircuitPython_WAV/StreetChicken.wav new file mode 100644 index 000000000..55d4eb0f2 Binary files /dev/null and b/PCM510x_Examples/CircuitPython_WAV/StreetChicken.wav differ diff --git a/PCM510x_Examples/CircuitPython_WAV/code.py b/PCM510x_Examples/CircuitPython_WAV/code.py new file mode 100644 index 000000000..ddfe982e6 --- /dev/null +++ b/PCM510x_Examples/CircuitPython_WAV/code.py @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +CircuitPython I2S WAV file playback. +Plays a WAV file once. +""" +import audiocore +import board +import audiobusio + +audio = audiobusio.I2SOut(board.D9, board.D10, board.D11) + +with open("StreetChicken.wav", "rb") as wave_file: + wav = audiocore.WaveFile(wave_file) + + print("Playing wav file!") + audio.play(wav) + while audio.playing: + pass + +print("Done!") diff --git a/PCM5122_Examples/Arduino_PCM5122/.feather_rp2040.test.only b/PCM5122_Examples/Arduino_PCM5122/.feather_rp2040.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/PCM5122_Examples/Arduino_PCM5122/Arduino_PCM5122.ino b/PCM5122_Examples/Arduino_PCM5122/Arduino_PCM5122.ino new file mode 100644 index 000000000..023aa6432 --- /dev/null +++ b/PCM5122_Examples/Arduino_PCM5122/Arduino_PCM5122.ino @@ -0,0 +1,274 @@ +// SPDX-FileCopyrightText: 2025 Ladyada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/*! + * + * Basic test example for the Adafruit PCM5122 + * + * Written by Limor 'ladyada' Fried with assistance from Claude Code + * for Adafruit Industries. + * + * MIT license, all text here must be included in any redistribution. + */ + +#include +#include +#include + +Adafruit_PCM51xx pcm; + +#define pBCLK D9 // BITCLOCK - I2S clock +#define pWS D10 // LRCLOCK - Word select +#define pDOUT D11 // DATA - I2S data + +// Create I2S port +I2S i2s(OUTPUT); + +const int frequency = 440; // frequency of square wave in Hz +const int amplitude = 500; // amplitude of square wave +const int sampleRate = 16000; // 16 KHz is a good quality + +const int halfWavelength = (sampleRate / frequency); // half wavelength of square wave + +int16_t sample = amplitude; // current sample value +int count = 0; + +void setup() { + Serial.begin(115200); + while (!Serial) delay(10); + + Serial.println(F("Adafruit PCM51xx Test")); + + // I2C mode (default) + if (!pcm.begin()) { + Serial.println(F("Could not find PCM51xx, check wiring!")); + while (1) delay(10); + } + + // Hardware SPI mode (uncomment to use) + // if (!pcm.begin(10, &SPI)) { // CS pin 10 + // Serial.println(F("Could not find PCM51xx over SPI, check wiring!")); + // while (1) delay(10); + // } + + // Software SPI mode (uncomment to use) + // if (!pcm.begin(10, 11, 12, 13)) { // CS, MOSI, MISO, SCLK + // Serial.println(F("Could not find PCM51xx over software SPI, check wiring!")); + // while (1) delay(10); + // } + + Serial.println(F("PCM51xx initialized successfully!")); + + // Set I2S format to I2S + Serial.println(F("Setting I2S format")); + pcm.setI2SFormat(PCM51XX_I2S_FORMAT_I2S); + + // Read and display current format + pcm51xx_i2s_format_t format = pcm.getI2SFormat(); + Serial.print(F("Current I2S format: ")); + switch (format) { + case PCM51XX_I2S_FORMAT_I2S: + Serial.println(F("I2S")); + break; + case PCM51XX_I2S_FORMAT_TDM: + Serial.println(F("TDM/DSP")); + break; + case PCM51XX_I2S_FORMAT_RTJ: + Serial.println(F("Right Justified")); + break; + case PCM51XX_I2S_FORMAT_LTJ: + Serial.println(F("Left Justified")); + break; + default: + Serial.println(F("Unknown")); + break; + } + + // Set I2S word length to 32-bit + Serial.println(F("Setting I2S word length")); + pcm.setI2SSize(PCM51XX_I2S_SIZE_16BIT); + + // Read and display current word length + pcm51xx_i2s_size_t size = pcm.getI2SSize(); + Serial.print(F("Current I2S word length: ")); + switch (size) { + case PCM51XX_I2S_SIZE_16BIT: + Serial.println(F("16 bits")); + break; + case PCM51XX_I2S_SIZE_20BIT: + Serial.println(F("20 bits")); + break; + case PCM51XX_I2S_SIZE_24BIT: + Serial.println(F("24 bits")); + break; + case PCM51XX_I2S_SIZE_32BIT: + Serial.println(F("32 bits")); + break; + default: + Serial.println(F("Unknown")); + break; + } + + // Set error detection bits + if (!pcm.ignoreFSDetect(true) || !pcm.ignoreBCKDetect(true) || !pcm.ignoreSCKDetect(true) || + !pcm.ignoreClockHalt(true) || !pcm.ignoreClockMissing(true) || !pcm.disableClockAutoset(false) || + !pcm.ignorePLLUnlock(true)) { + Serial.println(F("Error detection failed to configure")); + } + + // Enable PLL + Serial.println(F("Enabling PLL")); + pcm.enablePLL(true); + + // Check PLL status + bool pllEnabled = pcm.isPLLEnabled(); + Serial.print(F("PLL enabled: ")); + Serial.println(pllEnabled ? F("Yes") : F("No")); + + // Set PLL reference to BCK + Serial.println(F("Setting PLL reference")); + pcm.setPLLReference(PCM51XX_PLL_REF_BCK); + + // Read and display current PLL reference + pcm51xx_pll_ref_t pllRef = pcm.getPLLReference(); + Serial.print(F("Current PLL reference: ")); + switch (pllRef) { + case PCM51XX_PLL_REF_SCK: + Serial.println(F("SCK")); + break; + case PCM51XX_PLL_REF_BCK: + Serial.println(F("BCK")); + break; + case PCM51XX_PLL_REF_GPIO: + Serial.println(F("GPIO")); + break; + default: + Serial.println(F("Unknown")); + break; + } + + // Set DAC clock source to PLL + Serial.println(F("Setting DAC source")); + pcm.setDACSource(PCM51XX_DAC_CLK_PLL); + + // Read and display current DAC source + pcm51xx_dac_clk_src_t dacSource = pcm.getDACSource(); + Serial.print(F("Current DAC source: ")); + switch (dacSource) { + case PCM51XX_DAC_CLK_MASTER: + Serial.println(F("Master clock (auto-select)")); + break; + case PCM51XX_DAC_CLK_PLL: + Serial.println(F("PLL clock")); + break; + case PCM51XX_DAC_CLK_SCK: + Serial.println(F("SCK clock")); + break; + case PCM51XX_DAC_CLK_BCK: + Serial.println(F("BCK clock")); + break; + default: + Serial.println(F("Unknown")); + break; + } + + // Test auto mute (default turn off) + Serial.println(F("Setting auto mute")); + pcm.setAutoMute(false); + + // Read and display current auto mute status + bool autoMuteEnabled = pcm.getAutoMute(); + Serial.print(F("Auto mute: ")); + Serial.println(autoMuteEnabled ? F("Enabled") : F("Disabled")); + + // Test mute (default do not mute) + Serial.println(F("Setting mute")); + pcm.mute(false); + + // Read and display current mute status + bool muteEnabled = pcm.isMuted(); + Serial.print(F("Mute: ")); + Serial.println(muteEnabled ? F("Enabled") : F("Disabled")); + + // Check DSP boot status and power state + Serial.print(F("DSP boot done: ")); + Serial.println(pcm.getDSPBootDone() ? F("Yes") : F("No")); + + pcm51xx_power_state_t powerState = pcm.getPowerState(); + Serial.print(F("Power state: ")); + switch (powerState) { + case PCM51XX_POWER_POWERDOWN: + Serial.println(F("Powerdown")); + break; + case PCM51XX_POWER_WAIT_CP_VALID: + Serial.println(F("Wait for CP voltage valid")); + break; + case PCM51XX_POWER_CALIBRATION_1: + case PCM51XX_POWER_CALIBRATION_2: + Serial.println(F("Calibration")); + break; + case PCM51XX_POWER_VOLUME_RAMP_UP: + Serial.println(F("Volume ramp up")); + break; + case PCM51XX_POWER_RUN_PLAYING: + Serial.println(F("Run (Playing)")); + break; + case PCM51XX_POWER_LINE_SHORT: + Serial.println(F("Line output short / Low impedance")); + break; + case PCM51XX_POWER_VOLUME_RAMP_DOWN: + Serial.println(F("Volume ramp down")); + break; + case PCM51XX_POWER_STANDBY: + Serial.println(F("Standby")); + break; + default: + Serial.println(F("Unknown")); + break; + } + + // Check PLL lock status + bool pllLocked = pcm.isPLLLocked(); + Serial.print(F("PLL locked: ")); + Serial.println(pllLocked ? F("Yes") : F("No")); + + // Set volume to -6dB on both channels + Serial.println(F("Setting volume")); + pcm.setVolumeDB(-6.0, -6.0); + + // Read and display current volume + float leftVol, rightVol; + pcm.getVolumeDB(&leftVol, &rightVol); + Serial.print(F("Current volume - Left: ")); + Serial.print(leftVol, 1); + Serial.print(F("dB, Right: ")); + Serial.print(rightVol, 1); + Serial.println(F("dB")); + + // Initialize I2S peripheral + Serial.println("Initializing I2S..."); + i2s.setBCLK(pBCLK); + i2s.setDATA(pDOUT); + i2s.setBitsPerSample(16); + + // Start I2S at the sample rate + if (!i2s.begin(sampleRate)) { + Serial.println("Failed to initialize I2S!"); + } + +} + +void loop() { + if (count % halfWavelength == 0) { + // invert the sample every half wavelength count multiple to generate square wave + sample = -1 * sample; + } + + // write the same sample twice, once for left and once for the right channel + i2s.write(sample); + i2s.write(sample); + + // increment the counter for the next sample + count++; +} diff --git a/PCM5122_Examples/Arduino_PCM5122_HW_Mode/.feather_rp2040.test.only b/PCM5122_Examples/Arduino_PCM5122_HW_Mode/.feather_rp2040.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/PCM5122_Examples/Arduino_PCM5122_HW_Mode/Arduino_PCM5122_HW_Mode.ino b/PCM5122_Examples/Arduino_PCM5122_HW_Mode/Arduino_PCM5122_HW_Mode.ino new file mode 100644 index 000000000..4a2055178 --- /dev/null +++ b/PCM5122_Examples/Arduino_PCM5122_HW_Mode/Arduino_PCM5122_HW_Mode.ino @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2025 Ladyada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include +#include + +#define pBCLK D9 // BITCLOCK - I2S clock +#define pWS D10 // LRCLOCK - Word select +#define pDOUT D11 // DATA - I2S data + +// Create I2S port +I2S i2s(OUTPUT); + +const int frequency = 440; // frequency of square wave in Hz +const int amplitude = 500; // amplitude of square wave +const int sampleRate = 16000; // 16 KHz is a good quality + +const int halfWavelength = (sampleRate / frequency); // half wavelength of square wave + +int16_t sample = amplitude; // current sample value +int count = 0; + +void setup() { + Serial.begin(115200); + while (!Serial) delay(10); + + Serial.println(F("Adafruit PCM51xx Hardware Mode Test")); + + // Initialize I2S peripheral + Serial.println("Initializing I2S..."); + i2s.setBCLK(pBCLK); + i2s.setDATA(pDOUT); + i2s.setBitsPerSample(16); + + // Start I2S at the sample rate + if (!i2s.begin(sampleRate)) { + Serial.println("Failed to initialize I2S!"); + } + +} + +void loop() { + if (count % halfWavelength == 0) { + // invert the sample every half wavelength count multiple to generate square wave + sample = -1 * sample; + } + + // write the same sample twice, once for left and once for the right channel + i2s.write(sample); + i2s.write(sample); + + // increment the counter for the next sample + count++; +} diff --git a/PCM5122_Examples/CircuitPython_PCM5122_HW_Mode/code.py b/PCM5122_Examples/CircuitPython_PCM5122_HW_Mode/code.py new file mode 100644 index 000000000..3b5e1ca80 --- /dev/null +++ b/PCM5122_Examples/CircuitPython_PCM5122_HW_Mode/code.py @@ -0,0 +1,31 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +Sine tone playback test for the PCM5122 I2S DAC in hardware mode. +""" + +import array +import math +import time + +import audiobusio +import audiocore +import board + +audio = audiobusio.I2SOut(board.D9, board.D10, board.D11) + +tone_volume = 0.5 # Increase this to increase the volume of the tone. +frequency = 440 # Set this to the Hz of the tone you want to generate. +length = 8000 // frequency +sine_wave = array.array("h", [0] * length) +for i in range(length): + sine_wave[i] = int((math.sin(math.pi * 2 * i / length)) * tone_volume * (2**15 - 1)) +sine_wave_sample = audiocore.RawSample(sine_wave) + +while True: + audio.play(sine_wave_sample, loop=True) + time.sleep(1) + audio.stop() + time.sleep(1) diff --git a/Pep_Talk_Generator/clue/code.py b/Pep_Talk_Generator/clue/code.py index fe480460a..4308303eb 100644 --- a/Pep_Talk_Generator/clue/code.py +++ b/Pep_Talk_Generator/clue/code.py @@ -106,10 +106,10 @@ display = board.DISPLAY clue_group = displayio.Group() -bitmap_file = open("bmps/background.bmp", "rb") -bitmap1 = displayio.OnDiskBitmap(bitmap_file) + +bitmap1 = displayio.OnDiskBitmap("bmps/background.bmp") tile_grid = displayio.TileGrid( - bitmap1, pixel_shader=getattr(bitmap1, "pixel_shader", displayio.ColorConverter()) + bitmap1, pixel_shader=bitmap1.pixel_shader ) clue_group.append(tile_grid) diff --git a/PiCowbell_Camera_Demos/JPEG_Capture/code.py b/PiCowbell_Camera_Demos/JPEG_Capture/code.py index b660016c9..c2d196f9b 100644 --- a/PiCowbell_Camera_Demos/JPEG_Capture/code.py +++ b/PiCowbell_Camera_Demos/JPEG_Capture/code.py @@ -76,8 +76,27 @@ def open_next_image(): return open(filename, "wb") cam.colorspace = adafruit_ov5640.OV5640_COLOR_JPEG -cam.quality = 3 -b = bytearray(cam.capture_buffer_size) + +# Different platforms have different amounts of memory available. +# Typically a Pico 2 can handle quality = 2 and a Pico can handle quality = 5. +# Rather than detect and select sizes, let's try to detect the best dynamically +# for broader platform support. +# Start with the highest quality setting and attempt to allocate a buffer +# of the necessary size. If it fails, try the next lowest. +b = None +for quality in range(2,55): #valid range is 2 to 54 inclusive + try: + cam.quality = quality + print(f"Attempting to use quality {quality}.") + b = bytearray(cam.capture_buffer_size) + print(f"Quality {quality} successfully selected.") + break + except MemoryError: + print(f"Quality {quality} was too big. Trying next lowest.") + +if b is None: + print("There wasn't enough system memory to allocate the lowest quality buffer.") + jpeg = cam.capture(b) while True: diff --git a/PiCowbell_Camera_Demos/TFT_Viewer/code.py b/PiCowbell_Camera_Demos/TFT_Viewer/code.py index e8d275459..4f7abfd2f 100644 --- a/PiCowbell_Camera_Demos/TFT_Viewer/code.py +++ b/PiCowbell_Camera_Demos/TFT_Viewer/code.py @@ -15,10 +15,11 @@ import adafruit_ov5640 import adafruit_st7789 import displayio +import fourwire displayio.release_displays() spi = busio.SPI(clock=board.GP18, MOSI=board.GP19) -display_bus = displayio.FourWire(spi, command=board.GP21, chip_select=board.GP17, reset=None) +display_bus = fourwire.FourWire(spi, command=board.GP21, chip_select=board.GP17, reset=None) display = adafruit_st7789.ST7789(display_bus, width=240, height=240, rowstart=80, rotation=0) print("construct bus") diff --git a/PiCowbell_HSTX_DVI_Examples/arduino_rp2040_hstx_dvi_cowbell/.pico_rp2040.test.only b/PiCowbell_HSTX_DVI_Examples/arduino_rp2040_hstx_dvi_cowbell/.pico_rp2040.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/PiCowbell_HSTX_DVI_Examples/arduino_rp2040_hstx_dvi_cowbell/arduino_rp2040_hstx_dvi_cowbell.ino b/PiCowbell_HSTX_DVI_Examples/arduino_rp2040_hstx_dvi_cowbell/arduino_rp2040_hstx_dvi_cowbell.ino new file mode 100644 index 000000000..fd16c0d27 --- /dev/null +++ b/PiCowbell_HSTX_DVI_Examples/arduino_rp2040_hstx_dvi_cowbell/arduino_rp2040_hstx_dvi_cowbell.ino @@ -0,0 +1,623 @@ +// SPDX-FileCopyrightText: 2023 Phil B. for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Basic full-color PicoDVI test. Provides a 16-bit color video framebuffer to +// which Adafruit_GFX calls can be made. It's based on the EYESPI_Test.ino sketch. + +#include // Core display & graphics library +#include // A custom font + +// Here's how a 320x240 16-bit color framebuffer is declared. Double-buffering +// is not an option in 16-bit color mode, just not enough RAM; all drawing +// operations are shown as they occur. Second argument is a hardware +// configuration -- this example is written for Adafruit PiCowBell HSTX DVI, +// and Raspberry Pi RP2040, but that's easily switched out for boards +// like the Pimoroni Pico DV (use 'pimoroni_demo_hdmi_cfg') or Pico DVI Sock ('pico_sock_cfg'). +DVIGFX16 display(DVI_RES_320x240p60, adafruit_hstxdvibell_cfg); + +// A 400x240 mode is possible but pushes overclocking even higher than +// 320x240 mode. SOME BOARDS MIGHT SIMPLY NOT BE COMPATIBLE WITH THIS. +// May require selecting QSPI div4 clock (Tools menu) to slow down flash +// accesses, may require further over-volting the CPU to 1.25 or 1.3 V. +//DVIGFX16 display(DVI_RES_400x240p60, adafruit_feather_dvi_cfg); + +void setup() { // Runs once on startup + if (!display.begin()) { // Blink LED if insufficient RAM + pinMode(LED_BUILTIN, OUTPUT); + for (;;) digitalWrite(LED_BUILTIN, (millis() / 500) & 1); + } +} + +#define PAUSE 2000 // Delay (milliseconds) between examples +uint8_t rotate = 0; // Current screen orientation (0-3) +#define CORNER_RADIUS 0 + +void loop() { + // Each of these functions demonstrates a different Adafruit_GFX concept: + show_shapes(); + show_charts(); + show_basic_text(); + show_char_map(); + show_custom_text(); + show_bitmap(); + show_canvas(); + + if (++rotate > 3) rotate = 0; // Cycle through screen rotations 0-3 + display.setRotation(rotate); // Takes effect on next drawing command +} + +// BASIC SHAPES EXAMPLE ---------------------------------------------------- + +void show_shapes() { + // Draw outlined and filled shapes. This demonstrates: + // - Enclosed shapes supported by GFX (points & lines are shown later). + // - Adapting to different-sized displays, and to rounded corners. + + const int16_t cx = display.width() / 2; // Center of screen = + const int16_t cy = display.height() / 2; // half of width, height + int16_t minor = min(cx, cy); // Lesser of half width or height + // Shapes will be drawn in a square region centered on the screen. But one + // particular screen -- rounded 240x280 ST7789 -- has VERY rounded corners + // that would clip a couple of shapes if drawn full size. If using that + // screen type, reduce area by a few pixels to avoid drawing in corners. + if (CORNER_RADIUS > 40) minor -= 4; + const uint8_t pad = 5; // Space between shapes is 2X this + const int16_t size = minor - pad; // Shapes are this width & height + const int16_t half = size / 2; // 1/2 of shape size + + display.fillScreen(0); // Start by clearing the screen; color 0 = black + + // Draw outline version of basic shapes: rectangle, triangle, circle and + // rounded rectangle in different colors. Rather than hardcoded numbers + // for position and size, some arithmetic helps adapt to screen dimensions. + display.drawRect(cx - minor, cy - minor, size, size, 0xF800); + display.drawTriangle(cx + pad, cy - pad, cx + pad + half, cy - minor, + cx + minor - 1, cy - pad, 0x07E0); + display.drawCircle(cx - pad - half, cy + pad + half, half, 0x001F); + display.drawRoundRect(cx + pad, cy + pad, size, size, size / 5, 0xFFE0); + delay(PAUSE); + + // Draw same shapes, same positions, but filled this time. + display.fillRect(cx - minor, cy - minor, size, size, 0xF800); + display.fillTriangle(cx + pad, cy - pad, cx + pad + half, cy - minor, + cx + minor - 1, cy - pad, 0x07E0); + display.fillCircle(cx - pad - half, cy + pad + half, half, 0x001F); + display.fillRoundRect(cx + pad, cy + pad, size, size, size / 5, 0xFFE0); + delay(PAUSE); +} // END SHAPE EXAMPLE + +// CHART EXAMPLES ---------------------------------------------------------- + +void show_charts() { + // Draw some graphs and charts. GFX library doesn't handle these as native + // object types, but it only takes a little code to build them from simple + // shapes. This demonstrates: + // - Drawing points and horizontal, vertical and arbitrary lines. + // - Adapting to different-sized displays. + // - Graphics being clipped off edge. + // - Use of negative values to draw shapes "backward" from an anchor point. + // - C technique for finding array size at runtime (vs hardcoding). + + display.fillScreen(0); // Clear screen + + const int16_t cx = display.width() / 2; // Center of screen = + const int16_t cy = display.height() / 2; // half of width, height + const int16_t minor = min(cx, cy); // Lesser of half width or height + const int16_t major = max(cx, cy); // Greater of half width or height + + // Let's start with a relatively simple sine wave graph with axes. + // Draw graph axes centered on screen. drawFastHLine() and drawFastVLine() + // need fewer arguments than normal 2-point line drawing shown later. + display.drawFastHLine(0, cy, display.width(), 0x0210); // Dark blue + display.drawFastVLine(cx, 0, display.height(), 0x0210); + + // Then draw some tick marks along the axes. To keep this code simple, + // these aren't to any particular scale, but a real program may want that. + // The loop here draws them from the center outward and pays no mind + // whether the screen is rectangular; any ticks that go off-screen will + // be clipped by the library. + for (uint8_t i=1; i<=10; i++) { + // The Arduino map() function scales an input value (e.g. "i") from an + // input range (0-10 here) to an output range (0 to major-1 here). + // Very handy for making graphics adjust to different screens! + int16_t n = map(i, 0, 10, 0, major - 1); // Tick offset relative to center point + display.drawFastVLine(cx - n, cy - 5, 11, 0x210); + display.drawFastVLine(cx + n, cy - 5, 11, 0x210); + display.drawFastHLine(cx - 5, cy - n, 11, 0x210); + display.drawFastHLine(cx - 5, cy + n, 11, 0x210); + } + + // Then draw sine wave over this using GFX drawPixel() function. + for (int16_t x=0; x(str.c_str())); +} + +// TEXT EXAMPLES ----------------------------------------------------------- + +// This section demonstrates: +// - Using the default 5x7 built-in font, including scaling in each axis. +// - How to access all characters of this font, including symbols. +// - Using a custom font, including alignment techniques that aren't a normal +// part of the GFX library (uses functions above). + +void show_basic_text() { + // Show text scaling with built-in font. + display.fillScreen(0); + display.setFont(); // Use default font + display.setCursor(0, CORNER_RADIUS); // Initial cursor position + display.setTextSize(1); // Default size + display.println(F("Standard built-in font")); + display.setTextSize(2); + display.println(F("BIG TEXT")); + display.setTextSize(3); + // "BIGGER TEXT" won't fit on narrow screens, so abbreviate there. + display.println((display.width() >= 200) ? F("BIGGER TEXT") : F("BIGGER")); + display.setTextSize(2, 4); + display.println(F("TALL and")); + display.setTextSize(4, 2); + display.println(F("WIDE")); + + delay(PAUSE); +} // END BASIC TEXT EXAMPLE + +void show_char_map() { + // "Code Page 437" is a name given to the original IBM PC character set. + // Despite age and limited language support, still seen in small embedded + // settings as it has some useful symbols and accented characters. The + // default 5x7 pixel font of Adafruit_GFX is modeled after CP437. This + // function draws a table of all the characters & explains some issues. + + // There are 256 characters in all. Draw table as 16 rows of 16 columns, + // plus hexadecimal row & column labels. How big can each cell be drawn? + const int cell_size = min(display.width(), display.height()) / 17; + if (cell_size < 8) return; // Screen is too small for table, skip example. + const int total_size = cell_size * 17; // 16 cells + 1 row or column label + + // Set up for default 5x7 font at 1:1 scale. Custom fonts are NOT used + // here as most are only 128 characters to save space (the "7b" at the + // end of many GFX font names means "7 bits," i.e. 128 characters). + display.setFont(); + display.setTextSize(1); + + // Early Adafruit_GFX was missing one symbol, throwing off some indices! + // But fixing the library would break MANY existing sketches that relied + // on the degrees symbol and others. The default behavior is thus "broken" + // to keep older code working. New code can access the CORRECT full CP437 + // table by calling this function like so: + display.cp437(true); + + display.fillScreen(0); + + const int16_t x = (display.width() - total_size) / 2; // Upper left corner of + int16_t y = (display.height() - total_size) / 2; // table centered on screen + if (y >= 4) { // If there's a little extra space above & below, scoot table + y += 4; // down a few pixels and show a message centered at top. + display.setCursor((display.width() - 114) / 2, 0); // 114 = pixel width + display.print(F("CP437 Character Map")); // of this message + } + + const int16_t inset_x = (cell_size - 5) / 2; // To center each character within cell, + const int16_t inset_y = (cell_size - 8) / 2; // compute X & Y offset from corner. + + for (uint8_t row=0; row<16; row++) { // 16 down... + // Draw row and columm headings as hexadecimal single digits. To get the + // hex value for a specific character, combine the left & top labels, + // e.g. Pi symbol is row E, column 3, thus: display.print((char)0xE3); + display.setCursor(x + (row + 1) * cell_size + inset_x, y + inset_y); + display.print(row, HEX); // This actually draws column labels + display.setCursor(x + inset_x, y + (row + 1) * cell_size + inset_y); + display.print(row, HEX); // and THIS is the row labels + for (uint8_t col=0; col<16; col++) { // 16 across... + if ((row + col) & 1) { // Fill alternating cells w/gray + display.fillRect(x + (col + 1) * cell_size, y + (row + 1) * cell_size, + cell_size, cell_size, 0x630C); + } + // drawChar() bypasses usual cursor positioning to go direct to an X/Y + // location. If foreground & background match, it's drawn transparent. + display.drawChar(x + (col + 1) * cell_size + inset_x, + y + (row + 1) * cell_size + inset_y, row * 16 + col, + 0xFFFF, 0xFFFF, 1); + } + } + + delay(PAUSE * 2); +} // END CHAR MAP EXAMPLE + +void show_custom_text() { + // Show use of custom fonts, plus how to do center or right alignment + // using some additional functions provided earlier. + + display.fillScreen(0); + display.setFont(&FreeSansBold18pt7b); + display.setTextSize(1); + display.setTextWrap(false); // Allow text off edges + + // Get "M height" of custom font and move initial base line there: + uint16_t w, h; + int16_t x, y; + display.getTextBounds("M", 0, 0, &x, &y, &w, &h); + // On rounded 240x280 display in tall orientation, "Custom Font" gets + // clipped by top corners. Scoot text down a few pixels in that one case. + if (CORNER_RADIUS && (display.height() == 280)) h += 20; + display.setCursor(display.width() / 2, h); + + if (display.width() >= 200) { + print_aligned(display, F("Custom Font"), GFX_ALIGN_CENTER); + display.setCursor(0, display.getCursorY() + 10); + print_aligned(display, F("Align Left"), GFX_ALIGN_LEFT); + display.setCursor(display.width() / 2, display.getCursorY()); + print_aligned(display, F("Centered"), GFX_ALIGN_CENTER); + // Small rounded screen, when oriented the wide way, "Right" gets + // clipped by bottom right corner. Scoot left to compensate. + int16_t x_offset = (CORNER_RADIUS && (display.height() < 200)) ? 15 : 0; + display.setCursor(display.width() - x_offset, display.getCursorY()); + print_aligned(display, F("Align Right"), GFX_ALIGN_RIGHT); + } else { + // On narrow screens, use abbreviated messages + print_aligned(display, F("Font &"), GFX_ALIGN_CENTER); + print_aligned(display, F("Align"), GFX_ALIGN_CENTER); + display.setCursor(0, display.getCursorY() + 10); + print_aligned(display, F("Left"), GFX_ALIGN_LEFT); + display.setCursor(display.width() / 2, display.getCursorY()); + print_aligned(display, F("Center"), GFX_ALIGN_CENTER); + display.setCursor(display.width(), display.getCursorY()); + print_aligned(display, F("Right"), GFX_ALIGN_RIGHT); + } + + delay(PAUSE); +} // END CUSTOM FONT EXAMPLE + +// BITMAP EXAMPLE ---------------------------------------------------------- + +// This section demonstrates: +// - Embedding a small bitmap in the code (flash memory). +// - Drawing that bitmap in various colors, and transparently (only '1' bits +// are drawn; '0' bits are skipped, leaving screen contents in place). +// - Use of the color565() function to decimate 24-bit RGB to 16 bits. + +#define HEX_WIDTH 16 // Bitmap width in pixels +#define HEX_HEIGHT 16 // Bitmap height in pixels +// Bitmap data. PROGMEM ensures it's in flash memory (not RAM). And while +// it would be valid to leave the brackets empty here (i.e. hex_bitmap[]), +// having dimensions with a little math makes the compiler verify the +// correct number of bytes are present in the list. +PROGMEM const uint8_t hex_bitmap[(HEX_WIDTH + 7) / 8 * HEX_HEIGHT] = { + 0b00000001, 0b10000000, + 0b00000111, 0b11100000, + 0b00011111, 0b11111000, + 0b01111111, 0b11111110, + 0b01111111, 0b11111110, + 0b01111111, 0b11111110, + 0b01111111, 0b11111110, + 0b01111111, 0b11111110, + 0b01111111, 0b11111110, + 0b01111111, 0b11111110, + 0b01111111, 0b11111110, + 0b01111111, 0b11111110, + 0b01111111, 0b11111110, + 0b00011111, 0b11111000, + 0b00000111, 0b11100000, + 0b00000001, 0b10000000, +}; +#define Y_SPACING (HEX_HEIGHT - 2) // Used by code below for positioning + +void show_bitmap() { + display.fillScreen(0); + + // Not screen center, but UL coordinates of center hexagon bitmap + const int16_t center_x = (display.width() - HEX_WIDTH) / 2; + const int16_t center_y = (display.height() - HEX_HEIGHT) / 2; + const uint8_t steps = min((display.height() - HEX_HEIGHT) / Y_SPACING, + display.width() / HEX_WIDTH - 1) / 2; + + display.drawBitmap(center_x, center_y, hex_bitmap, HEX_WIDTH, HEX_HEIGHT, + 0xFFFF); // Draw center hexagon in white + + // Tile the hexagon bitmap repeatedly in a range of hues. Don't mind the + // bit of repetition in the math, the optimizer easily picks this up. + // Also, if math looks odd, keep in mind "PEMDAS" operator precedence; + // multiplication and division occur before addition and subtraction. + for (uint8_t a=0; a<=steps; a++) { + for (uint8_t b=1; b<=steps; b++) { + display.drawBitmap( // Right section centered red: a = green, b = blue + center_x + (a + b) * HEX_WIDTH / 2, + center_y + (a - b) * Y_SPACING, + hex_bitmap, HEX_WIDTH, HEX_HEIGHT, + display.color565(255, 255 - 255 * a / steps, 255 - 255 * b / steps)); + display.drawBitmap( // UL section centered green: a = blue, b = red + center_x - b * HEX_WIDTH + a * HEX_WIDTH / 2, + center_y - a * Y_SPACING, + hex_bitmap, HEX_WIDTH, HEX_HEIGHT, + display.color565(255 - 255 * b / steps, 255, 255 - 255 * a / steps)); + display.drawBitmap( // LL section centered blue: a = red, b = green + center_x - a * HEX_WIDTH + b * HEX_WIDTH / 2, + center_y + b * Y_SPACING, + hex_bitmap, HEX_WIDTH, HEX_HEIGHT, + display.color565(255 - 255 * a / steps, 255 - 255 * b / steps, 255)); + } + } + + delay(PAUSE); +} // END BITMAP EXAMPLE + +// CANVAS EXAMPLE ---------------------------------------------------------- + +// This section demonstrates: +// - How to refresh changing values onscreen without erase/redraw flicker. +// - Using an offscreen canvas. It's similar to a bitmap above, but rather +// than a fixed pattern in flash memory, it's drawable like the screen. +// - More tips on text alignment, and adapting to different screen sizes. + +#define PADDING 6 // Pixels between axis label and value + +void show_canvas() { + // For this example, let's suppose we want to display live readings from a + // sensor such as a three-axis accelerometer, something like: + // X: (number) + // Y: (number) + // Z: (number) + // To look extra classy, we want a custom font, and the labels for each + // axis are right-aligned so the ':' characters line up... + + display.setFont(&FreeSansBold18pt7b); // Use a custom font + display.setTextSize(1); // and reset to 1:1 scale + + char *label[] = { "X:", "Y:", "Z:" }; // Labels for each axis + const uint16_t color[] = { 0xF800, 0x07E0, 0x001F }; // Colors for each value + + // To get the labels right-aligned, one option would be simple trial and + // error to find a column that looks good and doesn't clip anything off. + // Let's do this dynamically though, so it adapts to any font or labels! + // Start by finding the widest of the label strings: + uint16_t w, h, max_w = 0; + int16_t x, y; + for (uint8_t i=0; i<3; i++) { // For each label... + display.getTextBounds(label[i], 0, 0, &x, &y, &w, &h); + if (w > max_w) max_w = w; // Keep track of widest label + } + + // Rounded corners throwing us a curve again. If needed, scoot everything + // to the right a bit on wide displays, down a bit on tall ones. + int16_t y_offset = 0; + if (display.width() > display.height()) max_w += CORNER_RADIUS; + else y_offset = CORNER_RADIUS; + + // Now we have max_w for right-aligning the labels. Before we draw them + // though...in order to perform flicker-free updates, the numbers we show + // will be rendered in either a GFXcanvas1 or GFXcanvas16 object; a 1-bit + // or 16-bit offscreen bitmap, RAM permitting. The correct size for this + // canvas could also be trial-and-errored, but again let's make this adapt + // automatically. The width of the canvas will span from max_w (plus a few + // pixels for padding) to the right edge. But the height? Looking at an + // uppercase 'M' can work in many situations, but some fonts have ascenders + // and descenders on digits, and in some locales a comma (extending below + // the baseline) is the decimal separator. Feed ALL the numeric chars into + // getTextBounds() for a cumulative height: + display.setTextWrap(false); // Keep on one line + display.getTextBounds(F("0123456789.,-"), 0, 0, &x, &y, &w, &h); + + // Now declare a GFXcanvas16 object based on the computed width & height: + GFXcanvas16 canvas16(display.width() - max_w - PADDING, h); + + // Small devices (e.g. ATmega328p) will almost certainly lack enough RAM + // for the canvas. Check if canvas buffer exists. If not, fall back on + // using a 1-bit (rather than 16-bit) canvas. Much more RAM friendly, but + // not as fast to draw. If a project doesn't require super interactive + // updates, consider just going straight for the more compact Canvas1. + if (canvas16.getBuffer()) { + // If here, 16-bit canvas allocated successfully! Point of interest, + // only one canvas is needed for this example, we can reuse it for all + // three numbers because the regions are the same size. + + // display and canvas are independent drawable objects; must explicitly + // set the same custom font to use on the canvas now: + canvas16.setFont(&FreeSansBold18pt7b); + + // Clear display and print labels. Once drawn, these remain untouched. + display.fillScreen(0); + display.setCursor(max_w, -y + y_offset); // Set baseline for first row + for (uint8_t i=0; i<3; i++) print_aligned(display, label[i], GFX_ALIGN_RIGHT); + + // Last part now is to print numbers on the canvas and copy the canvas to + // the display, repeating for several seconds... + uint32_t elapsed, startTime = millis(); + while ((elapsed = (millis() - startTime)) <= PAUSE * 2) { + for (uint8_t i=0; i<3; i++) { // For each label... + canvas16.fillScreen(0); // fillScreen() in this case clears canvas + canvas16.setCursor(0, -y); // Reset baseline for custom font + canvas16.setTextColor(color[i]); + // These aren't real accelerometer readings, just cool-looking numbers. + // Notice we print to the canvas, NOT the display: + canvas16.print(sin(elapsed / 200.0 + (float)i * M_PI * 2.0 / 3.0), 5); + // And HERE is the secret sauce to flicker-free updates. Canvas details + // can be passed to the drawRGBBitmap() function, which fully overwrites + // prior screen contents in that area. yAdvance is font line spacing. + display.drawRGBBitmap(max_w + PADDING, i * FreeSansBold18pt7b.yAdvance + + y_offset, canvas16.getBuffer(), canvas16.width(), + canvas16.height()); + } + } + } else { + // Insufficient RAM for Canvas16. Try declaring a 1-bit canvas instead... + GFXcanvas1 canvas1(display.width() - max_w - PADDING, h); + // If even this smaller object fails, can't proceed, cancel this example. + if (!canvas1.getBuffer()) return; + + // Remainder here is nearly identical to the code above, simply using a + // different canvas type. It's stripped of most comments for brevity. + canvas1.setFont(&FreeSansBold18pt7b); + display.fillScreen(0); + display.setCursor(max_w, -y + y_offset); + for (uint8_t i=0; i<3; i++) print_aligned(display, label[i], GFX_ALIGN_RIGHT); + uint32_t elapsed, startTime = millis(); + while ((elapsed = (millis() - startTime)) <= PAUSE * 2) { + for (uint8_t i=0; i<3; i++) { + canvas1.fillScreen(0); + canvas1.setCursor(0, -y); + canvas1.print(sin(elapsed / 200.0 + (float)i * M_PI * 2.0 / 3.0), 5); + // Here's the secret sauce to flicker-free updates with GFXcanvas1. + // Canvas details can be passed to the drawBitmap() function, and by + // specifying both a foreground AND BACKGROUND color (0), this will fully + // overwrite/erase prior screen contents in that area (vs transparent). + display.drawBitmap(max_w + PADDING, i * FreeSansBold18pt7b.yAdvance + + y_offset, canvas1.getBuffer(), canvas1.width(), + canvas1.height(), color[i], 0); + } + } + } + + // Because canvas object was declared locally to this function, it's freed + // automatically when the function returns; no explicit delete needed. +} // END CANVAS EXAMPLE diff --git a/PiCowbell_HSTX_DVI_Examples/circuitpython/Helvetica-Bold-16.pcf b/PiCowbell_HSTX_DVI_Examples/circuitpython/Helvetica-Bold-16.pcf new file mode 100644 index 000000000..deb9092d1 Binary files /dev/null and b/PiCowbell_HSTX_DVI_Examples/circuitpython/Helvetica-Bold-16.pcf differ diff --git a/PiCowbell_HSTX_DVI_Examples/circuitpython/blinka_computer.bmp b/PiCowbell_HSTX_DVI_Examples/circuitpython/blinka_computer.bmp new file mode 100644 index 000000000..a746387ba Binary files /dev/null and b/PiCowbell_HSTX_DVI_Examples/circuitpython/blinka_computer.bmp differ diff --git a/PiCowbell_HSTX_DVI_Examples/circuitpython/code.py b/PiCowbell_HSTX_DVI_Examples/circuitpython/code.py new file mode 100644 index 000000000..d4c7d3a02 --- /dev/null +++ b/PiCowbell_HSTX_DVI_Examples/circuitpython/code.py @@ -0,0 +1,316 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries +# SPDX-FileCopyrightText: Adapted from Phil B.'s 16bit_hello Arduino Code +# +# SPDX-License-Identifier: MIT + +import gc +import math +from random import randint +import time +import displayio +import vectorio +import terminalio +import supervisor +import simpleio +from setup_display import setup_display +from adafruit_bitmap_font import bitmap_font +from adafruit_display_text import label, wrap_text_to_lines +from adafruit_display_shapes.rect import Rect +from adafruit_display_shapes.circle import Circle +from adafruit_display_shapes.roundrect import RoundRect +from adafruit_display_shapes.triangle import Triangle +from adafruit_display_shapes.line import Line + +setup_display() +display = supervisor.runtime.display + +bitmap = displayio.Bitmap(display.width, display.height, 3) + +red = 0xff0000 +yellow = 0xcccc00 +orange = 0xff5500 +blue = 0x0000ff +pink = 0xff00ff +purple = 0x5500ff +white = 0xffffff +green = 0x00ff00 +aqua = 0x125690 + +palette = displayio.Palette(3) +palette[0] = 0x000000 # black +palette[1] = white +palette[2] = yellow + +palette.make_transparent(0) + +tile_grid = displayio.TileGrid(bitmap, pixel_shader=palette) + +group = displayio.Group() + +def clean_up(group_name): + for _ in range(len(group_name)): + group_name.pop() + gc.collect() + +def show_shapes(): + gc.collect() + cx = int(display.width / 2) + cy = int(display.height / 2) + minor = min(cx, cy) + pad = 5 + size = minor - pad + half = int(size / 2) + rect = Rect(cx - minor, cy - minor, size, size, stroke = 1, fill=red, outline = red) + tri = Triangle(cx + pad, cy - pad, cx + pad + half, cy - minor, + cx + minor - 1, cy - pad, fill=green, outline = green) + circ = Circle(cx - pad - half, cy + pad + half, half, fill=blue, stroke = 1, outline = blue) + rnd = RoundRect(cx + pad, cy + pad, size, size, int(size / 5), stroke = 1, + fill=yellow, outline = yellow) + + group.append(rect) + group.append(tri) + group.append(circ) + group.append(rnd) + rect.fill = None + tri.fill = None + circ.fill = None + rnd.fill = None + + time.sleep(2) + + rect.fill = red + tri.fill = green + circ.fill = blue + rnd.fill = yellow + time.sleep(2) + clean_up(group) + del rect + del tri + del circ + del rnd + gc.collect() + +def sine_chart(): + gc.collect() + cx = int(display.width / 2) + cy = int(display.height / 2) + minor = min(cx, cy) + major = max(cx, cy) + + group.append(Line(cx, 0, cx, display.height, blue)) # v + group.append(Line(0, cy, display.width, cy, blue)) # h + + for i in range(10): + _n = simpleio.map_range(i, 0, 10, 0, major - 1) + n = int(_n) + group.append(Line(cx - n, cy - 5, cx - n, (cy - 5) + 11, blue)) # v + group.append(Line(cx + n, cy - 5, cx + n, (cy - 5) + 11, blue)) # v + group.append(Line(cx - 5, cy - n, (cx - 5) + 11, cy - n, blue)) # h + group.append(Line(cx - 5, cy + n, (cx - 5) + 11, cy + n, blue)) # h + + for x in range(display.width): + y = cy - int(math.sin((x - cx) * 0.05) * float(minor * 0.5)) + bitmap[x, y] = 1 + group.append(tile_grid) + time.sleep(2) + clean_up(group) + +def widget0(): + gc.collect() + data = [31, 42, 36, 58, 67, 88] + num_points = len(data) + + text_area = label.Label(terminalio.FONT, text="Widget Sales", color=white) + text_area.anchor_point = (0.5, 0.0) + text_area.anchored_position = (display.width / 2, 3) + group.append(text_area) + for i in range(11): + _x = simpleio.map_range(i, 0, 10, 0, display.width - 1) + x = int(_x) + group.append(Line(x, 20, x, display.height, blue)) + _y = simpleio.map_range(i, 0, 10, 20, display.height - 1) + y = int(_y) + group.append(Line(0, y, display.width, y, blue)) + prev_x = 0 + _prev_y = simpleio.map_range(data[0], 0, 100, display.height - 1, 20) + prev_y = int(_prev_y) + for i in range(1, num_points): + _new_x = simpleio.map_range(i, 0, num_points - 1, 0, display.width - 1) + new_x = int(_new_x) + _new_y = simpleio.map_range(data[i], 0, 100, display.height - 1, 20) + new_y = int(_new_y) + group.append(Line(prev_x, prev_y, new_x, new_y, aqua)) + prev_x = new_x + prev_y = new_y + + for i in range(num_points): + _x = simpleio.map_range(i, 0, num_points - 1, 0, display.width - 1) + x = int(_x) + _y = simpleio.map_range(data[i], 0, 100, display.height - 1, 20) + y = int(_y) + group.append(Circle(x, y, 5, fill=None, stroke = 2, outline = white)) + + time.sleep(2) + clean_up(group) + +def widget1(): + gc.collect() + data = [31, 42, 36, 58, 67, 88] + num_points = len(data) + bar_width = int(display.width / num_points) - 4 + x_mapped_w = display.width + 2 + h_mapped_h = display.height + 20 + + text_area = label.Label(terminalio.FONT, text="Widget Sales", color=white) + text_area.anchor_point = (0.5, 0.0) + text_area.anchored_position = (display.width / 2, 3) + group.append(text_area) + for i in range(11): + _y = simpleio.map_range(i, 0, 10, 20, display.height - 1) + y = int(_y) + group.append(Line(0, y, display.width, y, blue)) + for i in range(num_points): + _x = simpleio.map_range(i, 0, num_points, 0, x_mapped_w) + x = int(_x) + _height = simpleio.map_range(data[i], 0, 100, h_mapped_h, 0) + height = int(_height) + group.append(vectorio.Rectangle(pixel_shader=palette, width=bar_width, + height=display.height + 1, x=x, y=height, color_index = 2)) + + time.sleep(2) + clean_up(group) + +def text_align(): + gc.collect() + TEXT = "hello world" + + text_area_top_left = label.Label(terminalio.FONT, text=TEXT, color=red) + text_area_top_left.anchor_point = (0.0, 0.0) + text_area_top_left.anchored_position = (0, 0) + + text_area_top_middle = label.Label(terminalio.FONT, text=TEXT, color=orange) + text_area_top_middle.anchor_point = (0.5, 0.0) + text_area_top_middle.anchored_position = (display.width / 2, 0) + + text_area_top_right = label.Label(terminalio.FONT, text=TEXT, color=yellow) + text_area_top_right.anchor_point = (1.0, 0.0) + text_area_top_right.anchored_position = (display.width, 0) + + text_area_middle_left = label.Label(terminalio.FONT, text=TEXT, color=green) + text_area_middle_left.anchor_point = (0.0, 0.5) + text_area_middle_left.anchored_position = (0, display.height / 2) + + text_area_middle_middle = label.Label(terminalio.FONT, text=TEXT, color=aqua) + text_area_middle_middle.anchor_point = (0.5, 0.5) + text_area_middle_middle.anchored_position = (display.width / 2, display.height / 2) + + text_area_middle_right = label.Label(terminalio.FONT, text=TEXT, color=blue) + text_area_middle_right.anchor_point = (1.0, 0.5) + text_area_middle_right.anchored_position = (display.width, display.height / 2) + + text_area_bottom_left = label.Label(terminalio.FONT, text=TEXT, color=purple) + text_area_bottom_left.anchor_point = (0.0, 1.0) + text_area_bottom_left.anchored_position = (0, display.height) + + text_area_bottom_middle = label.Label(terminalio.FONT, text=TEXT, color=pink) + text_area_bottom_middle.anchor_point = (0.5, 1.0) + text_area_bottom_middle.anchored_position = (display.width / 2, display.height) + + text_area_bottom_right = label.Label(terminalio.FONT, text=TEXT, color=white) + text_area_bottom_right.anchor_point = (1.0, 1.0) + text_area_bottom_right.anchored_position = (display.width, display.height) + + group.append(text_area_top_middle) + group.append(text_area_top_left) + group.append(text_area_top_right) + group.append(text_area_middle_middle) + group.append(text_area_middle_left) + group.append(text_area_middle_right) + group.append(text_area_bottom_middle) + group.append(text_area_bottom_left) + group.append(text_area_bottom_right) + + time.sleep(2) + clean_up(group) + +def custom_font(): + gc.collect() + my_font = bitmap_font.load_font("/Helvetica-Bold-16.pcf") + text_sample = "The quick brown fox jumps over the lazy dog." + text_sample = "\n".join(wrap_text_to_lines(text_sample, 28)) + text_area = label.Label(my_font, text="Custom Font", color=white) + text_area.anchor_point = (0.0, 0.0) + text_area.anchored_position = (0, 0) + + sample_text = label.Label(my_font, text=text_sample) + sample_text.anchor_point = (0.5, 0.5) + sample_text.anchored_position = (display.width / 2, display.height / 2) + + group.append(text_area) + group.append(sample_text) + + time.sleep(2) + clean_up(group) + + del my_font + gc.collect() + +def bitmap_example(): + gc.collect() + blinka_bitmap = displayio.OnDiskBitmap("/blinka_computer.bmp") + blinka_grid = displayio.TileGrid(blinka_bitmap, pixel_shader=blinka_bitmap.pixel_shader) + gc.collect() + group.append(blinka_grid) + + time.sleep(2) + clean_up(group) + + del blinka_grid + del blinka_bitmap + gc.collect() + +def sensor_values(): + gc.collect() + text_x = "X: %d" % randint(-25, 25) + text_y = "Y: %d" % randint(-25, 25) + text_z = "Z: %d" % randint(-25, 25) + x_text = label.Label(terminalio.FONT, text=text_x, color=red) + x_text.anchor_point = (0.0, 0.0) + x_text.anchored_position = (2, 0) + y_text = label.Label(terminalio.FONT, text=text_y, color=green) + y_text.anchor_point = (0.0, 0.0) + y_text.anchored_position = (2, 10) + z_text = label.Label(terminalio.FONT, text=text_z, color=blue) + z_text.anchor_point = (0.0, 0.0) + z_text.anchored_position = (2, 20) + group.append(x_text) + group.append(y_text) + group.append(z_text) + + for i in range(40): + if i == 10: + group.scale = 2 + elif i == 20: + group.scale = 3 + elif i == 30: + group.scale = 4 + x_text.text = "X: %d" % randint(-50, 50) + y_text.text = "Y: %d" % randint(-50, 50) + z_text.text = "Z: %d" % randint(-50, 50) + time.sleep(0.1) + time.sleep(0.1) + clean_up(group) + group.scale = 1 + +display.root_group = group + +while True: + show_shapes() + sine_chart() + widget0() + widget1() + text_align() + custom_font() + bitmap_example() + sensor_values() diff --git a/PiCowbell_HSTX_DVI_Examples/circuitpython/setup_display.py b/PiCowbell_HSTX_DVI_Examples/circuitpython/setup_display.py new file mode 100644 index 000000000..ff6baaa62 --- /dev/null +++ b/PiCowbell_HSTX_DVI_Examples/circuitpython/setup_display.py @@ -0,0 +1,24 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import supervisor +import displayio +import picodvi +import framebufferio +import board + +def setup_display(): + # Skip if the display is already initialized + if supervisor.runtime.display is None: + displayio.release_displays() + fb = picodvi.Framebuffer(320, 240, + clk_dp=board.GP14, clk_dn=board.GP15, + red_dp=board.GP12, red_dn=board.GP13, + green_dp=board.GP18, green_dn=board.GP19, + blue_dp=board.GP16, blue_dn=board.GP17, + color_depth=8) + display = framebufferio.FramebufferDisplay(fb) + + # set the display onto supervisor.runtime, + # so it will be available to code.py + supervisor.runtime.display = display diff --git a/Pi_Hole_Ad_Blocker/mini_pitft_stats.py b/Pi_Hole_Ad_Blocker/mini_pitft_stats.py index 3d1349458..68e4576a9 100755 --- a/Pi_Hole_Ad_Blocker/mini_pitft_stats.py +++ b/Pi_Hole_Ad_Blocker/mini_pitft_stats.py @@ -1,7 +1,34 @@ # SPDX-FileCopyrightText: 2019 Brent Rubell for Adafruit Industries +# SPDX-FileCopyrightText: 2025 Mikey Sklar for Adafruit Industries # # SPDX-License-Identifier: MIT +# Copyright (c) 2017 Adafruit Industries +# Author: Brent Rubell, Mikey Sklar +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# This example is for use on (Linux) computers that are using CPython with +# Adafruit Blinka to support CircuitPython libraries. CircuitPython does +# not support PIL/pillow (python imaging library)! + + # -*- coding: utf-8 -*- # Import Python System Libraries import time @@ -19,11 +46,10 @@ from PIL import Image, ImageDraw, ImageFont import adafruit_rgb_display.st7789 as st7789 -API_TOKEN = "YOUR_API_TOKEN_HERE" -api_url = "http://localhost/admin/api.php?summaryRaw&auth="+API_TOKEN +API_URL = "http://localhost/api/stats/summary" # Configuration for CS and DC pins (these are FeatherWing defaults on M0/M4): -cs_pin = digitalio.DigitalInOut(board.CE0) +cs_pin = digitalio.DigitalInOut(board.D17) dc_pin = digitalio.DigitalInOut(board.D25) reset_pin = None @@ -34,54 +60,42 @@ spi = board.SPI() # Create the ST7789 display: -disp = st7789.ST7789(spi, cs=cs_pin, dc=dc_pin, rst=reset_pin, baudrate=BAUDRATE, - width=135, height=240, x_offset=53, y_offset=40) +disp = st7789.ST7789( + spi, + dc_pin, + cs_pin, + reset_pin, + 135, + 240, + baudrate=BAUDRATE, + x_offset=53, + y_offset=40, + rotation=90 +) # Create blank image for drawing. # Make sure to create image with mode 'RGB' for full color. -height = disp.width # we swap height/width to rotate it to landscape! -width = disp.height -image = Image.new('RGB', (width, height)) -rotation = 90 - -# Get drawing object to draw on image. +CANVAS_WIDTH = disp.height +CANVAS_HEIGHT = disp.width +image = Image.new('RGB', (CANVAS_WIDTH, CANVAS_HEIGHT)) draw = ImageDraw.Draw(image) -# Draw a black filled box to clear the image. -draw.rectangle((0, 0, width, height), outline=0, fill=(0, 0, 0)) -disp.image(image, rotation) -# Draw some shapes. -# First define some constants to allow easy resizing of shapes. -padding = -2 -top = padding -bottom = height-padding -# Move left to right keeping track of the current x position for drawing shapes. -x = 0 - - -# Alternatively load a TTF font. Make sure the .ttf font file is in the -# same directory as the python script! -# Some other nice fonts to try: http://www.dafont.com/bitmap.php -font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 24) - -# Turn on the backlight -backlight = digitalio.DigitalInOut(board.D22) -backlight.switch_to_output() -backlight.value = True - -# Add buttons as inputs +# Load default font (or replace with a TTF if desired) +FONT_PATH = "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf" +font = ImageFont.truetype(FONT_PATH, 24) + buttonA = digitalio.DigitalInOut(board.D23) buttonA.switch_to_input() while True: # Draw a black filled box to clear the image. - draw.rectangle((0, 0, width, height), outline=0, fill=0) + draw.rectangle((0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), outline=0, fill=(0, 0, 0)) # Shell scripts for system monitoring from here: # https://unix.stackexchange.com/questions/119126/command-to-display-memory-usage-disk-usage-and-cpu-load - cmd = "hostname -I | cut -d\' \' -f1" - IP = "IP: "+subprocess.check_output(cmd, shell=True).decode("utf-8") - cmd = "hostname | tr -d \'\\n\'" + cmd = "hostname -I | cut -d' ' -f1" + IP = "IP: " + subprocess.check_output(cmd, shell=True).decode("utf-8").strip() + cmd = "hostname | tr -d '\\n'" HOST = subprocess.check_output(cmd, shell=True).decode("utf-8") cmd = "top -bn1 | grep load | awk '{printf \"CPU Load: %.2f\", $(NF-2)}'" CPU = subprocess.check_output(cmd, shell=True).decode("utf-8") @@ -89,22 +103,27 @@ MemUsage = subprocess.check_output(cmd, shell=True).decode("utf-8") cmd = "df -h | awk '$NF==\"/\"{printf \"Disk: %d/%d GB %s\", $3,$2,$5}'" Disk = subprocess.check_output(cmd, shell=True).decode("utf-8") - cmd = "cat /sys/class/thermal/thermal_zone0/temp | awk \'{printf \"CPU Temp: %.1f C\", $(NF-0) / 1000}\'" # pylint: disable=line-too-long + cmd = ( + "cat /sys/class/thermal/thermal_zone0/temp | " + "awk '{printf \"CPU Temp: %.1f C\", $(NF-0) / 1000}'" + ) Temp = subprocess.check_output(cmd, shell=True).decode("utf-8") - # Pi Hole data! try: - r = requests.get(api_url) - data = json.loads(r.text) - DNSQUERIES = data['dns_queries_today'] - ADSBLOCKED = data['ads_blocked_today'] - CLIENTS = data['unique_clients'] - except KeyError: - time.sleep(1) - continue - - y = top + r = requests.get(API_URL, timeout=5) + r.raise_for_status() + data = r.json() + DNSQUERIES = data["queries"]["total"] + ADSBLOCKED = data["queries"]["blocked"] + CLIENTS = data["clients"]["total"] + except (KeyError, requests.RequestException, json.JSONDecodeError): + DNSQUERIES = None + ADSBLOCKED = None + CLIENTS = None + + y = top = 5 + x = 5 if not buttonA.value: # just button A pressed draw.text((x, y), IP, font=font, fill="#FFFF00") y += font.getbbox(IP)[3] @@ -121,13 +140,19 @@ y += font.getbbox(IP)[3] draw.text((x, y), HOST, font=font, fill="#FFFF00") y += font.getbbox(HOST)[3] - draw.text((x, y), "Ads Blocked: {}".format(str(ADSBLOCKED)), font=font, fill="#00FF00") - y += font.getbbox(str(ADSBLOCKED))[3] - draw.text((x, y), "Clients: {}".format(str(CLIENTS)), font=font, fill="#0000FF") - y += font.getbbox(str(CLIENTS))[3] - draw.text((x, y), "DNS Queries: {}".format(str(DNSQUERIES)), font=font, fill="#FF00FF") - y += font.getbbox(str(DNSQUERIES))[3] + if ADSBLOCKED is not None: + txt = f"Ads Blocked: {ADSBLOCKED}" + draw.text((x, y), txt, font=font, fill="#00FF00") + y += font.getbbox(txt)[3] + if CLIENTS is not None: + txt = f"Clients: {CLIENTS}" + draw.text((x, y), txt, font=font, fill="#0000FF") + y += font.getbbox(txt)[3] + if DNSQUERIES is not None: + txt = f"DNS Queries: {DNSQUERIES}" + draw.text((x, y), txt, font=font, fill="#FF00FF") + y += font.getbbox(txt)[3] # Display image. - disp.image(image, rotation) + disp.image(image) time.sleep(.1) diff --git a/Pi_Hole_Ad_Blocker/stats.py b/Pi_Hole_Ad_Blocker/stats.py index d1021ba68..25e093404 100644 --- a/Pi_Hole_Ad_Blocker/stats.py +++ b/Pi_Hole_Ad_Blocker/stats.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2017 Limor Fried for Adafruit Industries # SPDX-FileCopyrightText: 2017 Tony DiCola for Adafruit Industries # SPDX-FileCopyrightText: 2017 James DeVito for Adafruit Industries +# SPDX-FileCopyrightText: 2025 Mikey Sklar for Adafruit Industries # # SPDX-License-Identifier: MIT @@ -29,44 +30,33 @@ # Adafruit Blinka to support CircuitPython libraries. CircuitPython does # not support PIL/pillow (python imaging library)! -# Import Python System Libraries -import json + import subprocess import time -# Import Requests Library import requests - -# Import Blinka from board import SCL, SDA import busio import adafruit_ssd1306 - -# Import Python Imaging Library from PIL import Image, ImageDraw, ImageFont -API_TOKEN = "YOUR_API_TOKEN_HERE" -api_url = "http://localhost/admin/api.php?summaryRaw&auth="+API_TOKEN +api_url = "http://localhost/api/stats/summary" # Create the I2C interface. i2c = busio.I2C(SCL, SDA) # Create the SSD1306 OLED class. -# The first two parameters are the pixel width and pixel height. Change these -# to the right size for your display! disp = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c) # Leaving the OLED on for a long period of time can damage it -# Set these to prevent OLED burn in -DISPLAY_ON = 10 # on time in seconds -DISPLAY_OFF = 50 # off time in seconds +DISPLAY_ON = 10 # on time in seconds +DISPLAY_OFF = 50 # off time in seconds # Clear display. disp.fill(0) disp.show() # Create blank image for drawing. -# Make sure to create image with mode '1' for 1-bit color. width = disp.width height = disp.height image = Image.new('1', (width, height)) @@ -77,27 +67,21 @@ # Draw a black filled box to clear the image. draw.rectangle((0, 0, width, height), outline=0, fill=0) -# Draw some shapes. -# First define some constants to allow easy resizing of shapes. padding = -2 top = padding -bottom = height - padding -# Move left to right keeping track of the current x position -# for drawing shapes. x = 0 # Load nice silkscreen font font = ImageFont.truetype('/home/pi/slkscr.ttf', 8) while True: - # Draw a black filled box to clear the image. + # Clear the image buffer draw.rectangle((0, 0, width, height), outline=0, fill=0) - # Shell scripts for system monitoring from here : - # https://unix.stackexchange.com/questions/119126/command-to-display-memory-usage-disk-usage-and-cpu-load - cmd = "hostname -I | cut -d\' \' -f1 | tr -d \'\\n\'" + # Shell scripts for system monitoring + cmd = "hostname -I | cut -d' ' -f1 | tr -d '\\n'" IP = subprocess.check_output(cmd, shell=True).decode("utf-8") - cmd = "hostname | tr -d \'\\n\'" + cmd = "hostname | tr -d '\\n'" HOST = subprocess.check_output(cmd, shell=True).decode("utf-8") cmd = "top -bn1 | grep load | awk " \ "'{printf \"CPU Load: %.2f\", $(NF-2)}'" @@ -109,35 +93,30 @@ "\"Disk: %d/%dGB %s\", $3,$2,$5}'" Disk = subprocess.check_output(cmd, shell=True).decode("utf-8") - # Pi Hole data! + # Pi-Hole data! try: - r = requests.get(api_url) - data = json.loads(r.text) - DNSQUERIES = data['dns_queries_today'] - ADSBLOCKED = data['ads_blocked_today'] - CLIENTS = data['unique_clients'] - except KeyError: - time.sleep(1) - continue - - draw.text((x, top), "IP: " + str(IP) + - " (" + HOST + ")", font=font, fill=255) - draw.text((x, top + 8), "Ads Blocked: " + - str(ADSBLOCKED), font=font, fill=255) - draw.text((x, top + 16), "Clients: " + - str(CLIENTS), font=font, fill=255) - draw.text((x, top + 24), "DNS Queries: " + - str(DNSQUERIES), font=font, fill=255) - - # skip over original stats - # draw.text((x, top+8), str(CPU), font=font, fill=255) - # draw.text((x, top+16), str(MemUsage), font=font, fill=255) - # draw.text((x, top+25), str(Disk), font=font, fill=255) + r = requests.get(api_url, timeout=2) + r.raise_for_status() + data = r.json() + DNSQUERIES = data["queries"]["total"] + ADSBLOCKED = data["queries"]["blocked"] + CLIENTS = data["clients"]["total"] + except (KeyError, requests.RequestException): + DNSQUERIES = 0 + ADSBLOCKED = 0 + CLIENTS = 0 + + draw.text((x, top), "IP: " + IP + " (" + HOST + ")", font=font, fill=255) + draw.text((x, top + 8), "Ads Blocked: " + str(ADSBLOCKED), font=font, fill=255) + draw.text((x, top + 16), "Clients: " + str(CLIENTS), font=font, fill=255) + draw.text((x, top + 24), "DNS Queries: " + str(DNSQUERIES), font=font, fill=255) # Display image. disp.image(image) disp.show() time.sleep(DISPLAY_ON) + + # Blank screen to prevent burn-in disp.fill(0) disp.show() time.sleep(DISPLAY_OFF) diff --git a/Pi_In_Stock_Notifier/code.py b/Pi_In_Stock_Notifier/code.py index 8d8f13f26..15006136b 100644 --- a/Pi_In_Stock_Notifier/code.py +++ b/Pi_In_Stock_Notifier/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import ssl import wifi @@ -14,6 +15,21 @@ from digitalio import DigitalInOut, Direction, Pull from adafruit_debouncer import Debouncer +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + alarm_out = DigitalInOut(board.A1) alarm_out.direction = Direction.OUTPUT alarm_out.value = False @@ -23,37 +39,28 @@ button = Debouncer(button_in) -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise - print("Adafruit Raspberry Pi In Stock Tweet Listener") # import your bearer token -bear = secrets['bearer_token'] +bearer_token = getenv('bearer_token') # query URL for tweets. looking for hashtag partyparrot sent to a specific username # disabling line-too-long because queries for tweet_query & TIME_URL cannot have line breaks # pylint: disable=line-too-long tweet_query = 'https://api.twitter.com/2/tweets/search/recent?query=In Stock at Adafruit from:rpilocator&tweet.fields=created_at' -headers = {'Authorization': 'Bearer ' + bear} +headers = {'Authorization': 'Bearer ' + bearer_token} -print("Connecting to %s"%secrets["ssid"]) -wifi.radio.connect(secrets["ssid"], secrets["password"]) -print("Connected to %s!"%secrets["ssid"]) -print("My IP address is", wifi.radio.ipv4_address) +print(f"Connecting to {ssid}") +wifi.radio.connect(ssid, password) +print(f"Connected to {ssid}!") +print(f"My IP address is {wifi.radio.ipv4_address}") pool = socketpool.SocketPool(wifi.radio) requests = adafruit_requests.Session(pool, ssl.create_default_context()) # gets and formats time from adafruit.io -aio_username = secrets["aio_username"] -aio_key = secrets["aio_key"] -location = secrets.get("timezone", None) +location = getenv("timezone", None) TIME_URL = "https://io.adafruit.com/api/v2/%s/integrations/time/strftime?x-aio-key=%s" % (aio_username, aio_key) TIME_URL += "&fmt=%25Y-%25m-%25dT%25H%3A%25M%3A%25S.%25L%25j%25u%25z%25Z" @@ -132,7 +139,7 @@ else: # if it's not new, then the wait continues - no_tweet_text = ("No stock in last hour :( Last stock: %s" % (timestamp)) + no_tweet_text = "No stock in last hour :( Last stock: %s" % (timestamp) text_area.text = "\n".join(wrap_text_to_lines(no_tweet_text, 21)) print("no new in stock notifications :(") # updates tweet ID @@ -140,6 +147,6 @@ # if the tweet wasn't today else: # if it's not new, then the wait continues - no_tweet_text = ("No stock in last hour :( Last stock: %s" % (timestamp)) + no_tweet_text = "No stock in last hour :( Last stock: %s" % (timestamp) text_area.text = "\n".join(wrap_text_to_lines(no_tweet_text, 21)) print("no new in stock notifications :(") diff --git a/Pi_SSD_Media_Server/display-info.py b/Pi_SSD_Media_Server/display-info.py index 41aee65ac..6b49f4e7f 100755 --- a/Pi_SSD_Media_Server/display-info.py +++ b/Pi_SSD_Media_Server/display-info.py @@ -4,6 +4,7 @@ import subprocess import board import displayio +import fourwire from adafruit_display_text import label from adafruit_bitmap_font import bitmap_font from adafruit_st7789 import ST7789 @@ -23,7 +24,7 @@ tft_dc = board.D25 tft_rst = board.D24 -display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_rst) +display_bus = fourwire.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_rst) display = ST7789(display_bus, width=320, height=170, colstart=35, rotation=270) diff --git a/PicoW_CircuitPython_HTTP_Server/code.py b/PicoW_CircuitPython_HTTP_Server/code.py index d56ca7205..746270e2d 100644 --- a/PicoW_CircuitPython_HTTP_Server/code.py +++ b/PicoW_CircuitPython_HTTP_Server/code.py @@ -11,6 +11,7 @@ import board import microcontroller import displayio +import i2cdisplaybus import terminalio from adafruit_display_text import label import adafruit_displayio_ssd1306 @@ -36,7 +37,7 @@ # scan for temp sensor ds18 = DS18X20(ow_bus, ow_bus.scan()[0]) -# function to convert celcius to fahrenheit +# function to convert celsius to fahrenheit def c_to_f(temp): temp_f = (temp * 9/5) + 32 return temp_f @@ -47,7 +48,7 @@ def c_to_f(temp): # STEMMA I2C on picowbell i2c = busio.I2C(board.GP5, board.GP4) -display_bus = displayio.I2CDisplay(i2c, device_address=0x3D, reset=oled_reset) +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3D, reset=oled_reset) WIDTH = 128 HEIGHT = 64 diff --git a/Pico_MIDI_Fighter/code.py b/Pico_MIDI_Fighter/code.py index 51ecff4f3..88ca4cf8b 100644 --- a/Pico_MIDI_Fighter/code.py +++ b/Pico_MIDI_Fighter/code.py @@ -4,6 +4,7 @@ import time import board +import i2cdisplaybus import displayio import terminalio import adafruit_aw9523 @@ -23,7 +24,7 @@ # i2c setup, higher frequency for display refresh i2c = busio.I2C(board.GP1, board.GP0, frequency=1000000) # i2c display setup -display_bus = displayio.I2CDisplay(i2c, device_address=0x3D) +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3D) # i2c AW9523 GPIO expander setup aw = adafruit_aw9523.AW9523(i2c) # MIDI setup as MIDI out device diff --git a/Pico_W_CircuitPython_WiFi_Examples/Pico_W_Adafruit_IO/code.py b/Pico_W_CircuitPython_WiFi_Examples/Pico_W_Adafruit_IO/code.py index 91d535665..2aba104fb 100644 --- a/Pico_W_CircuitPython_WiFi_Examples/Pico_W_Adafruit_IO/code.py +++ b/Pico_W_CircuitPython_WiFi_Examples/Pico_W_Adafruit_IO/code.py @@ -13,10 +13,18 @@ import adafruit_ahtx0 from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError -wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD')) +try: + wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD')) +except TypeError: + print("Could not find WiFi info. Check your settings.toml file!") + raise -aio_username = os.getenv('aio_username') -aio_key = os.getenv('aio_key') +try: + aio_username = os.getenv('ADAFRUIT_AIO_USERNAME') + aio_key = os.getenv('ADAFRUIT_AIO_KEY') +except TypeError: + print("Could not find Adafruit IO info. Check your settings.toml file!") + raise pool = socketpool.SocketPool(wifi.radio) requests = adafruit_requests.Session(pool, ssl.create_default_context()) diff --git a/Pico_W_CircuitPython_WiFi_Examples/Pico_W_Azure_IoT_Central/code.py b/Pico_W_CircuitPython_WiFi_Examples/Pico_W_Azure_IoT_Central/code.py index e59fef060..3f93762d3 100644 --- a/Pico_W_CircuitPython_WiFi_Examples/Pico_W_Azure_IoT_Central/code.py +++ b/Pico_W_CircuitPython_WiFi_Examples/Pico_W_Azure_IoT_Central/code.py @@ -19,7 +19,11 @@ aht20 = adafruit_ahtx0.AHTx0(i2c) print("Connecting to WiFi...") -wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD')) +try: + wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD')) +except TypeError: + print("Could not find WiFi info. Check your settings.toml file!") + raise print("Connected to WiFi!") @@ -38,9 +42,13 @@ # Create an IoT Hub device client and connect esp = None pool = socketpool.SocketPool(wifi.radio) -device = IoTCentralDevice( - pool, esp, os.getenv('id_scope'), os.getenv('device_id'), os.getenv('device_primary_key') -) +try: + device = IoTCentralDevice( + pool, esp, os.getenv('id_scope'), os.getenv('device_id'), os.getenv('device_primary_key') + ) +except TypeError: + print("Could not find Azure IoT info. Check your settings.toml file!") + raise print("Connecting to Azure IoT Central...") diff --git a/Pico_W_CircuitPython_WiFi_Examples/Pico_W_Basic_WiFi_Test/code.py b/Pico_W_CircuitPython_WiFi_Examples/Pico_W_Basic_WiFi_Test/code.py index 53992c0da..f62b2a6df 100644 --- a/Pico_W_CircuitPython_WiFi_Examples/Pico_W_Basic_WiFi_Test/code.py +++ b/Pico_W_CircuitPython_WiFi_Examples/Pico_W_Basic_WiFi_Test/code.py @@ -2,16 +2,32 @@ # # SPDX-License-Identifier: MIT -import os +from os import getenv import ipaddress import wifi import socketpool +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) + print() print("Connecting to WiFi") # connect to your SSID -wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD')) +try: + wifi.radio.connect(ssid, password) +except TypeError: + print("Could not find WiFi info. Check your settings.toml file!") + raise print("Connected to WiFi") @@ -21,7 +37,7 @@ print("My MAC addr:", [hex(i) for i in wifi.radio.mac_address]) # prints IP address to REPL -print("My IP address is", wifi.radio.ipv4_address) +print(f"My IP address is {wifi.radio.ipv4_address}") # pings Google ipv4 = ipaddress.ip_address("8.8.4.4") diff --git a/Pico_W_CircuitPython_WiFi_Examples/Pico_W_JSON_Feed/code.py b/Pico_W_CircuitPython_WiFi_Examples/Pico_W_JSON_Feed/code.py index e70db1f79..65c0eb8b4 100644 --- a/Pico_W_CircuitPython_WiFi_Examples/Pico_W_JSON_Feed/code.py +++ b/Pico_W_CircuitPython_WiFi_Examples/Pico_W_JSON_Feed/code.py @@ -10,15 +10,23 @@ import microcontroller import adafruit_requests -wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD')) +try: + wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD')) +except TypeError: + print("Could not find WiFi info. Check your settings.toml file!") + raise # Use cityname, country code where countrycode is ISO3166 format. # E.g. "New York, US" or "London, GB" location = "Manhattan, US" # openweathermap URL, brings in your location & your token -url = "http://api.openweathermap.org/data/2.5/weather?q="+location -url += "&appid="+os.getenv('openweather_token') +try: + url = "http://api.openweathermap.org/data/2.5/weather?q="+location + url += "&appid="+os.getenv('openweather_token') +except TypeError: + print("Could not find OpenWeatherMap token. Check your settings.toml file!") + raise pool = socketpool.SocketPool(wifi.radio) requests = adafruit_requests.Session(pool, ssl.create_default_context()) diff --git a/Pico_W_CircuitPython_WiFi_Examples/Pico_W_Requests/code.py b/Pico_W_CircuitPython_WiFi_Examples/Pico_W_Requests/code.py index 232326c80..c26c5a8d2 100644 --- a/Pico_W_CircuitPython_WiFi_Examples/Pico_W_Requests/code.py +++ b/Pico_W_CircuitPython_WiFi_Examples/Pico_W_Requests/code.py @@ -14,7 +14,11 @@ quotes_url = "https://www.adafruit.com/api/quotes.php" # connect to SSID -wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD')) +try: + wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD')) +except TypeError: + print("Could not find WiFi info. Check your settings.toml file!") + raise pool = socketpool.SocketPool(wifi.radio) requests = adafruit_requests.Session(pool, ssl.create_default_context()) diff --git a/PipBoy_2040/code.py b/PipBoy_2040/code.py index 997875c08..7249fb84d 100644 --- a/PipBoy_2040/code.py +++ b/PipBoy_2040/code.py @@ -4,6 +4,7 @@ import board from adafruit_simplemath import map_range import displayio +import fourwire from adafruit_seesaw.seesaw import Seesaw import adafruit_imageload from adafruit_st7789 import ST7789 @@ -17,7 +18,7 @@ spi = board.SPI() # setup for display over SPI tft_cs = board.D5 tft_dc = board.D6 -display_bus = displayio.FourWire( +display_bus = fourwire.FourWire( spi, command=tft_dc, chip_select=tft_cs, reset=board.D9 ) diff --git a/Plotting_Offline_Data/Offline_Data.ipynb b/Plotting_Offline_Data/Offline_Data.ipynb new file mode 100644 index 000000000..258767781 --- /dev/null +++ b/Plotting_Offline_Data/Offline_Data.ipynb @@ -0,0 +1,8007 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ed1eb34b-22bb-4fc7-8810-4f247a78f95d", + "metadata": {}, + "source": [ + "### Offline data logging - JSONL data wrangling and plotting\n", + "\n", + "Upload your data file using the file browser on the left hand side, then update the variable below called `log_file_path` to match your uploaded filename (including file extension).\n", + "\n", + "Use the play button to run the currently selected cell (and move on to the next), or try the fast forward button to restart the kernel and then run all code cells." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "f4161c1e-594a-45b4-83b1-6634fc4cbf63", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " i2c_address timestamp value si_unit pin\n", + "0 0x18 1742475983 78.12500 F NaN\n", + "1 0x18 1742475983 25.62500 C NaN\n", + "2 0x44 1742475984 30.02556 C NaN\n", + "3 0x44 1742475984 86.07004 F NaN\n", + "4 0x44 1742475984 31.18029 % NaN\n", + "5 NaN 1742476007 28.69000 C D13\n", + "6 NaN 1742476007 83.64000 F D13\n", + "7 NaN 1742476008 26.06000 C D14\n", + "8 NaN 1742476008 78.91000 F D14\n", + "9 0x18 1742476014 78.01250 F NaN\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "import json\n", + "import os\n", + "records = None\n", + "# Path to your log file, update and comment out `records` beneath\n", + "log_file_path = 'log_1742475983.log' # Replace with your actual file path\n", + "\n", + "## Example dataset, comment out or delete to instead load log_file_path\n", + "# records = [\n", + "# {\"i2c_address\":\"0x18\",\"timestamp\":1742475983,\"value\":78.125,\"si_unit\":\"F\"},\n", + "# {\"i2c_address\":\"0x18\",\"timestamp\":1742475983,\"value\":25.625,\"si_unit\":\"C\"},\n", + "# {\"i2c_address\":\"0x44\",\"timestamp\":1742475984,\"value\":30.02556,\"si_unit\":\"C\"},\n", + "# {\"i2c_address\":\"0x44\",\"timestamp\":1742475984,\"value\":86.07004,\"si_unit\":\"F\"},\n", + "# {\"i2c_address\":\"0x44\",\"timestamp\":1742475984,\"value\":31.18029,\"si_unit\":\"%\"},\n", + "# {\"timestamp\":1742476007,\"pin\":\"D13\",\"value\":28.69,\"si_unit\":\"C\"},\n", + "# {\"timestamp\":1742476007,\"pin\":\"D13\",\"value\":83.64,\"si_unit\":\"F\"},\n", + "# {\"timestamp\":1742476008,\"pin\":\"D14\",\"value\":26.06,\"si_unit\":\"C\"},\n", + "# {\"timestamp\":1742476008,\"pin\":\"D14\",\"value\":78.91,\"si_unit\":\"F\"},\n", + "# {\"i2c_address\":\"0x18\",\"timestamp\":1742476014,\"value\":78.0125,\"si_unit\":\"F\"},\n", + "# {\"i2c_address\":\"0x18\",\"timestamp\":1742476014,\"value\":25.5625,\"si_unit\":\"C\"},\n", + "# {\"i2c_address\":\"0x44\",\"timestamp\":1742476014,\"value\":30.03891,\"si_unit\":\"C\"},\n", + "# {\"i2c_address\":\"0x44\",\"timestamp\":1742476014,\"value\":86.09407,\"si_unit\":\"F\"},\n", + "# {\"i2c_address\":\"0x44\",\"timestamp\":1742476014,\"value\":31.02464,\"si_unit\":\"%\"},\n", + "# {\"timestamp\":1742476038,\"pin\":\"D13\",\"value\":28.75,\"si_unit\":\"C\"},\n", + "# {\"timestamp\":1742476038,\"pin\":\"D13\",\"value\":83.75,\"si_unit\":\"F\"},\n", + "# {\"timestamp\":1742476039,\"pin\":\"D14\",\"value\":26.06,\"si_unit\":\"C\"},\n", + "# {\"timestamp\":1742476039,\"pin\":\"D14\",\"value\":78.91,\"si_unit\":\"F\"}\n", + "# ]\n", + "\n", + "# If not using fake data above, then load from file:\n", + "if records is None:\n", + " # Read the JSONL file\n", + " records = []\n", + " with open(log_file_path, 'r') as file:\n", + " for (i,line) in enumerate(file):\n", + " try:\n", + " # Parse each line as JSON to avoid any erroneous lines\n", + " record = json.loads(line.strip())\n", + " records.append(record)\n", + " except json.JSONDecodeError:\n", + " # Skip lines that aren't valid JSON\n", + " print(f\"Skipping invalid JSON line #{i}: {line[:50]}...\")\n", + " continue\n", + "\n", + "\n", + "# Create DataFrame from the records\n", + "df = pd.DataFrame(records)\n", + "\n", + "# Display the first 10 rows to verify\n", + "print(df.head(10))" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "ce6ab50b-dcab-433b-afda-c8ff95296d87", + "metadata": {}, + "outputs": [], + "source": [ + "# In this optional step, we add the component names from config.json\n", + "\n", + "config_file_path = 'config.json' # Replace with your actual config file path\n", + "selected_columns = []\n", + "\n", + "# 2. Load the config.json file if exists, otherwise do nothing\n", + "if os.path.exists(config_file_path):\n", + " with open(config_file_path, 'r') as config_file:\n", + " config = json.load(config_file)\n", + " \n", + " # 3. Create mapping dictionaries for I2C addresses and pins to component names\n", + " i2c_to_component = {}\n", + " pin_to_component = {}\n", + " \n", + " # Assuming config has a \"components\" section with entries containing \"i2c_address\" or \"pin\"\n", + " for component_info in config.get('components', []):\n", + " address = \"\"\n", + " component_name = component_info[\"name\"]\n", + " # Handle I2C addresses\n", + " if 'i2cDeviceAddress' in component_info:\n", + " # If there is an alternate set of bus pins, and/or mux then add that too\n", + " if 'i2cBusScl' in component_info:\n", + " address = f\"scl{component_info['i2cBusScl']}\"\n", + " if 'i2cBusSda' in component_info:\n", + " address = address + f\"sda{component_info['i2cBusSda']}_\"\n", + " if 'i2cMuxAddress' in component_info and 'i2cMuxChannel' in component_info:\n", + " address = address + \\\n", + " f\"mux{component_info['i2cMuxAddress']}ch{component_info['i2cMuxChannel']}_\" \n", + " # Convert to lowercase string for consistent matching\n", + " address = address + str(component_info['i2cDeviceAddress']).lower()\n", + " \n", + " i2c_to_component[address] = component_name\n", + "\n", + " # Handle pins\n", + " if 'pinName' in component_info:\n", + " pin = str(component_info['pinName'])\n", + " pin_to_component[pin] = component_name\n", + " \n", + " # 4. Create a function to map addresses/pins to component names\n", + " def get_component_name(row): \n", + " address = '' \n", + " # print(f\"About to return row:\\n**********************\\n{row}\\n***********************\")\n", + " if 'i2c_address' in row and not pd.isnull(row['i2c_address']):\n", + " if 'i2c_bus_scl' in row and not pd.isnull(row['i2c_bus_scl']):\n", + " address = f\"scl{row['i2c_bus_scl']}\"\n", + " if 'i2c_bus_sda' in row and not pd.isnull(row['i2c_bus_sda']):\n", + " address = address + f\"sda{row['i2c_bus_sda']}_\"\n", + " if 'i2c_mux_address' in row and 'i2c_mux_channel' in row:\n", + " address = address + \\\n", + " f\"mux{row['i2c_mux_address']}ch{row['i2c_mux_channel']}_\"\n", + " # Convert address to lowercase string for consistent matching\n", + " address = address + str(row['i2c_address']).lower()\n", + " \n", + " # print(f\"component addr {i2c_to_component[address]} ({address})\")\n", + " if address in i2c_to_component:\n", + " return f\"{i2c_to_component[address]} ({address})\"\n", + "\n", + " if 'pin' in row and not pd.isnull(row['pin']):\n", + " pin = str(row['pin'])\n", + " if pin in pin_to_component:\n", + " # print(f\"component addr {pin_to_component[pin]} ({row['pin']})\")\n", + " return f\"{pin_to_component[pin]} ({row['pin']})\"\n", + " return 'Unknown' # Default if no match found\n", + "\n", + "\n", + " # 5. Apply the function to create the new column\n", + " df['component_name'] = df.apply(get_component_name, axis=1)\n", + " \n", + " # Display the result\n", + " selected_columns = [\"component_name\",\"timestamp\",\"value\",\"si_unit\"]\n", + " print(df[selected_columns].head(10))" + ] + }, + { + "cell_type": "markdown", + "id": "586907df-bbb9-49b9-a2c6-77e7c6fc7802", + "metadata": {}, + "source": [ + "Here we confirm if we are using the component names and addresses from the `config.json` file, or just a column of automatically concatenated pin and i2c address information as a name." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "8eaa64dd-0428-4469-b9b9-7e0b7c62c5cd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "No component names added, using concatenation of I2C Address and Pin\n" + ] + } + ], + "source": [ + "if not selected_columns:\n", + " print(\"No component names added, using concatenation of I2C Address and Pin\")\n", + " df[\"component_name\"] = (\n", + " (f'scl{df[\"i2c_bus_scl\"].fillna(\"\").astype(str)}' if \"i2c_bus_scl\" in df.columns else \"\") +\n", + " (f'sda{df[\"i2c_bus_sda\"].fillna(\"\").astype(str)}_' if \"i2c_bus_sda\" in df.columns else \"\") + \n", + " (f'mux{df[\"i2c_mux_address\"].fillna(\"\").astype(str)}' if \"i2c_mux_address\" in df.columns else \"\") +\n", + " (f'ch{df[\"i2c_mux_channel\"].fillna(\"\").astype(str)}_' if \"i2c_mux_channel\" in df.columns else \"\") +\n", + " (df[\"i2c_address\"].fillna(\"\").astype(str) if \"i2c_address\" in df.columns and not df[\"i2c_address\"].empty else \"\") + \n", + " (df[\"pin\"].fillna(\"\") if \"pin\" in df.columns and not df[\"pin\"].empty else \"\")\n", + " )\n", + "else:\n", + " print(\"Using component_name column generated from config.json\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "01818fe6-8fa1-4a96-ada4-ccac8918a009", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " i2c_address timestamp value si_unit pin component_name \\\n", + "0 0x18 1742475983 78.12500 F NaN 0x18 \n", + "1 0x18 1742475983 25.62500 C NaN 0x18 \n", + "2 0x44 1742475984 30.02556 C NaN 0x44 \n", + "3 0x44 1742475984 86.07004 F NaN 0x44 \n", + "4 0x44 1742475984 31.18029 % NaN 0x44 \n", + "5 NaN 1742476007 28.69000 C D13 D13 \n", + "6 NaN 1742476007 83.64000 F D13 D13 \n", + "7 NaN 1742476008 26.06000 C D14 D14 \n", + "8 NaN 1742476008 78.91000 F D14 D14 \n", + "9 0x18 1742476014 78.01250 F NaN 0x18 \n", + "\n", + " DateTime \n", + "0 2025-03-20 13:06:23 \n", + "1 2025-03-20 13:06:23 \n", + "2 2025-03-20 13:06:24 \n", + "3 2025-03-20 13:06:24 \n", + "4 2025-03-20 13:06:24 \n", + "5 2025-03-20 13:06:47 \n", + "6 2025-03-20 13:06:47 \n", + "7 2025-03-20 13:06:48 \n", + "8 2025-03-20 13:06:48 \n", + "9 2025-03-20 13:06:54 \n" + ] + } + ], + "source": [ + "# Convert Unix timestamps to datetime format\n", + "df['DateTime'] = pd.to_datetime(df['timestamp'], unit='s')\n", + "\n", + "filtered_df = df\n", + "print(df.head(10))" + ] + }, + { + "cell_type": "markdown", + "id": "2919171b-415e-422c-815e-334631982e97", + "metadata": {}, + "source": [ + "Now that we've resolved the dates and components into a human readable format, we'll plot the data (using some widgets to filter it as desired).\n", + "\n", + "Go down to the end of this code cell to see the output, and alter the first dropdown to select the sensor to chart, and the second drop down to filter to just one metric / SI Unit." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d79be65d-28d2-4c03-ad28-94790e548124", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "291dd9ffdf5d4806ba5b70042b324e8c", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(Dropdown(description='Component:', options=('All', '0x18', '0x44', 'D13', 'D14'), value='All'),…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "10ad05a432e94d1ab754033a4a3cc1d4", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "SelectionRangeSlider(description='Date Range:', index=(0, 1), options=(('2025-03-20', Timestamp('2025-03-20 00…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "d5c15d1261094bf19a745467c7dcb55e", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import pandas as pd\n", + "import plotly.express as px\n", + "from ipywidgets import widgets\n", + "from IPython.display import display, clear_output\n", + "from datetime import datetime, date\n", + "from typing import Optional, Tuple, Union, List\n", + "\n", + "# First, define the plot_data function\n", + "def plot_data(df, component, si_unit, start_date, end_date):\n", + " \"\"\"\n", + " Create a plot based on the selected filters.\n", + " \n", + " Args:\n", + " df (pd.DataFrame): The dataframe containing the data\n", + " component (str): Selected component name or 'All'\n", + " si_unit (str): Selected SI unit or 'All'\n", + " start_date (datetime): Start date for filtering\n", + " end_date (datetime): End date for filtering\n", + " \n", + " Returns:\n", + " plotly.graph_objects.Figure: The created plot\n", + " \"\"\"\n", + " # Filter the dataframe based on selections\n", + " plot_df = df.copy()\n", + " \n", + " # Filter by component if not 'All'\n", + " if component != 'All':\n", + " plot_df = plot_df[plot_df['component_name'] == component]\n", + " \n", + " # Filter by SI unit if not 'All'\n", + " if si_unit != 'All':\n", + " plot_df = plot_df[plot_df['si_unit'] == si_unit]\n", + " \n", + " # Filter by date range\n", + " plot_df = plot_df[(plot_df['DateTime'].dt.date >= start_date.date()) & \n", + " (plot_df['DateTime'].dt.date <= end_date.date())]\n", + " \n", + " # Create the plot (using plotly for interactive visualization)\n", + " fig = px.line(plot_df, x='DateTime', y='value', color='component_name',\n", + " title=f'Data for {component} ({si_unit if si_unit != \"All\" else \"All units\"})')\n", + " \n", + " return fig\n", + "\n", + "# Define the widgets\n", + "component_dropdown = widgets.Dropdown(\n", + " options=['All'] + list(filtered_df['component_name'].unique()),\n", + " description='Component:',\n", + " value='All'\n", + ")\n", + "\n", + "si_unit_dropdown = widgets.Dropdown(\n", + " options=['All'] + list(filtered_df['si_unit'].unique()),\n", + " description='Unit:',\n", + " value='All'\n", + ")\n", + "\n", + "# Get min and max dates from the dataframe\n", + "min_date = filtered_df['DateTime'].dt.date.min()\n", + "max_date = filtered_df['DateTime'].dt.date.max()\n", + "\n", + "# Use SelectionRangeSlider instead of DateRangeSlider\n", + "# Create a list of dates for the slider\n", + "dates = pd.date_range(min_date, max_date).tolist()\n", + "date_options = [(date.strftime('%Y-%m-%d'), date) for date in dates]\n", + "\n", + "date_range = widgets.SelectionRangeSlider(\n", + " options=date_options,\n", + " index=(0, len(dates)-1), # Select all dates initially\n", + " description='Date Range:',\n", + " orientation='horizontal'\n", + ")\n", + "\n", + "# Create an output widget for the plot\n", + "plot_output = widgets.Output()\n", + "\n", + "# Display widgets first (outside the update function)\n", + "display(widgets.HBox([component_dropdown, si_unit_dropdown]))\n", + "display(date_range)\n", + "display(plot_output)\n", + "\n", + "def update_plot(change: Optional[dict] = None) -> None:\n", + " \"\"\"\n", + " Update the plot based on widget selections.\n", + " \n", + " Args:\n", + " change (Optional[dict]): Change event from ipywidgets. Defaults to None.\n", + " \"\"\"\n", + " # Get current values from widgets\n", + " component = component_dropdown.value\n", + " si_unit = si_unit_dropdown.value\n", + " start_date, end_date = date_range.value\n", + " \n", + " # Create plot with the current filter settings\n", + " fig = plot_data(filtered_df, component, si_unit, start_date, end_date)\n", + " \n", + " # Clear previous plot and display new one\n", + " with plot_output:\n", + " plot_output.clear_output(wait=True)\n", + " display(fig)\n", + "\n", + "# Connect the widgets to the update function\n", + "component_dropdown.observe(update_plot, names='value')\n", + "si_unit_dropdown.observe(update_plot, names='value')\n", + "date_range.observe(update_plot, names='value')\n", + "\n", + "# Initial plot\n", + "update_plot()" + ] + }, + { + "cell_type": "markdown", + "id": "daed8831-64d8-413d-8aa0-4b34a97348d1", + "metadata": {}, + "source": [ + "And that's about it. \n", + "\n", + "If you want to add additional columns for the difference over time, or any other such things, it's as simple as using the data frame object, usually `df`, or `filtered_df` in this case, and defining the column as a filter. \n", + "\n", + "For example to see the change in temperature between readings of the SHT30, we could define a filtered dataset for just the SHT30 using this code:\n", + "```python\n", + "sht_df = df[df['component_name'] == 'Weatherproof SHT30 (0x44)'].copy()\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "4e9a4003-e49a-47e6-81a2-cbe0dd862a6f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
i2c_addresstimestampvaluesi_unitpincomponent_nameDateTime
20x44174247598430.02556CNaN0x442025-03-20 13:06:24
30x44174247598486.07004FNaN0x442025-03-20 13:06:24
40x44174247598431.18029%NaN0x442025-03-20 13:06:24
\n", + "
" + ], + "text/plain": [ + " i2c_address timestamp value si_unit pin component_name \\\n", + "2 0x44 1742475984 30.02556 C NaN 0x44 \n", + "3 0x44 1742475984 86.07004 F NaN 0x44 \n", + "4 0x44 1742475984 31.18029 % NaN 0x44 \n", + "\n", + " DateTime \n", + "2 2025-03-20 13:06:24 \n", + "3 2025-03-20 13:06:24 \n", + "4 2025-03-20 13:06:24 " + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "name_to_find = '0x44' # or if using config.json then 'Weatherproof SHT30 (0x44)'\n", + "sht_df = df[df['component_name'] == name_to_find].copy()\n", + "sht_df.head(3)" + ] + }, + { + "cell_type": "markdown", + "id": "fbec759b-104f-47fa-b0f2-a4dcabffd930", + "metadata": {}, + "source": [ + "__Or to only include temperature Celsius values for the SHT30:__" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "9ccbf03d-d404-4d14-b54a-a6d3f51eed85", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
i2c_addresstimestampvaluesi_unitpincomponent_nameDateTime
20x44174247598430.02556CNaN0x442025-03-20 13:06:24
110x44174247601430.03891CNaN0x442025-03-20 13:06:54
200x44174247604430.02556CNaN0x442025-03-20 13:07:24
\n", + "
" + ], + "text/plain": [ + " i2c_address timestamp value si_unit pin component_name \\\n", + "2 0x44 1742475984 30.02556 C NaN 0x44 \n", + "11 0x44 1742476014 30.03891 C NaN 0x44 \n", + "20 0x44 1742476044 30.02556 C NaN 0x44 \n", + "\n", + " DateTime \n", + "2 2025-03-20 13:06:24 \n", + "11 2025-03-20 13:06:54 \n", + "20 2025-03-20 13:07:24 " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sht_df = df[(df['component_name'] == name_to_find) & (df['si_unit'] == 'C')].copy()\n", + "sht_df.head(3)" + ] + }, + { + "cell_type": "markdown", + "id": "df12bc88-672d-47e4-bd25-4fd2b0c4dfb7", + "metadata": {}, + "source": [ + "__Finally we then add three columns, one to indicate the difference in time between readings and one for the temperature difference, then `temp_diff` divided by `time_diff`:__" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "8c30c5ed-6e00-4d84-92c5-d15f5fccecc9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
i2c_addresstimestampvaluesi_unitpincomponent_nameDateTimetime_difftemp_difftemp_diff_per_second
20x44174247598430.02556CNaN0x442025-03-20 13:06:24NaNNaNNaN
110x44174247601430.03891CNaN0x442025-03-20 13:06:5430.00.013350.000445
200x44174247604430.02556CNaN0x442025-03-20 13:07:2430.0-0.01335-0.000445
290x44174247607430.01221CNaN0x442025-03-20 13:07:5430.0-0.01335-0.000445
380x44174247610429.93744CNaN0x442025-03-20 13:08:2430.0-0.07477-0.002492
\n", + "
" + ], + "text/plain": [ + " i2c_address timestamp value si_unit pin component_name \\\n", + "2 0x44 1742475984 30.02556 C NaN 0x44 \n", + "11 0x44 1742476014 30.03891 C NaN 0x44 \n", + "20 0x44 1742476044 30.02556 C NaN 0x44 \n", + "29 0x44 1742476074 30.01221 C NaN 0x44 \n", + "38 0x44 1742476104 29.93744 C NaN 0x44 \n", + "\n", + " DateTime time_diff temp_diff temp_diff_per_second \n", + "2 2025-03-20 13:06:24 NaN NaN NaN \n", + "11 2025-03-20 13:06:54 30.0 0.01335 0.000445 \n", + "20 2025-03-20 13:07:24 30.0 -0.01335 -0.000445 \n", + "29 2025-03-20 13:07:54 30.0 -0.01335 -0.000445 \n", + "38 2025-03-20 13:08:24 30.0 -0.07477 -0.002492 " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sht_df['time_diff'] = sht_df['timestamp'].diff()\n", + "sht_df['temp_diff'] = sht_df['value'].diff()\n", + "sht_df['temp_diff_per_second'] = (sht_df['temp_diff'] / sht_df['time_diff'])\n", + "sht_df.head(5)" + ] + }, + { + "cell_type": "markdown", + "id": "63811915-a242-4bd3-874e-aee8afd30548", + "metadata": {}, + "source": [ + "Then finally we plot the data to see how the temperature changed over time:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "ff676f87-f167-4aa1-b98a-aa642a784d0b", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hovertemplate": "DateTime=%{x}
temp_diff_per_second=%{y}", + "legendgroup": "", + "line": { + "color": "#636efa", + "dash": "solid" + }, + "marker": { + "symbol": "circle" + }, + "mode": "lines", + "name": "", + "showlegend": false, + "type": "scattergl", + "x": [ + "2025-03-20T13:06:24", + "2025-03-20T13:06:54", + "2025-03-20T13:07:24", + "2025-03-20T13:07:54", + "2025-03-20T13:08:24", + "2025-03-20T13:08:54", + "2025-03-20T13:09:24", + "2025-03-20T13:09:54", + "2025-03-20T13:10:24", + "2025-03-20T13:10:54", + "2025-03-20T13:11:25", + "2025-03-20T13:11:56", + "2025-03-20T13:12:26", + "2025-03-20T13:12:57", + "2025-03-20T13:13:28", + "2025-03-20T13:13:59", + "2025-03-20T13:14:30", + "2025-03-20T13:15:00", + "2025-03-20T13:15:31", + "2025-03-20T13:16:02", + "2025-03-20T13:16:33", + "2025-03-20T13:17:03", + "2025-03-20T13:17:34", + "2025-03-20T13:18:05", + "2025-03-20T13:18:36", + "2025-03-20T13:19:07", + "2025-03-20T13:19:37", + "2025-03-20T13:20:08", + "2025-03-20T13:20:39", + "2025-03-20T13:21:10", + "2025-03-20T13:21:40", + "2025-03-20T13:22:11", + "2025-03-20T13:22:42", + "2025-03-20T13:23:13", + "2025-03-20T13:23:44", + "2025-03-20T13:24:14", + "2025-03-20T13:24:45", + "2025-03-20T13:25:16", + "2025-03-20T13:25:47", + "2025-03-20T13:26:17", + "2025-03-20T13:26:48", + "2025-03-20T13:27:19", + "2025-03-20T13:27:50", + "2025-03-20T13:28:21", + "2025-03-20T13:28:51", + "2025-03-20T13:29:22", + "2025-03-20T13:29:53", + "2025-03-20T13:30:24", + "2025-03-20T13:30:54", + "2025-03-20T13:31:25", + "2025-03-20T13:31:56", + "2025-03-20T13:32:27", + "2025-03-20T13:32:58", + "2025-03-20T13:33:28", + "2025-03-20T13:33:59", + "2025-03-20T13:34:30", + "2025-03-20T13:35:01", + "2025-03-20T13:35:31", + "2025-03-20T13:36:02", + "2025-03-20T13:36:33", + "2025-03-20T13:37:04", + "2025-03-20T13:37:35", + "2025-03-20T13:38:05", + "2025-03-20T13:38:36", + "2025-03-20T13:39:07", + "2025-03-20T13:39:38", + "2025-03-20T13:40:08", + "2025-03-20T13:40:39", + "2025-03-20T13:41:10", + "2025-03-20T13:41:41", + "2025-03-20T13:42:12", + "2025-03-20T13:42:42", + "2025-03-20T13:43:13", + "2025-03-20T13:43:44", + "2025-03-20T13:44:15", + "2025-03-20T13:44:45", + "2025-03-20T13:45:16", + "2025-03-20T13:45:47", + "2025-03-20T13:46:18", + "2025-03-20T13:46:49", + "2025-03-20T13:47:19", + "2025-03-20T13:47:50", + "2025-03-20T13:48:21", + "2025-03-20T13:48:52", + "2025-03-20T13:49:22", + "2025-03-20T13:49:53", + "2025-03-20T13:50:24", + "2025-03-20T13:50:55", + "2025-03-20T13:51:26", + "2025-03-20T13:51:56", + "2025-03-20T13:52:27", + "2025-03-20T13:52:58", + "2025-03-20T13:53:29", + "2025-03-20T13:53:59", + "2025-03-20T13:54:30", + "2025-03-20T13:55:01", + "2025-03-20T13:55:32", + "2025-03-20T13:56:02", + "2025-03-20T13:56:34", + "2025-03-20T13:57:05", + "2025-03-20T13:57:35", + "2025-03-20T13:58:06", + "2025-03-20T13:58:37", + "2025-03-20T13:59:08", + "2025-03-20T13:59:39", + "2025-03-20T14:00:09", + "2025-03-20T14:00:40", + "2025-03-20T14:01:11", + "2025-03-20T14:01:42", + "2025-03-20T14:02:12", + "2025-03-20T14:02:43", + "2025-03-20T14:03:14", + "2025-03-20T14:03:45", + "2025-03-20T14:04:16", + "2025-03-20T14:04:46", + "2025-03-20T14:05:17", + "2025-03-20T14:05:48", + "2025-03-20T14:06:19", + "2025-03-20T14:06:49", + "2025-03-20T14:07:20", + "2025-03-20T14:07:51", + "2025-03-20T14:08:22", + "2025-03-20T14:08:52", + "2025-03-20T14:09:23", + "2025-03-20T14:09:54", + "2025-03-20T14:10:25", + "2025-03-20T14:10:56", + "2025-03-20T14:11:26", + "2025-03-20T14:11:57", + "2025-03-20T14:12:28", + "2025-03-20T14:12:59", + "2025-03-20T14:13:30", + "2025-03-20T14:14:00", + "2025-03-20T14:14:31", + "2025-03-20T14:15:02", + "2025-03-20T14:15:33", + "2025-03-20T14:16:03", + "2025-03-20T14:16:34", + "2025-03-20T14:17:05", + "2025-03-20T14:17:36", + "2025-03-20T14:18:06", + "2025-03-20T14:18:37", + "2025-03-20T14:19:08", + "2025-03-20T14:19:39", + "2025-03-20T14:20:10", + "2025-03-20T14:20:41", + "2025-03-20T14:21:12", + "2025-03-20T14:21:43", + "2025-03-20T14:22:13", + "2025-03-20T14:22:44", + "2025-03-20T14:23:15", + "2025-03-20T14:23:46", + "2025-03-20T14:24:16", + "2025-03-20T14:24:47", + "2025-03-20T14:25:18", + "2025-03-20T14:25:49", + "2025-03-20T14:26:19", + "2025-03-20T14:26:50", + "2025-03-20T14:27:21", + "2025-03-20T14:27:52", + "2025-03-20T14:28:23", + "2025-03-20T14:28:53", + "2025-03-20T14:29:24", + "2025-03-20T14:29:55", + "2025-03-20T14:30:26", + "2025-03-20T14:30:56", + "2025-03-20T14:31:27", + "2025-03-20T14:31:58", + "2025-03-20T14:32:29", + "2025-03-20T14:33:00", + "2025-03-20T14:33:30", + "2025-03-20T14:34:01", + "2025-03-20T14:34:32", + "2025-03-20T14:35:03", + "2025-03-20T14:35:33", + "2025-03-20T14:36:04", + "2025-03-20T14:36:35", + "2025-03-20T14:37:06", + "2025-03-20T14:37:37", + "2025-03-20T14:38:07", + "2025-03-20T14:38:38", + "2025-03-20T14:39:09", + "2025-03-20T14:39:40", + "2025-03-20T14:40:10", + "2025-03-20T14:40:41", + "2025-03-20T14:41:12", + "2025-03-20T14:41:43", + "2025-03-20T14:42:14", + "2025-03-20T14:42:44", + "2025-03-20T14:43:15", + "2025-03-20T14:43:46", + "2025-03-20T14:44:17", + "2025-03-20T14:44:47", + "2025-03-20T14:45:18", + "2025-03-20T14:45:49", + "2025-03-20T14:46:20", + "2025-03-20T14:46:51", + "2025-03-20T14:47:21", + "2025-03-20T14:47:52", + "2025-03-20T14:48:23", + "2025-03-20T14:48:54", + "2025-03-20T14:49:24", + "2025-03-20T14:49:55", + "2025-03-20T14:50:26", + "2025-03-20T14:50:57", + "2025-03-20T14:51:28", + "2025-03-20T14:51:58", + "2025-03-20T14:52:29", + "2025-03-20T14:53:00", + "2025-03-20T14:53:31", + "2025-03-20T14:54:01", + "2025-03-20T14:54:32", + "2025-03-20T14:55:03", + "2025-03-20T14:55:34", + "2025-03-20T14:56:05", + "2025-03-20T14:56:35", + "2025-03-20T14:57:06", + "2025-03-20T14:57:37", + "2025-03-20T14:58:08", + "2025-03-20T14:58:38", + "2025-03-20T14:59:09", + "2025-03-20T14:59:40", + "2025-03-20T15:00:11", + "2025-03-20T15:00:42", + "2025-03-20T15:01:12", + "2025-03-20T15:01:43", + "2025-03-20T15:02:14", + "2025-03-20T15:02:45", + "2025-03-20T15:03:15", + "2025-03-20T15:03:46", + "2025-03-20T15:04:17", + "2025-03-20T15:04:48", + "2025-03-20T15:05:19", + "2025-03-20T15:05:49", + "2025-03-20T15:06:20", + "2025-03-20T15:06:51", + "2025-03-20T15:07:22", + "2025-03-20T15:07:52", + "2025-03-20T15:08:23", + "2025-03-20T15:08:54", + "2025-03-20T15:09:25", + "2025-03-20T15:09:55", + "2025-03-20T15:10:26", + "2025-03-20T15:10:57", + "2025-03-20T15:11:28", + "2025-03-20T15:11:59", + "2025-03-20T15:12:30", + "2025-03-20T15:13:01", + "2025-03-20T15:13:31", + "2025-03-20T15:14:02", + "2025-03-20T15:14:33", + "2025-03-20T15:15:04", + "2025-03-20T15:15:34", + "2025-03-20T15:16:05", + "2025-03-20T15:16:36", + "2025-03-20T15:17:07", + "2025-03-20T15:17:38", + "2025-03-20T15:18:08", + "2025-03-20T15:18:39", + "2025-03-20T15:19:10", + "2025-03-20T15:19:41", + "2025-03-20T15:20:11", + "2025-03-20T15:20:42", + "2025-03-20T15:21:13", + "2025-03-20T15:21:44", + "2025-03-20T15:22:15", + "2025-03-20T15:22:45", + "2025-03-20T15:23:16", + "2025-03-20T15:23:47", + "2025-03-20T15:24:18", + "2025-03-20T15:24:48", + "2025-03-20T15:25:19", + "2025-03-20T15:25:50", + "2025-03-20T15:26:21", + "2025-03-20T15:26:52", + "2025-03-20T15:27:22", + "2025-03-20T15:27:53", + "2025-03-20T15:28:24", + "2025-03-20T15:28:55", + "2025-03-20T15:29:25", + "2025-03-20T15:29:56", + "2025-03-20T15:30:27", + "2025-03-20T15:30:58", + "2025-03-20T15:31:28", + "2025-03-20T15:31:59", + "2025-03-20T15:32:30", + "2025-03-20T15:33:01", + "2025-03-20T15:33:32", + "2025-03-20T15:34:02", + "2025-03-20T15:34:33", + "2025-03-20T15:35:04", + "2025-03-20T15:35:35", + "2025-03-20T15:36:05", + "2025-03-20T15:36:36", + "2025-03-20T15:37:07", + "2025-03-20T15:37:38", + "2025-03-20T15:38:09", + "2025-03-20T15:38:39", + "2025-03-20T15:39:10", + "2025-03-20T15:39:41", + "2025-03-20T15:40:12", + "2025-03-20T15:40:42", + "2025-03-20T15:41:13", + "2025-03-20T15:41:44", + "2025-03-20T15:42:15", + "2025-03-20T15:42:46", + "2025-03-20T15:43:16", + "2025-03-20T15:43:47", + "2025-03-20T15:44:18", + "2025-03-20T15:44:49", + "2025-03-20T15:45:19", + "2025-03-20T15:45:50", + "2025-03-20T15:46:21", + "2025-03-20T15:46:52", + "2025-03-20T15:47:23", + "2025-03-20T15:47:53", + "2025-03-20T15:48:24", + "2025-03-20T15:48:55", + "2025-03-20T15:49:26", + "2025-03-20T15:49:56", + "2025-03-20T15:50:27", + "2025-03-20T15:50:58", + "2025-03-20T15:51:29", + "2025-03-20T15:52:00", + "2025-03-20T15:52:30", + "2025-03-20T15:53:01", + "2025-03-20T15:53:32", + "2025-03-20T15:54:03", + "2025-03-20T15:54:33", + "2025-03-20T15:55:04", + "2025-03-20T15:55:35", + "2025-03-20T15:56:06", + "2025-03-20T15:56:37", + "2025-03-20T15:57:07", + "2025-03-20T15:57:38", + "2025-03-20T15:58:09", + "2025-03-20T15:58:40", + "2025-03-20T15:59:10", + "2025-03-20T15:59:41", + "2025-03-20T16:00:12", + "2025-03-20T16:00:43", + "2025-03-20T16:01:14", + "2025-03-20T16:01:45", + "2025-03-20T16:02:15", + "2025-03-20T16:02:46", + "2025-03-20T16:03:17", + "2025-03-20T16:03:48", + "2025-03-20T16:04:19", + "2025-03-20T16:04:49", + "2025-03-20T16:05:20", + "2025-03-20T16:05:51", + "2025-03-20T16:06:22", + "2025-03-20T16:06:52", + "2025-03-20T16:07:23", + "2025-03-20T16:07:54", + "2025-03-20T16:08:25", + "2025-03-20T16:08:56", + "2025-03-20T16:09:26", + "2025-03-20T16:09:57", + "2025-03-20T16:10:28", + "2025-03-20T16:10:59", + "2025-03-20T16:11:29", + "2025-03-20T16:12:00", + "2025-03-20T16:12:31", + "2025-03-20T16:13:02", + "2025-03-20T16:13:33", + "2025-03-20T16:14:03", + "2025-03-20T16:14:34", + "2025-03-20T16:15:05", + "2025-03-20T16:15:36", + "2025-03-20T16:16:06", + "2025-03-20T16:16:37", + "2025-03-20T16:17:08", + "2025-03-20T16:17:39", + "2025-03-20T16:18:10", + "2025-03-20T16:18:40", + "2025-03-20T16:19:11", + "2025-03-20T16:19:42", + "2025-03-20T16:20:13", + "2025-03-20T16:20:43", + "2025-03-20T16:21:14", + "2025-03-20T16:21:45", + "2025-03-20T16:22:16", + "2025-03-20T16:22:46", + "2025-03-20T16:23:17", + "2025-03-20T16:23:48", + "2025-03-20T16:24:19", + "2025-03-20T16:24:50", + "2025-03-20T16:25:20", + "2025-03-20T16:25:51", + "2025-03-20T16:26:22", + "2025-03-20T16:26:53", + "2025-03-20T16:27:23", + "2025-03-20T16:27:54", + "2025-03-20T16:28:25", + "2025-03-20T16:28:56", + "2025-03-20T16:29:27", + "2025-03-20T16:29:57", + "2025-03-20T16:30:28", + "2025-03-20T16:30:59", + "2025-03-20T16:31:30", + "2025-03-20T16:32:00", + "2025-03-20T16:32:31", + "2025-03-20T16:33:02", + "2025-03-20T16:33:33", + "2025-03-20T16:34:04", + "2025-03-20T16:34:34", + "2025-03-20T16:35:05", + "2025-03-20T16:35:36", + "2025-03-20T16:36:07", + "2025-03-20T16:36:37", + "2025-03-20T16:37:08", + "2025-03-20T16:37:39", + "2025-03-20T16:38:10", + "2025-03-20T16:38:41", + "2025-03-20T16:39:11", + "2025-03-20T16:39:42", + "2025-03-20T16:40:13", + "2025-03-20T16:40:44", + "2025-03-20T16:41:14", + "2025-03-20T16:41:45", + "2025-03-20T16:42:16", + "2025-03-20T16:42:47", + "2025-03-20T16:43:18", + "2025-03-20T16:43:48", + "2025-03-20T16:44:19", + "2025-03-20T16:44:50", + "2025-03-20T16:45:21", + "2025-03-20T16:45:51", + "2025-03-20T16:46:22", + "2025-03-20T16:46:53", + "2025-03-20T16:47:24", + "2025-03-20T16:47:55", + "2025-03-20T16:48:25", + "2025-03-20T16:48:56", + "2025-03-20T16:49:27", + "2025-03-20T16:49:58", + "2025-03-20T16:50:28", + "2025-03-20T16:50:59", + "2025-03-20T16:51:30", + "2025-03-20T16:52:01", + "2025-03-20T16:52:32", + "2025-03-20T16:53:03", + "2025-03-20T16:53:33", + "2025-03-20T16:54:04", + "2025-03-20T16:54:35", + "2025-03-20T16:55:06", + "2025-03-20T16:55:37", + "2025-03-20T16:56:07", + "2025-03-20T16:56:38", + "2025-03-20T16:57:09", + "2025-03-20T16:57:40", + "2025-03-20T16:58:10", + "2025-03-20T16:58:41", + "2025-03-20T16:59:12", + "2025-03-20T16:59:43", + "2025-03-20T17:00:14", + "2025-03-20T17:00:44", + "2025-03-20T17:01:15", + "2025-03-20T17:01:46", + "2025-03-20T17:02:17", + "2025-03-20T17:02:47", + "2025-03-20T17:03:18", + "2025-03-20T17:03:49", + "2025-03-20T17:04:20", + "2025-03-20T17:04:51", + "2025-03-20T17:05:21", + "2025-03-20T17:05:52", + "2025-03-20T17:06:23", + "2025-03-20T17:06:54", + "2025-03-20T17:07:24", + "2025-03-20T17:07:55", + "2025-03-20T17:08:26", + "2025-03-20T17:08:57", + "2025-03-20T17:09:28", + "2025-03-20T17:09:58", + "2025-03-20T17:10:29", + "2025-03-20T17:11:00", + "2025-03-20T17:11:31", + "2025-03-20T17:12:01", + "2025-03-20T17:12:32", + "2025-03-20T17:13:03", + "2025-03-20T17:13:34", + "2025-03-20T17:14:05", + "2025-03-20T17:14:35", + "2025-03-20T17:15:06", + "2025-03-20T17:15:37", + "2025-03-20T17:16:08", + "2025-03-20T17:16:38", + "2025-03-20T17:17:09", + "2025-03-20T17:17:40", + "2025-03-20T17:18:11", + "2025-03-20T17:18:41", + "2025-03-20T17:19:12", + "2025-03-20T17:19:43", + "2025-03-20T17:20:14", + "2025-03-20T17:20:45", + "2025-03-20T17:21:15", + "2025-03-20T17:21:46", + "2025-03-20T17:22:17", + "2025-03-20T17:22:48", + "2025-03-20T17:23:18", + "2025-03-20T17:23:49", + "2025-03-20T17:24:20", + "2025-03-20T17:24:51", + "2025-03-20T17:25:22", + "2025-03-20T17:25:52", + "2025-03-20T17:26:23", + "2025-03-20T17:26:54", + "2025-03-20T17:27:25", + "2025-03-20T17:27:55", + "2025-03-20T17:28:26", + "2025-03-20T17:28:57", + "2025-03-20T17:29:28", + "2025-03-20T17:29:59", + "2025-03-20T17:30:29", + "2025-03-20T17:31:00", + "2025-03-20T17:31:31", + "2025-03-20T17:32:02", + "2025-03-20T17:32:32", + "2025-03-20T17:33:03", + "2025-03-20T17:33:34", + "2025-03-20T17:34:05", + "2025-03-20T17:34:36", + "2025-03-20T17:35:06", + "2025-03-20T17:35:37", + "2025-03-20T17:36:08", + "2025-03-20T17:36:39", + "2025-03-20T17:37:09", + "2025-03-20T17:37:40", + "2025-03-20T17:38:11", + "2025-03-20T17:38:42", + "2025-03-20T17:39:13", + "2025-03-20T17:39:43", + "2025-03-20T17:40:14", + "2025-03-20T17:40:45", + "2025-03-20T17:41:16", + "2025-03-20T17:41:47", + "2025-03-20T17:42:18", + "2025-03-20T17:42:48", + "2025-03-20T17:43:19", + "2025-03-20T17:43:50", + "2025-03-20T17:44:21", + "2025-03-20T17:44:51", + "2025-03-20T17:45:22", + "2025-03-20T17:45:53", + "2025-03-20T17:46:24", + "2025-03-20T17:46:55", + "2025-03-20T17:47:25", + "2025-03-20T17:47:56", + "2025-03-20T17:48:27", + "2025-03-20T17:48:58", + "2025-03-20T17:49:28", + "2025-03-20T17:49:59", + "2025-03-20T17:50:30", + "2025-03-20T17:51:01", + "2025-03-20T17:51:32", + "2025-03-20T17:52:02", + "2025-03-20T17:52:33", + "2025-03-20T17:53:04", + "2025-03-20T17:53:35", + "2025-03-20T17:54:05", + "2025-03-20T17:54:36", + "2025-03-20T17:55:07", + "2025-03-20T17:55:38", + "2025-03-20T17:56:09", + "2025-03-20T17:56:39", + "2025-03-20T17:57:10", + "2025-03-20T17:57:41", + "2025-03-20T17:58:12", + "2025-03-20T17:58:42", + "2025-03-20T17:59:13", + "2025-03-20T17:59:44", + "2025-03-20T18:00:15", + "2025-03-20T18:00:46", + "2025-03-20T18:01:16", + "2025-03-20T18:01:47", + "2025-03-20T18:02:18", + "2025-03-20T18:02:49", + "2025-03-20T18:03:19", + "2025-03-20T18:03:50", + "2025-03-20T18:04:21", + "2025-03-20T18:04:52", + "2025-03-20T18:05:23", + "2025-03-20T18:05:53", + "2025-03-20T18:06:24", + "2025-03-20T18:06:55", + "2025-03-20T18:07:26", + "2025-03-20T18:07:56", + "2025-03-20T18:08:27", + "2025-03-20T18:08:58", + "2025-03-20T18:09:29", + "2025-03-20T18:10:00", + "2025-03-20T18:10:30", + "2025-03-20T18:11:01", + "2025-03-20T18:11:32", + "2025-03-20T18:12:03", + "2025-03-20T18:12:33", + "2025-03-20T18:13:04", + "2025-03-20T18:13:35", + "2025-03-20T18:14:06", + "2025-03-20T18:14:37", + "2025-03-20T18:15:07", + "2025-03-20T18:15:38", + "2025-03-20T18:16:09", + "2025-03-20T18:16:40", + "2025-03-20T18:17:10", + "2025-03-20T18:17:41", + "2025-03-20T18:18:12", + "2025-03-20T18:18:43", + "2025-03-20T18:19:14", + "2025-03-20T18:19:44", + "2025-03-20T18:20:15", + "2025-03-20T18:20:46", + "2025-03-20T18:21:17", + "2025-03-20T18:21:47", + "2025-03-20T18:22:18", + "2025-03-20T18:22:49", + "2025-03-20T18:23:20", + "2025-03-20T18:23:51", + "2025-03-20T18:24:21", + "2025-03-20T18:24:52", + "2025-03-20T18:25:23", + "2025-03-20T18:25:54", + "2025-03-20T18:26:24", + "2025-03-20T18:26:55", + "2025-03-20T18:27:26", + "2025-03-20T18:27:57", + "2025-03-20T18:28:28", + "2025-03-20T18:28:58", + "2025-03-20T18:29:29", + "2025-03-20T18:30:00", + "2025-03-20T18:30:31", + "2025-03-20T18:31:01", + "2025-03-20T18:31:32", + "2025-03-20T18:32:03", + "2025-03-20T18:32:34", + "2025-03-20T18:33:05", + "2025-03-20T18:33:36", + "2025-03-20T18:34:06", + "2025-03-20T18:34:37", + "2025-03-20T18:35:08", + "2025-03-20T18:35:39", + "2025-03-20T18:36:10", + "2025-03-20T18:36:40", + "2025-03-20T18:37:11", + "2025-03-20T18:37:42", + "2025-03-20T18:38:13", + "2025-03-20T18:38:43", + "2025-03-20T18:39:14", + "2025-03-20T18:39:45", + "2025-03-20T18:40:16", + "2025-03-20T18:40:47", + "2025-03-20T18:41:17", + "2025-03-20T18:41:48", + "2025-03-20T18:42:19", + "2025-03-20T18:42:50", + "2025-03-20T18:43:20", + "2025-03-20T18:43:51", + "2025-03-20T18:44:22", + "2025-03-20T18:44:53", + "2025-03-20T18:45:24", + "2025-03-20T18:45:54", + "2025-03-20T18:46:25", + "2025-03-20T18:46:56", + "2025-03-20T18:47:27", + "2025-03-20T18:47:57", + "2025-03-20T18:48:28", + "2025-03-20T18:48:59", + "2025-03-20T18:49:30", + "2025-03-20T18:50:01", + "2025-03-20T18:50:31", + "2025-03-20T18:51:02", + "2025-03-20T18:51:33", + "2025-03-20T18:52:04", + "2025-03-20T18:52:34", + "2025-03-20T18:53:05", + "2025-03-20T18:53:36", + "2025-03-20T18:54:07", + "2025-03-20T18:54:38", + "2025-03-20T18:55:08", + "2025-03-20T18:55:39", + "2025-03-20T18:56:10", + "2025-03-20T18:56:41", + "2025-03-20T18:57:11", + "2025-03-20T18:57:42", + "2025-03-20T18:58:13", + "2025-03-20T18:58:44", + "2025-03-20T18:59:15", + "2025-03-20T18:59:45", + "2025-03-20T19:00:16", + "2025-03-20T19:00:47", + "2025-03-20T19:01:18", + "2025-03-20T19:01:48", + "2025-03-20T19:02:19", + "2025-03-20T19:02:50", + "2025-03-20T19:03:21", + "2025-03-20T19:03:52", + "2025-03-20T19:04:22", + "2025-03-20T19:04:53", + "2025-03-20T19:05:24", + "2025-03-20T19:05:55", + "2025-03-20T19:06:25", + "2025-03-20T19:06:56", + "2025-03-20T19:07:27", + "2025-03-20T19:07:58", + "2025-03-20T19:08:29", + "2025-03-20T19:08:59", + "2025-03-20T19:09:30", + "2025-03-20T19:10:01", + "2025-03-20T19:10:32", + "2025-03-20T19:11:02", + "2025-03-20T19:11:33", + "2025-03-20T19:12:04", + "2025-03-20T19:12:35", + "2025-03-20T19:13:05", + "2025-03-20T19:13:36", + "2025-03-20T19:14:07", + "2025-03-20T19:14:38", + "2025-03-20T19:15:09", + "2025-03-20T19:15:39", + "2025-03-20T19:16:10", + "2025-03-20T19:16:41", + "2025-03-20T19:17:12", + "2025-03-20T19:17:42", + "2025-03-20T19:18:13", + "2025-03-20T19:18:44", + "2025-03-20T19:19:15", + "2025-03-20T19:19:46", + "2025-03-20T19:20:16", + "2025-03-20T19:20:47", + "2025-03-20T19:21:18", + "2025-03-20T19:21:49", + "2025-03-20T19:22:20", + "2025-03-20T19:22:51", + "2025-03-20T19:23:21", + "2025-03-20T19:23:52", + "2025-03-20T19:24:23", + "2025-03-20T19:24:54", + "2025-03-20T19:25:25", + "2025-03-20T19:25:55", + "2025-03-20T19:26:26", + "2025-03-20T19:26:57", + "2025-03-20T19:27:28", + "2025-03-20T19:27:58", + "2025-03-20T19:28:29", + "2025-03-20T19:29:00", + "2025-03-20T19:29:31", + "2025-03-20T19:30:02", + "2025-03-20T19:30:32", + "2025-03-20T19:31:03", + "2025-03-20T19:31:34", + "2025-03-20T19:32:05", + "2025-03-20T19:32:35", + "2025-03-20T19:33:06", + "2025-03-20T19:33:37", + "2025-03-20T19:34:08", + "2025-03-20T19:34:39", + "2025-03-20T19:35:09", + "2025-03-20T19:35:40", + "2025-03-20T19:36:11", + "2025-03-20T19:36:42", + "2025-03-20T19:37:12", + "2025-03-20T19:37:43", + "2025-03-20T19:38:14", + "2025-03-20T19:38:45", + "2025-03-20T19:39:16", + "2025-03-20T19:39:46", + "2025-03-20T19:40:17", + "2025-03-20T19:40:48", + "2025-03-20T19:41:19", + "2025-03-20T19:41:49", + "2025-03-20T19:42:20", + "2025-03-20T19:42:51", + "2025-03-20T19:43:22", + "2025-03-20T19:43:53", + "2025-03-20T19:44:23", + "2025-03-20T19:44:54", + "2025-03-20T19:45:25", + "2025-03-20T19:45:56", + "2025-03-20T19:46:26", + "2025-03-20T19:46:57", + "2025-03-20T19:47:28", + "2025-03-20T19:47:59", + "2025-03-20T19:48:30", + "2025-03-20T19:49:00", + "2025-03-20T19:49:31", + "2025-03-20T19:50:02", + "2025-03-20T19:50:33", + "2025-03-20T19:51:03", + "2025-03-20T19:51:34", + "2025-03-20T19:52:05", + "2025-03-20T19:52:36", + "2025-03-20T19:53:07", + "2025-03-20T19:53:37", + "2025-03-20T19:54:08", + "2025-03-20T19:54:39", + "2025-03-20T19:55:10", + "2025-03-20T19:55:40", + "2025-03-20T19:56:11", + "2025-03-20T19:56:42", + "2025-03-20T19:57:13", + "2025-03-20T19:57:44", + "2025-03-20T19:58:14", + "2025-03-20T19:58:45", + "2025-03-20T19:59:16", + "2025-03-20T19:59:47", + "2025-03-20T20:00:17", + "2025-03-20T20:00:48", + "2025-03-20T20:01:19", + "2025-03-20T20:01:50", + "2025-03-20T20:02:20", + "2025-03-20T20:02:51", + "2025-03-20T20:03:22", + "2025-03-20T20:03:53", + "2025-03-20T20:04:24", + "2025-03-20T20:04:54", + "2025-03-20T20:05:25", + "2025-03-20T20:05:56", + "2025-03-20T20:06:27", + "2025-03-20T20:06:57", + "2025-03-20T20:07:28", + "2025-03-20T20:07:59", + "2025-03-20T20:08:30", + "2025-03-20T20:09:01", + "2025-03-20T20:09:31", + "2025-03-20T20:10:02", + "2025-03-20T20:10:33", + "2025-03-20T20:11:04", + "2025-03-20T20:11:34", + "2025-03-20T20:12:05", + "2025-03-20T20:12:36", + "2025-03-20T20:13:07", + "2025-03-20T20:13:38", + "2025-03-20T20:14:09", + "2025-03-20T20:14:40", + "2025-03-20T20:15:10", + "2025-03-20T20:15:41", + "2025-03-20T20:16:12", + "2025-03-20T20:16:43", + "2025-03-20T20:17:13", + "2025-03-20T20:17:44", + "2025-03-20T20:18:15", + "2025-03-20T20:18:46", + "2025-03-20T20:19:17", + "2025-03-20T20:19:47", + "2025-03-20T20:20:18", + "2025-03-20T20:20:49", + "2025-03-20T20:21:20", + "2025-03-20T20:21:50", + "2025-03-20T20:22:21", + "2025-03-20T20:22:52", + "2025-03-20T20:23:23", + "2025-03-20T20:23:54", + "2025-03-20T20:24:24", + "2025-03-20T20:24:55", + "2025-03-20T20:25:26", + "2025-03-20T20:25:57", + "2025-03-20T20:26:27", + "2025-03-20T20:26:58", + "2025-03-20T20:27:29", + "2025-03-20T20:28:00", + "2025-03-20T20:28:31", + "2025-03-20T20:29:01", + "2025-03-20T20:29:32", + "2025-03-20T20:30:03", + "2025-03-20T20:30:34", + "2025-03-20T20:31:04", + "2025-03-20T20:31:35", + "2025-03-20T20:32:06", + "2025-03-20T20:32:37", + "2025-03-20T20:33:08", + "2025-03-20T20:33:38", + "2025-03-20T20:34:09", + "2025-03-20T20:34:40", + "2025-03-20T20:35:11", + "2025-03-20T20:35:41", + "2025-03-20T20:36:12", + "2025-03-20T20:36:43", + "2025-03-20T20:37:14", + "2025-03-20T20:37:45", + "2025-03-20T20:38:15", + "2025-03-20T20:38:46", + "2025-03-20T20:39:17", + "2025-03-20T20:39:48", + "2025-03-20T20:40:18", + "2025-03-20T20:40:49", + "2025-03-20T20:41:20", + "2025-03-20T20:41:51", + "2025-03-20T20:42:22", + "2025-03-20T20:42:52", + "2025-03-20T20:43:23", + "2025-03-20T20:43:54", + "2025-03-20T20:44:25", + "2025-03-20T20:44:55", + "2025-03-20T20:45:26", + "2025-03-20T20:45:57", + "2025-03-20T20:46:28", + "2025-03-20T20:46:58", + "2025-03-20T20:47:29", + "2025-03-20T20:48:00", + "2025-03-20T20:48:31", + "2025-03-20T20:49:02", + "2025-03-20T20:49:32", + "2025-03-20T20:50:03", + "2025-03-20T20:50:34", + "2025-03-20T20:51:05", + "2025-03-20T20:51:35", + "2025-03-20T20:52:06", + "2025-03-20T20:52:37", + "2025-03-20T20:53:08", + "2025-03-20T20:53:39", + "2025-03-20T20:54:09", + "2025-03-20T20:54:40", + "2025-03-20T20:55:11", + "2025-03-20T20:55:42", + "2025-03-20T20:56:12", + "2025-03-20T20:56:43", + "2025-03-20T20:57:14", + "2025-03-20T20:57:45", + "2025-03-20T20:58:16", + "2025-03-20T20:58:46", + "2025-03-20T20:59:17", + "2025-03-20T20:59:48", + "2025-03-20T21:00:19", + "2025-03-20T21:00:49", + "2025-03-20T21:01:20", + "2025-03-20T21:01:51", + "2025-03-20T21:02:22", + "2025-03-20T21:02:53", + "2025-03-20T21:03:24", + "2025-03-20T21:03:55", + "2025-03-20T21:04:25", + "2025-03-20T21:04:56", + "2025-03-20T21:05:27", + "2025-03-20T21:05:58", + "2025-03-20T21:06:28", + "2025-03-20T21:06:59", + "2025-03-20T21:07:30", + "2025-03-20T21:08:01", + "2025-03-20T21:08:32", + "2025-03-20T21:09:02", + "2025-03-20T21:09:33", + "2025-03-20T21:10:04", + "2025-03-20T21:10:35", + "2025-03-20T21:11:05", + "2025-03-20T21:11:36", + "2025-03-20T21:12:07", + "2025-03-20T21:12:38", + "2025-03-20T21:13:09", + "2025-03-20T21:13:39", + "2025-03-20T21:14:10", + "2025-03-20T21:14:41", + "2025-03-20T21:15:12", + "2025-03-20T21:15:42", + "2025-03-20T21:16:13", + "2025-03-20T21:16:44", + "2025-03-20T21:17:15", + "2025-03-20T21:17:46", + "2025-03-20T21:18:16", + "2025-03-20T21:18:47", + "2025-03-20T21:19:18", + "2025-03-20T21:19:49", + "2025-03-20T21:20:19", + "2025-03-20T21:20:50", + "2025-03-20T21:21:21", + "2025-03-20T21:21:52", + "2025-03-20T21:22:23", + "2025-03-20T21:22:53", + "2025-03-20T21:23:24", + "2025-03-20T21:23:55", + "2025-03-20T21:24:26", + "2025-03-20T21:24:56", + "2025-03-20T21:25:27", + "2025-03-20T21:25:58", + "2025-03-20T21:26:29", + "2025-03-20T21:27:00", + "2025-03-20T21:27:30", + "2025-03-20T21:28:01", + "2025-03-20T21:28:32", + "2025-03-20T21:29:03", + "2025-03-20T21:29:33", + "2025-03-20T21:30:04", + "2025-03-20T21:30:35", + "2025-03-20T21:31:06", + "2025-03-20T21:31:37", + "2025-03-20T21:32:07", + "2025-03-20T21:32:38", + "2025-03-20T21:33:09", + "2025-03-20T21:33:40", + "2025-03-20T21:34:10", + "2025-03-20T21:34:41", + "2025-03-20T21:35:12", + "2025-03-20T21:35:43", + "2025-03-20T21:36:14", + "2025-03-20T21:36:44", + "2025-03-20T21:37:15", + "2025-03-20T21:37:46", + "2025-03-20T21:38:17", + "2025-03-20T21:38:47", + "2025-03-20T21:39:18", + "2025-03-20T21:39:49", + "2025-03-20T21:40:20", + "2025-03-20T21:40:50", + "2025-03-20T21:41:21", + "2025-03-20T21:41:52", + "2025-03-20T21:42:23", + "2025-03-20T21:42:54", + "2025-03-20T21:43:24", + "2025-03-20T21:43:55", + "2025-03-20T21:44:26", + "2025-03-20T21:44:57", + "2025-03-20T21:45:27", + "2025-03-20T21:45:58", + "2025-03-20T21:46:29", + "2025-03-20T21:47:00", + "2025-03-20T21:47:31", + "2025-03-20T21:48:01", + "2025-03-20T21:48:32", + "2025-03-20T21:49:03", + "2025-03-20T21:49:34", + "2025-03-20T21:50:04", + "2025-03-20T21:50:35", + "2025-03-20T21:51:06", + "2025-03-20T21:51:37", + "2025-03-20T21:52:08", + "2025-03-20T21:52:38", + "2025-03-20T21:53:10", + "2025-03-20T21:53:40", + "2025-03-20T21:54:11", + "2025-03-20T21:54:42", + "2025-03-20T21:55:13", + "2025-03-20T21:55:43", + "2025-03-20T21:56:14", + "2025-03-20T21:56:45", + "2025-03-20T21:57:16", + "2025-03-20T21:57:47", + "2025-03-20T21:58:17", + "2025-03-20T21:58:48", + "2025-03-20T21:59:19", + "2025-03-20T21:59:50", + "2025-03-20T22:00:20", + "2025-03-20T22:00:51", + "2025-03-20T22:01:22", + "2025-03-20T22:01:53", + "2025-03-20T22:02:24", + "2025-03-20T22:02:54", + "2025-03-20T22:03:25", + "2025-03-20T22:03:56", + "2025-03-20T22:04:27", + "2025-03-20T22:04:57", + "2025-03-20T22:05:28", + "2025-03-20T22:05:59", + "2025-03-20T22:06:30", + "2025-03-20T22:07:01", + "2025-03-20T22:07:31", + "2025-03-20T22:08:02", + "2025-03-20T22:08:33", + "2025-03-20T22:09:04", + "2025-03-20T22:09:34", + "2025-03-20T22:10:05", + "2025-03-20T22:10:36", + "2025-03-20T22:11:07", + "2025-03-20T22:11:38", + "2025-03-20T22:12:08", + "2025-03-20T22:12:39", + "2025-03-20T22:13:10", + "2025-03-20T22:13:41", + "2025-03-20T22:14:11", + "2025-03-20T22:14:42", + "2025-03-20T22:15:13", + "2025-03-20T22:15:44", + "2025-03-20T22:16:15", + "2025-03-20T22:16:45", + "2025-03-20T22:17:16", + "2025-03-20T22:17:47", + "2025-03-20T22:18:18", + "2025-03-20T22:18:48", + "2025-03-20T22:19:19", + "2025-03-20T22:19:50", + "2025-03-20T22:20:21", + "2025-03-20T22:20:52", + "2025-03-20T22:21:22", + "2025-03-20T22:21:53", + "2025-03-20T22:22:24", + "2025-03-20T22:22:55", + "2025-03-20T22:23:25", + "2025-03-20T22:23:56", + "2025-03-20T22:24:27", + "2025-03-20T22:24:58", + "2025-03-20T22:25:29", + "2025-03-20T22:25:59", + "2025-03-20T22:26:30", + "2025-03-20T22:27:01", + "2025-03-20T22:27:32", + "2025-03-20T22:28:02", + "2025-03-20T22:28:33", + "2025-03-20T22:29:04", + "2025-03-20T22:29:35", + "2025-03-20T22:30:06", + "2025-03-20T22:30:36", + "2025-03-20T22:31:07", + "2025-03-20T22:31:38", + "2025-03-20T22:32:09", + "2025-03-20T22:32:39", + "2025-03-20T22:33:10", + "2025-03-20T22:33:41", + "2025-03-20T22:34:12", + "2025-03-20T22:34:43", + "2025-03-20T22:35:13", + "2025-03-20T22:35:44", + "2025-03-20T22:36:15", + "2025-03-20T22:36:46", + "2025-03-20T22:37:16", + "2025-03-20T22:37:47", + "2025-03-20T22:38:18", + "2025-03-20T22:38:49", + "2025-03-20T22:39:19", + "2025-03-20T22:39:50", + "2025-03-20T22:40:21", + "2025-03-20T22:40:52", + "2025-03-20T22:41:23", + "2025-03-20T22:41:53", + "2025-03-20T22:42:24", + "2025-03-20T22:42:55", + "2025-03-20T22:43:26", + "2025-03-20T22:43:57", + "2025-03-20T22:44:28", + "2025-03-20T22:44:58", + "2025-03-20T22:45:29", + "2025-03-20T22:46:00", + "2025-03-20T22:46:31", + "2025-03-20T22:47:02", + "2025-03-20T22:47:32", + "2025-03-20T22:48:03", + "2025-03-20T22:48:34", + "2025-03-20T22:49:05", + "2025-03-20T22:49:35", + "2025-03-20T22:50:06", + "2025-03-20T22:50:37", + "2025-03-20T22:51:08", + "2025-03-20T22:51:39", + "2025-03-20T22:52:09", + "2025-03-20T22:52:40", + "2025-03-20T22:53:11", + "2025-03-20T22:53:42", + "2025-03-20T22:54:12", + "2025-03-20T22:54:43", + "2025-03-20T22:55:14", + "2025-03-20T22:55:45", + "2025-03-20T22:56:16", + "2025-03-20T22:56:46", + "2025-03-20T22:57:17", + "2025-03-20T22:57:48", + "2025-03-20T22:58:19", + "2025-03-20T22:58:49", + "2025-03-20T22:59:20", + "2025-03-20T22:59:51", + "2025-03-20T23:00:22", + "2025-03-20T23:00:53", + "2025-03-20T23:01:23", + "2025-03-20T23:01:54", + "2025-03-20T23:02:25", + "2025-03-20T23:02:56", + "2025-03-20T23:03:26", + "2025-03-20T23:03:57", + "2025-03-20T23:04:28", + "2025-03-20T23:04:59", + "2025-03-20T23:05:30", + "2025-03-20T23:06:00", + "2025-03-20T23:06:31", + "2025-03-20T23:07:02", + "2025-03-20T23:07:33", + "2025-03-20T23:08:03", + "2025-03-20T23:08:34", + "2025-03-20T23:09:05", + "2025-03-20T23:09:36", + "2025-03-20T23:10:07", + "2025-03-20T23:10:37", + "2025-03-20T23:11:08", + "2025-03-20T23:11:39", + "2025-03-20T23:12:10", + "2025-03-20T23:12:40", + "2025-03-20T23:13:11", + "2025-03-20T23:13:42", + "2025-03-20T23:14:13", + "2025-03-20T23:14:44", + "2025-03-20T23:15:14", + "2025-03-20T23:15:45", + "2025-03-20T23:16:16", + "2025-03-20T23:16:47", + "2025-03-20T23:17:17", + "2025-03-20T23:17:48", + "2025-03-20T23:18:19", + "2025-03-20T23:18:50", + "2025-03-20T23:19:21", + "2025-03-20T23:19:51", + "2025-03-20T23:20:22", + "2025-03-20T23:20:53", + "2025-03-20T23:21:24", + "2025-03-20T23:21:54", + "2025-03-20T23:22:25", + "2025-03-20T23:22:56", + "2025-03-20T23:23:27", + "2025-03-20T23:23:58", + "2025-03-20T23:24:28", + "2025-03-20T23:24:59", + "2025-03-20T23:25:30", + "2025-03-20T23:26:01", + "2025-03-20T23:26:31", + "2025-03-20T23:27:02", + "2025-03-20T23:27:33", + "2025-03-20T23:28:04", + "2025-03-20T23:28:35", + "2025-03-20T23:29:05", + "2025-03-20T23:29:36", + "2025-03-20T23:30:07", + "2025-03-20T23:30:38", + "2025-03-20T23:31:08", + "2025-03-20T23:31:39", + "2025-03-20T23:32:10", + "2025-03-20T23:32:41", + "2025-03-20T23:33:11", + "2025-03-20T23:33:43", + "2025-03-20T23:34:13", + "2025-03-20T23:34:44", + "2025-03-20T23:35:15", + "2025-03-20T23:35:46", + "2025-03-20T23:36:17", + "2025-03-20T23:36:47", + "2025-03-20T23:37:18", + "2025-03-20T23:37:49", + "2025-03-20T23:38:20", + "2025-03-20T23:38:50", + "2025-03-20T23:39:21", + "2025-03-20T23:39:52", + "2025-03-20T23:40:23", + "2025-03-20T23:40:54", + "2025-03-20T23:41:24", + "2025-03-20T23:41:55", + "2025-03-20T23:42:26", + "2025-03-20T23:42:57", + "2025-03-20T23:43:27", + "2025-03-20T23:43:58", + "2025-03-20T23:44:29", + "2025-03-20T23:45:00", + "2025-03-20T23:45:31", + "2025-03-20T23:46:01", + "2025-03-20T23:46:32", + "2025-03-20T23:47:03", + "2025-03-20T23:47:34", + "2025-03-20T23:48:04", + "2025-03-20T23:48:35", + "2025-03-20T23:49:06", + "2025-03-20T23:49:37", + "2025-03-20T23:50:08", + "2025-03-20T23:50:38", + "2025-03-20T23:51:09", + "2025-03-20T23:51:40", + "2025-03-20T23:52:11", + "2025-03-20T23:52:41", + "2025-03-20T23:53:12", + "2025-03-20T23:53:43", + "2025-03-20T23:54:14", + "2025-03-20T23:54:45", + "2025-03-20T23:55:15", + "2025-03-20T23:55:46", + "2025-03-20T23:56:17", + "2025-03-20T23:56:48", + "2025-03-20T23:57:18", + "2025-03-20T23:57:49", + "2025-03-20T23:58:20", + "2025-03-20T23:58:51", + "2025-03-20T23:59:22", + "2025-03-20T23:59:52", + "2025-03-21T00:00:23", + "2025-03-21T00:00:54", + "2025-03-21T00:01:25", + "2025-03-21T00:01:55", + "2025-03-21T00:02:26", + "2025-03-21T00:02:57", + "2025-03-21T00:03:28", + "2025-03-21T00:03:59", + "2025-03-21T00:04:29", + "2025-03-21T00:05:00", + "2025-03-21T00:05:31", + "2025-03-21T00:06:02", + "2025-03-21T00:06:32", + "2025-03-21T00:07:03", + "2025-03-21T00:07:34", + "2025-03-21T00:08:05", + "2025-03-21T00:08:36", + "2025-03-21T00:09:06", + "2025-03-21T00:09:37", + "2025-03-21T00:10:08", + "2025-03-21T00:10:39", + "2025-03-21T00:11:09", + "2025-03-21T00:11:40", + "2025-03-21T00:12:11", + "2025-03-21T00:12:42", + "2025-03-21T00:13:13", + "2025-03-21T00:13:43", + "2025-03-21T00:14:14", + "2025-03-21T00:14:45", + "2025-03-21T00:15:16", + "2025-03-21T00:15:46", + "2025-03-21T00:16:17", + "2025-03-21T00:16:48", + "2025-03-21T00:17:19", + "2025-03-21T00:17:50", + "2025-03-21T00:18:20", + "2025-03-21T00:18:51", + "2025-03-21T00:19:22", + "2025-03-21T00:19:53", + "2025-03-21T00:20:23", + "2025-03-21T00:20:54", + "2025-03-21T00:21:25", + "2025-03-21T00:21:56", + "2025-03-21T00:22:27", + "2025-03-21T00:22:57", + "2025-03-21T00:23:28", + "2025-03-21T00:23:59", + "2025-03-21T00:24:30", + "2025-03-21T00:25:01", + "2025-03-21T00:25:32", + "2025-03-21T00:26:02", + "2025-03-21T00:26:33", + "2025-03-21T00:27:04", + "2025-03-21T00:27:35", + "2025-03-21T00:28:05", + "2025-03-21T00:28:36", + "2025-03-21T00:29:07", + "2025-03-21T00:29:38", + "2025-03-21T00:30:09", + "2025-03-21T00:30:39", + "2025-03-21T00:31:10", + "2025-03-21T00:31:41", + "2025-03-21T00:32:12", + "2025-03-21T00:32:42", + "2025-03-21T00:33:13", + "2025-03-21T00:33:44", + "2025-03-21T00:34:15", + "2025-03-21T00:34:46", + "2025-03-21T00:35:16", + "2025-03-21T00:35:47", + "2025-03-21T00:36:18", + "2025-03-21T00:36:49", + "2025-03-21T00:37:19", + "2025-03-21T00:37:50", + "2025-03-21T00:38:21", + "2025-03-21T00:38:52", + "2025-03-21T00:39:23", + "2025-03-21T00:39:53", + "2025-03-21T00:40:24", + "2025-03-21T00:40:55", + "2025-03-21T00:41:26", + "2025-03-21T00:41:56", + "2025-03-21T00:42:27", + "2025-03-21T00:42:58", + "2025-03-21T00:43:29", + "2025-03-21T00:44:00", + "2025-03-21T00:44:30", + "2025-03-21T00:45:01", + "2025-03-21T00:45:32", + "2025-03-21T00:46:03", + "2025-03-21T00:46:33", + "2025-03-21T00:47:04", + "2025-03-21T00:47:35", + "2025-03-21T00:48:06", + "2025-03-21T00:48:37", + "2025-03-21T00:49:07", + "2025-03-21T00:49:38", + "2025-03-21T00:50:09", + "2025-03-21T00:50:40", + "2025-03-21T00:51:10", + "2025-03-21T00:51:41", + "2025-03-21T00:52:12", + "2025-03-21T00:52:43", + "2025-03-21T00:53:14", + "2025-03-21T00:53:44", + "2025-03-21T00:54:15", + "2025-03-21T00:54:46", + "2025-03-21T00:55:17", + "2025-03-21T00:55:47", + "2025-03-21T00:56:18", + "2025-03-21T00:56:49", + "2025-03-21T00:57:20", + "2025-03-21T00:57:51", + "2025-03-21T00:58:21", + "2025-03-21T00:58:52", + "2025-03-21T00:59:23", + "2025-03-21T00:59:54", + "2025-03-21T01:00:24", + "2025-03-21T01:00:55", + "2025-03-21T01:01:26", + "2025-03-21T01:01:57", + "2025-03-21T01:02:28", + "2025-03-21T01:02:58", + "2025-03-21T01:03:29", + "2025-03-21T01:04:00", + "2025-03-21T01:04:31", + "2025-03-21T01:05:01", + "2025-03-21T01:05:32", + "2025-03-21T01:06:03", + "2025-03-21T01:06:34", + "2025-03-21T01:07:05", + "2025-03-21T01:07:35", + "2025-03-21T01:08:06", + "2025-03-21T01:08:37", + "2025-03-21T01:09:08", + "2025-03-21T01:09:38", + "2025-03-21T01:10:09", + "2025-03-21T01:10:40", + "2025-03-21T01:11:11", + "2025-03-21T01:11:42", + "2025-03-21T01:12:12", + "2025-03-21T01:12:43", + "2025-03-21T01:13:14", + "2025-03-21T01:13:45", + "2025-03-21T01:14:16", + "2025-03-21T01:14:47", + "2025-03-21T01:15:17", + "2025-03-21T01:15:48", + "2025-03-21T01:16:19", + "2025-03-21T01:16:50", + "2025-03-21T01:17:20", + "2025-03-21T01:17:51", + "2025-03-21T01:18:22", + "2025-03-21T01:18:53", + "2025-03-21T01:19:24", + "2025-03-21T01:19:54", + "2025-03-21T01:20:25", + "2025-03-21T01:20:56", + "2025-03-21T01:21:27", + "2025-03-21T01:21:57", + "2025-03-21T01:22:28", + "2025-03-21T01:22:59", + "2025-03-21T01:23:30", + "2025-03-21T01:24:01", + "2025-03-21T01:24:31", + "2025-03-21T01:25:02", + "2025-03-21T01:25:33", + "2025-03-21T01:26:04", + "2025-03-21T01:26:34", + "2025-03-21T01:27:05", + "2025-03-21T01:27:36", + "2025-03-21T01:28:07", + "2025-03-21T01:28:38", + "2025-03-21T01:29:08", + "2025-03-21T01:29:39", + "2025-03-21T01:30:10", + "2025-03-21T01:30:41", + "2025-03-21T01:31:11", + "2025-03-21T01:31:42", + "2025-03-21T01:32:13", + "2025-03-21T01:32:44", + "2025-03-21T01:33:15", + "2025-03-21T01:33:45", + "2025-03-21T01:34:16", + "2025-03-21T01:34:47", + "2025-03-21T01:35:18", + "2025-03-21T01:35:48", + "2025-03-21T01:36:19", + "2025-03-21T01:36:50", + "2025-03-21T01:37:21", + "2025-03-21T01:37:52", + "2025-03-21T01:38:22", + "2025-03-21T01:38:53", + "2025-03-21T01:39:24", + "2025-03-21T01:39:55", + "2025-03-21T01:40:25", + "2025-03-21T01:40:56", + "2025-03-21T01:41:27", + "2025-03-21T01:41:58", + "2025-03-21T01:42:29", + "2025-03-21T01:42:59", + "2025-03-21T01:43:30", + "2025-03-21T01:44:01", + "2025-03-21T01:44:32", + "2025-03-21T01:45:02", + "2025-03-21T01:45:33", + "2025-03-21T01:46:04", + "2025-03-21T01:46:35", + "2025-03-21T01:47:06", + "2025-03-21T01:47:36", + "2025-03-21T01:48:07", + "2025-03-21T01:48:38", + "2025-03-21T01:49:09", + "2025-03-21T01:49:39", + "2025-03-21T01:50:10", + "2025-03-21T01:50:41", + "2025-03-21T01:51:12", + "2025-03-21T01:51:43", + "2025-03-21T01:52:13", + "2025-03-21T01:52:44", + "2025-03-21T01:53:15", + "2025-03-21T01:53:46", + "2025-03-21T01:54:16", + "2025-03-21T01:54:47", + "2025-03-21T01:55:18", + "2025-03-21T01:55:49", + "2025-03-21T01:56:20", + "2025-03-21T01:56:50", + "2025-03-21T01:57:21", + "2025-03-21T01:57:52", + "2025-03-21T01:58:23", + "2025-03-21T01:58:53", + "2025-03-21T01:59:24", + "2025-03-21T01:59:55", + "2025-03-21T02:00:26", + "2025-03-21T02:00:57", + "2025-03-21T02:01:27", + "2025-03-21T02:01:58", + "2025-03-21T02:02:29", + "2025-03-21T02:03:00", + "2025-03-21T02:03:30", + "2025-03-21T02:04:01", + "2025-03-21T02:04:32", + "2025-03-21T02:05:03", + "2025-03-21T02:05:34", + "2025-03-21T02:06:05", + "2025-03-21T02:06:36", + "2025-03-21T02:07:06", + "2025-03-21T02:07:37", + "2025-03-21T02:08:08", + "2025-03-21T02:08:39", + "2025-03-21T02:09:09", + "2025-03-21T02:09:40", + "2025-03-21T02:10:11", + "2025-03-21T02:10:42", + "2025-03-21T02:11:13", + "2025-03-21T02:11:43", + "2025-03-21T02:12:14", + "2025-03-21T02:12:45", + "2025-03-21T02:13:16", + "2025-03-21T02:13:46", + "2025-03-21T02:14:17", + "2025-03-21T02:14:48", + "2025-03-21T02:15:19", + "2025-03-21T02:15:50", + "2025-03-21T02:16:20", + "2025-03-21T02:16:51", + "2025-03-21T02:17:22", + "2025-03-21T02:17:53", + "2025-03-21T02:18:23", + "2025-03-21T02:18:54", + "2025-03-21T02:19:25", + "2025-03-21T02:19:56", + "2025-03-21T02:20:27", + "2025-03-21T02:20:57", + "2025-03-21T02:21:28", + "2025-03-21T02:21:59", + "2025-03-21T02:22:30", + "2025-03-21T02:23:00", + "2025-03-21T02:23:31", + "2025-03-21T02:24:02", + "2025-03-21T02:24:33", + "2025-03-21T02:25:04", + "2025-03-21T02:25:34", + "2025-03-21T02:26:05", + "2025-03-21T02:26:36", + "2025-03-21T02:27:07", + "2025-03-21T02:27:37", + "2025-03-21T02:28:08", + "2025-03-21T02:28:39", + "2025-03-21T02:29:10", + "2025-03-21T02:29:41", + "2025-03-21T02:30:11", + "2025-03-21T02:30:42", + "2025-03-21T02:31:13", + "2025-03-21T02:31:44", + "2025-03-21T02:32:14", + "2025-03-21T02:32:45", + "2025-03-21T02:33:16", + "2025-03-21T02:33:47", + "2025-03-21T02:34:18", + "2025-03-21T02:34:48", + "2025-03-21T02:35:19", + "2025-03-21T02:35:50", + "2025-03-21T02:36:21", + "2025-03-21T02:36:51", + "2025-03-21T02:37:22", + "2025-03-21T02:37:53", + "2025-03-21T02:38:24", + "2025-03-21T02:38:55", + "2025-03-21T02:39:25", + "2025-03-21T02:39:56", + "2025-03-21T02:40:27", + "2025-03-21T02:40:58", + "2025-03-21T02:41:28", + "2025-03-21T02:41:59", + "2025-03-21T02:42:30", + "2025-03-21T02:43:01", + "2025-03-21T02:43:32", + "2025-03-21T02:44:02", + "2025-03-21T02:44:33", + "2025-03-21T02:45:04", + "2025-03-21T02:45:35", + "2025-03-21T02:46:05", + "2025-03-21T02:46:36", + "2025-03-21T02:47:07", + "2025-03-21T02:47:38", + "2025-03-21T02:48:09", + "2025-03-21T02:48:39", + "2025-03-21T02:49:10", + "2025-03-21T02:49:41", + "2025-03-21T02:50:12", + "2025-03-21T02:50:42", + "2025-03-21T02:51:13", + "2025-03-21T02:51:44", + "2025-03-21T02:52:15", + "2025-03-21T02:52:46", + "2025-03-21T02:53:16", + "2025-03-21T02:53:47", + "2025-03-21T02:54:18", + "2025-03-21T02:54:49", + "2025-03-21T02:55:20", + "2025-03-21T02:55:51", + "2025-03-21T02:56:21", + "2025-03-21T02:56:52", + "2025-03-21T02:57:23", + "2025-03-21T02:57:54", + "2025-03-21T02:58:25", + "2025-03-21T02:58:55", + "2025-03-21T02:59:26", + "2025-03-21T02:59:57", + "2025-03-21T03:00:28", + "2025-03-21T03:00:58", + "2025-03-21T03:01:29", + "2025-03-21T03:02:00", + "2025-03-21T03:02:31", + "2025-03-21T03:03:02", + "2025-03-21T03:03:32", + "2025-03-21T03:04:03", + "2025-03-21T03:04:34", + "2025-03-21T03:05:05", + "2025-03-21T03:05:35", + "2025-03-21T03:06:06", + "2025-03-21T03:06:37", + "2025-03-21T03:07:08", + "2025-03-21T03:07:39", + "2025-03-21T03:08:09", + "2025-03-21T03:08:40", + "2025-03-21T03:09:11", + "2025-03-21T03:09:42", + "2025-03-21T03:10:12", + "2025-03-21T03:10:43", + "2025-03-21T03:11:14", + "2025-03-21T03:11:45", + "2025-03-21T03:12:16", + "2025-03-21T03:12:46", + "2025-03-21T03:13:17", + "2025-03-21T03:13:48", + "2025-03-21T03:14:19", + "2025-03-21T03:14:49", + "2025-03-21T03:15:20", + "2025-03-21T03:15:51", + "2025-03-21T03:16:22", + "2025-03-21T03:16:53", + "2025-03-21T03:17:23", + "2025-03-21T03:17:54", + "2025-03-21T03:18:25", + "2025-03-21T03:18:56", + "2025-03-21T03:19:26", + "2025-03-21T03:19:57", + "2025-03-21T03:20:28", + "2025-03-21T03:20:59", + "2025-03-21T03:21:30", + "2025-03-21T03:22:00", + "2025-03-21T03:22:31", + "2025-03-21T03:23:02", + "2025-03-21T03:23:33", + "2025-03-21T03:24:03", + "2025-03-21T03:24:34", + "2025-03-21T03:25:05", + "2025-03-21T03:25:36", + "2025-03-21T03:26:07", + "2025-03-21T03:26:37", + "2025-03-21T03:27:08", + "2025-03-21T03:27:39", + "2025-03-21T03:28:10", + "2025-03-21T03:28:40", + "2025-03-21T03:29:11", + "2025-03-21T03:29:42", + "2025-03-21T03:30:13", + "2025-03-21T03:30:44", + "2025-03-21T03:31:14", + "2025-03-21T03:31:45", + "2025-03-21T03:32:16", + "2025-03-21T03:32:47", + "2025-03-21T03:33:17", + "2025-03-21T03:33:48", + "2025-03-21T03:34:19", + "2025-03-21T03:34:50", + "2025-03-21T03:35:21", + "2025-03-21T03:35:51", + "2025-03-21T03:36:22", + "2025-03-21T03:36:53", + "2025-03-21T03:37:24", + "2025-03-21T03:37:54", + "2025-03-21T03:38:25", + "2025-03-21T03:38:56", + "2025-03-21T03:39:27", + "2025-03-21T03:39:58", + "2025-03-21T03:40:28", + "2025-03-21T03:40:59", + "2025-03-21T03:41:30", + "2025-03-21T03:42:01", + "2025-03-21T03:42:31", + "2025-03-21T03:43:02", + "2025-03-21T03:43:33", + "2025-03-21T03:44:04", + "2025-03-21T03:44:35", + "2025-03-21T03:45:06", + "2025-03-21T03:45:37", + "2025-03-21T03:46:07", + "2025-03-21T03:46:38", + "2025-03-21T03:47:09", + "2025-03-21T03:47:40", + "2025-03-21T03:48:10", + "2025-03-21T03:48:41", + "2025-03-21T03:49:12", + "2025-03-21T03:49:43", + "2025-03-21T03:50:14", + "2025-03-21T03:50:44", + "2025-03-21T03:51:15", + "2025-03-21T03:51:46", + "2025-03-21T03:52:17", + "2025-03-21T03:52:47", + "2025-03-21T03:53:18", + "2025-03-21T03:53:49", + "2025-03-21T03:54:20", + "2025-03-21T03:54:51", + "2025-03-21T03:55:21", + "2025-03-21T03:55:52", + "2025-03-21T03:56:23", + "2025-03-21T03:56:54", + "2025-03-21T03:57:24", + "2025-03-21T03:57:55", + "2025-03-21T03:58:26", + "2025-03-21T03:58:57", + "2025-03-21T03:59:28", + "2025-03-21T03:59:58", + "2025-03-21T04:00:29", + "2025-03-21T04:01:00", + "2025-03-21T04:01:31", + "2025-03-21T04:02:01", + "2025-03-21T04:02:32", + "2025-03-21T04:03:03", + "2025-03-21T04:03:34", + "2025-03-21T04:04:05", + "2025-03-21T04:04:35", + "2025-03-21T04:05:06", + "2025-03-21T04:05:37", + "2025-03-21T04:06:08", + "2025-03-21T04:06:38", + "2025-03-21T04:07:09", + "2025-03-21T04:07:40", + "2025-03-21T04:08:11", + "2025-03-21T04:08:42", + "2025-03-21T04:09:12", + "2025-03-21T04:09:43", + "2025-03-21T04:10:14", + "2025-03-21T04:10:45", + "2025-03-21T04:11:15", + "2025-03-21T04:11:46", + "2025-03-21T04:12:17", + "2025-03-21T04:12:48", + "2025-03-21T04:13:19", + "2025-03-21T04:13:49", + "2025-03-21T04:14:20", + "2025-03-21T04:14:51", + "2025-03-21T04:15:22", + "2025-03-21T04:15:52", + "2025-03-21T04:16:23", + "2025-03-21T04:16:54", + "2025-03-21T04:17:25", + "2025-03-21T04:17:56", + "2025-03-21T04:18:26", + "2025-03-21T04:18:57", + "2025-03-21T04:19:28", + "2025-03-21T04:19:59", + "2025-03-21T04:20:29", + "2025-03-21T04:21:00", + "2025-03-21T04:21:31", + "2025-03-21T04:22:02", + "2025-03-21T04:22:33", + "2025-03-21T04:23:03", + "2025-03-21T04:23:34", + "2025-03-21T04:24:05", + "2025-03-21T04:24:36", + "2025-03-21T04:25:06", + "2025-03-21T04:25:37", + "2025-03-21T04:26:08", + "2025-03-21T04:26:39", + "2025-03-21T04:27:10", + "2025-03-21T04:27:40", + "2025-03-21T04:28:11", + "2025-03-21T04:28:42", + "2025-03-21T04:29:13", + "2025-03-21T04:29:43", + "2025-03-21T04:30:14", + "2025-03-21T04:30:45", + "2025-03-21T04:31:16", + "2025-03-21T04:31:47", + "2025-03-21T04:32:17", + "2025-03-21T04:32:48", + "2025-03-21T04:33:19", + "2025-03-21T04:33:50", + "2025-03-21T04:34:20", + "2025-03-21T04:34:51", + "2025-03-21T04:35:22", + "2025-03-21T04:35:53", + "2025-03-21T04:36:24", + "2025-03-21T04:36:55", + "2025-03-21T04:37:26", + "2025-03-21T04:37:56", + "2025-03-21T04:38:27", + "2025-03-21T04:38:58", + "2025-03-21T04:39:29", + "2025-03-21T04:39:59", + "2025-03-21T04:40:30", + "2025-03-21T04:41:01", + "2025-03-21T04:41:32", + "2025-03-21T04:42:03", + "2025-03-21T04:42:33", + "2025-03-21T04:43:04", + "2025-03-21T04:43:35", + "2025-03-21T04:44:06", + "2025-03-21T04:44:36", + "2025-03-21T04:45:07", + "2025-03-21T04:45:38", + "2025-03-21T04:46:09", + "2025-03-21T04:46:40", + "2025-03-21T04:47:10", + "2025-03-21T04:47:41", + "2025-03-21T04:48:12", + "2025-03-21T04:48:43", + "2025-03-21T04:49:13", + "2025-03-21T04:49:44", + "2025-03-21T04:50:15", + "2025-03-21T04:50:46", + "2025-03-21T04:51:17", + "2025-03-21T04:51:47", + "2025-03-21T04:52:18", + "2025-03-21T04:52:49", + "2025-03-21T04:53:20", + "2025-03-21T04:53:50", + "2025-03-21T04:54:21", + "2025-03-21T04:54:52", + "2025-03-21T04:55:23", + "2025-03-21T04:55:54", + "2025-03-21T04:56:24", + "2025-03-21T04:56:55", + "2025-03-21T04:57:26", + "2025-03-21T04:57:57", + "2025-03-21T04:58:27", + "2025-03-21T04:58:58", + "2025-03-21T04:59:29", + "2025-03-21T05:00:00", + "2025-03-21T05:00:31", + "2025-03-21T05:01:01", + "2025-03-21T05:01:32", + "2025-03-21T05:02:03", + "2025-03-21T05:02:34", + "2025-03-21T05:03:04", + "2025-03-21T05:03:35", + "2025-03-21T05:04:06", + "2025-03-21T05:04:37", + "2025-03-21T05:05:08", + "2025-03-21T05:05:38", + "2025-03-21T05:06:09", + "2025-03-21T05:06:40", + "2025-03-21T05:07:11", + "2025-03-21T05:07:41", + "2025-03-21T05:08:12", + "2025-03-21T05:08:43", + "2025-03-21T05:09:14", + "2025-03-21T05:09:45", + "2025-03-21T05:10:15", + "2025-03-21T05:10:46", + "2025-03-21T05:11:17", + "2025-03-21T05:11:48", + "2025-03-21T05:12:18", + "2025-03-21T05:12:49", + "2025-03-21T05:13:20", + "2025-03-21T05:13:51", + "2025-03-21T05:14:22", + "2025-03-21T05:14:52", + "2025-03-21T05:15:23", + "2025-03-21T05:15:54", + "2025-03-21T05:16:25", + "2025-03-21T05:16:56", + "2025-03-21T05:17:26", + "2025-03-21T05:17:57", + "2025-03-21T05:18:28", + "2025-03-21T05:18:59", + "2025-03-21T05:19:29", + "2025-03-21T05:20:00", + "2025-03-21T05:20:31", + "2025-03-21T05:21:02", + "2025-03-21T05:21:33", + "2025-03-21T05:22:03", + "2025-03-21T05:22:34", + "2025-03-21T05:23:05", + "2025-03-21T05:23:36", + "2025-03-21T05:24:06", + "2025-03-21T05:24:37", + "2025-03-21T05:25:08", + "2025-03-21T05:25:39", + "2025-03-21T05:26:10", + "2025-03-21T05:26:41", + "2025-03-21T05:27:11", + "2025-03-21T05:27:42", + "2025-03-21T05:28:13", + "2025-03-21T05:28:44", + "2025-03-21T05:29:15", + "2025-03-21T05:29:45", + "2025-03-21T05:30:16", + "2025-03-21T05:30:47", + "2025-03-21T05:31:18", + "2025-03-21T05:31:48", + "2025-03-21T05:32:19", + "2025-03-21T05:32:50", + "2025-03-21T05:33:21", + "2025-03-21T05:33:52", + "2025-03-21T05:34:22", + "2025-03-21T05:34:53", + "2025-03-21T05:35:24", + "2025-03-21T05:35:55", + "2025-03-21T05:36:26", + "2025-03-21T05:36:56", + "2025-03-21T05:37:27", + "2025-03-21T05:37:58", + "2025-03-21T05:38:29", + "2025-03-21T05:38:59", + "2025-03-21T05:39:30", + "2025-03-21T05:40:01", + "2025-03-21T05:40:32", + "2025-03-21T05:41:03", + "2025-03-21T05:41:33", + "2025-03-21T05:42:04", + "2025-03-21T05:42:35", + "2025-03-21T05:43:06", + "2025-03-21T05:43:36", + "2025-03-21T05:44:07", + "2025-03-21T05:44:38", + "2025-03-21T05:45:09", + "2025-03-21T05:45:40", + "2025-03-21T05:46:10", + "2025-03-21T05:46:41", + "2025-03-21T05:47:12", + "2025-03-21T05:47:43", + "2025-03-21T05:48:13", + "2025-03-21T05:48:44", + "2025-03-21T05:49:15", + "2025-03-21T05:49:46", + "2025-03-21T05:50:17", + "2025-03-21T05:50:47", + "2025-03-21T05:51:18", + "2025-03-21T05:51:49", + "2025-03-21T05:52:20", + "2025-03-21T05:52:50", + "2025-03-21T05:53:21", + "2025-03-21T05:53:52", + "2025-03-21T05:54:23", + "2025-03-21T05:54:54", + "2025-03-21T05:55:24", + "2025-03-21T05:55:55", + "2025-03-21T05:56:26", + "2025-03-21T05:56:57", + "2025-03-21T05:57:27", + "2025-03-21T05:57:58", + "2025-03-21T05:58:29", + "2025-03-21T05:59:00", + "2025-03-21T05:59:31", + "2025-03-21T06:00:01", + "2025-03-21T06:00:32", + "2025-03-21T06:01:03", + "2025-03-21T06:01:34", + "2025-03-21T06:02:04", + "2025-03-21T06:02:35", + "2025-03-21T06:03:06", + "2025-03-21T06:03:37", + "2025-03-21T06:04:08", + "2025-03-21T06:04:38", + "2025-03-21T06:05:09", + "2025-03-21T06:05:40", + "2025-03-21T06:06:11", + "2025-03-21T06:06:41", + "2025-03-21T06:07:12", + "2025-03-21T06:07:43", + "2025-03-21T06:08:14", + "2025-03-21T06:08:45", + "2025-03-21T06:09:15", + "2025-03-21T06:09:46", + "2025-03-21T06:10:17", + "2025-03-21T06:10:48", + "2025-03-21T06:11:18", + "2025-03-21T06:11:49", + "2025-03-21T06:12:20", + "2025-03-21T06:12:51", + "2025-03-21T06:13:22", + "2025-03-21T06:13:52", + "2025-03-21T06:14:23", + "2025-03-21T06:14:54", + "2025-03-21T06:15:25", + "2025-03-21T06:15:56", + "2025-03-21T06:16:27", + "2025-03-21T06:16:57", + "2025-03-21T06:17:28", + "2025-03-21T06:17:59", + "2025-03-21T06:18:30", + "2025-03-21T06:19:01", + "2025-03-21T06:19:31", + "2025-03-21T06:20:02", + "2025-03-21T06:20:33", + "2025-03-21T06:21:04", + "2025-03-21T06:21:34", + "2025-03-21T06:22:05", + "2025-03-21T06:22:36", + "2025-03-21T06:23:07", + "2025-03-21T06:23:38", + "2025-03-21T06:24:08", + "2025-03-21T06:24:39", + "2025-03-21T06:25:10", + "2025-03-21T06:25:41", + "2025-03-21T06:26:11", + "2025-03-21T06:26:42", + "2025-03-21T06:27:13", + "2025-03-21T06:27:44", + "2025-03-21T06:28:15", + "2025-03-21T06:28:45", + "2025-03-21T06:29:16", + "2025-03-21T06:29:47", + "2025-03-21T06:30:18", + "2025-03-21T06:30:48", + "2025-03-21T06:31:19", + "2025-03-21T06:31:50", + "2025-03-21T06:32:21", + "2025-03-21T06:32:52", + "2025-03-21T06:33:22", + "2025-03-21T06:33:53", + "2025-03-21T06:34:24", + "2025-03-21T06:34:55", + "2025-03-21T06:35:25", + "2025-03-21T06:35:56", + "2025-03-21T06:36:27", + "2025-03-21T06:36:58", + "2025-03-21T06:37:29", + "2025-03-21T06:37:59", + "2025-03-21T06:38:30", + "2025-03-21T06:39:01", + "2025-03-21T06:39:32", + "2025-03-21T06:40:02", + "2025-03-21T06:40:33", + "2025-03-21T06:41:04", + "2025-03-21T06:41:35", + "2025-03-21T06:42:06", + "2025-03-21T06:42:36", + "2025-03-21T06:43:07", + "2025-03-21T06:43:38", + "2025-03-21T06:44:09", + "2025-03-21T06:44:39", + "2025-03-21T06:45:10", + "2025-03-21T06:45:41", + "2025-03-21T06:46:12", + "2025-03-21T06:46:43", + "2025-03-21T06:47:13", + "2025-03-21T06:47:44", + "2025-03-21T06:48:15", + "2025-03-21T06:48:46", + "2025-03-21T06:49:16", + "2025-03-21T06:49:47", + "2025-03-21T06:50:18", + "2025-03-21T06:50:49", + "2025-03-21T06:51:20", + "2025-03-21T06:51:50", + "2025-03-21T06:52:21", + "2025-03-21T06:52:52", + "2025-03-21T06:53:23", + "2025-03-21T06:53:53", + "2025-03-21T06:54:24", + "2025-03-21T06:54:55", + "2025-03-21T06:55:26", + "2025-03-21T06:55:57", + "2025-03-21T06:56:27", + "2025-03-21T06:56:58", + "2025-03-21T06:57:29", + "2025-03-21T06:58:00", + "2025-03-21T06:58:30", + "2025-03-21T06:59:01", + "2025-03-21T06:59:32", + "2025-03-21T07:00:03", + "2025-03-21T07:00:34", + "2025-03-21T07:01:04", + "2025-03-21T07:01:35", + "2025-03-21T07:02:06", + "2025-03-21T07:02:37", + "2025-03-21T07:03:07", + "2025-03-21T07:03:38", + "2025-03-21T07:04:09", + "2025-03-21T07:04:40", + "2025-03-21T07:05:11", + "2025-03-21T07:05:41", + "2025-03-21T07:06:13", + "2025-03-21T07:06:43", + "2025-03-21T07:07:14", + "2025-03-21T07:07:45", + "2025-03-21T07:08:16", + "2025-03-21T07:08:46", + "2025-03-21T07:09:17", + "2025-03-21T07:09:48", + "2025-03-21T07:10:19", + "2025-03-21T07:10:50", + "2025-03-21T07:11:20", + "2025-03-21T07:11:51", + "2025-03-21T07:12:22", + "2025-03-21T07:12:53", + "2025-03-21T07:13:23", + "2025-03-21T07:13:54", + "2025-03-21T07:14:25", + "2025-03-21T07:14:56", + "2025-03-21T07:15:27", + "2025-03-21T07:15:57", + "2025-03-21T07:16:28", + "2025-03-21T07:16:59", + "2025-03-21T07:17:30", + "2025-03-21T07:18:00", + "2025-03-21T07:18:31", + "2025-03-21T07:19:02", + "2025-03-21T07:19:33", + "2025-03-21T07:20:04", + "2025-03-21T07:20:34", + "2025-03-21T07:21:05", + "2025-03-21T07:21:36", + "2025-03-21T07:22:07", + "2025-03-21T07:22:37", + "2025-03-21T07:23:08", + "2025-03-21T07:23:39", + "2025-03-21T07:24:10", + "2025-03-21T07:24:41", + "2025-03-21T07:25:11", + "2025-03-21T07:25:42", + "2025-03-21T07:26:13", + "2025-03-21T07:26:44", + "2025-03-21T07:27:14", + "2025-03-21T07:27:45", + "2025-03-21T07:28:16", + "2025-03-21T07:28:47", + "2025-03-21T07:29:18", + "2025-03-21T07:29:48", + "2025-03-21T07:30:19", + "2025-03-21T07:30:50", + "2025-03-21T07:31:21", + "2025-03-21T07:31:51", + "2025-03-21T07:32:22", + "2025-03-21T07:32:53", + "2025-03-21T07:33:24", + "2025-03-21T07:33:55", + "2025-03-21T07:34:25", + "2025-03-21T07:34:56", + "2025-03-21T07:35:27", + "2025-03-21T07:35:58", + "2025-03-21T07:36:28", + "2025-03-21T07:36:59", + "2025-03-21T07:37:30", + "2025-03-21T07:38:01", + "2025-03-21T07:38:32", + "2025-03-21T07:39:02", + "2025-03-21T07:39:33", + "2025-03-21T07:40:04", + "2025-03-21T07:40:35", + "2025-03-21T07:41:05", + "2025-03-21T07:41:36", + "2025-03-21T07:42:07", + "2025-03-21T07:42:38", + "2025-03-21T07:43:09", + "2025-03-21T07:43:39", + "2025-03-21T07:44:10", + "2025-03-21T07:44:41", + "2025-03-21T07:45:12", + "2025-03-21T07:45:42", + "2025-03-21T07:46:13", + "2025-03-21T07:46:44", + "2025-03-21T07:47:15", + "2025-03-21T07:47:46", + "2025-03-21T07:48:16", + "2025-03-21T07:48:47", + "2025-03-21T07:49:18", + "2025-03-21T07:49:49", + "2025-03-21T07:50:19", + "2025-03-21T07:50:50", + "2025-03-21T07:51:21", + "2025-03-21T07:51:52", + "2025-03-21T07:52:23", + "2025-03-21T07:52:53", + "2025-03-21T07:53:24", + "2025-03-21T07:53:55", + "2025-03-21T07:54:26", + "2025-03-21T07:54:56", + "2025-03-21T07:55:27", + "2025-03-21T07:55:58", + "2025-03-21T07:56:29", + "2025-03-21T07:57:00", + "2025-03-21T07:57:31", + "2025-03-21T07:58:02", + "2025-03-21T07:58:32", + "2025-03-21T07:59:03", + "2025-03-21T07:59:34", + "2025-03-21T08:00:05", + "2025-03-21T08:00:35", + "2025-03-21T08:01:06", + "2025-03-21T08:01:37", + "2025-03-21T08:02:08", + "2025-03-21T08:02:39", + "2025-03-21T08:03:09", + "2025-03-21T08:03:40", + "2025-03-21T08:04:11", + "2025-03-21T08:04:42", + "2025-03-21T08:05:12", + "2025-03-21T08:05:43", + "2025-03-21T08:06:14", + "2025-03-21T08:06:45", + "2025-03-21T08:07:16", + "2025-03-21T08:07:46", + "2025-03-21T08:08:17", + "2025-03-21T08:08:48", + "2025-03-21T08:09:19", + "2025-03-21T08:09:49", + "2025-03-21T08:10:20", + "2025-03-21T08:10:51", + "2025-03-21T08:11:22", + "2025-03-21T08:11:53", + "2025-03-21T08:12:23", + "2025-03-21T08:12:54", + "2025-03-21T08:13:25", + "2025-03-21T08:13:56", + "2025-03-21T08:14:26", + "2025-03-21T08:14:57", + "2025-03-21T08:15:28", + "2025-03-21T08:15:59", + "2025-03-21T08:16:30", + "2025-03-21T08:17:00", + "2025-03-21T08:17:31", + "2025-03-21T08:18:02", + "2025-03-21T08:18:33", + "2025-03-21T08:19:03", + "2025-03-21T08:19:34", + "2025-03-21T08:20:05", + "2025-03-21T08:20:36", + "2025-03-21T08:21:07", + "2025-03-21T08:21:37", + "2025-03-21T08:22:08", + "2025-03-21T08:22:39", + "2025-03-21T08:23:10", + "2025-03-21T08:23:40", + "2025-03-21T08:24:11", + "2025-03-21T08:24:42", + "2025-03-21T08:25:13", + "2025-03-21T08:25:44", + "2025-03-21T08:26:14", + "2025-03-21T08:26:45", + "2025-03-21T08:27:16", + "2025-03-21T08:27:47", + "2025-03-21T08:28:18", + "2025-03-21T08:28:48", + "2025-03-21T08:29:19", + "2025-03-21T08:29:50", + "2025-03-21T08:30:21", + "2025-03-21T08:30:51", + "2025-03-21T08:31:22", + "2025-03-21T08:31:53", + "2025-03-21T08:32:24", + "2025-03-21T08:32:55", + "2025-03-21T08:33:25", + "2025-03-21T08:33:56", + "2025-03-21T08:34:27", + "2025-03-21T08:34:58", + "2025-03-21T08:35:28", + "2025-03-21T08:35:59", + "2025-03-21T08:36:30", + "2025-03-21T08:37:01", + "2025-03-21T08:37:32", + "2025-03-21T08:38:02", + "2025-03-21T08:38:33", + "2025-03-21T08:39:04", + "2025-03-21T08:39:35", + "2025-03-21T08:40:05", + "2025-03-21T08:40:36", + "2025-03-21T08:41:07", + "2025-03-21T08:41:38", + "2025-03-21T08:42:09", + "2025-03-21T08:42:39", + "2025-03-21T08:43:10", + "2025-03-21T08:43:41", + "2025-03-21T08:44:12", + "2025-03-21T08:44:42", + "2025-03-21T08:45:13", + "2025-03-21T08:45:44", + "2025-03-21T08:46:15", + "2025-03-21T08:46:46", + "2025-03-21T08:47:17", + "2025-03-21T08:47:48", + "2025-03-21T08:48:18", + "2025-03-21T08:48:49", + "2025-03-21T08:49:20", + "2025-03-21T08:49:51", + "2025-03-21T08:50:21", + "2025-03-21T08:50:52", + "2025-03-21T08:51:23", + "2025-03-21T08:51:54", + "2025-03-21T08:52:25", + "2025-03-21T08:52:55", + "2025-03-21T08:53:26", + "2025-03-21T08:53:57", + "2025-03-21T08:54:28", + "2025-03-21T08:54:58", + "2025-03-21T08:55:29", + "2025-03-21T08:56:00", + "2025-03-21T08:56:31", + "2025-03-21T08:57:02", + "2025-03-21T08:57:32", + "2025-03-21T08:58:03", + "2025-03-21T08:58:34", + "2025-03-21T08:59:05", + "2025-03-21T08:59:35", + "2025-03-21T09:00:06", + "2025-03-21T09:00:37", + "2025-03-21T09:01:08", + "2025-03-21T09:01:39", + "2025-03-21T09:02:09", + "2025-03-21T09:02:40", + "2025-03-21T09:03:11", + "2025-03-21T09:03:42", + "2025-03-21T09:04:12", + "2025-03-21T09:04:43", + "2025-03-21T09:05:14", + "2025-03-21T09:05:45", + "2025-03-21T09:06:16", + "2025-03-21T09:06:46", + "2025-03-21T09:07:17", + "2025-03-21T09:07:48", + "2025-03-21T09:08:19", + "2025-03-21T09:08:49", + "2025-03-21T09:09:20", + "2025-03-21T09:09:51", + "2025-03-21T09:10:22", + "2025-03-21T09:10:53", + "2025-03-21T09:11:23", + "2025-03-21T09:11:54", + "2025-03-21T09:12:25", + "2025-03-21T09:12:56", + "2025-03-21T09:13:26", + "2025-03-21T09:13:57", + "2025-03-21T09:14:28", + "2025-03-21T09:14:59", + "2025-03-21T09:15:30", + "2025-03-21T09:16:00", + "2025-03-21T09:16:31", + "2025-03-21T09:17:02", + "2025-03-21T09:17:33", + "2025-03-21T09:18:03", + "2025-03-21T09:18:34", + "2025-03-21T09:19:05", + "2025-03-21T09:19:36", + "2025-03-21T09:20:07", + "2025-03-21T09:20:37", + "2025-03-21T09:21:08", + "2025-03-21T09:21:39", + "2025-03-21T09:22:10", + "2025-03-21T09:22:40", + "2025-03-21T09:23:11", + "2025-03-21T09:23:42", + "2025-03-21T09:24:13", + "2025-03-21T09:24:44", + "2025-03-21T09:25:14", + "2025-03-21T09:25:45", + "2025-03-21T09:26:16", + "2025-03-21T09:26:47", + "2025-03-21T09:27:17", + "2025-03-21T09:27:48", + "2025-03-21T09:28:19", + "2025-03-21T09:28:50", + "2025-03-21T09:29:21", + "2025-03-21T09:29:51", + "2025-03-21T09:30:22", + "2025-03-21T09:30:53", + "2025-03-21T09:31:24", + "2025-03-21T09:31:54", + "2025-03-21T09:32:25", + "2025-03-21T09:32:56", + "2025-03-21T09:33:27", + "2025-03-21T09:33:58", + "2025-03-21T09:34:28", + "2025-03-21T09:34:59", + "2025-03-21T09:35:30", + "2025-03-21T09:36:01", + "2025-03-21T09:36:31", + "2025-03-21T09:37:03", + "2025-03-21T09:37:33", + "2025-03-21T09:38:04", + "2025-03-21T09:38:35", + "2025-03-21T09:39:06", + "2025-03-21T09:39:37", + "2025-03-21T09:40:07", + "2025-03-21T09:40:38", + "2025-03-21T09:41:09", + "2025-03-21T09:41:40", + "2025-03-21T09:42:10", + "2025-03-21T09:42:41", + "2025-03-21T09:43:12", + "2025-03-21T09:43:43", + "2025-03-21T09:44:14", + "2025-03-21T09:44:44", + "2025-03-21T09:45:15", + "2025-03-21T09:45:46", + "2025-03-21T09:46:17", + "2025-03-21T09:46:47", + "2025-03-21T09:47:18", + "2025-03-21T09:47:49", + "2025-03-21T09:48:20", + "2025-03-21T09:48:51", + "2025-03-21T09:49:21", + "2025-03-21T09:49:52", + "2025-03-21T09:50:23", + "2025-03-21T09:50:54", + "2025-03-21T09:51:24", + "2025-03-21T09:51:55", + "2025-03-21T09:52:26", + "2025-03-21T09:52:57", + "2025-03-21T09:53:28", + "2025-03-21T09:53:58", + "2025-03-21T09:54:29", + "2025-03-21T09:55:00", + "2025-03-21T09:55:31", + "2025-03-21T09:56:01", + "2025-03-21T09:56:32", + "2025-03-21T09:57:03", + "2025-03-21T09:57:34", + "2025-03-21T09:58:05", + "2025-03-21T09:58:35", + "2025-03-21T09:59:06", + "2025-03-21T09:59:37", + "2025-03-21T10:00:08", + "2025-03-21T10:00:38", + "2025-03-21T10:01:09", + "2025-03-21T10:01:40", + "2025-03-21T10:02:11", + "2025-03-21T10:02:42", + "2025-03-21T10:03:12", + "2025-03-21T10:03:43", + "2025-03-21T10:04:14", + "2025-03-21T10:04:45", + "2025-03-21T10:05:15", + "2025-03-21T10:05:46", + "2025-03-21T10:06:17", + "2025-03-21T10:06:48", + "2025-03-21T10:07:19", + "2025-03-21T10:07:49", + "2025-03-21T10:08:20", + "2025-03-21T10:08:51", + "2025-03-21T10:09:22", + "2025-03-21T10:09:52", + "2025-03-21T10:10:23", + "2025-03-21T10:10:54", + "2025-03-21T10:11:25", + "2025-03-21T10:11:56", + "2025-03-21T10:12:26", + "2025-03-21T10:12:57", + "2025-03-21T10:13:28", + "2025-03-21T10:13:59", + "2025-03-21T10:14:29", + "2025-03-21T10:15:00", + "2025-03-21T10:15:31", + "2025-03-21T10:16:02", + "2025-03-21T10:16:33", + "2025-03-21T10:17:03", + "2025-03-21T10:17:34", + "2025-03-21T10:18:05", + "2025-03-21T10:18:36", + "2025-03-21T10:19:06", + "2025-03-21T10:19:37", + "2025-03-21T10:20:08", + "2025-03-21T10:20:39", + "2025-03-21T10:21:10", + "2025-03-21T10:21:40", + "2025-03-21T10:22:11", + "2025-03-21T10:22:42", + "2025-03-21T10:23:13", + "2025-03-21T10:23:43", + "2025-03-21T10:24:14", + "2025-03-21T10:24:45", + "2025-03-21T10:25:16", + "2025-03-21T10:25:47", + "2025-03-21T10:26:17", + "2025-03-21T10:26:48", + "2025-03-21T10:27:19", + "2025-03-21T10:27:50", + "2025-03-21T10:28:21", + "2025-03-21T10:28:52", + "2025-03-21T10:29:22", + "2025-03-21T10:29:53", + "2025-03-21T10:30:24", + "2025-03-21T10:30:55", + "2025-03-21T10:31:26", + "2025-03-21T10:31:56", + "2025-03-21T10:32:27", + "2025-03-21T10:32:58", + "2025-03-21T10:33:29", + "2025-03-21T10:33:59", + "2025-03-21T10:34:30", + "2025-03-21T10:35:01", + "2025-03-21T10:35:32", + "2025-03-21T10:36:03", + "2025-03-21T10:36:33", + "2025-03-21T10:37:04", + "2025-03-21T10:37:35", + "2025-03-21T10:38:06", + "2025-03-21T10:38:36", + "2025-03-21T10:39:07", + "2025-03-21T10:39:38", + "2025-03-21T10:40:09", + "2025-03-21T10:40:40", + "2025-03-21T10:41:10", + "2025-03-21T10:41:41", + "2025-03-21T10:42:12", + "2025-03-21T10:42:43", + "2025-03-21T10:43:13", + "2025-03-21T10:43:44", + "2025-03-21T10:44:15", + "2025-03-21T10:44:46", + "2025-03-21T10:45:17", + "2025-03-21T10:45:47", + "2025-03-21T10:46:18", + "2025-03-21T10:46:49", + "2025-03-21T10:47:20", + "2025-03-21T10:47:50", + "2025-03-21T10:48:21", + "2025-03-21T10:48:52", + "2025-03-21T10:49:23", + "2025-03-21T10:49:54", + "2025-03-21T10:50:24", + "2025-03-21T10:50:55", + "2025-03-21T10:51:26", + "2025-03-21T10:51:57", + "2025-03-21T10:52:27", + "2025-03-21T10:52:58", + "2025-03-21T10:53:29", + "2025-03-21T10:54:00", + "2025-03-21T10:54:31", + "2025-03-21T10:55:01", + "2025-03-21T10:55:32", + "2025-03-21T10:56:03", + "2025-03-21T10:56:34", + "2025-03-21T10:57:04", + "2025-03-21T10:57:35", + "2025-03-21T10:58:06", + "2025-03-21T10:58:37", + "2025-03-21T10:59:08", + "2025-03-21T10:59:38", + "2025-03-21T11:00:09", + "2025-03-21T11:00:40", + "2025-03-21T11:01:11", + "2025-03-21T11:01:41", + "2025-03-21T11:02:12", + "2025-03-21T11:02:43", + "2025-03-21T11:03:14", + "2025-03-21T11:03:45", + "2025-03-21T11:04:15", + "2025-03-21T11:04:46", + "2025-03-21T11:05:17", + "2025-03-21T11:05:48", + "2025-03-21T11:06:18", + "2025-03-21T11:06:49", + "2025-03-21T11:07:20", + "2025-03-21T11:07:51", + "2025-03-21T11:08:22", + "2025-03-21T11:08:52", + "2025-03-21T11:09:23", + "2025-03-21T11:09:54", + "2025-03-21T11:10:25", + "2025-03-21T11:10:55", + "2025-03-21T11:11:26", + "2025-03-21T11:11:57", + "2025-03-21T11:12:28", + "2025-03-21T11:12:59", + "2025-03-21T11:13:29", + "2025-03-21T11:14:00", + "2025-03-21T11:14:31", + "2025-03-21T11:15:02", + "2025-03-21T11:15:33", + "2025-03-21T11:16:03", + "2025-03-21T11:16:34", + "2025-03-21T11:17:05", + "2025-03-21T11:17:36", + "2025-03-21T11:18:07", + "2025-03-21T11:18:38", + "2025-03-21T11:19:08", + "2025-03-21T11:19:39", + "2025-03-21T11:20:10", + "2025-03-21T11:20:41", + "2025-03-21T11:21:11", + "2025-03-21T11:21:42", + "2025-03-21T11:22:13", + "2025-03-21T11:22:44", + "2025-03-21T11:23:15", + "2025-03-21T11:23:45", + "2025-03-21T11:24:16", + "2025-03-21T11:24:47", + "2025-03-21T11:25:18", + "2025-03-21T11:25:49", + "2025-03-21T11:26:19", + "2025-03-21T11:26:50", + "2025-03-21T11:27:21", + "2025-03-21T11:27:52", + "2025-03-21T11:28:22", + "2025-03-21T11:28:53", + "2025-03-21T11:29:24", + "2025-03-21T11:29:55", + "2025-03-21T11:30:26", + "2025-03-21T11:30:56", + "2025-03-21T11:31:27", + "2025-03-21T11:31:58", + "2025-03-21T11:32:29", + "2025-03-21T11:32:59", + "2025-03-21T11:33:30", + "2025-03-21T11:34:01", + "2025-03-21T11:34:32", + "2025-03-21T11:35:03", + "2025-03-21T11:35:33", + "2025-03-21T11:36:04", + "2025-03-21T11:36:35", + "2025-03-21T11:37:06", + "2025-03-21T11:37:36", + "2025-03-21T11:38:07", + "2025-03-21T11:38:38", + "2025-03-21T11:39:09", + "2025-03-21T11:39:40", + "2025-03-21T11:40:10", + "2025-03-21T11:40:41", + "2025-03-21T11:41:12", + "2025-03-21T11:41:43", + "2025-03-21T11:42:13", + "2025-03-21T11:42:44", + "2025-03-21T11:43:15", + "2025-03-21T11:43:46", + "2025-03-21T11:44:17", + "2025-03-21T11:44:47", + "2025-03-21T11:45:18", + "2025-03-21T11:45:49", + "2025-03-21T11:46:20", + "2025-03-21T11:46:50", + "2025-03-21T11:47:21", + "2025-03-21T11:47:52", + "2025-03-21T11:48:23", + "2025-03-21T11:48:54", + "2025-03-21T11:49:24", + "2025-03-21T11:49:55", + "2025-03-21T11:50:26", + "2025-03-21T11:50:57", + "2025-03-21T11:51:27", + "2025-03-21T11:51:58", + "2025-03-21T11:52:29", + "2025-03-21T11:53:00", + "2025-03-21T11:53:31", + "2025-03-21T11:54:01", + "2025-03-21T11:54:32", + "2025-03-21T11:55:03", + "2025-03-21T11:55:34", + "2025-03-21T11:56:04", + "2025-03-21T11:56:35", + "2025-03-21T11:57:06", + "2025-03-21T11:57:37", + "2025-03-21T11:58:08", + "2025-03-21T11:58:38", + "2025-03-21T11:59:09", + "2025-03-21T11:59:40", + "2025-03-21T12:00:11", + "2025-03-21T12:00:41", + "2025-03-21T12:01:12", + "2025-03-21T12:01:43", + "2025-03-21T12:02:14", + "2025-03-21T12:02:45", + "2025-03-21T12:03:15", + "2025-03-21T12:03:46", + "2025-03-21T12:04:17", + "2025-03-21T12:04:48", + "2025-03-21T12:05:18", + "2025-03-21T12:05:49", + "2025-03-21T12:06:20", + "2025-03-21T12:06:51", + "2025-03-21T12:07:22", + "2025-03-21T12:07:53", + "2025-03-21T12:08:24", + "2025-03-21T12:08:54", + "2025-03-21T12:09:25", + "2025-03-21T12:09:56", + "2025-03-21T12:10:27", + "2025-03-21T12:10:57", + "2025-03-21T12:11:28", + "2025-03-21T12:11:59", + "2025-03-21T12:12:30", + "2025-03-21T12:13:01", + "2025-03-21T12:13:31", + "2025-03-21T12:14:02", + "2025-03-21T12:14:33", + "2025-03-21T12:15:04", + "2025-03-21T12:15:34", + "2025-03-21T12:16:05", + "2025-03-21T12:16:36", + "2025-03-21T12:17:07", + "2025-03-21T12:17:38", + "2025-03-21T12:18:08", + "2025-03-21T12:18:39", + "2025-03-21T12:19:10", + "2025-03-21T12:19:41", + "2025-03-21T12:20:11", + "2025-03-21T12:20:42", + "2025-03-21T12:21:13", + "2025-03-21T12:21:44", + "2025-03-21T12:22:15", + "2025-03-21T12:22:45", + "2025-03-21T12:23:16", + "2025-03-21T12:23:47", + "2025-03-21T12:24:18", + "2025-03-21T12:24:48", + "2025-03-21T12:25:19", + "2025-03-21T12:25:50", + "2025-03-21T12:26:21", + "2025-03-21T12:26:52", + "2025-03-21T12:27:22", + "2025-03-21T12:27:53", + "2025-03-21T12:28:24", + "2025-03-21T12:28:55", + "2025-03-21T12:29:25", + "2025-03-21T12:29:56", + "2025-03-21T12:30:27", + "2025-03-21T12:30:58", + "2025-03-21T12:31:29", + "2025-03-21T12:31:59", + "2025-03-21T12:32:30", + "2025-03-21T12:33:01", + "2025-03-21T12:33:32", + "2025-03-21T12:34:02", + "2025-03-21T12:34:33", + "2025-03-21T12:35:04", + "2025-03-21T12:35:35", + "2025-03-21T12:36:06", + "2025-03-21T12:36:36", + "2025-03-21T12:37:07", + "2025-03-21T12:37:38", + "2025-03-21T12:38:09", + "2025-03-21T12:38:39", + "2025-03-21T12:39:10", + "2025-03-21T12:39:41", + "2025-03-21T12:40:12", + "2025-03-21T12:40:43", + "2025-03-21T12:41:13", + "2025-03-21T12:41:44", + "2025-03-21T12:42:15", + "2025-03-21T12:42:46", + "2025-03-21T12:43:16", + "2025-03-21T12:43:47", + "2025-03-21T12:44:18", + "2025-03-21T12:44:49", + "2025-03-21T12:45:20", + "2025-03-21T12:45:50", + "2025-03-21T12:46:21", + "2025-03-21T12:46:52", + "2025-03-21T12:47:23", + "2025-03-21T12:47:53", + "2025-03-21T12:48:24", + "2025-03-21T12:48:55", + "2025-03-21T12:49:26", + "2025-03-21T12:49:57", + "2025-03-21T12:50:27", + "2025-03-21T12:50:58", + "2025-03-21T12:51:29", + "2025-03-21T12:52:00", + "2025-03-21T12:52:30", + "2025-03-21T12:53:01", + "2025-03-21T12:53:32", + "2025-03-21T12:54:03", + "2025-03-21T12:54:34", + "2025-03-21T12:55:04", + "2025-03-21T12:55:35", + "2025-03-21T12:56:06", + "2025-03-21T12:56:37", + "2025-03-21T12:57:07", + "2025-03-21T12:57:38", + "2025-03-21T12:58:09", + "2025-03-21T12:58:40", + "2025-03-21T12:59:11", + "2025-03-21T12:59:42", + "2025-03-21T13:00:13", + "2025-03-21T13:00:43", + "2025-03-21T13:01:14", + "2025-03-21T13:01:45", + "2025-03-21T13:02:16", + "2025-03-21T13:02:46", + "2025-03-21T13:03:17", + "2025-03-21T13:03:48", + "2025-03-21T13:04:19", + "2025-03-21T13:04:50", + "2025-03-21T13:05:20", + "2025-03-21T13:05:51", + "2025-03-21T13:06:22", + "2025-03-21T13:06:53", + "2025-03-21T13:07:23", + "2025-03-21T13:07:54", + "2025-03-21T13:08:25", + "2025-03-21T13:08:56", + "2025-03-21T13:09:27", + "2025-03-21T13:09:57", + "2025-03-21T13:10:28", + "2025-03-21T13:10:59", + "2025-03-21T13:11:30", + "2025-03-21T13:12:00", + "2025-03-21T13:12:31", + "2025-03-21T13:13:02", + "2025-03-21T13:13:33", + "2025-03-21T13:14:04", + "2025-03-21T13:14:34", + "2025-03-21T13:15:05", + "2025-03-21T13:15:36", + "2025-03-21T13:16:07", + "2025-03-21T13:16:37", + "2025-03-21T13:17:08", + "2025-03-21T13:17:39", + "2025-03-21T13:18:10", + "2025-03-21T13:18:41", + "2025-03-21T13:19:11", + "2025-03-21T13:19:42", + "2025-03-21T13:20:13", + "2025-03-21T13:20:44", + "2025-03-21T13:21:14", + "2025-03-21T13:21:45", + "2025-03-21T13:22:16", + "2025-03-21T13:22:47", + "2025-03-21T13:23:18", + "2025-03-21T13:23:48", + "2025-03-21T13:24:19", + "2025-03-21T13:24:50", + "2025-03-21T13:25:21", + "2025-03-21T13:25:51", + "2025-03-21T13:26:22", + "2025-03-21T13:26:53", + "2025-03-21T13:27:24", + "2025-03-21T13:27:55", + "2025-03-21T13:28:25", + "2025-03-21T13:28:56", + "2025-03-21T13:29:27", + "2025-03-21T13:29:58", + "2025-03-21T13:30:28", + "2025-03-21T13:30:59", + "2025-03-21T13:31:30", + "2025-03-21T13:32:01", + "2025-03-21T13:32:32", + "2025-03-21T13:33:02", + "2025-03-21T13:33:33", + "2025-03-21T13:34:04", + "2025-03-21T13:34:35", + "2025-03-21T13:35:05", + "2025-03-21T13:35:36", + "2025-03-21T13:36:07", + "2025-03-21T13:36:38", + "2025-03-21T13:37:09", + "2025-03-21T13:37:39", + "2025-03-21T13:38:10", + "2025-03-21T13:38:41", + "2025-03-21T13:39:12", + "2025-03-21T13:39:42", + "2025-03-21T13:40:13", + "2025-03-21T13:40:44", + "2025-03-21T13:41:15", + "2025-03-21T13:41:46", + "2025-03-21T13:42:16", + "2025-03-21T13:42:47", + "2025-03-21T13:43:18", + "2025-03-21T13:43:49", + "2025-03-21T13:44:19", + "2025-03-21T13:44:50", + "2025-03-21T13:45:21", + "2025-03-21T13:45:52", + "2025-03-21T13:46:23", + "2025-03-21T13:46:53", + "2025-03-21T13:47:24", + "2025-03-21T13:47:55", + "2025-03-21T13:48:26", + "2025-03-21T13:48:57", + "2025-03-21T13:49:28", + "2025-03-21T13:49:58", + "2025-03-21T13:50:29", + "2025-03-21T13:51:00", + "2025-03-21T13:51:31", + "2025-03-21T13:52:02", + "2025-03-21T13:52:32", + "2025-03-21T13:53:03", + "2025-03-21T13:53:34", + "2025-03-21T13:54:05", + "2025-03-21T13:54:35", + "2025-03-21T13:55:06", + "2025-03-21T13:55:37", + "2025-03-21T13:56:08", + "2025-03-21T13:56:39", + "2025-03-21T13:57:09", + "2025-03-21T13:57:40", + "2025-03-21T13:58:11", + "2025-03-21T13:58:42", + "2025-03-21T13:59:12", + "2025-03-21T13:59:43", + "2025-03-21T14:00:14", + "2025-03-21T14:00:45", + "2025-03-21T14:01:16", + "2025-03-21T14:01:46", + "2025-03-21T14:02:17", + "2025-03-21T14:02:48", + "2025-03-21T14:03:19", + "2025-03-21T14:03:50", + "2025-03-21T14:04:20", + "2025-03-21T14:04:51", + "2025-03-21T14:05:22", + "2025-03-21T14:05:53", + "2025-03-21T14:06:23", + "2025-03-21T14:06:54", + "2025-03-21T14:07:25", + "2025-03-21T14:07:56", + "2025-03-21T14:08:27", + "2025-03-21T14:08:57", + "2025-03-21T14:09:28", + "2025-03-21T14:09:59", + "2025-03-21T14:10:30", + "2025-03-21T14:11:00", + "2025-03-21T14:11:31", + "2025-03-21T14:12:02", + "2025-03-21T14:12:33", + "2025-03-21T14:13:04", + "2025-03-21T14:13:34", + "2025-03-21T14:14:05", + "2025-03-21T14:14:36", + "2025-03-21T14:15:07", + "2025-03-21T14:15:37", + "2025-03-21T14:16:08", + "2025-03-21T14:16:39", + "2025-03-21T14:17:10", + "2025-03-21T14:17:41", + "2025-03-21T14:18:11", + "2025-03-21T14:18:42", + "2025-03-21T14:19:13", + "2025-03-21T14:19:44", + "2025-03-21T14:20:14", + "2025-03-21T14:20:45", + "2025-03-21T14:21:16", + "2025-03-21T14:21:47", + "2025-03-21T14:22:18", + "2025-03-21T14:22:48", + "2025-03-21T14:23:19", + "2025-03-21T14:23:50", + "2025-03-21T14:24:21", + "2025-03-21T14:24:51", + "2025-03-21T14:25:22", + "2025-03-21T14:25:53", + "2025-03-21T14:26:24", + "2025-03-21T14:26:55", + "2025-03-21T14:27:25", + "2025-03-21T14:27:56", + "2025-03-21T14:28:27", + "2025-03-21T14:28:58", + "2025-03-21T14:29:28", + "2025-03-21T14:29:59", + "2025-03-21T14:30:30", + "2025-03-21T14:31:01", + "2025-03-21T14:31:32", + "2025-03-21T14:32:02", + "2025-03-21T14:32:33", + "2025-03-21T14:33:04", + "2025-03-21T14:33:35", + "2025-03-21T14:34:05", + "2025-03-21T14:34:36", + "2025-03-21T14:35:07", + "2025-03-21T14:35:38", + "2025-03-21T14:36:09", + "2025-03-21T14:36:39", + "2025-03-21T14:37:10", + "2025-03-21T14:37:41", + "2025-03-21T14:38:12", + "2025-03-21T14:38:43", + "2025-03-21T14:39:14", + "2025-03-21T14:39:44", + "2025-03-21T14:40:15", + "2025-03-21T14:40:46", + "2025-03-21T14:41:17", + "2025-03-21T14:41:48", + "2025-03-21T14:42:18", + "2025-03-21T14:42:49", + "2025-03-21T14:43:20", + "2025-03-21T14:43:51", + "2025-03-21T14:44:21", + "2025-03-21T14:44:52", + "2025-03-21T14:45:23", + "2025-03-21T14:45:54", + "2025-03-21T14:46:25", + "2025-03-21T14:46:55", + "2025-03-21T14:47:26", + "2025-03-21T14:47:57", + "2025-03-21T14:48:28", + "2025-03-21T14:48:58", + "2025-03-21T14:49:29", + "2025-03-21T14:50:00", + "2025-03-21T14:50:31", + "2025-03-21T14:51:02", + "2025-03-21T14:51:32", + "2025-03-21T14:52:03", + "2025-03-21T14:52:34", + "2025-03-21T14:53:05", + "2025-03-21T14:53:35", + "2025-03-21T14:54:06", + "2025-03-21T14:54:37", + "2025-03-21T14:55:08", + "2025-03-21T14:55:39", + "2025-03-21T14:56:09", + "2025-03-21T14:56:40", + "2025-03-21T14:57:11", + "2025-03-21T14:57:42", + "2025-03-21T14:58:12", + "2025-03-21T14:58:43", + "2025-03-21T14:59:14", + "2025-03-21T14:59:45", + "2025-03-21T15:00:16", + "2025-03-21T15:00:46", + "2025-03-21T15:01:17", + "2025-03-21T15:01:48", + "2025-03-21T15:02:19", + "2025-03-21T15:02:49", + "2025-03-21T15:03:20", + "2025-03-21T15:03:51", + "2025-03-21T15:04:22", + "2025-03-21T15:04:53", + "2025-03-21T15:05:23", + "2025-03-21T15:05:54", + "2025-03-21T15:06:25", + "2025-03-21T15:06:56", + "2025-03-21T15:07:26", + "2025-03-21T15:07:57", + "2025-03-21T15:08:28", + "2025-03-21T15:08:59", + "2025-03-21T15:09:30", + "2025-03-21T15:10:00", + "2025-03-21T15:10:31", + "2025-03-21T15:11:02", + "2025-03-21T15:11:33", + "2025-03-21T15:12:03", + "2025-03-21T15:12:34", + "2025-03-21T15:13:05", + "2025-03-21T15:13:36", + "2025-03-21T15:14:07", + "2025-03-21T15:14:37", + "2025-03-21T15:15:08", + "2025-03-21T15:15:39", + "2025-03-21T15:16:10", + "2025-03-21T15:16:40", + "2025-03-21T15:17:11", + "2025-03-21T15:17:42", + "2025-03-21T15:18:13", + "2025-03-21T15:18:44", + "2025-03-21T15:19:14", + "2025-03-21T15:19:45", + "2025-03-21T15:20:16", + "2025-03-21T15:20:47", + "2025-03-21T15:21:17", + "2025-03-21T15:21:48", + "2025-03-21T15:22:19", + "2025-03-21T15:22:50", + "2025-03-21T15:23:21", + "2025-03-21T15:23:51", + "2025-03-21T15:24:22", + "2025-03-21T15:24:53", + "2025-03-21T15:25:24", + "2025-03-21T15:25:54", + "2025-03-21T15:26:25", + "2025-03-21T15:26:56", + "2025-03-21T15:27:27", + "2025-03-21T15:27:58", + "2025-03-21T15:28:28", + "2025-03-21T15:29:00", + "2025-03-21T15:29:30", + "2025-03-21T15:30:01", + "2025-03-21T15:30:32", + "2025-03-21T15:31:03", + "2025-03-21T15:31:33", + "2025-03-21T15:32:04", + "2025-03-21T15:32:35", + "2025-03-21T15:33:06", + "2025-03-21T15:33:37", + "2025-03-21T15:34:07", + "2025-03-21T15:34:38", + "2025-03-21T15:35:09", + "2025-03-21T15:35:40", + "2025-03-21T15:36:10", + "2025-03-21T15:36:41", + "2025-03-21T15:37:12", + "2025-03-21T15:37:43", + "2025-03-21T15:38:14", + "2025-03-21T15:38:44", + "2025-03-21T15:39:15", + "2025-03-21T15:39:46", + "2025-03-21T15:40:17", + "2025-03-21T15:40:47", + "2025-03-21T15:41:18", + "2025-03-21T15:41:49", + "2025-03-21T15:42:20", + "2025-03-21T15:42:51", + "2025-03-21T15:43:21", + "2025-03-21T15:43:52", + "2025-03-21T15:44:23", + "2025-03-21T15:44:54", + "2025-03-21T15:45:24", + "2025-03-21T15:45:55", + "2025-03-21T15:46:26", + "2025-03-21T15:46:57", + "2025-03-21T15:47:28", + "2025-03-21T15:47:58", + "2025-03-21T15:48:29", + "2025-03-21T15:49:00", + "2025-03-21T15:49:31", + "2025-03-21T15:50:01", + "2025-03-21T15:50:32", + "2025-03-21T15:51:03", + "2025-03-21T15:51:34", + "2025-03-21T15:52:05" + ], + "xaxis": "x", + "y": [ + null, + 0.0004450000000000879, + -0.0004450000000000879, + -0.0004449999999999695, + -0.002492333333333363, + -0.005162666666666619, + -0.015487999999999976, + -0.012728333333333335, + -0.016022000000000012, + -0.017357333333333357, + -0.01550516129032259, + -0.01412677419354832, + -0.012728333333333335, + -0.012318387096774285, + -0.011370322580645157, + -0.01093967741935475, + -0.009561290322580709, + -0.011304666666666682, + -0.00861387096774188, + -0.008700000000000008, + -0.007322258064516151, + -0.006497666666666646, + -0.004651612903225853, + -0.016366129032258026, + -0.023688709677419328, + -0.029201290322580734, + -0.02634699999999993, + -0.02231032258064517, + -0.018606129032258032, + -0.016452580645161304, + -0.020205666666666743, + -0.0268758064516129, + -0.03281903225806448, + -0.03962419354838706, + -0.041863870967741974, + -0.04423833333333332, + -0.04289774193548385, + -0.041433225806451625, + -0.041863645161290305, + -0.042725233333333355, + -0.03729851612903225, + -0.036351, + -0.03557561290322581, + -0.031785516129032264, + -0.032934066666666664, + -0.029115129032258064, + -0.027737032258064516, + -0.02678938709677419, + -0.025902299999999996, + -0.023171451612903227, + -0.021448806451612897, + -0.021276548387096774, + -0.020070483870967756, + -0.020205433333333335, + -0.017658709677419348, + -0.016452677419354838, + -0.017227903225806453, + -0.015932966666666666, + -0.014988322580645157, + -0.014988322580645157, + -0.014643774193548386, + -0.014040645161290336, + -0.014508833333333311, + -0.013265419354838751, + -0.012662580645161244, + -0.01231803225806453, + -0.012639333333333329, + -0.011370645161290365, + -0.010939677419354808, + -0.010422903225806445, + -0.009561612903225802, + -0.010770000000000005, + -0.01007870967741937, + -0.009475161290322583, + -0.007752580645161295, + -0.007922, + -0.00861387096774194, + -0.008614193548387088, + -0.0077522580645161465, + -0.008183548387096737, + -0.007031666666666681, + -0.006805161290322582, + -0.008183225806451588, + -0.005426774193548426, + -0.007032000000000001, + -0.005857419354838719, + -0.005943548387096732, + -0.005426774193548426, + -0.005426774193548369, + -0.006142000000000003, + -0.004479032258064564, + -0.0049961290322580185, + -0.004565483870967725, + -0.005162666666666619, + -0.004565161290322691, + -0.004565483870967725, + -0.004048709677419305, + -0.002848333333333386, + -0.0017524999999999347, + -0.0013780645161290065, + 0.000979000000000004, + 0.0013783870967741555, + 0.0018087096774192996, + 0.003101290322580706, + 0.0027564516129031623, + 0.003738333333333325, + 0.0032732258064516974, + 0.004565483870967725, + 0.003617741935483863, + 0.004628666666666703, + 0.004565483870967725, + 0.004565483870967725, + 0.004479032258064506, + 0.004996129032258076, + 0.005607999999999969, + 0.0041345161290322835, + 0.005426774193548369, + 0.004479354838709712, + 0.006141666666666623, + 0.004565483870967783, + 0.006288064516129012, + 0.006805161290322582, + 0.006586666666666652, + 0.008269354838709659, + 0.006288387096774218, + 0.00861387096774194, + 0.007321935483870945, + 0.009346000000000031, + 0.009044516129032232, + 0.007752903225806444, + 0.00861387096774194, + 0.009561612903225802, + 0.009346000000000031, + 0.00861387096774194, + 0.009992258064516094, + 0.009130967741935508, + 0.009434999999999978, + 0.009475161290322583, + 0.01050929032258068, + 0.011801064516129042, + 0.0117495333333333, + 0.013696225806451618, + 0.01309316129032261, + 0.014557612903225794, + 0.014557516129032232, + 0.015849677419354842, + 0.01550516129032259, + 0.01679732258064517, + 0.01602199999999998, + 0.016366516129032276, + 0.015935838709677404, + 0.015419, + 0.01637803333333334, + 0.01507432258064516, + 0.01447148387096774, + 0.013265548387096775, + 0.012194433333333336, + 0.010853580645161287, + 0.010939806451612905, + 0.009992290322580644, + 0.007666290322580647, + 0.007120899999999999, + 0.007321903225806452, + 0.006288096774193549, + 0.005513096774193547, + 0.0051625333333333336, + 0.0031871290322580638, + 0.0009475161290322575, + -0.0013781935483870964, + -0.0040485161290322565, + -0.005251566666666666, + -0.008614064516129035, + -0.007321903225806452, + -0.009992161290322581, + -0.009880333333333331, + -0.010853548387096774, + -0.010939677419354844, + -0.010508999999999994, + -0.010853548387096781, + -0.010414366666666655, + -0.009475354838709678, + -0.010422967741935485, + -0.010078193548387097, + -0.010325366666666665, + -0.00999216129032259, + -0.009475354838709678, + -0.010078419354838714, + -0.008183161290322576, + -0.008901200000000001, + -0.009044516129032261, + -0.007752709677419349, + -0.008183129032258055, + -0.007477066666666676, + -0.0063743548387096855, + -0.009130677419354822, + -0.006805161290322582, + -0.006374225806451632, + -0.007031899999999988, + -0.007235741935483863, + -0.006460387096774193, + -0.005426838709677439, + -0.006052766666666661, + -0.005512967741935481, + -0.005857548387096744, + -0.005943548387096789, + -0.0049100000000000055, + -0.005251566666666699, + -0.00542683870967741, + -0.004565322580645151, + -0.004996161290322568, + -0.005162666666666678, + -0.005426709677419327, + -0.004048645161290321, + -0.006029806451612942, + -0.006374354838709657, + -0.006052666666666677, + -0.005426774193548369, + -0.005426774193548426, + -0.005426774193548369, + -0.006675999999999978, + -0.005426774193548426, + -0.0063741935483870825, + -0.004565483870967725, + -0.006805161290322582, + -0.0050733333333333516, + -0.005082258064516089, + -0.006805161290322582, + -0.004565161290322634, + -0.0047176666666666495, + -0.005427096774193518, + -0.004995806451612927, + -0.004996129032258076, + -0.004048709677419362, + -0.0047176666666666495, + -0.004479032258064506, + -0.004565483870967725, + -0.004048709677419362, + -0.00427233333333336, + -0.004565483870967725, + -0.003617741935483863, + -0.005512903225806439, + -0.002759666666666701, + -0.004565161290322577, + -0.0026703225806451493, + -0.004134838709677432, + -0.004048387096774213, + -0.0031874193548386614, + -0.00318709677419357, + -0.0032933333333333556, + -0.0031009677419354424, + -0.0027564516129032195, + -0.0036180645161290694, + -0.0023139999999999715, + -0.0037041935483871392, + -0.0026703225806451493, + -0.002239677419354799, + -0.00318709677419357, + -0.001869333333333323, + -0.0027564516129032195, + -0.002239677419354856, + -0.0027564516129032768, + -0.003293333333333237, + -0.001808709677419414, + -0.0026706451612902985, + -0.002325806451612869, + -0.0022393548387097074, + -0.0014243333333332942, + -0.00318709677419357, + -0.0013780645161291212, + -0.0018090322580644486, + -0.001869333333333382, + -0.0018948387096774269, + -0.0022400000000000054, + -0.0008612903225805861, + -0.0027564516129032768, + -0.002314333333333233, + -0.0013780645161291212, + -0.0018090322580644486, + 0.0018090322580644486, + 0.009791333333333322, + 0.009647419354838722, + 0.005857419354838719, + 0.003187419354838719, + 0.0005340000000000344, + -0.0013783870967742703, + -0.002325806451612869, + -0.0031009677419354424, + -0.00318709677419357, + -0.004806666666666714, + -0.004565161290322577, + -0.004048709677419305, + -0.0049961290322580185, + -0.005162666666666737, + -0.004479354838709712, + -0.0031870967741934554, + -0.004996129032258133, + -0.004048387096774156, + -0.003293666666666676, + -0.00499580645161287, + -0.002756774193548426, + -0.004048387096774156, + -0.0032933333333333556, + -0.004048709677419419, + -0.0027564516129031623, + -0.0027564516129032768, + -0.003617741935483863, + -0.0023143333333333514, + -0.004048709677419305, + -0.0018087096774192996, + -0.0036180645161291267, + -0.003293333333333237, + -0.0009477419354839772, + -0.0008612903225805861, + 0.0008612903225805861, + 0.002239677419354856, + 0.0009793333333333247, + 0.0027564516129032768, + 0.0026703225806451493, + 0.002239677419354856, + 0.0038273333333332716, + 0.002239677419354856, + 0.003617741935483863, + 0.003618064516129012, + 0.0036177419354839774, + 0.004272666666666562, + 0.003100967741935557, + 0.004134838709677432, + 0.004479032258064449, + 0.005162666666666737, + 0.004134838709677432, + 0.0049961290322580185, + 0.003617741935483863, + 0.004048387096774156, + 0.005608000000000028, + 0.004565161290322577, + 0.004996129032258133, + 0.004134838709677318, + 0.004717666666666768, + 0.00499580645161287, + 0.0049961290322580185, + 0.004996129032258133, + 0.004909999999999948, + 0.004134838709677432, + 0.005607666666666648, + 0.004996129032258076, + 0.007666451612903225, + 0.010939677419354865, + 0.010422903225806445, + 0.009345999999999972, + 0.010940000000000014, + 0.009130645161290302, + 0.006805161290322582, + 0.006497666666666705, + 0.004996129032258076, + 0.0031870967741935126, + 0.0027564516129032195, + 0, + 0, + 0, + -0.002325806451612869, + -0.0026703225806451493, + -0.002403333333333357, + -0.0012919354838709938, + -0.0031870967741935126, + -0.0036180645161290694, + -0.0027564516129032195, + -0.003293333333333296, + -0.00318709677419357, + -0.0026703225806451493, + -0.0036180645161290694, + -0.004361666666666627, + -0.0022393548387097074, + -0.004048709677419362, + -0.002325806451612869, + -0.003617741935483863, + -0.00275933333333338, + -0.0037038709677419328, + -0.001809032258064506, + -0.0026703225806451493, + -0.002848333333333327, + -0.00318709677419357, + -0.0012922580645160855, + -0.00318709677419357, + -0.002848333333333327, + -0.00318709677419357, + -0.0031870967741935126, + -0.003101290322580649, + -0.003617741935483863, + -0.005162666666666678, + -0.004565483870967783, + -0.004048387096774156, + -0.003618064516129012, + -0.005162666666666737, + -0.004565161290322577, + -0.005857741935483868, + -0.0037038709677418755, + -0.005512903225806439, + -0.0032933333333333556, + -0.005857741935483868, + -0.004565483870967725, + -0.004479032258064564, + -0.00427266666666668, + -0.00499580645161287, + -0.004048709677419419, + -0.004048709677419305, + -0.003617741935483863, + -0.00382733333333339, + -0.0022396774193547417, + -0.0008612903225807008, + 0, + 0, + 0.00043064516129029303, + 0.0022393548387097074, + 0.0013783870967741555, + 0.002239677419354856, + 0.002848333333333386, + 0.0018087096774192996, + 0.003187419354838719, + 0.001808709677419414, + 0.003738666666666646, + 0.0027564516129031623, + 0.003617741935483863, + 0.003100967741935557, + 0.004134838709677432, + 0.002759333333333321, + 0.004134838709677432, + 0.003617741935483863, + 0.0049961290322580185, + 0.00427233333333336, + 0.003618064516129012, + 0.00318709677419357, + 0.0049961290322580185, + 0.00318709677419357, + 0.005162666666666737, + 0.004479354838709598, + 0.004565483870967783, + 0.004565161290322577, + 0.004628666666666644, + 0.004134838709677432, + 0.004479032258064506, + 0.00318709677419357, + 0.004996129032258076, + 0.005943870967741938, + 0.0032043333333332904, + 0.004996129032258076, + 0.005943548387096789, + 0.005426774193548369, + 0.004048387096774213, + 0.005252000000000005, + 0.0027564516129032195, + 0.00223935483870965, + 0.001809032258064506, + 0.0014243333333333534, + 0.0004306451612903504, + 0.0013780645161290065, + -0.00043064516129029303, + 0.00043064516129029303, + -0.0004449999999999695, + -0.0009474193548387134, + -0.0004306451612903504, + -0.0009474193548387134, + 0, + -0.0012922580645161428, + -0.0005167741935483631, + -0.001378387096774213, + 0, + -0.0008899999999999982, + -0.0013783870967741555, + -0.0018087096774193569, + -0.0008616129032258498, + -0.003916333333333277, + -0.0018090322580645633, + -0.0031009677419354424, + -0.0023258064516129264, + -0.003617741935483863, + -0.0032933333333333556, + -0.003618064516129012, + -0.003617741935483863, + -0.003187419354838719, + -0.004183333333333354, + -0.004048387096774156, + -0.003187419354838719, + -0.0041345161290322835, + -0.004048709677419362, + -0.003293333333333296, + -0.0036180645161290694, + -0.004048387096774156, + -0.00318709677419357, + -0.003293666666666676, + -0.004565161290322519, + -0.00318709677419357, + -0.003101290322580706, + -0.0032933333333333556, + -0.003617741935483863, + -0.0027564516129031623, + -0.003187419354838719, + -0.0037038709677419904, + -0.002759333333333321, + -0.0027564516129031623, + -0.002239677419354856, + -0.003617741935483863, + -0.002848333333333386, + -0.002756774193548311, + -0.0026700000000000005, + -0.002756774193548426, + -0.0022393548387097074, + -0.0018693333333332637, + -0.0027564516129032768, + -0.0026703225806451493, + -0.0018090322580645633, + -0.001868999999999943, + -0.002325806451612869, + -0.002239677419354856, + -0.002239677419354856, + -0.0027564516129032768, + -0.000979000000000004, + -0.0026703225806451493, + -0.0013783870967741555, + -0.002239677419354856, + -0.000979000000000004, + -0.002239677419354856, + -0.0018090322580644486, + -0.0009474193548387134, + -0.003100967741935557, + -0.000533999999999916, + -0.0013783870967742703, + -0.0012919354838708793, + -0.0018090322580645633, + -0.0005340000000000344, + -0.0012922580645161428, + -0.002325806451612869, + -0.00043064516129029303, + -0.0009474193548387134, + -0.0023143333333333514, + -0.0008612903225805861, + -0.0013783870967742703, + -0.0013783870967741555, + -0.0013780645161290065, + -0.0013783870967742703, + -0.0013349999999999085, + -0.0018090322580645633, + -0.0009474193548387134, + 0, + 0.0004449999999999695, + 0.0023258064516129837, + 0.00043064516129029303, + 0.0027564516129031623, + 0.0026703225806451493, + 0.001869333333333382, + 0.001808709677419414, + 0.002756774193548311, + 0.0026703225806451493, + 0.002848333333333386, + 0.00318709677419357, + 0.0031870967741934554, + 0.0036180645161291267, + 0.0018087096774192996, + 0.004183666666666734, + 0.003617741935483863, + 0.0031870967741934554, + 0.004048709677419419, + 0.00427233333333336, + 0.0049961290322580185, + 0.0026703225806451493, + 0.004565483870967725, + 0.004565483870967725, + 0.0037383333333334432, + 0.003618064516129012, + 0.004479354838709598, + 0.004995806451612984, + 0.003827666666666592, + 0.005512903225806439, + 0.003617741935483863, + 0.004048709677419419, + 0.004565161290322577, + 0.004628666666666644, + 0.004134838709677432, + 0.004048387096774213, + 0.004565483870967725, + 0.005607666666666648, + 0.003617741935483863, + 0.004565483870967783, + 0.003618064516129012, + 0.005857419354838719, + 0.005607666666666648, + 0.003617741935483863, + 0.005512903225806496, + 0.0026703225806451493, + 0.003293333333333296, + 0.002756774193548426, + 0.0012919354838709365, + 0.0009474193548387134, + 0.0004306451612903504, + 0, + 0.0014645161290322258, + -0.0005167741935483631, + -0.0005167741935483631, + -0.0008903333333333781, + -0.00043064516129029303, + 0, + -0.0009474193548387134, + -0.001378387096774213, + -0.0008899999999999982, + 0, + -0.001378387096774213, + -0.00043064516129029303, + -0.0014239999999999735, + -0.0004306451612903504, + -0.0009477419354838626, + -0.0008612903225806434, + -0.0009474193548387134, + -0.00044533333333334943, + -0.0018087096774193569, + -0.0009474193548387134, + -0.0012922580645161428, + -0.0019583333333333284, + -0.0026703225806451493, + -0.002239677419354799, + -0.0018087096774193569, + -0.0027564516129032768, + -0.003293666666666617, + -0.004048387096774213, + -0.0027564516129032195, + -0.0036180645161290694, + -0.002847999999999947, + -0.004479354838709712, + -0.003187419354838719, + -0.004048387096774156, + -0.00318709677419357, + -0.00427266666666668, + -0.0036177419354838057, + -0.002239677419354856, + -0.004048709677419419, + -0.0038273333333332716, + -0.003618064516129012, + -0.003617741935483863, + -0.0036177419354839774, + -0.0032732258064515824, + -0.002239677419354856, + -0.003738666666666646, + -0.00318709677419357, + -0.003617741935483863, + -0.002756774193548311, + -0.0022393548387097074, + -0.003293666666666676, + -0.0026700000000000005, + -0.002756774193548426, + -0.002756129032258013, + -0.0023146666666666723, + -0.0026700000000000005, + -0.002756774193548426, + -0.0022393548387095925, + -0.0027564516129032768, + -0.001869333333333382, + -0.0018090322580644486, + -0.0027564516129032768, + -0.0018090322580644486, + -0.002759, + -0.0018090322580645633, + -0.0018090322580645633, + -0.0013780645161290065, + -0.003187419354838719, + -0.0014239999999999735, + -0.0013783870967741555, + -0.001808709677419414, + -0.0012922580645161428, + -0.0018693333333332637, + -0.0027564516129032768, + -0.0013780645161290065, + -0.0013783870967741555, + -0.0012919354838709938, + -0.0014243333333332942, + -0.001808709677419414, + -0.0013783870967741555, + -0.0013783870967742703, + -0.0014239999999999735, + 0.0005167741935484205, + 0.00043064516129029303, + 0.0013783870967742703, + 0.0018090322580644486, + 0.0018690000000000614, + 0.0018090322580644486, + 0.002239677419354856, + 0.002239677419354856, + 0.0014239999999999735, + 0.003618064516129012, + 0.0023258064516129837, + 0.0026703225806451493, + 0.0027564516129031623, + 0.004183333333333413, + 0.0027564516129031623, + 0.003618064516129012, + 0.0026703225806451493, + 0.004717333333333329, + 0.0036180645161291267, + 0.0031870967741934554, + 0.004048709677419419, + 0.004565161290322577, + 0.0032933333333333556, + 0.004565483870967725, + 0.004048709677419305, + 0.00318709677419357, + 0.004628666666666703, + 0.0041345161290322835, + 0.004565483870967725, + 0.0037038709677418755, + 0.0049100000000000055, + 0.0047176666666666495, + 0.00318709677419357, + 0.005426774193548426, + 0.004048709677419305, + 0.00427233333333336, + 0.004048709677419362, + 0.004134838709677432, + 0.004048387096774156, + 0.005162666666666678, + 0.003617741935483863, + 0.004565483870967783, + 0.004048709677419305, + 0.005426774193548426, + 0.005607666666666648, + 0.0041345161290322835, + 0.004048709677419362, + 0.0027564516129032195, + 0.0008899999999999982, + 0.0027564516129032195, + 0.00043064516129029303, + 0.0008616129032258498, + 0.0005167741935483631, + -0.0005339999999999752, + 0, + -0.0012922580645161428, + 0.0008612903225806434, + -0.0008612903225806434, + -0.0013780645161290638, + -0.0014243333333332942, + -0.0004306451612903504, + -0.00043064516129029303, + -0.0018090322580645633, + -0.0009474193548386562, + -0.001869333333333382, + -0.00043064516129029303, + -0.001378387096774213, + -0.0009474193548387134, + -0.0004449999999999695, + -0.0013780645161290638, + -0.0012922580645161428, + -0.0013783870967741555, + -0.0009474193548387134, + -0.0023143333333333514, + -0.0013780645161290065, + -0.003187419354838719, + -0.0026700000000000005, + -0.001869333333333323, + -0.00318709677419357, + -0.003187419354838719, + -0.00223935483870965, + -0.004134838709677432, + -0.003738333333333325, + -0.003618064516129012, + -0.00318709677419357, + -0.003617741935483863, + -0.0037386666666667048, + -0.004565483870967725, + -0.0031009677419354424, + -0.0041345161290322835, + -0.003618064516129012, + 0.0004453333333332902, + 0.003617741935483863, + 0.005943548387096847, + 0.002670322580645092, + 0.000979000000000004, + 0.003187419354838719, + 0.00318709677419357, + 0.0012919354838709365, + -0.0012919354838709365, + -0.002848333333333327, + 0.0031870967741935126, + 0.005426774193548426, + 0.004048709677419305, + 0.0005340000000000344, + -0.0027564516129032195, + -0.004048709677419362, + -0.005426774193548369, + -0.005512903225806496, + -0.00747700000000003, + -0.006374193548387025, + -0.007666451612903282, + -0.006891290322580595, + -0.007031666666666681, + -0.007235806451612875, + -0.0063745161290322885, + -0.005426774193548426, + -0.006804838709677433, + -0.0047176666666666495, + -0.003617741935483863, + -0.0026703225806451493, + -0.0005167741935484205, + 0.0005340000000000344, + -0.0005167741935484205, + 0.0009474193548387134, + 0.0018090322580645633, + 0.0009474193548387134, + 0.002759333333333321, + 0.0013780645161290065, + 0.002239677419354856, + 0.002325806451612869, + 0.002759333333333321, + 0.0027564516129032768, + 0.004048709677419305, + 0.00318709677419357, + 0.001869333333333382, + 0.004565483870967725, + 0.0026703225806451493, + 0.003617741935483863, + 0.004134838709677432, + 0.003738333333333325, + 0.004565483870967725, + 0.0037038709677419904, + 0.003617741935483863, + 0.004183666666666615, + 0.004565483870967725, + 0.004479032258064564, + 0.004134838709677432, + 0.003617741935483863, + 0.005607666666666648, + 0.002756774193548426, + 0.005426774193548369, + 0.00318709677419357, + 0.0050736666666666725, + 0.004134516129032226, + 0.004048709677419362, + 0.0041345161290322835, + 0.005426774193548369, + 0.005426774193548369, + 0.004048709677419362, + 0.005162666666666678, + 0.0032732258064515824, + 0.00318709677419357, + 0.0008616129032257925, + 0, + 0.0009474193548387134, + -0.00043064516129029303, + -0.001378387096774213, + -0.0009474193548387134, + -0.0018690000000000022, + -0.0018954838709677251, + -0.0022393548387097074, + -0.0027564516129032195, + -0.0023143333333332924, + -0.0018090322580645633, + -0.0031870967741935126, + -0.002239677419354856, + -0.00318709677419357, + -0.002848333333333327, + -0.0031009677419354424, + -0.0023258064516129264, + -0.00318709677419357, + -0.0023143333333332924, + -0.0027564516129032195, + -0.0026703225806452065, + -0.0027564516129032195, + -0.0026703225806451493, + -0.003738666666666646, + -0.00318709677419357, + -0.004134838709677432, + -0.004048387096774156, + -0.0047176666666667085, + -0.004479354838709655, + -0.004565161290322577, + -0.004565483870967725, + -0.0049100000000000055, + -0.005162666666666737, + -0.004651612903225738, + -0.004565161290322577, + -0.005426774193548426, + -0.006052999999999998, + -0.0041345161290322835, + -0.004479354838709598, + -0.004996129032258133, + -0.004565483870967725, + -0.005162666666666619, + -0.004995806451612984, + -0.0031009677419354424, + -0.003618064516129012, + -0.000979000000000004, + -0.0013783870967741555, + 0.0009477419354838626, + 0.00043064516129029303, + 0.0009474193548387134, + 0.001335000000000027, + 0.0018090322580644486, + 0.0018090322580645633, + 0.002325806451612869, + 0.002759333333333321, + 0.0013780645161290065, + 0.0027564516129032768, + 0.0026703225806451493, + 0.003738666666666646, + 0.00318709677419357, + 0.002325806451612869, + 0.0040483870967742705, + 0.003187419354838719, + 0.004183333333333294, + 0.004565483870967725, + 0.002239677419354856, + 0.004565483870967725, + 0.004628333333333383, + 0.0037041935483870247, + 0.0041345161290322835, + 0.003618064516129012, + 0.004565161290322577, + 0.004183666666666734, + 0.004565483870967725, + 0.004048387096774156, + 0.00318709677419357, + 0.004628666666666644, + 0.004134838709677432, + 0.004996129032258076, + 0.00318709677419357, + 0.004048387096774156, + 0.005162666666666678, + 0.004048709677419362, + 0.004565483870967725, + 0.004995806451612927, + 0.005607666666666648, + 0.004996129032258076, + 0.0026703225806451493, + 0.004651612903225796, + 0.0018090322580645633, + 0.0009474193548386562, + 0.0008616129032258498, + 0, + -0.0008616129032258498, + -0.0005167741935483631, + -0.002239677419354856, + -0.0015133333333333, + -0.0018087096774193569, + -0.0036180645161290694, + -0.0018087096774192996, + -0.0027564516129032768, + -0.0032043333333332904, + -0.002756774193548426, + -0.00223935483870965, + -0.0027564516129032195, + -0.0037386666666667048, + -0.0031870967741935126, + -0.00318709677419357, + -0.003618064516129012, + -0.003617741935483863, + -0.004183333333333354, + -0.004134838709677432, + -0.005426774193548369, + -0.004048709677419362, + -0.005162666666666678, + -0.005857419354838662, + -0.004996129032258133, + -0.004565161290322577, + -0.005857741935483868, + -0.005251333333333363, + -0.0049961290322580185, + -0.005943870967741881, + -0.004996129032258133, + -0.005162666666666619, + -0.004479032258064564, + -0.005943548387096732, + -0.004479354838709712, + -0.004134838709677432, + -0.0050736666666666725, + -0.0027564516129031623, + -0.0022393548387097074, + -0.0018090322580645633, + 0.0004450000000000879, + -0.0004306451612904077, + 0.002239677419354856, + 0, + 0.0013780645161291212, + 0.002314333333333233, + 0.0013783870967742703, + 0.0026700000000000005, + 0.002325806451612869, + 0.0023143333333333514, + 0.0027564516129031623, + 0.003101290322580706, + 0.0037038709677418755, + 0.0026703225806451493, + 0.002848333333333386, + 0.004048387096774156, + 0.0036180645161291267, + 0.0031870967741934554, + 0.003738333333333325, + 0.003187419354838719, + 0.005082258064516146, + 0.0040483870967742705, + 0.0031870967741934554, + 0.004183666666666734, + 0.0041345161290322835, + 0.004565483870967725, + 0.004048709677419305, + 0.003738333333333325, + 0.004996129032258076, + 0.004048709677419362, + 0.004565161290322577, + 0.003293666666666676, + 0.004048387096774213, + 0.004565483870967725, + 0.004048387096774213, + 0.0049961290322580185, + 0.0037386666666667048, + 0.005426774193548369, + 0.005426774193548369, + 0.0037038709677419328, + 0.00275933333333338, + 0.0027564516129032195, + 0.0027567741935483688, + 0.0013780645161290638, + 0.00043064516129029303, + 0.0005339999999999752, + -0.0005167741935483631, + 0.0009474193548387134, + -0.0009474193548387134, + 0.000979000000000004, + -0.0009474193548387134, + -0.0012919354838709938, + -0.0014645161290322258, + 0, + -0.0009793333333333247, + -0.001752187500000002, + -0.0014243333333333534, + -0.0008612903225806434, + -0.001378387096774213, + -0.002756129032258013, + -0.0013353333333333476, + -0.0023258064516129264, + -0.0031009677419354996, + -0.0027564516129032195, + -0.0027564516129032195, + -0.003738666666666646, + -0.0026700000000000005, + -0.004996129032258076, + -0.002325806451612869, + -0.0037386666666667048, + -0.004479032258064506, + -0.003187419354838719, + -0.0031870967741935126, + -0.004565483870967783, + -0.003738333333333325, + -0.004048709677419362, + -0.0031870967741935126, + -0.004565161290322577, + -0.0032046666666667297, + -0.00318709677419357, + -0.004134838709677318, + -0.0040483870967742705, + -0.0027564516129031623, + -0.00382733333333339, + -0.0026703225806451493, + -0.003187419354838719, + -0.003617741935483863, + -0.0032933333333333556, + -0.002756774193548311, + -0.0026700000000000005, + -0.0036180645161291267, + -0.002325806451612869, + -0.003738333333333325, + -0.00318709677419357, + -0.0012922580645161428, + -0.0037038709677418755, + -0.0013353333333333476, + -0.00318709677419357, + -0.0027564516129031623, + -0.0018090322580645633, + -0.0026700000000000005, + -0.001869333333333382, + -0.002325806451612869, + -0.0026703225806451493, + -0.0013783870967741555, + -0.002848333333333386, + -0.0018087096774192996, + -0.002239677419354856, + -0.002239677419354856, + -0.0013783870967741555, + -0.0018690000000000614, + -0.0009477419354838626, + -0.0026703225806451493, + -0.0018087096774192996, + -0.0014243333333334126, + -0.0009477419354838626, + -0.0018087096774192996, + -0.0004306451612904077, + 0, + 0.000979000000000004, + 0.0012919354838709938, + 0.002326129032258133, + 0.0018087096774192996, + 0.001869333333333382, + 0.0026703225806451493, + 0.0018090322580644486, + 0.0013780645161291212, + 0.004134838709677318, + 0.0023143333333333514, + 0.00318709677419357, + 0.0026703225806451493, + 0.00318709677419357, + 0.0032933333333333556, + 0.003187419354838719, + 0.003617741935483863, + 0.004565483870967725, + 0.0031009677419354424, + 0.00382733333333339, + 0.004048709677419305, + 0.003617741935483863, + 0.0040483870967742705, + 0.00427266666666668, + 0.0031870967741934554, + 0.004910322580645155, + 0.0041345161290322835, + 0.0047176666666666495, + 0.0041345161290322835, + 0.004048709677419419, + 0.004134516129032169, + 0.004479354838709712, + 0.0047176666666666495, + 0.003617741935483863, + 0.004048709677419362, + 0.004565161290322577, + 0.004048709677419362, + 0.004134838709677432, + 0.0032933333333333556, + 0.005426774193548369, + 0.004479354838709655, + 0.005943548387096789, + 0.004048387096774213, + 0.003738666666666646, + 0.00318709677419357, + 0.002239677419354799, + 0.0018090322580645633, + 0, + 0.0013780645161290065, + 0.0009474193548387134, + 0, + 0, + 0, + -0.0004306451612903504, + -0.0013780645161290065, + 0, + -0.0009793333333333247, + -0.0008612903225806434, + -0.0005167741935484205, + -0.0008616129032257925, + -0.0018087096774193569, + 0, + -0.0009474193548387134, + -0.00043096774193544216, + -0.0018090322580645633, + 0, + -0.0018087096774193569, + -0.0009474193548387134, + -0.001809032258064506, + -0.0012922580645160855, + -0.0018690000000000022, + -0.0027564516129032768, + -0.0027564516129032195, + -0.002239677419354799, + -0.002848333333333327, + -0.0031009677419354996, + -0.003187419354838719, + -0.00318709677419357, + -0.004048387096774156, + -0.0028486666666667068, + -0.003617741935483863, + -0.003617741935483863, + -0.004134838709677432, + -0.00320433333333335, + -0.004134838709677432, + -0.003617741935483863, + -0.0027564516129031623, + -0.004479354838709712, + -0.003738333333333325, + -0.00318709677419357, + -0.0037041935483870247, + -0.00318709677419357, + -0.0032933333333333556, + -0.003618064516129012, + -0.0027564516129032768, + -0.002239677419354856, + -0.004048387096774156, + -0.003738333333333325, + -0.002325806451612869, + -0.0036180645161291267, + -0.0022396774193547417, + -0.002848333333333386, + -0.0026703225806451493, + -0.0027564516129032768, + -0.0026703225806451493, + -0.002325806451612869, + -0.002314000000000031, + -0.002239677419354856, + -0.002325806451612869, + -0.0026703225806451493, + -0.001869333333333382, + -0.002325806451612869, + -0.002239677419354856, + -0.0018087096774192996, + -0.002239677419354856, + -0.001869333333333382, + -0.0031870967741934554, + -0.0009477419354838626, + -0.0013780645161291212, + -0.0023143333333333514, + -0.0008612903225805861, + -0.0018090322580645633, + 0.0008612903225807008, + 0.00043064516129029303, + 0.0009793333333333247, + 0.0018090322580645633, + 0.00043064516129029303, + 0.001808709677419414, + 0.0028486666666665884, + 0.001808709677419414, + 0.002239677419354856, + 0.0018090322580644486, + 0.002848333333333386, + 0.003504687499999992, + 0.003293666666666676, + 0.0031870967741934554, + 0.0026703225806452642, + 0.003617741935483863, + 0.002325806451612869, + 0.003738333333333325, + 0.004479354838709712, + 0.0031870967741934554, + 0.004134838709677432, + 0.003204333333333409, + 0.004134838709677432, + 0.004048387096774156, + 0.004134838709677432, + 0.0049100000000000055, + 0.0028483333333332674, + 0.004565483870967725, + 0.0041345161290322835, + 0.004565483870967725, + 0.003738333333333325, + 0.0036177419354839774, + 0.004048709677419305, + 0.004565483870967725, + 0.004565483870967783, + 0.004183333333333294, + 0.004048709677419362, + 0.0041345161290322835, + 0.004479354838709655, + 0.003738333333333325, + 0.005513225806451645, + 0.004479032258064506, + 0.004565483870967725, + 0.00318709677419357, + 0.004628666666666644, + 0.001809032258064506, + 0.0027561290322580703, + 0.0008616129032257925, + 0.000979000000000004, + 0.0008616129032258498, + 0.0009474193548387134, + -0.001378387096774213, + 0.0009477419354838626, + -0.0014243333333333534, + 0, + -0.00043064516129029303, + -0.001809032258064506, + -0.000979000000000004, + -0.0008612903225806434, + -0.0005167741935484205, + -0.0008616129032257925, + -0.001809032258064506, + 0, + -0.0018087096774193569, + -0.001378387096774213, + -0.0009474193548387134, + 0, + -0.002239677419354799, + -0.001378387096774213, + -0.0008612903225806434, + -0.00318709677419357, + -0.002848333333333327, + -0.002239677419354856, + -0.0027564516129032195, + -0.0031009677419354424, + -0.0038273333333333306, + -0.0026706451612903558, + -0.003617741935483863, + -0.00318709677419357, + -0.004048709677419305, + -0.0032933333333333556, + -0.004134838709677432, + -0.004048387096774156, + -0.00318709677419357, + -0.0032933333333333556, + -0.004479354838709712, + -0.004134838709677318, + -0.0026703225806452642, + -0.0032732258064515824, + -0.003738333333333325, + -0.004134838709677432, + -0.0026703225806451493, + -0.004134838709677432, + -0.0023143333333333514, + -0.0031870967741934554, + -0.0040483870967742705, + -0.0027564516129031623, + -0.002239677419354856, + -0.002848333333333386, + -0.003618064516129012, + -0.002239677419354856, + -0.003617741935483863, + -0.0028483333333332674, + -0.0018090322580645633, + -0.00318709677419357, + -0.0026703225806451493, + -0.0013780645161290065, + -0.003293666666666676, + -0.0022393548387097074, + -0.0018090322580644486, + -0.0027564516129032768, + -0.0018090322580644486, + -0.002239677419354856, + -0.0018690000000000614, + -0.002325806451612869, + -0.0012922580645161428, + -0.0027564516129032768, + -0.000889999999999939, + -0.0005170967741935695, + 0, + 0.0013783870967741555, + 0.0009477419354839772, + 0.000889999999999939, + 0.002239677419354856, + 0.0018948387096774269, + 0.002239677419354856, + 0.0018693333333332637, + 0.0026703225806451493, + 0.0027564516129032768, + 0.002239677419354856, + 0.0027564516129031623, + 0.0032933333333333556, + 0.004048709677419419, + 0.0031870967741934554, + 0.0018090322580645633, + 0.004183333333333294, + 0.004134838709677432, + 0.003617741935483863, + 0.00318709677419357, + 0.003618064516129012, + 0.003738333333333325, + 0.004565483870967725, + 0.0036177419354839774, + 0.004479354838709598, + 0.003738666666666646, + 0.004565161290322577, + 0.004134838709677432, + 0.004565161290322577, + 0.0036180645161291267, + 0.003293333333333237, + 0.004996129032258133, + 0.004048387096774156, + 0.004565483870967725, + 0.0037386666666667048, + 0.004565161290322577, + 0.003618064516129012, + 0.004479354838709712, + 0.004134516129032226, + 0.004183333333333354, + 0.004996129032258076, + 0.0049961290322580185, + 0.004565483870967783, + 0.004183333333333294, + 0.003187419354838719, + 0.00318709677419357, + 0.0008612903225806434, + 0.00043096774193549946, + 0.0014239999999999735, + 0.0005167741935483631, + -0.0018948387096773696, + -0.0012922580645161428, + -0.000979000000000004, + -0.0008616129032257925, + -0.0027564516129032195, + -0.0018090322580645633, + -0.0027561290322580703, + -0.0008903333333333189, + -0.003617741935483863, + -0.0023258064516129264, + -0.0031009677419354424, + -0.002403333333333357, + -0.0031870967741935126, + -0.002239677419354856, + -0.00318709677419357, + -0.0026703225806451493, + -0.002848333333333327, + -0.0026703225806451493, + -0.002756774193548426, + -0.003617741935483863, + -0.002848333333333327, + -0.004479354838709655, + -0.0027564516129032195, + -0.004996129032258133, + -0.004048387096774156, + -0.0047176666666666495, + -0.004479354838709712, + -0.005599032258064452, + -0.005426774193548426, + -0.004183333333333294, + -0.005426774193548426, + -0.0049961290322580185, + -0.005426774193548426, + -0.0049961290322580185, + -0.005607666666666707, + -0.0037041935483871392, + -0.005426774193548312, + -0.004996129032258133, + -0.003617741935483863, + -0.0026703225806451493, + -0.0014243333333332942, + -0.0004306451612904077, + 0, + 0.0008612903225807008, + 0, + 0.0018090322580645633, + 0.0013783870967741555, + 0.0022393548387097074, + 0.0013783870967741555, + 0.002848333333333386, + 0.0022396774193547417, + 0.0027564516129032768, + 0.002239677419354856, + 0.0032933333333333556, + 0.003617741935483863, + 0.0022396774193547417, + 0.0036180645161291267, + 0.003617741935483863, + 0.0032933333333333556, + 0.003617741935483863, + 0.004134838709677432, + 0.0031870967741934554, + 0.004628666666666703, + 0.00318709677419357, + 0.004651612903225738, + 0.0036180645161291267, + 0.004048387096774156, + 0.003738666666666646, + 0.00499580645161287, + 0.00318709677419357, + 0.0036180645161290694, + 0.0047176666666666495, + 0.004048387096774213, + 0.0031870967741935126, + 0.004565483870967783, + 0.004048709677419362, + 0.004183333333333294, + 0.004134838709677432, + 0.004479354838709655, + 0.003617741935483863, + 0.0047176666666667085, + 0.005426774193548369, + 0.004565161290322577, + 0.001378387096774213, + 0.0026703225806451493, + 0.002848333333333327, + 0.0008612903225806434, + 0.001378387096774213, + 0.0009474193548387134, + -0.0005340000000000344, + -0.0008612903225806434, + 0, + -0.0013783870967741555, + 0.00043064516129029303, + -0.0013349999999999677, + -0.001378387096774213, + -0.0004306451612903504, + -0.0009474193548386562, + -0.0014243333333333534, + -0.0013780645161290638, + -0.0012922580645160855, + -0.0018087096774193569, + -0.001378387096774213, + -0.0032933333333333556, + -0.002239677419354799, + -0.0027564516129032195, + -0.00318709677419357, + -0.0032933333333333556, + -0.0026703225806451493, + -0.004134838709677432, + -0.004048709677419362, + -0.003617741935483863, + -0.003738333333333325, + -0.003187419354838719, + -0.004048387096774156, + -0.004134838709677432, + -0.003738333333333325, + -0.0036180645161290694, + -0.004565161290322577, + -0.0031009677419354424, + -0.004996129032258133, + -0.003293333333333237, + -0.003187419354838719, + -0.0041345161290322835, + -0.00318709677419357, + -0.003738666666666646, + -0.003617741935483863, + -0.0027564516129032768, + -0.004048709677419305, + -0.0027564516129032768, + -0.0032933333333333556, + -0.003618064516129012, + -0.002756129032258013, + -0.0026706451612902985, + -0.002314000000000031, + -0.0037041935483871392, + -0.0031009677419354424, + -0.002325806451612869, + -0.0018090322580645633, + 0.0403996774193549, + 0.07898999999999992, + 0.09292733333333339, + 0.0876902258064516, + 0.08045445161290321, + 0.07227116129032259, + 0.06524503333333334, + 0.05366503225806451, + 0.04866877419354839, + 0.04367287096774193, + 0.03772922580645161, + 0.037206499999999997, + 0.02954593548387098, + 0.027306225806451603, + 0.022310193548387088, + 0.02118466666666669, + 0.01817541935483867, + 0.015935838709677432, + 0.014126806451612926, + 0.011284258064516129, + 0.011838533333333305, + 0.00947545161290324, + 0.007408064516129015, + 0.007235806451612932, + 0.006586666666666652, + 0.005943548387096789, + 0.004565483870967725, + 0.004048709677419362, + 0.004565161290322577, + 0.002759333333333321, + 0.004220967741935503, + 0.002239677419354856, + 0.0031870967741935126, + 0.0014240000000000327, + 0.0026703225806451493, + 0.001378387096774213, + 0.001809032258064506, + 0.0013780645161290065, + 0.0023143333333333514, + 0.0005167741935483631, + 0.0009474193548387134, + 0.0008616129032258498, + 0.0014239999999999735, + 0.0022400000000000054, + 0.0018948387096774269, + 0.004048709677419362, + 0.0063741935483870825, + 0.008990000000000008, + 0.006805161290322582, + 0.006891290322580652, + 0.004479032258064506, + 0.00427266666666668, + 0.004479354838709655, + 0.0027561290322580703, + 0.002239677419354799, + 0.004134838709677432, + 0.002848333333333327, + 0.0027564516129032195, + 0.0026703225806452065, + 0.002239677419354799, + 0.002848333333333327, + 0.002239677419354856, + 0.0024119354838709967, + 0.0013780645161290065, + 0.0012922580645161428, + 0.001869333333333323, + 0.0009474193548387134, + 0.002239677419354856, + 0.0009474193548387134, + 0.0013349999999999677, + 0.0005170967741935695, + 0.0013780645161290065, + 0.0008612903225806434, + 0.001378709677419362, + 0.0008899999999999982, + 0, + 0.0009474193548387134, + 0.001378387096774213, + 0.0015129999999999792, + 0.0004306451612903504, + -0.0004306451612903504, + 0.0012922580645161428, + 0.0005167741935483631, + 0.0008899999999999982, + 0.0004306451612903504, + 0.0005167741935483631, + 0.0004306451612903504, + 0, + 0.0008616129032257925, + 0, + 0.0009474193548387134, + 0, + 0, + 0, + 0.0008616129032257925, + 0, + 0, + -0.00043064516129029303, + -0.00044533333333334943, + 0.001378387096774213, + 0, + 0, + 0.00043064516129029303, + 0, + 0, + 0.0004306451612903504, + -0.0004306451612903504, + 0.0004450000000000287, + 0.0005167741935483631, + -0.0005167741935483631, + 0.0005167741935483631, + 0.0004306451612903504, + -0.0004450000000000287, + 0, + 0, + 0.0004306451612903504, + 0, + 0, + 0.00043096774193544216, + 0, + 0.0004306451612903504, + 0.0005339999999999752, + 0, + 0, + 0, + 0.0004450000000000287, + -0.0004306451612903504, + 0.0004306451612903504, + 0.00043064516129029303, + -0.00043064516129029303, + 0.0004449999999999695, + 0, + -0.00043064516129029303, + 0.00043064516129029303, + 0, + -0.00043064516129029303, + 0.00043064516129029303, + 0, + -0.00043064516129029303, + 0.0008899999999999982, + -0.0008612903225806434, + 0.00043064516129029303, + 0.0004306451612903504, + -0.0004450000000000287, + 0.0004306451612903504, + -0.0004306451612903504, + 0.0004306451612903504, + -0.0004306451612903504, + 0.0014243333333333534, + -0.0004306451612903504, + -0.0013783870967741555, + 0, + 0.0004449999999999695, + 0, + 0, + 0.0004306451612903504, + -0.0004306451612903504, + 0, + -0.0008612903225806434, + 0.0008612903225806434, + -0.0008612903225806434, + 0.0004450000000000287, + 0, + 0.00043064516129029303, + -0.00043064516129029303, + -0.0004306451612903504, + 0.0004450000000000287, + 0.00043064516129029303, + -0.0008612903225806434, + 0.0004306451612903504, + 0, + 0, + 0, + 0.00043064516129029303, + -0.0013780645161290065, + 0.000979000000000004, + -0.0004306451612903504, + 0, + 0, + 0.0004450000000000287, + 0, + -0.0009474193548387134, + 0, + 0.0005167741935483631, + 0, + -0.0005167741935483631, + 0.0005167741935483631, + 0.0004306451612903504, + -0.000979000000000004, + 0, + 0, + 0, + 0, + 0.0009474193548387134, + -0.0009474193548387134, + 0.0005339999999999752, + -0.0005167741935483631, + -0.0004306451612903504, + 0.0004306451612903504, + 0.0005339999999999752, + -0.0013783870967741555, + 0.0008616129032257925, + 0, + 0, + 0.0005339999999999752, + 0.0004306451612903504, + -0.0013780645161290638, + 0.0004306451612903504, + 0.0005339999999999752, + -0.0005167741935483631, + 0, + 0, + 0.0005167741935483631, + 0, + 0, + -0.0005167741935483631, + 0.0009474193548387134, + -0.0004450000000000287, + 0, + 0, + -0.0005167741935483631, + 0, + -0.0004450000000000287, + 0.0009474193548387134, + -0.0005167741935483631, + 0, + 0, + 0, + 0.0005167741935483631, + 0, + 0, + 0, + 0, + 0, + 0, + 0.0004450000000000287, + -0.0009474193548387134, + 0.0009474193548387134, + -0.0009474193548387134, + 0, + 0, + 0.0009474193548387134, + -0.0004306451612903504, + -0.0009474193548387134, + 0.0004450000000000287, + 0, + 0.0005167741935483631, + 0, + -0.0005167741935483631, + -0.0004450000000000287, + 0.0013780645161290638, + -0.0009474193548387134, + 0.0005167741935483631, + 0, + -0.0005167741935483631, + 0, + 0, + 0.0005167741935483631, + -0.0005339999999999752, + 0, + -0.0004306451612903504, + 0.0004306451612903504, + 0, + 0, + 0.0005167741935483631, + -0.0005167741935483631, + -0.0004306451612903504, + 0, + 0, + 0, + 0, + 0, + -0.0008616129032257925, + 0.0004306451612903504, + -0.0004306451612903504, + 0.0004306451612903504, + 0, + -0.0004306451612903504, + 0.0008616129032257925, + -0.0008616129032257925, + 0.0008903333333333189, + -0.00043096774193544216, + 0, + 0, + 0.00043096774193544216, + 0, + 0, + -0.00043096774193544216, + 0.00043096774193544216, + -0.0004453333333332902, + 0, + 0.0008616129032257925, + -0.0008616129032257925, + 0.00043096774193544216, + -0.0008616129032257925, + -0.0005167741935483631, + 0.0005339999999999752, + 0.0004306451612903504, + -0.0004306451612903504, + 0, + 0.0004450000000000287, + -0.0004306451612903504, + -0.0005167741935483631, + 0.0005167741935483631, + 0, + -0.0005339999999999752, + 0.0005167741935483631, + 0, + -0.0005167741935483631, + 0, + 0.0005167741935483631, + -0.0009474193548387134, + 0.0004306451612903504, + 0, + 0, + 0, + 0, + 0, + 0.000979000000000004, + -0.0004306451612903504, + 0, + -0.0005167741935483631, + 0.0005167741935483631, + 0.0004450000000000287, + -0.0013780645161290638, + 0, + 0.0009474193548387134, + -0.0005339999999999752, + 0.0005167741935483631, + 0, + 0.0004306451612903504, + -0.0004306451612903504, + -0.0005339999999999752, + 0.0009474193548387134, + -0.0004306451612903504, + 0, + -0.0005339999999999752, + 0.0005167741935483631, + 0, + -0.0005167741935483631, + 0.0009474193548387134, + -0.000979000000000004, + 0.0009474193548387134, + -0.0004306451612903504, + 0.0004306451612903504, + 0, + 0, + 0, + 0.00043096774193544216, + -0.0008616129032257925, + 0.0004450000000000287, + -0.0004306451612903504, + 0.0004306451612903504, + -0.0004306451612903504, + 0.0004450000000000287, + 0, + 0, + 0, + -0.0004306451612903504, + 0, + 0, + -0.0005167741935483631, + 0, + 0, + 0.0005167741935483631, + -0.0005167741935483631, + 0, + 0, + -0.0004450000000000287, + 0.0004306451612903504, + 0, + -0.0008612903225806434, + 0.0008612903225806434, + 0, + 0, + -0.0008612903225806434, + 0.0013780645161290065, + 0.0004450000000000287, + 0, + -0.0013780645161290638, + 0.0013780645161290638, + 0.00043096774193544216, + 0, + -0.0008616129032257925, + 0.0004306451612903504, + 0.00043096774193544216, + -0.0004453333333332902, + -0.0004306451612903504, + 0.0004306451612903504, + 0.00043096774193544216, + -0.0008616129032257925, + -0.0005167741935483631, + 0.000979000000000004, + -0.0004306451612903504, + 0, + -0.0009474193548387134, + 0.0009474193548387134, + -0.0005339999999999752, + 0.0005167741935483631, + -0.0009474193548387134, + 0, + -0.0004449999999999695, + -0.0005167741935484205, + 0.0013780645161290638, + -0.0008612903225806434, + 0.00043064516129029303, + 0, + -0.0009474193548387134, + 0.0009474193548387134, + 0, + 0, + -0.0004449999999999695, + -0.0005167741935484205, + 0.0005167741935484205, + 0, + -0.0005340000000000344, + 0.0005167741935484205, + 0, + -0.0009474193548387134, + 0.0009474193548387134, + -0.0005340000000000344, + 0, + 0, + 0, + -0.0004449999999999695, + 0.00043064516129029303, + 0, + 0.0005167741935484205, + -0.0009474193548387134, + 0, + 0.00043064516129029303, + 0, + -0.0008616129032257925, + 0.00044533333333334943, + -0.00043096774193549946, + 0.00043096774193549946, + -0.00043096774193549946, + 0.00043096774193549946, + 0, + 0, + -0.00043096774193549946, + 0.00043096774193549946, + -0.00044533333333334943, + 0.00043096774193549946, + 0, + 0, + 0, + 0, + -0.00043096774193549946, + 0, + 0, + 0.0008903333333333189, + -0.0008616129032257925, + 0, + 0.00043096774193549946, + -0.00043096774193549946, + 0.00044533333333334943, + -0.00043096774193549946, + 0, + 0.0008616129032257925, + -0.0004449999999999695, + 0, + 0, + 0.00043064516129029303, + -0.00043064516129029303, + -0.00044533333333334943, + 0.0008616129032257925, + -0.00043064516129029303, + 0, + 0.0004449999999999695, + -0.0008616129032257925, + 0, + -0.0004306451612903504, + 0.0008616129032258498, + -0.00044533333333334943, + 0.00043096774193549946, + 0, + -0.00043096774193549946, + -0.0004450000000000287, + 0.0004306451612903504, + 0.00043096774193549946, + -0.0008616129032258498, + 0, + 0.0004450000000000287, + -0.0009474193548387134, + 0.0009474193548387134, + -0.0004306451612903504, + 0, + -0.0005167741935483631, + 0.0005339999999999752, + 0, + -0.0005167741935483631, + 0.0005167741935483631, + 0, + 0.0004450000000000287, + 0, + -0.0009474193548387134, + 0, + -0.0008903333333333189, + 0.0008616129032257925, + -0.00043064516129029303, + 0.0009474193548386562, + -0.0005167741935483631, + 0, + 0, + -0.00043064516129029303, + 0.00043064516129029303, + 0, + -0.0008616129032257925, + 0.0008616129032257925, + 0, + -0.0008616129032257925, + 0.0008903333333333189, + 0, + -0.00043064516129029303, + -0.00043096774193549946, + 0.00044533333333334943, + -0.00043096774193549946, + -0.0004306451612903504, + 0.0004306451612903504, + 0.00043096774193549946, + -0.00044533333333334943, + 0.0008616129032257925, + -0.0008616129032257925, + 0.00043096774193549946, + -0.00044533333333334943, + -0.0004306451612903504, + 0.0008616129032258498, + -0.00043096774193549946, + 0, + 0.00044533333333334943, + -0.00043096774193549946, + -0.0004306451612903504, + 0.0012922580645161428, + -0.0004449999999999695, + 0, + -0.00043096774193549946, + -0.0004306451612903504, + 0, + 0.0008903333333333781, + -0.00043096774193549946, + 0, + -0.0004306451612903504, + 0.0004450000000000287, + 0, + -0.0009474193548387134, + 0.0005167741935483631, + 0.0008616129032258498, + -0.00044533333333334943, + 0.00043096774193549946, + -0.0008616129032258498, + 0, + 0.0004450000000000287, + 0, + -0.0004306451612903504, + 0.0008616129032258498, + -0.00043096774193549946, + 0, + 0.00043096774193549946, + 0.00043064516129029303, + -0.00043064516129029303, + 0, + 0.00043064516129029303, + -0.0008616129032257925, + 0, + 0, + 0.00044533333333334943, + -0.00043096774193549946, + 0.00043096774193549946, + 0.0009474193548386562, + -0.0014243333333332942, + 0, + 0.0008616129032257925, + -0.00043064516129029303, + -0.00043096774193549946, + 0, + 0.00043096774193549946, + -0.00043096774193549946, + -0.0004306451612903504, + 0.0004450000000000287, + 0, + 0, + -0.0004306451612903504, + 0, + 0.0004450000000000287, + -0.0004171875000000269, + 0.0008903333333333781, + 0.00043064516129029303, + -0.0008616129032257925, + -0.0004306451612903504, + -0.000979000000000004, + 0.0013780645161290638, + 0.00043096774193549946, + -0.0018090322580645633, + 0.0009474193548387134, + 0.0004450000000000287, + 0, + -0.0004306451612903504, + 0.0004306451612903504, + -0.0004450000000000287, + 0, + 0, + -0.0009474193548387134, + 0, + 0.000979000000000004, + 0, + 0, + 0, + 0.0004450000000000287, + -0.0009474193548387134, + 0, + 0, + -0.0004306451612903504, + 0, + 0.0004306451612903504, + 0, + 0.0005167741935483631, + -0.0005339999999999752, + 0, + 0, + 0, + 0, + 0.0005339999999999752, + -0.0005167741935483631, + 0.0005167741935483631, + 0, + -0.0005339999999999752, + 0, + 0, + 0, + -0.0004306451612903504, + 0, + 0, + 0.0004306451612903504, + 0.0005167741935483631, + -0.0005339999999999752, + -0.0004306451612903504, + 0, + -0.00043064516129029303, + 0.00043064516129029303, + 0, + 0, + -0.00043064516129029303, + 0, + 0, + 0, + 0, + 0, + 0, + 0.0004449999999999695, + -0.0008612903225806434, + 0, + 0.0004306451612903504, + 0.0004449999999999695, + -0.00043064516129029303, + 0, + -0.0004306451612903504, + 0.0004306451612903504, + 0, + -0.0004306451612903504, + 0.0004306451612903504, + -0.0004306451612903504, + 0.0004450000000000287, + -0.0004306451612903504, + 0, + -0.0009477419354838626, + 0, + 0.00044533333333334943, + 0.0005167741935483631, + -0.0005167741935483631, + -0.00043096774193549946, + 0.00044533333333334943, + -0.0008616129032257925, + 0.00043064516129029303, + 0.0009477419354838626, + 0, + -0.0009793333333333247, + 0, + 0.00043096774193549946, + 0, + 0, + -0.00043096774193549946, + 0.00043096774193549946, + -0.0012922580645161428, + 0.0004306451612903504, + 0.00043064516129029303, + -0.00043064516129029303, + 0.0004449999999999695, + 0.00043096774193549946, + -0.00043096774193549946, + 0, + 0, + 0, + -0.00043064516129029303, + 0.0008616129032257925, + -0.0008616129032257925, + 0.0008903333333333189, + -0.0008616129032257925, + 0.00043064516129029303, + -0.00043064516129029303, + 0.0004449999999999695, + -0.00043064516129029303, + 0.00043064516129029303, + -0.0008612903225806434, + 0.0004306451612903504, + 0, + 0, + 0, + 0.00043064516129029303, + -0.0004449999999999695, + -0.0004306451612903504, + 0, + -0.0006029032258064332, + 0.0014641935483870766, + -0.0004449999999999695, + 0, + 0, + -0.0004306451612903504, + 0, + 0.0004306451612903504, + 0, + 0.00043064516129029303, + -0.00043064516129029303, + 0, + -0.0004306451612903504, + 0.0004306451612903504, + 0, + 0.0004449999999999695, + 0.00043096774193549946, + -0.00043096774193549946, + -0.00043064516129029303, + 0, + 0, + 0, + 0, + 0.00043064516129029303, + 0.00044533333333334943, + -0.0008616129032257925, + 0.00043064516129029303, + 0, + 0.00043096774193549946, + -0.00044533333333334943, + 0.00043096774193549946, + -0.00043096774193549946, + -0.00043064516129029303, + 0.00043064516129029303, + -0.0008899999999999982, + 0.0008612903225806434, + -0.00043064516129029303, + 0.00043064516129029303, + -0.0008899999999999982, + 0.0008612903225806434, + -0.00043064516129029303, + 0, + 0.00043064516129029303, + 0, + -0.0008612903225806434, + 0.0008612903225806434, + -0.00043064516129029303, + -0.0004450000000000287, + 0.0008612903225806434, + 0.00043096774193549946, + -0.00043096774193549946, + -0.0008612903225806434, + 0.0004450000000000287, + 0, + 0.00043064516129029303, + -0.00043064516129029303, + 0.0004449999999999695, + 0, + 0, + 0, + 0, + -0.0004449999999999695, + 0, + 0.0013783870967741555, + -0.001809032258064506, + 0.0013353333333333476, + 0, + -0.0008616129032257925, + 0, + 0.00043064516129029303, + 0.0009477419354838626, + -0.0009477419354838626, + 0, + 0.0009477419354838626, + -0.0013783870967741555, + 0, + 0.0004449999999999695, + -0.00043064516129029303, + 0.0008616129032257925, + -0.0012922580645161428, + 0.0008612903225806434, + 0, + -0.0014641935483870766, + 0.0014641935483870766, + -0.0008612903225806434, + 0.0004450000000000287, + 0.0008616129032257925, + -0.00043096774193549946, + 0, + -0.00043064516129029303, + 0, + 0.00043064516129029303, + 0.0009477419354838626, + -0.0005167741935483631, + 0, + 0, + 0, + 0.0009474193548387134, + -0.0009474193548387134, + 0.000979000000000004, + 0.00043064516129029303, + 0, + 0.0004306451612903504, + 0.0005339999999999752, + 0.0004306451612903504, + -0.0009474193548387134, + 0.0005167741935483631, + 0.0004306451612903504, + 0.00044533333333334943, + 0.0013780645161290065, + 0.001378387096774213, + -0.0005167741935484205, + -0.0004449999999999695, + -0.0008616129032258498, + -0.0005167741935483631, + -0.00043064516129029303, + -0.00043096774193549946, + -0.0014240000000000327, + -0.0008612903225806434, + -0.0009477419354838626, + -0.0014641935483870766, + -0.0004450000000000287, + -0.0009477419354838626, + -0.0018087096774193569, + 0.0005167741935484205, + -0.0009474193548387134, + 0, + 0, + -0.0008616129032258498, + 0.0018090322580645633, + 0, + 0.00043064516129029303, + 0, + -0.00043064516129029303, + -0.0005167741935484205, + -0.0008899999999999982, + 0.0004306451612903504, + 0, + -0.0004306451612903504, + -0.0009793333333333247, + -0.0008616129032257925, + -0.0004306451612903504, + -0.0005167741935483631, + 0, + -0.0004450000000000287, + -0.00043064516129029303, + -0.0005170967741935695, + 0, + -0.0008899999999999982, + 0, + -0.00043064516129029303, + 0.00043064516129029303, + -0.00043064516129029303, + 0.0004449999999999695, + -0.0013780645161290065, + 0.0009474193548387134, + 0, + 0.0004449999999999695, + -0.0009474193548387134, + -0.00043064516129029303, + 0.00043064516129029303, + 0, + 0.000979000000000004, + 0.0004306451612903504, + 0.00043064516129029303, + -0.00043064516129029303, + 0.0009793333333333247, + -0.0009181249999999919, + 0, + 0, + 0.00043064516129029303, + -0.00043064516129029303, + -0.0004306451612903504, + -0.0004449999999999695, + 0, + 0, + 0.00043064516129029303, + 0, + -0.0009474193548387134, + 0, + 0, + 0, + -0.0004449999999999695, + 0, + 0.0009474193548387134, + 0, + -0.0005340000000000344, + -0.00043064516129029303, + 0.00043064516129029303, + 0, + -0.00043064516129029303, + 0, + 0.00043064516129029303, + -0.0008616129032257925, + 0.001809032258064506, + -0.0004449999999999695, + 0.0008612903225806434, + -0.0004306451612903504, + 0, + -0.0009474193548387134, + 0.0005340000000000344, + -0.0005167741935484205, + 0.0005167741935484205, + 0, + -0.0005340000000000344, + 0.0005167741935484205, + -0.0009474193548387134, + -0.00043096774193549946, + 0.001809032258064506, + -0.000979000000000004, + 0.0009474193548387134, + 0, + 0.0004306451612903504, + -0.0004450000000000287, + 0, + -0.00043064516129029303, + -0.0005167741935484205, + 0.0013780645161290638, + -0.0008899999999999982, + 0.0008612903225806434, + 0, + 0.00043064516129029303, + 0, + -0.00043064516129029303, + 0.00043064516129029303, + 0.0005170967741935695, + 0, + -0.0005343333333333552, + -0.00043064516129029303, + 0.00043064516129029303, + 0, + -0.0008899999999999982, + 0.0004306451612903504, + -0.0004306451612903504, + 0.0004306451612903504, + -0.0004306451612903504, + 0, + 0.0004306451612903504, + 0.0009477419354838626, + 0.00043064516129029303, + 0, + 0.0004306451612903504, + 0, + -0.0004306451612903504, + 0.0013780645161290638, + -0.0018690000000000022, + 0.00043064516129029303, + -0.00043064516129029303, + -0.0005170967741935695, + 0.0009793333333333247, + 0, + -0.00043064516129029303, + 0, + 0.0008612903225806434, + 0, + 0.0009474193548387134, + 0, + 0, + 0.0008903333333333189, + -0.00043096774193549946, + -0.0008612903225806434, + 0.0004306451612903504, + -0.0009474193548387134, + 0.0005339999999999752, + 0.0004306451612903504, + 0.00043064516129029303, + 0.00043096774193549946, + -0.00043096774193549946, + 0.0009477419354838626, + 0.00044533333333334943, + 0, + 0, + 0.0018087096774193569, + -0.0009474193548387134, + 0.000979000000000004, + 0, + 0.0008612903225806434, + 0, + 0.0009793333333333247, + -0.00043064516129029303, + 0.0008612903225806434, + 0, + -0.0008612903225806434, + 0, + -0.0005170967741935695, + 0, + -0.00043064516129029303, + -0.0004450000000000287, + 0.0004306451612903504, + -0.0008612903225806434, + 0.00043064516129029303, + -0.00043064516129029303, + 0, + 0, + 0, + -0.0005167741935484205, + 0.0005340000000000344, + 0, + -0.0005167741935484205, + 0, + 0.0005167741935484205, + -0.0005340000000000344, + -0.00043064516129029303, + 0.00043064516129029303, + 0.0005167741935484205, + 0, + 0, + 0.00043064516129029303, + 0.0008612903225806434, + 0, + -0.0013349999999999677, + 0.0008612903225806434, + 0, + 0, + 0.0004449999999999695, + 0.0005170967741935695, + -0.0005170967741935695, + 0.0005170967741935695, + 0, + -0.0005343333333333552, + 0, + 0.0005170967741935695, + 0, + -0.0005343333333333552, + 0.0005170967741935695, + 0.00043064516129029303, + 0.0004306451612903504, + 0, + 0, + 0.0006029032258064332, + 0, + 0, + 0.0008899999999999982, + -0.00043064516129029303, + -0.0010335483870967835, + 0.0010335483870967835, + -0.0004306451612903504, + 0, + -0.0010335483870967835, + 0.0010335483870967835, + -0.0006029032258064332, + 0, + 0.0006029032258064332, + -0.0006029032258064332, + 0.0006029032258064332, + 0, + -0.000622999999999981, + 0, + 0.0006029032258064332, + 0, + 0.0004450000000000287, + -0.0010335483870967835, + -0.0004306451612903504, + 0.0010335483870967835, + -0.0006029032258064332, + 0.000622999999999981, + -0.0006029032258064332, + 0.0006029032258064332, + -0.0006029032258064332, + -0.0004306451612903504, + 0.0004450000000000287, + -0.0008612903225806434, + -0.0005170967741935695, + 0.0009477419354838626, + 0.0010335483870967835, + 0, + 0, + 0.002239677419354856, + 0.00043064516129029303, + 0, + 0.001869333333333382, + 0.00043064516129029303, + -0.00043064516129029303, + 0.00043064516129029303, + 0.0005167741935483631, + 0, + 0.0008616129032258498, + 0, + -0.00043096774193549946, + 0.001378387096774213, + 0, + 0, + 0, + -0.0005167741935484205, + 0.000979000000000004, + 0, + 0, + -0.00043064516129029303, + 0.0018087096774193569, + -0.000979000000000004, + 0.0009474193548387134, + -0.0013780645161290638, + 0.0009474193548387134, + 0, + 0, + 0, + 0, + 0, + 0.0008903333333333189, + -0.0008616129032257925, + 0.0004306451612903504, + -0.0004306451612903504, + 0, + 0.0008616129032257925, + 0, + 0, + 0.0004306451612903504, + 0.000979000000000004, + -0.0004306451612903504, + 0.0004306451612903504, + -0.0004306451612903504, + -0.0005339999999999752, + 0.0005167741935483631, + -0.0005167741935483631, + 0.0005167741935483631, + -0.0009474193548387134, + -0.0004453333333332902, + -0.0004306451612903504, + -0.0013780645161290065, + 0, + -0.000979000000000004, + 0, + -0.00043096774193549946, + -0.0004306451612903504, + 0, + -0.0005339999999999752, + -0.00043064516129029303, + 0, + -0.00043096774193549946, + 0, + -0.0009474193548387134, + 0.0005167741935483631, + -0.0005167741935483631, + -0.0004306451612903504, + 0, + -0.00043064516129029303, + 0, + -0.0004306451612903504, + -0.0009793333333333247, + -0.00043064516129029303, + 0.00043064516129029303, + 0, + 0, + 0.00044533333333334943, + -0.0008616129032257925, + 0.00043064516129029303, + -0.00043064516129029303, + 0, + 0.00043064516129029303, + 0.00043096774193549946, + -0.0008616129032257925, + 0.00043064516129029303, + -0.0004449999999999695, + 0.0008616129032257925, + 0, + 0, + 0, + -0.00043096774193549946, + 0.00043096774193549946, + 0.0005167741935483631, + -0.0005167741935483631, + 0.0009474193548387134, + -0.0009474193548387134, + 0.000979000000000004, + 0, + -0.0004306451612903504, + 0.0004306451612903504, + 0, + -0.0004306451612903504, + 0.0008612903225806434, + -0.0013780645161290065, + 0.0013780645161290065, + -0.0008899999999999982, + 0.0008612903225806434, + -0.00043064516129029303, + 0.00043064516129029303, + 0.0004450000000000287, + 0.0005167741935483631, + 0.0012922580645161428, + -0.00043064516129029303, + 0.00043064516129029303, + 0, + 0, + 0, + 0, + -0.0004449999999999695, + 0, + 0.0009474193548386562, + -0.0005167741935483631, + 0.001378387096774213, + 0.0004449999999999695, + 0.0009474193548387134, + 0.0013780645161290638, + -0.0004306451612903504, + 0.0013353333333333476, + 0.0005167741935483631, + 0.0004306451612903504, + 0.0026703225806451493, + 0.0005167741935483631, + 0.001869333333333382, + 0.00043064516129029303, + 0.001809032258064506, + 0.0018951612903225761, + 0.000979000000000004, + 0.0018087096774193569, + 0.0008616129032257925, + -0.00043064516129029303, + 0.00223935483870965, + 0.0005343333333333552, + 0.0012922580645161428, + 0.0009474193548387134, + 0.0008612903225805861, + 0, + 0.0009477419354838626, + 0.001808709677419414, + 0, + 0.00043064516129029303, + 0.0014243333333334126, + 0.0009474193548387134, + 0, + 0.00043064516129029303, + 0.0008903333333332597, + 0.0009474193548387134, + 0.0004306451612904077, + 0.0009477419354838626, + 0, + -0.0005343333333333552, + 0.0005170967741935695, + 0, + 0, + 0.0004449999999999695, + 0, + 0, + -0.0013783870967741555, + 0, + -0.0004450000000000879, + -0.00043064516129029303, + 0.00043064516129029303, + 0, + 0.0004450000000000879, + 0, + 0.00043064516129029303, + -0.0008612903225807008, + 0, + 0.0004450000000000879, + 0, + 0.0009477419354838626, + -0.0005170967741935695, + 0.0015133333333333591, + 0.00043064516129029303, + 0.0005167741935484205, + 0.00043096774193544216, + -0.00043096774193544216, + 0.0004453333333332902, + 0.00043064516129029303, + -0.0008616129032257352, + 0.00043096774193544216, + -0.0004453333333332902, + 0, + 0.0008616129032257352, + -0.00043064516129029303, + 0, + 0.00043064516129029303, + -0.00043064516129029303, + 0.0004449999999999695, + 0, + 0, + -0.00043064516129029303, + 0.000979000000000004, + 0.00043064516129029303, + 0, + 0.00043064516129029303, + 0, + -0.0004449999999999695, + -0.00043064516129029303, + 0.00043064516129029303, + 0.00043064516129029303, + 0, + 0, + -0.00043064516129029303, + 0.00043064516129029303, + -0.00043064516129029303, + 0.0004449999999999695, + 0.0004306451612904077, + 0.0009477419354838626, + 0, + -0.00044533333333340863, + 0.00043096774193555676, + -0.0009477419354838626, + 0.0009477419354838626, + -0.0013783870967742703, + -0.000889999999999939, + 0.00043064516129029303, + -0.0009474193548387134, + -0.00043064516129029303, + 0, + -0.00043096774193544216, + 0.00043096774193544216, + -0.00043096774193544216, + 0, + 0, + 0, + -0.0005167741935484205, + 0, + -0.0004449999999999695, + 0.00043064516129029303, + 0.0005167741935484205, + -0.0009474193548387134, + 0.00043064516129029303, + 0.0005340000000000344, + -0.0009474193548387134, + 0.0009474193548387134, + -0.001464193548387134, + 0.000979000000000004, + -0.00043064516129029303, + 0, + -0.0009474193548387134, + -0.0005170967741935695, + 0, + -0.0008612903225807008, + 0.0004306451612904077, + -0.0004306451612904077, + 0, + 0.0008612903225807008, + -0.0008612903225807008, + 0, + 0.0008612903225807008, + -0.0004449999999999695, + -0.0004306451612904077, + 0, + 0.0004306451612904077, + 0, + 0, + 0, + 0, + 0, + 0, + -0.0004306451612904077, + 0, + -0.00043064516129029303, + 0.0004449999999999695, + -0.00043064516129029303, + 0, + 0.00043064516129029303, + 0, + 0, + 0.0004306451612904077, + -0.0008612903225807008, + 0, + 0.0004449999999999695, + -0.00043064516129029303, + 0.00043064516129029303, + 0, + -0.00043064516129029303, + 0, + -0.0009477419354838626, + 0.0009477419354838626, + 0.00043064516129029303, + -0.00043064516129029303, + -0.0005167741935484205, + -0.0004453333333332902, + 0.0009477419354838626, + -0.0009477419354838626, + 0.0009477419354838626, + 0.00043064516129029303, + 0.0004450000000000879, + 0, + 0.0009477419354838626, + -0.0009477419354838626, + 0.0004449999999999695, + 0, + 0, + 0, + 0.0005170967741935695, + 0.0004449999999999695, + 0, + 0, + -0.00043064516129029303, + 0.0004449999999999695, + 0, + 0.0005167741935484205, + -0.0005167741935484205, + 0.001464193548387134, + 0, + 0, + 0.00043096774193544216, + 0.00043064516129029303, + 0, + 0.0005340000000000344, + 0.0012919354838709938, + -0.0008612903225807008, + 0.0008612903225807008, + 0.000533999999999916, + 0, + 0, + -0.0005167741935483059, + 0.0018090322580644486, + 0, + 0.0005167741935484205, + -0.002325806451612869, + 0.0018090322580644486, + -0.0004449999999999695, + 0, + 0.00043064516129029303, + 0, + -0.00043064516129029303, + 0.0004449999999999695, + 0, + 0.0005167741935484205, + 0, + 0.0004449999999999695, + 0, + -0.00043064516129029303, + 0.0008612903225807008, + -0.0004306451612904077, + 0, + 0, + -0.0009474193548387134, + -0.00043064516129029303, + -0.0008903333333333781, + -0.0005167741935483059, + -0.0004306451612904077, + -0.0008612903225805861, + -0.0009474193548387134, + 0, + -0.00043096774193544216, + 0, + -0.0005167741935484205, + 0.0009793333333333247, + -0.0009477419354838626, + 0, + 0, + 0.0005167741935484205, + 0, + 0, + -0.0005167741935484205, + 0, + 0.0005340000000000344, + 0.00043096774193544216, + 0, + -0.0009477419354838626, + 0.0005167741935484205, + -0.0005340000000000344, + -0.0009474193548387134, + -0.0009477419354838626, + -0.0008612903225807008, + -0.0004449999999999695, + 0, + 0.0008612903225807008, + 0.0009477419354838626, + 0.00043064516129029303, + 0.0015130000000000384, + 0, + 0.0013783870967741555, + 0.00043064516129029303, + -0.00043064516129029303, + 0.00043064516129029303, + -0.0014239999999999735, + 0, + -0.0009477419354838626, + 0.0009477419354838626, + 0.00043064516129029303, + 0, + -0.00043064516129029303, + 0.0013780645161290065, + 0, + 0, + 0.0013780645161290065, + -0.0009474193548387134, + -0.00043064516129029303, + 0.00043064516129029303, + 0, + -0.00043064516129029303, + 0, + -0.0009474193548387134, + 0, + 0, + -0.00043064516129029303, + -0.00043096774193544216, + 0, + -0.000979000000000004, + -0.0005167741935484205, + 0.0005167741935484205, + -0.0018951612903225761, + 0.0004449999999999695, + -0.00043064516129029303, + -0.0004306451612904077, + 0, + 0.0004306451612904077, + -0.0004450000000000879, + -0.00043064516129029303, + 0.00043064516129029303, + 0.0004306451612904077, + -0.0014240000000000919, + 0, + -0.0008616129032257352, + 0.00043064516129029303, + -0.00043064516129029303, + 0, + 0.0008616129032257352, + 0, + 0, + 0, + 0.0013780645161291212, + 0.0009477419354838626, + 0.0009474193548387134, + -0.0005167741935484205, + 0.000979000000000004, + 0, + 0, + 0.0009477419354838626, + 0.0004449999999999695, + 0, + 0.0013780645161290065, + 0.004996129032258133, + 0.013265483870967733, + 0.012105666666666674, + 0.007838387096774159, + 0.0063745161290322885, + 0.004479354838709712, + 0.004272333333333241, + 0.00456548387096784, + 0.003617741935483863, + 0.003618064516129012, + 0.0013780645161290065, + 0.001869333333333382, + 0, + 0.0018087096774192996, + 0.0013783870967741555, + 0.0004450000000000879, + 0.0009474193548387134, + 0, + 0.00043096774193544216, + 0.0009477419354838626, + 0.0015130000000000384, + 0.00043064516129029303, + 0.0008616129032258498, + 0.0013780645161290065, + 0.000979000000000004, + 0.0008616129032257352, + 0.0009474193548387134, + 0.0008612903225807008, + 0, + 0.0009793333333333247, + 0.009992258064516151, + 0.009130645161290302, + 0.005426774193548426, + 0.002314333333333233, + 0.0009474193548387134, + -0.00043064516129029303, + -0.0005167741935484205, + -0.00043064516129029303, + -0.0014243333333332942, + -0.0008343750000000538, + -0.0018693333333332637, + -0.0005167741935484205, + -0.00043096774193544216, + -0.0004306451612904077, + -0.0014239999999999735, + -0.0008612903225805861, + -0.0009477419354838626, + -0.0004306451612904077, + -0.0009474193548387134, + -0.0004449999999999695, + -0.00043096774193544216, + -0.0005167741935484205, + -0.00043064516129029303, + -0.0008900000000000574, + 0, + -0.0005167741935483059, + -0.0004306451612904077, + -0.0005170967741934549, + 0, + -0.0009474193548387134, + 0.0009474193548387134, + -0.0013780645161291212, + -0.0004449999999999695, + -0.00043064516129029303, + 0, + -0.0005170967741935695, + 0, + -0.0008900000000000574, + 0, + -0.0009474193548387134, + -0.0008612903225805861, + 0, + -0.0005170967741935695, + 0, + 0.0005170967741935695, + 0, + 0, + -0.0009477419354838626, + 0.0013783870967741555, + 0.0008612903225807008, + -0.0008900000000000574, + 0.0008612903225807008, + -0.0004306451612904077, + 0, + 0.0009474193548387134 + ], + "yaxis": "y" + } + ], + "layout": { + "autosize": true, + "legend": { + "tracegroupgap": 0 + }, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Data for SHT30 temperature change over time" + }, + "xaxis": { + "anchor": "y", + "autorange": true, + "domain": [ + 0, + 1 + ], + "range": [ + "2025-03-20 13:06:24", + "2025-03-21 15:52:05" + ], + "title": { + "text": "DateTime" + }, + "type": "date" + }, + "yaxis": { + "anchor": "x", + "autorange": true, + "domain": [ + 0, + 1 + ], + "range": [ + -0.05185864814814813, + 0.1005476481481482 + ], + "title": { + "text": "temp_diff_per_second" + }, + "type": "linear" + } + } + }, + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAAFoCAYAAADKCW0/AAAAAXNSR0IArs4c6QAAIABJREFUeF7tvQ+YXVV57/+emSCTSCEQCSGICSAGigi59YJAf4VYBaFCxNuI0UahELhikD+5gpnH0hR9JoJNBIlYCBQ0apTcq4ItCrYGegsKt22kiBArEKSEgAIBIRMkM+fXdx/WyZo9e5+996xz9qy9zmc/jwJz9lrrXZ/vOvus717/avV6vS5cEIAABCAAAQhAAAIQgAAEHAjUMBYO9EgKAQhAAAIQgAAEIAABCEQEMBY0BAhAAAIQgAAEIAABCEDAmQDGwhkhGUAAAhCAAAQgAAEIQAACGAvaAAQgAAEIQAACEIAABCDgTABj4YyQDCAAAQhAAAIQgAAEIAABjAVtAAIQgAAEIAABCEAAAhBwJoCxcEZIBhCAAAQgAAEIQAACEIAAxoI2AAEIQAACEIAABCAAAQg4E8BYOCMkAwhAAAIQgAAEIAABCEAAY0EbgAAEIAABCEAAAhCAAAScCWAsnBGSAQQgAAEIQAACEIAABCCAsaANQAACEIAABCAAAQhAAALOBDAWzgjJAAIQgAAEIAABCEAAAhDAWNAGIAABCEAAAhCAAAQgAAFnAhgLZ4RkAAEIQAACEIAABCAAAQhgLGgDEIAABCAAAQhAAAIQgIAzAYyFM0IygAAEIAABCEAAAhCAAAQwFrQBCEAAAhCAAAQgAAEIQMCZAMbCGSEZQAACEIAABCAAAQhAAAIYC9oABCAAAQhAAAIQgAAEIOBMAGPhjJAMIAABCEAAAhCAAAQgAAGMBW0AAhCAAAQgAAEIQAACEHAmgLFwRkgGEIAABCAAAQhAAAIQgADGgjYAAQhAAAIQgAAEIAABCDgTwFg4IyQDCEAAAhCAAAQgAAEIQABjQRuAAAQgAAEIQAACEIAABJwJYCycEZIBBCAAAQhAAAIQgAAEIICxoA1AAAIQgAAEIAABCEAAAs4EMBbOCMkAAhCAAAQgAAEIQAACEMBY0AYgAAEIQAACEIAABCAAAWcCGAtnhGQAAQhAAAIQgAAEIAABCGAsaAMQgAAEIAABCEAAAhCAgDMBjIUzQjKAAAQgAAEIQAACEIAABDAWtAEIQAACEIAABCAAAQhAwJkAxsIZIRlAAAIQgAAEIAABCEAAAhgL2gAEIAABCEAAAhCAAAQg4EwAY+GMsHUGD27YKGctvkJefGlrdOPKgfNlztGzO1wq2UMgPAK/fnaLLDhvQP7boQfKwJKF4VWQGkEAAhCAAAQqTsB7Y7F1cJss6r9K7l3/0CjU+06fKquv7pc9p0weswz9y1bJvz3wH875JAVgTMVZH36vnDn/pDHHOJaEN6y5TVZce/OopHFjo/dd//W/k+uXXyyHzJo56n6bz6133JOYZzyRrcu6e9ZH+tnXkbMPjgzWpIl9I/6epPXcE47J3YnspJZj0cCnNFk6+xRrWiwYCz9VaqWLeQbOOWZ27u+xn7UkKghAAAIQyEOgMsZCKxPvjGpH8pbb75Yinc84lE52RrUzt/Z7d3bEtKSJazrnD/3H46PMguF10TkfaBqdrA5nKz6mQzHv5OMSjZMxFXZ5Jo3Gb5tCE7etc9GOZCe1zPNl8vmeLJ19jt3EVrQ9VKFOIcSIsQhBReoAAQhAoD0EKm0sFIHpvI7VXHSyMzoexsLwSJtypW8Qf/bwo3La3HdGLSirw+lqLLSM+NSvpDI17v6BVaPMUNrfk5p/J7Vsz9dt/HLJ0nn8IstfMsYiP6sy70SXMmlTFgQgAAG/CVTeWChe7VCuu3t9s1OaNn0qPgXHvMG3Jdp1l0lRPvu9aVriFKy0aTxxmZPyttPG116Ycu3pSHZn8Ovf/mE0OqNXq3UaRTuQWfe7GIu0pp9UZlo5eaeTtdLSMI1Py4pPpbNHYDR2eyqZGXWJl2OPxthG7arPfEL+5qu3NKfwpU3bM2U+semZJq64vobN31x+kVy24itRnqa9/OTffj5qelq8LWVNi9P8Nz/z3KgRwbgxtjuQH37/u5trh+x2nac+rR6JSelN/i9v3dZcY/HuY98+YopdXIekfLTc+AsIu05ZeZq4423gjXvvKS/+9mUZ6F84wkQnPYficRZlYbeNVh36tM/ibSH+PLO/b/vP2LvJOO3FTRpnk+9jv9octRN7Oqhpb//zI3Pl/L/4YnP9mUmj7duePpn2zM36Pvv900t0EIAABMIkEISxiE+50R/0Tw1cJ+f82SnNdQNJU22MKUlaY1Ekj1Yd6KSpUEmjCuYH3+442J2AvIu+Td55DVDZxiJpelSaNsq1yNvQViYobj5tE2DWl9idpPh0MWMysqaRGc3infuk2JJYJBkp05FNM59aF3sNT5KmrXQuaizUBCW1r7z1Sfu+JKXXewe++DWZe8IfytQ3TI6MhZZvd3STvk+q5SWfvVYu//Q5zTVYSW3J1jwrT9NONz397IhpfEnlJ60tKNKWk9pBEp80XeMxpcUeb5f2C4+8o8B5pkLFjYW+JEl70ZL09/g6tTzf5zB/sqkVBCAAAb8JBGEs8i4QTJpWU3T6TJGpOUlToVr9CMdjyer0tzI08YXbSZ1S07lOWuRt5531tj1tjYXJw35zm5RXp42FaR/xN8pxLdLWjBT5e5pm8Y6iqfO0qXuMWtQabwdF22hSvO00Fkm7MhWpT1K7zdPpTrunVdnxslqNwtg7TSXlmfbdT2pfrcxaq80SNN5W34e4jmkjevHys2I3Hfe8I4Q217EYi6QRsjRm8b/n/T77/dNLdBCAAATCJBC0sUiaApLnTbItdZ48ioxYpP0oJr1BH6uxMPHEp1vp35OmyeTdFSq++1bW4u1WHcjpe01pTr3ptLFotdbF7rSYqTZxo9QOYxHvfLVqB/FOYJaxSNJZ2WeNrhh9io5YJBmLIvVJahet0pv7s4yF3pe2wUOaUS6SZ9Z0PWNcW30vitQzybAnjY6kjTokTT+K84kbqCoYi7zf5/iuc2H+hFMrCEAAAn4RCMJYxKcImB/2F158acRi4CIjFkXyKGIsWi2ujn/maizicZlOw8EHzmh2wLLK6MQai7RpGkkdwzxvsu0OctK0tqT1Fzab+Bz+ThiLeAcuaRteOybbAGZN8dJpJUk7b9n16PSIRZH6JH1fsjYd0DRFTIBp67vtusuIaUtFRyxMm9R/mnn/8c553CykGT273q2mNrbq3LeaImXyjNex1ZbdJiYz7akKxiLv9xlj4Vdng2ggAIHuIBCEsYjPt2017zi+81Bap61IHkWMRZkjFklxFZ1u1QljkbaOIMkUFOnotNIyz7a/RUYm7I5ung58kRGLuG5Zb8rj88/HYypUnjfxrR6pedIXMRZ520LRPJOm8MRjH8tIns2mVfokA2ab1gvPnpd4iGDaqFTay4ciZ++UPRWq1YhFd/xsU0sIQAAC/hKovLEo0klNGrFI+5FK65j4vsbiW7f8SN560P6Jh90lTTnq5IjFF2/4PzL/fX886gDDpM5RGldX3vrVy/M2PM0oFP171hqL+HSZPKdIt2qL+hY9/vY7qWPaiqNrJ7zVaELeR1+rzul96x+W10/qay7ejjOLt+tWowtjHbHQt995tW01tS8PjyJrLEx+JrYPvu+P5Zvf/cdR2zZnfc9NPkWMvEnTao1L2vPZZY1F3u9zHtbcAwEIQAAC7SVQaWNhhsTju5ekdVy1ExZfY5D2I1UkjyIjFnZHN2nnofiuUFkLPeNlmzUh8V170g7Oy+pwuIxYGH3sOiVNx9I6tOOAvFYdjqRYjBY/vOtfogXUnRqxMPna60rsdpC0Baq9o1GaBkmdcfM33TnJbl+tOoxJ3Ew7shfbZ01LM/lk1Sft+5K065FtiMyuUFnGIs0EFKlT3vZo887bzuM71iXxMHrZJ1Yn8TFp7TiSduxqdXCmctFLdxYbi7HQtEVG1fIu0jZ1S7o/z/e5vT+V5AYBCEAAAnkIVMZY6N7m8StttyK702bSaGdH96lPOoTNXqBtG4/4vPFWeSTBbjVkH5+HnXWOhX2+RZawafPdk7aP7KSxMB0Oc/6GiTttL3/Xff81/zQtk9qE/s3m3i5jkbTLVtFzAGxGecydOQdDvxMrlp4rFy29RuJrReLtIm1rY+Wi5etlTyHLMhZ6v93Btdtp3vMbktYnmDiLTFuKt4WidUobNYjXT3lfsmh+9FzJc46FxlF0G9dWZ5zYjNM62/Y9SZtR2M/RsRqL+Hc3zzkWSQvti4xkJD3n0na/y3pm8jkEIAABCLSHgPfGoj3VJBcIlEMgy6iVEwWllEmgyHS9MuOiLAhAAAIQgEDZBDAWZROnvKAJYCzClbfVoZlJ55GES4KaQQACEIAABJIJYCxoGRBoIwGMRRthepZV2ratead5eVYdwoEABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdRwBj0X2aU2MIQAACEIAABCAAAQi0nQDGou1IyRACEIAABCAAAQhAAALdR6ArjcW6e9bLov6rIrX3nT5VVl/dL3tOmdxS/Qc3bJSly2+Sa5ZdkHlv9zUjagwBCEAAAhCAAAQg0O0Eus5YqEG4aOmXZMXSj8shs2bKDWtuk7vve0BWDpwvkyb2jWoPv352iyw4b0Ce2PRMbhPS7Y2K+kMAAhCAAAQgAAEIdB+BrjMWaiQe2fikDCxZGKkdNxppTYARi+77clBjCEAAAhCAAAQgAIH8BLrOWPQvWxXRMcbCjEhcsmi+zDl6dio5jEX+RsWdEIAABCAAAQhAAALdR6ArjcUBM/eRM+efFKntaiw2PTvYfa0mwBr3va5XJu3cK8/99ncB1o4qdYJArSYybfeJ8tRzPAM6wTfUPPec3CdbfvuKvDpUD7WK1KvNBHZ7/U6yfaguL2/b3uacyS6JwPQpEwHjQKArjUU7RywwFg6tz6OkGAuPxKhIKBiLigjlWZgYC88EqUA4GItyRcJYuPHuOmPR7jUWGAu3BuhLaoyFL0pUJw6MRXW08ilSjIVPalQjFoxFuTphLNx4d52xyNoVSo3H2u/dOWoL2rQ1FhgLtwboS2qMhS9KVCcOjEV1tPIpUoyFT2pUIxaMRbk6YSzceHedsVBcrc6xiBsLe7tZg3ruCcc0F39jLNwaoC+pMRa+KFGdODAW1dHKp0gxFj6pUY1YMBbl6oSxcOPdlcbCDdnI1BiLdtIcv7wwFuPHvqolYyyqqtz4xo2xGF/+VSwdY1GuahgLN94YCzd+grFwBOhJcoyFJ0JUKAyMRYXE8ihUjIVHYlQkFIxFuUJhLNx4Yyzc+GEsHPn5khxj4YsS1YkDY1EdrXyKFGPhkxrViAVjUa5OGAs33hgLN34YC0d+viTHWPiiRHXiwFhURyufIsVY+KRGNWLBWJSrE8bCjTfGwo0fxsKRny/JMRa+KFGdOEIxFjd+pVcee7wm7587JIcfxqFtnW6BGItOEw4vf4xFuZpiLNx4Yyzc+GEsHPn5khxj4YsS1YkDY1EdrXyKFGPhkxrViAVjUa5OGAs33hgLN34YC0d+viTHWPiiRHXiwFhURyufIsVY+KRGNWLBWJSrE8bCjXeisUg6uyGtmH2nTx11mJxbSNVKza5Q1dIrLVqMRRg6llmL0IzFiScMy1FHDpeJsCvLwlh0pexOlcZYOOErnBhjURjZiAS5Riz6l62SA2buI2fOP6mZeOvgNlnUf5UsmHe8zDl6tlsUFU6NsaiweFboGIswdCyzFqEZiznHDov+j6uzBDAWneUbYu4Yi3JVxVi48c40Fjp6ce6SK2Xp4tPlkFkzR5SmJ1ivXnuHrBw4XyZN7HOLpKKpMRYVFS4WNsYiDB3LrAXGokza4ZSFsQhHy7JqgrEoi3SjHIyFG28nY/Hgho2ydPlNcs2yC2TPKZPdIqloaoxFRYXDWIQh3DjWAmMxjvArXDTGosLijVPoGItywWMs3HhnGgsz5emYIw4dMRVKi9URi8tXrmGNhZsGpPaAACMWHohQsRAwFhUTzJNwMRaeCFGhMDAW5YqFsXDjnWksjIHoH1gl1y+/uDkdyizwnnfycaMMh1tI1UrNiEW19EqLFmMRho5l1iI0YzH7sLqcOneoTIRdWRbGoitld6o0xsIJX+HEGIvCyEYkyGUsNEXSTlG6tqKbF24rF4yFWwP0JTXGwhclqhMHxqI6WvkUKcbCJzWqEQvGolydMBZuvHMbC7diwk2NsQhDW4xFGDqWWYtQjMU1102QzZtFGLEop/VgLMrhHFIpGIty1cRYuPHGWLjxY8TCkZ8vyTEWvihRnThCMRYrvtgrW7bUMBYlNT2MRUmgAyoGY1GumBgLN965jEWrA/M4IG/QTQFSe0EAY+GFDJUKAmNRKbm8CRZj4Y0UlQkEY1GuVBgLN965jIUekKfXwJKFbqUFmJqpUGGIirEIQ8cyaxGasTh41rDMP40D8jrdhjAWnSYcXv4Yi3I1xVi48c40Fq0OyHMrOozUGIswdMRYhKFjmbUIzVjsN6MuZ3yUXaE63YYwFp0mHF7+GItyNcVYuPHGWLjxY42FIz9fkmMsfFGiOnFgLKqjlU+RYix8UqMasWAsytUJY+HGO9NYaPY6FeqAmft09XkVaZgZsXBrgL6kxlj4okR14sBYVEcrnyLFWPikRjViwViUqxPGwo13LmPx4IaNcu3XbpXP9Z8tkyb2uZUYWGqMRRiCYizC0LHMWmAsyqQdTlkYi3C0LKsmGIuySDfKwVi48c40Fq12hNKi2RWKXaHcmqAfqTEWfuhQpSgwFlVSy59YMRb+aFGVSDAW5SqFsXDjnWks3LIPPzUjFmFojLEIQ8cyaxGasZg2TeTcs7eXibAry8JYdKXsTpXGWDjhK5wYY1EY2YgEGAs3fizeduTnS3KMhS9KVCeO0IzF5Ml1uegT7ArV6RaIseg04fDyx1iUqynGwo13bmOx7p71sqj/qhGlrRw4X+YcPdstgoqnZsSi4gK+Fj7GIgwdy6wFxqJM2uGUhbEIR8uyaoKxKIt0oxyMhRvvXMZCTcXlK9fI6qv7Zc8pk6MSdUH3WYuvkLM+/N6u3i0KY+HWAH1JjbHwRYnqxIGxqI5WPkWKsfBJjWrEgrEoVyeMhRvvTGOxdXBbNFKxYN7xo0Yn1HCsXnuH6MhFt+4WhbFwa4C+pMZY+KJEdeLAWFRHK58ixVj4pEY1YsFYlKsTxsKNd6axaHXyto5aLF1+k1yz7ILmSIZbONVLjbGonmZJEWMswtCxzFpgLMqkHU5ZGItwtCyrJhiLskg3ysFYuPHONBaMWLQGjLFwa4C+pMZY+KJEdeIIzVgo+csuZVeoTrdAjEWnCYeXP8aiXE0xFm68M42FZn/Dmttk7ffuZI1FAmuMhVsD9CU1xsIXJaoTB8aiOlr5FCnGwic1qhELxqJcnTAWbrxzGQstgl2hkkFjLNwaoC+pMRa+KFGdODAW1dHKp0gxFj6pUY1YMBbl6oSxcOOd21i4FRNuaoxFGNpiLMLQscxaYCzKpB1OWRiLcLQsqyYYi7JIN8rBWLjxzmUs+petks3PPDdi9yez9uKYIw5lu1k3DUjtAQGMhQciVCyEUIzFpZdNaJJnjUXnGyHGovOMQysBY1GuohgLN96ZxoLF260BM2Lh1gB9SY2x8EWJ6sQRorFY8slXZeLEWnVEqGCkGIsKijbOIWMsyhUAY+HGO9NYsN0sxsKtiVUjNcaiGjr5FGWIxuLC87bL7rv7RDm8WDAW4Wna6RphLDpNeGT+GAs33pnGghELjIVbE6tGaoxFNXTyKcrQjEVfn8jHFmIsOt3GMBadJhxe/hiLcjXFWLjxzjQWmr3uCNU/sEquX36xHDJrZlSiHo531uIr5KwPv5c1Fm4akNoDAhgLD0SoWAihGQvFz4hF5xshxqLzjEMrAWNRrqIYCzfeuYyFbSRefGlrs8SVA+fLnKNnu0VQ8dSssai4gK+Fj7EIQ8cya4GxKJN2OGVhLMLRsqyaYCzKIt0oB2Phxju3sXArJtzUGIswtMVYhKFjmbXAWJRJO5yyMBbhaFlWTTAWZZHGWLSDNMbCkSLGwhGgJ8kxFp4IUaEwMBYVEsujUDEWHolRkVAwFuUKxYiFG+9cxsIs4L53/UOy6y6TorUW+71pmizqv0o4x2LQTQFSe0EAY+GFDJUKIkRjcfpHtsv+jWV0XB0igLHoENiAs8VYlCsuxsKNdy5joQfkHTBzH5n/vnfKpwauk3P+7JRoEbcu6l699o4RB+e5hVO91IxYVE+zpIgxFmHoWGYtMBZl0g6nLIxFOFqWVROMRVmkG+VgLNx4ZxoL+xwLHaWwjYXuDLV0+U1yzbILZM8pk90iqWhqjEVFhYuFjbEIQ8cya4GxKJN2OGVhLMLRsqyaYCzKIo2xaAdpJ2PBiIUIxqIdzXD888BYjL8GVYsAY1E1xfyIF2Phhw5VigJjUa5ajFi48c40Fpr9DWtuk7vve0Au//Q58pkrvxpNhZr6hsmy4LwBmXfycZxj4aYBqT0ggLHwQISKhYCxqJhgnoSLsfBEiAqFgbEoVyyMhRvvXMZCi9DRCV2sbV+cY8GIhVvz8yc1xsIfLaoSCcaiKkr5FSfGwi89qhANxqJclTAWbrxzGwu3YsJNzVSoMLTFWIShY5m1wFiUSTucsjAW4WhZVk0wFmWRbpSDsXDjjbFw48caC0d+viTHWPiiRHXiwFhURyufIsVY+KRGNWLBWJSrE8bCjXcuY6HbzW5+5rloW1m9dEqUfaaFbj3brRcjFmEoj7EIQ8cya4GxKJN2OGVhLMLRsqyaYCzKIs2IRTtIZxoL3W5WF2lfsmi+zDl69oizK9Rc+HiOhYn5iU3PRIyy1oK0ul+31D1r8RXy4ktbm7z3nT5VVl/dH22xi7FoRzMc/zwwFuOvQdUiCNFYvH/ukBx+WL1qUlQqXoxFpeTyIliMRbkyMGLhxjuXsTh3yZWydPHp0aF4Onqh18CSheLjORbmlHBzIrjGeNHSL8mKpR+P4o9fWfdnpcdYuDVAX1JjLHxRojpxYCyqo5VPkWIsfFKjGrFgLMrVCWPhxjvTWJiO94J5x8tbZ+03avTi8pVrmm/v3UJpT+q42Ykbh3gpWfdjLNqji++5YCx8V8i/+DAW/mlShYgwFlVQya8YMRbl6oGxcOOdaSw0e3s60NwTjolGK8z0of926IHRf/ty6ba4cbNjj7LE48y6Pz4Vyp4GpXkxYuGL8m5xYCzc+HVj6hCNxYknDMtRRw53o5yl1RljURrqYArCWJQrJcbCjXcuY+FWRLmpk04DzzIW8XUire63F7JPmtgnr27nR7hchTtTWq1Wk54ekaEh5pd3hnCYue40oafyz4CPLR5qivMnJ/TIe4+vhSmWJ7Wa0NsjQ8PDUudR44ki/ofR21MTbS7DwzSaMtTS5zrX2Am0xVjodKPPXrlaLjx7XrSgeTyvrBGIoiMW8fvjU6d+/cIr41ldym4TgZ136pG+nXrlha2vtilHsgmdgI5YTPm9neU3L1b7GbDk0h0/on88py7vmkPnpZNtd/ffe5389uVXZTudxE5iDirvXSZOiF56Df5ux0uAoCroWWX23G1nzyKqVjjBGYusNRNZRqHomgymQlWrwadFy1SoMHQssxYhToWac+yw6P+4OkeAqVCdYxtqzkyFKldZpkK58Q7OWOTZ5Um3jx3oXxhtn5t1/7du+ZG89aD9mztKxadJYSzcGqAvqTEWvihRnThCNBa6vkLXWXB1jgDGonNsQ80ZY1GushgLN97BGQvFkedcCmMssu7XqVV6IKC5jpx9cHQuhq6v0Atj4dYAfUmNsfBFierEEaKxmH1YXU6dy3SLTrZCjEUn6YaZN8aiXF0xFm68gzRwCR+0AAAgAElEQVQWbkiKpcZYFOPl690YC1+V8TcujIW/2vgcGcbCZ3X8jA1jUa4uGAs33hgLN36MWDjy8yU5xsIXJaoTRwjGYnCwLss+v1MTOiMWnW9/GIvOMw6tBIxFuYpiLNx4Yyzc+GEsHPn5khxj4YsS1YkjBGPx/PMiX7h6QhP6fjPqcsZHmQrVyVaIsegk3TDzxliUqyvGwo03xsKNH8bCkZ8vyTEWvihRnTgwFtXRyqdIMRY+qVGNWDAW5eqEsXDjjbFw44excOTnS3KMhS9KVCcOjEV1tPIpUoyFT2pUIxaMRbk6YSzceGcaC91h6dwlV8rSxac3t1x1KzKs1CzeDkNPjEUYOpZZC4xFmbTDKQtjEY6WZdUEY1EW6UY5GAs33hgLN36MWDjy8yU5xsIXJaoTR4jGYto0kXPP3l4dESoYKcaigqKNc8gYi3IFwFi48c40Fpq9Hgr37mPfHh0oxzWSACMWYbQIjEUYOpZZixCNxeTJdbnoEyze7mQ7wlh0km6YeWMsytUVY+HGO5exeHDDRrn2a7fK5/rPbh4M51ZsOKkxFmFoibEIQ8cya4GxKJN2OGVhLMLRsqyaYCzKIt0oB2PhxjvTWMRPsY4Xt+/0qbL66n7Zc8pkt0gqmhpjUVHhYmFjLMLQscxaYCzKpB1OWRiLcLQsqyYYi7JIYyzaQTrTWLSjkJDzwFiEoS7GIgwdy6xFSMZCp0Bt21aL8PVfzBqLTrYjjEUn6YaZN8aiXF0ZsXDjjbFw48fibUd+viTHWPiiRHXiCM1YKPktW2py4XnbZffdq6ND1SLFWFRNsfGPF2NRrgYYCzfeGAs3fhgLR36+JMdY+KJEdeLAWFRHK58ixVj4pEY1YsFYlKsTxsKNdy5jsXVwmyzqv0ruXf+Q7LrLJLl++cWy35umRX875ohD5cz5J7lFUeHUTIWqsHhW6BiLMHQssxahGYu+vpps3izysYWvyt57N6ZFcbWfAMai/UxDzxFjUa7CGAs33rmMhW43e8DMfWT++94pnxq4Ts75s1Oiw/LW3bNeVq+9Q1YOnN+1u0VhLNwaoC+pMRa+KFGdOEIzFrvvJvLY4zU5/SPbZf+Z1dGhapFiLKqm2PjHi7EoVwOMhRvvTGNhn7ytoxS2sdBtaJcuv0muWXYBu0K56UDqcSaAsRhnASpYPMaigqJ5EDLGwgMRKhYCxqJcwTAWbrydjAUjFsIaC7f2501qjIU3UlQmEIxFZaTyKlCMhVdyVCIYjEW5MmEs3HhnGgvN/oY1t8nd9z0gl3/6HPnMlV+NpkJNfcNkWXDegMw7+TjWWLhpQGoPCGAsPBChYiFgLCommCfhYiw8EaJCYWAsyhULY+HGO5ex0CJ0dEIXa9uXrq2Yc/Rstwgqnpo1FhUX8LXwMRZh6FhmLTAWZdIOpyyMRThallUTjEVZpBvlYCzceOc2Fm7FhJsaYxGGthiLMHQssxahGYu996rLQxt6ZP5pw3LwrOEyUXZVWRiLrpK7LZXFWLQFY+5MMBa5USXemNtY6HSoFdfe3MzEbDuru0N184WxCEN9jEUYOpZZi9CMxX4zRNbfX5P3zx2Sww+rl4myq8rCWHSV3G2pLMaiLRhzZ4KxyI1q7MZCTcXa790pq6/ub+7+pDtCnbX4ChnoX9jV06EwFm4N0JfUGAtflKhOHKEZi4Nn1eXH9/bInGOHo/9xdYYAxqIzXEPOFWNRrroYCzfemSMWut2sLtK+ZNH8UQaCXaHYFcqt+fmTGmPhjxZViSQ0YzH7sLqsuwtj0en2h7HoNOHw8sdYlKspxsKNdy5jce6SK2Xp4tOjQ/Hsi3MsMBZuzc+f1BgLf7SoSiShGYujjqzL92/vkaOOHJYTT2DEolPtEGPRKbLh5ouxKFdbjIUb70xjsXVwW7Qb1IJ5x48ascBYYCzcmp8/qTEW/mhRlUhCMxbvPHZYvn1Lr+jIxalzh6oiQ+XixFhUTrJxDxhjUa4EGAs33pnGQrNPm/Kkay8e2fikDCxZ6BZFhVOzxqLC4lmhYyzC0LHMWmAsyqQdTlkYi3C0LKsmGIuySDfKwVi48c40FmaNxRObnsksad/pU0cs8M5MEMANGIsARBQRjEUYOpZZC4xFmbTDKQtjEY6WZdUEY1EWaYxFO0hnGot2FBJyHhiLMNTFWIShY5m1CM1YvO+UIbnpqxNkvxl1OeOjTIXqVFvCWHSKbLj5YizK1ZYRCzfebTEWug7js1eulgvPntfcjtYtrOqkxlhUR6tWkWIswtCxzFqEaCy+efME0YPyMBada0kYi86xDTVnjEW5ymIs3HhjLNz4CcbCEaAnyTEWnghRoTBCMxZnLBiSL1w9QaZNEzn37O0VUqJaoWIsqqWXD9FiLMpVAWPhxhtj4cYPY+HIz5fkGAtflKhOHKEZi4s+MSSXXjYhEuCySzEWnWqJGItOkQ03X4xFudpiLNx4Yyzc+GEsHPn5khxj4YsS1YkDY1EdrXyKFGPhkxrViAVjUa5OGAs33hgLN34YC0d+viTHWPiiRHXiCMFYPLpRRizYXvHFXtmypSYXnrdddt+9OlpUKVKMRZXU8iNWjEW5OmAs3HhjLNz4YSwc+fmSHGPhixLViQNjUR2tfIoUY+GTGtWIBWNRrk4YCzfeGAs3fqUbi8HBumzbVoui5o2io3hWcoxF+1h2S04hGosbv9Irjz1ek9M/sl32n9ktSpZbT4xFubxDKA1jUa6KGAs33hgLN36lG4tv39IrP72/Jn19InOOHZajjhx2rAHJlQDGgnZQlADGoigx7lcCGAvaQVECGIuixNzux1i48Us0Fua07UsWzZe3ztpPzl1ypSxdfLocMiv5FRbnWLiJUCT1wBUTZNu2RgoOsipCrvW9GIv2seyWnEI0Ft+5pVfW31+T988dksMPq3eLlKXWE2NRKu4gCsNYlCsjxsKNd6qxMGZi6hsmZxoLtxCqnbrMcyyef16ifeZ1tCJ6y95XF90iksudAMbCnWG35RCisVh3V4/o/3Q0VP/H1X4CGIv2Mw09R4xFuQpjLNx4JxoLHYFY1H+VHHPEoXLK8UdjLFowLtNYrLuzJuv+qVdmH1aXhzbUopGLJZ98VSZObKy54Bo7AYzF2Nl1a8oQjcWP7+2R79/eE02xPPEEjEUn2jbGohNUw84TY1GuvhgLN96payzMdKgnNj3TsoR9p0+V1Vf3y55TJrtFUtHUZRoLs7BSpyms/2kPiyzb2GYwFm2E2SVZhWgsdP2WruPSlxenzmU0tBNNGWPRCaph54mxyKevPrse3lCTU+cOy8Gzxv5iBGORj3faXZmLt9VgZK2xcAuh2qnLMha6G9SXV01o7jH/gzt65KENPcyFblPzwVi0CWQXZROisdBnyppv9bB+q4PtGGPRQbiBZo2xyCesefnqOpUTY5GPdyFjUXTxtlsI1U5dlrEw6ysmT26sqzBzoXWBpY5g+HJpnM+/IPLiCzWZ9ZbhykzTwlj40oKqE0eIxsI8Z1SFyy7dXh0xKhQpxqJCYnkSKsYinxAYi3ycOn0Xi7cdCZdlLMwUBR3em3/asDz1lI5g7CTGaDhWIzW5lrP33vnXcJg52pphlfbCx1h0qgWFm2+IxkLVMjvPsX6rM20XY9EZriHnirHIp64xFvE1Yub8r7xnfzFikY93oRELFm/nh9ppY/HUZpE772pMe4qfXXHpZROiQDv1ZlG/pDr6cOopw7LfzHxbT5qRFI2rSltWYizyt3nubBAI1Vis+GJvc8pl3h9i2kR+AhiL/Ky4s0EAY5GvJRhjEV8jZp5peV92Yizy8S5kLPRmFm/nA9tpY6HzndVU6KXTnk48fntzelGn3yyaL2MRg2AbC91VpioH+GEs8rV37tpBIFRjkXT6tu4UpTvRvfPYYc63cPwSYCwcAXZhcoxFPtFNnyXNWOTty2As8vEubCxMAhZvtwbcSWNhpj9pBNOmiZx79sg5z6YD8LGFrxaarpS3yRjjkvfLqPmaA7b0310XUOWNsx33YSzaQbG78gjdWNjPlXbNXe6uFpJcW4wFraAoAYxFPmLGWMQPDy76khRjkY/3mI2FW/bhp+6ksdCt09Rc6JU039mMDph1F+2mbaZaFTEItrFgxKLdipCfTwRCNRa6rmrN2gmy9171aD2XXsZY+LZZhE/tIW8sGIu8pLjPEMBY5GsLxkDEX8Sal6R5+yQYi3y8MRZunFJTd8pYPLaxJt+/o1c2b05fq/DoRpFv3jxBJk8ePZrRjuqOxVhcc92EKGa9kkZZisSlC642/KJHdu6ridqrgxz2pc4q14xYPPiLV+TpZ3pkt90k97qSrLxbfa678GTNY1cOG3/VK5N3HSo0MlV04X1anFp+Ow5hbFc8SXEqx83P9BRm5KJdyMZCN4awv79pP9gu/Lo1LcaiW5Ufe70xFvnYmeeUrkftv3jHDI+ifRmMRT7eGAs3TqUaCzUVN361t1lmq8XZ2pHXa/687Zkd1KIIzJex1Sm82un86b/3Rtvf6qWngdtX0YXlmt9TT9fklVd6ZONGEd1lypiUMxa0/5Rx7ey+8GKP3PlPvbLtFZHnnmuPKWrFWkehHnpYT06vyeAr+s/GFsJplzlbQB+W+80YlpkzpeXaFX246qVvnPV6z/HDhduGdtT7+hqG5ju3NDRQ/nl3CLO3Hd5r6nCD77aavOf47bnzyGqv2la2bGnc9YM7JkQHRrZ79E7rodeWFxpGXy8zJbFdxkLboLYD3aJ5cLAWGegssxlnY+LUv3/31kacxx47JPvPbE1RX07c9NUJo86tMN99M1Jq3vh1ehe6LM1D+BxjEYKK5dYBY5GPtzEWerfd98BY5OPXrrsyT94+47T3yI3f+oGkncDNyduD7dIiykc70j++txbtyqIdyaOOGJI5x6XvyJS00LJdAZkvY6tTeNfdWZN1/7TDBGnM2vnQ+NVkFN2y0l5XEq9H3h0d8tb/5w/Xok5Y3AyZ9EVNUVq52ulTRnoiqF7x8pTZxxamG8M4k/j8Uc1TdXjoF1qXBnv70ukseU8h1U6udtJ1N7CoQ23llbfTrh3+n9zbM6JdmHiKrNdJ4qksn36mJut/WosMqPmeGKZJbPK2B/s+Zf7Yxh5Z/9pURNXIlGGmA43VWBjzrIy2vNDTHOEz5Rdt57rBg2GheZhY8wz7pxmL+NQn8yzQ/PPkOxbm3ZIGY9EtSrevnhiLfCzNCxC9e84f7eg75enL2CUwYpGPd9pdmSdvu2UfRuob1twmK669OarMkbMPlpUD58ukiX3Rf7d7KpRx3K1GCWyqZteoIp3HvKqYL2NaZ810PjQ/veegg+py+NuGomkzZkpUkYXl9pqSpBiLdrha1dPevUrvO2A/kZ4ekdfvUm+ua7nwPPdRIO1E6nQ1fZsev3SqiV46dayVfvFY43qYEQ27U2nKUpN34gn1XMZC89HRiTSjlWdqm31CvInB7pQXWa+TpJ/9Rsp8rjy0Y61xa33PWDBU+I2/XZYxaWZKn2nfOqqgfzNv7cdqLOyd3owJ13/OnCFR28u7jkFN4He+t9MoY2Lqkod1mrGwzax+D75wdWNk1FxFXxjkfeZ0w30Yi25Qub11xFjk42m/ALF/JzEW+fi16y6MRQbJdfesl8tXrpHVV/fLnlMmS/+yVVGKgSULo3+201iYH/Mi0w3MYmnXN8FxDNpBXPb5naI/JxmLhzf0yDe+1Zgio28GtDNkT98w21Pm7dTaIx+a11FHDknfzo31B5qXjuS0o476xvsn9zW2zjRvuw+eVZdj/1DkzTN75bnf/q65ULUdb2btDpqO/Bx+2LBM22vHieR5FuDHjYXdwbfX4qgWakj3nlaX518b8VJ2eUYaNJ/v3NozYoRCTaGu39GpbppPVrvUNqMjQGpQ9N6TTqiLToNSDU3+fX21aErVWNZsKMvbbm+MMCkDnVZlT/UxRtfFZGsexqSYtt03sRYZZp12pWsPzAjTHnuITNt9ojz1XP5RS23Hqqcxb9pp10sZ2d+5rNEys8DajCip6d59Nx1VaUxN1HJUAx0Ja8U6zVho/jeu3imKU9uP2fJaY22MSnZm+mW7fth8zgdj4bM6fsaW11joM3JwW00Oekvx6ZR+1rxYVLax0JTmOZr1kjReCiMWxbjH7049eXvBeQOp05/sTEKfCqVG4oCZ+8iZ80+Kqh03Gu00FqYDXaRDazqded5OFmkq2gE3bymT3lTbIyvvOGL0Q6xIXHZZamLed8rIN85mkbquLzC71BSpi32vMWJmvYJ2kJS3vd2sMQOtpoDlKd/urCvDpA61fVJ5WmfStAtTpt3BN2+/tT6zDxsWW4u0TmNS7PZb9A+dNiR7Td1hFM0ohK6RsBfExfOx5+Hrmp/4eoyxjGKZMuw2on9LemNuphGqUVRNi1722ibtTGs7jHfK7YOWdJSriLGwXxzo+hfT9uw48x56aVjq9yW+bsU2s1kjhq3aSLzdaVm6buPee3ecraNGVs3y5N3as8C/qGZVvB9jkU81e7OHsXSY1Qy/sq0uM95Ul8d/1RgxnvWWHS91sqLQ58nEPn0ZlO9w2LT87Oenmdqsz5oXXhDZa6+67P3ayHWrePIYC31G6m5uOqqqvwd66W+CPmfMTAJThsZkrrG85Mlil/a5qbean3hM8TRm3Ziu9csTo3mW6e+j/lbpSxHz0tP0ZfJMlVU2B7xx0lirSDo9PLZer2d+a+KdayVnTudeMO94mXP07CBh2ieQG2Px4IaNctHSL8mKpR+XQ2bNlGdf/F3b6v6Vb4j8/KGanP3n9WhqTp7rn39ck+/dJvKHR9Xl5Ib3acv13HN1ufwLjREJfZv6qYtGNpNL/qLxoE6L9YfravIPPxJ51ztF3j2ndRN75NG6XHdjj0zfW+Ts04dl4qTR04ZMeR94f13+wKG5ffUbIg8+VJNDDq7LRz60A9XrduqRnXfqkd9u3S5PbqrL6m/2iD7YXLiu/XZN/mW9yMknivzB4cn1euQxkev+tlFf1e/3Zw3LHnuMrL/Jx0TbN1Hkr/obTA0XTaux2pfRUPVTrvF8zb2bnhK56pqaaL7RfZNllAbX/m3jQf3eE5Pbpt1e3jWnLu9+5+hmaNhrnL9/cGP6Wd5Lvxe3fl+iEYp3HZdcF9OONM9PfGxY9pk+uh2llTe4tS7X3dQjykLb4fnnJrdZ/a7pd07b4LvnDMubZ+yc+xnQSisTl+qgMcTbpx23ts8vfrkn+l4u+ODoempd1n63FrVzjVO/M2mXYbb/fiLn/PnI+zSff/5JTf5h3cjvuv79qr9pfD/sNnnIQSK7T67Lv/60FnXI/vR9jfx09Gz6tMa/6wzSn2/Q70VNHv2vtq+s3zVHpG/nhhHURfLa6fiDw4bl+Rdq8ujGmkhdZO9pw9FnOuL1/GsL9nef3Chd/1vLU10GtzW+b3vv1chP/3vz0zvagabXS/lqPfTzn2/oif45cWf9RWzkqfnppfy0bZvr7p/U5MGHa81ng/5dR7T++ceNuv3hUTvSTtur3myDmofWR0e9JvVNEOkZkmHL+yrLiRMbZtNsSGDKfG5LLYpNP1dueu0/sxHT9L0b/63/P7htR5zagfr5wz3yzz9pMHj74fqioBZ9t/UFzXNbJIpN25LGrf/Tv+nner8+K5TPv97f+A1QHlof1fKVV7TjWpP9Zww325l5zmt7Uv3e+vsi+mxrdPDq0f2bnqrLH/xXHNp2tLxDDtK/S7N9aR7696eeEvnZw43av3tO47n2uRUN5mefMSwH7N+os+avrJTPludV00bdtH1pDKqJeYZr29DLjKpHvzN9ErVvbWPahvTZou1RL/0O/uv6xr9rXMpbn1emLWibUSbPPa/PduUi8ujjDVZ67TOtwTNqV30S/UabS2Mw3x1thxq3lqftSNt90nN628s98sQmkd9tr8ujjzW01Po1tGmUY38fd5TW+DctZ//9atHvi95vng8ai35fVCNlFjGaLM0y9N9V502bRZ56ulFn+z69Xz+P4pjUeObovdsGGzHq/Q8+1PjN1d8Xvba9NsD7p6cOy6SJPdF3X8tRpnopA83j737QeB5rOk2j/9RnzMnv2fFbap5RqqPJVzXU55CWGb/s3079zGis35dNm2vydz9opPn80sZsDa6xEcg0Fq0OyNO396vX3jFizcHYwvAzVZJ5ihuLv7piu5x2ao8cdOCOh8pYa3PW+a9GSa+/Kn+jvue+Yfnbrw/JMUf0yBkf3rGIeqwxmHS/ebYun7psx3Ztdkzmsyl7iFz+l8mxbvhlXT5/9XaZ9eaafPK8kfOz47H9w13D8sM7h2T2oT3ywfcn10HrqHXVMj/4/gkyaaJEeRe9VK/fPFeXj5/Z21KzS/7qVXn2uUYZ7zquV/adLvKGKcXKM3p+cdkEmZRglkzst35/SG79QePh/Ocf7pWjjxjZlr757SFRRvalemgaTZumw9b/6jhdctl2GRwU+fhZE2T2ocnxm/zfdWw6f1PWKSf2yinvGd3W1z9Qly9d32gvl36yV970xtb3aCynndqbm+mNXx+Su+8bTuRjuDz8H8Ny4zeGZOugyJv2qckxRzZieMsBtcxyTJueOFFk0VkTWrYto6vW4egje6Mfzzfs0boMk/+++9TkLy9O/z4Yzq2+N0YvLV91TbqUxV+v1BEXiZ4Nad8rc19aedqGfvVkowNlt0v9+4ZHRL757e3R90QvLUsvbW/mv82/639rOzX3Fv3eFrlf40iLIZ6PfW9SGXbMWfemxRjnUqQuee+Nx9YqVvOZ/U+jWxq7pDrE77XzsNtB3jok3adt7tnn6qK/J6ZNRd+1//odePiX9abOJm2n2pjWVX9zOt1+TTkHvblH/u2BHc98bc95258y099KvfR5o7939vcwS494OcpUr7S6x9tTVv7xzzX/WW/eEXNWehOPPufj7Uxj0X7EQQfW5Id3DsvWwXrz98C0oXPP7I3az08fqMsP7xqO2NjMNM8ifbCseLvxcydjoZ3spctvkmuWXRCtPwjtyjNioZ2Mk95dkz85wc1Y6A/1Jy/VYVqRv/5MfoPwi18Oy1V/U5cDD6jJBR9zi8Hop7Gs+791ue2HO96Aff6ynmbn+Iknh+W6r9Rlyu6ty/xffzEUfWnttEltZNmKIfnPTSKfurAm++6TXIf/3FSXK7/ceAjo9cbpNTn/f9ZSO+xah2efr8u//0zkPx597cH4fD3aTlbnxn+mfyRjXbjdW6vJq0ONOj/7bD2qo5ZrLi3z7I/WZEqGwdC0T2yqy6qv1BPLijPQMpateO2tz8TGD4iW9acnN8rSev/HIyPfJn/pr3tl9TeH5Sf/Upcj316Tj3wwmdvf31GX2+4Yljn/X03+dG7yPdfdNCz3/6wuCz7YI+94e7L50M/1vrT2acppFYtyufLa4eaWvoe9tSb/47U6tnp2aNn/+9ZGusuW9GTyN+3O5Nmq7nqPtpV//7lEPJX7kotaf4/+YmCoWQdTRit2eo/WYfW3huVth6Rrpffpd+tzX2i0mwUfqEXxxE2pthVtM62+L8p62ZWN74tqptonaduO54fWTa8D95fouaFvT7XcN+5TizqFjX82Omb/+aR+LyX6bpqtnbWOW7fVZVJfrfl90/prHvEOkd77xumNOqnZ+cUjOk2isU206fzqc+nAAyR6ptjpTQdIy1azqR0T/Xe9TCz6HNU0+veok9dXiwyRvuXV/DROc6+mszvc+u9JnSyN5x3/vRa1Ac1bF/2/7RBtEztavYlD79V/N7ppfvo3/W8te9/pNdlj90Ys5tmkTKJnlvV8M2ns55eJTz/TPMw3Xf+u+enflKnmc+D+Nfn3B0d3SFUXZWL0ajyrGvXQ6So6jeT+Bxta6j32pX/T++PPMvt7qs8zw9VoGm8DSW3D/puWofrqM9hwNJrZDLSeNifVXtuotim99DO7Dhr/PtPVINfkJ//SeB5puYcd0iCpsdu/T4a9iU2/g5GOW+vyk38d2f6j8vZoPCfMFW9baqjM/BK7HWr/48mnRPbZu/Gd03y0DB1Z0O+kXvpbrtpq/qZNaV2efK1Nv2X/Rpswl/5mGp00fvs7ov9u/qbtUcvV+7VuWmcTt/n+vO2tNZnUJ1G7MPdoHicd3xONmMXrbL5DtpkyuqW1Cf0tMeXoP+1LWegz9O9vH272aTT++PfY/s5dkfLCdETG/EcqgUxjkdS5NrnF1xuEyDlrjYUaizyLY7PYmMWSOieyyPzwIvPoW8VgzgR4+BeNQ/nsxZqazp6rbeZeZ63rMPPRzXx1Pexu/U97ZObMumhac+WdV65DvQ//oidaSKyXvZ2cycscJrf5qXridqc69K7z28/46MhzI+w1FiYv1eTH902I3kivv7+x4Fbn2554/OgFsVFsG3rkx/eZLWUbU4fy7u6l83kffrg2Yvcos/g2aVcpXfT7gzsac91bLVZ+arPIl1876yRtVy2zNuJjZ29vOd+31emlqokyUl21zmmX6qOLgnUKg+Gpi/LtS+dTazvRS+fX2m0xa1GzpjHp7UXYaYz0+/P05h75/h2N8vLMwTULsPV+swg7aWG72ShAp4M89nhj696sDQjia0ni9xdZ4K0cntpca25UkLR2y+wolncnqqznWJHPdR2Wfh/NXGvz/Y7Pazfz6/XvWXPS7cMc0w52NPPL7XnbRebw67166cYEuo4oKb9WHMwaixdfyjff354Pb/JNmnOu33V9Bumc/RlvanynvnNrbzQVLGsTjVaHYOpnm5/ukW2v1GTaa5sx2M9bO5Y0/vbfr7musQHD7Le99pyo1aKpK/G1DOb5q7y1nVx4XmNEX7/XulGBHoipayhsHdJi0XRpOpn1gLqmTtcrJbGN8zFrBeyDVM3ZP3Z6cwBqPL3+t/4e6mXqbf9N27muW9JL89upNkFet7PIy9sao8LmXj08Nu9W4kkxx9upHXsyfcsAACAASURBVKc+5/Q5bdbtadvSNma3rzRWJu54/vbzzTzLtczHHu+R3z+oUV/z37vvNhy5cNOm9Xwf/Uz117N3ou34jxxu/jPr2WNvSKFav+OI7bLlxd5GG9Izn+r15rpAFm9n0Wz9eaax0ORqIPoHVsn1yy+O1hXopVOkdIH3vJOPay5sdgvFz9RZu0KpscjTGcmqnVnEm7cjavIzX9SsHXvSyjc/5ubsjPh9ZqtQ7ZjNfNNQc4cgvS9rkbkxIGahtOkg2ovBxxK/ydfeWtT8CG18rQMXr4c+fLXcg96SfHp1krGw89D8dUcg80OgXQt96OoWpHrZW5OadNrJfscRoxcAp2lhfvjM7kN6n8acdDaFGguzUC9rga69QFyZ6VzpE61D8/IaO3s7YH3If+i0HQbC7MiUFYv54dAD8zQu8+OgukSfvVKLtudNOutj/geGCp+Gbupu2ooaFd01afPmRmffLPLTsvUeLSPPYkq9X988b/7PPvnSDY0f+2gh89uGopPbjTGKbzOcZ8cqe/tgfbZMm1aX4/6o0Y6Kfl+0TZkzRYxRNe1Pf6D1zBJtu0kmPeuZxedjI8Di7bFx6+ZUeRZvV4FP9Dy6rzFbwH65WFbsrQy0HQPGwk2RXMZCizBGwj4oT89zCHXhto211TkWaizy7O+fJZPZrSirsx7Pp2hHw06fdG6EdsD1LYhuWapGQk9e1o68fVaAySOrk6SxfXnVyE6i2a1i5ozh6A2FvlHVzl8Rhvb2qxqXLnjU7WNNZ1TrMGOGnt3Q2A0kz/Z7WcZC62x3+OI6aJlHHjksG15bgGY6glm6p31utuu1D6jTEYe77uqNRjX0300HPOtMAX2Yakde3wqZkQJjhu1TvVvt+KRxmtExE3PSAUR5RhSMubBHYpSfxhc3FPEdqoryNHXX0RS94vlruQe/1g61zRfZAcacY7Hiy680R1XsMztMrNq2dSSy1UiOXS8TszFeJmYzsqPf2yKjpPbuZBqffi/s74uWnfVdLsqd+9MJYCxoHUUJhGIsitZ7vO7HWLiRz20s3IoJN7Uai7GOFhgq2pEw+/+f8ZHib2Wz3jhrx2Lj42oWRPRNs54ArX/Tjote2tk46QTdYrQxtG9f9pt683ftfOm0hDydZ+2M6vaU2mnUKUi6XaUOY9qXlp81hWZETJtFnn66Jg89vOP0Zf1cO26zZg1Hw+T2mRp5Wl8eY6E6xaclaWevyHB0nljMPWqgtONvH8pmtoXVEQedvqPssgxBvNP6hasb5xOoMXj+hZ5o6lCejqoZUdFpEebMC81DWWtnt+j3wJ7WY2I0Bq0mtWgqQFEd0/gqN62rGVnSoXAdeI9Pwyqij31Anp7DolNOzKicGjcdHdHviBrfPNslxnUyIxTGnNvmfiwjm/qMsaeHaX5q8GfOlBFnqxRhwL3FCWAsijPr9hQYi3JbAMbCjXdbjIWuw/jslavlwrPnBbmIuxViNRamc6dvmXWKxXHHDueesmF3rtLOOsiS2Mx9Tzop2j54TuPUzo6Z/mHerrZaK6Hxff+OCZEZ0StpfUJWfPHPTbzm7y5TyXRUROfa6txfvcbaEc1jLDR/e75z0c5iUU56v9bPbNeodTOjNcpMRy6KjPSY8qO1ID/ZsZ7DGMsib+vjh/Zp3mPRUTv8uhWlGkJtm2MxhUW4qn46ahM30EXyMPcmnbythl0v+xDEseRtp4kfqqefjXWEwRh9zeM91nQ41xhJn58AxiI/K+5sEMBYlNsSMBZuvDEWbvzEbD2pU0DMPPOsBZqmSH27+Z1bGtM/ir55tsM25cYX55rF02b6kT0NRN8MH364yM47D0dmoVUnWTtjakbG2mlPQmxMmH4WPxDPUZIxJc9rLMaUeRsTmelIxhTmGWlIKt4cpqSdbHNoU5EwzejN8y80Uqk5OPXkV9vSYS8Sx3jem2QsOhWPWYit0/p0oWuRtTudiol8x0YAYzE2bt2cCmNRrvoYCzfeGAs3fiOMhenI5zUWZjTB7Hgx1jfgcWNh736g1dM5+LpgtbGzUWPnhaOOrOee8+2IqBLJq2Is4rsGFZ0SY4uRdyFbJQQchyDLNBbjUD2K7BABjEWHwAacLcaiXHExFm68MRZu/JrGQjvvyz7f2DUoj7Gw1y64dA61PGMszMJve/qTzsU/6h3p2386Vj+Y5FUxFmoGdLtWNYg60qRTYrjGhwDGYny4V71UjEXVFSw/foxFucwxFm68MRZu/JrGQrfZNNuRZp3vYJsKnZdeZE1GUrhmRyldkHr4YcOy5ubGPuF6Ja27cKxykMmrYiyChF/RSmEsKircOIeNsRhnASpYPMaiXNEwFm68MRZu/JrGQkcdzC5LWcZC50ubLSN1fcFYp0CZ0O1D8nab3DggzOx/X+SwPUcUlU6Osai0fOMSPMZiXLBXvlCMReUlLL0CGItykWMs3HhjLNz4yf/6y99FJ+raV9YuS2bKVNEzK9JCTdoSdqy7xjjiqGxyjEVlpRu3wDEW44a+0gVjLCot37gEj7EoFzvGwo03xsKNX2FjYUYrip7ymxWmjoDoqdO6O48aG90tiCs/AYxFflbc2SCAsaAljIUAxmIs1Lo7DcaiXP0xFm68MRZu/JrGwj5xt9WIhTntul2jFSZ8c76C67QqRxyVTY6xqKx04xY4xmLc0Fe6YIxFpeUbl+AxFuVix1i48c5tLG5Yc5usuPbmZmm77jJJrl9+sRwya6ZbBBVPbU+F0lEInRaVZiy086+nHus1/wPFT9iuOCqvw8dYeC2Pl8FhLLyUxfugMBbeS+RdgBiLciXBWLjxzmUs1FSs/d6dsvrq/ubJ2g9u2ChnLb5CBvoXypyjZ7tFUeHUtrHQU5A3b5ZUY6EH4ulJw7p706lzhypc6/BCx1iEp2mna4Sx6DThMPPHWISpaydrhbHoJN3ReWMs3HhnGotfP7tFFpw3IJcsmj/KQKy7Z72sXnuHrBw4XyZN7HOLpKKpbWOhhmH9/ekjFtdcN6Gl8agogiDCxlgEIWOplcBYlIo7mMIwFsFIWVpFMBaloY4Kwli48c5lLM5dcqUsXXz6qGlPOmqxdPlNcs2yC5ojGW7hVC+1bSzm/NGQrPun3uhE6/g2r49trMl3bu2JFlefe/b26lU08IgxFoEL3IHqYSw6ALULssRYdIHIba4ixqLNQDOyw1i48c40FlsHt8mi/qtkwbzjR41YYCxE/s9tr8j3b1fDIHLSCUPR+RRJU53MadjtXrTtJj+pDQGMBW2hKAGMRVFi3K8EMBa0g6IEMBZFibndj7Fw45dpLDT7tClPuvbikY1PysCShW5RVDj1P97zSrRuQhduv/PY4chYqMmYOWNYPnRaY8tXs2hbT8PmfAk/xcZY+KmLz1FhLHxWx9/YMBb+auNrZBiLcpXBWLjxzjQWZo3FE5ueySxp3+lTRyzwzkwQwA0P/nJQnn9BpCY1eeEFiYyFXmo0LvpEY4H288+LfHnVBOnrq8vHFm53Pmk7AGzeVQFj4Z0k3geEsfBeIi8DxFh4KYvXQWEsypUHY+HGO9NYuGUffupNzw42K2kOv4sbi0c3itz01Qmy34y6nPFRdoPysVVgLHxUxe+YMBZ+6+NrdBgLX5XxNy6MRbnaYCzceGMs3PhJmrHQ6VD9FzcWaZttZvU0bJ0KxeUfAYyFf5r4HhHGwneF/IwPY+GnLj5HhbEoVx2MhRtvjIUbvxHGwhgIk+VllzaMhVm4rbtGzTmu7lgiyTtBAGPRCaph54mxCFvfTtUOY9EpsuHmi7EoV1uMhRvvXMbCHIb34ktbR5XWjesqbAj2iIWZ8hQ3Frpr1I/v7WHhtltb7WhqjEVH8QaZOcYiSFk7XimMRccRB1cAxqJcSTEWbrwzjYXZbvaYIw6VM+ef5FZagKnzGIuBKyZENTdTowLEUPkqYSwqL2HpFcBYlI48iAIxFkHIWGolMBal4uaAPEfcmcZCd4VKOyDPsewgkrcyFks++aps21aTL1w9YcQuUUFUPLBKYCwCE7SE6mAsSoAcYBEYiwBF7XCVMBYdBhzLnhELN96ZxqLVAXluRYeRupWxuPC87bJtW12+vGonmTZNOHHbY8kxFh6L42loGAtPhfE8LIyF5wJ5GB7GolxRMBZuvDONhWavB+Hdfd8DsnLgfJk0sc+txMBSZxkLPeOCrWb9Fx1j4b9GvkWIsfBNkWrEg7Gohk4+RYmxKFcNjIUb71zGgsXb6ZBtY6EH4em0J3PpiMXjv6pFh+bNPqwup87lDAu35tq51BiLzrENNWeMRajKdrZeGIvO8g0xd4xFuapiLNx4ZxoLFm+3BpxlLB7+RY/orlBHHTksJ57AGRZuzbVzqTEWnWMbas4Yi1CV7Wy9MBad5Rti7hiLclXFWLjxzjQWLN4eu7E4/SPb5f77e2X9/bXIVKi54PKTAMbCT118jgpj4bM6/saGsfBXG18jw1iUqwzGwo13prFg8XZ+YzE4WJdln9+pmUCNxV139cpjj9fkYwtflb33rrmpReqOEcBYdAxtsBljLIKVtqMVw1h0FG+QmWMsypUVY+HGO9NYaPYs3k6HbE+F0rsuvWzHGgs1Ft+8eYJs2yai6y12391NLFJ3jgDGonNsQ80ZYxGqsp2tF8ais3xDzB1jUa6qGAs33pnGQqdCLThvQJ7Y9ExiSZy8PTiCi56+/YM7JsjmzSK2sbjs0u1uSpG6owQwFh3FG2TmGIsgZe14pTAWHUccXAEYi3IlxVi48c40Fm7Zh586PmKhNb7xK43pTx/8wJB88+Ze6evj1G3fWwLGwneF/IsPY+GfJlWICGNRBZX8ihFjUa4eGAs33hgLN36SZCy+c0tjwfacPxqSdf/Uy6nbjozLSI6xKINyWGVgLMLSs6zaYCzKIh1OORiLcrXEWLjxzmUszALue9c/JLvuMkmuX36x7PemabKo/yo55ohD5cz5J7lFUeHUrYzFQbOG5eENPRiLCuiLsaiASJ6FiLHwTJCKhIOxqIhQHoWJsShXDIyFG+9cxqJ/2So5YOY+Mv9975RPDVwn5/zZKXLIrJmy7p71snrtHV19IncrYzFtWl02b67JfjPqcsZHORzPral2NjXGorN8Q8wdYxGiqp2vE8ai84xDKwFjUa6iGAs33pnGwj7HQkcpbGOhJ3IvXX6TXLPsAtlzymS3SCqaupWxmDy5Llu21GTOscPR/7j8JYCx8FcbXyPDWPiqjN9xYSz81sfH6DAW5aqCsXDj7WQsGLGQxDUW6+7qEf2fuTAWbo20jNQYizIoh1UGxiIsPcuqDcaiLNLhlIOxKFdLjIUb70xjodmbcywu//Q58pkrvxpNhZr6hsnRNrTzTj6ONRYxDWxjoTtCnTp3WA6exYiFW1PtbGqMRWf5hpg7xiJEVTtfJ4xF5xmHVgLGolxFMRZuvHMZCy1CRyd0sbZ9rRw4X+YcPdstgoqnTpoKFR+xOOMjQ7LfzHrFaxp2+BiLsPXtRO0wFp2gGn6eGIvwNW53DTEW7SbaOj+MhRvv3MbCrZhwU+cxFks++apMnFgLF0IANcNYBCBiyVXAWJQMPJDiMBaBCFliNTAWJcIWEYyFG+9MY2Ev3tadoOyLNRb51lhw6rZbIy0jNcaiDMphlYGxCEvPsmqDsSiLdDjlYCzK1RJj4cbbyViwK1Sysfjp/TX59i29TWUwFm6NtIzUGIsyKIdVBsYiLD3Lqg3GoizS4ZSDsShXS4yFG28nY2EWdetai0kT+9wiqWjqpKlQaixuu71Xtm0TDseriK4Yi4oI5VGYGAuPxKhQKBiLConlSagYi3KFwFi48U41FjoacdbiK+TFl7amlmBO4Y5PkXILqVqpk4zFQxt6ZM23GtvN6lkWF32Cw/F8VxVj4btC/sWHsfBPkypEhLGogkp+xYixKFcPjIUbb6cRC7eiw0idZCwe3Shy01cnYCwqJDHGokJieRIqxsITISoWBsaiYoJ5EC7GolwRMBZuvDONhVv24adOMhZPPVWXL6/aCWNRIfkxFhUSy5NQMRaeCFGxMDAWFRPMg3AxFuWKgLFw442xcOOXePL288+LfOHqxojFh04bkoNmcYaFI+aOJ8dYdBxxcAVgLIKTtJQKYSxKwRxUIRiLcuXEWLjxxli48Us0FprlpZc1jAVnWDgCLik5xqIk0AEVg7EISMwSq4KxKBF2IEVhLMoVEmPhxhtj4cYv1VhotoODdQ7Gc+RbVnKMRVmkwykHYxGOlmXWBGNRJu0wysJYlKsjxsKNN8bCjV9LY+GYNclLJICxKBF2IEVhLAIRsuRqYCxKBh5AcRiLckXEWLjxDtJY6GnhC84bkCc2PRPR0XM25hw9O5VUq/uTtt3dd/pUWX11v+w5ZTLGwq39eZMaY+GNFJUJBGNRGam8ChRj4ZUclQgGY1GuTBgLN97BGYutg9tkUf9VcswRh8qZ808SNQYXLf2SrFj6cUk6byPr/qz0SbtCuUlC6vEggLEYD+rVLhNjUW39xit6jMV4ka9uuRiLcrXDWLjxDs5YqBFYuvwmuWbZBdGIQtw4xHFl3Y+xcGtgVUmNsaiKUv7EibHwR4sqRYKxqJJafsSKsShXB4yFG+/gjMW6e9bL5SvXNKcqKZ7+ZasiSgNLFo6ilXV/fCqUPQ1KM2PEwq0B+pIaY+GLEtWJA2NRHa18ihRj4ZMa1YgFY1GuThgLN95BGovVa++I1lVMmtgX0ckyFkXu17w2P/NcM/9tvxtyU4DUXhDo6alJb09NXt0+7EU8BFENAjvv1CuvvMozoBpq+RHl63bqke3bh2WY4438EKQCUUzorUm9LjJEoylFLX3RyDV2ApUyFtqpv+X2uxNre9E5H4jWVGSNQMQTF70/PnXq2RdfGTt9UnpD4HUTemTnnXrkt4PbvYmJQPwmoCMWu++yszz3W54BfivlV3S7vf518tLgq3QS/ZLF62he3zchai+8yCxHpim77lxOQYGWUiljkUeDrDUT8Txc72cqVB5V/L+HqVD+a+RbhEyF8k2RasTDVKhq6ORTlEyFKlcNpkK58Q7OWOTZ5emsxVfIQP/CaAvarPu/dcuP5K0H7d/cUarVtCo3KUgNAQhAAAIQgAAEIACB6hIIzlioFHnOpTDGIut+nSql29ea68jZB49Yv1Fd6YkcAhCAAAQgAAEIQAAC7SMQpLFoHx5yggAEIAABCEAAAhCAAATyEMBY5KHEPRCAAAQgAAEIQAACEIBASwIYCxpIUATii/FN5eLnkZhdxFpV3qy/uXf9Q9Ft8TT2NLn4+SZBQQ24Mq00zNI/DcsNa26TFdfeHH0cnzrZappmwJiDqlqWhmNpN51oh0FBD6Qy+mx4ZOOTI87UyjorK63qWe2w1XMoEJxUw1MCGAtPhSGsYgTsh2y8k28+u2TR/GjBfvy/00qyF+rH08RPZNeH+N33PcD6m2KyjevdWRq20j8t8Pj21XYeWRtFjCsMCs9FIEvD+Od5Mu1EO8xTLveUR8A2jnNPOGaEsdDPHn38qWi7fL3iZ2UlRZnVDls9h8qrNSV1KwGMRbcqH2i9k0Ys4j/cST/+agzWfu/O5ontaiTOXXKlLF18euKOYPE3T/EyAsUbVLVaaTj1DZNb6q8gzJtGeyMI7RQcMHOfZifB/oF/5jdbZOnym+SaZRfInlMmj9qRLii4gVYma3vypDfSNgrzgmLeycc124hrOwwUdZDVymofWum0s7Xsg3mz2mGr55A+e7gg0EkCGItO0iXv0gmkTYXSB+26u9fL9csvjmKyO3j633FjkWQU7FGJz165OspnYMnC6J95R0FKB0KBqQTiW0fbGk6dsrtctPRLsmLpx5vGMj4qFTcWSYbVbkfPPPu8XL5yTdO8amBsX12tBpp1oGr8ENddd5kUPXMOmTVzxHPCNhau7bBaBLs72jzGImn0Oz6K0aodfvqCBdFOlscccWjTvPLiq7vbXdm1x1iUTZzyOkogzVjog/hzV39DXvzty/LiS1tHrZeIB5WUT9xY2G+mMRYdlbUjmcff6sWNRZL5bDXdzRiLBfOOj6bc6RU3FqvX3jFiuhzGoiPSdixTfY6kaWg6dLb+8RcWSYG1ux12rPJk7Ewgy1jkNQBF22HefJ0rSAYQEBGMBc0gKAJpU6HsTmLSdIQkY9HqjTUjFtVvNu1+U8yIRfXbRFYN8rwpto1FnhcO7W6HWXXg8/Ej0MpYJE2tTIs0TztkxGL8dO72kjEW3d4CAqt/krFo9XbHTGWKY2CNRWANI6E6nZjbzhqLsNtN0bntSc+ROKFOtMOwVahu7dKMRRFTYUZCW63XYo1FddtICJFjLEJQkTo0CaSNWJy1+Aoxi2zTFlDai7c1Q3aFCrthue7Gk9QZYFeosNtMnt14+gdWNddVxOfLJz17XNth2MTDql3adrPx0fF4reNrLPK0Q3s9F1Muw2pHvtcGY+G7QsSXi0B8T29NZG/rZ2/3p5/Fz6RImgudtR8951jkksbrm1zOD0h7y8g5Fl5L7hxckfMD0ra+thdva0Au7dC5QmTQcQLx3x8tcOXA+dFaLPt5YQdiPjcvuexdofRvRdph/DydjleYArqaAMaiq+Wn8hCAAAQgAAEIQAACEGgPAYxFeziSCwQgAAEIQAACEIAABLqaAMaiq+Wn8hCAAAQgAAEIQAACEGgPAYxFeziSCwQgAAEIQAACEIAABLqaAMaiq+Wn8hCAAAQgAAEIQAACEGgPAYxFeziSCwQgAAEIQAACEIAABLqaAMaiq+Wn8hCAAAQgAAEIQAACEGgPAYxFeziSSw4CZt/t6XtNifbwnjSxL0plzgM4+MAZI/6eI8vUW+L7hsf38c46oyKr7Kz8W+0xbur74ktbo2Lie90n7Wtun8mRFVtInxudNj39rKy+ul/2nDI5qp7hq/9u/92l7lm6mLyTDmHMU25W/q3aZPwzLc/e5z6ed1K7yhMj90AAAhCAAARcCGAsXOiRthAB7Qyeu+RKefG3L8unzvtQdDiQXnoq6C8e/U/ZdZdJbTMW2jnff8beURmmUzZt6h4ysGRhs0z9F/1v00m9ZNH8ZkxZFWuVf55TUR99/Ck5c/5JzVjsw4/ip/VmxRLy54almrAT33lkk5ky+v6P7pWXXh5sm7FQs9hKF9ssxs1gHg2y8m910ruW/YXr1sqnL1gQGXLNyz7hOX56c554uAcCEIAABCDQbgIYi3YTJb9UAsZY/Omf/JHc/S8/k8/1ny2P/WqzXPu1W+WAGfvI/Q/+smkstJN1y+13R3mp4bh++cVyyKyZTROgncxvfvcfo8/NZ63Q2531l7duiwzO0sWnR3kac2OMxlgktPPXOi1dfpNcs+yC6A173GjE89dO4uUr1zQ7yBiLHYQMuxOO++9y+53/Ty7/9DnRh5d89lrRv934rR+M4Lbi2pubieMn1760dVBeemlQ7l3/0KiT15M0j+ti7hnriEUr3fWzIm0yboYxFmP51pIGAhCAAATaTQBj0W6i5JdpLLRD//Vv/1DefezbozfEOrKg/7z7vgciY6Ed/zXf/Uf5xJn/o9npN2/09bMF5w1IfDpVFnb7bXBSJ8y1M2/nn9QhtT+PxxovOz4VqlunQSknYywWzDs+aiN6mfai/zSG7PWT+mTV1/9eFn74T6I3+spw7ffubJoO5b/u7vW5TKjRJ61NtMtYxM3oRUu/JCuWfrxpdlu1yXgbzppmlfX94HMIQAACEIBAOwhgLNpBkTxyETAjFmos9PrLv75Rpk+bEo1crPnuj5rGwqy9MJnaHXX9mxqLItOW4h39pI6hi7GI56//vXrtHSOmdaUZi6w3zebN9LyTj2tOA8oFO5CbbGPx1ln7RW/1f+/1E6ORi59teGzESI9d5TjXVsYuCVUrXdphLJKMgT3KpTGltcmsETBNq/W1p9cF0hyoBgQgAAEIeE4AY+G5QCGFZxuL/d40TRb1XyX6JlrXQcQ7UfHF0WZOe1FjEZ+LrunbOWKRlH/eEQvzlnmgf2HLtR3K5pGNTzbXh4TUJrLqYhsLbSfaYT5g5j6RyUoyjGctvkLMonh7Cl0RY5Gli6uxSMo/b5tMWi+UZoziRiWLNZ9DAAIQgAAEXAlgLFwJkj43AdtYmLUNJrFtLHQOvL0wdawjFkmdfi0vKY4iHU8Tc1r+8Y5n0hvmrM6rDRVjscOA2lzsdvHMb7aImgpj0sY6YpFHFxdjkZZ/njaZ11QY84yxyP1o4kYIQAACEGgTAYxFm0CSTTaBIsYivpjZzJfXUvJMhUpbeGuibLUDj96TZTRa5Z+1K1SraTaa1l4rMJYdq7KVqM4d8RGLVsbCXqMQN31ZeprOeHydQxKpNGOR1eaypr21apNZ05++dcuP5K0H7d+2zQiq00KIFAIQgAAEfCKAsfBJjcBjyWssFINOk9KRC730fAuzrWheY2HvKmWw2lNjWp0ZkKczn5V/q3Msks6p0BjNLkbxvC865wNdub5CmeQ1Frr7ls3tjXvvGcluFkPnMRZZusQ11fzthfVZZWTl36pNJp1TYZefda5K4I8WqgcBCEAAAp4QwFh4IgRh+ENAO3G6Ba4uKo8vJPcnSiLxiYCagk8NXCfn/NkpzVEDn+IjFghAAAIQgEAZBDAWZVCmjEoR0DfLepkD7CoVPMGOCwHM6Lhgp1AIQAACEPCMAMbCM0EIBwIQgAAEIAABCEAAAlUkgLGoomrEDAEIQAACEIAABCAAAc8IYCw8E4RwIAABCEAAAhCAAAQgUEUCGIsqqkbMEIAABCAAAQhAAAIQ8IwAxsIzQQgHAhCAAAQgAAEIQAACVSSAsaiiasQMAQhAAAIQgAAEIAABzwhgLDwThHAgAAEIQAACEIAABCBQRQIYiyqqRswQgAAEIAABCEAAAhDwjADGwjNBCAcCEIAABCAAAQhAAAJVJICxqKJqxAwBCEAAAhCAAAQgjfpRAQAABXJJREFUAAHPCGAsPBOEcCAAAQhAAAIQgAAEIFBFAhiLKqpGzBCAAAQgAAEIQAACEPCMAMbCM0EIBwIQgAAEIAABCEAAAlUkgLGoomrEDAEIQAACEIAABCAAAc8IYCw8E4RwIAABCEAAAhCAAAQgUEUCGIsqqkbMEIBAVxHYOrhNFvVfJfeuf2hEvfedPlVWX90ve06ZnJuHyeuYIw6VM+eflJnuwQ0b5azFV8iLL21Nvfeicz4g+8/YW/oHVsn1yy+WQ2bNzMyXGyAAAQhAIDwCGIvwNKVGEIBAYASMGZg2dQ8ZWLKwWbsb1twmK669WbRjn8ckaMKixiKOUsu8+74HZOXA+TJpYl9gpKkOBCAAAQi4EMBYuNAjLQQgAIESCKQZCy163T3ro9EM7ejPOXq2/PrZLbLgvAF5YtMzzcjmnnBM05D0L1slt9x+d/OzXXeZ1BxliKc9cvbBowxEmrHQOC5fuaY5gmLuO+yQN8t1X/teVJ4ZYfnCdWubMaSVoYbJXKZuJaCmCAhAAAIQcCCAsXCAR1IIQAACZRBoZSzin6k50I77py9YEI0oGLMw7+TjolGNtBELc98li+ZHBkUvNSGbn3luhLkoYizs0RR7OpcZYUmKJZ6/mYo10L+wGVcZzCkDAhCAAASKE8BYFGdGCghAAAKlEmhlLNIMgB2gdtYf2fhkNGqRZizse0xa7dRftPRLsmLpx5vrJooYi/iUqaS09t9e3rpNzl1ypSxdfPqIdRpqcPSyp4GVKgCFQQACEIBALgIYi1yYuAkCEIDA+BEoaiySFlybKUdaC506FV+8HZ8iZWprT5XSv3XSWDz2q82pC8Xt6VzjpwQlQwACEIBAKwIYC9oHBCAAAc8JFJkKZRZ02+sSbDPQyljkGRXotLGIj5B4Lg3hQQACEICARQBjQXOAAAQg4DmBrMXb9javOvJwwMx9RuwSFTcDee5JQ9JJY6FToXThub3Ow3NpCA8CEIAABDAWtAEIQAAC1SFQZLvZ+IJrMy3q4ANnNBdhJy3KNvfNOWZ2cy2DlvvZK1fLhWfPa56V0UljoYvNNbZ1d68fcR6G7jj16ONP5d5StzrKEikEIACBsAgwYhGWntQGAhAIkECRA/Li9+raCt3y9f4Hf9k0Fva2sq22m1WU8bUNnTYWWqaZzmWkjK/zCFBiqgQBCEAgCAIYiyBkpBIQgAAEIAABCEAAAhAYXwIYi/HlT+kQgAAEIAABCEAAAhAIggDGIggZqQQEIAABCEAAAhCAAATGlwDGYnz5UzoEIAABCEAAAhCAAASCIICxCEJGKgEBCEAAAhCAAAQgAIHxJYCxGF/+lA4BCEAAAhCAAAQgAIEgCGAsgpCRSkAAAhCAAAQgAAEIQGB8CWAsxpc/pUMAAhCAAAQgAAEIQCAIAhiLIGSkEhCAAAQgAAEIQAACEBhfAhiL8eVP6RCAAAQgAAEIQAACEAiCAMYiCBmpBAQgAAEIQAACEIAABMaXAMZifPlTOgQgAAEIQAACEIAABIIggLEIQkYqAQEIQAACEIAABCAAgfElgLEYX/6UDgEIQAACEIAABCAAgSAIYCyCkJFKQAACEIAABCAAAQhAYHwJYCzGlz+lQwACEIAABCAAAQhAIAgCGIsgZKQSEIAABCAAAQhAAAIQGF8CGIvx5U/pEIAABCAAAQhAAAIQCIIAxiIIGakEBCAAAQhAAAIQgAAExpcAxmJ8+VM6BCAAAQhAAAIQgAAEgiCAsQhCRioBAQhAAAIQgAAEIACB8SWAsRhf/pQOAQhAAAIQgAAEIACBIAhgLIKQkUpAAAIQgAAEIAABCEBgfAlgLMaXP6VDAAIQgAAEIAABCEAgCAL/P9AMThC4bH0fAAAAAElFTkSuQmCC", + "text/html": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "px.line(sht_df, x='DateTime', y='temp_diff_per_second', title=f'Data for SHT30 temperature change over time')" + ] + }, + { + "cell_type": "markdown", + "id": "6110d72a-4877-488e-9576-27731ef6d90d", + "metadata": {}, + "source": [ + "THE END - Why not try extending this notebook to plot both DS18b20 sensors on the same chart..." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "anaconda-panel-2023.05-py310", + "language": "python", + "name": "conda-env-anaconda-panel-2023.05-py310-py" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Plotting_Offline_Data/config.json b/Plotting_Offline_Data/config.json new file mode 100644 index 000000000..a0ef929bd --- /dev/null +++ b/Plotting_Offline_Data/config.json @@ -0,0 +1,61 @@ +{ + "exportedFromDevice": { + "referenceVoltage": 3.3, + "totalGPIOPins": 32, + "totalAnalogPins": 6, + "sd_cs_pin": 17, + "rtc": "PCF8523", + "statusLEDBrightness": 0.1 + }, + "components": [ + { + "name": "mcp9808", + "componentAPI": "i2c", + "i2cDeviceName": "mcp9808", + "period": 30, + "i2cDeviceAddress": "0x18", + "i2cDeviceSensorTypes": [ + {"type": "ambient-temp-fahrenheit"}, + {"type": "ambient-temp"} + ] + }, + { + "componentAPI": "ds18x20", + "name": "DS18B20: Temperature Sensor", + "sensorTypeCount": 2, + "sensorType1": "object-temp-fahrenheit", + "sensorType2": "object-temp", + "pinName": "D13", + "sensorResolution": 12, + "period": 30 + }, + { + "componentAPI": "ds18x20", + "name": "DS18B20: Temperature Sensor", + "sensorTypeCount": 2, + "sensorType1": "object-temp-fahrenheit", + "sensorType2": "object-temp", + "pinName": "D14", + "sensorResolution": 12, + "period": 30 + }, + { + "name": "Weatherproof SHT30", + "componentAPI": "i2c", + "i2cDeviceName": "sht30_mesh", + "period": 30, + "i2cDeviceAddress": "0x44", + "i2cDeviceSensorTypes": [ + { + "type": "ambient-temp" + }, + { + "type": "ambient-temp-fahrenheit" + }, + { + "type": "relative-humidity" + } + ] + } + ] +} \ No newline at end of file diff --git a/Programmable_12v_Outdoor_Cafe_Lights/Programmable_12v_Outdoor_Cafe_Lights.ino b/Programmable_12v_Outdoor_Cafe_Lights/Programmable_12v_Outdoor_Cafe_Lights.ino index 24a46d888..a8f3771f3 100644 --- a/Programmable_12v_Outdoor_Cafe_Lights/Programmable_12v_Outdoor_Cafe_Lights.ino +++ b/Programmable_12v_Outdoor_Cafe_Lights/Programmable_12v_Outdoor_Cafe_Lights.ino @@ -15,6 +15,10 @@ // #include "FastLED.h" +#if defined(FASTLED_VERSION) && FASTLED_VERSION > 3010001 + #error "FastLED 3.10.2 has known compile issues with SAMD boards. Please downgrade to FastLED 3.10.1" +#endif + #define DATA_PIN SCL #define LED_TYPE WS2812 #define COLOR_ORDER RBG // If colors are coming out wrong, re-order (RGB, BRG, etc) diff --git a/Purple_Air_Display/code.py b/Purple_Air_Display/code.py index ef68d009a..be1584ee6 100644 --- a/Purple_Air_Display/code.py +++ b/Purple_Air_Display/code.py @@ -7,17 +7,23 @@ # or Matrix Portal # and 64 x 32 RGB LED Matrix +from os import getenv import time import board import terminalio from adafruit_matrixportal.matrixportal import MatrixPortal -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) def aqi_transform(val): aqi = pm_to_aqi(val) # derive Air Quality Index from Particulate Matter 2.5 value @@ -49,7 +55,7 @@ def message_transform(val): # picks message based on thresholds status_neopixel=board.NEOPIXEL, debug=True, url=DATA_SOURCE, - headers={"X-API-Key": secrets["purple_air_api_key"], # purpleair.com + headers={"X-API-Key": getenv("purple_air_api_key"), # purpleair.com "Accept": "application/json" }, json_path=(DATA_LOCATION, DATA_LOCATION), diff --git a/Minesweep/SpriteSheet.bmp b/PyPortal/Minesweep/SpriteSheet.bmp similarity index 100% rename from Minesweep/SpriteSheet.bmp rename to PyPortal/Minesweep/SpriteSheet.bmp diff --git a/PyPortal/Minesweep/code.py b/PyPortal/Minesweep/code.py new file mode 100644 index 000000000..95deb634e --- /dev/null +++ b/PyPortal/Minesweep/code.py @@ -0,0 +1,268 @@ +# SPDX-FileCopyrightText: 2019 Dave Astels for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +PyPortal MineSweeper + +Adafruit invests time and resources providing this open source code. +Please support Adafruit and open source hardware by purchasing +products from Adafruit! + +Written by Dave Astels for Adafruit Industries +Copyright (c) 2019 Adafruit Industries +Licensed under the MIT license. + +All text above must be included in any redistribution. +""" + +import time +from random import seed, randint +import board +import digitalio +import displayio +import audioio +try: + from audioio import WaveFile +except ImportError: + from audiocore import WaveFile + +import adafruit_imageload +import adafruit_touchscreen + +seed(int(time.monotonic())) + +# Set up audio +speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE) +speaker_enable.switch_to_output(False) +if hasattr(board, 'AUDIO_OUT'): + audio = audioio.AudioOut(board.AUDIO_OUT) +elif hasattr(board, 'SPEAKER'): + audio = audioio.AudioOut(board.SPEAKER) +else: + raise AttributeError('Board does not have a builtin speaker!') + + +NUMBER_OF_BOMBS = 15 + +# Board pieces + +OPEN0 = 0 +OPEN1 = 1 +OPEN2 = 2 +OPEN3 = 3 +OPEN4 = 4 +OPEN5 = 5 +OPEN6 = 6 +OPEN7 = 7 +OPEN8 = 8 +BLANK = 9 +BOMBDEATH = 10 +BOMBFLAGGED = 11 +BOMBMISFLAGGED = 12 +BOMBQUESTION = 13 +BOMB = 14 + +sprite_sheet, palette = adafruit_imageload.load("/SpriteSheet.bmp", + bitmap=displayio.Bitmap, + palette=displayio.Palette) + +display = board.DISPLAY +group = displayio.Group() +touchscreen = adafruit_touchscreen.Touchscreen(board.TOUCH_XL, board.TOUCH_XR, + board.TOUCH_YD, board.TOUCH_YU, + calibration=((9000, 59000), + (8000, 57000)), + size=(display.width, display.height)) +tilegrid = displayio.TileGrid(sprite_sheet, pixel_shader=palette, + width=20, height=15, + tile_height=16, tile_width=16, + default_tile=BLANK) +group.append(tilegrid) + + + +display.root_group = group + +board_data = bytearray(b'\x00' * 300) + +#pylint:disable=redefined-outer-name +def get_data(x, y): + return board_data[y * 20 + x] + +def set_data(x, y, value): + board_data[y * 20 + x] = value +#pylint:disable=redefined-outer-name + +def seed_bombs(how_many): + for _ in range(how_many): + while True: + bomb_x = randint(0, 19) + bomb_y = randint(0, 14) + if get_data(bomb_x, bomb_y) == 0: + set_data(bomb_x, bomb_y, 14) + break + +def compute_counts(): + """For each bomb, increment the count in each non-bomb square around it""" + for y in range(15): + for x in range(20): + if get_data(x, y) != 14: + continue # keep looking for bombs + for dx in (-1, 0, 1): + if x + dx < 0 or x + dx >= 20: + continue # off screen + for dy in (-1, 0, 1): + if y + dy < 0 or y + dy >= 15: + continue # off screen + count = get_data(x + dx, y + dy) + if count == 14: + continue # don't process bombs + set_data(x + dx, y + dy, count + 1) + +def reveal(): + for x in range(20): + for y in range(15): + if tilegrid[x, y] == BOMBFLAGGED and get_data(x, y) != BOMB: + tilegrid[x, y] = BOMBMISFLAGGED + else: + tilegrid[x, y] = get_data(x, y) + +#pylint:disable=too-many-nested-blocks +def expand_uncovered(start_x, start_y): + number_uncovered = 1 + stack = [(start_x, start_y)] + while len(stack) > 0: + x, y = stack.pop() + if tilegrid[x, y] == BLANK: + under_the_tile = get_data(x, y) + if under_the_tile <= OPEN8: + tilegrid[x, y] = under_the_tile + number_uncovered += 1 + if under_the_tile == OPEN0: + for dx in (-1, 0, 1): + if x + dx < 0 or x + dx >= 20: + continue # off screen + for dy in (-1, 0, 1): + if y + dy < 0 or y + dy >= 15: + continue # off screen + if dx == 0 and dy == 0: + continue # don't process where the bomb + stack.append((x + dx, y + dy)) + return number_uncovered +#pylint:enable=too-many-nested-blocks + +def check_for_win(): + """Check for a complete, winning game. That's one with all squares uncovered + and all bombs correctly flagged, with no non-bomb squares flaged. + """ + # first make sure everything has been explored and decided + for x in range(20): + for y in range(15): + if tilegrid[x, y] == BLANK or tilegrid[x, y] == BOMBQUESTION: + return None #still ignored or question squares + # then check for mistagged bombs + for x in range(20): + for y in range(15): + if tilegrid[x, y] == BOMBFLAGGED and get_data(x, y) != BOMB: + return False #misflagged bombs, not done + return True #nothing unexplored, and no misflagged bombs + +#pylint:disable=too-many-branches +# This could be broken apart but I think it's more understandable +# with it all in one place +def play_a_game(): + number_uncovered = 0 + touch_x = -1 + touch_y = -1 + touch_time = 0 + wait_for_release = False + while True: + now = time.monotonic() + if now >= touch_time: + touch_time = now + 0.2 + # process touch + touch_at = touchscreen.touch_point + if touch_at is None: + wait_for_release = False + else: + if wait_for_release: + continue + wait_for_release = True + touch_x = max(min([touch_at[0] // 16, 19]), 0) + touch_y = max(min([touch_at[1] // 16, 14]), 0) + if tilegrid[touch_x, touch_y] == BLANK: + tilegrid[touch_x, touch_y] = BOMBQUESTION + elif tilegrid[touch_x, touch_y] == BOMBQUESTION: + tilegrid[touch_x, touch_y] = BOMBFLAGGED + elif tilegrid[touch_x, touch_y] == BOMBFLAGGED: + under_the_tile = get_data(touch_x, touch_y) + if under_the_tile == 14: + set_data(touch_x, touch_y, BOMBDEATH) #reveal a red bomb + tilegrid[touch_x, touch_y] = BOMBDEATH + return False #lost + elif OPEN0 < under_the_tile <= OPEN8: + tilegrid[touch_x, touch_y] = under_the_tile + elif under_the_tile == OPEN0: + tilegrid[touch_x, touch_y] = BLANK + number_uncovered += expand_uncovered(touch_x, touch_y) + else: #something bad happened + raise ValueError('Unexpected value on board') + status = check_for_win() + if status is None: + continue + return status +#pylint:enable=too-many-branches + +def reset_board(): + for x in range(20): + for y in range(15): + tilegrid[x, y] = BLANK + set_data(x, y, 0) + seed_bombs(NUMBER_OF_BOMBS) + compute_counts() + +def play_sound(file_name): + try: + board.DISPLAY.refresh(target_frames_per_second=60) + except AttributeError: + board.DISPLAY.wait_for_frame() + wavfile = open(file_name, "rb") + wavedata = WaveFile(wavfile) + speaker_enable.value = True + audio.play(wavedata) + return wavfile + +def wait_for_sound_and_cleanup(wavfile): + while audio.playing: + pass + wavfile.close() + speaker_enable.value = False + +def win(): + print('You won') + wait_for_sound_and_cleanup(play_sound('win.wav')) + +def lose(): + print('You lost') + wavfile = play_sound('lose.wav') + for _ in range(10): + tilegrid.x = randint(-2, 2) + tilegrid.y = randint(-2, 2) + try: + board.DISPLAY.refresh(target_frames_per_second=60) + except AttributeError: + board.DISPLAY.refresh_soon() + board.DISPLAY.wait_for_frame() + tilegrid.x = 0 + tilegrid.y = 0 + wait_for_sound_and_cleanup(wavfile) + +while True: + reset_board() + if play_a_game(): + win() + else: + reveal() + lose() + time.sleep(5.0) diff --git a/Minesweep/lose.wav b/PyPortal/Minesweep/lose.wav similarity index 100% rename from Minesweep/lose.wav rename to PyPortal/Minesweep/lose.wav diff --git a/Minesweep/win.wav b/PyPortal/Minesweep/win.wav similarity index 100% rename from Minesweep/win.wav rename to PyPortal/Minesweep/win.wav diff --git a/PyPortal/Pathfinder/pathfinder_auto/code.py b/PyPortal/Pathfinder/pathfinder_auto/code.py index 94b48575d..29f0083e5 100755 --- a/PyPortal/Pathfinder/pathfinder_auto/code.py +++ b/PyPortal/Pathfinder/pathfinder_auto/code.py @@ -73,25 +73,21 @@ pyportal = PyPortal(status_neopixel=board.NEOPIXEL) -# Open the file -with open(emote_img[0], "rb") as bitmap_file: - # Setup the file as the bitmap data source - bitmap = displayio.OnDiskBitmap(bitmap_file) - # Create a TileGrid to hold the bitmap - tile_grid = displayio.TileGrid(bitmap, pixel_shader=getattr(bitmap, - 'pixel_shader', - displayio.ColorConverter())) - # Create a Group to hold the TileGrid - group = displayio.Group() - # Add the TileGrid to the Group - group.append(tile_grid) - # Add the Group to the Display - display.root_group = group - if sound_mode != 0: - # play a sound file - pyportal.play_file(vo_sound[10]) - else: - pyportal.play_file("/vo/pathfnd_silent.wav") # hack to deal w no mute method +# Setup the file as the bitmap data source +bitmap = displayio.OnDiskBitmap(emote_img[0]) +# Create a TileGrid to hold the bitmap +tile_grid = displayio.TileGrid(bitmap, pixel_shader=getattr(bitmap.pixel_shader)) +# Create a Group to hold the TileGrid +group = displayio.Group() +# Add the TileGrid to the Group +group.append(tile_grid) +# Add the Group to the Display +display.root_group = group +if sound_mode != 0: + # play a sound file + pyportal.play_file(vo_sound[10]) +else: + pyportal.play_file("/vo/pathfnd_silent.wav") # hack to deal w no mute method # Loop forever so you can enjoy your image @@ -107,7 +103,6 @@ pixel.show() time.sleep(1) - # CircuitPython 7+ compatible bitmap = displayio.OnDiskBitmap(emote_img[i]) tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader) group = displayio.Group() diff --git a/PyPortal/Pathfinder/pathfinder_touch/code.py b/PyPortal/Pathfinder/pathfinder_touch/code.py index 7db6fcda1..e171e23db 100755 --- a/PyPortal/Pathfinder/pathfinder_touch/code.py +++ b/PyPortal/Pathfinder/pathfinder_touch/code.py @@ -71,25 +71,21 @@ pyportal = PyPortal(status_neopixel=board.NEOPIXEL) -# Open the file -with open(emote_img[0], "rb") as bitmap_file: - # Setup the file as the bitmap data source - bitmap = displayio.OnDiskBitmap(bitmap_file) - # Create a TileGrid to hold the bitmap - tile_grid = displayio.TileGrid(bitmap, pixel_shader=getattr(bitmap, - 'pixel_shader', - displayio.ColorConverter())) - # Create a Group to hold the TileGrid - group = displayio.Group() - # Add the TileGrid to the Group - group.append(tile_grid) - # Add the Group to the Display - display.root_group = group - if sound_mode != 0: - # play a sound file - pyportal.play_file(vo_sound[10]) - else: - pyportal.play_file("/vo/pathfnd_silent.wav") # hack to deal w no mute method +# Setup the file as the bitmap data source +bitmap = displayio.OnDiskBitmap(emote_img[0]) +# Create a TileGrid to hold the bitmap +tile_grid = displayio.TileGrid(bitmap, pixel_shader=getattr(bitmap.pixel_shader)) +# Create a Group to hold the TileGrid +group = displayio.Group() +# Add the TileGrid to the Group +group.append(tile_grid) +# Add the Group to the Display +display.root_group = group +if sound_mode != 0: + # play a sound file + pyportal.play_file(vo_sound[10]) +else: + pyportal.play_file("/vo/pathfnd_silent.wav") # hack to deal w no mute method while True: if not pyportal.touchscreen.touch_point: @@ -101,7 +97,6 @@ pixel.show() time.sleep(1) - # CircuitPython 7+ compatible bitmap = displayio.OnDiskBitmap(emote_img[i]) tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader) group = displayio.Group() diff --git a/PyPortal/PyPortal_AWS_IOT_Planter/aws_gfx_helper.py b/PyPortal/PyPortal_AWS_IOT_Planter/aws_gfx_helper.py index ac94561af..293bab33b 100755 --- a/PyPortal/PyPortal_AWS_IOT_Planter/aws_gfx_helper.py +++ b/PyPortal/PyPortal_AWS_IOT_Planter/aws_gfx_helper.py @@ -135,16 +135,7 @@ def set_icon(self, filename): if not filename: return # we're done, no icon desired - # CircuitPython 6 & 7 compatible - if self._icon_file: - self._icon_file.close() - self._icon_file = open(filename, "rb") - icon = displayio.OnDiskBitmap(self._icon_file) - self._icon_sprite = displayio.TileGrid(icon, - pixel_shader=getattr(icon, 'pixel_shader', displayio.ColorConverter())) - - # # CircuitPython 7+ compatible - # icon = displayio.OnDiskBitmap(filename) - # self._icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) + icon = displayio.OnDiskBitmap(filename) + self._icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) self._icon_group.append(self._icon_sprite) diff --git a/PyPortal/PyPortal_AWS_IOT_Planter/code.py b/PyPortal/PyPortal_AWS_IOT_Planter/code.py index ee44b40fd..b9583b9e5 100755 --- a/PyPortal/PyPortal_AWS_IOT_Planter/code.py +++ b/PyPortal/PyPortal_AWS_IOT_Planter/code.py @@ -10,7 +10,8 @@ Author: Brent Rubell for Adafruit Industries, 2019 """ -import os + +from os import getenv import time import json import board @@ -28,10 +29,17 @@ # Time between polling the STEMMA, in minutes SENSOR_DELAY = 15 -secrets = { - "ssid" : os.getenv("CIRCUITPY_WIFI_SSID"), - "password" : os.getenv("CIRCUITPY_WIFI_PASSWORD"), -} +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Get device certificate try: @@ -65,9 +73,10 @@ # Verify nina-fw version >= 1.4.0 assert int(bytes(esp.firmware_version).decode("utf-8")[2]) >= 4, "Please update nina-fw to >=1.4.0." -status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager( - esp, secrets, status_light) +status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) +wifi = adafruit_esp32spi_wifimanager.WiFiManager( + esp, ssid, password, status_pixel=status_pixel +) # Initialize the graphics helper print("Loading AWS IoT Graphics...") @@ -126,8 +135,8 @@ def message(client, topic, msg): print("Message from {}: {}".format(topic, msg)) # Set up a new MiniMQTT Client -client = MQTT.MQTT(broker = os.getenv("BROKER"), - client_id = os.getenv("CLIENT_ID"), +client = MQTT.MQTT(broker = getenv("BROKER"), + client_id = getenv("CLIENT_ID"), socket_pool=pool, ssl_context=ssl_context) diff --git a/PyPortal/PyPortal_AdafruitIO/code.py b/PyPortal/PyPortal_AdafruitIO/code.py index bba018f89..a4ba33b31 100644 --- a/PyPortal/PyPortal_AdafruitIO/code.py +++ b/PyPortal/PyPortal_AdafruitIO/code.py @@ -7,19 +7,29 @@ and io plus subscribers... and display it on a screen If you can find something that spits out JSON data, we can display it! """ + +from os import getenv import time import board from adafruit_pyportal import PyPortal -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) # Set up where we'll be fetching data from -DATA_SOURCE = "https://io.adafruit.com/api/v2/stats?x-aio-key="+secrets['aio_key'] +DATA_SOURCE = f"https://io.adafruit.com/api/v2/stats?x-aio-key={aio_key}" DATA_LOCATION1 = ["io_plus", "io_plus_subscriptions"] DATA_LOCATION2 = ["users", "users_active_30_days"] diff --git a/PyPortal/PyPortal_AdafruitIO_Logger/code.py b/PyPortal/PyPortal_AdafruitIO_Logger/code.py index 77d37ead8..5d743b730 100644 --- a/PyPortal/PyPortal_AdafruitIO_Logger/code.py +++ b/PyPortal/PyPortal_AdafruitIO_Logger/code.py @@ -12,6 +12,8 @@ * CircuitPython_AdafruitIO https://github.com/adafruit/Adafruit_CircuitPython_AdafruitIO """ + +from os import getenv import time import board import busio @@ -33,12 +35,20 @@ # Timeout between sending data to Adafruit IO, in seconds IO_DELAY = 30 -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) # PyPortal ESP32 Setup esp32_cs = DigitalInOut(board.ESP_CS) @@ -46,17 +56,11 @@ esp32_reset = DigitalInOut(board.ESP_RESET) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) -status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) - -# Set your Adafruit IO Username and Key in secrets.py -# (visit io.adafruit.com if you need to create an account, -# or if you need your Adafruit IO key.) -ADAFRUIT_IO_USER = secrets['aio_username'] -ADAFRUIT_IO_KEY = secrets['aio_key'] +status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Create an instance of the Adafruit IO HTTP client -io = IO_HTTP(ADAFRUIT_IO_USER, ADAFRUIT_IO_KEY, wifi) +io = IO_HTTP(aio_username, aio_key, wifi) try: # Get the 'temperature' feed from Adafruit IO diff --git a/PyPortal/PyPortal_Alarm_Clock/code.py b/PyPortal/PyPortal_Alarm_Clock/code.py index 0234a7c83..a73f976fb 100644 --- a/PyPortal/PyPortal_Alarm_Clock/code.py +++ b/PyPortal/PyPortal_Alarm_Clock/code.py @@ -20,9 +20,9 @@ #pylint:disable=no-self-use,too-many-branches,too-many-statements #pylint:disable=useless-super-delegation, too-many-locals +from os import getenv import time import json -from secrets import secrets import board from adafruit_pyportal import PyPortal from adafruit_bitmap_font import bitmap_font @@ -32,9 +32,21 @@ import displayio import adafruit_logging as logging +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) + # Set up where we'll be fetching data from -DATA_SOURCE = 'http://api.openweathermap.org/data/2.5/weather?id='+secrets['city_id'] -DATA_SOURCE += '&appid='+secrets['openweather_token'] +DATA_SOURCE = 'http://api.openweathermap.org/data/2.5/weather?id='+getenv('city_id') +DATA_SOURCE += '&appid='+getenv('openweather_token') # You'll need to get a token from openweather.org, looks like 'b6907d289e10d714a6e88b30761fae22' DATA_LOCATION = [] @@ -73,7 +85,7 @@ icon_file = None icon_sprite = None -celcius = secrets['celcius'] +celsius = getenv('celsius') # display/data refresh timers @@ -124,8 +136,8 @@ def create_text_areas(configs): def clear_splash(): - for _ in range(len(pyportal.splash) - 1): - pyportal.splash.pop() + for _ in range(len(pyportal.root_group) - 1): + pyportal.root_group.pop() def touch_in_button(t, b): @@ -243,7 +255,7 @@ def tick(self, now): if (not self.refresh_time) or ((now - self.refresh_time) > 3600): logger.debug('Fetching time') try: - pyportal.get_local_time(location=secrets['timezone']) + pyportal.get_local_time(location=getenv('timezone')) self.refresh_time = now except RuntimeError as e: self.refresh_time = now - 3000 # delay 10 minutes before retrying @@ -265,24 +277,13 @@ def tick(self, now): filename = "/icons/"+weather_icon_name+".bmp" if filename: - # CircuitPython 6 & 7 compatible - if self.icon_file: - self.icon_file.close() - self.icon_file = open(filename, "rb") - icon = displayio.OnDiskBitmap(self.icon_file) - - icon_sprite = displayio.TileGrid(icon, - pixel_shader=getattr(icon, 'pixel_shader', displayio.ColorConverter()), - x=0, y=0) - - # # CircuitPython 7+ compatible - # icon = displayio.OnDiskBitmap(filename) - # icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) + icon = displayio.OnDiskBitmap(filename) + icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) self.weather_icon.append(icon_sprite) temperature = weather['main']['temp'] - 273.15 # its...in kelvin - if celcius: + if celsius: temperature_text = '%3d C' % round(temperature) else: temperature_text = '%3d F' % round(((temperature * 9 / 5) + 32)) @@ -336,23 +337,18 @@ def touch(self, t, touched): def enter(self): self.adjust_backlight_based_on_light(force=True) for ta in self.text_areas: - pyportal.splash.append(ta) - pyportal.splash.append(self.weather_icon) + pyportal.root_group.append(ta) + pyportal.root_group.append(self.weather_icon) if snooze_time: # CircuitPython 6 & 7 compatible if self.snooze_file: self.snooze_file.close() - self.snooze_file = open('/icons/zzz.bmp', "rb") - icon = displayio.OnDiskBitmap(self.snooze_file) - icon_sprite = displayio.TileGrid(icon, - pixel_shader=getattr(icon, 'pixel_shader', displayio.ColorConverter())) - # # CircuitPython 7+ compatible - # icon = displayio.OnDiskBitmap("/icons/zzz.bmp") - # icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) + icon = displayio.OnDiskBitmap("/icons/zzz.bmp") + icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) self.snooze_icon.append(icon_sprite) - pyportal.splash.append(self.snooze_icon) + pyportal.root_group.append(self.snooze_icon) if alarm_enabled: self.text_areas[1].text = '%2d:%02d' % (alarm_hour, alarm_minute) else: @@ -536,7 +532,7 @@ def enter(self): pyportal.set_background(self.background) for ta in self.text_areas: - pyportal.splash.append(ta) + pyportal.root_group.append(ta) if alarm_enabled: self.text_areas[0].text = '%02d:%02d' % (alarm_hour, alarm_minute) # set time textarea else: diff --git a/PyPortal/PyPortal_Astronauts/code.py b/PyPortal/PyPortal_Astronauts/code.py index e29278d83..35edad7a4 100644 --- a/PyPortal/PyPortal_Astronauts/code.py +++ b/PyPortal/PyPortal_Astronauts/code.py @@ -54,6 +54,6 @@ names_textarea.x = names_position[0] names_textarea.y = names_position[1] names_textarea.color = names_color - pyportal.splash.append(names_textarea) + pyportal.root_group.append(names_textarea) time.sleep(30) # wait 30 seconds to read it - pyportal.splash.pop() + pyportal.root_group.pop() diff --git a/PyPortal/PyPortal_Azure_Plant_Monitor/azure_gfx_helper.py b/PyPortal/PyPortal_Azure_Plant_Monitor/azure_gfx_helper.py index 1ca97732a..d96cffdbe 100755 --- a/PyPortal/PyPortal_Azure_Plant_Monitor/azure_gfx_helper.py +++ b/PyPortal/PyPortal_Azure_Plant_Monitor/azure_gfx_helper.py @@ -134,18 +134,7 @@ def set_icon(self, filename): if not filename: return # we're done, no icon desired - # CircuitPython 6 & 7 compatible - if self._icon_file: - self._icon_file.close() - self._icon_file = open(filename, "rb") - icon = displayio.OnDiskBitmap(self._icon_file) - self._icon_sprite = displayio.TileGrid( - icon, pixel_shader=getattr(icon, "pixel_shader", displayio.ColorConverter()) - ) - - # CircuitPython 7 compatible - # # Remove self._icon_file - it is no longer used - # icon = displayio.OnDiskBitmap(filename) - # self._icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) + icon = displayio.OnDiskBitmap(filename) + self._icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) self._icon_group.append(self._icon_sprite) diff --git a/PyPortal/PyPortal_Azure_Plant_Monitor/code.py b/PyPortal/PyPortal_Azure_Plant_Monitor/code.py index 832c14b6d..be79a9660 100755 --- a/PyPortal/PyPortal_Azure_Plant_Monitor/code.py +++ b/PyPortal/PyPortal_Azure_Plant_Monitor/code.py @@ -12,6 +12,8 @@ Authors: Brent Rubell for Adafruit Industries, 2019 : Jim Bennett for Microsoft, 2020 """ + +from os import getenv import time import json import board @@ -30,12 +32,17 @@ # init. graphics helper gfx = azure_gfx_helper.Azure_GFX(is_celsius=True) -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # PyPortal ESP32 Setup esp32_cs = DigitalInOut(board.ESP_CS) @@ -45,8 +52,8 @@ esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) # Set up the WiFi manager with a status light to show the WiFi connection status -status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) print("WiFi connecting...") wifi.connect() print("WiFi connected!") @@ -68,7 +75,7 @@ # Create an instance of the Azure IoT Central device device = IoTCentralDevice( - socket, esp, secrets["id_scope"], secrets["device_id"], secrets["key"] + socket, esp, getenv("id_scope"), getenv("device_id"), getenv("key") ) # Connect to Azure IoT Central diff --git a/PyPortal/PyPortal_CMA_Art_Frame/code.py b/PyPortal/PyPortal_CMA_Art_Frame/code.py index 6fe4a1940..bf4303f37 100644 --- a/PyPortal/PyPortal_CMA_Art_Frame/code.py +++ b/PyPortal/PyPortal_CMA_Art_Frame/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import random import board @@ -11,6 +12,21 @@ WIDTH = board.DISPLAY.width HEIGHT = board.DISPLAY.height +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + #pylint: disable=line-too-long # these lines show the entire collection @@ -37,7 +53,7 @@ text_color=0xFFFFFF) circle = Circle(WIDTH - 8, HEIGHT - 7, 5, fill=0) -pyportal.splash.append(circle) +pyportal.root_group.append(circle) loopcount = 0 errorcount = 0 while True: diff --git a/PyPortal/PyPortal_CMA_Art_Frame/secrets.py b/PyPortal/PyPortal_CMA_Art_Frame/secrets.py deleted file mode 100644 index 64c59aacb..000000000 --- a/PyPortal/PyPortal_CMA_Art_Frame/secrets.py +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-FileCopyrightText: 2019 Kattni Rembor for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -# This file is where you keep secret settings, passwords, and tokens! -# If you put them in the code you risk committing that info or sharing it - -secrets = { - 'ssid' : 'CHANGE ME', - 'password' : 'CHANGE ME', - 'aio_username' : 'CHANGE ME', - 'aio_key' : 'CHANGE ME', -} diff --git a/PyPortal/PyPortal_CMA_Art_Frame/settings.toml b/PyPortal/PyPortal_CMA_Art_Frame/settings.toml new file mode 100644 index 000000000..bc33202be --- /dev/null +++ b/PyPortal/PyPortal_CMA_Art_Frame/settings.toml @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: 2019 Kattni Rembor for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# This file is where you keep private settings, passwords, and tokens! +# If you put them in the code you risk committing that info or sharing it + +CIRCUITPY_WIFI_SSID="your-wifi-ssid" +CIRCUITPY_WIFI_PASSWORD="your-wifi-password" +ADAFRUIT_AIO_USERNAME="my_username" +ADAFRUIT_AIO_KEY="my_key" +CIRCUITPY_PYSTACK_SIZE=2048 diff --git a/PyPortal/PyPortal_CircuitPython_2020/code.py b/PyPortal/PyPortal_CircuitPython_2020/code.py index fc8a849aa..1433cc900 100644 --- a/PyPortal/PyPortal_CircuitPython_2020/code.py +++ b/PyPortal/PyPortal_CircuitPython_2020/code.py @@ -47,7 +47,7 @@ textarea.x = pos[0] textarea.y = pos[1] textarea.color = text_color - pyportal.splash.append(textarea) + pyportal.root_group.append(textarea) text_areas.append(textarea) refresh_time = None diff --git a/PyPortal/PyPortal_EZ_Make_Oven/profiles/sn63pb37.json b/PyPortal/PyPortal_EZ_Make_Oven/profiles/sn63pb37.json index f3b66cd5d..14d554eb3 100644 --- a/PyPortal/PyPortal_EZ_Make_Oven/profiles/sn63pb37.json +++ b/PyPortal/PyPortal_EZ_Make_Oven/profiles/sn63pb37.json @@ -18,7 +18,7 @@ [40,110], [110,140], [120,150], - [130,160] + [130,160], [150,183], [200,230], [210,235], diff --git a/PyPortal/PyPortal_Electioncal_US/.circuitpython.skip b/PyPortal/PyPortal_Electioncal_US/.circuitpython.skip deleted file mode 100644 index 25434fef9..000000000 --- a/PyPortal/PyPortal_Electioncal_US/.circuitpython.skip +++ /dev/null @@ -1,7 +0,0 @@ -PyPortal_Electioncal_US/electioncal_graphics.py 73: Line too long (120/100) (line-too-long) -PyPortal_Electioncal_US/electioncal_graphics.py 75: Line too long (108/100) (line-too-long) -PyPortal_Electioncal_US/electioncal_graphics.py 86: Line too long (141/100) (line-too-long) -PyPortal_Electioncal_US/electioncal_graphics.py 107: Unused variable 'time_str' (unused-variable) -PyPortal_Electioncal_US/electioncal_graphics.py 111: Method could be a function (no-self-use) -PyPortal_Electioncal_US/electioncal_graphics.py 72: Attribute 'electioncal' defined outside __init__ (attribute-defined-outside-init) -PyPortal_Electioncal_US/electioncal.py 11: Unused secrets imported from secrets (unused-import) diff --git a/PyPortal/PyPortal_Electioncal_US/code.py b/PyPortal/PyPortal_Electioncal_US/code.py index a7601499b..de4b6751a 100644 --- a/PyPortal/PyPortal_Electioncal_US/code.py +++ b/PyPortal/PyPortal_Electioncal_US/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import sys import time import board @@ -10,12 +11,17 @@ sys.path.append(cwd) import electioncal_graphics # pylint: disable=wrong-import-position -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets # pylint: disable=unused-import -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Change this to your state and county, replacing spaces for underscores and in lowercase STATE="new_york" @@ -32,7 +38,7 @@ default_bg=0x000000) -gfx = electioncal_graphics.Electioncal_Graphics(pyportal.splash, am_pm=True) +gfx = electioncal_graphics.Electioncal_Graphics(pyportal.root_group, am_pm=True) display_refresh = None while True: # only query the online time once per hour (and on first run) diff --git a/PyPortal/PyPortal_Electioncal_US/electioncal_graphics.py b/PyPortal/PyPortal_Electioncal_US/electioncal_graphics.py index 145219363..26ad15f5d 100644 --- a/PyPortal/PyPortal_Electioncal_US/electioncal_graphics.py +++ b/PyPortal/PyPortal_Electioncal_US/electioncal_graphics.py @@ -112,7 +112,8 @@ def update_time(self): date_str = date_format_str % (year, month, day) self.date_text.text = "Today is: " + date_str - def paragrapher(self, text, cut): # pylint: disable=no-self-use + @staticmethod + def paragrapher(text, cut): """ Cuts a long line into two, having spaces in mind. Note we return line2 first as it looks better to clear the line2 before printing a line1 with empty line2 @@ -142,18 +143,7 @@ def set_icon(self, filename): if not filename: return # we're done, no icon desired - # CircuitPython 6 & 7 compatible - if self._icon_file: - self._icon_file.close() - self._icon_file = open(filename, "rb") - icon = displayio.OnDiskBitmap(self._icon_file) - self._icon_sprite = displayio.TileGrid( - icon, - pixel_shader=getattr(icon, 'pixel_shader', displayio.ColorConverter()) - ) - - # # CircuitPython 7+ compatible - # icon = displayio.OnDiskBitmap(filename) - # self._icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) + icon = displayio.OnDiskBitmap(filename) + self._icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) self._icon_group.append(self._icon_sprite) diff --git a/PyPortal/PyPortal_Email_Display/code.py b/PyPortal/PyPortal_Email_Display/code.py index 987f90f1f..85a4fe70b 100755 --- a/PyPortal/PyPortal_Email_Display/code.py +++ b/PyPortal/PyPortal_Email_Display/code.py @@ -7,25 +7,30 @@ Displays an Adafruit IO Feed on a PyPortal. """ + +from os import getenv import time import board from adafruit_pyportal import PyPortal -# Get Adafruit IO details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("Adafruit IO secrets are kept in secrets.py, please add them there!") - raise +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) -# Adafruit IO Account -IO_USER = secrets['aio_username'] -IO_KEY = secrets['aio_key'] # Adafruit IO Feed -IO_FEED = 'zapemail' +io_feed = 'zapemail' -DATA_SOURCE = "https://io.adafruit.com/api/v2/{0}/feeds/{1}?X-AIO-Key={2}".format(IO_USER, - IO_FEED, IO_KEY) +DATA_SOURCE = f"https://io.adafruit.com/api/v2/{aio_username}/feeds/{io_feed}?X-AIO-Key={aio_key}" FEED_VALUE_LOCATION = ['last_value'] cwd = ("/"+__file__).rsplit('/', 1)[0] diff --git a/PyPortal/PyPortal_EventCountdown/code.py b/PyPortal/PyPortal_EventCountdown/code.py index 8a6f49a69..d587896f8 100644 --- a/PyPortal/PyPortal_EventCountdown/code.py +++ b/PyPortal/PyPortal_EventCountdown/code.py @@ -47,7 +47,7 @@ textarea.x = pos[0] textarea.y = pos[1] textarea.color = text_color - pyportal.splash.append(textarea) + pyportal.root_group.append(textarea) text_areas.append(textarea) refresh_time = None diff --git a/PyPortal/PyPortal_EventCountup/code.py b/PyPortal/PyPortal_EventCountup/code.py index 89a196389..2cf5a2391 100644 --- a/PyPortal/PyPortal_EventCountup/code.py +++ b/PyPortal/PyPortal_EventCountup/code.py @@ -47,7 +47,7 @@ textarea.x = pos[0] textarea.y = pos[1] textarea.color = text_color - pyportal.splash.append(textarea) + pyportal.root_group.append(textarea) text_areas.append(textarea) refresh_time = None diff --git a/PyPortal/PyPortal_GCP_IOT_Planter/code.py b/PyPortal/PyPortal_GCP_IOT_Planter/code.py index a7fc58140..6b8b23425 100644 --- a/PyPortal/PyPortal_GCP_IOT_Planter/code.py +++ b/PyPortal/PyPortal_GCP_IOT_Planter/code.py @@ -10,6 +10,8 @@ Author: Brent Rubell for Adafruit Industries, 2019 """ + +from os import getenv import time import json import board @@ -22,26 +24,33 @@ import adafruit_minimqtt.adafruit_minimqtt as MQTT from adafruit_seesaw.seesaw import Seesaw import digitalio +from rsa_private_key import private_key + +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Delay before reading the sensors, in minutes SENSOR_DELAY = 10 -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise - # PyPortal ESP32 Setup esp32_cs = digitalio.DigitalInOut(board.ESP_CS) esp32_ready = digitalio.DigitalInOut(board.ESP_BUSY) esp32_reset = digitalio.DigitalInOut(board.ESP_RESET) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) -status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager( - esp, secrets, status_light) +status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) +wifi = adafruit_esp32spi_wifimanager.WiFiManager( + esp, ssid, password, status_pixel=status_pixel +) # Connect to WiFi print("Connecting to WiFi...") @@ -137,7 +146,14 @@ def handle_pump(command): # Initialize Google Cloud IoT Core interface -google_iot = Cloud_Core(esp, secrets) +settings = { + "cloud_region": getenv("cloud_region"), + "device_id": getenv("device_id"), + "private_key": private_key, + "project_id": getenv("project_id"), + "registry_id": getenv("registry_id"), +} +google_iot = Cloud_Core(esp, settings) # JSON-Web-Token (JWT) Generation print("Generating JWT...") diff --git a/PyPortal/PyPortal_GCP_IOT_Planter/gcp_gfx_helper.py b/PyPortal/PyPortal_GCP_IOT_Planter/gcp_gfx_helper.py index fe6aa0720..11c6f0a04 100644 --- a/PyPortal/PyPortal_GCP_IOT_Planter/gcp_gfx_helper.py +++ b/PyPortal/PyPortal_GCP_IOT_Planter/gcp_gfx_helper.py @@ -59,7 +59,7 @@ def __init__(self, is_celsius=False): temp_group.append(temp_label) self.temp_data_label = Label(font, text="75 F") - self.temp_data_label.x = (self.display.width//3) + self.temp_data_label.x = self.display.width//3 self.temp_data_label.y = 55 temp_group.append(self.temp_data_label) self._text_group.append(temp_group) @@ -72,7 +72,7 @@ def __init__(self, is_celsius=False): water_group.append(self.water_level) self.water_lvl_label = Label(font, text="350") - self.water_lvl_label.x = (self.display.width//3) + self.water_lvl_label.x = self.display.width//3 self.water_lvl_label.y = 75 temp_group.append(self.water_lvl_label) self._text_group.append(water_group) @@ -136,18 +136,7 @@ def set_icon(self, filename): if not filename: return # we're done, no icon desired - # CircuitPython 6 & 7 compatible - if self._icon_file: - self._icon_file.close() - self._icon_file = open(filename, "rb") - icon = displayio.OnDiskBitmap(self._icon_file) - self._icon_sprite = displayio.TileGrid( - icon, - pixel_shader=getattr(icon, 'pixel_shader', displayio.ColorConverter()) - ) - - # # CircuitPython 7+ compatible - # icon = displayio.OnDiskBitmap(filename) - # self._icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) + icon = displayio.OnDiskBitmap(filename) + self._icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) self._icon_group.append(self._icon_sprite) diff --git a/PyPortal/PyPortal_GCP_IOT_Planter/rsa_private_key.py b/PyPortal/PyPortal_GCP_IOT_Planter/rsa_private_key.py new file mode 100644 index 000000000..9a732aebb --- /dev/null +++ b/PyPortal/PyPortal_GCP_IOT_Planter/rsa_private_key.py @@ -0,0 +1,6 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# Replace the value with your generated RSA Private Key +private_key = (0, 0, 0, 0, 0) diff --git a/PyPortal/PyPortal_GithubStars/code.py b/PyPortal/PyPortal_GithubStars/code.py index efab55c6e..7ed47111c 100644 --- a/PyPortal/PyPortal_GithubStars/code.py +++ b/PyPortal/PyPortal_GithubStars/code.py @@ -7,23 +7,31 @@ the number of stars for a repository... and display it on a screen! if you can find something that spits out JSON data, we can display it """ + +from os import getenv import time import board from adafruit_pyportal import PyPortal -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Set up where we'll be fetching data from DATA_SOURCE = "https://api.github.com/repos/adafruit/circuitpython" CAPTION = "www.github.com/adafruit/circuitpython" # If we have an access token, we can query more often -if 'github_token' in secrets: - DATA_SOURCE += "?access_token="+secrets['github_token'] +github_token = getenv("github_token") +if github_token: + DATA_SOURCE += f"?access_token={github_token}" # The data we want to display DATA_LOCATION = ["stargazers_count"] diff --git a/PyPortal/PyPortal_Google_Calendar/authenticator/code.py b/PyPortal/PyPortal_Google_Calendar/authenticator/code.py index 1764b58bb..3ebeffbfa 100644 --- a/PyPortal/PyPortal_Google_Calendar/authenticator/code.py +++ b/PyPortal/PyPortal_Google_Calendar/authenticator/code.py @@ -26,16 +26,16 @@ label_overview_text = Label( font_large, x=0, y=45, text="To authorize this device with Google:" ) -graphics.splash.append(label_overview_text) +graphics.root_group.append(label_overview_text) label_verification_url = Label(font_small, x=0, y=100, line_spacing=1) -graphics.splash.append(label_verification_url) +graphics.root_group.append(label_verification_url) label_user_code = Label(font_small, x=0, y=150) -graphics.splash.append(label_user_code) +graphics.root_group.append(label_user_code) label_qr_code = Label(font_small, x=0, y=190, text="Or scan the QR code:") -graphics.splash.append(label_qr_code) +graphics.root_group.append(label_qr_code) # Set scope(s) of access required by the API you're using scopes = ["https://www.googleapis.com/auth/calendar.readonly"] @@ -71,7 +71,7 @@ # Create a QR code graphics.qrcode(google_auth.verification_url.encode(), qr_size=2, x=170, y=165) -graphics.display.root_group = graphics.splash +graphics.display.root_group = graphics.root_group # Poll Google's authorization server print("Waiting for browser authorization...") @@ -85,9 +85,9 @@ print(f'GOOGLE_ACCESS_TOKEN = "{google_auth.access_token}"') print(f'GOOGLE_REFRESH_TOKEN = "{google_auth.refresh_token}"') # Remove QR code and code/verification labels -graphics.splash.pop() -graphics.splash.pop() -graphics.splash.pop() +graphics.root_group.pop() +graphics.root_group.pop() +graphics.root_group.pop() label_overview_text.text = "Successfully Authenticated!" label_verification_url.text = ( diff --git a/PyPortal/PyPortal_Google_Calendar/code.py b/PyPortal/PyPortal_Google_Calendar/code.py index 9aa515ba8..08b9589ec 100644 --- a/PyPortal/PyPortal_Google_Calendar/code.py +++ b/PyPortal/PyPortal_Google_Calendar/code.py @@ -202,7 +202,7 @@ def display_calendar_events(resp_events): # Add the header line_header = Line(0, 50, 320, 50, color=0x000000) -pyportal.splash.append(line_header) +pyportal.root_group.append(line_header) label_header = pyportal.add_text( text_font="fonts/Arial-18.pcf", diff --git a/PyPortal/PyPortal_Guitar_Tuner/code.py b/PyPortal/PyPortal_Guitar_Tuner/code.py index cc87b231c..4d385ded6 100644 --- a/PyPortal/PyPortal_Guitar_Tuner/code.py +++ b/PyPortal/PyPortal_Guitar_Tuner/code.py @@ -33,7 +33,7 @@ style=Button.RECT, fill_color=None, outline_color=0x5C3C15, name=peg['label']) - pyportal.splash.append(button.group) + pyportal.root_group.append(button.group) buttons.append(button) note_select = None diff --git a/PyPortal/PyPortal_Guitar_Tuner/secrets.py b/PyPortal/PyPortal_Guitar_Tuner/secrets.py deleted file mode 100644 index 8626bef95..000000000 --- a/PyPortal/PyPortal_Guitar_Tuner/secrets.py +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Liz Clark for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -secrets = { - 'ssid' : 'your-ssid-here', - 'password' : 'your-password-here', - 'openweather_token' : 'your-openweather-token-here', - 'aio_username' : "your-aio-username-here", - 'aio_key' : 'your-aio-key-here', - 'location' : 'New York, US' -} diff --git a/PyPortal/PyPortal_HaDSkulls/code.py b/PyPortal/PyPortal_HaDSkulls/code.py index b67bf1d20..051027cf5 100644 --- a/PyPortal/PyPortal_HaDSkulls/code.py +++ b/PyPortal/PyPortal_HaDSkulls/code.py @@ -8,20 +8,27 @@ If you can find something that spits out JSON data, we can display it! Note that you need a hackaday API key to access the API! """ + +from os import getenv import time import board from adafruit_pyportal import PyPortal -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Some data sources and JSON locations to try out CAPTION="hackaday.io/project/163309-circuitpython-hackaday" -DATA_SOURCE = "https://api.hackaday.io/v1/projects/163309?api_key="+secrets['hackaday_token'] +DATA_SOURCE = "https://api.hackaday.io/v1/projects/163309?api_key="+getenv('hackaday_token') DATA_LOCATION = ["skulls"] # the current working directory (where this file is) diff --git a/PyPortal/PyPortal_Hackster/code.py b/PyPortal/PyPortal_Hackster/code.py index e2d2d730d..3ec10d227 100644 --- a/PyPortal/PyPortal_Hackster/code.py +++ b/PyPortal/PyPortal_Hackster/code.py @@ -2,23 +2,29 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import board from adafruit_pyportal import PyPortal -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) PROJECT_NAME = "3c92f0" # Set up where we'll be fetching data from DATA_SOURCE = "https://api.hackster.io/v2/projects/"+PROJECT_NAME+"?" -DATA_SOURCE += "client_id="+secrets['hackster_clientid'] -DATA_SOURCE += "&client_secret="+secrets['hackster_secret'] +DATA_SOURCE += "client_id="+getenv('hackster_clientid') +DATA_SOURCE += "&client_secret="+getenv('hackster_secret') VIEWS_LOCATION = ['stats', 'views'] LIKES_LOCATION = ['stats', 'respects'] CAPTION = "http://www.hackster.com/project/"+PROJECT_NAME diff --git a/PyPortal/PyPortal_HacksterStream/code.py b/PyPortal/PyPortal_HacksterStream/code.py index f67709bc9..beff3429b 100644 --- a/PyPortal/PyPortal_HacksterStream/code.py +++ b/PyPortal/PyPortal_HacksterStream/code.py @@ -2,22 +2,28 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import random import board import adafruit_pyportal -# Get wifi details and more from a settings.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Set up where we'll be fetching data from DATA_SOURCE = "https://api.hackster.io/v2/projects?" -DATA_SOURCE += "client_id="+secrets['hackster_clientid'] -DATA_SOURCE += "&client_secret="+secrets['hackster_secret'] +DATA_SOURCE += "client_id="+getenv('hackster_clientid') +DATA_SOURCE += "&client_secret="+getenv('hackster_secret') IMAGE_LOCATION = ['records', 0, "cover_image_url"] TITLE_LOCATION = ['records',0, "name"] HID_LOCATION = ['records', 0, "hid"] diff --git a/PyPortal/PyPortal_Halloween_Countdown/code.py b/PyPortal/PyPortal_Halloween_Countdown/code.py index 6bdf44fc5..97618d61e 100644 --- a/PyPortal/PyPortal_Halloween_Countdown/code.py +++ b/PyPortal/PyPortal_Halloween_Countdown/code.py @@ -16,8 +16,7 @@ All text above must be included in any redistribution. """ -#pylint:disable=invalid-name -import os +from os import getenv import time import random import board @@ -25,6 +24,19 @@ from adafruit_bitmap_font import bitmap_font from adafruit_display_text.label import Label +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) + + # The time of the thing! EVENT_YEAR = 2019 EVENT_MONTH = 10 @@ -74,7 +86,7 @@ countdown_text.x = 25 countdown_text.y = 120 countdown_text.color = 0x7942a0 -pyportal.splash.append(countdown_text) +pyportal.root_group.append(countdown_text) refresh_time = None @@ -83,7 +95,7 @@ if (not refresh_time) or (time.monotonic() - refresh_time) > 3600: try: print("Getting time from internet!") - pyportal.get_local_time(location=os.getenv("TIMEZONE")) + pyportal.get_local_time(location=getenv("timezone")) refresh_time = time.monotonic() except RuntimeError as e: print("Some error occured, retrying! -", e) diff --git a/PyPortal/PyPortal_Halloween_Countdown/secrets.py b/PyPortal/PyPortal_Halloween_Countdown/secrets.py deleted file mode 100644 index 0d76178f1..000000000 --- a/PyPortal/PyPortal_Halloween_Countdown/secrets.py +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-FileCopyrightText: 2019 Kattni Rembor for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -# This file is where you keep secret settings, passwords, and tokens! -# If you put them in the code you risk committing that info or sharing it - -secrets = { - 'ssid' : 'CHANGE ME', - 'password' : 'CHANGE ME', - 'timezone' : 'CHANGE ME', - 'aio_username' : 'CHANGE ME', - 'aio_key' : 'CHANGE ME', -} diff --git a/PyPortal/PyPortal_Halloween_Countdown/settings.toml b/PyPortal/PyPortal_Halloween_Countdown/settings.toml new file mode 100644 index 000000000..01fc77e45 --- /dev/null +++ b/PyPortal/PyPortal_Halloween_Countdown/settings.toml @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: 2019 Kattni Rembor for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# This file is where you keep private settings, passwords, and tokens! +# If you put them in the code you risk committing that info or sharing it + +CIRCUITPY_WIFI_SSID="your-wifi-ssid" +CIRCUITPY_WIFI_PASSWORD="your-wifi-password" +ADAFRUIT_AIO_USERNAME="my_username" +ADAFRUIT_AIO_KEY="my_key" +timezone="America/New_York" # http://worldtimeapi.org/timezones diff --git a/PyPortal/PyPortal_Hurricane_Tracker/code.py b/PyPortal/PyPortal_Hurricane_Tracker/code.py index 139473575..bd6b505a1 100755 --- a/PyPortal/PyPortal_Hurricane_Tracker/code.py +++ b/PyPortal/PyPortal_Hurricane_Tracker/code.py @@ -41,7 +41,7 @@ if c == 0xFFFF00: icons_pal.make_transparent(i) storm_icons = displayio.Group() -pyportal.splash.append(storm_icons) +pyportal.root_group.append(storm_icons) STORM_CLASS = ("TD", "TS", "HU") # setup info label @@ -53,7 +53,7 @@ ) info_update.anchor_point = (0.0, 1.0) info_update.anchored_position = (10, board.DISPLAY.height - 10) -pyportal.splash.append(info_update) +pyportal.root_group.append(info_update) # these are need for lat/lon to screen x/y mapping VIRTUAL_WIDTH = board.DISPLAY.width * 360 / (LON_RANGE[1] - LON_RANGE[0]) diff --git a/PyPortal/PyPortal_IOT_Scale/code.py b/PyPortal/PyPortal_IOT_Scale/code.py index a10cd0c59..224e978f7 100644 --- a/PyPortal/PyPortal_IOT_Scale/code.py +++ b/PyPortal/PyPortal_IOT_Scale/code.py @@ -8,6 +8,8 @@ Brent Rubell for Adafruit Industries, 2019 """ + +from os import getenv import time import board import adafruit_dymoscale @@ -22,12 +24,20 @@ import neopixel from adafruit_io.adafruit_io import IO_HTTP -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) # the current working directory (where this file is) cwd = ("/"+__file__).rsplit('/', 1)[0] @@ -69,14 +79,8 @@ esp32_reset = digitalio.DigitalInOut(board.ESP_RESET) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) -status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) - -# Set your Adafruit IO Username and Key in secrets.py -# (visit io.adafruit.com if you need to create an account, -# or if you need your Adafruit IO key.) -aio_username = secrets['aio_username'] -aio_key = secrets['aio_key'] +status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Create an instance of the IO_HTTP client io = IO_HTTP(aio_username, aio_key, wifi) diff --git a/PyPortal/PyPortal_ISS_Tracker/code.py b/PyPortal/PyPortal_ISS_Tracker/code.py index 332627331..fa68bddcd 100644 --- a/PyPortal/PyPortal_ISS_Tracker/code.py +++ b/PyPortal/PyPortal_ISS_Tracker/code.py @@ -43,21 +43,21 @@ # Date and time label date_label = Label(FONT, text="0000-00-00", color=DATE_COLOR, x=165, y=223) time_label = Label(FONT, text="00:00:00", color=TIME_COLOR, x=240, y=223) -pyportal.splash.append(date_label) -pyportal.splash.append(time_label) +pyportal.root_group.append(date_label) +pyportal.root_group.append(time_label) # ISS trail trail_bitmap = displayio.Bitmap(3, 3, 1) trail_palette = displayio.Palette(1) trail_palette[0] = TRAIL_COLOR trail = displayio.Group() -pyportal.splash.append(trail) +pyportal.root_group.append(trail) # ISS location marker marker = displayio.Group() for r in range(MARK_SIZE - MARK_THICKNESS, MARK_SIZE): marker.append(Circle(0, 0, r, outline=MARK_COLOR)) -pyportal.splash.append(marker) +pyportal.root_group.append(marker) def get_location(width=WIDTH, height=HEIGHT): """Fetch current lat/lon, convert to (x, y) tuple scaled to width/height.""" diff --git a/PyPortal/PyPortal_LIFX_Controller/code.py b/PyPortal/PyPortal_LIFX_Controller/code.py index ebe489e89..139722e78 100755 --- a/PyPortal/PyPortal_LIFX_Controller/code.py +++ b/PyPortal/PyPortal_LIFX_Controller/code.py @@ -9,7 +9,8 @@ Brent Rubell for Adafruit Industries, 2019 """ -import os + +from os import getenv import board import displayio @@ -26,10 +27,17 @@ # import lifx library import adafruit_lifx -secrets = { - "ssid" : os.getenv("CIRCUITPY_WIFI_SSID"), - "password" : os.getenv("CIRCUITPY_WIFI_PASSWORD"), -} +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # ESP32 SPI esp32_cs = DigitalInOut(board.ESP_CS) @@ -37,8 +45,8 @@ esp32_reset = DigitalInOut(board.ESP_RESET) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) -status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # These pins are used as both analog and digital! XL, XR and YU must be analog # and digital capable. YD just need to be digital @@ -49,7 +57,7 @@ # Set this to your LIFX personal access token in settings.toml # (to obtain a token, visit: https://cloud.lifx.com/settings) -lifx_token = os.getenv("LIFX_TOKEN") +lifx_token = getenv("LIFX_TOKEN") # Initialize the LIFX API Helper lifx = adafruit_lifx.LIFX(wifi, lifx_token) diff --git a/PyPortal/PyPortal_LastFM/code.py b/PyPortal/PyPortal_LastFM/code.py index 53197d910..2be34fff8 100644 --- a/PyPortal/PyPortal_LastFM/code.py +++ b/PyPortal/PyPortal_LastFM/code.py @@ -7,26 +7,35 @@ and display it on a screen If you can find something that spits out JSON data, we can display it! """ + +from os import getenv import time import board from adafruit_pyportal import PyPortal -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Set up where we'll be fetching data from DATA_SOURCE = "http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&limit=1&format=json" CAPTION = "www.last.fm/user" # If we have an access token, we can query more often -if 'lfm_username' in secrets: - DATA_SOURCE += "&user="+secrets['lfm_username'] - CAPTION += "/"+secrets['lfm_username'] -if 'lfm_key' in secrets: - DATA_SOURCE += "&api_key="+secrets['lfm_key'] +lfm_username = getenv("lfm_username") +lfm_key = getenv("lfm_key") +if lfm_username: + DATA_SOURCE += "&user=" + lfm_username + CAPTION += "/" + lfm_username +if lfm_key: + DATA_SOURCE += "&api_key=" + lfm_key print(DATA_SOURCE) # Total number of plays diff --git a/PyPortal/PyPortal_LeagueLevel/code.py b/PyPortal/PyPortal_LeagueLevel/code.py index c8e178895..8d32d9c05 100644 --- a/PyPortal/PyPortal_LeagueLevel/code.py +++ b/PyPortal/PyPortal_LeagueLevel/code.py @@ -5,20 +5,33 @@ """ This project will access the League of Legends API, grab a Summoner's Level and display it on a screen. -You'll need a Riot API key in your secrets.py file +You'll need a Riot API key in your settings.toml file If you can find something that spits out JSON data, we can display it! """ -import os + +from os import getenv import time import board from adafruit_pyportal import PyPortal +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) + #Choose a valid Summoner name SUMMONER_NAME = "RiotSchmick" # Set up where we'll be fetching data from DATA_SOURCE = "https://na1.api.riotgames.com/lol/summoner/v4/summoners/by-name/"+SUMMONER_NAME -DATA_SOURCE += "?api_key=" + os.getenv("LEAGUE_TOKEN") +DATA_SOURCE += "?api_key=" + getenv("LEAGUE_TOKEN") DATA_LOCATION = ["summonerLevel"] CAPTION = "SUMMONER "+SUMMONER_NAME diff --git a/PyPortal/PyPortal_MQTT_Control/code.py b/PyPortal/PyPortal_MQTT_Control/code.py index b32ea9a2f..5ed7810d2 100644 --- a/PyPortal/PyPortal_MQTT_Control/code.py +++ b/PyPortal/PyPortal_MQTT_Control/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import board import displayio import busio @@ -18,14 +19,19 @@ import adafruit_touchscreen import adafruit_minimqtt.adafruit_minimqtt as MQTT -# ------------- WiFi ------------- # +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# ------------- WiFi ------------- # # If you are using a board with pre-defined ESP32 Pins: esp32_cs = DigitalInOut(board.ESP_CS) @@ -34,8 +40,8 @@ spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) -status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # ------- Sensor Setup ------- # # init. the temperature sensor @@ -234,10 +240,10 @@ def message(client, topic, message): # Set up a MiniMQTT Client client = MQTT.MQTT( - broker=secrets["broker"], + broker=getenv("mqtt_broker"), port=1883, - username=secrets["user"], - password=secrets["pass"], + username=getenv("mqtt_username"), + password=getenv("mqtt_password"), socket_pool=pool, ssl_context=ssl_context, ) diff --git a/PyPortal/PyPortal_MQTT_Control/secrets.py b/PyPortal/PyPortal_MQTT_Control/secrets.py deleted file mode 100644 index 2a4b3fce5..000000000 --- a/PyPortal/PyPortal_MQTT_Control/secrets.py +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Anne Barela for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -secrets = { - 'ssid' : '_your_wifi_ssid_', - 'password' : '_your_wifi_password_', - 'broker' : '_your_mqtt_broker_url_or_ip', - 'user' : '_your_mqtt_broker_username_', - 'pass' : '_your_mqtt_broker_password_' - } diff --git a/PyPortal/PyPortal_MQTT_Control/settings.toml b/PyPortal/PyPortal_MQTT_Control/settings.toml new file mode 100644 index 000000000..7dd5a1575 --- /dev/null +++ b/PyPortal/PyPortal_MQTT_Control/settings.toml @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: 2020 Anne Barela for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# This file is where you keep private settings, passwords, and tokens! +# If you put them in the code you risk committing that info or sharing it + +CIRCUITPY_WIFI_SSID="your-wifi-ssid" +CIRCUITPY_WIFI_PASSWORD="your-wifi-password" +mqtt_broker="your-mqtt-broker-url-or-ip" +mqtt_username="your-mqtt-broker-username" +mqtt_password="your-mqtt-broker-password" diff --git a/PyPortal/PyPortal_Mirror_Display/code.py b/PyPortal/PyPortal_Mirror_Display/code.py index 0f8ccb1cc..de8ac5efd 100644 --- a/PyPortal/PyPortal_Mirror_Display/code.py +++ b/PyPortal/PyPortal_Mirror_Display/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import sys import time import board @@ -11,12 +12,17 @@ sys.path.append(cwd) import openweather_graphics # pylint: disable=wrong-import-position -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Use cityname, country code where countrycode is ISO3166 format. # E.g. "New York, US" or "London, GB" @@ -24,7 +30,7 @@ # Set up where we'll be fetching data from DATA_SOURCE = "http://api.openweathermap.org/data/2.5/weather?q="+LOCATION -DATA_SOURCE += "&appid="+secrets['openweather_token'] +DATA_SOURCE += "&appid=" + getenv('openweather_token') # You'll need to get a token from openweather.org, looks like 'b6907d289e10d714a6e88b30761fae22' DATA_LOCATION = [] @@ -41,7 +47,7 @@ display.rotation = 270 # instantiate the openweather_graphics class -gfx = openweather_graphics.OpenWeather_Graphics(pyportal.splash, am_pm=True, celsius=False) +gfx = openweather_graphics.OpenWeather_Graphics(pyportal.root_group, am_pm=True, celsius=False) # time keeping for refreshing screen icons and weather information localtile_refresh = None diff --git a/PyPortal/PyPortal_Mirror_Display/openweather_graphics.py b/PyPortal/PyPortal_Mirror_Display/openweather_graphics.py index 4ab5f2909..8e4983f1c 100644 --- a/PyPortal/PyPortal_Mirror_Display/openweather_graphics.py +++ b/PyPortal/PyPortal_Mirror_Display/openweather_graphics.py @@ -129,11 +129,7 @@ def set_icon(self, filename): if not filename: return # we're done, no icon desired - if self._icon_file: - self._icon_file.close() - self._icon_file = open(filename, "rb") - - icon = displayio.OnDiskBitmap(self._icon_file) + icon = displayio.OnDiskBitmap(filename) self._icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) self._icon_group.append(self._icon_sprite) diff --git a/PyPortal/PyPortal_MogwaiClock/code.py b/PyPortal/PyPortal_MogwaiClock/code.py index f4168375f..dbf8dc3ad 100644 --- a/PyPortal/PyPortal_MogwaiClock/code.py +++ b/PyPortal/PyPortal_MogwaiClock/code.py @@ -45,7 +45,7 @@ time_textarea.x = 0 time_textarea.y = 130 time_textarea.color = 0xFF0000 -pyportal.splash.append(time_textarea) +pyportal.root_group.append(time_textarea) # To help us know if we've changed the times, print them out! gremlin_hour, gremlin_min = gremlin_time[3:5] diff --git a/PyPortal/PyPortal_NeoPixel_Color_Picker/code.py b/PyPortal/PyPortal_NeoPixel_Color_Picker/code.py index f5960ec78..919e58347 100755 --- a/PyPortal/PyPortal_NeoPixel_Color_Picker/code.py +++ b/PyPortal/PyPortal_NeoPixel_Color_Picker/code.py @@ -63,7 +63,7 @@ style=Button.SHADOWROUNDRECT, fill_color=spot['color'], outline_color=0x222222, name=spot['label']) - pyportal.splash.append(button) + pyportal.root_group.append(button) buttons.append(button) mode = 0 diff --git a/PyPortal/PyPortal_NeoPixel_Color_Picker/secrets.py b/PyPortal/PyPortal_NeoPixel_Color_Picker/secrets.py deleted file mode 100755 index 2bc3ff875..000000000 --- a/PyPortal/PyPortal_NeoPixel_Color_Picker/secrets.py +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-FileCopyrightText: 2019 Kattni Rembor for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -# This file is where you keep secret settings, passwords, and tokens! -# If you put them in the code you risk committing that info or sharing it - -secrets = { - } diff --git a/PyPortal/PyPortal_OpenWeather/code.py b/PyPortal/PyPortal_OpenWeather/code.py index b9b2299b1..e4c2dd5c1 100644 --- a/PyPortal/PyPortal_OpenWeather/code.py +++ b/PyPortal/PyPortal_OpenWeather/code.py @@ -7,6 +7,8 @@ weather for your location... and display it on a screen! if you can find something that spits out JSON data, we can display it """ + +from os import getenv import sys import time import board @@ -15,12 +17,17 @@ sys.path.append(cwd) import openweather_graphics # pylint: disable=wrong-import-position -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Use cityname, country code where countrycode is ISO3166 format. # E.g. "New York, US" or "London, GB" @@ -28,7 +35,7 @@ # Set up where we'll be fetching data from DATA_SOURCE = "http://api.openweathermap.org/data/2.5/weather?q="+LOCATION -DATA_SOURCE += "&appid="+secrets['openweather_token'] +DATA_SOURCE += "&appid=" + getenv('openweather_token') # You'll need to get a token from openweather.org, looks like 'b6907d289e10d714a6e88b30761fae22' DATA_LOCATION = [] @@ -40,7 +47,7 @@ status_neopixel=board.NEOPIXEL, default_bg=0x000000) -gfx = openweather_graphics.OpenWeather_Graphics(pyportal.splash, am_pm=True, celsius=False) +gfx = openweather_graphics.OpenWeather_Graphics(pyportal.root_group, am_pm=True, celsius=False) localtile_refresh = None weather_refresh = None diff --git a/PyPortal/PyPortal_OpenWeather/openweather_graphics.py b/PyPortal/PyPortal_OpenWeather/openweather_graphics.py index 5cd8376f7..8baa6cb98 100644 --- a/PyPortal/PyPortal_OpenWeather/openweather_graphics.py +++ b/PyPortal/PyPortal_OpenWeather/openweather_graphics.py @@ -130,16 +130,7 @@ def set_icon(self, filename): if not filename: return # we're done, no icon desired - # CircuitPython 6 & 7 compatible - if self._icon_file: - self._icon_file.close() - self._icon_file = open(filename, "rb") - icon = displayio.OnDiskBitmap(self._icon_file) - self._icon_sprite = displayio.TileGrid( - icon, pixel_shader=getattr(icon, 'pixel_shader', displayio.ColorConverter())) - - # # CircuitPython 7+ compatible - # icon = displayio.OnDiskBitmap(filename) - # self._icon_sprite = displayio.TileGrid(icon, pixel_shader=background.pixel_shader) + icon = displayio.OnDiskBitmap(filename) + self._icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) self._icon_group.append(self._icon_sprite) diff --git a/PyPortal/PyPortal_Philips_Hue_Controller/code.py b/PyPortal/PyPortal_Philips_Hue_Controller/code.py index 9e12aab05..1473c028c 100644 --- a/PyPortal/PyPortal_Philips_Hue_Controller/code.py +++ b/PyPortal/PyPortal_Philips_Hue_Controller/code.py @@ -7,7 +7,8 @@ Brent Rubell for Adafruit Industries, 2019 """ -import os + +from os import getenv import board import displayio @@ -23,9 +24,17 @@ # Import Philips Hue Bridge from adafruit_hue import Bridge -secrets = dict() -secrets["ssid"] = os.getenv("CIRCUITPY_WIFI_SSID") -secrets["password"] = os.getenv("CIRCUITPY_WIFI_PASSWORD") +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # ESP32 SPI esp32_cs = DigitalInOut(board.ESP_CS) @@ -33,13 +42,13 @@ esp32_reset = DigitalInOut(board.ESP_RESET) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) -status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) -# Attempt to load bridge username and IP address from secrets.py +# Attempt to load bridge username and IP address from settings.toml try: - username = os.getenv("HUE_USERNAME") - bridge_ip = os.getenv("BRIDGE_IP") + username = getenv("HUE_USERNAME") + bridge_ip = getenv("BRIDGE_IP") my_bridge = Bridge(wifi, bridge_ip, username) except: # Perform first-time bridge setup diff --git a/PyPortal/PyPortal_Quarantine_Clock/code.py b/PyPortal/PyPortal_Quarantine_Clock/code.py index 06144e5f8..91788e3c4 100755 --- a/PyPortal/PyPortal_Quarantine_Clock/code.py +++ b/PyPortal/PyPortal_Quarantine_Clock/code.py @@ -68,13 +68,13 @@ label_day = label.Label(font_large, color=LABEL_DAY_COLOR) label_day.x = board.DISPLAY.width // 7 label_day.y = 80 -pyportal.splash.append(label_day) +pyportal.root_group.append(label_day) # Set up label for the time label_time = label.Label(font_small, color=LABEL_TIME_COLOR) label_time.x = board.DISPLAY.width // 4 label_time.y = 150 -pyportal.splash.append(label_time) +pyportal.root_group.append(label_time) refresh_time = None while True: diff --git a/PyPortal/PyPortal_Quarantine_Clock/month_clock/code.py b/PyPortal/PyPortal_Quarantine_Clock/month_clock/code.py index 8101046ca..5ea33ae07 100644 --- a/PyPortal/PyPortal_Quarantine_Clock/month_clock/code.py +++ b/PyPortal/PyPortal_Quarantine_Clock/month_clock/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import board import busio @@ -13,12 +14,17 @@ from adafruit_bitmap_font import bitmap_font from adafruit_display_text import label -try: - from secrets import secrets -except ImportError: - print("""WiFi settings are kept in secrets.py, please add them there! -the secrets dictionary must contain 'ssid' and 'password' at a minimum""") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Label colors LABEL_DAY_COLOR = 0xFFFFFF @@ -88,7 +94,7 @@ print("Connecting to AP...") while not esp.is_connected: try: - esp.connect_AP(secrets['ssid'], secrets['password']) + esp.connect_AP(ssid, password) except RuntimeError as e: print("could not connect to AP, retrying: ", e) continue @@ -103,13 +109,13 @@ label_month = label.Label(font_large, color=LABEL_DAY_COLOR) label_month.x = board.DISPLAY.width // 10 label_month.y = 80 -pyportal.splash.append(label_month) +pyportal.root_group.append(label_month) # Set up label for the time label_time = label.Label(font_small, color=LABEL_TIME_COLOR) label_time.x = board.DISPLAY.width // 3 label_time.y = 150 -pyportal.splash.append(label_time) +pyportal.root_group.append(label_time) refresh_time = None while True: @@ -117,7 +123,7 @@ if (not refresh_time) or (time.monotonic() - refresh_time) > 3600: try: print("Getting new time from internet...") - pyportal.get_local_time(secrets['timezone']) + pyportal.get_local_time(getenv('timezone')) refresh_time = time.monotonic() # set the_time the_time = time.localtime() diff --git a/PyPortal/PyPortal_Remote/code.py b/PyPortal/PyPortal_Remote/code.py index 7a1c24af9..8fe00cdfa 100644 --- a/PyPortal/PyPortal_Remote/code.py +++ b/PyPortal/PyPortal_Remote/code.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2019 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT +from os import getenv import time import math import board @@ -13,6 +14,18 @@ import adafruit_touchscreen import adafruit_imageload +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) + # Set up the touchscreen ts = adafruit_touchscreen.Touchscreen( board.TOUCH_XL, @@ -23,13 +36,6 @@ size=(320, 240), ) -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise - # If you are using a board with pre-defined ESP32 Pins: esp32_cs = DigitalInOut(board.ESP_CS) esp32_ready = DigitalInOut(board.ESP_BUSY) @@ -38,9 +44,9 @@ spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) -status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) +status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Set the ip of your Roku here ip = "192.168.1.3" diff --git a/PyPortal/PyPortal_Smart_Switch/code.py b/PyPortal/PyPortal_Smart_Switch/code.py index 804647782..5517cd2e1 100644 --- a/PyPortal/PyPortal_Smart_Switch/code.py +++ b/PyPortal/PyPortal_Smart_Switch/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import gc import board @@ -20,6 +21,21 @@ from adafruit_minimqtt import MQTT +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + DISPLAY_COLOR = 0x006600 SWITCH_COLOR = 0x008800 SWITCH_FILL_COLOR = 0xffffff @@ -39,15 +55,8 @@ def get_local_timestamp(location=None): """Fetch and "set" the local time of this microcontroller to the local time at the location, using an internet time API. :param str location: Your city and country, e.g. ``"New York, US"``. """ - # pylint: enable=line-too-long api_url = None - try: - aio_username = secrets['aio_username'] - aio_key = secrets['aio_key'] - except KeyError: - raise KeyError("\n\nOur time service requires a login/password to rate-limit. Please register for a free adafruit.io account and place the user/key in your secrets file under 'aio_username' and 'aio_key'")# pylint: disable=line-too-long - - location = secrets.get('timezone', location) + location = getenv('timezone', location) if location: print("Getting time for timezone", location) api_url = (TIME_SERVICE + "&tz=%s") % (aio_username, aio_key, location) @@ -70,7 +79,7 @@ def get_local_timestamp(location=None): tzseconds += tzminutes * 60 print(seconds + tzseconds, tzoffset, tzhours, tzminutes) except KeyError: - raise KeyError("Was unable to lookup the time, try setting secrets['timezone'] according to http://worldtimeapi.org/timezones") # pylint: disable=line-too-long + raise KeyError("Was unable to lookup the time, try setting timezone in your settings.toml according to http://worldtimeapi.org/timezones") # pylint: disable=line-too-long # now clean up response.close() @@ -95,11 +104,11 @@ def __init__(self, pin, my_pyportal): self.switch.direction = digitalio.Direction.OUTPUT rect = RoundRect(SWITCHX, SWITCHY, 31, 60, 16, outline=SWITCH_COLOR, fill=SWITCH_FILL_COLOR, stroke=3) - my_pyportal.splash.append(rect) + my_pyportal.root_group.append(rect) self.circle_on = Circle(SWITCHX + 15, SWITCHY + 16, 10, fill=SWITCH_FILL_COLOR) - my_pyportal.splash.append(self.circle_on) + my_pyportal.root_group.append(self.circle_on) self.circle_off = Circle(SWITCHX + 15, SWITCHY + 42, 10, fill=DISPLAY_COLOR) - my_pyportal.splash.append(self.circle_off) + my_pyportal.root_group.append(self.circle_off) # turn switch on or off def enable(self, enable): @@ -140,7 +149,7 @@ def __init__(self, my_pyportal): self.text_areas = create_text_areas(text_area_configs) self.text_areas[2].text = "starting..." for ta in self.text_areas: - self.pyportal.splash.append(ta) + self.pyportal.root_group.append(ta) def adjust_backlight(self, force=False): """Check light level. Adjust the backlight and background image if it's dark.""" @@ -157,7 +166,7 @@ def tick(self, now): # Update the time print("update the time") self.update_time = int(now) - self.snapshot_time = get_local_timestamp(secrets['timezone']) + self.snapshot_time = get_local_timestamp(getenv("timezone")) self.current_time = time.localtime(self.snapshot_time) else: self.current_time = time.localtime(int(now) - self.update_time + self.snapshot_time) @@ -185,8 +194,8 @@ def tick(self, now): def connected(client, userdata, flags, rc): # This function will be called when the client is connected # successfully to the broker. - onoff_feed = secrets['aio_username'] + '/feeds/' + FEED_NAME - print('Connected to Adafruit IO! Listening for topic changes on %s' % onoff_feed) + onoff_feed = f"{aio_username}/feeds/{FEED_NAME}" + print(f"Connected to Adafruit IO! Listening for topic changes on {onoff_feed}") # Subscribe to all changes on the onoff_feed. client.subscribe(onoff_feed) @@ -205,13 +214,6 @@ def message(client, topic, message): ############################################ -try: - from secrets import secrets -except ImportError: - print("""WiFi settings are kept in secrets.py, please add them there! -the secrets dictionary must contain 'ssid' and 'password' at a minimum""") - raise - esp32_cs = digitalio.DigitalInOut(board.ESP_CS) esp32_ready = digitalio.DigitalInOut(board.ESP_BUSY) esp32_reset = digitalio.DigitalInOut(board.ESP_RESET) @@ -257,7 +259,7 @@ def message(client, topic, message): print("Connecting to AP...") while not esp.is_connected: try: - esp.connect_AP(secrets['ssid'], secrets['password']) + esp.connect_AP(ssid, password) except RuntimeError as e: print("could not connect to AP, retrying: ",e) continue @@ -265,14 +267,15 @@ def message(client, topic, message): print("My IP address is", esp.pretty_ip(esp.ip_address)) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager( - esp, secrets, debug = True) +wifi = adafruit_esp32spi_wifimanager.WiFiManager( + esp, ssid, password, debug=True +) # Set up a MiniMQTT Client mqtt_client = MQTT(broker='io.adafruit.com', - username=secrets['aio_username'], - password=secrets['aio_key'], + username=aio_username, + password=aio_key, network_manager=wifi, socket_pool=pool, ssl_context=ssl_context) diff --git a/PyPortal/PyPortal_Smart_Switch/secrets.py b/PyPortal/PyPortal_Smart_Switch/secrets.py deleted file mode 100644 index 56c9c2dd4..000000000 --- a/PyPortal/PyPortal_Smart_Switch/secrets.py +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-FileCopyrightText: 2019 Kattni Rembor for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -# This file is where you keep secret settings, passwords, and tokens! -# If you put them in the code you risk committing that info or sharing it - -secrets = { - 'ssid' : 'CHANGE ME', - 'password' : 'CHANGE ME', - # leave blank or use timezone from # http://worldtimeapi.org/timezones - 'timezone' : '', - 'aio_username' : 'CHANGE ME', - 'aio_key' : 'CHANGE ME', -} diff --git a/PyPortal/PyPortal_Smart_Switch/settings.toml b/PyPortal/PyPortal_Smart_Switch/settings.toml new file mode 100644 index 000000000..5bbf8b275 --- /dev/null +++ b/PyPortal/PyPortal_Smart_Switch/settings.toml @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: 2019 Kattni Rembor for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# This file is where you keep private settings, passwords, and tokens! +# If you put them in the code you risk committing that info or sharing it + +CIRCUITPY_WIFI_SSID="your-wifi-ssid" +CIRCUITPY_WIFI_PASSWORD="your-wifi-password" +ADAFRUIT_AIO_USERNAME="my_username" +ADAFRUIT_AIO_KEY="my_key" +timezone="" # leave blank or use timezone from # http://worldtimeapi.org/timezones diff --git a/PyPortal/PyPortal_Smart_Thermometer/code.py b/PyPortal/PyPortal_Smart_Thermometer/code.py index b32efa04e..e7fc0af61 100755 --- a/PyPortal/PyPortal_Smart_Thermometer/code.py +++ b/PyPortal/PyPortal_Smart_Thermometer/code.py @@ -10,6 +10,8 @@ Author: Brent Rubell for Adafruit Industries, 2019 """ + +from os import getenv import time import board import neopixel @@ -27,12 +29,20 @@ # rate at which to refresh the pyportal screen, in seconds PYPORTAL_REFRESH = 2 -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) # PyPortal ESP32 Setup esp32_cs = DigitalInOut(board.ESP_CS) @@ -40,21 +50,11 @@ esp32_reset = DigitalInOut(board.ESP_RESET) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) -status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) - -# Set your Adafruit IO Username and Key in secrets.py -# (visit io.adafruit.com if you need to create an account, -# or if you need your Adafruit IO key.) -try: - ADAFRUIT_IO_USER = secrets['aio_username'] - ADAFRUIT_IO_KEY = secrets['aio_key'] -except KeyError: - raise KeyError('To use this code, you need to include your Adafruit IO username \ -and password in a secrets.py file on the CIRCUITPY drive.') +status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Create an instance of the IO_HTTP client -io = IO_HTTP(ADAFRUIT_IO_USER, ADAFRUIT_IO_KEY, wifi) +io = IO_HTTP(aio_username, aio_key, wifi) # Get the temperature feed from Adafruit IO temperature_feed = io.get_feed('temperature') diff --git a/PyPortal/PyPortal_Smart_Thermometer/thermometer_helper.py b/PyPortal/PyPortal_Smart_Thermometer/thermometer_helper.py index 1786f253e..de1cf1158 100644 --- a/PyPortal/PyPortal_Smart_Thermometer/thermometer_helper.py +++ b/PyPortal/PyPortal_Smart_Thermometer/thermometer_helper.py @@ -135,13 +135,6 @@ def set_icon(self, filename): if self._icon_file: self._icon_file.close() - # CircuitPython 6 & 7 compatible - # self._icon_file = open(filename, "rb") - # icon = displayio.OnDiskBitmap(self._icon_file) - # self._icon_sprite = displayio.TileGrid(icon, - # pixel_shader=getattr(icon, 'pixel_shader', displayio.ColorConverter())) - - # # CircuitPython 7+ compatible icon = displayio.OnDiskBitmap(filename) self._icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) diff --git a/PyPortal/PyPortal_TOTP_Friend/code.py b/PyPortal/PyPortal_TOTP_Friend/code.py index 933b3c921..da7f838ef 100644 --- a/PyPortal/PyPortal_TOTP_Friend/code.py +++ b/PyPortal/PyPortal_TOTP_Friend/code.py @@ -36,12 +36,11 @@ # How long to stay on if not in always_on mode ON_SECONDS = 60 -# Get totp keys from a secrets.py file +# Get totp_keys from a totp_keys.py file try: - from secrets import secrets + from totp_keys import totp_keys except ImportError: - print("TOTP keys are kept in secrets.py, please add them there!") - raise + print("TOTP info not found in totp_keys.py, please add them there!") # Initialize PyPortal Display display = board.DISPLAY @@ -228,13 +227,13 @@ def display_otp_key(secret_name, secret_otp): print("Monotonic time", mono_time) # Add buttons to the interface -assert len(secrets['totp_keys']) < 6, "This code can only display 5 keys at a time" +assert len(totp_keys) < 6, "This code can only display 5 keys at a time" # generate buttons buttons = [] btn_x = 5 -for i in secrets['totp_keys']: +for i in totp_keys: button = Button(name=i[0], x=btn_x, y=175, width=60, height=60, label=i[0].strip(" "), @@ -264,7 +263,7 @@ def display_otp_key(secret_name, secret_otp): countdown = ON_SECONDS # current button state, defaults to first item in totp_keys -current_button = secrets['totp_keys'][0][0] +current_button = totp_keys[0][0] buttons[0].selected = True while ALWAYS_ON or (countdown > 0): @@ -295,7 +294,7 @@ def display_otp_key(secret_name, secret_otp): for i, b in enumerate(buttons): if b.contains(p): b.selected = True - for name, secret in secrets['totp_keys']: + for name, secret in totp_keys: # check if button name is the same as a key name if b.name == name: current_button = name @@ -305,7 +304,7 @@ def display_otp_key(secret_name, secret_otp): else: b.selected = False else: - for name, secret in secrets['totp_keys']: + for name, secret in totp_keys: if current_button == name: # Generate OTP otp = generate_otp(unix_time // 30, secret) diff --git a/PyPortal/PyPortal_TOTP_Friend/secrets.py b/PyPortal/PyPortal_TOTP_Friend/secrets.py deleted file mode 100755 index 19cd6267c..000000000 --- a/PyPortal/PyPortal_TOTP_Friend/secrets.py +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-FileCopyrightText: 2019 Brent Rubell for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -# This file is where you keep secret settings, passwords, and tokens! -# If you put them in the code you risk committing that info or sharing it - -secrets = { - 'totp_keys' : [("Discord ", "JBSWY3DPEHPK3PXP"), - ("Gmail", "JBSWY3DPEHPK3PZP"), - ("GitHub", "JBSWY5DZEHPK3PXP"), - ("Adafruit", "JBSWY6DZEHPK3PXP"), - ("Outlook", "JBSWY7DZEHPK3PXP")] - } diff --git a/PyPortal/PyPortal_TOTP_Friend/totp_keys.py b/PyPortal/PyPortal_TOTP_Friend/totp_keys.py new file mode 100644 index 000000000..b700732a5 --- /dev/null +++ b/PyPortal/PyPortal_TOTP_Friend/totp_keys.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2019 Brent Rubell for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# This file contains totp codes! +# If you put them in the code you risk committing that info or sharing it + +totp_keys = [ + ("Discord ", "JBSWY3DPEHPK3PXP"), + ("Gmail", "JBSWY3DPEHPK3PZP"), + ("GitHub", "JBSWY5DZEHPK3PXP"), + ("Adafruit", "JBSWY6DZEHPK3PXP"), + ("Outlook", "JBSWY7DZEHPK3PXP"), +] diff --git a/PyPortal/PyPortal_Tides/admiralty_tides/code.py b/PyPortal/PyPortal_Tides/admiralty_tides/code.py index 35eae1c1c..2a3a7c42e 100644 --- a/PyPortal/PyPortal_Tides/admiralty_tides/code.py +++ b/PyPortal/PyPortal_Tides/admiralty_tides/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import json import board @@ -9,12 +10,17 @@ from adafruit_bitmap_font import bitmap_font from adafruit_display_text.label import Label -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) #--| USER CONFIG |-------------------------- STATION_ID = "0245" # tide location, find yours from admiralty website/ @@ -30,7 +36,7 @@ # determine the current working directory needed so we know where to find files cwd = ("/"+__file__).rsplit('/', 1)[0] pyportal = PyPortal(url=DATA_SOURCE, - headers={"Ocp-Apim-Subscription-Key":secrets['Ocp-Apim-Subscription-Key']}, + headers={"Ocp-Apim-Subscription-Key": getenv('Ocp-Apim-Subscription-Key')}, json_path=DATA_LOCATION, status_neopixel=board.NEOPIXEL, default_bg=cwd+"/images/tides_bg.bmp") @@ -55,7 +61,7 @@ # Add all the labels to the display for label in HI_LABELS + LO_LABELS + [DATE_LABEL]: - pyportal.splash.append(label) + pyportal.root_group.append(label) def get_tide_info(): """Fetch JSON tide time info and return it.""" diff --git a/PyPortal/PyPortal_Tides/admiralty_tides_graphical/code.py b/PyPortal/PyPortal_Tides/admiralty_tides_graphical/code.py index b36ae2981..60103925d 100644 --- a/PyPortal/PyPortal_Tides/admiralty_tides_graphical/code.py +++ b/PyPortal/PyPortal_Tides/admiralty_tides_graphical/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import json import board @@ -10,12 +11,17 @@ from adafruit_bitmap_font import bitmap_font from adafruit_display_text.label import Label -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) #--| USER CONFIG |-------------------------- STATION_ID = "0245" # tide location, find yours from admiralty website @@ -44,7 +50,7 @@ bg_image_path = "/images/tides_bg_graph.bmp" pyportal = PyPortal(url=DATA_SOURCE, - headers={"Ocp-Apim-Subscription-Key":secrets['Ocp-Apim-Subscription-Key']}, + headers={"Ocp-Apim-Subscription-Key": getenv('Ocp-Apim-Subscription-Key')}, json_path=DATA_LOCATION, status_neopixel=board.NEOPIXEL, default_bg=cwd+bg_image_path) @@ -61,7 +67,7 @@ # Setup tide plot bitmap tide_plot = displayio.Bitmap(WIDTH, HEIGHT, 3) -pyportal.splash.append(displayio.TileGrid(tide_plot, pixel_shader=palette)) +pyportal.root_group.append(displayio.TileGrid(tide_plot, pixel_shader=palette)) # Setup font used for date and time date_font = bitmap_font.load_font(cwd+"/fonts/mono-bold-8.bdf") @@ -69,7 +75,7 @@ # Setup date label date_label = Label(date_font, text="0000-00-00", color=DATE_COLOR, x=7, y=14) -pyportal.splash.append(date_label) +pyportal.root_group.append(date_label) if board.board_id == "pyportal_titano": x_pos = 394 @@ -78,14 +84,14 @@ # Setup time label time_label = Label(date_font, text="00:00:00", color=TIME_COLOR, x=x_pos, y=14) -pyportal.splash.append(time_label) +pyportal.root_group.append(time_label) # Setup current time marker time_marker_bitmap = displayio.Bitmap(MARK_SIZE, MARK_SIZE, 3) for pixel in range(MARK_SIZE * MARK_SIZE): time_marker_bitmap[pixel] = 2 time_marker = displayio.TileGrid(time_marker_bitmap, pixel_shader=palette, x=-MARK_SIZE, y=-MARK_SIZE) -pyportal.splash.append(time_marker) +pyportal.root_group.append(time_marker) def get_tide_data(): """Fetch JSON tide data and return parsed results in a list.""" diff --git a/PyPortal/PyPortal_Tides/pp_tides/code.py b/PyPortal/PyPortal_Tides/pp_tides/code.py index 894795da2..2183802b5 100644 --- a/PyPortal/PyPortal_Tides/pp_tides/code.py +++ b/PyPortal/PyPortal_Tides/pp_tides/code.py @@ -51,7 +51,7 @@ # Add all the labels to the display for label in HI_LABELS + LO_LABELS + [DATE_LABEL]: - pyportal.graphics.splash.append(label) + pyportal.graphics.root_group.append(label) def get_tide_info(): diff --git a/PyPortal/PyPortal_Tides/pp_tides_graphical/code.py b/PyPortal/PyPortal_Tides/pp_tides_graphical/code.py index 3af7f13e8..24b1bc5fa 100644 --- a/PyPortal/PyPortal_Tides/pp_tides_graphical/code.py +++ b/PyPortal/PyPortal_Tides/pp_tides_graphical/code.py @@ -47,7 +47,7 @@ # Setup tide plot bitmap tide_plot = displayio.Bitmap(WIDTH, HEIGHT, 3) -pyportal.graphics.splash.append(displayio.TileGrid(tide_plot, pixel_shader=palette)) +pyportal.graphics.root_group.append(displayio.TileGrid(tide_plot, pixel_shader=palette)) # Setup font used for date and time date_font = bitmap_font.load_font("/fonts/mono-bold-8.bdf") @@ -55,11 +55,11 @@ # Setup date label date_label = Label(date_font, text="0000-00-00", color=DATE_COLOR, x=7, y=14) -pyportal.graphics.splash.append(date_label) +pyportal.graphics.root_group.append(date_label) # Setup time label time_label = Label(date_font, text="00:00:00", color=TIME_COLOR, x=234, y=14) -pyportal.graphics.splash.append(time_label) +pyportal.graphics.root_group.append(time_label) # Setup current time marker time_marker_bitmap = displayio.Bitmap(MARK_SIZE, MARK_SIZE, 3) @@ -67,7 +67,7 @@ time_marker = displayio.TileGrid( time_marker_bitmap, pixel_shader=palette, x=-MARK_SIZE, y=-MARK_SIZE ) -pyportal.graphics.splash.append(time_marker) +pyportal.graphics.root_group.append(time_marker) def get_tide_data(): diff --git a/PyPortal/PyPortal_Titano_Weather_Station/code.py b/PyPortal/PyPortal_Titano_Weather_Station/code.py index 9628aca9f..b752e94cd 100644 --- a/PyPortal/PyPortal_Titano_Weather_Station/code.py +++ b/PyPortal/PyPortal_Titano_Weather_Station/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time from calendar import alarms from calendar import timers @@ -12,20 +13,25 @@ from adafruit_pyportal import PyPortal import openweather_graphics # pylint: disable=wrong-import-position -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Use cityname, country code where countrycode is ISO3166 format. # E.g. "New York, US" or "London, GB" -LOCATION = secrets['location'] +LOCATION = getenv('location') # Set up where we'll be fetching data from -DATA_SOURCE = "http://api.openweathermap.org/data/2.5/weather?q="+LOCATION -DATA_SOURCE += "&appid="+secrets['openweather_token'] +DATA_SOURCE = "http://api.openweathermap.org/data/2.5/weather?q=" + LOCATION +DATA_SOURCE += "&appid=" + getenv('openweather_token') # You'll need to get a token from openweather.org, looks like 'b6907d289e10d714a6e88b30761fae22' DATA_LOCATION = [] @@ -50,20 +56,20 @@ # setting up the bitmaps for the alarms # sleep alarm -sleep_bitmap = displayio.OnDiskBitmap(open("/sleepBMP.bmp", "rb")) -sleep_tilegrid = displayio.TileGrid(sleep_bitmap, pixel_shader=getattr(sleep_bitmap, 'pixel_shader', displayio.ColorConverter())) +sleep_bitmap = displayio.OnDiskBitmap("/sleepBMP.bmp") +sleep_tilegrid = displayio.TileGrid(sleep_bitmap, pixel_shader=sleep_bitmap.pixel_shader) group_bed = displayio.Group() group_bed.append(sleep_tilegrid) # trash alarm -trash_bitmap = displayio.OnDiskBitmap(open("/trashBMP.bmp", "rb")) -trash_tilegrid = displayio.TileGrid(trash_bitmap, pixel_shader=getattr(trash_bitmap, 'pixel_shader', displayio.ColorConverter())) +trash_bitmap = displayio.OnDiskBitmap("/trashBMP.bmp") +trash_tilegrid = displayio.TileGrid(trash_bitmap, pixel_shader=trash_bitmap.pixel_shader) group_trash = displayio.Group() group_trash.append(trash_tilegrid) # meal alarm -eat_bitmap = displayio.OnDiskBitmap(open("/eatBMP.bmp", "rb")) -eat_tilegrid = displayio.TileGrid(eat_bitmap, pixel_shader=getattr(eat_bitmap, 'pixel_shader', displayio.ColorConverter())) +eat_bitmap = displayio.OnDiskBitmap("/eatBMP.bmp") +eat_tilegrid = displayio.TileGrid(eat_bitmap, pixel_shader=eat_bitmap.pixel_shader) group_eat = displayio.Group() group_eat.append(eat_tilegrid) @@ -127,7 +133,7 @@ alarm_gfx = [group_trash, group_bed, group_eat, group_eat, group_eat] # allows for the openweather_graphics to show -gfx = openweather_graphics.OpenWeather_Graphics(pyportal.splash, am_pm=True, celsius=False) +gfx = openweather_graphics.OpenWeather_Graphics(pyportal.root_group, am_pm=True, celsius=False) # state machines localtile_refresh = None @@ -244,13 +250,13 @@ print("pressed dismiss button") dismissed = True alarm = False - display.root_group = pyportal.splash + display.root_group = pyportal.root_group touched = time.monotonic() mode = mode if not switch_snooze.value and not phys_snooze: phys_snooze = True print("pressed snooze button") - display.root_group = pyportal.splash + display.root_group = pyportal.root_group snoozed = True alarm = False touched = time.monotonic() @@ -265,7 +271,7 @@ if touch: if snooze_buttons[button_mode].contains(touch) and not touch_button_snooze: print("Touched snooze") - display.root_group = pyportal.splash + display.root_group = pyportal.root_group touch_button_snooze = True snoozed = True alarm = False @@ -275,7 +281,7 @@ print("Touched dismiss") dismissed = True alarm = False - display.root_group = pyportal.splash + display.root_group = pyportal.root_group touch_button_dismiss = True touched = time.monotonic() mode = mode diff --git a/PyPortal/PyPortal_Titano_Weather_Station/openweather_graphics.py b/PyPortal/PyPortal_Titano_Weather_Station/openweather_graphics.py index 3aa815737..d711d52fa 100644 --- a/PyPortal/PyPortal_Titano_Weather_Station/openweather_graphics.py +++ b/PyPortal/PyPortal_Titano_Weather_Station/openweather_graphics.py @@ -178,14 +178,7 @@ def set_icon(self, filename): if self._icon_file: self._icon_file.close() - # CircuitPython 6 & 7 compatible - self._icon_file = open(filename, "rb") - icon = displayio.OnDiskBitmap(self._icon_file) - self._icon_sprite = displayio.TileGrid(icon, - pixel_shader=getattr(icon, 'pixel_shader', displayio.ColorConverter())) - - # # CircuitPython 7+ compatible - # icon = displayio.OnDiskBitmap(filename) - # self._icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) + icon = displayio.OnDiskBitmap(filename) + self._icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) self._icon_group.append(self._icon_sprite) diff --git a/PyPortal/PyPortal_Titano_Weather_Station/secrets.py b/PyPortal/PyPortal_Titano_Weather_Station/secrets.py deleted file mode 100644 index dd41b82bf..000000000 --- a/PyPortal/PyPortal_Titano_Weather_Station/secrets.py +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Liz Clark for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -# This file is where you keep secret settings, passwords, and tokens! -# If you put them in the code you risk committing that info or sharing it - -secrets = { - 'ssid' : 'your-ssid-here', - 'password' : 'your-password-here', - 'openweather_token' : 'your-openweather-token-here', - 'aio_username' : "your-aio-username-here", - 'aio_key' : 'your-aio-key-here', - 'location' : 'New York, US' -} diff --git a/PyPortal/PyPortal_Titano_Weather_Station/settings.toml b/PyPortal/PyPortal_Titano_Weather_Station/settings.toml new file mode 100644 index 000000000..fd18443ce --- /dev/null +++ b/PyPortal/PyPortal_Titano_Weather_Station/settings.toml @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2020 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# This file is where you keep private settings, passwords, and tokens! +# If you put them in the code you risk committing that info or sharing it + +CIRCUITPY_WIFI_SSID="your-wifi-ssid" +CIRCUITPY_WIFI_PASSWORD="your-wifi-password" +ADAFRUIT_AIO_USERNAME="my_username" +ADAFRUIT_AIO_KEY="my_key" +timezone="America/New_York" # http://worldtimeapi.org/timezones +openweather_token="my_openweather_token" +location="New York, US" \ No newline at end of file diff --git a/PyPortal/PyPortal_Trivia_Time/code.py b/PyPortal/PyPortal_Trivia_Time/code.py index 855c730c1..b4bf39ce6 100755 --- a/PyPortal/PyPortal_Trivia_Time/code.py +++ b/PyPortal/PyPortal_Trivia_Time/code.py @@ -121,12 +121,12 @@ def faceOff(timerLength): pyportal.preload_font() # speed things up by preloading font -pyportal.splash.append(loading_text_area) #loading... -pyportal.splash.append(q_text_area) -pyportal.splash.append(reveal_text_area) -pyportal.splash.append(timer_text_area) +pyportal.root_group.append(loading_text_area) #loading... +pyportal.root_group.append(q_text_area) +pyportal.root_group.append(reveal_text_area) +pyportal.root_group.append(timer_text_area) for textarea in ans_text_areas: - pyportal.splash.append(textarea) + pyportal.root_group.append(textarea) while True: # Load new question when screen is touched diff --git a/PyPortal/PyPortal_Twin_Peaks/code.py b/PyPortal/PyPortal_Twin_Peaks/code.py index 385c6746b..be572ae5a 100644 --- a/PyPortal/PyPortal_Twin_Peaks/code.py +++ b/PyPortal/PyPortal_Twin_Peaks/code.py @@ -14,11 +14,11 @@ cwd = ("/"+__file__).rsplit('/', 1)[0] -laura = (cwd+"/laura.bmp") +laura = cwd+"/laura.bmp" -woodsman = (cwd+"/woodsman.bmp") +woodsman = cwd+"/woodsman.bmp" -gottaLight = (cwd+"/gottaLight.wav") +gottaLight = cwd+"/gottaLight.wav" pyportal = PyPortal(default_bg=laura) diff --git a/PyPortal/PyPortal_UV_Index/code.py b/PyPortal/PyPortal_UV_Index/code.py index 82a231360..ea32a3b95 100644 --- a/PyPortal/PyPortal_UV_Index/code.py +++ b/PyPortal/PyPortal_UV_Index/code.py @@ -16,6 +16,7 @@ All text above must be included in any redistribution. """ +from os import getenv import time import json import board @@ -25,12 +26,17 @@ from adafruit_display_text.Label import Label from adafruit_bitmap_font import bitmap_font -try: - from secrets import secrets -except ImportError: - print("""WiFi settings are kept in secrets.py, please add them there! -the secrets dictionary must contain 'ssid' and 'password' at a minimum""") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) MAX_BAR_HEIGHT = 160 MARGIN = 10 @@ -48,7 +54,7 @@ BAR_FONT_FILE = cwd+'/fonts/Arial-Bold-12.bdf' #pylint:disable=line-too-long -url = 'https://enviro.epa.gov/enviro/efservice/getEnvirofactsUVHOURLY/ZIP/{0}/JSON'.format(secrets['zip']) +url = f"https://enviro.epa.gov/enviro/efservice/getEnvirofactsUVHOURLY/ZIP/{getenv('zip')}/JSON" #pylint:enable=line-too-long def extract_hour(date_time): @@ -74,7 +80,7 @@ def extract_date(date_time): caption_font=CAPTION_FONT_FILE) canvas = displayio.Group() -pyportal.splash.append(canvas) +pyportal.root_group.append(canvas) bar_font = bitmap_font.load_font(BAR_FONT_FILE) while True: diff --git a/PyPortal/PyPortal_UV_Index/secrets.py b/PyPortal/PyPortal_UV_Index/secrets.py deleted file mode 100644 index 6b3a03f08..000000000 --- a/PyPortal/PyPortal_UV_Index/secrets.py +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-FileCopyrightText: 2019 Kattni Rembor for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -# This file is where you keep secret settings, passwords, and tokens! -# If you put them in the code you risk committing that info or sharing it - -secrets = { - 'ssid' : 'CHANGE ME', - 'password' : 'CHANGE ME', - 'zip' : 'CHANGE ME', -} diff --git a/PyPortal/PyPortal_UV_Index/settings.toml b/PyPortal/PyPortal_UV_Index/settings.toml new file mode 100644 index 000000000..94ed10a98 --- /dev/null +++ b/PyPortal/PyPortal_UV_Index/settings.toml @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: 2019 Kattni Rembor for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# This file is where you keep private settings, passwords, and tokens! +# If you put them in the code you risk committing that info or sharing it + +CIRCUITPY_WIFI_SSID="your-wifi-ssid" +CIRCUITPY_WIFI_PASSWORD="your-wifi-password" +zip="CHANGE ME" diff --git a/PyPortal/PyPortal_User_Interface/.circuitpython.skip b/PyPortal/PyPortal_User_Interface/.circuitpython.skip deleted file mode 100644 index bf3e9ce8e..000000000 --- a/PyPortal/PyPortal_User_Interface/.circuitpython.skip +++ /dev/null @@ -1 +0,0 @@ -PyPortal_User_Interface/code.py 128: Line too long (117/100) (line-too-long) diff --git a/PyPortal/PyPortal_User_Interface/code.py b/PyPortal/PyPortal_User_Interface/code.py index 4feee76fe..543c98804 100644 --- a/PyPortal/PyPortal_User_Interface/code.py +++ b/PyPortal/PyPortal_User_Interface/code.py @@ -93,16 +93,8 @@ def set_image(group, filename): if not filename: return # we're done, no icon desired - # CircuitPython 6 & 7 compatible - image_file = open(filename, "rb") - image = displayio.OnDiskBitmap(image_file) - image_sprite = displayio.TileGrid( - image, pixel_shader=getattr(image, "pixel_shader", displayio.ColorConverter()) - ) - - # # CircuitPython 7+ compatible - # image = displayio.OnDiskBitmap(filename) - # image_sprite = displayio.TileGrid(image, pixel_shader=image.pixel_shader) + image = displayio.OnDiskBitmap(filename) + image_sprite = displayio.TileGrid(image, pixel_shader=image.pixel_shader) group.append(image_sprite) diff --git a/PyPortal/PyPortal_User_Interface/secrets.py b/PyPortal/PyPortal_User_Interface/secrets.py deleted file mode 100644 index 2a4b3fce5..000000000 --- a/PyPortal/PyPortal_User_Interface/secrets.py +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Anne Barela for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -secrets = { - 'ssid' : '_your_wifi_ssid_', - 'password' : '_your_wifi_password_', - 'broker' : '_your_mqtt_broker_url_or_ip', - 'user' : '_your_mqtt_broker_username_', - 'pass' : '_your_mqtt_broker_password_' - } diff --git a/PyPortal/PyPortal_Wakeup_Light/code.py b/PyPortal/PyPortal_Wakeup_Light/code.py index d5f64b39c..5a9c4f6a0 100644 --- a/PyPortal/PyPortal_Wakeup_Light/code.py +++ b/PyPortal/PyPortal_Wakeup_Light/code.py @@ -84,9 +84,9 @@ light_on_time_textarea = Label(info_font, color=light_on_time_color, x=light_on_time_position[0], y=light_on_time_position[1]) -pyportal.splash.append(time_textarea) -pyportal.splash.append(wakeup_time_textarea) -pyportal.splash.append(light_on_time_textarea) +pyportal.root_group.append(time_textarea) +pyportal.root_group.append(wakeup_time_textarea) +pyportal.root_group.append(light_on_time_textarea) while True: try: diff --git a/PyPortal/PyPortal_WeeklyCountdown/code.py b/PyPortal/PyPortal_WeeklyCountdown/code.py index 5f3ec465d..90cb48b5f 100644 --- a/PyPortal/PyPortal_WeeklyCountdown/code.py +++ b/PyPortal/PyPortal_WeeklyCountdown/code.py @@ -48,7 +48,7 @@ textarea.x = pos[0] textarea.y = pos[1] textarea.color = text_color - pyportal.splash.append(textarea) + pyportal.root_group.append(textarea) text_areas.append(textarea) refresh_time = None diff --git a/PyPortal/PyPortal_Wheres_My_Friend/code.py b/PyPortal/PyPortal_Wheres_My_Friend/code.py index 5f81b78b3..8fbf0b475 100755 --- a/PyPortal/PyPortal_Wheres_My_Friend/code.py +++ b/PyPortal/PyPortal_Wheres_My_Friend/code.py @@ -72,11 +72,10 @@ def set_image(image_group, filename): if image_group: image_group.pop() - image_file = open(filename, "rb") - image = displayio.OnDiskBitmap(image_file) + + image = displayio.OnDiskBitmap(filename) image_sprite = displayio.TileGrid(image, - pixel_shader=getattr(image, 'pixel_shader', - displayio.ColorConverter())) + pixel_shader=image.pixel_shader) image_sprite.x = IMAGE_SPRITE_X image_sprite.y = IMAGE_SPRITE_Y image_group.append(image_sprite) diff --git a/PyPortal/PyPortal_on_this_day/code.py b/PyPortal/PyPortal_on_this_day/code.py index b2137ffa2..4c323ff24 100644 --- a/PyPortal/PyPortal_on_this_day/code.py +++ b/PyPortal/PyPortal_on_this_day/code.py @@ -11,6 +11,7 @@ import time import board from adafruit_pyportal import PyPortal +from adafruit_pyportal.network import CONTENT_JSON cwd = ("/"+__file__).rsplit('/', 1)[0] # the current working directory (where this file is) @@ -34,7 +35,7 @@ def identity(x): default_bg = cwd + "/on_this_day_bg.bmp", text_font = cwd+"fonts/Arial-ItalicMT-17.bdf", text_transform = [identity]*6, # we do this so the date doesnt get commas - text_position=((10, 70), (10, 100), (10, 130),(60, 160), (105, 190), (10, 220)), + text_position=((10, 60), (10, 90), (10, 120),(60, 150), (105, 180), (10, 210)), text_color=(0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF), text_maxlen=(50, 50, 50, 50, 50, 50), # cut off characters ) @@ -54,13 +55,13 @@ def identity(x): print(url) response = None try: - response = pyportal.fetch(url) + response = pyportal.fetch(url, force_content_type = CONTENT_JSON) print("Response is", response) except RuntimeError as e: print("Some error occured, retrying! -", e) # Make a QR code from web reference - pyportal.show_QR(bytearray(response[5]), qr_size=3, + pyportal.show_QR(bytearray(response[5], "utf-8"), qr_size=3, x=220, y=10) # wait 10 minutes before running again diff --git a/PyPortal/Twitter_API/code.py b/PyPortal/Twitter_API/code.py new file mode 100644 index 000000000..9dd30f519 --- /dev/null +++ b/PyPortal/Twitter_API/code.py @@ -0,0 +1,68 @@ +# SPDX-FileCopyrightText: 2019 Dave Astels for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +Twitter API for PyPortal. + +Adafruit invests time and resources providing this open source code. +Please support Adafruit and open source hardware by purchasing +products from Adafruit! + +Written by Dave Astels for Adafruit Industries +Copyright (c) 2019 Adafruit Industries +Licensed under the MIT license. + +All text above must be included in any redistribution. +""" + +#pylint:disable=invalid-name + +from os import getenv +import time +import board +from adafruit_pyportal import PyPortal + +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) + +# Set this to the username you'd like to display tweets from +username = 'codewisdom' + +# determine the current working directory +# needed so we know where to find files +cwd = ("/"+__file__).rsplit('/', 1)[0] +url = 'https://api.twitter.com/1.1/statuses/user_timeline.json?count=1&screen_name=' + username + + +# Initialize the pyportal object and let us know what data to fetch and where +# to display it +pyportal = PyPortal(url=url, + json_path=(0, 'text'), + status_neopixel=board.NEOPIXEL, + default_bg=cwd + '/twitter_background.bmp', + text_font=cwd+'/fonts/Helvetica-Bold-16.bdf', + text_position=(20, 60), + text_color=0xFFFFFF, + text_wrap=35, + caption_text='@' + username, + caption_font=cwd+'/fonts/Helvetica-Bold-16.bdf', + caption_position=(5, 210), + caption_color=0x808080) + +# Set OAuth2.0 Bearer Token +bearer_token = getenv('twitter_bearer_token') +pyportal.set_headers({'Authorization': 'Bearer ' + bearer_token}) + +while True: + pyportal.fetch() + time.sleep(3600) # check every hour diff --git a/Twitter_API/fonts/Helvetica-Bold-16.bdf b/PyPortal/Twitter_API/fonts/Helvetica-Bold-16.bdf similarity index 100% rename from Twitter_API/fonts/Helvetica-Bold-16.bdf rename to PyPortal/Twitter_API/fonts/Helvetica-Bold-16.bdf diff --git a/Twitter_API/twitter_background.bmp b/PyPortal/Twitter_API/twitter_background.bmp similarity index 100% rename from Twitter_API/twitter_background.bmp rename to PyPortal/Twitter_API/twitter_background.bmp diff --git a/PyPortal/pyportal_pet_planter/code.py b/PyPortal/pyportal_pet_planter/code.py index e0dfaa66c..96b66ce75 100755 --- a/PyPortal/pyportal_pet_planter/code.py +++ b/PyPortal/pyportal_pet_planter/code.py @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: MIT -import os +from os import getenv import time import board @@ -21,6 +21,21 @@ from adafruit_seesaw.seesaw import Seesaw from simpleio import map_range +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + #---| User Config |--------------- # How often to poll the soil sensor, in seconds @@ -52,11 +67,6 @@ # the current working directory (where this file is) cwd = ("/"+__file__).rsplit('/', 1)[0] -secrets = { - "ssid" : os.getenv("CIRCUITPY_WIFI_SSID"), - "password" : os.getenv("CIRCUITPY_WIFI_PASSWORD"), -} - # Set up i2c bus i2c_bus = busio.I2C(board.SCL, board.SDA) @@ -70,8 +80,8 @@ spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) -status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Initialize PyPortal Display display = board.DISPLAY @@ -190,8 +200,8 @@ # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT(broker="io.adafruit.com", - username=os.getenv("AIO_USERNAME"), - password=os.getenv("AIO_KEY"), + username=aio_username, + password=aio_key, socket_pool=pool, ssl_context=ssl_context) diff --git a/PyPortal/pyportal_weather_station/code.py b/PyPortal/pyportal_weather_station/code.py index bba8cc2b5..b697fda17 100755 --- a/PyPortal/pyportal_weather_station/code.py +++ b/PyPortal/pyportal_weather_station/code.py @@ -10,6 +10,8 @@ Author: Brent Rubell for Adafruit Industries, 2019 """ + +from os import getenv import time import board import neopixel @@ -38,12 +40,20 @@ min_wind_speed = 0.0 max_wind_speed = 32.4 -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) # PyPortal ESP32 Setup esp32_cs = DigitalInOut(board.ESP_CS) @@ -51,14 +61,8 @@ esp32_reset = DigitalInOut(board.ESP_RESET) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) -status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) - -# Set your Adafruit IO Username and Key in secrets.py -# (visit io.adafruit.com if you need to create an account, -# or if you need your Adafruit IO key.) -ADAFRUIT_IO_USER = secrets['aio_username'] -ADAFRUIT_IO_KEY = secrets['aio_key'] +status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Create an instance of the Adafruit IO HTTP client io = IO_HTTP(ADAFRUIT_IO_USER, ADAFRUIT_IO_KEY, wifi) diff --git a/PyPortal/pyportal_weather_station/weatherstation_helper.py b/PyPortal/pyportal_weather_station/weatherstation_helper.py index 7a1b79b63..abd0f0579 100755 --- a/PyPortal/pyportal_weather_station/weatherstation_helper.py +++ b/PyPortal/pyportal_weather_station/weatherstation_helper.py @@ -132,18 +132,9 @@ def set_icon(self, filename): if not filename: return # we're done, no icon desired - if self._icon_file: - self._icon_file.close() - self._icon_file = open(filename, "rb") - icon = displayio.OnDiskBitmap(self._icon_file) - # CircuitPython 6 & 7 compatible + icon = displayio.OnDiskBitmap(filename) self._icon_sprite = displayio.TileGrid( icon, - pixel_shader=getattr(icon, 'pixel_shader', displayio.ColorConverter())) - - # # CircuitPython 7+ compatible - # self._icon_sprite = displayio.TileGrid( - # icon, - # pixel_shader=icon.pixel_shader) + pixel_shader=icon.pixel_shader) board.DISPLAY.refresh(target_frames_per_second=60) diff --git a/QT2040_Trinkey/bongo_cat/code.py b/QT2040_Trinkey/bongo_cat/code.py index 7f83748d1..43fb8b4f2 100644 --- a/QT2040_Trinkey/bongo_cat/code.py +++ b/QT2040_Trinkey/bongo_cat/code.py @@ -5,6 +5,7 @@ import time import board import displayio +import i2cdisplaybus import adafruit_displayio_ssd1306 import adafruit_imageload @@ -14,7 +15,7 @@ i2c = board.STEMMA_I2C() # oled oled_reset = board.D9 -display_bus = displayio.I2CDisplay(i2c, device_address=0x3D, reset=oled_reset) +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3D, reset=oled_reset) WIDTH = 128 HEIGHT = 64 display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=WIDTH, height=HEIGHT) diff --git a/QT_Py/AT_Py_ESP32-S2_Sunrise_Lamp/AIO/code.py b/QT_Py/AT_Py_ESP32-S2_Sunrise_Lamp/AIO/code.py index c69000306..0303e6c2f 100755 --- a/QT_Py/AT_Py_ESP32-S2_Sunrise_Lamp/AIO/code.py +++ b/QT_Py/AT_Py_ESP32-S2_Sunrise_Lamp/AIO/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import ssl import board @@ -22,26 +23,26 @@ NEO_CNT = 12 # neopixel count # ------------------------------------------------- +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + # Set up NeoPixels pixels = neopixel.NeoPixel(NEO_PIN, NEO_CNT) -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise - # Setup AIO time query URL TIME_URL = "https://io.adafruit.com/api/v2/" -TIME_URL += secrets["aio_username"] +TIME_URL += aio_username TIME_URL += "/integrations/time/strftime?x-aio-key=" -TIME_URL += secrets["aio_key"] +TIME_URL += aio_key TIME_URL += "&fmt=%25Y%3A%25m%3A%25d%3A%25H%3A%25M%3A%25S" # Connect to local network try: - wifi.radio.connect(secrets["ssid"], secrets["password"]) + wifi.radio.connect(ssid, password) except ConnectionError: print("Wifi failed to connect.") while True: diff --git a/QT_Py/AT_Py_ESP32-S2_Sunrise_Lamp/NTP/code.py b/QT_Py/AT_Py_ESP32-S2_Sunrise_Lamp/NTP/code.py index 948ef1636..7e1ece5e8 100755 --- a/QT_Py/AT_Py_ESP32-S2_Sunrise_Lamp/NTP/code.py +++ b/QT_Py/AT_Py_ESP32-S2_Sunrise_Lamp/NTP/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import time import board import rtc @@ -25,16 +26,13 @@ # Set up NeoPixels pixels = neopixel.NeoPixel(NEO_PIN, NEO_CNT) -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") # Connect to local network try: - wifi.radio.connect(secrets["ssid"], secrets["password"]) + wifi.radio.connect(ssid, password) except ConnectionError: print("Wifi failed to connect.") while True: diff --git a/QT_Py/NeoPixel_Moon_Phase_Clock/code.py b/QT_Py/NeoPixel_Moon_Phase_Clock/code.py new file mode 100644 index 000000000..9a67f893a --- /dev/null +++ b/QT_Py/NeoPixel_Moon_Phase_Clock/code.py @@ -0,0 +1,190 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# SPDX-License-Identifier: MIT + +import os +import time +import ssl +import board +import wifi +import socketpool +import microcontroller +import neopixel +import adafruit_requests +from adafruit_ticks import ticks_ms, ticks_add, ticks_diff + +# US Navy Astronomical Applications API for moon phase +# https://aa.usno.navy.mil/api +# Your location coordinates (adjust these to your location) +LATITUDE = 40.71 +LONGITUDE = -74.0060 +TIMEZONE = -5 # EST/EDT, adjust for your timezone +DST = True # Set to False if not in daylight saving time + +# Adafruit IO time server for current date, no API key needed +date_url = "https://io.adafruit.com/api/v2/time/ISO-8601" +# connect to wifi +try: + wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD')) +except TypeError: + print("Could not find WiFi info. Check your settings.toml file!") + raise +pool = socketpool.SocketPool(wifi.radio) +requests = adafruit_requests.Session(pool, ssl.create_default_context()) + +# neopixels, 49 total +OFF = (0, 0, 0) +ON = (255, 255, 255) +RED = (255,0,0) +pixel_pin = board.A3 +num_pixels = 49 +pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.1, auto_write=False) +pixels.fill(0) + +# phases of the moon +NEW_MOON = 0 +WAXING_CRESCENT = 1 +FIRST_QUARTER = 2 +WAXING_GIBBOUS = 3 +FULL_MOON = 4 +WANING_GIBBOUS = 5 +LAST_QUARTER = 6 +WANING_CRESCENT = 7 +DARK_MOON = 8 +RED_MOON = 9 +# strings that match return from API +phase_names = ["New Moon", "Waxing Crescent", "First Quarter", "Waxing Gibbous", + "Full Moon", "Waning Gibbous", "Last Quarter", "Waning Crescent","Dark Moon","Red Moon"] + +# functions for each moon phase to light up based on neopixel orientation +def set_new_moon(): + pixels.fill(OFF) + pixels.show() + +def set_waxing_crescent(): + pixels.fill(OFF) + for i in range(31, 44): + pixels[i] = ON + pixels.show() + +def set_first_quarter(): + pixels.fill(OFF) + for i in range(24, 49): + pixels[i] = ON + pixels.show() + +def set_waxing_gibbous(): + pixels.fill(OFF) + for i in range(0, 4): + pixels[i] = ON + for i in range(18, 49): + pixels[i] = ON + pixels.show() + +def set_full_moon(): + pixels.fill(ON) + pixels.show() + +def set_waning_gibbous(): + pixels.fill(OFF) + for i in range(0, 30): + pixels[i] = ON + for i in range(44, 49): + pixels[i] = ON + pixels.show() + +def set_last_quarter(): + pixels.fill(OFF) + for i in range(0, 24): + pixels[i] = ON + pixels.show() + +def set_waning_crescent(): + pixels.fill(OFF) + for i in range(5, 18): + pixels[i] = ON + pixels.show() + +def set_dark_moon(): + pixels.fill(OFF) + for i in range(9,14): + pixels[i] = ON + pixels.show() + +def set_red_moon(): + pixels.fill(RED) + pixels.show() + +# match functions with phases +phase_functions = { + NEW_MOON: set_new_moon, + WAXING_CRESCENT: set_waxing_crescent, + FIRST_QUARTER: set_first_quarter, + WAXING_GIBBOUS: set_waxing_gibbous, + FULL_MOON: set_full_moon, + WANING_GIBBOUS: set_waning_gibbous, + LAST_QUARTER: set_last_quarter, + WANING_CRESCENT: set_waning_crescent, + DARK_MOON: set_dark_moon, + RED_MOON: set_red_moon +} + +# test function, runs through all 8 in order +def demo_all_phases(delay=1): + for phase in range(9): + print(f"Setting phase: {phase_names[phase]}") + phase_functions[phase]() + time.sleep(delay) +demo_all_phases() + +# takes response from API, matches to function, runs function +def set_moon_phase(phase): + phase_lower = phase.lower() + error_check = 0 + for i, name in enumerate(phase_names): + if phase_lower == name.lower(): + error_check = 1 + phase_functions[i]() + print(f"Moon phase set to: {name}") + if error_check == 0: + print("ERROR") + set_red_moon() #error indicator if API responce is unexpected + +# time keeping, fetches API every 6 hours +timer_clock = ticks_ms() +timer = (6 * 3600) * 1000 +first_run = True + +while True: + try: + if first_run or ticks_diff(ticks_ms(), timer_clock) >= timer: + # get current date + date_response = requests.get(date_url) + iso_date = date_response.text.strip('"') + current_date = iso_date.split('T')[0] + date_response.close() + # build Navy API URL with parameters + # pylint: disable=line-too-long + url = f"https://aa.usno.navy.mil/api/rstt/oneday?date={current_date}&coords={LATITUDE},{LONGITUDE}&tz={TIMEZONE}" + if DST: + url += "&dst=true" + # get the JSON response + response = requests.get(url) + json_response = response.json() + # isolate phase info + current_phase = json_response["properties"]["data"]["curphase"] + print("-" * 40) + print(current_phase) + print("-" * 40) + # run function to update neopixels with current phase + set_moon_phase(current_phase) + response.close() + time.sleep(1) + first_run = False + # reset clock + timer_clock = ticks_add(timer_clock, timer) + # pylint: disable=broad-except + except Exception as e: + print("Error:\n", str(e)) + print("Resetting microcontroller in 10 seconds") + time.sleep(10) + microcontroller.reset() diff --git a/QT_Py/QT_Py_Cube/code.py b/QT_Py/QT_Py_Cube/code.py index e4d607439..3dbb97c7c 100644 --- a/QT_Py/QT_Py_Cube/code.py +++ b/QT_Py/QT_Py_Cube/code.py @@ -1,7 +1,8 @@ # SPDX-FileCopyrightText: 2022 Charlyn Gonda for Adafruit Industries # # SPDX-License-Identifier: MIT -from secrets import secrets + +from os import getenv import ssl import busio import board @@ -16,6 +17,21 @@ from cube import Cube +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + # Specify pins top_cin = board.A0 top_din = board.A1 @@ -42,9 +58,9 @@ connected = False while not connected: try: - wifi.radio.connect(secrets["ssid"], secrets["password"]) - print("Connected to %s!" % secrets["ssid"]) - print("My IP address is", wifi.radio.ipv4_address) + wifi.radio.connect(ssid, password) + print(f"Connected to {ssid}!") + print(f"My IP address is {wifi.radio.ipv4_address}") connected = True # pylint: disable=broad-except except Exception as error: @@ -54,8 +70,8 @@ # Setup for http requests pool = socketpool.SocketPool(wifi.radio) -REQUESTS = adafruit_requests.Session(pool, ssl.create_default_context()) -IO = IO_HTTP(secrets["aio_username"], secrets["aio_key"], REQUESTS) +requests = adafruit_requests.Session(pool, ssl.create_default_context()) +IO = IO_HTTP(aio_username, aio_key, requests) # Data for top pixels, will be updated by update_data() TOP_PIXELS_ON = [] diff --git a/QT_Py/QT_Py_ESP32_S2_RoundDisplay_Compass/calibrate.py b/QT_Py/QT_Py_ESP32_S2_RoundDisplay_Compass/calibrate.py new file mode 100644 index 000000000..8629e6216 --- /dev/null +++ b/QT_Py/QT_Py_ESP32_S2_RoundDisplay_Compass/calibrate.py @@ -0,0 +1,129 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +# +# Adapted from Liz Clark's calibrate.py in the QualiaS3 Compass learn guide +# https://learn.adafruit.com/qualia-s3-compass/code-the-compass +# +# Which was adapted from Gamblor21's calibrate.py in the Gamblor21_CircuitPython_AHRS library +# https://github.com/gamblor21/Gamblor21_CircuitPython_AHRS/blob/master/examples/calibrate.py +# +# Gyro will be calibrated first, followed by magnetometer +# Keep the board still for gyro, move around for magnetometer + +import time + +import board +from adafruit_lsm6ds.lsm6dsox import LSM6DSOX +import adafruit_lis3mdl + + +i2c = board.STEMMA_I2C() +accel_gyro = LSM6DSOX(i2c) +magnetometer = adafruit_lis3mdl.LIS3MDL(i2c) +MAG_MIN = [1000, 1000, 1000] +MAG_MAX = [-1000, -1000, -1000] + +def map_range(x, in_min, in_max, out_min, out_max): + """ + Maps a number from one range to another. + :return: Returns value mapped to new range + :rtype: float + """ + mapped = (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min + if out_min <= out_max: + return max(min(mapped, out_max), out_min) + + return min(max(mapped, out_max), out_min) + +def calibrate_gyro(): + """ + Calibrates gyroscope + Gyroscope values are in rads/s + """ + gx, gy, gz = accel_gyro.gyro + min_gx = gx + min_gy = gy + min_gz = gz + + max_gx = gx + max_gy = gy + max_gz = gz + + mid_gx = gx + mid_gy = gy + mid_gz = gz + + for _ in range(10): + gx, gy, gz = accel_gyro.gyro + + min_gx = min(min_gx, gx) + min_gy = min(min_gy, gy) + min_gz = min(min_gz, gz) + + max_gx = max(max_gx, gx) + max_gy = max(max_gy, gy) + max_gz = max(max_gz, gz) + + mid_gx = (max_gx + min_gx) / 2 + mid_gy = (max_gy + min_gy) / 2 + mid_gz = (max_gz + min_gz) / 2 + + print("Uncalibrated gyro: ", (gx, gy, gz)) + print("Calibrated gyro: ", (gx + mid_gx, gy + mid_gy, gz + mid_gz)) + print("Gyro calibration: ", (mid_gx, mid_gy, mid_gz)) + + time.sleep(1) + mid_gx = float(f"{mid_gx:.4f}") + mid_gy = float(f"{mid_gy:.4f}") + mid_gz = float(f"{mid_gz:.4f}") + _CAL = [mid_gx, mid_gy, mid_gz] + return _CAL + +def calibrate_mag(): + """ + Calibrates a magnometer + """ + countavg = 0 + x, y, z = magnetometer.magnetic + mag_vals = [x, y, z] + for i in range(3): + MAG_MIN[i] = min(MAG_MIN[i], mag_vals[i]) + MAG_MAX[i] = max(MAG_MAX[i], mag_vals[i]) + + for _ in range(10): + x, y, z = magnetometer.magnetic + mag_vals = [x, y, z] + + for i in range(3): + MAG_MIN[i] = min(MAG_MIN[i], mag_vals[i]) + MAG_MAX[i] = max(MAG_MAX[i], mag_vals[i]) + + countavg += 1 + print("Uncalibrated:", x, y, z) + cal_x = map_range(x, MAG_MIN[0], MAG_MAX[0], -1, 1) + cal_y = map_range(y, MAG_MIN[1], MAG_MAX[1], -1, 1) + cal_z = map_range(z, MAG_MIN[2], MAG_MAX[2], -1, 1) + print("Calibrate: ", cal_x, cal_y, cal_z) + print("MAG_MIN =", MAG_MIN) + print("MAG_MAX =", MAG_MAX) + + time.sleep(1) + return MAG_MIN, MAG_MAX + +print("Preparing gyroscope calibration. Keep board perfectly still on flat surface.") +time.sleep(5) +print("Starting gyroscope calibration..") +print() +GYRO_CAL = calibrate_gyro() +print("Gyroscope calibrated!") + +print("Preparing magnetometer calibration. Move board around in 3D space.") +time.sleep(5) +print("Starting magnetometer calibration..") +print() +MAG_MIN, MAG_MAX = calibrate_mag() +print("Magnetometer calibrated!") +print() +print("MAG_MIN =", MAG_MIN) +print("MAG_MAX =", MAG_MAX) +print("GYRO_CAL =", GYRO_CAL) diff --git a/QT_Py/QT_Py_ESP32_S2_RoundDisplay_Compass/code.py b/QT_Py/QT_Py_ESP32_S2_RoundDisplay_Compass/code.py new file mode 100644 index 000000000..50068826c --- /dev/null +++ b/QT_Py/QT_Py_ESP32_S2_RoundDisplay_Compass/code.py @@ -0,0 +1,169 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +# +# Adapted from QualiaS3 Compass Learn Guide by Liz Clark (Adafruit Industries) +# https://learn.adafruit.com/qualia-s3-compass/ + +import time +from math import atan2, degrees, radians +import adafruit_lis3mdl +import board +from adafruit_lsm6ds.lsm6dsox import LSM6DSOX +from gamblor21_ahrs import mahony +import bitmaptools +from adafruit_gc9a01a import GC9A01A +import adafruit_imageload +import displayio +from fourwire import FourWire + + +# change these values to your calibration values +MAG_MIN = [-75.1973, -22.5665, -34.5221] +MAG_MAX = [-1.2131, 68.1379, 20.8126] +GYRO_CAL = [-0.0038, -0.0026, -0.0011] + + +# use filter for more accurate, but slightly slower readings +# otherwise just reads from magnetometer +ahrs = True +center_x, center_y = 120, 120 + +i2c = board.STEMMA_I2C() +accel_gyro = LSM6DSOX(i2c) +magnetometer = adafruit_lis3mdl.LIS3MDL(i2c) +# Create the AHRS filter +ahrs_filter = mahony.Mahony(50, 5, 100) + +# Variable to account for the offset between raw heading values +# and the orientation of the display. +offset_angle = 90 + + +def map_range(x, in_min, in_max, out_min, out_max): + """ + Maps a value from one range to another. + + :param x: The value to map + :param in_min: The minimum value of the input range + :param in_max: The maximum value of the input range + :param out_min: The minimum value of the output range + :param out_max: The maximum value of the output range + + :return: The value mapped to the output range + """ + mapped = (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min + if out_min <= out_max: + return max(min(mapped, out_max), out_min) + + return min(max(mapped, out_max), out_min) + +last_heading = offset_angle +heading = offset_angle +last_update = time.monotonic() # last time we printed the yaw/pitch/roll values +timestamp = time.monotonic_ns() # used to tune the frequency to approx 100 Hz + +# Display Setup +spi = board.SPI() +tft_cs = board.TX +tft_dc = board.RX +displayio.release_displays() +display_bus = FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=None) +display = GC9A01A(display_bus, width=240, height=240) +display.rotation = 90 + +# group to hold all of our visual elements +main_group = displayio.Group() +display.root_group = main_group + +# load the compass rose background image +rose_bmp, rose_palette = adafruit_imageload.load("compass_rose.png") +rose_tg = displayio.TileGrid(bitmap=rose_bmp, pixel_shader=rose_palette) + +# bitmap for the pointer needle +pointer = displayio.Bitmap(5, 90, 2) + +# bitmap for erasing the pointer needle +pointer_eraser = displayio.Bitmap(5, 90, 1) + +# pointer needle palette, red foreground, transparent background +pointer_palette = displayio.Palette(2) +pointer_palette[0] = 0x000000 +pointer_palette[1] = 0xFF0000 +pointer_palette.make_transparent(0) +pointer.fill(1) + +# display sized bitmap to paste the rotated needle into +rotated_pointer = displayio.Bitmap(240, 240, 2) + +# tilegrid for the rotated pointer needle +pointer_tg = displayio.TileGrid(rotated_pointer, pixel_shader=pointer_palette) + +# add rose then pointer to the displaying group +main_group.append(rose_tg) +main_group.append(pointer_tg) + +while True: + # if it's time to take a compass reading from the mag/gyro + if (time.monotonic_ns() - timestamp) > 6500000: + # read magnetic data + mx, my, mz = magnetometer.magnetic + + # map it to the calibrated values + cal_x = map_range(mx, MAG_MIN[0], MAG_MAX[0], -1, 1) + cal_y = map_range(my, MAG_MIN[1], MAG_MAX[1], -1, 1) + cal_z = map_range(mz, MAG_MIN[2], MAG_MAX[2], -1, 1) + + # if using ahrs filter + if ahrs: + # get accel/gyro data + ax, ay, az, gx, gy, gz = accel_gyro.acceleration + accel_gyro.gyro + + # apply callibration offset + gx += GYRO_CAL[0] + gy += GYRO_CAL[1] + gz += GYRO_CAL[2] + + # update filter + ahrs_filter.update(gx, gy, -gz, ax, ay, az, cal_x, -cal_y, cal_z) + + # get yaw + yaw_degree = ahrs_filter.yaw + + # convert radians to degrees + heading = degrees(yaw_degree) + + else: # not using ahrs filter + # calculate heading from calibrated mag data + # and convert from radians to degrees + heading = degrees(atan2(cal_y, cal_x)) + + # save time to compare next iteration + timestamp = time.monotonic_ns() + + # if it's time to update the display + if time.monotonic() > last_update + 0.2: + # wrap negative heading values + if heading < 0: + heading += 360 + + # if the heading is sufficiently different from previous heading + if abs(last_heading - heading) >= 2: + #print(heading) + + # erase the previous pointer needle + bitmaptools.rotozoom(rotated_pointer, pointer_eraser, + ox=120, oy=120, + px=pointer.width // 2, py=pointer.height, + angle=radians(last_heading + offset_angle)) + + # draw the new pointer needle + bitmaptools.rotozoom(rotated_pointer, pointer, + ox=120, oy=120, + px=pointer.width // 2, py=pointer.height, + angle=radians(heading + offset_angle)) + + # set the previous heading to compare next iteration + last_heading = heading + + # set the last update time to compare next iteration + last_update = time.monotonic() diff --git a/QT_Py/QT_Py_ESP32_S2_RoundDisplay_Compass/compass_rose.png b/QT_Py/QT_Py_ESP32_S2_RoundDisplay_Compass/compass_rose.png new file mode 100644 index 000000000..41c782a04 Binary files /dev/null and b/QT_Py/QT_Py_ESP32_S2_RoundDisplay_Compass/compass_rose.png differ diff --git a/Quad_Color_eInk_Demos/Arduino_Quad_Color_ImageReader/.uno.test.only b/Quad_Color_eInk_Demos/Arduino_Quad_Color_ImageReader/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Quad_Color_eInk_Demos/Arduino_Quad_Color_ImageReader/Arduino_Quad_Color_ImageReader.ino b/Quad_Color_eInk_Demos/Arduino_Quad_Color_ImageReader/Arduino_Quad_Color_ImageReader.ino new file mode 100644 index 000000000..dccba00ed --- /dev/null +++ b/Quad_Color_eInk_Demos/Arduino_Quad_Color_ImageReader/Arduino_Quad_Color_ImageReader.ino @@ -0,0 +1,117 @@ +// SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Adafruit_ImageReader test for Adafruit E-Ink Breakouts. +// Demonstrates loading images from SD card or flash memory to the screen, +// to RAM, and how to query image file dimensions. +// Requires BMP file in root directory of QSPI Flash: +// blinka.bmp. + +#include // Core graphics library +#include "Adafruit_ThinkInk.h" +#include // SD card & FAT filesystem library +#include // SPI / QSPI flash library +#include // Image-reading functions + +// Comment out the next line to load from SPI/QSPI flash instead of SD card: +#define USE_SD_CARD + +#define EPD_DC 10 +#define EPD_CS 9 +#define EPD_BUSY 7 // can set to -1 to not use a pin (will wait a fixed delay) +#define SRAM_CS 6 +#define EPD_RESET 8 // can set to -1 and share with microcontroller Reset! +#define EPD_SPI &SPI // primary SPI +#define SD_CS 5 // SD card chip select + +// 2.13" Quadcolor EPD with JD79661 chipset +ThinkInk_213_Quadcolor_AJHE5 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY, + EPD_SPI); + +#if defined(USE_SD_CARD) + SdFat SD; // SD card filesystem + Adafruit_ImageReader_EPD reader(SD); // Image-reader object, pass in SD filesys +#else + +// SPI or QSPI flash filesystem (i.e. CIRCUITPY drive) + #if defined(__SAMD51__) || defined(NRF52840_XXAA) + Adafruit_FlashTransport_QSPI flashTransport(PIN_QSPI_SCK, PIN_QSPI_CS, + PIN_QSPI_IO0, PIN_QSPI_IO1, PIN_QSPI_IO2, PIN_QSPI_IO3); + #else + #if (SPI_INTERFACES_COUNT == 1 || defined(ADAFRUIT_CIRCUITPLAYGROUND_M0)) + Adafruit_FlashTransport_SPI flashTransport(SS, &SPI); + #else + Adafruit_FlashTransport_SPI flashTransport(SS1, &SPI1); + #endif + #endif + Adafruit_SPIFlash flash(&flashTransport); + FatVolume filesys; + Adafruit_ImageReader_EPD reader(filesys); // Image-reader, pass in flash filesys +#endif + +Adafruit_Image_EPD img; // An image loaded into RAM +int32_t width = 0, // BMP image dimensions + height = 0; + +void setup(void) { + + ImageReturnCode stat; // Status from image-reading functions + + Serial.begin(115200); + while(!Serial); // Wait for Serial Monitor before continuing + + display.begin(); + display.setRotation(3); + + // The Adafruit_ImageReader constructor call (above, before setup()) + // accepts an uninitialized SdFat or FatVolume object. This MUST + // BE INITIALIZED before using any of the image reader functions! + Serial.print(F("Initializing filesystem...")); + // SPI or QSPI flash requires two steps, one to access the bare flash + // memory itself, then the second to access the filesystem within... +#if defined(USE_SD_CARD) + // SD card is pretty straightforward, a single call... + if(!SD.begin(SD_CS, SD_SCK_MHZ(10))) { // Breakouts require 10 MHz limit due to longer wires + Serial.println(F("SD begin() failed")); + for(;;); // Fatal error, do not continue + } +#else + // SPI or QSPI flash requires two steps, one to access the bare flash + // memory itself, then the second to access the filesystem within... + if(!flash.begin()) { + Serial.println(F("flash begin() failed")); + for(;;); + } + if(!filesys.begin(&flash)) { + Serial.println(F("filesys begin() failed")); + for(;;); + } +#endif + Serial.println(F("OK!")); + + // Load full-screen BMP file 'blinka.bmp' at position (0,0) (top left). + // Notice the 'reader' object performs this, with 'epd' as an argument. + Serial.print(F("Loading blinka.bmp to canvas...")); + stat = reader.drawBMP((char *)"/blinka.bmp", display, 0, 0); + reader.printStatus(stat); // How'd we do? + display.display(); + + // Query the dimensions of image 'blinka.bmp' WITHOUT loading to screen: + Serial.print(F("Querying blinka.bmp image size...")); + stat = reader.bmpDimensions("blinka.bmp", &width, &height); + reader.printStatus(stat); // How'd we do? + if(stat == IMAGE_SUCCESS) { // If it worked, print image size... + Serial.print(F("Image dimensions: ")); + Serial.print(width); + Serial.write('x'); + Serial.println(height); + } + + delay(30 * 1000); // Pause 30 seconds before continuing because it's eInk + +} + +void loop() { + +} diff --git a/Quad_Color_eInk_Demos/Arduino_Quad_Color_ImageReader/blinka.bmp b/Quad_Color_eInk_Demos/Arduino_Quad_Color_ImageReader/blinka.bmp new file mode 100644 index 000000000..0cb13dc89 Binary files /dev/null and b/Quad_Color_eInk_Demos/Arduino_Quad_Color_ImageReader/blinka.bmp differ diff --git a/Quad_Color_eInk_Demos/Arduino_Quad_ThinkInk/.uno.test.only b/Quad_Color_eInk_Demos/Arduino_Quad_ThinkInk/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Quad_Color_eInk_Demos/Arduino_Quad_ThinkInk/Arduino_Quad_ThinkInk.ino b/Quad_Color_eInk_Demos/Arduino_Quad_ThinkInk/Arduino_Quad_ThinkInk.ino new file mode 100644 index 000000000..13a0417d5 --- /dev/null +++ b/Quad_Color_eInk_Demos/Arduino_Quad_ThinkInk/Arduino_Quad_ThinkInk.ino @@ -0,0 +1,116 @@ +// SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/*************************************************** + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_ThinkInk.h" + +#ifdef ARDUINO_ADAFRUIT_FEATHER_RP2040_THINKINK // detects if compiling for + // Feather RP2040 ThinkInk +#define EPD_DC PIN_EPD_DC // ThinkInk 24-pin connector DC +#define EPD_CS PIN_EPD_CS // ThinkInk 24-pin connector CS +#define EPD_BUSY PIN_EPD_BUSY // ThinkInk 24-pin connector Busy +#define SRAM_CS -1 // use onboard RAM +#define EPD_RESET PIN_EPD_RESET // ThinkInk 24-pin connector Reset +#define EPD_SPI &SPI1 // secondary SPI for ThinkInk +#else +#define EPD_DC 10 +#define EPD_CS 9 +#define EPD_BUSY 7 // can set to -1 to not use a pin (will wait a fixed delay) +#define SRAM_CS 6 +#define EPD_RESET 8 // can set to -1 and share with microcontroller Reset! +#define EPD_SPI &SPI // primary SPI +#endif + +// 2.13" Quadcolor EPD with JD79661 chipset +ThinkInk_213_Quadcolor_AJHE5 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY, + EPD_SPI); + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + Serial.println("Adafruit EPD full update test in red/yellow/black/white"); + display.begin(THINKINK_QUADCOLOR); +} + +void loop() { + Serial.println("Banner demo"); + display.clearBuffer(); + display.setTextSize(3); + display.setCursor((display.width() - 144) / 2, (display.height() - 24) / 2); + String text = "QuadColor"; + uint16_t colors[] = {EPD_BLACK, EPD_RED, EPD_YELLOW}; + + for (int i = 0; i < text.length(); i++) { + // Change color for every character (0: BLACK, 1: RED, 2: YELLOW, 3: BLACK, etc.) + display.setTextColor(colors[i % 3]); + display.print(text.charAt(i)); + } + display.display(); + + delay(15000); + + Serial.println("Color quadrant demo"); + display.clearBuffer(); + // Top-left quadrant - EPD_BLACK + display.fillRect(0, 0, display.width() / 2, display.height() / 2, EPD_BLACK); + // Top-right quadrant - EPD_RED + display.fillRect(display.width() / 2, 0, display.width() / 2, display.height() / 2, EPD_RED); + // Bottom-left quadrant - EPD_YELLOW + display.fillRect(0, display.height() / 2, display.width() / 2, display.height() / 2, EPD_YELLOW); + // Bottom-right quadrant - assume you have a 4th color like EPD_WHITE or another color + display.fillRect(display.width() / 2, display.height() / 2, display.width() / 2, display.height() / 2, EPD_WHITE); + + display.display(); + + delay(15000); + + Serial.println("Text demo"); + // large block of text + display.clearBuffer(); + display.setTextSize(1); + testdrawtext( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " + "adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, " + "fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor " + "neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet " + "ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a " + "tortor imperdiet posuere. ", + EPD_BLACK); + display.display(); + + delay(15000); + + display.clearBuffer(); + for (int16_t i = 0; i < display.width(); i += 4) { + display.drawLine(0, 0, i, display.height() - 1, EPD_BLACK); + } + for (int16_t i = 0; i < display.height(); i += 4) { + display.drawLine(display.width() - 1, 0, 0, i, EPD_RED); + } + for (int16_t i = 0; i < display.width(); i += 4) { + display.drawLine(display.width()/2, display.height()-1, i, 0, + EPD_YELLOW); + } + + display.display(); + + delay(15000); +} + +void testdrawtext(const char *text, uint16_t color) { + display.setCursor(0, 0); + display.setTextColor(color); + display.setTextWrap(true); + display.print(text); +} diff --git a/Quad_Color_eInk_Demos/Blinka_EPD_Demo/code.py b/Quad_Color_eInk_Demos/Blinka_EPD_Demo/code.py new file mode 100644 index 000000000..458fb4c2c --- /dev/null +++ b/Quad_Color_eInk_Demos/Blinka_EPD_Demo/code.py @@ -0,0 +1,79 @@ +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT +"""Blinka EPD Demo for the Quad Color eInk""" +import board +import digitalio +from PIL import Image, ImageDraw, ImageFont + +from adafruit_epd.epd import Adafruit_EPD +from adafruit_epd.jd79661 import Adafruit_JD79661 + +# create the spi device and pins we will need +spi = board.SPI() +ecs = digitalio.DigitalInOut(board.CE0) +dc = digitalio.DigitalInOut(board.D25) +srcs = None +rst = digitalio.DigitalInOut(board.D27) # can be None to not use this pin +busy = digitalio.DigitalInOut(board.D17) # can be None to not use this pin + +display = Adafruit_JD79661(122, 250, spi, + cs_pin=ecs, dc_pin=dc, sramcs_pin=srcs, + rst_pin=rst, busy_pin=busy) + +display.rotation = 3 +width = display.width +height = display.height +image = Image.new("RGB", (width, height)) + +WHITE = (0xFF, 0xFF, 0xFF) +YELLOW = (0xFF, 0xFF, 0x00) +RED = (0xFF, 0x00, 0x00) +BLACK = (0x00, 0x00, 0x00) + +# clear the buffer +display.fill(Adafruit_EPD.WHITE) + +# Get drawing object to draw on image. +draw = ImageDraw.Draw(image) +# empty it +draw.rectangle((0, 0, width, height), fill=WHITE) + +# Draw an outline box +draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE) + +# Draw some shapes. +# First define some constants to allow easy resizing of shapes. +padding = 5 +shape_width = 30 +top = padding +bottom = height - padding +# Move left to right keeping track of the current x position for drawing shapes. +x = padding +# Draw an ellipse. +draw.ellipse((x, top, x + shape_width, bottom), outline=YELLOW, fill=WHITE) +x += shape_width + padding +# Draw a rectangle. +draw.rectangle((x, top, x + shape_width, bottom), outline=RED, fill=BLACK) +x += shape_width + padding +# Draw a triangle. +draw.polygon( + [(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)], + outline=BLACK, + fill=RED, +) +x += shape_width + padding +# Draw an X. +draw.line((x, bottom, x + shape_width, top), fill=YELLOW) +draw.line((x, top, x + shape_width, bottom), fill=YELLOW) +x += shape_width + padding + +# Load default font. +font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20) + +draw.text((x, top), "Hello", font=font, fill=YELLOW) +draw.text((x, top + 20), "World!", font=font, fill=YELLOW) + +# Display image. +display.image(image) + +display.display() diff --git a/Quad_Color_eInk_Demos/Blinka_EPD_Pillow_Image_Demo/blinka.png b/Quad_Color_eInk_Demos/Blinka_EPD_Pillow_Image_Demo/blinka.png new file mode 100644 index 000000000..1482c9dd8 Binary files /dev/null and b/Quad_Color_eInk_Demos/Blinka_EPD_Pillow_Image_Demo/blinka.png differ diff --git a/Quad_Color_eInk_Demos/Blinka_EPD_Pillow_Image_Demo/code.py b/Quad_Color_eInk_Demos/Blinka_EPD_Pillow_Image_Demo/code.py new file mode 100644 index 000000000..10e6f74cb --- /dev/null +++ b/Quad_Color_eInk_Demos/Blinka_EPD_Pillow_Image_Demo/code.py @@ -0,0 +1,92 @@ +# SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +Image resizing and drawing using the Pillow Library for Quad Color eInk +""" +import board +import digitalio +from PIL import Image, ImageEnhance +from adafruit_epd.jd79661 import Adafruit_JD79661 + +# create the spi device and pins we will need +spi = board.SPI() +ecs = digitalio.DigitalInOut(board.CE0) +dc = digitalio.DigitalInOut(board.D25) +srcs = None +rst = digitalio.DigitalInOut(board.D27) # can be None to not use this pin +busy = digitalio.DigitalInOut(board.D17) # can be None to not use this pin + +# give them all to our driver +display = Adafruit_JD79661(122, 250, # 2.13" Quad-color display + spi, + cs_pin=ecs, + dc_pin=dc, + sramcs_pin=srcs, + rst_pin=rst, + busy_pin=busy, +) +display.rotation = 3 + +image = Image.open("blinka.png") + +# Scale the image to the smaller screen dimension +image_ratio = image.width / image.height +screen_ratio = display.width / display.height +if screen_ratio < image_ratio: + scaled_width = image.width * display.height // image.height + scaled_height = display.height +else: + scaled_width = display.width + scaled_height = image.height * display.width // image.width +image = image.resize((scaled_width, scaled_height), Image.BICUBIC) + +# Crop and center the image +x = scaled_width // 2 - display.width // 2 +y = scaled_height // 2 - display.height // 2 +image = image.crop((x, y, x + display.width, y + display.height)).convert("RGB") + +quad_colors = [ + (0, 0, 0), # Black + (255, 255, 255), # White + (255, 0, 0), # Red + (255, 255, 0), # Yellow +] +palette_image = Image.new('P', (1, 1)) + +# Create palette data - PIL expects 768 values (256 colors * 3 channels) +palette_data = [] +for color in quad_colors: + palette_data.extend(color) +# Fill remaining palette entries with black +for i in range(4, 256): + palette_data.extend([0, 0, 0]) + +palette_image.putpalette(palette_data) + +enhancer = ImageEnhance.Color(image) +image = enhancer.enhance(1.5) + +temp_image = image.quantize(palette=palette_image, dither=Image.Dither.FLOYDSTEINBERG) + +pixels = temp_image.load() +width, height = temp_image.size + +final_palette = Image.new('P', (1, 1)) +final_palette.putpalette(palette_data) +final_image = Image.new('P', (width, height)) +final_pixels = final_image.load() + +# Copy pixels, ensuring they use indices 0-3 +for y in range(height): + for x in range(width): + # Clamp pixel values to 0-3 range + final_pixels[x, y] = min(pixels[x, y], 3) + +final_image.putpalette(palette_data) + +# Convert back to RGB for display +image = final_image.convert('RGB') + +# Display image. +display.image(image) +display.display() diff --git a/README.md b/README.md index aa915102f..c0a78c015 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,9 @@ Starting in 2023, guides using a specific Adafruit board will be placed in a sub * PyLeap/ * PyPortal/ * QTPy/ +* Metro/ (all types) +* Matrix_Portal/ +* Crickits/ If a new product or project group is contemplated, contact Learn moderators for guidance. @@ -54,4 +57,4 @@ Adafruit_Learning_System_Guides, not a sub-directory): Adafruit Learning System code files should have author and license information conforming to the open [SPDX specification](https://www.iso.org/standard/81870.html). See [this page](https://learn.adafruit.com/contribute-to-the-adafruit-learning-system-with-git-and-github/add-author-and-license-information) for more. -Updated November 29, 2023 +Updated November 5, 2025 diff --git a/RP2040_PiCowbell_Timelapse/code.py b/RP2040_PiCowbell_Timelapse/code.py index 969bffb9a..c780603f4 100644 --- a/RP2040_PiCowbell_Timelapse/code.py +++ b/RP2040_PiCowbell_Timelapse/code.py @@ -13,6 +13,7 @@ import busio from adafruit_ticks import ticks_ms, ticks_add, ticks_diff import displayio +import fourwire from adafruit_neokey.neokey1x4 import NeoKey1x4 import adafruit_st7789 from adafruit_display_text import label @@ -33,7 +34,7 @@ i2c = busio.I2C(board.GP5, board.GP4) tft_cs = board.GP21 tft_dc = board.GP20 -display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=None) +display_bus = fourwire.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=None) display = adafruit_st7789.ST7789(display_bus, width=240, height=240, rowstart=80, rotation=0) gc.collect() diff --git a/Raspberry_Pi/Raspberry_Pi5_Edge_Model_Demos/SmolLM3.modelfile b/Raspberry_Pi/Raspberry_Pi5_Edge_Model_Demos/SmolLM3.modelfile new file mode 100644 index 000000000..b8ab473fa --- /dev/null +++ b/Raspberry_Pi/Raspberry_Pi5_Edge_Model_Demos/SmolLM3.modelfile @@ -0,0 +1,42 @@ +FROM hf.co/unsloth/SmolLM3-3B-128K-GGUF +TEMPLATE " +{{- $lastUserIdx := -1 }} +{{- range $i, $_ := .Messages }} +{{- if eq .Role "user" }}{{- $lastUserIdx = $i }}{{ end }} +{{- end -}} +<|im_start|>system +## Metadata + +Knowledge Cutoff Date: June 2025 +Today Date: {{ currentDate }} +Reasoning Mode: {{ if $.IsThinkSet }}{{ if $.Think }}/think{{ else }}/no_think{{ end }}{{ else }}/think{{ end }} + +{{ if .System }} +## Custom Instructions + +{{ .System }} + + +{{ end }} +{{- range $i, $_ := .Messages }} +{{- $last := eq (len (slice $.Messages $i)) 1 }} +{{- if eq .Role "user" }}<|im_start|>user +{{ .Content }}<|im_end|> +{{- else if eq .Role "assistant" }}<|im_start|>assistant +{{- if (and $.IsThinkSet (and .Thinking (or $last (gt $i $lastUserIdx)))) -}} +{{ .Thinking }} +{{- end }} +{{ .Content }} +{{- end }} +{{ if and (ne .Role "assistant") $last }}<|im_start|>assistant +{{- if and $.IsThinkSet (not $.Think) -}} + + + + +{{ end }} +{{ end }} +{{- end -}} +" +PARAMETER temperature 0.3 +PARAMETER top_p 0.9 \ No newline at end of file diff --git a/Raspberry_Pi/Raspberry_Pi5_Edge_Model_Demos/download_voices.sh b/Raspberry_Pi/Raspberry_Pi5_Edge_Model_Demos/download_voices.sh new file mode 100755 index 000000000..04886ccde --- /dev/null +++ b/Raspberry_Pi/Raspberry_Pi5_Edge_Model_Demos/download_voices.sh @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +python -m piper.download_voices es_MX-claude-high +python -m piper.download_voices de_DE-kerstin-low +python -m piper.download_voices fr_FR-upmc-medium +python -m piper.download_voices it_IT-paola-medium +python -m piper.download_voices pt_BR-jeff-medium +python -m piper.download_voices en_US-amy-medium diff --git a/Raspberry_Pi/Raspberry_Pi5_Edge_Model_Demos/make_weather_wardrobe_audio.py b/Raspberry_Pi/Raspberry_Pi5_Edge_Model_Demos/make_weather_wardrobe_audio.py new file mode 100755 index 000000000..b336cbb5f --- /dev/null +++ b/Raspberry_Pi/Raspberry_Pi5_Edge_Model_Demos/make_weather_wardrobe_audio.py @@ -0,0 +1,168 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import argparse +import json +from pathlib import Path +import os +import shutil +import wave +import requests +from ollama import chat +from ollama import ChatResponse +from piper import PiperVoice + +# pylint: disable=line-too-long +parser = argparse.ArgumentParser( + prog="python generate_translated_weather_audio.py", + description="Multi-Lingual Weather & Wardrobe Assistant - " + "Fetches weather conditions from weather.gov for a given set of location points. " + "Generates a wardrobe suggestion based on the weather conditions. " + "Translates the weather and wardrobe suggestion into one of 5 other languages. " + "Synthesizes a wave audio file narrating the weather and wardrobe info in " + "the specified language.", + epilog="Made with: SmolLM3 & Piper1-gpl", +) +parser.add_argument( + "-l", + "--language", + default="es", + help="The language to translate into. One of (de, es, fr, it, pt). Default is es.", +) +parser.add_argument( + "-p", + "--location-points", + default="36,33", + help="The weather.gov API location points to get weather for. Default is 36,33. " + "Visit https://api.weather.gov/points/{lat},{lon} to find location points " + "for GPS coordinates", +) +parser.add_argument( + "-e", + "--period", + default="current", + help="The weather period to consider, current or next. Default is current.", +) +parser.add_argument( + "-c", + "--cached", + action="store_true", + help="Use the cached weather data from forecast.json instead of fetching from the server.", +) +args = parser.parse_args() +language_name_map = { + "es": "spanish", + "de": "german", + "fr": "french", + "it": "italian", + "pt": "portuguese", +} + +language_voice_map = { + "es": "es_MX-claude-high.onnx", + "de": "de_DE-kerstin-low.onnx", + "fr": "fr_FR-upmc-medium.onnx", + "it": "it_IT-paola-medium.onnx", + "pt": "pt_BR-jeff-medium.onnx", +} +if args.language not in language_name_map.keys(): # pylint: disable=consider-iterating-dictionary + raise ValueError( + f"Invalid language {args.language}. Valid languages are {language_name_map.keys()}" + ) + +if args.period.lower() not in {"current", "cur", "next"}: + raise ValueError( + f"Invalid period {args.period}. Valid periods are 'current', 'next'" + ) + +replacements = {"mph": "miles per hour"} + +# latlng_lookup_url = "https://api.weather.gov/points/{lat},{lon}" +location_points = args.location_points + +if not args.cached: + weather_data = requests.get( + f"https://api.weather.gov/gridpoints/TOP/{location_points}/forecast", timeout=20 + ).json() + print("Fetched weather...") + + with open("forecast.json", "w") as f: + json.dump(weather_data, f) +else: + weather_data = json.loads(Path("forecast.json").read_text()) + print("Read cached weather...") +period_index = 0 +if args.period == "next": + period_index = 1 +elif args.period in {"cur", "current"}: + period_index = 0 + +period = weather_data["properties"]["periods"][period_index] + +english_weather = ( + f'Current Temperature is {period["temperature"]}{period["temperatureUnit"]}. ' +) +english_weather += f'{period["name"]} {period["detailedForecast"]}' + +for key, replacement in replacements.items(): + english_weather = english_weather.replace(key, replacement) + +print(f"english_weather: {english_weather}") + +print("Generating wardrobe suggestion...") +response: ChatResponse = chat( + model="translator-smollm3", + messages=[ + { + "role": "system", + "content": "You are a wardrobe assistant. Your job is to suggest some appropriate " + "clothes attire for a person to wear based on the weather. You can include clothing items " + "and accessories that are appropriate for the specified weather conditions. " + "Use positive and re-affirming language. Do not output any explanations, " + "only output the wardrobe suggestion. Do not summarize the weather." + "The wardrobe suggestion output should be no more than 2 sentences.", + }, + { + "role": "user", + "content": f"{english_weather}", + }, + ], +) + +print(response["message"]["content"]) +# combine weather and wardrobe suggestion +english_weather += " " + response["message"]["content"] + +print("Translating weather & wardrobe...") + +language = language_name_map[args.language] +response: ChatResponse = chat( + model="translator-smollm3", + messages=[ + { + "role": "system", + "content": "You are a translation assistant. The user is going to give you a short passage in english, " + f"please translate it to {language}. Output only the {language} translation of the input. " + "Do not output explanations, notes, or anything else. If there is not an exact literal translation, " + "just output the best fitting alternate word or phrase that you can. Do not explain anything, " + f"only output the translation. All output should be in {language}", + }, + { + "role": "user", + "content": f"{english_weather}", + }, + ], +) +translated_weather = response["message"]["content"] +print(translated_weather) + +print("Generating audio...") + +shutil.rmtree("sound_files", ignore_errors=True) +os.mkdir("sound_files") + +voice = PiperVoice.load(language_voice_map[args.language]) +with wave.open("sound_files/weather_and_wardrobe.wav", "wb") as wav_file: + voice.synthesize_wav(translated_weather, wav_file) + +print("Audio generation complete...") diff --git a/Raspberry_Pi/Raspberry_Pi5_Edge_Model_Demos/requirements.txt b/Raspberry_Pi/Raspberry_Pi5_Edge_Model_Demos/requirements.txt new file mode 100644 index 000000000..b4d99b49c --- /dev/null +++ b/Raspberry_Pi/Raspberry_Pi5_Edge_Model_Demos/requirements.txt @@ -0,0 +1,3 @@ +ollama +piper-tts +requests diff --git a/Raspberry_Pi/Raspberry_Pi5_Edge_Model_Demos/translate.py b/Raspberry_Pi/Raspberry_Pi5_Edge_Model_Demos/translate.py new file mode 100644 index 000000000..1fc082c84 --- /dev/null +++ b/Raspberry_Pi/Raspberry_Pi5_Edge_Model_Demos/translate.py @@ -0,0 +1,165 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# pylint: disable=line-too-long +import argparse +import json +import os +import sys +from pathlib import Path +import wave +from ollama import chat +from ollama import ChatResponse +from piper import PiperVoice + +translation_wavs_dir = Path("translation_wavs") + +if not translation_wavs_dir.exists(): + translation_wavs_dir.mkdir() + +history_file = Path("history.json") +if not history_file.exists(): + history_obj = {"history": []} + with open(history_file, "w") as f: + f.write(json.dumps(history_obj)) + +with open(history_file, "r") as f: + history_obj = json.loads(f.read()) + + +def save_history(): + with open(history_file, "w") as open_history_file: + open_history_file.write(json.dumps(history_obj)) + + +def get_translation_filepath(text): + filename = text.replace(" ", "_") + return str(translation_wavs_dir / Path(filename + ".wav")) + + +def create_history_entry(text, translated_text, language_choice): + new_entry = { + "input_text": text, + "translation_file": get_translation_filepath(text), + "translated_text": translated_text, + "language": language_choice, + } + return new_entry + + +def add_to_history(entry_obj): + history_obj["history"].append(entry_obj) + save_history() + + +def play_translation_wav(entry_obj): + print(f"{entry_obj['language']}: {entry_obj['translated_text']}") + os.system(f"aplay --disable-softvol {entry_obj['translation_file']}") + + +parser = argparse.ArgumentParser( + prog="translate.py", + description="Translates a word or phrase from english to another language and then speak the translation.", + epilog="Made with: SmolLM3 & Piper TTS.", +) + +language_name_map = { + "es": "spanish", + "de": "german", + "fr": "french", + "it": "italian", + "pt": "portuguese", +} + +language_voice_map = { + "es": "es_MX-claude-high.onnx", + "de": "de_DE-kerstin-low.onnx", + "fr": "fr_FR-upmc-medium.onnx", + "it": "it_IT-paola-medium.onnx", + "pt": "pt_BR-jeff-medium.onnx", +} + +parser.add_argument("input", nargs="?") +parser.add_argument("-l", "--language", default="es") +parser.add_argument("-r", "--replay", action="store_true") +parser.add_argument("-t", "--history", action="store_true") +args = parser.parse_args() +input_str = args.input + +if args.replay: + replay_num = None + try: + replay_num = int(args.input) + except (ValueError, TypeError): + if args.input is not None: + print("Replay number must be an integer.") + sys.exit() + + if replay_num is None: + chosen_entry = history_obj["history"][-1] + else: + index = len(history_obj["history"]) - replay_num + chosen_entry = history_obj["history"][index] + + play_translation_wav(chosen_entry) + sys.exit() + +if args.history: + for i, entry in enumerate(reversed(history_obj["history"])): + print( + f"{i+1}: {entry['language']} - {entry['input_text']} - {entry['translated_text']}" + ) + sys.exit() + + +if args.language not in language_name_map.keys(): # pylint: disable=consider-iterating-dictionary + raise ValueError( + f"Invalid language {args.language}. Valid languages are {language_name_map.keys()}" + ) + +language = language_name_map[args.language] + +for history_entry in history_obj["history"]: + if ( + history_entry["input_text"].lower() == input_str.lower() + and history_entry["language"] == args.language + ): + play_translation_wav(history_entry) + sys.exit() + +response: ChatResponse = chat( + model="translator-smollm3", + messages=[ + { + "role": "system", + "content": "You are a translation assistant. The user is going to give you a word or short phrase in english, " + f"please translate it to {language}. Output only the {language} translation of the input. Do not output " + "explanations, notes, or anything else. If there is not an exact literal translation, just output " + "the best fitting alternate word or phrase that you can. Do not explain anything, only output " + "the translation.", + }, + { + "role": "user", + "content": f"{input_str}", + }, + ], +) + +translation = response["message"]["content"] +# print(translation) +if "\n" in translation: + translation = translation.split("\n")[0] + if len(translation) == 0: + parts = translation.split("\n") + for part in parts: + if len(part) > 0: + translation = part + +history_entry = create_history_entry(input_str, translation, args.language) + +voice = PiperVoice.load(language_voice_map[args.language]) +with wave.open(history_entry["translation_file"], "wb") as wav_file: + voice.synthesize_wav(translation, wav_file) + +add_to_history(history_entry) +play_translation_wav(history_entry) diff --git a/Raspberry_Pi_Azure_IoT_Hub_Dashboard/featherTft_bme680/code.py b/Raspberry_Pi_Azure_IoT_Hub_Dashboard/featherTft_bme680/code.py index ceee73fa3..88592f92b 100644 --- a/Raspberry_Pi_Azure_IoT_Hub_Dashboard/featherTft_bme680/code.py +++ b/Raspberry_Pi_Azure_IoT_Hub_Dashboard/featherTft_bme680/code.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries # SPDX-License-Identifier: MIT +from os import getenv import json import time import digitalio @@ -17,18 +18,23 @@ from adafruit_display_text import bitmap_label, wrap_text_to_lines from adafruit_bitmap_font import bitmap_font from adafruit_azureiot import IoTHubDevice -import adafruit_bme680 from adafruit_lc709203f import LC709203F, PackSize +import adafruit_bme680 + +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) print("Connecting to WiFi...") -wifi.radio.connect(secrets["ssid"], secrets["password"]) +wifi.radio.connect(ssid, password) print("Connected to WiFi!") @@ -47,7 +53,7 @@ esp = None pool = socketpool.SocketPool(wifi.radio) # Create an IoT Hub device client and connect -device = IoTHubDevice(pool, esp, secrets["device_connection_string"]) +device = IoTHubDevice(pool, esp, getenv("device_connection_string")) print("Connecting to Azure IoT Hub...") diff --git a/Raspberry_Pi_Azure_IoT_Hub_Dashboard/qtPyEsp32S2_co2/code.py b/Raspberry_Pi_Azure_IoT_Hub_Dashboard/qtPyEsp32S2_co2/code.py index 01b98de0a..90f4bd9a8 100644 --- a/Raspberry_Pi_Azure_IoT_Hub_Dashboard/qtPyEsp32S2_co2/code.py +++ b/Raspberry_Pi_Azure_IoT_Hub_Dashboard/qtPyEsp32S2_co2/code.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries # SPDX-License-Identifier: MIT +from os import getenv import time import json import digitalio @@ -13,15 +14,20 @@ from adafruit_azureiot import IoTHubDevice import adafruit_scd4x -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) print("Connecting to WiFi...") -wifi.radio.connect(secrets["ssid"], secrets["password"]) +wifi.radio.connect(ssid, password) print("Connected to WiFi!") @@ -40,7 +46,7 @@ esp = None pool = socketpool.SocketPool(wifi.radio) # Create an IoT Hub device client and connect -device = IoTHubDevice(pool, esp, secrets["device_connection_string"]) +device = IoTHubDevice(pool, esp, getenv("device_connection_string")) print("Connecting to Azure IoT Hub...") diff --git a/Raspberry_Pi_Halloween_Costume_Detector/code.py b/Raspberry_Pi_Halloween_Costume_Detector/code.py new file mode 100644 index 000000000..afc9fc7af --- /dev/null +++ b/Raspberry_Pi_Halloween_Costume_Detector/code.py @@ -0,0 +1,236 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT +'''Raspberry Pi Halloween Costume Detector with OpenCV and Claude Vision API''' + +#!/usr/bin/python3 +import os +import subprocess +import time +import base64 +import wave +import cv2 +from picamera2 import Picamera2 +import anthropic +from piper import PiperVoice, SynthesisConfig +import board +import digitalio + +ANTHROPIC_API_KEY = "your-api-key-here" + +try: + username = os.getlogin() + print(f"The current user is: {username}") +except OSError: + print("Could not determine the login name.") + print("Consider checking environment variables like USER or LOGNAME.") + # Fallback to environment variables if os.getlogin() fails + username = os.environ.get('USER') or os.environ.get('LOGNAME') + if username: + print(f"The user from environment variable is: {username}") + else: + print("User information not found in environment variables either.") + +# Initialize LED +led = digitalio.DigitalInOut(board.D5) +led.direction = digitalio.Direction.OUTPUT +led.value = False # Start with LED off + +# Initialize detectors +upperbody_detector = cv2.CascadeClassifier( + "/usr/share/opencv4/haarcascades/haarcascade_upperbody.xml") +fgbg = cv2.createBackgroundSubtractorMOG2(detectShadows=False) + +# Initialize camera +cv2.startWindowThread() +picam2 = Picamera2() +picam2.configure(picam2.create_preview_configuration( + main={"format": 'XRGB8888', "size": (640, 480)})) +picam2.start() + +# Initialize Piper voice +voice = PiperVoice.load("/home/pi/en_US-joe-medium.onnx") +syn_config = SynthesisConfig( + volume=1.0, + length_scale=1.5, + noise_scale=1.2, + noise_w_scale=1.5, + normalize_audio=False, +) + +# Check for and create audio files if they don't exist +def create_audio_file_if_needed(filename, text): + """Create audio file if it doesn't exist""" + if not os.path.exists(filename): + print(f"Creating {filename}...") + with wave.open(filename, "wb") as wav: + voice.synthesize_wav(text, wav, syn_config=syn_config) + print(f"{filename} created!") + else: + print(f"{filename} already exists.") + +# Create the hello and halloween audio files +create_audio_file_if_needed("hello.wav", "Hello? Who goes there?") +create_audio_file_if_needed("halloween.wav", "Happy Halloween!") + +# Initialize Anthropic client +client = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY) +# set API key via the terminal as an environmental variable: +# export ANTHROPIC_API_KEY="your-api-key-here" + +# Detection parameters +MOTION_THRESHOLD = 100000 +COOLDOWN_SECONDS = 15 +last_capture_time = 0 +capture_delay = 5 +motion_frame_count = 0 +MOTION_FRAMES_REQUIRED = 5 + +def encode_image(image_path): + """Encode image to base64 for Claude API""" + with open(image_path, "rb") as image_file: + return base64.standard_b64encode(image_file.read()).decode("utf-8") + +def get_costume_joke(image_path): + """Send image to Claude and get dad joke about costume""" + print("Analyzing costume with Claude...") + + # Encode the image + image_data = encode_image(image_path) + + # Send to Claude API + message = client.messages.create( + model="claude-sonnet-4-5-20250929", + max_tokens=250, + messages=[ + { + "role": "user", + "content": [ + { + "type": "image", + "source": { + "type": "base64", + "media_type": "image/jpeg", + "data": image_data, + }, + }, + { + "type": "text", + "text": """Look at this image. + Your response must follow these rules exactly: + + 1. If you see a person in a Halloween costume, respond with ONLY a single-sentence cute, + family-friendly, encouraging, dad joke about the costume. Nothing else. + + 2. If you do NOT see a clear Halloween costume (empty room, unclear image, person in regular clothes, etc.), + respond with ONLY the character: 0 + + Examples of good responses: + - "Looks like that ghost costume is really boo-tiful!" + - "0" + - "I guess you could say that vampire costume really sucks... in a good way!" + + Do not add any explanations, commentary, or descriptions. Just the joke or just 0. + """ + } + ], + } + ], + ) + + # Extract the joke from the response + joke = message.content[0].text + print(f"Claude's joke: {joke}") + return joke +# pylint: disable=subprocess-run-check, broad-except +def play_audio_file(filename): + """Play a pre-existing audio file""" + print(f"Playing {filename}...") + subprocess.run(["su", username, "-c", f"aplay {filename}"]) + +def speak_joke(joke_text): + """Convert joke to speech and play it""" + print("Generating speech...") + + wav_file = "joke.wav" + + # Generate audio with Piper + with wave.open(wav_file, "wb") as wav: + voice.synthesize_wav(joke_text, wav, syn_config=syn_config) + + print("Playing audio...") + # Play the audio file (using aplay for Raspberry Pi) + subprocess.run(["su", username, "-c", f"aplay {wav_file}"]) + + # Optional: clean up the audio file after playing + # os.remove(wav_file) + +# Main loop +while True: + im = picam2.capture_array() + grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) + + # Check for motion + fgmask = fgbg.apply(im) + motion_amount = cv2.countNonZero(fgmask) + motion_detected = motion_amount > MOTION_THRESHOLD + + if motion_detected: + motion_frame_count += 1 + else: + motion_frame_count = 0 + + if motion_frame_count >= MOTION_FRAMES_REQUIRED: + # Detect upperbody + bodies = upperbody_detector.detectMultiScale(grey, 1.1, 3) + person_detected = len(bodies) > 0 + + # Draw rectangles + for (x, y, w, h) in bodies: + cv2.rectangle(im, (x, y), (x + w, y + h), (0, 255, 0), 2) + + # Process if person detected and cooldown passed + current_time = time.time() + if person_detected and (current_time - last_capture_time) > COOLDOWN_SECONDS: + print("Person detected!") + + # Turn on LED and play hello message + led.value = True + play_audio_file("hello.wav") + + im = picam2.capture_array() + # Capture image + timestamp = time.strftime("%Y%m%d-%H%M%S") + file = f"costume_{timestamp}.jpg" + cv2.imwrite(file, im) + print(f"\nPicture saved: {file}") + + try: + # Get joke from Claude + the_joke = get_costume_joke(file) + + # If Claude returns 0, use the halloween fallback + if the_joke.strip() == "0": + print("No costume detected, playing halloween.wav") + play_audio_file("halloween.wav") + else: + # Speak the joke + speak_joke(the_joke) + + except Exception as e: + print(f"Error: {e}") + # Fallback to halloween.wav if something goes wrong + play_audio_file("halloween.wav") + + # Turn off LED after processing + led.value = False + + last_capture_time = current_time + motion_frame_count = 0 + + # Show motion amount + cv2.putText(im, f"Motion: {motion_amount}", (10, 30), + cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + + cv2.imshow("Camera", im) + cv2.waitKey(1) diff --git a/Raspberry_Pi_KittenTTS/code.py b/Raspberry_Pi_KittenTTS/code.py new file mode 100644 index 000000000..055683962 --- /dev/null +++ b/Raspberry_Pi_KittenTTS/code.py @@ -0,0 +1,126 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import json +import time +import glob +import os +import tomllib +from datetime import datetime +import board +from digitalio import DigitalInOut, Direction, Pull +from adafruit_debouncer import Debouncer + + +from kittentts import KittenTTS +import soundfile as sf + + +print("initializing...") + +with open("weather_narrator.toml", "rb") as f: + config = tomllib.load(f) +voice = config.get("voice", None) +sound_device = config.get("sound_device", None) + +day_of_month_words = [ + "1st", + "2nd", + "3rd", + "4th", + "5th", + "6th", + "7th", + "8th", + "9th", + "10th", + "11th", + "12th", + "13th", + "14th", + "15th", + "16th", + "17th", + "18th", + "19th", + "20th", + "21st", + "22nd", + "23rd", + "24th", + "25th", + "26th", + "27th", + "28th", + "29th", + "30th", + "31st", +] + +button = DigitalInOut(board.D17) +button.direction = Direction.INPUT +button.pull = Pull.UP + +debounced_btn = Debouncer(button) + +with open("forecast.json", "r") as f: + forecast = json.load(f) + +m = KittenTTS("KittenML/kitten-tts-nano-0.2") + + +def generate_date_time_audio(date_obj): + replacements = { + "00": "oh clock", + "01": "oh 1", + "02": "oh 2", + "03": "oh 3", + "04": "oh 4", + "05": "oh 5", + "06": "oh 6", + "07": "oh 7", + "08": "oh 8", + "09": "oh 9", + } + + now_date_obj = datetime.now() + try: + os.remove("date.wav") + except FileNotFoundError: + pass + month = date_obj.strftime("%B") + day_word = day_of_month_words[date_obj.day - 1] + date_script = f"{month} {day_word}, {date_obj.year}." + + time_script = now_date_obj.strftime("%-I %M %p") + for key, val in replacements.items(): + time_script = time_script.replace(key, val) + + date_script += f" The time is: {time_script}." + audio = m.generate(date_script, voice=voice) + sf.write("date.wav", audio, 24000) + + +print("Press button to hear time and weather...") +while True: + debounced_btn.update() + if debounced_btn.fell: + print("just pressed") + + dt_format = "%Y-%m-%dT%H:%M:%S%z" + forecast_date_obj = datetime.strptime( + forecast["properties"]["periods"][0]["startTime"], dt_format + ) + + generate_date_time_audio(forecast_date_obj) + + files_to_read = glob.glob("sound_files/*.wav") + sorted_files_asc = sorted(files_to_read, key=os.path.getmtime) + sorted_files_asc.insert(0, "date.wav") + for file in sorted_files_asc: + if sound_device is None: + os.system(f"aplay {file}") + else: + os.system(f"aplay -D {sound_device} {file}") + + time.sleep(0.01) diff --git a/Raspberry_Pi_KittenTTS/generate_forecast.py b/Raspberry_Pi_KittenTTS/generate_forecast.py new file mode 100644 index 000000000..fdb59645d --- /dev/null +++ b/Raspberry_Pi_KittenTTS/generate_forecast.py @@ -0,0 +1,54 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import json +import os +import tomllib +import shutil +import requests +from kittentts import KittenTTS +import soundfile as sf + + +with open("weather_narrator.toml", "rb") as f: + config = tomllib.load(f) + +m = KittenTTS("KittenML/kitten-tts-nano-0.2") + +replacements = {"mph": "miles per hour"} + +# latlng_lookup_url = "https://api.weather.gov/points/{lat},{lon}" + +voice = config.get("voice", None) +location_points = config.get("location_points", "36,33") + +weather_data = requests.get( + f"https://api.weather.gov/gridpoints/TOP/{location_points}/forecast", timeout=20 +).json() +print("Got weather. Building script...") + +with open("forecast.json", "w") as f: + json.dump(weather_data, f) + +forecast_length = config.get("forecast_length", None) + +shutil.rmtree("sound_files", ignore_errors=True) +os.mkdir("sound_files") + +for i, period in enumerate(weather_data["properties"]["periods"]): + if forecast_length is None or i < forecast_length: + filename = period["name"].replace(" ", "_") + outstr = "" + if i == 0: + outstr += f'Current Temperature is {period["temperature"]} degrees. ' + outstr += f'{period["name"]} {period["detailedForecast"]}' + + for key, replacement in replacements.items(): + outstr = outstr.replace(key, replacement) + print(f"script: {outstr}") + print("Generating audio...") + audio = m.generate(outstr, voice=voice) + output_file = f"sound_files/{filename}.wav" + print(f"Writing {output_file}") + sf.write(output_file, audio, 24000) +print("Audio generation complete") diff --git a/Raspberry_Pi_KittenTTS/weather_narrator.toml b/Raspberry_Pi_KittenTTS/weather_narrator.toml new file mode 100644 index 000000000..15acb2987 --- /dev/null +++ b/Raspberry_Pi_KittenTTS/weather_narrator.toml @@ -0,0 +1,16 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +voice = "expr-voice-3-f" +location_points = "36,33" +forecast_length = 3 +#sound_device = "plughw:3,0" +available_voices = [ + 'expr-voice-2-m', + 'expr-voice-2-f', + 'expr-voice-3-m', + 'expr-voice-3-f', + 'expr-voice-4-m', + 'expr-voice-4-f', + 'expr-voice-5-m', + 'expr-voice-5-f' ] diff --git a/Raspberry_Pi_LLM_Sensor_Data/db_models.py b/Raspberry_Pi_LLM_Sensor_Data/db_models.py new file mode 100644 index 000000000..40abdc7eb --- /dev/null +++ b/Raspberry_Pi_LLM_Sensor_Data/db_models.py @@ -0,0 +1,52 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +from datetime import datetime +from sqlalchemy import Column, Integer, Float, String, DateTime, create_engine +from sqlalchemy.ext.declarative import declarative_base + + +Base = declarative_base() + + +class SensorReading(Base): + """ + Database model for environmental sensor readings. + """ + + __tablename__ = "sensor_readings" + + id = Column(Integer, primary_key=True, autoincrement=True) + datetime = Column(DateTime, nullable=False, default=datetime.utcnow) + room_name = Column(String(100), nullable=False) + temperature_c = Column(Float, nullable=True) + temperature_f = Column(Float, nullable=True) + humidity = Column(Float, nullable=True) # Percentage + pm25 = Column(Float, nullable=True) # PM2.5 in µg/m³ + voc_index = Column(Float, nullable=True) # VOC index + nox_index = Column(Float, nullable=True) # NOx index + co2 = Column(Float, nullable=True) # CO2 in ppm + + def __repr__(self): + return ( + f"" + ) + + +if __name__ == "__main__": + + def create_database(db_url="sqlite:///sensor_data.db"): + """Create the database and all tables.""" + engine = create_engine(db_url, echo=True) + + # Create all tables + Base.metadata.create_all(engine) + + print(f"Database created successfully at: {db_url}") + return engine + + # Create the database when script is run directly + create_database() diff --git a/Raspberry_Pi_LLM_Sensor_Data/prompt_llm_for_summary.py b/Raspberry_Pi_LLM_Sensor_Data/prompt_llm_for_summary.py new file mode 100644 index 000000000..a6eaa317a --- /dev/null +++ b/Raspberry_Pi_LLM_Sensor_Data/prompt_llm_for_summary.py @@ -0,0 +1,197 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import csv +from datetime import datetime, timedelta, UTC +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from ollama import chat +from db_models import SensorReading + +# pylint: disable=too-many-locals, too-many-nested-blocks + +# Database connection configuration +DATABASE_URL = "sqlite:///sensor_data.db" + +MODEL = "gemma3:1b" + +# Room name to pull data for. Update to match one of your rooms. +ROOM = "Basement" + +# Specify a Custom Date Range +# QUERY_START = datetime(2025, 9, 16, 0, 0, 0, tzinfo=UTC) +# QUERY_END = datetime(2025, 9, 18, 19, 0, 0, tzinfo=UTC) + +# Defaults to last 24 hours if start and end are None +QUERY_START = None +QUERY_END = None + +# Time interval in minutes to export data with i.e. one data point every 30 minutes. +SAMPLE_RATE = 30 # minutes + + +PROMPT = """Analyze the following environmental sensor data. Provide a summary of its content, + identify key patterns or insights, and suggest potential further analysis or questions based on this data. + +Data: +--- +%%_DATA_PLACEHOLDER_%% +--- + +The data fields are: +- UTC Datetime +- Temperature in degrees F +- Humidity percent +- pm2.5 in µg/m³ +- VOC index +- NOx index +- CO2 in ppm + +Please summarize the data, identify key patterns, insights, or trends. +""" + + +def fetch_data( + room, start_datetime=None, end_datetime=None, output_file=None, sample_rate=30 +): + """ + Fetch all SensorReading records from a specified time range for RoomC + and save them to a CSV file + + Args: + room (str): Room name + start_datetime (Optional[datetime]): Start of the time range (default: 24 hours ago) + end_datetime (Optional[datetime]): End of the time range (default: now) + output_file (str): Name of the CSV file to create + sample_rate (int): Sampling interval in minutes (e.g., 5 for every 5 minutes) + """ + # Create database engine and session + engine = create_engine(DATABASE_URL) + Session = sessionmaker(bind=engine) + session = Session() + + try: + # Set default values if not provided + if end_datetime is None: + end_datetime = datetime.now(UTC) + if start_datetime is None: + start_datetime = end_datetime - timedelta(hours=24) + + # Ensure start_datetime is before end_datetime + if start_datetime >= end_datetime: + raise ValueError("start_datetime must be before end_datetime") + + print(f"Fetching data for {room} from {start_datetime} to {end_datetime}") + + # Query for RoomC records within the specified time range + query = ( + session.query(SensorReading) + .filter( + SensorReading.room_name == room, + SensorReading.datetime >= start_datetime, + SensorReading.datetime <= end_datetime, + ) + .order_by(SensorReading.datetime.desc()) + ) + + # Execute the query + results = query.all() + + # Apply sampling if sample_rate > 1 + if sample_rate > 1: + sampled_results = [] + if results: + # Start from the most recent record (first in desc order) + base_time = results[0].datetime + + for reading in results: + # Calculate minutes difference from the base time + time_diff = abs((base_time - reading.datetime).total_seconds() / 60) + + # Include reading if it falls on a sample interval + if time_diff % sample_rate < 1: # Allow 1 minute tolerance + sampled_results.append(reading) + + results = sampled_results + print( + f"Applied {sample_rate}-minute sampling: {len(results)} records selected" + ) + + if output_file is not None: + # Write results to CSV file + with open(output_file, "w", newline="", encoding="utf-8") as csvfile: + fieldnames = [ + "datetime", + "temperature_f", + "humidity", + "pm25", + "voc_index", + "nox_index", + "co2", + ] + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + + # Write header + writer.writeheader() + + # Write data rows + for reading in results: + writer.writerow( + { + "datetime": ( + reading.datetime.isoformat() + if reading.datetime + else None + ), + "temperature_f": reading.temperature_f, + "humidity": reading.humidity, + "pm25": reading.pm25, + "voc_index": reading.voc_index, + "nox_index": reading.nox_index, + "co2": reading.co2, + } + ) + + time_range = end_datetime - start_datetime + print( + f"Successfully saved {len(results)} records for RoomC to '{output_file}'" + + f" (time range: {time_range})" + + (f" (sampled every {sample_rate} minutes)" if sample_rate > 1 else "") + ) + return results + # pylint:disable=broad-except + except Exception as e: + print(f"Error fetching data: {e}") + return [] + + finally: + # Always close the session + session.close() + + +if __name__ == "__main__": + + records = fetch_data( + room=ROOM, + start_datetime=QUERY_START, + end_datetime=QUERY_END, + sample_rate=30, + output_file="sensor_data.csv", + ) + + with open("sensor_data.csv", "r") as f: + csv_data = f.read() + + stream = chat( + model=MODEL, + messages=[ + { + "role": "user", + "content": PROMPT.replace("%%_DATA_PLACEHOLDER_%%", csv_data), + }, + ], + stream=True, + ) + + for chunk in stream: + print(chunk["message"]["content"], end="", flush=True) diff --git a/Raspberry_Pi_LLM_Sensor_Data/sensor-reading.service b/Raspberry_Pi_LLM_Sensor_Data/sensor-reading.service new file mode 100644 index 000000000..d2cbe784c --- /dev/null +++ b/Raspberry_Pi_LLM_Sensor_Data/sensor-reading.service @@ -0,0 +1,35 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +[Unit] +Description=Python Script with Virtual Environment +After=network.target +Wants=network.target + +[Service] +Type=simple +User=pi +Group=pi +WorkingDirectory=/home/pi/RaspberryPi_LLM_Sensor_Data +Environment=PATH=/home/pi/venvs/sensor_llm_venv/bin +ExecStart=/home/pi/RaspberryPi_LLM_Sensor_Data/start_service.sh +Restart=always +RestartSec=10 + +# Optional: Set environment variables +Environment=PYTHONPATH=/home/pi/RaspberryPi_LLM_Sensor_Data +Environment=PYTHONUNBUFFERED=1 + +# Optional: Logging +StandardOutput=journal +StandardError=journal +SyslogIdentifier=Environmental-Sensor-Reader + +# Optional: Security settings +NoNewPrivileges=yes +ProtectSystem=strict +#ProtectHome=yes +ReadWritePaths=/home/pi/RaspberryPi_LLM_Sensor_Data + +[Install] +WantedBy=multi-user.target diff --git a/Raspberry_Pi_LLM_Sensor_Data/start_service.sh b/Raspberry_Pi_LLM_Sensor_Data/start_service.sh new file mode 100755 index 000000000..3de819f61 --- /dev/null +++ b/Raspberry_Pi_LLM_Sensor_Data/start_service.sh @@ -0,0 +1,7 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +cd /home/pi/RaspberryPi_LLM_Sensor_Data +source /home/pi/venvs/sensor_llm_venv/bin/activate +exec python /home/pi/RaspberryPi_LLM_Sensor_Data/take_sensor_readings.py diff --git a/Raspberry_Pi_LLM_Sensor_Data/take_sensor_readings.py b/Raspberry_Pi_LLM_Sensor_Data/take_sensor_readings.py new file mode 100644 index 000000000..db99ce489 --- /dev/null +++ b/Raspberry_Pi_LLM_Sensor_Data/take_sensor_readings.py @@ -0,0 +1,109 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT + + +import time +import board +import adafruit_sen6x +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from db_models import SensorReading + + +# How many seconds in between taking readings +INTERVAL = 60 # seconds + +ROOM_NAME = "basement" + +# Initialize I2C +i2c = board.I2C() + +# Create SEN66 instance +sensor = adafruit_sen6x.SEN66(i2c) + +# Read sensor info +print(f"Product: {sensor.product_name}") +print(f"Serial: {sensor.serial_number}") + +# Check device status +status = sensor.device_status +print(f"Device {status}") + +# Optional: Configure sensor before starting +# sensor.temperature_offset(offset=-2.0, slot=0) # Apply -2°C offset +# sensor.voc_algorithm_tuning(index_offset=100) # Adjust VOC baseline +# print(sensor.voc_algorithm) # Print VOC baseline + +# CO2 configuration examples: +# sensor.co2_automatic_self_calibration = False # Disable ASC for greenhouses +# sensor.ambient_pressure = 1020 # Set pressure in hPa +# sensor.sensor_altitude = 500 # Or set altitude in meters + +# Start measurements +sensor.start_measurement() + +# Wait for first measurement to be ready +print("Waiting for first measurement...") +time.sleep(2) +print("-" * 40) + +# connect to database +engine = create_engine("sqlite:///sensor_data.db") +Session = sessionmaker(bind=engine) +session = Session() + +# Read data continuously +while True: + if sensor.data_ready: + # Check for errors before reading + sensor.check_sensor_errors() + + # Read all measurements + data = sensor.all_measurements() + + # create data object instance + reading = SensorReading( + room_name=ROOM_NAME, + temperature_c=data["temperature"], + temperature_f=(data["temperature"] * 9 / 5) + 32, + humidity=data["humidity"], + pm25=data["pm2_5"], + voc_index=data["voc_index"], + nox_index=data["nox_index"], + co2=data["co2"], + ) + + # Add and commit the reading to database + session.add(reading) + session.commit() + print(reading) + # Display values (None = sensor still initializing) + print( + f"Temperature: {data['temperature']:.1f}°C" + if data["temperature"] + else "Temperature: initializing..." + ) + print( + f"Humidity: {data['humidity']:.1f}%" + if data["humidity"] + else "Humidity: initializing..." + ) + print( + f"PM2.5: {data['pm2_5']:.1f} µg/m³" + if data["pm2_5"] + else "PM2.5: initializing..." + ) + print( + f"VOC Index: {data['voc_index']:.1f}" + if data["voc_index"] + else "VOC Index: initializing..." + ) + print( + f"NOx Index: {data['nox_index']:.1f}" + if data["nox_index"] + else "NOx Index: initializing..." + ) + print(f"CO2: {data['co2']} ppm" if data["co2"] else "CO2: initializing...") + print("-" * 40) + time.sleep(INTERVAL) diff --git a/Raspberry_Pi_Severance_MDR_Terminal/data.py b/Raspberry_Pi_Severance_MDR_Terminal/data.py new file mode 100644 index 000000000..6c4070dce --- /dev/null +++ b/Raspberry_Pi_Severance_MDR_Terminal/data.py @@ -0,0 +1,300 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# SPDX-License-Identifier: MIT + +import math +import random +import tkinter as tk +import time +from palette import Palette + +class DataNumber: + active_bin = None + + @classmethod + def reset_active_bin(cls): + """Reset the class-level active bin tracker""" + cls.active_bin = None + + def __init__(self, x: int, y: int, canvas: tk.Canvas, base_size: int = 35, palette=Palette): + """ + Initialize a data number for macrodata refinement + """ + self.num = random.randint(0, 9) + self.home_x = x + self.home_y = y + self.x = x + self.y = y + self.mouse_offset_x = 0 + self.mouse_offset_y = 0 + self.palette = palette + self.color = self.palette.FG + self.alpha = 255 + self.base_size = base_size + self.size = base_size + self.refined = False + self.bin_it = False + self.bin = None + self.bin_pause_time = 2 + self.bin_pause = self.bin_pause_time + self.canvas = canvas + self.text_id = self.canvas.create_text( + self.x, self.y, + text=str(self.num), + font=('Courier', self.size), + fill=self.color, + anchor='center' + ) + self.needs_refinement = False + self.wiggle_offset_x = 0 + self.wiggle_offset_y = 0 + + def refine(self, bin_obj=None, bins_list=None): + """ + Mark this number for refinement and assign it to a bin. + """ + if bin_obj is not None: + if bin_obj.is_full(): + return False + target_bin = bin_obj + elif bins_list is not None: + target_bin = self.get_non_full_bin_for_position(bins_list) + if target_bin is None: + return False + else: + raise ValueError("Either bin_obj or bins_list must be provided") + self.bin_it = True + if DataNumber.active_bin is None: + DataNumber.active_bin = target_bin + self.bin = target_bin + else: + if DataNumber.active_bin.is_full(): + DataNumber.active_bin = target_bin + self.bin = DataNumber.active_bin + return True + + def get_non_full_bin_for_position(self, bins_list): + """ + Determine which available bin should open based on the position of this number. + """ + non_full_bins = [bin_obj for bin_obj in bins_list if not bin_obj.is_full()] + if not non_full_bins: + return None + screen_width = self.canvas.winfo_width() + original_bin_index = self.get_bin_index_for_position(screen_width, len(bins_list)) + closest_bin = None + min_distance = float('inf') + for bin_obj in non_full_bins: + distance = abs(bin_obj.i - original_bin_index) + if distance < min_distance: + min_distance = distance + closest_bin = bin_obj + return closest_bin + + def get_bin_index_for_position(self, screen_width, num_bins): + """ + Get the bin index that corresponds to this number's position + """ + bin_width = screen_width / num_bins + bin_index = int(self.x / bin_width) + bin_index = max(0, min(bin_index, num_bins - 1)) + return bin_index + + def go_bin(self): + """Move toward the bin for refinement""" + if self.bin: + self.bin.open() + if self.bin_pause <= 0: + dx = self.bin.x - self.x + dy = self.bin.y - self.y + distance = math.sqrt(dx*dx + dy*dy) + if distance < 20: + self.alpha = int(255 * (distance / 20)) + if distance < 3: + self.wiggle_offset_x = 0 + self.wiggle_offset_y = 0 + self.mouse_offset_x = 0 + self.mouse_offset_y = 0 + self.bin.add_number() + self.reset() + return + easing = max(0.03, min(0.1, 5.0 / distance)) + self.x += dx * easing + self.y += dy * easing + fade_start_distance = self.distance(self.home_x, self.home_y, + self.bin.x, self.bin.y) * 0.4 + current_distance = self.distance(self.x, self.y, self.bin.x, self.bin.y) + if distance >= 20: + self.alpha = self.map_value(current_distance, fade_start_distance, 20, 255, 55) + self.update_display() + if hasattr(self.bin, 'level_elements'): + for element_id in self.bin.level_elements.values(): + self.canvas.tag_raise(self.text_id, element_id) + self.bin.last_refined_time = int(time.time() * 1000) + else: + self.bin_pause -= 1 + if self.bin_pause > 0: + pulse_size = self.base_size * (1.0 + 0.5 * + (1.0 - (self.bin_pause / self.bin_pause_time))) + self.set_size(pulse_size) + if hasattr(self.bin, 'level_elements'): + for element_id in self.bin.level_elements.values(): + self.canvas.tag_raise(self.text_id, element_id) + + def reset(self): + """Reset the number after being binned.""" + self.num = random.randint(0, 9) + self.x = self.home_x + self.y = self.home_y + self.wiggle_offset_x = 0 + self.wiggle_offset_y = 0 + self.mouse_offset_x = 0 + self.mouse_offset_y = 0 + self.refined = False + self.bin_it = False + self.bin = None + self.color = self.palette.FG + self.alpha = 255 + self.bin_pause = self.bin_pause_time + self.update_display() + still_active = False + if not still_active and DataNumber.active_bin is not None: + DataNumber.active_bin = None + + def go_home(self): + """Move the number back to its home position with easing.""" + self.x = self.lerp(self.x, self.home_x, 0.1) + self.y = self.lerp(self.y, self.home_y, 0.1) + self.size = self.lerp(self.size, self.base_size, 0.1) + self.update_display() + + def set_size(self, sz): + """Set the size of the number.""" + self.size = sz + self.update_display() + + def turn(self, new_color): + """Change the color of the number.""" + self.color = new_color + self.update_display() + + def inside(self, x1, y1, x2, y2): + """Check if this number is inside the given rectangle.""" + return ( + self.x > min(x1, x2) and + self.x < max(x1, x2) and + self.y > min(y1, y2) and + self.y < max(y1, y2) + ) + + def show(self): + """Update the display of this number.""" + self.update_display() + + def update_display(self): + """Update the text display with current properties and improved alpha handling""" + if self.bin_it: + digit_size = self.lerp(self.size, self.size * 2.5, + self.map_value(self.bin_pause, self.bin_pause_time, 0, 0, 1)) + else: + digit_size = self.size + font = ('Courier', int(digit_size)) + clamped_alpha = max(0, min(255, self.alpha)) + if clamped_alpha == 0: + self.canvas.itemconfig(self.text_id, state='hidden') + return + else: + self.canvas.itemconfig(self.text_id, state='normal') + if clamped_alpha < 255: + bg_color = self.palette.BG + fg_color = self.color + alpha_ratio = clamped_alpha / 255.0 + if alpha_ratio < 0.05: + display_color = self.blend_colors(bg_color, fg_color, 0.05) + else: + display_color = self.blend_colors(bg_color, fg_color, alpha_ratio) + else: + display_color = self.color + self.canvas.itemconfig(self.text_id, + text=str(self.num), + font=font, + fill=display_color) + if not hasattr(self, 'wiggle_offset_x'): + self.wiggle_offset_x = 0 + if not hasattr(self, 'wiggle_offset_y'): + self.wiggle_offset_y = 0 + if not hasattr(self, 'mouse_offset_x'): + self.mouse_offset_x = 0 + if not hasattr(self, 'mouse_offset_y'): + self.mouse_offset_y = 0 + smooth_wiggle_x = round(self.wiggle_offset_x * 10) / 10 + smooth_wiggle_y = round(self.wiggle_offset_y * 10) / 10 + smooth_mouse_x = round(self.mouse_offset_x * 10) / 10 + smooth_mouse_y = round(self.mouse_offset_y * 10) / 10 + display_x = self.x + smooth_wiggle_x + smooth_mouse_x + display_y = self.y + smooth_wiggle_y + smooth_mouse_y + self.canvas.coords(self.text_id, display_x, display_y) + + def resize(self, new_x, new_y): + """Update the home position when the window is resized.""" + self.home_x = new_x + self.home_y = new_y + + def show_wiggle(self, proximity_factor=0): + """Make the number threatening""" + if self.needs_refinement and not self.bin_it: + original_x, original_y = self.x, self.y + smooth_x = round(self.wiggle_offset_x * 10) / 10 + smooth_y = round(self.wiggle_offset_y * 10) / 10 + self.x += smooth_x + self.y += smooth_y + original_color = self.color + base_pulse = 0.7 + wave1 = math.sin(time.time() * 0.9) * 0.15 + wave2 = math.sin(time.time() * 1.8) * 0.05 + highlight_intensity = base_pulse + wave1 + wave2 + (proximity_factor * 0.2) + highlight_intensity = max(0.6, min(1.0, highlight_intensity)) + if highlight_intensity > 0.82: + self.color = self.palette.SELECT + else: + blend_amount = (highlight_intensity - 0.6) / 0.22 + self.color = self.blend_colors(self.palette.FG, self.palette.SELECT, blend_amount) + self.update_display() + self.x, self.y = original_x, original_y + self.color = original_color + + @staticmethod + def lerp(start, end, amt): + """Linear interpolation between start and end by amt.""" + return start + (end - start) * amt + + @staticmethod + def map_value(value, start1, stop1, start2, stop2): + """Re-maps a number from one range to another.""" + if stop1 == start1: + return start2 + return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1)) + + @staticmethod + def distance(x1, y1, x2, y2): + """Calculate distance between two points.""" + return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) + + @staticmethod + def hex_to_rgb(hex_color): + """Convert hex color to RGB values.""" + # Strip the # if it exists + hex_color = hex_color.lstrip('#') + return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4)) + + @staticmethod + def rgb_to_hex(rgb): + """Convert RGB tuple to hex color.""" + return f"#{rgb[0]:02x}{rgb[1]:02x}{rgb[2]:02x}" + + @staticmethod + def blend_colors(color1, color2, ratio): + """Blend two colors based on ratio (0-1).""" + c1 = DataNumber.hex_to_rgb(color1) + c2 = DataNumber.hex_to_rgb(color2) + blended = tuple(int(c1[i] + (c2[i] - c1[i]) * ratio) for i in range(3)) + return DataNumber.rgb_to_hex(blended) diff --git a/Raspberry_Pi_Severance_MDR_Terminal/data_bin.py b/Raspberry_Pi_Severance_MDR_Terminal/data_bin.py new file mode 100644 index 000000000..ed7f9a788 --- /dev/null +++ b/Raspberry_Pi_Severance_MDR_Terminal/data_bin.py @@ -0,0 +1,417 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# SPDX-License-Identifier: MIT + +import math +import time +import random +import tkinter as tk +from PIL import Image, ImageTk, ImageFont, ImageDraw + +# pylint: disable=broad-except,too-many-locals + +class Bin: + KEYS = ['WO', 'FC', 'DR', 'MA'] + MAX_LID_ANGLE = 45 + CLOSED_LID_ANGLE = 180 + MAX_SHOW_TIME = 1500 # milliseconds + LID_OPEN_CLOSE_TIME = 750 # milliseconds + + def __init__(self, width, index, goal, canvas, levels=None, palette=None): + self.w = width + self.i = index + self.x = index * width + width * 0.5 + self.canvas = canvas + self.buffer = 60 + self.y = canvas.winfo_height() - 50 + self.palette = palette + self.fg_color = self.palette.FG + self.bg_color = self.palette.BG + self.goal = goal + self.level_goal = self.goal / 4 + self.level_h = self.buffer * 1.7 + self.levels_y_offset = self.level_h + self.last_refined_time = self.get_millis() + if levels is None: + self.levels = { + 'WO': 0, + 'FC': 0, + 'DR': 0, + 'MA': 0 + } + else: + self.levels = levels + self.count = sum(self.levels.values()) + + self.show_levels = False + self.closing_animation = False + self.opening_animation = False + self.lid_angle = self.CLOSED_LID_ANGLE + self.show_time = 0 + self.animation_start_time = 0 + self.animation_progress = 0 + + self.visual_elements = {} + self.level_elements = {} + self.progress_bar_elements = {} + + self.create_visual_elements() + + def create_outlined_text(self, text, font_size=22, stroke_width=4): + font = ImageFont.truetype("/usr/share/fonts/truetype/msttcorefonts/arial.ttf", font_size) + dummy_img = Image.new("RGBA", (1, 1), (0, 0, 0, 0)) + dummy_draw = ImageDraw.Draw(dummy_img) + bbox = dummy_draw.textbbox((0, 0), text, font=font) + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] + padding = 12 + width = text_width + padding * 2 + stroke_width * 2 + height = text_height + padding * 2 + stroke_width * 2 + img = Image.new("RGBA", (width, height), (0, 0, 0, 0)) + draw = ImageDraw.Draw(img) + fill_color = self.bg_color + stroke_color = self.fg_color + position = (padding + stroke_width, padding+stroke_width) + draw.text(position, text, font=font, fill=fill_color, + stroke_width=stroke_width, stroke_fill=stroke_color) + photo = ImageTk.PhotoImage(img) + return photo + + def create_visual_elements(self): + for key in list(self.visual_elements.keys()): + try: + self.canvas.delete(self.visual_elements[key]) + except Exception: + pass + for key in list(self.level_elements.keys()): + try: + self.canvas.delete(self.level_elements[key]) + except Exception: + pass + for key in list(self.progress_bar_elements.keys()): + try: + self.canvas.delete(self.progress_bar_elements[key]) + except Exception: + pass + self.visual_elements = {} + self.level_elements = {} + self.progress_bar_elements = {} + rw = self.w + popup_width = rw + popup_height = self.buffer * 3 + base_y = self.y - self.buffer/4 + popup_y = base_y - popup_height/2 + self.visual_elements['main'] = self.canvas.create_rectangle( + self.x - rw/2, self.y - self.buffer/4, + self.x + rw/2, self.y + self.buffer/4, + outline=self.fg_color, fill=self.bg_color, width=1 + ) + self.visual_elements['label'] = self.canvas.create_text( + self.x, self.y, + text=f"{self.i:02d}", + font=('Arial', 16), + fill=self.fg_color + ) + self.level_elements['popup_bg'] = self.canvas.create_rectangle( + self.x - popup_width/2, popup_y - popup_height/2, + self.x + popup_width/2, popup_y + popup_height/2, + outline="", fill=self.bg_color, + state='hidden' + ) + self.level_elements['container'] = self.canvas.create_rectangle( + self.x - popup_width/2, popup_y - popup_height/2, + self.x + popup_width/2, popup_y + popup_height/2, + outline=self.fg_color, fill="", width=1, + state='hidden' + ) + bar_height = popup_height * 0.15 + for i, key in enumerate(self.KEYS): + level_y = popup_y - popup_height * 0.3 + i * (popup_height * 0.6 / 3) + self.level_elements[f'{key}_label'] = self.canvas.create_text( + self.x - popup_width * 0.4, level_y, + text=key, + font=('Courier', 14), + fill=self.fg_color, + anchor='w', + state='hidden' + ) + self.level_elements[f'{key}_outline'] = self.canvas.create_rectangle( + self.x - popup_width * 0.2, level_y - bar_height/2, + self.x + popup_width * 0.4, level_y + bar_height/2, + outline=self.fg_color, fill="", + state='hidden' + ) + self.level_elements[f'{key}_progress'] = self.canvas.create_rectangle( + self.x - popup_width * 0.2, level_y - bar_height/2, + self.x - popup_width * 0.2, level_y + bar_height/2, + outline="", fill=self.fg_color, + state='hidden' + ) + left_edge_x = self.x - rw/2 + right_edge_x = self.x + rw/2 + top_edge_y = self.y - self.buffer/4 + self.level_elements['left_lid'] = self.canvas.create_line( + left_edge_x, top_edge_y, + self.x, top_edge_y, + fill=self.fg_color, width=1, + state='normal' + ) + self.level_elements['right_lid'] = self.canvas.create_line( + self.x, top_edge_y, + right_edge_x, top_edge_y, + fill=self.fg_color, width=1, + state='normal' + ) + progress_bar_y = self.y + self.buffer/4 + 2 + progress_bar_height = self.buffer/2 + self.progress_bar_elements['outline'] = self.canvas.create_rectangle( + self.x - rw/2, progress_bar_y, + self.x + rw/2, progress_bar_y + progress_bar_height, + outline=self.fg_color, fill=self.bg_color, width=1 + ) + self.progress_bar_elements['fill'] = self.canvas.create_rectangle( + self.x - rw/2 + 1, progress_bar_y + 1, + self.x - rw/2 + 1, progress_bar_y + progress_bar_height - 1, + outline="", fill=self.fg_color + ) + percentage_text = "0%" + outlined_img = self.create_outlined_text(percentage_text, font_size=14, stroke_width=1) + left_edge = self.x - rw/2 + text_padding = 14 + self.progress_bar_elements['text'] = self.canvas.create_image( + left_edge + text_padding, progress_bar_y + progress_bar_height/2, + image=outlined_img, + anchor=tk.CENTER + ) + self.fix_z_order() + self.update_progress_bar() + + def fix_z_order(self): + self.canvas.tag_raise(self.level_elements['popup_bg']) + self.canvas.tag_raise(self.level_elements['container']) + for key in self.KEYS: + if f'{key}_label' in self.level_elements: + self.canvas.tag_raise(self.level_elements[f'{key}_label']) + if f'{key}_outline' in self.level_elements: + self.canvas.tag_raise(self.level_elements[f'{key}_outline']) + if f'{key}_progress' in self.level_elements: + self.canvas.tag_raise(self.level_elements[f'{key}_progress']) + self.canvas.tag_raise(self.visual_elements['main']) + self.canvas.tag_raise(self.visual_elements['label']) + self.canvas.tag_raise(self.level_elements['left_lid']) + self.canvas.tag_raise(self.level_elements['right_lid']) + self.canvas.tag_raise(self.progress_bar_elements['outline']) + self.canvas.tag_raise(self.progress_bar_elements['fill']) + self.canvas.tag_raise(self.progress_bar_elements['text']) + + def is_full(self): + total_levels = sum(self.levels.values()) + return total_levels >= self.goal + + def add_number(self): + if self.is_full(): + return False + options = [key for key in self.KEYS if self.levels[key] < self.level_goal] + if options: + key = random.choice(options) + self.levels[key] += 1 + self.open() + self.last_refined_time = self.get_millis() + self.update_display() + self.update_progress_bar() + self.fix_z_order() + return True + return False + + def open(self): + if not self.show_levels and not self.opening_animation: + self.animation_start_time = self.get_millis() + self.opening_animation = True + self.closing_animation = False + self.show_levels = True + + def update(self): + current_time = self.get_millis() + if self.opening_animation: + elapsed = current_time - self.animation_start_time + if elapsed >= self.LID_OPEN_CLOSE_TIME: + self.opening_animation = False + self.animation_progress = 1.0 + else: + progress = elapsed / self.LID_OPEN_CLOSE_TIME + self.animation_progress = 1 - (1 - progress) * (1 - progress) + self.update_display() + self.fix_z_order() + elif self.show_levels and not self.closing_animation: + if current_time - self.last_refined_time > self.MAX_SHOW_TIME: + self.closing_animation = True + self.animation_start_time = current_time + elif self.closing_animation: + elapsed = current_time - self.animation_start_time + if elapsed >= self.LID_OPEN_CLOSE_TIME: + self.closing_animation = False + self.show_levels = False + self.animation_progress = 0.0 + else: + progress = elapsed / self.LID_OPEN_CLOSE_TIME + self.animation_progress = 1.0 - (progress * progress) + self.update_display() + self.fix_z_order() + self.update_progress_bar() + + def update_progress_bar(self): + total_levels = sum(self.levels.values()) + completion_percentage = (total_levels / self.goal) * 100 if self.goal > 0 else 0 + rw = self.w + progress_bar_y = self.y + self.buffer/4 + 2 + progress_bar_height = self.buffer/2 + fill_width = (rw * completion_percentage) / 100 + if completion_percentage == 0: + self.canvas.coords( + self.progress_bar_elements['fill'], + self.x - rw/2 + 1, progress_bar_y + 1, + self.x - rw/2 + 1, progress_bar_y + progress_bar_height - 1 + ) + else: + self.canvas.coords( + self.progress_bar_elements['fill'], + self.x - rw/2 + 1, progress_bar_y + 1, + self.x - rw/2 + max(1, fill_width), progress_bar_y + progress_bar_height - 1 + ) + percentage_text = f"{int(completion_percentage)}%" + outlined_img = self.create_outlined_text( + percentage_text, + font_size=14, + stroke_width=1 + ) + left_edge = self.x - rw/2 + text_padding = 30 if completion_percentage >= 100 else 24 + self.canvas.itemconfig(self.progress_bar_elements['text'], image=outlined_img) + self.canvas.coords( + self.progress_bar_elements['text'], + left_edge + text_padding, progress_bar_y + progress_bar_height/2 + ) + + def update_display(self): + self.count = sum(self.levels.values()) + self.count = min(max(self.count, 0), self.goal) + rw = self.w + popup_width = rw + popup_height = self.buffer * 3 + base_y = self.y - self.buffer/4 + popup_y_closed = base_y + popup_y_open = base_y - popup_height/2 + current_popup_y = self.map_value( + self.animation_progress, + 0, 1, + popup_y_closed, popup_y_open + ) + self.canvas.coords( + self.level_elements['popup_bg'], + self.x - popup_width/2, current_popup_y - popup_height/2, + self.x + popup_width/2, current_popup_y + popup_height/2 + ) + self.canvas.coords( + self.level_elements['container'], + self.x - popup_width/2, current_popup_y - popup_height/2, + self.x + popup_width/2, current_popup_y + popup_height/2 + ) + left_edge_x = self.x - rw/2 + right_edge_x = self.x + rw/2 + top_edge_y = base_y + max_lid_angle = 120 + current_angle = self.animation_progress * max_lid_angle + angle_rad = math.radians(current_angle) + + left_lid_end_x = left_edge_x + (rw/2) * math.cos(angle_rad) + left_lid_end_y = top_edge_y - (rw/2) * math.sin(angle_rad) + right_lid_end_x = right_edge_x - (rw/2) * math.cos(angle_rad) + right_lid_end_y = top_edge_y - (rw/2) * math.sin(angle_rad) + self.canvas.coords( + self.level_elements['left_lid'], + left_edge_x, top_edge_y, + left_lid_end_x, left_lid_end_y + ) + self.canvas.coords( + self.level_elements['right_lid'], + right_edge_x, top_edge_y, + right_lid_end_x, right_lid_end_y + ) + visibility_threshold = 0.05 + state = 'normal' if self.animation_progress > visibility_threshold else 'hidden' + + self.canvas.itemconfig(self.level_elements['popup_bg'], state=state) + self.canvas.itemconfig(self.level_elements['container'], state=state) + self.canvas.itemconfig(self.level_elements['left_lid'], state='normal') + self.canvas.itemconfig(self.level_elements['right_lid'], state='normal') + self.update_level_displays(current_popup_y, popup_height, popup_width) + if state == 'hidden': + for key in self.KEYS: + if f'{key}_label' in self.level_elements: + self.canvas.itemconfig(self.level_elements[f'{key}_label'], state='hidden') + if f'{key}_outline' in self.level_elements: + self.canvas.itemconfig(self.level_elements[f'{key}_outline'], state='hidden') + if f'{key}_progress' in self.level_elements: + self.canvas.itemconfig(self.level_elements[f'{key}_progress'], state='hidden') + + def update_level_displays(self, popup_y, popup_height, popup_width): + bar_height = popup_height * 0.15 + state = 'normal' if self.animation_progress > 0.05 else 'hidden' + bar_width = popup_width * 0.6 + for i, key in enumerate(self.KEYS): + level_y = popup_y - popup_height * 0.3 + i * (popup_height * 0.6 / 3) + self.canvas.coords( + self.level_elements[f'{key}_label'], + self.x - popup_width * 0.4, level_y + ) + self.canvas.coords( + self.level_elements[f'{key}_outline'], + self.x - popup_width * 0.2, level_y - bar_height/2, + self.x + popup_width * 0.4, level_y + bar_height/2 + ) + progress_width = ((bar_width * self.levels[key]) + / self.level_goal if self.level_goal > 0 else 0) + self.canvas.coords( + self.level_elements[f'{key}_progress'], + self.x - popup_width * 0.2, level_y - bar_height/2, + self.x - popup_width * 0.2 + progress_width, level_y + bar_height/2 + ) + self.canvas.itemconfig(self.level_elements[f'{key}_label'], state=state) + self.canvas.itemconfig(self.level_elements[f'{key}_outline'], state=state) + self.canvas.itemconfig(self.level_elements[f'{key}_progress'], state=state) + + def resize(self, new_w): + self.w = new_w + self.x = self.i * new_w + new_w * 0.5 + self.y = self.canvas.winfo_height() - 50 + for key in list(self.visual_elements.keys()): + try: + self.canvas.delete(self.visual_elements[key]) + except Exception: + pass + + for key in list(self.level_elements.keys()): + try: + self.canvas.delete(self.level_elements[key]) + except Exception: + pass + + for key in list(self.progress_bar_elements.keys()): + try: + self.canvas.delete(self.progress_bar_elements[key]) + except Exception: + pass + self.visual_elements = {} + self.level_elements = {} + self.progress_bar_elements = {} + self.create_visual_elements() + self.update_display() + + @staticmethod + def get_millis(): + return int(time.time() * 1000) + + @staticmethod + def map_value(value, start1, stop1, start2, stop2): + if stop1 == start1: + return start2 + return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1)) diff --git a/Raspberry_Pi_Severance_MDR_Terminal/lumon-logo-small.png b/Raspberry_Pi_Severance_MDR_Terminal/lumon-logo-small.png new file mode 100644 index 000000000..17839cd21 Binary files /dev/null and b/Raspberry_Pi_Severance_MDR_Terminal/lumon-logo-small.png differ diff --git a/Raspberry_Pi_Severance_MDR_Terminal/lumon-logo.png b/Raspberry_Pi_Severance_MDR_Terminal/lumon-logo.png new file mode 100644 index 000000000..4b64e6622 Binary files /dev/null and b/Raspberry_Pi_Severance_MDR_Terminal/lumon-logo.png differ diff --git a/Raspberry_Pi_Severance_MDR_Terminal/lumon.py b/Raspberry_Pi_Severance_MDR_Terminal/lumon.py new file mode 100644 index 000000000..74750daae --- /dev/null +++ b/Raspberry_Pi_Severance_MDR_Terminal/lumon.py @@ -0,0 +1,1068 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# SPDX-License-Identifier: MIT + +# Based on https://github.com/Lumon-Industries/Macrodata-Refinement +# JavaScript project + +import json +import os +import math +import hashlib +import shutil +import time +import random +import tkinter as tk +from PIL import Image, ImageTk, ImageFont, ImageDraw +from data import DataNumber +from data_bin import Bin +from palette import Palette +try: # blinka with haptics? + import board + import busio + import adafruit_drv2605 +except NotImplementedError: + pass + +TOTAL_REFINEMENT_GOAL = 250 # how many numbers to refine? +LOCATION = "Cold Harbor" + +def get_username(): + username = os.environ.get('USER') + if username: + return username + username = os.environ.get('LOGNAME') + if username: + return username + username = os.environ.get('USERNAME') + if username: + return username + return "Mark S." + +def generate_serial_number(username): + """ + Generate a Severance-style serial number based on the username. + Format: 0xAAAAAA : 0xBBBBBB where A and B are hex values derived from username. + """ + username_bytes = username.encode('utf-8') + first_hex = 0 + for i in range(min(3, len(username_bytes))): + first_hex = (first_hex << 8) | username_bytes[i] + second_hex = 0 + if len(username_bytes) > 3: + remaining_bytes = username_bytes[3:] + for i, byte in enumerate(remaining_bytes): + second_hex ^= (byte << (8 * (i % 3))) + else: + hash_obj = hashlib.md5(username_bytes) + digest = hash_obj.digest() + second_hex = int.from_bytes(digest[:3], byteorder='big') + serial = f"0x{first_hex:06X} : 0x{second_hex:06X}" + return serial +def calculate_distance(x1, y1, x2, y2): + """Calculate Euclidean distance between two points""" + return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) +# pylint: disable=too-many-branches,too-many-lines,broad-except,unused-argument +# pylint: disable=too-many-statements,too-many-locals,too-many-public-methods,too-many-nested-blocks +class MacrodataRefinementTerminal: + def __init__(self, username=None, location=LOCATION): + self.palette = Palette() + if username is None: + username = get_username() + # game settings + self.username = username + self.location = location + self.completion = 0 + self.total_goal = TOTAL_REFINEMENT_GOAL + self.total_refined = 0 + self.image_path = "lumon-logo.png" + self.logo_img = Image.open("lumon-logo-small.png") + + # graphics + self.root = tk.Tk() + self.root.title("Lumon MDR Terminal") + self.screen_width = self.root.winfo_screenwidth() + self.screen_height = self.root.winfo_screenheight() + self.root.geometry(f"{self.screen_width}x{self.screen_height}+0+0") + self.root.grid_rowconfigure(0, weight=1) + self.root.grid_columnconfigure(0, weight=1) + self.root.bind("", self.toggle_fullscreen) + self.root.bind("", self.exit_fullscreen) + self.root.bind("", self.exit_program) + self.root.protocol("WM_DELETE_WINDOW", self.exit_program) + self.root.focus_force() + self.canvas = tk.Canvas( + self.root, + width=self.screen_width, + height=self.screen_height, + bg=self.palette.BG, + highlightthickness=0 + ) + self.canvas.pack(fill="both", expand=True) + try: + self.image = Image.open(self.image_path) + self.photo = ImageTk.PhotoImage(self.image) + self.canvas_image = self.canvas.create_image(0, 0, image=self.photo, anchor="nw") + except Exception as e: + print(f"Error loading image: {e}") + self.canvas_image = None + self.screen = 1 + # macrodata settings + self.completion_message_elements = {} + self.x_pos, self.y_pos = 100, 100 + self.x_speed, self.y_speed = 2, 2 + self.base_size = 24 + self.number_spacing = 50 + self.margin = 80 + self.data_numbers = [] + self.ui_elements = {} + self.selection_start = None + self.selection_rect = None + self.selection_active = False + self.wiggle_numbers = [] + self.wiggle_timer = 0 + self.wiggle_interval = 600 + self.wiggle_amplitude = 2.0 + self.wiggle_speed = 0.2 + self.wiggle_phase = 0 + self.wiggle_phase_x = 0.0 + self.wiggle_phase_y = 0.0 + self.wiggle_phase_rotation = 0.0 + self.numbers_need_selection = False + self.waiting_for_next_wiggle = False + self.next_wiggle_timer = 0 + self.next_wiggle_delay = 210 + self.base_wiggle_amplitude = 1.5 + self.max_wiggle_amplitude = 10.0 + self.proximity_threshold = 350 + self.wiggle_speed_x = 0.058 + self.wiggle_speed_y = 0.047 + self.wiggle_speed_rotation = 0.02 + self.glow_step = 0 + self.fade_step = 0 + self.fade_timer = 0 + self.max_fade_steps = 20 + self.completion_photo = 0 + self.completion_triggered = False + + # mouse settings + self.mouse_x = 0 + self.mouse_y = 0 + self.canvas.bind("", self.track_mouse) + self.bins = [] + self.canvas.bind("", self.start_selection) + self.canvas.bind("", self.update_selection) + self.canvas.bind("", self.end_selection) + self.root.bind("", self.toggle_screen) + # start program & autosave + self.animate() + self.setup_autosave(interval=300) + try: + self.i2c = busio.I2C(board.SCL, board.SDA) + self.drv = adafruit_drv2605.DRV2605(self.i2c) + self.haptic_enabled = True + self.effect_level = 0 + self.haptic_effects = { + 0: 0, + 1: 9, + 2: 13, + 3: 47, + } + print("Haptic feedback initialized") + except Exception as e: + print(f"Haptic initialization error: {e}") + self.haptic_enabled = False + + def update_haptic_intensity(self, proximity_factor): + if not self.haptic_enabled: + return + + if proximity_factor < 0.1: + self.effect_level = 0 + elif proximity_factor < 0.4: + self.effect_level = 1 + elif proximity_factor < 0.7: + self.effect_level = 2 + else: + self.effect_level = 3 + + if self.effect_level == 0: + self.drv.stop() + else: + effect_id = self.haptic_effects[self.effect_level] + self.drv.sequence[0] = adafruit_drv2605.Effect(effect_id) + self.drv.play() + + def track_mouse(self, event): + self.mouse_x = event.x + self.mouse_y = event.y + + def apply_mouse_avoidance(self, number): + """ + Apply an avoidance effect where numbers move away from the mouse cursor + """ + if not hasattr(number, 'mouse_offset_x'): + number.mouse_offset_x = 0 + if not hasattr(number, 'mouse_offset_y'): + number.mouse_offset_y = 0 + if self.screen != 2 or number.bin_it: + return + dx = number.x - self.mouse_x + dy = number.y - self.mouse_y + distance = math.sqrt(dx*dx + dy*dy) + avoidance_radius = 100 + max_repel_distance = 12 + if distance < avoidance_radius: + normalized_distance = 1.0 - (distance / avoidance_radius) + repel_factor = normalized_distance * normalized_distance * 0.8 + repel_distance = max_repel_distance * repel_factor + if distance > 0.1: + repel_x = (dx / distance) * repel_distance + repel_y = (dy / distance) * repel_distance + else: + angle = random.uniform(0, 2 * math.pi) + repel_x = math.cos(angle) * repel_distance + repel_y = math.sin(angle) * repel_distance + number.mouse_offset_x = repel_x + number.mouse_offset_y = repel_y + else: + if hasattr(number, 'mouse_offset_x') and number.mouse_offset_x != 0: + number.mouse_offset_x *= 0.95 + if abs(number.mouse_offset_x) < 0.05: + number.mouse_offset_x = 0 + if hasattr(number, 'mouse_offset_y') and number.mouse_offset_y != 0: + number.mouse_offset_y *= 0.95 + if abs(number.mouse_offset_y) < 0.05: + number.mouse_offset_y = 0 + + def save_progress(self, filepath=None): + """ + Save the current progress and bin data to a JSON file. + """ + if self.screen != 2 or not self.bins: + return False + if filepath is None: + save_dir = f"/home/{self.username}/mdr_saves/" + os.makedirs(save_dir, exist_ok=True) + filepath = os.path.join(save_dir, f"mdr_{self.location.lower()}.json") + try: + save_data = { + "timestamp": int(time.time()), + "username": self.username, + "location": self.location, + "completion": self.completion, + "total_goal": self.total_goal, + "total_refined": self.total_refined, + "bins": [] + } + for bin_idx, bin_obj in enumerate(self.bins): + bin_data = { + "bin_id": bin_idx, + "levels": bin_obj.levels, + "last_refined_time": bin_obj.last_refined_time + } + save_data["bins"].append(bin_data) + with open(filepath, 'w') as f: + json.dump(save_data, f, indent=2) + print(f"Progress autosaved to {filepath}") + return True + except Exception as e: + print(f"Error saving progress: {str(e)}") + return False + + def load_progress(self, filepath=None): + """ + Load progress and bin data from a JSON file. + Verifies that the saved total goal matches the current total goal, + otherwise starts a new save. + """ + if filepath is None: + filepath = os.path.join(f"/home/{self.username}/mdr_saves/", + f"mdr_{self.location.lower()}.json") + if not os.path.exists(filepath): + print(f"Save file {filepath} not found") + return False + try: + with open(filepath, 'r') as f: + save_data = json.load(f) + required_keys = ["timestamp", "username", "location", "completion", "bins"] + for key in required_keys: + if key not in save_data: + print(f"Invalid save file: missing '{key}' field") + return False + if "total_goal" in save_data: + saved_goal = save_data["total_goal"] + if saved_goal != TOTAL_REFINEMENT_GOAL: + print("Starting fresh with new refinement goal") + backup_path = filepath + f".goal_{saved_goal}.bak" + try: + shutil.copy2(filepath, backup_path) + print(f"Created backup of old save at {backup_path}") + except Exception as backup_err: + print(f"Warning: Could not create backup: {str(backup_err)}") + return False + self.completion = save_data["completion"] + if "total_goal" in save_data: + self.total_goal = save_data["total_goal"] + else: + self.total_goal = TOTAL_REFINEMENT_GOAL + + if "total_refined" in save_data: + self.total_refined = save_data["total_refined"] + if self.screen == 2 and self.bins: + for bin_data in save_data["bins"]: + bin_idx = bin_data["bin_id"] + if bin_idx < len(self.bins): + self.bins[bin_idx].levels = bin_data["levels"] + self.bins[bin_idx].last_refined_time = bin_data["last_refined_time"] + self.bins[bin_idx].update_progress_bar() + if "total_refined" not in save_data: + self.update_total_refined() + self.update_top_progress_bar() + return True + except Exception as e: + print(f"Error loading progress: {str(e)}") + return False + + def setup_autosave(self, interval=300): + """ + Setup automatic saving at five minutes. + """ + self.save_progress() + self.root.after(interval * 1000, lambda: self.setup_autosave(interval)) + + def create_ui_elements(self): + """Create the UI elements for the MDR terminal""" + for element_id in self.ui_elements.values(): + self.canvas.delete(element_id) + self.ui_elements.clear() + if hasattr(self, 'progress_fill_id'): + self.canvas.delete(self.progress_fill_id) + usable_width = self.screen_width - (2 * self.margin) + header_height = 40 + footer_height = 30 + self.ui_elements['top_frame'] = self.canvas.create_rectangle( + self.margin - 5, self.margin - 5, + self.margin + usable_width -50, self.margin + header_height + 5, + outline=self.palette.FG, fill=self.palette.BG, width=2 + ) + print(self.canvas.bbox(self.ui_elements['top_frame'])) + self.ui_elements['top_curve'] = self.canvas.create_line( + self.margin, self.margin + header_height + 15, + self.margin + usable_width, self.margin + header_height + 15, + fill=self.palette.FG, width=2 + ) + self.ui_elements['location'] = self.canvas.create_text( + self.margin + 20, self.margin + header_height/2, + text=self.location, + font=('Arial', 18), + fill=self.palette.FG, + anchor='w' + ) + logo_x = self.margin + usable_width - 75 + logo_y = self.margin + header_height/2 + self.lumon_logo_photo = ImageTk.PhotoImage(self.logo_img) # pylint: disable=attribute-defined-outside-init + self.ui_elements['logo'] = self.canvas.create_image( + logo_x, logo_y, + image=self.lumon_logo_photo, + anchor=tk.CENTER + ) + logo_bbox = self.canvas.bbox(self.ui_elements['logo']) + completion_text = f"{self.completion}% Complete" + outlined_img = self.create_outlined_text(completion_text, font_size=20, stroke_width=1) + self.completion_photo = outlined_img + completion_x = logo_bbox[0] - 20 + self.ui_elements['completion'] = self.canvas.create_image( + completion_x, self.margin + header_height/2, + image=outlined_img, + anchor=tk.E + ) + + bins_y_position = self.screen_height - self.margin - 100 + progress_bar_height = 30 + spacing_after_bar = 30 + bottom_frame_y = bins_y_position + 5 + progress_bar_height + spacing_after_bar + self.ui_elements['bottom_curve'] = self.canvas.create_line( + self.margin, bins_y_position - 25, + self.margin + usable_width, bins_y_position - 25, + fill=self.palette.FG, width=2 + ) + self.ui_elements['bottom_shield'] = self.canvas.create_rectangle( + self.margin - 5, bottom_frame_y-16, + self.margin + usable_width + 5, bottom_frame_y, + outline='', fill=self.palette.BG, width=2 + ) + self.ui_elements['bottom_frame'] = self.canvas.create_rectangle( + self.margin - 5, bottom_frame_y, + self.margin + usable_width + 5, bottom_frame_y + footer_height, + outline=self.palette.FG, fill=self.palette.FG, width=2 + ) + serial = generate_serial_number(self.username) + self.ui_elements['serial'] = self.canvas.create_text( + self.margin + usable_width/2, bottom_frame_y + footer_height/2, + text=serial, + font=('Courier', 14), + fill=self.palette.BG + ) + if 'completion' in self.ui_elements: + self.canvas.tag_raise(self.ui_elements['completion']) + print("Raised completion text to top") + self.update_top_progress_bar() + + def create_outlined_text(self, text, font_size=24, stroke_width=1): + """ + Creates an image with outlined text using PIL's stroke feature + """ + font = ImageFont.truetype("/usr/share/fonts/truetype/msttcorefonts/arial.ttf", font_size) + dummy_img = Image.new("RGBA", (1, 1), (0, 0, 0, 0)) + dummy_draw = ImageDraw.Draw(dummy_img) + bbox = dummy_draw.textbbox((0, 0), text, font=font) + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] + padding = 6 + width = text_width + padding * 2 + stroke_width * 2 + height = text_height + padding * 2 + stroke_width * 2 + + img = Image.new("RGBA", (width, height), (0, 0, 0, 0)) + draw = ImageDraw.Draw(img) + fill_color = self.palette.BG + stroke_color = self.palette.FG + position = (padding + stroke_width, padding) + draw.text(position, text, font=font, fill=fill_color, + stroke_width=stroke_width, stroke_fill=stroke_color) + photo = ImageTk.PhotoImage(img) + return photo + + def create_completion_text(self, text): + """Creates and returns a canvas image item with stroke-outlined text""" + photo = self.create_outlined_text(text) + self.completion_photo = photo + return photo + + def create_bins(self): + """Create bins at the bottom of the screen""" + bin_count = 5 + usable_width = self.screen_width - (2 * self.margin) + actual_bin_width = (usable_width / bin_count) * 0.9 + spacing = (usable_width - (bin_count * actual_bin_width)) / (bin_count + 1) + + for bin_obj in self.bins: + if hasattr(bin_obj, 'visual_elements'): + for element_id in bin_obj.visual_elements.values(): + self.canvas.delete(element_id) + if hasattr(bin_obj, 'level_elements'): + for element_id in bin_obj.level_elements.values(): + self.canvas.delete(element_id) + if hasattr(bin_obj, 'progress_bar_elements'): + for element_id in bin_obj.progress_bar_elements.values(): + self.canvas.delete(element_id) + self.bins.clear() + bin_goal = self.total_goal // bin_count + bins_y_position = self.screen_height - self.margin - 100 + for i in range(bin_count): + bin_obj = Bin(actual_bin_width, i, bin_goal, self.canvas, palette=self.palette) + x_pos = (self.margin + spacing + (i *(actual_bin_width + spacing)) + + (actual_bin_width / 2)) + bin_obj.x = x_pos + bin_obj.y = bins_y_position + self.bins.append(bin_obj) + bin_obj.create_visual_elements() + bin_obj.update_progress_bar() + + if 'bottom_shield' in self.ui_elements: + self.canvas.tag_raise(self.ui_elements['bottom_shield']) + if 'bottom_frame' in self.ui_elements: + self.canvas.tag_raise(self.ui_elements['bottom_frame']) + if 'serial' in self.ui_elements: + self.canvas.tag_raise(self.ui_elements['serial']) + + def update_total_refined(self): + """Update total refined count based on all bins' levels""" + previous_total = self.total_refined + self.total_refined = 0 + + for bin_obj in self.bins: + bin_total = sum(bin_obj.levels.values()) + self.total_refined += bin_total + if self.total_refined != previous_total: + self.update_overall_completion() + + def update_completion_text(self): + """Updates the completion text with new percentage""" + if 'completion' in self.ui_elements: + completion_text = f"{self.completion}% Complete" + outlined_img = self.create_completion_text(completion_text) + self.canvas.itemconfig(self.ui_elements['completion'], image=outlined_img) + + def should_update_completion(self): + """Check if we should update the completion percentage""" + if not self.bins: + return False + for bin_obj in self.bins: + if bin_obj.show_levels or bin_obj.opening_animation or bin_obj.closing_animation: + return False + return True + + def calculate_bin_percentages(self): + """Calculate the average completion percentage across all bins""" + if not self.bins: + return 0 + bin_percentages = [] + for bin_obj in self.bins: + total_levels = sum(bin_obj.levels.values()) + max_possible = bin_obj.level_goal * len(bin_obj.KEYS) + bin_percentage = (total_levels / max_possible) * 100 if max_possible > 0 else 0 + bin_percentages.append(bin_percentage) + avg_percentage = sum(bin_percentages) / len(bin_percentages) if bin_percentages else 0 + return avg_percentage + + def update_overall_completion(self): + """ + Update the overall completion percentage based on total numbers refined. + """ + if not self.bins: + return + raw_completion = (self.total_refined / self.total_goal) * 100 + self.completion = int(raw_completion) + self.update_top_progress_bar() + + def update_top_progress_bar(self): + """ + Update the top progress bar based on bin percentages. + """ + total_percentage = 0 + bin_count = 0 + for bin_obj in self.bins: + total_levels = sum(bin_obj.levels.values()) + max_possible = bin_obj.level_goal * len(bin_obj.KEYS) + bin_percentage = (total_levels / max_possible) * 100 if max_possible > 0 else 0 + total_percentage += bin_percentage + bin_count += 1 + if bin_count > 0: + calculated_completion = int(total_percentage / bin_count) + self.completion = calculated_completion + frame_bbox = self.canvas.bbox(self.ui_elements['top_frame']) + frame_left = frame_bbox[0] + frame_top = frame_bbox[1] + frame_bottom = frame_bbox[3] + logo_bbox = self.canvas.bbox(self.ui_elements['logo']) + logo_left = logo_bbox[0] + location_right = frame_left + if 'location' in self.ui_elements: + location_bbox = self.canvas.bbox(self.ui_elements['location']) + location_right = location_bbox[2] + 20 + fill_right = logo_left + 15 + fillable_width = fill_right - location_right - 4 + fill_width = (self.completion / 100) * fillable_width + if self.completion == 0: + fill_left = fill_right + else: + fill_left = fill_right - fill_width + fill_left = max(fill_left, location_right) + if 'completion' in self.ui_elements: + completion_text = f"{self.completion}% Complete" + outlined_img = self.create_outlined_text(completion_text, font_size=20, stroke_width=1) + self.completion_photo = outlined_img + self.canvas.itemconfig(self.ui_elements['completion'], image=self.completion_photo) + completion_x = logo_left - 20 + if 'completion' in self.ui_elements: + self.canvas.coords( + self.ui_elements['completion'], + completion_x, self.margin + 40/2 + ) + self.canvas.tag_raise(self.ui_elements['completion']) + if hasattr(self, 'progress_fill_id'): + self.canvas.delete(self.progress_fill_id) # pylint: disable=access-member-before-definition + self.progress_fill_id = self.canvas.create_rectangle( # pylint: disable=attribute-defined-outside-init + fill_left, frame_top + 2, + fill_right, frame_bottom - 2, + fill=self.palette.FG, + outline="", + width=0 + ) + if 'location' in self.ui_elements: + self.canvas.tag_raise(self.ui_elements['location']) + if 'completion' in self.ui_elements: + self.canvas.tag_raise(self.ui_elements['completion']) + if 'logo' in self.ui_elements: + self.canvas.tag_raise(self.ui_elements['logo']) + + def toggle_fullscreen(self, event=None): + """Toggle fullscreen mode""" + is_fullscreen = self.root.attributes("-fullscreen") + self.root.attributes("-fullscreen", not is_fullscreen) + return "break" + + def exit_fullscreen(self, event=None): + """Exit fullscreen mode and quit application""" + self.root.attributes("-fullscreen", False) + self.exit_program() + return "break" + + def exit_program(self, event=None): + """Exit the program and clean up resources""" + if hasattr(self, 'haptic_enabled') and self.haptic_enabled: + try: + self.drv.stop() + except Exception as e: + print(f"Error stopping haptic motor: {e}") + self.root.quit() + self.root.destroy() + + def move_logo(self): + """Animate the logo bouncing around""" + if self.screen == 1 and self.canvas_image: + self.x_pos += self.x_speed + self.y_pos += self.y_speed + if self.x_pos + self.photo.width() >= self.screen_width or self.x_pos <= 0: + self.x_speed = -self.x_speed + if self.y_pos + self.photo.height() >= self.screen_height or self.y_pos <= 0: + self.y_speed = -self.y_speed + self.canvas.coords(self.canvas_image, self.x_pos, self.y_pos) + + def create_number_grid(self): + """Create the grid of numbers with proper horizontal centering""" + for number in self.data_numbers: + self.canvas.delete(number.text_id) + self.data_numbers.clear() + num_columns = 22 + num_rows = 8 + usable_width = self.screen_width - (2 * self.margin) + header_height = 40 + bottom_line_y = self.screen_height - self.margin - 80 - 25 + total_available_height = bottom_line_y - (self.margin + header_height + 15) + horizontal_spacing = usable_width / (num_columns + 1) + vertical_spacing = total_available_height / (num_rows + 1) + grid_width = horizontal_spacing * num_columns + grid_height = vertical_spacing * num_rows + start_x = self.margin + (usable_width - grid_width) / 2 + horizontal_spacing/2 + start_y = self.margin + header_height + 15 + (total_available_height + - grid_height) / 2 + vertical_spacing/2 + for row in range(num_rows): + for col in range(num_columns): + x = start_x + (col * horizontal_spacing) + y = start_y + (row * vertical_spacing) + data_number = DataNumber(x, y, self.canvas, self.base_size, palette=self.palette) + self.data_numbers.append(data_number) + + def update_numbers(self): + """Update the number animations""" + if self.screen == 2: + for number in self.data_numbers: + if number.bin_it: + number.go_bin() + else: + number.go_home() + + def update_bins(self): + """Update the bin animations and ensure proper z-ordering""" + if self.screen == 2: + self.update_total_refined() + self.check_for_completion() + + for bin_obj in self.bins: + bin_obj.update() + if 'bottom_shield' in self.ui_elements: + self.canvas.tag_raise(self.ui_elements['bottom_shield']) + if 'bottom_frame' in self.ui_elements: + self.canvas.tag_raise(self.ui_elements['bottom_frame']) + if 'serial' in self.ui_elements: + self.canvas.tag_raise(self.ui_elements['serial']) + for number in self.data_numbers: + if number.bin_it and number.bin == bin_obj: + if hasattr(bin_obj, 'level_elements'): + for element_id in bin_obj.level_elements.values(): + self.canvas.tag_raise(number.text_id, element_id) + + def toggle_screen(self, event): + """Toggle between logo and number screens with autosave""" + if self.screen == 1: + self.root.attributes("-fullscreen", True) + self.screen = 2 + if self.canvas_image: + self.canvas.itemconfig(self.canvas_image, state='hidden') + self.canvas.configure(bg=self.palette.BG) + self.completion = 0 + self.total_refined = 0 + if hasattr(self, 'completion_triggered'): + self.completion_triggered = False + if hasattr(self, 'completion_message_elements'): + for element_id in self.completion_message_elements.values(): + self.canvas.delete(element_id) + self.completion_message_elements = {} + self.create_ui_elements() + self.create_bins() + self.create_number_grid() + self.wiggle_timer = 0 + self.waiting_for_next_wiggle = False + self.next_wiggle_timer = 0 + load_successful = self.load_progress() + all_bins_full = all(bin_obj.is_full() for bin_obj in self.bins) + if all_bins_full: + print("All bins were previously full. Resetting progress to start over.") + for bin_obj in self.bins: + bin_obj.levels = { + 'WO': 0, + 'FC': 0, + 'DR': 0, + 'MA': 0 + } + bin_obj.update_progress_bar() + self.total_refined = 0 + self.completion = 0 + self.update_top_progress_bar() + elif not load_successful: + self.total_refined = 0 + self.completion = 0 + for bin_obj in self.bins: + bin_obj.levels = { + 'WO': 0, + 'FC': 0, + 'DR': 0, + 'MA': 0 + } + bin_obj.update_progress_bar() + self.update_top_progress_bar() + self.select_random_wiggle_group() + else: + self.save_progress() + self.root.attributes("-fullscreen", True) + self.wiggle_numbers.clear() + self.wiggle_timer = 0 + self.waiting_for_next_wiggle = False + self.next_wiggle_timer = 0 + if hasattr(self, 'progress_fill_id'): + self.canvas.delete(self.progress_fill_id) + for element_id in self.ui_elements.values(): + self.canvas.delete(element_id) + self.ui_elements.clear() + for bin_obj in self.bins: + if hasattr(bin_obj, 'visual_elements'): + for element_id in bin_obj.visual_elements.values(): + self.canvas.delete(element_id) + if hasattr(bin_obj, 'level_elements'): + for element_id in bin_obj.level_elements.values(): + self.canvas.delete(element_id) + if hasattr(bin_obj, 'progress_bar_elements'): + for element_id in bin_obj.progress_bar_elements.values(): + self.canvas.delete(element_id) + self.bins.clear() + for number in self.data_numbers: + self.canvas.delete(number.text_id) + self.data_numbers.clear() + if hasattr(self, 'top_progress_elements'): + for element_id in self.top_progress_elements.values(): + self.canvas.delete(element_id) + self.top_progress_elements.clear() + if hasattr(self, 'completion_message_elements'): + for element_id in self.completion_message_elements.values(): + self.canvas.delete(element_id) + self.completion_message_elements.clear() + if self.selection_rect: + self.canvas.delete(self.selection_rect) + self.selection_rect = None + self.selection_active = False + self.screen = 1 + self.canvas.configure(bg=self.palette.BG) + if self.canvas_image: + self.canvas.itemconfig(self.canvas_image, state='normal') + self.canvas.tag_raise(self.canvas_image) + if hasattr(self, 'x_pos') and hasattr(self, 'y_pos'): + self.canvas.coords(self.canvas_image, self.x_pos, self.y_pos) + + def start_selection(self, event): + """Start a selection box when mouse is pressed""" + if self.screen == 2: + self.selection_start = (event.x, event.y) + self.selection_rect = self.canvas.create_rectangle( + event.x, event.y, event.x, event.y, + outline=self.palette.SELECT, width=2, dash=(5, 5) + ) + self.selection_active = True + + def update_selection(self, event): + """Update the selection box when mouse is dragged""" + if self.screen == 2 and self.selection_active: + x1, y1 = self.selection_start + x2, y2 = event.x, event.y + self.canvas.coords(self.selection_rect, x1, y1, x2, y2) + + def end_selection(self, event): + """Process the selection when mouse is released""" + if self.screen == 2 and self.selection_active: + x1, y1 = self.selection_start + x2, y2 = event.x, event.y + selected_numbers = [] + for number in self.data_numbers: + if number.inside(x1, y1, x2, y2) and not number.bin_it: + selected_numbers.append(number) + number.turn(self.palette.SELECT) + wiggle_selected = [n for n in selected_numbers if n in self.wiggle_numbers] + non_wiggle_selected = [n for n in selected_numbers if n not in self.wiggle_numbers] + wiggle_capture_percent = (len(wiggle_selected) / len(self.wiggle_numbers) + if self.wiggle_numbers else 0) + valid_selection = ( + wiggle_capture_percent >= 0.7 and + len(non_wiggle_selected) <= len(wiggle_selected) * 2 + ) + if valid_selection: + self.pulse_selected(wiggle_selected, 3) + self.refine_numbers(wiggle_selected) + for number in wiggle_selected: + if number in self.wiggle_numbers: + self.wiggle_numbers.remove(number) + number.needs_refinement = False + self.waiting_for_next_wiggle = True + self.next_wiggle_timer = 0 + else: + for number in selected_numbers: + number.turn(self.palette.FG) + self.update_overall_completion() + self.canvas.delete(self.selection_rect) + self.selection_active = False + + def pulse_selected(self, numbers, count, size_factor=1.5, current=0): + """Create a pulsing animation for selected numbers""" + if current >= count * 2: + return + if current < count: + progress = current / count + size_mod = 1.0 + (progress * (size_factor - 1.0)) + else: + progress = (current - count) / count + size_mod = size_factor - (progress * (size_factor - 1.0)) + for number in numbers: + number.set_size(self.base_size * size_mod) + self.root.after(50, lambda: self.pulse_selected(numbers, count, size_factor, current + 1)) + + def refine_numbers(self, numbers): + """Send selected numbers to bins based on their horizontal position""" + wiggling_numbers = [n for n in numbers if n in self.wiggle_numbers] + if not wiggling_numbers: + return + DataNumber.reset_active_bin() + all_bins_full = all(bin_obj.is_full() for bin_obj in self.bins) + if all_bins_full: + print("All bins are full - can't refine more numbers") + return + number_positions = {} + for number in wiggling_numbers: + target_bin = number.get_non_full_bin_for_position(self.bins) + if target_bin: + if target_bin not in number_positions: + number_positions[target_bin] = [] + number_positions[target_bin].append(number) + selected_bin = None + max_count = 0 + for bin_obj, bin_numbers in number_positions.items(): + if len(bin_numbers) > max_count: + max_count = len(bin_numbers) + selected_bin = bin_obj + if selected_bin: + DataNumber.active_bin = selected_bin + for number in wiggling_numbers: + success = number.refine(bin_obj=selected_bin) + if not success: + number.needs_refinement = False + if number in self.wiggle_numbers: + self.wiggle_numbers.remove(number) + + def select_random_wiggle_group(self): + """Randomly select a CLUSTERED group of numbers that need refinement""" + for number in self.wiggle_numbers: + number.needs_refinement = False + number.wiggle_offset_x = 0 + number.wiggle_offset_y = 0 + self.wiggle_numbers.clear() + all_bins_full = all(bin_obj.is_full() for bin_obj in self.bins) + if all_bins_full: + return + if not self.data_numbers: + return + available_numbers = [n for n in self.data_numbers if not n.bin_it] + if not available_numbers: + return + seed_number = random.choice(available_numbers) + for number in available_numbers: + number.distance_to_seed = calculate_distance( + seed_number.x, seed_number.y, number.x, number.y + ) + available_numbers.sort(key=lambda n: n.distance_to_seed) + cluster_size = random.randint(3, 6) + clustered_numbers = available_numbers[:min(cluster_size, len(available_numbers))] + self.wiggle_numbers = clustered_numbers + for number in self.wiggle_numbers: + number.needs_refinement = True + + def wiggle_selected_numbers(self): + """Apply smooth, floating wiggle effect to numbers + that need refinement and update haptics + """ + if self.screen == 2 and self.wiggle_numbers: + self.wiggle_phase_x += self.wiggle_speed_x + self.wiggle_phase_y += self.wiggle_speed_y + self.wiggle_phase_rotation += self.wiggle_speed_rotation + proximity_factor = 0 + if len(self.wiggle_numbers) > 0: + center_x = sum(number.x for number in + self.wiggle_numbers) / len(self.wiggle_numbers) + center_y = sum(number.y for number in + self.wiggle_numbers) / len(self.wiggle_numbers) + distance_to_mouse = math.sqrt((self.mouse_x - center_x)**2 + + (self.mouse_y - center_y)**2) + normalized_distance = max(0, min(1, distance_to_mouse / self.proximity_threshold)) + proximity_factor = 1.0 - normalized_distance + dynamic_amplitude = self.base_wiggle_amplitude + ( + (self.max_wiggle_amplitude - self.base_wiggle_amplitude) * + proximity_factor**1.5 + ) + self.update_haptic_intensity(proximity_factor) + else: + dynamic_amplitude = self.base_wiggle_amplitude + self.update_haptic_intensity(0) + for number in self.wiggle_numbers: + if not number.bin_it: + index = self.wiggle_numbers.index(number) + phase_offset = index * 0.5 + x_freq2 = 0.37 + y_freq2 = 0.29 + primary_x = math.sin(self.wiggle_phase_x + + phase_offset) * dynamic_amplitude + primary_y = math.cos(self.wiggle_phase_y + + phase_offset) * dynamic_amplitude * 0.8 + secondary_x = math.sin(self.wiggle_phase_x * x_freq2 + + phase_offset * 1.3) * dynamic_amplitude * 0.3 + secondary_y = math.cos(self.wiggle_phase_y * y_freq2 + + phase_offset * 0.9) * dynamic_amplitude * 0.25 + rot_x = math.cos(self.wiggle_phase_rotation + + index * 0.7) * dynamic_amplitude * 0.2 + rot_y = math.sin(self.wiggle_phase_rotation + + index * 0.7) * dynamic_amplitude * 0.2 + offset_x = primary_x + secondary_x + rot_x + offset_y = primary_y + secondary_y + rot_y + number.wiggle_offset_x = offset_x + number.wiggle_offset_y = offset_y + number.show_wiggle(proximity_factor) + + def check_for_completion(self): + """Check if all bins are full and trigger completion sequence if needed""" + if self.screen != 2: + return + if hasattr(self, 'completion_triggered') and self.completion_triggered: + return + all_bins_full = all(bin_obj.is_full() for bin_obj in self.bins) + if self.bins: + total_refined = sum(sum(bin_obj.levels.values()) for bin_obj in self.bins) + completion_pct = (total_refined / self.total_goal) * 100 + else: + completion_pct = 0 + if all_bins_full or completion_pct >= 100: + self.completion_sequence() + + def completion_sequence(self): + """Start sequence for completion""" + self.completion_triggered = True + self.fade_out_numbers() + self.completion = 100 + self.update_top_progress_bar() + + def fade_out_numbers(self): + """Fade out all numbers gradually""" + self.fade_step = 0 + self.fade_timer = 0 + self.max_fade_steps = 20 + self.animate_number_fade() + + def animate_number_fade(self): + """Animate the fading out of all numbers""" + if self.fade_step >= self.max_fade_steps: + self.show_completion_message() + return + alpha = int(255 * (1 - (self.fade_step / self.max_fade_steps))) + for number in self.data_numbers: + number.alpha = alpha + number.update_display() + self.fade_step += 1 + self.root.after(50, self.animate_number_fade) + + def show_completion_message(self): + """Show the completion celebration message""" + if hasattr(self, 'completion_message_elements'): + for element_id in self.completion_message_elements.values(): + self.canvas.delete(element_id) + self.completion_message_elements = {} + if 'top_curve' in self.ui_elements: + top_y = self.canvas.coords(self.ui_elements['top_curve'])[1] + 15 + else: + top_y = self.margin + 80 + if 'bottom_curve' in self.ui_elements: + bottom_y = self.canvas.coords(self.ui_elements['bottom_curve'])[1] - 15 + else: + bottom_y = self.screen_height - self.margin - 130 + center_x = self.screen_width / 2 + center_y = (top_y + bottom_y) / 2 + self.completion_message_elements['percent'] = self.canvas.create_text( + center_x, center_y - 30, + text="100%", + font=('Courier', 48, 'bold'), + fill=self.palette.FG, + anchor='center' + ) + self.completion_message_elements['praise'] = self.canvas.create_text( + center_x, center_y + 30, + text="Praise Kier", + font=('Courier', 36, 'bold'), + fill=self.palette.FG, + anchor='center' + ) + self.glow_step = 0 + self.animate_completion_glow() + + def animate_completion_glow(self): + """Create a subtle glowing/pulsing effect for the completion message""" + if (not hasattr(self, 'completion_message_elements') + or 'percent' not in self.completion_message_elements): + return + glow_factor = 0.8 + (0.2 * (math.sin(self.glow_step / 10) + 1) / 2) + percent_size = int(48 * glow_factor) + praise_size = int(36 * glow_factor) + self.canvas.itemconfig( + self.completion_message_elements['percent'], + font=('Courier', percent_size, 'bold') + ) + self.canvas.itemconfig( + self.completion_message_elements['praise'], + font=('Courier', praise_size, 'bold') + ) + self.glow_step += 1 + self.root.after(100, self.animate_completion_glow) + + def animate(self): + """Main animation loop""" + if self.screen == 1: + self.root.attributes("-fullscreen", True) + self.move_logo() + else: + self.update_bins() + self.update_numbers() + for number in self.data_numbers: + self.apply_mouse_avoidance(number) + if self.waiting_for_next_wiggle: + self.next_wiggle_timer += 1 + self.next_wiggle_delay = random.randint(180, 240) + if self.next_wiggle_timer >= self.next_wiggle_delay: + self.waiting_for_next_wiggle = False + self.next_wiggle_timer = 0 + self.select_random_wiggle_group() + elif (not self.wiggle_numbers and not self.waiting_for_next_wiggle + and self.wiggle_timer == 0): + self.select_random_wiggle_group() + self.wiggle_selected_numbers() + self.root.after(20, self.animate) + + def run(self): + """Start the application""" + self.root.mainloop() + +if __name__ == "__main__": + app = MacrodataRefinementTerminal() + app.run() diff --git a/Raspberry_Pi_Severance_MDR_Terminal/mdr.service b/Raspberry_Pi_Severance_MDR_Terminal/mdr.service new file mode 100644 index 000000000..1f8322ddf --- /dev/null +++ b/Raspberry_Pi_Severance_MDR_Terminal/mdr.service @@ -0,0 +1,18 @@ +[Unit] +Description=Macrodata Refinement +After=multi-user.service + +[Service] +Type=simple +PAMName=login +User=pi-lumon +Group=pi-lumon +WorkingDirectory=/home/pi-lumon +Environment=DISPLAY=:0 +Environment=XAUTHORITY=/home/pi-lumon/.Xauthority +ExecStart=/home/pi-lumon/lumon/bin/python /home/pi-lumon/lumon.py +Restart=on-failure +RestartSec=5s + +[Install] +WantedBy=multi-user.target diff --git a/Raspberry_Pi_Severance_MDR_Terminal/palette.py b/Raspberry_Pi_Severance_MDR_Terminal/palette.py new file mode 100644 index 000000000..5775c7faa --- /dev/null +++ b/Raspberry_Pi_Severance_MDR_Terminal/palette.py @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# SPDX-License-Identifier: MIT + +class Palette: + """Color palette based on the Severance MDR terminal""" + def __init__(self): + self.BG = '#010A13' # Dark blue-black background + self.FG = '#ABFFE9' # Light cyan text + self.SELECT = '#ABFFE9' # Selection color diff --git a/Raspberry_Pi_Thermal_Camera_Overlay/code.py b/Raspberry_Pi_Thermal_Camera_Overlay/code.py new file mode 100644 index 000000000..84e3da4c4 --- /dev/null +++ b/Raspberry_Pi_Thermal_Camera_Overlay/code.py @@ -0,0 +1,316 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +Thermal Camera Overlay for Raspberry Pi 4, +PiCamera 3 and STEMMA MLX90640 + +Inspired by PitFusion Thermal Imager +""" + +import time +import numpy as np +import cv2 +import board +import busio +import adafruit_mlx90640 +from picamera2 import Picamera2 +from PIL import Image + +# Temperature range for thermal camera (in Celsius) +MIN_TEMP = 20.0 +MAX_TEMP = 35.0 + +# Thermal overlay opacity (0.0 = invisible, 1.0 = fully opaque) +THERMAL_OPACITY = 0.7 + +# Display window size +WINDOW_WIDTH = 1280 +WINDOW_HEIGHT = 720 + +# Camera settings +CAMERA_WIDTH = 1280 +CAMERA_HEIGHT = 720 + +SKIP_FRAMES = 2 # Process every Nth frame for thermal +frame_counter = 0 + +# Thermal camera size +THERMAL_WIDTH = 32 +THERMAL_HEIGHT = 24 + +# Thermal zoom factor (1.7x to compensate for FoV difference) +# Thermal camera FoV: 110°x75°, Pi camera FoV: 66°x41° +# Ratio: 66/110 = 0.6, so we need 1/0.6 = 1.67x zoom +THERMAL_ZOOM = 1.7 + +# Camera crop settings to compensate for thermal offset +# This crops the camera image to match the thermal coverage area +CAMERA_CROP_LEFT = 65 # Match thermal X offset +CAMERA_CROP_TOP = 85 # Match thermal Y offset +CAMERA_CROP_RIGHT = 0 # No crop on right +CAMERA_CROP_BOTTOM = 0 # No crop on bottom + +# Calculate effective camera size after cropping +CAMERA_CROP_WIDTH = CAMERA_WIDTH - CAMERA_CROP_LEFT - CAMERA_CROP_RIGHT +CAMERA_CROP_HEIGHT = CAMERA_HEIGHT - CAMERA_CROP_TOP - CAMERA_CROP_BOTTOM + +# ============= SETUP THERMAL CAMERA ============= +print("Setting up thermal camera...") +i2c = busio.I2C(board.SCL, board.SDA) +mlx = adafruit_mlx90640.MLX90640(i2c) +mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_4_HZ + +# Create array to hold thermal data +thermal_frame = np.zeros(768, dtype=np.float32) + +# ============= SETUP REGULAR CAMERA ============= +print("Setting up Pi camera...") +picam2 = Picamera2() +camera_config = picam2.create_preview_configuration( + main={"size": (CAMERA_WIDTH, CAMERA_HEIGHT), "format": "RGB888"}, + buffer_count=2, # Reduce buffer count for lower latency + queue=False # Don't queue frames +) +picam2.configure(camera_config) +picam2.start() +picam2.set_controls({"ExposureTime": 20000, "AnalogueGain": 1.0}) +time.sleep(2) + +# ============= CREATE THERMAL COLORMAP ============= +def create_thermal_colormap(): + """Create a colormap for thermal visualization""" + # Define color points (blue -> cyan -> green -> yellow -> orange -> red) + colors = np.array([ + [0, 0, 64], # Dark blue (cold) + [0, 0, 255], # Blue + [0, 255, 255], # Cyan + [0, 255, 0], # Green + [255, 255, 0], # Yellow + [255, 128, 0], # Orange + [255, 0, 0], # Red (hot) + ], dtype=np.uint8) + + # Create smooth gradient between colors + colormap = np.zeros((256, 3), dtype=np.uint8) + positions = np.linspace(0, len(colors)-1, 256) + + for i in range(256): + pos = positions[i] + idx = int(pos) + frac = pos - idx + + if idx >= len(colors) - 1: + colormap[i] = colors[-1] + else: + colormap[i] = (1 - frac) * colors[idx] + frac * colors[idx + 1] + + colormap = colormap[::-1] # Reverse the colormap + return colormap +the_colormap = create_thermal_colormap() + +# ============= HELPER FUNCTIONS ============= +def process_thermal_frame(thermal_data, colormap): + """Convert thermal data to colored image""" + # Calculate temperature statistics + min_temp = np.min(thermal_data) + max_temp = np.max(thermal_data) + avg_temp = np.mean(thermal_data) + if min_temp < -100: + min_temp = MIN_TEMP + avg_temp = (MIN_TEMP + MAX_TEMP) / 2 + + # Normalize temperature data to 0-255 range + normalized = np.clip( + (thermal_data - MIN_TEMP) / (MAX_TEMP - MIN_TEMP) * 255, + 0, 255 + ).astype(np.uint8) + + # Apply colormap + colored = colormap[normalized] + + # Reshape to 2D image (24x32x3) + thermal_image = colored.reshape(THERMAL_HEIGHT, THERMAL_WIDTH, 3) + + # Flip horizontally to match camera view + thermal_image = np.fliplr(thermal_image) + + # Scale up to camera size using PIL for smooth interpolation + pil_thermal = Image.fromarray(thermal_image) + + # Apply zoom by scaling to a larger size than the camera + scaled_width = int(CAMERA_WIDTH * THERMAL_ZOOM) + scaled_height = int(CAMERA_HEIGHT * THERMAL_ZOOM) + pil_thermal = pil_thermal.resize((scaled_width, scaled_height), Image.BICUBIC) + + # Crop the center to match camera size (this creates the zoom effect) + thermal_array = np.array(pil_thermal) + crop_x = (scaled_width - CAMERA_WIDTH) // 2 + crop_y = (scaled_height - CAMERA_HEIGHT) // 2 + thermal_cropped = thermal_array[crop_y:crop_y+CAMERA_HEIGHT, crop_x:crop_x+CAMERA_WIDTH] + + return thermal_cropped, min_temp, max_temp, avg_temp + +def blend_images(camera_image, thermal_image, opacity): + """Blend camera and thermal images with position offset""" + # Create a canvas the same size as the camera image + canvas = camera_image.copy() + + # Calculate position with offset + x_offset = 0 + y_offset = 0 + + # Ensure the thermal image fits within bounds + x_start = max(0, x_offset) + y_start = max(0, y_offset) + x_end = min(camera_image.shape[1], x_offset + thermal_image.shape[1]) + y_end = min(camera_image.shape[0], y_offset + thermal_image.shape[0]) + + # Calculate the corresponding region in the thermal image + thermal_x_start = max(0, -x_offset) + thermal_y_start = max(0, -y_offset) + thermal_x_end = thermal_x_start + (x_end - x_start) + thermal_y_end = thermal_y_start + (y_end - y_start) + + # Blend only the overlapping region + if x_end > x_start and y_end > y_start: + canvas[y_start:y_end, x_start:x_end] = ( + canvas[y_start:y_end, x_start:x_end] * (1 - opacity) + + thermal_image[thermal_y_start:thermal_y_end, thermal_x_start:thermal_x_end] * opacity + ) + + return canvas.astype(np.uint8) + +def add_temperature_scale(image, colormap): + """Add temperature scale bar to the image""" + # Create scale bar + scale_height = 20 + scale_width = 200 + scale_x = image.shape[1] - scale_width - 20 + scale_y = 90 # Moved down to make room for buttons + + # Draw temperature gradient + for i in range(scale_width): + temp_normalized = i / scale_width + color_idx = int(temp_normalized * 255) + color = colormap[color_idx] + cv2.line(image, + (scale_x + i, scale_y), + (scale_x + i, scale_y + scale_height), + color.tolist(), 1) + + # Add temperature labels + cv2.putText(image, f"{MIN_TEMP:.0f}C", + (scale_x - 35, scale_y + 15), + cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) + cv2.putText(image, f"{MAX_TEMP:.0f}C", + (scale_x + scale_width + 5, scale_y + 15), + cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) + + # Draw border around scale + cv2.rectangle(image, + (scale_x - 1, scale_y - 1), + (scale_x + scale_width + 1, scale_y + scale_height + 1), + (255, 255, 255), 1) + +# ============= MAIN LOOP ============= +print("Starting thermal camera overlay...") +print("Use Up/Down keys to increase/decrease max temp") +print("Use Left/Right keys to increase/decrease min temp") +print("Use +/- keys to increase/decrease overlay opacity") +print("Use Q key to exit") + +cv2.namedWindow('Thermal Overlay', cv2.WINDOW_NORMAL) +cv2.resizeWindow('Thermal Overlay', WINDOW_WIDTH, WINDOW_HEIGHT) + +# Temperature statistics +temp_stats = {"min": 0, "max": 0, "avg": 0} +last_thermal_colored = None + +try: + while True: + + # Read thermal data (only every SKIP_FRAMES frames) + if frame_counter % SKIP_FRAMES == 0: + try: + mlx.getFrame(thermal_frame) + # Process thermal data to colored image + last_thermal_colored, temp_stats["min"], temp_stats["max"], temp_stats["avg"] = process_thermal_frame(thermal_frame, the_colormap) # pylint: disable=line-too-long + except Exception as e: # pylint: disable=broad-except + print(f"Thermal read error: {e}") + + frame_counter += 1 + + # Use the last processed thermal frame + if last_thermal_colored is not None: + thermal_colored = last_thermal_colored + else: + # Create a blank thermal image if we don't have one yet + thermal_colored = np.zeros((CAMERA_HEIGHT, CAMERA_WIDTH, 3), dtype=np.uint8) + + # Capture camera frame + camera_frame = picam2.capture_array() + + # Crop the camera frame to match thermal coverage area + camera_cropped = camera_frame[ + CAMERA_CROP_TOP:CAMERA_HEIGHT-CAMERA_CROP_BOTTOM, + CAMERA_CROP_LEFT:CAMERA_WIDTH-CAMERA_CROP_RIGHT + ] + + # Resize cropped camera back to full display size + camera_resized = cv2.resize(camera_cropped, (CAMERA_WIDTH, CAMERA_HEIGHT), + interpolation=cv2.INTER_LINEAR) + + # Blend camera and thermal images (now both are aligned) + overlay_image = blend_images(camera_resized, thermal_colored, THERMAL_OPACITY) + + # Add temperature scale + add_temperature_scale(overlay_image, the_colormap) + + # Add status text with temperature statistics and FPS + status_text = f"Range: {MIN_TEMP:.0f}-{MAX_TEMP:.0f}C | Opacity: {THERMAL_OPACITY:.1f} | " + status_text += f"Min: {temp_stats['min']:.1f}C | Max: {temp_stats['max']:.1f}C | Avg: {temp_stats['avg']:.1f}C | " # pylint: disable=line-too-long + cv2.putText(overlay_image, status_text, + (10, overlay_image.shape[0] - 10), + cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2) + + # Display the image + cv2.imshow('Thermal Overlay', overlay_image) + + # Check if window was closed + if cv2.getWindowProperty('Thermal Overlay', cv2.WND_PROP_VISIBLE) < 1: + break + + key_action = cv2.waitKey(1) & 0xFF + if key_action == ord('q'): + raise KeyboardInterrupt + if key_action == 82: + MAX_TEMP = min(MAX_TEMP + 1, 100) + print(f"Max temp: {MAX_TEMP:.1f}C") + elif key_action == 84: + MAX_TEMP = max(MAX_TEMP - 1, MIN_TEMP + 1) + print(f"Max temp: {MAX_TEMP:.1f}C") + elif key_action == 81: + MIN_TEMP = max(MIN_TEMP - 1, -20) + print(f"Min temp: {MIN_TEMP:.1f}C") + elif key_action == 83: + MIN_TEMP = min(MIN_TEMP + 1, MAX_TEMP - 1) + print(f"Min temp: {MIN_TEMP:.1f}C") + elif key_action == ord('+'): + THERMAL_OPACITY = min(THERMAL_OPACITY + 0.1, 1.0) + print(f"Opacity: {THERMAL_OPACITY:.1f}") + elif key_action == ord('-'): + THERMAL_OPACITY = max(THERMAL_OPACITY - 0.1, 0.0) + print(f"Opacity: {THERMAL_OPACITY:.1f}") + elif key_action == ord('z'): + THERMAL_OPACITY = not THERMAL_OPACITY + print(f"Opacity: {THERMAL_OPACITY:.1f}") + +except KeyboardInterrupt: + print("\nShutting down...") + +finally: + print("Cleaning up...") + cv2.destroyAllWindows() + cv2.waitKey(1) + picam2.stop() diff --git a/Resin_table_circuitplayground_modes/Resin_table_circuitplayground_modes.ino b/Resin_table_circuitplayground_modes/Resin_table_circuitplayground_modes.ino index 5bfb604b2..c1628de70 100644 --- a/Resin_table_circuitplayground_modes/Resin_table_circuitplayground_modes.ino +++ b/Resin_table_circuitplayground_modes/Resin_table_circuitplayground_modes.ino @@ -8,6 +8,10 @@ #include #include +#if defined(FASTLED_VERSION) && FASTLED_VERSION > 3010001 + #error "FastLED 3.10.2 has known compile issues with SAMD boards. Please downgrade to FastLED 3.10.1" +#endif + // tell FastLED all about the Circuit Playground's layout #define DATA_PIN A1 //LED data on pin A1 diff --git a/Shadow_Box/code.py b/Shadow_Box/code.py index 72717a7c5..74d9cd6ff 100644 --- a/Shadow_Box/code.py +++ b/Shadow_Box/code.py @@ -5,12 +5,14 @@ """ Clock & sky colorbox for Adafruit MagTag: displays current time while NeoPixels provide theme lighting for the time of day. Requires WiFi -internet access -- configure credentials in secrets.py. An Adafruit IO +internet access -- configure credentials in settings.toml. An Adafruit IO user name and API key are also needed there, plus timezone and geographic coords. """ # pylint: disable=import-error + +from os import getenv import time import json import board @@ -18,12 +20,20 @@ from adafruit_magtag.magtag import MagTag import adafruit_fancyled.adafruit_fancyled as fancy -# UTC offset queries require some info from the secrets table... -try: - from secrets import secrets -except ImportError: - print('Please set up secrets.py with network credentials.') +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) # CONFIGURABLE SETTINGS ---------------------------------------------------- @@ -179,16 +189,13 @@ def blend(palette1, palette2, weight2, offset): # Since time is synced only once per hour, the extra request # isn't particularly burdensome. try: - RESPONSE = MAGTAG.network.requests.get( - 'https://io.adafruit.com/api/v2/%s/integrations/time/' - 'strftime?x-aio-key=%s&tz=%s' % (secrets.get('aio_username'), - secrets.get('aio_key'), - secrets.get('timezone')) + - '&fmt=%25z') - if RESPONSE.status_code == 200: + url = f"https://io.adafruit.com/api/v2/{aio_username}/integrations/time/strftime" + url += f'x-aio-key={aio_key}tz={getenv("timezone")}&fmt=%25z' + response = MAGTAG.network.requests.get(url) + if response.status_code == 200: # Arrives as sHHMM, convert to sHH:MM - print(RESPONSE.text) - UTC_OFFSET = RESPONSE.text[:3] + ':' + RESPONSE.text[-2:] + print(response.text) + UTC_OFFSET = response.text[:3] + ':' + response.text[-2:] except: # pylint: disable=bare-except # If query fails, prior value is kept until next query. # Only changes 2X a year anyway -- worst case, if these @@ -217,7 +224,7 @@ def blend(palette1, palette2, weight2, offset): try: URL = ('https://api.met.no/weatherapi/sunrise/2.0/.json?' 'lat=%s&lon=%s&date=%s-%s-%s&offset=%s' % - (secrets.get('latitude'), secrets.get('longitude'), + (getenv('latitude'), getenv('longitude'), str(NOW.tm_year), '{0:0>2}'.format(NOW.tm_mon), '{0:0>2}'.format(NOW.tm_mday), UTC_OFFSET)) print('Fetching sun data via', URL) diff --git a/Simple_Soil_Sensor_Demos/Arduino/metroAdvSoilSensor/.uno.test.only b/Simple_Soil_Sensor_Demos/Arduino/metroAdvSoilSensor/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Simple_Soil_Sensor_Demos/Arduino/metroAdvSoilSensor/metroAdvSoilSensor.ino b/Simple_Soil_Sensor_Demos/Arduino/metroAdvSoilSensor/metroAdvSoilSensor.ino new file mode 100644 index 000000000..d820a7cb8 --- /dev/null +++ b/Simple_Soil_Sensor_Demos/Arduino/metroAdvSoilSensor/metroAdvSoilSensor.ino @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/* Advanced Soil Sensor Demo */ + +int sensorPin = A0; +int onPin = 2; +int moisture = 0; + +void setup() { + Serial.begin(115200); + while ( !Serial ) delay(10); + pinMode(onPin, OUTPUT); + +} + +void loop() { + digitalWrite(onPin, HIGH); + delay(1000); + // read the value from the sensor: + moisture = analogRead(sensorPin); + Serial.println(moisture); + digitalWrite(onPin, LOW); + delay(1000); +} diff --git a/Simple_Soil_Sensor_Demos/Arduino/metroSimpleSoilSensor/.uno.test.only b/Simple_Soil_Sensor_Demos/Arduino/metroSimpleSoilSensor/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Simple_Soil_Sensor_Demos/Arduino/metroSimpleSoilSensor/metroSimpleSoilSensor.ino b/Simple_Soil_Sensor_Demos/Arduino/metroSimpleSoilSensor/metroSimpleSoilSensor.ino new file mode 100644 index 000000000..1b1939ab9 --- /dev/null +++ b/Simple_Soil_Sensor_Demos/Arduino/metroSimpleSoilSensor/metroSimpleSoilSensor.ino @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/* Simple Soil Sensor Demo */ + +int sensorPin = A0; +int moisture = 0; + +void setup() { + Serial.begin(115200); + while ( !Serial ) delay(10); + +} + +void loop() { + // read the value from the sensor: + moisture = analogRead(sensorPin); + Serial.println(moisture); + delay(2000); +} diff --git a/Simple_Soil_Sensor_Demos/Arduino/microBitAdvSoilSensor/.none.test.only b/Simple_Soil_Sensor_Demos/Arduino/microBitAdvSoilSensor/.none.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Simple_Soil_Sensor_Demos/Arduino/microBitAdvSoilSensor/microBitAdvSoilSensor.ino b/Simple_Soil_Sensor_Demos/Arduino/microBitAdvSoilSensor/microBitAdvSoilSensor.ino new file mode 100644 index 000000000..20b9546c2 --- /dev/null +++ b/Simple_Soil_Sensor_Demos/Arduino/microBitAdvSoilSensor/microBitAdvSoilSensor.ino @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/* micro:bit Advanced Soil Sensor Demo */ + +#include + +Adafruit_Microbit_Matrix microbit; + +int sensorPin = 0; +int onPin = 2; +int moisture = 0; + +const uint8_t + frown_bmp[] = + { B00000, + B01010, + B00000, + B01110, + B10001, }; +const uint8_t + smile_bmp[] = + { B00000, + B01010, + B00000, + B10001, + B01110, }; + +void setup() { + Serial.begin(115200); + while ( !Serial ) delay(10); + Serial.println("micro:bit advanced soil sensor"); + microbit.begin(); + pinMode(onPin, OUTPUT); + +} + +void loop() { + digitalWrite(onPin, HIGH); + delay(50); + // read the value from the sensor: + moisture = analogRead(sensorPin); + Serial.print("Soil moisture: "); + Serial.println(moisture); + if (moisture > 200) { + microbit.show(smile_bmp); + } else { + microbit.show(frown_bmp); + } + digitalWrite(onPin, LOW); + delay(5000); +} diff --git a/Simple_Soil_Sensor_Demos/Arduino/microBitSimpleSoilSensor/.none.test.only b/Simple_Soil_Sensor_Demos/Arduino/microBitSimpleSoilSensor/.none.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Simple_Soil_Sensor_Demos/Arduino/microBitSimpleSoilSensor/microBitSimpleSoilSensor.ino b/Simple_Soil_Sensor_Demos/Arduino/microBitSimpleSoilSensor/microBitSimpleSoilSensor.ino new file mode 100644 index 000000000..96b27e35b --- /dev/null +++ b/Simple_Soil_Sensor_Demos/Arduino/microBitSimpleSoilSensor/microBitSimpleSoilSensor.ino @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/* micro:bit Simple Soil Sensor Demo */ + +#include + +Adafruit_Microbit_Matrix microbit; + +int sensorPin = 0; +int moisture = 0; + +const uint8_t + frown_bmp[] = + { B00000, + B01010, + B00000, + B01110, + B10001, }; +const uint8_t + smile_bmp[] = + { B00000, + B01010, + B00000, + B10001, + B01110, }; + +void setup() { + Serial.begin(115200); + while ( !Serial ) delay(10); + Serial.println("micro:bit simple soil sensor"); + microbit.begin(); + +} + +void loop() { + // read the value from the sensor: + moisture = analogRead(sensorPin); + Serial.print("Soil moisture: "); + Serial.println(moisture); + if (moisture > 200) { + microbit.show(smile_bmp); + } else { + microbit.show(frown_bmp); + } + delay(5000); +} diff --git a/Simple_Soil_Sensor_Demos/CircuitPython_Advanced/code.py b/Simple_Soil_Sensor_Demos/CircuitPython_Advanced/code.py new file mode 100644 index 000000000..d60cc31af --- /dev/null +++ b/Simple_Soil_Sensor_Demos/CircuitPython_Advanced/code.py @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import time +import board +from analogio import AnalogIn +from digitalio import DigitalInOut, Direction + +sensor_power = DigitalInOut(board.D5) +sensor_power.direction = Direction.OUTPUT + +analog_in = AnalogIn(board.A0) + +while True: + sensor_power.value = True + print(f"Soil Moisture: {analog_in.value}") + sensor_power.value = False + time.sleep(5) diff --git a/Simple_Soil_Sensor_Demos/CircuitPython_Simple/code.py b/Simple_Soil_Sensor_Demos/CircuitPython_Simple/code.py new file mode 100644 index 000000000..2641319e4 --- /dev/null +++ b/Simple_Soil_Sensor_Demos/CircuitPython_Simple/code.py @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import time +import board +from analogio import AnalogIn + +analog_in = AnalogIn(board.A0) + +while True: + print(f"Soil Moisture: {analog_in.value}") + time.sleep(5) diff --git a/Simple_Soil_Sensor_Demos/MicroPython/adv_soil_sensor_demo.py b/Simple_Soil_Sensor_Demos/MicroPython/adv_soil_sensor_demo.py new file mode 100644 index 000000000..3f6fd2c6f --- /dev/null +++ b/Simple_Soil_Sensor_Demos/MicroPython/adv_soil_sensor_demo.py @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# pylint: disable=wildcard-import, undefined-variable + +"""MicroPython Advanced Soil Sensing Demo for micro:bit""" +from microbit import * + +while True: + pin2.write_digital(1) + sleep(100) + moisture = pin0.read_analog() + if moisture > 200: + display.show(Image.HAPPY) + else: + display.show(Image.SAD) + pin2.write_digital(0) + sleep(5000) diff --git a/Simple_Soil_Sensor_Demos/MicroPython/simple_soil_sensor_demo.py b/Simple_Soil_Sensor_Demos/MicroPython/simple_soil_sensor_demo.py new file mode 100644 index 000000000..c9509543c --- /dev/null +++ b/Simple_Soil_Sensor_Demos/MicroPython/simple_soil_sensor_demo.py @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# pylint: disable=wildcard-import, undefined-variable + +"""MicroPython Simple Soil Sensing Demo for micro:bit""" +from microbit import * + +while True: + moisture = pin0.read_analog() + if moisture > 200: + display.show(Image.HAPPY) + else: + display.show(Image.SAD) + sleep(5000) diff --git a/Smart_Alarm_Clock/button/code.py b/Smart_Alarm_Clock/button/code.py index eff9eb3dd..228820cec 100644 --- a/Smart_Alarm_Clock/button/code.py +++ b/Smart_Alarm_Clock/button/code.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2021 Eva Herrada for Adafruit Industries # SPDX-License-Identifier: MIT +from os import getenv import ssl import time import board @@ -17,19 +18,28 @@ btn1.direction = digitalio.Direction.INPUT btn1.pull = digitalio.Pull.DOWN +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + + ALARM = None ### WiFi ### -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise - -print("Connecting to %s" % secrets["ssid"]) -wifi.radio.connect(secrets["ssid"], secrets["password"]) -print("Connected to %s!" % secrets["ssid"]) +print(f"Connecting to {ssid}") +wifi.radio.connect(ssid, password) +print(f"Connected to {ssid}!") # Define callback functions which will be called when certain events happen. # pylint: disable=unused-argument @@ -78,8 +88,8 @@ def on_alarm(client, feed_id, payload): # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", - username=secrets["aio_username"], - password=secrets["aio_key"], + username=aio_username, + password=aio_key, socket_pool=pool, ssl_context=ssl.create_default_context(), ) diff --git a/Smart_Alarm_Clock/code.py b/Smart_Alarm_Clock/code.py index c7fe68600..1c9fd89bb 100644 --- a/Smart_Alarm_Clock/code.py +++ b/Smart_Alarm_Clock/code.py @@ -2,6 +2,8 @@ # SPDX-License-Identifier: MIT # General imports + +from os import getenv import gc import time import math @@ -35,6 +37,22 @@ import audiocore import audiobusio +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + + TIMES = {} ENABLED = {} @@ -59,21 +77,9 @@ 6: "sunday", } -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise - -# Set your Adafruit IO Username and Key in secrets.py -# (visit io.adafruit.com if you need to create an account, -# or if you need your Adafruit IO key.) -aio_username = secrets["aio_username"] -aio_key = secrets["aio_key"] - -print("Connecting to %s" % secrets["ssid"]) -wifi.radio.connect(secrets["ssid"], secrets["password"]) -print("Connected to %s!" % secrets["ssid"]) +print(f"Connecting to {ssid}") +wifi.radio.connect(ssid, password) +print(f"Connected to {ssid}!") # Define callback functions which will be called when certain events happen. # pylint: disable=unused-argument @@ -97,7 +103,7 @@ def connected(client, userdata, flags, rc): "alarm", ] for feed in feeds: - feed_slug = secrets["aio_username"] + "/feeds/alarm-clock." + feed + feed_slug = f"{aio_username}/feeds/alarm-clock." + feed print("Subscribed to: alarm-clock." + feed) client.subscribe(feed_slug, 1) @@ -126,7 +132,7 @@ def fade(warm_val, cool_val): def get(feed_key): - mqtt_client.publish(f'{secrets["aio_username"]}/feeds/{feed_key}/get', "\0") + mqtt_client.publish(f'{aio_username}/feeds/{feed_key}/get', "\0") time.sleep(0.1) @@ -169,7 +175,7 @@ def on_iso(client, feed_id, payload): and WAIT < time.monotonic() ): mqtt_client.publish( - f"{secrets['aio_username']}/feeds/alarm-clock.alarm", "True" + f"{aio_username}/feeds/alarm-clock.alarm", "True" ) get("alarm-clock.alarm") gc.collect() @@ -314,8 +320,8 @@ def brighten_cool(i): # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", - username=secrets["aio_username"], - password=secrets["aio_key"], + username=aio_username, + password=aio_key, socket_pool=pool, ssl_context=ssl.create_default_context(), ) @@ -331,51 +337,51 @@ def brighten_cool(i): mqtt_client.add_topic_callback("time/ISO-8601", on_iso) mqtt_client.add_topic_callback( - secrets["aio_username"] + "/feeds/alarm-clock.alarm", on_alarm + f"{aio_username}/feeds/alarm-clock.alarm", on_alarm ) mqtt_client.add_topic_callback( - secrets["aio_username"] + "/feeds/alarm-clock.sunday", on_time + f"{aio_username}/feeds/alarm-clock.sunday", on_time ) mqtt_client.add_topic_callback( - secrets["aio_username"] + "/feeds/alarm-clock.monday", on_time + f"{aio_username}/feeds/alarm-clock.monday", on_time ) mqtt_client.add_topic_callback( - secrets["aio_username"] + "/feeds/alarm-clock.tuesday", on_time + f"{aio_username}/feeds/alarm-clock.tuesday", on_time ) mqtt_client.add_topic_callback( - secrets["aio_username"] + "/feeds/alarm-clock.wednesday", on_time + f"{aio_username}/feeds/alarm-clock.wednesday", on_time ) mqtt_client.add_topic_callback( - secrets["aio_username"] + "/feeds/alarm-clock.thursday", on_time + f"{aio_username}/feeds/alarm-clock.thursday", on_time ) mqtt_client.add_topic_callback( - secrets["aio_username"] + "/feeds/alarm-clock.friday", on_time + f"{aio_username}/feeds/alarm-clock.friday", on_time ) mqtt_client.add_topic_callback( - secrets["aio_username"] + "/feeds/alarm-clock.saturday", on_time + f"{aio_username}/feeds/alarm-clock.saturday", on_time ) mqtt_client.add_topic_callback( - secrets["aio_username"] + "/feeds/alarm-clock.sunday-enable", on_enable + f"{aio_username}/feeds/alarm-clock.sunday-enable", on_enable ) mqtt_client.add_topic_callback( - secrets["aio_username"] + "/feeds/alarm-clock.monday-enable", on_enable + f"{aio_username}/feeds/alarm-clock.monday-enable", on_enable ) mqtt_client.add_topic_callback( - secrets["aio_username"] + "/feeds/alarm-clock.tuesday-enable", on_enable + f"{aio_username}/feeds/alarm-clock.tuesday-enable", on_enable ) mqtt_client.add_topic_callback( - secrets["aio_username"] + "/feeds/alarm-clock.wednesday-enable", on_enable + f"{aio_username}/feeds/alarm-clock.wednesday-enable", on_enable ) mqtt_client.add_topic_callback( - secrets["aio_username"] + "/feeds/alarm-clock.thursday-enable", on_enable + f"{aio_username}/feeds/alarm-clock.thursday-enable", on_enable ) mqtt_client.add_topic_callback( - secrets["aio_username"] + "/feeds/alarm-clock.friday-enable", on_enable + f"{aio_username}/feeds/alarm-clock.friday-enable", on_enable ) mqtt_client.add_topic_callback( - secrets["aio_username"] + "/feeds/alarm-clock.saturday-enable", on_enable + f"{aio_username}/feeds/alarm-clock.saturday-enable", on_enable ) @@ -398,7 +404,7 @@ def brighten_cool(i): while len(TIMES) < 7 or len(ENABLED) < 7: mqtt_client.loop() -mqtt_client.publish(secrets["aio_username"] + "/feeds/alarm-clock.alarm", "False") +mqtt_client.publish(f"{aio_username}/feeds/alarm-clock.alarm", "False") mqtt_client.subscribe("time/ISO-8601", 1) print("Starting") diff --git a/Sparkle_Motion_Examples/Arduino_Sparkle_Motion_Multi_NeoPixels/.feather_esp32_v2.test.only b/Sparkle_Motion_Examples/Arduino_Sparkle_Motion_Multi_NeoPixels/.feather_esp32_v2.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Sparkle_Motion_Examples/Arduino_Sparkle_Motion_Multi_NeoPixels/Arduino_Sparkle_Motion_Multi_NeoPixels.ino b/Sparkle_Motion_Examples/Arduino_Sparkle_Motion_Multi_NeoPixels/Arduino_Sparkle_Motion_Multi_NeoPixels.ino index af8651820..74c5334b7 100644 --- a/Sparkle_Motion_Examples/Arduino_Sparkle_Motion_Multi_NeoPixels/Arduino_Sparkle_Motion_Multi_NeoPixels.ino +++ b/Sparkle_Motion_Examples/Arduino_Sparkle_Motion_Multi_NeoPixels/Arduino_Sparkle_Motion_Multi_NeoPixels.ino @@ -23,7 +23,7 @@ uint16_t pixelHue_2 = 256; void loop() { pixelHue_1 += 256; - for(int i=0; i +#include "ESP_I2S.h" + +// I2S pin definitions for Sparklemotion +const uint8_t I2S_SCK = 14; // BCLK +const uint8_t I2S_WS = 12; // LRCLK +const uint8_t I2S_DIN = 13; // DATA_IN + +// Create I2S instance +I2SClass i2s; + +void setup() { + // Fast serial for plotting + Serial.begin(500000); + + // Initialize I2S + i2s.setPins(I2S_SCK, I2S_WS, -1, I2S_DIN); + if (!i2s.begin(I2S_MODE_STD, 44100, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO, I2S_STD_SLOT_LEFT)) { + Serial.println("Failed to initialize I2S bus!"); + return; + } + + Serial.println("I2S Mic Plotter Ready"); +} + +void loop() { + static uint32_t lastPlot = 0; + + // Get a sample + int32_t sample = i2s.read(); + + // Only plot every 1ms (1000 samples/sec is plenty for visualization) + if (millis() - lastPlot >= 1) { + if (sample >= 0) { // Valid sample + // Plot both raw and absolute values + Serial.printf("%d,%d\n", (int16_t)sample, abs((int16_t)sample)); + } + lastPlot = millis(); + } +} diff --git a/Sparkle_Motion_Stick_Examples/Arduino_Sparkle_Motion_Stick_IR_Remote/.feather_esp32_v2.test.only b/Sparkle_Motion_Stick_Examples/Arduino_Sparkle_Motion_Stick_IR_Remote/.feather_esp32_v2.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Sparkle_Motion_Stick_Examples/Arduino_Sparkle_Motion_Stick_IR_Remote/Arduino_Sparkle_Motion_Stick_IR_Remote.ino b/Sparkle_Motion_Stick_Examples/Arduino_Sparkle_Motion_Stick_IR_Remote/Arduino_Sparkle_Motion_Stick_IR_Remote.ino new file mode 100644 index 000000000..dac459c32 --- /dev/null +++ b/Sparkle_Motion_Stick_Examples/Arduino_Sparkle_Motion_Stick_IR_Remote/Arduino_Sparkle_Motion_Stick_IR_Remote.ino @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries +// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/* + * Based on the SimpleReceiver.cpp and SimpleSender.cpp from the + * Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote. + * by Armin Joachimsmeyer + ************************************************************************************ + * MIT License + * + * Copyright (c) 2020-2023 Armin Joachimsmeyer + * + */ + +#include + +#include // include the library +#include + +#define NEOPIXEL_STRIP_PIN 21 +#define NUM_PIXELS 8 + +#define IR_RECEIVE_PIN 10 + +Adafruit_NeoPixel NEOPIXEL_STRIP(NUM_PIXELS, NEOPIXEL_STRIP_PIN, NEO_GRB + NEO_KHZ800); + +uint8_t upCmd = 0x5; +uint8_t downCmd = 0xD; +uint8_t rightCmd = 0xA; +uint8_t leftCmd = 0x8; + +uint16_t pixelHue = 0; +uint8_t brightness = 25; + +void setup() { + Serial.begin(115200); + //while (!Serial); + Serial.println("Adafruit Sparkle Motion IR Remote Control NeoPixels Demo"); + IrReceiver.begin(IR_RECEIVE_PIN); + Serial.print("IRin on pin "); + Serial.print(IR_RECEIVE_PIN); + NEOPIXEL_STRIP.begin(); + NEOPIXEL_STRIP.setBrightness(25); +} + +void loop() { + /* + * Check if received data is available and if yes, try to decode it. + * When left or right buttons are pressed, change the pixelHue. + * When up or down buttons are pressed, change the brightness. + */ + if (IrReceiver.decode()) { + if (IrReceiver.decodedIRData.protocol == UNKNOWN) { + Serial.println("unknown"); + IrReceiver.printIRResultRawFormatted(&Serial, true); + IrReceiver.resume(); + } else { + IrReceiver.resume(); + //IrReceiver.printIRResultShort(&Serial); + + // Ignore repeat codes from holding down the button + if (IrReceiver.decodedIRData.flags == 0){ + //Serial.printf("Command: %d\n",IrReceiver.decodedIRData.command); + if (IrReceiver.decodedIRData.command == upCmd){ + Serial.println("UP btn"); + brightness = min(brightness + 25, 255); + }else if (IrReceiver.decodedIRData.command == downCmd){ + Serial.println("DOWN btn"); + brightness = max(brightness - 25, 0); + }else if (IrReceiver.decodedIRData.command == leftCmd){ + Serial.println("LEFT btn"); + pixelHue = (pixelHue - 8192) % 65536; + }else if (IrReceiver.decodedIRData.command == rightCmd){ + Serial.println("RIGHT btn"); + pixelHue = (pixelHue + 8192) % 65536; + } + + NEOPIXEL_STRIP.setBrightness(brightness); + NEOPIXEL_STRIP.fill(NEOPIXEL_STRIP.gamma32(NEOPIXEL_STRIP.ColorHSV(pixelHue))); + NEOPIXEL_STRIP.show(); + delay(100); + } + } + Serial.println(); + } +} diff --git a/Starduino_8bit_Super_Mario_Tree_Topper/Starduino_8bit_Super_Mario_Tree_Topper.ino b/Starduino_8bit_Super_Mario_Tree_Topper/Starduino_8bit_Super_Mario_Tree_Topper.ino index 948c43281..11d8b24c0 100644 --- a/Starduino_8bit_Super_Mario_Tree_Topper/Starduino_8bit_Super_Mario_Tree_Topper.ino +++ b/Starduino_8bit_Super_Mario_Tree_Topper/Starduino_8bit_Super_Mario_Tree_Topper.ino @@ -4,6 +4,10 @@ #include +#if defined(FASTLED_VERSION) && FASTLED_VERSION > 3010001 + #error "FastLED 3.10.2 has known compile issues with SAMD boards. Please downgrade to FastLED 3.10.1" +#endif + #define LED_PIN 0 #define COLOR_ORDER GRB #define CHIPSET WS2811 @@ -105,4 +109,4 @@ void Fire2012() } leds[pixelnumber] = color; } -} \ No newline at end of file +} diff --git a/TFT_FeatherWing_TSC2007_Demos/CircuitPython/code.py b/TFT_FeatherWing_TSC2007_Demos/CircuitPython/code.py index 35a883571..c8c869484 100644 --- a/TFT_FeatherWing_TSC2007_Demos/CircuitPython/code.py +++ b/TFT_FeatherWing_TSC2007_Demos/CircuitPython/code.py @@ -10,6 +10,7 @@ import os import board import displayio +import fourwire import adafruit_ili9341 import adafruit_tsc2007 @@ -25,7 +26,7 @@ display_width = 320 display_height = 240 -display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs) +display_bus = fourwire.FourWire(spi, command=tft_dc, chip_select=tft_cs) display = adafruit_ili9341.ILI9341(display_bus, width=display_width, height=display_height) i2c = board.STEMMA_I2C() diff --git a/TFT_FeatherWing_V2_CircuitPython_Example/code.py b/TFT_FeatherWing_V2_CircuitPython_Example/code.py index 118b7cb3f..d8defda1b 100644 --- a/TFT_FeatherWing_V2_CircuitPython_Example/code.py +++ b/TFT_FeatherWing_V2_CircuitPython_Example/code.py @@ -10,6 +10,7 @@ import os import board import displayio +import fourwire import adafruit_hx8357 import adafruit_tsc2007 @@ -25,7 +26,7 @@ display_width = 480 display_height = 320 -display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs) +display_bus = fourwire.FourWire(spi, command=tft_dc, chip_select=tft_cs) display = adafruit_hx8357.HX8357(display_bus, width=display_width, height=display_height) i2c = board.STEMMA_I2C() diff --git a/TFT_Gizmo_Turtle_Graphics/turtle_asterix/code.py b/TFT_Gizmo_Turtle_Graphics/turtle_asterix/code.py index 0b8e36631..88a772075 100644 --- a/TFT_Gizmo_Turtle_Graphics/turtle_asterix/code.py +++ b/TFT_Gizmo_Turtle_Graphics/turtle_asterix/code.py @@ -7,11 +7,12 @@ import board import busio import displayio +import fourwire from adafruit_st7789 import ST7789 from adafruit_turtle import turtle displayio.release_displays() spi = busio.SPI(board.SCL, MOSI=board.SDA) -display_bus = displayio.FourWire(spi, command=board.TX, chip_select=board.RX) +display_bus = fourwire.FourWire(spi, command=board.TX, chip_select=board.RX) display = ST7789(display_bus, width=240, height=240, rowstart=80, backlight_pin=board.A3, rotation=180) turtle = turtle(display) diff --git a/TFT_Gizmo_Turtle_Graphics/turtle_benzene/code.py b/TFT_Gizmo_Turtle_Graphics/turtle_benzene/code.py index 55e876394..f28f63151 100644 --- a/TFT_Gizmo_Turtle_Graphics/turtle_benzene/code.py +++ b/TFT_Gizmo_Turtle_Graphics/turtle_benzene/code.py @@ -7,11 +7,12 @@ import board import busio import displayio +import fourwire from adafruit_st7789 import ST7789 from adafruit_turtle import Color, turtle displayio.release_displays() spi = busio.SPI(board.SCL, MOSI=board.SDA) -display_bus = displayio.FourWire(spi, command=board.TX, chip_select=board.RX) +display_bus = fourwire.FourWire(spi, command=board.TX, chip_select=board.RX) display = ST7789(display_bus, width=240, height=240, rowstart=80, backlight_pin=board.A3, rotation=180) turtle = turtle(display) diff --git a/TFT_Gizmo_Turtle_Graphics/turtle_christmas_tree/code.py b/TFT_Gizmo_Turtle_Graphics/turtle_christmas_tree/code.py index 063550866..8910a049b 100644 --- a/TFT_Gizmo_Turtle_Graphics/turtle_christmas_tree/code.py +++ b/TFT_Gizmo_Turtle_Graphics/turtle_christmas_tree/code.py @@ -7,11 +7,12 @@ import board import busio import displayio +import fourwire from adafruit_st7789 import ST7789 from adafruit_turtle import Color, turtle displayio.release_displays() spi = busio.SPI(board.SCL, MOSI=board.SDA) -display_bus = displayio.FourWire(spi, command=board.TX, chip_select=board.RX) +display_bus = fourwire.FourWire(spi, command=board.TX, chip_select=board.RX) display = ST7789(display_bus, width=240, height=240, rowstart=80, backlight_pin=board.A3, rotation=180) turtle = turtle(display) diff --git a/TFT_Gizmo_Turtle_Graphics/turtle_circle/code.py b/TFT_Gizmo_Turtle_Graphics/turtle_circle/code.py index c4fa7082b..44dcb08c3 100644 --- a/TFT_Gizmo_Turtle_Graphics/turtle_circle/code.py +++ b/TFT_Gizmo_Turtle_Graphics/turtle_circle/code.py @@ -7,11 +7,12 @@ import board import busio import displayio +import fourwire from adafruit_st7789 import ST7789 from adafruit_turtle import turtle displayio.release_displays() spi = busio.SPI(board.SCL, MOSI=board.SDA) -display_bus = displayio.FourWire(spi, command=board.TX, chip_select=board.RX) +display_bus = fourwire.FourWire(spi, command=board.TX, chip_select=board.RX) display = ST7789(display_bus, width=240, height=240, rowstart=80, backlight_pin=board.A3, rotation=180) turtle = turtle(display) diff --git a/TFT_Gizmo_Turtle_Graphics/turtle_circle_petals/code.py b/TFT_Gizmo_Turtle_Graphics/turtle_circle_petals/code.py index 50497af58..c37c64a7d 100644 --- a/TFT_Gizmo_Turtle_Graphics/turtle_circle_petals/code.py +++ b/TFT_Gizmo_Turtle_Graphics/turtle_circle_petals/code.py @@ -7,11 +7,12 @@ import board import busio import displayio +import fourwire from adafruit_st7789 import ST7789 from adafruit_turtle import Color, turtle displayio.release_displays() spi = busio.SPI(board.SCL, MOSI=board.SDA) -display_bus = displayio.FourWire(spi, command=board.TX, chip_select=board.RX) +display_bus = fourwire.FourWire(spi, command=board.TX, chip_select=board.RX) display = ST7789(display_bus, width=240, height=240, rowstart=80, backlight_pin=board.A3, rotation=180) turtle = turtle(display) diff --git a/TFT_Gizmo_Turtle_Graphics/turtle_hilbert/code.py b/TFT_Gizmo_Turtle_Graphics/turtle_hilbert/code.py index 6697bb993..d7c9cd456 100644 --- a/TFT_Gizmo_Turtle_Graphics/turtle_hilbert/code.py +++ b/TFT_Gizmo_Turtle_Graphics/turtle_hilbert/code.py @@ -7,11 +7,12 @@ import board import busio import displayio +import fourwire from adafruit_st7789 import ST7789 from adafruit_turtle import Color, turtle displayio.release_displays() spi = busio.SPI(board.SCL, MOSI=board.SDA) -display_bus = displayio.FourWire(spi, command=board.TX, chip_select=board.RX) +display_bus = fourwire.FourWire(spi, command=board.TX, chip_select=board.RX) display = ST7789(display_bus, width=240, height=240, rowstart=80, backlight_pin=board.A3, rotation=180) turtle = turtle(display) diff --git a/TFT_Gizmo_Turtle_Graphics/turtle_koch/code.py b/TFT_Gizmo_Turtle_Graphics/turtle_koch/code.py index 043a123f3..43db6a04d 100644 --- a/TFT_Gizmo_Turtle_Graphics/turtle_koch/code.py +++ b/TFT_Gizmo_Turtle_Graphics/turtle_koch/code.py @@ -7,11 +7,12 @@ import board import busio import displayio +import fourwire from adafruit_st7789 import ST7789 from adafruit_turtle import turtle displayio.release_displays() spi = busio.SPI(board.SCL, MOSI=board.SDA) -display_bus = displayio.FourWire(spi, command=board.TX, chip_select=board.RX) +display_bus = fourwire.FourWire(spi, command=board.TX, chip_select=board.RX) display = ST7789(display_bus, width=240, height=240, rowstart=80, backlight_pin=board.A3, rotation=180) turtle = turtle(display) diff --git a/TFT_Gizmo_Turtle_Graphics/turtle_parabolic_jack/code.py b/TFT_Gizmo_Turtle_Graphics/turtle_parabolic_jack/code.py index 2c2679603..f94072e5d 100644 --- a/TFT_Gizmo_Turtle_Graphics/turtle_parabolic_jack/code.py +++ b/TFT_Gizmo_Turtle_Graphics/turtle_parabolic_jack/code.py @@ -7,11 +7,12 @@ import board import busio import displayio +import fourwire from adafruit_st7789 import ST7789 from adafruit_turtle import Color, turtle displayio.release_displays() spi = busio.SPI(board.SCL, MOSI=board.SDA) -display_bus = displayio.FourWire(spi, command=board.TX, chip_select=board.RX) +display_bus = fourwire.FourWire(spi, command=board.TX, chip_select=board.RX) display = ST7789(display_bus, width=240, height=240, rowstart=80, backlight_pin=board.A3, rotation=180) turtle = turtle(display) diff --git a/TFT_Gizmo_Turtle_Graphics/turtle_sierpinski/code.py b/TFT_Gizmo_Turtle_Graphics/turtle_sierpinski/code.py index 9adf706b3..87be598fe 100644 --- a/TFT_Gizmo_Turtle_Graphics/turtle_sierpinski/code.py +++ b/TFT_Gizmo_Turtle_Graphics/turtle_sierpinski/code.py @@ -7,11 +7,12 @@ import board import busio import displayio +import fourwire from adafruit_st7789 import ST7789 from adafruit_turtle import turtle displayio.release_displays() spi = busio.SPI(board.SCL, MOSI=board.SDA) -display_bus = displayio.FourWire(spi, command=board.TX, chip_select=board.RX) +display_bus = fourwire.FourWire(spi, command=board.TX, chip_select=board.RX) display = ST7789(display_bus, width=240, height=240, rowstart=80, backlight_pin=board.A3, rotation=180) turtle = turtle(display) diff --git a/TFT_Gizmo_Turtle_Graphics/turtle_snowflakes/code.py b/TFT_Gizmo_Turtle_Graphics/turtle_snowflakes/code.py index d2a1d9c56..5e78640a5 100644 --- a/TFT_Gizmo_Turtle_Graphics/turtle_snowflakes/code.py +++ b/TFT_Gizmo_Turtle_Graphics/turtle_snowflakes/code.py @@ -9,11 +9,12 @@ import board import busio import displayio +import fourwire from adafruit_st7789 import ST7789 from adafruit_turtle import turtle displayio.release_displays() spi = busio.SPI(board.SCL, MOSI=board.SDA) -display_bus = displayio.FourWire(spi, command=board.TX, chip_select=board.RX) +display_bus = fourwire.FourWire(spi, command=board.TX, chip_select=board.RX) display = ST7789(display_bus, width=240, height=240, rowstart=80, backlight_pin=board.A3, rotation=180) turtle = turtle(display) diff --git a/TFT_Gizmo_Turtle_Graphics/turtle_square01/code.py b/TFT_Gizmo_Turtle_Graphics/turtle_square01/code.py index 344569b45..6542b44f8 100644 --- a/TFT_Gizmo_Turtle_Graphics/turtle_square01/code.py +++ b/TFT_Gizmo_Turtle_Graphics/turtle_square01/code.py @@ -7,11 +7,12 @@ import board import busio import displayio +import fourwire from adafruit_st7789 import ST7789 from adafruit_turtle import turtle displayio.release_displays() spi = busio.SPI(board.SCL, MOSI=board.SDA) -display_bus = displayio.FourWire(spi, command=board.TX, chip_select=board.RX) +display_bus = fourwire.FourWire(spi, command=board.TX, chip_select=board.RX) display = ST7789(display_bus, width=240, height=240, rowstart=80, backlight_pin=board.A3, rotation=180) turtle = turtle(display) diff --git a/TFT_Gizmo_Turtle_Graphics/turtle_square_loop/code.py b/TFT_Gizmo_Turtle_Graphics/turtle_square_loop/code.py index b2ae90462..eddf04879 100644 --- a/TFT_Gizmo_Turtle_Graphics/turtle_square_loop/code.py +++ b/TFT_Gizmo_Turtle_Graphics/turtle_square_loop/code.py @@ -7,11 +7,12 @@ import board import busio import displayio +import fourwire from adafruit_st7789 import ST7789 from adafruit_turtle import turtle displayio.release_displays() spi = busio.SPI(board.SCL, MOSI=board.SDA) -display_bus = displayio.FourWire(spi, command=board.TX, chip_select=board.RX) +display_bus = fourwire.FourWire(spi, command=board.TX, chip_select=board.RX) display = ST7789(display_bus, width=240, height=240, rowstart=80, backlight_pin=board.A3, rotation=180) turtle = turtle(display) diff --git a/TFT_Gizmo_Turtle_Graphics/turtle_star_fancy/code.py b/TFT_Gizmo_Turtle_Graphics/turtle_star_fancy/code.py index 5629730f7..400d2a4ed 100644 --- a/TFT_Gizmo_Turtle_Graphics/turtle_star_fancy/code.py +++ b/TFT_Gizmo_Turtle_Graphics/turtle_star_fancy/code.py @@ -7,11 +7,12 @@ import board import busio import displayio +import fourwire from adafruit_st7789 import ST7789 from adafruit_turtle import Color, turtle displayio.release_displays() spi = busio.SPI(board.SCL, MOSI=board.SDA) -display_bus = displayio.FourWire(spi, command=board.TX, chip_select=board.RX) +display_bus = fourwire.FourWire(spi, command=board.TX, chip_select=board.RX) display = ST7789(display_bus, width=240, height=240, rowstart=80, backlight_pin=board.A3, rotation=180) turtle = turtle(display) diff --git a/TFT_Shield_TSC2007_Demos/CircuitPython/code.py b/TFT_Shield_TSC2007_Demos/CircuitPython/code.py index b490f4c8d..ccd2599c9 100644 --- a/TFT_Shield_TSC2007_Demos/CircuitPython/code.py +++ b/TFT_Shield_TSC2007_Demos/CircuitPython/code.py @@ -10,6 +10,7 @@ import os import board import displayio +import fourwire import adafruit_ili9341 import adafruit_tsc2007 @@ -29,7 +30,7 @@ display_width = 320 display_height = 240 -display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs) +display_bus = fourwire.FourWire(spi, command=tft_dc, chip_select=tft_cs) display = adafruit_ili9341.ILI9341(display_bus, width=display_width, height=display_height) i2c = board.I2C() diff --git a/TFT_Spirit_Board/esp32s3_s2_tft_featherwing_480x320/code.py b/TFT_Spirit_Board/esp32s3_s2_tft_featherwing_480x320/code.py index dc5c778cd..deca670dd 100644 --- a/TFT_Spirit_Board/esp32s3_s2_tft_featherwing_480x320/code.py +++ b/TFT_Spirit_Board/esp32s3_s2_tft_featherwing_480x320/code.py @@ -8,8 +8,10 @@ Receive and display messages from the spirits. """ # pylint: disable=import-error, invalid-name -import os + +from os import getenv import displayio +import fourwire import board from digitalio import DigitalInOut import adafruit_connection_manager @@ -21,6 +23,20 @@ from spirit_board import SpiritBoard +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) # 3.5" TFT Featherwing is 480x320 @@ -32,7 +48,7 @@ spi = board.SPI() tft_cs = board.D9 tft_dc = board.D10 -display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs) +display_bus = fourwire.FourWire(spi, command=tft_dc, chip_select=tft_cs) display = HX8357(display_bus, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT) display.rotation = 0 _touch_flip = (False, True) @@ -48,12 +64,6 @@ ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio) requests = adafruit_requests.Session(pool, ssl_context) - # Set your Adafruit IO Username and Key in secrets.py - # (visit io.adafruit.com if you need to create an account, - # or if you need your Adafruit IO key.) - aio_username = os.getenv("AIO_USERNAME") - aio_key = os.getenv("AIO_KEY") - # Initialize an Adafruit IO HTTP API object io = IO_HTTP(aio_username, aio_key, requests) except (RuntimeError, TypeError) as e: diff --git a/TFT_Spirit_Board/esp32s3_s2_tft_featherwing_480x320/spirit_board.py b/TFT_Spirit_Board/esp32s3_s2_tft_featherwing_480x320/spirit_board.py index 9a889f608..af4e5d007 100644 --- a/TFT_Spirit_Board/esp32s3_s2_tft_featherwing_480x320/spirit_board.py +++ b/TFT_Spirit_Board/esp32s3_s2_tft_featherwing_480x320/spirit_board.py @@ -45,7 +45,7 @@ def __init__(self, display): """ Create a SpiritBoard instance and put it in the displays root_group to make it visible. - :param displayio.Display display: Display object to show the spirit board on. + :param displayio.AnyDisplay display: Display object to show the spirit board on. """ self._display = display super().__init__() diff --git a/TFT_Spirit_Board/pyportal/code.py b/TFT_Spirit_Board/pyportal/code.py index 441a4733d..84cd1adf0 100644 --- a/TFT_Spirit_Board/pyportal/code.py +++ b/TFT_Spirit_Board/pyportal/code.py @@ -9,7 +9,7 @@ """ # pylint: disable=import-error, invalid-name -import os +from os import getenv import board from digitalio import DigitalInOut import adafruit_connection_manager @@ -22,6 +22,21 @@ display = board.DISPLAY +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + # Initialize the touch overlay touchscreen = adafruit_touchscreen.Touchscreen( board.TOUCH_XL, @@ -43,19 +58,13 @@ print("Connecting to AP...") try: - esp.connect_AP(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD")) + esp.connect_AP(ssid, password) # Initialize a requests session pool = adafruit_connection_manager.get_radio_socketpool(esp) ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp) requests = adafruit_requests.Session(pool, ssl_context) - # Set your Adafruit IO Username and Key in secrets.py - # (visit io.adafruit.com if you need to create an account, - # or if you need your Adafruit IO key.) - aio_username = os.getenv("AIO_USERNAME") - aio_key = os.getenv("AIO_KEY") - # Initialize an Adafruit IO HTTP API object io = IO_HTTP(aio_username, aio_key, requests) except (RuntimeError, TypeError) as e: diff --git a/TFT_Spirit_Board/pyportal/spirit_board.py b/TFT_Spirit_Board/pyportal/spirit_board.py index 9a889f608..af4e5d007 100644 --- a/TFT_Spirit_Board/pyportal/spirit_board.py +++ b/TFT_Spirit_Board/pyportal/spirit_board.py @@ -45,7 +45,7 @@ def __init__(self, display): """ Create a SpiritBoard instance and put it in the displays root_group to make it visible. - :param displayio.Display display: Display object to show the spirit board on. + :param displayio.AnyDisplay display: Display object to show the spirit board on. """ self._display = display super().__init__() diff --git a/TFT_Spirit_Board/pyportal_titano/code.py b/TFT_Spirit_Board/pyportal_titano/code.py index 68b77d401..1329d330d 100644 --- a/TFT_Spirit_Board/pyportal_titano/code.py +++ b/TFT_Spirit_Board/pyportal_titano/code.py @@ -9,7 +9,7 @@ """ # pylint: disable=import-error, invalid-name -import os +from os import getenv import board from digitalio import DigitalInOut import adafruit_connection_manager @@ -22,6 +22,21 @@ display = board.DISPLAY +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + # Initialize the touch overlay touchscreen = adafruit_touchscreen.Touchscreen( board.TOUCH_XL, @@ -43,19 +58,13 @@ print("Connecting to AP...") try: - esp.connect_AP(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD")) + esp.connect_AP(ssid, password) # Initialize a requests session pool = adafruit_connection_manager.get_radio_socketpool(esp) ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp) requests = adafruit_requests.Session(pool, ssl_context) - # Set your Adafruit IO Username and Key in secrets.py - # (visit io.adafruit.com if you need to create an account, - # or if you need your Adafruit IO key.) - aio_username = os.getenv("AIO_USERNAME") - aio_key = os.getenv("AIO_KEY") - # Initialize an Adafruit IO HTTP API object io = IO_HTTP(aio_username, aio_key, requests) except (RuntimeError, TypeError) as e: diff --git a/TFT_Spirit_Board/pyportal_titano/spirit_board.py b/TFT_Spirit_Board/pyportal_titano/spirit_board.py index 9a889f608..af4e5d007 100644 --- a/TFT_Spirit_Board/pyportal_titano/spirit_board.py +++ b/TFT_Spirit_Board/pyportal_titano/spirit_board.py @@ -45,7 +45,7 @@ def __init__(self, display): """ Create a SpiritBoard instance and put it in the displays root_group to make it visible. - :param displayio.Display display: Display object to show the spirit board on. + :param displayio.AnyDisplay display: Display object to show the spirit board on. """ self._display = display super().__init__() diff --git a/TLV320DAC3100_Examples/TLV320_Audio_Playback_Arduino/.feather_rp2040.test.only b/TLV320DAC3100_Examples/TLV320_Audio_Playback_Arduino/.feather_rp2040.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/TLV320DAC3100_Examples/TLV320_Audio_Playback_Arduino/TLV320_Audio_Playback_Arduino.ino b/TLV320DAC3100_Examples/TLV320_Audio_Playback_Arduino/TLV320_Audio_Playback_Arduino.ino new file mode 100644 index 000000000..4a813673f --- /dev/null +++ b/TLV320DAC3100_Examples/TLV320_Audio_Playback_Arduino/TLV320_Audio_Playback_Arduino.ino @@ -0,0 +1,144 @@ +// SPDX-FileCopyrightText: 2023 Ladyada for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/* + This example plays a 'raw' PCM file from memory to I2S +*/ + +#include +#include +#include + +#include "startup.h" // audio file in flash + +Adafruit_TLV320DAC3100 codec; // Create codec object + +// Create the I2S port using a PIO state machine +I2S i2s(OUTPUT); + +// GPIO pin numbers on Feather RP2040 +#define pBCLK D9 // BITCLOCK +#define pWS D10 // LRCLOCK +#define pDOUT D11 // DATA + +void setup() { + Serial.begin(115200); + while (!Serial) delay(10); + Serial.println("I2S playback demo"); +} + +void loop() { +} + +void setup1() { + Serial.begin(115200); + + while (!Serial) delay(10); + Serial.println("\n\nTLV320DAC3100 Sine Tone Test"); + // Start I2C communication with codec + Serial.println("Initializing codec..."); + if (!codec.begin()) { + Serial.println("Failed to initialize codec!"); + } + codec.reset(); + // Step 1: Set codec interface to I2S with 16-bit data + Serial.println("Configuring codec interface..."); + if (!codec.setCodecInterface(TLV320DAC3100_FORMAT_I2S, TLV320DAC3100_DATA_LEN_16)) { + Serial.println("Failed to configure codec interface!"); + } + + // Step 2: Configure clock - using PLL with BCLK as input + Serial.println("Configuring codec clocks..."); + if (!codec.setCodecClockInput(TLV320DAC3100_CODEC_CLKIN_PLL) || + !codec.setPLLClockInput(TLV320DAC3100_PLL_CLKIN_BCLK)) { + Serial.println("Failed to configure codec clocks!"); + } + + // Step 3: Set up PLL - these values work well for 44.1kHz sample rate + if (!codec.setPLLValues(1, 1, 8, 0)) { + Serial.println("Failed to configure PLL values!"); + } + + // Step 4: Configure DAC dividers + if (!codec.setNDAC(true, 8) || + !codec.setMDAC(true, 2) || + !codec.setDOSR(128)) { + Serial.println("Failed to configure DAC dividers!"); + } + + // Step 5: Power up PLL + if (!codec.powerPLL(true)) { + Serial.println("Failed to power up PLL!"); + } + + // Step 6: Configure DAC path - power up both left and right DACs + Serial.println("Configuring DAC path..."); + if (!codec.setDACDataPath(true, true, + TLV320_DAC_PATH_NORMAL, + TLV320_DAC_PATH_NORMAL, + TLV320_VOLUME_STEP_1SAMPLE)) { + Serial.println("Failed to configure DAC data path!"); + } + + // Step 7: Route DAC output to headphone + if (!codec.configureAnalogInputs(TLV320_DAC_ROUTE_MIXER, // Left DAC to mixer + TLV320_DAC_ROUTE_MIXER, // Right DAC to mixer + false, false, false, // No AIN routing + false)) { // No HPL->HPR + Serial.println("Failed to configure DAC routing!"); + } + + // Step 8: Unmute DAC and set volume (higher for testing) + Serial.println("Setting DAC volume..."); + if (!codec.setDACVolumeControl( + false, false, TLV320_VOL_INDEPENDENT) || // Unmute both channels + !codec.setChannelVolume(false, 18) || // Left DAC +0dB + !codec.setChannelVolume(true, 18)) { // Right DAC +0dB + Serial.println("Failed to configure DAC volume control!"); + } + + + if (!codec.setChannelVolume(false, 12.0) || + !codec.setChannelVolume(true, 12.0)) { + Serial.println("Failed to set DAC channel volumes!"); + } + + if (!codec.enableSpeaker(true) || // Dis/Enable speaker amp + !codec.configureSPK_PGA(TLV320_SPK_GAIN_6DB, // Set gain to 6dB + true) || // Unmute + !codec.setSPKVolume(true, 0)) { // Enable and set volume to 0dB + Serial.println("Failed to configure speaker output!"); + } + + // Initialize I2S peripheral + Serial.println("Initializing I2S..."); + i2s.setBCLK(pBCLK); + i2s.setDATA(pDOUT); + i2s.setBitsPerSample(16); + +} + +void loop1() { + // the main loop will tell us when it wants us to play! + play_i2s(startupAudioData, sizeof(startupAudioData), startupSampleRate); + delay(1000); +} + +void play_i2s(const uint8_t *data, uint32_t len, uint32_t rate) { + // start I2S at the sample rate with 16-bits per sample + if (!i2s.begin(rate)) { + Serial.println("Failed to initialize I2S!"); + delay(500); + i2s.end(); + return; + } + + for(uint32_t i=0; i +#include +#include + +Adafruit_TLV320DAC3100 codec; // Create codec object + +#define pBCLK D9 // BITCLOCK - I2S clock +#define pWS D10 // LRCLOCK - Word select +#define pDOUT D11 // DATA - I2S data + +// Create I2S port +I2S i2s(OUTPUT); + +const int frequency = 440; // frequency of square wave in Hz +const int amplitude = 500; // amplitude of square wave +const int sampleRate = 16000; // 16 KHz is a good quality + +const int halfWavelength = (sampleRate / frequency); // half wavelength of square wave + +int16_t sample = amplitude; // current sample value +int count = 0; + +void setup() { + Serial.begin(115200); + + while (!Serial) delay(10); + Serial.println("\n\nTLV320DAC3100 Sine Tone Test"); + // Start I2C communication with codec + Serial.println("Initializing codec..."); + if (!codec.begin()) { + Serial.println("Failed to initialize codec!"); + } + codec.reset(); + // Step 1: Set codec interface to I2S with 16-bit data + Serial.println("Configuring codec interface..."); + if (!codec.setCodecInterface(TLV320DAC3100_FORMAT_I2S, TLV320DAC3100_DATA_LEN_16)) { + Serial.println("Failed to configure codec interface!"); + } + + // Step 2: Configure clock - using PLL with BCLK as input + Serial.println("Configuring codec clocks..."); + if (!codec.setCodecClockInput(TLV320DAC3100_CODEC_CLKIN_PLL) || + !codec.setPLLClockInput(TLV320DAC3100_PLL_CLKIN_BCLK)) { + Serial.println("Failed to configure codec clocks!"); + } + + // Step 3: Set up PLL - these values work well for 44.1kHz sample rate + if (!codec.setPLLValues(1, 1, 8, 0)) { + Serial.println("Failed to configure PLL values!"); + } + + // Step 4: Configure DAC dividers + if (!codec.setNDAC(true, 8) || + !codec.setMDAC(true, 2) || + !codec.setDOSR(128)) { + Serial.println("Failed to configure DAC dividers!"); + } + + // Step 5: Power up PLL + if (!codec.powerPLL(true)) { + Serial.println("Failed to power up PLL!"); + } + + // Step 6: Configure DAC path - power up both left and right DACs + Serial.println("Configuring DAC path..."); + if (!codec.setDACDataPath(true, true, + TLV320_DAC_PATH_NORMAL, + TLV320_DAC_PATH_NORMAL, + TLV320_VOLUME_STEP_1SAMPLE)) { + Serial.println("Failed to configure DAC data path!"); + } + + // Step 7: Route DAC output to headphone + if (!codec.configureAnalogInputs(TLV320_DAC_ROUTE_MIXER, // Left DAC to mixer + TLV320_DAC_ROUTE_MIXER, // Right DAC to mixer + false, false, false, // No AIN routing + false)) { // No HPL->HPR + Serial.println("Failed to configure DAC routing!"); + } + + // Step 8: Unmute DAC and set volume (higher for testing) + Serial.println("Setting DAC volume..."); + if (!codec.setDACVolumeControl( + false, false, TLV320_VOL_INDEPENDENT) || // Unmute both channels + !codec.setChannelVolume(false, 18) || // Left DAC +0dB + !codec.setChannelVolume(true, 18)) { // Right DAC +0dB + Serial.println("Failed to configure DAC volume control!"); + } + + + if (!codec.setChannelVolume(false, 12.0) || + !codec.setChannelVolume(true, 12.0)) { + Serial.println("Failed to set DAC channel volumes!"); + } + + if (!codec.enableSpeaker(true) || // Dis/Enable speaker amp + !codec.configureSPK_PGA(TLV320_SPK_GAIN_6DB, // Set gain to 6dB + true) || // Unmute + !codec.setSPKVolume(true, 0)) { // Enable and set volume to 0dB + Serial.println("Failed to configure speaker output!"); + } + + // Initialize I2S peripheral + Serial.println("Initializing I2S..."); + i2s.setBCLK(pBCLK); + i2s.setDATA(pDOUT); + i2s.setBitsPerSample(16); + + // Start I2S at the sample rate + if (!i2s.begin(sampleRate)) { + Serial.println("Failed to initialize I2S!"); + } + +} + +void loop() { + if (count % halfWavelength == 0) { + // invert the sample every half wavelength count multiple to generate square wave + sample = -1 * sample; + } + + // write the same sample twice, once for left and once for the right channel + i2s.write(sample); + i2s.write(sample); + + // increment the counter for the next sample + count++; +} diff --git a/TMC2209_Camera_Slider/CircuitPython/Arial-14.bdf b/TMC2209_Camera_Slider/CircuitPython/Arial-14.bdf new file mode 100644 index 000000000..a92736e1a --- /dev/null +++ b/TMC2209_Camera_Slider/CircuitPython/Arial-14.bdf @@ -0,0 +1,27566 @@ +STARTFONT 2.1 +COMMENT +COMMENT Converted from OpenType font "arial.ttf" by "otf2bdf 3.0". +COMMENT +FONT -FreeType-Arial-Medium-R-Normal--19-140-100-100-P-94-ISO10646-1 +SIZE 14 100 100 +FONTBOUNDINGBOX 34 26 -13 -6 +STARTPROPERTIES 19 +FOUNDRY "FreeType" +FAMILY_NAME "Arial" +WEIGHT_NAME "Medium" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 19 +POINT_SIZE 140 +RESOLUTION_X 100 +RESOLUTION_Y 100 +SPACING "P" +AVERAGE_WIDTH 94 +CHARSET_REGISTRY "ISO10646" +CHARSET_ENCODING "1" +FONT_ASCENT 17 +FONT_DESCENT 4 +COPYRIGHT "Typeface The Monotype Corporation plc. Data The Monotype Corporation plc/Type Solutions Inc. 1990-1992. All Rights Reserved" +_OTF_FONTFILE "arial.ttf" +_OTF_PSNAME "ArialMT" +ENDPROPERTIES +CHARS 1419 +STARTCHAR 0020 +ENCODING 32 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 0 0 0 0 +BITMAP +ENDCHAR +STARTCHAR 0021 +ENCODING 33 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 14 2 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +80 +80 +80 +80 +00 +C0 +C0 +ENDCHAR +STARTCHAR 0022 +ENCODING 34 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 5 1 9 +BITMAP +D8 +D8 +D8 +D8 +90 +ENDCHAR +STARTCHAR 0023 +ENCODING 35 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +0880 +0880 +1880 +FFC0 +FFC0 +1100 +3100 +3100 +FFC0 +FFC0 +2200 +6200 +6200 +4600 +ENDCHAR +STARTCHAR 0024 +ENCODING 36 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 -2 +BITMAP +0800 +3E00 +7F00 +CB00 +C800 +C800 +7800 +3E00 +0F00 +0900 +0980 +C980 +CB00 +7F00 +3E00 +0800 +0800 +ENDCHAR +STARTCHAR 0025 +ENCODING 37 +SWIDTH 874 0 +DWIDTH 17 0 +BBX 15 14 1 0 +BITMAP +7830 +4C20 +CC40 +CC40 +CC80 +4880 +7900 +0338 +0264 +0646 +0446 +0C46 +0864 +1838 +ENDCHAR +STARTCHAR 0026 +ENCODING 38 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +1E00 +3F00 +3300 +2300 +3300 +1E00 +3C00 +7C00 +C6C0 +C3C0 +C180 +E3C0 +7FE0 +3C60 +ENDCHAR +STARTCHAR 0027 +ENCODING 39 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 5 1 9 +BITMAP +C0 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR 0028 +ENCODING 40 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 18 1 -4 +BITMAP +10 +30 +20 +60 +60 +40 +C0 +C0 +C0 +C0 +C0 +C0 +40 +60 +60 +20 +30 +10 +ENDCHAR +STARTCHAR 0029 +ENCODING 41 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 18 1 -4 +BITMAP +C0 +40 +60 +20 +30 +10 +10 +18 +18 +18 +18 +10 +10 +30 +20 +60 +40 +C0 +ENDCHAR +STARTCHAR 002A +ENCODING 42 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 6 6 1 8 +BITMAP +20 +20 +FC +30 +50 +48 +ENDCHAR +STARTCHAR 002B +ENCODING 43 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 1 +BITMAP +0800 +0800 +0800 +0800 +FF80 +FF80 +0800 +0800 +0800 +0800 +ENDCHAR +STARTCHAR 002C +ENCODING 44 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 5 2 -3 +BITMAP +C0 +C0 +40 +80 +80 +ENDCHAR +STARTCHAR 002D +ENCODING 45 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 2 1 4 +BITMAP +F8 +F8 +ENDCHAR +STARTCHAR 002E +ENCODING 46 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 2 2 0 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR 002F +ENCODING 47 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 14 0 0 +BITMAP +08 +08 +18 +10 +10 +30 +20 +20 +20 +60 +40 +40 +C0 +80 +ENDCHAR +STARTCHAR 0030 +ENCODING 48 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3C00 +7E00 +6300 +C300 +C100 +C180 +C180 +C180 +C180 +C100 +C300 +E300 +7E00 +3C00 +ENDCHAR +STARTCHAR 0031 +ENCODING 49 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 5 14 2 0 +BITMAP +08 +18 +38 +F8 +98 +18 +18 +18 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 0032 +ENCODING 50 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3E00 +7F00 +C300 +C180 +0180 +0300 +0300 +0600 +1C00 +3800 +6000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 0033 +ENCODING 51 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3C00 +7E00 +C300 +C300 +0300 +1E00 +1F00 +0300 +0180 +0180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 0034 +ENCODING 52 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +0300 +0700 +0700 +0F00 +1B00 +1300 +3300 +6300 +4300 +FFC0 +FFC0 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 0035 +ENCODING 53 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +7F00 +7F00 +6000 +4000 +4000 +DE00 +FF00 +C300 +0180 +0180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 0036 +ENCODING 54 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3E00 +7F00 +6300 +C100 +C000 +9E00 +BF00 +E300 +C180 +C180 +C180 +E300 +7F00 +3C00 +ENDCHAR +STARTCHAR 0037 +ENCODING 55 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +FF80 +FF80 +0300 +0600 +0600 +0C00 +0C00 +1800 +1800 +1000 +3000 +3000 +3000 +3000 +ENDCHAR +STARTCHAR 0038 +ENCODING 56 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3C00 +7E00 +6300 +C300 +C300 +6300 +3E00 +7E00 +C300 +C180 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 0039 +ENCODING 57 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3C00 +7E00 +E300 +C100 +C180 +C180 +C380 +7F80 +3D80 +0180 +C300 +C300 +7E00 +3C00 +ENDCHAR +STARTCHAR 003A +ENCODING 58 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 10 2 0 +BITMAP +C0 +C0 +00 +00 +00 +00 +00 +00 +C0 +C0 +ENDCHAR +STARTCHAR 003B +ENCODING 59 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 13 2 -3 +BITMAP +C0 +C0 +00 +00 +00 +00 +00 +00 +C0 +C0 +40 +80 +80 +ENDCHAR +STARTCHAR 003C +ENCODING 60 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 9 1 2 +BITMAP +0080 +0380 +1F00 +7800 +C000 +7800 +1F00 +0380 +0080 +ENDCHAR +STARTCHAR 003D +ENCODING 61 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 6 1 4 +BITMAP +FF80 +FF80 +0000 +0000 +FF80 +FF80 +ENDCHAR +STARTCHAR 003E +ENCODING 62 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 9 1 2 +BITMAP +8000 +E000 +7C00 +0F00 +0180 +0F00 +7C00 +E000 +8000 +ENDCHAR +STARTCHAR 003F +ENCODING 63 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3E00 +7F00 +C300 +C180 +0180 +0300 +0600 +0C00 +0C00 +1800 +1800 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 0040 +ENCODING 64 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 17 18 1 -4 +BITMAP +03F000 +0FFC00 +1C0E00 +300300 +61D980 +47F980 +C63880 +CC1080 +8C1080 +883180 +883100 +CC7700 +CFFE00 +67BC00 +700180 +3C0700 +1FFE00 +03F800 +ENDCHAR +STARTCHAR 0041 +ENCODING 65 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 14 0 0 +BITMAP +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 0042 +ENCODING 66 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FF00 +FF80 +C0C0 +C0C0 +C0C0 +C0C0 +FF80 +FF80 +C0C0 +C060 +C060 +C0C0 +FFC0 +FF80 +ENDCHAR +STARTCHAR 0043 +ENCODING 67 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F80 +3FC0 +70E0 +6070 +C000 +C000 +C000 +C000 +C000 +C030 +6070 +70E0 +3FC0 +0F80 +ENDCHAR +STARTCHAR 0044 +ENCODING 68 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +FF00 +FFC0 +C0E0 +C060 +C020 +C030 +C030 +C030 +C030 +C060 +C060 +C0E0 +FFC0 +FF00 +ENDCHAR +STARTCHAR 0045 +ENCODING 69 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0046 +ENCODING 70 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 9 14 2 0 +BITMAP +FF80 +FF80 +8000 +8000 +8000 +8000 +FF00 +FF00 +8000 +8000 +8000 +8000 +8000 +8000 +ENDCHAR +STARTCHAR 0047 +ENCODING 71 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0F80 +3FE0 +7070 +6030 +C010 +C000 +C000 +C1F8 +C1F8 +C018 +6018 +7038 +3FF0 +0FC0 +ENDCHAR +STARTCHAR 0048 +ENCODING 72 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 10 14 2 0 +BITMAP +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +FFC0 +FFC0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +ENDCHAR +STARTCHAR 0049 +ENCODING 73 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 14 2 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 004A +ENCODING 74 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 14 1 0 +BITMAP +06 +06 +06 +06 +06 +06 +06 +06 +06 +06 +86 +C6 +FC +78 +ENDCHAR +STARTCHAR 004B +ENCODING 75 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +C0E0 +C1C0 +C380 +C700 +CE00 +DC00 +FC00 +F600 +E700 +C300 +C180 +C0C0 +C0E0 +C060 +ENDCHAR +STARTCHAR 004C +ENCODING 76 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 004D +ENCODING 77 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 13 14 1 0 +BITMAP +E018 +F038 +F028 +D028 +D868 +D868 +C848 +CCC8 +CCC8 +C488 +C788 +C788 +C308 +C308 +ENDCHAR +STARTCHAR 004E +ENCODING 78 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 1 0 +BITMAP +E060 +E060 +F060 +D860 +D860 +CC60 +CC60 +C660 +C360 +C360 +C1E0 +C0E0 +C0E0 +C060 +ENDCHAR +STARTCHAR 004F +ENCODING 79 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 0050 +ENCODING 80 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FF80 +FFC0 +C0E0 +C060 +C060 +C060 +C0C0 +FFC0 +FF80 +C000 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 0051 +ENCODING 81 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 15 1 -1 +BITMAP +0F80 +3FE0 +7070 +6030 +C038 +C018 +C018 +C018 +C018 +C030 +61B0 +70E0 +3FE0 +0FB8 +0008 +ENDCHAR +STARTCHAR 0052 +ENCODING 82 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +FFC0 +FFE0 +C060 +C060 +C060 +C060 +FFE0 +FF80 +C300 +C180 +C0C0 +C060 +C060 +C030 +ENDCHAR +STARTCHAR 0053 +ENCODING 83 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +1F00 +7F80 +60C0 +C0C0 +C000 +7000 +3F00 +07C0 +00C0 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 0054 +ENCODING 84 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 0 0 +BITMAP +FFE0 +FFE0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0055 +ENCODING 85 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 1 0 +BITMAP +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 0056 +ENCODING 86 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 14 0 0 +BITMAP +C010 +6030 +6030 +6060 +3060 +3040 +10C0 +18C0 +1880 +0980 +0D80 +0D00 +0700 +0600 +ENDCHAR +STARTCHAR 0057 +ENCODING 87 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 14 0 0 +BITMAP +C0C0C0 +40C080 +61E180 +61E180 +612180 +233100 +333300 +323300 +321200 +161A00 +161E00 +1C0E00 +1C0C00 +0C0C00 +ENDCHAR +STARTCHAR 0058 +ENCODING 88 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 14 0 0 +BITMAP +6030 +3060 +30C0 +18C0 +0D80 +0F00 +0700 +0700 +0D80 +1980 +18C0 +3060 +6070 +E030 +ENDCHAR +STARTCHAR 0059 +ENCODING 89 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 14 0 0 +BITMAP +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 005A +ENCODING 90 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 0 0 +BITMAP +7FE0 +7FE0 +00C0 +01C0 +0180 +0300 +0600 +0C00 +1C00 +3800 +3000 +6000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 005B +ENCODING 91 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 18 1 -4 +BITMAP +F0 +F0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +F0 +F0 +ENDCHAR +STARTCHAR 005C +ENCODING 92 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 14 0 0 +BITMAP +80 +C0 +40 +40 +60 +20 +20 +20 +30 +10 +10 +18 +08 +08 +ENDCHAR +STARTCHAR 005D +ENCODING 93 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 18 0 -4 +BITMAP +F0 +F0 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +F0 +F0 +ENDCHAR +STARTCHAR 005E +ENCODING 94 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 7 1 7 +BITMAP +10 +38 +28 +6C +44 +C6 +82 +ENDCHAR +STARTCHAR 005F +ENCODING 95 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 2 0 -4 +BITMAP +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0060 +ENCODING 96 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 3 3 1 11 +BITMAP +C0 +60 +20 +ENDCHAR +STARTCHAR 0061 +ENCODING 97 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 0062 +ENCODING 98 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +C000 +C000 +C000 +C000 +DE00 +FF00 +E300 +C180 +C180 +C180 +C180 +E300 +FF00 +DC00 +ENDCHAR +STARTCHAR 0063 +ENCODING 99 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +3C +7F +E3 +C0 +80 +80 +C0 +C3 +7F +3C +ENDCHAR +STARTCHAR 0064 +ENCODING 100 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +01 +01 +01 +01 +39 +7D +C3 +C3 +81 +81 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 0065 +ENCODING 101 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0066 +ENCODING 102 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 14 0 0 +BITMAP +1C +3C +20 +20 +F8 +F8 +20 +20 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR 0067 +ENCODING 103 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +3D +7F +C3 +C3 +81 +81 +C3 +C3 +7F +3D +01 +C3 +FE +7C +ENDCHAR +STARTCHAR 0068 +ENCODING 104 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +C0 +C0 +C0 +C0 +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +ENDCHAR +STARTCHAR 0069 +ENCODING 105 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 14 1 0 +BITMAP +C0 +C0 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 006A +ENCODING 106 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 18 -1 -4 +BITMAP +30 +30 +00 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +F0 +E0 +ENDCHAR +STARTCHAR 006B +ENCODING 107 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +C0 +C0 +C0 +C0 +C7 +CE +DC +F8 +F8 +D8 +CC +C6 +C6 +C3 +ENDCHAR +STARTCHAR 006C +ENCODING 108 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 14 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 006D +ENCODING 109 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 10 1 0 +BITMAP +DC70 +FEF8 +E38C +C30C +C30C +C30C +C30C +C30C +C30C +C30C +ENDCHAR +STARTCHAR 006E +ENCODING 110 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 10 1 0 +BITMAP +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +ENDCHAR +STARTCHAR 006F +ENCODING 111 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 0070 +ENCODING 112 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 -4 +BITMAP +DE00 +FF00 +E300 +C180 +C180 +C180 +C180 +E300 +FF00 +DC00 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 0071 +ENCODING 113 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +39 +7D +C3 +C3 +81 +81 +C3 +C3 +7D +39 +01 +01 +01 +01 +ENDCHAR +STARTCHAR 0072 +ENCODING 114 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 10 1 0 +BITMAP +DC +F8 +E0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0073 +ENCODING 115 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +7C +FE +C6 +E0 +FC +3E +03 +C3 +FE +7C +ENDCHAR +STARTCHAR 0074 +ENCODING 116 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 13 0 0 +BITMAP +20 +20 +20 +F8 +F8 +20 +20 +20 +20 +20 +20 +38 +38 +ENDCHAR +STARTCHAR 0075 +ENCODING 117 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 10 1 0 +BITMAP +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 0076 +ENCODING 118 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 0 0 +BITMAP +C180 +6180 +6100 +2300 +3300 +3200 +1600 +1C00 +1C00 +0C00 +ENDCHAR +STARTCHAR 0077 +ENCODING 119 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 10 0 0 +BITMAP +C308 +4308 +4718 +6798 +6590 +24B0 +3CB0 +3CE0 +18E0 +1860 +ENDCHAR +STARTCHAR 0078 +ENCODING 120 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 0 0 +BITMAP +6180 +6300 +3600 +1E00 +0C00 +1C00 +1E00 +3300 +6300 +E180 +ENDCHAR +STARTCHAR 0079 +ENCODING 121 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 -4 +BITMAP +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 007A +ENCODING 122 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 0 0 +BITMAP +7F80 +7F80 +0300 +0600 +0C00 +1800 +3000 +6000 +FF80 +FF80 +ENDCHAR +STARTCHAR 007B +ENCODING 123 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 18 1 -4 +BITMAP +38 +38 +60 +60 +60 +60 +60 +60 +C0 +C0 +60 +60 +60 +60 +60 +20 +38 +38 +ENDCHAR +STARTCHAR 007C +ENCODING 124 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 1 18 2 -4 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR 007D +ENCODING 125 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 18 0 -4 +BITMAP +E0 +F0 +30 +30 +30 +30 +30 +18 +1C +1C +18 +30 +30 +30 +30 +30 +F0 +E0 +ENDCHAR +STARTCHAR 007E +ENCODING 126 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 4 1 4 +BITMAP +7000 +FC80 +8F80 +0700 +ENDCHAR +STARTCHAR 00A0 +ENCODING 160 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 0 0 0 0 +BITMAP +ENDCHAR +STARTCHAR 00A1 +ENCODING 161 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 14 2 -4 +BITMAP +C0 +C0 +00 +40 +40 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00A2 +ENCODING 162 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 18 1 -4 +BITMAP +02 +02 +02 +06 +3C +7F +E7 +C8 +C8 +C8 +D1 +F3 +7F +3C +20 +20 +20 +40 +ENDCHAR +STARTCHAR 00A3 +ENCODING 163 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +1F00 +3F80 +30C0 +6000 +6000 +2000 +FE00 +FE00 +3000 +3000 +2000 +7C40 +FFC0 +4380 +ENDCHAR +STARTCHAR 00A4 +ENCODING 164 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 8 1 2 +BITMAP +9D +FF +63 +C1 +C1 +63 +FF +9D +ENDCHAR +STARTCHAR 00A5 +ENCODING 165 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +C0C0 +60C0 +6180 +3180 +3300 +1B00 +1E00 +7FC0 +7FC0 +0C00 +7FC0 +7FC0 +0C00 +0C00 +ENDCHAR +STARTCHAR 00A6 +ENCODING 166 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 1 18 2 -4 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +00 +00 +00 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR 00A7 +ENCODING 167 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 -4 +BITMAP +3C00 +7E00 +6300 +6000 +7000 +7C00 +8E00 +8300 +C180 +E180 +3900 +1E00 +0600 +0300 +C300 +6300 +7F00 +3C00 +ENDCHAR +STARTCHAR 00A8 +ENCODING 168 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 2 1 12 +BITMAP +98 +98 +ENDCHAR +STARTCHAR 00A9 +ENCODING 169 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 14 14 0 0 +BITMAP +0FC0 +1860 +2010 +4788 +CC4C +8804 +9804 +9804 +8844 +CCCC +4788 +2010 +1860 +0FC0 +ENDCHAR +STARTCHAR 00AA +ENCODING 170 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 6 7 0 7 +BITMAP +3C +44 +04 +7C +C4 +4C +7C +ENDCHAR +STARTCHAR 00AB +ENCODING 171 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 9 1 1 +BITMAP +13 +32 +26 +64 +CC +64 +26 +32 +13 +ENDCHAR +STARTCHAR 00AC +ENCODING 172 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 6 1 4 +BITMAP +FF80 +FF80 +0180 +0180 +0180 +0180 +ENDCHAR +STARTCHAR 00AD +ENCODING 173 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 2 1 4 +BITMAP +F8 +F8 +ENDCHAR +STARTCHAR 00AE +ENCODING 174 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 14 14 0 0 +BITMAP +0FC0 +1860 +2010 +4F88 +C8CC +88C4 +8F84 +8904 +8884 +C8CC +4848 +2010 +1860 +0FC0 +ENDCHAR +STARTCHAR 00AF +ENCODING 175 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 2 0 15 +BITMAP +FFE0 +FFE0 +ENDCHAR +STARTCHAR 00B0 +ENCODING 176 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 5 5 1 9 +BITMAP +70 +C8 +88 +C8 +70 +ENDCHAR +STARTCHAR 00B1 +ENCODING 177 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 11 1 0 +BITMAP +1800 +1800 +1800 +1800 +FF80 +FF80 +1800 +1800 +1800 +FF80 +FF80 +ENDCHAR +STARTCHAR 00B2 +ENCODING 178 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 7 0 7 +BITMAP +78 +4C +0C +18 +30 +60 +FC +ENDCHAR +STARTCHAR 00B3 +ENCODING 179 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 7 0 7 +BITMAP +78 +4C +0C +18 +0C +CC +78 +ENDCHAR +STARTCHAR 00B4 +ENCODING 180 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 3 3 2 11 +BITMAP +60 +40 +C0 +ENDCHAR +STARTCHAR 00B5 +ENCODING 181 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +C1 +C1 +C1 +C1 +C1 +C1 +C1 +E3 +FF +DD +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00B6 +ENCODING 182 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 17 0 -3 +BITMAP +3FC0 +7FC0 +F980 +F980 +F980 +F980 +7980 +3980 +0980 +0980 +0980 +0980 +0980 +0980 +0980 +0980 +0980 +ENDCHAR +STARTCHAR 00B7 +ENCODING 183 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 2 2 6 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR 00B8 +ENCODING 184 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 4 1 -4 +BITMAP +60 +70 +30 +E0 +ENDCHAR +STARTCHAR 00B9 +ENCODING 185 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 3 7 1 7 +BITMAP +20 +60 +E0 +A0 +20 +20 +20 +ENDCHAR +STARTCHAR 00BA +ENCODING 186 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 7 0 7 +BITMAP +38 +44 +44 +C6 +44 +44 +38 +ENDCHAR +STARTCHAR 00BB +ENCODING 187 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 7 9 2 1 +BITMAP +98 +C8 +4C +66 +36 +66 +4C +C8 +98 +ENDCHAR +STARTCHAR 00BC +ENCODING 188 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 1 0 +BITMAP +2018 +6030 +E020 +A040 +20C0 +2080 +2100 +030C +061C +041C +082C +186C +307E +200C +ENDCHAR +STARTCHAR 00BD +ENCODING 189 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 1 0 +BITMAP +2010 +6030 +E020 +A040 +20C0 +2180 +2100 +023C +0664 +0C04 +080C +1018 +3030 +607E +ENDCHAR +STARTCHAR 00BE +ENCODING 190 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 16 14 0 0 +BITMAP +780C +4C18 +0C10 +1820 +0C60 +CC40 +7880 +0186 +030E +020E +0416 +0C36 +183F +1006 +ENDCHAR +STARTCHAR 00BF +ENCODING 191 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 9 14 1 -4 +BITMAP +0C00 +0C00 +0000 +0C00 +0C00 +0800 +1800 +3000 +6000 +4000 +C180 +6180 +7F00 +1E00 +ENDCHAR +STARTCHAR 00C0 +ENCODING 192 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0600 +0600 +0200 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 00C1 +ENCODING 193 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0300 +0200 +0600 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 00C2 +ENCODING 194 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0600 +0F00 +0980 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 00C3 +ENCODING 195 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0C80 +1F80 +1B80 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 00C4 +ENCODING 196 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 17 0 0 +BITMAP +0980 +0980 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 00C5 +ENCODING 197 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0600 +0900 +0900 +0900 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 00C6 +ENCODING 198 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 18 14 0 0 +BITMAP +03FFC0 +03FFC0 +066000 +066000 +0C6000 +0C6000 +087F80 +187F80 +1FE000 +3FE000 +306000 +606000 +607FC0 +C07FC0 +ENDCHAR +STARTCHAR 00C7 +ENCODING 199 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 -4 +BITMAP +0F80 +3FC0 +70E0 +6070 +C000 +C000 +C000 +C000 +C000 +C030 +6070 +70E0 +3FC0 +0F80 +0400 +0600 +0300 +0E00 +ENDCHAR +STARTCHAR 00C8 +ENCODING 200 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0C00 +0C00 +0600 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 00C9 +ENCODING 201 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0600 +0600 +0C00 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 00CA +ENCODING 202 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0E00 +0A00 +1B00 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 00CB +ENCODING 203 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 17 1 0 +BITMAP +1B00 +1B00 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 00CC +ENCODING 204 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 3 18 1 0 +BITMAP +C0 +40 +60 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 00CD +ENCODING 205 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 18 2 0 +BITMAP +C0 +C0 +80 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00CE +ENCODING 206 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 18 0 0 +BITMAP +70 +58 +D8 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 00CF +ENCODING 207 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 17 0 0 +BITMAP +D8 +D8 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 00D0 +ENCODING 208 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 14 0 0 +BITMAP +7F80 +7FE0 +6070 +6030 +6010 +6018 +FE18 +FE18 +6018 +6030 +6030 +6070 +7FE0 +7F80 +ENDCHAR +STARTCHAR 00D1 +ENCODING 209 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0C80 +1F80 +1300 +0000 +E060 +E060 +F060 +D860 +D860 +CC60 +CC60 +C660 +C360 +C360 +C1E0 +C0E0 +C0E0 +C060 +ENDCHAR +STARTCHAR 00D2 +ENCODING 210 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0C00 +0600 +0200 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 00D3 +ENCODING 211 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0300 +0300 +0600 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 00D4 +ENCODING 212 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0700 +0D00 +0D80 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 00D5 +ENCODING 213 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0EC0 +0F80 +1B80 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 00D6 +ENCODING 214 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 17 1 0 +BITMAP +0D80 +0D80 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 00D7 +ENCODING 215 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 7 7 2 3 +BITMAP +82 +C6 +7C +38 +7C +C6 +82 +ENDCHAR +STARTCHAR 00D8 +ENCODING 216 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 15 1 -1 +BITMAP +0F88 +3FD0 +7060 +6070 +C0D0 +C198 +C318 +C618 +CC18 +D818 +7030 +7070 +7FE0 +DF80 +8000 +ENDCHAR +STARTCHAR 00D9 +ENCODING 217 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0C00 +0400 +0600 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 00DA +ENCODING 218 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0300 +0600 +0400 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 00DB +ENCODING 219 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0600 +0F00 +1900 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 00DC +ENCODING 220 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 17 1 0 +BITMAP +1900 +1900 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 00DD +ENCODING 221 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +0300 +0300 +0600 +0000 +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 00DE +ENCODING 222 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +C000 +C000 +C000 +FF80 +FFC0 +C0E0 +C060 +C060 +C0E0 +FFC0 +FF80 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 00DF +ENCODING 223 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +3C00 +7E00 +6300 +C300 +C200 +C600 +C400 +C600 +C380 +C1C0 +C0C0 +D8C0 +CFC0 +C780 +ENDCHAR +STARTCHAR 00E0 +ENCODING 224 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3800 +1800 +0800 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 00E1 +ENCODING 225 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 00E2 +ENCODING 226 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +1800 +3400 +2600 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 00E3 +ENCODING 227 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3200 +7E00 +4E00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 00E4 +ENCODING 228 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 0 +BITMAP +2600 +2600 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 00E5 +ENCODING 229 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 16 1 0 +BITMAP +1800 +2400 +2400 +2400 +1800 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 00E6 +ENCODING 230 +SWIDTH 874 0 +DWIDTH 17 0 +BBX 15 10 1 0 +BITMAP +3E78 +7FFC +C386 +0F06 +7FFE +F3FE +8300 +C786 +FFFC +7878 +ENDCHAR +STARTCHAR 00E7 +ENCODING 231 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 -4 +BITMAP +3C +7F +E3 +C0 +80 +80 +C0 +C3 +7F +3C +10 +18 +0C +38 +ENDCHAR +STARTCHAR 00E8 +ENCODING 232 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3000 +1800 +0800 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 00E9 +ENCODING 233 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 00EA +ENCODING 234 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 00EB +ENCODING 235 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 0 +BITMAP +2600 +2600 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 00EC +ENCODING 236 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 3 14 1 0 +BITMAP +C0 +C0 +60 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 00ED +ENCODING 237 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 3 14 2 0 +BITMAP +60 +C0 +80 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 00EE +ENCODING 238 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 14 0 0 +BITMAP +30 +78 +C8 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 00EF +ENCODING 239 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 13 0 0 +BITMAP +C8 +C8 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 00F0 +ENCODING 240 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3200 +1E00 +3C00 +2600 +3B00 +7F00 +C300 +C180 +8180 +8180 +C180 +E300 +7F00 +3C00 +ENDCHAR +STARTCHAR 00F1 +ENCODING 241 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +3B +3E +6E +00 +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +ENDCHAR +STARTCHAR 00F2 +ENCODING 242 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3000 +1800 +0800 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 00F3 +ENCODING 243 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 00F4 +ENCODING 244 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 00F5 +ENCODING 245 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3200 +7E00 +4E00 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 00F6 +ENCODING 246 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 0 +BITMAP +2600 +2600 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 00F7 +ENCODING 247 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 8 1 2 +BITMAP +1800 +1800 +0000 +FF80 +FF80 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 00F8 +ENCODING 248 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 9 12 1 -1 +BITMAP +0080 +1E80 +7F00 +6380 +C680 +C480 +C880 +D180 +7380 +7F00 +5E00 +8000 +ENDCHAR +STARTCHAR 00F9 +ENCODING 249 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +18 +18 +0C +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 00FA +ENCODING 250 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +0C +0C +18 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 00FB +ENCODING 251 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +18 +3C +26 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 00FC +ENCODING 252 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 13 1 0 +BITMAP +26 +26 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 00FD +ENCODING 253 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 18 1 -4 +BITMAP +0C +08 +18 +00 +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 00FE +ENCODING 254 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 -4 +BITMAP +C000 +C000 +C000 +C000 +DE00 +FF00 +E300 +C180 +C180 +C180 +C180 +E300 +FF00 +DC00 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 00FF +ENCODING 255 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 17 1 -4 +BITMAP +64 +64 +00 +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 0100 +ENCODING 256 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 16 0 0 +BITMAP +1F80 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 0101 +ENCODING 257 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +3E00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 0102 +ENCODING 258 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0880 +0980 +0700 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 0103 +ENCODING 259 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +2200 +2200 +1C00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 0104 +ENCODING 260 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 18 0 -4 +BITMAP +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +0010 +0020 +0030 +001C +ENDCHAR +STARTCHAR 0105 +ENCODING 261 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 14 1 -4 +BITMAP +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +0100 +0100 +0100 +01E0 +ENDCHAR +STARTCHAR 0106 +ENCODING 262 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +0300 +0300 +0600 +0000 +0F80 +3FC0 +70E0 +6070 +C000 +C000 +C000 +C000 +C000 +C030 +6070 +70E0 +3FC0 +0F80 +ENDCHAR +STARTCHAR 0107 +ENCODING 263 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +0C +08 +18 +00 +3C +7F +E3 +C0 +80 +80 +C0 +C3 +7F +3C +ENDCHAR +STARTCHAR 0108 +ENCODING 264 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +0600 +0F00 +0980 +0000 +0F80 +3FC0 +70E0 +6070 +C000 +C000 +C000 +C000 +C000 +C030 +6070 +70E0 +3FC0 +0F80 +ENDCHAR +STARTCHAR 0109 +ENCODING 265 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +1C +14 +36 +00 +3C +7F +E3 +C0 +80 +80 +C0 +C3 +7F +3C +ENDCHAR +STARTCHAR 010A +ENCODING 266 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 17 1 0 +BITMAP +0600 +0600 +0000 +0F80 +3FC0 +70E0 +6070 +C000 +C000 +C000 +C000 +C000 +C030 +6070 +70E0 +3FC0 +0F80 +ENDCHAR +STARTCHAR 010B +ENCODING 267 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 13 1 0 +BITMAP +18 +18 +00 +3C +7F +E3 +C0 +80 +80 +C0 +C3 +7F +3C +ENDCHAR +STARTCHAR 010C +ENCODING 268 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +0D80 +0D00 +0700 +0000 +0F80 +3FC0 +70E0 +6070 +C000 +C000 +C000 +C000 +C000 +C030 +6070 +70E0 +3FC0 +0F80 +ENDCHAR +STARTCHAR 010D +ENCODING 269 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +26 +3C +18 +00 +3C +7F +E3 +C0 +80 +80 +C0 +C3 +7F +3C +ENDCHAR +STARTCHAR 010E +ENCODING 270 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +3600 +1400 +1C00 +0000 +FF00 +FFC0 +C0E0 +C060 +C020 +C030 +C030 +C030 +C030 +C060 +C060 +C0E0 +FFC0 +FF00 +ENDCHAR +STARTCHAR 010F +ENCODING 271 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 1 0 +BITMAP +0160 +0160 +0120 +0140 +3D00 +7F00 +C300 +C300 +8100 +8100 +C300 +C300 +7D00 +3900 +ENDCHAR +STARTCHAR 0110 +ENCODING 272 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 14 0 0 +BITMAP +7F80 +7FE0 +6070 +6030 +6010 +6018 +FE18 +FE18 +6018 +6030 +6030 +6070 +7FE0 +7F80 +ENDCHAR +STARTCHAR 0111 +ENCODING 273 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 0 +BITMAP +0100 +1FC0 +1FC0 +0100 +3900 +7D00 +C300 +C300 +8100 +8100 +C300 +C300 +7D00 +3900 +ENDCHAR +STARTCHAR 0112 +ENCODING 274 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 16 1 0 +BITMAP +1F80 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0113 +ENCODING 275 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +7E00 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0114 +ENCODING 276 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +1100 +1100 +0E00 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0115 +ENCODING 277 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +2200 +2200 +1C00 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0116 +ENCODING 278 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 17 1 0 +BITMAP +0600 +0600 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0117 +ENCODING 279 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 0 +BITMAP +1C00 +1C00 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0118 +ENCODING 280 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 -4 +BITMAP +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +0100 +0100 +0100 +01E0 +ENDCHAR +STARTCHAR 0119 +ENCODING 281 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 -4 +BITMAP +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +0800 +0800 +0800 +0F00 +ENDCHAR +STARTCHAR 011A +ENCODING 282 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +1300 +1E00 +0C00 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 011B +ENCODING 283 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3600 +3400 +1C00 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 011C +ENCODING 284 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0300 +0780 +0CC0 +0000 +0F80 +3FE0 +7070 +6030 +C010 +C000 +C000 +C1F8 +C1F8 +C018 +6018 +7038 +3FF0 +0FC0 +ENDCHAR +STARTCHAR 011D +ENCODING 285 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 18 1 -4 +BITMAP +18 +3C +66 +00 +3D +7F +C3 +C3 +81 +81 +C3 +C3 +7F +3D +01 +C3 +FE +7C +ENDCHAR +STARTCHAR 011E +ENCODING 286 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0C40 +0480 +0780 +0000 +0F80 +3FE0 +7070 +6030 +C010 +C000 +C000 +C1F8 +C1F8 +C018 +6018 +7038 +3FF0 +0FC0 +ENDCHAR +STARTCHAR 011F +ENCODING 287 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 18 1 -4 +BITMAP +22 +26 +1C +00 +3D +7F +C3 +C3 +81 +81 +C3 +C3 +7F +3D +01 +C3 +FE +7C +ENDCHAR +STARTCHAR 0120 +ENCODING 288 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 17 1 0 +BITMAP +0300 +0300 +0000 +0F80 +3FE0 +7070 +6030 +C010 +C000 +C000 +C1F8 +C1F8 +C018 +6018 +7038 +3FF0 +0FC0 +ENDCHAR +STARTCHAR 0121 +ENCODING 289 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 17 1 -4 +BITMAP +18 +18 +00 +3D +7F +C3 +C3 +81 +81 +C3 +C3 +7F +3D +01 +C3 +FE +7C +ENDCHAR +STARTCHAR 0122 +ENCODING 290 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 -4 +BITMAP +0F80 +3FE0 +7070 +6030 +C010 +C000 +C000 +C1F8 +C1F8 +C018 +6018 +7038 +3FF0 +0FC0 +0300 +0380 +0180 +0700 +ENDCHAR +STARTCHAR 0123 +ENCODING 291 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 19 1 -4 +BITMAP +08 +10 +18 +18 +00 +3D +7F +C3 +C3 +81 +81 +C3 +C3 +7F +3D +03 +C3 +FE +7C +ENDCHAR +STARTCHAR 0124 +ENCODING 292 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 10 18 2 0 +BITMAP +0C00 +1E00 +1300 +0000 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +FFC0 +FFC0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +ENDCHAR +STARTCHAR 0125 +ENCODING 293 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 18 1 0 +BITMAP +0C +1E +33 +00 +C0 +C0 +C0 +C0 +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +ENDCHAR +STARTCHAR 0126 +ENCODING 294 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 14 0 0 +BITMAP +2030 +FFF8 +FFF8 +2030 +2030 +3FF0 +3FF0 +2030 +2030 +2030 +2030 +2030 +2030 +2030 +ENDCHAR +STARTCHAR 0127 +ENCODING 295 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 0 0 +BITMAP +6000 +FC00 +FC00 +6000 +6F00 +7F80 +7180 +6080 +6080 +6080 +6080 +6080 +6080 +6080 +ENDCHAR +STARTCHAR 0128 +ENCODING 296 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 7 18 -1 0 +BITMAP +76 +7C +DC +00 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 0129 +ENCODING 297 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 14 0 0 +BITMAP +EC +FC +98 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012A +ENCODING 298 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 16 0 0 +BITMAP +FC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012B +ENCODING 299 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 12 0 0 +BITMAP +FC +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012C +ENCODING 300 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 18 0 0 +BITMAP +88 +C8 +70 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012D +ENCODING 301 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 14 0 0 +BITMAP +88 +C8 +70 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 012E +ENCODING 302 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 18 2 -4 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +80 +80 +80 +F0 +ENDCHAR +STARTCHAR 012F +ENCODING 303 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 18 1 -4 +BITMAP +C0 +C0 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +80 +80 +80 +70 +ENDCHAR +STARTCHAR 0130 +ENCODING 304 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 17 2 0 +BITMAP +C0 +C0 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0131 +ENCODING 305 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 10 2 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0132 +ENCODING 306 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 2 0 +BITMAP +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C860 +CC60 +CFC0 +C780 +ENDCHAR +STARTCHAR 0133 +ENCODING 307 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 6 18 1 -4 +BITMAP +C4 +C4 +00 +00 +C4 +C4 +C4 +C4 +C4 +C4 +C4 +C4 +C4 +C4 +04 +04 +1C +1C +ENDCHAR +STARTCHAR 0134 +ENCODING 308 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 18 1 0 +BITMAP +0700 +0D00 +0D80 +0000 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +8600 +C600 +FC00 +7800 +ENDCHAR +STARTCHAR 0135 +ENCODING 309 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 6 18 -1 -4 +BITMAP +30 +78 +4C +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +F0 +E0 +ENDCHAR +STARTCHAR 0136 +ENCODING 310 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 -4 +BITMAP +C0E0 +C1C0 +C380 +C700 +CE00 +DC00 +FC00 +F600 +E700 +C300 +C180 +C0C0 +C0E0 +C060 +0000 +0700 +0100 +0F00 +ENDCHAR +STARTCHAR 0137 +ENCODING 311 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 18 1 -4 +BITMAP +C0 +C0 +C0 +C0 +C7 +CE +DC +F8 +F8 +D8 +CC +C6 +C6 +C3 +00 +0C +06 +1C +ENDCHAR +STARTCHAR 0138 +ENCODING 312 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +C7 +CE +D8 +F0 +F8 +C8 +CC +C6 +C6 +C3 +ENDCHAR +STARTCHAR 0139 +ENCODING 313 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +1800 +3000 +3000 +0000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 013A +ENCODING 314 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 18 1 0 +BITMAP +60 +C0 +80 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 013B +ENCODING 315 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 -4 +BITMAP +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FF80 +FF80 +0000 +0E00 +0200 +1E00 +ENDCHAR +STARTCHAR 013C +ENCODING 316 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 18 0 -4 +BITMAP +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +00 +70 +30 +E0 +ENDCHAR +STARTCHAR 013D +ENCODING 317 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +C300 +C300 +C200 +C200 +C200 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 013E +ENCODING 318 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 14 1 0 +BITMAP +D8 +D8 +D0 +D0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 013F +ENCODING 319 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +C000 +C000 +C000 +C000 +C000 +C000 +C300 +C300 +C000 +C000 +C000 +C000 +FF80 +FF80 +ENDCHAR +STARTCHAR 0140 +ENCODING 320 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 14 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +D8 +D8 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0141 +ENCODING 321 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +6000 +6000 +6000 +6400 +6C00 +7800 +7000 +E000 +E000 +6000 +6000 +6000 +7FC0 +7FC0 +ENDCHAR +STARTCHAR 0142 +ENCODING 322 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 14 0 0 +BITMAP +60 +60 +60 +60 +70 +70 +60 +E0 +E0 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 0143 +ENCODING 323 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0600 +0600 +0400 +0000 +E060 +E060 +F060 +D860 +D860 +CC60 +CC60 +C660 +C360 +C360 +C1E0 +C0E0 +C0E0 +C060 +ENDCHAR +STARTCHAR 0144 +ENCODING 324 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +0C +0C +18 +00 +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +ENDCHAR +STARTCHAR 0145 +ENCODING 325 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 -4 +BITMAP +E060 +E060 +F060 +D860 +D860 +CC60 +CC60 +C660 +C360 +C360 +C1E0 +C0E0 +C0E0 +C060 +0000 +0700 +0180 +0700 +ENDCHAR +STARTCHAR 0146 +ENCODING 326 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +00 +1C +04 +3C +ENDCHAR +STARTCHAR 0147 +ENCODING 327 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +1900 +0F00 +0600 +0000 +E060 +E060 +F060 +D860 +D860 +CC60 +CC60 +C660 +C360 +C360 +C1E0 +C0E0 +C0E0 +C060 +ENDCHAR +STARTCHAR 0148 +ENCODING 328 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +36 +34 +1C +00 +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +ENDCHAR +STARTCHAR 0149 +ENCODING 329 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +C000 +C000 +4000 +8000 +B780 +3FC0 +38C0 +30C0 +30C0 +30C0 +30C0 +30C0 +30C0 +30C0 +ENDCHAR +STARTCHAR 014A +ENCODING 330 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 2 0 +BITMAP +9F00 +BF80 +E1C0 +C0C0 +C060 +8060 +8060 +8060 +8060 +8060 +80C0 +80C0 +8780 +8F00 +ENDCHAR +STARTCHAR 014B +ENCODING 331 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +01 +03 +07 +06 +ENDCHAR +STARTCHAR 014C +ENCODING 332 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 16 1 0 +BITMAP +0F80 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 014D +ENCODING 333 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 1 0 +BITMAP +7E00 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 014E +ENCODING 334 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0880 +0880 +0700 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 014F +ENCODING 335 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +2200 +2600 +1C00 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 0150 +ENCODING 336 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0CC0 +0D80 +0900 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 0151 +ENCODING 337 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +1B00 +3600 +2600 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 0152 +ENCODING 338 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 17 14 1 0 +BITMAP +1F7F80 +3FFF80 +71E000 +60E000 +C06000 +C06000 +C07F80 +C07F80 +C06000 +C06000 +60E000 +71E000 +3FFF80 +1F7F80 +ENDCHAR +STARTCHAR 0153 +ENCODING 339 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 16 10 1 0 +BITMAP +3C3C +7F7E +E3C3 +C183 +C1FF +C1FF +C180 +E3C3 +7F7E +3C3C +ENDCHAR +STARTCHAR 0154 +ENCODING 340 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +0600 +0C00 +0800 +0000 +FFC0 +FFE0 +C060 +C060 +C060 +C060 +FFE0 +FF80 +C300 +C180 +C0C0 +C060 +C060 +C030 +ENDCHAR +STARTCHAR 0155 +ENCODING 341 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 14 1 0 +BITMAP +30 +30 +60 +00 +DC +F8 +E0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0156 +ENCODING 342 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 -4 +BITMAP +FFC0 +FFE0 +C060 +C060 +C060 +C060 +FFE0 +FF80 +C300 +C180 +C0C0 +C060 +C060 +C030 +0000 +0700 +0180 +0700 +ENDCHAR +STARTCHAR 0157 +ENCODING 343 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 14 1 -4 +BITMAP +DC +F8 +E0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +00 +70 +10 +F0 +ENDCHAR +STARTCHAR 0158 +ENCODING 344 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +3300 +1E00 +0C00 +0000 +FFC0 +FFE0 +C060 +C060 +C060 +C060 +FFE0 +FF80 +C300 +C180 +C0C0 +C060 +C060 +C030 +ENDCHAR +STARTCHAR 0159 +ENCODING 345 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 14 1 0 +BITMAP +D8 +50 +70 +00 +DC +F8 +E0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 015A +ENCODING 346 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0600 +0C00 +0800 +0000 +1F00 +7F80 +60C0 +C0C0 +C000 +7000 +3F00 +07C0 +00C0 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 015B +ENCODING 347 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +0C +18 +10 +00 +7C +FE +C6 +E0 +FC +3E +03 +C3 +FE +7C +ENDCHAR +STARTCHAR 015C +ENCODING 348 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0C00 +1A00 +1300 +0000 +1F00 +7F80 +60C0 +C0C0 +C000 +7000 +3F00 +07C0 +00C0 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 015D +ENCODING 349 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +18 +3C +66 +00 +7C +FE +C6 +E0 +FC +3E +03 +C3 +FE +7C +ENDCHAR +STARTCHAR 015E +ENCODING 350 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 -4 +BITMAP +1F00 +7F80 +60C0 +C0C0 +C000 +7000 +3F00 +07C0 +00C0 +C060 +C060 +60C0 +7FC0 +1F00 +0400 +0E00 +0200 +1C00 +ENDCHAR +STARTCHAR 015F +ENCODING 351 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 -4 +BITMAP +7C +FE +C6 +E0 +FC +3E +03 +C3 +FE +7C +10 +18 +08 +38 +ENDCHAR +STARTCHAR 0160 +ENCODING 352 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +3300 +1E00 +0C00 +0000 +1F00 +7F80 +60C0 +C0C0 +C000 +7000 +3F00 +07C0 +00C0 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 0161 +ENCODING 353 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +6C +2C +38 +00 +7C +FE +C6 +E0 +FC +3E +03 +C3 +FE +7C +ENDCHAR +STARTCHAR 0162 +ENCODING 354 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 19 0 -5 +BITMAP +FFE0 +FFE0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0000 +0600 +0600 +0200 +0400 +ENDCHAR +STARTCHAR 0163 +ENCODING 355 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 18 0 -5 +BITMAP +20 +20 +20 +F8 +F8 +20 +20 +20 +20 +20 +20 +38 +38 +00 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 0164 +ENCODING 356 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 18 0 0 +BITMAP +1900 +0F00 +0600 +0000 +FFE0 +FFE0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0165 +ENCODING 357 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 14 0 0 +BITMAP +06 +26 +22 +22 +F8 +F8 +20 +20 +20 +20 +20 +20 +38 +38 +ENDCHAR +STARTCHAR 0166 +ENCODING 358 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 0 0 +BITMAP +FFE0 +FFE0 +0600 +0600 +0600 +0600 +0600 +3FC0 +3FC0 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0167 +ENCODING 359 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 13 0 0 +BITMAP +20 +60 +60 +F8 +F8 +60 +60 +F8 +F8 +60 +60 +78 +38 +ENDCHAR +STARTCHAR 0168 +ENCODING 360 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0C80 +1F80 +1300 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 0169 +ENCODING 361 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +32 +7E +6E +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 016A +ENCODING 362 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 16 1 0 +BITMAP +1F80 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 016B +ENCODING 363 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 12 1 0 +BITMAP +7E +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 016C +ENCODING 364 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +1180 +0900 +0E00 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 016D +ENCODING 365 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +22 +26 +1C +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 016E +ENCODING 366 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0600 +0A00 +0900 +0A00 +C660 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 016F +ENCODING 367 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 16 1 0 +BITMAP +18 +24 +24 +24 +18 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 0170 +ENCODING 368 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0CC0 +0D80 +1900 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 0171 +ENCODING 369 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +36 +36 +64 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 0172 +ENCODING 370 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 -4 +BITMAP +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +0400 +0400 +0400 +0380 +ENDCHAR +STARTCHAR 0173 +ENCODING 371 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 -4 +BITMAP +C100 +C100 +C100 +C100 +C100 +C100 +C300 +C300 +7F00 +3D00 +0100 +0300 +0300 +01C0 +ENDCHAR +STARTCHAR 0174 +ENCODING 372 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 18 0 0 +BITMAP +00C000 +01E000 +033000 +000000 +C0C0C0 +40C080 +61E180 +61E180 +612180 +233100 +333300 +323300 +321200 +161A00 +161E00 +1C0E00 +1C0C00 +0C0C00 +ENDCHAR +STARTCHAR 0175 +ENCODING 373 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 14 0 0 +BITMAP +0300 +0780 +0CC0 +0000 +C308 +4308 +4718 +6798 +6590 +24B0 +3CB0 +3CE0 +18E0 +1860 +ENDCHAR +STARTCHAR 0176 +ENCODING 374 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +0700 +0500 +0D80 +0000 +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0177 +ENCODING 375 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 18 1 -4 +BITMAP +18 +3C +26 +00 +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 0178 +ENCODING 376 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 17 0 0 +BITMAP +0980 +0980 +0000 +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0179 +ENCODING 377 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 18 0 0 +BITMAP +0600 +0600 +0400 +0000 +7FE0 +7FE0 +00C0 +01C0 +0180 +0300 +0600 +0C00 +1C00 +3800 +3000 +6000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 017A +ENCODING 378 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 0 0 +BITMAP +0600 +0C00 +0800 +0000 +7F80 +7F80 +0300 +0600 +0C00 +1800 +3000 +6000 +FF80 +FF80 +ENDCHAR +STARTCHAR 017B +ENCODING 379 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 17 0 0 +BITMAP +0600 +0600 +0000 +7FE0 +7FE0 +00C0 +01C0 +0180 +0300 +0600 +0C00 +1C00 +3800 +3000 +6000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 017C +ENCODING 380 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 13 0 0 +BITMAP +0C00 +0C00 +0000 +7F80 +7F80 +0300 +0600 +0C00 +1800 +3000 +6000 +FF80 +FF80 +ENDCHAR +STARTCHAR 017D +ENCODING 381 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 18 0 0 +BITMAP +1900 +0F00 +0600 +0000 +7FE0 +7FE0 +00C0 +01C0 +0180 +0300 +0600 +0C00 +1C00 +3800 +3000 +6000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 017E +ENCODING 382 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 0 0 +BITMAP +3300 +1E00 +0C00 +0000 +7F80 +7F80 +0300 +0600 +0C00 +1800 +3000 +6000 +FF80 +FF80 +ENDCHAR +STARTCHAR 017F +ENCODING 383 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 5 14 1 0 +BITMAP +78 +F0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 018F +ENCODING 399 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F80 +3FC0 +70E0 +6030 +6030 +0030 +FFF0 +FFF0 +C010 +C030 +6030 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 0192 +ENCODING 402 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 18 0 -4 +BITMAP +03C0 +03C0 +0200 +0600 +1F80 +1F80 +0600 +0400 +0400 +0C00 +0C00 +0C00 +0800 +0800 +1800 +1800 +7800 +F000 +ENDCHAR +STARTCHAR 01A0 +ENCODING 416 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 1 0 +BITMAP +0F86 +3FE6 +7072 +6034 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 01A1 +ENCODING 417 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 10 1 0 +BITMAP +3C60 +7F60 +C320 +C1C0 +81C0 +8180 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 01AF +ENCODING 431 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 14 1 0 +BITMAP +C064 +C064 +C064 +C064 +C078 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 01B0 +ENCODING 432 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 10 1 0 +BITMAP +C160 +C160 +C120 +C120 +C1C0 +C100 +C300 +C300 +7D00 +3900 +ENDCHAR +STARTCHAR 01CD +ENCODING 461 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0980 +0F00 +0600 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 01CE +ENCODING 462 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3600 +1400 +1C00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 01CF +ENCODING 463 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 18 0 0 +BITMAP +D8 +58 +70 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 01D0 +ENCODING 464 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 5 14 0 0 +BITMAP +98 +F0 +60 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 01D1 +ENCODING 465 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0D80 +0500 +0700 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 01D2 +ENCODING 466 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +2600 +3400 +1800 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 01D3 +ENCODING 467 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +1980 +0F00 +0600 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 01D4 +ENCODING 468 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +36 +34 +1C +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 01D5 +ENCODING 469 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0F00 +0000 +0900 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 01D6 +ENCODING 470 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 15 1 0 +BITMAP +7E +00 +26 +26 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 01D7 +ENCODING 471 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0300 +0600 +0900 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 01D8 +ENCODING 472 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 17 1 0 +BITMAP +0C +0C +18 +00 +26 +26 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 01D9 +ENCODING 473 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0F00 +0600 +0900 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 01DA +ENCODING 474 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 17 1 0 +BITMAP +36 +34 +1C +00 +26 +26 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 01DB +ENCODING 475 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0C00 +0600 +0900 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 01DC +ENCODING 476 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 17 1 0 +BITMAP +30 +18 +08 +00 +26 +26 +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 01FA +ENCODING 506 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 20 0 0 +BITMAP +0300 +0300 +0600 +0900 +0900 +0900 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 01FB +ENCODING 507 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 20 1 0 +BITMAP +0600 +0C00 +0800 +0000 +1800 +2400 +2400 +2400 +1800 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 01FC +ENCODING 508 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 18 18 0 0 +BITMAP +006000 +006000 +00C000 +000000 +03FFC0 +03FFC0 +066000 +066000 +0C6000 +0C6000 +087F80 +187F80 +1FE000 +3FE000 +306000 +606000 +607FC0 +C07FC0 +ENDCHAR +STARTCHAR 01FD +ENCODING 509 +SWIDTH 874 0 +DWIDTH 17 0 +BBX 15 14 1 0 +BITMAP +00C0 +0180 +0100 +0000 +3E78 +7FFC +C386 +0F06 +7FFE +F3FE +8300 +C786 +FFFC +7878 +ENDCHAR +STARTCHAR 01FE +ENCODING 510 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 19 1 -1 +BITMAP +0300 +0300 +0200 +0000 +0F88 +3FD0 +7060 +6070 +C0D0 +C198 +C318 +C618 +CC18 +D818 +7030 +7070 +7FE0 +DF80 +8000 +ENDCHAR +STARTCHAR 01FF +ENCODING 511 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 9 15 1 -1 +BITMAP +0600 +0400 +0C00 +0080 +1E80 +7F00 +6380 +C680 +C480 +C880 +D180 +7380 +7F00 +5E00 +8000 +ENDCHAR +STARTCHAR 0259 +ENCODING 601 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3E00 +FF00 +C300 +0180 +FF80 +FF80 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 02C6 +ENCODING 710 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 3 1 11 +BITMAP +60 +F0 +98 +ENDCHAR +STARTCHAR 02C7 +ENCODING 711 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 3 1 11 +BITMAP +D8 +D0 +70 +ENDCHAR +STARTCHAR 02C9 +ENCODING 713 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 1 0 11 +BITMAP +FC +ENDCHAR +STARTCHAR 02D8 +ENCODING 728 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 3 0 11 +BITMAP +C4 +4C +38 +ENDCHAR +STARTCHAR 02D9 +ENCODING 729 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 2 2 11 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR 02DA +ENCODING 730 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 5 1 9 +BITMAP +60 +90 +90 +90 +60 +ENDCHAR +STARTCHAR 02DB +ENCODING 731 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 4 2 -4 +BITMAP +80 +80 +80 +F0 +ENDCHAR +STARTCHAR 02DC +ENCODING 732 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 3 0 11 +BITMAP +64 +FC +9C +ENDCHAR +STARTCHAR 02DD +ENCODING 733 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 3 1 11 +BITMAP +EC +D8 +90 +ENDCHAR +STARTCHAR 0300 +ENCODING 768 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -5 15 +BITMAP +C0 +60 +20 +ENDCHAR +STARTCHAR 0301 +ENCODING 769 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -3 15 +BITMAP +60 +C0 +80 +ENDCHAR +STARTCHAR 0303 +ENCODING 771 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -8 15 +BITMAP +EC +98 +ENDCHAR +STARTCHAR 0309 +ENCODING 777 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -4 15 +BITMAP +E0 +30 +60 +ENDCHAR +STARTCHAR 0323 +ENCODING 803 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -7 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR 037E +ENCODING 894 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 13 2 -3 +BITMAP +C0 +C0 +00 +00 +00 +00 +00 +00 +C0 +C0 +40 +80 +80 +ENDCHAR +STARTCHAR 0384 +ENCODING 900 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 3 3 2 11 +BITMAP +60 +40 +C0 +ENDCHAR +STARTCHAR 0385 +ENCODING 901 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 7 3 0 11 +BITMAP +18 +96 +A6 +ENDCHAR +STARTCHAR 0386 +ENCODING 902 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 14 0 0 +BITMAP +3600 +6700 +4F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 0387 +ENCODING 903 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 2 2 8 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR 0388 +ENCODING 904 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 14 -1 0 +BITMAP +67FE +67FE +C600 +0600 +0600 +0600 +07FC +07FC +0600 +0600 +0600 +0600 +07FE +07FE +ENDCHAR +STARTCHAR 0389 +ENCODING 905 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 -1 0 +BITMAP +6C06 +6C06 +CC06 +0C06 +0C06 +0C06 +0FFE +0FFE +0C06 +0C06 +0C06 +0C06 +0C06 +0C06 +ENDCHAR +STARTCHAR 038A +ENCODING 906 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 6 14 -1 0 +BITMAP +6C +6C +CC +0C +0C +0C +0C +0C +0C +0C +0C +0C +0C +0C +ENDCHAR +STARTCHAR 038C +ENCODING 908 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 14 -1 0 +BITMAP +63E0 +6FF8 +DC18 +180C +300C +3006 +3006 +3006 +3006 +300C +180C +1C18 +0FF8 +03E0 +ENDCHAR +STARTCHAR 038E +ENCODING 910 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 17 14 -1 0 +BITMAP +660180 +630300 +C30600 +018600 +018C00 +00D800 +007800 +007000 +003000 +003000 +003000 +003000 +003000 +003000 +ENDCHAR +STARTCHAR 038F +ENCODING 911 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 14 14 -1 0 +BITMAP +63E0 +6FF0 +DC38 +181C +300C +300C +300C +300C +300C +180C +0818 +0C30 +3E7C +3E7C +ENDCHAR +STARTCHAR 0390 +ENCODING 912 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 6 15 -1 0 +BITMAP +18 +94 +A4 +00 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 0391 +ENCODING 913 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 14 0 0 +BITMAP +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 0392 +ENCODING 914 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FF00 +FF80 +C0C0 +C0C0 +C0C0 +C0C0 +FF80 +FF80 +C0C0 +C060 +C060 +C0C0 +FFC0 +FF80 +ENDCHAR +STARTCHAR 0393 +ENCODING 915 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 2 0 +BITMAP +FF +FF +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR 0394 +ENCODING 916 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 14 0 0 +BITMAP +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3060 +2060 +6060 +6030 +7FF0 +FFF8 +ENDCHAR +STARTCHAR 0395 +ENCODING 917 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0396 +ENCODING 918 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 0 0 +BITMAP +7FE0 +7FE0 +00C0 +01C0 +0180 +0300 +0600 +0C00 +1C00 +3800 +3000 +6000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0397 +ENCODING 919 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 10 14 2 0 +BITMAP +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +FFC0 +FFC0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +ENDCHAR +STARTCHAR 0398 +ENCODING 920 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0F80 +3FE0 +7070 +6030 +C018 +C018 +CF98 +CF98 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 0399 +ENCODING 921 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 14 2 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 039A +ENCODING 922 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +C0E0 +C1C0 +C380 +C700 +CE00 +DC00 +FC00 +F600 +E700 +C300 +C180 +C0C0 +C0E0 +C060 +ENDCHAR +STARTCHAR 039B +ENCODING 923 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 14 0 0 +BITMAP +0600 +0700 +0F00 +0D80 +0980 +1880 +18C0 +10C0 +3040 +3060 +6060 +6030 +4030 +C030 +ENDCHAR +STARTCHAR 039C +ENCODING 924 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 13 14 1 0 +BITMAP +E018 +F038 +F028 +D028 +D868 +D868 +C848 +CCC8 +CCC8 +C488 +C788 +C788 +C308 +C308 +ENDCHAR +STARTCHAR 039D +ENCODING 925 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 1 0 +BITMAP +E060 +E060 +F060 +D860 +D860 +CC60 +CC60 +C660 +C360 +C360 +C1E0 +C0E0 +C0E0 +C060 +ENDCHAR +STARTCHAR 039E +ENCODING 926 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +FFC0 +FFC0 +0000 +0000 +0000 +0000 +7F80 +7F80 +0000 +0000 +0000 +0000 +FFC0 +FFC0 +ENDCHAR +STARTCHAR 039F +ENCODING 927 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 03A0 +ENCODING 928 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 10 14 2 0 +BITMAP +FFC0 +FFC0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +ENDCHAR +STARTCHAR 03A1 +ENCODING 929 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FF80 +FFC0 +C0E0 +C060 +C060 +C060 +C0C0 +FFC0 +FF80 +C000 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 03A3 +ENCODING 931 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +FFC0 +FFC0 +6000 +3000 +1800 +0C00 +0600 +0C00 +1800 +3800 +7000 +6000 +FFC0 +FFC0 +ENDCHAR +STARTCHAR 03A4 +ENCODING 932 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 0 0 +BITMAP +FFE0 +FFE0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 03A5 +ENCODING 933 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 14 0 0 +BITMAP +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 03A6 +ENCODING 934 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0200 +0200 +1FC0 +7FF0 +E238 +C218 +C218 +C218 +C218 +E238 +7FF0 +1FC0 +0200 +0200 +ENDCHAR +STARTCHAR 03A7 +ENCODING 935 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 14 0 0 +BITMAP +6030 +3060 +30C0 +18C0 +0D80 +0F00 +0700 +0700 +0D80 +1980 +18C0 +3060 +6070 +E030 +ENDCHAR +STARTCHAR 03A8 +ENCODING 936 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 14 1 0 +BITMAP +C30C +C30C +C30C +C30C +C30C +C30C +E318 +7338 +3FF0 +1FE0 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 03A9 +ENCODING 937 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F80 +3FC0 +70E0 +6070 +C030 +C030 +C030 +C030 +C030 +4020 +6060 +30C0 +F9F0 +F9F0 +ENDCHAR +STARTCHAR 03AA +ENCODING 938 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 17 0 0 +BITMAP +D8 +D8 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 03AB +ENCODING 939 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 17 0 0 +BITMAP +0980 +0980 +0000 +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 03AC +ENCODING 940 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +3D80 +7F80 +C380 +C300 +C100 +C100 +C300 +C380 +7F80 +3D80 +ENDCHAR +STARTCHAR 03AD +ENCODING 941 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 14 1 0 +BITMAP +18 +18 +10 +00 +78 +7C +C4 +C0 +70 +70 +C0 +C4 +FE +78 +ENDCHAR +STARTCHAR 03AE +ENCODING 942 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 18 1 -4 +BITMAP +0C +0C +08 +00 +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +01 +01 +01 +01 +ENDCHAR +STARTCHAR 03AF +ENCODING 943 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 14 1 0 +BITMAP +60 +40 +C0 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 03B0 +ENCODING 944 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +0C +4B +53 +00 +C3 +C3 +C3 +C3 +C3 +C3 +C3 +E3 +7E +3C +ENDCHAR +STARTCHAR 03B1 +ENCODING 945 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3D80 +7F80 +C380 +C300 +C100 +C100 +C300 +C380 +7F80 +3D80 +ENDCHAR +STARTCHAR 03B2 +ENCODING 946 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 -4 +BITMAP +3E00 +7F00 +6300 +C100 +C300 +DC00 +DF00 +C380 +C180 +C180 +C180 +E380 +FF00 +DE00 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 03B3 +ENCODING 947 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 0 -4 +BITMAP +C180 +6180 +6100 +2300 +3300 +3200 +1600 +1E00 +1C00 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 03B4 +ENCODING 948 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +7F00 +7F00 +3000 +1800 +3E00 +7F00 +E300 +C180 +8180 +8180 +C180 +E300 +7F00 +3C00 +ENDCHAR +STARTCHAR 03B5 +ENCODING 949 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 10 1 0 +BITMAP +78 +7C +C4 +C0 +70 +70 +C0 +C4 +FE +78 +ENDCHAR +STARTCHAR 03B6 +ENCODING 950 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 18 1 -4 +BITMAP +7E +7E +0C +18 +30 +60 +40 +C0 +C0 +80 +80 +C0 +FC +7E +06 +06 +0C +0C +ENDCHAR +STARTCHAR 03B7 +ENCODING 951 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +01 +01 +01 +01 +ENDCHAR +STARTCHAR 03B8 +ENCODING 952 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3C00 +7E00 +6300 +C100 +C180 +C180 +FF80 +FF80 +C180 +C180 +C100 +6300 +7E00 +3C00 +ENDCHAR +STARTCHAR 03B9 +ENCODING 953 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 10 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 03BA +ENCODING 954 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +C7 +CE +D8 +F0 +F0 +D8 +CC +CC +C6 +C3 +ENDCHAR +STARTCHAR 03BB +ENCODING 955 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 0 0 +BITMAP +1000 +1800 +1800 +0800 +0C00 +1C00 +1E00 +1600 +3600 +3300 +6300 +6100 +6180 +C180 +ENDCHAR +STARTCHAR 03BC +ENCODING 956 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +C1 +C1 +C1 +C1 +C1 +C1 +C1 +E3 +FF +DD +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 03BD +ENCODING 957 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 0 0 +BITMAP +C180 +6180 +6100 +2300 +3300 +3200 +1600 +1C00 +1C00 +0C00 +ENDCHAR +STARTCHAR 03BE +ENCODING 958 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 18 1 -4 +BITMAP +3C +7C +C0 +C0 +40 +7C +1C +60 +C0 +C0 +C0 +C0 +7C +3E +06 +06 +0E +0C +ENDCHAR +STARTCHAR 03BF +ENCODING 959 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 03C0 +ENCODING 960 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 10 0 0 +BITMAP +FFF8 +FFF8 +1840 +1840 +1840 +1840 +1840 +1840 +1840 +1840 +ENDCHAR +STARTCHAR 03C1 +ENCODING 961 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 -4 +BITMAP +3E00 +7F00 +6380 +C180 +C180 +C180 +C180 +E380 +FF00 +DE00 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 03C2 +ENCODING 962 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 14 1 -4 +BITMAP +1F +3F +60 +C0 +C0 +80 +C0 +E0 +7C +3E +03 +02 +1E +1C +ENDCHAR +STARTCHAR 03C3 +ENCODING 963 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 10 10 1 0 +BITMAP +3FC0 +7FC0 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 03C4 +ENCODING 964 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 10 0 0 +BITMAP +FE +FE +18 +18 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 03C5 +ENCODING 965 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +C3 +C3 +C3 +C3 +C3 +C3 +C3 +E3 +7E +3C +ENDCHAR +STARTCHAR 03C6 +ENCODING 966 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 1 -4 +BITMAP +3780 +6FC0 +CCC0 +CC60 +8C60 +8C60 +CCC0 +EDC0 +7F80 +3F00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 03C7 +ENCODING 967 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 14 0 -4 +BITMAP +6080 +6180 +3300 +3300 +1E00 +1E00 +0C00 +0C00 +1E00 +1600 +3300 +2100 +6180 +C0C0 +ENDCHAR +STARTCHAR 03C8 +ENCODING 968 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 1 -4 +BITMAP +C620 +C620 +C620 +C620 +C620 +C620 +C620 +C660 +66C0 +3F80 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 03C9 +ENCODING 969 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 10 1 0 +BITMAP +6030 +4010 +C218 +C218 +C218 +C218 +C618 +C538 +7DF0 +38E0 +ENDCHAR +STARTCHAR 03CA +ENCODING 970 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 5 13 0 0 +BITMAP +98 +98 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 03CB +ENCODING 971 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 13 1 0 +BITMAP +36 +36 +00 +C3 +C3 +C3 +C3 +C3 +C3 +C3 +E3 +7E +3C +ENDCHAR +STARTCHAR 03CC +ENCODING 972 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 03CD +ENCODING 973 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +0C +0C +18 +00 +C3 +C3 +C3 +C3 +C3 +C3 +C3 +E3 +7E +3C +ENDCHAR +STARTCHAR 03CE +ENCODING 974 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0180 +0300 +0200 +0000 +6030 +4010 +C218 +C218 +C218 +C218 +C618 +C538 +7DF0 +38E0 +ENDCHAR +STARTCHAR 0401 +ENCODING 1025 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 17 1 0 +BITMAP +1B00 +1B00 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0402 +ENCODING 1026 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 16 14 0 0 +BITMAP +FFE0 +FFE0 +0600 +0600 +0600 +06F8 +07FE +0706 +0603 +0603 +0603 +0646 +067E +063C +ENDCHAR +STARTCHAR 0403 +ENCODING 1027 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 18 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +FF80 +FF80 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 0404 +ENCODING 1028 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F80 +3FC0 +70E0 +6070 +C020 +C000 +FE00 +FE00 +C000 +C000 +6030 +7060 +3FE0 +0F80 +ENDCHAR +STARTCHAR 0405 +ENCODING 1029 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +1F00 +7F80 +60C0 +C0C0 +C000 +7000 +3F00 +07C0 +00C0 +C060 +C060 +60C0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 0406 +ENCODING 1030 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 14 2 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0407 +ENCODING 1031 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 17 0 0 +BITMAP +D8 +D8 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 0408 +ENCODING 1032 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 14 1 0 +BITMAP +06 +06 +06 +06 +06 +06 +06 +06 +06 +06 +86 +C6 +FC +78 +ENDCHAR +STARTCHAR 0409 +ENCODING 1033 +SWIDTH 1028 0 +DWIDTH 20 0 +BBX 19 14 0 0 +BITMAP +3FE000 +3FE000 +306000 +306000 +306000 +306000 +307F80 +307FE0 +306060 +306060 +306060 +B06060 +F07FE0 +607F80 +ENDCHAR +STARTCHAR 040A +ENCODING 1034 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 16 14 2 0 +BITMAP +8300 +8300 +8300 +8300 +8300 +8300 +FFFE +FFFF +8303 +8301 +8301 +8303 +83FF +83FE +ENDCHAR +STARTCHAR 040B +ENCODING 1035 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 0 0 +BITMAP +FFE0 +FFE0 +0600 +0600 +0600 +06F8 +07FC +0706 +0606 +0602 +0602 +0602 +0602 +0602 +ENDCHAR +STARTCHAR 040C +ENCODING 1036 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 18 1 0 +BITMAP +0600 +0C00 +0C00 +0000 +C1C0 +C3C0 +C300 +C600 +C600 +CC00 +F800 +CC00 +C600 +C600 +C300 +C380 +C180 +C1C0 +ENDCHAR +STARTCHAR 040E +ENCODING 1038 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 18 0 0 +BITMAP +0880 +0880 +0700 +0000 +C030 +6020 +6060 +3040 +10C0 +1880 +0980 +0D00 +0700 +0600 +0600 +0600 +3C00 +3800 +ENDCHAR +STARTCHAR 040F +ENCODING 1039 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 -4 +BITMAP +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +FFE0 +FFE0 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0410 +ENCODING 1040 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 14 0 0 +BITMAP +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 0411 +ENCODING 1041 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 10 14 2 0 +BITMAP +FF00 +FF00 +8000 +8000 +8000 +8000 +FF00 +FF80 +81C0 +80C0 +80C0 +81C0 +FF80 +FF00 +ENDCHAR +STARTCHAR 0412 +ENCODING 1042 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FF00 +FF80 +C0C0 +C0C0 +C0C0 +C0C0 +FF80 +FF80 +C0C0 +C060 +C060 +C0C0 +FFC0 +FF80 +ENDCHAR +STARTCHAR 0413 +ENCODING 1043 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 1 0 +BITMAP +FF80 +FF80 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 0414 +ENCODING 1044 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 17 0 -3 +BITMAP +1FE0 +1FE0 +1060 +1060 +1060 +1060 +1060 +3060 +3060 +3060 +2060 +6060 +FFF0 +FFF0 +C010 +C010 +C010 +ENDCHAR +STARTCHAR 0415 +ENCODING 1045 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 0416 +ENCODING 1046 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 17 14 0 0 +BITMAP +E0C180 +F0C380 +30C600 +18C600 +18CC00 +0CDC00 +07F000 +0CDC00 +18CC00 +18C600 +30C700 +70C300 +60C380 +E0C180 +ENDCHAR +STARTCHAR 0417 +ENCODING 1047 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 0 +BITMAP +3E00 +7F00 +E380 +C180 +0180 +0380 +0F00 +0F80 +0180 +00C0 +C0C0 +E180 +7F80 +3E00 +ENDCHAR +STARTCHAR 0418 +ENCODING 1048 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 1 0 +BITMAP +C060 +C0E0 +C0E0 +C1A0 +C3A0 +C320 +C620 +CE20 +CC20 +D820 +D820 +F020 +E020 +E020 +ENDCHAR +STARTCHAR 0419 +ENCODING 1049 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +1100 +1900 +0E00 +0000 +C060 +C0E0 +C0E0 +C1A0 +C3A0 +C320 +C620 +CE20 +CC20 +D820 +D820 +F020 +E020 +E020 +ENDCHAR +STARTCHAR 041A +ENCODING 1050 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 0 +BITMAP +C1C0 +C3C0 +C300 +C600 +C600 +CC00 +F800 +CC00 +C600 +C600 +C300 +C380 +C180 +C1C0 +ENDCHAR +STARTCHAR 041B +ENCODING 1051 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 0 0 +BITMAP +3FE0 +3FE0 +3060 +3060 +3060 +3060 +3060 +3060 +3060 +3060 +3060 +B060 +F060 +6060 +ENDCHAR +STARTCHAR 041C +ENCODING 1052 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 13 14 1 0 +BITMAP +E018 +F038 +F028 +D028 +D868 +D868 +C848 +CCC8 +CCC8 +C488 +C788 +C788 +C308 +C308 +ENDCHAR +STARTCHAR 041D +ENCODING 1053 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 10 14 2 0 +BITMAP +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +FFC0 +FFC0 +80C0 +80C0 +80C0 +80C0 +80C0 +80C0 +ENDCHAR +STARTCHAR 041E +ENCODING 1054 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 041F +ENCODING 1055 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 1 0 +BITMAP +FFE0 +FFE0 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +ENDCHAR +STARTCHAR 0420 +ENCODING 1056 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FF80 +FFC0 +C0E0 +C060 +C060 +C060 +C0C0 +FFC0 +FF80 +C000 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 0421 +ENCODING 1057 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F80 +3FC0 +70E0 +6070 +C000 +C000 +C000 +C000 +C000 +C030 +6070 +70E0 +3FC0 +0F80 +ENDCHAR +STARTCHAR 0422 +ENCODING 1058 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 0 0 +BITMAP +FFE0 +FFE0 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 0423 +ENCODING 1059 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 14 0 0 +BITMAP +C030 +6020 +6060 +3040 +10C0 +1880 +0980 +0D00 +0700 +0600 +0600 +0600 +3C00 +3800 +ENDCHAR +STARTCHAR 0424 +ENCODING 1060 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 14 1 0 +BITMAP +0600 +0600 +1FC0 +7FE0 +E670 +C630 +C618 +C618 +C630 +E670 +7FE0 +1FC0 +0600 +0600 +ENDCHAR +STARTCHAR 0425 +ENCODING 1061 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 14 0 0 +BITMAP +6030 +3060 +30C0 +18C0 +0D80 +0F00 +0700 +0700 +0D80 +1980 +18C0 +3060 +6070 +E030 +ENDCHAR +STARTCHAR 0426 +ENCODING 1062 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 -4 +BITMAP +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +FFF0 +FFF0 +0010 +0010 +0010 +0010 +ENDCHAR +STARTCHAR 0427 +ENCODING 1063 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 10 14 1 0 +BITMAP +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +C0C0 +E1C0 +7FC0 +3EC0 +00C0 +00C0 +00C0 +00C0 +ENDCHAR +STARTCHAR 0428 +ENCODING 1064 +SWIDTH 874 0 +DWIDTH 17 0 +BBX 15 14 1 0 +BITMAP +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +FFFE +FFFE +ENDCHAR +STARTCHAR 0429 +ENCODING 1065 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 16 18 1 -4 +BITMAP +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +C186 +FFFF +FFFF +0001 +0001 +0001 +0001 +ENDCHAR +STARTCHAR 042A +ENCODING 1066 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 14 14 0 0 +BITMAP +FC00 +FC00 +0C00 +0C00 +0C00 +0C00 +0FF0 +0FFC +0C0C +0C0C +0C0C +0C0C +0FFC +0FF0 +ENDCHAR +STARTCHAR 042B +ENCODING 1067 +SWIDTH 874 0 +DWIDTH 17 0 +BBX 13 14 2 0 +BITMAP +8018 +8018 +8018 +8018 +8018 +8018 +FF18 +FF98 +81D8 +80D8 +80D8 +81D8 +FF98 +FF18 +ENDCHAR +STARTCHAR 042C +ENCODING 1068 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 10 14 2 0 +BITMAP +8000 +8000 +8000 +8000 +8000 +8000 +FF00 +FF80 +81C0 +80C0 +80C0 +8180 +FF80 +FF00 +ENDCHAR +STARTCHAR 042D +ENCODING 1069 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +1F00 +7FC0 +60C0 +C060 +4060 +0030 +07F0 +07F0 +0030 +0020 +C060 +E0E0 +7FC0 +1F00 +ENDCHAR +STARTCHAR 042E +ENCODING 1070 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 16 14 2 0 +BITMAP +80F8 +83FC +870E +8607 +8C03 +8C03 +FC03 +FC03 +8C03 +8C03 +8607 +870E +83FC +80F8 +ENDCHAR +STARTCHAR 042F +ENCODING 1071 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 1 0 +BITMAP +3FE0 +7FE0 +6060 +C060 +C060 +6060 +7FE0 +3FE0 +1C60 +3860 +3060 +6060 +C060 +C060 +ENDCHAR +STARTCHAR 0430 +ENCODING 1072 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 0431 +ENCODING 1073 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3F80 +7F00 +E000 +C000 +9E00 +BF00 +E380 +C180 +C180 +C180 +C180 +6380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0432 +ENCODING 1074 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +FE +FF +C3 +C3 +FE +FF +C3 +C3 +FF +FE +ENDCHAR +STARTCHAR 0433 +ENCODING 1075 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 6 10 1 0 +BITMAP +FC +FC +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0434 +ENCODING 1076 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 13 0 -3 +BITMAP +1F80 +1F80 +3080 +3080 +3080 +3080 +2080 +6080 +FFE0 +FFE0 +8060 +8060 +8060 +ENDCHAR +STARTCHAR 0435 +ENCODING 1077 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0436 +ENCODING 1078 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 10 0 0 +BITMAP +E630 +E670 +3660 +16C0 +0F80 +16C0 +3660 +6620 +6630 +C610 +ENDCHAR +STARTCHAR 0437 +ENCODING 1079 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 10 1 0 +BITMAP +78 +FC +C6 +06 +3C +3C +06 +86 +FE +7C +ENDCHAR +STARTCHAR 0438 +ENCODING 1080 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 10 1 0 +BITMAP +C3 +C3 +C7 +CD +C9 +D9 +D1 +F1 +E1 +C1 +ENDCHAR +STARTCHAR 0439 +ENCODING 1081 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +22 +22 +1C +00 +C3 +C3 +C7 +CD +C9 +D9 +D1 +F1 +E1 +C1 +ENDCHAR +STARTCHAR 043A +ENCODING 1082 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 10 1 0 +BITMAP +C6 +CE +CC +D8 +F0 +D8 +CC +CC +C6 +C6 +ENDCHAR +STARTCHAR 043B +ENCODING 1083 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 10 0 0 +BITMAP +3FC0 +3FC0 +30C0 +30C0 +30C0 +30C0 +30C0 +30C0 +F0C0 +E0C0 +ENDCHAR +STARTCHAR 043C +ENCODING 1084 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 10 1 0 +BITMAP +E0E0 +E0E0 +F1E0 +D1E0 +D160 +DB60 +CA60 +CA60 +CE60 +C460 +ENDCHAR +STARTCHAR 043D +ENCODING 1085 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 10 1 0 +BITMAP +C1 +C1 +C1 +C1 +FF +FF +C1 +C1 +C1 +C1 +ENDCHAR +STARTCHAR 043E +ENCODING 1086 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 043F +ENCODING 1087 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +FF +FF +C3 +C3 +C3 +C3 +C3 +C3 +C3 +C3 +ENDCHAR +STARTCHAR 0440 +ENCODING 1088 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 -4 +BITMAP +DE00 +FF00 +E300 +C180 +C180 +C180 +C180 +E300 +FF00 +DC00 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 0441 +ENCODING 1089 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +3C +7F +E3 +C0 +80 +80 +C0 +C3 +7F +3C +ENDCHAR +STARTCHAR 0442 +ENCODING 1090 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 10 0 0 +BITMAP +FF +FF +08 +08 +08 +08 +08 +08 +08 +08 +ENDCHAR +STARTCHAR 0443 +ENCODING 1091 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 -4 +BITMAP +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 0444 +ENCODING 1092 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 18 1 -4 +BITMAP +0300 +0300 +0300 +0300 +3BF0 +7FF8 +C71C +C30C +830C +830C +C30C +C718 +7FF8 +3BF0 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 0445 +ENCODING 1093 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 0 0 +BITMAP +6180 +6300 +3600 +1E00 +0C00 +1C00 +1E00 +3300 +6300 +E180 +ENDCHAR +STARTCHAR 0446 +ENCODING 1094 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 -4 +BITMAP +C100 +C100 +C100 +C100 +C100 +C100 +C100 +C100 +FF80 +FF80 +0080 +0080 +0080 +0080 +ENDCHAR +STARTCHAR 0447 +ENCODING 1095 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +83 +83 +83 +83 +C3 +FF +7F +03 +03 +03 +ENDCHAR +STARTCHAR 0448 +ENCODING 1096 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 10 1 0 +BITMAP +C218 +C218 +C218 +C218 +C218 +C218 +C218 +C218 +FFF8 +FFF8 +ENDCHAR +STARTCHAR 0449 +ENCODING 1097 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 14 1 -4 +BITMAP +C218 +C218 +C218 +C218 +C218 +C218 +C218 +C218 +FFFC +FFFC +0004 +0004 +0004 +0004 +ENDCHAR +STARTCHAR 044A +ENCODING 1098 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 10 0 0 +BITMAP +F800 +F800 +1800 +1800 +1FC0 +1FE0 +1860 +1860 +1FE0 +1FC0 +ENDCHAR +STARTCHAR 044B +ENCODING 1099 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 10 1 0 +BITMAP +C020 +C020 +C020 +FE20 +FF20 +C320 +C120 +C320 +FF20 +FE20 +ENDCHAR +STARTCHAR 044C +ENCODING 1100 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +C0 +C0 +C0 +FE +FF +C3 +C1 +C3 +FF +FE +ENDCHAR +STARTCHAR 044D +ENCODING 1101 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +7C +FE +C7 +03 +1F +1F +03 +87 +FE +7C +ENDCHAR +STARTCHAR 044E +ENCODING 1102 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 10 1 0 +BITMAP +C3C0 +C7E0 +CE30 +CC10 +FC10 +FC10 +CC10 +CE30 +C7F0 +C3C0 +ENDCHAR +STARTCHAR 044F +ENCODING 1103 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +7F +FF +C3 +C3 +7F +1F +73 +63 +C3 +C3 +ENDCHAR +STARTCHAR 0451 +ENCODING 1105 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 0 +BITMAP +2600 +2600 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 0452 +ENCODING 1106 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 0 -4 +BITMAP +6000 +FC00 +FC00 +6000 +6F00 +7F80 +7180 +6080 +6080 +6080 +6080 +6080 +6080 +6080 +0080 +0180 +0380 +0300 +ENDCHAR +STARTCHAR 0453 +ENCODING 1107 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 6 14 1 0 +BITMAP +18 +18 +30 +00 +FC +FC +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0454 +ENCODING 1108 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +3C +7F +C3 +C0 +F8 +F8 +C0 +C3 +7F +3C +ENDCHAR +STARTCHAR 0455 +ENCODING 1109 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +7C +FE +C6 +E0 +FC +3E +03 +C3 +FE +7C +ENDCHAR +STARTCHAR 0456 +ENCODING 1110 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 14 1 0 +BITMAP +C0 +C0 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0457 +ENCODING 1111 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 13 0 0 +BITMAP +C8 +C8 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR 0458 +ENCODING 1112 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 18 -1 -4 +BITMAP +30 +30 +00 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +F0 +E0 +ENDCHAR +STARTCHAR 0459 +ENCODING 1113 +SWIDTH 874 0 +DWIDTH 17 0 +BBX 17 10 0 0 +BITMAP +3FC000 +3FC000 +30C000 +30FE00 +30FF00 +30C300 +30C180 +30C300 +F0FF00 +E0FE00 +ENDCHAR +STARTCHAR 045A +ENCODING 1114 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 14 10 1 0 +BITMAP +C200 +C200 +C200 +C200 +FFF0 +FFF8 +C20C +C20C +C3F8 +C3F0 +ENDCHAR +STARTCHAR 045B +ENCODING 1115 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 0 0 +BITMAP +6000 +FC00 +FC00 +6000 +6F00 +7F80 +7180 +6080 +6080 +6080 +6080 +6080 +6080 +6080 +ENDCHAR +STARTCHAR 045C +ENCODING 1116 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 14 1 0 +BITMAP +18 +18 +30 +00 +C6 +CE +CC +D8 +F0 +D8 +CC +CC +C6 +C6 +ENDCHAR +STARTCHAR 045E +ENCODING 1118 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 18 1 -4 +BITMAP +46 +64 +38 +00 +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 045F +ENCODING 1119 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +C1 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +FF +FF +08 +08 +08 +08 +ENDCHAR +STARTCHAR 0490 +ENCODING 1168 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 17 1 0 +BITMAP +03 +03 +03 +FF +FF +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0491 +ENCODING 1169 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 6 14 1 0 +BITMAP +04 +04 +04 +04 +FC +FC +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0492 +ENCODING 1170 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 14 0 0 +BITMAP +7FC0 +7FC0 +6000 +6000 +6000 +6000 +FE00 +FE00 +6000 +6000 +6000 +6000 +6000 +6000 +ENDCHAR +STARTCHAR 0493 +ENCODING 1171 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 10 0 0 +BITMAP +7E +7E +60 +F8 +F8 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 0496 +ENCODING 1174 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 17 18 0 -4 +BITMAP +E0C380 +F0C780 +38C600 +18CE00 +1CCC00 +0FF800 +07F800 +0CDC00 +18CE00 +38C600 +30C700 +70C300 +60C380 +E0C180 +000080 +000080 +000080 +000080 +ENDCHAR +STARTCHAR 0497 +ENCODING 1175 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 13 0 -3 +BITMAP +E630 +E670 +3660 +1FC0 +1FC0 +36E0 +3660 +6630 +6638 +C618 +0018 +0018 +0018 +ENDCHAR +STARTCHAR 049A +ENCODING 1178 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 18 1 -4 +BITMAP +C1C0 +C3C0 +C700 +C600 +CE00 +FC00 +FC00 +CE00 +C600 +C700 +C300 +C380 +C1C0 +C1C0 +00C0 +00C0 +00C0 +00C0 +ENDCHAR +STARTCHAR 049B +ENCODING 1179 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 13 1 -3 +BITMAP +C6 +CE +D8 +F8 +F8 +D8 +CC +CC +C6 +C6 +02 +02 +02 +ENDCHAR +STARTCHAR 049C +ENCODING 1180 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 0 +BITMAP +C1C0 +C3C0 +DF00 +DE00 +DE00 +FC00 +FC00 +DC00 +DE00 +DF00 +DB00 +DB80 +C180 +C1C0 +ENDCHAR +STARTCHAR 049D +ENCODING 1181 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 10 1 0 +BITMAP +C6 +DE +D8 +F8 +F8 +D8 +DC +DC +C6 +C6 +ENDCHAR +STARTCHAR 04A2 +ENCODING 1186 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 2 -4 +BITMAP +80C0 +80C0 +80C0 +80C0 +80C0 +FFC0 +FFC0 +80C0 +80C0 +80C0 +80C0 +80C0 +80E0 +80E0 +0020 +0020 +0020 +0020 +ENDCHAR +STARTCHAR 04A3 +ENCODING 1187 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 -3 +BITMAP +C100 +C100 +C100 +C100 +FF00 +FF00 +C100 +C100 +C180 +C180 +0080 +0080 +0080 +ENDCHAR +STARTCHAR 04AE +ENCODING 1198 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +C0C0 +60C0 +6180 +3180 +3300 +1A00 +0E00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 04AF +ENCODING 1199 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 0 -4 +BITMAP +C180 +6180 +6100 +6300 +3300 +3600 +1600 +1E00 +1C00 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 04B0 +ENCODING 1200 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +C0C0 +60C0 +2180 +3100 +1B00 +1E00 +7FC0 +7FC0 +0C00 +0C00 +0C00 +0C00 +0C00 +0C00 +ENDCHAR +STARTCHAR 04B1 +ENCODING 1201 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 0 -4 +BITMAP +C180 +6180 +6100 +6300 +3300 +3600 +1600 +1E00 +1C00 +0C00 +7F80 +7F80 +0C00 +0C00 +ENDCHAR +STARTCHAR 04B2 +ENCODING 1202 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 -4 +BITMAP +6030 +3060 +38C0 +18C0 +0D80 +0F00 +0700 +0700 +0D80 +1DC0 +18C0 +3060 +6078 +E038 +0018 +0018 +0018 +0018 +ENDCHAR +STARTCHAR 04B3 +ENCODING 1203 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 13 0 -3 +BITMAP +6180 +7300 +3600 +1E00 +0C00 +1E00 +1E00 +3300 +6380 +E180 +0080 +0080 +0080 +ENDCHAR +STARTCHAR 04B8 +ENCODING 1208 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 10 14 1 0 +BITMAP +C0C0 +C0C0 +C0C0 +CCC0 +CCC0 +CCC0 +EDC0 +7FC0 +3EC0 +0CC0 +0CC0 +0CC0 +00C0 +00C0 +ENDCHAR +STARTCHAR 04B9 +ENCODING 1209 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +83 +83 +93 +D3 +FF +7F +13 +13 +03 +03 +ENDCHAR +STARTCHAR 04BA +ENCODING 1210 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +C000 +C000 +C000 +C000 +C000 +DF80 +FFC0 +E0E0 +C060 +C060 +C060 +C060 +C060 +C060 +ENDCHAR +STARTCHAR 04BB +ENCODING 1211 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +C0 +C0 +C0 +C0 +DE +FF +E3 +C1 +C1 +C1 +C1 +C1 +C1 +C1 +ENDCHAR +STARTCHAR 04D8 +ENCODING 1240 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F80 +3FC0 +70E0 +6030 +6030 +0030 +FFF0 +FFF0 +C010 +C030 +6030 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 04D9 +ENCODING 1241 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3E00 +FF00 +C300 +0180 +FF80 +FF80 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 04E8 +ENCODING 1256 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0F80 +3FE0 +7070 +6030 +C018 +C018 +FFF8 +FFF8 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 04E9 +ENCODING 1257 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3E00 +7F00 +C300 +C180 +FF80 +FF80 +8180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 05B0 +ENCODING 1456 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 3 2 -4 +BITMAP +C0 +00 +C0 +ENDCHAR +STARTCHAR 05B1 +ENCODING 1457 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 3 0 -4 +BITMAP +FC +00 +6C +ENDCHAR +STARTCHAR 05B2 +ENCODING 1458 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 3 0 -4 +BITMAP +FC +00 +0C +ENDCHAR +STARTCHAR 05B3 +ENCODING 1459 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 3 0 -4 +BITMAP +FC +60 +0C +ENDCHAR +STARTCHAR 05B4 +ENCODING 1460 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 1 2 -3 +BITMAP +C0 +ENDCHAR +STARTCHAR 05B5 +ENCODING 1461 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 1 1 -3 +BITMAP +D0 +ENDCHAR +STARTCHAR 05B6 +ENCODING 1462 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 3 1 -4 +BITMAP +D0 +00 +60 +ENDCHAR +STARTCHAR 05B7 +ENCODING 1463 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 1 1 -3 +BITMAP +F0 +ENDCHAR +STARTCHAR 05B8 +ENCODING 1464 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 3 1 -4 +BITMAP +F0 +20 +20 +ENDCHAR +STARTCHAR 05B9 +ENCODING 1465 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 1 2 11 +BITMAP +C0 +ENDCHAR +STARTCHAR 05BA +ENCODING 1466 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 1 2 11 +BITMAP +C0 +ENDCHAR +STARTCHAR 05BB +ENCODING 1467 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 3 0 -4 +BITMAP +C0 +30 +04 +ENDCHAR +STARTCHAR 05BC +ENCODING 1468 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 1 2 5 +BITMAP +C0 +ENDCHAR +STARTCHAR 05BD +ENCODING 1469 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 1 3 3 -4 +BITMAP +80 +80 +80 +ENDCHAR +STARTCHAR 05BE +ENCODING 1470 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 2 1 8 +BITMAP +F8 +F8 +ENDCHAR +STARTCHAR 05BF +ENCODING 1471 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 1 1 12 +BITMAP +F0 +ENDCHAR +STARTCHAR 05C0 +ENCODING 1472 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 1 12 2 0 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR 05C1 +ENCODING 1473 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 1 7 12 +BITMAP +C0 +ENDCHAR +STARTCHAR 05C2 +ENCODING 1474 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 1 1 -2 12 +BITMAP +80 +ENDCHAR +STARTCHAR 05C3 +ENCODING 1475 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 10 2 0 +BITMAP +C0 +C0 +00 +00 +00 +00 +00 +00 +C0 +C0 +ENDCHAR +STARTCHAR 05D0 +ENCODING 1488 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +E180 +6100 +3300 +3B00 +7F00 +4E00 +C600 +C600 +C300 +C180 +ENDCHAR +STARTCHAR 05D1 +ENCODING 1489 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 10 0 0 +BITMAP +7C00 +7E00 +0700 +0300 +0100 +0100 +0100 +0100 +FFC0 +FFC0 +ENDCHAR +STARTCHAR 05D2 +ENCODING 1490 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 10 0 0 +BITMAP +78 +7C +0C +0C +0C +1C +3C +64 +66 +C6 +ENDCHAR +STARTCHAR 05D3 +ENCODING 1491 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 0 0 +BITMAP +FF80 +FF80 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 05D4 +ENCODING 1492 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +FE00 +7F00 +0380 +0180 +C180 +C180 +C180 +C180 +C180 +C180 +ENDCHAR +STARTCHAR 05D5 +ENCODING 1493 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 10 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 05D6 +ENCODING 1494 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 6 10 1 0 +BITMAP +FC +FC +30 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 05D7 +ENCODING 1495 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +FE00 +FF00 +C380 +C180 +C180 +C180 +C180 +C180 +C180 +C180 +ENDCHAR +STARTCHAR 05D8 +ENCODING 1496 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +C700 +CF80 +C980 +C180 +C180 +C180 +C180 +6380 +7F00 +1E00 +ENDCHAR +STARTCHAR 05D9 +ENCODING 1497 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 5 1 5 +BITMAP +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 05DA +ENCODING 1498 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 0 -4 +BITMAP +FC +FE +07 +03 +01 +01 +01 +01 +01 +01 +01 +01 +01 +01 +ENDCHAR +STARTCHAR 05DB +ENCODING 1499 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 10 1 0 +BITMAP +F0 +FC +0C +06 +06 +06 +06 +0C +FC +F0 +ENDCHAR +STARTCHAR 05DC +ENCODING 1500 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 14 1 0 +BITMAP +80 +80 +80 +80 +FE +FE +06 +06 +04 +0C +18 +18 +18 +18 +ENDCHAR +STARTCHAR 05DD +ENCODING 1501 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +FE00 +FF00 +C380 +C180 +C180 +C180 +C180 +C180 +FF80 +FF80 +ENDCHAR +STARTCHAR 05DE +ENCODING 1502 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +CE00 +DF00 +7180 +6180 +6180 +6180 +4180 +4180 +CF80 +CF80 +ENDCHAR +STARTCHAR 05DF +ENCODING 1503 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 14 1 -4 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 05E0 +ENCODING 1504 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 4 10 1 0 +BITMAP +E0 +F0 +30 +10 +10 +10 +10 +10 +F0 +F0 +ENDCHAR +STARTCHAR 05E1 +ENCODING 1505 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3E00 +7F00 +E380 +C180 +C180 +C180 +C180 +E380 +7F00 +3E00 +ENDCHAR +STARTCHAR 05E2 +ENCODING 1506 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 11 0 -1 +BITMAP +6180 +2180 +3180 +3180 +3180 +3180 +1300 +1700 +1E00 +FC00 +E000 +ENDCHAR +STARTCHAR 05E3 +ENCODING 1507 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +FC +FF +C3 +C3 +C1 +C1 +71 +01 +01 +01 +01 +01 +01 +01 +ENDCHAR +STARTCHAR 05E4 +ENCODING 1508 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 1 0 +BITMAP +FC00 +FE00 +C700 +C300 +C180 +7180 +0300 +8700 +FE00 +7C00 +ENDCHAR +STARTCHAR 05E5 +ENCODING 1509 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 14 0 -4 +BITMAP +C3 +63 +23 +33 +16 +1C +18 +18 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR 05E6 +ENCODING 1510 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 10 0 0 +BITMAP +C3 +63 +33 +33 +1E +0C +04 +06 +7F +7F +ENDCHAR +STARTCHAR 05E7 +ENCODING 1511 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 -4 +BITMAP +FF +FF +01 +01 +43 +43 +46 +44 +44 +44 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 05E8 +ENCODING 1512 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 0 0 +BITMAP +FC +FE +07 +03 +01 +01 +01 +01 +01 +01 +ENDCHAR +STARTCHAR 05E9 +ENCODING 1513 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 10 1 0 +BITMAP +C460 +C460 +C460 +CC60 +CC60 +F860 +40C0 +61C0 +3F80 +1F00 +ENDCHAR +STARTCHAR 05EA +ENCODING 1514 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 10 0 0 +BITMAP +7F80 +7FC0 +18E0 +1860 +1860 +1860 +1860 +1860 +7860 +F060 +ENDCHAR +STARTCHAR 05F0 +ENCODING 1520 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 10 1 0 +BITMAP +C6 +C6 +C6 +C6 +C6 +C6 +C6 +C6 +C6 +C6 +ENDCHAR +STARTCHAR 05F1 +ENCODING 1521 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 10 1 0 +BITMAP +C6 +C6 +C6 +C6 +C6 +06 +06 +06 +06 +06 +ENDCHAR +STARTCHAR 05F2 +ENCODING 1522 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 5 1 5 +BITMAP +C6 +C6 +C6 +C6 +C6 +ENDCHAR +STARTCHAR 05F3 +ENCODING 1523 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 4 1 6 +BITMAP +40 +C0 +C0 +80 +ENDCHAR +STARTCHAR 05F4 +ENCODING 1524 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 6 4 1 6 +BITMAP +4C +C8 +C8 +98 +ENDCHAR +STARTCHAR 060C +ENCODING 1548 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 3 6 2 3 +BITMAP +40 +80 +80 +C0 +E0 +C0 +ENDCHAR +STARTCHAR 061B +ENCODING 1563 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 3 9 1 3 +BITMAP +20 +40 +80 +E0 +60 +60 +00 +60 +60 +ENDCHAR +STARTCHAR 061F +ENCODING 1567 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 11 1 3 +BITMAP +70 +C8 +98 +D8 +C0 +60 +20 +20 +00 +60 +60 +ENDCHAR +STARTCHAR 0621 +ENCODING 1569 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 6 8 1 1 +BITMAP +30 +70 +40 +CC +FC +70 +60 +40 +ENDCHAR +STARTCHAR 0622 +ENCODING 1570 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 14 0 2 +BITMAP +F0 +00 +00 +40 +60 +20 +20 +20 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR 0623 +ENCODING 1571 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 14 1 2 +BITMAP +40 +80 +C0 +80 +00 +00 +80 +C0 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 0624 +ENCODING 1572 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 16 0 -2 +BITMAP +0C +10 +0C +10 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 0625 +ENCODING 1573 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 16 0 -2 +BITMAP +40 +60 +20 +20 +20 +20 +20 +20 +20 +20 +20 +00 +60 +80 +60 +80 +ENDCHAR +STARTCHAR 0626 +ENCODING 1574 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 12 0 -1 +BITMAP +2000 +4000 +6060 +40F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +ENDCHAR +STARTCHAR 0627 +ENCODING 1575 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 11 1 3 +BITMAP +80 +C0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 0628 +ENCODING 1576 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 0629 +ENCODING 1577 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 11 0 3 +BITMAP +10 +D0 +C0 +00 +20 +30 +78 +48 +48 +78 +70 +ENDCHAR +STARTCHAR 062A +ENCODING 1578 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 9 1 3 +BITMAP +0300 +0F00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR 062B +ENCODING 1579 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 10 1 3 +BITMAP +0400 +0700 +0F00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR 062C +ENCODING 1580 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4000 +8600 +8600 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 062D +ENCODING 1581 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4000 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 062E +ENCODING 1582 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 16 0 -4 +BITMAP +0C00 +0400 +0000 +0000 +3F80 +7F80 +0C00 +3000 +4000 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 062F +ENCODING 1583 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 8 1 3 +BITMAP +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR 0630 +ENCODING 1584 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 3 +BITMAP +40 +60 +00 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR 0631 +ENCODING 1585 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 10 1 -2 +BITMAP +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR 0632 +ENCODING 1586 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +04 +04 +00 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR 0633 +ENCODING 1587 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 9 1 -1 +BITMAP +0104 +0182 +0092 +80FE +80FE +8080 +8180 +FF00 +7C00 +ENDCHAR +STARTCHAR 0634 +ENCODING 1588 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 1 -1 +BITMAP +0030 +0038 +0028 +0020 +0000 +0104 +0182 +0092 +80FE +80FE +8080 +8180 +FF00 +7C00 +ENDCHAR +STARTCHAR 0635 +ENCODING 1589 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 9 1 -1 +BITMAP +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810000 +FF0000 +7C0000 +ENDCHAR +STARTCHAR 0636 +ENCODING 1590 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 12 1 -1 +BITMAP +000800 +000800 +000000 +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810000 +FF0000 +7C0000 +ENDCHAR +STARTCHAR 0637 +ENCODING 1591 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1800 +0800 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 0638 +ENCODING 1592 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1880 +0880 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 0639 +ENCODING 1593 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 16 0 -4 +BITMAP +3800 +7C00 +6000 +8000 +8100 +6700 +7C00 +3000 +2000 +4000 +8000 +8000 +C000 +6000 +7F80 +1F00 +ENDCHAR +STARTCHAR 063A +ENCODING 1594 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 20 0 -4 +BITMAP +1000 +1000 +0000 +0000 +3800 +7C00 +6000 +8000 +8100 +6700 +7C00 +3000 +2000 +4000 +8000 +8000 +C000 +6000 +7F80 +1F00 +ENDCHAR +STARTCHAR 0640 +ENCODING 1600 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 5 2 -1 3 +BITMAP +F8 +F8 +ENDCHAR +STARTCHAR 0641 +ENCODING 1601 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 10 0 3 +BITMAP +0018 +0018 +0000 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR 0642 +ENCODING 1602 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 -1 +BITMAP +0100 +0580 +0400 +0000 +0000 +0180 +03C0 +02C0 +83C0 +83C0 +8040 +80C0 +FF80 +7F00 +ENDCHAR +STARTCHAR 0643 +ENCODING 1603 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 12 0 3 +BITMAP +0040 +0060 +0060 +0240 +0420 +0720 +0120 +0120 +9E20 +C020 +7FE0 +7FE0 +ENDCHAR +STARTCHAR 0644 +ENCODING 1604 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 15 1 0 +BITMAP +0200 +0300 +0100 +0100 +0100 +0100 +0100 +0100 +8100 +8080 +8080 +8080 +8300 +FF00 +7E00 +ENDCHAR +STARTCHAR 0645 +ENCODING 1605 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 11 0 -4 +BITMAP +38 +3C +0C +3C +7C +C0 +80 +80 +40 +40 +40 +ENDCHAR +STARTCHAR 0646 +ENCODING 1606 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 12 1 -1 +BITMAP +0800 +0800 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR 0647 +ENCODING 1607 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 7 1 3 +BITMAP +40 +E0 +F0 +90 +90 +F0 +E0 +ENDCHAR +STARTCHAR 0648 +ENCODING 1608 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 11 0 -2 +BITMAP +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 0649 +ENCODING 1609 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 10 0 -1 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +ENDCHAR +STARTCHAR 064A +ENCODING 1610 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 13 0 -4 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +0300 +0B00 +0800 +ENDCHAR +STARTCHAR 064B +ENCODING 1611 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 4 1 12 +BITMAP +60 +80 +60 +80 +ENDCHAR +STARTCHAR 064C +ENCODING 1612 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 3 5 1 12 +BITMAP +20 +60 +A0 +E0 +C0 +ENDCHAR +STARTCHAR 064D +ENCODING 1613 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 4 1 -3 +BITMAP +60 +80 +60 +80 +ENDCHAR +STARTCHAR 064E +ENCODING 1614 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 2 1 12 +BITMAP +60 +80 +ENDCHAR +STARTCHAR 064F +ENCODING 1615 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 5 1 12 +BITMAP +60 +60 +60 +60 +80 +ENDCHAR +STARTCHAR 0650 +ENCODING 1616 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 2 1 0 +BITMAP +60 +80 +ENDCHAR +STARTCHAR 0651 +ENCODING 1617 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 3 1 12 +BITMAP +40 +60 +80 +ENDCHAR +STARTCHAR 0652 +ENCODING 1618 +SWIDTH 154 0 +DWIDTH 3 0 +BBX 2 3 1 12 +BITMAP +C0 +C0 +C0 +ENDCHAR +STARTCHAR 0653 +ENCODING 1619 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 2 0 13 +BITMAP +C0 +70 +ENDCHAR +STARTCHAR 0654 +ENCODING 1620 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 4 1 13 +BITMAP +40 +80 +C0 +80 +ENDCHAR +STARTCHAR 0655 +ENCODING 1621 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 4 1 -3 +BITMAP +40 +80 +C0 +80 +ENDCHAR +STARTCHAR 0660 +ENCODING 1632 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 3 4 4 4 +BITMAP +80 +E0 +C0 +40 +ENDCHAR +STARTCHAR 0661 +ENCODING 1633 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 3 10 3 3 +BITMAP +80 +C0 +C0 +60 +60 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR 0662 +ENCODING 1634 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 5 11 2 3 +BITMAP +80 +C8 +F8 +78 +60 +20 +30 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 0663 +ENCODING 1635 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 4 +BITMAP +CD +7F +76 +20 +20 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 0664 +ENCODING 1636 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 4 11 3 3 +BITMAP +10 +20 +40 +80 +F0 +60 +40 +40 +C0 +F0 +70 +ENDCHAR +STARTCHAR 0665 +ENCODING 1637 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 6 8 2 5 +BITMAP +30 +78 +9C +84 +84 +84 +F8 +F0 +ENDCHAR +STARTCHAR 0666 +ENCODING 1638 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 6 11 2 3 +BITMAP +80 +F0 +F0 +10 +10 +10 +10 +18 +08 +0C +04 +ENDCHAR +STARTCHAR 0667 +ENCODING 1639 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 3 +BITMAP +81 +C1 +C3 +62 +24 +24 +18 +18 +18 +08 +ENDCHAR +STARTCHAR 0668 +ENCODING 1640 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 4 +BITMAP +10 +18 +28 +28 +24 +26 +46 +C3 +81 +81 +ENDCHAR +STARTCHAR 0669 +ENCODING 1641 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 6 11 2 3 +BITMAP +30 +70 +98 +88 +F8 +78 +08 +08 +08 +0C +08 +ENDCHAR +STARTCHAR 066A +ENCODING 1642 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 13 1 2 +BITMAP +63 +62 +06 +04 +0C +08 +18 +10 +30 +20 +60 +46 +C6 +ENDCHAR +STARTCHAR 066B +ENCODING 1643 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 5 2 1 +BITMAP +C0 +C0 +C0 +40 +80 +ENDCHAR +STARTCHAR 066C +ENCODING 1644 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 3 6 2 3 +BITMAP +40 +80 +80 +C0 +E0 +C0 +ENDCHAR +STARTCHAR 066D +ENCODING 1645 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 6 7 2 7 +BITMAP +20 +E8 +50 +FC +70 +E8 +20 +ENDCHAR +STARTCHAR 066E +ENCODING 1646 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 6 1 3 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR 066F +ENCODING 1647 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 9 1 -1 +BITMAP +0180 +03C0 +02C0 +83C0 +83C0 +8040 +80C0 +FF80 +7F00 +ENDCHAR +STARTCHAR 0670 +ENCODING 1648 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 4 0 11 +BITMAP +80 +80 +80 +80 +ENDCHAR +STARTCHAR 0671 +ENCODING 1649 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 15 0 2 +BITMAP +30 +F0 +80 +00 +40 +60 +20 +20 +20 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR 0672 +ENCODING 1650 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 15 0 2 +BITMAP +20 +40 +E0 +00 +40 +60 +20 +20 +20 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR 0673 +ENCODING 1651 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 15 0 -1 +BITMAP +40 +60 +20 +20 +20 +20 +20 +20 +20 +20 +20 +00 +20 +40 +E0 +ENDCHAR +STARTCHAR 0674 +ENCODING 1652 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 4 1 13 +BITMAP +40 +80 +C0 +80 +ENDCHAR +STARTCHAR 0675 +ENCODING 1653 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 12 1 2 +BITMAP +10 +A0 +D0 +60 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 0676 +ENCODING 1654 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 9 16 0 -2 +BITMAP +0080 +0100 +0080 +0100 +0000 +0300 +0700 +0500 +0500 +0700 +0300 +0100 +0100 +0200 +8600 +7C00 +ENDCHAR +STARTCHAR 0677 +ENCODING 1655 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 9 16 0 -2 +BITMAP +0C80 +0D00 +0C80 +0D00 +1000 +0300 +0700 +0500 +0500 +0700 +0300 +0100 +0100 +0200 +8600 +7C00 +ENDCHAR +STARTCHAR 0678 +ENCODING 1656 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 15 0 -1 +BITMAP +0010 +0020 +0010 +0020 +0000 +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +ENDCHAR +STARTCHAR 0679 +ENCODING 1657 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 13 1 3 +BITMAP +0400 +0800 +0400 +0780 +0480 +1F80 +0000 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR 067A +ENCODING 1658 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 3 +BITMAP +0400 +0400 +0600 +0200 +0000 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR 067B +ENCODING 1659 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 -2 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0200 +0200 +0200 +0200 +ENDCHAR +STARTCHAR 067C +ENCODING 1660 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 1 +BITMAP +0300 +0F00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0500 +0600 +ENDCHAR +STARTCHAR 067D +ENCODING 1661 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 3 +BITMAP +0300 +0F00 +0E00 +0200 +0000 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR 067E +ENCODING 1662 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 -2 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0100 +0500 +0700 +0300 +ENDCHAR +STARTCHAR 067F +ENCODING 1663 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 3 +BITMAP +0200 +0A00 +0900 +0D00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR 0680 +ENCODING 1664 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 12 1 -3 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0300 +0D00 +0D00 +0500 +0400 +ENDCHAR +STARTCHAR 0681 +ENCODING 1665 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 0 -4 +BITMAP +0600 +0800 +0600 +0800 +0000 +3F80 +7F80 +0C00 +3000 +4000 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 0682 +ENCODING 1666 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 0 -4 +BITMAP +0C00 +0C00 +0400 +0400 +0000 +0000 +3F80 +7F80 +0C00 +3000 +4000 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 0683 +ENCODING 1667 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4000 +8300 +8B00 +8800 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 0684 +ENCODING 1668 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4000 +8400 +8400 +8600 +4600 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 0685 +ENCODING 1669 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 0 -4 +BITMAP +0800 +0A00 +0A00 +0800 +0000 +0000 +3F80 +7F80 +0C00 +3000 +4000 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 0686 +ENCODING 1670 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4200 +8B00 +8A00 +8200 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 0687 +ENCODING 1671 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4300 +8B00 +8D00 +8500 +4400 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 0688 +ENCODING 1672 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 15 0 3 +BITMAP +20 +20 +20 +2C +34 +FC +00 +10 +18 +0C +04 +04 +04 +7C +7C +ENDCHAR +STARTCHAR 0689 +ENCODING 1673 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 10 1 1 +BITMAP +20 +30 +18 +08 +08 +08 +F8 +F8 +50 +30 +ENDCHAR +STARTCHAR 068A +ENCODING 1674 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 11 1 0 +BITMAP +20 +30 +18 +08 +08 +08 +F8 +F8 +00 +20 +30 +ENDCHAR +STARTCHAR 068B +ENCODING 1675 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 18 0 0 +BITMAP +20 +20 +20 +2C +34 +FC +00 +10 +18 +0C +04 +04 +04 +7C +7C +00 +10 +18 +ENDCHAR +STARTCHAR 068C +ENCODING 1676 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 3 +BITMAP +30 +D0 +C0 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR 068D +ENCODING 1677 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 -1 +BITMAP +20 +30 +18 +08 +08 +08 +F8 +F8 +00 +10 +50 +40 +ENDCHAR +STARTCHAR 068E +ENCODING 1678 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 13 1 3 +BITMAP +40 +50 +50 +40 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR 068F +ENCODING 1679 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 13 1 3 +BITMAP +20 +A0 +A0 +20 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR 0690 +ENCODING 1680 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 14 1 3 +BITMAP +30 +B0 +90 +50 +40 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR 0691 +ENCODING 1681 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 17 1 -2 +BITMAP +08 +10 +08 +0F +09 +3F +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR 0692 +ENCODING 1682 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 13 1 -2 +BITMAP +0A +04 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR 0693 +ENCODING 1683 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 11 1 -3 +BITMAP +02 +03 +01 +01 +01 +01 +01 +03 +8F +7D +03 +ENDCHAR +STARTCHAR 0694 +ENCODING 1684 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 11 1 -3 +BITMAP +02 +03 +01 +01 +01 +01 +01 +03 +8E +79 +01 +ENDCHAR +STARTCHAR 0695 +ENCODING 1685 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 12 1 -4 +BITMAP +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +05 +02 +ENDCHAR +STARTCHAR 0696 +ENCODING 1686 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 11 1 -3 +BITMAP +02 +03 +01 +01 +11 +11 +01 +03 +8E +79 +01 +ENDCHAR +STARTCHAR 0697 +ENCODING 1687 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +06 +1E +18 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR 0698 +ENCODING 1688 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 15 1 -2 +BITMAP +0C +0F +0B +08 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR 0699 +ENCODING 1689 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 16 1 -2 +BITMAP +04 +14 +16 +1A +18 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR 069A +ENCODING 1690 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 12 1 -1 +BITMAP +0020 +0030 +0000 +0104 +0182 +0092 +80FE +80FE +8080 +8188 +FF08 +7C00 +ENDCHAR +STARTCHAR 069B +ENCODING 1691 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 10 1 -2 +BITMAP +0104 +0182 +0092 +80FE +80FE +8080 +8184 +FF14 +7C14 +0004 +ENDCHAR +STARTCHAR 069C +ENCODING 1692 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 15 1 -2 +BITMAP +0060 +0070 +0050 +0040 +0000 +0104 +0182 +0092 +80FE +80FE +8080 +8184 +FF14 +7C14 +0004 +ENDCHAR +STARTCHAR 069D +ENCODING 1693 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 9 1 -1 +BITMAP +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810100 +FF0500 +7C0400 +ENDCHAR +STARTCHAR 069E +ENCODING 1694 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 14 1 -1 +BITMAP +000400 +000500 +000500 +000400 +000000 +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810000 +FF0000 +7C0000 +ENDCHAR +STARTCHAR 069F +ENCODING 1695 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1880 +18E0 +09E0 +0980 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 06A0 +ENCODING 1696 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 21 0 -4 +BITMAP +2000 +2800 +2800 +2000 +0000 +3800 +7C00 +6000 +8000 +8100 +6700 +7C00 +3000 +2000 +4000 +8000 +8000 +C000 +6000 +7F80 +1F00 +ENDCHAR +STARTCHAR 06A1 +ENCODING 1697 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 6 0 3 +BITMAP +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR 06A2 +ENCODING 1698 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 9 0 0 +BITMAP +400C +800E +801A +C00E +7FFE +3FFE +0000 +0004 +0004 +ENDCHAR +STARTCHAR 06A3 +ENCODING 1699 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 12 0 0 +BITMAP +0008 +0008 +0000 +400C +800E +801A +C00E +7FFE +3FFE +0000 +0180 +0080 +ENDCHAR +STARTCHAR 06A4 +ENCODING 1700 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 11 0 3 +BITMAP +0010 +001C +0014 +0010 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR 06A5 +ENCODING 1701 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 11 0 -2 +BITMAP +400C +800E +801A +C00E +7FFE +3FFE +0000 +0002 +000A +000A +0002 +ENDCHAR +STARTCHAR 06A6 +ENCODING 1702 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 12 0 3 +BITMAP +0004 +0014 +0014 +0014 +0010 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR 06A7 +ENCODING 1703 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 13 1 -1 +BITMAP +0300 +0300 +0000 +0000 +0180 +03C0 +02C0 +83C0 +83C0 +8040 +80C0 +FF80 +7F00 +ENDCHAR +STARTCHAR 06A8 +ENCODING 1704 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 -1 +BITMAP +0400 +0700 +0500 +0400 +0000 +0180 +03C0 +02C0 +83C0 +83C0 +8040 +80C0 +FF80 +7F00 +ENDCHAR +STARTCHAR 06A9 +ENCODING 1705 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 11 0 3 +BITMAP +0006 +001E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR 06AA +ENCODING 1706 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 10 0 3 +BITMAP +0080 +0380 +0E00 +1000 +1F00 +8FF8 +80FE +C002 +FFFE +7FFE +ENDCHAR +STARTCHAR 06AB +ENCODING 1707 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 11 0 3 +BITMAP +0006 +001E +007A +004C +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR 06AC +ENCODING 1708 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 12 0 3 +BITMAP +0640 +0660 +0060 +0240 +0420 +0720 +0120 +0120 +9E20 +C020 +7FE0 +7FE0 +ENDCHAR +STARTCHAR 06AD +ENCODING 1709 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 13 0 3 +BITMAP +0C00 +0E40 +0B60 +0860 +0240 +0420 +0720 +0120 +0120 +9E20 +C020 +7FE0 +7FE0 +ENDCHAR +STARTCHAR 06AE +ENCODING 1710 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 17 0 -2 +BITMAP +0040 +0060 +0060 +0240 +0420 +0720 +0120 +0120 +9E20 +C020 +7FE0 +7FE0 +0000 +0300 +0F00 +0E00 +0200 +ENDCHAR +STARTCHAR 06AF +ENCODING 1711 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 14 0 3 +BITMAP +0002 +000E +0038 +0066 +009E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR 06B0 +ENCODING 1712 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 14 0 3 +BITMAP +0002 +000E +0038 +0066 +009E +007A +004C +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR 06B1 +ENCODING 1713 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 14 0 3 +BITMAP +0012 +004E +0038 +0066 +009E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR 06B2 +ENCODING 1714 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 18 0 -1 +BITMAP +0002 +000E +0038 +0066 +009E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +0000 +0040 +0140 +0100 +ENDCHAR +STARTCHAR 06B3 +ENCODING 1715 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 19 0 -2 +BITMAP +0002 +000E +0038 +0066 +009E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +0000 +0080 +0080 +0080 +0080 +ENDCHAR +STARTCHAR 06B4 +ENCODING 1716 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 14 0 3 +BITMAP +0042 +001E +0078 +0066 +009E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR 06B5 +ENCODING 1717 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 17 1 0 +BITMAP +0500 +0200 +0000 +0300 +0100 +0100 +0100 +0100 +0100 +0100 +8100 +8080 +8080 +8080 +8300 +FF00 +7E00 +ENDCHAR +STARTCHAR 06B6 +ENCODING 1718 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 17 1 0 +BITMAP +0300 +0300 +0000 +0300 +0100 +0100 +0100 +0100 +0100 +0100 +8100 +8080 +8080 +8080 +8300 +FF00 +7E00 +ENDCHAR +STARTCHAR 06B7 +ENCODING 1719 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 17 1 0 +BITMAP +0600 +0100 +0400 +0300 +0100 +0100 +0100 +0100 +0100 +0100 +8100 +8080 +8080 +8080 +8300 +FF00 +7E00 +ENDCHAR +STARTCHAR 06B8 +ENCODING 1720 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 19 1 -4 +BITMAP +0200 +0300 +0100 +0100 +0100 +0100 +0100 +0100 +8100 +8080 +8080 +8080 +8300 +FF00 +7E00 +0400 +2C00 +3C00 +0C00 +ENDCHAR +STARTCHAR 06B9 +ENCODING 1721 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 15 1 -4 +BITMAP +0800 +0800 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +0000 +0800 +0800 +ENDCHAR +STARTCHAR 06BA +ENCODING 1722 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 8 1 0 +BITMAP +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR 06BB +ENCODING 1723 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 16 1 -1 +BITMAP +1000 +1000 +1000 +1600 +1A00 +3E00 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR 06BC +ENCODING 1724 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 1 -3 +BITMAP +0800 +0800 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +2800 +1800 +ENDCHAR +STARTCHAR 06BD +ENCODING 1725 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 1 -1 +BITMAP +1000 +1400 +3400 +1000 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR 06BE +ENCODING 1726 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 8 -1 3 +BITMAP +08 +1C +1C +26 +27 +19 +FF +E7 +ENDCHAR +STARTCHAR 06BF +ENCODING 1727 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 16 0 -4 +BITMAP +0C00 +0400 +0000 +0000 +3F80 +7F80 +0C00 +3000 +4200 +8B00 +8A00 +8200 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR 06C0 +ENCODING 1728 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 12 1 3 +BITMAP +60 +80 +60 +80 +00 +40 +E0 +F0 +90 +90 +F0 +E0 +ENDCHAR +STARTCHAR 06C1 +ENCODING 1729 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 5 0 2 +BITMAP +18 +3C +6E +46 +80 +ENDCHAR +STARTCHAR 06C2 +ENCODING 1730 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 10 0 2 +BITMAP +10 +20 +10 +20 +00 +18 +3C +6E +46 +80 +ENDCHAR +STARTCHAR 06C3 +ENCODING 1731 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 9 0 2 +BITMAP +08 +28 +20 +00 +18 +3C +6E +46 +80 +ENDCHAR +STARTCHAR 06C4 +ENCODING 1732 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 11 0 -2 +BITMAP +03 +07 +05 +05 +07 +03 +01 +0D +16 +8E +7C +ENDCHAR +STARTCHAR 06C5 +ENCODING 1733 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 11 0 -2 +BITMAP +03 +07 +05 +05 +07 +03 +19 +07 +02 +86 +7C +ENDCHAR +STARTCHAR 06C6 +ENCODING 1734 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 14 0 -2 +BITMAP +05 +02 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 06C7 +ENCODING 1735 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 17 0 -2 +BITMAP +03 +03 +03 +03 +04 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 06C8 +ENCODING 1736 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 17 0 -1 +BITMAP +02 +02 +02 +02 +02 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 06C9 +ENCODING 1737 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 14 0 -2 +BITMAP +02 +05 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 06CA +ENCODING 1738 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 15 0 -2 +BITMAP +03 +0F +0C +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 06CB +ENCODING 1739 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 16 0 -2 +BITMAP +04 +07 +0D +0C +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 06CC +ENCODING 1740 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 10 0 -1 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +ENDCHAR +STARTCHAR 06CD +ENCODING 1741 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 13 10 -1 -1 +BITMAP +0030 +0078 +0080 +2100 +E1F0 +40F0 +4010 +60E0 +3FC0 +1F00 +ENDCHAR +STARTCHAR 06CE +ENCODING 1742 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 11 0 -1 +BITMAP +0C00 +0860 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +ENDCHAR +STARTCHAR 06CF +ENCODING 1743 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 14 0 -2 +BITMAP +04 +04 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR 06D0 +ENCODING 1744 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 13 0 -4 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +0000 +0400 +0400 +ENDCHAR +STARTCHAR 06D1 +ENCODING 1745 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 13 0 -4 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +0000 +0A00 +0600 +ENDCHAR +STARTCHAR 06D2 +ENCODING 1746 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 14 7 1 0 +BITMAP +0600 +0E00 +3800 +7000 +8000 +FFFC +FFF8 +ENDCHAR +STARTCHAR 06D3 +ENCODING 1747 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 14 10 1 0 +BITMAP +0800 +3000 +1800 +2600 +0E00 +3800 +7000 +8000 +FFFC +FFF8 +ENDCHAR +STARTCHAR 06D4 +ENCODING 1748 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 2 0 3 +BITMAP +F0 +F0 +ENDCHAR +STARTCHAR 06D5 +ENCODING 1749 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 7 1 3 +BITMAP +40 +E0 +F0 +90 +90 +F0 +E0 +ENDCHAR +STARTCHAR 06D6 +ENCODING 1750 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 8 7 -4 10 +BITMAP +20 +20 +20 +23 +7F +80 +FE +ENDCHAR +STARTCHAR 06D7 +ENCODING 1751 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 7 7 -3 10 +BITMAP +28 +30 +38 +24 +7C +80 +FE +ENDCHAR +STARTCHAR 06D8 +ENCODING 1752 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -2 10 +BITMAP +20 +50 +F0 +ENDCHAR +STARTCHAR 06D9 +ENCODING 1753 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 6 -2 10 +BITMAP +90 +D0 +50 +20 +60 +60 +ENDCHAR +STARTCHAR 06DA +ENCODING 1754 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 5 -2 10 +BITMAP +F0 +80 +A0 +80 +F0 +ENDCHAR +STARTCHAR 06DB +ENCODING 1755 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -1 10 +BITMAP +80 +C0 +ENDCHAR +STARTCHAR 06DC +ENCODING 1756 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 8 5 -4 10 +BITMAP +08 +09 +87 +88 +70 +ENDCHAR +STARTCHAR 06DD +ENCODING 1757 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 21 21 0 -4 +BITMAP +00FC00 +0F0380 +13FE80 +1C01C0 +100060 +200020 +400010 +400010 +400008 +400008 +800008 +400008 +400008 +400010 +400010 +200020 +100060 +1C01C0 +13FE80 +0F0380 +00FC00 +ENDCHAR +STARTCHAR 06DE +ENCODING 1758 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 21 0 -4 +BITMAP +002000 +005000 +008800 +1FFF80 +120480 +140280 +180180 +100080 +307040 +5090A0 +909090 +5090A0 +307040 +100080 +180180 +140280 +120480 +1FFF80 +008800 +005000 +002000 +ENDCHAR +STARTCHAR 06DF +ENCODING 1759 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -1 10 +BITMAP +C0 +ENDCHAR +STARTCHAR 06E0 +ENCODING 1760 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -1 10 +BITMAP +C0 +ENDCHAR +STARTCHAR 06E1 +ENCODING 1761 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 3 -3 10 +BITMAP +30 +18 +FC +ENDCHAR +STARTCHAR 06E2 +ENCODING 1762 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 5 -1 10 +BITMAP +40 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR 06E3 +ENCODING 1763 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 8 5 -4 -4 +BITMAP +08 +09 +87 +88 +70 +ENDCHAR +STARTCHAR 06E4 +ENCODING 1764 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -1 10 +BITMAP +C0 +ENDCHAR +STARTCHAR 06E5 +ENCODING 1765 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 4 1 10 +BITMAP +60 +60 +40 +C0 +ENDCHAR +STARTCHAR 06E6 +ENCODING 1766 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 4 0 10 +BITMAP +10 +70 +80 +FE +ENDCHAR +STARTCHAR 06E7 +ENCODING 1767 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 7 4 -4 10 +BITMAP +10 +20 +C0 +FE +ENDCHAR +STARTCHAR 06E8 +ENCODING 1768 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 6 -2 10 +BITMAP +20 +00 +10 +90 +90 +F0 +ENDCHAR +STARTCHAR 06E9 +ENCODING 1769 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 16 1 0 +BITMAP +0800 +1400 +2A00 +5580 +AA40 +D780 +7700 +5300 +5300 +5300 +5300 +5F00 +6300 +9E80 +8080 +FFC0 +ENDCHAR +STARTCHAR 06EA +ENCODING 1770 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -2 -3 +BITMAP +60 +90 +60 +ENDCHAR +STARTCHAR 06EB +ENCODING 1771 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -2 10 +BITMAP +60 +90 +60 +ENDCHAR +STARTCHAR 06EC +ENCODING 1772 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 1 -1 10 +BITMAP +C0 +ENDCHAR +STARTCHAR 06ED +ENCODING 1773 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 5 -1 -4 +BITMAP +40 +C0 +C0 +80 +80 +ENDCHAR +STARTCHAR 06F0 +ENCODING 1776 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 3 4 4 4 +BITMAP +80 +E0 +C0 +40 +ENDCHAR +STARTCHAR 06F1 +ENCODING 1777 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 3 10 3 3 +BITMAP +80 +C0 +C0 +60 +60 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR 06F2 +ENCODING 1778 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 5 11 2 3 +BITMAP +80 +C8 +F8 +78 +60 +20 +30 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 06F3 +ENCODING 1779 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 4 +BITMAP +CD +7F +76 +20 +20 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 06F4 +ENCODING 1780 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 10 2 3 +BITMAP +1C +A0 +E2 +FC +78 +60 +20 +20 +20 +20 +ENDCHAR +STARTCHAR 06F5 +ENCODING 1781 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 11 1 3 +BITMAP +10 +18 +1C +1C +26 +42 +42 +42 +CA +FE +7C +ENDCHAR +STARTCHAR 06F6 +ENCODING 1782 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 6 11 2 3 +BITMAP +30 +78 +80 +84 +FC +F8 +30 +20 +40 +40 +40 +ENDCHAR +STARTCHAR 06F7 +ENCODING 1783 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 3 +BITMAP +81 +C1 +C3 +62 +24 +24 +18 +18 +18 +08 +ENDCHAR +STARTCHAR 06F8 +ENCODING 1784 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 1 4 +BITMAP +10 +18 +28 +28 +24 +26 +46 +C3 +81 +81 +ENDCHAR +STARTCHAR 06F9 +ENCODING 1785 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 6 11 2 3 +BITMAP +30 +70 +98 +88 +F8 +78 +08 +08 +08 +0C +08 +ENDCHAR +STARTCHAR 06FA +ENCODING 1786 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 1 -1 +BITMAP +0060 +0070 +0050 +0040 +0000 +0104 +0182 +0092 +80FE +80FE +8080 +8188 +FF08 +7C00 +ENDCHAR +STARTCHAR 06FB +ENCODING 1787 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 12 1 -1 +BITMAP +000800 +000800 +000000 +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810200 +FF0200 +7C0000 +ENDCHAR +STARTCHAR 06FC +ENCODING 1788 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 20 0 -4 +BITMAP +1000 +1000 +0000 +0000 +3800 +7C00 +6000 +8000 +8100 +6700 +7C00 +3000 +2000 +4000 +8200 +8200 +C000 +6000 +7F80 +1F00 +ENDCHAR +STARTCHAR 06FD +ENCODING 1789 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 6 12 1 -3 +BITMAP +30 +70 +40 +CC +FC +70 +60 +40 +28 +28 +28 +28 +ENDCHAR +STARTCHAR 06FE +ENCODING 1790 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 11 0 -4 +BITMAP +38 +3C +0C +3C +7C +C0 +80 +94 +54 +54 +54 +ENDCHAR +STARTCHAR 1E80 +ENCODING 7808 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 18 0 0 +BITMAP +018000 +00C000 +004000 +000000 +C0C0C0 +40C080 +61E180 +61E180 +612180 +233100 +333300 +323300 +321200 +161A00 +161E00 +1C0E00 +1C0C00 +0C0C00 +ENDCHAR +STARTCHAR 1E81 +ENCODING 7809 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 14 0 0 +BITMAP +0600 +0600 +0200 +0000 +C308 +4308 +4718 +6798 +6590 +24B0 +3CB0 +3CE0 +18E0 +1860 +ENDCHAR +STARTCHAR 1E82 +ENCODING 7810 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 18 0 0 +BITMAP +006000 +004000 +00C000 +000000 +C0C0C0 +40C080 +61E180 +61E180 +612180 +233100 +333300 +323300 +321200 +161A00 +161E00 +1C0E00 +1C0C00 +0C0C00 +ENDCHAR +STARTCHAR 1E83 +ENCODING 7811 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 14 0 0 +BITMAP +0300 +0300 +0200 +0000 +C308 +4308 +4718 +6798 +6590 +24B0 +3CB0 +3CE0 +18E0 +1860 +ENDCHAR +STARTCHAR 1E84 +ENCODING 7812 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 17 0 0 +BITMAP +033000 +033000 +000000 +C0C0C0 +40C080 +61E180 +61E180 +612180 +233100 +333300 +323300 +321200 +161A00 +161E00 +1C0E00 +1C0C00 +0C0C00 +ENDCHAR +STARTCHAR 1E85 +ENCODING 7813 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 13 0 0 +BITMAP +0CC0 +0CC0 +0000 +C308 +4308 +4718 +6798 +6590 +24B0 +3CB0 +3CE0 +18E0 +1860 +ENDCHAR +STARTCHAR 1EA0 +ENCODING 7840 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 17 0 -3 +BITMAP +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EA1 +ENCODING 7841 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 -3 +BITMAP +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1EA2 +ENCODING 7842 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0F00 +0100 +0300 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EA3 +ENCODING 7843 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +1C00 +0600 +0C00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EA4 +ENCODING 7844 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0300 +0200 +0700 +0900 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EA5 +ENCODING 7845 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +1800 +3400 +2600 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EA6 +ENCODING 7846 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0C00 +0600 +0700 +0900 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EA7 +ENCODING 7847 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +3000 +1000 +1800 +0000 +1800 +3400 +2600 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EA8 +ENCODING 7848 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0700 +0300 +0700 +0900 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EA9 +ENCODING 7849 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +3C00 +0400 +0C00 +0000 +1800 +3400 +2600 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EAA +ENCODING 7850 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0C80 +1380 +0700 +0900 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EAB +ENCODING 7851 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 0 +BITMAP +3200 +4E00 +0000 +1800 +3400 +2600 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EAC +ENCODING 7852 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 20 0 -3 +BITMAP +0700 +0900 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EAD +ENCODING 7853 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 -3 +BITMAP +1800 +3400 +2600 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1EAE +ENCODING 7854 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0300 +0200 +0880 +0700 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EAF +ENCODING 7855 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +0C00 +0C00 +1800 +0000 +2200 +2200 +1C00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EB0 +ENCODING 7856 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0C00 +0600 +0880 +0700 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EB1 +ENCODING 7857 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +3000 +1800 +0800 +0000 +2200 +2200 +1C00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EB2 +ENCODING 7858 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0700 +0300 +0880 +0700 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EB3 +ENCODING 7859 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +1C00 +0600 +0C00 +0000 +2200 +2200 +1C00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EB4 +ENCODING 7860 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 18 0 0 +BITMAP +0E80 +1380 +0880 +0700 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +ENDCHAR +STARTCHAR 1EB5 +ENCODING 7861 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 0 +BITMAP +3B00 +2600 +0000 +2200 +2200 +1C00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +ENDCHAR +STARTCHAR 1EB6 +ENCODING 7862 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 20 0 -3 +BITMAP +0880 +0700 +0000 +0600 +0700 +0F00 +0D80 +0980 +1980 +18C0 +30C0 +3FE0 +3FE0 +6060 +6030 +4030 +C038 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EB7 +ENCODING 7863 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 -3 +BITMAP +2200 +2200 +1C00 +0000 +3E00 +7F00 +C300 +0F00 +7F00 +F100 +C300 +C700 +FF00 +7D80 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1EB8 +ENCODING 7864 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 17 1 -3 +BITMAP +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EB9 +ENCODING 7865 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 -3 +BITMAP +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1EBA +ENCODING 7866 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0E00 +0300 +0600 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 1EBB +ENCODING 7867 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +1C00 +0600 +0C00 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EBC +ENCODING 7868 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +1C80 +1F80 +1300 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 1EBD +ENCODING 7869 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3A00 +3E00 +6E00 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EBE +ENCODING 7870 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0600 +0400 +0E00 +1B00 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 1EBF +ENCODING 7871 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EC0 +ENCODING 7872 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0800 +0400 +0E00 +1B00 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 1EC1 +ENCODING 7873 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +3000 +1000 +1800 +0000 +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EC2 +ENCODING 7874 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0E00 +0600 +0E00 +1B00 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 1EC3 +ENCODING 7875 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +3C00 +0400 +0C00 +0000 +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EC4 +ENCODING 7876 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +1D00 +2700 +0E00 +1B00 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 1EC5 +ENCODING 7877 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 0 +BITMAP +3200 +4E00 +0000 +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EC6 +ENCODING 7878 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 20 1 -3 +BITMAP +0E00 +1B00 +0000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFC0 +FFC0 +C000 +C000 +C000 +C000 +FFE0 +FFE0 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EC7 +ENCODING 7879 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 -3 +BITMAP +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +FF80 +FF80 +C000 +C380 +7F00 +3E00 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1EC8 +ENCODING 7880 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 18 1 0 +BITMAP +E0 +30 +70 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 1EC9 +ENCODING 7881 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 14 0 0 +BITMAP +F0 +10 +30 +00 +60 +60 +60 +60 +60 +60 +60 +60 +60 +60 +ENDCHAR +STARTCHAR 1ECA +ENCODING 7882 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 17 2 -3 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +00 +C0 +C0 +ENDCHAR +STARTCHAR 1ECB +ENCODING 7883 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 17 1 -3 +BITMAP +C0 +C0 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +00 +C0 +C0 +ENDCHAR +STARTCHAR 1ECC +ENCODING 7884 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 17 1 -3 +BITMAP +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1ECD +ENCODING 7885 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 -3 +BITMAP +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1ECE +ENCODING 7886 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0700 +0180 +0300 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1ECF +ENCODING 7887 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +1C00 +0600 +0C00 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 1ED0 +ENCODING 7888 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0300 +0200 +0700 +0D80 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1ED1 +ENCODING 7889 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 1ED2 +ENCODING 7890 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0400 +0200 +0700 +0D80 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1ED3 +ENCODING 7891 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +3000 +1000 +1800 +0000 +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 1ED4 +ENCODING 7892 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0700 +0300 +0700 +0D80 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1ED5 +ENCODING 7893 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 18 1 0 +BITMAP +3C00 +0400 +0C00 +0000 +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 1ED6 +ENCODING 7894 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 18 1 0 +BITMAP +0E40 +1380 +0700 +0D80 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1ED7 +ENCODING 7895 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 0 +BITMAP +3200 +4E00 +0000 +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +ENDCHAR +STARTCHAR 1ED8 +ENCODING 7896 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 20 1 -3 +BITMAP +0700 +0D80 +0000 +0F80 +3FE0 +7070 +6030 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1ED9 +ENCODING 7897 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 -3 +BITMAP +1800 +3400 +2600 +0000 +3C00 +7F00 +C300 +C180 +8180 +8180 +C180 +C300 +7F00 +3C00 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1EDA +ENCODING 7898 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 18 1 0 +BITMAP +0300 +0300 +0600 +0000 +0F86 +3FE6 +7072 +6034 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1EDB +ENCODING 7899 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 1 0 +BITMAP +0C00 +0C00 +0800 +0000 +3C60 +7F60 +C320 +C1C0 +81C0 +8180 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EDC +ENCODING 7900 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 18 1 0 +BITMAP +0C00 +0600 +0200 +0000 +0F86 +3FE6 +7072 +6034 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1EDD +ENCODING 7901 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 1 0 +BITMAP +3000 +1800 +0800 +0000 +3C60 +7F60 +C320 +C1C0 +81C0 +8180 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EDE +ENCODING 7902 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 18 1 0 +BITMAP +0700 +0180 +0300 +0000 +0F86 +3FE6 +7072 +6034 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1EDF +ENCODING 7903 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 1 0 +BITMAP +1C00 +0600 +0C00 +0000 +3C60 +7F60 +C320 +C1C0 +81C0 +8180 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EE0 +ENCODING 7904 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 18 1 0 +BITMAP +0EC0 +0F80 +1B80 +0000 +0F86 +3FE6 +7072 +6034 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +ENDCHAR +STARTCHAR 1EE1 +ENCODING 7905 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 14 1 0 +BITMAP +3200 +7E00 +4E00 +0000 +3C60 +7F60 +C320 +C1C0 +81C0 +8180 +C180 +C300 +7F00 +3E00 +ENDCHAR +STARTCHAR 1EE2 +ENCODING 7906 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 17 1 -3 +BITMAP +0F86 +3FE6 +7072 +6034 +C018 +C018 +C018 +C018 +C018 +C018 +6030 +7070 +3FE0 +0F80 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EE3 +ENCODING 7907 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 13 1 -3 +BITMAP +3C60 +7F60 +C320 +C1C0 +81C0 +8180 +C180 +C300 +7F00 +3E00 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1EE4 +ENCODING 7908 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 17 1 -3 +BITMAP +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EE5 +ENCODING 7909 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 13 1 -3 +BITMAP +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +00 +18 +18 +ENDCHAR +STARTCHAR 1EE6 +ENCODING 7910 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 18 1 0 +BITMAP +0E00 +0300 +0700 +0000 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 1EE7 +ENCODING 7911 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 0 +BITMAP +3C +04 +0C +00 +C1 +C1 +C1 +C1 +C1 +C1 +C3 +C3 +7D +39 +ENDCHAR +STARTCHAR 1EE8 +ENCODING 7912 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 18 1 0 +BITMAP +0300 +0600 +0400 +0000 +C064 +C064 +C064 +C064 +C078 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 1EE9 +ENCODING 7913 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +0C00 +0C00 +1800 +0000 +C160 +C160 +C120 +C120 +C1C0 +C100 +C300 +C300 +7D00 +3900 +ENDCHAR +STARTCHAR 1EEA +ENCODING 7914 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 18 1 0 +BITMAP +0C00 +0400 +0600 +0000 +C064 +C064 +C064 +C064 +C078 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 1EEB +ENCODING 7915 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +3000 +1800 +0800 +0000 +C160 +C160 +C120 +C120 +C1C0 +C100 +C300 +C300 +7D00 +3900 +ENDCHAR +STARTCHAR 1EEC +ENCODING 7916 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 18 1 0 +BITMAP +0E00 +0300 +0700 +0000 +C064 +C064 +C064 +C064 +C078 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 1EED +ENCODING 7917 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +3C00 +0400 +0C00 +0000 +C160 +C160 +C120 +C120 +C1C0 +C100 +C300 +C300 +7D00 +3900 +ENDCHAR +STARTCHAR 1EEE +ENCODING 7918 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 18 1 0 +BITMAP +0C80 +1F80 +1300 +0000 +C064 +C064 +C064 +C064 +C078 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 1EEF +ENCODING 7919 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +3200 +7E00 +6E00 +0000 +C160 +C160 +C120 +C120 +C1C0 +C100 +C300 +C300 +7D00 +3900 +ENDCHAR +STARTCHAR 1EF0 +ENCODING 7920 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 17 1 -3 +BITMAP +C064 +C064 +C064 +C064 +C078 +C060 +C060 +C060 +4060 +4060 +6060 +70E0 +3FC0 +1F80 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EF1 +ENCODING 7921 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 13 1 -3 +BITMAP +C160 +C160 +C120 +C120 +C1C0 +C100 +C300 +C300 +7D00 +3900 +0000 +1800 +1800 +ENDCHAR +STARTCHAR 1EF2 +ENCODING 7922 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +0C00 +0600 +0200 +0000 +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 1EF3 +ENCODING 7923 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 18 1 -4 +BITMAP +30 +10 +18 +00 +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 1EF4 +ENCODING 7924 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 17 0 -3 +BITMAP +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +0000 +0600 +0600 +ENDCHAR +STARTCHAR 1EF5 +ENCODING 7925 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 -4 +BITMAP +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +36 +F6 +E0 +ENDCHAR +STARTCHAR 1EF6 +ENCODING 7926 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +0F00 +0100 +0300 +0000 +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 1EF7 +ENCODING 7927 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 18 1 -4 +BITMAP +38 +04 +1C +00 +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 1EF8 +ENCODING 7928 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +0EC0 +0F80 +1B80 +0000 +E030 +6070 +3060 +30C0 +1880 +0D80 +0F00 +0600 +0600 +0600 +0600 +0600 +0600 +0600 +ENDCHAR +STARTCHAR 1EF9 +ENCODING 7929 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 18 1 -4 +BITMAP +32 +7E +4C +00 +83 +C3 +C2 +46 +66 +64 +3C +3C +18 +18 +10 +30 +F0 +E0 +ENDCHAR +STARTCHAR 200C +ENCODING 8204 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 15 0 -3 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR 200D +ENCODING 8205 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 16 -2 -2 +BITMAP +90 +E0 +D0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 200E +ENCODING 8206 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 15 0 -3 +BITMAP +20 +F0 +A0 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR 200F +ENCODING 8207 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 15 -4 -3 +BITMAP +40 +F0 +50 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 2013 +ENCODING 8211 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 2 0 4 +BITMAP +FFE0 +FFE0 +ENDCHAR +STARTCHAR 2014 +ENCODING 8212 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 19 2 0 4 +BITMAP +FFFFE0 +FFFFE0 +ENDCHAR +STARTCHAR 2015 +ENCODING 8213 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 17 2 1 4 +BITMAP +FFFF80 +FFFF80 +ENDCHAR +STARTCHAR 2017 +ENCODING 8215 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 5 0 -6 +BITMAP +FFE0 +FFE0 +0000 +FFE0 +FFE0 +ENDCHAR +STARTCHAR 2018 +ENCODING 8216 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 5 1 9 +BITMAP +40 +C0 +80 +C0 +C0 +ENDCHAR +STARTCHAR 2019 +ENCODING 8217 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 5 1 9 +BITMAP +C0 +C0 +40 +40 +80 +ENDCHAR +STARTCHAR 201A +ENCODING 8218 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 5 1 -3 +BITMAP +C0 +C0 +40 +40 +80 +ENDCHAR +STARTCHAR 201B +ENCODING 8219 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 5 1 9 +BITMAP +C0 +C0 +80 +C0 +40 +ENDCHAR +STARTCHAR 201C +ENCODING 8220 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 5 1 9 +BITMAP +50 +90 +90 +D0 +D0 +ENDCHAR +STARTCHAR 201D +ENCODING 8221 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 5 1 9 +BITMAP +D0 +D0 +50 +90 +90 +ENDCHAR +STARTCHAR 201E +ENCODING 8222 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 5 1 -3 +BITMAP +D0 +D0 +50 +90 +90 +ENDCHAR +STARTCHAR 2020 +ENCODING 8224 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 -3 +BITMAP +1800 +1800 +1800 +1800 +FF80 +FF80 +1800 +1800 +1800 +1800 +1800 +1800 +1800 +1800 +1800 +1800 +1800 +ENDCHAR +STARTCHAR 2021 +ENCODING 8225 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 17 1 -3 +BITMAP +1800 +1800 +1800 +1800 +FF80 +FF80 +1800 +1800 +1800 +1800 +1800 +FF80 +FF80 +1800 +1800 +1800 +1800 +ENDCHAR +STARTCHAR 2022 +ENCODING 8226 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 5 1 4 +BITMAP +70 +F8 +F8 +F8 +70 +ENDCHAR +STARTCHAR 2026 +ENCODING 8230 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 15 2 2 0 +BITMAP +C106 +C106 +ENDCHAR +STARTCHAR 202A +ENCODING 8234 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 14 0 -3 +BITMAP +F0 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR 202B +ENCODING 8235 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 14 -4 -3 +BITMAP +F0 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 202C +ENCODING 8236 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 16 -2 -3 +BITMAP +F0 +F0 +F0 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 202D +ENCODING 8237 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 17 -2 -3 +BITMAP +F0 +80 +80 +80 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 202E +ENCODING 8238 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 17 -2 -3 +BITMAP +F0 +10 +10 +10 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 2030 +ENCODING 8240 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 19 14 0 0 +BITMAP +78C000 +488000 +CC8000 +CD0000 +CD0000 +4B0000 +7A0000 +02E3C0 +059240 +059660 +0D1660 +099660 +099240 +10E3C0 +ENDCHAR +STARTCHAR 2032 +ENCODING 8242 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 5 1 9 +BITMAP +60 +C0 +C0 +C0 +80 +ENDCHAR +STARTCHAR 2033 +ENCODING 8243 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 5 1 9 +BITMAP +78 +58 +D8 +D0 +90 +ENDCHAR +STARTCHAR 2039 +ENCODING 8249 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 9 1 1 +BITMAP +30 +20 +60 +40 +C0 +40 +60 +20 +30 +ENDCHAR +STARTCHAR 203A +ENCODING 8250 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 9 1 1 +BITMAP +C0 +40 +60 +20 +30 +20 +60 +40 +C0 +ENDCHAR +STARTCHAR 203C +ENCODING 8252 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 6 14 2 0 +BITMAP +CC +CC +CC +CC +CC +CC +CC +8C +8C +88 +88 +00 +CC +CC +ENDCHAR +STARTCHAR 203E +ENCODING 8254 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 7 2 0 11 +BITMAP +FE +FE +ENDCHAR +STARTCHAR 2044 +ENCODING 8260 +SWIDTH 154 0 +DWIDTH 3 0 +BBX 11 14 -4 0 +BITMAP +0020 +0040 +00C0 +0180 +0100 +0200 +0600 +0400 +0800 +1800 +3000 +2000 +4000 +C000 +ENDCHAR +STARTCHAR 206A +ENCODING 8298 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 17 -2 -3 +BITMAP +F0 +40 +40 +40 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 206B +ENCODING 8299 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 17 -2 -3 +BITMAP +F0 +90 +90 +90 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 206C +ENCODING 8300 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 16 -2 -3 +BITMAP +F0 +60 +60 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 206D +ENCODING 8301 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 16 -2 -3 +BITMAP +40 +60 +60 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 206E +ENCODING 8302 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 17 -2 -3 +BITMAP +40 +60 +90 +60 +60 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 206F +ENCODING 8303 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 17 -2 -3 +BITMAP +C0 +40 +40 +40 +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR 207F +ENCODING 8319 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 7 1 5 +BITMAP +B0 +F8 +88 +88 +88 +88 +88 +ENDCHAR +STARTCHAR 20A3 +ENCODING 8355 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +3FC0 +3FC0 +2000 +2000 +2000 +2000 +3F80 +3F80 +2000 +2000 +FC00 +FC00 +2000 +2000 +ENDCHAR +STARTCHAR 20A4 +ENCODING 8356 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +1F00 +3F80 +3180 +60C0 +6000 +FE00 +FE00 +3000 +FE00 +FE00 +3000 +7C40 +FFC0 +4380 +ENDCHAR +STARTCHAR 20A7 +ENCODING 8359 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 14 0 0 +BITMAP +FE0000 +FF3000 +C3B000 +C1B000 +C1FFC0 +C3FFF0 +FFB430 +FE3700 +C037E0 +C031F0 +C03030 +C03630 +C03FF0 +C03BE0 +ENDCHAR +STARTCHAR 20AA +ENCODING 8362 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 13 10 1 0 +BITMAP +FF18 +FF98 +C098 +CC98 +CC98 +CC98 +CC98 +CC18 +CFF8 +CFF0 +ENDCHAR +STARTCHAR 20AB +ENCODING 8363 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 11 1 3 +BITMAP +0E +04 +3C +44 +44 +C4 +44 +44 +3C +00 +FE +ENDCHAR +STARTCHAR 20AC +ENCODING 8364 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 0 0 +BITMAP +0780 +1FC0 +3840 +3000 +6000 +6000 +FF80 +6000 +FF80 +6000 +3000 +3840 +1FC0 +0780 +ENDCHAR +STARTCHAR 2105 +ENCODING 8453 +SWIDTH 874 0 +DWIDTH 17 0 +BBX 15 14 1 0 +BITMAP +7820 +CC60 +8040 +80C0 +8480 +C980 +7900 +033C +0244 +0642 +04C2 +0842 +0844 +103C +ENDCHAR +STARTCHAR 2113 +ENCODING 8467 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 14 1 0 +BITMAP +30 +78 +48 +48 +50 +50 +60 +60 +C0 +C0 +40 +40 +78 +78 +ENDCHAR +STARTCHAR 2116 +ENCODING 8470 +SWIDTH 1028 0 +DWIDTH 20 0 +BBX 19 14 1 0 +BITMAP +E06000 +E06000 +F06000 +F06780 +D86FC0 +CC6C40 +CC6C60 +C66C40 +C76FC0 +C36780 +C1E000 +C1EFC0 +C0EFC0 +C06000 +ENDCHAR +STARTCHAR 2122 +ENCODING 8482 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 15 8 2 6 +BITMAP +FD86 +118E +114E +114E +1156 +1136 +1136 +1136 +ENDCHAR +STARTCHAR 2126 +ENCODING 8486 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 13 14 1 0 +BITMAP +0F80 +3FE0 +7060 +6030 +6030 +C030 +C010 +C010 +6030 +6030 +3060 +18C0 +FDF8 +FDF8 +ENDCHAR +STARTCHAR 212E +ENCODING 8494 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 10 1 0 +BITMAP +3E00 +6100 +C180 +C180 +FFC0 +C000 +C000 +C080 +6100 +3E00 +ENDCHAR +STARTCHAR 2153 +ENCODING 8531 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 1 0 +BITMAP +2010 +6030 +E020 +A040 +20C0 +2180 +2100 +023C +0664 +0C04 +0818 +1006 +3066 +603C +ENDCHAR +STARTCHAR 2154 +ENCODING 8532 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 0 0 +BITMAP +7808 +4C18 +0C10 +1820 +3060 +60C0 +FC80 +011E +0332 +0602 +040C +0802 +1822 +301E +ENDCHAR +STARTCHAR 215B +ENCODING 8539 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 14 1 0 +BITMAP +2010 +6030 +A020 +2040 +20C0 +2180 +2100 +0238 +0664 +0C64 +0838 +1044 +3044 +603C +ENDCHAR +STARTCHAR 215C +ENCODING 8540 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 0 0 +BITMAP +7808 +4C18 +0C10 +1020 +0C60 +CCC0 +7880 +011E +0332 +0632 +041C +0822 +1822 +301E +ENDCHAR +STARTCHAR 215D +ENCODING 8541 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 0 0 +BITMAP +7C08 +4018 +7810 +4C20 +0460 +CCC0 +7880 +011E +0332 +0632 +041C +0822 +1822 +301E +ENDCHAR +STARTCHAR 215E +ENCODING 8542 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 14 14 1 0 +BITMAP +F810 +1020 +3060 +2040 +6080 +4180 +4300 +0238 +0464 +0C64 +1838 +1044 +2044 +603C +ENDCHAR +STARTCHAR 2190 +ENCODING 8592 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 17 6 1 1 +BITMAP +100000 +200000 +600000 +FFFF80 +600000 +100000 +ENDCHAR +STARTCHAR 2191 +ENCODING 8593 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 16 1 -4 +BITMAP +10 +38 +7C +D2 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +ENDCHAR +STARTCHAR 2192 +ENCODING 8594 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 17 6 1 1 +BITMAP +000400 +000200 +000300 +FFFF80 +000200 +000400 +ENDCHAR +STARTCHAR 2193 +ENCODING 8595 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 16 1 -4 +BITMAP +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +90 +56 +3C +18 +10 +ENDCHAR +STARTCHAR 2194 +ENCODING 8596 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 17 7 1 1 +BITMAP +100400 +200200 +600300 +FFFF80 +600300 +100400 +100400 +ENDCHAR +STARTCHAR 2195 +ENCODING 8597 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 18 1 -4 +BITMAP +10 +18 +38 +74 +92 +10 +10 +10 +10 +10 +10 +10 +10 +90 +56 +3C +18 +10 +ENDCHAR +STARTCHAR 21A8 +ENCODING 8616 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 7 20 1 -6 +BITMAP +10 +18 +38 +74 +92 +10 +10 +10 +10 +10 +10 +10 +10 +90 +56 +3C +18 +10 +00 +FE +ENDCHAR +STARTCHAR 2202 +ENCODING 8706 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +0E +1E +33 +21 +01 +0F +3D +61 +C3 +82 +86 +CC +FC +70 +ENDCHAR +STARTCHAR 2206 +ENCODING 8710 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 12 0 1 +BITMAP +0600 +0600 +0A00 +0B00 +1100 +1180 +2180 +20C0 +20C0 +4040 +4060 +FFE0 +ENDCHAR +STARTCHAR 220F +ENCODING 8719 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 13 18 1 -4 +BITMAP +FFF8 +FFF8 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +C018 +ENDCHAR +STARTCHAR 2211 +ENCODING 8721 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 18 1 -4 +BITMAP +FFF0 +FFF0 +6000 +3000 +3800 +1800 +0C00 +0600 +0300 +0700 +0600 +0C00 +1800 +3000 +6000 +6000 +FFF0 +FFF0 +ENDCHAR +STARTCHAR 2212 +ENCODING 8722 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 2 1 6 +BITMAP +FF80 +FF80 +ENDCHAR +STARTCHAR 2215 +ENCODING 8725 +SWIDTH 154 0 +DWIDTH 3 0 +BBX 11 14 -4 0 +BITMAP +0020 +0040 +00C0 +0180 +0100 +0200 +0600 +0400 +0800 +1800 +3000 +2000 +4000 +C000 +ENDCHAR +STARTCHAR 2219 +ENCODING 8729 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 2 2 6 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR 221A +ENCODING 8730 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 18 1 -1 +BITMAP +0080 +0080 +0080 +0080 +0080 +0080 +0100 +2100 +E100 +3100 +1900 +1900 +0E00 +0E00 +0600 +0600 +0200 +0200 +ENDCHAR +STARTCHAR 221E +ENCODING 8734 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 6 1 4 +BITMAP +71C0 +7BE0 +CE20 +CE20 +7BE0 +71C0 +ENDCHAR +STARTCHAR 221F +ENCODING 8735 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 12 12 3 0 +BITMAP +8000 +8000 +8000 +8000 +8000 +8000 +8000 +8000 +8000 +8000 +8000 +FFF0 +ENDCHAR +STARTCHAR 2229 +ENCODING 8745 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 14 1 0 +BITMAP +0F00 +3FC0 +70C0 +6060 +4020 +4020 +C020 +C020 +C020 +C020 +C020 +C020 +C020 +C020 +ENDCHAR +STARTCHAR 222B +ENCODING 8747 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 19 0 -2 +BITMAP +18 +38 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +20 +E0 +C0 +ENDCHAR +STARTCHAR 2248 +ENCODING 8776 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 7 0 3 +BITMAP +7C40 +FFC0 +8780 +0000 +7C40 +FFC0 +8780 +ENDCHAR +STARTCHAR 2260 +ENCODING 8800 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 14 1 0 +BITMAP +0300 +0200 +0200 +0400 +FF80 +FF80 +0800 +1800 +FF80 +FF80 +2000 +2000 +4000 +4000 +ENDCHAR +STARTCHAR 2261 +ENCODING 8801 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 2 +BITMAP +FF80 +FF80 +0000 +0000 +FF80 +FF80 +0000 +0000 +FF80 +FF80 +ENDCHAR +STARTCHAR 2264 +ENCODING 8804 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +0080 +0780 +1E00 +7000 +C000 +7000 +1E00 +0780 +0080 +0000 +FF80 +FF80 +ENDCHAR +STARTCHAR 2265 +ENCODING 8805 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 12 1 0 +BITMAP +8000 +E000 +7800 +0F00 +0180 +0F00 +7800 +E000 +8000 +0000 +FF80 +FF80 +ENDCHAR +STARTCHAR 2302 +ENCODING 8962 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 1 +BITMAP +0C00 +1200 +2100 +4100 +8080 +8080 +8080 +8080 +8080 +FF80 +ENDCHAR +STARTCHAR 2310 +ENCODING 8976 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 6 1 4 +BITMAP +FF80 +FF80 +C000 +C000 +C000 +C000 +ENDCHAR +STARTCHAR 2320 +ENCODING 8992 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 4 21 5 -5 +BITMAP +70 +10 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR 2321 +ENCODING 8993 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 4 21 2 -5 +BITMAP +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +D0 +60 +ENDCHAR +STARTCHAR 2500 +ENCODING 9472 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 2 0 5 +BITMAP +FFFC +FFFC +ENDCHAR +STARTCHAR 2502 +ENCODING 9474 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 2 23 4 -6 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 250C +ENCODING 9484 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 13 6 -6 +BITMAP +FF +FF +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 2510 +ENCODING 9488 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 13 0 -6 +BITMAP +FF +FF +03 +03 +03 +03 +03 +03 +03 +03 +03 +03 +03 +ENDCHAR +STARTCHAR 2514 +ENCODING 9492 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 12 6 5 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +FF +FF +ENDCHAR +STARTCHAR 2518 +ENCODING 9496 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 12 0 5 +BITMAP +03 +03 +03 +03 +03 +03 +03 +03 +03 +03 +FF +FF +ENDCHAR +STARTCHAR 251C +ENCODING 9500 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 23 6 -6 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +FF +FF +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 2524 +ENCODING 9508 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 23 0 -6 +BITMAP +03 +03 +03 +03 +03 +03 +03 +03 +03 +03 +FF +FF +03 +03 +03 +03 +03 +03 +03 +03 +03 +03 +03 +ENDCHAR +STARTCHAR 252C +ENCODING 9516 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 13 0 -6 +BITMAP +FFFC +FFFC +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 2534 +ENCODING 9524 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 12 0 5 +BITMAP +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +FFFC +FFFC +ENDCHAR +STARTCHAR 253C +ENCODING 9532 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 23 0 -6 +BITMAP +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +FFFC +FFFC +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 2550 +ENCODING 9552 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 5 0 3 +BITMAP +FFFC +0000 +0000 +FFFC +FFFC +ENDCHAR +STARTCHAR 2551 +ENCODING 9553 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 5 23 4 -6 +BITMAP +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +C8 +ENDCHAR +STARTCHAR 2552 +ENCODING 9554 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 14 6 -6 +BITMAP +FF +C0 +C0 +FF +FF +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 2553 +ENCODING 9555 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 10 13 4 -6 +BITMAP +FFC0 +FFC0 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +ENDCHAR +STARTCHAR 2554 +ENCODING 9556 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 10 14 4 -6 +BITMAP +FFC0 +C000 +C000 +CFC0 +CFC0 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +ENDCHAR +STARTCHAR 2555 +ENCODING 9557 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 14 0 -6 +BITMAP +FF +03 +03 +FF +FF +03 +03 +03 +03 +03 +03 +03 +03 +03 +ENDCHAR +STARTCHAR 2556 +ENCODING 9558 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 9 13 0 -6 +BITMAP +FF80 +FF80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +ENDCHAR +STARTCHAR 2557 +ENCODING 9559 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 9 14 0 -6 +BITMAP +FF80 +0080 +0080 +FC80 +FC80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +ENDCHAR +STARTCHAR 2558 +ENCODING 9560 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 14 6 3 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +FF +C0 +C0 +FF +FF +ENDCHAR +STARTCHAR 2559 +ENCODING 9561 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 10 12 4 5 +BITMAP +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +FFC0 +FFC0 +ENDCHAR +STARTCHAR 255A +ENCODING 9562 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 10 14 4 3 +BITMAP +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +CFC0 +C000 +C000 +FFC0 +FFC0 +ENDCHAR +STARTCHAR 255B +ENCODING 9563 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 14 0 3 +BITMAP +03 +03 +03 +03 +03 +03 +03 +03 +03 +FF +03 +03 +FF +FF +ENDCHAR +STARTCHAR 255C +ENCODING 9564 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 9 12 0 5 +BITMAP +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +FF80 +FF80 +ENDCHAR +STARTCHAR 255D +ENCODING 9565 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 9 14 0 3 +BITMAP +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +FC80 +0080 +0080 +FF80 +FF80 +ENDCHAR +STARTCHAR 255E +ENCODING 9566 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 23 6 -6 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +FF +C0 +C0 +FF +FF +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR 255F +ENCODING 9567 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 10 23 4 -6 +BITMAP +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +CFC0 +CFC0 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +ENDCHAR +STARTCHAR 2560 +ENCODING 9568 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 10 23 4 -6 +BITMAP +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +CFC0 +C000 +C000 +CFC0 +CFC0 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +C800 +ENDCHAR +STARTCHAR 2561 +ENCODING 9569 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 8 23 0 -6 +BITMAP +03 +03 +03 +03 +03 +03 +03 +03 +03 +FF +03 +03 +FF +FF +03 +03 +03 +03 +03 +03 +03 +03 +03 +ENDCHAR +STARTCHAR 2562 +ENCODING 9570 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 9 23 0 -6 +BITMAP +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +FC80 +FC80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +ENDCHAR +STARTCHAR 2563 +ENCODING 9571 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 9 23 0 -6 +BITMAP +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +FC80 +0080 +0080 +FC80 +FC80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +ENDCHAR +STARTCHAR 2564 +ENCODING 9572 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 14 0 -6 +BITMAP +FFFC +0000 +0000 +FFFC +FFFC +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 2565 +ENCODING 9573 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 13 0 -6 +BITMAP +FFFC +FFFC +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +ENDCHAR +STARTCHAR 2566 +ENCODING 9574 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 14 0 -6 +BITMAP +FFFC +0000 +0000 +FCFC +FCFC +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +ENDCHAR +STARTCHAR 2567 +ENCODING 9575 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 14 0 3 +BITMAP +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +FFFC +0000 +0000 +FFFC +FFFC +ENDCHAR +STARTCHAR 2568 +ENCODING 9576 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 12 0 5 +BITMAP +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +FFFC +FFFC +ENDCHAR +STARTCHAR 2569 +ENCODING 9577 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 14 0 3 +BITMAP +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +FCFC +0000 +0000 +FFFC +FFFC +ENDCHAR +STARTCHAR 256A +ENCODING 9578 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 23 0 -6 +BITMAP +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +FFFC +0300 +0300 +FFFC +FFFC +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR 256B +ENCODING 9579 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 23 0 -6 +BITMAP +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +FFFC +FFFC +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +ENDCHAR +STARTCHAR 256C +ENCODING 9580 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 23 0 -6 +BITMAP +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +FCFC +0000 +0000 +FCFC +FCFC +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +0C80 +ENDCHAR +STARTCHAR 2580 +ENCODING 9600 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 11 0 6 +BITMAP +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +ENDCHAR +STARTCHAR 2584 +ENCODING 9604 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 12 0 -6 +BITMAP +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +ENDCHAR +STARTCHAR 2588 +ENCODING 9608 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 23 0 -6 +BITMAP +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +FFFC +ENDCHAR +STARTCHAR 258C +ENCODING 9612 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 7 23 0 -6 +BITMAP +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +ENDCHAR +STARTCHAR 2590 +ENCODING 9616 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 7 23 7 -6 +BITMAP +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +FE +ENDCHAR +STARTCHAR 2591 +ENCODING 9617 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 13 22 1 -5 +BITMAP +8440 +0000 +2118 +0000 +8440 +0000 +0000 +2118 +0000 +8440 +0000 +2118 +0000 +0000 +8440 +0000 +2118 +0000 +8440 +0000 +0000 +2118 +ENDCHAR +STARTCHAR 2592 +ENCODING 9618 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 14 22 0 -5 +BITMAP +52A4 +0000 +AD58 +0000 +52A4 +0000 +0000 +AD58 +0000 +52A4 +0000 +AD58 +0000 +0000 +52A4 +0000 +AD58 +0000 +52A4 +0000 +0000 +AD58 +ENDCHAR +STARTCHAR 2593 +ENCODING 9619 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 14 23 0 -6 +BITMAP +5AB4 +FFFC +A548 +FFFC +5AB4 +FFFC +FFFC +A548 +FFFC +5AB4 +FFFC +A548 +FFFC +FFFC +5AB4 +FFFC +A548 +FFFC +5AB4 +FFFC +FFFC +A548 +FFFC +ENDCHAR +STARTCHAR 25A0 +ENCODING 9632 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 9 1 0 +BITMAP +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +FF80 +ENDCHAR +STARTCHAR 25A1 +ENCODING 9633 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 9 1 0 +BITMAP +FF80 +8080 +8080 +8080 +8080 +8080 +8080 +8080 +FF80 +ENDCHAR +STARTCHAR 25AA +ENCODING 9642 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 4 1 4 +BITMAP +F8 +F8 +F8 +F8 +ENDCHAR +STARTCHAR 25AB +ENCODING 9643 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 4 1 4 +BITMAP +88 +88 +88 +F8 +ENDCHAR +STARTCHAR 25AC +ENCODING 9644 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 19 4 0 3 +BITMAP +FFFFE0 +FFFFE0 +FFFFE0 +FFFFE0 +ENDCHAR +STARTCHAR 25B2 +ENCODING 9650 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 13 13 3 0 +BITMAP +0200 +0200 +0700 +0700 +0F80 +0F80 +1FC0 +1FC0 +3FE0 +3FE0 +7FF0 +7FF0 +FFF8 +ENDCHAR +STARTCHAR 25BA +ENCODING 9658 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 13 13 3 0 +BITMAP +8000 +E000 +F800 +FE00 +FF80 +FFE0 +FFF8 +FFE0 +FF80 +FE00 +F800 +E000 +8000 +ENDCHAR +STARTCHAR 25BC +ENCODING 9660 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 13 13 3 0 +BITMAP +FFF8 +7FF0 +7FF0 +3FE0 +3FE0 +1FC0 +1FC0 +0F80 +0F80 +0700 +0700 +0200 +0200 +ENDCHAR +STARTCHAR 25C4 +ENCODING 9668 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 13 13 3 0 +BITMAP +0008 +0038 +00F8 +03F8 +0FF8 +3FF8 +FFF8 +3FF8 +0FF8 +03F8 +00F8 +0038 +0008 +ENDCHAR +STARTCHAR 25CA +ENCODING 9674 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 14 1 0 +BITMAP +10 +28 +28 +44 +42 +82 +81 +81 +82 +42 +44 +28 +28 +10 +ENDCHAR +STARTCHAR 25CB +ENCODING 9675 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 8 2 1 +BITMAP +44 +82 +81 +01 +01 +80 +42 +38 +ENDCHAR +STARTCHAR 25CF +ENCODING 9679 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 8 2 1 +BITMAP +7C +FE +FF +FF +FF +FE +7E +38 +ENDCHAR +STARTCHAR 25D8 +ENCODING 9688 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 9 1 0 +BITMAP +FF80 +FF80 +FF80 +E380 +E180 +E380 +FF80 +FF80 +FF80 +ENDCHAR +STARTCHAR 25D9 +ENCODING 9689 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 11 0 0 +BITMAP +FFE0 +FFE0 +E6E0 +DF60 +DFA0 +FFA0 +FFA0 +DFE0 +EF60 +F1E0 +FFE0 +ENDCHAR +STARTCHAR 25E6 +ENCODING 9702 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 5 5 1 4 +BITMAP +20 +90 +88 +88 +70 +ENDCHAR +STARTCHAR 263A +ENCODING 9786 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 12 12 4 -1 +BITMAP +0E00 +3080 +4040 +8020 +91A0 +9190 +8010 +8000 +9120 +4E20 +20C0 +1F00 +ENDCHAR +STARTCHAR 263B +ENCODING 9787 +SWIDTH 1028 0 +DWIDTH 20 0 +BBX 12 12 4 -1 +BITMAP +0F00 +3FC0 +7FE0 +7FE0 +EF70 +EF70 +FFF0 +FFF0 +7FE0 +70E0 +3FC0 +1F80 +ENDCHAR +STARTCHAR 263C +ENCODING 9788 +SWIDTH 874 0 +DWIDTH 17 0 +BBX 17 17 0 -2 +BITMAP +008000 +008000 +208200 +11E400 +0C1800 +080800 +000400 +100400 +F00780 +100400 +000400 +080800 +0C1800 +11E400 +208200 +008000 +008000 +ENDCHAR +STARTCHAR 2640 +ENCODING 9792 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 10 14 2 -4 +BITMAP +1E00 +0080 +0000 +8040 +8040 +8040 +0040 +4000 +2000 +0E00 +0000 +0000 +0000 +7FC0 +ENDCHAR +STARTCHAR 2642 +ENCODING 9794 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 12 17 1 -2 +BITMAP +0060 +0160 +0440 +0000 +0090 +0010 +0100 +0000 +2300 +4080 +8000 +8040 +8040 +8040 +8000 +4080 +2100 +ENDCHAR +STARTCHAR 2660 +ENCODING 9824 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 1 1 +BITMAP +1800 +3C00 +7E00 +FF00 +FF00 +FF80 +E700 +0000 +1800 +3E00 +ENDCHAR +STARTCHAR 2663 +ENCODING 9827 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 11 1 0 +BITMAP +1E00 +1F00 +1F00 +7EC0 +FFE0 +FFE0 +FFE0 +F3C0 +0400 +0C00 +3F00 +ENDCHAR +STARTCHAR 2665 +ENCODING 9829 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 11 1 0 +BITMAP +F780 +FFC0 +FFC0 +FF80 +7F80 +7F00 +3E00 +1E00 +1C00 +0800 +0800 +ENDCHAR +STARTCHAR 2666 +ENCODING 9830 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 11 1 0 +BITMAP +10 +18 +3C +7E +FE +FF +FE +7C +3C +18 +10 +ENDCHAR +STARTCHAR 266A +ENCODING 9834 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 13 0 0 +BITMAP +0600 +0780 +0380 +0080 +0080 +0000 +0000 +0000 +0000 +7800 +F800 +F800 +7800 +ENDCHAR +STARTCHAR 266B +ENCODING 9835 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 11 15 1 -1 +BITMAP +0060 +03E0 +0FE0 +0E20 +0820 +0820 +0820 +0820 +0820 +09E0 +0BE0 +FBE0 +F9E0 +F800 +F000 +ENDCHAR +STARTCHAR E801 +ENCODING 59393 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 12 -1 0 +BITMAP +C0 +00 +30 +30 +30 +30 +30 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR E802 +ENCODING 59394 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 0 -4 +BITMAP +FC +FE +07 +03 +01 +01 +01 +31 +01 +31 +01 +01 +01 +01 +ENDCHAR +STARTCHAR E803 +ENCODING 59395 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 0 -4 +BITMAP +FC +FE +07 +03 +01 +01 +01 +79 +11 +11 +01 +01 +01 +01 +ENDCHAR +STARTCHAR E804 +ENCODING 59396 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 10 14 -2 0 +BITMAP +1000 +D000 +1000 +1000 +1FC0 +1FC0 +00C0 +00C0 +0080 +0180 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR E805 +ENCODING 59397 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 10 14 -2 0 +BITMAP +1000 +D000 +1000 +1000 +1FC0 +1FC0 +00C0 +0CC0 +0080 +0180 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR E818 +ENCODING 59416 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 7 1 12 +BITMAP +60 +80 +60 +80 +40 +60 +80 +ENDCHAR +STARTCHAR E83A +ENCODING 59450 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 13 2 -1 3 +BITMAP +FFF8 +FFF8 +ENDCHAR +STARTCHAR F001 +ENCODING 61441 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 0 0 +BITMAP +1D +3D +30 +20 +F9 +F9 +21 +21 +21 +21 +21 +21 +21 +21 +ENDCHAR +STARTCHAR F002 +ENCODING 61442 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 0 0 +BITMAP +1D +3D +31 +21 +F9 +F9 +21 +21 +21 +21 +21 +21 +21 +21 +ENDCHAR +STARTCHAR F004 +ENCODING 61444 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 2 4 2 -5 +BITMAP +C0 +C0 +40 +80 +ENDCHAR +STARTCHAR F005 +ENCODING 61445 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 3 1 -4 +BITMAP +70 +30 +E0 +ENDCHAR +STARTCHAR F006 +ENCODING 61446 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 2 -4 16 +BITMAP +60 +C0 +ENDCHAR +STARTCHAR F007 +ENCODING 61447 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -7 16 +BITMAP +C0 +80 +ENDCHAR +STARTCHAR F008 +ENCODING 61448 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -3 11 +BITMAP +60 +40 +C0 +ENDCHAR +STARTCHAR F009 +ENCODING 61449 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -6 15 +BITMAP +60 +40 +C0 +ENDCHAR +STARTCHAR F00A +ENCODING 61450 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 21 0 -4 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +80 +00 +00 +00 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR F00B +ENCODING 61451 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 21 -2 -4 +BITMAP +F0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +F0 +ENDCHAR +STARTCHAR F00C +ENCODING 61452 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 21 0 -4 +BITMAP +80 +C0 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +ENDCHAR +STARTCHAR F00D +ENCODING 61453 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 21 -2 -4 +BITMAP +40 +C0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR F00E +ENCODING 61454 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 21 0 -4 +BITMAP +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +80 +C0 +ENDCHAR +STARTCHAR F00F +ENCODING 61455 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 3 -8 11 +BITMAP +C0 +60 +20 +ENDCHAR +STARTCHAR F010 +ENCODING 61456 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 2 -5 16 +BITMAP +F0 +30 +ENDCHAR +STARTCHAR F011 +ENCODING 61457 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 3 2 -8 16 +BITMAP +E0 +60 +ENDCHAR +STARTCHAR F012 +ENCODING 61458 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -4 11 +BITMAP +E0 +30 +70 +ENDCHAR +STARTCHAR F013 +ENCODING 61459 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -7 15 +BITMAP +E0 +30 +70 +ENDCHAR +STARTCHAR F014 +ENCODING 61460 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 4 3 -7 11 +BITMAP +E0 +30 +70 +ENDCHAR +STARTCHAR F015 +ENCODING 61461 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 7 2 -10 16 +BITMAP +72 +9C +ENDCHAR +STARTCHAR F016 +ENCODING 61462 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -10 15 +BITMAP +64 +9C +ENDCHAR +STARTCHAR F017 +ENCODING 61463 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -12 15 +BITMAP +64 +9C +ENDCHAR +STARTCHAR F018 +ENCODING 61464 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 7 2 -13 15 +BITMAP +76 +DC +ENDCHAR +STARTCHAR F019 +ENCODING 61465 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -8 11 +BITMAP +EC +98 +ENDCHAR +STARTCHAR F01A +ENCODING 61466 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -10 11 +BITMAP +E4 +98 +ENDCHAR +STARTCHAR F01B +ENCODING 61467 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -11 11 +BITMAP +64 +9C +ENDCHAR +STARTCHAR F01C +ENCODING 61468 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -6 15 +BITMAP +74 +DC +ENDCHAR +STARTCHAR F01D +ENCODING 61469 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -5 11 +BITMAP +E4 +98 +ENDCHAR +STARTCHAR F01E +ENCODING 61470 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -7 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F01F +ENCODING 61471 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -8 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F020 +ENCODING 61472 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -10 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F021 +ENCODING 61473 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -8 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F022 +ENCODING 61474 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 1 2 -10 -3 +BITMAP +80 +80 +ENDCHAR +STARTCHAR F023 +ENCODING 61475 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -6 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F024 +ENCODING 61476 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -6 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F025 +ENCODING 61477 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -6 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F026 +ENCODING 61478 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -8 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F027 +ENCODING 61479 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -7 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F028 +ENCODING 61480 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -9 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F029 +ENCODING 61481 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -4 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F02A +ENCODING 61482 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -3 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F02B +ENCODING 61483 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -7 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F02C +ENCODING 61484 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 2 2 -2 -3 +BITMAP +C0 +C0 +ENDCHAR +STARTCHAR F02D +ENCODING 61485 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -9 16 +BITMAP +E4 +98 +ENDCHAR +STARTCHAR F02E +ENCODING 61486 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -9 15 +BITMAP +E4 +98 +ENDCHAR +STARTCHAR F02F +ENCODING 61487 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -10 16 +BITMAP +E4 +98 +ENDCHAR +STARTCHAR F030 +ENCODING 61488 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -10 15 +BITMAP +EC +98 +ENDCHAR +STARTCHAR F031 +ENCODING 61489 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 10 1 0 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR FB01 +ENCODING 64257 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 0 0 +BITMAP +1D +3D +30 +20 +F9 +F9 +21 +21 +21 +21 +21 +21 +21 +21 +ENDCHAR +STARTCHAR FB02 +ENCODING 64258 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 0 0 +BITMAP +1D +3D +31 +21 +F9 +F9 +21 +21 +21 +21 +21 +21 +21 +21 +ENDCHAR +STARTCHAR FB1D +ENCODING 64285 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 8 1 2 +BITMAP +C0 +C0 +C0 +C0 +C0 +00 +00 +40 +ENDCHAR +STARTCHAR FB1E +ENCODING 64286 +SWIDTH 0 0 +DWIDTH 0 0 +BBX 6 2 -3 12 +BITMAP +CC +78 +ENDCHAR +STARTCHAR FB1F +ENCODING 64287 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 7 1 3 +BITMAP +C6 +C6 +C6 +C6 +C6 +00 +FE +ENDCHAR +STARTCHAR FB20 +ENCODING 64288 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 0 0 +BITMAP +6180 +2180 +3180 +3180 +3180 +3180 +1300 +1B00 +FE00 +FC00 +ENDCHAR +STARTCHAR FB2A +ENCODING 64298 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 13 1 0 +BITMAP +0020 +0000 +0000 +C460 +C460 +C460 +CC60 +CC60 +F860 +40C0 +61C0 +3F80 +1F00 +ENDCHAR +STARTCHAR FB2B +ENCODING 64299 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 13 1 0 +BITMAP +C000 +0000 +0000 +C460 +C460 +C460 +CC60 +CC60 +F860 +40C0 +61C0 +3F80 +1F00 +ENDCHAR +STARTCHAR FB2C +ENCODING 64300 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 13 1 0 +BITMAP +0020 +0000 +0000 +C460 +C460 +C460 +CC60 +CC60 +FB60 +40C0 +61C0 +3F80 +1F00 +ENDCHAR +STARTCHAR FB2D +ENCODING 64301 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 13 1 0 +BITMAP +C000 +0000 +0000 +C460 +C460 +C460 +CC60 +CC60 +FB60 +40C0 +61C0 +3F80 +1F00 +ENDCHAR +STARTCHAR FB2E +ENCODING 64302 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 13 1 -3 +BITMAP +E180 +6100 +3300 +3B00 +7F00 +4E00 +C600 +C600 +C300 +C180 +0000 +0000 +3C00 +ENDCHAR +STARTCHAR FB2F +ENCODING 64303 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 15 1 -5 +BITMAP +E180 +6100 +3300 +3B00 +7F00 +4E00 +C600 +C600 +C300 +C180 +0000 +0000 +3C00 +0800 +0800 +ENDCHAR +STARTCHAR FB30 +ENCODING 64304 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +E180 +6100 +3300 +3B00 +7F00 +4E00 +C600 +C600 +DB00 +C180 +ENDCHAR +STARTCHAR FB31 +ENCODING 64305 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 10 0 0 +BITMAP +7C00 +7E00 +0700 +0300 +3100 +0100 +0100 +0100 +FFC0 +FFC0 +ENDCHAR +STARTCHAR FB32 +ENCODING 64306 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 7 10 0 0 +BITMAP +78 +7C +0C +3C +0C +1C +3C +64 +66 +C6 +ENDCHAR +STARTCHAR FB33 +ENCODING 64307 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 0 0 +BITMAP +FF80 +FF80 +0300 +1B00 +0300 +0300 +0300 +0300 +0300 +0300 +ENDCHAR +STARTCHAR FB34 +ENCODING 64308 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +FE00 +7F00 +0380 +0180 +C980 +C180 +C180 +C180 +C180 +C180 +ENDCHAR +STARTCHAR FB35 +ENCODING 64309 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 10 0 0 +BITMAP +30 +30 +30 +30 +F0 +30 +30 +30 +30 +30 +ENDCHAR +STARTCHAR FB36 +ENCODING 64310 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 10 0 0 +BITMAP +3F +3F +0C +D8 +18 +18 +18 +18 +18 +18 +ENDCHAR +STARTCHAR FB38 +ENCODING 64312 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +C700 +CF80 +C980 +C180 +CD80 +C180 +C180 +6380 +7F00 +1E00 +ENDCHAR +STARTCHAR FB39 +ENCODING 64313 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 5 0 5 +BITMAP +30 +30 +F0 +30 +30 +ENDCHAR +STARTCHAR FB3A +ENCODING 64314 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 0 -4 +BITMAP +FC +FE +07 +03 +11 +01 +01 +01 +01 +01 +01 +01 +01 +01 +ENDCHAR +STARTCHAR FB3B +ENCODING 64315 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 10 1 0 +BITMAP +F0 +FC +0C +06 +66 +06 +06 +0C +FC +F0 +ENDCHAR +STARTCHAR FB3C +ENCODING 64316 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 14 1 0 +BITMAP +80 +80 +80 +80 +FE +FE +06 +26 +04 +0C +18 +18 +18 +18 +ENDCHAR +STARTCHAR FB3E +ENCODING 64318 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +CE00 +DF00 +7180 +6180 +6D80 +6180 +4180 +4180 +CF80 +CF80 +ENDCHAR +STARTCHAR FB40 +ENCODING 64320 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 4 10 1 0 +BITMAP +E0 +F0 +30 +10 +90 +10 +10 +10 +F0 +F0 +ENDCHAR +STARTCHAR FB41 +ENCODING 64321 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +3E00 +7F00 +E380 +C180 +C980 +C180 +C180 +E380 +7F00 +3E00 +ENDCHAR +STARTCHAR FB43 +ENCODING 64323 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 8 14 1 -4 +BITMAP +FC +FF +C3 +C3 +C1 +CD +61 +01 +01 +01 +01 +01 +01 +01 +ENDCHAR +STARTCHAR FB44 +ENCODING 64324 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 10 1 0 +BITMAP +FC00 +FE00 +C700 +C300 +C180 +6D80 +0300 +8700 +FE00 +7C00 +ENDCHAR +STARTCHAR FB46 +ENCODING 64326 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 10 0 0 +BITMAP +C3 +63 +33 +33 +7E +0C +04 +06 +7F +7F +ENDCHAR +STARTCHAR FB47 +ENCODING 64327 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 14 1 -4 +BITMAP +FF +FF +01 +19 +43 +43 +46 +44 +44 +44 +40 +40 +40 +40 +ENDCHAR +STARTCHAR FB48 +ENCODING 64328 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 8 10 0 0 +BITMAP +FC +FE +07 +03 +11 +01 +01 +01 +01 +01 +ENDCHAR +STARTCHAR FB49 +ENCODING 64329 +SWIDTH 668 0 +DWIDTH 13 0 +BBX 11 10 1 0 +BITMAP +C460 +C460 +C460 +CC60 +CC60 +FB60 +40C0 +61C0 +3F80 +1F00 +ENDCHAR +STARTCHAR FB4A +ENCODING 64330 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 10 0 0 +BITMAP +7F80 +7FC0 +18E0 +1860 +1B60 +1860 +1860 +1860 +7860 +F060 +ENDCHAR +STARTCHAR FB4B +ENCODING 64331 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 2 13 1 0 +BITMAP +40 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR +STARTCHAR FB4C +ENCODING 64332 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 13 0 0 +BITMAP +1C00 +0000 +0000 +7C00 +7E00 +0700 +0300 +0100 +0100 +0100 +0100 +FFC0 +FFC0 +ENDCHAR +STARTCHAR FB4D +ENCODING 64333 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 7 13 1 0 +BITMAP +78 +00 +00 +F0 +FC +0C +06 +06 +06 +06 +0C +FC +F0 +ENDCHAR +STARTCHAR FB4E +ENCODING 64334 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 13 1 0 +BITMAP +3C00 +0000 +0000 +FC00 +FE00 +C700 +C300 +C180 +7180 +0300 +8700 +FE00 +7C00 +ENDCHAR +STARTCHAR FB4F +ENCODING 64335 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +8000 +8000 +8000 +8000 +E180 +E180 +3180 +3B00 +7F00 +6E00 +4600 +4700 +C300 +C180 +ENDCHAR +STARTCHAR FB50 +ENCODING 64336 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 15 0 2 +BITMAP +30 +F0 +80 +00 +40 +60 +20 +20 +20 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR FB51 +ENCODING 64337 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 5 14 -1 3 +BITMAP +30 +F0 +00 +00 +60 +20 +20 +20 +20 +20 +20 +20 +18 +18 +ENDCHAR +STARTCHAR FB52 +ENCODING 64338 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 -2 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0200 +0200 +0200 +0200 +ENDCHAR +STARTCHAR FB53 +ENCODING 64339 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 -2 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0200 +0200 +0200 +0200 +ENDCHAR +STARTCHAR FB54 +ENCODING 64340 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 -2 +BITMAP +08 +08 +0C +04 +FC +FC +00 +30 +30 +10 +10 +ENDCHAR +STARTCHAR FB55 +ENCODING 64341 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 -2 +BITMAP +08 +08 +0C +04 +FC +FC +00 +30 +30 +10 +10 +ENDCHAR +STARTCHAR FB56 +ENCODING 64342 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 -2 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0100 +0500 +0700 +0300 +ENDCHAR +STARTCHAR FB57 +ENCODING 64343 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 -2 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0100 +0500 +0700 +0300 +ENDCHAR +STARTCHAR FB58 +ENCODING 64344 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 -2 +BITMAP +08 +08 +0C +04 +FC +FC +00 +08 +28 +38 +18 +ENDCHAR +STARTCHAR FB59 +ENCODING 64345 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 -2 +BITMAP +08 +08 +0C +04 +FC +FC +00 +08 +28 +38 +18 +ENDCHAR +STARTCHAR FB5A +ENCODING 64346 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 12 1 -3 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0300 +0D00 +0D00 +0500 +0400 +ENDCHAR +STARTCHAR FB5B +ENCODING 64347 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 12 1 -3 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0300 +0D00 +0D00 +0500 +0400 +ENDCHAR +STARTCHAR FB5C +ENCODING 64348 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 12 -1 -3 +BITMAP +08 +08 +0C +04 +FC +FC +00 +18 +68 +68 +28 +20 +ENDCHAR +STARTCHAR FB5D +ENCODING 64349 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 12 -1 -3 +BITMAP +08 +08 +0C +04 +FC +FC +00 +18 +68 +68 +28 +20 +ENDCHAR +STARTCHAR FB5E +ENCODING 64350 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 3 +BITMAP +0400 +0400 +0600 +0200 +0000 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FB5F +ENCODING 64351 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 3 +BITMAP +0400 +0400 +0600 +0200 +0000 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FB60 +ENCODING 64352 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +20 +20 +30 +10 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FB61 +ENCODING 64353 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +20 +20 +30 +10 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FB62 +ENCODING 64354 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 3 +BITMAP +0200 +0A00 +0900 +0D00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FB63 +ENCODING 64355 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 11 1 3 +BITMAP +0200 +0A00 +0900 +0D00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FB64 +ENCODING 64356 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +10 +50 +48 +68 +60 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FB65 +ENCODING 64357 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +10 +50 +48 +68 +60 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FB66 +ENCODING 64358 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 13 1 3 +BITMAP +0400 +0800 +0400 +0780 +0480 +1F80 +0000 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FB67 +ENCODING 64359 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 13 1 3 +BITMAP +0400 +0800 +0400 +0780 +0480 +1F80 +0000 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FB68 +ENCODING 64360 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 13 -1 3 +BITMAP +20 +20 +20 +2C +34 +7C +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FB69 +ENCODING 64361 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 13 -1 3 +BITMAP +20 +20 +20 +2C +34 +7C +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FB6A +ENCODING 64362 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 11 0 3 +BITMAP +0010 +001C +0014 +0010 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR FB6B +ENCODING 64363 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 11 0 3 +BITMAP +0010 +001C +0014 +0010 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR FB6C +ENCODING 64364 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 12 -1 3 +BITMAP +20 +38 +78 +60 +18 +38 +2C +3C +3C +04 +FC +FC +ENDCHAR +STARTCHAR FB6D +ENCODING 64365 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 12 -1 3 +BITMAP +20 +28 +68 +20 +18 +1C +24 +24 +1C +0C +FC +FC +ENDCHAR +STARTCHAR FB6E +ENCODING 64366 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 12 0 3 +BITMAP +0004 +0014 +0014 +0014 +0010 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR FB6F +ENCODING 64367 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 12 0 3 +BITMAP +0004 +0014 +0014 +0014 +0010 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR FB70 +ENCODING 64368 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 14 -1 3 +BITMAP +10 +50 +48 +68 +60 +00 +18 +38 +2C +3C +3C +04 +FC +FC +ENDCHAR +STARTCHAR FB71 +ENCODING 64369 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 14 -1 3 +BITMAP +10 +50 +48 +68 +60 +00 +18 +1C +24 +24 +1C +0C +FC +FC +ENDCHAR +STARTCHAR FB72 +ENCODING 64370 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4000 +8400 +8400 +8600 +4600 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FB73 +ENCODING 64371 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 12 0 -4 +BITMAP +3F80 +7F80 +0E00 +31C0 +41C0 +8800 +8800 +8C00 +4C00 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FB74 +ENCODING 64372 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 11 -1 -2 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0400 +0400 +0600 +0600 +ENDCHAR +STARTCHAR FB75 +ENCODING 64373 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 11 -1 -2 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0400 +0400 +0600 +0600 +ENDCHAR +STARTCHAR FB76 +ENCODING 64374 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4000 +8300 +8B00 +8800 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FB77 +ENCODING 64375 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 12 0 -4 +BITMAP +3F80 +7F80 +0E00 +31C0 +41C0 +8400 +9400 +9000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FB78 +ENCODING 64376 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 10 -1 -1 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0200 +0A00 +0800 +ENDCHAR +STARTCHAR FB79 +ENCODING 64377 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 10 -1 -1 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0200 +0A00 +0800 +ENDCHAR +STARTCHAR FB7A +ENCODING 64378 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4200 +8B00 +8A00 +8200 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FB7B +ENCODING 64379 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 12 0 -4 +BITMAP +3F80 +7F80 +0E00 +31C0 +41C0 +8400 +9400 +9400 +4400 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FB7C +ENCODING 64380 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 11 -1 -2 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0200 +0A00 +0E00 +0200 +ENDCHAR +STARTCHAR FB7D +ENCODING 64381 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 11 -1 -2 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0200 +0A00 +0E00 +0200 +ENDCHAR +STARTCHAR FB7E +ENCODING 64382 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4300 +8B00 +8D00 +8500 +4400 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FB7F +ENCODING 64383 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 12 0 -4 +BITMAP +3F80 +7F80 +0E00 +31C0 +45C0 +9400 +9600 +9E00 +5800 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FB80 +ENCODING 64384 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 12 -1 -3 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0200 +0A00 +0B00 +0D00 +0C00 +ENDCHAR +STARTCHAR FB81 +ENCODING 64385 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 12 -1 -3 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0200 +0A00 +0B00 +0D00 +0C00 +ENDCHAR +STARTCHAR FB82 +ENCODING 64386 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 -1 +BITMAP +20 +30 +18 +08 +08 +08 +F8 +F8 +00 +10 +50 +40 +ENDCHAR +STARTCHAR FB83 +ENCODING 64387 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 -1 +BITMAP +20 +30 +18 +08 +08 +08 +F8 +F8 +00 +10 +50 +40 +ENDCHAR +STARTCHAR FB84 +ENCODING 64388 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 3 +BITMAP +30 +D0 +C0 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FB85 +ENCODING 64389 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 3 +BITMAP +30 +D0 +C0 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FB86 +ENCODING 64390 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 13 1 3 +BITMAP +40 +50 +50 +40 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FB87 +ENCODING 64391 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 13 1 3 +BITMAP +40 +50 +50 +40 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FB88 +ENCODING 64392 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 15 0 3 +BITMAP +20 +20 +20 +2C +34 +FC +00 +10 +18 +0C +04 +04 +04 +7C +7C +ENDCHAR +STARTCHAR FB89 +ENCODING 64393 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 15 0 3 +BITMAP +20 +20 +20 +2C +34 +FC +00 +10 +18 +0C +04 +04 +04 +7C +7C +ENDCHAR +STARTCHAR FB8A +ENCODING 64394 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 15 1 -2 +BITMAP +0C +0F +0B +08 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR FB8B +ENCODING 64395 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 15 1 -2 +BITMAP +0C +0F +0B +08 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR FB8C +ENCODING 64396 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 17 1 -2 +BITMAP +08 +10 +08 +0F +09 +3F +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR FB8D +ENCODING 64397 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 17 1 -2 +BITMAP +08 +10 +08 +0F +09 +3F +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR FB8E +ENCODING 64398 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 11 0 3 +BITMAP +0006 +001E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR FB8F +ENCODING 64399 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 11 0 3 +BITMAP +000600 +001E00 +007800 +004000 +006000 +007000 +001800 +800C00 +801200 +FFF3C0 +7FE1C0 +ENDCHAR +STARTCHAR FB90 +ENCODING 64400 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 11 -1 3 +BITMAP +03 +0F +3C +20 +30 +38 +0C +02 +01 +FF +FF +ENDCHAR +STARTCHAR FB91 +ENCODING 64401 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 11 -1 3 +BITMAP +0300 +0F00 +3C00 +2000 +3000 +3800 +0C00 +0600 +0900 +F9E0 +F0E0 +ENDCHAR +STARTCHAR FB92 +ENCODING 64402 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 14 0 3 +BITMAP +0002 +000E +0038 +0066 +009E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR FB93 +ENCODING 64403 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 14 0 3 +BITMAP +000200 +000E00 +003800 +006600 +009E00 +007800 +004000 +006000 +007000 +001800 +800C00 +801200 +FFF3C0 +7FE1C0 +ENDCHAR +STARTCHAR FB94 +ENCODING 64404 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 14 -1 3 +BITMAP +01 +07 +1C +33 +4F +3C +20 +30 +38 +0C +02 +01 +FF +FF +ENDCHAR +STARTCHAR FB95 +ENCODING 64405 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 14 -1 3 +BITMAP +0100 +0700 +1C00 +3300 +4F00 +3C00 +2000 +3000 +3800 +0C00 +0600 +0900 +F9E0 +F0E0 +ENDCHAR +STARTCHAR FB96 +ENCODING 64406 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 19 0 -2 +BITMAP +0002 +000E +0038 +0066 +009E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +0000 +0080 +0080 +0080 +0080 +ENDCHAR +STARTCHAR FB97 +ENCODING 64407 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 19 0 -2 +BITMAP +000200 +000E00 +003800 +006600 +009E00 +007800 +004000 +006000 +007000 +001800 +800C00 +801200 +FFF3C0 +7FE1C0 +000000 +020000 +020000 +020000 +020000 +ENDCHAR +STARTCHAR FB98 +ENCODING 64408 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 19 -1 -2 +BITMAP +01 +07 +1C +33 +4F +3C +20 +30 +38 +0C +02 +01 +FF +FF +00 +08 +08 +0C +0C +ENDCHAR +STARTCHAR FB99 +ENCODING 64409 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 19 -1 -2 +BITMAP +0100 +0700 +1C00 +3300 +4F00 +3C00 +2000 +3000 +3800 +0C00 +0600 +0900 +F9E0 +F0E0 +0000 +3000 +3000 +1000 +1000 +ENDCHAR +STARTCHAR FB9A +ENCODING 64410 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 14 0 3 +BITMAP +0012 +004E +0038 +0066 +009E +0078 +0040 +0060 +0070 +0018 +8004 +8002 +FFFE +7FFE +ENDCHAR +STARTCHAR FB9B +ENCODING 64411 +SWIDTH 925 0 +DWIDTH 18 0 +BBX 18 14 0 3 +BITMAP +001200 +004E00 +003800 +006600 +009E00 +007800 +004000 +006000 +007000 +001800 +800C00 +801200 +FFF3C0 +7FE1C0 +ENDCHAR +STARTCHAR FB9C +ENCODING 64412 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 14 -1 3 +BITMAP +09 +27 +1C +33 +4F +3C +20 +30 +38 +0C +02 +01 +FF +FF +ENDCHAR +STARTCHAR FB9D +ENCODING 64413 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 14 -1 3 +BITMAP +0900 +2700 +1C00 +3300 +4F00 +3C00 +2000 +3000 +3800 +0C00 +0600 +0900 +F9E0 +F0E0 +ENDCHAR +STARTCHAR FB9E +ENCODING 64414 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 8 1 0 +BITMAP +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR FB9F +ENCODING 64415 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 8 1 0 +BITMAP +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR FBA0 +ENCODING 64416 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 16 1 -1 +BITMAP +1000 +1000 +1000 +1600 +1A00 +3E00 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR FBA1 +ENCODING 64417 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 16 1 -1 +BITMAP +1000 +1000 +1000 +1600 +1A00 +3E00 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR FBA2 +ENCODING 64418 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 13 -1 3 +BITMAP +20 +20 +20 +2C +34 +7C +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FBA3 +ENCODING 64419 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 13 -1 3 +BITMAP +20 +20 +20 +2C +34 +7C +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FBA4 +ENCODING 64420 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 12 1 3 +BITMAP +60 +80 +60 +80 +00 +40 +E0 +F0 +90 +90 +F0 +E0 +ENDCHAR +STARTCHAR FBA5 +ENCODING 64421 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 13 0 3 +BITMAP +30 +40 +30 +40 +10 +10 +28 +48 +F8 +E8 +08 +06 +06 +ENDCHAR +STARTCHAR FBA6 +ENCODING 64422 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 7 1 3 +BITMAP +40 +E0 +F0 +90 +90 +F0 +E0 +ENDCHAR +STARTCHAR FBA7 +ENCODING 64423 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 5 0 2 +BITMAP +18 +3C +6E +46 +80 +ENDCHAR +STARTCHAR FBA8 +ENCODING 64424 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 -2 +BITMAP +08 +08 +0C +04 +FC +FC +00 +10 +20 +30 +10 +ENDCHAR +STARTCHAR FBA9 +ENCODING 64425 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 7 12 -1 -4 +BITMAP +10 +10 +10 +F6 +DE +18 +10 +00 +08 +10 +08 +08 +ENDCHAR +STARTCHAR FBAA +ENCODING 64426 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 8 -1 3 +BITMAP +08 +1C +1C +26 +27 +19 +FF +E7 +ENDCHAR +STARTCHAR FBAB +ENCODING 64427 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 9 0 4 +BITMAP +10 +10 +28 +48 +F8 +E8 +08 +06 +06 +ENDCHAR +STARTCHAR FBAC +ENCODING 64428 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 8 -1 3 +BITMAP +08 +1C +1C +26 +27 +19 +FF +E7 +ENDCHAR +STARTCHAR FBAD +ENCODING 64429 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 10 -1 -1 +BITMAP +04 +0C +14 +18 +FF +FF +24 +34 +1E +0C +ENDCHAR +STARTCHAR FBAE +ENCODING 64430 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 14 7 1 0 +BITMAP +0600 +0E00 +3800 +7000 +8000 +FFFC +FFF8 +ENDCHAR +STARTCHAR FBAF +ENCODING 64431 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 14 9 1 -4 +BITMAP +00FC +07FC +1F00 +3800 +6000 +8000 +8000 +FFFC +FFF8 +ENDCHAR +STARTCHAR FBB0 +ENCODING 64432 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 14 10 1 0 +BITMAP +0800 +3000 +1800 +2600 +0E00 +3800 +7000 +8000 +FFFC +FFF8 +ENDCHAR +STARTCHAR FBB1 +ENCODING 64433 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 14 14 1 -4 +BITMAP +0020 +0040 +0020 +0040 +0000 +00FC +07FC +1F00 +3800 +6000 +8000 +8000 +FFFC +FFF8 +ENDCHAR +STARTCHAR FBD3 +ENCODING 64467 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 13 0 3 +BITMAP +0C00 +0E40 +0B60 +0860 +0240 +0420 +0720 +0120 +0120 +9E20 +C020 +7FE0 +7FE0 +ENDCHAR +STARTCHAR FBD4 +ENCODING 64468 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 13 0 3 +BITMAP +0C00 +0E40 +0B60 +0860 +0240 +0420 +0720 +0120 +0120 +9E20 +C020 +7FE0 +7FE0 +ENDCHAR +STARTCHAR FBD5 +ENCODING 64469 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 13 -1 3 +BITMAP +30 +0C +23 +0F +3C +20 +30 +38 +0C +02 +01 +FF +FF +ENDCHAR +STARTCHAR FBD6 +ENCODING 64470 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 13 -1 3 +BITMAP +30 +0C +23 +0F +3C +20 +30 +38 +0C +02 +01 +FF +FF +ENDCHAR +STARTCHAR FBD7 +ENCODING 64471 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 17 0 -2 +BITMAP +03 +03 +03 +03 +04 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBD8 +ENCODING 64472 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 17 0 -2 +BITMAP +03 +03 +03 +03 +04 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBD9 +ENCODING 64473 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 14 0 -2 +BITMAP +05 +02 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBDA +ENCODING 64474 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 14 0 -2 +BITMAP +05 +02 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBDB +ENCODING 64475 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 17 0 -1 +BITMAP +02 +02 +02 +02 +02 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBDC +ENCODING 64476 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 17 0 -1 +BITMAP +02 +02 +02 +02 +02 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBDD +ENCODING 64477 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 9 16 0 -2 +BITMAP +0C80 +0D00 +0C80 +0D00 +1000 +0300 +0700 +0500 +0500 +0700 +0300 +0100 +0100 +0200 +8600 +7C00 +ENDCHAR +STARTCHAR FBDE +ENCODING 64478 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 16 0 -2 +BITMAP +04 +07 +0D +0C +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBDF +ENCODING 64479 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 16 0 -2 +BITMAP +04 +07 +0D +0C +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBE0 +ENCODING 64480 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 11 0 -2 +BITMAP +03 +07 +05 +05 +07 +03 +19 +07 +02 +86 +7C +ENDCHAR +STARTCHAR FBE1 +ENCODING 64481 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 11 0 -2 +BITMAP +03 +07 +05 +05 +07 +03 +19 +07 +02 +86 +7C +ENDCHAR +STARTCHAR FBE2 +ENCODING 64482 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 14 0 -2 +BITMAP +02 +05 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBE3 +ENCODING 64483 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 14 0 -2 +BITMAP +02 +05 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FBE4 +ENCODING 64484 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 13 0 -4 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +0000 +0400 +0400 +ENDCHAR +STARTCHAR FBE5 +ENCODING 64485 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 9 0 -4 +BITMAP +01E0 +43E0 +8200 +83C0 +C040 +7FC0 +3F00 +0400 +0400 +ENDCHAR +STARTCHAR FBE6 +ENCODING 64486 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 -2 +BITMAP +08 +08 +0C +04 +FC +FC +00 +30 +30 +10 +10 +ENDCHAR +STARTCHAR FBE7 +ENCODING 64487 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 -2 +BITMAP +08 +08 +0C +04 +FC +FC +00 +30 +30 +10 +10 +ENDCHAR +STARTCHAR FBFC +ENCODING 64508 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 10 0 -1 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +ENDCHAR +STARTCHAR FBFD +ENCODING 64509 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 7 0 -2 +BITMAP +01E0 +43E0 +8200 +83C0 +C040 +7FC0 +3F00 +ENDCHAR +STARTCHAR FBFE +ENCODING 64510 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 10 -1 -1 +BITMAP +08 +08 +0C +04 +FC +FC +00 +08 +28 +20 +ENDCHAR +STARTCHAR FBFF +ENCODING 64511 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 10 -1 -1 +BITMAP +08 +08 +0C +04 +FC +FC +00 +08 +28 +20 +ENDCHAR +STARTCHAR FC5E +ENCODING 64606 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 8 0 12 +BITMAP +10 +30 +50 +F0 +40 +20 +30 +40 +ENDCHAR +STARTCHAR FC5F +ENCODING 64607 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 7 1 12 +BITMAP +40 +60 +80 +60 +80 +60 +80 +ENDCHAR +STARTCHAR FC60 +ENCODING 64608 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 5 1 12 +BITMAP +60 +80 +40 +60 +80 +ENDCHAR +STARTCHAR FC61 +ENCODING 64609 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 7 1 12 +BITMAP +60 +60 +60 +80 +40 +60 +80 +ENDCHAR +STARTCHAR FC62 +ENCODING 64610 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 5 1 12 +BITMAP +40 +60 +80 +60 +80 +ENDCHAR +STARTCHAR FD3E +ENCODING 64830 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 19 1 -4 +BITMAP +10 +10 +20 +60 +60 +60 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +40 +60 +60 +20 +10 +10 +ENDCHAR +STARTCHAR FD3F +ENCODING 64831 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 4 19 1 -4 +BITMAP +80 +80 +40 +60 +60 +20 +30 +30 +30 +30 +30 +30 +30 +20 +60 +60 +40 +80 +80 +ENDCHAR +STARTCHAR FDF2 +ENCODING 65010 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 11 13 0 3 +BITMAP +0200 +0000 +0080 +0580 +0600 +0100 +0120 +0920 +1920 +2920 +49A0 +FFE0 +E760 +ENDCHAR +STARTCHAR FE80 +ENCODING 65152 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 6 8 1 1 +BITMAP +30 +70 +40 +CC +FC +70 +60 +40 +ENDCHAR +STARTCHAR FE81 +ENCODING 65153 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 14 0 2 +BITMAP +F0 +00 +00 +40 +60 +20 +20 +20 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR FE82 +ENCODING 65154 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 13 0 3 +BITMAP +E0 +00 +00 +C0 +40 +40 +40 +40 +40 +40 +40 +30 +30 +ENDCHAR +STARTCHAR FE83 +ENCODING 65155 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 14 1 2 +BITMAP +40 +80 +C0 +80 +00 +00 +80 +C0 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR FE84 +ENCODING 65156 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 13 0 3 +BITMAP +40 +80 +60 +80 +00 +40 +C0 +40 +40 +40 +40 +70 +30 +ENDCHAR +STARTCHAR FE85 +ENCODING 65157 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 16 0 -2 +BITMAP +0C +10 +0C +10 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FE86 +ENCODING 65158 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 16 0 -2 +BITMAP +0C +10 +0C +10 +00 +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FE87 +ENCODING 65159 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 3 16 0 -2 +BITMAP +40 +60 +20 +20 +20 +20 +20 +20 +20 +20 +20 +00 +60 +80 +60 +80 +ENDCHAR +STARTCHAR FE88 +ENCODING 65160 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 15 0 -1 +BITMAP +C0 +40 +40 +40 +40 +40 +40 +40 +30 +30 +00 +40 +80 +60 +80 +ENDCHAR +STARTCHAR FE89 +ENCODING 65161 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 12 0 -1 +BITMAP +2000 +4000 +6060 +40F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +ENDCHAR +STARTCHAR FE8A +ENCODING 65162 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 13 0 -2 +BITMAP +2000 +4000 +6000 +4000 +0000 +0000 +01E0 +43E0 +8200 +83C0 +C040 +7FC0 +3F00 +ENDCHAR +STARTCHAR FE8B +ENCODING 65163 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +10 +20 +10 +20 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FE8C +ENCODING 65164 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +10 +20 +10 +20 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FE8D +ENCODING 65165 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 2 11 1 3 +BITMAP +80 +C0 +40 +40 +40 +40 +40 +40 +40 +40 +40 +ENDCHAR +STARTCHAR FE8E +ENCODING 65166 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 4 10 0 4 +BITMAP +C0 +40 +40 +40 +40 +40 +40 +40 +30 +30 +ENDCHAR +STARTCHAR FE8F +ENCODING 65167 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0600 +0600 +ENDCHAR +STARTCHAR FE90 +ENCODING 65168 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 9 1 0 +BITMAP +8010 +8010 +8010 +8008 +FFF8 +7FF8 +0000 +0600 +0600 +ENDCHAR +STARTCHAR FE91 +ENCODING 65169 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 9 -1 0 +BITMAP +08 +08 +0C +04 +FC +FC +00 +10 +10 +ENDCHAR +STARTCHAR FE92 +ENCODING 65170 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 9 -1 0 +BITMAP +08 +08 +0C +04 +FC +FC +00 +10 +10 +ENDCHAR +STARTCHAR FE93 +ENCODING 65171 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 5 11 0 3 +BITMAP +10 +D0 +C0 +00 +20 +30 +78 +48 +48 +78 +70 +ENDCHAR +STARTCHAR FE94 +ENCODING 65172 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 14 0 3 +BITMAP +10 +50 +40 +00 +00 +10 +10 +28 +48 +F8 +E8 +08 +06 +06 +ENDCHAR +STARTCHAR FE95 +ENCODING 65173 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 9 1 3 +BITMAP +0300 +0F00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FE96 +ENCODING 65174 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 9 1 3 +BITMAP +0300 +0F00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FE97 +ENCODING 65175 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 10 -1 3 +BITMAP +08 +28 +20 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FE98 +ENCODING 65176 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 10 -1 3 +BITMAP +08 +28 +20 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FE99 +ENCODING 65177 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 10 1 3 +BITMAP +0400 +0700 +0F00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FE9A +ENCODING 65178 +SWIDTH 720 0 +DWIDTH 14 0 +BBX 13 10 1 3 +BITMAP +0400 +0700 +0F00 +0C00 +8010 +8010 +8010 +8008 +FFF8 +7FF8 +ENDCHAR +STARTCHAR FE9B +ENCODING 65179 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +20 +28 +28 +20 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FE9C +ENCODING 65180 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +20 +28 +28 +20 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FE9D +ENCODING 65181 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4000 +8600 +8600 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FE9E +ENCODING 65182 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 12 0 -4 +BITMAP +3F80 +7F80 +0E00 +31C0 +41C0 +8000 +8400 +8400 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FE9F +ENCODING 65183 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 9 -1 0 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0400 +0400 +ENDCHAR +STARTCHAR FEA0 +ENCODING 65184 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 9 -1 0 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +0000 +0400 +0400 +ENDCHAR +STARTCHAR FEA1 +ENCODING 65185 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 12 0 -4 +BITMAP +3F80 +7F80 +0C00 +3000 +4000 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FEA2 +ENCODING 65186 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 12 0 -4 +BITMAP +3F80 +7F80 +0E00 +31C0 +41C0 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FEA3 +ENCODING 65187 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 6 -1 3 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +ENDCHAR +STARTCHAR FEA4 +ENCODING 65188 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 6 -1 3 +BITMAP +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +ENDCHAR +STARTCHAR FEA5 +ENCODING 65189 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 9 16 0 -4 +BITMAP +0C00 +0400 +0000 +0000 +3F80 +7F80 +0C00 +3000 +4000 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FEA6 +ENCODING 65190 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 16 0 -4 +BITMAP +0400 +0400 +0000 +0000 +3F80 +7F80 +0E00 +31C0 +41C0 +8000 +8000 +8000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FEA7 +ENCODING 65191 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 10 -1 3 +BITMAP +0400 +0400 +0000 +0000 +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +ENDCHAR +STARTCHAR FEA8 +ENCODING 65192 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 10 -1 3 +BITMAP +0400 +0400 +0000 +0000 +1C00 +1F00 +0780 +01C0 +FFE0 +FFE0 +ENDCHAR +STARTCHAR FEA9 +ENCODING 65193 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 8 1 3 +BITMAP +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FEAA +ENCODING 65194 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 8 1 3 +BITMAP +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FEAB +ENCODING 65195 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 3 +BITMAP +40 +60 +00 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FEAC +ENCODING 65196 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 5 12 1 3 +BITMAP +40 +60 +00 +00 +20 +30 +18 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FEAD +ENCODING 65197 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 10 1 -2 +BITMAP +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR FEAE +ENCODING 65198 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 10 1 -2 +BITMAP +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR FEAF +ENCODING 65199 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +04 +04 +00 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR FEB0 +ENCODING 65200 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 14 1 -2 +BITMAP +04 +04 +00 +00 +02 +03 +01 +01 +01 +01 +01 +03 +8E +78 +ENDCHAR +STARTCHAR FEB1 +ENCODING 65201 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 9 1 -1 +BITMAP +0104 +0182 +0092 +80FE +80FE +8080 +8180 +FF00 +7C00 +ENDCHAR +STARTCHAR FEB2 +ENCODING 65202 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 9 1 -1 +BITMAP +0104 +0182 +0092 +80FE +80FE +8080 +8180 +FF00 +7C00 +ENDCHAR +STARTCHAR FEB3 +ENCODING 65203 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 5 -1 3 +BITMAP +0020 +10A0 +08A0 +FFE0 +FF60 +ENDCHAR +STARTCHAR FEB4 +ENCODING 65204 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 5 -1 3 +BITMAP +0020 +10A0 +08A0 +FFE0 +FF60 +ENDCHAR +STARTCHAR FEB5 +ENCODING 65205 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 1 -1 +BITMAP +0030 +0038 +0028 +0020 +0000 +0104 +0182 +0092 +80FE +80FE +8080 +8180 +FF00 +7C00 +ENDCHAR +STARTCHAR FEB6 +ENCODING 65206 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 15 14 1 -1 +BITMAP +0030 +0038 +0028 +0020 +0000 +0104 +0182 +0092 +80FE +80FE +8080 +8180 +FF00 +7C00 +ENDCHAR +STARTCHAR FEB7 +ENCODING 65207 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 10 -1 3 +BITMAP +0100 +01C0 +0340 +0300 +0000 +0020 +10A0 +08A0 +FFE0 +FF60 +ENDCHAR +STARTCHAR FEB8 +ENCODING 65208 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 11 10 -1 3 +BITMAP +0100 +01C0 +0340 +0300 +0000 +0020 +10A0 +08A0 +FFE0 +FF60 +ENDCHAR +STARTCHAR FEB9 +ENCODING 65209 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 9 1 -1 +BITMAP +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810000 +FF0000 +7C0000 +ENDCHAR +STARTCHAR FEBA +ENCODING 65210 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 9 1 -1 +BITMAP +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810000 +FF0000 +7C0000 +ENDCHAR +STARTCHAR FEBB +ENCODING 65211 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 17 6 -1 3 +BITMAP +000700 +001F80 +103180 +08C180 +FFFF80 +FFFF80 +ENDCHAR +STARTCHAR FEBC +ENCODING 65212 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 17 6 -1 3 +BITMAP +000700 +001F80 +103180 +08C180 +FFFF80 +FFFF80 +ENDCHAR +STARTCHAR FEBD +ENCODING 65213 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 12 1 -1 +BITMAP +000800 +000800 +000000 +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810000 +FF0000 +7C0000 +ENDCHAR +STARTCHAR FEBE +ENCODING 65214 +SWIDTH 1080 0 +DWIDTH 21 0 +BBX 20 12 1 -1 +BITMAP +000800 +000800 +000000 +0101E0 +0187F0 +008C30 +80FFF0 +80FFF0 +808000 +810000 +FF0000 +7C0000 +ENDCHAR +STARTCHAR FEBF +ENCODING 65215 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 17 9 -1 3 +BITMAP +006000 +006000 +000000 +000700 +001F80 +103180 +08C180 +FFFF80 +FFFF80 +ENDCHAR +STARTCHAR FEC0 +ENCODING 65216 +SWIDTH 822 0 +DWIDTH 16 0 +BBX 17 9 -1 3 +BITMAP +006000 +006000 +000000 +000700 +001F80 +103180 +08C180 +FFFF80 +FFFF80 +ENDCHAR +STARTCHAR FEC1 +ENCODING 65217 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1800 +0800 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR FEC2 +ENCODING 65218 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1800 +0800 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR FEC3 +ENCODING 65219 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1800 +0800 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR FEC4 +ENCODING 65220 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1800 +0800 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR FEC5 +ENCODING 65221 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1880 +0880 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR FEC6 +ENCODING 65222 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1880 +0880 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR FEC7 +ENCODING 65223 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1880 +0880 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR FEC8 +ENCODING 65224 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 12 11 -1 4 +BITMAP +1800 +1880 +0880 +0800 +0800 +08E0 +0BF0 +0630 +0830 +FFF0 +FFF0 +ENDCHAR +STARTCHAR FEC9 +ENCODING 65225 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 16 0 -4 +BITMAP +3800 +7C00 +6000 +8000 +8100 +6700 +7C00 +3000 +2000 +4000 +8000 +8000 +C000 +6000 +7F80 +1F00 +ENDCHAR +STARTCHAR FECA +ENCODING 65226 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 9 13 0 -4 +BITMAP +1C00 +3C00 +1C00 +3C00 +2780 +4380 +4000 +8000 +4000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FECB +ENCODING 65227 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 6 -1 3 +BITMAP +1E00 +3F00 +2040 +3380 +FF00 +FC00 +ENDCHAR +STARTCHAR FECC +ENCODING 65228 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 6 -1 3 +BITMAP +1E +3E +3E +0C +FF +E3 +ENDCHAR +STARTCHAR FECD +ENCODING 65229 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 20 0 -4 +BITMAP +1000 +1000 +0000 +0000 +3800 +7C00 +6000 +8000 +8100 +6700 +7C00 +3000 +2000 +4000 +8000 +8000 +C000 +6000 +7F80 +1F00 +ENDCHAR +STARTCHAR FECE +ENCODING 65230 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 9 17 0 -4 +BITMAP +0800 +0800 +0000 +0000 +1C00 +3C00 +1C00 +3C00 +2780 +4380 +4000 +8000 +4000 +4000 +7000 +3F80 +1F00 +ENDCHAR +STARTCHAR FECF +ENCODING 65231 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 9 -1 3 +BITMAP +0C00 +0C00 +0000 +1E00 +3F00 +2040 +3380 +FF00 +FC00 +ENDCHAR +STARTCHAR FED0 +ENCODING 65232 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 10 -1 3 +BITMAP +08 +08 +00 +00 +1E +3E +3E +0C +FF +E3 +ENDCHAR +STARTCHAR FED1 +ENCODING 65233 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 10 0 3 +BITMAP +0018 +0018 +0000 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR FED2 +ENCODING 65234 +SWIDTH 771 0 +DWIDTH 15 0 +BBX 15 10 0 3 +BITMAP +0018 +0018 +0000 +0000 +400C +800E +801A +C00E +7FFE +3FFE +ENDCHAR +STARTCHAR FED3 +ENCODING 65235 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 11 -1 3 +BITMAP +10 +10 +00 +18 +38 +2C +3C +3C +04 +FC +FC +ENDCHAR +STARTCHAR FED4 +ENCODING 65236 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 12 -1 3 +BITMAP +08 +08 +00 +00 +18 +1C +24 +24 +1C +0C +FC +FC +ENDCHAR +STARTCHAR FED5 +ENCODING 65237 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 -1 +BITMAP +0100 +0580 +0400 +0000 +0000 +0180 +03C0 +02C0 +83C0 +83C0 +8040 +80C0 +FF80 +7F00 +ENDCHAR +STARTCHAR FED6 +ENCODING 65238 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 14 1 -1 +BITMAP +0100 +0580 +0400 +0000 +0000 +0180 +03C0 +02C0 +83C0 +83C0 +8040 +80C0 +FF80 +7F00 +ENDCHAR +STARTCHAR FED7 +ENCODING 65239 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 12 -1 3 +BITMAP +08 +28 +20 +00 +18 +38 +2C +3C +3C +04 +FC +FC +ENDCHAR +STARTCHAR FED8 +ENCODING 65240 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 13 -1 3 +BITMAP +08 +28 +20 +00 +00 +18 +1C +24 +24 +1C +0C +FC +FC +ENDCHAR +STARTCHAR FED9 +ENCODING 65241 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 12 0 3 +BITMAP +0040 +0060 +0060 +0240 +0420 +0720 +0120 +0120 +9E20 +C020 +7FE0 +7FE0 +ENDCHAR +STARTCHAR FEDA +ENCODING 65242 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 12 0 3 +BITMAP +0040 +0060 +0060 +0240 +0420 +0720 +0120 +0120 +9E20 +C020 +7FE0 +7FE0 +ENDCHAR +STARTCHAR FEDB +ENCODING 65243 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 11 -1 3 +BITMAP +03 +0F +3C +20 +30 +38 +0C +02 +01 +FF +FF +ENDCHAR +STARTCHAR FEDC +ENCODING 65244 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 11 -1 3 +BITMAP +03 +0F +3C +20 +30 +38 +0C +02 +01 +FF +FF +ENDCHAR +STARTCHAR FEDD +ENCODING 65245 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 15 1 0 +BITMAP +0200 +0300 +0100 +0100 +0100 +0100 +0100 +0100 +8100 +8080 +8080 +8080 +8300 +FF00 +7E00 +ENDCHAR +STARTCHAR FEDE +ENCODING 65246 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 15 1 0 +BITMAP +0200 +0300 +0100 +0100 +0100 +0100 +0100 +0100 +8100 +8080 +8080 +8080 +8300 +FF00 +7E00 +ENDCHAR +STARTCHAR FEDF +ENCODING 65247 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 5 12 -1 3 +BITMAP +20 +38 +10 +10 +10 +10 +10 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FEE0 +ENCODING 65248 +SWIDTH 205 0 +DWIDTH 4 0 +BBX 5 12 -1 3 +BITMAP +20 +38 +10 +10 +10 +10 +10 +08 +08 +08 +F8 +F8 +ENDCHAR +STARTCHAR FEE1 +ENCODING 65249 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 11 0 -4 +BITMAP +38 +3C +0C +3C +7C +C0 +80 +80 +40 +40 +40 +ENDCHAR +STARTCHAR FEE2 +ENCODING 65250 +SWIDTH 308 0 +DWIDTH 6 0 +BBX 6 11 0 -4 +BITMAP +38 +3C +0C +3C +7C +C0 +80 +80 +40 +40 +40 +ENDCHAR +STARTCHAR FEE3 +ENCODING 65251 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 5 -1 3 +BITMAP +02 +0D +1D +FF +F7 +ENDCHAR +STARTCHAR FEE4 +ENCODING 65252 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 5 -1 3 +BITMAP +02 +0D +1D +FF +F7 +ENDCHAR +STARTCHAR FEE5 +ENCODING 65253 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 12 1 -1 +BITMAP +0800 +0800 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR FEE6 +ENCODING 65254 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 12 1 -1 +BITMAP +0800 +0800 +0000 +0000 +0080 +0080 +8080 +8080 +8080 +8180 +FF00 +7E00 +ENDCHAR +STARTCHAR FEE7 +ENCODING 65255 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 9 -1 3 +BITMAP +10 +10 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FEE8 +ENCODING 65256 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 9 -1 3 +BITMAP +10 +10 +00 +08 +08 +0C +04 +FC +FC +ENDCHAR +STARTCHAR FEE9 +ENCODING 65257 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 4 7 1 3 +BITMAP +40 +E0 +F0 +90 +90 +F0 +E0 +ENDCHAR +STARTCHAR FEEA +ENCODING 65258 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 7 9 0 4 +BITMAP +10 +10 +28 +48 +F8 +E8 +08 +06 +06 +ENDCHAR +STARTCHAR FEEB +ENCODING 65259 +SWIDTH 462 0 +DWIDTH 9 0 +BBX 8 8 -1 3 +BITMAP +08 +1C +1C +26 +27 +19 +FF +E7 +ENDCHAR +STARTCHAR FEEC +ENCODING 65260 +SWIDTH 360 0 +DWIDTH 7 0 +BBX 8 10 -1 -1 +BITMAP +04 +0C +14 +18 +FF +FF +24 +34 +1E +0C +ENDCHAR +STARTCHAR FEED +ENCODING 65261 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 11 0 -2 +BITMAP +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FEEE +ENCODING 65262 +SWIDTH 411 0 +DWIDTH 8 0 +BBX 8 11 0 -2 +BITMAP +03 +07 +05 +05 +07 +03 +01 +01 +02 +86 +7C +ENDCHAR +STARTCHAR FEEF +ENCODING 65263 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 10 0 -1 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +ENDCHAR +STARTCHAR FEF0 +ENCODING 65264 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 7 0 -2 +BITMAP +01E0 +43E0 +8200 +83C0 +C040 +7FC0 +3F00 +ENDCHAR +STARTCHAR FEF1 +ENCODING 65265 +SWIDTH 617 0 +DWIDTH 12 0 +BBX 12 13 0 -4 +BITMAP +0060 +00F0 +0100 +0200 +43E0 +81E0 +8020 +C1C0 +7F80 +3E00 +0300 +0B00 +0800 +ENDCHAR +STARTCHAR FEF2 +ENCODING 65266 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 11 9 0 -4 +BITMAP +01E0 +43E0 +8200 +83C0 +C040 +7FC0 +3F00 +0A00 +0A00 +ENDCHAR +STARTCHAR FEF3 +ENCODING 65267 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 10 -1 -1 +BITMAP +08 +08 +0C +04 +FC +FC +00 +08 +28 +20 +ENDCHAR +STARTCHAR FEF4 +ENCODING 65268 +SWIDTH 257 0 +DWIDTH 5 0 +BBX 6 10 -1 -1 +BITMAP +08 +08 +0C +04 +FC +FC +00 +08 +28 +20 +ENDCHAR +STARTCHAR FEF5 +ENCODING 65269 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 15 1 1 +BITMAP +E000 +0000 +8200 +C380 +E100 +6100 +1100 +0A00 +0A00 +0600 +0400 +0600 +1A00 +1E00 +1C00 +ENDCHAR +STARTCHAR FEF6 +ENCODING 65270 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 13 1 3 +BITMAP +E000 +0000 +C000 +F100 +7900 +0500 +0280 +0080 +0180 +0280 +0680 +3CC0 +F840 +ENDCHAR +STARTCHAR FEF7 +ENCODING 65271 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 10 15 0 1 +BITMAP +6000 +8000 +6100 +81C0 +0080 +4080 +6080 +3080 +0900 +0500 +0300 +0200 +0500 +0F00 +0E00 +ENDCHAR +STARTCHAR FEF8 +ENCODING 65272 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 13 1 3 +BITMAP +4000 +8000 +C000 +8100 +E100 +7900 +0480 +0280 +0180 +0280 +0680 +3CC0 +F840 +ENDCHAR +STARTCHAR FEF9 +ENCODING 65273 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 18 1 -4 +BITMAP +8200 +C380 +E100 +6100 +1100 +0A00 +0A00 +0600 +0400 +0600 +1A00 +1E00 +1C00 +0000 +1000 +2000 +1800 +2000 +ENDCHAR +STARTCHAR FEFA +ENCODING 65274 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 16 1 -2 +BITMAP +C000 +F100 +7900 +0500 +0280 +0080 +0180 +0280 +0680 +3CC0 +F840 +0000 +2000 +4000 +6000 +4000 +ENDCHAR +STARTCHAR FEFB +ENCODING 65275 +SWIDTH 514 0 +DWIDTH 10 0 +BBX 9 13 1 1 +BITMAP +8200 +C380 +E100 +6100 +1100 +0A00 +0A00 +0600 +0400 +0600 +1A00 +1E00 +1C00 +ENDCHAR +STARTCHAR FEFC +ENCODING 65276 +SWIDTH 565 0 +DWIDTH 11 0 +BBX 10 11 1 3 +BITMAP +C000 +F100 +7900 +0500 +0280 +0080 +0180 +0280 +0680 +3CC0 +F840 +ENDCHAR +STARTCHAR FFFC +ENCODING 65532 +SWIDTH 977 0 +DWIDTH 19 0 +BBX 19 14 0 0 +BITMAP +E71CE0 +800020 +800020 +000000 +1EF980 +B3C9A0 +A1F1A0 +A1C9A0 +B3C920 +1EFF00 +000000 +800020 +800020 +E71CE0 +ENDCHAR +ENDFONT diff --git a/TMC2209_Camera_Slider/CircuitPython/adafruit_tmc2209.py b/TMC2209_Camera_Slider/CircuitPython/adafruit_tmc2209.py new file mode 100644 index 000000000..e15672f47 --- /dev/null +++ b/TMC2209_Camera_Slider/CircuitPython/adafruit_tmc2209.py @@ -0,0 +1,768 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import time +import busio +from micropython import const +from generic_uart_device import GenericUARTDevice + +# pylint: disable=protected-access, too-many-public-methods, bare-except, too-many-function-args + +class TMC2209: + + GCONF = const(0x00) # Global configuration + GSTAT = const(0x01) # Global status flags + IFCNT = const(0x02) # Interface transmission counter + NODECONF = const(0x03) # Node configuration + OTP_PROG = const(0x04) # OTP programming + OTP_READ = const(0x05) # OTP read data + IOIN = const(0x06) + FACTORY_CONF = const(0x07) # Factory configuration + + # Velocity Dependent Control Registers + IHOLD_IRUN = const(0x10) + TPOWERDOWN = const(0x11) # Power down delay + TSTEP = const(0x12) # Time between steps + TPWMTHRS = const(0x13) # Upper velocity for StealthChop + TCOOLTHRS = const(0x14) # Lower threshold velocity for CoolStep + VACTUAL = const(0x22) + + # StallGuard Control Registers + SGTHRS = const(0x40) # StallGuard threshold + SG_RESULT = const(0x41) # StallGuard result + COOLCONF = const(0x42) # CoolStep configuration + + # Sequencer Registers + MSCNT = const(0x6A) + MSCURACT = const(0x6B) + + # Chopper Control Registers + DRV_STATUS = const(0x6F) # Driver status + PWMCONF = const(0x70) # StealthChop PWM config + PWM_SCALE = const(0x71) # PWM scaling values + PWM_AUTO = const(0x72) # PWM automatic configuration + + CHOPCONF = const(0x6C) + MRES_START = 24 # Microstepping resolution bits start position + MRES_LENGTH = 4 # Number of bits for microstepping resolution + + # GCONF register bit positions + GCONF_I_SCALE_ANALOG = const(0) + GCONF_INTERNAL_RSENSE = const(1) + GCONF_EN_SPREADCYCLE = const(2) + GCONF_SHAFT = const(3) + GCONF_INDEX_OTPW = const(4) + GCONF_INDEX_STEP = const(5) + GCONF_PDN_DISABLE = const(6) + GCONF_MSTEP_REG_SELECT = const(7) + GCONF_MULTISTEP_FILT = const(8) + GCONF_TEST_MODE = const(9) + + # GSTAT register bit positions + GSTAT_RESET = const(0) + GSTAT_DRV_ERR = const(1) + GSTAT_UV_CP = const(2) + + # CHOPCONF register bit positions + CHOPCONF_TOFF_START = const(0) + CHOPCONF_HSTRT_START = const(4) + CHOPCONF_HEND_START = const(7) + CHOPCONF_TBL_START = const(15) + CHOPCONF_VSENSE = const(17) + CHOPCONF_MRES_START = const(24) + CHOPCONF_INTPOL = const(28) + CHOPCONF_DEDGE = const(29) + CHOPCONF_DISS2G = const(30) + CHOPCONF_DISS2VS = const(31) + + # PWMCONF register bit positions + PWMCONF_PWM_OFS = const(0) + PWMCONF_PWM_GRAD = const(8) + PWMCONF_PWM_FREQ = const(16) + PWMCONF_PWM_AUTOSCALE = const(18) + PWMCONF_PWM_AUTOGRAD = const(19) + PWMCONF_FREEWHEEL = const(20) + PWMCONF_PWM_REG = const(24) + PWMCONF_PWM_LIM = const(28) + + # DRV_STATUS bit positions + DRV_STATUS_OTPW = const(0) + DRV_STATUS_OT = const(1) + DRV_STATUS_S2GA = const(2) + DRV_STATUS_S2GB = const(3) + DRV_STATUS_S2VSA = const(4) + DRV_STATUS_S2VSB = const(5) + DRV_STATUS_OLA = const(6) + DRV_STATUS_OLB = const(7) + DRV_STATUS_T120 = const(8) + DRV_STATUS_T143 = const(9) + DRV_STATUS_T150 = const(10) + DRV_STATUS_T157 = const(11) + DRV_STATUS_CS_ACTUAL = const(16) # Start bit for CS_ACTUAL + DRV_STATUS_STEALTH = const(30) + DRV_STATUS_STST = const(31) + + # COOLCONF register bit positions + COOLCONF_SEMIN = const(0) + COOLCONF_SEUP = const(5) + COOLCONF_SEMAX = const(8) + COOLCONF_SEDN = const(13) + COOLCONF_SEIMIN = const(15) + + def __init__(self, uart=None, tx_pin=None, rx_pin=None, addr=0, baudrate=115200): + + if uart is None and tx_pin is not None and rx_pin is not None: + uart = busio.UART(tx=tx_pin, rx=rx_pin, baudrate=baudrate, timeout=0.1) + elif uart is None: + raise ValueError("Either uart or tx_pin and rx_pin must be provided") + + self._addr = addr & 0x03 + + self._device = GenericUARTDevice( + uart=uart, + read_func=self._uart_read, + write_func=self._uart_write, + readreg_func=self.read_reg, + writereg_func=self.write_reg + ) + gconf = self.read_reg(self.GCONF) + gconf |= (1 << 7) + self.write_reg(self.GCONF, gconf) + ihold_irun = ( + (16 << 0) | # IHOLD = 16 (50% of max current) + (31 << 8) | # IRUN = 31 (max current) + (1 << 16) # IHOLDDELAY = 1 + ) + self.write_reg(self.IHOLD_IRUN, ihold_irun) + + self._step_count = 0 # Track full steps + self._last_mscnt = self.mscnt # Initialize last microstep counter + self._step_count = 0 + self._last_mscnt = 0 + try: + self._last_mscnt = self.mscnt + except: + pass + self._start_position = None + self._end_position = None + + @staticmethod + def calc_crc(data: bytes) -> int: + """Calculate CRC8-ATM + Polynomial: x^8 + x^2 + x + 1 (0x07) + """ + crc = 0 + for byte in data: + for _ in range(8): + if (crc >> 7) ^ (byte & 0x01): + crc = ((crc << 1) ^ 0x07) & 0xFF + else: + crc = (crc << 1) & 0xFF + byte = byte >> 1 + return crc + + def read_reg(self, reg_addr: int) -> int: + """Read a register value""" + while self._device._uart.in_waiting: + self._device._uart.read() + datagram = bytes([ + 0x05, + self._addr << 1, + reg_addr, + 0x00 + ]) + datagram = datagram[:-1] + bytes([self.calc_crc(datagram[:-1])]) + self._device._uart.write(datagram) + echo = bytearray(4) + if not self._device._uart.readinto(echo): + return 0 + response = bytearray(8) + if not self._device._uart.readinto(response): + return 0 + value = (response[3] << 24) | (response[4] << 16) | (response[5] << 8) | response[6] + return value + + def write_reg(self, reg_addr: int, value: int): + """Write a value to a register""" + if value < 0: + value = value & 0xFFFFFFFF + while self._device._uart.in_waiting: + self._device._uart.read() + data = value.to_bytes(4, 'big', signed=False) + datagram = bytes([ + 0x05, + self._addr << 1, + reg_addr | 0x80, + data[0], + data[1], + data[2], + data[3], + 0x00 + ]) + datagram = datagram[:-1] + bytes([self.calc_crc(datagram[:-1])]) + self._device._uart.write(datagram) + echo = bytearray(8) + self._device._uart.readinto(echo) + + def _uart_read(self, buffer: bytearray) -> int: + """Read raw data from UART""" + return self._device._uart.readinto(buffer) + + def _uart_write(self, buffer: bytes) -> int: + """Write raw data to UART""" + return self._device._uart.write(buffer) + + @property + def mscnt(self) -> int: + """Read the microstep counter + Returns the current position in the microstep table (0-1023) + """ + return self.read_reg(self.MSCNT) & 0x3FF # 10-bit value (0-1023) + + @property + def mscuract(self) -> tuple: + """Read the current microstep current for both phases + Returns: + tuple: (CUR_A, CUR_B) - Current for phase A and B (-255 to 255) + """ + value = self.read_reg(self.MSCURACT) + cur_a = (value >> 16) & 0x1FF + cur_b = value & 0x1FF + if cur_a & 0x100: + cur_a = -(cur_a ^ 0x1FF) - 1 + if cur_b & 0x100: + cur_b = -(cur_b ^ 0x1FF) - 1 + return (cur_a, cur_b) + + @property + def position(self) -> float: + """Get the current motor position in steps + This combines full steps tracked by software and microsteps from the driver + """ + return self._step_count + + def reset_position(self): + """Reset the position counter to zero at the current position""" + self._step_count = 0 + self._last_mscnt = self.mscnt + + @property + def version(self) -> int: + """Read chip version""" + ioin = self.read_reg(self.IOIN) + return (ioin >> 24) & 0xFF + + @property + def microsteps(self) -> int: + """Get current microsteps (1-256)""" + chopconf = self.read_reg(self.CHOPCONF) + mres = (chopconf >> self.MRES_START) & ((1 << self.MRES_LENGTH) - 1) + return 256 >> mres if mres <= 8 else 0 + + @microsteps.setter + def microsteps(self, steps: int): + """Set microsteps (1-256, will be rounded to power of 2)""" + steps = min(256, max(1, steps)) + mres = 0 + while steps < 256: + steps = steps << 1 + mres += 1 + + chopconf = self.read_reg(self.CHOPCONF) + mask = ((1 << self.MRES_LENGTH) - 1) << self.MRES_START + chopconf = (chopconf & ~mask) | ((mres & 0xF) << self.MRES_START) + + self.write_reg(self.CHOPCONF, chopconf) + + @property + def direction(self) -> bool: + """Get current direction (True = reversed, False = normal)""" + gconf = self.read_reg(self.GCONF) + return bool(gconf & (1 << 3)) + + @direction.setter + def direction(self, reverse: bool): + """Set motor direction (True = reversed, False = normal)""" + gconf = self.read_reg(self.GCONF) + if reverse: + gconf |= (1 << 3) + else: + gconf &= ~(1 << 3) + self.write_reg(self.GCONF, gconf) + + def rotate(self, velocity: int): + """Rotate the motor at a specific velocity + Args: + velocity: Rotation velocity (-2^23 to +2^23) + Positive for forward, negative for reverse + """ + # Clamp velocity to valid range (-2^23 to 2^23 - 1) + velocity = max(-(1 << 23), min((1 << 23) - 1, velocity)) + self.write_reg(self.VACTUAL, velocity) + + def step(self, steps: int, delay: float = 0.001): + """Step the motor a specific number of steps + Args: + steps: Number of steps (negative for reverse direction) + delay: Delay between steps in seconds + """ + direction = 1 if steps > 0 else -1 + for _ in range(abs(steps)): + self.rotate(10000 * direction) + time.sleep(delay) + self.stop() + # Update position counter + self._step_count += direction + + def stop(self): + """Stop the motor""" + self.write_reg(self.VACTUAL, 0) + + def set_current(self, run_current: int, hold_current: int = None): + """Set motor current + + Args: + run_current: Running current (0-31) + hold_current: Holding current (0-31), defaults to 50% of run_current + """ + if hold_current is None: + hold_current = run_current // 2 + + run_current = min(31, max(0, run_current)) + hold_current = min(31, max(0, hold_current)) + + ihold_irun = ( + (hold_current << 0) | # IHOLD + (run_current << 8) | # IRUN + (1 << 16) # IHOLDDELAY + ) + self.write_reg(self.IHOLD_IRUN, ihold_irun) + + @property + def stealth_chop_enabled(self): + """Check if StealthChop mode is enabled + + Returns: + bool: True if StealthChop is enabled, False if SpreadCycle is active + """ + gconf = self.read_reg(self.GCONF) + return not bool(gconf & (1 << self.GCONF_EN_SPREADCYCLE)) + + @stealth_chop_enabled.setter + def stealth_chop_enabled(self, enable): + """Enable or disable StealthChop mode (voltage PWM mode) + + Args: + enable (bool): True to enable StealthChop, False to use SpreadCycle + """ + gconf = self.read_reg(self.GCONF) + if enable: + # Clear EN_SPREADCYCLE bit to enable StealthChop + gconf &= ~(1 << self.GCONF_EN_SPREADCYCLE) + else: + # Set EN_SPREADCYCLE bit to enable SpreadCycle mode + gconf |= (1 << self.GCONF_EN_SPREADCYCLE) + self.write_reg(self.GCONF, gconf) + + @property + def pwm_threshold(self): + """Get the TSTEP threshold for switching to StealthChop + + Returns: + int: Current TSTEP threshold value + """ + return self.read_reg(self.TPWMTHRS) + + @pwm_threshold.setter + def pwm_threshold(self, threshold): + """Set the TSTEP threshold for switching to StealthChop + + This sets the upper velocity threshold for StealthChop operation. + When TSTEP falls below this value (higher velocity), the driver + will switch from StealthChop to SpreadCycle. + + Args: + threshold (int): TSTEP threshold value (0-1048575) + 0 = Disabled (use SpreadCycle only) + """ + # Clamp threshold to valid range + threshold = max(0, min(threshold, (1 << 20) - 1)) + self.write_reg(self.TPWMTHRS, threshold) + + @property + def pwm_scale(self): + """Read the PWM scaling values (results of StealthChop amplitude regulator) + + Returns: + tuple: (PWM_SCALE_SUM, PWM_SCALE_AUTO) where: + PWM_SCALE_SUM (0-255): Actual PWM duty cycle + PWM_SCALE_AUTO (-255 to +255): Signed offset from automatic amplitude regulation + """ + pwm_scale = self.read_reg(self.PWM_SCALE) + pwm_scale_sum = pwm_scale & 0xFF + pwm_scale_auto = (pwm_scale >> 16) & 0x1FF + if pwm_scale_auto & 0x100: + pwm_scale_auto = -(pwm_scale_auto ^ 0x1FF) - 1 + return (pwm_scale_sum, pwm_scale_auto) + + @property + def pwm_auto(self): + """Read the automatically generated PWM configuration values + + These values can be used as defaults for future configurations. + + Returns: + tuple: (PWM_OFS_AUTO, PWM_GRAD_AUTO) where: + PWM_OFS_AUTO (0-255): Automatically determined offset value + PWM_GRAD_AUTO (0-255): Automatically determined gradient value + """ + pwm_auto = self.read_reg(self.PWM_AUTO) + pwm_ofs_auto = pwm_auto & 0xFF + pwm_grad_auto = (pwm_auto >> 16) & 0xFF + + return (pwm_ofs_auto, pwm_grad_auto) + + def set_pwm_config(self, + pwm_offset=36, # PWM amplitude offset + pwm_gradient=0, # PWM amplitude gradient + pwm_freq=1, # PWM frequency setting + pwm_autoscale=True, # Automatic amplitude scaling + pwm_autograd=True, # Automatic gradient adaptation + freewheel_mode=0, # Standstill mode + pwm_reg=4, # Regulation loop gradient + pwm_lim=12): # PWM scale limit + """Configure StealthChop PWM mode parameters + + Args: + pwm_offset (int): PWM amplitude offset (0-255) + pwm_gradient (int): PWM amplitude gradient (0-255) + pwm_freq (int): PWM frequency selection (0-3) + 0: fPWM=2/1024 fCLK + 1: fPWM=2/683 fCLK + 2: fPWM=2/512 fCLK + 3: fPWM=2/410 fCLK + pwm_autoscale (bool): Enable automatic current scaling + pwm_autograd (bool): Enable automatic gradient adaptation + freewheel_mode (int): Standstill mode when motor current is 0 (0-3) + 0: Normal operation + 1: Freewheeling + 2: Coil shorted using LS drivers + 3: Coil shorted using HS drivers + pwm_reg (int): Regulation loop gradient (1-15) + pwm_lim (int): PWM automatic scale amplitude limit (0-15) + """ + pwm_offset = max(0, min(pwm_offset, 255)) + pwm_gradient = max(0, min(pwm_gradient, 255)) + pwm_freq = max(0, min(pwm_freq, 3)) + freewheel_mode = max(0, min(freewheel_mode, 3)) + pwm_reg = max(1, min(pwm_reg, 15)) + pwm_lim = max(0, min(pwm_lim, 15)) + pwmconf = ( + (pwm_lim & 0x0F) << self.PWMCONF_PWM_LIM | + (pwm_reg & 0x0F) << self.PWMCONF_PWM_REG | + (freewheel_mode & 0x03) << self.PWMCONF_FREEWHEEL | + (int(pwm_autograd) & 0x01) << self.PWMCONF_PWM_AUTOGRAD | + (int(pwm_autoscale) & 0x01) << self.PWMCONF_PWM_AUTOSCALE | + (pwm_freq & 0x03) << self.PWMCONF_PWM_FREQ | + (pwm_gradient & 0xFF) << self.PWMCONF_PWM_GRAD | + (pwm_offset & 0xFF) << self.PWMCONF_PWM_OFS + ) + + self.write_reg(self.PWMCONF, pwmconf) + + @property + def stall_threshold(self): + """Get the StallGuard threshold for stall detection + + Returns: + int: StallGuard threshold value (0-255) + Lower values = more sensitive + """ + return self.read_reg(self.SGTHRS) + + @stall_threshold.setter + def stall_threshold(self, threshold): + """Set the StallGuard threshold for stall detection + + Args: + threshold (int): StallGuard threshold value (0-255) + Lower values = more sensitive stall detection + """ + # Clamp threshold to valid range + threshold = max(0, min(threshold, 255)) + self.write_reg(self.SGTHRS, threshold & 0xFF) + + @property + def stall_guard_result(self): + """Read the current StallGuard result + + Returns: + int: StallGuard value (0-1023), higher = less motor load + A value of 0 typically indicates a stalled motor + """ + return self.read_reg(self.SG_RESULT) + + @property + def coolstep_threshold(self): + """Get the TSTEP threshold for enabling CoolStep and StallGuard + + Returns: + int: TSTEP threshold value (0-1048575) + """ + return self.read_reg(self.TCOOLTHRS) + + @coolstep_threshold.setter + def coolstep_threshold(self, threshold): + """Set the TSTEP threshold for enabling CoolStep and StallGuard + + When TSTEP is between TCOOLTHRS and TPWMTHRS: + - StallGuard output signal becomes enabled + - CoolStep becomes enabled (if configured) + + Args: + threshold (int): TSTEP threshold value (0-1048575) + 0 = Disabled + """ + threshold = max(0, min(threshold, (1 << 20) - 1)) + self.write_reg(self.TCOOLTHRS, threshold) + + def configure_coolstep(self, + semin=0, # Minimum StallGuard value (0-15) + semax=0, # StallGuard hysteresis (0-15) + sedn=0, # Current down step speed (0-3) + seup=0, # Current up step width (0-3) + seimin=False): # Minimum current setting + """Configure CoolStep adaptive current scaling + + Args: + semin (int): Minimum StallGuard value for smart current control (0-15) + 0 = CoolStep disabled + semax (int): StallGuard hysteresis value (0-15) + sedn (int): Current down step speed (0-3) + 0: Slowest (for each 32 StallGuard values) + 1: Down step for each 8 StallGuard values + 2: Down step for each 2 StallGuard values + 3: Down step for each StallGuard value + seup (int): Current up step width (0-3) + 0: 1 step per measurement + 1: 2 steps per measurement + 2: 4 steps per measurement + 3: 8 steps per measurement + seimin (bool): Minimum current setting + False = 1/2 of current setting (IRUN) + True = 1/4 of current setting (IRUN) + """ + semin = max(0, min(semin, 15)) + semax = max(0, min(semax, 15)) + sedn = max(0, min(sedn, 3)) + seup = max(0, min(seup, 3)) + + coolconf = ( + (int(seimin) & 0x01) << self.COOLCONF_SEIMIN | + (sedn & 0x03) << self.COOLCONF_SEDN | + (semax & 0x0F) << self.COOLCONF_SEMAX | + (seup & 0x03) << self.COOLCONF_SEUP | + (semin & 0x0F) << self.COOLCONF_SEMIN + ) + + self.write_reg(self.COOLCONF, coolconf) + + def is_stalled(self): + """Check if the motor has stalled based on StallGuard threshold + + Note: TCOOLTHRS must be set and StallGuard must be active + (stepper must be moving at a speed where TSTEP > TCOOLTHRS) + + Returns: + bool: True if motor is stalled, False otherwise + """ + if self.coolstep_threshold == 0: + return False + sg_result = self.stall_guard_result + threshold = self.stall_threshold * 2 + return sg_result <= threshold + + def get_temperature_status(self): + """Get the current temperature status of the driver + + Returns: + dict: Temperature flags + 'warning': True if temperature warning is active + 'shutdown': True if overtemperature shutdown is active + 't120': True if temperature exceeds 120°C + 't143': True if temperature exceeds 143°C + 't150': True if temperature exceeds 150°C + 't157': True if temperature exceeds 157°C + """ + status = self.read_reg(self.DRV_STATUS) + + return { + 'warning': bool(status & (1 << self.DRV_STATUS_OTPW)), + 'shutdown': bool(status & (1 << self.DRV_STATUS_OT)), + 't120': bool(status & (1 << self.DRV_STATUS_T120)), + 't143': bool(status & (1 << self.DRV_STATUS_T143)), + 't150': bool(status & (1 << self.DRV_STATUS_T150)), + 't157': bool(status & (1 << self.DRV_STATUS_T157)) + } + + @property + def driver_status(self): + """Read driver status flags + + Returns: + dict: Dictionary with status flags including: + - standstill: Motor standstill detected + - stealth_mode: Driver is in StealthChop mode + - overtemperature_warning: Temperature warning flag + - overtemperature_shutdown: Overtemperature shutdown flag + - short_to_ground: Short to ground detected + - low_side_short: Short on low side detected + - open_load: Open load detected + - temperature: Temperature status flags + - current_scaling: Actual current scaling value + """ + status = self.read_reg(self.DRV_STATUS) + + return { + 'standstill': bool(status & (1 << self.DRV_STATUS_STST)), + 'stealth_mode': bool(status & (1 << self.DRV_STATUS_STEALTH)), + 'overtemperature_warning': bool(status & (1 << self.DRV_STATUS_OTPW)), + 'overtemperature_shutdown': bool(status & (1 << self.DRV_STATUS_OT)), + 'short_to_ground': bool(status & ((1 << self.DRV_STATUS_S2GA) | + (1 << self.DRV_STATUS_S2GB))), + 'low_side_short': bool(status & ((1 << self.DRV_STATUS_S2VSA) | + (1 << self.DRV_STATUS_S2VSB))), + 'open_load': bool(status & ((1 << self.DRV_STATUS_OLA) | (1 << self.DRV_STATUS_OLB))), + 'temperature': { + 't120': bool(status & (1 << self.DRV_STATUS_T120)), + 't143': bool(status & (1 << self.DRV_STATUS_T143)), + 't150': bool(status & (1 << self.DRV_STATUS_T150)), + 't157': bool(status & (1 << self.DRV_STATUS_T157)) + }, + 'current_scaling': (status >> self.DRV_STATUS_CS_ACTUAL) & 0x1F + } + + @property + def global_status(self): + """Read global status flags + + Returns: + dict: Dictionary with global status flags: + - reset: Indicates IC has been reset + - driver_error: Driver has been shut down due to error + - undervoltage: Undervoltage on charge pump + """ + gstat = self.read_reg(self.GSTAT) + + return { + 'reset': bool(gstat & (1 << self.GSTAT_RESET)), + 'driver_error': bool(gstat & (1 << self.GSTAT_DRV_ERR)), + 'undervoltage': bool(gstat & (1 << self.GSTAT_UV_CP)) + } + + def clear_error_flags(self): + """Clear all error flags in GSTAT register + + This clears the reset, driver_error and undervoltage flags. + """ + # Write 1 to each bit to clear the flags + self.write_reg(self.GSTAT, 0x07) # 0b111 + + def interface_transmission_counter(self): + """Read the interface transmission counter + + This counter is incremented with each successful UART write access. + It can be used to verify that the UART communication is working correctly. + + Returns: + int: Number of successful UART transmissions (0-255) + """ + return self.read_reg(self.IFCNT) + + def set_freewheel_mode(self, mode): + """Set the freewheel mode for when motor current is 0 + + Args: + mode (int): Freewheel mode (0-3) + 0: Normal operation + 1: Freewheeling (motor can spin freely) + 2: Coil shorted using LS drivers (passive braking) + 3: Coil shorted using HS drivers + """ + mode = max(0, min(mode, 3)) + pwmconf = self.read_reg(self.PWMCONF) + pwmconf &= ~(0x03 << self.PWMCONF_FREEWHEEL) + pwmconf |= (mode & 0x03) << self.PWMCONF_FREEWHEEL + self.write_reg(self.PWMCONF, pwmconf) + + def set_pwm_frequency(self, freq): + """Set PWM frequency for StealthChop mode + + Args: + freq (int): PWM frequency selection (0-3) + 0: fPWM=2/1024 fCLK (~23kHz @ 12MHz clock) + 1: fPWM=2/683 fCLK (~35kHz @ 12MHz clock) + 2: fPWM=2/512 fCLK (~47kHz @ 12MHz clock) + 3: fPWM=2/410 fCLK (~58kHz @ 12MHz clock) + """ + freq = max(0, min(freq, 3)) + pwmconf = self.read_reg(self.PWMCONF) + pwmconf &= ~(0x03 << self.PWMCONF_PWM_FREQ) + pwmconf |= (freq & 0x03) << self.PWMCONF_PWM_FREQ + self.write_reg(self.PWMCONF, pwmconf) + + def release_motor(self): + """Release motor by setting hold current to zero + + This completely disables current to the motor when idle. + """ + ihold_irun = self.read_reg(self.IHOLD_IRUN) + ihold_irun &= ~0x1F + self.write_reg(self.IHOLD_IRUN, ihold_irun) + + def enable_motor(self, run_current=None): + """Enable the motor with specified current + + Args: + run_current: Run current 0-31 (None = use current setting) + """ + chopconf = self.read_reg(self.CHOPCONF) + if (chopconf & 0x0F) == 0: + chopconf = (chopconf & ~0x0F) | 4 + self.write_reg(self.CHOPCONF, chopconf) + pwmconf = self.read_reg(self.PWMCONF) + pwmconf &= ~(0x03 << self.PWMCONF_FREEWHEEL) # Clear freewheel bits + self.write_reg(self.PWMCONF, pwmconf) + if run_current is not None: + ihold_irun = self.read_reg(self.IHOLD_IRUN) + ihold_irun = (ihold_irun & ~(0x1F << 8)) | ((run_current & 0x1F) << 8) + self.write_reg(self.IHOLD_IRUN, ihold_irun) + + def disable_motor(self, mode="freewheel"): + """Disable the motor to prevent heat buildup + + Args: + mode: How to disable the motor + "release": Set current to zero but keep driver enabled + "freewheel": Set to freewheel mode and zero current + "powerdown": Completely disable driver (TOFF=0) + """ + if mode == "release": + ihold_irun = self.read_reg(self.IHOLD_IRUN) + ihold_irun &= ~0x1F + self.write_reg(self.IHOLD_IRUN, ihold_irun) + + elif mode == "freewheel": + ihold_irun = self.read_reg(self.IHOLD_IRUN) + ihold_irun &= ~0x1F + self.write_reg(self.IHOLD_IRUN, ihold_irun) + pwmconf = self.read_reg(self.PWMCONF) + pwmconf &= ~(0x03 << self.PWMCONF_FREEWHEEL) + pwmconf |= (1 << self.PWMCONF_FREEWHEEL) + self.write_reg(self.PWMCONF, pwmconf) + + elif mode == "powerdown": + chopconf = self.read_reg(self.CHOPCONF) + chopconf &= ~0x0F + self.write_reg(self.CHOPCONF, chopconf) diff --git a/TMC2209_Camera_Slider/CircuitPython/code.py b/TMC2209_Camera_Slider/CircuitPython/code.py new file mode 100644 index 000000000..b241b06cb --- /dev/null +++ b/TMC2209_Camera_Slider/CircuitPython/code.py @@ -0,0 +1,575 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import time +import supervisor +import rotaryio +import keypad +import board +import busio +import displayio +from adafruit_display_text import label +from fourwire import FourWire +from adafruit_st7789 import ST7789 +from adafruit_bitmap_font import bitmap_font +from adafruit_tmc2209 import TMC2209 + +displayio.release_displays() + +RAILS = 520 # length of rails in mm +microsteps = 128 +gear_ratio = 41 / 16 + +shot_velocities = [ + 20, + 15, + 10 +] + +keys = keypad.Keys((board.D2, board.A2, board.A3), value_when_pressed=False, pull=True) + +encoder = rotaryio.IncrementalEncoder(board.D7, board.D6) +last_position = None + +spi = board.SPI() +tft_cs = board.D10 +tft_dc = board.D8 + +display_bus = FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=board.D9) + +display = ST7789(display_bus, width=240, height=240, rowstart=80, auto_refresh=False) + +splash = displayio.Group() +display.root_group = splash + +bitmap = displayio.OnDiskBitmap("/icons.bmp") + +grid_bg = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader, + tile_height=100, tile_width=100, + x=(display.width - 100) // 2, + y=(display.height - 100) // 2) +splash.append(grid_bg) + +text_group = displayio.Group() +font = bitmap_font.load_font("/Arial-14.bdf") +title_text = "Camera Slider" +title_area = label.Label(font, text=title_text, color=0xFFFFFF) +title_area.anchor_point = (0.5, 0.0) +title_area.anchored_position = (display.width / 2, 25) +text_group.append(title_area) +splash.append(text_group) + +font = bitmap_font.load_font("/Arial-14.bdf") +text_area = label.Label(font, text="", color=0xFFFFFF) +text_area.anchor_point = (0.5, 1.0) +text_area.anchored_position = (display.width / 2, display.height - 25) +text_group.append(text_area) + +uart = busio.UART(tx=board.TX, rx=board.RX, baudrate=115200, timeout=0.1) + +driver1 = TMC2209(uart=uart, addr=0) +driver2 = TMC2209(tx_pin=board.D4, rx_pin=board.D5, addr=0) + +version1 = driver1.version +version2 = driver2.version +print(f"TMC2209 #1 Version: 0x{version1:02X}") +print(f"TMC2209 #2 Version: 0x{version2:02X}") + +driver1.microsteps = microsteps +print(driver1.microsteps) +driver2.microsteps = microsteps +print(driver2.microsteps) + +STEPS_PER_MM = 200 * microsteps / 8 +driver1.direction = False +driver2.direction = True + +last_pos = 0 +select = 0 +menu = 0 +time_mode = 0 +shot_mode = 0 +timelapse = True +movement_time = 0 +titles = ["Camera Slider", "Motor 1", "Motor 2", "Mode", + "Timelapse", "One-Shot", "Start?", "Running"] + +home_text = ["Press to Begin", "0"] +motor1_text = ["Slide to Start Point", "0"] +motor2_text = ["Move to Start", "Move to End", "0"] +mode_text = ["Timelapse", "One-Shot"] +time_text = ["1", "5", "10", "15", "30"] +shot_speeds = [10, 5, 2] +speeds = [] +shot_text = ["Slow", "Medium", "Fast"] +start_text = ["Go!", 0] +running_text = ["STOP!", "Pause/Resume"] +running_icons = [6, 7] +mode_icons = [3, 4] +sub_titles = [home_text, motor1_text, motor2_text, mode_text, + time_text, shot_text, start_text, running_text] +motor2_coordinates = [0.0, 0.0] +text_area.text = home_text[0] +display.refresh() + +def adv_menu(m): + m = (m + 1) % 8 + title_area.text = titles[m] + sub = sub_titles[m] + if m == 4: + grid_bg[0] = 3 + elif m == 5: + grid_bg[0] = 4 + elif m > 5: + grid_bg[0] = m - 1 + else: + grid_bg[0] = m + text_area.text = sub[0] + display.refresh() + return m + +motor1_movement = { + "is_active": False, + "current_step": 0, + "total_steps": 0, + "start_pos": 0, + "end_pos": 0, + "step_direction": 1, + "last_step_time": 0, + "step_interval": 0, + "is_paused": False, + "toggle_pause": False, + "stop_requested": False +} + +motor2_movement = { + "is_active": False, + "current_step": 0, + "total_steps": 0, + "start_pos": 0, + "end_pos": 0, + "step_direction": 1, + "last_step_time": 0, + "step_interval": 0, + "is_paused": False, + "toggle_pause": False, + "stop_requested": False +} + +# pylint: disable=too-many-branches, too-many-statements, inconsistent-return-statements + +def calculate_linear_velocity(steps_per_second, clock_frequency=12000000, + micro=128, scaling_factor=6): + frequency = steps_per_second * micro + vactual = int((frequency * (1 << 23)) / (clock_frequency * scaling_factor)) + vactual = max(-(1 << 23), min((1 << 23) - 1, vactual)) + return vactual + +def move_steps_over_time(camera_driver, start_position, end_position, + time_seconds, micro=128, ratio=None): + steps = abs(end_position - start_position) + + if camera_driver: + direction = -1 if end_position < start_position else 1 + time_seconds = time_seconds * 2 + else: + direction = 1 if driver1.direction else -1 + + if ratio is not None: + steps = steps / ratio + + total_microsteps = steps * micro + microsteps_per_second = total_microsteps / time_seconds + fCLK = 12000000 + if camera_driver: + vactual = int(microsteps_per_second / (fCLK / (1 << 24))) + else: + vactual = int(microsteps_per_second / (fCLK / (1 << 27))) + velocity = max(-(1 << 23), min((1 << 23) - 1, vactual)) + velocity *= direction + return velocity + +def calculate_timelapse_velocity(start_position, end_position, duration_seconds, micro=128, + clock_frequency=12000000, scaling_factor=6, min_velocity=100): + total_steps = abs(end_position - start_position) + steps_per_second = total_steps / duration_seconds + full_steps_per_second = steps_per_second / micro + vactual = calculate_linear_velocity(full_steps_per_second, clock_frequency, + micro, scaling_factor) + direction = -1 if end_position < start_position else 1 + if abs(vactual) < min_velocity and vactual != 0: + vactual = min_velocity * direction + return vactual + +def calculate_rail_velocity(total_steps, duration_sec, direction, + is_timelapse=True, micro=128, clock_frequency=12000000): + steps_per_second = total_steps / duration_sec + full_steps_per_second = steps_per_second / micro + if not is_timelapse: + base_scaling = 1.0 + min_velocity = 400 + vactual = int((full_steps_per_second * micro * (1 << 23)) + / (clock_frequency * base_scaling)) + vactual *= direction + if abs(vactual) < min_velocity: + vactual = min_velocity * direction + else: + base_scaling = 6.0 + min_velocity = 50 + vactual = int((full_steps_per_second * micro * (1 << 23)) / + (clock_frequency * base_scaling)) + vactual *= direction + if abs(vactual) < min_velocity: + vactual = min_velocity * direction + vactual = max(-(1 << 23), min((1 << 23) - 1, vactual)) + return vactual + +def move_motor_with_rotate(driver, movement_state, start_position=None, + end_position=None, duration_sec=0, micro=128): + if start_position is not None and end_position is not None and not movement_state["is_active"]: + if timelapse: + driver.enable_motor(run_current=20) + scaling_factor = 6 + min_velocity = 50 + velocity = calculate_timelapse_velocity( + start_position, + end_position, + duration_sec, + micro, + scaling_factor=scaling_factor, + min_velocity=min_velocity + ) + else: + driver.enable_motor(run_current=30) + velocity = calculate_rail_velocity( + int(RAILS*STEPS_PER_MM), + duration_sec, + movement_state["step_direction"], + is_timelapse=timelapse, + micro=micro + ) + initial_velocity = int(velocity * 0.2) + if abs(initial_velocity) < 200: + initial_velocity = 200 * (1 if velocity > 0 else -1) + driver.rotate(initial_velocity) + movement_state["initial_velocity"] = initial_velocity + movement_state["final_velocity"] = velocity + movement_state["ramp_up_done"] = False + movement_state["ramp_up_time"] = 500 + movement_state["total_steps"] = int(RAILS*STEPS_PER_MM) + movement_state["step_direction"] = 1 if end_position > start_position else -1 + movement_state["start_pos"] = 0 + movement_state["end_pos"] = int(RAILS*STEPS_PER_MM) + movement_state["movement_start_time"] = supervisor.ticks_ms() + movement_state["movement_duration_ms"] = duration_sec * 1000 + movement_state["is_active"] = True + movement_state["is_paused"] = False + return + movement_state["total_steps"] = int(RAILS*STEPS_PER_MM) + movement_state["step_direction"] = driver.direction + movement_state["start_pos"] = 0 + movement_state["end_pos"] = int(RAILS*STEPS_PER_MM) + + if duration_sec > 0 and movement_state["total_steps"] > 0: + movement_state["velocity"] = velocity + driver.rotate(velocity) + movement_state["movement_start_time"] = supervisor.ticks_ms() + movement_state["movement_duration_ms"] = duration_sec * 1000 + else: + default_velocity = 2000 * movement_state["step_direction"] + driver.rotate(default_velocity) + movement_state["movement_duration_ms"] = movement_state["total_steps"] * 10 + movement_state["movement_start_time"] = supervisor.ticks_ms() + movement_state["is_active"] = True + movement_state["is_paused"] = False + + if movement_state["is_active"] and movement_state["toggle_pause"]: + movement_state["is_paused"] = not movement_state["is_paused"] + movement_state["toggle_pause"] = False + if movement_state["is_paused"]: + driver.rotate(0) + movement_state["pause_time"] = supervisor.ticks_ms() + else: + elapsed_ms = movement_state["pause_time"] - movement_state["movement_start_time"] + remaining_ms = movement_state["movement_duration_ms"] - elapsed_ms + if remaining_ms > 0: + driver.rotate(movement_state["velocity"]) + movement_state["movement_start_time"] = supervisor.ticks_ms() - elapsed_ms + else: + driver.rotate(0) + driver.disable_motor() + movement_state["is_active"] = False + + if movement_state["is_active"] and movement_state["stop_requested"]: + driver.rotate(0) + driver.disable_motor() + movement_state["is_active"] = False + movement_state["stop_requested"] = False + return { + "active": False, + "complete": False, + "progress_percent": (supervisor.ticks_ms() - movement_state["movement_start_time"]) + / movement_state["movement_duration_ms"] * 100, + "stopped_by_user": True + } + + if movement_state["is_active"] and not movement_state["is_paused"]: + current_t = supervisor.ticks_ms() + e = current_t - movement_state["movement_start_time"] + if e >= movement_state["movement_duration_ms"]: + print("Movement time complete!") + driver.rotate(0) + driver.disable_motor() + movement_state["is_active"] = False + return { + "active": False, + "complete": True, + "progress_percent": 100, + "stopped_by_user": False + } + + return { + "active": movement_state["is_active"], + "paused": movement_state["is_paused"], + "progress_percent": (supervisor.ticks_ms() - movement_state["movement_start_time"]) / + movement_state["movement_duration_ms"] * 100 + if movement_state["is_active"] else 0, + "stopped_by_user": False + } + +def pause_resume_motor1(): + motor1_movement["toggle_pause"] = True + +def stop_motor1(): + driver1.disable_motor() + driver1.reset_position() + motor1_movement["stop_requested"] = True + +def pause_resume_motor2(): + motor2_movement["toggle_pause"] = True + +def stop_motor2(): + driver2.disable_motor() + driver2.reset_position() + motor2_movement["stop_requested"] = True + +def stop_all_motors(): + driver1.rotate(0) + driver2.rotate(0) + driver1.disable_motor() + driver2.disable_motor() + motor1_movement["is_active"] = False + motor2_movement["is_active"] = False + motor1_movement["stop_requested"] = False + motor2_movement["stop_requested"] = False + time.sleep(0.1) + +driver1.disable_motor() +driver1.reset_position() +driver2.reset_position() + +while True: + if motor1_movement["is_active"]: + current_time = supervisor.ticks_ms() + elapsed = current_time - motor1_movement["movement_start_time"] + if elapsed >= motor1_movement["movement_duration_ms"]: + driver1.rotate(0) + driver1.disable_motor() + motor1_movement["is_active"] = False + if motor2_movement["is_active"]: + current_time = supervisor.ticks_ms() + elapsed = current_time - motor2_movement["movement_start_time"] + if elapsed >= motor2_movement["movement_duration_ms"]: + driver2.rotate(0) + driver2.disable_motor() + motor2_movement["is_active"] = False + if menu == 7: + active_motors = 0 + progress1 = 0 + progress2 = 0 + if motor1_movement["is_active"]: + active_motors += 1 + current_time = supervisor.ticks_ms() + elapsed = current_time - motor1_movement["movement_start_time"] + progress1 = (elapsed / motor1_movement["movement_duration_ms"]) * 100 + if motor2_movement["is_active"]: + active_motors += 1 + current_time = supervisor.ticks_ms() + elapsed = current_time - motor2_movement["movement_start_time"] + progress2 = (elapsed / motor2_movement["movement_duration_ms"]) * 100 + if active_motors > 0: + avg_progress = (progress1 + progress2) / active_motors + text_area.text = f"{running_text[select]} {avg_progress:.1f}%" + display.refresh() + elif active_motors == 0 and (motor1_movement["movement_duration_ms"] > 0 + or motor2_movement["movement_duration_ms"] > 0): + text_area.text = "Movement Complete!" + display.refresh() + event = keys.events.get() + if event: + if event.pressed: + print(f"{event.key_number} pressed") + if event.key_number == 0: + if menu == 0: + menu = adv_menu(menu) + elif menu == 2: + if select == 0: + motor2_coordinates[select] = driver2.position + if select == 1: + motor2_coordinates[select] = driver2.position + select += 1 + text_area.text = motor2_text[select] + if select > 1: + select = 0 + menu = adv_menu(menu) + if motor2_coordinates[0] > motor2_coordinates[1]: + move = motor2_coordinates[0] - motor2_coordinates[1] + else: + move = motor2_coordinates[1] - motor2_coordinates[0] + move = -move + driver2.step(move) + elif menu == 3: + if select == 1: + timelapse = False + menu += 1 + select = 0 + else: + timelapse = True + menu = adv_menu(menu) + elif menu == 4: + menu += 1 + time_mode = select + menu = adv_menu(menu) + select = 0 + print(f"{time_text[time_mode]}, timelapse: {timelapse}") + elif menu == 5: + shot_mode = select + menu = adv_menu(menu) + select = 0 + print(f"{shot_text[shot_mode]}, timelapse: {timelapse}") + elif menu == 6: + menu = adv_menu(menu) + if timelapse: + movement_time = int(time_text[time_mode]) * 60 + print(f"starting a timelapse for {time_text[time_mode]} minutes") + status1 = move_motor_with_rotate( + driver1, + motor1_movement, + start_position=0, + end_position=int(RAILS * STEPS_PER_MM), + duration_sec=movement_time, + microsteps=microsteps + ) + if abs(motor2_coordinates[1] - motor2_coordinates[0]) > 0: + velocity2 = move_steps_over_time(camera_driver=True, + start_position=motor2_coordinates[0], + end_position=motor2_coordinates[1], + time_seconds=movement_time, + microsteps=microsteps, + ratio=gear_ratio) + print(f"driver2 velocity is: {velocity2}") + driver2.enable_motor(run_current=25) + driver2.rotate(velocity2) + motor2_movement["is_active"] = True + motor2_movement["start_pos"] = motor2_coordinates[0] + motor2_movement["end_pos"] = motor2_coordinates[1] + motor2_movement["movement_start_time"] = supervisor.ticks_ms() + motor2_movement["movement_duration_ms"] = movement_time * 1000 + motor2_movement["velocity"] = velocity2 + motor2_movement["total_steps"] = (abs(motor2_coordinates[1] - + motor2_coordinates[0])) + else: + print(f"starting a {shot_text[shot_mode]} one-shot") + movement_time = shot_velocities[shot_mode] + status1 = move_motor_with_rotate( + driver1, + motor1_movement, + start_position=0, + end_position=int(RAILS * STEPS_PER_MM), + duration_sec=movement_time, + microsteps=microsteps + ) + if abs(motor2_coordinates[1] - motor2_coordinates[0]) > 0: + velocity2 = move_steps_over_time(camera_driver=True, + start_position=motor2_coordinates[0], + end_position=motor2_coordinates[1], + time_seconds=movement_time, + microsteps=microsteps, + ratio=gear_ratio) + driver2.enable_motor(run_current=25) + driver2.rotate(velocity2) + motor2_movement["is_active"] = True + motor2_movement["start_pos"] = motor2_coordinates[0] + motor2_movement["end_pos"] = motor2_coordinates[1] + motor2_movement["movement_start_time"] = supervisor.ticks_ms() + motor2_movement["movement_duration_ms"] = movement_time * 1000 + motor2_movement["velocity"] = velocity2 + motor2_movement["total_steps"] = (abs(motor2_coordinates[1] - + motor2_coordinates[0])) + elif menu == 7: + if select == 0: + stop_all_motors() + text_area.text = "Stopping..." + menu = adv_menu(menu) + elif select == 1: + pause_resume_motor1() + pause_resume_motor2() + paused_state = motor1_movement["is_paused"] or motor2_movement["is_paused"] + text_area.text = "Paused" if paused_state else "Running" + display.refresh() + if event.key_number == 1: + if menu == 1: + driver1.direction = False + driver1.reset_position() + menu = adv_menu(menu) + elif menu == 7: + stop_all_motors() + menu = adv_menu(menu) + if event.key_number == 2: + if menu == 1: + driver1.direction = True + driver1.reset_position() + menu = adv_menu(menu) + elif menu == 7: + stop_all_motors() + menu = adv_menu(menu) + display.refresh() + pos = encoder.position + if pos != last_pos: + if pos > last_pos: + if menu == 2: + driver2.step(-10) + if menu == 3: + select = (select + 1) % 2 + text_area.text = mode_text[select] + grid_bg[0] = mode_icons[select] + if menu == 4: + select = (select + 1) % len(time_text) + text_area.text = time_text[select] + if menu == 5: + select = (select + 1) % len(shot_text) + text_area.text = shot_text[select] + if menu == 7: + select = (select + 1) % len(running_text) + text_area.text = running_text[select] + grid_bg[0] = running_icons[select] + else: + if menu == 2: + driver2.step(10) + if menu == 3: + select = (select - 1) % 2 + text_area.text = mode_text[select] + grid_bg[0] = mode_icons[select] + if menu == 4: + select = (select - 1) % len(time_text) + text_area.text = time_text[select] + if menu == 5: + select = (select - 1) % len(shot_text) + text_area.text = shot_text[select] + if menu == 7: + select = (select - 1) % len(running_text) + text_area.text = running_text[select] + grid_bg[0] = running_icons[select] + last_pos = pos + display.refresh() diff --git a/TMC2209_Camera_Slider/CircuitPython/generic_uart_device.py b/TMC2209_Camera_Slider/CircuitPython/generic_uart_device.py new file mode 100644 index 000000000..541623cc6 --- /dev/null +++ b/TMC2209_Camera_Slider/CircuitPython/generic_uart_device.py @@ -0,0 +1,46 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# pylint: disable=too-few-public-methods + +__version__ = "0.0.0+auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BusDevice.git" + +class GenericUARTDevice: + """Class for communicating with a device via generic UART read/write functions""" + + def __init__(self, uart, read_func=None, write_func=None, + readreg_func=None, writereg_func=None): + self._uart = uart + self._read_func = read_func + self._write_func = write_func + self._readreg_func = readreg_func + self._writereg_func = writereg_func + + def read(self, buffer: bytearray, length: int) -> int: + """Read raw data from device into buffer""" + if self._read_func is None: + return 0 + while self._uart.in_waiting: + self._uart.read() + return self._read_func(buffer, length) + + def write(self, buffer: bytes, length: int) -> int: + """Write raw data from buffer to device""" + if self._write_func is None: + return 0 + return self._write_func(buffer, length) + + def read_register(self, addr_buf: bytes, addr_len: int, + data_buf: bytearray, data_len: int) -> int: + """Read from device register""" + if self._readreg_func is None: + return 0 + return self._readreg_func(addr_buf, addr_len, data_buf, data_len) + + def write_register(self, addr_buf: bytes, addr_len: int, data_buf: bytes, data_len: int) -> int: + """Write to device register""" + if self._writereg_func is None: + return 0 + return self._writereg_func(addr_buf, addr_len, data_buf, data_len) diff --git a/TMC2209_Camera_Slider/CircuitPython/icons.bmp b/TMC2209_Camera_Slider/CircuitPython/icons.bmp new file mode 100644 index 000000000..49da8481f Binary files /dev/null and b/TMC2209_Camera_Slider/CircuitPython/icons.bmp differ diff --git a/TMC2209_Camera_Slider/PCB_Files/TMC2209_Camera_Slider_PCB_revB.brd b/TMC2209_Camera_Slider/PCB_Files/TMC2209_Camera_Slider_PCB_revB.brd new file mode 100644 index 000000000..7eae982ba --- /dev/null +++ b/TMC2209_Camera_Slider/PCB_Files/TMC2209_Camera_Slider_PCB_revB.brd @@ -0,0 +1,43161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +EN +UART +INDX +DIAG +MS2 +MS1 +STEP +DIR +GND +VDD +EN +UART +INDX +DIAG +MS2 +MS1 +STEP +DIR +GND +VDD +D9 +D8 +D7 +D6 +D5 +D4 +D3 +D2 +GND +GND +RX +TX +D+ +D10 +MOSI +MISO +SCK +A0 +A1 +A2 +A3 +3V +RST +GND +RAW +D- +GND +3V +VIN +EN +V+ +GND +MOTOR 1 +MOTOR 2 +A3 +A2 +D3 +D4 +D2 +2.2K +TFT +DISPLAY +3.3V +GND +SCK +MI +MO +CS +RST +DC +D8 +D9 +D10 +3.3V +GND +V+ +MS1 +MS2 +MS2 +MS1 +3.3V +3.3V +KB2040 +USB +MPM3601 +Camera Slider +Helper +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 + + +🐗 +⚙️ +⚙️ +v0, April 2025 +📸 +D6 +D7 +D4 +D5 +v1, April 2025 + + + + + + + + +<h2><b>microBuilder.eu</b> Eagle Footprint Library</h2> + +<p>Footprints for common components used in our projects and products. This is the same library that we use internally, and it is regularly updated. The newest version can always be found at <b>www.microBuilder.eu</b>. If you find this library useful, please feel free to purchase something from our online store. Please also note that all holes are optimised for metric drill bits!</p> + +<h3>Obligatory Warning</h3> +<p>While it probably goes without saying, there are no guarantees that the footprints or schematic symbols in this library are flawless, and we make no promises of fitness for production, prototyping or any other purpose. These libraries are provided for information puposes only, and are used at your own discretion. While we make every effort to produce accurate footprints, and many of the items found in this library have be proven in production, we can't make any promises of suitability for a specific purpose. If you do find any errors, though, please feel free to contact us at www.microbuilder.eu to let us know about it so that we can update the library accordingly!</p> + +<h3>License</h3> +<p>This work is placed in the public domain, and may be freely used for commercial and non-commercial work with the following conditions:</p> +<p>THIS SOFTWARE IS PROVIDED ''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 INSTITUTE 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. +</p> + + + + + + + + + + + + +3,0 + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + +<b>1x10 PIN HEADER</b> + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + +<b>PIN HEADER</b> + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + +DJ Jack 2.0mm PTH Right-Angle + + + + + + + + + + + + + + + + + + +>NAME +>VALUE +DC 2.0/2.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>RESISTOR</b><p> +type 0309, grid 12.5 mm + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +>NAME + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Generated from <b>thermalBonnet.sch</b><p> +by exp-lbrs.ulp + + +<b>JST XH Connector Long Pads (Package)</b><p> + +Wire to board connector. + +Pitch: 2,54 mm, (0.100")<p> +Number of pins: <b>2</b><b><P> + +<b>Created by Rembrandt Electronics</b><p> +<b>www.rembrandtelectronics.com</b><p> + + + + + + + + + +>NAME +>VALUE +1 + + + + + + + + + + + + + +<b>EAGLE Design Rules</b> +<p> +Die Standard-Design-Rules sind so gewählt, dass sie für +die meisten Anwendungen passen. Sollte ihre Platine +besondere Anforderungen haben, treffen Sie die erforderlichen +Einstellungen hier und speichern die Design Rules unter +einem neuen Namen ab. +<b>EAGLE Design Rules</b> +<p> +The default Design Rules have been set to cover +a wide range of applications. Your particular design +may have different requirements, so please make the +necessary adjustments and save your customized +design rules under a new name. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Since Version 6.2.2 text objects can contain more than one line, +which will not be processed correctly with this version. + + +Since Version 8.2, EAGLE supports online libraries. The ids +of those online libraries will not be understood (or retained) +with this version. + + +Since Version 8.3, EAGLE supports URNs for individual library +assets (packages, symbols, and devices). The URNs of those assets +will not be understood (or retained) with this version. + + +Since Version 8.3, EAGLE supports the association of 3D packages +with devices in libraries, schematics, and board files. Those 3D +packages will not be understood (or retained) with this version. + + + diff --git a/TMC2209_Camera_Slider/PCB_Files/TMC2209_Camera_Slider_PCB_revB.sch b/TMC2209_Camera_Slider/PCB_Files/TMC2209_Camera_Slider_PCB_revB.sch new file mode 100644 index 000000000..aa8d40410 --- /dev/null +++ b/TMC2209_Camera_Slider/PCB_Files/TMC2209_Camera_Slider_PCB_revB.sch @@ -0,0 +1,7570 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<h2><b>microBuilder.eu</b> Eagle Footprint Library</h2> + +<p>Footprints for common components used in our projects and products. This is the same library that we use internally, and it is regularly updated. The newest version can always be found at <b>www.microBuilder.eu</b>. If you find this library useful, please feel free to purchase something from our online store. Please also note that all holes are optimised for metric drill bits!</p> + +<h3>Obligatory Warning</h3> +<p>While it probably goes without saying, there are no guarantees that the footprints or schematic symbols in this library are flawless, and we make no promises of fitness for production, prototyping or any other purpose. These libraries are provided for information puposes only, and are used at your own discretion. While we make every effort to produce accurate footprints, and many of the items found in this library have be proven in production, we can't make any promises of suitability for a specific purpose. If you do find any errors, though, please feel free to contact us at www.microbuilder.eu to let us know about it so that we can update the library accordingly!</p> + +<h3>License</h3> +<p>This work is placed in the public domain, and may be freely used for commercial and non-commercial work with the following conditions:</p> +<p>THIS SOFTWARE IS PROVIDED ''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 INSTITUTE 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. +</p> + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>1x10 PIN HEADER</b> + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + +1x10 2.0mm Header Pins + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + +<p><b>Pin Headers</b><br/> +10 Pin, 0.1"/2.54mm pitch, SMT</p> +<p>4UCON: 06680</p> + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>Name +>Value + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + +<b>PIN HEADER</b> + + + + + +>NAME +>VALUE + + + + + + + + + + + +>NAME +>VALUE + + + + + + +<p><b>Pin Headers</b><br/> +4 Pin, 0.1"/2.54mm pitch, SMT</p> + + + + + +>NAME +>VALUE + + + + + + + +>NAME +>VALUE + + + + + + + +>NAME +>VALUE + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>PIN HEADER</b> + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>DRAWING_NAME +>LAST_DATE_TIME +>SHEET +Sheet: +Adafruit Industries + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>PIN HEADER</b> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>PIN HEADER</b> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Frame - A3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + +DJ Jack 2.0mm PTH Right-Angle + + + + + + + + + + + + + + + + + + +>NAME +>VALUE +DC 2.0/2.1 + + + + + + + + + + + + + + + + + + + + + + + + + + +2.0/2.1mm DC Jack - SMT +<p>4UConnector: 03267</p> +<p>Note: Small tRestrict polygon's were added to the ground pads to improve solderability when this part is used in combination with a ground pour. By default, Eagle will product four large bridges to the ground pour significantly increasing the heat distribution on the pads and preventing lead-free solder from reflowing in certain situations. For more details, see: http://www.microbuilder.eu/Blog/09-12-14/Reducing_Thermals_for_Large_Pads_in_Eagle.aspx</p> + + + + + + + + + + + + + + + + + + + + + + + + ++ +GND + + +>VALUE +>NAME + + + + + + + + + + + + + + +>NAME +>VALUE +DC 1.3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 +2 +A +B +C +>VALUE +>NAME +GND + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + +<p><b>Rotary Encoder with Built-In Switch</b></p> +<p><ul> +<li>PEC11 - 24 Step, PEC11-4215F-S24 - http://www.adafruit.com/products/377</li> +</ul></p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<p><b>DC Barrel Jack</b></p> +<p><b>DCJACK_1.3MM_PTH</b> - Through Hole 1.3mm Jack (4UConnector: 05536)</p> +<p><b>DCJACK_2MM_PTH</b> - Through Hole 2.0/2.1 Jack (4UConnector: 05537)</p> +<p><b>DCJACK_2MM_SMT</b> - SMT 2.0/2.1mm Jack(4UConnector: 03267)</p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>Supply Symbols</b><p> + GND, VCC, 0V, +5V, -5V, etc.<p> + Please keep in mind, that these devices are necessary for the + automatic wiring of the supply signals.<p> + The pin name defined in the symbol is identical to the net which is to be wired automatically.<p> + In this library the device names are the same as the pin names of the symbols, therefore the correct signal names appear next to the supply symbols in the schematic.<p> + <author>Created by librarian@cadsoft.de</author> + + + + + +>VALUE + + + + + +>VALUE + + + + + +>VALUE + + + + + +>VALUE + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + + + + + +<b>RESISTOR</b><p> +chip + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip, wave soldering + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip, wave soldering + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip, wave soldering + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR</b><p> +chip, wave soldering + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR</b><p> +chip + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip, wave soldering + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip + + + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip, wave soldering + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip, wave soldering + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip, wave soldering + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip + + + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip, wave soldering + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip + + + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +chip, wave soldering + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +MELF 0.10 W + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +MELF 0.25 W + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +MELF 0.12 W + + + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +MELF 0.10 W + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +MELF 0.25 W + + + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +MELF 0.25 W + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +MELF 0.12 W + + + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +MELF 0.25 W + + + + + + + + + + +>NAME +>VALUE + + + + + +<b>RESISTOR</b><p> +type 0204, grid 5 mm + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR</b><p> +type 0204, grid 7.5 mm + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR</b><p> +type 0207, grid 10 mm + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR</b><p> +type 0207, grid 12 mm + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + +<b>RESISTOR</b><p> +type 0207, grid 15mm + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + +<b>RESISTOR</b><p> +type 0207, grid 2.5 mm + + + + + + + +>NAME +>VALUE + + +<b>RESISTOR</b><p> +type 0207, grid 5 mm + + + + + + + +>NAME +>VALUE + + +<b>RESISTOR</b><p> +type 0207, grid 7.5 mm + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR</b><p> +type 0309, grid 10mm + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR</b><p> +type 0309, grid 12.5 mm + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR</b><p> +type 0411, grid 12.5 mm + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR</b><p> +type 0411, grid 15 mm + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR</b><p> +type 0411, grid 3.81 mm + + + + + + +>NAME +>VALUE + + + +<b>RESISTOR</b><p> +type 0414, grid 15 mm + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR</b><p> +type 0414, grid 5 mm + + + + + + +>NAME +>VALUE + + + +<b>RESISTOR</b><p> +type 0617, grid 17.5 mm + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR</b><p> +type 0617, grid 22.5 mm + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR</b><p> +type 0617, grid 5 mm + + + + + + +>NAME +>VALUE + + + +<b>RESISTOR</b><p> +type 0922, grid 22.5 mm + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + +<b>RESISTOR</b><p> +type 0613, grid 5 mm + + + + + + +>NAME +>VALUE + + + +<b>RESISTOR</b><p> +type 0613, grid 15 mm + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR</b><p> +type 0817, grid 22.5 mm + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE +0817 + + + + +<b>RESISTOR</b><p> +type 0817, grid 6.35 mm + + + + + + +>NAME +>VALUE +0817 + + + +<b>RESISTOR</b><p> +type V234, grid 12.5 mm + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR</b><p> +type V235, grid 17.78 mm + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>RESISTOR</b><p> +type V526-0, grid 2.5 mm + + + + + + + + + + +>NAME +>VALUE + + +<b>Mini MELF 0102 Axial</b> + + + + +>NAME +>VALUE + + + +<b>RESISTOR</b><p> +type 0922, grid 7.5 mm + + + + + + +>NAME +>VALUE +0922 + + + +<b>CECC Size RC2211</b> Reflow Soldering<p> +source Beyschlag + + + + + + +>NAME +>VALUE + + +<b>CECC Size RC2211</b> Wave Soldering<p> +source Beyschlag + + + + + + +>NAME +>VALUE + + +<b>CECC Size RC3715</b> Reflow Soldering<p> +source Beyschlag + + + + + + +>NAME +>VALUE + + +<b>CECC Size RC3715</b> Wave Soldering<p> +source Beyschlag + + + + + + +>NAME +>VALUE + + +<b>CECC Size RC6123</b> Reflow Soldering<p> +source Beyschlag + + + + + + +>NAME +>VALUE + + +<b>CECC Size RC6123</b> Wave Soldering<p> +source Beyschlag + + + + + + +>NAME +>VALUE + + +<b>RESISTOR</b><p> +type RDH, grid 15 mm + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE +RDH + + + + +<b>RESISTOR</b><p> +type 0204, grid 2.5 mm + + + + + + +>NAME +>VALUE + + +<b>RESISTOR</b><p> +type 0309, grid 2.5 mm + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + +<B>RESISTOR</B>, American symbol + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME + + + + + + + + + + + + + + + + + + + + + +3.5mm Terminal block +<p>http://www.ladyada.net/library/pcb/eaglelibrary.html<p> + + + + + + + + + + + + + + + + + + + + + +Generated from <b>thermalBonnet.sch</b><p> +by exp-lbrs.ulp + + +<b>JST XH Connector Long Pads (Package)</b><p> + +Wire to board connector. + +Pitch: 2,54 mm, (0.100")<p> +Number of pins: <b>2</b><b><P> + +<b>Created by Rembrandt Electronics</b><p> +<b>www.rembrandtelectronics.com</b><p> + + + + + + + + + +>NAME +>VALUE +1 + + +<b>JST XH Connector Round Pads (Package)</b><p> + +Wire to board connector. + +Pitch: 2,54 mm, (0.100")<p> +Number of pins: <b>2</b><b><P> + +<b>Created by Rembrandt Electronics</b><p> +<b>www.rembrandtelectronics.com</b><p> + + + + + + + + + +>NAME +>VALUE +1 + + + + + + +>NAME +>VALUE + + + + +>NAME + + + + +<b>JST XH Connector 2 Pin</b><p> + +Wire to board connector. + +Pitch: 2,54 mm, (0.100")<p> +Number of pins: <b>2</b><b><P> + +<b>Created by Rembrandt Electronics</b><p> +<b>www.rembrandtelectronics.com</b><p> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Power + + +TFT + + + + +TMC2209 Breakouts +KB2040 + + +JST Connectors + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Since Version 8.2, EAGLE supports online libraries. The ids +of those online libraries will not be understood (or retained) +with this version. + + +Since Version 8.3, EAGLE supports URNs for individual library +assets (packages, symbols, and devices). The URNs of those assets +will not be understood (or retained) with this version. + + +Since Version 8.3, EAGLE supports the association of 3D packages +with devices in libraries, schematics, and board files. Those 3D +packages will not be understood (or retained) with this version. + + + diff --git a/TMC2209_Camera_Slider/PCB_Files/TMC2209_Camera_Slider_PCB_revB_2025-05-12.zip b/TMC2209_Camera_Slider/PCB_Files/TMC2209_Camera_Slider_PCB_revB_2025-05-12.zip new file mode 100644 index 000000000..4d11ecdca Binary files /dev/null and b/TMC2209_Camera_Slider/PCB_Files/TMC2209_Camera_Slider_PCB_revB_2025-05-12.zip differ diff --git a/TMC2209_Camera_Slider/PCB_Files/TMC2209_Camera_Slider_PCB_revB_noPinguin.brd b/TMC2209_Camera_Slider/PCB_Files/TMC2209_Camera_Slider_PCB_revB_noPinguin.brd new file mode 100644 index 000000000..861a9b1ab --- /dev/null +++ b/TMC2209_Camera_Slider/PCB_Files/TMC2209_Camera_Slider_PCB_revB_noPinguin.brd @@ -0,0 +1,42002 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +EN +UART +INDX +DIAG +MS2 +MS1 +STEP +DIR +GND +VDD +EN +UART +INDX +DIAG +MS2 +MS1 +STEP +DIR +GND +VDD +D9 +D8 +D7 +D6 +D5 +D4 +D3 +D2 +GND +GND +RX +TX +D+ +D10 +MOSI +MISO +SCK +A0 +A1 +A2 +A3 +3V +RST +GND +RAW +D- +GND +3V +VIN +EN +V+ +GND +MOTOR 1 +MOTOR 2 +A3 +A2 +D3 +D4 +D2 +2.2K +TFT +DISPLAY +3.3V +GND +SCK +MI +MO +CS +RST +DC +D8 +D9 +D10 +3.3V +GND +V+ +MS1 +MS2 +MS2 +MS1 +3.3V +3.3V +KB2040 +USB +MPM3601 +Camera Slider +Helper +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +📷 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 +🎥 + + +🐗 +⚙️ +⚙️ +v0, April 2025 +📸 +D6 +D7 +D4 +D5 +v1, April 2025 + + + +<h2><b>microBuilder.eu</b> Eagle Footprint Library</h2> + +<p>Footprints for common components used in our projects and products. This is the same library that we use internally, and it is regularly updated. The newest version can always be found at <b>www.microBuilder.eu</b>. If you find this library useful, please feel free to purchase something from our online store. Please also note that all holes are optimised for metric drill bits!</p> + +<h3>Obligatory Warning</h3> +<p>While it probably goes without saying, there are no guarantees that the footprints or schematic symbols in this library are flawless, and we make no promises of fitness for production, prototyping or any other purpose. These libraries are provided for information puposes only, and are used at your own discretion. While we make every effort to produce accurate footprints, and many of the items found in this library have be proven in production, we can't make any promises of suitability for a specific purpose. If you do find any errors, though, please feel free to contact us at www.microbuilder.eu to let us know about it so that we can update the library accordingly!</p> + +<h3>License</h3> +<p>This work is placed in the public domain, and may be freely used for commercial and non-commercial work with the following conditions:</p> +<p>THIS SOFTWARE IS PROVIDED ''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 INSTITUTE 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. +</p> + + + + + + + + + + + + +3,0 + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + +<b>1x10 PIN HEADER</b> + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + +<b>PIN HEADER</b> + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + + +DJ Jack 2.0mm PTH Right-Angle + + + + + + + + + + + + + + + + + + +>NAME +>VALUE +DC 2.0/2.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>RESISTOR</b><p> +type 0309, grid 12.5 mm + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + + + +>NAME + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Generated from <b>thermalBonnet.sch</b><p> +by exp-lbrs.ulp + + +<b>JST XH Connector Long Pads (Package)</b><p> + +Wire to board connector. + +Pitch: 2,54 mm, (0.100")<p> +Number of pins: <b>2</b><b><P> + +<b>Created by Rembrandt Electronics</b><p> +<b>www.rembrandtelectronics.com</b><p> + + + + + + + + + +>NAME +>VALUE +1 + + + + + + + + + + + + + +<b>EAGLE Design Rules</b> +<p> +Die Standard-Design-Rules sind so gewählt, dass sie für +die meisten Anwendungen passen. Sollte ihre Platine +besondere Anforderungen haben, treffen Sie die erforderlichen +Einstellungen hier und speichern die Design Rules unter +einem neuen Namen ab. +<b>EAGLE Design Rules</b> +<p> +The default Design Rules have been set to cover +a wide range of applications. Your particular design +may have different requirements, so please make the +necessary adjustments and save your customized +design rules under a new name. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Since Version 6.2.2 text objects can contain more than one line, +which will not be processed correctly with this version. + + +Since Version 8.2, EAGLE supports online libraries. The ids +of those online libraries will not be understood (or retained) +with this version. + + +Since Version 8.3, EAGLE supports URNs for individual library +assets (packages, symbols, and devices). The URNs of those assets +will not be understood (or retained) with this version. + + +Since Version 8.3, EAGLE supports the association of 3D packages +with devices in libraries, schematics, and board files. Those 3D +packages will not be understood (or retained) with this version. + + + diff --git a/TMC2209_Motorized_Turntable/code.py b/TMC2209_Motorized_Turntable/code.py index 852dadb2f..fcd02425c 100644 --- a/TMC2209_Motorized_Turntable/code.py +++ b/TMC2209_Motorized_Turntable/code.py @@ -5,6 +5,7 @@ import asyncio import board import displayio +import i2cdisplaybus import adafruit_imageload from digitalio import DigitalInOut, Direction from adafruit_seesaw import seesaw, rotaryio, digitalio @@ -27,7 +28,7 @@ # oled oled_reset = board.D9 -display_bus = displayio.I2CDisplay(i2c, device_address=0x3D, reset=oled_reset) +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3D, reset=oled_reset) WIDTH = 128 HEIGHT = 64 display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=WIDTH, height=HEIGHT) diff --git a/Tilemap_Game_With_CircuitPython/code.py b/Tilemap_Game_With_CircuitPython/code.py index 49ac85252..36ee7b2db 100644 --- a/Tilemap_Game_With_CircuitPython/code.py +++ b/Tilemap_Game_With_CircuitPython/code.py @@ -443,17 +443,9 @@ def show_splash(new_text, color, vertical_offset=18): # Make the splash context splash = displayio.Group() -# CircuitPython 6 & 7 compatible - -# game message background bmp file -game_message_background = open("tilegame_assets/game_message_background.bmp", "rb") -odb = displayio.OnDiskBitmap(game_message_background) -bg_grid = displayio.TileGrid(odb, pixel_shader=getattr(odb, 'pixel_shader', displayio.ColorConverter())) - -# # CircuitPython 7+ compatible # game message background bmp file -# odb = displayio.OnDiskBitmap("tilegame_assets/game_message_background.bmp") -# bg_grid = displayio.TileGrid(odb, pixel_shader=odb.pixel_shader) +odb = displayio.OnDiskBitmap("tilegame_assets/game_message_background.bmp") +bg_grid = displayio.TileGrid(odb, pixel_shader=odb.pixel_shader) splash.append(bg_grid) diff --git a/Toddler_Timer/code.py b/Toddler_Timer/code.py index 5236402e9..bb8f76c3b 100755 --- a/Toddler_Timer/code.py +++ b/Toddler_Timer/code.py @@ -5,6 +5,7 @@ import time import board import displayio +import i2cdisplaybus import neopixel import digitalio from adafruit_seesaw import seesaw, rotaryio, digitalio @@ -41,7 +42,7 @@ # oled oled_reset = board.D9 -display_bus = displayio.I2CDisplay(i2c, device_address=0x3D, reset=oled_reset) +display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3D, reset=oled_reset) WIDTH = 128 HEIGHT = 64 display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=WIDTH, height=HEIGHT) diff --git a/Tombstone_Matrix_Prop-Maker/code.py b/Tombstone_Matrix_Prop-Maker/code.py index 52cfeb92b..15c552fa0 100644 --- a/Tombstone_Matrix_Prop-Maker/code.py +++ b/Tombstone_Matrix_Prop-Maker/code.py @@ -77,7 +77,7 @@ def scroll(line): audio = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WORD_SELECT, board.I2S_DATA) mixer = audiomixer.Mixer(voice_count=1, sample_rate=22050, channel_count=1, - bits_per_sample=16, samples_signed=True, buffer_size=32768) + bits_per_sample=16, samples_signed=True) mixer.voice[0].level = 1 audio.play(mixer) diff --git a/Toy_Robot_Xylophone/code.py b/Toy_Robot_Xylophone/code.py new file mode 100644 index 000000000..883db2585 --- /dev/null +++ b/Toy_Robot_Xylophone/code.py @@ -0,0 +1,97 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import os +from random import randint +import board +import usb_midi +import keypad +from adafruit_mcp230xx.mcp23017 import MCP23017 +import adafruit_midi +from adafruit_midi.note_on import NoteOn +from adafruit_midi.note_off import NoteOff +import adafruit_midi_parser + +# music_box plays back MIDI files on CP drive +# set to false for live MIDI over USB control +music_box = True +# define the notes that correspond to each solenoid +notes = [48, 50, 52, 53, 55, 57, 59, 60] + +key = keypad.Keys((board.BUTTON,), value_when_pressed=False, pull=True) + +i2c = board.STEMMA_I2C() +mcp = MCP23017(i2c) +noids = [] +for i in range(8): + noid = mcp.get_pin(i) + noid.switch_to_output(value=False) + noids.append(noid) +# pylint: disable=used-before-assignment, unused-argument, global-statement, no-self-use +if not music_box: + midi = adafruit_midi.MIDI( + midi_in=usb_midi.ports[0], in_channel=0, midi_out=usb_midi.ports[1], out_channel=0 + ) +else: + midi_files = [] + for filename in os.listdir('/'): + if filename.lower().endswith('.mid') and not filename.startswith('.'): + midi_files.append("/"+filename) + print(midi_files) + + class Custom_Player(adafruit_midi_parser.MIDIPlayer): + def on_note_on(self, note, velocity, channel): # noqa: PLR6301 + for z in range(len(notes)): + if notes[z] == note: + print(f"Playing note: {note}") + noids[z].value = True + + def on_note_off(self, note, velocity, channel): # noqa: PLR6301 + for z in range(len(notes)): + if notes[z] == note: + noids[z].value = False + + def on_end_of_track(self, track): # noqa: PLR6301 + print(f"End of track {track}") + for z in range(8): + noids[z].value = False + + def on_playback_complete(self): # noqa: PLR6301 + global now_playing + now_playing = False + for z in range(8): + noids[z].value = False + parser = adafruit_midi_parser.MIDIParser() + parser.parse(midi_files[randint(0, (len(midi_files) - 1))]) + player = Custom_Player(parser) + new_file = False + now_playing = False + +while True: + if music_box: + event = key.events.get() + if event: + if event.pressed: + now_playing = not now_playing + if now_playing: + new_file = True + if new_file: + parser.parse(midi_files[randint(0, (len(midi_files) - 1))]) + print(f"Successfully parsed! Found {len(parser.events)} events.") + print(f"BPM: {parser.bpm:.1f}") + print(f"Note Count: {parser.note_count}") + new_file = False + if now_playing: + player.play(loop=False) + + else: + msg = midi.receive() + if msg is not None: + for i in range(8): + noid_output = noids[i] + notes_played = notes[i] + if isinstance(msg, NoteOn) and msg.note == notes_played: + noid_output.value = True + elif isinstance(msg, NoteOff) and msg.note == notes_played: + noid_output.value = False diff --git a/Toy_Robot_Xylophone/song_1.mid b/Toy_Robot_Xylophone/song_1.mid new file mode 100644 index 000000000..87bbc1b8c Binary files /dev/null and b/Toy_Robot_Xylophone/song_1.mid differ diff --git a/Toy_Robot_Xylophone/song_2.mid b/Toy_Robot_Xylophone/song_2.mid new file mode 100644 index 000000000..bc4602a4b Binary files /dev/null and b/Toy_Robot_Xylophone/song_2.mid differ diff --git a/Toy_Robot_Xylophone/song_3.mid b/Toy_Robot_Xylophone/song_3.mid new file mode 100644 index 000000000..46fda0d23 Binary files /dev/null and b/Toy_Robot_Xylophone/song_3.mid differ diff --git a/Toy_Robot_Xylophone/song_4.mid b/Toy_Robot_Xylophone/song_4.mid new file mode 100644 index 000000000..0ee97a9a3 Binary files /dev/null and b/Toy_Robot_Xylophone/song_4.mid differ diff --git a/Tripler_PiCowbell_Demos/CircuitPython/code.py b/Tripler_PiCowbell_Demos/CircuitPython/code.py index 989d17894..16f71c7a8 100644 --- a/Tripler_PiCowbell_Demos/CircuitPython/code.py +++ b/Tripler_PiCowbell_Demos/CircuitPython/code.py @@ -7,6 +7,7 @@ from analogio import AnalogIn import adafruit_st7789 import displayio +import fourwire import neopixel from rainbowio import colorwheel from adafruit_display_text import label @@ -15,7 +16,7 @@ displayio.release_displays() spi = busio.SPI(clock=board.GP18, MOSI=board.GP19) -display_bus = displayio.FourWire(spi, command=board.GP20, chip_select=board.GP21, reset=None) +display_bus = fourwire.FourWire(spi, command=board.GP20, chip_select=board.GP21, reset=None) display = adafruit_st7789.ST7789(display_bus, width=240, height=240, rowstart=80, rotation=0) group = displayio.Group() diff --git a/Twitter_API/code.py b/Twitter_API/code.py deleted file mode 100644 index 06c3edafc..000000000 --- a/Twitter_API/code.py +++ /dev/null @@ -1,61 +0,0 @@ -# SPDX-FileCopyrightText: 2019 Dave Astels for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -""" -Twitter API for PyPortal. - -Adafruit invests time and resources providing this open source code. -Please support Adafruit and open source hardware by purchasing -products from Adafruit! - -Written by Dave Astels for Adafruit Industries -Copyright (c) 2019 Adafruit Industries -Licensed under the MIT license. - -All text above must be included in any redistribution. -""" - -#pylint:disable=invalid-name -import time -import board -from adafruit_pyportal import PyPortal - -try: - from secrets import secrets -except ImportError: - print("""WiFi settings are kept in secrets.py, please add them there! -the secrets dictionary must contain 'ssid' and 'password' at a minimum""") - raise - -# Set this to the username you'd like to display tweets from -username = 'codewisdom' - -# determine the current working directory -# needed so we know where to find files -cwd = ("/"+__file__).rsplit('/', 1)[0] -url = 'https://api.twitter.com/1.1/statuses/user_timeline.json?count=1&screen_name=' + username - - -# Initialize the pyportal object and let us know what data to fetch and where -# to display it -pyportal = PyPortal(url=url, - json_path=(0, 'text'), - status_neopixel=board.NEOPIXEL, - default_bg=cwd + '/twitter_background.bmp', - text_font=cwd+'/fonts/Helvetica-Bold-16.bdf', - text_position=(20, 60), - text_color=0xFFFFFF, - text_wrap=35, - caption_text='@' + username, - caption_font=cwd+'/fonts/Helvetica-Bold-16.bdf', - caption_position=(5, 210), - caption_color=0x808080) - -# Set OAuth2.0 Bearer Token -bearer_token = secrets['twitter_bearer_token'] -pyportal.set_headers({'Authorization': 'Bearer ' + bearer_token}) - -while True: - pyportal.fetch() - time.sleep(3600) # check every hour diff --git a/Two_Way_Servo_Telegraph/code.py b/Two_Way_Servo_Telegraph/code.py index 56ca08f29..e2f1c5683 100644 --- a/Two_Way_Servo_Telegraph/code.py +++ b/Two_Way_Servo_Telegraph/code.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries # SPDX-License-Identifier: MIT +from os import getenv import time import ssl import board @@ -14,22 +15,32 @@ from simpleio import map_range from adafruit_motor import servo +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + # select which display is running the code servo_one = True # servo_two = True -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise -# connect to adafruitio -aio_username = secrets["aio_username"] -aio_key = secrets["aio_key"] +# angles for servo +ANGLE_MIN = 0 +ANGLE_MAX = 180 -print("Connecting to %s" % secrets["ssid"]) -wifi.radio.connect(secrets["ssid"], secrets["password"]) -print("Connected to %s!" % secrets["ssid"]) +print(f"Connecting to {ssid}") +wifi.radio.connect(ssid, password) +print(f"Connected to {ssid}!") pool = socketpool.SocketPool(wifi.radio) requests = adafruit_requests.Session(pool, ssl.create_default_context()) @@ -51,9 +62,10 @@ out_feed = io.get_feed("touch-1") in_feed = io.get_feed("touch-2") except AdafruitIO_RequestError: - # if no feed exists, create one + # if no feed exists, create one and push the first value out_feed = io.create_new_feed("touch-1") in_feed = io.create_new_feed("touch-2") + io.send_data(in_feed["key"], float(abs((ANGLE_MAX-ANGLE_MIN)/2))) # setup for display 2 if servo_two: CALIB_MIN = 15668 @@ -63,9 +75,10 @@ out_feed = io.get_feed("touch-2") in_feed = io.get_feed("touch-1") except AdafruitIO_RequestError: - # if no feed exists, create one + # if no feed exists, create one and push the first value out_feed = io.create_new_feed("touch-2") in_feed = io.create_new_feed("touch-1") + io.send_data(in_feed["key"], float(abs((ANGLE_MAX-ANGLE_MIN)/2))) received_data = io.receive_data(in_feed["key"]) @@ -74,10 +87,6 @@ FEEDBACK_PIN = board.A2 touch = touchio.TouchIn(board.TX) -# angles for servo -ANGLE_MIN = 0 -ANGLE_MAX = 180 - # servo setup pwm = pwmio.PWMOut(SERVO_PIN, duty_cycle=2 ** 15, frequency=50) servo = servo.Servo(pwm) diff --git a/USB_Host_BFF_Examples/Arduino_USB_Host_BFF_DeviceInfo/.metro_m4_tinyusb.test.only b/USB_Host_BFF_Examples/Arduino_USB_Host_BFF_DeviceInfo/.metro_m4_tinyusb.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/USB_Host_BFF_Examples/Arduino_USB_Host_BFF_DeviceInfo/Arduino_USB_Host_BFF_DeviceInfo.ino b/USB_Host_BFF_Examples/Arduino_USB_Host_BFF_DeviceInfo/Arduino_USB_Host_BFF_DeviceInfo.ino index f629f8873..fa0fef0a1 100644 --- a/USB_Host_BFF_Examples/Arduino_USB_Host_BFF_DeviceInfo/Arduino_USB_Host_BFF_DeviceInfo.ino +++ b/USB_Host_BFF_Examples/Arduino_USB_Host_BFF_DeviceInfo/Arduino_USB_Host_BFF_DeviceInfo.ino @@ -45,6 +45,7 @@ #include "Adafruit_TinyUSB.h" #include "SPI.h" +// USB Host with MAX3421E Adafruit_USBH_Host USBHost(&SPI, A1, A2); // Language ID: English diff --git a/USB_Host_BFF_Examples/Arduino_USB_Host_BFF_HIDReport/.metro_m4_tinyusb.test.only b/USB_Host_BFF_Examples/Arduino_USB_Host_BFF_HIDReport/.metro_m4_tinyusb.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Keyboard/.feather_rp2040_usbhost_tinyusb.test.only b/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Keyboard/.feather_rp2040_usbhost_tinyusb.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Keyboard/usbh_helper.h b/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Keyboard/usbh_helper.h new file mode 100644 index 000000000..4f3cc5503 --- /dev/null +++ b/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Keyboard/usbh_helper.h @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: 2024 Ha Thach for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +#ifndef USBH_HELPER_H +#define USBH_HELPER_H + +#ifdef ARDUINO_ARCH_RP2040 + // pio-usb is required for rp2040 host + #include "pio_usb.h" + + // Pin D+ for host, D- = D+ + 1 + #ifndef PIN_USB_HOST_DP + #define PIN_USB_HOST_DP 16 + #endif + + // Pin for enabling Host VBUS. comment out if not used + #ifndef PIN_5V_EN + #define PIN_5V_EN 18 + #endif + + #ifndef PIN_5V_EN_STATE + #define PIN_5V_EN_STATE 1 + #endif +#endif // ARDUINO_ARCH_RP2040 + +#ifdef ARDUINO_ARCH_RP2350 + + // pio-usb is required for rp2040 host + #include "pio_usb.h" + + // Pin D+ for host, D- = D+ + 1 + #ifndef PIN_USB_HOST_DP + #define PIN_USB_HOST_DP 32 + #endif + + // Pin for enabling Host VBUS. comment out if not used + #ifndef PIN_5V_EN + #define PIN_5V_EN 29 + #endif + + #ifndef PIN_5V_EN_STATE + #define PIN_5V_EN_STATE 1 + #endif +#endif // ARDUINO_ARCH_RP2350 + +#include "Adafruit_TinyUSB.h" + +#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 + // USB Host using MAX3421E: SPI, CS, INT + #include "SPI.h" + + #if defined(ARDUINO_METRO_ESP32S2) + Adafruit_USBH_Host USBHost(&SPI, 15, 14); + #elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2) + Adafruit_USBH_Host USBHost(&SPI, 33, 15); + #else + // Default CS and INT are pin 10, 9 + Adafruit_USBH_Host USBHost(&SPI, 10, 9); + #endif +#else + // Native USB Host such as rp2040 + Adafruit_USBH_Host USBHost; +#endif + +//--------------------------------------------------------------------+ +// Helper Functions +//--------------------------------------------------------------------+ + +#ifdef ARDUINO_ARCH_RP2040 +static void rp2040_configure_pio_usb(void) { + //while ( !Serial ) delay(10); // wait for native usb + Serial.println("Core1 setup to run TinyUSB host with pio-usb"); + +#ifdef PIN_5V_EN + pinMode(PIN_5V_EN, OUTPUT); + digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE); +#endif + + pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG; + pio_cfg.pin_dp = PIN_USB_HOST_DP; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + // For pico-w, PIO is also used to communicate with cyw43 + // Therefore we need to alternate the pio-usb configuration + // details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46 + pio_cfg.sm_tx = 3; + pio_cfg.sm_rx = 2; + pio_cfg.sm_eop = 3; + pio_cfg.pio_rx_num = 0; + pio_cfg.pio_tx_num = 1; + pio_cfg.tx_ch = 9; +#endif + + USBHost.configure_pio_usb(1, &pio_cfg); +} +#endif + +#endif diff --git a/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Keyboard/usbhost_keyboard_simpletest.ino b/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Keyboard/usbhost_keyboard_simpletest.ino new file mode 100644 index 000000000..f03d72986 --- /dev/null +++ b/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Keyboard/usbhost_keyboard_simpletest.ino @@ -0,0 +1,222 @@ +// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This example demonstrates use of usb host with a standard HID boot keyboard. + * - Host depends on MCU: + * - rp2040: bit-banging 2 GPIOs with Pico-PIO-USB library (roothub port1) + * + * Requirements: + * - For rp2040: + * - Pico-PIO-USB library + * - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1 + * - Provide VBus (5v) and GND for peripheral + */ + +// USBHost is defined in usbh_helper.h +#include "usbh_helper.h" +#include "tusb.h" +#include "Adafruit_TinyUSB.h" + + +bool printed_blank = false; + +void setup() { + Serial.begin(115200); + + // configure pio-usb: defined in usbh_helper.h + rp2040_configure_pio_usb(); + + // run host stack on controller (rhport) 1 + // Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the + // host bit-banging processing works done in core1 to free up core0 for other works + USBHost.begin(1); + delay(3000); + Serial.print("USB D+ Pin:"); + Serial.println(PIN_USB_HOST_DP); + Serial.print("USB 5V Pin:"); + Serial.println(PIN_5V_EN); +} + +void loop() { + USBHost.task(); + Serial.flush(); + +} + +//--------------------------------------------------------------------+ +// HID Host Callback Functions +//--------------------------------------------------------------------+ + +void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) +{ + Serial.printf("HID device mounted (address %d, instance %d)\n", dev_addr, instance); + + // Start receiving HID reports + if (!tuh_hid_receive_report(dev_addr, instance)) + { + Serial.printf("Error: cannot request to receive report\n"); + } +} + +void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) +{ + Serial.printf("HID device unmounted (address %d, instance %d)\n", dev_addr, instance); +} + +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) { + + if (len > 0){ + + //debug print report data + // Serial.print("Report data: "); + // for (int i = 0; i < len; i++) { + // Serial.print(report[i], HEX); + // Serial.print(" "); + + // } + // Serial.println(); + + printKeyboardReport(report); + } + + // Continue to receive the next report + if (!tuh_hid_receive_report(dev_addr, instance)) { + Serial.println("Error: cannot request to receive report"); + } +} + +// Helper function to print key names +void printKeyName(uint8_t key) { + // This is a simplified list. Full HID keyboard has many more key codes + switch (key) { + case 0x04: Serial.print("A"); break; + case 0x05: Serial.print("B"); break; + case 0x06: Serial.print("C"); break; + case 0x07: Serial.print("D"); break; + case 0x08: Serial.print("E"); break; + case 0x09: Serial.print("F"); break; + case 0x0A: Serial.print("G"); break; + case 0x0B: Serial.print("H"); break; + case 0x0C: Serial.print("I"); break; + case 0x0D: Serial.print("J"); break; + case 0x0E: Serial.print("K"); break; + case 0x0F: Serial.print("L"); break; + case 0x10: Serial.print("M"); break; + case 0x11: Serial.print("N"); break; + case 0x12: Serial.print("O"); break; + case 0x13: Serial.print("P"); break; + case 0x14: Serial.print("Q"); break; + case 0x15: Serial.print("R"); break; + case 0x16: Serial.print("S"); break; + case 0x17: Serial.print("T"); break; + case 0x18: Serial.print("U"); break; + case 0x19: Serial.print("V"); break; + case 0x1A: Serial.print("W"); break; + case 0x1B: Serial.print("X"); break; + case 0x1C: Serial.print("Y"); break; + case 0x1D: Serial.print("Z"); break; + case 0x1E: Serial.print("1"); break; + case 0x1F: Serial.print("2"); break; + case 0x20: Serial.print("3"); break; + case 0x21: Serial.print("4"); break; + case 0x22: Serial.print("5"); break; + case 0x23: Serial.print("6"); break; + case 0x24: Serial.print("7"); break; + case 0x25: Serial.print("8"); break; + case 0x26: Serial.print("9"); break; + case 0x27: Serial.print("0"); break; + case 0x28: Serial.print("ENTER"); break; + case 0x29: Serial.print("ESC"); break; + case 0x2A: Serial.print("BACKSPACE"); break; + case 0x2B: Serial.print("TAB"); break; + case 0x2C: Serial.print("SPACE"); break; + case 0x2D: Serial.print("MINUS"); break; + case 0x2E: Serial.print("EQUAL"); break; + case 0x2F: Serial.print("LBRACKET"); break; + case 0x30: Serial.print("RBRACKET"); break; + case 0x31: Serial.print("BACKSLASH"); break; + case 0x33: Serial.print("SEMICOLON"); break; + case 0x34: Serial.print("QUOTE"); break; + case 0x35: Serial.print("GRAVE"); break; + case 0x36: Serial.print("COMMA"); break; + case 0x37: Serial.print("PERIOD"); break; + case 0x38: Serial.print("SLASH"); break; + case 0x39: Serial.print("CAPS_LOCK"); break; + case 0x4F: Serial.print("RIGHT_ARROW"); break; + case 0x50: Serial.print("LEFT_ARROW"); break; + case 0x51: Serial.print("DOWN_ARROW"); break; + case 0x52: Serial.print("UP_ARROW"); break; + default: + if (key >= 0x3A && key <= 0x45) { // F1-F12 + Serial.print("F"); + Serial.print(key - 0x3A + 1); + } else { + // For keys not handled above, just print the HID code + Serial.print("0x"); + Serial.print(key, HEX); + } + break; + } +} + +void printKeyboardReport(uint8_t const* report) { + // First byte contains modifier keys + uint8_t modifiers = report[0]; + + // Print modifier keys if pressed + if (modifiers > 0) { + Serial.print("Modifiers: "); + + if (modifiers & 0x01) Serial.print("LEFT_CTRL "); + if (modifiers & 0x02) Serial.print("LEFT_SHIFT "); + if (modifiers & 0x04) Serial.print("LEFT_ALT "); + if (modifiers & 0x08) Serial.print("LEFT_GUI "); + if (modifiers & 0x10) Serial.print("RIGHT_CTRL "); + if (modifiers & 0x20) Serial.print("RIGHT_SHIFT "); + if (modifiers & 0x40) Serial.print("RIGHT_ALT "); + if (modifiers & 0x80) Serial.print("RIGHT_GUI "); + + Serial.println(); + } + + // Second byte is reserved (usually 0) + + // Bytes 2-7 contain up to 6 key codes + bool keysPressed = false; + + for (int i = 2; i < 8; i++) { + uint8_t key = report[i]; + + // Skip if no key or error rollover + if (key == 0 || key == 1) { + continue; + } + + if (!keysPressed) { + Serial.print("Keys: "); + keysPressed = true; + } + + // Print key name based on HID Usage Tables for standard keyboard + printKeyName(key); + Serial.print(" "); + } + + if (keysPressed) { + Serial.println(); + } else if (modifiers == 0) { + Serial.println("No keys pressed"); + } +} diff --git a/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Mouse/usbhost_mouse_simpletest/.feather_rp2040_usbhost_tinyusb.test.only b/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Mouse/usbhost_mouse_simpletest/.feather_rp2040_usbhost_tinyusb.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Mouse/usbhost_mouse_simpletest/hid_mouse_reports.h b/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Mouse/usbhost_mouse_simpletest/hid_mouse_reports.h new file mode 100644 index 000000000..33ad947b1 --- /dev/null +++ b/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Mouse/usbhost_mouse_simpletest/hid_mouse_reports.h @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// HID reports for standard boot mouse + +// Byte indices for the gamepad report +#define BYTE_BUTTONS 0 // Left, right, middle click buttons +#define BYTE_DELTA_X 1 // Mouse movement horizontal +#define BYTE_DELTA_Y 2 // Mouse movement vertical + +#define BUTTON_NEUTRAL 0x00 +#define BUTTON_LEFT 0x01 +#define BUTTON_RIGHT 0x02 +#define BUTTON_MIDDLE 0x04 diff --git a/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Mouse/usbhost_mouse_simpletest/usbh_helper.h b/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Mouse/usbhost_mouse_simpletest/usbh_helper.h new file mode 100644 index 000000000..4f3cc5503 --- /dev/null +++ b/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Mouse/usbhost_mouse_simpletest/usbh_helper.h @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: 2024 Ha Thach for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +#ifndef USBH_HELPER_H +#define USBH_HELPER_H + +#ifdef ARDUINO_ARCH_RP2040 + // pio-usb is required for rp2040 host + #include "pio_usb.h" + + // Pin D+ for host, D- = D+ + 1 + #ifndef PIN_USB_HOST_DP + #define PIN_USB_HOST_DP 16 + #endif + + // Pin for enabling Host VBUS. comment out if not used + #ifndef PIN_5V_EN + #define PIN_5V_EN 18 + #endif + + #ifndef PIN_5V_EN_STATE + #define PIN_5V_EN_STATE 1 + #endif +#endif // ARDUINO_ARCH_RP2040 + +#ifdef ARDUINO_ARCH_RP2350 + + // pio-usb is required for rp2040 host + #include "pio_usb.h" + + // Pin D+ for host, D- = D+ + 1 + #ifndef PIN_USB_HOST_DP + #define PIN_USB_HOST_DP 32 + #endif + + // Pin for enabling Host VBUS. comment out if not used + #ifndef PIN_5V_EN + #define PIN_5V_EN 29 + #endif + + #ifndef PIN_5V_EN_STATE + #define PIN_5V_EN_STATE 1 + #endif +#endif // ARDUINO_ARCH_RP2350 + +#include "Adafruit_TinyUSB.h" + +#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 + // USB Host using MAX3421E: SPI, CS, INT + #include "SPI.h" + + #if defined(ARDUINO_METRO_ESP32S2) + Adafruit_USBH_Host USBHost(&SPI, 15, 14); + #elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2) + Adafruit_USBH_Host USBHost(&SPI, 33, 15); + #else + // Default CS and INT are pin 10, 9 + Adafruit_USBH_Host USBHost(&SPI, 10, 9); + #endif +#else + // Native USB Host such as rp2040 + Adafruit_USBH_Host USBHost; +#endif + +//--------------------------------------------------------------------+ +// Helper Functions +//--------------------------------------------------------------------+ + +#ifdef ARDUINO_ARCH_RP2040 +static void rp2040_configure_pio_usb(void) { + //while ( !Serial ) delay(10); // wait for native usb + Serial.println("Core1 setup to run TinyUSB host with pio-usb"); + +#ifdef PIN_5V_EN + pinMode(PIN_5V_EN, OUTPUT); + digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE); +#endif + + pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG; + pio_cfg.pin_dp = PIN_USB_HOST_DP; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + // For pico-w, PIO is also used to communicate with cyw43 + // Therefore we need to alternate the pio-usb configuration + // details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46 + pio_cfg.sm_tx = 3; + pio_cfg.sm_rx = 2; + pio_cfg.sm_eop = 3; + pio_cfg.pio_rx_num = 0; + pio_cfg.pio_tx_num = 1; + pio_cfg.tx_ch = 9; +#endif + + USBHost.configure_pio_usb(1, &pio_cfg); +} +#endif + +#endif diff --git a/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Mouse/usbhost_mouse_simpletest/usbhost_mouse_simpletest.ino b/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Mouse/usbhost_mouse_simpletest/usbhost_mouse_simpletest.ino new file mode 100644 index 000000000..8adaaa291 --- /dev/null +++ b/USB_Host_Examples/Arduino_Feather_RP2040_USB_Host_Mouse/usbhost_mouse_simpletest/usbhost_mouse_simpletest.ino @@ -0,0 +1,121 @@ +// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This example demonstrates use of usb host with a standard HID boot mouse. + * - Host depends on MCU: + * - rp2040: bit-banging 2 GPIOs with Pico-PIO-USB library (roothub port1) + * + * Requirements: + * - For rp2040: + * - Pico-PIO-USB library + * - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1 + * - Provide VBus (5v) and GND for peripheral + */ + +// USBHost is defined in usbh_helper.h +#include "usbh_helper.h" +#include "tusb.h" +#include "Adafruit_TinyUSB.h" +#include "hid_mouse_reports.h" + + +bool printed_blank = false; + +void setup() { + Serial.begin(115200); + + // configure pio-usb: defined in usbh_helper.h + rp2040_configure_pio_usb(); + + // run host stack on controller (rhport) 1 + // Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the + // host bit-banging processing works done in core1 to free up core0 for other works + USBHost.begin(1); + delay(3000); + Serial.print("USB D+ Pin:"); + Serial.println(PIN_USB_HOST_DP); + Serial.print("USB 5V Pin:"); + Serial.println(PIN_5V_EN); +} + +void loop() { + USBHost.task(); + Serial.flush(); + +} + +//--------------------------------------------------------------------+ +// HID Host Callback Functions +//--------------------------------------------------------------------+ + +void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) +{ + Serial.printf("HID device mounted (address %d, instance %d)\n", dev_addr, instance); + + // Start receiving HID reports + if (!tuh_hid_receive_report(dev_addr, instance)) + { + Serial.printf("Error: cannot request to receive report\n"); + } +} + +void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) +{ + Serial.printf("HID device unmounted (address %d, instance %d)\n", dev_addr, instance); +} + +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) { + + if (len > 0){ + + //debug print report data + // Serial.print("Report data: "); + // for (int i = 0; i < len; i++) { + // if (i == 0 || i == 3){ + // Serial.print(report[i], HEX); + // Serial.print(" "); + // }else { // i==1 or i==2 + // Serial.print((int8_t)report[i]); + // Serial.print(" "); + // } + // } + // Serial.println(); + + Serial.print("X: "); + Serial.print((int8_t)report[1]); + Serial.print(" "); + Serial.print("Y: "); + Serial.print((int8_t)report[2]); + Serial.print(" "); + + if (report[BYTE_BUTTONS] != BUTTON_NEUTRAL){ + if ((report[BYTE_BUTTONS] & BUTTON_LEFT) == BUTTON_LEFT){ + Serial.print("Left "); + } + if ((report[BYTE_BUTTONS] & BUTTON_RIGHT) == BUTTON_RIGHT){ + Serial.print("Right "); + } + if ((report[BYTE_BUTTONS] & BUTTON_MIDDLE) == BUTTON_MIDDLE){ + Serial.print("Middle "); + } + } + Serial.println(); + } + + // Continue to receive the next report + if (!tuh_hid_receive_report(dev_addr, instance)) { + Serial.println("Error: cannot request to receive report"); + } +} diff --git a/USB_Host_Examples/Arduino_Metro_RP2350_Mouse_USB_Host/usbhost_mouse_simpletest/.metro_rp2350_tinyusb.test.only b/USB_Host_Examples/Arduino_Metro_RP2350_Mouse_USB_Host/usbhost_mouse_simpletest/.metro_rp2350_tinyusb.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/USB_Host_Examples/Arduino_Metro_RP2350_Mouse_USB_Host/usbhost_mouse_simpletest/hid_mouse_reports.h b/USB_Host_Examples/Arduino_Metro_RP2350_Mouse_USB_Host/usbhost_mouse_simpletest/hid_mouse_reports.h new file mode 100644 index 000000000..33ad947b1 --- /dev/null +++ b/USB_Host_Examples/Arduino_Metro_RP2350_Mouse_USB_Host/usbhost_mouse_simpletest/hid_mouse_reports.h @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// HID reports for standard boot mouse + +// Byte indices for the gamepad report +#define BYTE_BUTTONS 0 // Left, right, middle click buttons +#define BYTE_DELTA_X 1 // Mouse movement horizontal +#define BYTE_DELTA_Y 2 // Mouse movement vertical + +#define BUTTON_NEUTRAL 0x00 +#define BUTTON_LEFT 0x01 +#define BUTTON_RIGHT 0x02 +#define BUTTON_MIDDLE 0x04 diff --git a/USB_Host_Examples/Arduino_Metro_RP2350_Mouse_USB_Host/usbhost_mouse_simpletest/usbh_helper.h b/USB_Host_Examples/Arduino_Metro_RP2350_Mouse_USB_Host/usbhost_mouse_simpletest/usbh_helper.h new file mode 100644 index 000000000..4f3cc5503 --- /dev/null +++ b/USB_Host_Examples/Arduino_Metro_RP2350_Mouse_USB_Host/usbhost_mouse_simpletest/usbh_helper.h @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: 2024 Ha Thach for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +#ifndef USBH_HELPER_H +#define USBH_HELPER_H + +#ifdef ARDUINO_ARCH_RP2040 + // pio-usb is required for rp2040 host + #include "pio_usb.h" + + // Pin D+ for host, D- = D+ + 1 + #ifndef PIN_USB_HOST_DP + #define PIN_USB_HOST_DP 16 + #endif + + // Pin for enabling Host VBUS. comment out if not used + #ifndef PIN_5V_EN + #define PIN_5V_EN 18 + #endif + + #ifndef PIN_5V_EN_STATE + #define PIN_5V_EN_STATE 1 + #endif +#endif // ARDUINO_ARCH_RP2040 + +#ifdef ARDUINO_ARCH_RP2350 + + // pio-usb is required for rp2040 host + #include "pio_usb.h" + + // Pin D+ for host, D- = D+ + 1 + #ifndef PIN_USB_HOST_DP + #define PIN_USB_HOST_DP 32 + #endif + + // Pin for enabling Host VBUS. comment out if not used + #ifndef PIN_5V_EN + #define PIN_5V_EN 29 + #endif + + #ifndef PIN_5V_EN_STATE + #define PIN_5V_EN_STATE 1 + #endif +#endif // ARDUINO_ARCH_RP2350 + +#include "Adafruit_TinyUSB.h" + +#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 + // USB Host using MAX3421E: SPI, CS, INT + #include "SPI.h" + + #if defined(ARDUINO_METRO_ESP32S2) + Adafruit_USBH_Host USBHost(&SPI, 15, 14); + #elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2) + Adafruit_USBH_Host USBHost(&SPI, 33, 15); + #else + // Default CS and INT are pin 10, 9 + Adafruit_USBH_Host USBHost(&SPI, 10, 9); + #endif +#else + // Native USB Host such as rp2040 + Adafruit_USBH_Host USBHost; +#endif + +//--------------------------------------------------------------------+ +// Helper Functions +//--------------------------------------------------------------------+ + +#ifdef ARDUINO_ARCH_RP2040 +static void rp2040_configure_pio_usb(void) { + //while ( !Serial ) delay(10); // wait for native usb + Serial.println("Core1 setup to run TinyUSB host with pio-usb"); + +#ifdef PIN_5V_EN + pinMode(PIN_5V_EN, OUTPUT); + digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE); +#endif + + pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG; + pio_cfg.pin_dp = PIN_USB_HOST_DP; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + // For pico-w, PIO is also used to communicate with cyw43 + // Therefore we need to alternate the pio-usb configuration + // details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46 + pio_cfg.sm_tx = 3; + pio_cfg.sm_rx = 2; + pio_cfg.sm_eop = 3; + pio_cfg.pio_rx_num = 0; + pio_cfg.pio_tx_num = 1; + pio_cfg.tx_ch = 9; +#endif + + USBHost.configure_pio_usb(1, &pio_cfg); +} +#endif + +#endif diff --git a/USB_Host_Examples/Arduino_Metro_RP2350_Mouse_USB_Host/usbhost_mouse_simpletest/usbhost_mouse_simpletest.ino b/USB_Host_Examples/Arduino_Metro_RP2350_Mouse_USB_Host/usbhost_mouse_simpletest/usbhost_mouse_simpletest.ino new file mode 100644 index 000000000..8adaaa291 --- /dev/null +++ b/USB_Host_Examples/Arduino_Metro_RP2350_Mouse_USB_Host/usbhost_mouse_simpletest/usbhost_mouse_simpletest.ino @@ -0,0 +1,121 @@ +// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This example demonstrates use of usb host with a standard HID boot mouse. + * - Host depends on MCU: + * - rp2040: bit-banging 2 GPIOs with Pico-PIO-USB library (roothub port1) + * + * Requirements: + * - For rp2040: + * - Pico-PIO-USB library + * - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1 + * - Provide VBus (5v) and GND for peripheral + */ + +// USBHost is defined in usbh_helper.h +#include "usbh_helper.h" +#include "tusb.h" +#include "Adafruit_TinyUSB.h" +#include "hid_mouse_reports.h" + + +bool printed_blank = false; + +void setup() { + Serial.begin(115200); + + // configure pio-usb: defined in usbh_helper.h + rp2040_configure_pio_usb(); + + // run host stack on controller (rhport) 1 + // Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the + // host bit-banging processing works done in core1 to free up core0 for other works + USBHost.begin(1); + delay(3000); + Serial.print("USB D+ Pin:"); + Serial.println(PIN_USB_HOST_DP); + Serial.print("USB 5V Pin:"); + Serial.println(PIN_5V_EN); +} + +void loop() { + USBHost.task(); + Serial.flush(); + +} + +//--------------------------------------------------------------------+ +// HID Host Callback Functions +//--------------------------------------------------------------------+ + +void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) +{ + Serial.printf("HID device mounted (address %d, instance %d)\n", dev_addr, instance); + + // Start receiving HID reports + if (!tuh_hid_receive_report(dev_addr, instance)) + { + Serial.printf("Error: cannot request to receive report\n"); + } +} + +void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) +{ + Serial.printf("HID device unmounted (address %d, instance %d)\n", dev_addr, instance); +} + +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) { + + if (len > 0){ + + //debug print report data + // Serial.print("Report data: "); + // for (int i = 0; i < len; i++) { + // if (i == 0 || i == 3){ + // Serial.print(report[i], HEX); + // Serial.print(" "); + // }else { // i==1 or i==2 + // Serial.print((int8_t)report[i]); + // Serial.print(" "); + // } + // } + // Serial.println(); + + Serial.print("X: "); + Serial.print((int8_t)report[1]); + Serial.print(" "); + Serial.print("Y: "); + Serial.print((int8_t)report[2]); + Serial.print(" "); + + if (report[BYTE_BUTTONS] != BUTTON_NEUTRAL){ + if ((report[BYTE_BUTTONS] & BUTTON_LEFT) == BUTTON_LEFT){ + Serial.print("Left "); + } + if ((report[BYTE_BUTTONS] & BUTTON_RIGHT) == BUTTON_RIGHT){ + Serial.print("Right "); + } + if ((report[BYTE_BUTTONS] & BUTTON_MIDDLE) == BUTTON_MIDDLE){ + Serial.print("Middle "); + } + } + Serial.println(); + } + + // Continue to receive the next report + if (!tuh_hid_receive_report(dev_addr, instance)) { + Serial.println("Error: cannot request to receive report"); + } +} diff --git a/USB_Host_Examples/Arduino_Metro_RP2350_USB_Host_Keyboard/.metro_rp2350_tinyusb.test.only b/USB_Host_Examples/Arduino_Metro_RP2350_USB_Host_Keyboard/.metro_rp2350_tinyusb.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/USB_Host_Examples/Arduino_Metro_RP2350_USB_Host_Keyboard/usbh_helper.h b/USB_Host_Examples/Arduino_Metro_RP2350_USB_Host_Keyboard/usbh_helper.h new file mode 100644 index 000000000..4f3cc5503 --- /dev/null +++ b/USB_Host_Examples/Arduino_Metro_RP2350_USB_Host_Keyboard/usbh_helper.h @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: 2024 Ha Thach for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +#ifndef USBH_HELPER_H +#define USBH_HELPER_H + +#ifdef ARDUINO_ARCH_RP2040 + // pio-usb is required for rp2040 host + #include "pio_usb.h" + + // Pin D+ for host, D- = D+ + 1 + #ifndef PIN_USB_HOST_DP + #define PIN_USB_HOST_DP 16 + #endif + + // Pin for enabling Host VBUS. comment out if not used + #ifndef PIN_5V_EN + #define PIN_5V_EN 18 + #endif + + #ifndef PIN_5V_EN_STATE + #define PIN_5V_EN_STATE 1 + #endif +#endif // ARDUINO_ARCH_RP2040 + +#ifdef ARDUINO_ARCH_RP2350 + + // pio-usb is required for rp2040 host + #include "pio_usb.h" + + // Pin D+ for host, D- = D+ + 1 + #ifndef PIN_USB_HOST_DP + #define PIN_USB_HOST_DP 32 + #endif + + // Pin for enabling Host VBUS. comment out if not used + #ifndef PIN_5V_EN + #define PIN_5V_EN 29 + #endif + + #ifndef PIN_5V_EN_STATE + #define PIN_5V_EN_STATE 1 + #endif +#endif // ARDUINO_ARCH_RP2350 + +#include "Adafruit_TinyUSB.h" + +#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 + // USB Host using MAX3421E: SPI, CS, INT + #include "SPI.h" + + #if defined(ARDUINO_METRO_ESP32S2) + Adafruit_USBH_Host USBHost(&SPI, 15, 14); + #elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2) + Adafruit_USBH_Host USBHost(&SPI, 33, 15); + #else + // Default CS and INT are pin 10, 9 + Adafruit_USBH_Host USBHost(&SPI, 10, 9); + #endif +#else + // Native USB Host such as rp2040 + Adafruit_USBH_Host USBHost; +#endif + +//--------------------------------------------------------------------+ +// Helper Functions +//--------------------------------------------------------------------+ + +#ifdef ARDUINO_ARCH_RP2040 +static void rp2040_configure_pio_usb(void) { + //while ( !Serial ) delay(10); // wait for native usb + Serial.println("Core1 setup to run TinyUSB host with pio-usb"); + +#ifdef PIN_5V_EN + pinMode(PIN_5V_EN, OUTPUT); + digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE); +#endif + + pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG; + pio_cfg.pin_dp = PIN_USB_HOST_DP; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + // For pico-w, PIO is also used to communicate with cyw43 + // Therefore we need to alternate the pio-usb configuration + // details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46 + pio_cfg.sm_tx = 3; + pio_cfg.sm_rx = 2; + pio_cfg.sm_eop = 3; + pio_cfg.pio_rx_num = 0; + pio_cfg.pio_tx_num = 1; + pio_cfg.tx_ch = 9; +#endif + + USBHost.configure_pio_usb(1, &pio_cfg); +} +#endif + +#endif diff --git a/USB_Host_Examples/Arduino_Metro_RP2350_USB_Host_Keyboard/usbhost_keyboard_simpletest.ino b/USB_Host_Examples/Arduino_Metro_RP2350_USB_Host_Keyboard/usbhost_keyboard_simpletest.ino new file mode 100644 index 000000000..f03d72986 --- /dev/null +++ b/USB_Host_Examples/Arduino_Metro_RP2350_USB_Host_Keyboard/usbhost_keyboard_simpletest.ino @@ -0,0 +1,222 @@ +// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This example demonstrates use of usb host with a standard HID boot keyboard. + * - Host depends on MCU: + * - rp2040: bit-banging 2 GPIOs with Pico-PIO-USB library (roothub port1) + * + * Requirements: + * - For rp2040: + * - Pico-PIO-USB library + * - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1 + * - Provide VBus (5v) and GND for peripheral + */ + +// USBHost is defined in usbh_helper.h +#include "usbh_helper.h" +#include "tusb.h" +#include "Adafruit_TinyUSB.h" + + +bool printed_blank = false; + +void setup() { + Serial.begin(115200); + + // configure pio-usb: defined in usbh_helper.h + rp2040_configure_pio_usb(); + + // run host stack on controller (rhport) 1 + // Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the + // host bit-banging processing works done in core1 to free up core0 for other works + USBHost.begin(1); + delay(3000); + Serial.print("USB D+ Pin:"); + Serial.println(PIN_USB_HOST_DP); + Serial.print("USB 5V Pin:"); + Serial.println(PIN_5V_EN); +} + +void loop() { + USBHost.task(); + Serial.flush(); + +} + +//--------------------------------------------------------------------+ +// HID Host Callback Functions +//--------------------------------------------------------------------+ + +void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) +{ + Serial.printf("HID device mounted (address %d, instance %d)\n", dev_addr, instance); + + // Start receiving HID reports + if (!tuh_hid_receive_report(dev_addr, instance)) + { + Serial.printf("Error: cannot request to receive report\n"); + } +} + +void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) +{ + Serial.printf("HID device unmounted (address %d, instance %d)\n", dev_addr, instance); +} + +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) { + + if (len > 0){ + + //debug print report data + // Serial.print("Report data: "); + // for (int i = 0; i < len; i++) { + // Serial.print(report[i], HEX); + // Serial.print(" "); + + // } + // Serial.println(); + + printKeyboardReport(report); + } + + // Continue to receive the next report + if (!tuh_hid_receive_report(dev_addr, instance)) { + Serial.println("Error: cannot request to receive report"); + } +} + +// Helper function to print key names +void printKeyName(uint8_t key) { + // This is a simplified list. Full HID keyboard has many more key codes + switch (key) { + case 0x04: Serial.print("A"); break; + case 0x05: Serial.print("B"); break; + case 0x06: Serial.print("C"); break; + case 0x07: Serial.print("D"); break; + case 0x08: Serial.print("E"); break; + case 0x09: Serial.print("F"); break; + case 0x0A: Serial.print("G"); break; + case 0x0B: Serial.print("H"); break; + case 0x0C: Serial.print("I"); break; + case 0x0D: Serial.print("J"); break; + case 0x0E: Serial.print("K"); break; + case 0x0F: Serial.print("L"); break; + case 0x10: Serial.print("M"); break; + case 0x11: Serial.print("N"); break; + case 0x12: Serial.print("O"); break; + case 0x13: Serial.print("P"); break; + case 0x14: Serial.print("Q"); break; + case 0x15: Serial.print("R"); break; + case 0x16: Serial.print("S"); break; + case 0x17: Serial.print("T"); break; + case 0x18: Serial.print("U"); break; + case 0x19: Serial.print("V"); break; + case 0x1A: Serial.print("W"); break; + case 0x1B: Serial.print("X"); break; + case 0x1C: Serial.print("Y"); break; + case 0x1D: Serial.print("Z"); break; + case 0x1E: Serial.print("1"); break; + case 0x1F: Serial.print("2"); break; + case 0x20: Serial.print("3"); break; + case 0x21: Serial.print("4"); break; + case 0x22: Serial.print("5"); break; + case 0x23: Serial.print("6"); break; + case 0x24: Serial.print("7"); break; + case 0x25: Serial.print("8"); break; + case 0x26: Serial.print("9"); break; + case 0x27: Serial.print("0"); break; + case 0x28: Serial.print("ENTER"); break; + case 0x29: Serial.print("ESC"); break; + case 0x2A: Serial.print("BACKSPACE"); break; + case 0x2B: Serial.print("TAB"); break; + case 0x2C: Serial.print("SPACE"); break; + case 0x2D: Serial.print("MINUS"); break; + case 0x2E: Serial.print("EQUAL"); break; + case 0x2F: Serial.print("LBRACKET"); break; + case 0x30: Serial.print("RBRACKET"); break; + case 0x31: Serial.print("BACKSLASH"); break; + case 0x33: Serial.print("SEMICOLON"); break; + case 0x34: Serial.print("QUOTE"); break; + case 0x35: Serial.print("GRAVE"); break; + case 0x36: Serial.print("COMMA"); break; + case 0x37: Serial.print("PERIOD"); break; + case 0x38: Serial.print("SLASH"); break; + case 0x39: Serial.print("CAPS_LOCK"); break; + case 0x4F: Serial.print("RIGHT_ARROW"); break; + case 0x50: Serial.print("LEFT_ARROW"); break; + case 0x51: Serial.print("DOWN_ARROW"); break; + case 0x52: Serial.print("UP_ARROW"); break; + default: + if (key >= 0x3A && key <= 0x45) { // F1-F12 + Serial.print("F"); + Serial.print(key - 0x3A + 1); + } else { + // For keys not handled above, just print the HID code + Serial.print("0x"); + Serial.print(key, HEX); + } + break; + } +} + +void printKeyboardReport(uint8_t const* report) { + // First byte contains modifier keys + uint8_t modifiers = report[0]; + + // Print modifier keys if pressed + if (modifiers > 0) { + Serial.print("Modifiers: "); + + if (modifiers & 0x01) Serial.print("LEFT_CTRL "); + if (modifiers & 0x02) Serial.print("LEFT_SHIFT "); + if (modifiers & 0x04) Serial.print("LEFT_ALT "); + if (modifiers & 0x08) Serial.print("LEFT_GUI "); + if (modifiers & 0x10) Serial.print("RIGHT_CTRL "); + if (modifiers & 0x20) Serial.print("RIGHT_SHIFT "); + if (modifiers & 0x40) Serial.print("RIGHT_ALT "); + if (modifiers & 0x80) Serial.print("RIGHT_GUI "); + + Serial.println(); + } + + // Second byte is reserved (usually 0) + + // Bytes 2-7 contain up to 6 key codes + bool keysPressed = false; + + for (int i = 2; i < 8; i++) { + uint8_t key = report[i]; + + // Skip if no key or error rollover + if (key == 0 || key == 1) { + continue; + } + + if (!keysPressed) { + Serial.print("Keys: "); + keysPressed = true; + } + + // Print key name based on HID Usage Tables for standard keyboard + printKeyName(key); + Serial.print(" "); + } + + if (keysPressed) { + Serial.println(); + } else if (modifiers == 0) { + Serial.println("No keys pressed"); + } +} diff --git a/USB_Host_Examples/CircuitPython_Keyboard_Stdin/code.py b/USB_Host_Examples/CircuitPython_Keyboard_Stdin/code.py new file mode 100644 index 000000000..250dda0d9 --- /dev/null +++ b/USB_Host_Examples/CircuitPython_Keyboard_Stdin/code.py @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import sys +import supervisor + + +# main loop +while True: + # check how many bytes are available + available = supervisor.runtime.serial_bytes_available + + # if there are some bytes available + if available: + # read data from the keyboard input + c = sys.stdin.read(available) + # print the data that was read + print(c, end="") diff --git a/USB_Host_Examples/CircuitPython_Keyboard_USB_Host/code.py b/USB_Host_Examples/CircuitPython_Keyboard_USB_Host/code.py new file mode 100644 index 000000000..e9957f3a3 --- /dev/null +++ b/USB_Host_Examples/CircuitPython_Keyboard_USB_Host/code.py @@ -0,0 +1,166 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import array + +import usb +import adafruit_usb_host_descriptors + +#interface index, and endpoint addresses for USB Device instance +kbd_interface_index = None +kbd_endpoint_address = None +keyboard = None + +# scan for connected USB devices +for device in usb.core.find(find_all=True): + # check for boot keyboard endpoints on this device + kbd_interface_index, kbd_endpoint_address = ( + adafruit_usb_host_descriptors.find_boot_keyboard_endpoint(device) + ) + # if a boot keyboard interface index and endpoint address were found + if kbd_interface_index is not None and kbd_interface_index is not None: + keyboard = device + + # detach device from kernel if needed + if keyboard.is_kernel_driver_active(0): + keyboard.detach_kernel_driver(0) + + # set the configuration so it can be used + keyboard.set_configuration() + +if keyboard is None: + raise RuntimeError("No boot keyboard endpoint found") + +buf = array.array("b", [0] * 8) + + +def print_keyboard_report(report_data): + # Dictionary for modifier keys (first byte) + modifier_dict = { + 0x01: "LEFT_CTRL", + 0x02: "LEFT_SHIFT", + 0x04: "LEFT_ALT", + 0x08: "LEFT_GUI", + 0x10: "RIGHT_CTRL", + 0x20: "RIGHT_SHIFT", + 0x40: "RIGHT_ALT", + 0x80: "RIGHT_GUI", + } + + # Dictionary for key codes (main keys) + key_dict = { + 0x04: "A", + 0x05: "B", + 0x06: "C", + 0x07: "D", + 0x08: "E", + 0x09: "F", + 0x0A: "G", + 0x0B: "H", + 0x0C: "I", + 0x0D: "J", + 0x0E: "K", + 0x0F: "L", + 0x10: "M", + 0x11: "N", + 0x12: "O", + 0x13: "P", + 0x14: "Q", + 0x15: "R", + 0x16: "S", + 0x17: "T", + 0x18: "U", + 0x19: "V", + 0x1A: "W", + 0x1B: "X", + 0x1C: "Y", + 0x1D: "Z", + 0x1E: "1", + 0x1F: "2", + 0x20: "3", + 0x21: "4", + 0x22: "5", + 0x23: "6", + 0x24: "7", + 0x25: "8", + 0x26: "9", + 0x27: "0", + 0x28: "ENTER", + 0x29: "ESC", + 0x2A: "BACKSPACE", + 0x2B: "TAB", + 0x2C: "SPACE", + 0x2D: "MINUS", + 0x2E: "EQUAL", + 0x2F: "LBRACKET", + 0x30: "RBRACKET", + 0x31: "BACKSLASH", + 0x33: "SEMICOLON", + 0x34: "QUOTE", + 0x35: "GRAVE", + 0x36: "COMMA", + 0x37: "PERIOD", + 0x38: "SLASH", + 0x39: "CAPS_LOCK", + 0x4F: "RIGHT_ARROW", + 0x50: "LEFT_ARROW", + 0x51: "DOWN_ARROW", + 0x52: "UP_ARROW", + } + + # Add F1-F12 keys to the dictionary + for i in range(12): + key_dict[0x3A + i] = f"F{i + 1}" + + # First byte contains modifier keys + modifiers = report_data[0] + + # Print modifier keys if pressed + if modifiers > 0: + print("Modifiers:", end=" ") + + # Check each bit for modifiers and print if pressed + for bit, name in modifier_dict.items(): + if modifiers & bit: + print(name, end=" ") + + print() + + # Bytes 2-7 contain up to 6 key codes (byte 1 is reserved) + keys_pressed = False + + for i in range(2, 8): + key = report_data[i] + + # Skip if no key or error rollover + if key in {0, 1}: + continue + + if not keys_pressed: + print("Keys:", end=" ") + keys_pressed = True + + # Print key name based on dictionary lookup + if key in key_dict: + print(key_dict[key], end=" ") + else: + # For keys not in the dictionary, print the HID code + print(f"0x{key:02X}", end=" ") + + if keys_pressed: + print() + elif modifiers == 0: + print("No keys pressed") + + +while True: + # try to read data from the keyboard + try: + count = keyboard.read(kbd_endpoint_address, buf, timeout=10) + + # if there is no data it will raise USBTimeoutError + except usb.core.USBTimeoutError: + # Nothing to do if there is no data for this keyboard + continue + + print_keyboard_report(buf) diff --git a/USB_Host_Examples/CircuitPython_Mouse_Basic/code.py b/USB_Host_Examples/CircuitPython_Mouse_Basic/code.py new file mode 100644 index 000000000..7a331523b --- /dev/null +++ b/USB_Host_Examples/CircuitPython_Mouse_Basic/code.py @@ -0,0 +1,70 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +This example is made for a basic mouse with +two buttons and a wheel that can be pressed. + +It assumes there is a single mouse connected to USB Host. +""" +import array +import usb.core +import adafruit_usb_host_descriptors + +# button names +# This is ordered by bit position. +BUTTONS = ["left", "right", "middle"] + +# scan for connected USB device and loop over any found +for device in usb.core.find(find_all=True): + # print device info + print(f"{device.idVendor:04x}:{device.idProduct:04x}") + print(device.manufacturer, device.product) + print(device.serial_number) + + # try to find mouse endpoint on the current device. + mouse_interface_index, mouse_endpoint_address = ( + adafruit_usb_host_descriptors.find_boot_mouse_endpoint(device) + ) + if mouse_interface_index is not None and mouse_endpoint_address is not None: + mouse = device + print( + f"mouse interface: {mouse_interface_index} " + + f"endpoint_address: {hex(mouse_endpoint_address)}" + ) + + # detach the kernel driver if needed + if mouse.is_kernel_driver_active(0): + mouse.detach_kernel_driver(0) + + # set configuration on the mouse so we can use it + mouse.set_configuration() + + break + +# buffer to hold mouse data +buf = array.array("b", [0] * 8) + +# main loop +while True: + try: + # attempt to read data from the mouse + # 20ms timeout, so we don't block long if there + # is no data + count = mouse.read(0x81, buf, timeout=20) + except usb.core.USBTimeoutError: + # skip the rest of the loop if there is no data + continue + + # string with delta x, y values to print + out_str = f"{buf[1]},{buf[2]}" + + # loop over the button names + for i, button in enumerate(BUTTONS): + # check if each button is pressed using bitwise AND shifted + # to the appropriate index for this button + if buf[0] & (1 << i) != 0: + # append the button name to the string to show if + # it is being clicked. + out_str += f" {button}" + + print(out_str) diff --git a/USB_Host_Examples/CircuitPython_Mouse_Displayio_Cursor/code.py b/USB_Host_Examples/CircuitPython_Mouse_Displayio_Cursor/code.py new file mode 100644 index 000000000..c8ab2fb05 --- /dev/null +++ b/USB_Host_Examples/CircuitPython_Mouse_Displayio_Cursor/code.py @@ -0,0 +1,118 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +This example is made for a basic boot mouse with +two buttons and a wheel that can be pressed. + +It assumes there is a single mouse connected to USB Host, +and no other devices connected. +""" +import array +from displayio import Group, OnDiskBitmap, TileGrid +import supervisor +import terminalio +import usb.core +from adafruit_display_text.bitmap_label import Label +import adafruit_usb_host_descriptors + +display = supervisor.runtime.display + +# group to hold visual elements +main_group = Group() + +# make the group visible on the display +display.root_group = main_group + +# load the mouse cursor bitmap +mouse_bmp = OnDiskBitmap("mouse_cursor.bmp") + +# make the background pink pixels transparent +mouse_bmp.pixel_shader.make_transparent(0) + +# create a TileGrid for the mouse, using its bitmap and pixel_shader +mouse_tg = TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader) + +# move it to the center of the display +mouse_tg.x = display.width // 2 +mouse_tg.y = display.height // 2 + +# text label to show the x, y coordinates on the screen +output_lbl = Label( + terminalio.FONT, text=f"{mouse_tg.x},{mouse_tg.y}", color=0xFFFFFF, scale=1 +) + +# move it to the upper left corner +output_lbl.anchor_point = (0, 0) +output_lbl.anchored_position = (1, 1) + +# add it to the main group +main_group.append(output_lbl) + +# add the mouse tile grid to the main group +main_group.append(mouse_tg) + +# button names +# This is ordered by bit position. +BUTTONS = ["left", "right", "middle"] + +# scan for connected USB device and loop over any found +for device in usb.core.find(find_all=True): + # print device info + print(f"{device.idVendor:04x}:{device.idProduct:04x}") + print(device.manufacturer, device.product) + print(device.serial_number) + + # try to find mouse endpoint on the current device. + mouse_interface_index, mouse_endpoint_address = ( + adafruit_usb_host_descriptors.find_boot_mouse_endpoint(device) + ) + if mouse_interface_index is not None and mouse_endpoint_address is not None: + mouse = device + print( + f"mouse interface: {mouse_interface_index} " + + f"endpoint_address: {hex(mouse_endpoint_address)}" + ) + + # detach the kernel driver if needed + if mouse.is_kernel_driver_active(0): + mouse.detach_kernel_driver(0) + + # set configuration on the mouse so we can use it + mouse.set_configuration() + + break + +# buffer to hold mouse data +buf = array.array("b", [0] * 8) + +# main loop +while True: + try: + # attempt to read data from the mouse + # 20ms timeout, so we don't block long if there + # is no data + count = mouse.read(0x81, buf, timeout=20) + except usb.core.USBTimeoutError: + # skip the rest of the loop if there is no data + continue + + # update the mouse tilegrid x and y coordinates + # based on the delta values read from the mouse + mouse_tg.x = max(0, min(display.width - 1, mouse_tg.x + buf[1])) + mouse_tg.y = max(0, min(display.height - 1, mouse_tg.y + buf[2])) + + # string with updated coordinates for the text label + out_str = f"{mouse_tg.x},{mouse_tg.y}" + + # loop over the button names + for i, button in enumerate(BUTTONS): + # check if each button is pressed using bitwise AND shifted + # to the appropriate index for this button + if buf[0] & (1 << i) != 0: + # append the button name to the string to show if + # it is being clicked. + out_str += f" {button}" + + # update the text label with the new coordinates + # and buttons being pressed + output_lbl.text = out_str diff --git a/USB_Host_Examples/CircuitPython_Mouse_Displayio_Cursor/mouse_cursor.bmp b/USB_Host_Examples/CircuitPython_Mouse_Displayio_Cursor/mouse_cursor.bmp new file mode 100644 index 000000000..94ec32889 Binary files /dev/null and b/USB_Host_Examples/CircuitPython_Mouse_Displayio_Cursor/mouse_cursor.bmp differ diff --git a/USB_MIDI_Host2Host/.qt_py_rp2040.test.only b/USB_MIDI_Host2Host/.qt_py_rp2040.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/USB_MIDI_Host2Host/USBMIDIHost2Host_QTPyRP2040.ino b/USB_MIDI_Host2Host/USBMIDIHost2Host_QTPyRP2040.ino new file mode 100644 index 000000000..0e71c059e --- /dev/null +++ b/USB_MIDI_Host2Host/USBMIDIHost2Host_QTPyRP2040.ino @@ -0,0 +1,163 @@ +// SPDX-FileCopyrightText: 2025 John Park and Tod Kurt +// +// SPDX-License-Identifier: MIT + +// Use a DMX controller to drive NeoPixel strips +// Arduino Uno or Metro 328 + Conceptinetics DMX Shield +// Recieves incoming DMX messages from controller, translates to NeoPixel + +// MIDIHost2Host -- Connect two USB-MIDI host devices together +// 2019 @todbot / Tod E. Kurt +// 2025 @johnedgarpark / John E. Park + // This sketch is meant to be installed on two Adafruit QT Py RP2040s. +// The connections between the two QT Py RP2040s are +// QTPyA Gnd ----- QTPyB Gnd +// QTPyA TX ----- QTPyB RX +// QTPyA RX ----- QTPyB TX +// except it's done w PIO over the stemma qt cable (remove red wire first) + + +// When compiling: +// Install libraries: Adafruit_TinyUSB & MIDI +// Be sure to have updated all boards and libraries +// Select "Tools" -> "USB Stack" -> "TinyUSB" + +// The following libraries are required: +// Adafruit_TinyUSB library by Adafruit +// https://github.com/adafruit/Adafruit_TinyUSB_Arduino +// MIDI Library by Forty Seven Effects +// https://github.com/FortySevenEffects/arduino_midi_library + + +#include +#include +#include +#include + +// Adjust these for flashing the two different boards either "red" or "blue" +#define RED_BOARD +// #define BLUE_BOARD + + + +// Color definitions +uint32_t RED = 0xCC0000; +uint32_t DIM_RED = 0x3F0000; // 25% brightness red +uint32_t GREEN = 0x00DD00; +uint32_t BLUE = 0x0000CC; +uint32_t DIM_BLUE = 0x00003F; // 25% brightness blue +uint32_t YELLOW = 0xAAAA00; +char mfgstr[32] = "Lars Productions"; +#ifdef RED_BOARD + char prodstr[32] = "QTHost2 Red"; + uint32_t LED_COLOR = RED; + uint32_t LED_DIM_COLOR = DIM_RED; + SerialPIO pioserial(23, 22); +#else + char prodstr[32] = "QTHost2 Blue"; + uint32_t LED_COLOR = BLUE; + uint32_t LED_DIM_COLOR = DIM_BLUE; + SerialPIO pioserial(22, 23); +#endif + + +// NeoPixel settings +#define NUM_PIXELS 1 + +// NeoPixel RGB LED +Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUM_PIXELS, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); + +bool led_on = false; +uint32_t led_time; +uint32_t led_on_time = 50; // how long LED should blink +uint32_t last_color = LED_DIM_COLOR; // Track last active color + +// USB MIDI object +Adafruit_USBD_MIDI usb_midi; + +// Create instance of Arduino MIDI library, +// and attach usb_midi as the transport. +// MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, midiA); +MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, midiA); + +// Create instance of Arduino MIDI library, +// and attach HardwareSerial Serial1 (TrinketM0 pins 3 & 4 or TX/RX on a QT Py, this is automatic) +MIDI_CREATE_INSTANCE(HardwareSerial, pioserial, midiB); + + +void setup() +{ + + + #if defined(NEOPIXEL_POWER) + // If this board has a power control pin, we must set it to output and high + // in order to enable the NeoPixels. We put this in an #if defined so it can + // be reused for other boards without compilation errors + pinMode(NEOPIXEL_POWER, OUTPUT); + digitalWrite(NEOPIXEL_POWER, HIGH); + #endif + pixels.begin(); + pixels.setBrightness(60); + set_pixel(YELLOW); + + USBDevice.setManufacturerDescriptor(mfgstr); + USBDevice.setProductDescriptor (prodstr); + + // Initialize MIDI, and listen to all MIDI channels + // This will also call usb_midi's and Serial1's begin() + midiA.begin(MIDI_CHANNEL_OMNI); + midiB.begin(MIDI_CHANNEL_OMNI); + + midiA.turnThruOff(); + midiB.turnThruOff(); + +// Serial.begin(115200); + + // wait until device mounted + while ( !USBDevice.mounted() ) delay(1); + set_pixel(LED_COLOR); +} + +void loop() +{ + // read any new MIDI messages + if ( midiA.read() ) { + midiB.send(midiA.getType(), + midiA.getData1(), + midiA.getData2(), + midiA.getChannel()); + last_color = LED_DIM_COLOR; // Update last color to red + pixel_on(LED_COLOR); + // Serial.println("midiA"); + } + + if ( midiB.read() ) { + midiA.send(midiB.getType(), + midiB.getData1(), + midiB.getData2(), + midiB.getChannel()); + last_color = LED_DIM_COLOR; // Update last color to blue + pixel_on(LED_COLOR); + // Serial.println("midiB"); + } + + pixel_check(); +} + +void pixel_check() { + if( led_on && (millis() - led_time) > led_on_time ) { + led_on = false; + set_pixel(last_color); // Return to dimmed version of last active color + } +} + +void pixel_on(uint32_t color) { + set_pixel(color); + led_on = true; + led_time = millis(); +} + +void set_pixel(uint32_t color) { + pixels.setPixelColor(0, color); + pixels.show(); +} \ No newline at end of file diff --git a/USB_SNES_Gamepad/Arduino_Feather_RP2040_USB_Host/snes_gamepad_simpletest/.feather_rp2040_usbhost_tinyusb.test.only b/USB_SNES_Gamepad/Arduino_Feather_RP2040_USB_Host/snes_gamepad_simpletest/.feather_rp2040_usbhost_tinyusb.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/USB_SNES_Gamepad/Arduino_Feather_RP2040_USB_Host/snes_gamepad_simpletest/gamepad_reports.h b/USB_SNES_Gamepad/Arduino_Feather_RP2040_USB_Host/snes_gamepad_simpletest/gamepad_reports.h new file mode 100644 index 000000000..aea7c259f --- /dev/null +++ b/USB_SNES_Gamepad/Arduino_Feather_RP2040_USB_Host/snes_gamepad_simpletest/gamepad_reports.h @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// HID reports for USB SNES-like controller + +// Byte indices for the gamepad report +#define BYTE_DPAD_LEFT_RIGHT 0 // D-Pad left and right +#define BYTE_DPAD_UP_DOWN 1 // D-Pad up and down +// bytes 2,3,4 unused +#define BYTE_ABXY_BUTTONS 5 // A, B, X, Y +#define BYTE_OTHER_BUTTONS 6 // Shoulders, start, and select + + +#define DPAD_NEUTRAL 0x7F +// D-Pad directions +#define DPAD_UP 0x00 +#define DPAD_RIGHT 0xFF +#define DPAD_DOWN 0xFF +#define DPAD_LEFT 0x00 + + +// Face buttons (Byte[5]) +#define BUTTON_NEUTRAL 0x0F +#define BUTTON_X 0x1F +#define BUTTON_A 0x2F +#define BUTTON_B 0x4F +#define BUTTON_Y 0x8F + + +// Miscellaneous buttons (Byte[6]) +#define BUTTON_MISC_NEUTRAL 0x00 +#define BUTTON_LEFT_SHOULDER 0x01 +#define BUTTON_RIGHT_SHOULDER 0x02 +#define BUTTON_SELECT 0x10 +#define BUTTON_START 0x20 diff --git a/USB_SNES_Gamepad/Arduino_Feather_RP2040_USB_Host/snes_gamepad_simpletest/snes_gamepad_simpletest.ino b/USB_SNES_Gamepad/Arduino_Feather_RP2040_USB_Host/snes_gamepad_simpletest/snes_gamepad_simpletest.ino new file mode 100644 index 000000000..a4775caf3 --- /dev/null +++ b/USB_SNES_Gamepad/Arduino_Feather_RP2040_USB_Host/snes_gamepad_simpletest/snes_gamepad_simpletest.ino @@ -0,0 +1,157 @@ +// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This example demonstrates use of usb host with a SNES-like game controller + * - Host depends on MCU: + * - rp2040: bit-banging 2 GPIOs with Pico-PIO-USB library (roothub port1) + * + * Requirements: + * - For rp2040: + * - Pico-PIO-USB library + * - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1 + * - Provide VBus (5v) and GND for peripheral + * - CPU Speed must be either 120 or 240 MHz. Selected via "Menu -> CPU Speed" + */ + +// USBHost is defined in usbh_helper.h +#include "usbh_helper.h" +#include "tusb.h" +#include "Adafruit_TinyUSB.h" +#include "gamepad_reports.h" + +// HID report descriptor using TinyUSB's template +// Single Report (no ID) descriptor +uint8_t const desc_hid_report[] = { + TUD_HID_REPORT_DESC_GAMEPAD() +}; + +// USB HID object +Adafruit_USBD_HID usb_hid; + +// Report payload defined in src/class/hid/hid.h +// - For Gamepad Button Bit Mask see hid_gamepad_button_bm_t +// - For Gamepad Hat Bit Mask see hid_gamepad_hat_t +hid_gamepad_report_t gp; + +bool printed_blank = false; + +void setup() { + Serial.begin(115200); + + // configure pio-usb: defined in usbh_helper.h + rp2040_configure_pio_usb(); + + // run host stack on controller (rhport) 1 + USBHost.begin(1); + delay(3000); + Serial.print("USB D+ Pin:"); + Serial.println(PIN_USB_HOST_DP); + Serial.print("USB 5V Pin:"); + Serial.println(PIN_5V_EN); +} + +void loop() { + USBHost.task(); + Serial.flush(); + +} + +//--------------------------------------------------------------------+ +// HID Host Callback Functions +//--------------------------------------------------------------------+ + +void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) +{ + Serial.printf("HID device mounted (address %d, instance %d)\n", dev_addr, instance); + + // Start receiving HID reports + if (!tuh_hid_receive_report(dev_addr, instance)) + { + Serial.printf("Error: cannot request to receive report\n"); + } +} + +void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) +{ + Serial.printf("HID device unmounted (address %d, instance %d)\n", dev_addr, instance); +} + +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) { + + if (report[BYTE_DPAD_LEFT_RIGHT] != DPAD_NEUTRAL || + report[BYTE_DPAD_UP_DOWN] != DPAD_NEUTRAL || + report[BYTE_ABXY_BUTTONS] != BUTTON_NEUTRAL || + report[BYTE_OTHER_BUTTONS] != BUTTON_MISC_NEUTRAL){ + + printed_blank = false; + + //debug print report data + // Serial.print("Report data: "); + // for (int i = 0; i < len; i++) { + // Serial.print(report[i], HEX); + // Serial.print(" "); + // } + // Serial.println(); + + if (report[BYTE_DPAD_LEFT_RIGHT] == DPAD_LEFT){ + Serial.print("Left "); + }else if (report[BYTE_DPAD_LEFT_RIGHT] == DPAD_RIGHT){ + Serial.print("Right "); + } + + if (report[BYTE_DPAD_UP_DOWN] == DPAD_UP){ + Serial.print("Up "); + }else if (report[BYTE_DPAD_UP_DOWN] == DPAD_DOWN){ + Serial.print("Down "); + } + + if ((report[BYTE_ABXY_BUTTONS] & BUTTON_A) == BUTTON_A){ + Serial.print("A "); + } + if ((report[BYTE_ABXY_BUTTONS] & BUTTON_B) == BUTTON_B){ + Serial.print("B "); + } + if ((report[BYTE_ABXY_BUTTONS] & BUTTON_X) == BUTTON_X){ + Serial.print("X "); + } + if ((report[BYTE_ABXY_BUTTONS] & BUTTON_Y) == BUTTON_Y){ + Serial.print("Y "); + } + + if ((report[BYTE_OTHER_BUTTONS] & BUTTON_LEFT_SHOULDER) == BUTTON_LEFT_SHOULDER){ + Serial.print("Left Shoulder "); + } + if ((report[BYTE_OTHER_BUTTONS] & BUTTON_RIGHT_SHOULDER) == BUTTON_RIGHT_SHOULDER){ + Serial.print("Right Shoulder "); + } + if ((report[BYTE_OTHER_BUTTONS] & BUTTON_START) == BUTTON_START){ + Serial.print("Start "); + } + if ((report[BYTE_OTHER_BUTTONS] & BUTTON_SELECT) == BUTTON_SELECT){ + Serial.print("Select "); + } + Serial.println(); + } else { + if (! printed_blank){ + Serial.println("NEUTRAL"); + printed_blank = true; + } + } + + // Continue to receive the next report + if (!tuh_hid_receive_report(dev_addr, instance)) { + Serial.println("Error: cannot request to receive report"); + } +} diff --git a/USB_SNES_Gamepad/Arduino_Feather_RP2040_USB_Host/snes_gamepad_simpletest/usbh_helper.h b/USB_SNES_Gamepad/Arduino_Feather_RP2040_USB_Host/snes_gamepad_simpletest/usbh_helper.h new file mode 100644 index 000000000..daca1cb62 --- /dev/null +++ b/USB_SNES_Gamepad/Arduino_Feather_RP2040_USB_Host/snes_gamepad_simpletest/usbh_helper.h @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: 2024 Ha Thach for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +#ifndef USBH_HELPER_H +#define USBH_HELPER_H + +#ifdef ARDUINO_ARCH_RP2040 + // pio-usb is required for rp2040 host + #include "pio_usb.h" + + // Pin D+ for host, D- = D+ + 1 + #ifndef PIN_USB_HOST_DP + #define PIN_USB_HOST_DP 16 + #endif + + // Pin for enabling Host VBUS. comment out if not used + #ifndef PIN_5V_EN + #define PIN_5V_EN 18 + #endif + + #ifndef PIN_5V_EN_STATE + #define PIN_5V_EN_STATE 1 + #endif +#endif // ARDUINO_ARCH_RP2040 + +#ifdef ARDUINO_ARCH_RP2350 + + // pio-usb is required for rp2040 host + #include "pio_usb.h" + + // Pin D+ for host, D- = D+ + 1 + #ifndef PIN_USB_HOST_DP + #define PIN_USB_HOST_DP 32 + #endif + + // Pin for enabling Host VBUS. comment out if not used + #ifndef PIN_5V_EN + #define PIN_5V_EN 29 + #endif + + #ifndef PIN_5V_EN_STATE + #define PIN_5V_EN_STATE 1 + #endif +#endif // ARDUINO_ARCH_RP2350 + +#include "Adafruit_TinyUSB.h" + +#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 + // USB Host using MAX3421E: SPI, CS, INT + #include "SPI.h" + + #if defined(ARDUINO_METRO_ESP32S2) + Adafruit_USBH_Host USBHost(&SPI, 15, 14); + #elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2) + Adafruit_USBH_Host USBHost(&SPI, 33, 15); + #else + // Default CS and INT are pin 10, 9 + Adafruit_USBH_Host USBHost(&SPI, 10, 9); + #endif +#else + // Native USB Host such as rp2040 + Adafruit_USBH_Host USBHost; +#endif + +//--------------------------------------------------------------------+ +// Helper Functions +//--------------------------------------------------------------------+ + +#ifdef ARDUINO_ARCH_RP2040 +static void rp2040_configure_pio_usb(void) { + //while ( !Serial ) delay(10); // wait for native usb + Serial.println("Setup to run TinyUSB host with pio-usb"); + +#ifdef PIN_5V_EN + pinMode(PIN_5V_EN, OUTPUT); + digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE); +#endif + + pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG; + pio_cfg.pin_dp = PIN_USB_HOST_DP; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + // For pico-w, PIO is also used to communicate with cyw43 + // Therefore we need to alternate the pio-usb configuration + // details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46 + pio_cfg.sm_tx = 3; + pio_cfg.sm_rx = 2; + pio_cfg.sm_eop = 3; + pio_cfg.pio_rx_num = 0; + pio_cfg.pio_tx_num = 1; + pio_cfg.tx_ch = 9; +#endif + + USBHost.configure_pio_usb(1, &pio_cfg); +} +#endif + +#endif diff --git a/USB_SNES_Gamepad/Arduino_Metro_RP2350_USB_Host/snes_gamepad_simpletest/.metro_rp2350_tinyusb.test.only b/USB_SNES_Gamepad/Arduino_Metro_RP2350_USB_Host/snes_gamepad_simpletest/.metro_rp2350_tinyusb.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/USB_SNES_Gamepad/Arduino_Metro_RP2350_USB_Host/snes_gamepad_simpletest/gamepad_reports.h b/USB_SNES_Gamepad/Arduino_Metro_RP2350_USB_Host/snes_gamepad_simpletest/gamepad_reports.h new file mode 100644 index 000000000..aea7c259f --- /dev/null +++ b/USB_SNES_Gamepad/Arduino_Metro_RP2350_USB_Host/snes_gamepad_simpletest/gamepad_reports.h @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// HID reports for USB SNES-like controller + +// Byte indices for the gamepad report +#define BYTE_DPAD_LEFT_RIGHT 0 // D-Pad left and right +#define BYTE_DPAD_UP_DOWN 1 // D-Pad up and down +// bytes 2,3,4 unused +#define BYTE_ABXY_BUTTONS 5 // A, B, X, Y +#define BYTE_OTHER_BUTTONS 6 // Shoulders, start, and select + + +#define DPAD_NEUTRAL 0x7F +// D-Pad directions +#define DPAD_UP 0x00 +#define DPAD_RIGHT 0xFF +#define DPAD_DOWN 0xFF +#define DPAD_LEFT 0x00 + + +// Face buttons (Byte[5]) +#define BUTTON_NEUTRAL 0x0F +#define BUTTON_X 0x1F +#define BUTTON_A 0x2F +#define BUTTON_B 0x4F +#define BUTTON_Y 0x8F + + +// Miscellaneous buttons (Byte[6]) +#define BUTTON_MISC_NEUTRAL 0x00 +#define BUTTON_LEFT_SHOULDER 0x01 +#define BUTTON_RIGHT_SHOULDER 0x02 +#define BUTTON_SELECT 0x10 +#define BUTTON_START 0x20 diff --git a/USB_SNES_Gamepad/Arduino_Metro_RP2350_USB_Host/snes_gamepad_simpletest/snes_gamepad_simpletest.ino b/USB_SNES_Gamepad/Arduino_Metro_RP2350_USB_Host/snes_gamepad_simpletest/snes_gamepad_simpletest.ino new file mode 100644 index 000000000..a4775caf3 --- /dev/null +++ b/USB_SNES_Gamepad/Arduino_Metro_RP2350_USB_Host/snes_gamepad_simpletest/snes_gamepad_simpletest.ino @@ -0,0 +1,157 @@ +// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +/* This example demonstrates use of usb host with a SNES-like game controller + * - Host depends on MCU: + * - rp2040: bit-banging 2 GPIOs with Pico-PIO-USB library (roothub port1) + * + * Requirements: + * - For rp2040: + * - Pico-PIO-USB library + * - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1 + * - Provide VBus (5v) and GND for peripheral + * - CPU Speed must be either 120 or 240 MHz. Selected via "Menu -> CPU Speed" + */ + +// USBHost is defined in usbh_helper.h +#include "usbh_helper.h" +#include "tusb.h" +#include "Adafruit_TinyUSB.h" +#include "gamepad_reports.h" + +// HID report descriptor using TinyUSB's template +// Single Report (no ID) descriptor +uint8_t const desc_hid_report[] = { + TUD_HID_REPORT_DESC_GAMEPAD() +}; + +// USB HID object +Adafruit_USBD_HID usb_hid; + +// Report payload defined in src/class/hid/hid.h +// - For Gamepad Button Bit Mask see hid_gamepad_button_bm_t +// - For Gamepad Hat Bit Mask see hid_gamepad_hat_t +hid_gamepad_report_t gp; + +bool printed_blank = false; + +void setup() { + Serial.begin(115200); + + // configure pio-usb: defined in usbh_helper.h + rp2040_configure_pio_usb(); + + // run host stack on controller (rhport) 1 + USBHost.begin(1); + delay(3000); + Serial.print("USB D+ Pin:"); + Serial.println(PIN_USB_HOST_DP); + Serial.print("USB 5V Pin:"); + Serial.println(PIN_5V_EN); +} + +void loop() { + USBHost.task(); + Serial.flush(); + +} + +//--------------------------------------------------------------------+ +// HID Host Callback Functions +//--------------------------------------------------------------------+ + +void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) +{ + Serial.printf("HID device mounted (address %d, instance %d)\n", dev_addr, instance); + + // Start receiving HID reports + if (!tuh_hid_receive_report(dev_addr, instance)) + { + Serial.printf("Error: cannot request to receive report\n"); + } +} + +void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) +{ + Serial.printf("HID device unmounted (address %d, instance %d)\n", dev_addr, instance); +} + +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) { + + if (report[BYTE_DPAD_LEFT_RIGHT] != DPAD_NEUTRAL || + report[BYTE_DPAD_UP_DOWN] != DPAD_NEUTRAL || + report[BYTE_ABXY_BUTTONS] != BUTTON_NEUTRAL || + report[BYTE_OTHER_BUTTONS] != BUTTON_MISC_NEUTRAL){ + + printed_blank = false; + + //debug print report data + // Serial.print("Report data: "); + // for (int i = 0; i < len; i++) { + // Serial.print(report[i], HEX); + // Serial.print(" "); + // } + // Serial.println(); + + if (report[BYTE_DPAD_LEFT_RIGHT] == DPAD_LEFT){ + Serial.print("Left "); + }else if (report[BYTE_DPAD_LEFT_RIGHT] == DPAD_RIGHT){ + Serial.print("Right "); + } + + if (report[BYTE_DPAD_UP_DOWN] == DPAD_UP){ + Serial.print("Up "); + }else if (report[BYTE_DPAD_UP_DOWN] == DPAD_DOWN){ + Serial.print("Down "); + } + + if ((report[BYTE_ABXY_BUTTONS] & BUTTON_A) == BUTTON_A){ + Serial.print("A "); + } + if ((report[BYTE_ABXY_BUTTONS] & BUTTON_B) == BUTTON_B){ + Serial.print("B "); + } + if ((report[BYTE_ABXY_BUTTONS] & BUTTON_X) == BUTTON_X){ + Serial.print("X "); + } + if ((report[BYTE_ABXY_BUTTONS] & BUTTON_Y) == BUTTON_Y){ + Serial.print("Y "); + } + + if ((report[BYTE_OTHER_BUTTONS] & BUTTON_LEFT_SHOULDER) == BUTTON_LEFT_SHOULDER){ + Serial.print("Left Shoulder "); + } + if ((report[BYTE_OTHER_BUTTONS] & BUTTON_RIGHT_SHOULDER) == BUTTON_RIGHT_SHOULDER){ + Serial.print("Right Shoulder "); + } + if ((report[BYTE_OTHER_BUTTONS] & BUTTON_START) == BUTTON_START){ + Serial.print("Start "); + } + if ((report[BYTE_OTHER_BUTTONS] & BUTTON_SELECT) == BUTTON_SELECT){ + Serial.print("Select "); + } + Serial.println(); + } else { + if (! printed_blank){ + Serial.println("NEUTRAL"); + printed_blank = true; + } + } + + // Continue to receive the next report + if (!tuh_hid_receive_report(dev_addr, instance)) { + Serial.println("Error: cannot request to receive report"); + } +} diff --git a/USB_SNES_Gamepad/Arduino_Metro_RP2350_USB_Host/snes_gamepad_simpletest/usbh_helper.h b/USB_SNES_Gamepad/Arduino_Metro_RP2350_USB_Host/snes_gamepad_simpletest/usbh_helper.h new file mode 100644 index 000000000..daca1cb62 --- /dev/null +++ b/USB_SNES_Gamepad/Arduino_Metro_RP2350_USB_Host/snes_gamepad_simpletest/usbh_helper.h @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: 2024 Ha Thach for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + MIT license, check LICENSE for more information + Copyright (c) 2019 Ha Thach for Adafruit Industries + All text above, and the splash screen below must be included in + any redistribution +*********************************************************************/ + +#ifndef USBH_HELPER_H +#define USBH_HELPER_H + +#ifdef ARDUINO_ARCH_RP2040 + // pio-usb is required for rp2040 host + #include "pio_usb.h" + + // Pin D+ for host, D- = D+ + 1 + #ifndef PIN_USB_HOST_DP + #define PIN_USB_HOST_DP 16 + #endif + + // Pin for enabling Host VBUS. comment out if not used + #ifndef PIN_5V_EN + #define PIN_5V_EN 18 + #endif + + #ifndef PIN_5V_EN_STATE + #define PIN_5V_EN_STATE 1 + #endif +#endif // ARDUINO_ARCH_RP2040 + +#ifdef ARDUINO_ARCH_RP2350 + + // pio-usb is required for rp2040 host + #include "pio_usb.h" + + // Pin D+ for host, D- = D+ + 1 + #ifndef PIN_USB_HOST_DP + #define PIN_USB_HOST_DP 32 + #endif + + // Pin for enabling Host VBUS. comment out if not used + #ifndef PIN_5V_EN + #define PIN_5V_EN 29 + #endif + + #ifndef PIN_5V_EN_STATE + #define PIN_5V_EN_STATE 1 + #endif +#endif // ARDUINO_ARCH_RP2350 + +#include "Adafruit_TinyUSB.h" + +#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 + // USB Host using MAX3421E: SPI, CS, INT + #include "SPI.h" + + #if defined(ARDUINO_METRO_ESP32S2) + Adafruit_USBH_Host USBHost(&SPI, 15, 14); + #elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2) + Adafruit_USBH_Host USBHost(&SPI, 33, 15); + #else + // Default CS and INT are pin 10, 9 + Adafruit_USBH_Host USBHost(&SPI, 10, 9); + #endif +#else + // Native USB Host such as rp2040 + Adafruit_USBH_Host USBHost; +#endif + +//--------------------------------------------------------------------+ +// Helper Functions +//--------------------------------------------------------------------+ + +#ifdef ARDUINO_ARCH_RP2040 +static void rp2040_configure_pio_usb(void) { + //while ( !Serial ) delay(10); // wait for native usb + Serial.println("Setup to run TinyUSB host with pio-usb"); + +#ifdef PIN_5V_EN + pinMode(PIN_5V_EN, OUTPUT); + digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE); +#endif + + pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG; + pio_cfg.pin_dp = PIN_USB_HOST_DP; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + // For pico-w, PIO is also used to communicate with cyw43 + // Therefore we need to alternate the pio-usb configuration + // details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46 + pio_cfg.sm_tx = 3; + pio_cfg.sm_rx = 2; + pio_cfg.sm_eop = 3; + pio_cfg.pio_rx_num = 0; + pio_cfg.pio_tx_num = 1; + pio_cfg.tx_ch = 9; +#endif + + USBHost.configure_pio_usb(1, &pio_cfg); +} +#endif + +#endif diff --git a/USB_SNES_Gamepad/CircuitPython_USB_Host/code.py b/USB_SNES_Gamepad/CircuitPython_USB_Host/code.py new file mode 100644 index 000000000..0f69b992f --- /dev/null +++ b/USB_SNES_Gamepad/CircuitPython_USB_Host/code.py @@ -0,0 +1,172 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import array +import time +import usb.core +import adafruit_usb_host_descriptors + +# Set to true to print detailed information about all devices found +VERBOSE_SCAN = True + +BTN_DPAD_UPDOWN_INDEX = 1 +BTN_DPAD_RIGHTLEFT_INDEX = 0 +BTN_ABXY_INDEX = 5 +BTN_OTHER_INDEX = 6 + +DIR_IN = 0x80 +controller = None + +if VERBOSE_SCAN: + for device in usb.core.find(find_all=True): + controller = device + print("pid", hex(device.idProduct)) + print("vid", hex(device.idVendor)) + print("man", device.manufacturer) + print("product", device.product) + print("serial", device.serial_number) + print("config[0]:") + config_descriptor = adafruit_usb_host_descriptors.get_configuration_descriptor( + device, 0 + ) + + i = 0 + while i < len(config_descriptor): + descriptor_len = config_descriptor[i] + descriptor_type = config_descriptor[i + 1] + if descriptor_type == adafruit_usb_host_descriptors.DESC_CONFIGURATION: + config_value = config_descriptor[i + 5] + print(f" value {config_value:d}") + elif descriptor_type == adafruit_usb_host_descriptors.DESC_INTERFACE: + interface_number = config_descriptor[i + 2] + interface_class = config_descriptor[i + 5] + interface_subclass = config_descriptor[i + 6] + print(f" interface[{interface_number:d}]") + print( + f" class {interface_class:02x} subclass {interface_subclass:02x}" + ) + elif descriptor_type == adafruit_usb_host_descriptors.DESC_ENDPOINT: + endpoint_address = config_descriptor[i + 2] + if endpoint_address & DIR_IN: + print(f" IN {endpoint_address:02x}") + else: + print(f" OUT {endpoint_address:02x}") + i += descriptor_len + +# get the first device found +device = None +while device is None: + for d in usb.core.find(find_all=True): + device = d + break + time.sleep(0.1) + +# set configuration so we can read data from it +device.set_configuration() +print( + f"configuration set for {device.manufacturer}, {device.product}, {device.serial_number}" +) + +# Test to see if the kernel is using the device and detach it. +if device.is_kernel_driver_active(0): + device.detach_kernel_driver(0) + +# buffer to hold 64 bytes +buf = array.array("B", [0] * 64) + + +def print_array(arr, max_index=None, fmt="hex"): + """ + Print the values of an array + :param arr: The array to print + :param max_index: The maximum index to print. None means print all. + :param fmt: The format to use, either "hex" or "bin" + :return: None + """ + out_str = "" + if max_index is None or max_index >= len(arr): + length = len(arr) + else: + length = max_index + + for _ in range(length): + if fmt == "hex": + out_str += f"{int(arr[_]):02x} " + elif fmt == "bin": + out_str += f"{int(arr[_]):08b} " + print(out_str) + + +def reports_equal(report_a, report_b, check_length=None): + """ + Test if two reports are equal. If check_length is provided then + check for equality in only the first check_length number of bytes. + + :param report_a: First report data + :param report_b: Second report data + :param check_length: How many bytes to check + :return: True if the reports are equal, otherwise False. + """ + if ( + report_a is None + and report_b is not None + or report_b is None + and report_a is not None + ): + return False + + length = len(report_a) if check_length is None else check_length + for _ in range(length): + if report_a[_] != report_b[_]: + return False + return True + + +idle_state = None +prev_state = None + +while True: + try: + count = device.read(0x81, buf) + # print(f"read size: {count}") + except usb.core.USBTimeoutError: + continue + + if idle_state is None: + idle_state = buf[:] + print("Idle state:") + print_array(idle_state[:8], max_index=count) + print() + + if not reports_equal(buf, prev_state, 8) and not reports_equal(buf, idle_state, 8): + if buf[BTN_DPAD_UPDOWN_INDEX] == 0x0: + print("D-Pad UP pressed") + elif buf[BTN_DPAD_UPDOWN_INDEX] == 0xFF: + print("D-Pad DOWN pressed") + + if buf[BTN_DPAD_RIGHTLEFT_INDEX] == 0: + print("D-Pad LEFT pressed") + elif buf[BTN_DPAD_RIGHTLEFT_INDEX] == 0xFF: + print("D-Pad RIGHT pressed") + + if buf[BTN_ABXY_INDEX] == 0x2F: + print("A pressed") + elif buf[BTN_ABXY_INDEX] == 0x4F: + print("B pressed") + elif buf[BTN_ABXY_INDEX] == 0x1F: + print("X pressed") + elif buf[BTN_ABXY_INDEX] == 0x8F: + print("Y pressed") + + if buf[BTN_OTHER_INDEX] == 0x01: + print("L shoulder pressed") + elif buf[BTN_OTHER_INDEX] == 0x02: + print("R shoulder pressed") + elif buf[BTN_OTHER_INDEX] == 0x10: + print("SELECT pressed") + elif buf[BTN_OTHER_INDEX] == 0x20: + print("START pressed") + + # print_array(buf[:8]) + + prev_state = buf[:] diff --git a/UnicornHorn_CapacitiveTouch/UnicornHorn_CapacitiveTouch.ino b/UnicornHorn_CapacitiveTouch/UnicornHorn_CapacitiveTouch.ino index 276a7ff82..89d51f643 100644 --- a/UnicornHorn_CapacitiveTouch/UnicornHorn_CapacitiveTouch.ino +++ b/UnicornHorn_CapacitiveTouch/UnicornHorn_CapacitiveTouch.ino @@ -5,6 +5,10 @@ #include "Adafruit_FreeTouch.h" #include "FastLED.h" +#if defined(FASTLED_VERSION) && FASTLED_VERSION > 3010001 + #error "FastLED 3.10.2 has known compile issues with SAMD boards. Please downgrade to FastLED 3.10.1" +#endif + #define CAPTOUCH_PIN A1 #define NEOPIXEL_PIN 1 #define LED_PIN 0 @@ -97,4 +101,3 @@ void dark() delay(20); } } - diff --git a/Vertical_Garden_Barometer/code.py b/Vertical_Garden_Barometer/code.py index b52ef7187..5db7b95f6 100755 --- a/Vertical_Garden_Barometer/code.py +++ b/Vertical_Garden_Barometer/code.py @@ -61,26 +61,14 @@ clue_display = displayio.Group() # draw the rising image -# CircuitPython 6 & 7 compatible -rising_file = open("rising.bmp", "rb") -rising_bmp = displayio.OnDiskBitmap(rising_file) -rising_sprite = displayio.TileGrid(rising_bmp, pixel_shader=getattr(rising_bmp, 'pixel_shader', displayio.ColorConverter())) - -# # CircuitPython 7+ compatible -# rising_bmp = displayio.OnDiskBitmap("rising.bmp") -# rising_sprite = displayio.TileGrid(rising_bmp, pixel_shader=rising_bmp.pixel_shader) +rising_bmp = displayio.OnDiskBitmap("rising.bmp") +rising_sprite = displayio.TileGrid(rising_bmp, pixel_shader=rising_bmp.pixel_shader) clue_display.append(rising_sprite) # draw the sinking image -# CircuitPython 6 & 7 compatible -sinking_file = open("sinking.bmp", "rb") -sinking_bmp = displayio.OnDiskBitmap(sinking_file) -sinking_sprite = displayio.TileGrid(sinking_bmp, pixel_shader=getattr(sinking_bmp, 'pixel_shader', displayio.ColorConverter())) - -# # CircuitPython 7+ compatible -# sinking_bmp = displayio.OnDiskBitmap("sinking.bmp") -# sinking_sprite = displayio.TileGrid(sinking_bmp, pixel_shader=sinking_bmp.pixel_shader) +sinking_bmp = displayio.OnDiskBitmap("sinking.bmp") +sinking_sprite = displayio.TileGrid(sinking_bmp, pixel_shader=sinking_bmp.pixel_shader) clue_display.append(sinking_sprite) diff --git a/Voice2Json_Edge_Detection/demo.py b/Voice2Json_Edge_Detection/demo.py index 9ec8b9559..aa53858bc 100644 --- a/Voice2Json_Edge_Detection/demo.py +++ b/Voice2Json_Edge_Detection/demo.py @@ -10,6 +10,7 @@ from datetime import datetime import board import displayio +import fourwire import adafruit_dotstar from adafruit_st7789 import ST7789 @@ -57,13 +58,9 @@ def load_image(path): "Load an image from the path" if len(splash): splash.pop() - # CircuitPython 6 & 7 compatible - bitmap = displayio.OnDiskBitmap(open(path, "rb")) - sprite = displayio.TileGrid(bitmap, pixel_shader=getattr(bitmap, 'pixel_shader', displayio.ColorConverter())) - # # CircuitPython 7+ compatible - # bitmap = displayio.OnDiskBitmap(path) - # sprite = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader) + bitmap = displayio.OnDiskBitmap(path) + sprite = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader) splash.append(sprite) @@ -98,7 +95,7 @@ def process_output(line): tft_dc = board.D25 tft_lite = board.D26 -display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs) +display_bus = fourwire.FourWire(spi, command=tft_dc, chip_select=tft_cs) display = ST7789( display_bus, diff --git a/Walkmp3rson/code.py b/Walkmp3rson/code.py index 2b895f549..20df47195 100644 --- a/Walkmp3rson/code.py +++ b/Walkmp3rson/code.py @@ -14,6 +14,7 @@ from adafruit_neokey.neokey1x4 import NeoKey1x4 from adafruit_seesaw import seesaw, rotaryio import displayio +import fourwire import terminalio from adafruit_display_text import label from adafruit_st7789 import ST7789 @@ -29,7 +30,7 @@ tft_cs = board.D6 tft_dc = board.D9 tft_reset = board.D12 -display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_reset) +display_bus = fourwire.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_reset) display = ST7789(display_bus, width=320, height=240, rotation=90) # SD Card setup @@ -101,7 +102,7 @@ def tracktext(full_path_name, position): display.root_group = main_display_group # show main group (clears screen, too) # background bitmap w OnDiskBitmap -tape_bitmap = displayio.OnDiskBitmap(open("mp3_tape.bmp", "rb")) +tape_bitmap = displayio.OnDiskBitmap("mp3_tape.bmp") tape_tilegrid = displayio.TileGrid(tape_bitmap, pixel_shader=tape_bitmap.pixel_shader) main_display_group.append(tape_tilegrid) diff --git a/Weather_Display_Matrix/.circuitpython.skip b/Weather_Display_Matrix/.circuitpython.skip deleted file mode 100644 index 29726fd3e..000000000 --- a/Weather_Display_Matrix/.circuitpython.skip +++ /dev/null @@ -1 +0,0 @@ -Weather_Display_Matrix/weather_display_matrix.py 71: Consider merging these comparisons with "in" to "UNITS in ('imperial', 'metric')" (consider-using-in) diff --git a/Weather_Display_Matrix/code.py b/Weather_Display_Matrix/code.py index ef9e3d70f..2a062f772 100644 --- a/Weather_Display_Matrix/code.py +++ b/Weather_Display_Matrix/code.py @@ -10,6 +10,8 @@ weather for your location... and display it on a screen! if you can find something that spits out JSON data, we can display it """ + +from os import getenv import time import board import microcontroller @@ -18,12 +20,17 @@ from adafruit_matrixportal.matrix import Matrix import openweather_graphics # pylint: disable=wrong-import-position -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) if hasattr(board, "D12"): jumper = DigitalInOut(board.D12) @@ -62,10 +69,10 @@ DATA_SOURCE = ( "http://api.openweathermap.org/data/2.5/weather?q=" + LOCATION + "&units=" + UNITS ) -DATA_SOURCE += "&appid=" + secrets["openweather_token"] +DATA_SOURCE += "&appid=" + getenv("openweather_token") # You'll need to get a token from openweather.org, looks like 'b6907d289e10d714a6e88b30761fae22' -# it goes in your secrets.py file on a line such as: -# 'openweather_token' : 'your_big_humongous_gigantor_token', +# it goes in your settings.toml file on a line such as: +# 'openweather_token="your_big_humongous_gigantor_token"', DATA_LOCATION = [] SCROLL_HOLD_TIME = 0 # set this to hold each line before finishing scroll diff --git a/Weather_Display_Matrix/openweather_graphics.py b/Weather_Display_Matrix/openweather_graphics.py index fa35e4f63..fdebe7c1a 100644 --- a/Weather_Display_Matrix/openweather_graphics.py +++ b/Weather_Display_Matrix/openweather_graphics.py @@ -47,15 +47,8 @@ def __init__( self.display = display splash = displayio.Group() - # CircuitPython 6 & 7 compatible - background = displayio.OnDiskBitmap(open("loading.bmp", "rb")) - bg_sprite = displayio.TileGrid( - background, - pixel_shader=getattr(background, 'pixel_shader', displayio.ColorConverter()), - ) - # # CircuitPython 7+ compatible - # background = displayio.OnDiskBitmap("loading.bmp") - # bg_sprite = displayio.TileGrid(background, pixel_shader=background.pixel_shader) + background = displayio.OnDiskBitmap("loading.bmp") + bg_sprite = displayio.TileGrid(background, pixel_shader=background.pixel_shader) splash.append(bg_sprite) display.root_group = splash @@ -73,22 +66,13 @@ def __init__( self._current_label = None # Load the icon sprite sheet - # CircuitPython 6 & 7 compatible - icons = displayio.OnDiskBitmap(open(icon_spritesheet, "rb")) + icons = displayio.OnDiskBitmap(icon_spritesheet) self._icon_sprite = displayio.TileGrid( icons, - pixel_shader=getattr(icons, 'pixel_shader', displayio.ColorConverter()), + pixel_shader=icons.pixel_shader, tile_width=icon_width, tile_height=icon_height ) - # # CircuitPython 7+ compatible - # icons = displayio.OnDiskBitmap(icon_spritesheet) - # self._icon_sprite = displayio.TileGrid( - # icons, - # pixel_shader=icons.pixel_shader, - # tile_width=icon_width, - # tile_height=icon_height - # ) self.set_icon(None) self._scrolling_texts = [] diff --git a/Webhook_Plant_Sensor/code.py b/Webhook_Plant_Sensor/code.py index f02dc95e9..ea25ee7ab 100644 --- a/Webhook_Plant_Sensor/code.py +++ b/Webhook_Plant_Sensor/code.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2021 Eva Herrada for Adafruit Industries # SPDX-License-Identifier: MIT +from os import getenv import time import board @@ -14,6 +15,21 @@ from adafruit_seesaw.seesaw import Seesaw import busio +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + # Used to make sure that the Adafruit IO Trigger is only run once when the moisture value is below # the desired threshold, set in MIN LOW = False @@ -28,13 +44,6 @@ # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller seesaw = Seesaw(i2c, addr=0x36) -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise - # Set up WiFi esp32_cs = DigitalInOut(board.D13) esp32_ready = DigitalInOut(board.D11) @@ -42,8 +51,8 @@ spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) -status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) -wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) +status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) +wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Define callback functions which will be called when certain events happen. # pylint: disable=unused-argument @@ -73,8 +82,8 @@ def message(client, feed_id, payload): # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", - username=secrets["aio_username"], - password=secrets["aio_key"], + username=aio_username, + password=aio_key, socket_pool=pool, ssl_context=ssl_context, ) diff --git a/WiFi_Mailbox_Notifier/mailbox_code/code.py b/WiFi_Mailbox_Notifier/mailbox_code/code.py index c51e98cb7..f51ffafb1 100644 --- a/WiFi_Mailbox_Notifier/mailbox_code/code.py +++ b/WiFi_Mailbox_Notifier/mailbox_code/code.py @@ -4,6 +4,7 @@ """CircuitPython WiFi Mailbox Notifier""" +from os import getenv import time import ssl import alarm @@ -17,12 +18,20 @@ import adafruit_requests from adafruit_io.adafruit_io import IO_HTTP -# Get WiFi/Adafruit IO details from secrets.py -try: - from secrets import secrets -except ImportError: - print("Please create secrets.py and add your WiFi and AIO credentials there!") - raise +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) # Update to True if you want metadata sent to Adafruit IO. Defaults to False. METADATA = False @@ -81,9 +90,9 @@ def send_io_data(feed_name, value): # Connect to WiFi try: - wifi.radio.connect(secrets["ssid"], secrets["password"]) - print("Connected to {}!".format(secrets["ssid"])) - print("IP:", wifi.radio.ipv4_address) + wifi.radio.connect(ssid, password) + print(f"Connected to {ssid}!") + print(f"IP: {wifi.radio.ipv4_address}") pool = socketpool.SocketPool(wifi.radio) requests = adafruit_requests.Session(pool, ssl.create_default_context()) @@ -94,9 +103,6 @@ def send_io_data(feed_name, value): time.sleep(15) supervisor.reload() -# Pull your Adafruit IO username and key from secrets.py -aio_username = secrets["aio_username"] -aio_key = secrets["aio_key"] # Initialize an Adafruit IO HTTP API object io = IO_HTTP(aio_username, aio_key, requests) diff --git a/WipperSnapper_Offline/config.json b/WipperSnapper_Offline/config.json new file mode 100755 index 000000000..fa2e79414 --- /dev/null +++ b/WipperSnapper_Offline/config.json @@ -0,0 +1,36 @@ +{ + "exportedFromDevice": { + "sd_cs_pin": 23, + "referenceVoltage": 0, + "totalGPIOPins": 0, + "totalAnalogPins": 0, + "statusLEDBrightness": 0.3 + }, + "components": [ + { + "name": "bme280", + "componentAPI": "i2c", + "i2cDeviceName": "bme280", + "period": 30, + "autoConfig": "true", + "i2cDeviceAddress": "0x77", + "i2cDeviceSensorTypes": [ + { + "type": "ambient-temp" + }, + { + "type": "ambient-temp-fahrenheit" + }, + { + "type": "relative-humidity" + }, + { + "type": "pressure" + }, + { + "type": "altitude" + } + ] + } + ] + } \ No newline at end of file diff --git a/Wireless_ESP32-S2_Controller_For_Pure_Data/code.py b/Wireless_ESP32-S2_Controller_For_Pure_Data/code.py index 0edc406fa..87a91f2dd 100644 --- a/Wireless_ESP32-S2_Controller_For_Pure_Data/code.py +++ b/Wireless_ESP32-S2_Controller_For_Pure_Data/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import ipaddress import wifi import socketpool @@ -10,12 +11,17 @@ import adafruit_tsc2007 import adafruit_adxl34x -# Get wifi details and host IP from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # I2C setup for STEMMA port i2c = board.STEMMA_I2C() @@ -56,16 +62,16 @@ new_val = False # URLs to fetch from -HOST = secrets["host"] +HOST = getenv("host") PORT = 12345 TIMEOUT = 5 INTERVAL = 5 MAXBUF = 256 # connect to WIFI -print("Connecting to %s"%secrets["ssid"]) -wifi.radio.connect(secrets["ssid"], secrets["password"]) -print("Connected to %s!"%secrets["ssid"]) +print(f"Connecting to {ssid}") +wifi.radio.connect(ssid, password) +print(f"Connected to {ssid}!") pool = socketpool.SocketPool(wifi.radio) diff --git a/Wiz5500_Ethernet_Breakout/Arduino_Wiz5500_Breakout/.uno.test.only b/Wiz5500_Ethernet_Breakout/Arduino_Wiz5500_Breakout/.uno.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/Wiz5500_Ethernet_Breakout/Arduino_Wiz5500_Breakout/Arduino_Wiz5500_Breakout.ino b/Wiz5500_Ethernet_Breakout/Arduino_Wiz5500_Breakout/Arduino_Wiz5500_Breakout.ino new file mode 100644 index 000000000..584410a8c --- /dev/null +++ b/Wiz5500_Ethernet_Breakout/Arduino_Wiz5500_Breakout/Arduino_Wiz5500_Breakout.ino @@ -0,0 +1,135 @@ +// SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +/* + Web client + + This sketch connects to a website (http://wifitest.adafruit.com) + using an Adafruit Wiz5500 Ethernet Breakout + + Circuit: + * Ethernet breakout attached to pins 10, 11, 12, 13 + + created 18 Dec 2009 + by David A. Mellis + modified 9 Apr 2012 + by Tom Igoe, based on work by Adrian McEwen + modified 10 June 2025 + by Liz Clark + + */ + +#include +#include + +// Enter a MAC address for your controller below. +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; + +char server[] = "wifitest.adafruit.com"; + +// Set the static IP address to use if the DHCP fails to assign +IPAddress ip(192, 168, 0, 177); +IPAddress myDns(192, 168, 0, 1); + +// Initialize the Ethernet client library +// with the IP address and port of the server +// that you want to connect to (port 80 is default for HTTP): +EthernetClient client; + +// Variables to measure the speed +unsigned long beginMicros, endMicros; +unsigned long byteCount = 0; +bool printWebData = true; // set to false for better speed measurement + +void setup() { + // You can use Ethernet.init(pin) to configure the CS pin + // Here you're using pin 10 for CS + // SCK: 13, MISO: 12, MOSI: 11 + Ethernet.init(10); // Most Arduino shields + + // Open serial communications and wait for port to open: + Serial.begin(115200); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // start the Ethernet connection: + Serial.println("Initialize Ethernet with DHCP:"); + if (Ethernet.begin(mac) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // Check for Ethernet hardware present + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println("Ethernet breakout was not found. Check your wiring."); + while (true) { + delay(1); // do nothing, no point running without Ethernet hardware + } + } + if (Ethernet.linkStatus() == LinkOFF) { + Serial.println("Ethernet cable is not connected."); + } + // try to configure using IP address instead of DHCP: + Ethernet.begin(mac, ip, myDns); + } else { + Serial.print(" DHCP assigned IP "); + Serial.println(Ethernet.localIP()); + } + // give the Ethernet a second to initialize: + delay(1000); + Serial.print("connecting to "); + Serial.print(server); + Serial.println("..."); + + // if you get a connection, report back via serial: + if (client.connect(server, 80)) { + Serial.print("connected to "); + Serial.println(client.remoteIP()); + // Make a HTTP request: + client.println("GET /testwifi/index.html HTTP/1.1"); + client.println("Host: wifitest.adafruit.com"); + client.println("Connection: close"); + client.println(); + } else { + // if you didn't get a connection to the server: + Serial.println("connection failed"); + } + beginMicros = micros(); +} + +void loop() { + // if there are incoming bytes available + // from the server, read them and print them: + int len = client.available(); + if (len > 0) { + byte buffer[80]; + if (len > 80) len = 80; + client.read(buffer, len); + if (printWebData) { + Serial.write(buffer, len); // show in the serial monitor (slows some boards) + } + byteCount = byteCount + len; + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + endMicros = micros(); + Serial.println(); + Serial.println("disconnecting."); + client.stop(); + Serial.print("Received "); + Serial.print(byteCount); + Serial.print(" bytes in "); + float seconds = (float)(endMicros - beginMicros) / 1000000.0; + Serial.print(seconds, 4); + float rate = (float)byteCount / seconds / 1000.0; + Serial.print(", rate = "); + Serial.print(rate); + Serial.print(" kbytes/second"); + Serial.println(); + + // do nothing forevermore: + while (true) { + delay(1); + } + } +} diff --git a/Wiz5500_Ethernet_Breakout/CircuitPython_Wiz5500_Breakout/code.py b/Wiz5500_Ethernet_Breakout/CircuitPython_Wiz5500_Breakout/code.py new file mode 100644 index 000000000..c683fbad4 --- /dev/null +++ b/Wiz5500_Ethernet_Breakout/CircuitPython_Wiz5500_Breakout/code.py @@ -0,0 +1,41 @@ +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT + +import adafruit_connection_manager +import adafruit_requests +import board +import busio +import digitalio + +from adafruit_wiznet5k.adafruit_wiznet5k import WIZNET5K + +print("Wiz5100 Breakout WebClient Test") + +TEXT_URL = "http://wifitest.adafruit.com/testwifi/index.html" + +cs = digitalio.DigitalInOut(board.D10) +spi_bus = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) + +# Initialize ethernet interface with DHCP +eth = WIZNET5K(spi_bus, cs) + +# Initialize a requests session +pool = adafruit_connection_manager.get_radio_socketpool(eth) +ssl_context = adafruit_connection_manager.get_radio_ssl_context(eth) +requests = adafruit_requests.Session(pool, ssl_context) + +print("Chip Version:", eth.chip) +print("MAC Address:", [hex(i) for i in eth.mac_address]) +print("My IP address is:", eth.pretty_ip(eth.ip_address)) +print("IP lookup adafruit.com: %s" % eth.pretty_ip(eth.get_host_by_name("adafruit.com"))) + + +# eth._debug = True +print("Fetching text from", TEXT_URL) +r = requests.get(TEXT_URL) +print("-" * 40) +print(r.text) +print("-" * 40) +r.close() + +print("Done!") diff --git a/World_Clock_Round_Display/README.md b/World_Clock_Round_Display/README.md new file mode 100644 index 000000000..a92bdf0db --- /dev/null +++ b/World_Clock_Round_Display/README.md @@ -0,0 +1,3 @@ +This code is for the Adafruit Learning System Guide "World clock" + +https://learn.adafruit.com/world-clock/overview diff --git a/World_Clock_Round_Display/circuitpython_world.bmp b/World_Clock_Round_Display/circuitpython_world.bmp new file mode 100644 index 000000000..12851f329 Binary files /dev/null and b/World_Clock_Round_Display/circuitpython_world.bmp differ diff --git a/World_Clock_Round_Display/code.py b/World_Clock_Round_Display/code.py new file mode 100644 index 000000000..4db00be5e --- /dev/null +++ b/World_Clock_Round_Display/code.py @@ -0,0 +1,49 @@ +# SPDX-FileCopyrightText: 2025 Ben Everard for Adafruit Industries +# +# SPDX-License-Identifier: MIT +'''Display a world clock on a round LCD''' + +import os +import time +import board +import displayio +import fourwire +from adafruit_gc9a01a import GC9A01A +import wifi +import adafruit_ntp +import adafruit_connection_manager + +wifi.radio.connect(ssid=os.getenv('CIRCUITPY_WIFI_SSID'), + password=os.getenv('CIRCUITPY_WIFI_PASSWORD')) + +pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio) +ntp = adafruit_ntp.NTP(pool, tz_offset=0, cache_seconds=3600) + +displayio.release_displays() +spi = board.SPI() +tft_cs = board.TX +tft_dc = board.RX + +display_bus = fourwire.FourWire( + spi, command=tft_dc, chip_select=tft_cs, reset=None +) + +display = GC9A01A(display_bus, width=240, height=240, auto_refresh=False) + +world = displayio.OnDiskBitmap("/world.bmp") + +tile_grid_1 = displayio.TileGrid(world, pixel_shader=world.pixel_shader) +tile_grid_2 = displayio.TileGrid(world, pixel_shader=world.pixel_shader) + +group = displayio.Group() + +group.append(tile_grid_1) +group.append(tile_grid_2) +display.root_group = group + +# Loop forever so you can enjoy your image +while True: + tile_grid_1.x = (20*ntp.datetime.tm_hour)+120 + tile_grid_2.x = tile_grid_1.x-480 + display.refresh() + time.sleep(60) diff --git a/color_touch_pendant/color_touch_pendant.ino b/color_touch_pendant/color_touch_pendant.ino index 1c4fdfdce..4a195bb2e 100644 --- a/color_touch_pendant/color_touch_pendant.ino +++ b/color_touch_pendant/color_touch_pendant.ino @@ -9,6 +9,10 @@ #include "Adafruit_FreeTouch.h" #include "FastLED.h" +#if defined(FASTLED_VERSION) && FASTLED_VERSION > 3010001 + #error "FastLED 3.10.2 has known compile issues with SAMD boards. Please downgrade to FastLED 3.10.1" +#endif + #define CAPTOUCH_PIN 0 //capacitive touch pin #define NEOPIXEL_PIN 1 //neopixel ring pin #define NUM_LEDS 28 //how many pixels total @@ -140,4 +144,3 @@ void dark() delay(20); } } - diff --git a/library.deps b/library.deps index c25f99062..9baaf655f 100644 --- a/library.deps +++ b/library.deps @@ -1 +1 @@ -depends=Adafruit ILI9341, Adafruit BusIO, SD, Adafruit NeoPixel, Adafruit VS1053 Library, Adafruit BluefruitLE nRF51, Adafruit seesaw Library, Ethernet, Adafruit IO Arduino, FastLED, Adafruit LiquidCrystal, Adafruit SoftServo, TinyWireM, Adafruit AM radio library, WaveHC, Adafruit LED Backpack Library, MAX31850 OneWire, Adafruit VC0706 Serial Camera Library, RTClib, Adafruit SleepyDog Library, Adafruit Thermal Printer Library, Adafruit Zero I2S Library, Adafruit EPD, Adafruit SSD1351 library, Adafruit FONA Library, Adafruit Motor Shield V2 Library, Adafruit NeoMatrix, Adafruit Soundboard library, Adafruit Circuit Playground, ArduinoJson, Adafruit TCS34725, Adafruit Pixie, Adafruit GPS Library, TinyGPS, WiFi101, Adafruit DotStar, Adafruit Si7021 Library, Adafruit WS2801 Library, Mouse, Keyboard, Time, IRremote, Adafruit LSM9DS0 Library, Adafruit Arcada Library, MIDIUSB, PubSubClient, Adafruit LIS2MDL, Adafruit NeoPXL8, Adafruit MCP23017 Arduino Library, Adafruit MLX90640, LiquidCrystal, Adafruit NeoTrellis M4 Library, RGB matrix Panel, Adafruit MLX90614 Library, Adafruit RGB LCD Shield Library, MAX6675 library, Adafruit MP3, Adafruit Keypad, Adafruit Arcada GifDecoder, Keypad, Neosegment, Encoder, Adafruit TiCoServo, Adafruit Trellis Library, FauxmoESP, Adafruit LSM303 Accel, Adafruit LSM303DLH Mag, Adafruit LSM303DLHC, CapacitiveSensor, Adafruit Zero PDM Library, Adafruit DMA neopixel library, elapsedMillis, DST RTC, Adafruit SHARP Memory Display, Adafruit SPIFlash, BSEC Software Library, WiiChuck, Adafruit DPS310, Adafruit AHTX0, RotaryEncoder, Adafruit MCP9808 Library, LSM303, Adafruit Protomatter, Adafruit IS31FL3741 Library, Sensirion I2C SCD4x, Adafruit TestBed, Bounce2, Adafruit AHRS, Adafruit DRV2605 Library, STM32duino VL53L4CD, PicoDVI - Adafruit Fork, Adafruit MMA8451 Library, Adafruit TSC2007, GFX Library for Arduino, Adafruit PyCamera Library, Adafruit ADG72x, Adafruit BNO055, Adafruit SHT4x Library, Adafruit VCNL4200 Library, Adafruit GC9A01A +depends=Adafruit SSD1305, Adafruit ILI9341, Adafruit BusIO, SD, Adafruit NeoPixel, Adafruit VS1053 Library, Adafruit BluefruitLE nRF51, Adafruit seesaw Library, Ethernet, Stepper, Adafruit IO Arduino, FastLED@3.10.1, Adafruit LiquidCrystal, Adafruit SoftServo, TinyWireM, Adafruit AM radio library, WaveHC, Adafruit LED Backpack Library, MAX31850 OneWire, Adafruit VC0706 Serial Camera Library, RTClib, Adafruit SleepyDog Library, Adafruit Thermal Printer Library, Adafruit Zero I2S Library, Adafruit EPD, Adafruit SSD1351 library, Adafruit FONA Library, Adafruit Motor Shield V2 Library, Adafruit NeoMatrix, Adafruit Soundboard library, Adafruit Circuit Playground, ArduinoJson, Adafruit TCS34725, Adafruit Pixie, Adafruit GPS Library, TinyGPS, WiFi101, Adafruit DotStar, Adafruit Si7021 Library, Adafruit WS2801 Library, Mouse, Keyboard, Time, IRremote, Adafruit LSM9DS0 Library, Adafruit Arcada Library, MIDIUSB, PubSubClient, Adafruit LIS2MDL, Adafruit NeoPXL8, Adafruit MCP23017 Arduino Library, Adafruit MLX90640, LiquidCrystal, Adafruit NeoTrellis M4 Library, RGB matrix Panel, Adafruit MLX90614 Library, Adafruit RGB LCD Shield Library, MAX6675 library, Adafruit MP3, Adafruit Keypad, Adafruit Arcada GifDecoder, Keypad, Neosegment, Encoder, Adafruit TiCoServo, Adafruit Trellis Library, FauxmoESP, Adafruit LSM303 Accel, Adafruit LSM303DLH Mag, Adafruit LSM303DLHC, CapacitiveSensor, Adafruit Zero PDM Library, Adafruit DMA neopixel library, elapsedMillis, DST RTC, Adafruit SHARP Memory Display, Adafruit SPIFlash, BSEC Software Library, WiiChuck, Adafruit DPS310, Adafruit AHTX0, RotaryEncoder, Adafruit MCP9808 Library, LSM303, Adafruit Protomatter, Adafruit IS31FL3741 Library, Sensirion I2C SCD4x, Adafruit TestBed, Bounce2, Adafruit AHRS, Adafruit DRV2605 Library, STM32duino VL53L4CD, PicoDVI - Adafruit Fork, Adafruit MMA8451 Library, Adafruit TSC2007, GFX Library for Arduino, Adafruit PyCamera Library, Adafruit ADG72x, Adafruit BNO055, Adafruit SHT4x Library, Adafruit VCNL4200 Library, Adafruit GC9A01A, Adafruit DVI HSTX, Adafruit TLV320 I2S, Adafruit PCM51xx diff --git a/literary-clock/code.py b/literary-clock/code.py index 57ce1bcde..fcb8baf2f 100644 --- a/literary-clock/code.py +++ b/literary-clock/code.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2022 Eva Herrada for Adafruit Industries # SPDX-License-Identifier: MIT +from os import getenv import time import ssl @@ -17,6 +18,21 @@ import displayio from adafruit_display_shapes.rect import Rect +# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") + +if None in [ssid, password, aio_username, aio_key]: + raise RuntimeError( + "WiFi and Adafruit IO settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum." + ) + UTC_OFFSET = -4 quotes = {} @@ -81,18 +97,9 @@ ) splash.append(author_label) -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise - -aio_username = secrets["aio_username"] -aio_key = secrets["aio_key"] - -print(f"Connecting to {secrets['ssid']}") -wifi.radio.connect(secrets["ssid"], secrets["password"]) -print(f"Connected to {secrets['ssid']}!") +print(f"Connecting to {ssid}") +wifi.radio.connect(ssid, password) +print(f"Connected to {ssid}!") def get_width(font, text): @@ -202,8 +209,8 @@ def message(client, feed_id, payload): # pylint: disable=unused-argument mqtt_client = MQTT.MQTT( broker="io.adafruit.com", port=1883, - username=secrets["aio_username"], - password=secrets["aio_key"], + username=aio_username, + password=aio_key, socket_pool=pool, ssl_context=ssl.create_default_context(), ) diff --git a/oshwa_magtag_display/code.py b/oshwa_magtag_display/code.py index 680fcf588..5ef1bf817 100644 --- a/oshwa_magtag_display/code.py +++ b/oshwa_magtag_display/code.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from os import getenv import random import ssl import gc @@ -10,12 +11,17 @@ import adafruit_requests from adafruit_magtag.magtag import MagTag -# Get wifi details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise +# Get WiFi details, ensure these are setup in settings.toml +ssid = getenv("CIRCUITPY_WIFI_SSID") +password = getenv("CIRCUITPY_WIFI_PASSWORD") + +if None in [ssid, password]: + raise RuntimeError( + "WiFi settings are kept in settings.toml, " + "please add them there. The settings file must contain " + "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " + "at a minimum." + ) # Initialize magtag object magtag = MagTag() @@ -23,9 +29,9 @@ magtag.set_background("bmps/oshwa_full.bmp") # Set up WiFi -wifi.radio.connect(secrets["ssid"], secrets["password"]) -print(f"Connected to {secrets['ssid']}!") -print("My IP address is", wifi.radio.ipv4_address) +wifi.radio.connect(ssid, password) +print(f"Connected to {ssid}!") +print(f"My IP address is {wifi.radio.ipv4_address}") socket = socketpool.SocketPool(wifi.radio) https = adafruit_requests.Session(socket, ssl.create_default_context()) diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/.metro_rp2350_tinyusb.test.only b/runcpm-rp2350-hstx-usb/runcpm-pico/.metro_rp2350_tinyusb.test.only new file mode 100644 index 000000000..e69de29bb diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/LICENSE b/runcpm-rp2350-hstx-usb/runcpm-pico/LICENSE new file mode 100644 index 000000000..f7a6865b8 --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Mockba the Borg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/README.md b/runcpm-rp2350-hstx-usb/runcpm-pico/README.md new file mode 100644 index 000000000..bf8a5e7f7 --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/README.md @@ -0,0 +1,31 @@ + + +This is a port of runcpm to the raspberry pi pico. + +It is based on: + * [RunCPM](https://github.com/MockbaTheBorg/RunCPM/) + * [RunCPM_RPi_Pico](https://github.com/guidol70/RunCPM_RPi_Pico) + +It works on a Raspberry Pi Pico (or Pico W). It uses the internal flash +for storage, and can be mounted as USB storage. + +If your Pico is placed on the Pico DV carrier board, you also get a 100x30 +character screen to enjoy your CP/M output on! + +First, build for your device. You must + * Use the Philhower Pico Core + * In the Tools menu, select + * A flash size option that includes at least 512kB for filesystem + * USB Stack: Adafruit TinyUSB + +After it boots the first time, you need to + * Format the flash device on your host computer + * Create the folder "/A/0" + * Put something useful in that folder, such as [Zork](http://www.retroarchive.org/cpm/games/zork123_80.zip) + * Files must respect the "8.3" naming convention (8 letters filename + 3 letters extension) and be all uppercase + * Safely eject the drive, then reset the emulator. + * Now at the "A0>" prompt you can run "ZORK1". diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/abstraction_arduino.h b/runcpm-rp2350-hstx-usb/runcpm-pico/abstraction_arduino.h new file mode 100644 index 000000000..f16d86cd5 --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/abstraction_arduino.h @@ -0,0 +1,531 @@ +// SPDX-FileCopyrightText: 2023 Mockba the Borg +// +// SPDX-License-Identifier: MIT + +#ifndef ABSTRACT_H +#define ABSTRACT_H + +#ifdef PROFILE +#define printf(a, b) Serial.println(b) +#endif + +// #if defined ARDUINO_SAM_DUE || defined ADAFRUIT_GRAND_CENTRAL_M4 +#define HostOS 0x01 +// #endif + +#if !defined(FILE_TYPE) +#define FILE_TYPE FsFile +#endif + +#if defined CORE_TEENSY +#define HostOS 0x04 +#endif +#if defined ESP32 +#define HostOS 0x05 +#endif +#if defined _STM32_DEF_ +#define HostOS 0x06 +#endif + +/* Memory abstraction functions */ +/*===============================================================================*/ +bool _RamLoad(char* filename, uint16 address) { + FILE_TYPE f; + bool result = false; + + if (f = SD.open(filename, FILE_READ)) { + while (f.available()) + _RamWrite(address++, f.read()); + f.close(); + result = true; + } + return(result); +} + +/* Filesystem (disk) abstraction fuctions */ +/*===============================================================================*/ +FILE_TYPE rootdir, userdir; +#define FOLDERCHAR '/' + +typedef struct { + uint8 dr; + uint8 fn[8]; + uint8 tp[3]; + uint8 ex, s1, s2, rc; + uint8 al[16]; + uint8 cr, r0, r1, r2; +} CPM_FCB; + +typedef struct { + uint8 dr; + uint8 fn[8]; + uint8 tp[3]; + uint8 ex, s1, s2, rc; + uint8 al[16]; +} CPM_DIRENTRY; + +bool _sys_exists(uint8* filename) { + return(SD.exists((const char *)filename)); +} + +FILE_TYPE _sys_fopen_w(uint8* filename) { + return(SD.open((char*)filename, O_CREAT | O_WRITE)); +} + +int _sys_fputc(uint8 ch, FILE_TYPE& f) { + return(f.write(ch)); +} + +void _sys_fflush(FILE_TYPE& f) { + f.flush(); +} + +void _sys_fclose(FILE_TYPE& f) { + f.close(); +} + +int _sys_select(uint8* disk) { + uint8 result = FALSE; + FILE_TYPE f; + + digitalWrite(LED, HIGH ^ LEDinv); + if (f = SD.open((char*)disk, O_READ)) { + if (f.isDirectory()) + result = TRUE; + f.close(); + } + digitalWrite(LED, LOW ^ LEDinv); + return(result); +} + +long _sys_filesize(uint8* filename) { + long l = -1; + FILE_TYPE f; + + digitalWrite(LED, HIGH ^ LEDinv); + if (f = SD.open((char*)filename, O_RDONLY)) { + l = f.size(); + f.close(); + } + digitalWrite(LED, LOW ^ LEDinv); + return(l); +} + +int _sys_openfile(uint8* filename) { + FILE_TYPE f; + int result = 0; + + digitalWrite(LED, HIGH ^ LEDinv); + f = SD.open((char*)filename, O_READ); + if (f) { + f.close(); + result = 1; + } + digitalWrite(LED, LOW ^ LEDinv); + return(result); +} + +int _sys_makefile(uint8* filename) { + FILE_TYPE f; + int result = 0; + + digitalWrite(LED, HIGH ^ LEDinv); + f = SD.open((char*)filename, O_CREAT | O_WRITE); + if (f) { + f.close(); + result = 1; + } + digitalWrite(LED, LOW ^ LEDinv); + return(result); +} + +int _sys_deletefile(uint8* filename) { + digitalWrite(LED, HIGH ^ LEDinv); + return(SD.remove((char*)filename)); + digitalWrite(LED, LOW ^ LEDinv); +} + +int _sys_renamefile(uint8* filename, uint8* newname) { + FILE_TYPE f; + int result = 0; + + digitalWrite(LED, HIGH ^ LEDinv); + f = SD.open((char*)filename, O_WRITE | O_APPEND); + if (f) { + if (f.rename((char*)newname)) { + f.close(); + result = 1; + } + } + digitalWrite(LED, LOW ^ LEDinv); + return(result); +} + +#ifdef DEBUGLOG +void _sys_logbuffer(uint8* buffer) { +#ifdef CONSOLELOG + puts((char*)buffer); +#else + FILE_TYPE f; + uint8 s = 0; + while (*(buffer + s)) // Computes buffer size + ++s; + if (f = SD.open(LogName, O_CREAT | O_APPEND | O_WRITE)) { + f.write(buffer, s); + f.flush(); + f.close(); + } +#endif +} +#endif + +bool _sys_extendfile(char* fn, unsigned long fpos) +{ + uint8 result = true; + FILE_TYPE f; + unsigned long i; + + digitalWrite(LED, HIGH ^ LEDinv); + if (f = SD.open(fn, O_WRITE | O_APPEND)) { + if (fpos > f.size()) { + for (i = 0; i < f.size() - fpos; ++i) { + if (f.write((uint8)0) != 1) { + result = false; + break; + } + } + } + f.close(); + } else { + result = false; + } + digitalWrite(LED, LOW ^ LEDinv); + return(result); +} + +uint8 _sys_readseq(uint8* filename, long fpos) { + uint8 result = 0xff; + FILE_TYPE f; + uint8 bytesread; + uint8 dmabuf[BlkSZ]; + uint8 i; + + digitalWrite(LED, HIGH ^ LEDinv); + f = SD.open((char*)filename, O_READ); + if (f) { + if (f.seek(fpos)) { + for (i = 0; i < BlkSZ; ++i) + dmabuf[i] = 0x1a; + bytesread = f.read(&dmabuf[0], BlkSZ); + if (bytesread) { + for (i = 0; i < BlkSZ; ++i) + _RamWrite(dmaAddr + i, dmabuf[i]); + } + result = bytesread ? 0x00 : 0x01; + } else { + result = 0x01; + } + f.close(); + } else { + result = 0x10; + } + digitalWrite(LED, LOW ^ LEDinv); + return(result); +} + +uint8 _sys_writeseq(uint8* filename, long fpos) { + uint8 result = 0xff; + FILE_TYPE f; + + digitalWrite(LED, HIGH ^ LEDinv); + if (_sys_extendfile((char*)filename, fpos)) + f = SD.open((char*)filename, O_RDWR); + if (f) { + if (f.seek(fpos)) { + if (f.write(_RamSysAddr(dmaAddr), BlkSZ)) + result = 0x00; + } else { + result = 0x01; + } + f.close(); + } else { + result = 0x10; + } + digitalWrite(LED, LOW ^ LEDinv); + return(result); +} + +uint8 _sys_readrand(uint8* filename, long fpos) { + uint8 result = 0xff; + FILE_TYPE f; + uint8 bytesread; + uint8 dmabuf[BlkSZ]; + uint8 i; + long extSize; + + digitalWrite(LED, HIGH ^ LEDinv); + f = SD.open((char*)filename, O_READ); + if (f) { + if (f.seek(fpos)) { + for (i = 0; i < BlkSZ; ++i) + dmabuf[i] = 0x1a; + bytesread = f.read(&dmabuf[0], BlkSZ); + if (bytesread) { + for (i = 0; i < BlkSZ; ++i) + _RamWrite(dmaAddr + i, dmabuf[i]); + } + result = bytesread ? 0x00 : 0x01; + } else { + if (fpos >= 65536L * BlkSZ) { + result = 0x06; // seek past 8MB (largest file size in CP/M) + } else { + extSize = f.size(); + // round file size up to next full logical extent + extSize = ExtSZ * ((extSize / ExtSZ) + ((extSize % ExtSZ) ? 1 : 0)); + if (fpos < extSize) + result = 0x01; // reading unwritten data + else + result = 0x04; // seek to unwritten extent + } + } + f.close(); + } else { + result = 0x10; + } + digitalWrite(LED, LOW ^ LEDinv); + return(result); +} + +uint8 _sys_writerand(uint8* filename, long fpos) { + uint8 result = 0xff; + FILE_TYPE f; + + digitalWrite(LED, HIGH ^ LEDinv); + if (_sys_extendfile((char*)filename, fpos)) { + f = SD.open((char*)filename, O_RDWR); + } + if (f) { + if (f.seek(fpos)) { + if (f.write(_RamSysAddr(dmaAddr), BlkSZ)) + result = 0x00; + } else { + result = 0x06; + } + f.close(); + } else { + result = 0x10; + } + digitalWrite(LED, LOW ^ LEDinv); + return(result); +} + +static uint8 findNextDirName[13]; +static uint16 fileRecords = 0; +static uint16 fileExtents = 0; +static uint16 fileExtentsUsed = 0; +static uint16 firstFreeAllocBlock; + +uint8 _findnext(uint8 isdir) { + FILE_TYPE f; + uint8 result = 0xff; + bool isfile; + uint32 bytes; + + digitalWrite(LED, HIGH ^ LEDinv); + if (allExtents && fileRecords) { + _mockupDirEntry(); + result = 0; + } else { + while (f = userdir.openNextFile()) { + f.getName((char*)&findNextDirName[0], 13); + isfile = !f.isDirectory(); + bytes = f.size(); + f.close(); + if (!isfile) + continue; + _HostnameToFCBname(findNextDirName, fcbname); + if (match(fcbname, pattern)) { + if (isdir) { + // account for host files that aren't multiples of the block size + // by rounding their bytes up to the next multiple of blocks + if (bytes & (BlkSZ - 1)) { + bytes = (bytes & ~(BlkSZ - 1)) + BlkSZ; + } + fileRecords = bytes / BlkSZ; + fileExtents = fileRecords / BlkEX + ((fileRecords & (BlkEX - 1)) ? 1 : 0); + fileExtentsUsed = 0; + firstFreeAllocBlock = firstBlockAfterDir; + _mockupDirEntry(); + } else { + fileRecords = 0; + fileExtents = 0; + fileExtentsUsed = 0; + firstFreeAllocBlock = firstBlockAfterDir; + } + _RamWrite(tmpFCB, filename[0] - '@'); + _HostnameToFCB(tmpFCB, findNextDirName); + result = 0x00; + break; + } + } + } + digitalWrite(LED, LOW ^ LEDinv); + return(result); +} + +uint8 _findfirst(uint8 isdir) { + uint8 path[4] = { '?', FOLDERCHAR, '?', 0 }; + path[0] = filename[0]; + path[2] = filename[2]; + if (userdir) + userdir.close(); + userdir = SD.open((char*)path); // Set directory search to start from the first position + _HostnameToFCBname(filename, pattern); + fileRecords = 0; + fileExtents = 0; + fileExtentsUsed = 0; + return(_findnext(isdir)); +} + +uint8 _findnextallusers(uint8 isdir) { + uint8 result = 0xFF; + char dirname[13]; + bool done = false; + + while (!done) { + while (!userdir) { + userdir = rootdir.openNextFile(); + if (!userdir) { + done = true; + break; + } + userdir.getName(dirname, sizeof dirname); + if (userdir.isDirectory() && strlen(dirname) == 1 && isxdigit(dirname[0])) { + currFindUser = dirname[0] <= '9' ? dirname[0] - '0' : toupper(dirname[0]) - 'A' + 10; + break; + } + userdir.close(); + } + if (userdir) { + result = _findnext(isdir); + if (result) { + userdir.close(); + } else { + done = true; + } + } else { + result = 0xFF; + done = true; + } + } + return result; +} + +uint8 _findfirstallusers(uint8 isdir) { + uint8 path[2] = { '?', 0 }; + + path[0] = filename[0]; + if (rootdir) + rootdir.close(); + if (userdir) + userdir.close(); + rootdir = SD.open((char*)path); // Set directory search to start from the first position + strcpy((char*)pattern, "???????????"); + if (!rootdir) + return 0xFF; + fileRecords = 0; + fileExtents = 0; + fileExtentsUsed = 0; + return(_findnextallusers(isdir)); +} + +uint8 _Truncate(char* filename, uint8 rc) { + FILE_TYPE f; + int result = 0; + + digitalWrite(LED, HIGH ^ LEDinv); + f = SD.open((char*)filename, O_WRITE | O_APPEND); + if (f) { + if (f.truncate(rc * BlkSZ)) { + f.close(); + result = 1; + } + } + digitalWrite(LED, LOW ^ LEDinv); + return(result); +} + +void _MakeUserDir() { + uint8 dFolder = cDrive + 'A'; + uint8 uFolder = toupper(tohex(userCode)); + + uint8 path[4] = { dFolder, FOLDERCHAR, uFolder, 0 }; + + digitalWrite(LED, HIGH ^ LEDinv); + SD.mkdir((char*)path); + digitalWrite(LED, LOW ^ LEDinv); +} + +uint8 _sys_makedisk(uint8 drive) { + uint8 result = 0; + if (drive < 1 || drive>16) { + result = 0xff; + } else { + uint8 dFolder = drive + '@'; + uint8 disk[2] = { dFolder, 0 }; + digitalWrite(LED, HIGH ^ LEDinv); + if (!SD.mkdir((char*)disk)) { + result = 0xfe; + } else { + uint8 path[4] = { dFolder, FOLDERCHAR, '0', 0 }; + SD.mkdir((char*)path); + } + digitalWrite(LED, LOW ^ LEDinv); + } + + return(result); +} + +/* Hardware abstraction functions */ +/*===============================================================================*/ +void _HardwareOut(const uint32 Port, const uint32 Value) { + +} + +uint32 _HardwareIn(const uint32 Port) { + return 0; +} + +/* Console abstraction functions */ +/*===============================================================================*/ + +#include "arduino_hooks.h" + +int _kbhit(void) { + if (_kbhit_hook && _kbhit_hook()) { return true; } + return(Serial.available()); +} + +uint8 _getch(void) { + while(true) { + if(_kbhit_hook && _kbhit_hook()) { return _getch_hook(); } + if(Serial.available()) { return Serial.read(); } + } +} + +uint8 _getche(void) { + uint8 ch = _getch(); + _putch(ch); + return(ch); +} + +void _putch(uint8 ch) { + Serial.write(ch); + if(_putch_hook) _putch_hook(ch); +} + +void _clrscr(void) { + Serial.print("\e[H\e[J"); +} + +#endif diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/arduino_hooks.c b/runcpm-rp2350-hstx-usb/runcpm-pico/arduino_hooks.c new file mode 100644 index 000000000..be225ac5a --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/arduino_hooks.c @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: 2023 Jeff Epler for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "arduino_hooks.h" + +bool (*_kbhit_hook)(void); +uint8_t (*_getch_hook)(void); +void (*_putch_hook)(uint8_t ch); + diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/arduino_hooks.h b/runcpm-rp2350-hstx-usb/runcpm-pico/arduino_hooks.h new file mode 100644 index 000000000..a1baed74b --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/arduino_hooks.h @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Jeff Epler for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +extern bool (*_kbhit_hook)(void); +extern uint8_t (*_getch_hook)(void); +extern void (*_putch_hook)(uint8_t ch); + diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/ccp.h b/runcpm-rp2350-hstx-usb/runcpm-pico/ccp.h new file mode 100644 index 000000000..38da86fc2 --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/ccp.h @@ -0,0 +1,891 @@ +// SPDX-FileCopyrightText: 2023 Mockba the Borg +// +// SPDX-License-Identifier: MIT + +#ifndef CCP_H +#define CCP_H + +// CP/M BDOS calls +#include "cpm.h" + +#define CmdFCB (BatchFCB + 48) // FCB for use by internal commands +#define ParFCB 0x005C // FCB for use by line parameters +#define SecFCB 0x006C // Secondary part of FCB for renaming files +#define Trampoline (CmdFCB + 36) // Trampoline for running external commands + +#define inBuf (BDOSjmppage - 256) // Input buffer location +#define cmdLen 125 // Maximum size of a command line (sz+rd+cmd+\0) + +#define defDMA 0x0080 // Default DMA address +#define defLoad 0x0100 // Default load address + +// CCP global variables +uint8 pgSize = 22; // for TYPE +uint8 curDrive = 0; // 0 -> 15 = A -> P .. Current drive for the CCP (same as RAM[DSKByte]) +uint8 parDrive = 0; // 0 -> 15 = A -> P .. Drive for the first file parameter +uint8 curUser = 0; // 0 -> 15 .. Current user area to access +bool sFlag = FALSE; // Submit Flag +uint8 sRecs = 0; // Number of records on the Submit file +uint8 prompt[8] = "\r\n >"; +uint16 pbuf, perr; +uint8 blen; // Actual size of the typed command line (size of the buffer) + +static const char *Commands[] = +{ + // Standard CP/M commands + "DIR", + "ERA", + "TYPE", + "SAVE", + "REN", + "USER", + + // Extra CCP commands + "CLS", + "DEL", + "EXIT", + "PAGE", + "VOL", + "?", + NULL +}; + +// Used to call BDOS from inside the CCP +uint16 _ccp_bdos(uint8 function, uint16 de) { + SET_LOW_REGISTER(BC, function); + DE = de; + _Bdos(); + + return (HL & 0xffff); +} // _ccp_bdos + +// Compares two strings (Atmel doesn't like strcmp) +uint8 _ccp_strcmp(char *stra, char *strb) { + while (*stra && *strb && (*stra == *strb)) { + ++stra; + ++strb; + } + return (*stra == *strb); +} // _ccp_strcmp + +// Gets the command ID number +uint8 _ccp_cnum(void) { + uint8 result = 255; + uint8 command[9]; + uint8 i = 0; + + if (!_RamRead(CmdFCB)) { // If a drive was set, then the command is external + while (i < 8 && _RamRead(CmdFCB + i + 1) != ' ') { + command[i] = _RamRead(CmdFCB + i + 1); + ++i; + } + command[i] = 0; + i = 0; + while (Commands[i]) { + if (_ccp_strcmp((char *)command, (char *)Commands[i])) { + result = i; + perr = defDMA + 2; + break; + } + ++i; + } + } + return (result); +} // _ccp_cnum + +// Returns true if character is a separator +uint8 _ccp_delim(uint8 ch) { + return (ch == 0 || ch == ' ' || ch == '=' || ch == '.' || ch == ':' || ch == ';' || ch == '<' || ch == '>'); +} + +// Prints the FCB filename +void _ccp_printfcb(uint16 fcb, uint8 compact) { + uint8 i, ch; + + ch = _RamRead(fcb); + if (ch && compact) { + _ccp_bdos( C_WRITE, ch + '@'); + _ccp_bdos( C_WRITE, ':'); + } + + for (i = 1; i < 12; ++i) { + ch = _RamRead(fcb + i); + if ((ch == ' ') && compact) + continue; + if (i == 9) + _ccp_bdos(C_WRITE, compact ? '.' : ' '); + _ccp_bdos(C_WRITE, ch); + } +} // _ccp_printfcb + +// Initializes the FCB +void _ccp_initFCB(uint16 address, uint8 size) { + uint8 i; + + for (i = 0; i < size; ++i) + _RamWrite(address + i, 0x00); + + for (i = 0; i < 11; ++i) + _RamWrite(address + 1 + i, 0x20); +} // _ccp_initFCB + +// Name to FCB +uint8 _ccp_nameToFCB(uint16 fcb) { + uint8 pad, plen, ch, n = 0; + + // Checks for a drive and places it on the Command FCB + if (_RamRead(pbuf + 1) == ':') { + ch = toupper(_RamRead(pbuf++)); + _RamWrite(fcb, ch - '@'); // Makes the drive 0x1-0xF for A-P + ++pbuf; // Points pbuf past the : + blen -= 2; + } + if (blen) { + ++fcb; + + plen = 8; + pad = ' '; + ch = toupper(_RamRead(pbuf)); + + while (blen && plen) { + if (_ccp_delim(ch)) + break; + ++pbuf; + --blen; + if (ch == '*') + pad = '?'; + if (pad == '?') { + ch = pad; + n = n | 0x80; // Name is not unique + } + --plen; + ++n; + _RamWrite(fcb++, ch); + ch = toupper(_RamRead(pbuf)); + } + + while (plen--) + _RamWrite(fcb++, pad); + plen = 3; + pad = ' '; + if (ch == '.') { + ++pbuf; + --blen; + } + + while (blen && plen) { + ch = toupper(_RamRead(pbuf)); + if (_ccp_delim(ch)) + break; + ++pbuf; + --blen; + if (ch == '*') + pad = '?'; + if (pad == '?') { + ch = pad; + n = n | 0x80; // Name is not unique + } + --plen; + ++n; + _RamWrite(fcb++, ch); + } + + while (plen--) + _RamWrite(fcb++, pad); + } + return (n); +} // _ccp_nameToFCB + +// Converts the ParFCB name to a number +uint16 _ccp_fcbtonum() { + uint8 ch; + uint16 n = 0; + uint8 pos = ParFCB + 1; + + while (TRUE) { + ch = _RamRead(pos++); + if ((ch < '0') || (ch > '9')) { + break; + } + n = (n * 10) + (ch - '0'); + } + return (n); +} // _ccp_fcbtonum + +// DIR command +void _ccp_dir(void) { + uint8 i; + uint8 dirHead[6] = "A: "; + uint8 dirSep[6] = " | "; + uint32 fcount = 0; // Number of files printed + uint32 ccount = 0; // Number of columns printed + + if (_RamRead(ParFCB + 1) == ' ') + for (i = 1; i < 12; ++i) + _RamWrite(ParFCB + i, '?'); + dirHead[0] = _RamRead(ParFCB) ? _RamRead(ParFCB) + '@' : prompt[2]; + + _puts("\r\n"); + if (!_SearchFirst(ParFCB, TRUE)) { + _puts((char *)dirHead); + _ccp_printfcb(tmpFCB, FALSE); + ++fcount; + ++ccount; + + while (!_SearchNext(ParFCB, TRUE)) { + if (!ccount) { + _puts( "\r\n"); + _puts( (char *)dirHead); + } else { + _puts((char *)dirSep); + } + _ccp_printfcb(tmpFCB, FALSE); + ++fcount; + ++ccount; + if (ccount > 3) + ccount = 0; + } + } else { + _puts("No file"); + } +} // _ccp_dir + +// ERA command +void _ccp_era(void) { + if (_ccp_bdos(F_DELETE, ParFCB)) + _puts("\r\nNo file"); +} // _ccp_era + +// TYPE command +uint8 _ccp_type(void) { + uint8 i, c, l = 0, error = TRUE; + uint16 a, p = 0; + + if (!_ccp_bdos(F_OPEN, ParFCB)) { + _puts("\r\n"); + + while (!_ccp_bdos(F_READ, ParFCB)) { + i = 128; + a = dmaAddr; + + while (i) { + c = _RamRead(a); + if (c == 0x1a) + break; + _ccp_bdos(C_WRITE, c); + if (c == 0x0a) { + ++l; + if (pgSize && (l == pgSize)) { + l = 0; + p = _ccp_bdos(C_READ, 0x0000); + if (p == 3) + break; + } + } + --i; + ++a; + } + if (p == 3) + break; + } + error = FALSE; + } + return (error); +} // _ccp_type + +// SAVE command +uint8 _ccp_save(void) { + uint8 error = TRUE; + uint16 pages = _ccp_fcbtonum(); + uint16 i, dma; + + if (pages < 256) { + error = FALSE; + + while (_RamRead(pbuf) == ' ' && blen) { // Skips any leading spaces + ++pbuf; + --blen; + } + _ccp_nameToFCB(SecFCB); // Loads file name onto the ParFCB + if (_ccp_bdos(F_MAKE, SecFCB)) { + _puts("Err: create"); + } else { + if (_ccp_bdos(F_OPEN, SecFCB)) { + _puts("Err: open"); + } else { + pages *= 2; // Calculates the number of CP/M blocks to write + dma = defLoad; + _puts("\r\n"); + + for (i = 0; i < pages; i++) { + _ccp_bdos( F_DMAOFF, dma); + _ccp_bdos( F_WRITE, SecFCB); + dma += 128; + _ccp_bdos( C_WRITE, '.'); + } + _ccp_bdos(F_CLOSE, SecFCB); + } + } + } + return (error); +} // _ccp_save + +// REN command +void _ccp_ren(void) { + uint8 ch, i; + + ++pbuf; + + _ccp_nameToFCB(SecFCB); + + for (i = 0; i < 12; ++i) { // Swap the filenames on the fcb + ch = _RamRead(ParFCB + i); + _RamWrite( ParFCB + i, _RamRead(SecFCB + i)); + _RamWrite( SecFCB + i, ch); + } + if (_ccp_bdos(F_RENAME, ParFCB)) + _puts("\r\nNo file"); +} // _ccp_ren + +// USER command +uint8 _ccp_user(void) { + uint8 error = TRUE; + + curUser = (uint8)_ccp_fcbtonum(); + if (curUser < 16) { + _ccp_bdos(F_USERNUM, curUser); + error = FALSE; + } + return (error); +} // _ccp_user + +// PAGE command +uint8 _ccp_page(void) { + uint8 error = TRUE; + uint16 r = _ccp_fcbtonum(); + + if (r < 256) { + pgSize = (uint8)r; + error = FALSE; + } + return (error); +} // _ccp_page + +// VOL command +uint8 _ccp_vol(void) { + uint8 error = FALSE; + uint8 letter = _RamRead(ParFCB) ? '@' + _RamRead(ParFCB) : 'A' + curDrive; + uint8 folder[5] = {letter, FOLDERCHAR, '0', FOLDERCHAR, 0}; + uint8 filename[13] = {letter, FOLDERCHAR, '0', FOLDERCHAR, 'I', 'N', 'F', 'O', '.', 'T', 'X', 'T', 0}; + uint8 bytesread; + uint8 i, j; + + _puts("\r\nVolumes on "); + _putcon(folder[0]); + _puts(":\r\n"); + + for (i = 0; i < 16; ++i) { + folder[2] = i < 10 ? i + 48 : i + 55; + if (_sys_exists(folder)) { + _putcon(i < 10 ? ' ' : '1'); + _putcon(i < 10 ? folder[2] : 38 + i); + _puts(": "); + filename[2] = i < 10 ? i + 48 : i + 55; + bytesread = (uint8)_sys_readseq(filename, 0); + if (!bytesread) { + for (j = 0; j < 128; ++j) { + if ((_RamRead(dmaAddr + j) < 32) || (_RamRead(dmaAddr + j) > 126)) + break; + _putcon(_RamRead(dmaAddr + j)); + } + } + _puts("\r\n"); + } + } + return (error); +} // _ccp_vol + +// ?/Help command +uint8 _ccp_hlp(void) { + _puts("\r\nCCP Commands:\r\n"); + _puts("\t? - Shows this list of commands\r\n"); + _puts("\tCLS - Clears the screen\r\n"); + _puts("\tDEL - Alias to ERA\r\n"); + _puts("\tEXIT - Terminates RunCPM\r\n"); + _puts("\tPAGE [] - Sets the page size for TYPE\r\n"); + _puts("\t or disables paging if no parameter passed\r\n"); + _puts("\tVOL [drive] - Shows the volume information\r\n"); + _puts("\t which comes from each volume's INFO.TXT"); + return(FALSE); +} +#ifdef HASLUA + +// External (.LUA) command +uint8 _ccp_lua(void) { + uint8 error = TRUE; + uint8 found, drive, user = 0; + uint16 loadAddr = defLoad; + + _RamWrite( CmdFCB + 9, 'L'); + _RamWrite( CmdFCB + 10, 'U'); + _RamWrite( CmdFCB + 11, 'A'); + + drive = _RamRead(CmdFCB); + found = !_ccp_bdos(F_OPEN, CmdFCB); // Look for the program on the FCB drive, current or specified + if (!found) { // If not found + if (!drive) { // and the search was on the default drive + _RamWrite(CmdFCB, 0x01); // Then look on drive A: user 0 + if (curUser) { + user = curUser; // Save the current user + _ccp_bdos(F_USERNUM, 0x0000); // then set it to 0 + } + found = !_ccp_bdos(F_OPEN, CmdFCB); + if (!found) { // If still not found then + if (curUser) { // If current user not = 0 + _RamWrite(CmdFCB, 0x00); // look on current drive user 0 + found = !_ccp_bdos(F_OPEN, CmdFCB); // and try again + } + } + } + } + if (found) { + _puts("\r\n"); + + _ccp_bdos(F_RUNLUA, CmdFCB); + if (user) { // If a user was selected + _ccp_bdos(F_USERNUM, curUser); // Set it back + user = 0; + } + _RamWrite(CmdFCB, drive); // Set the command FCB drive back to what it was + cDrive = oDrive; // And restore cDrive + error = FALSE; + } + if (user) // If a user was selected + _ccp_bdos(F_USERNUM, curUser); // Set it back + _RamWrite(CmdFCB, drive); // Set the command FCB drive back to what it was + + return (error); +} // _ccp_lua +#endif // ifdef HASLUA + +// External (.COM) command +uint8 _ccp_ext(void) { + bool error = TRUE, found = FALSE; + uint8 drive = 0, user = 0; + uint16 loadAddr = defLoad; + + bool wasBlank = (_RamRead(CmdFCB + 9) == ' '); + bool wasSUB = ((_RamRead(CmdFCB + 9) == 'S') && + (_RamRead(CmdFCB + 10) == 'U') && + (_RamRead(CmdFCB + 11) == 'B')); + + if (!wasSUB) { + if (wasBlank) { + _RamWrite(CmdFCB + 9, 'C'); //first look for a .COM file + _RamWrite(CmdFCB + 10, 'O'); + _RamWrite(CmdFCB + 11, 'M'); + } + + drive = _RamRead(CmdFCB); // Get the drive from the command FCB + found = !_ccp_bdos(F_OPEN, CmdFCB); // Look for the program on the FCB drive, current or specified + if (!found) { // If not found + if (!drive) { // and the search was on the default drive + _RamWrite(CmdFCB, 0x01); // Then look on drive A: user 0 + if (curUser) { + user = curUser; // Save the current user + _ccp_bdos(F_USERNUM, 0x0000); // then set it to 0 + } + found = !_ccp_bdos(F_OPEN, CmdFCB); + if (!found) { // If still not found then + if (curUser) { // If current user not = 0 + _RamWrite(CmdFCB, 0x00); // look on current drive user 0 + found = !_ccp_bdos(F_OPEN, CmdFCB); // and try again + } + } + } + } + if (!found) { + _RamWrite(CmdFCB, drive); // restore previous drive + _ccp_bdos(F_USERNUM, curUser); // restore to previous user + } + } + + //if .COM not found then look for a .SUB file + if ((wasBlank || wasSUB) && !found && !sFlag) { //don't auto-submit while executing a submit file + _RamWrite(CmdFCB + 9, 'S'); + _RamWrite(CmdFCB + 10, 'U'); + _RamWrite(CmdFCB + 11, 'B'); + + drive = _RamRead(CmdFCB); // Get the drive from the command FCB + found = !_ccp_bdos(F_OPEN, CmdFCB); // Look for the program on the FCB drive, current or specified + if (!found) { // If not found + if (!drive) { // and the search was on the default drive + _RamWrite(CmdFCB, 0x01); // Then look on drive A: user 0 + if (curUser) { + user = curUser; // Save the current user + _ccp_bdos(F_USERNUM, 0x0000); // then set it to 0 + } + found = !_ccp_bdos(F_OPEN, CmdFCB); + if (!found) { // If still not found then + if (curUser) { // If current user not = 0 + _RamWrite(CmdFCB, 0x00); // look on current drive user 0 + found = !_ccp_bdos(F_OPEN, CmdFCB); // and try again + } + } + } + } + if (!found) { + _RamWrite(CmdFCB, drive); // restore previous drive + _ccp_bdos(F_USERNUM, curUser); // restore to previous user + } + + if (found) { + //_puts(".SUB file found!\n"); + int i; + + //move FCB's (CmdFCB --> ParFCB --> SecFCB) + for (i = 0; i < 16; i++) { + //ParFCB to SecFCB + _RamWrite(SecFCB + i, _RamRead(ParFCB + i)); + //CmdFCB to ParFCB + _RamWrite(ParFCB + i, _RamRead(CmdFCB + i)); + } + // (Re)Initialize the CmdFCB + _ccp_initFCB(CmdFCB, 36); + + //put 'SUBMIT.COM' in CmdFCB + const char *str = "SUBMIT COM"; + int s = (int)strlen(str); + for (i = 0; i < s; i++) + _RamWrite(CmdFCB + i + 1, str[i]); + + //now try to find SUBMIT.COM file + found = !_ccp_bdos(F_OPEN, CmdFCB); // Look for the program on the FCB drive, current or specified + if (!found) { // If not found + if (!drive) { // and the search was on the default drive + _RamWrite(CmdFCB, 0x01); // Then look on drive A: user 0 + if (curUser) { + user = curUser; // Save the current user + _ccp_bdos(F_USERNUM, 0x0000); // then set it to 0 + } + found = !_ccp_bdos(F_OPEN, CmdFCB); + if (!found) { // If still not found then + if (curUser) { // If current user not = 0 + _RamWrite(CmdFCB, 0x00); // look on current drive user 0 + found = !_ccp_bdos(F_OPEN, CmdFCB); // and try again + } + } + } + } + if (found) { + //insert "@" into command buffer + //note: this is so the rest will be parsed correctly + blen = _RamRead(defDMA); + if (blen < cmdLen) { + blen++; + _RamWrite(defDMA, blen); + } + uint8 lc = '@'; + for (i = 0; i < blen; i++) { + uint8 nc = _RamRead(defDMA + 1 + i); + _RamWrite(defDMA + 1 + i, lc); + lc = nc; + } + } + } + } + + if (found) { // Program was found somewhere + _puts("\r\n"); + _ccp_bdos(F_DMAOFF, loadAddr); // Sets the DMA address for the loading + while (!_ccp_bdos(F_READ, CmdFCB)) { // Loads the program into memory + loadAddr += 128; + if (loadAddr == BDOSjmppage) { // Breaks if it reaches the end of TPA + _puts("\r\nNo Memory"); + break; + } + _ccp_bdos(F_DMAOFF, loadAddr); // Points the DMA offset to the next loadAddr + } + _ccp_bdos(F_DMAOFF, defDMA); // Points the DMA offset back to the default + + if (user) { // If a user was selected + _ccp_bdos(F_USERNUM, curUser); // Set it back + user = 0; + } + _RamWrite(CmdFCB, drive); // Set the command FCB drive back to what it was + cDrive = oDrive; // And restore cDrive + + // Place a trampoline to call the external command + // as it may return using RET instead of JP 0000h + loadAddr = Trampoline; + _RamWrite(loadAddr, CALL); // CALL 0100h + _RamWrite16(loadAddr + 1, defLoad); + _RamWrite(loadAddr + 3, JP); // JP USERF + _RamWrite16(loadAddr + 4, BIOSjmppage + B_USERF); + + Z80reset(); // Resets the Z80 CPU + SET_LOW_REGISTER(BC, _RamRead(DSKByte)); // Sets C to the current drive/user + PC = loadAddr; // Sets CP/M application jump point + SP = BDOSjmppage; // Sets the stack to the top of the TPA + + Z80run(); // Starts Z80 simulation + + error = FALSE; + } + + if (user) // If a user was selected + _ccp_bdos(F_USERNUM, curUser); // Set it back + _RamWrite(CmdFCB, drive); // Set the command FCB drive back to what it was + + return(error); +} // _ccp_ext + +// Prints a command error +void _ccp_cmdError() { + uint8 ch; + + _puts("\r\n"); + while ((ch = _RamRead(perr++))) { + if (ch == ' ') + break; + _ccp_bdos(C_WRITE, toupper(ch)); + } + _puts("?\r\n"); +} // _ccp_cmdError + +// Reads input, either from the $$$.SUB or console +void _ccp_readInput(void) { + uint8 i; + uint8 chars; + + if (sFlag) { // Are we running a submit? + if (!sRecs) { // Are we already counting? + _ccp_bdos(F_OPEN, BatchFCB); // Open the batch file + sRecs = _RamRead(BatchFCB + 15); // Gets its record count + } + --sRecs; // Counts one less + _RamWrite(BatchFCB + 32, sRecs); // And sets to be the next read + _ccp_bdos( F_DMAOFF, defDMA); // Reset current DMA + _ccp_bdos( F_READ, BatchFCB); // And reads the last sector + chars = _RamRead(defDMA); // Then moves it to the input buffer + + for (i = 0; i <= chars; ++i) + _RamWrite(inBuf + i + 1, _RamRead(defDMA + i)); + _RamWrite(inBuf + i + 1, 0); + _puts((char *)_RamSysAddr(inBuf + 2)); + if (!sRecs) { + _ccp_bdos(F_DELETE, BatchFCB); // Deletes the submit file + sFlag = FALSE; // and clears the submit flag + } + } else { + _ccp_bdos(C_READSTR, inBuf); // Reads the command line from console + if (Debug) + Z80run(); + } +} // _ccp_readInput + +// Main CCP code +void _ccp(void) { + uint8 i; + + sFlag = (bool)_ccp_bdos(DRV_ALLRESET, 0x0000); + _ccp_bdos(DRV_SET, curDrive); + + for (i = 0; i < 36; ++i) + _RamWrite(BatchFCB + i, _RamRead(tmpFCB + i)); + + while (TRUE) { + curDrive = (uint8)_ccp_bdos(DRV_GET, 0x0000); // Get current drive + curUser = (uint8)_ccp_bdos(F_USERNUM, 0x00FF); // Get current user + _RamWrite(DSKByte, (curUser << 4) + curDrive); // Set user/drive on addr DSKByte + + parDrive = curDrive; // Initially the parameter drive is the same as the current drive + + sprintf((char *) prompt, "\r\n%c%u%c", 'A' + curDrive, curUser, sFlag ? '$' : '>'); + _puts((char *)prompt); + + _RamWrite(inBuf, cmdLen); // Sets the buffer size to read the command line + _ccp_readInput(); + + blen = _RamRead(inBuf + 1); // Obtains the number of bytes read + + _ccp_bdos(F_DMAOFF, defDMA); // Reset current DMA + if (blen) { + _RamWrite(inBuf + 2 + blen, 0); // "Closes" the read buffer with a \0 + pbuf = inBuf + 2; // Points pbuf to the first command character + + while (_RamRead(pbuf) == ' ' && blen) { // Skips any leading spaces + ++pbuf; + --blen; + } + if (!blen) // There were only spaces + continue; + if (_RamRead(pbuf) == ';') // Found a comment line + continue; + + // parse for DU: command line shortcut + bool errorFlag = FALSE, continueFlag = FALSE; + uint8 ch, tDrive = 0, tUser = curUser, u = 0; + + for (i = 0; i < blen; i++) { + ch = toupper(_RamRead(pbuf + i)); + if ((ch >= 'A') && (ch <= 'P')) { + if (tDrive) { // if we've already specified a new drive + break; // not a DU: command + } else { + tDrive = ch - '@'; + } + } else if ((ch >= '0') && (ch <= '9')) { + tUser = u = (u * 10) + (ch - '0'); + } else if (ch == ':') { + if (i == blen - 1) { // if we at the end of the command line + if (tUser >= 16) { // if invalid user + errorFlag = TRUE; + break; + } + if (tDrive != 0) { + cDrive = oDrive = tDrive - 1; + _RamWrite(DSKByte, (_RamRead(DSKByte) & 0xf0) | cDrive); + _ccp_bdos(DRV_SET, cDrive); + if (Status) + curDrive = 0; + } + if (tUser != curUser) { + curUser = tUser; + _ccp_bdos(F_USERNUM, curUser); + } + continueFlag = TRUE; + } + break; + } else { // invalid character + break; // don't error; may be valid (non-DU:) command + } + } + if (errorFlag) { + _ccp_cmdError(); // print command error + continue; + } + if (continueFlag) { + continue; + } + _ccp_initFCB(CmdFCB, 36); // Initializes the command FCB + + perr = pbuf; // Saves the pointer in case there's an error + if (_ccp_nameToFCB(CmdFCB) > 8) { // Extracts the command from the buffer + _ccp_cmdError(); // Command name cannot be non-unique or have an extension + continue; + } + _RamWrite(defDMA, blen); // Move the command line at this point to 0x0080 + + for (i = 0; i < blen; ++i) + _RamWrite(defDMA + i + 1, toupper(_RamRead(pbuf + i))); + while (i++ < 127) // "Zero" the rest of the DMA buffer + _RamWrite(defDMA + i, 0); + _ccp_initFCB( ParFCB, 18); // Initializes the parameter FCB + _ccp_initFCB( SecFCB, 18); // Initializes the secondary FCB + + while (_RamRead(pbuf) == ' ' && blen) { // Skips any leading spaces + ++pbuf; + --blen; + } + _ccp_nameToFCB(ParFCB); // Loads the next file parameter onto the parameter FCB + + while (_RamRead(pbuf) == ' ' && blen) { // Skips any leading spaces + ++pbuf; + --blen; + } + _ccp_nameToFCB(SecFCB); // Loads the next file parameter onto the secondary FCB + + i = FALSE; // Checks if the command is valid and executes + + switch (_ccp_cnum()) { + // Standard CP/M commands + case 0: { // DIR + _ccp_dir(); + break; + } + + case 1: { // ERA + _ccp_era(); + break; + } + + case 2: { // TYPE + i = _ccp_type(); + break; + } + + case 3: { // SAVE + i = _ccp_save(); + break; + } + + case 4: { // REN + _ccp_ren(); + break; + } + + case 5: { // USER + i = _ccp_user(); + break; + } + + // Extra CCP commands + case 6: { // CLS + _clrscr(); + break; + } + + case 7: { // DEL is an alias to ERA + _ccp_era(); + break; + } + + case 8: { // EXIT + _puts( "Terminating RunCPM.\r\n"); + _puts( "CPU Halted.\r\n"); + Status = 1; + break; + } + + case 9: { // PAGE + i = _ccp_page(); + break; + } + + case 10: { // VOL + i = _ccp_vol(); + break; + } + + case 11: { // HELP + i = _ccp_hlp(); + break; + } + + // External/Lua commands + case 255: { // It is an external command + i = _ccp_ext(); +#ifdef HASLUA + if (i) + i = _ccp_lua(); +#endif // ifdef HASLUA + break; + } + + default: { + i = TRUE; + break; + } + } // switch + cDrive = oDrive = curDrive; // Restore cDrive and oDrive + if (i) + _ccp_cmdError(); + } + if ((Status == 1) || (Status == 2)) + break; + } + _puts("\r\n"); +} // _ccp + +#endif // ifndef CCP_H diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/console.h b/runcpm-rp2350-hstx-usb/runcpm-pico/console.h new file mode 100644 index 000000000..1e9cf168b --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/console.h @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2023 Mockba the Borg +// +// SPDX-License-Identifier: MIT + +#ifndef CONSOLE_H +#define CONSOLE_H + +extern int _kbhit(void); +uint8_t _getch(void); +void _putch(uint8 ch); + +/* see main.c for definition */ + +uint8 mask8bit = 0x7f; // TO be used for masking 8 bit characters (XMODEM related) + // If set to 0x7f, RunCPM masks the 8th bit of characters sent + // to the console. This is the standard CP/M behavior. + // If set to 0xff, RunCPM passes 8 bit characters. This is + // required for XMODEM to work. + // Use the CONSOLE7 and CONSOLE8 programs to change this on the fly. + +uint8 _chready(void) // Checks if there's a character ready for input +{ + return(_kbhit() ? 0xff : 0x00); +} + +uint8 _getchNB(void) // Gets a character, non-blocking, no echo +{ + return(_kbhit() ? _getch() : 0x00); +} + +void _putcon(uint8 ch) // Puts a character +{ + _putch(ch & mask8bit); +} + +void _puts(const char* str) // Puts a \0 terminated string +{ + while (*str) + _putcon(*(str++)); +} + +void _puthex8(uint8 c) // Puts a HH hex string +{ + _putcon(tohex(c >> 4)); + _putcon(tohex(c & 0x0f)); +} + +void _puthex16(uint16 w) // puts a HHHH hex string +{ + _puthex8(w >> 8); + _puthex8(w & 0x00ff); +} + +void _putdec(uint16_t w) { + char buf[] = " 0"; + size_t i=sizeof(buf)-1; + while(w) { + assert(i > 0); + buf[--i] = '0' + (w % 10); + w /= 10; + } + _puts(buf); +} +#endif diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/cpm.h b/runcpm-rp2350-hstx-usb/runcpm-pico/cpm.h new file mode 100644 index 000000000..b580a3cc9 --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/cpm.h @@ -0,0 +1,1782 @@ +// SPDX-FileCopyrightText: 2023 Mockba the Borg +// +// SPDX-License-Identifier: MIT + +#ifndef CPM_H +#define CPM_H + +enum eBIOSFunc { +// CP/M 2.2 Stuff + B_BOOT = 0, + B_WBOOT = 3, + B_CONST = 6, + B_CONIN = 9, + B_CONOUT = 12, + B_LIST = 15, + B_AUXOUT = 18, + B_READER = 21, + B_HOME = 24, + B_SELDSK = 27, + B_SETTRK = 30, + B_SETSEC = 33, + B_SETDMA = 36, + B_READ = 39, + B_WRITE = 42, + B_LISTST = 45, + B_SECTRAN = 48, +// CP/M 3.0 Stuff + B_CONOST = 51, + B_AUXIST = 54, + B_AUXOST = 57, + B_DEVTBL = 60, + B_DEVINI = 63, + B_DRVTBL = 66, + B_MULTIO = 69, + B_FLUSH = 72, + B_MOVE = 75, + B_TIME = 78, + B_SELMEM = 81, + B_SETBNK = 84, + B_XMOVE = 87, + B_USERF = 90, // Used by internal CCP to return to prompt + B_RESERV1 = 93, + B_RESERV2 = 96 +}; + +enum eBDOSFunc { +// CP/M 2.2 Stuff + P_TERMCPM = 0, + C_READ = 1, + C_WRITE = 2, + A_READ = 3, + A_WRITE = 4, + L_WRITE = 5, + C_RAWIO = 6, + A_STATIN = 7, + A_STATOUT = 8, + C_WRITESTR = 9, + C_READSTR = 10, + C_STAT = 11, + S_BDOSVER = 12, + DRV_ALLRESET = 13, + DRV_SET = 14, + F_OPEN = 15, + F_CLOSE = 16, + F_SFIRST = 17, + F_SNEXT = 18, + F_DELETE = 19, + F_READ = 20, + F_WRITE = 21, + F_MAKE = 22, + F_RENAME = 23, + DRV_LOGINVEC = 24, + DRV_GET = 25, + F_DMAOFF = 26, + DRV_ALLOCVEC = 27, + DRV_SETRO = 28, + DRV_ROVEC = 29, + F_ATTRIB = 30, + DRV_PDB = 31, + F_USERNUM = 32, + F_READRAND = 33, + F_WRITERAND = 34, + F_SIZE = 35, + F_RANDREC = 36, + DRV_RESET = 37, + DRV_ACCESS = 38, // This is an MP/M function that is not supported under CP/M 3. + DRV_FREE = 39, // This is an MP/M function that is not supported under CP/M 3. + F_WRITEZF = 40, +// CP/M 3.0 Stuff + F_TESTWRITE = 41, + F_LOCKFILE = 42, + F_UNLOCKFILE = 43, + F_MULTISEC = 44, + F_ERRMODE = 45, + DRV_SPACE = 46, + P_CHAIN = 47, + DRV_FLUSH = 48, + S_SCB = 49, + S_BIOS = 50, + P_LOAD = 59, + S_RSX = 60, + F_CLEANUP = 98, + F_TRUNCATE = 99, + DRV_SETLABEL = 100, + DRV_GETLABEL = 101, + F_TIMEDATE = 102, + F_WRITEXFCB = 103, + T_SET = 104, + T_GET = 105, + F_PASSWD = 106, + S_SERIAL = 107, + P_CODE = 108, + C_MODE = 109, + C_DELIMIT = 110, + C_WRITEBLK = 111, + L_WRITEBLK = 112, + F_PARSE = 152, +// RunCPM Stuff + F_RUNLUA = 254 +}; + +/* see main.c for definition */ + +#define JP 0xc3 +#define CALL 0xcd +#define RET 0xc9 +#define INa 0xdb // Triggers a BIOS call +#define OUTa 0xd3 // Triggers a BDOS call + +/* set up full PUN and LST filenames to be on drive A: user 0 */ +#ifdef USE_PUN +char pun_file[17] = {'A', FOLDERCHAR, '0', FOLDERCHAR, 'P', 'U', 'N', '.', 'T', 'X', 'T', 0}; + +#endif // ifdef USE_PUN +#ifdef USE_LST +char lst_file[17] = {'A', FOLDERCHAR, '0', FOLDERCHAR, 'L', 'S', 'T', '.', 'T', 'X', 'T', 0}; + +#endif // ifdef USE_LST + +#ifdef PROFILE +unsigned long time_start = 0; +unsigned long time_now = 0; + +#endif // ifdef PROFILE + +void _PatchCPM(void) { + uint16 i; + + // ********** Patch CP/M page zero into the memory ********** + + /* BIOS entry point */ + _RamWrite(0x0000, JP); /* JP BIOS+3 (warm boot) */ + _RamWrite16(0x0001, BIOSjmppage + 3); + if (Status != 2) { + /* IOBYTE - Points to Console */ + _RamWrite( IOByte, 0x3D); + + /* Current drive/user - A:/0 */ + _RamWrite( DSKByte, 0x00); + } + /* BDOS entry point (0x0005) */ + _RamWrite(0x0005, JP); + _RamWrite16(0x0006, BDOSjmppage + 0x06); + + // ********** Patch CP/M Version into the memory so the CCP can see it + _RamWrite16(BDOSjmppage, 0x1600); + _RamWrite16(BDOSjmppage + 2, 0x0000); + _RamWrite16(BDOSjmppage + 4, 0x0000); + + // Patches in the BDOS jump destination + _RamWrite( BDOSjmppage + 6, JP); + _RamWrite16(BDOSjmppage + 7, BDOSpage); + + // Patches in the BDOS page content + _RamWrite( BDOSpage, INa); + _RamWrite( BDOSpage + 1, 0xFF); + _RamWrite( BDOSpage + 2, RET); + + // Patches in the BIOS jump destinations + for (i = 0; i < 99; i = i + 3) { + _RamWrite( BIOSjmppage + i, JP); + _RamWrite16(BIOSjmppage + i + 1, BIOSpage + i); + } + + // Patches in the BIOS page content + for (i = 0; i < 99; i = i + 3) { + _RamWrite( BIOSpage + i, OUTa); + _RamWrite( BIOSpage + i + 1, 0xFF); + _RamWrite( BIOSpage + i + 2, RET); + } + // ********** Patch CP/M (fake) Disk Paramater Block after the BDOS call entry ********** + i = DPBaddr; + _RamWrite( i++, 64); // spt - Sectors Per Track + _RamWrite( i++, 0); + _RamWrite( i++, 5); // bsh - Data allocation "Block Shift Factor" + _RamWrite( i++, 0x1F); // blm - Data allocation Block Mask + _RamWrite( i++, 1); // exm - Extent Mask + _RamWrite( i++, 0xFF); // dsm - Total storage capacity of the disk drive + _RamWrite( i++, 0x07); + _RamWrite( i++, 255); // drm - Number of the last directory entry + _RamWrite( i++, 3); + _RamWrite( i++, 0xFF); // al0 + _RamWrite( i++, 0x00); // al1 + _RamWrite( i++, 0); // cks - Check area Size + _RamWrite( i++, 0); + _RamWrite( i++, 0x02); // off - Number of system reserved tracks at the beginning of the ( logical ) disk + _RamWrite( i++, 0x00); + blockShift = _RamRead(DPBaddr + 2); + blockMask = _RamRead(DPBaddr + 3); + extentMask = _RamRead(DPBaddr + 4); + numAllocBlocks = _RamRead16(DPBaddr + 5) + 1; + extentsPerDirEntry = extentMask + 1; + + // ********** Patch CP/M (fake) Disk Parameter Header after the Disk Parameter Block ********** + _RamWrite( i++, 0); // Addr of the sector translation table + _RamWrite( i++, 0); + _RamWrite( i++, 0); // Workspace + _RamWrite( i++, 0); + _RamWrite( i++, 0); + _RamWrite( i++, 0); + _RamWrite( i++, 0); + _RamWrite( i++, 0); + _RamWrite( i++, 0x80); // Addr of the Sector Buffer + _RamWrite( i++, 0); + _RamWrite( i++, LOW_REGISTER(DPBaddr)); // Addr of the DPB Disk Parameter Block + _RamWrite( i++, HIGH_REGISTER(DPBaddr)); + _RamWrite( i++, 0); // Addr of the Directory Checksum Vector + _RamWrite( i++, 0); + _RamWrite( i++, 0); // Addr of the Allocation Vector + _RamWrite( i++, 0); + + // + + // figure out the number of the first allocation block + // after the directory for the phoney allocation block + // list in _findnext() + firstBlockAfterDir = 0; + i = 0x80; + + while (_RamRead(DPBaddr + 9) & i) { + firstBlockAfterDir++; + i >>= 1; + } + if (_RamRead(DPBaddr + 9) == 0xFF) { + i = 0x80; + + while (_RamRead(DPBaddr + 10) & i) { + firstBlockAfterDir++; + i >>= 1; + } + } + physicalExtentBytes = logicalExtentBytes * (extentMask + 1); +} // _PatchCPM + +#ifdef DEBUGLOG +uint8 LogBuffer[128]; + +void _logRegs(void) { + uint8 J, I; + uint8 Flags[9] = {'S', 'Z', '5', 'H', '3', 'P', 'N', 'C'}; + uint8 c = HIGH_REGISTER(AF); + + if ((c < 32) || (c > 126)) + c = 46; + + for (J = 0, I = LOW_REGISTER(AF); J < 8; ++J, I <<= 1) + Flags[J] = I & 0x80 ? Flags[J] : '.'; + sprintf((char *)LogBuffer, " BC:%04x DE:%04x HL:%04x AF:%02x(%c)|%s| IX:%04x IY:%04x SP:%04x PC:%04x\n", + WORD16(BC), WORD16(DE), WORD16(HL), HIGH_REGISTER(AF), c, Flags, WORD16(IX), WORD16(IY), WORD16(SP), WORD16(PC)); + _sys_logbuffer(LogBuffer); +} // _logRegs + +void _logMem(uint16 address, uint8 amount) { // Amount = number of 16 bytes lines, so 1 CP/M block = 8, not 128 + uint8 i, m, c, pos; + uint8 head = 8; + uint8 hexa[] = "0123456789ABCDEF"; + + for (i = 0; i < amount; ++i) { + pos = 0; + + for (m = 0; m < head; ++m) + LogBuffer[pos++] = ' '; + sprintf((char *)LogBuffer, " %04x: ", address); + + for (m = 0; m < 16; ++m) { + c = _RamRead(address++); + LogBuffer[pos++] = hexa[c >> 4]; + LogBuffer[pos++] = hexa[c & 0x0f]; + LogBuffer[pos++] = ' '; + LogBuffer[m + head + 48] = c > 31 && c < 127 ? c : '.'; + } + pos += 16; + LogBuffer[pos++] = 0x0a; + LogBuffer[pos++] = 0x00; + _sys_logbuffer(LogBuffer); + } +} // _logMem + +void _logChar(char *txt, uint8 c) { + uint8 asc[2]; + + asc[0] = c > 31 && c < 127 ? c : '.'; + asc[1] = 0; + sprintf((char *)LogBuffer, " %s = %02xh:%3d (%s)\n", txt, c, c, asc); + _sys_logbuffer(LogBuffer); +} // _logChar + +void _logBiosIn(uint8 ch) { +#ifdef LOGBIOS_NOT + if (ch == LOGBIOS_NOT) + return; +#endif // ifdef LOGBIOS_NOT +#ifdef LOGBIOS_ONLY + if (ch != LOGBIOS_ONLY) + return; +#endif // ifdef LOGBIOS_ONLY + static const char *BIOSCalls[33] = + { + "boot", "wboot", "const", "conin", "conout", "list", "punch/aux", "reader", "home", "seldsk", "settrk", "setsec", "setdma", + "read", "write", "listst", "sectran", "conost", "auxist", "auxost", "devtbl", "devini", "drvtbl", "multio", "flush", "move", + "time", "selmem", "setbnk", "xmove", "userf", "reserv1", "reserv2" + }; + int index = ch / 3; + + if (index < 18) { + sprintf((char *)LogBuffer, "\nBios call: %3d/%02xh (%s) IN:\n", ch, ch, BIOSCalls[index]); + _sys_logbuffer(LogBuffer); + } else { + sprintf((char *)LogBuffer, "\nBios call: %3d/%02xh IN:\n", ch, ch); + _sys_logbuffer(LogBuffer); + } + _logRegs(); +} // _logBiosIn + +void _logBiosOut(uint8 ch) { +#ifdef LOGBIOS_NOT + if (ch == LOGBIOS_NOT) + return; +#endif // ifdef LOGBIOS_NOT +#ifdef LOGBIOS_ONLY + if (ch != LOGBIOS_ONLY) + return; +#endif // ifdef LOGBIOS_ONLY + sprintf((char *)LogBuffer, " OUT:\n"); + _sys_logbuffer(LogBuffer); + _logRegs(); +} // _logBiosOut + +void _logBdosIn(uint8 ch) { +#ifdef LOGBDOS_NOT + if (ch == LOGBDOS_NOT) + return; +#endif // ifdef LOGBDOS_NOT +#ifdef LOGBDOS_ONLY + if (ch != LOGBDOS_ONLY) + return; +#endif // ifdef LOGBDOS_ONLY + uint16 address = 0; + uint8 size = 0; + + static const char *CPMCalls[41] = + { + "System Reset", "Console Input", "Console Output", "Reader Input", "Punch Output", "List Output", "Direct I/O", + "Get IOByte", "Set IOByte", "Print String", "Read Buffered", "Console Status", "Get Version", "Reset Disk", + "Select Disk", "Open File", "Close File", "Search First", "Search Next", "Delete File", "Read Sequential", + "Write Sequential", "Make File", "Rename File", "Get Login Vector", "Get Current Disk", "Set DMA Address", + "Get Alloc", "Write Protect Disk", "Get R/O Vector", "Set File Attr", "Get Disk Params", "Get/Set User", + "Read Random", "Write Random", "Get File Size", "Set Random Record", "Reset Drive", "N/A", "N/A", + "Write Random 0 fill" + }; + + if (ch < 41) { + sprintf((char *)LogBuffer, "\nBdos call: %3d/%02xh (%s) IN from 0x%04x:\n", ch, ch, CPMCalls[ch], _RamRead16(SP) - 3); + _sys_logbuffer(LogBuffer); + } else { + sprintf((char *)LogBuffer, "\nBdos call: %3d/%02xh IN from 0x%04x:\n", ch, ch, _RamRead16(SP) - 3); + _sys_logbuffer(LogBuffer); + } + _logRegs(); + + switch (ch) { + case 2: + case 4: + case 5: + case 6: { + _logChar("E", LOW_REGISTER(DE)); + break; + } + + case 9: + case 10: { + address = DE; + size = 8; + break; + } + + case 15: + case 16: + case 17: + case 18: + case 19: + case 22: + case 23: + case 30: + case 35: + case 36: { + address = DE; + size = 3; + break; + } + + case 20: + case 21: + case 33: + case 34: + case 40: { + address = DE; + size = 3; + _logMem(address, size); + sprintf((char *)LogBuffer, "\n"); + _sys_logbuffer(LogBuffer); + address = dmaAddr; + size = 8; + break; + } + + default: { + break; + } + } // switch + if (size) + _logMem(address, size); +} // _logBdosIn + +void _logBdosOut(uint8 ch) { +#ifdef LOGBDOS_NOT + if (ch == LOGBDOS_NOT) + return; +#endif // ifdef LOGBDOS_NOT +#ifdef LOGBDOS_ONLY + if (ch != LOGBDOS_ONLY) + return; +#endif // ifdef LOGBDOS_ONLY + uint16 address = 0; + uint8 size = 0; + + sprintf((char *)LogBuffer, " OUT:\n"); + _sys_logbuffer(LogBuffer); + _logRegs(); + + switch (ch) { + case 1: + case 3: + case 6: { + _logChar("A", HIGH_REGISTER(AF)); + break; + } + + case 10: { + address = DE; + size = 8; + break; + } + + case 20: + case 21: + case 33: + case 34: + case 40: { + address = DE; + size = 3; + _logMem(address, size); + sprintf((char *)LogBuffer, "\n"); + _sys_logbuffer(LogBuffer); + address = dmaAddr; + size = 8; + break; + } + + case 26: { + address = dmaAddr; + size = 8; + break; + } + + case 35: + case 36: { + address = DE; + size = 3; + break; + } + + default: { + break; + } + } // switch + if (size) + _logMem(address, size); +} // _logBdosOut +#endif // ifdef DEBUGLOG + +void _Bios(void) { + uint8 ch = LOW_REGISTER(PCX); + uint8 disk[2] = {'A', 0}; + +#ifdef DEBUGLOG + _logBiosIn(ch); +#endif + + switch (ch) { + case B_BOOT: { + Status = 1; // 0 - Ends RunCPM + break; + } + case B_WBOOT: { + Status = 2; // 1 - Back to CCP + break; + } + case B_CONST: { // 2 - Console status + SET_HIGH_REGISTER(AF, _chready()); + break; + } + case B_CONIN: { // 3 - Console input + SET_HIGH_REGISTER(AF, _getch()); +#ifdef DEBUG + if (HIGH_REGISTER(AF) == 4) + Debug = 1; +#endif // ifdef DEBUG + break; + } + case B_CONOUT: { // 4 - Console output + _putcon(LOW_REGISTER(BC)); + break; + } + case B_LIST: { // 5 - List output + break; + } + case B_AUXOUT: { // 6 - Aux/Punch output + break; + } + case B_READER: { // 7 - Reader input (returns 0x1a = device not implemented) + SET_HIGH_REGISTER(AF, 0x1a); + break; + } + case B_HOME: { // 8 - Home disk head + break; + } + case B_SELDSK: { // 9 - Select disk drive + disk[0] += LOW_REGISTER(BC); + HL = 0x0000; + if (_sys_select(&disk[0])) + HL = DPHaddr; + break; + } + case B_SETTRK: { // 10 - Set track number + break; + } + case B_SETSEC: { // 11 - Set sector number + break; + } + case B_SETDMA: { // 12 - Set DMA address + HL = BC; + dmaAddr = BC; + break; + } + case B_READ: { // 13 - Read selected sector + SET_HIGH_REGISTER(AF, 0x00); + break; + } + case B_WRITE: { // 14 - Write selected sector + SET_HIGH_REGISTER(AF, 0x00); + break; + } + case B_LISTST: { // 15 - Get list device status + SET_HIGH_REGISTER(AF, 0x0ff); + break; + } + case B_SECTRAN: { // 16 - Sector translate + HL = BC; // HL=BC=No translation (1:1) + break; + } + case B_CONOST: { // 17 - Return status of current screen output device + SET_HIGH_REGISTER(AF, 0x0ff); + break; + } + case B_AUXIST: { // 18 - Return status of current auxiliary input device + SET_HIGH_REGISTER(AF, 0x00); + break; + } + case B_AUXOST: { // 19 - Return status of current auxiliary output device + SET_HIGH_REGISTER(AF, 0x00); + break; + } + case B_DEVTBL: { // 20 - Return the address of the devices table, or 0 if not implemented + HL = 0x0000; + break; + } + case B_DEVINI: { // 21 - Reinitialise character device number C + break; + } + case B_DRVTBL: { // 22 - Return the address of the drive table + HL = 0x0FFFF; + break; + } + case B_MULTIO: { // 23 - Notify the BIOS of multi sector transfer + break; + } + case B_FLUSH: { // 24 - Write any pending data to disc + SET_HIGH_REGISTER(AF, 0x00); + break; + } + case B_MOVE: { // 25 - Move a block of memory + if (!isXmove) + srcBank = dstBank = curBank; + while (BC--) + RAM[HL++ * dstBank] = RAM[DE++ * srcBank]; + isXmove = FALSE; + break; + } + case B_TIME: { // 26 - Get/Set SCB time + break; + } + case B_SELMEM: { // 27 - Select memory bank + curBank = HIGH_REGISTER(AF); + break; + } + case B_SETBNK: { // 28 - Set the bank to be used for the next read/write sector operation + ioBank = HIGH_REGISTER(AF); + } + case B_XMOVE: { // 29 - Preload banks for MOVE + srcBank = LOW_REGISTER(BC); + dstBank = HIGH_REGISTER(BC); + isXmove = TRUE; + break; + } + case B_USERF: { // 30 - This allows programs ending in RET return to internal CCP + Status = 3; + break; + } + case B_RESERV1: + case B_RESERV2: { + break; + } + default: { +#ifdef DEBUG // Show unimplemented BIOS calls only when debugging + _puts("\r\nUnimplemented BIOS call.\r\n"); + _puts("C = 0x"); + _puthex8(ch); + _puts("\r\n"); +#endif // ifdef DEBUG + break; + } + } // switch +#ifdef DEBUGLOG + _logBiosOut(ch); +#endif +} // _Bios + +void _Bdos(void) { + uint16 i; + uint8 j, chr, ch = LOW_REGISTER(BC); + +#ifdef DEBUGLOG + _logBdosIn(ch); +#endif + + HL = 0x0000; // HL is reset by the BDOS + SET_LOW_REGISTER(BC, LOW_REGISTER(DE)); // C ends up equal to E + + switch (ch) { + /* + C = 0 : System reset + Doesn't return. Reloads CP/M + */ + case P_TERMCPM: { + Status = 2; // Same as call to "BOOT" + break; + } + + /* + C = 1 : Console input + Gets a char from the console + Returns: A=Char + */ + case C_READ: { + HL = _getche(); +#ifdef DEBUG + if (HL == 4) + Debug = 1; +#endif // ifdef DEBUG + break; + } + + /* + C = 2 : Console output + E = Char + Sends the char in E to the console + */ + case C_WRITE: { + _putcon(LOW_REGISTER(DE)); + break; + } + + /* + C = 3 : Auxiliary (Reader) input + Returns: A=Char + */ + case A_READ: { + HL = 0x1a; + break; + } + + /* + C = 4 : Auxiliary (Punch) output + */ + case A_WRITE: { +#ifdef USE_PUN + if (!pun_open) { + pun_dev = _sys_fopen_w((uint8 *)pun_file); + pun_open = TRUE; + } + if (pun_dev) { + _sys_fputc(LOW_REGISTER(DE), pun_dev); + } +#endif // ifdef USE_PUN + break; + } + + /* + C = 5 : Printer output + */ + case L_WRITE: { +#ifdef USE_LST + if (!lst_open) { + lst_dev = _sys_fopen_w((uint8 *)lst_file); + lst_open = TRUE; + } + if (lst_dev) + _sys_fputc(LOW_REGISTER(DE), lst_dev); +#endif // ifdef USE_LST + break; + } + + /* + C = 6 : Direct console IO + E = 0xFF : Checks for char available and returns it, or 0x00 if none (read) + ToDo E = 0xFE : Return console input status. Zero if no character is waiting, nonzero otherwise. (CPM3) + ToDo E = 0xFD : Wait until a character is ready, return it without echoing. (CPM3) + E = char : Outputs char (write) + Returns: A=Char or 0x00 (on read) + */ + case C_RAWIO: { + if (LOW_REGISTER(DE) == 0xff) { + HL = _getchNB(); +#ifdef DEBUG + if (HL == 4) + Debug = 1; +#endif // ifdef DEBUG + } else { + _putcon(LOW_REGISTER(DE)); + } + break; + } + + /* + C = 7 : Get IOBYTE (CPM2) + Gets the system IOBYTE + Returns: A = IOBYTE (CPM2) + ToDo REPLACE with + C = 7 : Auxiliary Input status (CPM3) + 0FFh is returned if the Auxiliary Input device has a character ready; otherwise 0 is returned. + Returns: A=0 or 0FFh (CPM3) + */ + case A_STATIN: { + HL = _RamRead(0x0003); + break; + } + + /* + C = 8 : Set IOBYTE (CPM2) + E = IOBYTE + Sets the system IOBYTE to E + ToDo REPLACE with + C = 8 : Auxiliary Output status (CPM3) + 0FFh is returned if the Auxiliary Output device is ready for characters; otherwise 0 is returned. + Returns: A=0 or 0FFh (CPM3) + */ + case A_STATOUT: { + _RamWrite(0x0003, LOW_REGISTER(DE)); + break; + } + + /* + C = 9 : Output string + DE = Address of string + Sends the $ terminated string pointed by (DE) to the screen + */ + case C_WRITESTR: { + while ((ch = _RamRead(DE++)) != '$') + _putcon(ch); + break; + } + + /* + C = 10 (0Ah) : Buffered input + DE = Address of buffer + ToDo DE = 0 Use DMA address (CPM3) AND + DE=address: DE=0: + buffer: DEFB size buffer: DEFB size + DEFB ? DEFB len + bytes bytes + Reads (DE) bytes from the console + Returns: A = Number of chars read + DE) = First char + */ + case C_READSTR: { + uint16 chrsMaxIdx = WORD16(DE); //index to max number of characters + uint16 chrsCntIdx = (chrsMaxIdx + 1) & 0xFFFF; //index to number of characters read + uint16 chrsIdx = (chrsCntIdx + 1) & 0xFFFF; //index to characters + //printf("\n\r chrsMaxIdx: %0X, chrsCntIdx: %0X", chrsMaxIdx, chrsCntIdx); + + static uint8 *last = 0; + if (!last) + last = (uint8*)calloc(1,256); //allocate one (for now!) + +#ifdef PROFILE + if (time_start != 0) { + time_now = millis(); + printf(": %ld\n", time_now - time_start); + time_start = 0; + } +#endif // ifdef PROFILE + uint8 chrsMax = _RamRead(chrsMaxIdx); // Gets the max number of characters that can be read + uint8 chrsCnt = 0; // this is the number of characters read + uint8 curCol = 0; //this is the cursor column (relative to where it started) + + while (chrsMax) { + // pre-backspace, retype & post backspace counts + uint8 preBS = 0, reType = 0, postBS = 0; + + chr = _getch(); //input a character + + if (chr == 1) { // ^A - Move cursor one character to the left + if (curCol > 0) { + preBS++; //backspace one + } else { + _putcon('\007'); //ring the bell + } + } + + if (chr == 2) { // ^B - Toggle between beginning & end of line + if (curCol) { + preBS = curCol; //move to beginning + } else { + reType = chrsCnt - curCol; //move to EOL + } + } + + if ((chr == 3) && (chrsCnt == 0)) { // ^C - Abort string input + _puts("^C"); + Status = 2; + break; + } + +#ifdef DEBUG + if (chr == 4) { // ^D - DEBUG + Debug = 1; + break; + } +#endif // ifdef DEBUG + + if (chr == 5) { // ^E - goto beginning of next line + _putcon('\n'); + preBS = curCol; + reType = postBS = chrsCnt; + } + + if (chr == 6) { // ^F - Move the cursor one character forward + if (curCol < chrsCnt) { + reType++; + } else { + _putcon('\007'); //ring the bell + } + } + + if (chr == 7) { // ^G - Delete character at cursor + if (curCol < chrsCnt) { + //delete this character from buffer + for (i = curCol, j = i + 1; j < chrsCnt; i++, j++) { + ch = _RamRead(((chrsIdx + j) & 0xFFFF)); + _RamWrite((chrsIdx + i) & 0xFFFF, ch); + } + reType = postBS = chrsCnt - curCol; + chrsCnt--; + } else { + _putcon('\007'); //ring the bell + } + } + + if (((chr == 0x08) || (chr == 0x7F))) { // ^H and DEL - Delete one character to left of cursor + if (curCol > 0) { //not at BOL + if (curCol < chrsCnt) { //not at EOL + //delete previous character from buffer + for (i = curCol, j = i - 1; i < chrsCnt; i++, j++) { + ch = _RamRead(((chrsIdx + i) & 0xFFFF)); + _RamWrite((chrsIdx + j) & 0xFFFF, ch); + } + preBS++; //pre-backspace one + //note: does one extra to erase EOL + reType = postBS = chrsCnt - curCol + 1; + } else { + preBS = reType = postBS = 1; + } + chrsCnt--; + } else { + _putcon('\007'); //ring the bell + } + } + + if ((chr == 0x0A) || (chr == 0x0D)) { // ^J and ^M - Ends editing +#ifdef PROFILE + time_start = millis(); +#endif + break; + } + + if (chr == 0x0B) { // ^K - Delete to EOL from cursor + if (curCol < chrsCnt) { + reType = postBS = chrsCnt - curCol; + chrsCnt = curCol; //truncate buffer to here + } else { + _putcon('\007'); //ring the bell + } + } + + if (chr == 18) { // ^R - Retype the command line + _puts("#\b\n"); + preBS = curCol; //backspace to BOL + reType = chrsCnt; //retype everything + postBS = chrsCnt - curCol; //backspace to cursor column + } + + if (chr == 21) { // ^U - delete all characters + _puts("#\b\n"); + preBS = curCol; //backspace to BOL + chrsCnt = 0; + } + + if (chr == 23) { // ^W - recall last command + if (!curCol) { //if at beginning of command line + uint8 lastCnt = last[0]; + if (lastCnt) { //and there's a last command + //restore last command + for (j = 0; j <= lastCnt; j++) { + _RamWrite((chrsCntIdx + j) & 0xFFFF, last[j]); + } + //retype to greater of chrsCnt & lastCnt + reType = (chrsCnt > lastCnt) ? chrsCnt : lastCnt; + chrsCnt = lastCnt; //this is the restored length + //backspace to end of restored command + postBS = reType - chrsCnt; + } else { + _putcon('\007'); //ring the bell + } + } else if (curCol < chrsCnt) { //if not at EOL + reType = chrsCnt - curCol; //move to EOL + } + } + + if (chr == 24) { // ^X - delete all character left of the cursor + if (curCol > 0) { + //move rest of line to beginning of line + for (i = 0, j = curCol; j < chrsCnt;i++, j++) { + ch = _RamRead(((chrsIdx + j) & 0xFFFF)); + _RamWrite((chrsIdx +i) & 0xFFFF, ch); + } + preBS = curCol; + reType = chrsCnt; + postBS = chrsCnt; + chrsCnt -= curCol; + } else { + _putcon('\007'); //ring the bell + } + } + + if ((chr >= 0x20) && (chr <= 0x7E)) { //valid character + if (curCol < chrsCnt) { + //move rest of buffer one character right + for (i = chrsCnt, j = i - 1; i > curCol; i--, j--) { + ch = _RamRead(((chrsIdx + j) & 0xFFFF)); + _RamWrite((chrsIdx + i) & 0xFFFF, ch); + } + } + //put the new character in the buffer + _RamWrite((chrsIdx + curCol) & 0xffff, chr); + + chrsCnt++; + reType = chrsCnt - curCol; + postBS = reType - 1; + } + + //pre-backspace + for (i = 0; i < preBS; i++) { + _putcon('\b'); + curCol--; + } + + //retype + for (i = 0; i < reType; i++) { + if (curCol < chrsCnt) { + ch = _RamRead(((chrsIdx + curCol) & 0xFFFF)); + } else { + ch = ' '; + } + _putcon(ch); + curCol++; + } + + //post-backspace + for (i = 0; i < postBS; i++) { + _putcon('\b'); + curCol--; + } + + if (chrsCnt == chrsMax) // Reached the maximum count + break; + } // while (chrsMax) + + // Save the number of characters read + _RamWrite(chrsCntIdx, chrsCnt); + + //if there are characters... + if (chrsCnt) { + //... then save this as last command + for (j = 0; j <= chrsCnt; j++) { + last[j] = _RamRead((chrsCntIdx + j) & 0xFFFF); + } + } +#if 0 + printf("\n\r chrsMaxIdx: %0X, chrsMax: %u, chrsCnt: %u", chrsMaxIdx, chrsMax, chrsCnt); + for (j = 0; j < chrsCnt + 2; j++) { + printf("\n\r chrsMaxIdx[%u]: %0.2x", j, last[j]); + } +#endif + _putcon('\r'); // Gives a visual feedback that read ended + break; + } + + /* + C = 11 (0Bh) : Get console status + Returns: A=0x00 or 0xFF + */ + case C_STAT: { + HL = _chready(); + break; + } + + /* + C = 12 (0Ch) : Get version number + Returns: B=H=system type, A=L=version number + */ + case S_BDOSVER: { + HL = 0x22; + break; + } + + /* + C = 13 (0Dh) : Reset disk system + */ + case DRV_ALLRESET: { + roVector = 0; // Make all drives R/W + loginVector = 0; + dmaAddr = 0x0080; + cDrive = 0; // userCode remains unchanged + HL = _CheckSUB(); // Checks if there's a $$$.SUB on the boot disk + break; + } + + /* + C = 14 (0Eh) : Select Disk + Returns: A=0x00 or 0xFF + */ + case DRV_SET: { + oDrive = cDrive; + cDrive = LOW_REGISTER(DE); + HL = _SelectDisk(LOW_REGISTER(DE) + 1); // +1 here is to allow SelectDisk to be used directly by disk.h as well + if (!HL) { + oDrive = cDrive; + } else { + if ((_RamRead(DSKByte) & 0x0f) == cDrive) { + cDrive = oDrive = 0; + _RamWrite(DSKByte, _RamRead(DSKByte) & 0xf0); + } else { + cDrive = oDrive; + } + } + break; + } + + /* + C = 15 (0Fh) : Open file + Returns: A=0x00 or 0xFF + */ + case F_OPEN: { + HL = _OpenFile(DE); + break; + } + + /* + C = 16 (10h) : Close file + */ + case F_CLOSE: { + HL = _CloseFile(DE); + break; + } + + /* + C = 17 (11h) : Search for first + */ + case F_SFIRST: { + HL = _SearchFirst(DE, TRUE); // TRUE = Creates a fake dir entry when finding the file + break; + } + + /* + C = 18 (12h) : Search for next + */ + case F_SNEXT: { + HL = _SearchNext(DE, TRUE); // TRUE = Creates a fake dir entry when finding the file + break; + } + + /* + C = 19 (13h) : Delete file + */ + case F_DELETE: { + HL = _DeleteFile(DE); + break; + } + + /* + C = 20 (14h) : Read sequential + DE = address of FCB + ToDo under CP/M 3 this can be a multiple of 128 bytes + Returns: A = return code + */ + case F_READ: { + HL = _ReadSeq(DE); + break; + } + + /* + C = 21 (15h) : Write sequential + DE = address of FCB + ToDo under CP/M 3 this can be a multiple of 128 bytes + Returns: A=return code + */ + case F_WRITE: { + HL = _WriteSeq(DE); + break; + } + + /* + C = 22 (16h) : Make file + */ + case F_MAKE: { + HL = _MakeFile(DE); + break; + } + + /* + C = 23 (17h) : Rename file + */ + case F_RENAME: { + HL = _RenameFile(DE); + break; + } + + /* + C = 24 (18h) : Return log-in vector (active drive map) + */ + case DRV_LOGINVEC: { + HL = loginVector; // (todo) improve this + break; + } + + /* + C = 25 (19h) : Return current disk + */ + case DRV_GET: { + HL = cDrive; + break; + } + + /* + C = 26 (1Ah) : Set DMA address + */ + case F_DMAOFF: { + dmaAddr = DE; + break; + } + + /* + C = 27 (1Bh) : Get ADDR(Alloc) + */ + case DRV_ALLOCVEC: { + HL = SCBaddr; + break; + } + + /* + C = 28 (1Ch) : Write protect current disk + */ + case DRV_SETRO: { + roVector = roVector | (1 << cDrive); + break; + } + + /* + C = 29 (1Dh) : Get R/O vector + */ + case DRV_ROVEC: { + HL = roVector; + break; + } + + /* + C = 30 (1Eh) : Set file attributes (does nothing) + */ + case F_ATTRIB: { + HL = 0; + break; + } + + /* + C = 31 (1Fh) : Get ADDR(Disk Parms) + */ + case DRV_PDB: { + HL = DPBaddr; + break; + } + + /* + C = 32 (20h) : Get/Set user code + */ + case F_USERNUM: { + if (LOW_REGISTER(DE) == 0xFF) { + HL = userCode; + } else { + _SetUser(DE); + } + break; + } + + /* + C = 33 (21h) : Read random + ToDo under CPM3, if A returns 0xFF, H returns hardware error + */ + case F_READRAND: { + HL = _ReadRand(DE); + break; + } + + /* + C = 34 (22h) : Write random + ToDo under CPM3, if A returns 0xFF, H returns hardware error + */ + case F_WRITERAND: { + HL = _WriteRand(DE); + break; + } + + /* + C = 35 (23h) : Compute file size + */ + case F_SIZE: { + HL = _GetFileSize(DE); + break; + } + + /* + C = 36 (24h) : Set random record + */ + case F_RANDREC: { + HL = _SetRandom(DE); + break; + } + + /* + C = 37 (25h) : Reset drive + */ + case DRV_RESET: { + roVector = roVector & ~DE; + break; + } + + /* ********* Function 38: Not supported by CP/M 2.2 ********* + ********* Function 39: Not supported by CP/M 2.2 ********* + ********* (todo) Function 40: Write random with zero fill ********* + */ + + /* + ToDo C = 38 (26h) : Access drives (CPM3) + This is an MP/M function that is not supported under CP/M 3. If called, the file + system returns a zero In register A indicating that the access request is successful. + */ + case DRV_ACCESS: { + break; + } + + /* + ToDo C = 39 (27h) : Free drives (CPM3) + This is an MP/M function that is not supported under CP/M 3. If called, the file + system returns a zero In register A indicating that the access request is successful. + */ + case DRV_FREE: { + break; + } + + /* + C = 40 (28h) : Write random with zero fill (we have no disk blocks, so just write random) + DE = address of FCB + Returns: A = return code + H = Physical Error + */ + case F_WRITEZF: { + HL = _WriteRand(DE); + break; + } + + /* + ToDo: C = 41 (29h) : Test and Write Record (CPM3) + DE = address of FCB + Returns: A = return code + H = Physical Error + */ + case F_TESTWRITE: { + break; + } + + /* + ToDo: C = 42 (2Ah) : Lock Record (CPM3) + DE = address of FCB + Returns: A = return code + H = Physical Error + */ + case F_LOCKFILE: { + break; + } + + /* + ToDo: C = 43 (2Bh) : Unlock Record (CPM3) + DE = address of FCB + Returns: A = return code + H = Physical Error + */ + case F_UNLOCKFILE: { + break; + } + + + /* + ToDo: C = 44 (2Ch) : Set number of records to read/write at once (CPM3) + E = Number of Sectors + Returns: A = return code (Returns A=0 if E was valid, 0FFh otherwise) + */ + case F_MULTISEC: { + break; + } + + /* + ToDo: C = 45 (2Dh) : Set BDOS Error Mode (CPM3) + E = BDOS Error Mode + E < 254 Compatibility mode; program is terminated and an error message printed. + E = 254 Error code is returned in H, error message is printed. + E = 255 Error code is returned in H, no error message is printed. + Returns: None + */ + case F_ERRMODE: { + break; + } + + /* + ToDo: C = 46 (2Eh) : Get Free Disk Space (CPM3) + E = Drive + Returns: A = return code + H = Physical Error + Binary result in the first 3 bytes of current DMA buffer + */ + case DRV_SPACE: { + break; + } + + /* + ToDo: C = 47 (2Fh) : Chain to program (CPM3) + E = Chain flag + Returns: None + */ + case P_CHAIN: { + break; + } + + /* + ToDo: C = 48 (30h) : Flush Bufers (CPM3) + E = Purge flag + Returns: A = return code + H = Physical Error + */ + case DRV_FLUSH: { + break; + } + + /* + ToDo: C = 49 (31h) : Get/Set System Control (CPM3) + DE = SCB PB Address + Returns: A = Returned Byte + HL = Returned Word + */ + case S_SCB: { + break; + } + + + /* + ToDo: C = 50 (32h) : Direct BIOS Calls (CPM3) + DE = BIOS PB Address + Returns: BIOS Return + */ + case S_BIOS: { + break; + } + + /* + ToDo: C = 59 (3Bh) : Load Overlay (CPM3) + DE = address of FCB + Returns: A = return code + H = Physical Error + */ + case P_LOAD: { + break; + } + + + /* + ToDo: C = 60 (3Ch) : Call Resident System Extension (RSX) (CPM3) + DE = RSX PB Address + Returns: A = return code + H = Physical Error + */ + case S_RSX: { + break; + } + + + /* + ToDo: C = 98 (62h) : Free Blocks (CPM3) + Returns: A = return code + H = Physical Error + */ + case F_CLEANUP: { + break; + } + + + /* + ToDo: C = 99 (63h) : Truncate File (CPM3) + DE = address of FCB + Returns: A = Directory code + H = Extended or Physical Error + */ + case F_TRUNCATE: { + break; + } + + + /* + ToDo: C = 100 (64h) : Set Directory Label (CPM3) + DE = address of FCB + Returns: A = Directory code + H = Extended or Physical Error + */ + case DRV_SETLABEL: { + break; + } + + + /* + ToDo: C = 101 (65h) : Return Directory Label Data (CPM3) + E = Drive + Returns: A = Directory Label Data Byte or 0xFF + H = Physical Error + */ + case DRV_GETLABEL: { + break; + } + + + /* + ToDo: C = 102 (66h) : Read File Date Stamps and Password Mode (CPM3) + DE = address of FCB + Returns: A = Directory code + H = Physical Error + */ + case F_TIMEDATE: { + break; + } + + + /* + ToDo: C = 103 (67h) : Write File XFCB (CPM3) + DE = address of FCB + Returns: A = Directory code + H = Physical Error + */ + case F_WRITEXFCB: { + break; + } + + + /* + ToDo: C = 104 (68h) : Set Date and Time (CPM3) + DE = Date and Time (DAT) Address + Returns: None + */ + case T_SET: { + break; + } + + + /* + ToDo: C = 105 (69h) : Get Date and Time (CPM3) + DE = Date and Time (DAT) Address + Returns: Date and Time (DAT) set + A = Seconds (in packed BCD format) + */ + case T_GET: { + break; + } + + + /* + ToDo: C = 106 (6Ah) : Set Default Password (CPM3) + DE = Password Addresss + Returns: None + */ + case F_PASSWD: { + break; + } + + + /* + ToDo: C = 107 (6Bh) : Return Serial Number (CPM3) + DE = Serial Number Field + Returns: Serial number field set + */ + case S_SERIAL: { + break; + } + + + /* + ToDo: C = 108 (6Ch) : Get/Set Program Return Code (CPM3) + DE = 0xFFFF (Get) or Program Return Code (Set) + Returns: HL = Program Return Code or (none) + */ + case P_CODE: { + break; + } + + + /* + ToDo: C = 109 (6Dh) : Get/Set Console Mode (CPM3) + DE = 0xFFFF (Get) or Console Mode (Set) + Returns: HL = Console Mode or (none) + */ + case C_MODE: { + break; + } + + + /* + ToDo: C = 110 (6Eh) : Get/Set Output Delimiter (CPM3) + DE = 0xFFFF (Get) or E = Delimiter (Set) + Returns: A = Output Delimiter or (none) + */ + case C_DELIMIT: { + break; + } + + + /* + ToDo: C = 111 (6Fh) : Print Block (CPM3) + DE = address of CCB + Returns: None + */ + case C_WRITEBLK: { + break; + } + + + /* + ToDo: C = 112 (70h) : List Block (CPM3) + DE = address of CCB + Returns: None + */ + case L_WRITEBLK: { + break; + } + + + /* + ToDo: C = 152 (98h) : List Block (CPM3) + DE = address of PFCB + Returns: HL = Return code + Parsed file control block + */ + case F_PARSE: { + break; + } + + +#if defined board_digital_io + + /* + C = 220 (DCh) : PinMode + */ + case 220: { + pinMode(HIGH_REGISTER(DE), LOW_REGISTER(DE)); + break; + } + + /* + C = 221 (DDh) : DigitalRead + */ + case 221: { + HL = digitalRead(HIGH_REGISTER(DE)); + break; + } + + /* + C = 222 (DEh) : DigitalWrite + */ + case 222: { + digitalWrite(HIGH_REGISTER(DE), LOW_REGISTER(DE)); + break; + } + + /* + C = 223 (DFh) : AnalogRead + */ + case 223: { + HL = analogRead(HIGH_REGISTER(DE)); + break; + } + +#endif // if defined board_digital_io +#if defined board_analog_io + + /* + C = 224 (E0h) : AnalogWrite + */ + case 224: { + analogWrite(HIGH_REGISTER(DE), LOW_REGISTER(DE)); + break; + } + +#endif // if defined board_analog_io + + /* + C = 230 (E6h) : Set 8 bit masking + */ + case 230: { + mask8bit = LOW_REGISTER(DE); + break; + } + + /* + C = 231 (E7h) : Host specific BDOS call + */ + case 231: { + HL = hostbdos(DE); + break; + } + + /* + C = 232 (E8h) : ESP32 specific BDOS call + */ +#if defined board_esp32 + case 232: { + HL = esp32bdos(DE); + break; + } + +#endif // if defined board_esp32 +#if defined board_stm32 + case 232: { + HL = stm32bdos(DE); + break; + } + +#endif // if defined board_stm32 + + /* + C = 249 (F9h) : MakeDisk + Makes a disk directory if not existent. + */ + case 249: { + HL = _MakeDisk(DE); + break; + } + + /* + C = 250 (FAh) : HostOS + Returns: A = 0x00 - Windows / 0x01 - Arduino / 0x02 - Posix / 0x03 - Dos / 0x04 - Teensy / 0x05 - ESP32 / 0x06 - STM32 + */ + case 250: { + HL = HostOS; + break; + } + + /* + C = 251 (FBh) : Version + Returns: A = 0xVv - Version in BCD representation: V.v + */ + case 251: { + HL = VersionBCD; + break; + } + + /* + C = 252 (FCh) : CCP version + Returns: A = 0x00-0x04 = DRI|CCPZ|ZCPR2|ZCPR3|Z80CCP / 0xVv = Internal version in BCD: V.v + */ + case 252: { + HL = VersionCCP; + break; + } + + /* + C = 253 (FDh) : CCP address + */ + case 253: { + HL = CCPaddr; + break; + } + +#ifdef HASLUA + + /* + C = 254 (FEh) : Run Lua file + */ + case 254: { + HL = _RunLua(DE); + break; + } + +#endif // ifdef HASLUA + + /* + Unimplemented calls get listed + */ + default: { +#ifdef DEBUG // Show unimplemented BDOS calls only when debugging + _puts("\r\nUnimplemented BDOS call.\r\n"); + _puts("C = 0x"); + _puthex8(ch); + _puts("\r\n"); +#endif // ifdef DEBUG + break; + } + } // switch + + // CP/M BDOS does this before returning + SET_HIGH_REGISTER( BC, HIGH_REGISTER(HL)); + SET_HIGH_REGISTER( AF, LOW_REGISTER(HL)); + +#ifdef DEBUGLOG + _logBdosOut(ch); +#endif +} // _Bdos + +#endif // ifndef CPM_H diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/cpu.h b/runcpm-rp2350-hstx-usb/runcpm-pico/cpu.h new file mode 100644 index 000000000..92b40993d --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/cpu.h @@ -0,0 +1,4637 @@ +// SPDX-FileCopyrightText: 2023 Mockba the Borg +// +// SPDX-License-Identifier: MIT + +#ifndef CPU_H +#define CPU_H + +/* see main.c for definition */ + +int32 PCX; /* external view of PC */ +int32 AF; /* AF register */ +int32 BC; /* BC register */ +int32 DE; /* DE register */ +int32 HL; /* HL register */ +int32 IX; /* IX register */ +int32 IY; /* IY register */ +int32 PC; /* program counter */ +int32 SP; /* SP register */ +int32 AF1; /* alternate AF register */ +int32 BC1; /* alternate BC register */ +int32 DE1; /* alternate DE register */ +int32 HL1; /* alternate HL register */ +int32 IFF; /* Interrupt Flip Flop */ +int32 IR; /* Interrupt (upper) / Refresh (lower) register */ +int32 Status = 0; /* Status of the CPU 0=running 1=end request 2=back to CCP */ +int32 Debug = 0; +int32 Break = -1; +int32 Step = -1; + +#ifdef iDEBUG +FILE* iLogFile; +char iLogBuffer[256]; +const char* iLogTxt; +#endif + +/* increase R by val (to correctly implement refresh counter) if enabled */ +#ifdef DO_INCR +#define INCR(val) IR = (IR & ~0x3f) | ((IR + (val)) & 0x3f) +#else +#define INCR(val) ; +#endif + +/* + Functions needed by the soft CPU implementation +*/ +void cpu_out(const uint32 Port, const uint32 Value) { + if (Port == 0xFF) { + _Bios(); + } else { + _HardwareOut(Port, Value); + } +} + +uint32 cpu_in(const uint32 Port) { + uint32 Result; + if (Port == 0xFF) { + _Bdos(); + Result = HIGH_REGISTER(AF); + } else { + Result = _HardwareIn(Port); + } + return(Result); +} + +/* Z80 Custom soft core */ + +/* simulator stop codes */ +#define STOP_HALT 0 /* HALT */ +#define STOP_IBKPT 1 /* breakpoint (program counter) */ +#define STOP_MEM 2 /* breakpoint (memory access) */ +#define STOP_INSTR 3 /* breakpoint (instruction access) */ +#define STOP_OPCODE 4 /* invalid operation encountered (8080, Z80, 8086) */ + +#define ADDRMASK 0xffff + +#define FLAG_C 1 +#define FLAG_N 2 +#define FLAG_P 4 +#define FLAG_H 16 +#define FLAG_Z 64 +#define FLAG_S 128 + +#define SETFLAG(f,c) (AF = (c) ? AF | FLAG_ ## f : AF & ~FLAG_ ## f) +#define TSTFLAG(f) ((AF & FLAG_ ## f) != 0) + +#define PARITY(x) parityTable[(x) & 0xff] + +#define SET_PVS(s) (((cbits >> 6) ^ (cbits >> 5)) & 4) +#define SET_PV (SET_PVS(sum)) +#define SET_PV2(x) ((temp == (x)) << 2) + +#define POP(x) { \ + uint32 y = RAM_PP(SP); \ + x = y + (RAM_PP(SP) << 8); \ +} + +#define JPC(cond) { \ + if (cond) { \ + PC = GET_WORD(PC); \ + } else { \ + PC += 2; \ + } \ +} + +#define CALLC(cond) { \ + if (cond) { \ + uint32 adrr = GET_WORD(PC); \ + PUSH(PC + 2); \ + PC = adrr; \ + } else { \ + PC += 2; \ + } \ +} + +/* the following tables precompute some common subexpressions +parityTable[i] 0..255 (number of 1's in i is odd) ? 0 : 4 +incTable[i] 0..256! (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0) << 4) +decTable[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0xf) << 4) | 2 +cbitsTable[i] 0..511 (i & 0x10) | ((i >> 8) & 1) +cbitsDup8Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) +cbitsDup16Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | (i & 0x28) +cbits2Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | 2 +rrcaTable[i] 0..255 ((i & 1) << 15) | ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1) +rraTable[i] 0..255 ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1) +addTable[i] 0..511 ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) +subTable[i] 0..255 ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | 2 +andTable[i] 0..255 (i << 8) | (i & 0xa8) | ((i == 0) << 6) | 0x10 | parityTable[i] +xororTable[i] 0..255 (i << 8) | (i & 0xa8) | ((i == 0) << 6) | parityTable[i] +rotateShiftTable[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i & 0xff] +incZ80Table[i] 0..256! (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0) << 4) | ((i == 0x80) << 2) +decZ80Table[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0xf) << 4) | ((i == 0x7f) << 2) | 2 +cbitsZ80Table[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) +cbitsZ80DupTable[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | (i & 0xa8) +cbits2Z80Table[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 +cbits2Z80DupTable[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 | (i & 0xa8) +negTable[i] 0..255 (((i & 0x0f) != 0) << 4) | ((i == 0x80) << 2) | 2 | (i != 0) +rrdrldTable[i] 0..255 (i << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i] +cpTable[i] 0..255 (i & 0x80) | (((i & 0xff) == 0) << 6) +*/ + +/* parityTable[i] = (number of 1's in i is odd) ? 0 : 4, i = 0..255 */ +static const uint8 parityTable[256] = { + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, +}; + +/* incTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0) << 4), i = 0..256 */ +static const uint8 incTable[257] = { + 80, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, 80 +}; + +/* decTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0xf) << 4) | 2, i = 0..255 */ +static const uint8 decTable[256] = { + 66, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, +}; + +/* cbitsTable[i] = (i & 0x10) | ((i >> 8) & 1), i = 0..511 */ +static const uint8 cbitsTable[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +}; + +/* cbitsDup8Table[i] = (i & 0x10) | ((i >> 8) & 1) | ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6), i = 0..511 */ +static const uint16 cbitsDup8Table[512] = { + 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, + 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, + 0x1010,0x1110,0x1210,0x1310,0x1410,0x1510,0x1610,0x1710, + 0x1818,0x1918,0x1a18,0x1b18,0x1c18,0x1d18,0x1e18,0x1f18, + 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, + 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, + 0x3030,0x3130,0x3230,0x3330,0x3430,0x3530,0x3630,0x3730, + 0x3838,0x3938,0x3a38,0x3b38,0x3c38,0x3d38,0x3e38,0x3f38, + 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, + 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, + 0x5010,0x5110,0x5210,0x5310,0x5410,0x5510,0x5610,0x5710, + 0x5818,0x5918,0x5a18,0x5b18,0x5c18,0x5d18,0x5e18,0x5f18, + 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, + 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, + 0x7030,0x7130,0x7230,0x7330,0x7430,0x7530,0x7630,0x7730, + 0x7838,0x7938,0x7a38,0x7b38,0x7c38,0x7d38,0x7e38,0x7f38, + 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, + 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, + 0x9090,0x9190,0x9290,0x9390,0x9490,0x9590,0x9690,0x9790, + 0x9898,0x9998,0x9a98,0x9b98,0x9c98,0x9d98,0x9e98,0x9f98, + 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, + 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, + 0xb0b0,0xb1b0,0xb2b0,0xb3b0,0xb4b0,0xb5b0,0xb6b0,0xb7b0, + 0xb8b8,0xb9b8,0xbab8,0xbbb8,0xbcb8,0xbdb8,0xbeb8,0xbfb8, + 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, + 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, + 0xd090,0xd190,0xd290,0xd390,0xd490,0xd590,0xd690,0xd790, + 0xd898,0xd998,0xda98,0xdb98,0xdc98,0xdd98,0xde98,0xdf98, + 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, + 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, + 0xf0b0,0xf1b0,0xf2b0,0xf3b0,0xf4b0,0xf5b0,0xf6b0,0xf7b0, + 0xf8b8,0xf9b8,0xfab8,0xfbb8,0xfcb8,0xfdb8,0xfeb8,0xffb8, + 0x0041,0x0101,0x0201,0x0301,0x0401,0x0501,0x0601,0x0701, + 0x0809,0x0909,0x0a09,0x0b09,0x0c09,0x0d09,0x0e09,0x0f09, + 0x1011,0x1111,0x1211,0x1311,0x1411,0x1511,0x1611,0x1711, + 0x1819,0x1919,0x1a19,0x1b19,0x1c19,0x1d19,0x1e19,0x1f19, + 0x2021,0x2121,0x2221,0x2321,0x2421,0x2521,0x2621,0x2721, + 0x2829,0x2929,0x2a29,0x2b29,0x2c29,0x2d29,0x2e29,0x2f29, + 0x3031,0x3131,0x3231,0x3331,0x3431,0x3531,0x3631,0x3731, + 0x3839,0x3939,0x3a39,0x3b39,0x3c39,0x3d39,0x3e39,0x3f39, + 0x4001,0x4101,0x4201,0x4301,0x4401,0x4501,0x4601,0x4701, + 0x4809,0x4909,0x4a09,0x4b09,0x4c09,0x4d09,0x4e09,0x4f09, + 0x5011,0x5111,0x5211,0x5311,0x5411,0x5511,0x5611,0x5711, + 0x5819,0x5919,0x5a19,0x5b19,0x5c19,0x5d19,0x5e19,0x5f19, + 0x6021,0x6121,0x6221,0x6321,0x6421,0x6521,0x6621,0x6721, + 0x6829,0x6929,0x6a29,0x6b29,0x6c29,0x6d29,0x6e29,0x6f29, + 0x7031,0x7131,0x7231,0x7331,0x7431,0x7531,0x7631,0x7731, + 0x7839,0x7939,0x7a39,0x7b39,0x7c39,0x7d39,0x7e39,0x7f39, + 0x8081,0x8181,0x8281,0x8381,0x8481,0x8581,0x8681,0x8781, + 0x8889,0x8989,0x8a89,0x8b89,0x8c89,0x8d89,0x8e89,0x8f89, + 0x9091,0x9191,0x9291,0x9391,0x9491,0x9591,0x9691,0x9791, + 0x9899,0x9999,0x9a99,0x9b99,0x9c99,0x9d99,0x9e99,0x9f99, + 0xa0a1,0xa1a1,0xa2a1,0xa3a1,0xa4a1,0xa5a1,0xa6a1,0xa7a1, + 0xa8a9,0xa9a9,0xaaa9,0xaba9,0xaca9,0xada9,0xaea9,0xafa9, + 0xb0b1,0xb1b1,0xb2b1,0xb3b1,0xb4b1,0xb5b1,0xb6b1,0xb7b1, + 0xb8b9,0xb9b9,0xbab9,0xbbb9,0xbcb9,0xbdb9,0xbeb9,0xbfb9, + 0xc081,0xc181,0xc281,0xc381,0xc481,0xc581,0xc681,0xc781, + 0xc889,0xc989,0xca89,0xcb89,0xcc89,0xcd89,0xce89,0xcf89, + 0xd091,0xd191,0xd291,0xd391,0xd491,0xd591,0xd691,0xd791, + 0xd899,0xd999,0xda99,0xdb99,0xdc99,0xdd99,0xde99,0xdf99, + 0xe0a1,0xe1a1,0xe2a1,0xe3a1,0xe4a1,0xe5a1,0xe6a1,0xe7a1, + 0xe8a9,0xe9a9,0xeaa9,0xeba9,0xeca9,0xeda9,0xeea9,0xefa9, + 0xf0b1,0xf1b1,0xf2b1,0xf3b1,0xf4b1,0xf5b1,0xf6b1,0xf7b1, + 0xf8b9,0xf9b9,0xfab9,0xfbb9,0xfcb9,0xfdb9,0xfeb9,0xffb9, +}; + +/* cbitsDup16Table[i] = (i & 0x10) | ((i >> 8) & 1) | (i & 0x28), i = 0..511 */ +static const uint8 cbitsDup16Table[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, + 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, + 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, + 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, + 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, + 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, + 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, + 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, + 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, + 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, + 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, + 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, + 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, + 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, + 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, + 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, + 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, + 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, + 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, + 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, + 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, +}; + +/* cbits2Table[i] = (i & 0x10) | ((i >> 8) & 1) | 2, i = 0..511 */ +static const uint8 cbits2Table[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, +}; + +/* rrcaTable[i] = ((i & 1) << 15) | ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1), i = 0..255 */ +static const uint16 rrcaTable[256] = { + 0x0000,0x8001,0x0100,0x8101,0x0200,0x8201,0x0300,0x8301, + 0x0400,0x8401,0x0500,0x8501,0x0600,0x8601,0x0700,0x8701, + 0x0808,0x8809,0x0908,0x8909,0x0a08,0x8a09,0x0b08,0x8b09, + 0x0c08,0x8c09,0x0d08,0x8d09,0x0e08,0x8e09,0x0f08,0x8f09, + 0x1000,0x9001,0x1100,0x9101,0x1200,0x9201,0x1300,0x9301, + 0x1400,0x9401,0x1500,0x9501,0x1600,0x9601,0x1700,0x9701, + 0x1808,0x9809,0x1908,0x9909,0x1a08,0x9a09,0x1b08,0x9b09, + 0x1c08,0x9c09,0x1d08,0x9d09,0x1e08,0x9e09,0x1f08,0x9f09, + 0x2020,0xa021,0x2120,0xa121,0x2220,0xa221,0x2320,0xa321, + 0x2420,0xa421,0x2520,0xa521,0x2620,0xa621,0x2720,0xa721, + 0x2828,0xa829,0x2928,0xa929,0x2a28,0xaa29,0x2b28,0xab29, + 0x2c28,0xac29,0x2d28,0xad29,0x2e28,0xae29,0x2f28,0xaf29, + 0x3020,0xb021,0x3120,0xb121,0x3220,0xb221,0x3320,0xb321, + 0x3420,0xb421,0x3520,0xb521,0x3620,0xb621,0x3720,0xb721, + 0x3828,0xb829,0x3928,0xb929,0x3a28,0xba29,0x3b28,0xbb29, + 0x3c28,0xbc29,0x3d28,0xbd29,0x3e28,0xbe29,0x3f28,0xbf29, + 0x4000,0xc001,0x4100,0xc101,0x4200,0xc201,0x4300,0xc301, + 0x4400,0xc401,0x4500,0xc501,0x4600,0xc601,0x4700,0xc701, + 0x4808,0xc809,0x4908,0xc909,0x4a08,0xca09,0x4b08,0xcb09, + 0x4c08,0xcc09,0x4d08,0xcd09,0x4e08,0xce09,0x4f08,0xcf09, + 0x5000,0xd001,0x5100,0xd101,0x5200,0xd201,0x5300,0xd301, + 0x5400,0xd401,0x5500,0xd501,0x5600,0xd601,0x5700,0xd701, + 0x5808,0xd809,0x5908,0xd909,0x5a08,0xda09,0x5b08,0xdb09, + 0x5c08,0xdc09,0x5d08,0xdd09,0x5e08,0xde09,0x5f08,0xdf09, + 0x6020,0xe021,0x6120,0xe121,0x6220,0xe221,0x6320,0xe321, + 0x6420,0xe421,0x6520,0xe521,0x6620,0xe621,0x6720,0xe721, + 0x6828,0xe829,0x6928,0xe929,0x6a28,0xea29,0x6b28,0xeb29, + 0x6c28,0xec29,0x6d28,0xed29,0x6e28,0xee29,0x6f28,0xef29, + 0x7020,0xf021,0x7120,0xf121,0x7220,0xf221,0x7320,0xf321, + 0x7420,0xf421,0x7520,0xf521,0x7620,0xf621,0x7720,0xf721, + 0x7828,0xf829,0x7928,0xf929,0x7a28,0xfa29,0x7b28,0xfb29, + 0x7c28,0xfc29,0x7d28,0xfd29,0x7e28,0xfe29,0x7f28,0xff29, +}; + +/* rraTable[i] = ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1), i = 0..255 */ +static const uint16 rraTable[256] = { + 0x0000,0x0001,0x0100,0x0101,0x0200,0x0201,0x0300,0x0301, + 0x0400,0x0401,0x0500,0x0501,0x0600,0x0601,0x0700,0x0701, + 0x0808,0x0809,0x0908,0x0909,0x0a08,0x0a09,0x0b08,0x0b09, + 0x0c08,0x0c09,0x0d08,0x0d09,0x0e08,0x0e09,0x0f08,0x0f09, + 0x1000,0x1001,0x1100,0x1101,0x1200,0x1201,0x1300,0x1301, + 0x1400,0x1401,0x1500,0x1501,0x1600,0x1601,0x1700,0x1701, + 0x1808,0x1809,0x1908,0x1909,0x1a08,0x1a09,0x1b08,0x1b09, + 0x1c08,0x1c09,0x1d08,0x1d09,0x1e08,0x1e09,0x1f08,0x1f09, + 0x2020,0x2021,0x2120,0x2121,0x2220,0x2221,0x2320,0x2321, + 0x2420,0x2421,0x2520,0x2521,0x2620,0x2621,0x2720,0x2721, + 0x2828,0x2829,0x2928,0x2929,0x2a28,0x2a29,0x2b28,0x2b29, + 0x2c28,0x2c29,0x2d28,0x2d29,0x2e28,0x2e29,0x2f28,0x2f29, + 0x3020,0x3021,0x3120,0x3121,0x3220,0x3221,0x3320,0x3321, + 0x3420,0x3421,0x3520,0x3521,0x3620,0x3621,0x3720,0x3721, + 0x3828,0x3829,0x3928,0x3929,0x3a28,0x3a29,0x3b28,0x3b29, + 0x3c28,0x3c29,0x3d28,0x3d29,0x3e28,0x3e29,0x3f28,0x3f29, + 0x4000,0x4001,0x4100,0x4101,0x4200,0x4201,0x4300,0x4301, + 0x4400,0x4401,0x4500,0x4501,0x4600,0x4601,0x4700,0x4701, + 0x4808,0x4809,0x4908,0x4909,0x4a08,0x4a09,0x4b08,0x4b09, + 0x4c08,0x4c09,0x4d08,0x4d09,0x4e08,0x4e09,0x4f08,0x4f09, + 0x5000,0x5001,0x5100,0x5101,0x5200,0x5201,0x5300,0x5301, + 0x5400,0x5401,0x5500,0x5501,0x5600,0x5601,0x5700,0x5701, + 0x5808,0x5809,0x5908,0x5909,0x5a08,0x5a09,0x5b08,0x5b09, + 0x5c08,0x5c09,0x5d08,0x5d09,0x5e08,0x5e09,0x5f08,0x5f09, + 0x6020,0x6021,0x6120,0x6121,0x6220,0x6221,0x6320,0x6321, + 0x6420,0x6421,0x6520,0x6521,0x6620,0x6621,0x6720,0x6721, + 0x6828,0x6829,0x6928,0x6929,0x6a28,0x6a29,0x6b28,0x6b29, + 0x6c28,0x6c29,0x6d28,0x6d29,0x6e28,0x6e29,0x6f28,0x6f29, + 0x7020,0x7021,0x7120,0x7121,0x7220,0x7221,0x7320,0x7321, + 0x7420,0x7421,0x7520,0x7521,0x7620,0x7621,0x7720,0x7721, + 0x7828,0x7829,0x7928,0x7929,0x7a28,0x7a29,0x7b28,0x7b29, + 0x7c28,0x7c29,0x7d28,0x7d29,0x7e28,0x7e29,0x7f28,0x7f29, +}; + +/* addTable[i] = ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6), i = 0..511 */ +static const uint16 addTable[512] = { + 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, + 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, + 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, + 0x1808,0x1908,0x1a08,0x1b08,0x1c08,0x1d08,0x1e08,0x1f08, + 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, + 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, + 0x3020,0x3120,0x3220,0x3320,0x3420,0x3520,0x3620,0x3720, + 0x3828,0x3928,0x3a28,0x3b28,0x3c28,0x3d28,0x3e28,0x3f28, + 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, + 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, + 0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,0x5700, + 0x5808,0x5908,0x5a08,0x5b08,0x5c08,0x5d08,0x5e08,0x5f08, + 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, + 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, + 0x7020,0x7120,0x7220,0x7320,0x7420,0x7520,0x7620,0x7720, + 0x7828,0x7928,0x7a28,0x7b28,0x7c28,0x7d28,0x7e28,0x7f28, + 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, + 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, + 0x9080,0x9180,0x9280,0x9380,0x9480,0x9580,0x9680,0x9780, + 0x9888,0x9988,0x9a88,0x9b88,0x9c88,0x9d88,0x9e88,0x9f88, + 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, + 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, + 0xb0a0,0xb1a0,0xb2a0,0xb3a0,0xb4a0,0xb5a0,0xb6a0,0xb7a0, + 0xb8a8,0xb9a8,0xbaa8,0xbba8,0xbca8,0xbda8,0xbea8,0xbfa8, + 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, + 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, + 0xd080,0xd180,0xd280,0xd380,0xd480,0xd580,0xd680,0xd780, + 0xd888,0xd988,0xda88,0xdb88,0xdc88,0xdd88,0xde88,0xdf88, + 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, + 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, + 0xf0a0,0xf1a0,0xf2a0,0xf3a0,0xf4a0,0xf5a0,0xf6a0,0xf7a0, + 0xf8a8,0xf9a8,0xfaa8,0xfba8,0xfca8,0xfda8,0xfea8,0xffa8, + 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, + 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, + 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, + 0x1808,0x1908,0x1a08,0x1b08,0x1c08,0x1d08,0x1e08,0x1f08, + 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, + 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, + 0x3020,0x3120,0x3220,0x3320,0x3420,0x3520,0x3620,0x3720, + 0x3828,0x3928,0x3a28,0x3b28,0x3c28,0x3d28,0x3e28,0x3f28, + 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, + 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, + 0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,0x5700, + 0x5808,0x5908,0x5a08,0x5b08,0x5c08,0x5d08,0x5e08,0x5f08, + 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, + 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, + 0x7020,0x7120,0x7220,0x7320,0x7420,0x7520,0x7620,0x7720, + 0x7828,0x7928,0x7a28,0x7b28,0x7c28,0x7d28,0x7e28,0x7f28, + 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, + 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, + 0x9080,0x9180,0x9280,0x9380,0x9480,0x9580,0x9680,0x9780, + 0x9888,0x9988,0x9a88,0x9b88,0x9c88,0x9d88,0x9e88,0x9f88, + 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, + 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, + 0xb0a0,0xb1a0,0xb2a0,0xb3a0,0xb4a0,0xb5a0,0xb6a0,0xb7a0, + 0xb8a8,0xb9a8,0xbaa8,0xbba8,0xbca8,0xbda8,0xbea8,0xbfa8, + 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, + 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, + 0xd080,0xd180,0xd280,0xd380,0xd480,0xd580,0xd680,0xd780, + 0xd888,0xd988,0xda88,0xdb88,0xdc88,0xdd88,0xde88,0xdf88, + 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, + 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, + 0xf0a0,0xf1a0,0xf2a0,0xf3a0,0xf4a0,0xf5a0,0xf6a0,0xf7a0, + 0xf8a8,0xf9a8,0xfaa8,0xfba8,0xfca8,0xfda8,0xfea8,0xffa8, +}; + +/* subTable[i] = ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | 2, i = 0..255 */ +static const uint16 subTable[256] = { + 0x0042,0x0102,0x0202,0x0302,0x0402,0x0502,0x0602,0x0702, + 0x080a,0x090a,0x0a0a,0x0b0a,0x0c0a,0x0d0a,0x0e0a,0x0f0a, + 0x1002,0x1102,0x1202,0x1302,0x1402,0x1502,0x1602,0x1702, + 0x180a,0x190a,0x1a0a,0x1b0a,0x1c0a,0x1d0a,0x1e0a,0x1f0a, + 0x2022,0x2122,0x2222,0x2322,0x2422,0x2522,0x2622,0x2722, + 0x282a,0x292a,0x2a2a,0x2b2a,0x2c2a,0x2d2a,0x2e2a,0x2f2a, + 0x3022,0x3122,0x3222,0x3322,0x3422,0x3522,0x3622,0x3722, + 0x382a,0x392a,0x3a2a,0x3b2a,0x3c2a,0x3d2a,0x3e2a,0x3f2a, + 0x4002,0x4102,0x4202,0x4302,0x4402,0x4502,0x4602,0x4702, + 0x480a,0x490a,0x4a0a,0x4b0a,0x4c0a,0x4d0a,0x4e0a,0x4f0a, + 0x5002,0x5102,0x5202,0x5302,0x5402,0x5502,0x5602,0x5702, + 0x580a,0x590a,0x5a0a,0x5b0a,0x5c0a,0x5d0a,0x5e0a,0x5f0a, + 0x6022,0x6122,0x6222,0x6322,0x6422,0x6522,0x6622,0x6722, + 0x682a,0x692a,0x6a2a,0x6b2a,0x6c2a,0x6d2a,0x6e2a,0x6f2a, + 0x7022,0x7122,0x7222,0x7322,0x7422,0x7522,0x7622,0x7722, + 0x782a,0x792a,0x7a2a,0x7b2a,0x7c2a,0x7d2a,0x7e2a,0x7f2a, + 0x8082,0x8182,0x8282,0x8382,0x8482,0x8582,0x8682,0x8782, + 0x888a,0x898a,0x8a8a,0x8b8a,0x8c8a,0x8d8a,0x8e8a,0x8f8a, + 0x9082,0x9182,0x9282,0x9382,0x9482,0x9582,0x9682,0x9782, + 0x988a,0x998a,0x9a8a,0x9b8a,0x9c8a,0x9d8a,0x9e8a,0x9f8a, + 0xa0a2,0xa1a2,0xa2a2,0xa3a2,0xa4a2,0xa5a2,0xa6a2,0xa7a2, + 0xa8aa,0xa9aa,0xaaaa,0xabaa,0xacaa,0xadaa,0xaeaa,0xafaa, + 0xb0a2,0xb1a2,0xb2a2,0xb3a2,0xb4a2,0xb5a2,0xb6a2,0xb7a2, + 0xb8aa,0xb9aa,0xbaaa,0xbbaa,0xbcaa,0xbdaa,0xbeaa,0xbfaa, + 0xc082,0xc182,0xc282,0xc382,0xc482,0xc582,0xc682,0xc782, + 0xc88a,0xc98a,0xca8a,0xcb8a,0xcc8a,0xcd8a,0xce8a,0xcf8a, + 0xd082,0xd182,0xd282,0xd382,0xd482,0xd582,0xd682,0xd782, + 0xd88a,0xd98a,0xda8a,0xdb8a,0xdc8a,0xdd8a,0xde8a,0xdf8a, + 0xe0a2,0xe1a2,0xe2a2,0xe3a2,0xe4a2,0xe5a2,0xe6a2,0xe7a2, + 0xe8aa,0xe9aa,0xeaaa,0xebaa,0xecaa,0xedaa,0xeeaa,0xefaa, + 0xf0a2,0xf1a2,0xf2a2,0xf3a2,0xf4a2,0xf5a2,0xf6a2,0xf7a2, + 0xf8aa,0xf9aa,0xfaaa,0xfbaa,0xfcaa,0xfdaa,0xfeaa,0xffaa, +}; + +/* andTable[i] = (i << 8) | (i & 0xa8) | ((i == 0) << 6) | 0x10 | parityTable[i], i = 0..255 */ +static const uint16 andTable[256] = { + 0x0054,0x0110,0x0210,0x0314,0x0410,0x0514,0x0614,0x0710, + 0x0818,0x091c,0x0a1c,0x0b18,0x0c1c,0x0d18,0x0e18,0x0f1c, + 0x1010,0x1114,0x1214,0x1310,0x1414,0x1510,0x1610,0x1714, + 0x181c,0x1918,0x1a18,0x1b1c,0x1c18,0x1d1c,0x1e1c,0x1f18, + 0x2030,0x2134,0x2234,0x2330,0x2434,0x2530,0x2630,0x2734, + 0x283c,0x2938,0x2a38,0x2b3c,0x2c38,0x2d3c,0x2e3c,0x2f38, + 0x3034,0x3130,0x3230,0x3334,0x3430,0x3534,0x3634,0x3730, + 0x3838,0x393c,0x3a3c,0x3b38,0x3c3c,0x3d38,0x3e38,0x3f3c, + 0x4010,0x4114,0x4214,0x4310,0x4414,0x4510,0x4610,0x4714, + 0x481c,0x4918,0x4a18,0x4b1c,0x4c18,0x4d1c,0x4e1c,0x4f18, + 0x5014,0x5110,0x5210,0x5314,0x5410,0x5514,0x5614,0x5710, + 0x5818,0x591c,0x5a1c,0x5b18,0x5c1c,0x5d18,0x5e18,0x5f1c, + 0x6034,0x6130,0x6230,0x6334,0x6430,0x6534,0x6634,0x6730, + 0x6838,0x693c,0x6a3c,0x6b38,0x6c3c,0x6d38,0x6e38,0x6f3c, + 0x7030,0x7134,0x7234,0x7330,0x7434,0x7530,0x7630,0x7734, + 0x783c,0x7938,0x7a38,0x7b3c,0x7c38,0x7d3c,0x7e3c,0x7f38, + 0x8090,0x8194,0x8294,0x8390,0x8494,0x8590,0x8690,0x8794, + 0x889c,0x8998,0x8a98,0x8b9c,0x8c98,0x8d9c,0x8e9c,0x8f98, + 0x9094,0x9190,0x9290,0x9394,0x9490,0x9594,0x9694,0x9790, + 0x9898,0x999c,0x9a9c,0x9b98,0x9c9c,0x9d98,0x9e98,0x9f9c, + 0xa0b4,0xa1b0,0xa2b0,0xa3b4,0xa4b0,0xa5b4,0xa6b4,0xa7b0, + 0xa8b8,0xa9bc,0xaabc,0xabb8,0xacbc,0xadb8,0xaeb8,0xafbc, + 0xb0b0,0xb1b4,0xb2b4,0xb3b0,0xb4b4,0xb5b0,0xb6b0,0xb7b4, + 0xb8bc,0xb9b8,0xbab8,0xbbbc,0xbcb8,0xbdbc,0xbebc,0xbfb8, + 0xc094,0xc190,0xc290,0xc394,0xc490,0xc594,0xc694,0xc790, + 0xc898,0xc99c,0xca9c,0xcb98,0xcc9c,0xcd98,0xce98,0xcf9c, + 0xd090,0xd194,0xd294,0xd390,0xd494,0xd590,0xd690,0xd794, + 0xd89c,0xd998,0xda98,0xdb9c,0xdc98,0xdd9c,0xde9c,0xdf98, + 0xe0b0,0xe1b4,0xe2b4,0xe3b0,0xe4b4,0xe5b0,0xe6b0,0xe7b4, + 0xe8bc,0xe9b8,0xeab8,0xebbc,0xecb8,0xedbc,0xeebc,0xefb8, + 0xf0b4,0xf1b0,0xf2b0,0xf3b4,0xf4b0,0xf5b4,0xf6b4,0xf7b0, + 0xf8b8,0xf9bc,0xfabc,0xfbb8,0xfcbc,0xfdb8,0xfeb8,0xffbc, +}; + +/* xororTable[i] = (i << 8) | (i & 0xa8) | ((i == 0) << 6) | parityTable[i], i = 0..255 */ +static const uint16 xororTable[256] = { + 0x0044,0x0100,0x0200,0x0304,0x0400,0x0504,0x0604,0x0700, + 0x0808,0x090c,0x0a0c,0x0b08,0x0c0c,0x0d08,0x0e08,0x0f0c, + 0x1000,0x1104,0x1204,0x1300,0x1404,0x1500,0x1600,0x1704, + 0x180c,0x1908,0x1a08,0x1b0c,0x1c08,0x1d0c,0x1e0c,0x1f08, + 0x2020,0x2124,0x2224,0x2320,0x2424,0x2520,0x2620,0x2724, + 0x282c,0x2928,0x2a28,0x2b2c,0x2c28,0x2d2c,0x2e2c,0x2f28, + 0x3024,0x3120,0x3220,0x3324,0x3420,0x3524,0x3624,0x3720, + 0x3828,0x392c,0x3a2c,0x3b28,0x3c2c,0x3d28,0x3e28,0x3f2c, + 0x4000,0x4104,0x4204,0x4300,0x4404,0x4500,0x4600,0x4704, + 0x480c,0x4908,0x4a08,0x4b0c,0x4c08,0x4d0c,0x4e0c,0x4f08, + 0x5004,0x5100,0x5200,0x5304,0x5400,0x5504,0x5604,0x5700, + 0x5808,0x590c,0x5a0c,0x5b08,0x5c0c,0x5d08,0x5e08,0x5f0c, + 0x6024,0x6120,0x6220,0x6324,0x6420,0x6524,0x6624,0x6720, + 0x6828,0x692c,0x6a2c,0x6b28,0x6c2c,0x6d28,0x6e28,0x6f2c, + 0x7020,0x7124,0x7224,0x7320,0x7424,0x7520,0x7620,0x7724, + 0x782c,0x7928,0x7a28,0x7b2c,0x7c28,0x7d2c,0x7e2c,0x7f28, + 0x8080,0x8184,0x8284,0x8380,0x8484,0x8580,0x8680,0x8784, + 0x888c,0x8988,0x8a88,0x8b8c,0x8c88,0x8d8c,0x8e8c,0x8f88, + 0x9084,0x9180,0x9280,0x9384,0x9480,0x9584,0x9684,0x9780, + 0x9888,0x998c,0x9a8c,0x9b88,0x9c8c,0x9d88,0x9e88,0x9f8c, + 0xa0a4,0xa1a0,0xa2a0,0xa3a4,0xa4a0,0xa5a4,0xa6a4,0xa7a0, + 0xa8a8,0xa9ac,0xaaac,0xaba8,0xacac,0xada8,0xaea8,0xafac, + 0xb0a0,0xb1a4,0xb2a4,0xb3a0,0xb4a4,0xb5a0,0xb6a0,0xb7a4, + 0xb8ac,0xb9a8,0xbaa8,0xbbac,0xbca8,0xbdac,0xbeac,0xbfa8, + 0xc084,0xc180,0xc280,0xc384,0xc480,0xc584,0xc684,0xc780, + 0xc888,0xc98c,0xca8c,0xcb88,0xcc8c,0xcd88,0xce88,0xcf8c, + 0xd080,0xd184,0xd284,0xd380,0xd484,0xd580,0xd680,0xd784, + 0xd88c,0xd988,0xda88,0xdb8c,0xdc88,0xdd8c,0xde8c,0xdf88, + 0xe0a0,0xe1a4,0xe2a4,0xe3a0,0xe4a4,0xe5a0,0xe6a0,0xe7a4, + 0xe8ac,0xe9a8,0xeaa8,0xebac,0xeca8,0xedac,0xeeac,0xefa8, + 0xf0a4,0xf1a0,0xf2a0,0xf3a4,0xf4a0,0xf5a4,0xf6a4,0xf7a0, + 0xf8a8,0xf9ac,0xfaac,0xfba8,0xfcac,0xfda8,0xfea8,0xffac, +}; + +/* rotateShiftTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i & 0xff], i = 0..255 */ +static const uint8 rotateShiftTable[256] = { + 68, 0, 0, 4, 0, 4, 4, 0, 8, 12, 12, 8, 12, 8, 8, 12, + 0, 4, 4, 0, 4, 0, 0, 4, 12, 8, 8, 12, 8, 12, 12, 8, + 32, 36, 36, 32, 36, 32, 32, 36, 44, 40, 40, 44, 40, 44, 44, 40, + 36, 32, 32, 36, 32, 36, 36, 32, 40, 44, 44, 40, 44, 40, 40, 44, + 0, 4, 4, 0, 4, 0, 0, 4, 12, 8, 8, 12, 8, 12, 12, 8, + 4, 0, 0, 4, 0, 4, 4, 0, 8, 12, 12, 8, 12, 8, 8, 12, + 36, 32, 32, 36, 32, 36, 36, 32, 40, 44, 44, 40, 44, 40, 40, 44, + 32, 36, 36, 32, 36, 32, 32, 36, 44, 40, 40, 44, 40, 44, 44, 40, + 128,132,132,128,132,128,128,132,140,136,136,140,136,140,140,136, + 132,128,128,132,128,132,132,128,136,140,140,136,140,136,136,140, + 164,160,160,164,160,164,164,160,168,172,172,168,172,168,168,172, + 160,164,164,160,164,160,160,164,172,168,168,172,168,172,172,168, + 132,128,128,132,128,132,132,128,136,140,140,136,140,136,136,140, + 128,132,132,128,132,128,128,132,140,136,136,140,136,140,140,136, + 160,164,164,160,164,160,160,164,172,168,168,172,168,172,172,168, + 164,160,160,164,160,164,164,160,168,172,172,168,172,168,168,172, +}; + +/* incZ80Table[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0) << 4) | ((i == 0x80) << 2), i = 0..256 */ +static const uint8 incZ80Table[257] = { + 80, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 148,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, 80, +}; + +/* decZ80Table[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0xf) << 4) | ((i == 0x7f) << 2) | 2, i = 0..255 */ +static const uint8 decZ80Table[256] = { + 66, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 62, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, +}; + +/* cbitsZ80Table[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1), i = 0..511 */ +static const uint8 cbitsZ80Table[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +}; + +/* cbitsZ80DupTable[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | (i & 0xa8), i = 0..511 */ +static const uint8 cbitsZ80DupTable[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, + 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 48, 48, 48, 48, 48, 48, 48, 56, 56, 56, 56, 56, 56, 56, 56, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, + 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 48, 48, 48, 48, 48, 48, 48, 56, 56, 56, 56, 56, 56, 56, 56, + 132,132,132,132,132,132,132,132,140,140,140,140,140,140,140,140, + 148,148,148,148,148,148,148,148,156,156,156,156,156,156,156,156, + 164,164,164,164,164,164,164,164,172,172,172,172,172,172,172,172, + 180,180,180,180,180,180,180,180,188,188,188,188,188,188,188,188, + 132,132,132,132,132,132,132,132,140,140,140,140,140,140,140,140, + 148,148,148,148,148,148,148,148,156,156,156,156,156,156,156,156, + 164,164,164,164,164,164,164,164,172,172,172,172,172,172,172,172, + 180,180,180,180,180,180,180,180,188,188,188,188,188,188,188,188, + 5, 5, 5, 5, 5, 5, 5, 5, 13, 13, 13, 13, 13, 13, 13, 13, + 21, 21, 21, 21, 21, 21, 21, 21, 29, 29, 29, 29, 29, 29, 29, 29, + 37, 37, 37, 37, 37, 37, 37, 37, 45, 45, 45, 45, 45, 45, 45, 45, + 53, 53, 53, 53, 53, 53, 53, 53, 61, 61, 61, 61, 61, 61, 61, 61, + 5, 5, 5, 5, 5, 5, 5, 5, 13, 13, 13, 13, 13, 13, 13, 13, + 21, 21, 21, 21, 21, 21, 21, 21, 29, 29, 29, 29, 29, 29, 29, 29, + 37, 37, 37, 37, 37, 37, 37, 37, 45, 45, 45, 45, 45, 45, 45, 45, + 53, 53, 53, 53, 53, 53, 53, 53, 61, 61, 61, 61, 61, 61, 61, 61, + 129,129,129,129,129,129,129,129,137,137,137,137,137,137,137,137, + 145,145,145,145,145,145,145,145,153,153,153,153,153,153,153,153, + 161,161,161,161,161,161,161,161,169,169,169,169,169,169,169,169, + 177,177,177,177,177,177,177,177,185,185,185,185,185,185,185,185, + 129,129,129,129,129,129,129,129,137,137,137,137,137,137,137,137, + 145,145,145,145,145,145,145,145,153,153,153,153,153,153,153,153, + 161,161,161,161,161,161,161,161,169,169,169,169,169,169,169,169, + 177,177,177,177,177,177,177,177,185,185,185,185,185,185,185,185, +}; + +/* cbits2Z80Table[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2, i = 0..511 */ +static const uint8 cbits2Z80Table[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, +}; + +/* cbits2Z80DupTable[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 | (i & 0xa8), i = 0..511 */ +static const uint8 cbits2Z80DupTable[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, + 18, 18, 18, 18, 18, 18, 18, 18, 26, 26, 26, 26, 26, 26, 26, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 42, + 50, 50, 50, 50, 50, 50, 50, 50, 58, 58, 58, 58, 58, 58, 58, 58, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, + 18, 18, 18, 18, 18, 18, 18, 18, 26, 26, 26, 26, 26, 26, 26, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 42, + 50, 50, 50, 50, 50, 50, 50, 50, 58, 58, 58, 58, 58, 58, 58, 58, + 134,134,134,134,134,134,134,134,142,142,142,142,142,142,142,142, + 150,150,150,150,150,150,150,150,158,158,158,158,158,158,158,158, + 166,166,166,166,166,166,166,166,174,174,174,174,174,174,174,174, + 182,182,182,182,182,182,182,182,190,190,190,190,190,190,190,190, + 134,134,134,134,134,134,134,134,142,142,142,142,142,142,142,142, + 150,150,150,150,150,150,150,150,158,158,158,158,158,158,158,158, + 166,166,166,166,166,166,166,166,174,174,174,174,174,174,174,174, + 182,182,182,182,182,182,182,182,190,190,190,190,190,190,190,190, + 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, + 23, 23, 23, 23, 23, 23, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, + 39, 39, 39, 39, 39, 39, 39, 39, 47, 47, 47, 47, 47, 47, 47, 47, + 55, 55, 55, 55, 55, 55, 55, 55, 63, 63, 63, 63, 63, 63, 63, 63, + 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, + 23, 23, 23, 23, 23, 23, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, + 39, 39, 39, 39, 39, 39, 39, 39, 47, 47, 47, 47, 47, 47, 47, 47, + 55, 55, 55, 55, 55, 55, 55, 55, 63, 63, 63, 63, 63, 63, 63, 63, + 131,131,131,131,131,131,131,131,139,139,139,139,139,139,139,139, + 147,147,147,147,147,147,147,147,155,155,155,155,155,155,155,155, + 163,163,163,163,163,163,163,163,171,171,171,171,171,171,171,171, + 179,179,179,179,179,179,179,179,187,187,187,187,187,187,187,187, + 131,131,131,131,131,131,131,131,139,139,139,139,139,139,139,139, + 147,147,147,147,147,147,147,147,155,155,155,155,155,155,155,155, + 163,163,163,163,163,163,163,163,171,171,171,171,171,171,171,171, + 179,179,179,179,179,179,179,179,187,187,187,187,187,187,187,187, +}; + +/* negTable[i] = (((i & 0x0f) != 0) << 4) | ((i == 0x80) << 2) | 2 | (i != 0), i = 0..255 */ +static const uint8 negTable[256] = { + 2,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 7,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, +}; + +/* rrdrldTable[i] = (i << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i], i = 0..255 */ +static const uint16 rrdrldTable[256] = { + 0x0044,0x0100,0x0200,0x0304,0x0400,0x0504,0x0604,0x0700, + 0x0808,0x090c,0x0a0c,0x0b08,0x0c0c,0x0d08,0x0e08,0x0f0c, + 0x1000,0x1104,0x1204,0x1300,0x1404,0x1500,0x1600,0x1704, + 0x180c,0x1908,0x1a08,0x1b0c,0x1c08,0x1d0c,0x1e0c,0x1f08, + 0x2020,0x2124,0x2224,0x2320,0x2424,0x2520,0x2620,0x2724, + 0x282c,0x2928,0x2a28,0x2b2c,0x2c28,0x2d2c,0x2e2c,0x2f28, + 0x3024,0x3120,0x3220,0x3324,0x3420,0x3524,0x3624,0x3720, + 0x3828,0x392c,0x3a2c,0x3b28,0x3c2c,0x3d28,0x3e28,0x3f2c, + 0x4000,0x4104,0x4204,0x4300,0x4404,0x4500,0x4600,0x4704, + 0x480c,0x4908,0x4a08,0x4b0c,0x4c08,0x4d0c,0x4e0c,0x4f08, + 0x5004,0x5100,0x5200,0x5304,0x5400,0x5504,0x5604,0x5700, + 0x5808,0x590c,0x5a0c,0x5b08,0x5c0c,0x5d08,0x5e08,0x5f0c, + 0x6024,0x6120,0x6220,0x6324,0x6420,0x6524,0x6624,0x6720, + 0x6828,0x692c,0x6a2c,0x6b28,0x6c2c,0x6d28,0x6e28,0x6f2c, + 0x7020,0x7124,0x7224,0x7320,0x7424,0x7520,0x7620,0x7724, + 0x782c,0x7928,0x7a28,0x7b2c,0x7c28,0x7d2c,0x7e2c,0x7f28, + 0x8080,0x8184,0x8284,0x8380,0x8484,0x8580,0x8680,0x8784, + 0x888c,0x8988,0x8a88,0x8b8c,0x8c88,0x8d8c,0x8e8c,0x8f88, + 0x9084,0x9180,0x9280,0x9384,0x9480,0x9584,0x9684,0x9780, + 0x9888,0x998c,0x9a8c,0x9b88,0x9c8c,0x9d88,0x9e88,0x9f8c, + 0xa0a4,0xa1a0,0xa2a0,0xa3a4,0xa4a0,0xa5a4,0xa6a4,0xa7a0, + 0xa8a8,0xa9ac,0xaaac,0xaba8,0xacac,0xada8,0xaea8,0xafac, + 0xb0a0,0xb1a4,0xb2a4,0xb3a0,0xb4a4,0xb5a0,0xb6a0,0xb7a4, + 0xb8ac,0xb9a8,0xbaa8,0xbbac,0xbca8,0xbdac,0xbeac,0xbfa8, + 0xc084,0xc180,0xc280,0xc384,0xc480,0xc584,0xc684,0xc780, + 0xc888,0xc98c,0xca8c,0xcb88,0xcc8c,0xcd88,0xce88,0xcf8c, + 0xd080,0xd184,0xd284,0xd380,0xd484,0xd580,0xd680,0xd784, + 0xd88c,0xd988,0xda88,0xdb8c,0xdc88,0xdd8c,0xde8c,0xdf88, + 0xe0a0,0xe1a4,0xe2a4,0xe3a0,0xe4a4,0xe5a0,0xe6a0,0xe7a4, + 0xe8ac,0xe9a8,0xeaa8,0xebac,0xeca8,0xedac,0xeeac,0xefa8, + 0xf0a4,0xf1a0,0xf2a0,0xf3a4,0xf4a0,0xf5a4,0xf6a4,0xf7a0, + 0xf8a8,0xf9ac,0xfaac,0xfba8,0xfcac,0xfda8,0xfea8,0xffac, +}; + +/* cpTable[i] = (i & 0x80) | (((i & 0xff) == 0) << 6), i = 0..255 */ +static const uint8 cpTable[256] = { + 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +}; + +#if defined(DEBUG) || defined(iDEBUG) +static const char* Mnemonics[256] = +{ + "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", + "EX AF,AF'", "ADD HL,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", + "DJNZ @h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", + "JR @h", "ADD HL,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", + "JR NZ,@h", "LD HL,#h", "LD (#h),HL", "INC HL", "INC H", "DEC H", "LD H,*h", "DAA", + "JR Z,@h", "ADD HL,HL", "LD HL,(#h)", "DEC HL", "INC L", "DEC L", "LD L,*h", "CPL", + "JR NC,@h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL),*h", "SCF", + "JR C,@h", "ADD HL,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", + "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,H", "LD B,L", "LD B,(HL)", "LD B,A", + "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,H", "LD C,L", "LD C,(HL)", "LD C,A", + "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,H", "LD D,L", "LD D,(HL)", "LD D,A", + "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,H", "LD E,L", "LD E,(HL)", "LD E,A", + "LD H,B", "LD H,C", "LD H,D", "LD H,E", "LD H,H", "LD H,L", "LD H,(HL)", "LD H,A", + "LD L,B", "LD L,C", "LD L,D", "LD L,E", "LD L,H", "LD L,L", "LD L,(HL)", "LD L,A", + "LD (HL),B", "LD (HL),C", "LD (HL),D", "LD (HL),E", "LD (HL),H", "LD (HL),L", "HALT", "LD (HL),A", + "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,H", "LD A,L", "LD A,(HL)", "LD A,A", + "ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD (HL)", "ADD A", + "ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC (HL)", "ADC A", + "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", + "SBC B", "SBC C", "SBC D", "SBC E", "SBC H", "SBC L", "SBC (HL)", "SBC A", + "AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", + "XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A", + "OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", + "CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A", + "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD *h", "RST 00h", + "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC *h", "RST 08h", + "RET NC", "POP DE", "JP NC,#h", "OUTA (*h)", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", + "RET C", "EXX", "JP C,#h", "INA (*h)", "CALL C,#h", "PFX_DD", "SBC *h", "RST 18h", + "RET PO", "POP HL", "JP PO,#h", "EX HL,(SP)", "CALL PO,#h", "PUSH HL", "AND *h", "RST 20h", + "RET PE", "LD PC,HL", "JP PE,#h", "EX DE,HL", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", + "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", + "RET M", "LD SP,HL", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" +}; + +static const char* MnemonicsCB[256] = +{ + "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", + "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A", + "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", + "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A", + "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", + "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A", + "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (HL)", "SLL A", + "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", + "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(HL)", "BIT 0,A", + "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(HL)", "BIT 1,A", + "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(HL)", "BIT 2,A", + "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(HL)", "BIT 3,A", + "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(HL)", "BIT 4,A", + "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(HL)", "BIT 5,A", + "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(HL)", "BIT 6,A", + "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(HL)", "BIT 7,A", + "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(HL)", "RES 0,A", + "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(HL)", "RES 1,A", + "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(HL)", "RES 2,A", + "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(HL)", "RES 3,A", + "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(HL)", "RES 4,A", + "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(HL)", "RES 5,A", + "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(HL)", "RES 6,A", + "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(HL)", "RES 7,A", + "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(HL)", "SET 0,A", + "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(HL)", "SET 1,A", + "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(HL)", "SET 2,A", + "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(HL)", "SET 3,A", + "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(HL)", "SET 4,A", + "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(HL)", "SET 5,A", + "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(HL)", "SET 6,A", + "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(HL)", "SET 7,A" +}; + +static const char* MnemonicsED[256] = +{ + "DB EDh,00h", "DB EDh,01h", "DB EDh,02h", "DB EDh,03h", + "DB EDh,04h", "DB EDh,05h", "DB EDh,06h", "DB EDh,07h", + "DB EDh,08h", "DB EDh,09h", "DB EDh,0Ah", "DB EDh,0Bh", + "DB EDh,0Ch", "DB EDh,0Dh", "DB EDh,0Eh", "DB EDh,0Fh", + "DB EDh,10h", "DB EDh,11h", "DB EDh,12h", "DB EDh,13h", + "DB EDh,14h", "DB EDh,15h", "DB EDh,16h", "DB EDh,17h", + "DB EDh,18h", "DB EDh,19h", "DB EDh,1Ah", "DB EDh,1Bh", + "DB EDh,1Ch", "DB EDh,1Dh", "DB EDh,1Eh", "DB EDh,1Fh", + "DB EDh,20h", "DB EDh,21h", "DB EDh,22h", "DB EDh,23h", + "DB EDh,24h", "DB EDh,25h", "DB EDh,26h", "DB EDh,27h", + "DB EDh,28h", "DB EDh,29h", "DB EDh,2Ah", "DB EDh,2Bh", + "DB EDh,2Ch", "DB EDh,2Dh", "DB EDh,2Eh", "DB EDh,2Fh", + "DB EDh,30h", "DB EDh,31h", "DB EDh,32h", "DB EDh,33h", + "DB EDh,34h", "DB EDh,35h", "DB EDh,36h", "DB EDh,37h", + "DB EDh,38h", "DB EDh,39h", "DB EDh,3Ah", "DB EDh,3Bh", + "DB EDh,3Ch", "DB EDh,3Dh", "DB EDh,3Eh", "DB EDh,3Fh", + "IN B,(C)", "OUT (C),B", "SBC HL,BC", "LD (#h),BC", + "NEG", "RETN", "IM 0", "LD I,A", + "IN C,(C)", "OUT (C),C", "ADC HL,BC", "LD BC,(#h)", + "DB EDh,4Ch", "RETI", "DB EDh,4Eh", "LD R,A", + "IN D,(C)", "OUT (C),D", "SBC HL,DE", "LD (#h),DE", + "DB EDh,54h", "DB EDh,55h", "IM 1", "LD A,I", + "IN E,(C)", "OUT (C),E", "ADC HL,DE", "LD DE,(#h)", + "DB EDh,5Ch", "DB EDh,5Dh", "IM 2", "LD A,R", + "IN H,(C)", "OUT (C),H", "SBC HL,HL", "LD (#h),HL", + "DB EDh,64h", "DB EDh,65h", "DB EDh,66h", "RRD", + "IN L,(C)", "OUT (C),L", "ADC HL,HL", "LD HL,(#h)", + "DB EDh,6Ch", "DB EDh,6Dh", "DB EDh,6Eh", "RLD", + "IN F,(C)", "DB EDh,71h", "SBC HL,SP", "LD (#h),SP", + "DB EDh,74h", "DB EDh,75h", "DB EDh,76h", "DB EDh,77h", + "IN A,(C)", "OUT (C),A", "ADC HL,SP", "LD SP,(#h)", + "DB EDh,7Ch", "DB EDh,7Dh", "DB EDh,7Eh", "DB EDh,7Fh", + "DB EDh,80h", "DB EDh,81h", "DB EDh,82h", "DB EDh,83h", + "DB EDh,84h", "DB EDh,85h", "DB EDh,86h", "DB EDh,87h", + "DB EDh,88h", "DB EDh,89h", "DB EDh,8Ah", "DB EDh,8Bh", + "DB EDh,8Ch", "DB EDh,8Dh", "DB EDh,8Eh", "DB EDh,8Fh", + "DB EDh,90h", "DB EDh,91h", "DB EDh,92h", "DB EDh,93h", + "DB EDh,94h", "DB EDh,95h", "DB EDh,96h", "DB EDh,97h", + "DB EDh,98h", "DB EDh,99h", "DB EDh,9Ah", "DB EDh,9Bh", + "DB EDh,9Ch", "DB EDh,9Dh", "DB EDh,9Eh", "DB EDh,9Fh", + "LDI", "CPI", "INI", "OUTI", + "DB EDh,A4h", "DB EDh,A5h", "DB EDh,A6h", "DB EDh,A7h", + "LDD", "CPD", "IND", "OUTD", + "DB EDh,ACh", "DB EDh,ADh", "DB EDh,AEh", "DB EDh,AFh", + "LDIR", "CPIR", "INIR", "OTIR", + "DB EDh,B4h", "DB EDh,B5h", "DB EDh,B6h", "DB EDh,B7h", + "LDDR", "CPDR", "INDR", "OTDR", + "DB EDh,BCh", "DB EDh,BDh", "DB EDh,BEh", "DB EDh,BFh", + "DB EDh,C0h", "DB EDh,C1h", "DB EDh,C2h", "DB EDh,C3h", + "DB EDh,C4h", "DB EDh,C5h", "DB EDh,C6h", "DB EDh,C7h", + "DB EDh,C8h", "DB EDh,C9h", "DB EDh,CAh", "DB EDh,CBh", + "DB EDh,CCh", "DB EDh,CDh", "DB EDh,CEh", "DB EDh,CFh", + "DB EDh,D0h", "DB EDh,D1h", "DB EDh,D2h", "DB EDh,D3h", + "DB EDh,D4h", "DB EDh,D5h", "DB EDh,D6h", "DB EDh,D7h", + "DB EDh,D8h", "DB EDh,D9h", "DB EDh,DAh", "DB EDh,DBh", + "DB EDh,DCh", "DB EDh,DDh", "DB EDh,DEh", "DB EDh,DFh", + "DB EDh,E0h", "DB EDh,E1h", "DB EDh,E2h", "DB EDh,E3h", + "DB EDh,E4h", "DB EDh,E5h", "DB EDh,E6h", "DB EDh,E7h", + "DB EDh,E8h", "DB EDh,E9h", "DB EDh,EAh", "DB EDh,EBh", + "DB EDh,ECh", "DB EDh,EDh", "DB EDh,EEh", "DB EDh,EFh", + "DB EDh,F0h", "DB EDh,F1h", "DB EDh,F2h", "DB EDh,F3h", + "DB EDh,F4h", "DB EDh,F5h", "DB EDh,F6h", "DB EDh,F7h", + "DB EDh,F8h", "DB EDh,F9h", "DB EDh,FAh", "DB EDh,FBh", + "DB EDh,FCh", "DB EDh,FDh", "DB EDh,FEh", "DB EDh,FFh" +}; + +static const char* MnemonicsXX[256] = +{ + "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", + "EX AF,AF'", "ADD I%,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", + "DJNZ @h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", + "JR @h", "ADD I%,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", + "JR NZ,@h", "LD I%,#h", "LD (#h),I%", "INC I%", "INC I%h", "DEC I%h", "LD I%h,*h", "DAA", + "JR Z,@h", "ADD I%,I%", "LD I%,(#h)", "DEC I%", "INC I%l", "DEC I%l", "LD I%l,*h", "CPL", + "JR NC,@h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (I%+^h)", "DEC (I%+^h)", "LD (I%+^h),*h", "SCF", + "JR C,@h", "ADD I%,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", + "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,I%h", "LD B,I%l", "LD B,(I%+^h)", "LD B,A", + "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,I%h", "LD C,I%l", "LD C,(I%+^h)", "LD C,A", + "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,I%h", "LD D,I%l", "LD D,(I%+^h)", "LD D,A", + "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,I%h", "LD E,I%l", "LD E,(I%+^h)", "LD E,A", + "LD I%h,B", "LD I%h,C", "LD I%h,D", "LD I%h,E", "LD I%h,I%h", "LD I%h,I%l", "LD H,(I%+^h)", "LD I%h,A", + "LD I%l,B", "LD I%l,C", "LD I%l,D", "LD I%l,E", "LD I%l,I%h", "LD I%l,I%l", "LD L,(I%+^h)", "LD I%l,A", + "LD (I%+^h),B", "LD (I%+^h),C", "LD (I%+^h),D", "LD (I%+^h),E", "LD (I%+^h),H", "LD (I%+^h),L", "HALT", "LD (I%+^h),A", + "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,I%h", "LD A,I%l", "LD A,(I%+^h)", "LD A,A", + "ADD B", "ADD C", "ADD D", "ADD E", "ADD I%h", "ADD I%l", "ADD (I%+^h)", "ADD A", + "ADC B", "ADC C", "ADC D", "ADC E", "ADC I%h", "ADC I%l", "ADC (I%+^h)", "ADC,A", + "SUB B", "SUB C", "SUB D", "SUB E", "SUB I%h", "SUB I%l", "SUB (I%+^h)", "SUB A", + "SBC B", "SBC C", "SBC D", "SBC E", "SBC I%h", "SBC I%l", "SBC (I%+^h)", "SBC A", + "AND B", "AND C", "AND D", "AND E", "AND I%h", "AND I%l", "AND (I%+^h)", "AND A", + "XOR B", "XOR C", "XOR D", "XOR E", "XOR I%h", "XOR I%l", "XOR (I%+^h)", "XOR A", + "OR B", "OR C", "OR D", "OR E", "OR I%h", "OR I%l", "OR (I%+^h)", "OR A", + "CP B", "CP C", "CP D", "CP E", "CP I%h", "CP I%l", "CP (I%+^h)", "CP A", + "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD *h", "RST 00h", + "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC *h", "RST 08h", + "RET NC", "POP DE", "JP NC,#h", "OUTA (*h)", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", + "RET C", "EXX", "JP C,#h", "INA (*h)", "CALL C,#h", "PFX_DD", "SBC *h", "RST 18h", + "RET PO", "POP I%", "JP PO,#h", "EX I%,(SP)", "CALL PO,#h", "PUSH I%", "AND *h", "RST 20h", + "RET PE", "LD PC,I%", "JP PE,#h", "EX DE,I%", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", + "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", + "RET M", "LD SP,I%", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" +}; + +static const char* MnemonicsXCB[256] = +{ + "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (I%@h)", "RLC A", + "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (I%@h)", "RRC A", + "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (I%@h)", "RL A", + "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (I%@h)", "RR A", + "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (I%@h)", "SLA A", + "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (I%@h)", "SRA A", + "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (I%@h)", "SLL A", + "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (I%@h)", "SRL A", + "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(I%@h)", "BIT 0,A", + "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(I%@h)", "BIT 1,A", + "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(I%@h)", "BIT 2,A", + "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(I%@h)", "BIT 3,A", + "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(I%@h)", "BIT 4,A", + "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(I%@h)", "BIT 5,A", + "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(I%@h)", "BIT 6,A", + "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(I%@h)", "BIT 7,A", + "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(I%@h)", "RES 0,A", + "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(I%@h)", "RES 1,A", + "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(I%@h)", "RES 2,A", + "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(I%@h)", "RES 3,A", + "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(I%@h)", "RES 4,A", + "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(I%@h)", "RES 5,A", + "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(I%@h)", "RES 6,A", + "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(I%@h)", "RES 7,A", + "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(I%@h)", "SET 0,A", + "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(I%@h)", "SET 1,A", + "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(I%@h)", "SET 2,A", + "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(I%@h)", "SET 3,A", + "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(I%@h)", "SET 4,A", + "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(I%@h)", "SET 5,A", + "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(I%@h)", "SET 6,A", + "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(I%@h)", "SET 7,A" +}; + +static const char* CPMCalls[41] = +{ + "System Reset", "Console Input", "Console Output", "Reader Input", "Punch Output", "List Output", "Direct I/O", "Get IOByte", + "Set IOByte", "Print String", "Read Buffered", "Console Status", "Get Version", "Reset Disk", "Select Disk", "Open File", + "Close File", "Search First", "Search Next", "Delete File", "Read Sequential", "Write Sequential", "Make File", "Rename File", + "Get Login Vector", "Get Current Disk", "Set DMA Address", "Get Alloc", "Write Protect Disk", "Get R/O Vector", "Set File Attr", "Get Disk Params", + "Get/Set User", "Read Random", "Write Random", "Get File Size", "Set Random Record", "Reset Drive", "N/A", "N/A", "Write Random 0 fill" +}; + +int32 Watch = -1; +#endif + +/* Memory management */ +static uint8 GET_BYTE(uint32 Addr) { + return _RamRead(Addr & ADDRMASK); +} + +static void PUT_BYTE(uint32 Addr, uint32 Value) { + _RamWrite(Addr & ADDRMASK, Value); +} + +static uint16 GET_WORD(uint32 a) { + return GET_BYTE(a) | (GET_BYTE(a + 1) << 8); +} + +static void PUT_WORD(uint32 Addr, uint32 Value) { + _RamWrite(Addr, Value); + _RamWrite(++Addr, Value >> 8); +} + +#define RAM_MM(a) GET_BYTE(a--) +#define RAM_PP(a) GET_BYTE(a++) + +#define PUT_BYTE_PP(a,v) PUT_BYTE(a++, v) +#define PUT_BYTE_MM(a,v) PUT_BYTE(a--, v) +#define MM_PUT_BYTE(a,v) PUT_BYTE(--a, v) + +#define PUSH(x) do { \ + MM_PUT_BYTE(SP, (x) >> 8); \ + MM_PUT_BYTE(SP, x); \ +} while (0) + +/* Macros for the IN/OUT instructions INI/INIR/IND/INDR/OUTI/OTIR/OUTD/OTDR + +Pre condition +temp == value of register B at entry of the instruction +acu == value of transferred byte (IN or OUT) +Post condition +F is set correctly + +Use INOUTFLAGS_ZERO(x) for INIR/INDR/OTIR/OTDR where +x == (C + 1) & 0xff for INIR +x == L for OTIR and OTDR +x == (C - 1) & 0xff for INDR +Use INOUTFLAGS_NONZERO(x) for INI/IND/OUTI/OUTD where +x == (C + 1) & 0xff for INI +x == L for OUTI and OUTD +x == (C - 1) & 0xff for IND +*/ +#define INOUTFLAGS(syxz, x) \ + AF = (AF & 0xff00) | (syxz) | /* SF, YF, XF, ZF */ \ + ((acu & 0x80) >> 6) | /* NF */ \ + ((acu + (x)) > 0xff ? (FLAG_C | FLAG_H) : 0) | /* CF, HF */ \ + parityTable[((acu + (x)) & 7) ^ temp] /* PF */ + +#define INOUTFLAGS_ZERO(x) INOUTFLAGS(FLAG_Z, x) +#define INOUTFLAGS_NONZERO(x) \ + INOUTFLAGS((HIGH_REGISTER(BC) & 0xa8) | ((HIGH_REGISTER(BC) == 0) << 6), x) + +static inline void Z80reset(void) { + PC = 0; + IFF = 0; + IR = 0; + Status = 0; + Debug = 0; + Break = -1; + Step = -1; +} + +#ifdef DEBUG +void watchprint(uint16 pos) { + uint8 I, J; + _puts("\r\n"); + _puts(" Watch : "); _puthex16(Watch); + _puts(" = "); _puthex8(_RamRead(Watch)); _putcon(':'); _puthex8(_RamRead(Watch + 1)); + _puts(" / "); + for (J = 0, I = _RamRead(Watch); J < 8; ++J, I <<= 1) _putcon(I & 0x80 ? '1' : '0'); + _putcon(':'); + for (J = 0, I = _RamRead(Watch + 1); J < 8; ++J, I <<= 1) _putcon(I & 0x80 ? '1' : '0'); +} + +void memdump(uint16 pos) { + uint16 h = pos; + uint16 c = pos; + uint8 l, i; + uint8 ch = pos & 0xff; + + _puts(" "); + for (i = 0; i < 16; ++i) { + _puthex8(ch++ & 0x0f); + _puts(" "); + } + _puts("\r\n"); + _puts(" "); + for (i = 0; i < 16; ++i) + _puts("---"); + _puts("\r\n"); + for (l = 0; l < 16; ++l) { + _puthex16(h); + _puts(" : "); + for (i = 0; i < 16; ++i) { + _puthex8(_RamRead(h++)); + _puts(" "); + } + for (i = 0; i < 16; ++i) { + ch = _RamRead(c++); + _putcon(ch > 31 && ch < 127 ? ch : '.'); + } + _puts("\r\n"); + } +} + +uint8 Disasm(uint16 pos) { + const char* txt; + char jr; + uint8 ch = _RamRead(pos); + uint8 count = 1; + uint8 C = 0; + + switch (ch) { + case 0xCB: ++pos; txt = MnemonicsCB[_RamRead(pos++)]; count++; break; + case 0xED: ++pos; txt = MnemonicsED[_RamRead(pos++)]; count++; break; + case 0xDD: ++pos; C = 'X'; + if (_RamRead(pos) != 0xCB) { + txt = MnemonicsXX[_RamRead(pos++)]; ++count; + } else { + ++pos; txt = MnemonicsXCB[_RamRead(pos++)]; count += 2; + } + break; + case 0xFD: ++pos; C = 'Y'; + if (_RamRead(pos) != 0xCB) { + txt = MnemonicsXX[_RamRead(pos++)]; ++count; + } else { + ++pos; txt = MnemonicsXCB[_RamRead(pos++)]; count += 2; + } + break; + default: txt = Mnemonics[_RamRead(pos++)]; + } + while (*txt != 0) { + switch (*txt) { + case '*': + txt += 2; + ++count; + _puthex8(_RamRead(pos++)); + break; + case '^': + txt += 2; + ++count; + _puthex8(_RamRead(pos++)); + break; + case '#': + txt += 2; + count += 2; + _puthex8(_RamRead(pos + 1)); + _puthex8(_RamRead(pos)); + break; + case '@': + txt += 2; + ++count; + jr = _RamRead(pos++); + _puthex16(pos + jr); + break; + case '%': + _putch(C); + ++txt; + break; + default: + _putch(*txt); + ++txt; + } + } + + return(count); +} + +void Z80debug(void) { + uint8 ch = 0; + uint16 pos, l; + static const char Flags[9] = "SZ5H3PNC"; + uint8 J, I; + unsigned int bpoint; + uint8 loop = TRUE; + uint8 res = 0; + + _puts("\r\nDebug Mode - Press '?' for help"); + + while (loop) { + pos = PC; + _puts("\r\n"); + _puts("BC:"); _puthex16(BC); + _puts(" DE:"); _puthex16(DE); + _puts(" HL:"); _puthex16(HL); + _puts(" AF:"); _puthex16(AF); + _puts(" : ["); + for (J = 0, I = LOW_REGISTER(AF); J < 8; ++J, I <<= 1) _putcon(I & 0x80 ? Flags[J] : '.'); + _puts("]\r\n"); + _puts("IX:"); _puthex16(IX); + _puts(" IY:"); _puthex16(IY); + _puts(" SP:"); _puthex16(SP); + _puts(" PC:"); _puthex16(PC); + _puts(" : "); + + Disasm(pos); + + if (PC == 0x0005) { + if (LOW_REGISTER(BC) > 40) { + _puts(" (Unknown)"); + } else { + _puts(" ("); + _puts(CPMCalls[LOW_REGISTER(BC)]); + _puts(")"); + } + } + + if (Watch != -1) { + watchprint(Watch); + } + + _puts("\r\n"); + _puts("Command|? : "); + ch = _getch(); + if (ch > 21 && ch < 127) + _putch(ch); + switch (ch) { + case 't': + loop = FALSE; + break; + case 'c': + loop = FALSE; + _puts("\r\n"); + Debug = 0; + break; + case 'b': + _puts("\r\n"); memdump(BC); break; + case 'd': + _puts("\r\n"); memdump(DE); break; + case 'h': + _puts("\r\n"); memdump(HL); break; + case 'p': + _puts("\r\n"); memdump(PC & 0xFF00); break; + case 's': + _puts("\r\n"); memdump(SP & 0xFF00); break; + case 'x': + _puts("\r\n"); memdump(IX & 0xFF00); break; + case 'y': + _puts("\r\n"); memdump(IY & 0xFF00); break; + case 'a': + _puts("\r\n"); memdump(dmaAddr); break; + case 'l': + _puts("\r\n"); + I = 16; + l = pos; + while (I > 0) { + _puthex16(l); + _puts(" : "); + l += Disasm(l); + _puts("\r\n"); + --I; + } + break; + case 'B': + _puts(" Addr: "); + res=scanf("%04x", &bpoint); + if (res) { + Break = bpoint; + _puts("Breakpoint set to "); + _puthex16(Break); + _puts("\r\n"); + } + break; + case 'C': + Break = -1; + _puts(" Breakpoint cleared\r\n"); + break; + case 'D': + _puts(" Addr: "); + res=scanf("%04x", &bpoint); + if(res) + memdump(bpoint); + break; + case 'L': + _puts(" Addr: "); + res=scanf("%04x", &bpoint); + if (res) { + I = 16; + l = bpoint; + while (I > 0) { + _puthex16(l); + _puts(" : "); + l += Disasm(l); + _puts("\r\n"); + --I; + } + } + break; + case 'T': + loop = FALSE; + Step = pos + 3; // This only works correctly with CALL + // If the called function messes with the stack, this will fail as well. + Debug = 0; + break; + case 'W': + _puts(" Addr: "); + res=scanf("%04x", &bpoint); + if (res) { + Watch = bpoint; + _puts("Watch set to "); + _puthex16(Watch); + _puts("\r\n"); + } + break; + case '?': + _puts("\r\n"); + _puts("Lowercase commands:\r\n"); + _puts(" t - traces to the next instruction\r\n"); + _puts(" c - Continue execution\r\n"); + _puts(" b - Dumps memory pointed by (BC)\r\n"); + _puts(" d - Dumps memory pointed by (DE)\r\n"); + _puts(" h - Dumps memory pointed by (HL)\r\n"); + _puts(" p - Dumps the page (PC) points to\r\n"); + _puts(" s - Dumps the page (SP) points to\r\n"); + _puts(" x - Dumps the page (IX) points to\r\n"); + _puts(" y - Dumps the page (IY) points to\r\n"); + _puts(" a - Dumps memory pointed by dmaAddr\r\n"); + _puts(" l - Disassembles from current PC\r\n"); + _puts("Uppercase commands:\r\n"); + _puts(" B - Sets breakpoint at address\r\n"); + _puts(" C - Clears breakpoint\r\n"); + _puts(" D - Dumps memory at address\r\n"); + _puts(" L - Disassembles at address\r\n"); + _puts(" T - Steps over a call\r\n"); + _puts(" W - Sets a byte/word watch\r\n"); + break; + default: + _puts(" ???\r\n"); + } + } +} +#endif + +static inline void Z80run(void) { + uint32 temp = 0; + uint32 acu; + uint32 sum; + uint32 cbits; + uint32 op; + uint32 adr; + + /* main instruction fetch/decode loop */ + while (!Status) { /* loop until Status != 0 */ + +#ifdef DEBUG + if (PC == Break) { + _puts(":BREAK at "); + _puthex16(Break); + _puts(":"); + Debug = 1; + } + if (PC == Step) { + Debug = 1; + Step = -1; + } + if (Debug) + Z80debug(); +#endif + + PCX = PC; + INCR(1); /* Add one M1 cycle to refresh counter */ + +#ifdef iDEBUG + iLogFile = fopen("iDump.log", "a"); + switch (RAM[PCX & 0xffff]) { + case 0xCB: iLogTxt = MnemonicsCB[RAM[(PCX & 0xffff) + 1]]; break; + case 0xED: iLogTxt = MnemonicsED[RAM[(PCX & 0xffff) + 1]]; break; + case 0xDD: + case 0xFD: + if (RAM[PCX & 0xffff] == 0xCB) { + iLogTxt = MnemonicsXCB[RAM[(PCX & 0xffff) + 1]]; break; + } else { + iLogTxt = MnemonicsXX[RAM[(PCX & 0xffff) + 1]]; break; + } + default: iLogTxt = Mnemonics[RAM[PCX & 0xffff]]; + } + sprintf(iLogBuffer, "0x%04x : 0x%02x = %s\n", PCX, RAM[PCX & 0xffff], iLogTxt); + fputs(iLogBuffer, iLogFile); + fclose(iLogFile); +#endif + + switch (RAM_PP(PC)) { + + case 0x00: /* NOP */ + break; + + case 0x01: /* LD BC,nnnn */ + BC = GET_WORD(PC); + PC += 2; + break; + + case 0x02: /* LD (BC),A */ + PUT_BYTE(BC, HIGH_REGISTER(AF)); + break; + + case 0x03: /* INC BC */ + ++BC; + break; + + case 0x04: /* INC B */ + BC += 0x100; + temp = HIGH_REGISTER(BC); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ + break; + + case 0x05: /* DEC B */ + BC -= 0x100; + temp = HIGH_REGISTER(BC); + AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ + break; + + case 0x06: /* LD B,nn */ + SET_HIGH_REGISTER(BC, RAM_PP(PC)); + break; + + case 0x07: /* RLCA */ + AF = ((AF >> 7) & 0x0128) | ((AF << 1) & ~0x1ff) | + (AF & 0xc4) | ((AF >> 15) & 1); + break; + + case 0x08: /* EX AF,AF' */ + temp = AF; + AF = AF1; + AF1 = temp; + break; + + case 0x09: /* ADD HL,BC */ + HL &= ADDRMASK; + BC &= ADDRMASK; + sum = HL + BC; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ BC ^ sum) >> 8]; + HL = sum; + break; + + case 0x0a: /* LD A,(BC) */ + SET_HIGH_REGISTER(AF, GET_BYTE(BC)); + break; + + case 0x0b: /* DEC BC */ + --BC; + break; + + case 0x0c: /* INC C */ + temp = LOW_REGISTER(BC) + 1; + SET_LOW_REGISTER(BC, temp); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); + break; + + case 0x0d: /* DEC C */ + temp = LOW_REGISTER(BC) - 1; + SET_LOW_REGISTER(BC, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); + break; + + case 0x0e: /* LD C,nn */ + SET_LOW_REGISTER(BC, RAM_PP(PC)); + break; + + case 0x0f: /* RRCA */ + AF = (AF & 0xc4) | rrcaTable[HIGH_REGISTER(AF)]; + break; + + case 0x10: /* DJNZ dd */ + if ((BC -= 0x100) & 0xff00) + PC += (int8)GET_BYTE(PC) + 1; + else + ++PC; + break; + + case 0x11: /* LD DE,nnnn */ + DE = GET_WORD(PC); + PC += 2; + break; + + case 0x12: /* LD (DE),A */ + PUT_BYTE(DE, HIGH_REGISTER(AF)); + break; + + case 0x13: /* INC DE */ + ++DE; + break; + + case 0x14: /* INC D */ + DE += 0x100; + temp = HIGH_REGISTER(DE); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ + break; + + case 0x15: /* DEC D */ + DE -= 0x100; + temp = HIGH_REGISTER(DE); + AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ + break; + + case 0x16: /* LD D,nn */ + SET_HIGH_REGISTER(DE, RAM_PP(PC)); + break; + + case 0x17: /* RLA */ + AF = ((AF << 8) & 0x0100) | ((AF >> 7) & 0x28) | ((AF << 1) & ~0x01ff) | + (AF & 0xc4) | ((AF >> 15) & 1); + break; + + case 0x18: /* JR dd */ + PC += (int8)GET_BYTE(PC) + 1; + break; + + case 0x19: /* ADD HL,DE */ + HL &= ADDRMASK; + DE &= ADDRMASK; + sum = HL + DE; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ DE ^ sum) >> 8]; + HL = sum; + break; + + case 0x1a: /* LD A,(DE) */ + SET_HIGH_REGISTER(AF, GET_BYTE(DE)); + break; + + case 0x1b: /* DEC DE */ + --DE; + break; + + case 0x1c: /* INC E */ + temp = LOW_REGISTER(DE) + 1; + SET_LOW_REGISTER(DE, temp); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); + break; + + case 0x1d: /* DEC E */ + temp = LOW_REGISTER(DE) - 1; + SET_LOW_REGISTER(DE, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); + break; + + case 0x1e: /* LD E,nn */ + SET_LOW_REGISTER(DE, RAM_PP(PC)); + break; + + case 0x1f: /* RRA */ + AF = ((AF & 1) << 15) | (AF & 0xc4) | rraTable[HIGH_REGISTER(AF)]; + break; + + case 0x20: /* JR NZ,dd */ + if (TSTFLAG(Z)) + ++PC; + else + PC += (int8)GET_BYTE(PC) + 1; + break; + + case 0x21: /* LD HL,nnnn */ + HL = GET_WORD(PC); + PC += 2; + break; + + case 0x22: /* LD (nnnn),HL */ + PUT_WORD(GET_WORD(PC), HL); + PC += 2; + break; + + case 0x23: /* INC HL */ + ++HL; + break; + + case 0x24: /* INC H */ + HL += 0x100; + temp = HIGH_REGISTER(HL); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ + break; + + case 0x25: /* DEC H */ + HL -= 0x100; + temp = HIGH_REGISTER(HL); + AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ + break; + + case 0x26: /* LD H,nn */ + SET_HIGH_REGISTER(HL, RAM_PP(PC)); + break; + + case 0x27: /* DAA */ + acu = HIGH_REGISTER(AF); + temp = LOW_DIGIT(acu); + cbits = TSTFLAG(C); + if (TSTFLAG(N)) { /* last operation was a subtract */ + int hd = cbits || acu > 0x99; + if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ + if (temp > 5) + SETFLAG(H, 0); + acu -= 6; + acu &= 0xff; + } + if (hd) + acu -= 0x160; /* adjust high digit */ + } else { /* last operation was an add */ + if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ + SETFLAG(H, (temp > 9)); + acu += 6; + } + if (cbits || ((acu & 0x1f0) > 0x90)) + acu += 0x60; /* adjust high digit */ + } + AF = (AF & 0x12) | rrdrldTable[acu & 0xff] | ((acu >> 8) & 1) | cbits; + break; + + case 0x28: /* JR Z,dd */ + if (TSTFLAG(Z)) + PC += (int8)GET_BYTE(PC) + 1; + else + ++PC; + break; + + case 0x29: /* ADD HL,HL */ + HL &= ADDRMASK; + sum = HL + HL; + AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; + HL = sum; + break; + + case 0x2a: /* LD HL,(nnnn) */ + HL = GET_WORD(GET_WORD(PC)); + PC += 2; + break; + + case 0x2b: /* DEC HL */ + --HL; + break; + + case 0x2c: /* INC L */ + temp = LOW_REGISTER(HL) + 1; + SET_LOW_REGISTER(HL, temp); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); + break; + + case 0x2d: /* DEC L */ + temp = LOW_REGISTER(HL) - 1; + SET_LOW_REGISTER(HL, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); + break; + + case 0x2e: /* LD L,nn */ + SET_LOW_REGISTER(HL, RAM_PP(PC)); + break; + + case 0x2f: /* CPL */ + AF = (~AF & ~0xff) | (AF & 0xc5) | ((~AF >> 8) & 0x28) | 0x12; + break; + + case 0x30: /* JR NC,dd */ + if (TSTFLAG(C)) + ++PC; + else + PC += (int8)GET_BYTE(PC) + 1; + break; + + case 0x31: /* LD SP,nnnn */ + SP = GET_WORD(PC); + PC += 2; + break; + + case 0x32: /* LD (nnnn),A */ + PUT_BYTE(GET_WORD(PC), HIGH_REGISTER(AF)); + PC += 2; + break; + + case 0x33: /* INC SP */ + ++SP; + break; + + case 0x34: /* INC (HL) */ + temp = GET_BYTE(HL) + 1; + PUT_BYTE(HL, temp); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); + break; + + case 0x35: /* DEC (HL) */ + temp = GET_BYTE(HL) - 1; + PUT_BYTE(HL, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); + break; + + case 0x36: /* LD (HL),nn */ + PUT_BYTE(HL, RAM_PP(PC)); + break; + + case 0x37: /* SCF */ + AF = (AF & ~0x3b) | ((AF >> 8) & 0x28) | 1; + break; + + case 0x38: /* JR C,dd */ + if (TSTFLAG(C)) + PC += (int8)GET_BYTE(PC) + 1; + else + ++PC; + break; + + case 0x39: /* ADD HL,SP */ + HL &= ADDRMASK; + SP &= ADDRMASK; + sum = HL + SP; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ SP ^ sum) >> 8]; + HL = sum; + break; + + case 0x3a: /* LD A,(nnnn) */ + SET_HIGH_REGISTER(AF, GET_BYTE(GET_WORD(PC))); + PC += 2; + break; + + case 0x3b: /* DEC SP */ + --SP; + break; + + case 0x3c: /* INC A */ + AF += 0x100; + temp = HIGH_REGISTER(AF); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ + break; + + case 0x3d: /* DEC A */ + AF -= 0x100; + temp = HIGH_REGISTER(AF); + AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ + break; + + case 0x3e: /* LD A,nn */ + SET_HIGH_REGISTER(AF, RAM_PP(PC)); + break; + + case 0x3f: /* CCF */ + AF = (AF & ~0x3b) | ((AF >> 8) & 0x28) | ((AF & 1) << 4) | (~AF & 1); + break; + + case 0x40: /* LD B,B */ + break; + + case 0x41: /* LD B,C */ + BC = (BC & 0xff) | ((BC & 0xff) << 8); + break; + + case 0x42: /* LD B,D */ + BC = (BC & 0xff) | (DE & ~0xff); + break; + + case 0x43: /* LD B,E */ + BC = (BC & 0xff) | ((DE & 0xff) << 8); + break; + + case 0x44: /* LD B,H */ + BC = (BC & 0xff) | (HL & ~0xff); + break; + + case 0x45: /* LD B,L */ + BC = (BC & 0xff) | ((HL & 0xff) << 8); + break; + + case 0x46: /* LD B,(HL) */ + SET_HIGH_REGISTER(BC, GET_BYTE(HL)); + break; + + case 0x47: /* LD B,A */ + BC = (BC & 0xff) | (AF & ~0xff); + break; + + case 0x48: /* LD C,B */ + BC = (BC & ~0xff) | ((BC >> 8) & 0xff); + break; + + case 0x49: /* LD C,C */ + break; + + case 0x4a: /* LD C,D */ + BC = (BC & ~0xff) | ((DE >> 8) & 0xff); + break; + + case 0x4b: /* LD C,E */ + BC = (BC & ~0xff) | (DE & 0xff); + break; + + case 0x4c: /* LD C,H */ + BC = (BC & ~0xff) | ((HL >> 8) & 0xff); + break; + + case 0x4d: /* LD C,L */ + BC = (BC & ~0xff) | (HL & 0xff); + break; + + case 0x4e: /* LD C,(HL) */ + SET_LOW_REGISTER(BC, GET_BYTE(HL)); + break; + + case 0x4f: /* LD C,A */ + BC = (BC & ~0xff) | ((AF >> 8) & 0xff); + break; + + case 0x50: /* LD D,B */ + DE = (DE & 0xff) | (BC & ~0xff); + break; + + case 0x51: /* LD D,C */ + DE = (DE & 0xff) | ((BC & 0xff) << 8); + break; + + case 0x52: /* LD D,D */ + break; + + case 0x53: /* LD D,E */ + DE = (DE & 0xff) | ((DE & 0xff) << 8); + break; + + case 0x54: /* LD D,H */ + DE = (DE & 0xff) | (HL & ~0xff); + break; + + case 0x55: /* LD D,L */ + DE = (DE & 0xff) | ((HL & 0xff) << 8); + break; + + case 0x56: /* LD D,(HL) */ + SET_HIGH_REGISTER(DE, GET_BYTE(HL)); + break; + + case 0x57: /* LD D,A */ + DE = (DE & 0xff) | (AF & ~0xff); + break; + + case 0x58: /* LD E,B */ + DE = (DE & ~0xff) | ((BC >> 8) & 0xff); + break; + + case 0x59: /* LD E,C */ + DE = (DE & ~0xff) | (BC & 0xff); + break; + + case 0x5a: /* LD E,D */ + DE = (DE & ~0xff) | ((DE >> 8) & 0xff); + break; + + case 0x5b: /* LD E,E */ + break; + + case 0x5c: /* LD E,H */ + DE = (DE & ~0xff) | ((HL >> 8) & 0xff); + break; + + case 0x5d: /* LD E,L */ + DE = (DE & ~0xff) | (HL & 0xff); + break; + + case 0x5e: /* LD E,(HL) */ + SET_LOW_REGISTER(DE, GET_BYTE(HL)); + break; + + case 0x5f: /* LD E,A */ + DE = (DE & ~0xff) | ((AF >> 8) & 0xff); + break; + + case 0x60: /* LD H,B */ + HL = (HL & 0xff) | (BC & ~0xff); + break; + + case 0x61: /* LD H,C */ + HL = (HL & 0xff) | ((BC & 0xff) << 8); + break; + + case 0x62: /* LD H,D */ + HL = (HL & 0xff) | (DE & ~0xff); + break; + + case 0x63: /* LD H,E */ + HL = (HL & 0xff) | ((DE & 0xff) << 8); + break; + + case 0x64: /* LD H,H */ + break; + + case 0x65: /* LD H,L */ + HL = (HL & 0xff) | ((HL & 0xff) << 8); + break; + + case 0x66: /* LD H,(HL) */ + SET_HIGH_REGISTER(HL, GET_BYTE(HL)); + break; + + case 0x67: /* LD H,A */ + HL = (HL & 0xff) | (AF & ~0xff); + break; + + case 0x68: /* LD L,B */ + HL = (HL & ~0xff) | ((BC >> 8) & 0xff); + break; + + case 0x69: /* LD L,C */ + HL = (HL & ~0xff) | (BC & 0xff); + break; + + case 0x6a: /* LD L,D */ + HL = (HL & ~0xff) | ((DE >> 8) & 0xff); + break; + + case 0x6b: /* LD L,E */ + HL = (HL & ~0xff) | (DE & 0xff); + break; + + case 0x6c: /* LD L,H */ + HL = (HL & ~0xff) | ((HL >> 8) & 0xff); + break; + + case 0x6d: /* LD L,L */ + break; + + case 0x6e: /* LD L,(HL) */ + SET_LOW_REGISTER(HL, GET_BYTE(HL)); + break; + + case 0x6f: /* LD L,A */ + HL = (HL & ~0xff) | ((AF >> 8) & 0xff); + break; + + case 0x70: /* LD (HL),B */ + PUT_BYTE(HL, HIGH_REGISTER(BC)); + break; + + case 0x71: /* LD (HL),C */ + PUT_BYTE(HL, LOW_REGISTER(BC)); + break; + + case 0x72: /* LD (HL),D */ + PUT_BYTE(HL, HIGH_REGISTER(DE)); + break; + + case 0x73: /* LD (HL),E */ + PUT_BYTE(HL, LOW_REGISTER(DE)); + break; + + case 0x74: /* LD (HL),H */ + PUT_BYTE(HL, HIGH_REGISTER(HL)); + break; + + case 0x75: /* LD (HL),L */ + PUT_BYTE(HL, LOW_REGISTER(HL)); + break; + + case 0x76: /* HALT */ +#ifdef DEBUG + _puts("\r\n::CPU HALTED::"); // A halt is a good indicator of broken code + _puts("Press any key..."); + _getch(); +#endif + --PC; + goto end_decode; + break; + + case 0x77: /* LD (HL),A */ + PUT_BYTE(HL, HIGH_REGISTER(AF)); + break; + + case 0x78: /* LD A,B */ + AF = (AF & 0xff) | (BC & ~0xff); + break; + + case 0x79: /* LD A,C */ + AF = (AF & 0xff) | ((BC & 0xff) << 8); + break; + + case 0x7a: /* LD A,D */ + AF = (AF & 0xff) | (DE & ~0xff); + break; + + case 0x7b: /* LD A,E */ + AF = (AF & 0xff) | ((DE & 0xff) << 8); + break; + + case 0x7c: /* LD A,H */ + AF = (AF & 0xff) | (HL & ~0xff); + break; + + case 0x7d: /* LD A,L */ + AF = (AF & 0xff) | ((HL & 0xff) << 8); + break; + + case 0x7e: /* LD A,(HL) */ + SET_HIGH_REGISTER(AF, GET_BYTE(HL)); + break; + + case 0x7f: /* LD A,A */ + break; + + case 0x80: /* ADD A,B */ + temp = HIGH_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x81: /* ADD A,C */ + temp = LOW_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x82: /* ADD A,D */ + temp = HIGH_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x83: /* ADD A,E */ + temp = LOW_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x84: /* ADD A,H */ + temp = HIGH_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x85: /* ADD A,L */ + temp = LOW_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x86: /* ADD A,(HL) */ + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x87: /* ADD A,A */ + cbits = 2 * HIGH_REGISTER(AF); + AF = cbitsDup8Table[cbits] | (SET_PVS(cbits)); + break; + + case 0x88: /* ADC A,B */ + temp = HIGH_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x89: /* ADC A,C */ + temp = LOW_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8a: /* ADC A,D */ + temp = HIGH_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8b: /* ADC A,E */ + temp = LOW_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8c: /* ADC A,H */ + temp = HIGH_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8d: /* ADC A,L */ + temp = LOW_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8e: /* ADC A,(HL) */ + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8f: /* ADC A,A */ + cbits = 2 * HIGH_REGISTER(AF) + TSTFLAG(C); + AF = cbitsDup8Table[cbits] | (SET_PVS(cbits)); + break; + + case 0x90: /* SUB B */ + temp = HIGH_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x91: /* SUB C */ + temp = LOW_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x92: /* SUB D */ + temp = HIGH_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x93: /* SUB E */ + temp = LOW_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x94: /* SUB H */ + temp = HIGH_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x95: /* SUB L */ + temp = LOW_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x96: /* SUB (HL) */ + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x97: /* SUB A */ + AF = 0x42; + break; + + case 0x98: /* SBC A,B */ + temp = HIGH_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x99: /* SBC A,C */ + temp = LOW_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9a: /* SBC A,D */ + temp = HIGH_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9b: /* SBC A,E */ + temp = LOW_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9c: /* SBC A,H */ + temp = HIGH_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9d: /* SBC A,L */ + temp = LOW_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9e: /* SBC A,(HL) */ + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9f: /* SBC A,A */ + cbits = -TSTFLAG(C); + AF = subTable[cbits & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PVS(cbits)); + break; + + case 0xa0: /* AND B */ + AF = andTable[((AF & BC) >> 8) & 0xff]; + break; + + case 0xa1: /* AND C */ + AF = andTable[((AF >> 8)& BC) & 0xff]; + break; + + case 0xa2: /* AND D */ + AF = andTable[((AF & DE) >> 8) & 0xff]; + break; + + case 0xa3: /* AND E */ + AF = andTable[((AF >> 8)& DE) & 0xff]; + break; + + case 0xa4: /* AND H */ + AF = andTable[((AF & HL) >> 8) & 0xff]; + break; + + case 0xa5: /* AND L */ + AF = andTable[((AF >> 8)& HL) & 0xff]; + break; + + case 0xa6: /* AND (HL) */ + AF = andTable[((AF >> 8)& GET_BYTE(HL)) & 0xff]; + break; + + case 0xa7: /* AND A */ + AF = andTable[(AF >> 8) & 0xff]; + break; + + case 0xa8: /* XOR B */ + AF = xororTable[((AF ^ BC) >> 8) & 0xff]; + break; + + case 0xa9: /* XOR C */ + AF = xororTable[((AF >> 8) ^ BC) & 0xff]; + break; + + case 0xaa: /* XOR D */ + AF = xororTable[((AF ^ DE) >> 8) & 0xff]; + break; + + case 0xab: /* XOR E */ + AF = xororTable[((AF >> 8) ^ DE) & 0xff]; + break; + + case 0xac: /* XOR H */ + AF = xororTable[((AF ^ HL) >> 8) & 0xff]; + break; + + case 0xad: /* XOR L */ + AF = xororTable[((AF >> 8) ^ HL) & 0xff]; + break; + + case 0xae: /* XOR (HL) */ + AF = xororTable[((AF >> 8) ^ GET_BYTE(HL)) & 0xff]; + break; + + case 0xaf: /* XOR A */ + AF = 0x44; + break; + + case 0xb0: /* OR B */ + AF = xororTable[((AF | BC) >> 8) & 0xff]; + break; + + case 0xb1: /* OR C */ + AF = xororTable[((AF >> 8) | BC) & 0xff]; + break; + + case 0xb2: /* OR D */ + AF = xororTable[((AF | DE) >> 8) & 0xff]; + break; + + case 0xb3: /* OR E */ + AF = xororTable[((AF >> 8) | DE) & 0xff]; + break; + + case 0xb4: /* OR H */ + AF = xororTable[((AF | HL) >> 8) & 0xff]; + break; + + case 0xb5: /* OR L */ + AF = xororTable[((AF >> 8) | HL) & 0xff]; + break; + + case 0xb6: /* OR (HL) */ + AF = xororTable[((AF >> 8) | GET_BYTE(HL)) & 0xff]; + break; + + case 0xb7: /* OR A */ + AF = xororTable[(AF >> 8) & 0xff]; + break; + + case 0xb8: /* CP B */ + temp = HIGH_REGISTER(BC); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xb9: /* CP C */ + temp = LOW_REGISTER(BC); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xba: /* CP D */ + temp = HIGH_REGISTER(DE); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xbb: /* CP E */ + temp = LOW_REGISTER(DE); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xbc: /* CP H */ + temp = HIGH_REGISTER(HL); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xbd: /* CP L */ + temp = LOW_REGISTER(HL); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xbe: /* CP (HL) */ + temp = GET_BYTE(HL); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xbf: /* CP A */ + SET_LOW_REGISTER(AF, (HIGH_REGISTER(AF) & 0x28) | 0x42); + break; + + case 0xc0: /* RET NZ */ + if (!(TSTFLAG(Z))) + POP(PC); + break; + + case 0xc1: /* POP BC */ + POP(BC); + break; + + case 0xc2: /* JP NZ,nnnn */ + JPC(!TSTFLAG(Z)); + break; + + case 0xc3: /* JP nnnn */ + JPC(1); + break; + + case 0xc4: /* CALL NZ,nnnn */ + CALLC(!TSTFLAG(Z)); + break; + + case 0xc5: /* PUSH BC */ + PUSH(BC); + break; + + case 0xc6: /* ADD A,nn */ + temp = RAM_PP(PC); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0xc7: /* RST 0 */ + PUSH(PC); + PC = 0; + break; + + case 0xc8: /* RET Z */ + if (TSTFLAG(Z)) + POP(PC); + break; + + case 0xc9: /* RET */ + POP(PC); + break; + + case 0xca: /* JP Z,nnnn */ + JPC(TSTFLAG(Z)); + break; + + case 0xcb: /* CB prefix */ + INCR(1); /* Add one M1 cycle to refresh counter */ + adr = HL; + switch ((op = GET_BYTE(PC)) & 7) { + + case 0: + ++PC; + acu = HIGH_REGISTER(BC); + break; + + case 1: + ++PC; + acu = LOW_REGISTER(BC); + break; + + case 2: + ++PC; + acu = HIGH_REGISTER(DE); + break; + + case 3: + ++PC; + acu = LOW_REGISTER(DE); + break; + + case 4: + ++PC; + acu = HIGH_REGISTER(HL); + break; + + case 5: + ++PC; + acu = LOW_REGISTER(HL); + break; + + case 6: + ++PC; + acu = GET_BYTE(adr); + break; + + case 7: + ++PC; + acu = HIGH_REGISTER(AF); + break; + } + switch (op & 0xc0) { + + case 0x00: /* shift/rotate */ + switch (op & 0x38) { + + case 0x00:/* RLC */ + temp = (acu << 1) | (acu >> 7); + cbits = temp & 1; + goto cbshflg1; + + case 0x08:/* RRC */ + temp = (acu >> 1) | (acu << 7); + cbits = temp & 0x80; + goto cbshflg1; + + case 0x10:/* RL */ + temp = (acu << 1) | TSTFLAG(C); + cbits = acu & 0x80; + goto cbshflg1; + + case 0x18:/* RR */ + temp = (acu >> 1) | (TSTFLAG(C) << 7); + cbits = acu & 1; + goto cbshflg1; + + case 0x20:/* SLA */ + temp = acu << 1; + cbits = acu & 0x80; + goto cbshflg1; + + case 0x28:/* SRA */ + temp = (acu >> 1) | (acu & 0x80); + cbits = acu & 1; + goto cbshflg1; + + case 0x30:/* SLIA */ + temp = (acu << 1) | 1; + cbits = acu & 0x80; + goto cbshflg1; + + case 0x38:/* SRL */ + temp = acu >> 1; + cbits = acu & 1; + cbshflg1: + AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; + } + break; + + case 0x40: /* BIT */ + if (acu & (1 << ((op >> 3) & 7))) + AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); + else + AF = (AF & ~0xfe) | 0x54; + if ((op & 7) != 6) + AF |= (acu & 0x28); + temp = acu; + break; + + case 0x80: /* RES */ + temp = acu & ~(1 << ((op >> 3) & 7)); + break; + + case 0xc0: /* SET */ + temp = acu | (1 << ((op >> 3) & 7)); + break; + } + switch (op & 7) { + + case 0: + SET_HIGH_REGISTER(BC, temp); + break; + + case 1: + SET_LOW_REGISTER(BC, temp); + break; + + case 2: + SET_HIGH_REGISTER(DE, temp); + break; + + case 3: + SET_LOW_REGISTER(DE, temp); + break; + + case 4: + SET_HIGH_REGISTER(HL, temp); + break; + + case 5: + SET_LOW_REGISTER(HL, temp); + break; + + case 6: + PUT_BYTE(adr, temp); + break; + + case 7: + SET_HIGH_REGISTER(AF, temp); + break; + } + break; + + case 0xcc: /* CALL Z,nnnn */ + CALLC(TSTFLAG(Z)); + break; + + case 0xcd: /* CALL nnnn */ + CALLC(1); + break; + + case 0xce: /* ADC A,nn */ + temp = RAM_PP(PC); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0xcf: /* RST 8 */ + PUSH(PC); + PC = 8; + break; + + case 0xd0: /* RET NC */ + if (!(TSTFLAG(C))) + POP(PC); + break; + + case 0xd1: /* POP DE */ + POP(DE); + break; + + case 0xd2: /* JP NC,nnnn */ + JPC(!TSTFLAG(C)); + break; + + case 0xd3: /* OUT (nn),A */ + cpu_out(RAM_PP(PC), HIGH_REGISTER(AF)); + break; + + case 0xd4: /* CALL NC,nnnn */ + CALLC(!TSTFLAG(C)); + break; + + case 0xd5: /* PUSH DE */ + PUSH(DE); + break; + + case 0xd6: /* SUB nn */ + temp = RAM_PP(PC); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0xd7: /* RST 10H */ + PUSH(PC); + PC = 0x10; + break; + + case 0xd8: /* RET C */ + if (TSTFLAG(C)) + POP(PC); + break; + + case 0xd9: /* EXX */ + temp = BC; + BC = BC1; + BC1 = temp; + temp = DE; + DE = DE1; + DE1 = temp; + temp = HL; + HL = HL1; + HL1 = temp; + break; + + case 0xda: /* JP C,nnnn */ + JPC(TSTFLAG(C)); + break; + + case 0xdb: /* IN A,(nn) */ + SET_HIGH_REGISTER(AF, cpu_in(RAM_PP(PC))); + break; + + case 0xdc: /* CALL C,nnnn */ + CALLC(TSTFLAG(C)); + break; + + case 0xdd: /* DD prefix */ + INCR(1); /* Add one M1 cycle to refresh counter */ + switch (RAM_PP(PC)) { + + case 0x09: /* ADD IX,BC */ + IX &= ADDRMASK; + BC &= ADDRMASK; + sum = IX + BC; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ BC ^ sum) >> 8]; + IX = sum; + break; + + case 0x19: /* ADD IX,DE */ + IX &= ADDRMASK; + DE &= ADDRMASK; + sum = IX + DE; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ DE ^ sum) >> 8]; + IX = sum; + break; + + case 0x21: /* LD IX,nnnn */ + IX = GET_WORD(PC); + PC += 2; + break; + + case 0x22: /* LD (nnnn),IX */ + PUT_WORD(GET_WORD(PC), IX); + PC += 2; + break; + + case 0x23: /* INC IX */ + ++IX; + break; + + case 0x24: /* INC IXH */ + IX += 0x100; + AF = (AF & ~0xfe) | incZ80Table[HIGH_REGISTER(IX)]; + break; + + case 0x25: /* DEC IXH */ + IX -= 0x100; + AF = (AF & ~0xfe) | decZ80Table[HIGH_REGISTER(IX)]; + break; + + case 0x26: /* LD IXH,nn */ + SET_HIGH_REGISTER(IX, RAM_PP(PC)); + break; + + case 0x29: /* ADD IX,IX */ + IX &= ADDRMASK; + sum = IX + IX; + AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; + IX = sum; + break; + + case 0x2a: /* LD IX,(nnnn) */ + IX = GET_WORD(GET_WORD(PC)); + PC += 2; + break; + + case 0x2b: /* DEC IX */ + --IX; + break; + + case 0x2c: /* INC IXL */ + temp = LOW_REGISTER(IX) + 1; + SET_LOW_REGISTER(IX, temp); + AF = (AF & ~0xfe) | incZ80Table[temp]; + break; + + case 0x2d: /* DEC IXL */ + temp = LOW_REGISTER(IX) - 1; + SET_LOW_REGISTER(IX, temp); + AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; + break; + + case 0x2e: /* LD IXL,nn */ + SET_LOW_REGISTER(IX, RAM_PP(PC)); + break; + + case 0x34: /* INC (IX+dd) */ + adr = IX + (int8)RAM_PP(PC); + temp = GET_BYTE(adr) + 1; + PUT_BYTE(adr, temp); + AF = (AF & ~0xfe) | incZ80Table[temp]; + break; + + case 0x35: /* DEC (IX+dd) */ + adr = IX + (int8)RAM_PP(PC); + temp = GET_BYTE(adr) - 1; + PUT_BYTE(adr, temp); + AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; + break; + + case 0x36: /* LD (IX+dd),nn */ + adr = IX + (int8)RAM_PP(PC); + PUT_BYTE(adr, RAM_PP(PC)); + break; + + case 0x39: /* ADD IX,SP */ + IX &= ADDRMASK; + SP &= ADDRMASK; + sum = IX + SP; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ SP ^ sum) >> 8]; + IX = sum; + break; + + case 0x44: /* LD B,IXH */ + SET_HIGH_REGISTER(BC, HIGH_REGISTER(IX)); + break; + + case 0x45: /* LD B,IXL */ + SET_HIGH_REGISTER(BC, LOW_REGISTER(IX)); + break; + + case 0x46: /* LD B,(IX+dd) */ + SET_HIGH_REGISTER(BC, GET_BYTE(IX + (int8)RAM_PP(PC))); + break; + + case 0x4c: /* LD C,IXH */ + SET_LOW_REGISTER(BC, HIGH_REGISTER(IX)); + break; + + case 0x4d: /* LD C,IXL */ + SET_LOW_REGISTER(BC, LOW_REGISTER(IX)); + break; + + case 0x4e: /* LD C,(IX+dd) */ + SET_LOW_REGISTER(BC, GET_BYTE(IX + (int8)RAM_PP(PC))); + break; + + case 0x54: /* LD D,IXH */ + SET_HIGH_REGISTER(DE, HIGH_REGISTER(IX)); + break; + + case 0x55: /* LD D,IXL */ + SET_HIGH_REGISTER(DE, LOW_REGISTER(IX)); + break; + + case 0x56: /* LD D,(IX+dd) */ + SET_HIGH_REGISTER(DE, GET_BYTE(IX + (int8)RAM_PP(PC))); + break; + + case 0x5c: /* LD E,IXH */ + SET_LOW_REGISTER(DE, HIGH_REGISTER(IX)); + break; + + case 0x5d: /* LD E,IXL */ + SET_LOW_REGISTER(DE, LOW_REGISTER(IX)); + break; + + case 0x5e: /* LD E,(IX+dd) */ + SET_LOW_REGISTER(DE, GET_BYTE(IX + (int8)RAM_PP(PC))); + break; + + case 0x60: /* LD IXH,B */ + SET_HIGH_REGISTER(IX, HIGH_REGISTER(BC)); + break; + + case 0x61: /* LD IXH,C */ + SET_HIGH_REGISTER(IX, LOW_REGISTER(BC)); + break; + + case 0x62: /* LD IXH,D */ + SET_HIGH_REGISTER(IX, HIGH_REGISTER(DE)); + break; + + case 0x63: /* LD IXH,E */ + SET_HIGH_REGISTER(IX, LOW_REGISTER(DE)); + break; + + case 0x64: /* LD IXH,IXH */ + break; + + case 0x65: /* LD IXH,IXL */ + SET_HIGH_REGISTER(IX, LOW_REGISTER(IX)); + break; + + case 0x66: /* LD H,(IX+dd) */ + SET_HIGH_REGISTER(HL, GET_BYTE(IX + (int8)RAM_PP(PC))); + break; + + case 0x67: /* LD IXH,A */ + SET_HIGH_REGISTER(IX, HIGH_REGISTER(AF)); + break; + + case 0x68: /* LD IXL,B */ + SET_LOW_REGISTER(IX, HIGH_REGISTER(BC)); + break; + + case 0x69: /* LD IXL,C */ + SET_LOW_REGISTER(IX, LOW_REGISTER(BC)); + break; + + case 0x6a: /* LD IXL,D */ + SET_LOW_REGISTER(IX, HIGH_REGISTER(DE)); + break; + + case 0x6b: /* LD IXL,E */ + SET_LOW_REGISTER(IX, LOW_REGISTER(DE)); + break; + + case 0x6c: /* LD IXL,IXH */ + SET_LOW_REGISTER(IX, HIGH_REGISTER(IX)); + break; + + case 0x6d: /* LD IXL,IXL */ + break; + + case 0x6e: /* LD L,(IX+dd) */ + SET_LOW_REGISTER(HL, GET_BYTE(IX + (int8)RAM_PP(PC))); + break; + + case 0x6f: /* LD IXL,A */ + SET_LOW_REGISTER(IX, HIGH_REGISTER(AF)); + break; + + case 0x70: /* LD (IX+dd),B */ + PUT_BYTE(IX + (int8)RAM_PP(PC), HIGH_REGISTER(BC)); + break; + + case 0x71: /* LD (IX+dd),C */ + PUT_BYTE(IX + (int8)RAM_PP(PC), LOW_REGISTER(BC)); + break; + + case 0x72: /* LD (IX+dd),D */ + PUT_BYTE(IX + (int8)RAM_PP(PC), HIGH_REGISTER(DE)); + break; + + case 0x73: /* LD (IX+dd),E */ + PUT_BYTE(IX + (int8)RAM_PP(PC), LOW_REGISTER(DE)); + break; + + case 0x74: /* LD (IX+dd),H */ + PUT_BYTE(IX + (int8)RAM_PP(PC), HIGH_REGISTER(HL)); + break; + + case 0x75: /* LD (IX+dd),L */ + PUT_BYTE(IX + (int8)RAM_PP(PC), LOW_REGISTER(HL)); + break; + + case 0x77: /* LD (IX+dd),A */ + PUT_BYTE(IX + (int8)RAM_PP(PC), HIGH_REGISTER(AF)); + break; + + case 0x7c: /* LD A,IXH */ + SET_HIGH_REGISTER(AF, HIGH_REGISTER(IX)); + break; + + case 0x7d: /* LD A,IXL */ + SET_HIGH_REGISTER(AF, LOW_REGISTER(IX)); + break; + + case 0x7e: /* LD A,(IX+dd) */ + SET_HIGH_REGISTER(AF, GET_BYTE(IX + (int8)RAM_PP(PC))); + break; + + case 0x84: /* ADD A,IXH */ + temp = HIGH_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x85: /* ADD A,IXL */ + temp = LOW_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x86: /* ADD A,(IX+dd) */ + adr = IX + (int8)RAM_PP(PC); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8c: /* ADC A,IXH */ + temp = HIGH_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8d: /* ADC A,IXL */ + temp = LOW_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8e: /* ADC A,(IX+dd) */ + adr = IX + (int8)RAM_PP(PC); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x96: /* SUB (IX+dd) */ + adr = IX + (int8)RAM_PP(PC); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x94: /* SUB IXH */ + SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ + + case 0x9c: /* SBC A,IXH */ + temp = HIGH_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x95: /* SUB IXL */ + SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ + + case 0x9d: /* SBC A,IXL */ + temp = LOW_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x9e: /* SBC A,(IX+dd) */ + adr = IX + (int8)RAM_PP(PC); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xa4: /* AND IXH */ + AF = andTable[((AF & IX) >> 8) & 0xff]; + break; + + case 0xa5: /* AND IXL */ + AF = andTable[((AF >> 8)& IX) & 0xff]; + break; + + case 0xa6: /* AND (IX+dd) */ + AF = andTable[((AF >> 8)& GET_BYTE(IX + (int8)RAM_PP(PC))) & 0xff]; + break; + + case 0xac: /* XOR IXH */ + AF = xororTable[((AF ^ IX) >> 8) & 0xff]; + break; + + case 0xad: /* XOR IXL */ + AF = xororTable[((AF >> 8) ^ IX) & 0xff]; + break; + + case 0xae: /* XOR (IX+dd) */ + AF = xororTable[((AF >> 8) ^ GET_BYTE(IX + (int8)RAM_PP(PC))) & 0xff]; + break; + + case 0xb4: /* OR IXH */ + AF = xororTable[((AF | IX) >> 8) & 0xff]; + break; + + case 0xb5: /* OR IXL */ + AF = xororTable[((AF >> 8) | IX) & 0xff]; + break; + + case 0xb6: /* OR (IX+dd) */ + AF = xororTable[((AF >> 8) | GET_BYTE(IX + (int8)RAM_PP(PC))) & 0xff]; + break; + + case 0xbc: /* CP IXH */ + temp = HIGH_REGISTER(IX); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xbd: /* CP IXL */ + temp = LOW_REGISTER(IX); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xbe: /* CP (IX+dd) */ + adr = IX + (int8)RAM_PP(PC); + temp = GET_BYTE(adr); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xcb: /* CB prefix */ + adr = IX + (int8)RAM_PP(PC); + switch ((op = GET_BYTE(PC)) & 7) { + + case 0: + ++PC; + acu = HIGH_REGISTER(BC); + break; + + case 1: + ++PC; + acu = LOW_REGISTER(BC); + break; + + case 2: + ++PC; + acu = HIGH_REGISTER(DE); + break; + + case 3: + ++PC; + acu = LOW_REGISTER(DE); + break; + + case 4: + ++PC; + acu = HIGH_REGISTER(HL); + break; + + case 5: + ++PC; + acu = LOW_REGISTER(HL); + break; + + case 6: + ++PC; + acu = GET_BYTE(adr); + break; + + case 7: + ++PC; + acu = HIGH_REGISTER(AF); + break; + } + switch (op & 0xc0) { + + case 0x00: /* shift/rotate */ + switch (op & 0x38) { + + case 0x00:/* RLC */ + temp = (acu << 1) | (acu >> 7); + cbits = temp & 1; + goto cbshflg2; + + case 0x08:/* RRC */ + temp = (acu >> 1) | (acu << 7); + cbits = temp & 0x80; + goto cbshflg2; + + case 0x10:/* RL */ + temp = (acu << 1) | TSTFLAG(C); + cbits = acu & 0x80; + goto cbshflg2; + + case 0x18:/* RR */ + temp = (acu >> 1) | (TSTFLAG(C) << 7); + cbits = acu & 1; + goto cbshflg2; + + case 0x20:/* SLA */ + temp = acu << 1; + cbits = acu & 0x80; + goto cbshflg2; + + case 0x28:/* SRA */ + temp = (acu >> 1) | (acu & 0x80); + cbits = acu & 1; + goto cbshflg2; + + case 0x30:/* SLIA */ + temp = (acu << 1) | 1; + cbits = acu & 0x80; + goto cbshflg2; + + case 0x38:/* SRL */ + temp = acu >> 1; + cbits = acu & 1; + cbshflg2: + AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; + } + break; + + case 0x40: /* BIT */ + if (acu & (1 << ((op >> 3) & 7))) + AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); + else + AF = (AF & ~0xfe) | 0x54; + if ((op & 7) != 6) + AF |= (acu & 0x28); + temp = acu; + break; + + case 0x80: /* RES */ + temp = acu & ~(1 << ((op >> 3) & 7)); + break; + + case 0xc0: /* SET */ + temp = acu | (1 << ((op >> 3) & 7)); + break; + } + switch (op & 7) { + + case 0: + SET_HIGH_REGISTER(BC, temp); + break; + + case 1: + SET_LOW_REGISTER(BC, temp); + break; + + case 2: + SET_HIGH_REGISTER(DE, temp); + break; + + case 3: + SET_LOW_REGISTER(DE, temp); + break; + + case 4: + SET_HIGH_REGISTER(HL, temp); + break; + + case 5: + SET_LOW_REGISTER(HL, temp); + break; + + case 6: + PUT_BYTE(adr, temp); + break; + + case 7: + SET_HIGH_REGISTER(AF, temp); + break; + } + break; + + case 0xe1: /* POP IX */ + POP(IX); + break; + + case 0xe3: /* EX (SP),IX */ + temp = IX; + POP(IX); + PUSH(temp); + break; + + case 0xe5: /* PUSH IX */ + PUSH(IX); + break; + + case 0xe9: /* JP (IX) */ + PC = IX; + break; + + case 0xf9: /* LD SP,IX */ + SP = IX; + break; + + default: /* ignore DD */ + --PC; + } + break; + + case 0xde: /* SBC A,nn */ + temp = RAM_PP(PC); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0xdf: /* RST 18H */ + PUSH(PC); + PC = 0x18; + break; + + case 0xe0: /* RET PO */ + if (!(TSTFLAG(P))) + POP(PC); + break; + + case 0xe1: /* POP HL */ + POP(HL); + break; + + case 0xe2: /* JP PO,nnnn */ + JPC(!TSTFLAG(P)); + break; + + case 0xe3: /* EX (SP),HL */ + temp = HL; + POP(HL); + PUSH(temp); + break; + + case 0xe4: /* CALL PO,nnnn */ + CALLC(!TSTFLAG(P)); + break; + + case 0xe5: /* PUSH HL */ + PUSH(HL); + break; + + case 0xe6: /* AND nn */ + AF = andTable[((AF >> 8)& RAM_PP(PC)) & 0xff]; + break; + + case 0xe7: /* RST 20H */ + PUSH(PC); + PC = 0x20; + break; + + case 0xe8: /* RET PE */ + if (TSTFLAG(P)) + POP(PC); + break; + + case 0xe9: /* JP (HL) */ + PC = HL; + break; + + case 0xea: /* JP PE,nnnn */ + JPC(TSTFLAG(P)); + break; + + case 0xeb: /* EX DE,HL */ + temp = HL; + HL = DE; + DE = temp; + break; + + case 0xec: /* CALL PE,nnnn */ + CALLC(TSTFLAG(P)); + break; + + case 0xed: /* ED prefix */ + INCR(1); /* Add one M1 cycle to refresh counter */ + switch (RAM_PP(PC)) { + + case 0x40: /* IN B,(C) */ + temp = cpu_in(LOW_REGISTER(BC)); + SET_HIGH_REGISTER(BC, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x41: /* OUT (C),B */ + cpu_out(LOW_REGISTER(BC), HIGH_REGISTER(BC)); + break; + + case 0x42: /* SBC HL,BC */ + HL &= ADDRMASK; + BC &= ADDRMASK; + sum = HL - BC - TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbits2Z80Table[((HL ^ BC ^ sum) >> 8) & 0x1ff]; + HL = sum; + break; + + case 0x43: /* LD (nnnn),BC */ + PUT_WORD(GET_WORD(PC), BC); + PC += 2; + break; + + case 0x44: /* NEG */ + + case 0x4C: /* NEG, unofficial */ + + case 0x54: /* NEG, unofficial */ + + case 0x5C: /* NEG, unofficial */ + + case 0x64: /* NEG, unofficial */ + + case 0x6C: /* NEG, unofficial */ + + case 0x74: /* NEG, unofficial */ + + case 0x7C: /* NEG, unofficial */ + temp = HIGH_REGISTER(AF); + AF = ((~(AF & 0xff00) + 1) & 0xff00); /* AF = (-(AF & 0xff00) & 0xff00); */ + AF |= ((AF >> 8) & 0xa8) | (((AF & 0xff00) == 0) << 6) | negTable[temp]; + break; + + case 0x45: /* RETN */ + + case 0x55: /* RETN, unofficial */ + + case 0x5D: /* RETN, unofficial */ + + case 0x65: /* RETN, unofficial */ + + case 0x6D: /* RETN, unofficial */ + + case 0x75: /* RETN, unofficial */ + + case 0x7D: /* RETN, unofficial */ + IFF |= IFF >> 1; + POP(PC); + break; + + case 0x46: /* IM 0 */ + /* interrupt mode 0 */ + break; + + case 0x47: /* LD I,A */ + IR = (IR & 0xff) | (AF & ~0xff); + break; + + case 0x48: /* IN C,(C) */ + temp = cpu_in(LOW_REGISTER(BC)); + SET_LOW_REGISTER(BC, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x49: /* OUT (C),C */ + cpu_out(LOW_REGISTER(BC), LOW_REGISTER(BC)); + break; + + case 0x4a: /* ADC HL,BC */ + HL &= ADDRMASK; + BC &= ADDRMASK; + sum = HL + BC + TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbitsZ80Table[(HL ^ BC ^ sum) >> 8]; + HL = sum; + break; + + case 0x4b: /* LD BC,(nnnn) */ + BC = GET_WORD(GET_WORD(PC)); + PC += 2; + break; + + case 0x4d: /* RETI */ + IFF |= IFF >> 1; + POP(PC); + break; + + case 0x4f: /* LD R,A */ + IR = (IR & ~0xff) | ((AF >> 8) & 0xff); + break; + + case 0x50: /* IN D,(C) */ + temp = cpu_in(LOW_REGISTER(BC)); + SET_HIGH_REGISTER(DE, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x51: /* OUT (C),D */ + cpu_out(LOW_REGISTER(BC), HIGH_REGISTER(DE)); + break; + + case 0x52: /* SBC HL,DE */ + HL &= ADDRMASK; + DE &= ADDRMASK; + sum = HL - DE - TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbits2Z80Table[((HL ^ DE ^ sum) >> 8) & 0x1ff]; + HL = sum; + break; + + case 0x53: /* LD (nnnn),DE */ + PUT_WORD(GET_WORD(PC), DE); + PC += 2; + break; + + case 0x56: /* IM 1 */ + /* interrupt mode 1 */ + break; + + case 0x57: /* LD A,I */ + AF = (AF & 0x29) | (IR & ~0xff) | ((IR >> 8) & 0x80) | (((IR & ~0xff) == 0) << 6) | ((IFF & 2) << 1); + break; + + case 0x58: /* IN E,(C) */ + temp = cpu_in(LOW_REGISTER(BC)); + SET_LOW_REGISTER(DE, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x59: /* OUT (C),E */ + cpu_out(LOW_REGISTER(BC), LOW_REGISTER(DE)); + break; + + case 0x5a: /* ADC HL,DE */ + HL &= ADDRMASK; + DE &= ADDRMASK; + sum = HL + DE + TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbitsZ80Table[(HL ^ DE ^ sum) >> 8]; + HL = sum; + break; + + case 0x5b: /* LD DE,(nnnn) */ + DE = GET_WORD(GET_WORD(PC)); + PC += 2; + break; + + case 0x5e: /* IM 2 */ + /* interrupt mode 2 */ + break; + + case 0x5f: /* LD A,R */ + AF = (AF & 0x29) | ((IR & 0xff) << 8) | (IR & 0x80) | + (((IR & 0xff) == 0) << 6) | ((IFF & 2) << 1); + break; + + case 0x60: /* IN H,(C) */ + temp = cpu_in(LOW_REGISTER(BC)); + SET_HIGH_REGISTER(HL, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x61: /* OUT (C),H */ + cpu_out(LOW_REGISTER(BC), HIGH_REGISTER(HL)); + break; + + case 0x62: /* SBC HL,HL */ + HL &= ADDRMASK; + sum = HL - HL - TSTFLAG(C); + AF = (AF & ~0xff) | (((sum & ADDRMASK) == 0) << 6) | + cbits2Z80DupTable[(sum >> 8) & 0x1ff]; + HL = sum; + break; + + case 0x63: /* LD (nnnn),HL */ + PUT_WORD(GET_WORD(PC), HL); + PC += 2; + break; + + case 0x67: /* RRD */ + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); + PUT_BYTE(HL, HIGH_DIGIT(temp) | (LOW_DIGIT(acu) << 4)); + AF = rrdrldTable[(acu & 0xf0) | LOW_DIGIT(temp)] | (AF & 1); + break; + + case 0x68: /* IN L,(C) */ + temp = cpu_in(LOW_REGISTER(BC)); + SET_LOW_REGISTER(HL, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x69: /* OUT (C),L */ + cpu_out(LOW_REGISTER(BC), LOW_REGISTER(HL)); + break; + + case 0x6a: /* ADC HL,HL */ + HL &= ADDRMASK; + sum = HL + HL + TSTFLAG(C); + AF = (AF & ~0xff) | (((sum & ADDRMASK) == 0) << 6) | + cbitsZ80DupTable[sum >> 8]; + HL = sum; + break; + + case 0x6b: /* LD HL,(nnnn) */ + HL = GET_WORD(GET_WORD(PC)); + PC += 2; + break; + + case 0x6f: /* RLD */ + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); + PUT_BYTE(HL, (LOW_DIGIT(temp) << 4) | LOW_DIGIT(acu)); + AF = rrdrldTable[(acu & 0xf0) | HIGH_DIGIT(temp)] | (AF & 1); + break; + + case 0x70: /* IN (C) */ + temp = cpu_in(LOW_REGISTER(BC)); + SET_LOW_REGISTER(temp, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x71: /* OUT (C),0 */ + cpu_out(LOW_REGISTER(BC), 0); + break; + + case 0x72: /* SBC HL,SP */ + HL &= ADDRMASK; + SP &= ADDRMASK; + sum = HL - SP - TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbits2Z80Table[((HL ^ SP ^ sum) >> 8) & 0x1ff]; + HL = sum; + break; + + case 0x73: /* LD (nnnn),SP */ + PUT_WORD(GET_WORD(PC), SP); + PC += 2; + break; + + case 0x78: /* IN A,(C) */ + temp = cpu_in(LOW_REGISTER(BC)); + SET_HIGH_REGISTER(AF, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x79: /* OUT (C),A */ + cpu_out(LOW_REGISTER(BC), HIGH_REGISTER(AF)); + break; + + case 0x7a: /* ADC HL,SP */ + HL &= ADDRMASK; + SP &= ADDRMASK; + sum = HL + SP + TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbitsZ80Table[(HL ^ SP ^ sum) >> 8]; + HL = sum; + break; + + case 0x7b: /* LD SP,(nnnn) */ + SP = GET_WORD(GET_WORD(PC)); + PC += 2; + break; + + case 0xa0: /* LDI */ + acu = RAM_PP(HL); + PUT_BYTE_PP(DE, acu); + acu += HIGH_REGISTER(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | + (((--BC & ADDRMASK) != 0) << 2); + break; + + case 0xa1: /* CPI */ + acu = HIGH_REGISTER(AF); + temp = RAM_PP(HL); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits & 16) >> 4)) & 2) << 4) | (cbits & 16) | + ((sum - ((cbits >> 4) & 1)) & 8) | + ((--BC & ADDRMASK) != 0) << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) + AF &= ~8; + break; + + /* SF, ZF, YF, XF flags are affected by decreasing register B, as in DEC B. + NF flag A is copy of bit 7 of the value read from or written to an I/O port. + INI/INIR/IND/INDR use the C flag in stead of the L register. There is a + catch though, because not the value of C is used, but C + 1 if it's INI/INIR or + C - 1 if it's IND/INDR. So, first of all INI/INIR: + HF and CF Both set if ((HL) + ((C + 1) & 255) > 255) + PF The parity of (((HL) + ((C + 1) & 255)) & 7) xor B) */ + case 0xa2: /* INI */ + acu = cpu_in(LOW_REGISTER(BC)); + PUT_BYTE(HL, acu); + ++HL; + temp = HIGH_REGISTER(BC); + BC -= 0x100; + INOUTFLAGS_NONZERO((LOW_REGISTER(BC) + 1) & 0xff); + break; + + /* SF, ZF, YF, XF flags are affected by decreasing register B, as in DEC B. + NF flag A is copy of bit 7 of the value read from or written to an I/O port. + And now the for OUTI/OTIR/OUTD/OTDR instructions. Take state of the L + after the increment or decrement of HL; add the value written to the I/O port + to; call that k for now. If k > 255, then the CF and HF flags are set. The PF + flags is set like the parity of k bitwise and'ed with 7, bitwise xor'ed with B. + HF and CF Both set if ((HL) + L > 255) + PF The parity of ((((HL) + L) & 7) xor B) */ + case 0xa3: /* OUTI */ + acu = GET_BYTE(HL); + cpu_out(LOW_REGISTER(BC), acu); + ++HL; + temp = HIGH_REGISTER(BC); + BC -= 0x100; + INOUTFLAGS_NONZERO(LOW_REGISTER(HL)); + break; + + case 0xa8: /* LDD */ + acu = RAM_MM(HL); + PUT_BYTE_MM(DE, acu); + acu += HIGH_REGISTER(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | + (((--BC & ADDRMASK) != 0) << 2); + break; + + case 0xa9: /* CPD */ + acu = HIGH_REGISTER(AF); + temp = RAM_MM(HL); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits & 16) >> 4)) & 2) << 4) | (cbits & 16) | + ((sum - ((cbits >> 4) & 1)) & 8) | + ((--BC & ADDRMASK) != 0) << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) + AF &= ~8; + break; + + /* SF, ZF, YF, XF flags are affected by decreasing register B, as in DEC B. + NF flag A is copy of bit 7 of the value read from or written to an I/O port. + INI/INIR/IND/INDR use the C flag in stead of the L register. There is a + catch though, because not the value of C is used, but C + 1 if it's INI/INIR or + C - 1 if it's IND/INDR. And last IND/INDR: + HF and CF Both set if ((HL) + ((C - 1) & 255) > 255) + PF The parity of (((HL) + ((C - 1) & 255)) & 7) xor B) */ + case 0xaa: /* IND */ + acu = cpu_in(LOW_REGISTER(BC)); + PUT_BYTE(HL, acu); + --HL; + temp = HIGH_REGISTER(BC); + BC -= 0x100; + INOUTFLAGS_NONZERO((LOW_REGISTER(BC) - 1) & 0xff); + break; + + case 0xab: /* OUTD */ + acu = GET_BYTE(HL); + cpu_out(LOW_REGISTER(BC), acu); + --HL; + temp = HIGH_REGISTER(BC); + BC -= 0x100; + INOUTFLAGS_NONZERO(LOW_REGISTER(HL)); + break; + + case 0xb0: /* LDIR */ + BC &= ADDRMASK; + if (BC == 0) + BC = 0x10000; + do { + INCR(2); /* Add two M1 cycles to refresh counter */ + acu = RAM_PP(HL); + PUT_BYTE_PP(DE, acu); + } while (--BC); + acu += HIGH_REGISTER(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); + break; + + case 0xb1: /* CPIR */ + acu = HIGH_REGISTER(AF); + BC &= ADDRMASK; + if (BC == 0) + BC = 0x10000; + do { + INCR(1); /* Add one M1 cycle to refresh counter */ + temp = RAM_PP(HL); + op = --BC != 0; + sum = acu - temp; + } while (op && sum != 0); + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits & 16) >> 4)) & 2) << 4) | + (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | + op << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) + AF &= ~8; + break; + + case 0xb2: /* INIR */ + temp = HIGH_REGISTER(BC); + if (temp == 0) + temp = 0x100; + do { + INCR(1); /* Add one M1 cycle to refresh counter */ + acu = cpu_in(LOW_REGISTER(BC)); + PUT_BYTE(HL, acu); + ++HL; + } while (--temp); + temp = HIGH_REGISTER(BC); + SET_HIGH_REGISTER(BC, 0); + INOUTFLAGS_ZERO((LOW_REGISTER(BC) + 1) & 0xff); + break; + + case 0xb3: /* OTIR */ + temp = HIGH_REGISTER(BC); + if (temp == 0) + temp = 0x100; + do { + INCR(1); /* Add one M1 cycle to refresh counter */ + acu = GET_BYTE(HL); + cpu_out(LOW_REGISTER(BC), acu); + ++HL; + } while (--temp); + temp = HIGH_REGISTER(BC); + SET_HIGH_REGISTER(BC, 0); + INOUTFLAGS_ZERO(LOW_REGISTER(HL)); + break; + + case 0xb8: /* LDDR */ + BC &= ADDRMASK; + if (BC == 0) + BC = 0x10000; + do { + INCR(2); /* Add two M1 cycles to refresh counter */ + acu = RAM_MM(HL); + PUT_BYTE_MM(DE, acu); + } while (--BC); + acu += HIGH_REGISTER(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); + break; + + case 0xb9: /* CPDR */ + acu = HIGH_REGISTER(AF); + BC &= ADDRMASK; + if (BC == 0) + BC = 0x10000; + do { + INCR(1); /* Add one M1 cycle to refresh counter */ + temp = RAM_MM(HL); + op = --BC != 0; + sum = acu - temp; + } while (op && sum != 0); + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits & 16) >> 4)) & 2) << 4) | + (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | + op << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) + AF &= ~8; + break; + + case 0xba: /* INDR */ + temp = HIGH_REGISTER(BC); + if (temp == 0) + temp = 0x100; + do { + INCR(1); /* Add one M1 cycle to refresh counter */ + acu = cpu_in(LOW_REGISTER(BC)); + PUT_BYTE(HL, acu); + --HL; + } while (--temp); + temp = HIGH_REGISTER(BC); + SET_HIGH_REGISTER(BC, 0); + INOUTFLAGS_ZERO((LOW_REGISTER(BC) - 1) & 0xff); + break; + + case 0xbb: /* OTDR */ + temp = HIGH_REGISTER(BC); + if (temp == 0) + temp = 0x100; + do { + INCR(1); /* Add one M1 cycle to refresh counter */ + acu = GET_BYTE(HL); + cpu_out(LOW_REGISTER(BC), acu); + --HL; + } while (--temp); + temp = HIGH_REGISTER(BC); + SET_HIGH_REGISTER(BC, 0); + INOUTFLAGS_ZERO(LOW_REGISTER(HL)); + break; + + default: /* ignore ED and following byte */ + break; + } + break; + + case 0xee: /* XOR nn */ + AF = xororTable[((AF >> 8) ^ RAM_PP(PC)) & 0xff]; + break; + + case 0xef: /* RST 28H */ + PUSH(PC); + PC = 0x28; + break; + + case 0xf0: /* RET P */ + if (!(TSTFLAG(S))) + POP(PC); + break; + + case 0xf1: /* POP AF */ + POP(AF); + break; + + case 0xf2: /* JP P,nnnn */ + JPC(!TSTFLAG(S)); + break; + + case 0xf3: /* DI */ + IFF = 0; + break; + + case 0xf4: /* CALL P,nnnn */ + CALLC(!TSTFLAG(S)); + break; + + case 0xf5: /* PUSH AF */ + PUSH(AF); + break; + + case 0xf6: /* OR nn */ + AF = xororTable[((AF >> 8) | RAM_PP(PC)) & 0xff]; + break; + + case 0xf7: /* RST 30H */ + PUSH(PC); + PC = 0x30; + break; + + case 0xf8: /* RET M */ + if (TSTFLAG(S)) + POP(PC); + break; + + case 0xf9: /* LD SP,HL */ + SP = HL; + break; + + case 0xfa: /* JP M,nnnn */ + JPC(TSTFLAG(S)); + break; + + case 0xfb: /* EI */ + IFF = 3; + break; + + case 0xfc: /* CALL M,nnnn */ + CALLC(TSTFLAG(S)); + break; + + case 0xfd: /* FD prefix */ + INCR(1); /* Add one M1 cycle to refresh counter */ + switch (RAM_PP(PC)) { + + case 0x09: /* ADD IY,BC */ + IY &= ADDRMASK; + BC &= ADDRMASK; + sum = IY + BC; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ BC ^ sum) >> 8]; + IY = sum; + break; + + case 0x19: /* ADD IY,DE */ + IY &= ADDRMASK; + DE &= ADDRMASK; + sum = IY + DE; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ DE ^ sum) >> 8]; + IY = sum; + break; + + case 0x21: /* LD IY,nnnn */ + IY = GET_WORD(PC); + PC += 2; + break; + + case 0x22: /* LD (nnnn),IY */ + temp = GET_WORD(PC); + PUT_WORD(temp, IY); + PC += 2; + break; + + case 0x23: /* INC IY */ + ++IY; + break; + + case 0x24: /* INC IYH */ + IY += 0x100; + AF = (AF & ~0xfe) | incZ80Table[HIGH_REGISTER(IY)]; + break; + + case 0x25: /* DEC IYH */ + IY -= 0x100; + AF = (AF & ~0xfe) | decZ80Table[HIGH_REGISTER(IY)]; + break; + + case 0x26: /* LD IYH,nn */ + SET_HIGH_REGISTER(IY, RAM_PP(PC)); + break; + + case 0x29: /* ADD IY,IY */ + IY &= ADDRMASK; + sum = IY + IY; + AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; + IY = sum; + break; + + case 0x2a: /* LD IY,(nnnn) */ + IY = GET_WORD(GET_WORD(PC)); + PC += 2; + break; + + case 0x2b: /* DEC IY */ + --IY; + break; + + case 0x2c: /* INC IYL */ + temp = LOW_REGISTER(IY) + 1; + SET_LOW_REGISTER(IY, temp); + AF = (AF & ~0xfe) | incZ80Table[temp]; + break; + + case 0x2d: /* DEC IYL */ + temp = LOW_REGISTER(IY) - 1; + SET_LOW_REGISTER(IY, temp); + AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; + break; + + case 0x2e: /* LD IYL,nn */ + SET_LOW_REGISTER(IY, RAM_PP(PC)); + break; + + case 0x34: /* INC (IY+dd) */ + adr = IY + (int8)RAM_PP(PC); + temp = GET_BYTE(adr) + 1; + PUT_BYTE(adr, temp); + AF = (AF & ~0xfe) | incZ80Table[temp]; + break; + + case 0x35: /* DEC (IY+dd) */ + adr = IY + (int8)RAM_PP(PC); + temp = GET_BYTE(adr) - 1; + PUT_BYTE(adr, temp); + AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; + break; + + case 0x36: /* LD (IY+dd),nn */ + adr = IY + (int8)RAM_PP(PC); + PUT_BYTE(adr, RAM_PP(PC)); + break; + + case 0x39: /* ADD IY,SP */ + IY &= ADDRMASK; + SP &= ADDRMASK; + sum = IY + SP; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ SP ^ sum) >> 8]; + IY = sum; + break; + + case 0x44: /* LD B,IYH */ + SET_HIGH_REGISTER(BC, HIGH_REGISTER(IY)); + break; + + case 0x45: /* LD B,IYL */ + SET_HIGH_REGISTER(BC, LOW_REGISTER(IY)); + break; + + case 0x46: /* LD B,(IY+dd) */ + SET_HIGH_REGISTER(BC, GET_BYTE(IY + (int8)RAM_PP(PC))); + break; + + case 0x4c: /* LD C,IYH */ + SET_LOW_REGISTER(BC, HIGH_REGISTER(IY)); + break; + + case 0x4d: /* LD C,IYL */ + SET_LOW_REGISTER(BC, LOW_REGISTER(IY)); + break; + + case 0x4e: /* LD C,(IY+dd) */ + SET_LOW_REGISTER(BC, GET_BYTE(IY + (int8)RAM_PP(PC))); + break; + + case 0x54: /* LD D,IYH */ + SET_HIGH_REGISTER(DE, HIGH_REGISTER(IY)); + break; + + case 0x55: /* LD D,IYL */ + SET_HIGH_REGISTER(DE, LOW_REGISTER(IY)); + break; + + case 0x56: /* LD D,(IY+dd) */ + SET_HIGH_REGISTER(DE, GET_BYTE(IY + (int8)RAM_PP(PC))); + break; + + case 0x5c: /* LD E,IYH */ + SET_LOW_REGISTER(DE, HIGH_REGISTER(IY)); + break; + + case 0x5d: /* LD E,IYL */ + SET_LOW_REGISTER(DE, LOW_REGISTER(IY)); + break; + + case 0x5e: /* LD E,(IY+dd) */ + SET_LOW_REGISTER(DE, GET_BYTE(IY + (int8)RAM_PP(PC))); + break; + + case 0x60: /* LD IYH,B */ + SET_HIGH_REGISTER(IY, HIGH_REGISTER(BC)); + break; + + case 0x61: /* LD IYH,C */ + SET_HIGH_REGISTER(IY, LOW_REGISTER(BC)); + break; + + case 0x62: /* LD IYH,D */ + SET_HIGH_REGISTER(IY, HIGH_REGISTER(DE)); + break; + + case 0x63: /* LD IYH,E */ + SET_HIGH_REGISTER(IY, LOW_REGISTER(DE)); + break; + + case 0x64: /* LD IYH,IYH */ + break; + + case 0x65: /* LD IYH,IYL */ + SET_HIGH_REGISTER(IY, LOW_REGISTER(IY)); + break; + + case 0x66: /* LD H,(IY+dd) */ + SET_HIGH_REGISTER(HL, GET_BYTE(IY + (int8)RAM_PP(PC))); + break; + + case 0x67: /* LD IYH,A */ + SET_HIGH_REGISTER(IY, HIGH_REGISTER(AF)); + break; + + case 0x68: /* LD IYL,B */ + SET_LOW_REGISTER(IY, HIGH_REGISTER(BC)); + break; + + case 0x69: /* LD IYL,C */ + SET_LOW_REGISTER(IY, LOW_REGISTER(BC)); + break; + + case 0x6a: /* LD IYL,D */ + SET_LOW_REGISTER(IY, HIGH_REGISTER(DE)); + break; + + case 0x6b: /* LD IYL,E */ + SET_LOW_REGISTER(IY, LOW_REGISTER(DE)); + break; + + case 0x6c: /* LD IYL,IYH */ + SET_LOW_REGISTER(IY, HIGH_REGISTER(IY)); + break; + + case 0x6d: /* LD IYL,IYL */ + break; + + case 0x6e: /* LD L,(IY+dd) */ + SET_LOW_REGISTER(HL, GET_BYTE(IY + (int8)RAM_PP(PC))); + break; + + case 0x6f: /* LD IYL,A */ + SET_LOW_REGISTER(IY, HIGH_REGISTER(AF)); + break; + + case 0x70: /* LD (IY+dd),B */ + PUT_BYTE(IY + (int8)RAM_PP(PC), HIGH_REGISTER(BC)); + break; + + case 0x71: /* LD (IY+dd),C */ + PUT_BYTE(IY + (int8)RAM_PP(PC), LOW_REGISTER(BC)); + break; + + case 0x72: /* LD (IY+dd),D */ + PUT_BYTE(IY + (int8)RAM_PP(PC), HIGH_REGISTER(DE)); + break; + + case 0x73: /* LD (IY+dd),E */ + PUT_BYTE(IY + (int8)RAM_PP(PC), LOW_REGISTER(DE)); + break; + + case 0x74: /* LD (IY+dd),H */ + PUT_BYTE(IY + (int8)RAM_PP(PC), HIGH_REGISTER(HL)); + break; + + case 0x75: /* LD (IY+dd),L */ + PUT_BYTE(IY + (int8)RAM_PP(PC), LOW_REGISTER(HL)); + break; + + case 0x77: /* LD (IY+dd),A */ + PUT_BYTE(IY + (int8)RAM_PP(PC), HIGH_REGISTER(AF)); + break; + + case 0x7c: /* LD A,IYH */ + SET_HIGH_REGISTER(AF, HIGH_REGISTER(IY)); + break; + + case 0x7d: /* LD A,IYL */ + SET_HIGH_REGISTER(AF, LOW_REGISTER(IY)); + break; + + case 0x7e: /* LD A,(IY+dd) */ + SET_HIGH_REGISTER(AF, GET_BYTE(IY + (int8)RAM_PP(PC))); + break; + + case 0x84: /* ADD A,IYH */ + temp = HIGH_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x85: /* ADD A,IYL */ + temp = LOW_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x86: /* ADD A,(IY+dd) */ + adr = IY + (int8)RAM_PP(PC); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8c: /* ADC A,IYH */ + temp = HIGH_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8d: /* ADC A,IYL */ + temp = LOW_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8e: /* ADC A,(IY+dd) */ + adr = IY + (int8)RAM_PP(PC); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x96: /* SUB (IY+dd) */ + adr = IY + (int8)RAM_PP(PC); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x94: /* SUB IYH */ + SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ + + case 0x9c: /* SBC A,IYH */ + temp = HIGH_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x95: /* SUB IYL */ + SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ + + case 0x9d: /* SBC A,IYL */ + temp = LOW_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x9e: /* SBC A,(IY+dd) */ + adr = IY + (int8)RAM_PP(PC); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xa4: /* AND IYH */ + AF = andTable[((AF & IY) >> 8) & 0xff]; + break; + + case 0xa5: /* AND IYL */ + AF = andTable[((AF >> 8)& IY) & 0xff]; + break; + + case 0xa6: /* AND (IY+dd) */ + AF = andTable[((AF >> 8)& GET_BYTE(IY + (int8)RAM_PP(PC))) & 0xff]; + break; + + case 0xac: /* XOR IYH */ + AF = xororTable[((AF ^ IY) >> 8) & 0xff]; + break; + + case 0xad: /* XOR IYL */ + AF = xororTable[((AF >> 8) ^ IY) & 0xff]; + break; + + case 0xae: /* XOR (IY+dd) */ + AF = xororTable[((AF >> 8) ^ GET_BYTE(IY + (int8)RAM_PP(PC))) & 0xff]; + break; + + case 0xb4: /* OR IYH */ + AF = xororTable[((AF | IY) >> 8) & 0xff]; + break; + + case 0xb5: /* OR IYL */ + AF = xororTable[((AF >> 8) | IY) & 0xff]; + break; + + case 0xb6: /* OR (IY+dd) */ + AF = xororTable[((AF >> 8) | GET_BYTE(IY + (int8)RAM_PP(PC))) & 0xff]; + break; + + case 0xbc: /* CP IYH */ + temp = HIGH_REGISTER(IY); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xbd: /* CP IYL */ + temp = LOW_REGISTER(IY); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xbe: /* CP (IY+dd) */ + adr = IY + (int8)RAM_PP(PC); + temp = GET_BYTE(adr); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xcb: /* CB prefix */ + adr = IY + (int8)RAM_PP(PC); + switch ((op = GET_BYTE(PC)) & 7) { + + case 0: + ++PC; + acu = HIGH_REGISTER(BC); + break; + + case 1: + ++PC; + acu = LOW_REGISTER(BC); + break; + + case 2: + ++PC; + acu = HIGH_REGISTER(DE); + break; + + case 3: + ++PC; + acu = LOW_REGISTER(DE); + break; + + case 4: + ++PC; + acu = HIGH_REGISTER(HL); + break; + + case 5: + ++PC; + acu = LOW_REGISTER(HL); + break; + + case 6: + ++PC; + acu = GET_BYTE(adr); + break; + + case 7: + ++PC; + acu = HIGH_REGISTER(AF); + break; + } + switch (op & 0xc0) { + + case 0x00: /* shift/rotate */ + switch (op & 0x38) { + + case 0x00:/* RLC */ + temp = (acu << 1) | (acu >> 7); + cbits = temp & 1; + goto cbshflg3; + + case 0x08:/* RRC */ + temp = (acu >> 1) | (acu << 7); + cbits = temp & 0x80; + goto cbshflg3; + + case 0x10:/* RL */ + temp = (acu << 1) | TSTFLAG(C); + cbits = acu & 0x80; + goto cbshflg3; + + case 0x18:/* RR */ + temp = (acu >> 1) | (TSTFLAG(C) << 7); + cbits = acu & 1; + goto cbshflg3; + + case 0x20:/* SLA */ + temp = acu << 1; + cbits = acu & 0x80; + goto cbshflg3; + + case 0x28:/* SRA */ + temp = (acu >> 1) | (acu & 0x80); + cbits = acu & 1; + goto cbshflg3; + + case 0x30:/* SLIA */ + temp = (acu << 1) | 1; + cbits = acu & 0x80; + goto cbshflg3; + + case 0x38:/* SRL */ + temp = acu >> 1; + cbits = acu & 1; + cbshflg3: + AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; + } + break; + + case 0x40: /* BIT */ + if (acu & (1 << ((op >> 3) & 7))) + AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); + else + AF = (AF & ~0xfe) | 0x54; + if ((op & 7) != 6) + AF |= (acu & 0x28); + temp = acu; + break; + + case 0x80: /* RES */ + temp = acu & ~(1 << ((op >> 3) & 7)); + break; + + case 0xc0: /* SET */ + temp = acu | (1 << ((op >> 3) & 7)); + break; + } + switch (op & 7) { + + case 0: + SET_HIGH_REGISTER(BC, temp); + break; + + case 1: + SET_LOW_REGISTER(BC, temp); + break; + + case 2: + SET_HIGH_REGISTER(DE, temp); + break; + + case 3: + SET_LOW_REGISTER(DE, temp); + break; + + case 4: + SET_HIGH_REGISTER(HL, temp); + break; + + case 5: + SET_LOW_REGISTER(HL, temp); + break; + + case 6: + PUT_BYTE(adr, temp); + break; + + case 7: + SET_HIGH_REGISTER(AF, temp); + break; + } + break; + + case 0xe1: /* POP IY */ + POP(IY); + break; + + case 0xe3: /* EX (SP),IY */ + temp = IY; + POP(IY); + PUSH(temp); + break; + + case 0xe5: /* PUSH IY */ + PUSH(IY); + break; + + case 0xe9: /* JP (IY) */ + PC = IY; + break; + + case 0xf9: /* LD SP,IY */ + SP = IY; + break; + + default: /* ignore FD */ + --PC; + } + break; + + case 0xfe: /* CP nn */ + temp = RAM_PP(PC); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xff: /* RST 38H */ + PUSH(PC); + PC = 0x38; + } + } +end_decode: + ; +} + + +#endif diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/disk.h b/runcpm-rp2350-hstx-usb/runcpm-pico/disk.h new file mode 100644 index 000000000..d8ee06c76 --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/disk.h @@ -0,0 +1,635 @@ +// SPDX-FileCopyrightText: 2023 Mockba the Borg +// +// SPDX-License-Identifier: MIT + +#ifndef DISK_H +#define DISK_H + +/* see main.c for definition */ + +#ifdef __linux__ +#include +#endif + +#ifdef __DJGPP__ +#include +#endif + +/* +Disk errors +*/ +#define errWRITEPROT 1 +#define errSELECT 2 + +#define RW (roVector & (1 << cDrive)) + +// Prints out a BDOS error +void _error(uint8 error) { + _puts("\r\nBdos Err on "); + _putcon('A' + cDrive); + _puts(": "); + switch (error) { + case errWRITEPROT: + _puts("R/O"); + break; + case errSELECT: + _puts("Select"); + break; + default: + _puts("\r\nCP/M ERR"); + break; + } + Status = _getch(); + _puts("\r\n"); + cDrive = oDrive = _RamRead(DSKByte) & 0x0f; + Status = 2; +} + +// Selects the disk to be used by the next disk function +int _SelectDisk(uint8 dr) { + uint8 result = 0xff; + uint8 disk[2] = { 'A', 0 }; + + if (!dr || dr == '?') { + dr = cDrive; // This will set dr to defDisk in case no disk is passed + } else { + --dr; // Called from BDOS, set dr back to 0=A: format + } + + disk[0] += dr; + if (_sys_select(&disk[0])) { + loginVector = loginVector | (1 << (disk[0] - 'A')); + result = 0x00; + } else { + _error(errSELECT); + } + + return(result); +} + +// Converts a FCB entry onto a host OS filename string +uint8 _FCBtoHostname(uint16 fcbaddr, uint8* filename) { + uint8 addDot = TRUE; + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(fcbaddr); + uint8 i = 0; + uint8 unique = TRUE; + uint8 c; + + if (F->dr && F->dr != '?') { + *(filename++) = (F->dr - 1) + 'A'; + } else { + *(filename++) = cDrive + 'A'; + } + *(filename++) = FOLDERCHAR; + + *(filename++) = toupper(tohex(userCode)); + *(filename++) = FOLDERCHAR; + + if (F->dr != '?') { + while (i < 8) { + c = F->fn[i] & 0x7F; +#ifdef NOSLASH + if (c == '/') + c = '_'; +#endif + if (c > 32) + *(filename++) = toupper(c); + if (c == '?') + unique = FALSE; + ++i; + } + i = 0; + while (i < 3) { + c = F->tp[i] & 0x7F; + if (c > 32) { + if (addDot) { + addDot = FALSE; + *(filename++) = '.'; // Only add the dot if there's an extension + } +#ifdef NOSLASH + if (c == '/') + c = '_'; +#endif + *(filename++) = toupper(c); + } + if (c == '?') + unique = FALSE; + ++i; + } + } else { + for (i = 0; i < 8; ++i) + *(filename++) = '?'; + *(filename++) = '.'; + for (i = 0; i < 3; ++i) + *(filename++) = '?'; + unique = FALSE; + } + *filename = 0x00; + + return(unique); +} + +// Convers a host OS filename string onto a FCB entry +void _HostnameToFCB(uint16 fcbaddr, uint8* filename) { + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(fcbaddr); + uint8 i = 0; + + ++filename; + if (*filename == FOLDERCHAR) { // Skips the drive and / if needed + filename += 3; + } else { + --filename; + } + + while (*filename != 0 && *filename != '.') { + F->fn[i] = toupper(*filename); + ++filename; + ++i; + } + while (i < 8) { + F->fn[i] = ' '; + ++i; + } + if (*filename == '.') + ++filename; + i = 0; + while (*filename != 0) { + F->tp[i] = toupper(*filename); + ++filename; + ++i; + } + while (i < 3) { + F->tp[i] = ' '; + ++i; + } +} + +// Converts a string name (AB.TXT) onto FCB name (AB TXT) +void _HostnameToFCBname(uint8* from, uint8* to) { + int i = 0; + + ++from; + if (*from == FOLDERCHAR) { // Skips the drive and / if needed + from += 3; + } else { + --from; + } + + while (*from != 0 && *from != '.') { + *to = toupper(*from); + ++to; ++from; ++i; + } + while (i < 8) { + *to = ' '; + ++to; ++i; + } + if (*from == '.') + ++from; + i = 0; + while (*from != 0) { + *to = toupper(*from); + ++to; ++from; ++i; + } + while (i < 3) { + *to = ' '; + ++to; ++i; + } + *to = 0; +} + +// Creates a fake directory entry for the current dmaAddr FCB +void _mockupDirEntry(void) { + CPM_DIRENTRY* DE = (CPM_DIRENTRY*)_RamSysAddr(dmaAddr); + uint8 blocks, i; + + for (i = 0; i < sizeof(CPM_DIRENTRY); ++i) + _RamWrite(dmaAddr + i, 0x00); // zero out directory entry + _HostnameToFCB(dmaAddr, (uint8*)findNextDirName); + + if (allUsers) { + DE->dr = currFindUser; // set user code for return + } else { + DE->dr = userCode; + } + // does file fit in a single directory entry? + if (fileExtents <= extentsPerDirEntry) { + if (fileExtents) { + DE->ex = (fileExtents - 1 + fileExtentsUsed) % (MaxEX + 1); + DE->s2 = (fileExtents - 1 + fileExtentsUsed) / (MaxEX + 1); + DE->rc = fileRecords - (BlkEX * (fileExtents - 1)); + } + blocks = (fileRecords >> blockShift) + ((fileRecords & blockMask) ? 1 : 0); + fileRecords = 0; + fileExtents = 0; + fileExtentsUsed = 0; + } else { // no, max out the directory entry + DE->ex = (extentsPerDirEntry - 1 + fileExtentsUsed) % (MaxEX + 1); + DE->s2 = (extentsPerDirEntry - 1 + fileExtentsUsed) / (MaxEX + 1); + DE->rc = BlkEX; + blocks = numAllocBlocks < 256 ? 16 : 8; + // update remaining records and extents for next call + fileRecords -= BlkEX * extentsPerDirEntry; + fileExtents -= extentsPerDirEntry; + fileExtentsUsed += extentsPerDirEntry; + } + // phoney up an appropriate number of allocation blocks + if (numAllocBlocks < 256) { + for (i = 0; i < blocks; ++i) + DE->al[i] = (uint8)firstFreeAllocBlock++; + } else { + for (i = 0; i < 2 * blocks; i += 2) { + DE->al[i] = firstFreeAllocBlock & 0xFF; + DE->al[i + 1] = firstFreeAllocBlock >> 8; + ++firstFreeAllocBlock; + } + } +} + +// Matches a FCB name to a search pattern +uint8 match(uint8* fcbname, uint8* pattern) { + uint8 result = 1; + uint8 i; + + for (i = 0; i < 12; ++i) { + if (*pattern == '?' || *pattern == *fcbname) { + ++pattern; ++fcbname; + continue; + } else { + result = 0; + break; + } + } + return(result); +} + +// Returns the size of a file +long _FileSize(uint16 fcbaddr) { + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(fcbaddr); + long r, l = -1; + + if (!_SelectDisk(F->dr)) { + _FCBtoHostname(fcbaddr, &filename[0]); + l = _sys_filesize(filename); + r = l % BlkSZ; + if (r) + l = l + BlkSZ - r; + } + return(l); +} + +// Opens a file +uint8 _OpenFile(uint16 fcbaddr) { + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(fcbaddr); + uint8 result = 0xff; + long len; + int32 i; + + if (!_SelectDisk(F->dr)) { + _FCBtoHostname(fcbaddr, &filename[0]); + if (_sys_openfile(&filename[0])) { + + len = _FileSize(fcbaddr) / BlkSZ; // Compute the len on the file in blocks + + F->s1 = 0x00; + F->s2 = 0x80; // set unmodified flag + + + F->rc = len > MaxRC ? MaxRC : (uint8)len; + for (i = 0; i < 16; ++i) // Clean up AL + F->al[i] = 0x00; + + result = 0x00; + } + } + return(result); +} + +// Closes a file +uint8 _CloseFile(uint16 fcbaddr) { + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(fcbaddr); + uint8 result = 0xff; + + if (!_SelectDisk(F->dr)) { + if (!(F->s2 & 0x80)) { // if file is modified + if (!RW) { + _FCBtoHostname(fcbaddr, &filename[0]); + if (fcbaddr == BatchFCB) + _Truncate((char*)filename, F->rc); // Truncate $$$.SUB to F->rc CP/M records so SUBMIT.COM can work + result = 0x00; + } else { + _error(errWRITEPROT); + } + } else { + result = 0x00; + } + } + return(result); +} + +// Creates a file +uint8 _MakeFile(uint16 fcbaddr) { + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(fcbaddr); + uint8 result = 0xff; + uint8 i; + + if (!_SelectDisk(F->dr)) { + if (!RW) { + _FCBtoHostname(fcbaddr, &filename[0]); + if (_sys_makefile(&filename[0])) { + F->ex = 0x00; // Makefile also initializes the FCB (file becomes "open") + F->s1 = 0x00; + F->s2 = 0x00; // newly created files are already modified + F->rc = 0x00; + for (i = 0; i < 16; ++i) // Clean up AL + F->al[i] = 0x00; + F->cr = 0x00; + result = 0x00; + } + } else { + _error(errWRITEPROT); + } + } + return(result); +} + +// Searches for the first directory file +uint8 _SearchFirst(uint16 fcbaddr, uint8 isdir) { + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(fcbaddr); + uint8 result = 0xff; + + if (!_SelectDisk(F->dr)) { + _FCBtoHostname(fcbaddr, &filename[0]); + allUsers = F->dr == '?'; + allExtents = F->ex == '?'; + if (allUsers) { + result = _findfirstallusers(isdir); + } else { + result = _findfirst(isdir); + } + } + return(result); +} + +// Searches for the next directory file +uint8 _SearchNext(uint16 fcbaddr, uint8 isdir) { + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(tmpFCB); + uint8 result = 0xff; + + if (!_SelectDisk(F->dr)) { + if (allUsers) { + result = _findnextallusers(isdir); + } else { + result = _findnext(isdir); + } + } + return(result); +} + +// Deletes a file +uint8 _DeleteFile(uint16 fcbaddr) { + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(fcbaddr); +#if defined(USE_PUN) || defined(USE_LST) + CPM_FCB* T = (CPM_FCB*)_RamSysAddr(tmpFCB); +#endif + uint8 result = 0xff; + uint8 deleted = 0xff; + + if (!_SelectDisk(F->dr)) { + if (!RW) { + result = _SearchFirst(fcbaddr, FALSE); // FALSE = Does not create a fake dir entry when finding the file + while (result != 0xff) { +#ifdef USE_PUN + if (!strcmp((char*)T->fn, "PUN TXT") && pun_open) { + _sys_fclose(pun_dev); + pun_open = FALSE; + } +#endif +#ifdef USE_LST + if (!strcmp((char*)T->fn, "LST TXT") && lst_open) { + _sys_fclose(lst_dev); + lst_open = FALSE; + } +#endif + _FCBtoHostname(tmpFCB, &filename[0]); + if (_sys_deletefile(&filename[0])) + deleted = 0x00; + result = _SearchFirst(fcbaddr, FALSE); // FALSE = Does not create a fake dir entry when finding the file + } + } else { + _error(errWRITEPROT); + } + } + return(deleted); +} + +// Renames a file +uint8 _RenameFile(uint16 fcbaddr) { + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(fcbaddr); + uint8 result = 0xff; + + if (!_SelectDisk(F->dr)) { + if (!RW) { + _RamWrite(fcbaddr + 16, _RamRead(fcbaddr)); // Prevents rename from moving files among folders + _FCBtoHostname(fcbaddr + 16, &newname[0]); + _FCBtoHostname(fcbaddr, &filename[0]); + if (_sys_renamefile(&filename[0], &newname[0])) + result = 0x00; + } else { + _error(errWRITEPROT); + } + } + return(result); +} + +// Sequential read +uint8 _ReadSeq(uint16 fcbaddr) { + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(fcbaddr); + uint8 result = 0xff; + + long fpos = ((F->s2 & MaxS2) * BlkS2 * BlkSZ) + + (F->ex * BlkEX * BlkSZ) + + (F->cr * BlkSZ); + + if (!_SelectDisk(F->dr)) { + _FCBtoHostname(fcbaddr, &filename[0]); + result = _sys_readseq(&filename[0], fpos); + if (!result) { // Read succeeded, adjust FCB + ++F->cr; + if (F->cr > MaxCR) { + F->cr = 1; + ++F->ex; + } + if (F->ex > MaxEX) { + F->ex = 0; + ++F->s2; + } + if ((F->s2 & 0x7F) > MaxS2) + result = 0xfe; // (todo) not sure what to do + } + } + return(result); +} + +// Sequential write +uint8 _WriteSeq(uint16 fcbaddr) { + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(fcbaddr); + uint8 result = 0xff; + + long fpos = ((F->s2 & MaxS2) * BlkS2 * BlkSZ) + + (F->ex * BlkEX * BlkSZ) + + (F->cr * BlkSZ); + + if (!_SelectDisk(F->dr)) { + if (!RW) { + _FCBtoHostname(fcbaddr, &filename[0]); + result = _sys_writeseq(&filename[0], fpos); + if (!result) { // Write succeeded, adjust FCB + F->s2 &= 0x7F; // reset unmodified flag + ++F->cr; + if (F->cr > MaxCR) { + F->cr = 1; + ++F->ex; + } + if (F->ex > MaxEX) { + F->ex = 0; + ++F->s2; + } + if (F->s2 > MaxS2) + result = 0xfe; // (todo) not sure what to do + } + } else { + _error(errWRITEPROT); + } + } + return(result); +} + +// Random read +uint8 _ReadRand(uint16 fcbaddr) { + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(fcbaddr); + uint8 result = 0xff; + + int32 record = (F->r2 << 16) | (F->r1 << 8) | F->r0; + long fpos = record * BlkSZ; + + if (!_SelectDisk(F->dr)) { + _FCBtoHostname(fcbaddr, &filename[0]); + result = _sys_readrand(&filename[0], fpos); + if (result == 0 || result == 1 || result == 4) { + // adjust FCB unless error #6 (seek past 8MB - max CP/M file & disk size) + F->cr = record & 0x7F; + F->ex = (record >> 7) & 0x1f; + if (F->s2 & 0x80) { + F->s2 = ((record >> 12) & MaxS2) | 0x80; + } else { + F->s2 = (record >> 12) & MaxS2; + } + } + } + return(result); +} + +// Random write +uint8 _WriteRand(uint16 fcbaddr) { + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(fcbaddr); + uint8 result = 0xff; + + int32 record = (F->r2 << 16) | (F->r1 << 8) | F->r0; + long fpos = record * BlkSZ; + + if (!_SelectDisk(F->dr)) { + if (!RW) { + _FCBtoHostname(fcbaddr, &filename[0]); + result = _sys_writerand(&filename[0], fpos); + if (!result) { // Write succeeded, adjust FCB + F->cr = record & 0x7F; + F->ex = (record >> 7) & 0x1f; + F->s2 = (record >> 12) & MaxS2; // resets unmodified flag + } + } else { + _error(errWRITEPROT); + } + } + return(result); +} + +// Returns the size of a CP/M file +uint8 _GetFileSize(uint16 fcbaddr) { + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(fcbaddr); + uint8 result = 0xff; + int32 count = _FileSize(DE) >> 7; + + if (count != -1) { + F->r0 = count & 0xff; + F->r1 = (count >> 8) & 0xff; + F->r2 = (count >> 16) & 0xff; + } + return(result); +} + +// Set the next random record +uint8 _SetRandom(uint16 fcbaddr) { + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(fcbaddr); + uint8 result = 0x00; + + int32 count = F->cr & 0x7f; + count += (F->ex & 0x1f) << 7; + count += (F->s2 & MaxS2) << 12; + + F->r0 = count & 0xff; + F->r1 = (count >> 8) & 0xff; + F->r2 = (count >> 16) & 0xff; + + return(result); +} + +// Sets the current user area +void _SetUser(uint8 user) { + userCode = user & 0x1f; // BDOS unoficially allows user areas 0-31 + // this may create folders from G-V if this function is called from an user program + // It is an unwanted behavior, but kept as BDOS does it +#ifdef NOHIGHUSER + if(userCode < 16) +#endif + _MakeUserDir(); // Creates the user dir (0-F[G-V]) if needed +} + +// Creates a disk directory folder +uint8 _MakeDisk(uint16 fcbaddr) { + CPM_FCB* F = (CPM_FCB*)_RamSysAddr(fcbaddr); + return(_sys_makedisk(F->dr)); +} + +// Checks if there's a temp submit file present +uint8 _CheckSUB(void) { + uint8 result; + uint8 oCode = userCode; // Saves the current user code (original BDOS does not do this) + _HostnameToFCB(tmpFCB, (uint8*)"$???????.???"); // The original BDOS in fact only looks for a file which start with $ +#ifdef BATCHA + _RamWrite(tmpFCB, 1); // Forces it to be checked on drive A: +#endif +#ifdef BATCH0 + userCode = 0; // Forces it to be checked on user 0 +#endif + result = (_SearchFirst(tmpFCB, FALSE) == 0x00) ? 0xff : 0x00; + userCode = oCode; // Restores the current user code + return(result); +} + +#ifdef HASLUA +// Executes a Lua script +uint8 _RunLua(uint16 fcbaddr) { + uint8 luascript[17]; + uint8 result = 0xff; + + if (_FCBtoHostname(fcbaddr, &luascript[0])) { // Script name must be unique + if (!_SearchFirst(fcbaddr, FALSE)) { // and must exist + result = _RunLuaScript((char*)&luascript[0]); + } + } + + return(result); +} +#endif + +#endif diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/globals.h b/runcpm-rp2350-hstx-usb/runcpm-pico/globals.h new file mode 100644 index 000000000..511c0ddf9 --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/globals.h @@ -0,0 +1,252 @@ +// SPDX-FileCopyrightText: 2023 Mockba the Borg +// +// SPDX-License-Identifier: MIT + +#ifndef GLOBALS_H +#define GLOBALS_H + +/* Some definitions needed globally */ +#ifdef __MINGW32__ +#include +#endif + +/* Definition for enabling incrementing the R register for each M1 cycle */ +#define DO_INCR + +/* Definitions for enabling PUN: and LST: devices */ +#define USE_PUN // The pun.txt and lst.txt files will appear on drive A: user 0 +#define USE_LST + +/* Definitions for file/console based debugging */ +//#define DEBUG // Enables the internal debugger (enabled by default on vstudio debug builds) +//#define iDEBUG // Enables instruction logging onto iDebug.log (for development debug only) +//#define DEBUGLOG // Writes extensive call trace information to RunCPM.log +//#define CONSOLELOG // Writes debug information to console instead of file +//#define LOGBIOS_NOT 01 // If defined will not log this BIOS function number +//#define LOGBIOS_ONLY 02 // If defines will log only this BIOS function number +//#define LOGBDOS_NOT 06 // If defined will not log this BDOS function number +//#define LOGBDOS_ONLY 22 // If defines will log only this BDOS function number +#define LogName "RunCPM.log" + +/* RunCPM version for the greeting header */ +#define VERSION "6.0" +#define VersionBCD 0x60 + +/* Definition of which CCP to use (must define only one) */ +#define CCP_INTERNAL // If this is defined, an internal CCP will emulated +//#define CCP_DR +//#define CCP_CCPZ +//#define CCP_ZCPR2 +//#define CCP_ZCPR3 +//#define CCP_Z80 + +/* Definition of the CCP memory information */ +// +#ifdef CCP_INTERNAL +#define CCPname "INTERNAL v3.0" // Will use the CCP from ccp.h +#define VersionCCP 0x30 // 0x10 and above reserved for Internal CCP +#define BatchFCB (tmpFCB + 48) +#define CCPaddr BDOSjmppage // Internal CCP has size 0 +#endif +// +#ifdef CCP_DR +#define CCPname "CCP-DR." STR(TPASIZE) "K" +#define VersionCCP 0x00 // Version to be used by INFO.COM +#define BatchFCB (CCPaddr + 0x7AC) // Position of the $$$.SUB fcb on this CCP +#define CCPaddr (BDOSjmppage-0x0800) // CCP memory address +#endif +// +#ifdef CCP_CCPZ +#define CCPname "CCP-CCPZ." STR(TPASIZE) "K" +#define VersionCCP 0x01 +#define BatchFCB (CCPaddr + 0x7A) // Position of the $$$.SUB fcb on this CCP +#define CCPaddr (BDOSjmppage-0x0800) +#endif +// +#ifdef CCP_ZCPR2 +#define CCPname "CCP-ZCP2." STR(TPASIZE) "K" +#define VersionCCP 0x02 +#define BatchFCB (CCPaddr + 0x5E) // Position of the $$$.SUB fcb on this CCP +#define CCPaddr (BDOSjmppage-0x0800) +#endif +// +#ifdef CCP_ZCPR3 +#define CCPname "CCP-ZCP3." STR(TPASIZE) "K" +#define VersionCCP 0x03 +#define BatchFCB (CCPaddr + 0x5E) // Position of the $$$.SUB fcb on this CCP +#define CCPaddr (BDOSjmppage-0x1000) +#endif +// +#ifdef CCP_Z80 +#define CCPname "CCP-Z80." STR(TPASIZE) "K" +#define VersionCCP 0x04 +#define BatchFCB (CCPaddr + 0x79E) // Position of the $$$.SUB fcb on this CCP +#define CCPaddr (BDOSjmppage-0x0800) +#endif +// +#ifndef CCPname +#error No CCP defined +#endif +// +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) +// #define CCPHEAD "\r\nRunCPM Version " VERSION " (CP/M " STR(TPASIZE) "K)\r\n" +#define CCPHEAD "\r\nRunCPM [" TEXT_BOLD "v" VERSION TEXT_NORMAL "] => CCP:[" TEXT_BOLD CCPname TEXT_NORMAL "] TPA:" TEXT_BOLD STR(TPASIZE) "K" TEXT_NORMAL "\r\n" + +#define NOSLASH // Will translate '/' to '_' on filenames to prevent directory errors + +//#define HASLUA // Will enable Lua scripting (BDOS call 254) + // Should be passed externally per-platform with -DHASLUA + +//#define PROFILE // For measuring time taken to run a CP/M command + // This should be enabled only for debugging purposes when trying to improve emulation speed + +#define NOHIGHUSER // Prevents the creation of user folders above 'F' (15) by programs + // Original CP/M BDOS allows it, but I prefer to keep the folders clean + +/* Definition for CP/M 2.2 user number support */ + +#define BATCHA // If this is defined, the $$$.SUB will be looked for on drive A: +//#define BATCH0 // If this is defined, the $$$.SUB will be looked for on user area 0 + // The default behavior of DRI's CP/M 2.2 was to have $$$.SUB created on the current drive/user while looking for it + // on drive A: current user, which made it complicated to run SUBMITs when not logged to drive A: user 0 + +/* Some environment and type definitions */ + +#ifndef TRUE +#define FALSE 0 +#define TRUE 1 +#endif + +typedef signed char int8; +typedef signed short int16; +typedef signed int int32; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; + +#define LOW_DIGIT(x) ((x) & 0xf) +#define HIGH_DIGIT(x) (((x) >> 4) & 0xf) +#define LOW_REGISTER(x) ((x) & 0xff) +#define HIGH_REGISTER(x) (((x) >> 8) & 0xff) + +#define SET_LOW_REGISTER(x, v) x = (((x) & 0xff00) | ((v) & 0xff)) +#define SET_HIGH_REGISTER(x, v) x = (((x) & 0xff) | (((v) & 0xff) << 8)) + +#define WORD16(x) ((x) & 0xffff) + +/* CP/M Page 0 definitions */ +#define IOByte 0x03 +#define DSKByte 0x04 + +/* CP/M disk definitions */ +#define BlkSZ 128 // CP/M block size +#define BlkEX 128 // Number of blocks on an extension +#define ExtSZ (BlkSZ * BlkEX) +#define BlkS2 4096 // Number of blocks on a S2 (module) +#define MaxEX 31 // Maximum value the EX field can take +#define MaxS2 15 // Maximum value the S2 (modules) field can take - Can be set to 63 to emulate CP/M Plus +#define MaxCR 128 // Maximum value the CR field can take +#define MaxRC 128 // Maximum value the RC field can take + +/* CP/M memory definitions */ +#define TPASIZE 64 // Can be 60 for CP/M 2.2 compatibility or more, up to 64 for extra memory + // Values other than 60 or 64 would require rebuilding the CCP + // For TPASIZE<60 CCP ORG = (SIZEK * 1024) - 0x0C00 + +#define BANKS 1 // Number of memory banks available +static uint8 curBank = 1; // Number of the current RAM bank in use (1-x, not 0-x) +static uint8 isXmove = FALSE; // Used by BIOS +static uint8 srcBank = 1; // Source bank for memory MOVE +static uint8 dstBank = 1; // Destination bank for memory MOVE +static uint8 ioBank = 1; // Destination bank for sector IO + +#define PAGESIZE 64 * 1024 // RAM(plus ROM) needs to be 64K to avoid compatibility issues +#define MEMSIZE PAGESIZE * BANKS // Total RAM size + +#if BANKS==1 +#define RAM_FAST // If this is defined, all RAM function calls become direct access (see below) + // This saves about 2K on the Arduino code and should bring speed improvements +#endif + +#ifdef RAM_FAST // Makes all function calls to memory access into direct RAM access (less calls / less code) + static uint8 RAM[MEMSIZE]; + #define _RamSysAddr(a) &RAM[a] + #define _RamRead(a) RAM[a] + #define _RamRead16(a) ((RAM[((a) & 0xffff) + 1] << 8) | RAM[(a) & 0xffff]) + #define _RamWrite(a, v) RAM[a] = v + #define _RamWrite16(a, v) RAM[a] = (v) & 0xff; RAM[(a) + 1] = (v) >> 8 +#endif + +// Size of the allocated pages (Minimum size = 1 page = 256 bytes) + +// BIOS Pages (512 bytes from the top of memory) +#define BIOSjmppage (PAGESIZE - 512) +#define BIOSpage (BIOSjmppage + 256) + +// BDOS Pages (depends on TPASIZE for external CCPs) +#if defined CCP_INTERNAL + #define BDOSjmppage (BIOSjmppage - 256) + #define BDOSpage (BDOSjmppage + 16) +#else + #define BDOSjmppage (TPASIZE * 1024) - 1024 + #define BDOSpage (BDOSjmppage + 256) +#endif + +#define DPBaddr (BIOSpage + 128) // Address of the Disk Parameter Block (Hardcoded in BIOS) +#define DPHaddr (DPBaddr + 15) // Address of the Disk Parameter Header + +#define SCBaddr (BDOSpage + 3) // Address of the System Control Block +#define tmpFCB (BDOSpage + 16) // Address of the temporary FCB + +/* Definition of global variables */ +static uint8 filename[17]; // Current filename in host filesystem format +static uint8 newname[17]; // New filename in host filesystem format +static uint8 fcbname[13]; // Current filename in CP/M format +static uint8 pattern[13]; // File matching pattern in CP/M format +static uint16 dmaAddr = 0x0080; // Current dmaAddr +static uint8 oDrive = 0; // Old selected drive +static uint8 cDrive = 0; // Currently selected drive +static uint8 userCode = 0; // Current user code +static uint16 roVector = 0; +static uint16 loginVector = 0; +static uint8 allUsers = FALSE; // true when dr is '?' in BDOS search first +static uint8 allExtents = FALSE; // true when ex is '?' in BDOS search first +static uint8 currFindUser = 0; // user number of current directory in BDOS search first on all user numbers +static uint8 blockShift; // disk allocation block shift +static uint8 blockMask; // disk allocation block mask +static uint8 extentMask; // disk extent mask +static uint16 firstBlockAfterDir; // first allocation block after directory +static uint16 numAllocBlocks; // # of allocation blocks on disk +static uint8 extentsPerDirEntry; // # of logical (16K) extents in a directory entry +#define logicalExtentBytes (16*1024UL) +static uint16 physicalExtentBytes;// # bytes described by 1 directory entry + +#define tohex(x) ((x) < 10 ? (x) + 48 : (x) + 87) + +/* Definition of externs to prevent precedence compilation errors */ +#ifdef __cplusplus // If building on Arduino +extern "C" +{ +#endif + +#ifndef RAM_FAST + extern uint8* _RamSysAddr(uint16 address); + extern void _RamWrite(uint16 address, uint8 value); +#endif + + extern void _Bdos(void); + extern void _Bios(void); + + extern void _HostnameToFCB(uint16 fcbaddr, uint8* filename); + extern void _HostnameToFCBname(uint8* from, uint8* to); + extern void _mockupDirEntry(void); + extern uint8 match(uint8* fcbname, uint8* pattern); + + extern void _puts(const char* str); + +#ifdef __cplusplus // If building on Arduino +} +#endif + +#endif diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/hardware/pico/metro_rp2350.h b/runcpm-rp2350-hstx-usb/runcpm-pico/hardware/pico/metro_rp2350.h new file mode 100644 index 000000000..e4d4b1503 --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/hardware/pico/metro_rp2350.h @@ -0,0 +1,341 @@ +// SPDX-FileCopyrightText: 2023 Mockba the Borg +// SPDX-FileCopyrightText: 2023 Jeff Epler for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "../../arduino_hooks.h" +#include "../../console.h" +#include +#include +#include +#include +#include + +DVHSTXText display(DVHSTX_PINOUT_DEFAULT); + +// USB Host object +Adafruit_USBH_Host USBHost; + +SdFat SD; +#if PIN_SPI1_SCK == PIN_SD_CLK +SdSpiConfig config(PIN_SD_DAT3_CS, DEDICATED_SPI, SD_SCK_MHZ(16), &SPI1); +#else +SdSpiConfig config(PIN_SD_DAT3_CS, DEDICATED_SPI, SD_SCK_MHZ(16)); +#endif + +static bool start1; + +// ========================================================================================= +// Define Board-Data +// GP25 green onboard LED +// ========================================================================================= +#define LED (13) +#define LEDinv (false) +#define board_pico +#define board_analog_io +#define board_digital_io + +queue_t kb_queue; + +void putch_display(uint8_t ch) { + if (ch == 8) { + auto x = display.getCursorX(); + if (x > 0) { + auto y = display.getCursorY(); + display.setCursor(--x, y); + display.drawPixel(x, y, ' '); + } + } else { + display.write(ch); + } +} + +uint8_t getch_usbhost(void) { + uint8_t result; + queue_remove_blocking(&kb_queue, &result); + return result; +} + +bool kbhit_usbhost(void) { return queue_get_level(&kb_queue) > 0; } + +bool port_init_early() { + if (!display.begin()) { + return false; + } + display.showCursor(); + _putch_hook = putch_display; + delay(10); + + queue_init_with_spinlock(&kb_queue, 1, 64, spin_lock_claim_unused(true)); + start1 = true; + _getch_hook = getch_usbhost; + _kbhit_hook = kbhit_usbhost; + + return true; +} + +bool port_flash_begin() { + if (!SD.begin(config)) { + return false; + } + return true; +} + +/************************************************************************* + * USB Host keyboard + *************************************************************************/ + +void setup1() { + while (!start1) + ; + +#ifdef PIN_5V_EN + pinMode(PIN_5V_EN, OUTPUT); + digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE); +#endif + + pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG; + pio_cfg.pin_dp = PIN_USB_HOST_DP; + pio_cfg.tx_ch = dma_claim_unused_channel(true); + dma_channel_unclaim(pio_cfg.tx_ch); + + USBHost.configure_pio_usb(1, &pio_cfg); + + // run host stack on controller (rhport) 1 + // Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have + // most of the host bit-banging processing works done in core1 to free up + // core0 for other works + USBHost.begin(1); + Serial.println("end of setup1"); +} + +int old_ascii = -1; +uint32_t repeat_timeout; +// this matches Linux default of 500ms to first repeat, 1/20s thereafter +const uint32_t default_repeat_time = 50; +const uint32_t initial_repeat_time = 500; + +void send_ascii(uint8_t code, uint32_t repeat_time = default_repeat_time) { + old_ascii = code; + repeat_timeout = millis() + repeat_time; + queue_try_add(&kb_queue, &code); // failure is ignored +} + +void loop1() { + uint32_t now = millis(); + uint32_t deadline = repeat_timeout - now; + if (old_ascii >= 0 && deadline > INT32_MAX) { + send_ascii(old_ascii); + deadline = repeat_timeout - now; + } else if (old_ascii < 0) { + deadline = UINT32_MAX; + } + tuh_task_ext(deadline, false); +} + +// Invoked when device with hid interface is mounted +// Report descriptor is also available for use. +// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough +// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, +// it will be skipped therefore report_desc = NULL, desc_len = 0 +void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, + uint8_t const *desc_report, uint16_t desc_len) { + (void)desc_report; + (void)desc_len; + uint16_t vid, pid; + tuh_vid_pid_get(dev_addr, &vid, &pid); + + Serial.printf("HID device address = %d, instance = %d is mounted\r\n", + dev_addr, instance); + Serial.printf("VID = %04x, PID = %04x\r\n", vid, pid); + + uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); + if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) { + Serial.printf("HID Keyboard\r\n"); + if (!tuh_hid_receive_report(dev_addr, instance)) { + Serial.printf("Error: cannot request to receive report\r\n"); + } + } +} + +// Invoked when device with hid interface is un-mounted +void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) { + Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", + dev_addr, instance); +} + +#define FLAG_ALPHABETIC (1) +#define FLAG_SHIFT (2) +#define FLAG_NUMLOCK (4) +#define FLAG_CTRL (8) +#define FLAG_LUT (16) + +const char *const lut[] = { + "!@#$%^&*()", /* 0 - shifted numeric keys */ + "\r\x1b\10\t -=[]\\#;'`,./", /* 1 - symbol keys */ + "\n\x1b\177\t _+{}|~:\"~<>?", /* 2 - shifted */ + "\12\13\10\22", /* 3 - arrow keys RLDU */ + "/*-+\n1234567890.", /* 4 - keypad w/numlock */ + "/*-+\n\xff\2\xff\4\xff\3\xff\1\xff\xff.", /* 5 - keypad w/o numlock */ +}; + +struct keycode_mapper { + uint8_t first, last, code, flags; +} keycode_to_ascii[] = { + { + HID_KEY_A, + HID_KEY_Z, + 'a', + FLAG_ALPHABETIC, + }, + + { + HID_KEY_1, + HID_KEY_9, + 0, + FLAG_SHIFT | FLAG_LUT, + }, + { + HID_KEY_1, + HID_KEY_9, + '1', + 0, + }, + { + HID_KEY_0, + HID_KEY_0, + ')', + FLAG_SHIFT, + }, + { + HID_KEY_0, + HID_KEY_0, + '0', + 0, + }, + + {HID_KEY_ENTER, HID_KEY_ENTER, '\n', FLAG_CTRL}, + { + HID_KEY_ENTER, + HID_KEY_SLASH, + 2, + FLAG_SHIFT | FLAG_LUT, + }, + { + HID_KEY_ENTER, + HID_KEY_SLASH, + 1, + FLAG_LUT, + }, + + { + HID_KEY_F1, + HID_KEY_F1, + 0x1e, + 0, + }, // help key on xerox 820 kbd + + {HID_KEY_ARROW_RIGHT, HID_KEY_ARROW_UP, 3, FLAG_LUT}, + + {HID_KEY_KEYPAD_DIVIDE, HID_KEY_KEYPAD_DECIMAL, 4, FLAG_NUMLOCK | FLAG_LUT}, + {HID_KEY_KEYPAD_DIVIDE, HID_KEY_KEYPAD_DECIMAL, 5, FLAG_LUT}, +}; + +bool report_contains(const hid_keyboard_report_t &report, uint8_t key) { + for (int i = 0; i < 6; i++) { + if (report.keycode[i] == key) + return true; + } + return false; +} + +hid_keyboard_report_t old_report; + +static bool caps, num; +static uint8_t old_leds; +void process_event(uint8_t dev_addr, uint8_t instance, + const hid_keyboard_report_t &report) { + bool alt = report.modifier & 0x44; + bool shift = report.modifier & 0x22; + bool ctrl = report.modifier & 0x11; + uint8_t code = 0; + + if (report.keycode[0] == 1 && report.keycode[1] == 1) { + // keyboard says it has exceeded max kro + return; + } + + // something was pressed or release, so cancel any key repeat + old_ascii = -1; + + for (auto keycode : report.keycode) { + if (keycode == 0) + continue; + if (report_contains(old_report, keycode)) + continue; + + /* key is newly pressed */ + if (keycode == HID_KEY_NUM_LOCK) { + Serial.println("toggle numlock"); + num = !num; + } else if (keycode == HID_KEY_CAPS_LOCK) { + Serial.println("toggle capslock"); + caps = !caps; + } else { + for (const auto &mapper : keycode_to_ascii) { + if (!(keycode >= mapper.first && keycode <= mapper.last)) + continue; + if (mapper.flags & FLAG_SHIFT && !shift) + continue; + if (mapper.flags & FLAG_NUMLOCK && !num) + continue; + if (mapper.flags & FLAG_CTRL && !ctrl) + continue; + if (mapper.flags & FLAG_LUT) { + code = lut[mapper.code][keycode - mapper.first]; + } else { + code = keycode - mapper.first + mapper.code; + } + if (mapper.flags & FLAG_ALPHABETIC) { + if (shift ^ caps) { + code ^= ('a' ^ 'A'); + } + } + if (ctrl) + code &= 0x1f; + if (alt) + code ^= 0x80; + send_ascii(code, initial_repeat_time); + break; + } + } + } + + uint8_t leds = (caps << 1) | num; + if (leds != old_leds) { + old_leds = leds; + Serial.printf("Send LEDs report %d (dev:instance = %d:%d)\r\n", leds, + dev_addr, instance); + // no worky + auto r = tuh_hid_set_report(dev_addr, instance /*idx*/, 0 /*report_id*/, + HID_REPORT_TYPE_OUTPUT /*report_type*/, + &old_leds, sizeof(old_leds)); + Serial.printf("set_report() -> %d\n", (int)r); + } + old_report = report; +} + +// Invoked when received report from device via interrupt endpoint +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, + uint8_t const *report, uint16_t len) { + if (len != sizeof(hid_keyboard_report_t)) { + Serial.printf("report len = %u NOT 8, probably something wrong !!\r\n", + len); + } else { + process_event(dev_addr, instance, *(hid_keyboard_report_t *)report); + } + // continue to request to receive report + if (!tuh_hid_receive_report(dev_addr, instance)) { + Serial.printf("Error: cannot request to receive report\r\n"); + } +} diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/host.h b/runcpm-rp2350-hstx-usb/runcpm-pico/host.h new file mode 100644 index 000000000..024f98e14 --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/host.h @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2023 Mockba the Borg +// +// SPDX-License-Identifier: MIT + +#ifndef HOST_H +#define HOST_H + +uint8 hostbdos(uint16 dmaaddr) { + return(0x00); +} + +#endif diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/main.c b/runcpm-rp2350-hstx-usb/runcpm-pico/main.c new file mode 100644 index 000000000..683ad7243 --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/main.c @@ -0,0 +1,115 @@ +// Copyright (c) 2016 - Marcelo Dantas +// SPDX-FileCopyrightText: 2023 Mockba the Borg +// +// SPDX-License-Identifier: MIT + +// Only build this code if not on Arduino +#ifndef ARDUINO + +/* globals.h must be the first file included - it defines the bare essentials */ +#include "globals.h" + +/* Any system specific includes should go here - this will define system functions used by the abstraction */ + +/* all the RunCPM includes must go after the system specific includes */ + +/* +abstraction.h - Adds all system dependent calls and definitions needed by RunCPM +This should be the only file modified for portability. Any other file +shoud be kept the same. +*/ + +#ifdef _WIN32 +#include "abstraction_vstudio.h" +#else +#include "abstraction_posix.h" +#endif + +// AUX: device configuration +#ifdef USE_PUN +FILE* pun_dev; +int pun_open = FALSE; +#endif + +// PRT: device configuration +#ifdef USE_LST +FILE* lst_dev; +int lst_open = FALSE; +#endif + +#include "ram.h" // ram.h - Implements the RAM +#include "console.h" // console.h - Defines all the console abstraction functions +#include "cpu.h" // cpu.h - Implements the emulated CPU +#include "disk.h" // disk.h - Defines all the disk access abstraction functions +#include "host.h" // host.h - Custom host-specific BDOS call +#include "cpm.h" // cpm.h - Defines the CPM structures and calls +#ifdef CCP_INTERNAL +#include "ccp.h" // ccp.h - Defines a simple internal CCP +#endif + +int main(int argc, char* argv[]) { + +#ifdef DEBUGLOG + _sys_deletefile((uint8*)LogName); +#endif + + _host_init(argc, &argv[0]); + _console_init(); + _clrscr(); + _puts(" CP/M Emulator v" VERSION " by Marcelo Dantas\r\n"); + _puts(" Built " __DATE__ " - " __TIME__ "\r\n"); +#ifdef HASLUA + _puts(" with Lua scripting support\r\n"); +#endif + _puts("-----------------------------------------\r\n"); + _puts("BIOS at 0x"); + _puthex16(BIOSjmppage); + _puts(" - "); + _puts("BDOS at 0x"); + _puthex16(BDOSjmppage); + _puts("\r\n"); + _puts("CCP " CCPname " at 0x"); + _puthex16(CCPaddr); + _puts("\r\n"); +#if BANKS > 1 + _puts("Banked Memory: "); + _puthex8(BANKS); + _puts(" banks\r\n"); +#endif + + while (TRUE) { + _puts(CCPHEAD); + _PatchCPM(); // Patches the CP/M entry points and other things in + Status = 0; +#ifdef CCP_INTERNAL + _ccp(); +#else + if (!_sys_exists((uint8*)CCPname)) { + _puts("Unable to load CP/M CCP.\r\nCPU halted.\r\n"); + break; + } + _RamLoad((uint8*)CCPname, CCPaddr); // Loads the CCP binary file into memory + Z80reset(); // Resets the Z80 CPU + SET_LOW_REGISTER(BC, _RamRead(DSKByte)); // Sets C to the current drive/user + PC = CCPaddr; // Sets CP/M application jump point + Z80run(); // Starts simulation +#endif + if (Status == 1) // This is set by a call to BIOS 0 - ends CP/M + break; +#ifdef USE_PUN + if (pun_dev) + _sys_fflush(pun_dev); +#endif +#ifdef USE_LST + if (lst_dev) + _sys_fflush(lst_dev); +#endif + } + + _puts("\r\n"); + _console_reset(); + + return(0); +} + +#endif diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/ram.h b/runcpm-rp2350-hstx-usb/runcpm-pico/ram.h new file mode 100644 index 000000000..3c7604bd7 --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/ram.h @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2023 Mockba the Borg +// +// SPDX-License-Identifier: MIT + +#ifndef RAM_H +#define RAM_H + +/* see main.c for definition */ + +#ifndef RAM_FAST +static uint8 RAM[MEMSIZE]; // Definition of the emulated RAM + +uint8* _RamSysAddr(uint16 address) { + if (address < CCPaddr) { + return(&RAM[address * curBank]); + } else { + return(&RAM[address]); + } +} + +uint8 _RamRead(uint16 address) { + if (address < CCPaddr) { + return(RAM[address * curBank]); + } else { + return(RAM[address]); + } +} + +uint16 _RamRead16(uint16 address) { + if (address < CCPaddr) { + return(RAM[address * curBank] + (RAM[(address * curBank) + 1] << 8)); + } else { + return(RAM[address] + (RAM[address + 1] << 8)); + } +} + +void _RamWrite(uint16 address, uint8 value) { + if (address < CCPaddr) { + RAM[address * curBank] = value; + } else { + RAM[address] = value; + } +} + +void _RamWrite16(uint16 address, uint16 value) { + // Z80 is a "little indian" (8 bit era joke) + _RamWrite(address, value & 0xff); + _RamWrite(address + 1, (value >> 8) & 0xff); +} +#endif + +#endif diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/resource.h b/runcpm-rp2350-hstx-usb/runcpm-pico/resource.h new file mode 100644 index 000000000..018f0cef8 --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/resource.h @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: 2023 Mockba the Borg +// +// SPDX-License-Identifier: MIT + +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by RunCPM.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/runcpm-rp2350-hstx-usb/runcpm-pico/runcpm-pico.ino b/runcpm-rp2350-hstx-usb/runcpm-pico/runcpm-pico.ino new file mode 100644 index 000000000..f6afb1844 --- /dev/null +++ b/runcpm-rp2350-hstx-usb/runcpm-pico/runcpm-pico.ino @@ -0,0 +1,227 @@ +// SPDX-FileCopyrightText: 2023 Mockba the Borg +// +// SPDX-License-Identifier: MIT + +// only AVR and ARM CPU +// #include + +// ========================================================================================= +// Guido Lehwalder's Code-Revision-Number +// ========================================================================================= +#define GL_REV "GL20230303.0" + +#include + +#include // One SD library to rule them all - Greinman SdFat from Library Manager + +#ifndef USE_VT100 +#define USE_VT100 (0) +#endif + +#if USE_VT100 +#define TEXT_BOLD "\033[1m" +#define TEXT_NORMAL "\033[0m" +#else +#define TEXT_BOLD "" +#define TEXT_NORMAL "" +#endif + +#include "globals.h" + +// ========================================================================================= +// Board definitions go into the "hardware" folder, if you use a board different +// than the Arduino DUE, choose/change a file from there and reference that file +// here +// ========================================================================================= + +// Metro RP2350 +#include "hardware/pico/metro_rp2350.h" + +#ifndef BOARD_TEXT +#define BOARD_TEXT USB_MANUFACTURER " " USB_PRODUCT +#endif + +#include "abstraction_arduino.h" +// Raspberry Pi Pico W(iFi) (LED = GPIO32) +// #include "hardware/pico/pico_w_sd_spi.h" + +// ========================================================================================= +// Delays for LED blinking +// ========================================================================================= +#define sDELAY 100 +#define DELAY 1200 + +// ========================================================================================= +// Serial port speed +// ========================================================================================= +#define SERIALSPD 115200 + +// ========================================================================================= +// PUN: device configuration +// ========================================================================================= +#ifdef USE_PUN +FILE_TYPE pun_dev; +int pun_open = FALSE; +#endif + +// ========================================================================================= +// LST: device configuration +// ========================================================================================= +#ifdef USE_LST +FILE_TYPE lst_dev; +int lst_open = FALSE; +#endif + +// (n.b. these are order sensitive. don't let clang-format reorder them!) +#include "ram.h" +#include "console.h" +#include "cpu.h" +#include "disk.h" +#include "host.h" +#include "cpm.h" +#ifdef CCP_INTERNAL +#include "ccp.h" +#endif + +void setup(void) { + pinMode(LED, OUTPUT); + digitalWrite(LED, LOW ^ LEDinv); + + // ========================================================================================= + // Serial Port Definition + // ========================================================================================= + // Serial =USB / Serial1 =UART0/COM1 / Serial2 =UART1/COM2 + + Serial1.setRX(1); // Pin 2 + Serial1.setTX(0); // Pin 1 + Serial1.begin(SERIALSPD); + + Serial2.setRX(5); // Pin 7 + Serial2.setTX(4); // Pin 6 + Serial2.begin(SERIALSPD); + + // or + + // Serial1.setRX(17); // Pin 22 + // Serial1.setTX(16); // Pin 21 + + // Serial2.setRX(21); // Pin 27 + // Serial2.setTX(20); // Pin 26 + // ========================================================================================= + + if (!port_init_early()) { + return; + } + +#if defined(WAIT_SERIAL) + // _clrscr(); + // _puts("Opening serial-port...\r\n"); + Serial.begin(SERIALSPD); + while (!Serial) { // Wait until serial is connected + digitalWrite(LED, HIGH ^ LEDinv); + delay(sDELAY); + digitalWrite(LED, LOW ^ LEDinv); + delay(DELAY); + } +#endif + +#ifdef DEBUGLOG + _sys_deletefile((uint8 *)LogName); +#endif + + // ========================================================================================= + // Printing the Startup-Messages + // ========================================================================================= + + _clrscr(); + + // if (bootup_press == 1) + // { _puts("Recognized " TEXT_BOLD "#" TEXT_NORMAL " key as pressed! + // :)\r\n\r\n"); + // } + + _puts("CP/M Emulator " TEXT_BOLD "v" VERSION "" TEXT_NORMAL + " by " TEXT_BOLD "Marcelo Dantas" TEXT_NORMAL "\r\n"); + _puts("----------------------------------------------\r\n"); + _puts(" running on [" TEXT_BOLD BOARD_TEXT TEXT_NORMAL "]\r\n"); + _puts("----------------------------------------------\r\n"); + + _puts("BIOS at [" TEXT_BOLD "0x"); + _puthex16(BIOSjmppage); + // _puts(" - "); + _puts("" TEXT_NORMAL "]\r\n"); + + _puts("BDOS at [" TEXT_BOLD "0x"); + _puthex16(BDOSjmppage); + _puts("" TEXT_NORMAL "]\r\n"); + + _puts("CCP " CCPname " at [" TEXT_BOLD "0x"); + _puthex16(CCPaddr); + _puts("" TEXT_NORMAL "]\r\n"); + +#if BANKS > 1 + _puts("Banked Memory [" TEXT_BOLD ""); + _puthex8(BANKS); + _puts("" TEXT_NORMAL "]banks\r\n"); +#endif + + // Serial.printf("Free Memory [" TEXT_BOLD "%d bytes" TEXT_NORMAL + // "]\r\n", freeMemory()); + + _puts("CPU-Clock [" TEXT_BOLD); + _putdec((clock_get_hz(clk_sys) + 500'000) / 1'000'000); + _puts(TEXT_NORMAL "] MHz\r\n"); + + _puts("Init Storage [ " TEXT_BOLD ""); + if (port_flash_begin()) { + _puts("OK " TEXT_NORMAL "]\r\n"); + _puts("----------------------------------------------"); + + if (VersionCCP >= 0x10 || SD.exists(CCPname)) { + while (true) { + _puts(CCPHEAD); + _PatchCPM(); + Status = 0; +#ifndef CCP_INTERNAL + if (!_RamLoad((char *)CCPname, CCPaddr)) { + _puts("Unable to load the CCP.\r\nCPU halted.\r\n"); + break; + } + Z80reset(); + SET_LOW_REGISTER(BC, _RamRead(DSKByte)); + PC = CCPaddr; + Z80run(); +#else + _ccp(); +#endif + if (Status == 1) + break; +#ifdef USE_PUN + if (pun_dev) + _sys_fflush(pun_dev); +#endif +#ifdef USE_LST + if (lst_dev) + _sys_fflush(lst_dev); +#endif + } + } else { + _puts("Unable to load CP/M CCP.\r\nCPU halted.\r\n"); + } + } else { + _puts("ERR " TEXT_NORMAL + "]\r\nUnable to initialize SD card.\r\nCPU halted.\r\n"); + } +} + +// if loop is reached, blink LED forever to signal error +void loop(void) { + digitalWrite(LED, HIGH ^ LEDinv); + delay(DELAY); + digitalWrite(LED, LOW ^ LEDinv); + delay(DELAY); + digitalWrite(LED, HIGH ^ LEDinv); + delay(DELAY); + digitalWrite(LED, LOW ^ LEDinv); + delay(DELAY * 4); +} diff --git a/simple_strand_palettes/simple_strand_palettes.ino b/simple_strand_palettes/simple_strand_palettes.ino index 6054840ca..6affaf59a 100644 --- a/simple_strand_palettes/simple_strand_palettes.ino +++ b/simple_strand_palettes/simple_strand_palettes.ino @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: MIT - #include "FastLED.h" // ColorWavesWithPalettes @@ -16,9 +15,9 @@ // http://fastled.io/tools/paletteknife/ // -//#if FASTLED_VERSION < 3001000 -//#error "Requires FastLED 3.1 or later; check github for latest code." -//#endif +#if defined(FASTLED_VERSION) && FASTLED_VERSION > 3010001 + #error "FastLED 3.10.2 has known compile issues with SAMD boards. Please downgrade to FastLED 3.10.1" +#endif #define DATA_PIN 6 #define LED_TYPE WS2812B